No description
Find a file
Joey Yakimowich-Payne f74e204211
feat(presets): monster-rules (scope-flip) + first-promotion-wins
Phase B.3 + B.4 of the rule-variants epic.

monster-rules — scope-aware asymmetric double-move:
  - scope='white' (canonical Monster pairing) → white plays 2
    half-moves per turn, black plays 1.
  - scope='black' → black plays 2, white plays 1 (symmetric flip).
  - scope='both' → both sides play 2 (equivalent to double-move;
    prefer that preset for that mode).
  The hook reads the preset's live scope from
  engine.activePresets.list() at dispatch time, so a scope change
  mid-game takes effect immediately.
  15 tests covering activation, W2+B1 asymmetry, scope='black'
  flip, scope='both' symmetric mode, onTurnStart gating, checkmate
  detection on either color's move, and double-move incompatibility.

first-promotion-wins:
  - Winner is declared when either side promotes a pawn. First
    promotion locks; later promotions don't overwrite.
  - Two-phase latch: onBeforeMove records (pieceId, mover) when the
    move is a pawn reaching its promotion rank; onAfterMove
    confirms the promotion resolved (piece is no longer a pawn)
    and sets the winner. This avoids the moveLog-timing bug
    (moveLog.push fires AFTER onAfterMove + checkGameResult).
  - onCheckGameResult converts the recorded winner to
    white-wins / black-wins. Composes with piece-hp thanks to the
    engine's updated 'ongoing' semantics (separate commit).
  - Does NOT opt out of shouldFilterSelfCheck — documented in-file
    why (would also legalize non-promotion exposing moves).
  - 11 tests covering activation, baseline, white/black promotion,
    first-promotion lock, pawns-only layout composition, piece-hp
    composition, double-move composition, and incompatibility
    enforcement.

presets.test.ts: bumped EXPECTED_IDS to include first-promotion-wins
(17 → 18). Barrel import order keeps first-promotion-wins at end.

Tests: 1506 passing total (was 1492, +14 net — +15 monster-rules
+ 11 first-promotion-wins - 12 overlap with existing suite
reruns).
2026-04-21 07:32:48 -06:00
.github/workflows chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00
.sisyphus docs(preset-api): hook ordering + Phase A summary 2026-04-20 20:52:51 -06:00
docs docs(adr): T4 scripted modifiers forward-design 2026-04-19 21:09:52 -06:00
packages feat(presets): monster-rules (scope-flip) + first-promotion-wins 2026-04-21 07:32:48 -06:00
scripts feat(rete): add replay engine + state-hash determinism verifier (P3.3) 2026-04-16 15:25:13 -06:00
.gitignore chore: ignore .org.chromium.Chromium.* runtime files 2026-04-19 10:20:42 -06:00
eslint.config.js feat(engine): damage-resistance modifier descriptor 2026-04-18 22:22:31 -06:00
lefthook.yml chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00
LICENSE chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00
package.json feat(rete): add replay engine + state-hash determinism verifier (P3.3) 2026-04-16 15:25:13 -06:00
playwright.config.ts fix(rete): inject clock into EventLog; use tsc for DTS; fix cycle.test.ts private access; add Playwright worker limit 2026-04-16 18:25:49 -06:00
README.md chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00
tsconfig.base.json chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00
tsconfig.json chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00
vitest.workspace.ts chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00

@paratype

A Doorenbos-style Rete II rules engine for TypeScript games, with an authoritative WebSocket chess demo.

Packages

Docs

Getting Started

bun install && bun run check