Solo PLAY AGAIN routes to multiplayer mode instead of new solo game (state-machine session-mode bug) #91

Closed
opened 2026-06-22 16:28:35 +02:00 by bosun · 1 comment
Owner

Behavior (operator-observed 2026-06-22 post-round-13)

After a solo game, player enters initials at game-over leaderboard entry. Player then clicks "PLAY AGAIN" button. Instead of starting a new solo game, the game proceeds in multiplayer mode:

  • A previously-entered name is displayed
  • The screen shows "Scanning the yard for a cellmate..." (the multiplayer-lobby waiting screen)

Severity

Functionally worse than the #80 Re-Enter symptom (silent score-loss was data correctness; this is wrong-mode-transition with stale state leak). Solo player is dumped into a multiplayer flow they did not choose; previously-entered name suggests stale checkin-name state from prior multiplayer session leaking through.

Plus harness coverage gap implied: #81 didn't catch this. Either:

  • Harness doesn't cover "solo-gameover → PLAY AGAIN → solo-game" transition (coverage gap, separate from the error-resolution-path gap closed in #86)
  • Or harness mock setup doesn't reflect prod state-machine behavior (substrate-claim-vs-empirical-reality gap, third instance after round-7 metric series + round-12 BAD JSON)

Diagnostic hypotheses (NEEDS PROBE BEFORE FIX)

Per filed-rootcause-is-hypothesis discipline — verify against live before fix-shape commits.

(a) PLAY AGAIN handler doesn't differentiate session-mode: handler always routes to multiplayer-start regardless of whether player just finished solo or versus
(b) State-machine session-mode flag not reset/preserved correctly between solo-game-over and PLAY AGAIN click
(c) Something else — needs Shipwright probe of the actual handler + state-machine

Sharpened probe (Shipwright lane, read-only investigation)

  1. Read PLAY AGAIN button click handler (main.ts likely) — what does it call?
  2. Read state-machine transitions from game-over → next-state on PLAY AGAIN — is session-mode (solo vs versus) preserved?
  3. Read checkin-name state lifetime — when is it cleared, when does it leak across sessions?
  4. Assess harness coverage gap for solo-PLAY-AGAIN transition row — does #81 have this row?

Lane + size

Shipwright lane primary (client state-machine + button handler + harness extension). Engineer lane possibly involved if server-side session-mode also leaks (less likely but worth checking during probe).

Size unclear pending probe. Likely size/S-M (one fix + harness extension).

Acceptance criteria

  1. Probe identifies the exact bug-mechanism (PLAY AGAIN handler routing + session-mode preservation + stale-state lifetime)
  2. Fix lands so solo-game → game-over → PLAY AGAIN → new solo game (correct session mode preserved)
  3. Stale checkin-name state cleared appropriately on solo→solo transition
  4. Harness #81 extended with solo-PLAY-AGAIN → solo-game transition row (closes the coverage gap empirically located by this issue)
  5. No regression on versus-PLAY-AGAIN → new versus session (if that path exists)
  6. No regression on solo-game-over → leaderboard-entry → PLAY AGAIN flow

Cross-refs

  • cellblock#85 (lobby cancel-transition, related screen)
  • cellblock#80 (Re-Enter behavior, similar visual-vs-substrate-state-gap pattern)
  • cellblock#81 (harness, needs extension to cover this transition)
  • Discipline-instance: substrate-claim-vs-empirical-reality gap (third instance — round-7 metric series gap, round-12 BAD JSON gap, this one)

Anchor

2026-06-22 operator playtest of round-13 deployed substrate. "After a solo game, when the player has entered his initials and clicks the 'Play again' button, the game proceeds in multiplayer mode: A previously entered name is displayed, and the screen shows 'Scanning the yard for a cellmate...' message."

## Behavior (operator-observed 2026-06-22 post-round-13) After a solo game, player enters initials at game-over leaderboard entry. Player then clicks "PLAY AGAIN" button. **Instead of starting a new solo game, the game proceeds in multiplayer mode**: - A previously-entered name is displayed - The screen shows "Scanning the yard for a cellmate..." (the multiplayer-lobby waiting screen) ## Severity Functionally worse than the #80 Re-Enter symptom (silent score-loss was data correctness; this is wrong-mode-transition with stale state leak). Solo player is dumped into a multiplayer flow they did not choose; previously-entered name suggests stale checkin-name state from prior multiplayer session leaking through. Plus harness coverage gap implied: #81 didn't catch this. Either: - Harness doesn't cover "solo-gameover → PLAY AGAIN → solo-game" transition (coverage gap, separate from the error-resolution-path gap closed in #86) - Or harness mock setup doesn't reflect prod state-machine behavior (substrate-claim-vs-empirical-reality gap, third instance after round-7 metric series + round-12 BAD JSON) ## Diagnostic hypotheses (NEEDS PROBE BEFORE FIX) Per filed-rootcause-is-hypothesis discipline — verify against live before fix-shape commits. **(a) PLAY AGAIN handler doesn't differentiate session-mode**: handler always routes to multiplayer-start regardless of whether player just finished solo or versus **(b) State-machine session-mode flag not reset/preserved correctly** between solo-game-over and PLAY AGAIN click **(c) Something else** — needs Shipwright probe of the actual handler + state-machine ## Sharpened probe (Shipwright lane, read-only investigation) 1. Read PLAY AGAIN button click handler (main.ts likely) — what does it call? 2. Read state-machine transitions from game-over → next-state on PLAY AGAIN — is session-mode (solo vs versus) preserved? 3. Read checkin-name state lifetime — when is it cleared, when does it leak across sessions? 4. Assess harness coverage gap for solo-PLAY-AGAIN transition row — does #81 have this row? ## Lane + size Shipwright lane primary (client state-machine + button handler + harness extension). Engineer lane possibly involved if server-side session-mode also leaks (less likely but worth checking during probe). Size unclear pending probe. Likely size/S-M (one fix + harness extension). ## Acceptance criteria 1. **Probe** identifies the exact bug-mechanism (PLAY AGAIN handler routing + session-mode preservation + stale-state lifetime) 2. Fix lands so solo-game → game-over → PLAY AGAIN → **new solo game** (correct session mode preserved) 3. Stale checkin-name state cleared appropriately on solo→solo transition 4. Harness #81 extended with solo-PLAY-AGAIN → solo-game transition row (closes the coverage gap empirically located by this issue) 5. No regression on versus-PLAY-AGAIN → new versus session (if that path exists) 6. No regression on solo-game-over → leaderboard-entry → PLAY AGAIN flow ## Cross-refs - cellblock#85 (lobby cancel-transition, related screen) - cellblock#80 (Re-Enter behavior, similar visual-vs-substrate-state-gap pattern) - cellblock#81 (harness, needs extension to cover this transition) - Discipline-instance: substrate-claim-vs-empirical-reality gap (third instance — round-7 metric series gap, round-12 BAD JSON gap, this one) ## Anchor 2026-06-22 operator playtest of round-13 deployed substrate. "After a solo game, when the player has entered his initials and clicks the 'Play again' button, the game proceeds in multiplayer mode: A previously entered name is displayed, and the screen shows 'Scanning the yard for a cellmate...' message."
bosun closed this issue 2026-06-22 16:51:17 +02:00
Author
Owner

AC-tick pass — closed by PR #94 (squashed):

  1. Probe identifies exact bug-mechanism ✓ — Shipwright 3-layer substrate-grounded probe with line-number precision: client main.ts:658+:843+:483 (mode-blind sendRestart) → wire net.ts:219 ({type:rematch} bare) → server main.go:195+lobby.go:290-298+solo.go:30 (Requeue treats as versus-only). Hypothesis (a)+(b) both true.
  2. Fix lands so solo-game → game-over → PLAY AGAIN → new solo game ✓ — client-only branch on state.mode in shared playAgain() function. solo→startSolo() fresh; versus→net.sendRestart() unchanged.
  3. Stale checkin-name state cleared appropriately ✓ — NOT a separate bug; name (LS_NAME) is correctly persistent player handle; only appeared leaked because buggy path landed in versus lobby which displays yourName. Implicitly fixed.
  4. Harness #81 extended with solo-PLAY-AGAIN → solo-game transition row ✓ — via net-stub seam (bridging-substrate-form): mock injects non-null net so the harness can reach the buggy branch which ?mock-default-null-net structurally cannot. Mutation-proven (stub gives the test teeth).
  5. No regression on versus-PLAY-AGAIN → new versus session ✓ — playAgain() extraction is byte-preserving for versus + mock paths.
  6. No regression on solo-game-over → leaderboard-entry → PLAY AGAIN flow ✓ — verified by 20/20 ×2 green + Surveyor independent verification.

BONUS substrate-discipline applied:

  • Input-path-symmetry-by-construction-via-shared-function (strongest form): one shared playAgain() called from both keyboard + touch handlers; literally cannot diverge. Evolved variant from PR #90s symmetric-branches pattern (which itself was n=3 of the discipline). Now n=7 + the strongest-form variant.
  • Bridging-substrate-form: net-stub seam closes AC#4 gap without waiting for full WS-mock substrate (#92, deferred). Minimal substrate-change meets the AC; deeper end-to-end closure remains separable.
  • Substrate-grounded probe with line-number precision: probe-discipline reaching reflex-shape across crew (same depth as Engineer #80 + #86 probes).

Honest ceiling: on-device solo-PLAY-AGAIN confirm is operator-device-gated (next redeploy round-14). Code axis + mutation-proof + harness-with-faithful-stub all done; live-flow confirmation awaits operator playtest.

**AC-tick pass** — closed by PR #94 (squashed): 1. **Probe identifies exact bug-mechanism** ✓ — Shipwright 3-layer substrate-grounded probe with line-number precision: client main.ts:658+:843+:483 (mode-blind sendRestart) → wire net.ts:219 ({type:rematch} bare) → server main.go:195+lobby.go:290-298+solo.go:30 (Requeue treats as versus-only). Hypothesis (a)+(b) both true. 2. **Fix lands so solo-game → game-over → PLAY AGAIN → new solo game** ✓ — client-only branch on state.mode in shared playAgain() function. solo→startSolo() fresh; versus→net.sendRestart() unchanged. 3. **Stale checkin-name state cleared appropriately** ✓ — NOT a separate bug; name (LS_NAME) is correctly persistent player handle; only appeared leaked because buggy path landed in versus lobby which displays yourName. Implicitly fixed. 4. **Harness #81 extended with solo-PLAY-AGAIN → solo-game transition row** ✓ — via net-stub seam (bridging-substrate-form): mock injects non-null net so the harness can reach the buggy branch which ?mock-default-null-net structurally cannot. Mutation-proven (stub gives the test teeth). 5. **No regression on versus-PLAY-AGAIN → new versus session** ✓ — playAgain() extraction is byte-preserving for versus + mock paths. 6. **No regression on solo-game-over → leaderboard-entry → PLAY AGAIN flow** ✓ — verified by 20/20 ×2 green + Surveyor independent verification. BONUS substrate-discipline applied: - **Input-path-symmetry-by-construction-via-shared-function (strongest form)**: one shared playAgain() called from both keyboard + touch handlers; literally cannot diverge. Evolved variant from PR #90s symmetric-branches pattern (which itself was n=3 of the discipline). Now n=7 + the strongest-form variant. - **Bridging-substrate-form**: net-stub seam closes AC#4 gap without waiting for full WS-mock substrate (#92, deferred). Minimal substrate-change meets the AC; deeper end-to-end closure remains separable. - **Substrate-grounded probe with line-number precision**: probe-discipline reaching reflex-shape across crew (same depth as Engineer #80 + #86 probes). Honest ceiling: on-device solo-PLAY-AGAIN confirm is operator-device-gated (next redeploy round-14). Code axis + mutation-proof + harness-with-faithful-stub all done; live-flow confirmation awaits operator playtest.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/cellblock#91
No description provided.