docs(plans): record the review of the dev implementation

This commit is contained in:
tiennm99 committed 2026-09-21 00:25:04 +07:00
1 parent 064c1733b6
commit addf2c0f2e
6 files changed
+476

No files matched your search

@@ -40,3 +40,15 @@ Both were fixed in the same change: the comment now states the exposure, and
`data/boundaries`. Treat the invariant as enforced, and treat any *new*
server-only module holding pano ids the same way -- the walk only guards what
is named in it.
Third exposure, found 2026-09-21 on branch `dev`: the daily challenge. `/api/daily`
mints a fresh session for the SAME panorama on every call with no per-player check,
and `/api/guess` scores it onto the permanent (untrimmed) score boards. Since the
first submit returns `exactLocation`, the loop GET /api/daily -> POST /api/guess
with the known coordinates is +5 on three boards for two HTTP requests, unbounded.
Ordinary rounds are immune only because `/api/new-game` draws randomly and reveals
nothing. The team's "browser-only attempt limit is fine, there is no daily board"
rationale assumes the daily credits no board; it credits the main ones.
**How to apply:** whenever a mode makes the answer repeatable (daily, replay,
shared link), check what it credits before accepting a client-side attempt limit.
@@ -36,3 +36,10 @@ members).
non-top-200 player's total lives. Also note the read-modify-write in the same
function is not atomic — concurrent rounds under one username lose an update;
`upstash.js` has no `zIncrBy` yet. Related: [[project-anti-cheat-invariant]].
Update 2026-09-21 (`dev`): the top-200 trim is GONE from the score boards
(`leaderboard.js`) and `creditScore` now uses ZINCRBY (2 commands/level instead of
4). Distance boards are still trimmed at 200; `MAX_LEADERBOARD_SIZE` is only a
serving window for scores. The `trimmed` field and the `score === null` ->
"Below top 200" dialog branch are gone — but `tests/e2e/helpers.js` still emits
`trimmed: false`.