refactor(#74) P3: add the 8 ability modules + ABILITIES registry

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.
This commit is contained in:
2026-10-16 07:23:11 +00:00
parent 5cfbce861b
commit 2d17c743f6
11 changed files with 1831 additions and 0 deletions
+13
View File
@@ -94,3 +94,16 @@ export const NEW_NATION_STATS: NationStats = {
stability: 50,
population: 50,
};
/**
* Coerce an unknown LLM JSON value to a trimmed, non-empty string, or `null`
* when it is not a non-empty string. An optional `max` caps the length (used
* for the 200-char caps on nationOp fields). Shared by every defensive
* validator (engine + the ability modules). Never throws.
*/
export function str(s: unknown, max = 0): string | null {
if (typeof s !== 'string') return null;
const t = s.trim();
if (!t) return null;
return max ? t.slice(0, max) : t;
}