Nobody has started this yet — be first.
Business impact
This is the demo bank/UPI simulator, so nothing real is at stake -- but imagine it wasn't a demo. simulator_profile: "decline" exists so QA, demos, and integration tests can deterministically prove the created -> failed path works. If it silently approves instead, every test and demo that relies on it to exercise the decline branch is actually testing nothing -- a false green across the board. In a real issuer integration this exact class of bug (a response-code mapping inverted) is how a "payment declined" webhook ends up crediting an order that was never actually paid for.
Problem
Simulator.Initiate called with Profile: "decline" returns Outcome: "approved" instead of Outcome: "declined".
Current behavior
A payment created with simulator_profile: "decline" ends up authorized instead of failed.
Expected behavior
Profile: "decline" should return Outcome: "declined", matching its own Detail string ("issuer declined the collect request") and driving the payment to failed via the decline event.
Steps to reproduce
go test ./tickets/tests/... -run TestTicket03 -v
Or manually, once the server is running:
curl -s -X POST localhost:8080/v1/payments
-d '{"amount_minor": 1000, "currency": "INR", "simulator_profile": "decline"}'
curl -s localhost:8080/v1/payments/<id>
Why this matters
Simulator.Initiate's switch req.Profile has one case per profile, each returning a Result{Outcome: ..., Detail: ...}. The Detail string for the ProfileDecline case correctly says "issuer declined the collect request" -- but the Outcome field right next to it names the wrong constant. internal/outbox.Dispatcher.resolve switches on outcome.Outcome (not Detail) to decide whether to fire authorize or decline against the payment machine, so this is the field that actually drives behavior.
Suggested approach
Look at the case payment.ProfileDecline: branch in internal/bank/simulator.go's Initiate, and compare its Outcome value against the two exported constants bank.OutcomeApproved / bank.OutcomeDeclined declared right above it.
Acceptance criteria
Verification
go test ./tickets/tests/... -run TestTicket03 -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b fix/decline-profile-approvesFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/decline-profile-approvesSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign indocker composepaystate/paystate/go.modreplace reliable => ../reliabledocker compose up --buildpaystate/context: ..docker-compose.ymlCREATED_TIMEOUTAUTHORIZED_TIMEOUTWork the tickets in tickets/docs/ (ticket-01 through ticket-25); each names one Go test in tickets/tests/:
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket01 -v # a single ticket
TEST_DATABASE_URL=postgresql://... ./tickets/run_tickets.sh # all 25, clean pass/fail summary
Tickets that don't touch Postgres (02, 03, 04, 05, 06, 14, 15, 24) run fine without TEST_DATABASE_URL set; the rest report FAIL with a "TEST_DATABASE_URL not set" message if it's missing. make test-race runs the full go test -race -p 1 ./... suite the same way.
Level 1
Fix a bug
Read existing behaviour, correct it.