No description
Feature 4a of post-epic-deferrals. Introduces the PlayerAction
surface — a turn-consuming event orthogonal to LegalMove — and one
preset that uses it to transfer royalty between friendly pieces
once per game per color. Solo-only for v1 (F4b will add the WS
protocol; F4c will add the UI).
Engine surface:
- New module packages/chess/src/actions.ts exports PlayerAction
(discriminated union; starts with 'transfer-royalty' kind),
PlayerActionKind, and ActionResult {ok,error,reason}.
- ChessEngine.performAction(action): ActionResult runs a parallel
pipeline to applyMove: terminal-state guard → poll every
active preset's performAction hook (first non-undefined wins)
→ handler returns ok=false => no turn consumption → handler
returns ok=true => advanceTurnAfterMutation shared helper
(factored out of applyMove) which handles HalfMovesThisTurn
increment, shouldAdvanceTurn poll, onTurnStart fire, etc.
- ActionResult error codes: NO_HANDLER, REJECTED, INVALID_TARGET,
NOT_YOUR_TURN, GAME_OVER. Stable for future UI / protocol.
PresetDef additions:
- performAction(ctx): ActionResult | undefined — first non-
undefined wins. Handlers validate + mutate state + return.
- transformRoyalPieces(ctx, current): EntityId[] — a POST-union
transform on the accumulated royal set, letting a preset
reassign rather than append. Used by transferable-royalty to
swap transferredFrom -> transferredTo.
Preset: transferable-royalty
- category 'king'; incompat with suicide-chess + capture-all
(both empty the royal set).
- State: transferredFrom/To keyed by color — one-shot per color.
- performAction validates: fromPiece alive, currently royal,
toPiece alive, same color, not already royal, not already
transferred. Returns INVALID_TARGET / REJECTED on failure,
ok:true on success.
- transformRoyalPieces swaps old royal for new in the engine's
royal resolution; defensively drops dead ids so a transferred
royal that later died doesn't linger.
Tests:
- transferable-royalty.test.ts: 20 tests covering registration,
happy path, once-per-game cap, all INVALID_TARGET paths,
turn consumption, composition with knightmate-rules and
piece-hp.
- engine.performAction.test.ts: 7 tests covering NO_HANDLER,
GAME_OVER guard, first-match-wins, shouldAdvanceTurn veto,
performAction + applyMove interleaving.
- presets.test.ts: EXPECTED_IDS bumped; symmetry + dangling-ref
audits still green.
- capture-all.ts: reciprocated incompat with transferable-royalty
(symmetry audit).
Verification: 1699 tests passing (was 1671, +28). Typecheck + lint
clean. No regressions.
Plan: .sisyphus/plans/post-epic-deferrals.md F4a complete.
F4b (WS protocol) and F4c (UI) remain.
(Agent hit 200-tool-cap near the end; orchestrator reconciled
a missing defaultKingRoyals helper + 2 test setups that triggered
insufficient-material draws + symmetric incompat declaration.)
|
||
|---|---|---|
| .github/workflows | ||
| .sisyphus | ||
| docs | ||
| packages | ||
| scripts | ||
| .gitignore | ||
| eslint.config.js | ||
| lefthook.yml | ||
| LICENSE | ||
| package.json | ||
| playwright.config.ts | ||
| README.md | ||
| tsconfig.base.json | ||
| tsconfig.json | ||
| vitest.workspace.ts | ||
@paratype
A Doorenbos-style Rete II rules engine for TypeScript games, with an authoritative WebSocket chess demo.
Packages
packages/rete— Rete II engine corepackages/chess— Browser chess demo (React + Vite)packages/server— Authoritative Bun WebSocket server
Docs
- SPEC.md — Engine specification
- PHASES.md — Development phases & perf budgets
- RULES.md — Chess rule presets
- PROTOCOL.md — WebSocket message protocol
Getting Started
bun install && bun run check