fetchLeaderboard conflates load-board with decide-eligibility — solo PLAY AGAIN race + title-L overlay (HIGH, mechanism-traced) #98
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/cellblock#98
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?
Behavior (Surveyor chamber-playtest 2026-06-22, deployed round-15 @
44ef77f, mechanism-traced in source not speculated)fetchLeaderboard() conflates two concerns:
ANY fetch mutates eligibility. This creates two empirically-reproduced manifestations + one mechanism-derived latent harm.
Manifestation 1 — solo PLAY AGAIN race (EMPIRICALLY REPRODUCED)
After solo gameover → submit → PLAY AGAIN, the fresh PLAYING solo game persistently shows
initialsPhase='entering'(should be'idle'— no top-out yet). 6/6 polls over 2s, phase=playing.Mechanism (traced in
44ef77fsource):leaderboardvia resetLeaderboard()state.phaseis server-driven and still reads'gameover'until the new game's first WS state arrivesif (phase==='gameover' && leaderboard===null && !leaderboardFetching)) briefly re-firesfetchLeaderboard(state.you.score)with the PREVIOUS game's scorequalifies ? 'entering' : 'idle')Manifestation 2 — title-L overlay flips initialsPhase (EMPIRICALLY REPRODUCED)
Pressing L on title (high-scores overlay) flips initialsPhase from
'idle'→'entering'.The inline comment at main.ts:596 is WRONG:
// score=0 → won't trigger initials entry. Actually:qualifies = entries.length < 10 || score > lastScoreshort-circuits TRUE on non-full boardfetchLeaderboard(0)sets'entering'regardless of scoreLatent harm (mechanism-derived, NOT yet force-reproduced — needs 10-entry board)
Because M1's spurious fetch re-populates
leaderboard, the NEXT game's real gameover-fetch is SKIPPED (leaderboard !== null) → the NEXT game's initials-entry eligibility is decided by the PREVIOUS game's score, NOT the current one.entries<10⇒ everything qualifies — which is why it's been silent)Fix-direction (Shipwright lane)
Three options that address the root conflation:
Lean: option 1 or 2 (root-cause fix) > option 3 (narrowest, may leave related issues latent). Option 2 may be cleaner because eligibility IS a property of the game-just-ended, not a fetch-time decision.
Acceptance criteria
initialsPhase='idle'(no spurious entering state)Cross-refs
Anchor
2026-06-22 Surveyor chamber-playtest. Mechanism-tracing surfaced the conflation root that operator-playtest sees as symptoms but can't reach the cause of. Two findings, same root — qualitatively stronger than per-symptom fixes.
AC-tick pass — closed by PR #106 (squashed):
BONUS substrate-discipline applied:
Honest ceiling: real server-lagged M1 (where Surveyor originally found it on deployed substrate) confirms post-deploy — operator solo→submit→PLAY AGAIN → observe no spurious 'entering' state. Code axis + harness-seam done; live confirm is operator-device-gated.