Commit graph

4 commits

Author SHA1 Message Date
4c25277449
feat(thressgame-coverage): Wave 15 (e2e for 5 parity rules + lift T68/3 parry)
Closes 5 of 5 unit-only parity rules with real Playwright validation:

- T83/all_on_red: probabilistic on-turn-start arm seeds BlockAllExceptKing (verified via UI move attempt + restoration)
- T83/ice_physics: SlideMustBeMaxDistance forces sliders to max-distance ray step (verified via legal-move highlight + drag rejection)
- T68/3 parry (lifted from .fixme): capture triggers RPS → defender wins → cancel-capture restores defender + reverts attacker
- T84/religious_conversion: bishop move converts adjacent enemy non-king pieces (verified via data-piece color flip)
- T84/kamikaze: capture triggers AOE destroying adjacent non-king; king immune (verified via DOM + RNG seed)

Helper: .sisyphus/scripts/run-pw.sh — nohup-based Playwright runner with done-marker poll. Avoids 30min agent timeout when running long e2e suites.

Tests: 2865 -> 2866 (+1 unit). E2E: 8/8 pass (was 3 active + 1 fixme; now 8 active + 0 fixme). bun run check exit 0.
2026-04-26 18:06:05 -06:00
4ec48af0f9
feat(thressgame-coverage): Wave 13 (real-pipeline integration tests + Playwright e2e)
Closes systemic gap S1 from oracle audit: parity tests now drive the REAL move pipeline, not direct primitive .apply() calls.

T78 — 8 *-real.test.ts files alongside existing parity tests:
- minefield-real, mr_freeze-real, parry-real, all_on_red-real, religious_conversion-real, ice_physics-real, kamikaze-real, mind_control-real
- Each registers descriptor via applyCustomDescriptor (production path), drives engine.applyMove, asserts engine.session state
- Existing *.test.ts files unchanged (kept as logical-semantics locks)

T79 — Playwright e2e for 3 request-choice flows:
- T68/1 single-player (mr_freeze) PASSES (1.7s) — real WS round-trip
- T68/2 both-player (mind_control) PASSES (2.8s) — 2 browser contexts
- T68/3 nested (parry) is .fixme() with documented gaps:
  * Gap G: trigger dispatcher uses synthetic descriptorId='__trigger__' that submitChoiceAndResume can't resolve
  * Gap H: cancel-capture has engine-level rollback but no compensating wire-level game.delta reversal

Production additions (minimal, test-supporting):
- GameClient declares protocolVersion=2 to receive request-choice broadcasts
- data-testid='request-choice-modal' + data-choice-kind + data-marker-kind selectors on UI
- Dev-only globalThis.__paratypeChessClient debug hook (gated on import.meta.env.DEV)
- Test-only __test__.activate-descriptor WS frame handler (gated on NODE_ENV !== production)

Tests: 2824 -> 2853 (+29 unit). Playwright e2e: 3 active pass + 1 .fixme(). bun run check exit 0. No regressions in 120-test e2e suite.
2026-04-26 16:03:59 -06:00
88581ff6a9
fix(thressgame-coverage): F1+F4 remediation (T58 RequestChoiceModal + coin-flip kind)
Final Verification Wave found two real blockers:
1. T58 RequestChoiceModal.tsx was marked complete but did NOT exist on disk.
2. request-choice locked 6-kind enum was shipped as 5 (missing 'coin-flip').

Remediation:
- Build RequestChoiceModal.tsx with role=dialog, aria-modal=true, ESC/backdrop close, kind-specific input UI for all 6 kinds (rps / coin-flip / piece / square / column / row); 4 tests
- Add 'coin-flip' to:
  - request-choice primitive paramsSchema enum
  - PendingChoice.kind union (schema.ts + util/pending-choices.ts)
  - WS protocol ChoiceKindSchema (server/protocol.ts)
  - choice-timeout.firstDefaultForKind (defaults to 'heads')
  - broadcast.isValidChoiceValue (accepts 'heads' | 'tails')
- AutoChoiceResolver: deterministic alternating heads/tails for coin-flip

T68 e2e tests remain .skip()'d pending UI integration (modal-into-GameView wiring + activate-descriptor UI) — a follow-up task. The sentinel test asserts the gap exists so when integration lands, skips lift in the documented order.

Tests: 2740 -> 2744 (+4). bun run check exit 0.
2026-04-26 14:09:28 -06:00
21838af5c1
feat(thressgame-coverage): Wave 10 (8 parity descriptors + 6 templates + perf + e2e spec)
8 parity tests (recreate ThressGame rules via descriptor JSON):
- T59 minefield: spawn mines + on-piece-entered destroys; one-shot consumption
- T60 mr_freeze: request-choice column + for-row + frozen-square spawn (lifetime moves:9)
- T61 parry: on-captured + RPS request-choice + conditional + cancel-capture
- T62 all_on_red: on-turn-start + with-probability(0.1) + BlockAllExceptKing seed (lifetime turns:5)
- T63 religious_conversion: on-move(bishop) + for-each-adjacent + set-piece-attr Color
- T64 ice_physics: on-rule-activated + for-each-piece(slider filter) + SlideMustBeMaxDistance
- T65 kamikaze: on-capture + with-probability(0.25) + for-each-adjacent + destroy-piece (king excluded)
- T66 mind_control: on-rule-activated + request-choice(forPlayer:both, LIFO stack) + for-each-piece + Color set

T67: 6 template descriptors in custom/recipes.ts (simple-mine, vampire-on-capture, frozen-column, coin-flip-restriction, religious-bishop, no-mans-land)
T68: Playwright e2e spec for 3 request-choice flows (.skip()'d pending UI integration; documents the gap)
T69: 100-marker performance budget test (p99 < 50ms via deterministic engine + perf.now timing)

Tests: 2703 -> 2740 (+37). bun run check exit 0.
2026-04-26 13:50:28 -06:00