A bilateral trade + embargo economy layer with a deterministic per-turn effect:
TurnResult.economy = { trade, embargo } (required, default empty) — the model can declare/lift bilateral trade agreements (symmetric, stored sorted a < b) and unilateral embargoes (ordered from → target). No lift = declare/impose; lift: true = end/lift.
GameState.trades / GameState.embargoes — required, [] on creation; rows saved before v0.35 load with them defaulted to [] (additive, never wiped).
Per-turn effect (fully deterministic, no hidden randomness) — every committed turn: each active trade grants both parties a small economy gain; each active embargo dips the target only. Clamped to 0–100, mirrored to every owned region (regionStats), and each affected nation's derived stats re-derived (same 0-region/no-entry guards as the hybrid dip). Sole ownership is untouched — the layer moves stats, never territory.
War auto-suspension — any trade or embargo whose two nations are on opposite sides of an active war (#56) is removed: a war severs the economic link. Runs after the turn's war declare/end ops, before the effect.
isMeaningful counts non-empty economy ops; the system prompt documents the field (at most 1–2 ops per turn, narrated in events, warring pairs auto-suspended) and the user payload carries the active trades/embargoes so the model can lift them.
Stub returns an empty economy (never declares) — the CI e2e (LLM_STUB=1) is unaffected; the path is covered by unit tests only (20 new tests in server/engine.test.ts + a legacy-load test in server/db.test.ts).
All four local checks pass (typecheck, lint, unit tests 407/407, build). Full details in CHANGELOG.md and AGENTS.md.
Fixes #58
## v0.35.0 — Trade & Embargoes
A bilateral trade + embargo economy layer with a deterministic per-turn effect:
- **`TurnResult.economy = { trade, embargo }`** (required, default empty) — the model can declare/lift **bilateral trade agreements** (symmetric, stored sorted `a < b`) and **unilateral embargoes** (ordered `from → target`). No `lift` = declare/impose; `lift: true` = end/lift.
- **`GameState.trades` / `GameState.embargoes`** — required, `[]` on creation; rows saved before v0.35 load with them defaulted to `[]` (additive, never wiped).
- **Per-turn effect (fully deterministic, no hidden randomness)** — every committed turn: each active trade grants **both** parties a small economy gain; each active embargo dips the **target only**. Clamped to 0–100, mirrored to every owned region (`regionStats`), and each affected nation's derived `stats` re-derived (same 0-region/no-entry guards as the hybrid dip). Sole ownership is untouched — the layer moves stats, never territory.
- **War auto-suspension** — any trade or embargo whose two nations are on opposite sides of an **active** war (#56) is removed: a war severs the economic link. Runs after the turn's war declare/end ops, before the effect.
- `isMeaningful` counts non-empty economy ops; the system prompt documents the field (at most 1–2 ops per turn, narrated in `events`, warring pairs auto-suspended) and the user payload carries the active `trades`/`embargoes` so the model can `lift` them.
- **Stub** returns an empty economy (never declares) — the CI e2e (LLM_STUB=1) is unaffected; the path is covered by unit tests only (20 new tests in `server/engine.test.ts` + a legacy-load test in `server/db.test.ts`).
All four local checks pass (typecheck, lint, unit tests 407/407, build). Full details in `CHANGELOG.md` and `AGENTS.md`.
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.
Fixes #58
v0.35.0 — Trade & Embargoes
A bilateral trade + embargo economy layer with a deterministic per-turn effect:
TurnResult.economy = { trade, embargo }(required, default empty) — the model can declare/lift bilateral trade agreements (symmetric, stored sorteda < b) and unilateral embargoes (orderedfrom → target). Nolift= declare/impose;lift: true= end/lift.GameState.trades/GameState.embargoes— required,[]on creation; rows saved before v0.35 load with them defaulted to[](additive, never wiped).regionStats), and each affected nation's derivedstatsre-derived (same 0-region/no-entry guards as the hybrid dip). Sole ownership is untouched — the layer moves stats, never territory.isMeaningfulcounts non-empty economy ops; the system prompt documents the field (at most 1–2 ops per turn, narrated inevents, warring pairs auto-suspended) and the user payload carries the activetrades/embargoesso the model canliftthem.server/engine.test.ts+ a legacy-load test inserver/db.test.ts).All four local checks pass (typecheck, lint, unit tests 407/407, build). Full details in
CHANGELOG.mdandAGENTS.md.