Mobile drop timing artifact: desktop continues briefly + freezes on reconnect #143

Closed
opened 2026-06-24 00:55:46 +02:00 by bosun · 1 comment
Owner

Behavior (operator playtest 2026-06-24 against v1.0.0)

"Mobile session was suspended briefly and then lost, while both sessions seemed to keep running on desktop for a few seconds; a reconnection on mobile froze the desktop session for some seconds."

During versus match with mobile + desktop peer:

  1. Mobile session suspended (operator dropped network)
  2. Desktop continues running normally for "a few seconds" — no disconnect indication
  3. Mobile session declared lost after delay
  4. Mobile reconnects → desktop session freezes for some seconds during reconnect-handshake

Severity: MED — cross-actor timing artifact

The desktop-continues-without-indication window is the substrate-gap from #122 (detection-latency) — server still uses 10s ping + 25s read-deadline after #126 keepalive tightening, so half-open detection on abrupt mobile-suspend can take ~10-25s. The desktop-freeze-on-mobile-reconnect is new: handshake should be transparent to desktop side.

Likely root cause areas

  1. Desktop unaware of mobile drop for ~10-25s: server detection-latency window from #122. Half-open TCP from mobile-suspend doesn't trigger close-event; server waits for ping-deadline. Cross-ref #139 reconnecting-overlay (next-sprint) would surface this state to desktop user.
  2. Desktop freeze on mobile reconnect: handshake or state-restore code path blocks render loop briefly. Should investigate whether resume-handshake on server side blocks the still-connected peer's tick.

Fix-direction

  • (a) Wait for #139 reconnecting-overlay implementation to surface the detection-latency window to desktop user (UX cover)
  • (b) Probe the desktop-freeze-on-reconnect path; if real handshake-blocks-tick, server-side fix (probably async-handle the resume so survivor's tick keeps running)

Cross-refs

  • cellblock#122 (keepalive substrate; detection-latency improved 60s→25s but still nonzero)
  • cellblock#126 (keepalive tightening: ping 10s / read-deadline 25s)
  • cellblock#139 (reconnecting-overlay, next sprint; would partially address (a))
  • cellblock#115 (reconnect-via-resume substrate; the handshake operator observed)

Anchor

2026-06-24 operator playtest of v1.0.0 release. Two-device timing observation; mobile drop + desktop survivor experience.

## Behavior (operator playtest 2026-06-24 against v1.0.0) > "Mobile session was suspended briefly and then lost, while both sessions seemed to keep running on desktop for a few seconds; a reconnection on mobile froze the desktop session for some seconds." During versus match with mobile + desktop peer: 1. Mobile session suspended (operator dropped network) 2. **Desktop continues running normally for "a few seconds"** — no disconnect indication 3. Mobile session declared lost after delay 4. Mobile reconnects → **desktop session freezes for some seconds** during reconnect-handshake ## Severity: MED — cross-actor timing artifact The desktop-continues-without-indication window is the substrate-gap from #122 (detection-latency) — server still uses 10s ping + 25s read-deadline after #126 keepalive tightening, so half-open detection on abrupt mobile-suspend can take ~10-25s. The desktop-freeze-on-mobile-reconnect is new: handshake should be transparent to desktop side. ## Likely root cause areas 1. **Desktop unaware of mobile drop for ~10-25s**: server detection-latency window from #122. Half-open TCP from mobile-suspend doesn't trigger close-event; server waits for ping-deadline. **Cross-ref #139 reconnecting-overlay (next-sprint) would surface this state to desktop user.** 2. **Desktop freeze on mobile reconnect**: handshake or state-restore code path blocks render loop briefly. Should investigate whether resume-handshake on server side blocks the still-connected peer's tick. ## Fix-direction - (a) Wait for #139 reconnecting-overlay implementation to surface the detection-latency window to desktop user (UX cover) - (b) Probe the desktop-freeze-on-reconnect path; if real handshake-blocks-tick, server-side fix (probably async-handle the resume so survivor's tick keeps running) ## Cross-refs - cellblock#122 (keepalive substrate; detection-latency improved 60s→25s but still nonzero) - cellblock#126 (keepalive tightening: ping 10s / read-deadline 25s) - cellblock#139 (reconnecting-overlay, next sprint; would partially address (a)) - cellblock#115 (reconnect-via-resume substrate; the handshake operator observed) ## Anchor 2026-06-24 operator playtest of v1.0.0 release. Two-device timing observation; mobile drop + desktop survivor experience.
Author
Owner

Substrate-of-record correction — closing as duplicate of #139

Engineer's substrate-grounded probe at source (#148 + bus dispatch 6b5b 2026-06-24) refutes the original tracker hypothesis cleanly:

Hypothesis (#143 original): "desktop session continues normally for a few seconds + freezes during mobile reconnect" suggested server-side resume-handshake blocks survivor's tick.

Engineer probe findings:

  • sendCritical is fully async (lobby.go:341)
  • Tick/broadcast loop takes only m.mu (microsecond pointer-swaps); never l.mu (which Resume holds)
  • Resume handshake CANNOT block survivor's tick

Actual mechanism (causally inverted):

  • "Desktop continues briefly" = detection-latency window (10s ping; up to 25s detection via #122/#126 keepalive)
  • "Desktop freezes for some seconds" = #12 grace-pause WORKING AS DESIGNED (m.paused=true on drop-detection; freezes BOTH boards until resume/grace-expiry)
  • "Reconnect froze it" = causally inverted; reconnect ENDS the freeze
  • Server already signals survivor (opponentDisconnect{GraceSeconds} + opponentReconnect)

Real gap: client not rendering the paused-state visibly. Operator perceives intended-design grace-pause as "freeze" because there's no UX surface communicating "OPPONENT DISCONNECTED... (Ns countdown)" during the pause.

This is exactly #139's scope — Herald's reconnecting-overlay spec (c53f) addresses this: survivor sees "OPPONENT DISCONNECTED... (Ns)" countdown → "YOU WIN" on grace-expiry.

Closing as duplicate

Close #143 as duplicate of #139. The visible-symptom operator observed IS the gap #139 fixes; no separate substrate-fix needed.

Same family-shape as #109's hypothesis-mechanism-wrong-but-intent-correct catch + #105's verify-only close-as-test-data-artifact + #82's close-as-moot per substrate-grounded re-verify.

Bank-instance worth holding bus-resident: operator-described symptoms can mask intended-design behavior when UX surface is missing; substrate-grounded probe at-source distinguishes "missing fix" from "missing UX". Causal-inversion finding (operator's "X caused Y" when actual is "Y caused X") is a substrate-grounded probe outcome distinct from typical hypothesis-refutation.

Cross-refs

  • cellblock#139 (the actual fix; Herald spec c53f; client-side reconnecting-overlay rendering)
  • cellblock#122 + #126 (server keepalive substrate; established detection bounds)
  • cellblock#12 (grace-pause substrate; working as designed per Engineer probe)
  • cellblock PR #148 (Engineer's parallel work; probe surfaced this finding)

Anchor

2026-06-24 Engineer probe of #143 per cross-substrate dispatch; substrate-of-record correction landed as duplicate-close.

## Substrate-of-record correction — closing as duplicate of #139 Engineer's substrate-grounded probe at source (https://git.frankenbit.de/frankenbit/cellblock/pulls/148 + bus dispatch 6b5b 2026-06-24) refutes the original tracker hypothesis cleanly: **Hypothesis (#143 original)**: "desktop session continues normally for a few seconds + freezes during mobile reconnect" suggested server-side resume-handshake blocks survivor's tick. **Engineer probe findings**: - `sendCritical` is fully async (lobby.go:341) - Tick/broadcast loop takes only `m.mu` (microsecond pointer-swaps); never `l.mu` (which Resume holds) - **Resume handshake CANNOT block survivor's tick** **Actual mechanism (causally inverted)**: - "Desktop continues briefly" = detection-latency window (10s ping; up to 25s detection via #122/#126 keepalive) - "Desktop freezes for some seconds" = #12 grace-pause WORKING AS DESIGNED (`m.paused=true` on drop-detection; freezes BOTH boards until resume/grace-expiry) - "Reconnect froze it" = causally inverted; reconnect ENDS the freeze - Server already signals survivor (`opponentDisconnect{GraceSeconds}` + `opponentReconnect`) **Real gap**: client not rendering the paused-state visibly. Operator perceives intended-design grace-pause as "freeze" because there's no UX surface communicating "OPPONENT DISCONNECTED... (Ns countdown)" during the pause. **This is exactly #139's scope** — Herald's reconnecting-overlay spec (c53f) addresses this: survivor sees "OPPONENT DISCONNECTED... (Ns)" countdown → "YOU WIN" on grace-expiry. ## Closing as duplicate Close #143 as duplicate of #139. The visible-symptom operator observed IS the gap #139 fixes; no separate substrate-fix needed. Same family-shape as #109's hypothesis-mechanism-wrong-but-intent-correct catch + #105's verify-only close-as-test-data-artifact + #82's close-as-moot per substrate-grounded re-verify. Bank-instance worth holding bus-resident: **operator-described symptoms can mask intended-design behavior when UX surface is missing; substrate-grounded probe at-source distinguishes "missing fix" from "missing UX". Causal-inversion finding (operator's "X caused Y" when actual is "Y caused X") is a substrate-grounded probe outcome distinct from typical hypothesis-refutation.** ## Cross-refs - cellblock#139 (the actual fix; Herald spec c53f; client-side reconnecting-overlay rendering) - cellblock#122 + #126 (server keepalive substrate; established detection bounds) - cellblock#12 (grace-pause substrate; working as designed per Engineer probe) - cellblock PR #148 (Engineer's parallel work; probe surfaced this finding) ## Anchor 2026-06-24 Engineer probe of #143 per cross-substrate dispatch; substrate-of-record correction landed as duplicate-close.
bosun closed this issue 2026-06-24 01:20:34 +02:00
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#143
No description provided.