Nobody has started this yet — be first.
Business impact
The HTTP API's POST /v1/payments/{id}/events/{event} response is the payment record a client sees immediately after acting on it. If its version field is one behind what's actually stored, any client that implements its own "only proceed if nothing else changed" logic against that version will always think it's acting on stale data one step sooner than it actually is -- every follow-up request looks like a conflict from the client's point of view, or worse, race-condition-shaped bugs downstream that are hard to reproduce because the database is fine, only the response body lied.
Problem
After a successful ApplyEvent, the returned *Payment's Version field is the pre-transition version, not the post-transition one -- even though the database was correctly updated.
Current behavior
ApplyEvent returns Version=1 for a payment whose database row actually has version=2.
Expected behavior
The returned Payment.Version should match what's actually committed (expectedVersion + 1).
Steps to reproduce
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket16 -v
This also collaterally breaks the project's own TestService_ApplyEvent_HappyPath (in internal/payment/store_test.go) -- expected, both should pass together once fixed.
Why this matters
applyFireAndPersist reads a payment, computes a transition, and attempts Store.UpdateState(ctx, tx, p, expectedVersion). On success (applied == true), the SQL has already bumped the row's version column by one -- but the in-memory p struct the function goes on to return still holds whatever value it had before that call.
Suggested approach
Right after the if !applied { ... } early-return in applyFireAndPersist, is there anything updating p.Version to reflect what was just committed? Compare against what expectedVersion was captured as a few lines earlier, and what the SQL in UpdateState actually does to the version column.
Acceptance criteria
Verification
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket16 -v && TEST_DATABASE_URL=postgresql://... go test ./internal/payment/... -run TestService_ApplyEvent_HappyPath -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/apply-event-stale-versionFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/apply-event-stale-versionSubmit 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.