Behavior-preserving rewire: every per-ability code path now iterates the
ordered ABILITIES registry instead of hand-enumerating the eight fields.
- engine.ts: buildSystemPrompt (schema lines + constraint bullets),
buildUserPrompt (payload keys at their historical positions),
validateTurnResult (per-field validate), applyTurnResult (ordered apply
block), isMeaningful, and the runTurn "unclear" fallback all drive off
ABILITIES. The eight moved ability bodies (~1,249 lines) are deleted;
the names the engine and its tests import are re-exported from
./abilities.
- abilities/types.ts: Ability.stub is a zero-arg method (the stub has no
GameState/AbilityCtx to pass; it needs none) — all eight implementations
were already arg-less.
- stub.ts: deterministicTurn fills the eight ability fields from the
registry (each contributes its inert default), between the core fields
and markers — JSON output stays byte-identical (verified against
origin/master).
- db.ts: the legacy-row migration for ability-owned GameState fields
(wars/trades/embargoes/industry) iterates the registry's stateFields,
only-if-undefined, instead of a hardcoded field list.
No client changes, no new deps, no shared/ runtime deps. typecheck + lint
+ 511 unit tests green; stub JSON byte-identical to origin/master.
Fixes#74
Each per-feature LLM ability is now a self-contained module in
server/abilities/ with its own Ability<K> const (schema line, constraint
bullet, validator, applier, isMeaningful, stub default, user-payload
field). The ordered ABILITIES registry (index.ts) assembles them in the
canonical order: takeovers → wars → hybrid → economy → industry → nuclear
→ leaders → ideology.
All function bodies are moved VERBATIM from engine.ts. The engine is
untouched in this commit — P4 will rewire it to use the registry.
Move the 5 shared reference/id primitives (resolveNationRef, resolveRegionKey,
freshNationId, freshWarId, NEW_NATION_STATS) from engine.ts into the new
server/abilities/shared.ts (breaking the engine<->ability import cycle), and
add server/abilities/types.ts with the Ability<K> interface + AbilityCtx /
UserPromptCtx types that the 8 per-feature ability modules will implement.
engine.ts imports the helpers and re-exports them so existing callers
(server/index.ts, the unit tests) are untouched. Behavior is identical; all
511 unit tests, lint and typecheck stay green.
Adds deterministic golden fixtures (server/abilities/goldens/) pinning the
EXACT output of buildSystemPrompt (no-tool + tool modes) and buildUserPrompt
for a fixed wwii-1939 preset plus a crafted state that exercises every
optional payload branch (regions, frontier, frontierMilitary, takeoverRisks,
unowned, markers, wars, relations, trades, embargoes, resources, industry).
These are the target: the v0.40.0 modular ability registry (P2-P5) must
reproduce these byte-for-byte. Part of #74.