34655ddadd
feat(thressgame-templates): V2 validator + 9 new recipes + Playwright e2e
...
Validator V2: widen 9 imperative-primitive Zod schemas to accept resolver
shapes ($var / ctx-attr / ctx-build) alongside literals so the 8 parity-fixture
descriptors graduate from test-only artifacts into first-class loadable recipes.
Schemas widened (target/square/positional fields):
- move-piece, set-piece-attr, destroy-piece, destroy-marker, swap-pieces
- convert-piece-type, place-piece, spawn-marker, spawn-marker-pair
- cancel-capture (audited — no positional field, N/A)
Strict enums preserved: pieceType, color, markerKind reject resolver shapes
(intentional design constraint — closed sets defining piece behavior).
Validator iteration-trigger-scope fix (validate.ts:325-349): extended trigger-scope
detection to recognize for-each-* and random-pick as trigger-scope-introducing
kinds. Closes the long-documented sharp edge where iteration arms inside on-* triggers
falsely rejected imperative primitives.
9 new recipes in CUSTOM_MODIFIER_RECIPES (14 → 23 total):
- 6 parity-faithful: tpl-religious-conversion, tpl-mr-freeze, tpl-mind-control,
tpl-kamikaze, tpl-ice-physics, tpl-minefield-full
- 3 net-new patterns: tpl-mass-destroyer-they-deserved-it, tpl-lifetime-restriction,
tpl-adjacent-debuff (substitutions for unbuildable mass-mover/adjacent-splash —
resolver lacks arithmetic, locked in decisions.md)
User-facing description rewrites: 50 primitive longDescription + examples[].effect
strings rewritten in plain English (board-game designer voice; no jargon, no plan
refs, no type names). 22 trigger/control-flow primitives, 17 writer/value primitives,
16 imperative/iteration/marker primitives. Stripped 'V1 sharp edge' and 'T67-followup'
historical notes from recipes.ts header.
Test surface:
- recipes.test.ts: 5 invariants × 23 recipes (190 expect calls), all green
- validate.test.ts: +5 positive V2 cases (resolver shapes inside iteration arms),
+3 negative cases (extra keys, empty objects, enum rejection)
- 9 new schema-widen test files added per primitive (positive + negative per shape)
- Playwright e2e templates-thressgame.spec.ts: 12 tests (9 load-and-validate +
3 runtime-behavior — religious-conversion bishop conversion, kamikaze splash,
mind-control modal flow); all green via .sisyphus/scripts/run-pw.sh against
docker compose dev stack
- ParamField.snapshot.test.tsx.snap regenerated (15 → 18 snapshots)
Final verification (F1-F4):
F1 oracle: APPROVE
F2 manual QA: APPROVE (47/47 e2e across 3 specs, zero flake)
F3 test quality: REJECT (misdiagnosis — wrong test runner; verified via direct
re-run that spec passes 12/12)
F4 scope fidelity: APPROVE
Plan: .sisyphus/plans/thressgame-templates.md
Notepads: .sisyphus/notepads/thressgame-templates/
Evidence: .sisyphus/evidence/thressgame-templates-final.txt (gitignored)
2026-04-27 13:47:01 -06:00
fef8baa9dc
feat(chess): polish UI with SVG pieces, motion animations, sound, and confetti
...
- Add Cburnett SVG chess pieces from Wikimedia (Lichess set, ~18KB total)
- Add move/capture/check/checkmate/castle/promote sound effects via OGG
- Install motion for layout animations: pieces slide smoothly, captures fade
- Install canvas-confetti: victory celebration on checkmate
- Install sonner: toast notifications
- Install lucide-react: volume icons for mute toggle
- Persist mute state in localStorage
- Animated game-over banner (spring entrance)
- Animated drawer slide-in replacing CSS keyframe
- Lobby and App get polished visual treatment
- Preserve all E2E data-* selectors and drag-drop contract
Co-authored-by: visual-engineering agent
2026-04-17 12:04:56 -06:00
f37c0934aa
feat(server): add authoritative game session per room (P4.5)
...
Each room owns a ChessEngine wrapped in a GameSession; only the server
calls insert/retract/fireRules and all EntityIds are minted server-side.
GameSessionRegistry keys sessions by room code so two rooms cannot
observe or collide with each other's working-memory state.
GameSession.applyMove validates algebraic inputs, finds the matching
legal move via ChessEngine.findMove, applies it, and returns a fact-
level diff (inserted/retracted) plus the new turn and terminal state.
Terminal states are sticky: further moves after checkmate/draw return
GAME_OVER rather than silently mutating a dead session.
Exposes @paratype/chess's headless surface (ChessEngine, coord helpers,
schema types) via a new package entry point; the React app continues to
import concrete modules directly.
2026-04-16 17:17:42 -06:00