Adds the 9th modular LLM ability: a turn-transientTurnResult.disasters lever that lets the LLM declare natural/man-made disasters (earthquake / flood / volcanic / wildfire / famine / plague / epidemic) on a nation or a region, applying a deterministic(type, severity) stat dip (no hidden randomness).
shared/protocol.ts: new DisasterType / DisasterSeverity / DisasterEvent / DisastersOps and the required TurnResult.disasters field (between ideology and markers; default { events: [] }).
server/abilities/disasters.ts: the new ability module — validate (defensive, never throws), apply (deterministic dip: clamped 0–100, mirrored to the target's regions via regionStats, then the target nation's derived stats re-derived with the same 0-region / no-entry guards), the DISASTER_EFFECTS deterministic (type, severity) table, the schema line + constraint bullet, isMeaningful, an inert stub(), and an empty payload(). It owns noGameState field (turn-transient, exactly like hybrid) — no db.ts change.
Target resolution mirrors hybrid (a region key hits its sole owner; a 0/2+-owner key is dropped, never thrown) but has nofrom field, so the hybrid's self-target drop does not apply.
Registered last in ABILITIES (after ideology).
Prompt goldens
system-no-tool.txt / system-tool.txt regenerated (each gains exactly the disasters schema line + the constraint bullet).
user.txt is byte-identical (the disasterspayload() is empty — verified by checksum).
Tests
New server/abilities/disasters.test.ts (33 tests).
registry.test.ts updated to the 9-ability contract (order, fullDefaultTurn(), meaningfulFor, re-export pin).
All 555 unit tests pass; typecheck + lint + build clean. The stub is disasters-inert, so e2e (CI, LLM_STUB=1) is unaffected.
Secondary cleanups (from the v0.40.0 refactor)
AGENTS.md: server/abilities/ added to the Layout tree; a “how to add a new ability” Conventions bullet and a “Disasters & pandemics” bullet.
Deleted the orphaned validateTakeovers JSDoc.
Folded both inline as unknown casts into the single top-level ./abilities import (AbilityCtx + UserPromptCtx).
De-duplicated str (now imported from ./abilities/shared).
Version bumped 0.40.0 → 0.41.0.
Adds the 9th modular LLM ability: a **turn-transient** `TurnResult.disasters` lever that lets the LLM declare natural/man-made disasters (earthquake / flood / volcanic / wildfire / famine / plague / epidemic) on a nation or a region, applying a **deterministic** `(type, severity)` stat dip (no hidden randomness).
**Fixes #63**
## What changed
**Feature (v0.41.0)**
- `shared/protocol.ts`: new `DisasterType` / `DisasterSeverity` / `DisasterEvent` / `DisastersOps` and the required `TurnResult.disasters` field (between `ideology` and `markers`; default `{ events: [] }`).
- `server/abilities/disasters.ts`: the new ability module — `validate` (defensive, never throws), `apply` (deterministic dip: clamped 0–100, mirrored to the target's regions via `regionStats`, then the target nation's derived `stats` re-derived with the same 0-region / no-entry guards), the `DISASTER_EFFECTS` deterministic `(type, severity)` table, the schema line + constraint bullet, `isMeaningful`, an inert `stub()`, and an empty `payload()`. It owns **no** `GameState` field (turn-transient, exactly like `hybrid`) — **no `db.ts` change**.
- Target resolution mirrors `hybrid` (a region key hits its **sole** owner; a 0/2+-owner key is dropped, never thrown) but has **no** `from` field, so the hybrid's self-target drop does **not** apply.
- Registered last in `ABILITIES` (after `ideology`).
**Prompt goldens**
- `system-no-tool.txt` / `system-tool.txt` regenerated (each gains exactly the `disasters` schema line + the constraint bullet).
- `user.txt` is **byte-identical** (the `disasters` `payload()` is empty — verified by checksum).
**Tests**
- New `server/abilities/disasters.test.ts` (33 tests).
- `registry.test.ts` updated to the 9-ability contract (order, `fullDefaultTurn()`, `meaningfulFor`, re-export pin).
- All **555** unit tests pass; `typecheck` + `lint` + `build` clean. The stub is disasters-inert, so e2e (CI, `LLM_STUB=1`) is unaffected.
**Secondary cleanups (from the v0.40.0 refactor)**
- `AGENTS.md`: `server/abilities/` added to the Layout tree; a “how to add a new ability” Conventions bullet and a “Disasters & pandemics” bullet.
- Deleted the orphaned `validateTakeovers` JSDoc.
- Folded both inline `as unknown` casts into the single top-level `./abilities` import (`AbilityCtx` + `UserPromptCtx`).
- De-duplicated `str` (now imported from `./abilities/shared`).
**Version** bumped `0.40.0 → 0.41.0`.
Add the 9th modular LLM ability: a turn-transient `TurnResult.disasters`
lever letting the LLM declare natural/man-made disasters (earthquake /
flood / volcanic / wildfire / famine / plague / epidemic) on a nation or
a region, applying a DETERMINISTIC (type, severity) stat dip (no hidden
randomness). Like the hybrid layer it owns no GameState field, needs no
db.ts change, and leaves no durable list — an ongoing plague/epidemic is
simply re-declared each turn it persists.
- shared/protocol.ts: DisasterType / DisasterSeverity / DisasterEvent /
DisastersOps, and `TurnResult.disasters` (between `ideology` and
`markers`; required, default `{ events: [] }`).
- server/abilities/disasters.ts: the ability module (validate / apply /
schemaLine / constraint / isMeaningful / inert stub / empty payload; no
stateFields). `DISASTER_EFFECTS` is the deterministic (type, severity)
dip table (population never touched). Target resolution mirrors hybrid
(a region key hits its SOLE owner; 0/2+ owners dropped) but has NO
`from` field, so there is no self-target drop. Dips clamp to 0-100,
mirror to the target's regions (regionStats), and re-derive the target
nation's stats (same 0-region / no-entry guards).
- Registered last in ABILITIES (after ideology). System-prompt goldens
regenerated (one schema line + one constraint bullet each); the
user.txt golden stays byte-identical (payload() is {}).
- New server/abilities/disasters.test.ts (33 tests); registry.test.ts
updated to the 9-ability contract.
- Secondary cleanups from the v0.40 refactor: AGENTS.md (abilities/ in
the Layout tree + a "how to add a new ability" bullet + a disasters
bullet), delete the orphaned validateTakeovers JSDoc, fold both inline
`as unknown` casts into the top-level ./abilities import, and de-dup
`str` (now imported from ./abilities/shared).
Version bumped 0.40.0 -> 0.41.0.
kamilkrzywda
scheduled this pull request to auto merge when all checks succeed 2026-10-16 11:19:01 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds the 9th modular LLM ability: a turn-transient
TurnResult.disasterslever that lets the LLM declare natural/man-made disasters (earthquake / flood / volcanic / wildfire / famine / plague / epidemic) on a nation or a region, applying a deterministic(type, severity)stat dip (no hidden randomness).Fixes #63
What changed
Feature (v0.41.0)
shared/protocol.ts: newDisasterType/DisasterSeverity/DisasterEvent/DisastersOpsand the requiredTurnResult.disastersfield (betweenideologyandmarkers; default{ events: [] }).server/abilities/disasters.ts: the new ability module —validate(defensive, never throws),apply(deterministic dip: clamped 0–100, mirrored to the target's regions viaregionStats, then the target nation's derivedstatsre-derived with the same 0-region / no-entry guards), theDISASTER_EFFECTSdeterministic(type, severity)table, the schema line + constraint bullet,isMeaningful, an inertstub(), and an emptypayload(). It owns noGameStatefield (turn-transient, exactly likehybrid) — nodb.tschange.hybrid(a region key hits its sole owner; a 0/2+-owner key is dropped, never thrown) but has nofromfield, so the hybrid's self-target drop does not apply.ABILITIES(afterideology).Prompt goldens
system-no-tool.txt/system-tool.txtregenerated (each gains exactly thedisastersschema line + the constraint bullet).user.txtis byte-identical (thedisasterspayload()is empty — verified by checksum).Tests
server/abilities/disasters.test.ts(33 tests).registry.test.tsupdated to the 9-ability contract (order,fullDefaultTurn(),meaningfulFor, re-export pin).typecheck+lint+buildclean. The stub is disasters-inert, so e2e (CI,LLM_STUB=1) is unaffected.Secondary cleanups (from the v0.40.0 refactor)
AGENTS.md:server/abilities/added to the Layout tree; a “how to add a new ability” Conventions bullet and a “Disasters & pandemics” bullet.validateTakeoversJSDoc.as unknowncasts into the single top-level./abilitiesimport (AbilityCtx+UserPromptCtx).str(now imported from./abilities/shared).Version bumped
0.40.0 → 0.41.0.Add the 9th modular LLM ability: a turn-transient `TurnResult.disasters` lever letting the LLM declare natural/man-made disasters (earthquake / flood / volcanic / wildfire / famine / plague / epidemic) on a nation or a region, applying a DETERMINISTIC (type, severity) stat dip (no hidden randomness). Like the hybrid layer it owns no GameState field, needs no db.ts change, and leaves no durable list — an ongoing plague/epidemic is simply re-declared each turn it persists. - shared/protocol.ts: DisasterType / DisasterSeverity / DisasterEvent / DisastersOps, and `TurnResult.disasters` (between `ideology` and `markers`; required, default `{ events: [] }`). - server/abilities/disasters.ts: the ability module (validate / apply / schemaLine / constraint / isMeaningful / inert stub / empty payload; no stateFields). `DISASTER_EFFECTS` is the deterministic (type, severity) dip table (population never touched). Target resolution mirrors hybrid (a region key hits its SOLE owner; 0/2+ owners dropped) but has NO `from` field, so there is no self-target drop. Dips clamp to 0-100, mirror to the target's regions (regionStats), and re-derive the target nation's stats (same 0-region / no-entry guards). - Registered last in ABILITIES (after ideology). System-prompt goldens regenerated (one schema line + one constraint bullet each); the user.txt golden stays byte-identical (payload() is {}). - New server/abilities/disasters.test.ts (33 tests); registry.test.ts updated to the 9-ability contract. - Secondary cleanups from the v0.40 refactor: AGENTS.md (abilities/ in the Layout tree + a "how to add a new ability" bullet + a disasters bullet), delete the orphaned validateTakeovers JSDoc, fold both inline `as unknown` casts into the top-level ./abilities import, and de-dup `str` (now imported from ./abilities/shared). Version bumped 0.40.0 -> 0.41.0.