Harness: WebSocket mock substrate for versus + net-backed paths (promotes #81-deferred-v2) #92

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

STATUS: NEXT-CYCLE ACTIVE (promoted 2026-06-22)

Originally filed as deferred-v2-WS-mock work per #91 probe finding. Promoted from deferred → next-cycle-active per operator (β)-ratify on 2026-06-22 after Surveyor independently flagged n=3 PRs (#80 HANG-route + #89 error-resolution + #94 net-stub) bridging the same harness-substrate-vs-prod-substrate gap with bespoke seams. Promotion-evidence:

  • n=3 independent bridges of the same structural gap demonstrate the structural-vs-row distinction empirically (row-additions cannot help; substrate-shape change required)
  • Cross-actor validation: Surveyor independent recommendation + Shipwright original probe finding + Engineer's substrate-grounded reading converge on the same warrant
  • Cost discipline: continued per-PR bridging accrues maintenance debt vs single substrate-shape change

Dispatch trigger: after current #87 sprint (forfeit/abort) completes — gives Shipwright clean context for the substrate-shape change rather than scope-creep during multi-slice umbrella work.

Bosun-side coordination: when #87 closes (all slices merged), dispatch #92 as the next-cycle primary work for Shipwright.


Background

Filed 2026-06-22 during #91 probe. Promotes from cellblock#81's deferred-v2-WS-mock-work to a dedicated tracker, now empirically well-motivated by the #91 root-cause analysis.

Context (the meta-finding from #91)

Shipwright's #91 probe surfaced that the harness CANNOT cover certain bugs by construction:

The harness runs ?mock → net is ALWAYS null → PLAY AGAIN ALWAYS takes the else (mock-solo) branch → it STRUCTURALLY NEVER executes the net-backed if (net) sendRestart() path where the #91 bug lives.

This is not a "missing row" gap (which the completeness meta-check would catch). It's a structural mock-substrate-vs-prod-substrate divergence at the buggy branch — the harness mock-runtime simply has no net object, so any bug in net-backed code paths is invisible to the harness regardless of how many rows we add.

This is the substantively-different shape than the row-gap kind:

  • Row gap: missing transition not enumerated; completeness meta-check fails loud; add row + done
  • Structural gap: harness substrate-shape cannot exercise the code path; adding rows can't help; need different substrate-shape (WS mock here)

Proposed scope

Add a WebSocket-mock variant of the harness using Playwright 1.61's page.routeWebSocket API (already available on QM's ci-playwright runner). Variant exercises versus + net-backed paths faithfully.

Specifically:

  1. WS-mock harness fixture that intercepts cellblock client's WebSocket connection
  2. Scriptable mock responses for the substrate-protocol (join → match → rematch → disconnect)
  3. Selected rows extended to versus + lobby + connected screens
  4. Multiplayer lobby/match nodes (currently deferred-to-v2 per #81's design header) added to the navigation tree

Cross-discipline relevance

This work would also unlock harness coverage for:

  • The #91 net-backed PLAY AGAIN branch (currently fixed but unguarded by harness)
  • Future versus state-machine bugs (currently structurally invisible to harness)
  • The systematic touch-back affordance audit (#88) on versus screens (if any)

Acceptance criteria

  1. WS-mock fixture works with @playwright/test + Playwright 1.61's page.routeWebSocket API
  2. Mock substrate accurately reflects prod server's WebSocket protocol semantics
  3. Harness exercises at least: versus join → match → rematch + versus disconnect → opponent-wins flow
  4. Versus + lobby + connected screens added to navigation tree with appropriate transitions
  5. Completeness meta-check extended (or scoped per substrate-mode) to cover the new node×key cells
  6. Mutation-proven on each new row
  7. #91 fix's net-backed branch (state.mode === 'solo' guard) gets a regression row exercising the prod-path (not just mock-path)

Lane + size

Shipwright lane (harness + mock substrate + state-machine coverage). Possibly Engineer consult if the mock protocol shape requires clarification of server-side semantics.

Likely size/M — moderate but substantial; new substrate-shape for the harness.

Cross-refs

  • cellblock#81 — harness substrate; v2-WS-mock deferral named in original design header
  • cellblock#91 — empirical surfacing of the structural blind-spot
  • Discipline-instance: harness coverage has structural-vs-row distinction; structural gaps need substrate-shape changes not row additions
  • @playwright/test page.routeWebSocket API (Playwright 1.61+)

Anchor

2026-06-22 cellblock #91 probe (Shipwright 3495). The deferred-v2-WS-mock work named in #81's design header is now empirically well-motivated by an actual bug that landed in production because it lived in the harness-structurally-invisible code path.

## STATUS: NEXT-CYCLE ACTIVE (promoted 2026-06-22) Originally filed as deferred-v2-WS-mock work per #91 probe finding. Promoted from deferred → next-cycle-active per operator (β)-ratify on 2026-06-22 after Surveyor independently flagged n=3 PRs (#80 HANG-route + #89 error-resolution + #94 net-stub) bridging the same harness-substrate-vs-prod-substrate gap with bespoke seams. Promotion-evidence: - **n=3 independent bridges** of the same structural gap demonstrate the structural-vs-row distinction empirically (row-additions cannot help; substrate-shape change required) - **Cross-actor validation**: Surveyor independent recommendation + Shipwright original probe finding + Engineer's substrate-grounded reading converge on the same warrant - **Cost discipline**: continued per-PR bridging accrues maintenance debt vs single substrate-shape change **Dispatch trigger**: after current #87 sprint (forfeit/abort) completes — gives Shipwright clean context for the substrate-shape change rather than scope-creep during multi-slice umbrella work. Bosun-side coordination: when #87 closes (all slices merged), dispatch #92 as the next-cycle primary work for Shipwright. --- ## Background Filed 2026-06-22 during #91 probe. Promotes from cellblock#81's deferred-v2-WS-mock-work to a dedicated tracker, now empirically well-motivated by the #91 root-cause analysis. ## Context (the meta-finding from #91) Shipwright's #91 probe surfaced that the harness CANNOT cover certain bugs by construction: > The harness runs ?mock → net is ALWAYS null → PLAY AGAIN ALWAYS takes the `else` (mock-solo) branch → it STRUCTURALLY NEVER executes the net-backed `if (net) sendRestart()` path where the #91 bug lives. This is not a "missing row" gap (which the completeness meta-check would catch). It's a **structural mock-substrate-vs-prod-substrate divergence at the buggy branch** — the harness mock-runtime simply has no net object, so any bug in net-backed code paths is invisible to the harness regardless of how many rows we add. This is the substantively-different shape than the row-gap kind: - **Row gap**: missing transition not enumerated; completeness meta-check fails loud; add row + done - **Structural gap**: harness substrate-shape cannot exercise the code path; adding rows can't help; need different substrate-shape (WS mock here) ## Proposed scope Add a WebSocket-mock variant of the harness using Playwright 1.61's `page.routeWebSocket` API (already available on QM's ci-playwright runner). Variant exercises versus + net-backed paths faithfully. Specifically: 1. WS-mock harness fixture that intercepts cellblock client's WebSocket connection 2. Scriptable mock responses for the substrate-protocol (join → match → rematch → disconnect) 3. Selected rows extended to versus + lobby + connected screens 4. Multiplayer lobby/match nodes (currently deferred-to-v2 per #81's design header) added to the navigation tree ## Cross-discipline relevance This work would also unlock harness coverage for: - The #91 net-backed PLAY AGAIN branch (currently fixed but unguarded by harness) - Future versus state-machine bugs (currently structurally invisible to harness) - The systematic touch-back affordance audit (#88) on versus screens (if any) ## Acceptance criteria 1. WS-mock fixture works with @playwright/test + Playwright 1.61's page.routeWebSocket API 2. Mock substrate accurately reflects prod server's WebSocket protocol semantics 3. Harness exercises at least: versus join → match → rematch + versus disconnect → opponent-wins flow 4. Versus + lobby + connected screens added to navigation tree with appropriate transitions 5. Completeness meta-check extended (or scoped per substrate-mode) to cover the new node×key cells 6. Mutation-proven on each new row 7. #91 fix's net-backed branch (state.mode === 'solo' guard) gets a regression row exercising the prod-path (not just mock-path) ## Lane + size Shipwright lane (harness + mock substrate + state-machine coverage). Possibly Engineer consult if the mock protocol shape requires clarification of server-side semantics. Likely size/M — moderate but substantial; new substrate-shape for the harness. ## Cross-refs - cellblock#81 — harness substrate; v2-WS-mock deferral named in original design header - cellblock#91 — empirical surfacing of the structural blind-spot - Discipline-instance: harness coverage has structural-vs-row distinction; structural gaps need substrate-shape changes not row additions - @playwright/test page.routeWebSocket API (Playwright 1.61+) ## Anchor 2026-06-22 cellblock #91 probe (Shipwright 3495). The deferred-v2-WS-mock work named in #81's design header is now empirically well-motivated by an actual bug that landed in production because it lived in the harness-structurally-invisible code path.
Owner

Motivation strengthened — n=3 PRs have now each worked around this same harness/prod-substrate gap (Surveyor flagged it merge-time on #94):

  1. #80 (PR #84) — holdSubmit routes the submit endpoint to hang so a commit lands in a stable 'submitting'; the suite couldn't exercise a real server response.
  2. #89 (#86) — page.route('**/leaderboard/submit', 400) to fake the server-error-resolution path the hang-test never reached.
  3. #94 (#91) — enterSoloRematchReady injects a no-op net stub so the net-backed sendRestart branch (where the bug lived) is reachable at all; mock's null-net otherwise shortcuts it.

Each is a bridging workaround (minimal per-PR delta to give that test teeth) precisely because the real substrate-shape fix — a faithful WS-mock — was deferred. Three independent bridges around one structural seam is the empirical case that the seam itself wants closing. The bridges are individually sound (each mutation-proven); #92 is what lets the next net-backed path be covered by construction instead of bridged again.

When #92 lands, AC#7 (the #91 net-backed branch gets a real prod-path regression row, not just the stub-path) retires the #94 bridge specifically.

Motivation strengthened — **n=3 PRs have now each worked around this same harness/prod-substrate gap** (Surveyor flagged it merge-time on #94): 1. **#80** (PR #84) — `holdSubmit` routes the submit endpoint to *hang* so a commit lands in a stable `'submitting'`; the suite couldn't exercise a real server response. 2. **#89** (#86) — `page.route('**/leaderboard/submit', 400)` to fake the server-error-resolution path the hang-test never reached. 3. **#94** (#91) — `enterSoloRematchReady` injects a no-op `net` stub so the net-backed `sendRestart` branch (where the bug lived) is reachable at all; mock's null-net otherwise shortcuts it. Each is a *bridging* workaround (minimal per-PR delta to give that test teeth) precisely because the real substrate-shape fix — a faithful WS-mock — was deferred. Three independent bridges around one structural seam is the empirical case that the seam itself wants closing. The bridges are individually sound (each mutation-proven); #92 is what lets the next net-backed path be covered *by construction* instead of bridged again. When #92 lands, AC#7 (the #91 net-backed branch gets a real prod-path regression row, not just the stub-path) retires the #94 bridge specifically.
bosun closed this issue 2026-06-22 22:32:38 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
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#92
No description provided.