Optional defense-in-depth: idempotency-token guard for leaderboard submit (deferred) #82
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Background
Filed as deferred-optional defense-in-depth per operator ratification on 2026-06-22, following the #80 design conversation.
Context
The #80 client-only fix (deactivate input on Enter-commit, kills double-submit at source) is the load-bearing fix and sufficient for jam-scope. The server side has been substrate-grounded: leaderboard.go
submit()has no dedup; duplicate (initials, score) rows are semantically valid (legit ties — two real players, same initials AAA / same score 1000 — are plausible).So a naive server-side content-dedup ("reject if (initials, score) already present") would FALSE-POSITIVE on legit ties and is the WRONG mechanism. This tracker captures the CORRECT optional belt-and-suspenders mechanism: per-run idempotency-token.
Proposed mechanism
Client-provided per-run idempotency-token (e.g. ULID or UUID per game session). Each /submit POST carries the token. Server keeps a short-window cache (e.g. 10 min) of recently-seen submit-tokens + rejects repeats with same token.
Distinguishes "same player re-submitting via Re-Enter" (same token → reject) from "two players genuinely colliding" (different tokens → both accept). Preserves the legit-tie invariant while preventing same-player double-submits even if the client guard fails.
Priority + status
Deferred: client-only fix in #80 is sufficient for jam-scope. Filed for board-visibility of the optional future-work; NOT a commitment to build.
Trigger to promote from deferred → active:
Lane + size
Engineer lane (server-side protocol field + cache + reject logic) + Shipwright (client-side token generation + send). Moderate scope; new protocol field, new server-state. Likely size/M.
Acceptance criteria
Cross-refs
Anchor
2026-06-22 cellblock next-sprint design conversation. Engineer flagged that the original #80 AC#4 encoded a content-dedup mechanism-assumption that would break legit-ties invariant; reshape-to-match-observable-outcome-via-different-mechanism produced this idempotency-token form as the correct optional belt-and-suspenders.
Closing per Shipwright's substrate-grounded re-verification (c08e):
Substrate state on current main:
Neither promotion-trigger fired:
Close-as deferred-won't-build-for-jam-scope per the #105 pattern. Knowledge preserved in issue body (design rationale + re-file triggers) — substrate-of-record survives the close.
Same close-with-substrate-of-record discipline as #105 (verify-only confirmed no-fix-needed) applied here at decision-not-build layer (verify-mootness + close-without-action). Idempotency-token-guard remains the right mechanism for if-and-when triggers fire.