Nobody has started this yet — be first.
Business impact
Right now a client (or a support engineer reading a captured request/response pair) cannot tell, from the response alone, whether a charge was just executed or is a replay of a previous execution -- both look identical except for the attempts field, which a caller would have to independently know the "right" value for. A dedicated header turns "did this actually charge the customer again or not?" -- a question that comes up in exactly the stressful moments (a customer dispute, a support escalation, debugging a client's own retry logic) where a clear, explicit answer saves real back-and-forth.
Problem
POST /v1/charges responses look the same whether the operation actually ran (idempotency.Proceed) or the response was served from the idempotency store (idempotency.Replay, or an idempotency.InProgress claim that resolved via Wait). There is no header or field indicating which happened.
Current behavior
A charge's first execution and a replayed charge (same Idempotency-Key, same body) return byte-for-byte identical response headers -- nothing distinguishes "this just charged the customer" from "this is a cached replay."
Expected behavior
Every /v1/charges response that did not trigger a fresh execution -- i.e. the Replay branch, and the InProgress branch once claim.Wait resolves successfully -- carries a response header X-Idempotency-Replayed: true. A response from a fresh execution (the Proceed branch) should not carry this header (or should carry it as absent/false -- pick one and be consistent; the test only checks for the presence of "true" on a replayed response).
Steps to reproduce
POST /v1/charges with a fresh Idempotency-Key and body -- the operation actually runs; inspect the response headers. POST the exact same request again (same key, same body) -- the response is served from the idempotency store, not a fresh execution. Observe: neither response carries any header indicating which one was a replay.
Why this matters
This is a small, low-risk addition that directly improves debuggability for exactly the kind of situation ("did we double-charge this customer?") this whole project exists to make provably impossible -- the header makes the proof visible in the response itself, not just in server-side logs.
Suggested approach
handleCharge in internal/server/handlers_charges.go already branches on claim.Status with a switch. Set the header on w (via w.Header().Set(...)) before calling writeStoredResponse, in the idempotency.Replay case and in the idempotency.InProgress case's successful-Wait path. Do not set it in the idempotency.Proceed case.
Acceptance criteria
Verification
go test ./test/ -run TestTask03 -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 feat/idempotency-replayed-headerFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/idempotency-replayed-headerSubmit 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 inhttp://localhost:8080POST /v1/chargesTo run against Redis (the multi-replica-safe backend) with zero local setup:
docker compose up --build # app + redis, hot-reloading on save
Work the tickets in tasks/ (ordered easy → hard); each names one Go test in test/:
make test-race # go test -race -count=1 ./...
go test ./test/ -run TestTask01 -v # a single ticket
Level 2
Implement a feature
Extend the system within its own patterns.