No description
Find a file
Joey Yakimowich-Payne 1d5efaa95f
feat(engine): apply custom modifier descriptors + multi-profile stacking
T3 Wave 3 (T22 + T23). Two tightly-coupled deliverables landed in one
commit because the second's API surface depends on the first's signature
extensions:

T22 — Custom descriptor application
- new CustomModifierRegistry (per-engine, in custom/registry.ts) — ADR-4
  isolation: descriptors registered on engineA never leak to engineB.
- new applyCustomDescriptor(engine, session, pieceId, descriptor) walks
  primitive nodes, dispatches each kind through PRIMITIVE_REGISTRY,
  and recurses into nested children via childPrimitives() with depth
  tracking (mirrors T19's static depth guard at runtime).
- ChessEngine gains a customModifiers field + opts.customModifiers in
  EngineOptions for bootstrap registration.
- applyProfileToSession's signature widens to accept (..., engine?,
  customRegistry?) — when a profile entry's kind misses MODIFIER_REGISTRY,
  the custom registry is consulted as a fallback. Existing T1/T2
  callers stay source-compatible (the new params are optional).

T23 — Multi-profile stacking
- collectProfileContributions: pure value-collection helper extracted
  from applyProfileToSession's body.
- new applyProfilesToSession(session, profiles[], layout, engine?,
  customRegistry?) iterates the helper across every profile in order
  before stacking — built-in stacking rules apply across the union.
- new reconcileProfilesSwap mirrors the same generalization for the
  retract-then-reapply hot-swap path.
- single-profile applyProfileToSession / reconcileProfileSwap remain as
  thin wrappers calling the array versions with [profile].

14 vitest scenarios cover: single-primitive apply, multi-primitive
apply, nested-children walk via on-turn-start, unknown-kind tolerance,
custom-registry fallback in applyProfileToSession, per-engine isolation,
constructor pre-registration, two-profile additive stacking, mixed
built-in + custom across profiles, single-profile passthrough, empty
array no-op, and CustomModifierRegistry CRUD.

Engine wiring (damage pipeline, turn-start hooks, aura recompute) is
deferred to T28 — primitives currently SEED facts that those wires
will observe.
2026-04-19 18:12:19 -06:00
.github/workflows chore(root): scaffold monorepo — Phase 0 complete 2026-04-16 13:32:21 -06:00
.sisyphus chore(sisyphus): mark T3 Wave 2 (15 primitives) complete + notepad updates 2026-04-19 17:42:32 -06:00
docs docs(adr): T3 custom modifier DSL architecture decisions 2026-04-19 17:16:17 -06:00
packages feat(engine): apply custom modifier descriptors + multi-profile stacking 2026-04-19 18:12:19 -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