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