Nobody has started this yet — be first.
Business impact
positiveAmountGuard is the one guard standing between "capture"/"refund" and a payment that has no real money attached to it. If it lets amount_minor = 0 through, a captured payment with zero value becomes a valid, terminal-adjacent state in the ledger -- invisible in most revenue dashboards (₹0 doesn't move any totals) but very visible to finance during reconciliation, and a clean way for a data-quality bug elsewhere to slip a "successful" payment into the system that represents no actual transaction.
Problem
positiveAmountGuard only rejects a negative AmountMinor; zero passes.
Current behavior
A capture or refund fired with AmountMinor=0 succeeds instead of being rejected by positiveAmountGuard.
Expected behavior
Zero should be rejected exactly like a negative amount -- the guard's own error, errNonPositiveAmount, literally says "must be positive".
Steps to reproduce
go test ./tickets/tests/... -run TestTicket04 -v
This also collaterally breaks the project's own existing test, TestPaymentMachine_ZeroAmountGuard_RejectsCapture in internal/payment/machine_test.go -- that's expected; both should go green together once this is fixed.
Why this matters
positiveAmountGuard is attached (via internal/payment/machine.go's BuildMachine) to both the capture and refund transitions. Its condition determines what data ever reaches the corresponding Action (which schedules the actual bank-facing outbox call) -- so this boundary is the last line of defense before a zero-value capture/refund is treated as legitimate.
Suggested approach
The fix is entirely inside positiveAmountGuard in internal/payment/machine.go -- a single comparison operator, the same class of fix as ticket 01. Don't touch the transition table itself.
Acceptance criteria
Verification
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket04 -v && TEST_DATABASE_URL=postgresql://... go test ./internal/payment/... -run TestPaymentMachine_ZeroAmountGuard -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/zero-amount-guard-boundaryFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/zero-amount-guard-boundarySubmit 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.