# GENESIS module contract

Shared ES modules, no runtime dependencies. All simulation state is JSON data. `src/engine.js` exports:

- `createWorld({seed=42,width=32,height=22,population=140,...parameters}={})` → state
- `stepWorld(state, ticks=1)` → same mutated state
- `cloneWorld(state)` → isolated deep copy
- `serializeWorld(state)` → JSON string
- `deserializeWorld(string)` → validated state or throws; never partially applies
- `intervene(state, {type, ...})` → mutates and logs. Types: `drought` with `factor` (0..1), `duration` (1..1000); `deplete` with `fraction` (0..1) removes that fraction of environmental stocks; `trade` with `enabled`; `migration` with `enabled`; `technology` with `value` (0.5..3); `transport` with `value` (0..3); `cooperation` with `enabled`.
- `getMetrics(state)` → latest derived metrics
- `assertInvariants(state)` → true or throws
- `getClusters(state)` → [{id, tiles: [tileIndex], population, food, wood}] descriptive spatial groups; no causal settlement rule

State fields: `version`, `seed`, `rng`, `tick`, `width`, `height`, `nextAgentId`, `params`, `tiles`, `agents`, `events`, `history`, `ledger`, `shocks`, `totals`.

`params`: `tradeEnabled`, `migrationEnabled`, `cooperationEnabled`, `technology`, `transportCost`, `degradationRate`, `regrowthRate`, `birthRate`, `maxPopulation` (other documented model parameters may be added).

Tiles in row-major order: `{x,y,terrain:'water'|'plain'|'forest'|'hill',food,wood,foodCapacity,woodCapacity,soil,elevation}`. Water impassable and unproductive. Coordinates are integers.

Agents: `{id,x,y,age,health,food,wood,tool,foodSkill,woodSkill,sociability,birthTick,parentId,lastAction,explanation,trust}`. `trust` is an object keyed by peer ID, bounded to at most 12 peers. `lastAction` one of `forage`, `woodcut`, `craft`, `move`, `rest`. Extra fields allowed. No names from remote services.

Metrics: `{tick,population,food,wood,biomass,soil,health,trades,tradeVolume,price,births,deaths,moves,gifts,gini,foodProduced,woodProduced,consumed,starving,clusters,specialization}`. `food`/`wood` agent stocks; `biomass` environment food+wood; `soil`, `health` means; `trades`, `tradeVolume`, `births`, `deaths`, `moves`, `gifts`, `foodProduced`, `woodProduced`, `consumed` per tick; `price` food per wood or null if no trade; `specialization` mean absolute lifetime difference of food and wood production action shares. `history` includes initial and then every tick, retains last 2000 rows; `events` bounded at 400. Totals lifetime numeric counters, ledger cumulative sources/sinks. All arrays bounded except agents (bounded by maxPopulation) and tiles (fixed).

Events: `{tick,type,message,agentIds:[],...detail}` from actual transitions. Aggregate events per tick acceptable. Agent decision explanations must reflect actual inputs, not speculative narrative.

Initial planned mechanisms: seasonal renewable food/wood stocks; harvest transfers; soil degradation from extraction with slow recovery; inventory-driven local utility actions; skill heterogeneity; wood consumed as fuel and craft input, tools depreciate; barter transfers goods with a local scarcity-dependent price; costly movement into locally attractive neighboring tiles; trust from successful exchange and gifts; resource-funded births, hunger/age deaths. No scripted history. Random generator fully serialized. Food/wood source-sink ledgers must include initial sources, regrowth, consumption, spoilage, crafting, deaths, interventions; harvest and barter are internal transfers. Population reconciliation required.

UI owns rendering/speed/selection; they must never affect the engine. Baseline comparisons clone the entire checkpoint and advance equal ticks in both branches. State validation must reject nonfinite/negative stock, mismatched coordinates, duplicate IDs and bad schema before replacing current state.
