Nobody has started this yet — be first.
Business impact
POST /v1/payments/{id}/events/authorize -- the literal, documented API endpoint every real integration (a merchant's backend, a support tool, a curl command in this very README) calls to authorize a payment -- currently declines it instead. And the reverse: calling .../events/decline authorizes it. This is about as bad as a payment API bug gets: it's not a crash, not a 500, not even an obviously wrong response -- the request succeeds, returns 200, and does the opposite of what was asked. A merchant integration built and tested against this API would ship completely broken, while every one of this project's own Go-level tests keeps passing, because they all refer to payment.EventAuthorize/EventDecline by their symbolic Go names rather than by the literal string a real HTTP client sends.
Problem
internal/payment/models.go declares EventAuthorize = "decline" and EventDecline = "authorize". Every internal call site (the transition table in machine.go, the outbox dispatcher's resolve) consistently uses the symbolic names payment.EventAuthorize / payment.EventDecline, so internal Go code is self-consistent and its own tests don't notice anything is wrong. But the HTTP handler for POST /v1/payments/{id}/events/{event} takes {event} as a raw path parameter -- a literal string -- and fires it directly against the machine. The literal string "authorize" in the URL now maps (via the swapped constants) to the transition originally meant for "decline".
Current behavior
POST .../events/authorize moves a created payment to failed instead of authorized, and vice versa for .../events/decline.
Expected behavior
POST .../events/authorize should move a created payment to authorized. POST .../events/decline should move it to failed.
Steps to reproduce
ID=$(curl -s -X POST localhost:8080/v1/payments -d '{"amount_minor":1000,"currency":"INR"}' | jq -r .id) curl -s -X POST localhost:8080/v1/payments/$ID/events/authorize curl -s localhost:8080/v1/payments/$ID | jq .state
Why this matters
This is a real lesson about string constants that are also part of a public, external contract (an HTTP path segment, in this case): as long as every reference goes through the symbolic Go constant, swapping the constants' underlying values is invisible to Go-level tests. Only a test that exercises the actual wire format -- the literal strings a real caller sends -- can catch this class of bug. This is exactly why tickets/tests/ticket12_test.go posts to a literal URL path instead of calling payment.EventAuthorize from Go.
Suggested approach
Look at the two constant declarations in internal/payment/models.go and check each one's string literal against its own name and the comment right next to it.
Acceptance criteria
Verification
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket12 -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/authorize-decline-constants-swappedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/authorize-decline-constants-swappedSubmit 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.