# Sprint 34: Pulse — Server Tasks **Goal:** Close Phase 2 — wire the economics simulation into the live game, expose price history and trade flows in the implant, and make the economy observable and tweakable at runtime. **Branch:** `sprint-34/server` **Agents:** Dudley (simulation), Tyre (architecture) ## New Tickets | # | Title | Blocked by | |---|-------|------------| | #810 | Event input port implementation | #809 (done) | | #821 | Integrate econ-sim into game server tick loop | #810 | | #822 | Expose economy state over IPC bridge to client | #821 | | #823 | Economics debug command handler — event injection and parameter mutation | #821 | ## Key Decisions - `decisions/economics.md` — D-178 (model architecture — Leontief + tâtonnement + agents), D-179 (stability criteria), D-180 (event input port — EconEvent struct and visibility modes), D-181 (7-signal vocabulary per node), D-183 (iterative dev cycle) - `decisions/architecture.md` — D-020 (IPC architecture — ObserverSnapshot + PlayerAction), D-031 (tick-to-time mapping — 10 ticks = 1 game-minute) ## Notes ### #810 — Event input port implementation The EconEvent struct (D-180) must be added to `tooling/econ-sim/src/model.rs` or a new `events.rs` module. The port is the typed interface through which all external disruptions enter the simulation. An event carries: ``` EconEvent { target: Node | NodeSet | Corridor | TradeRoute | Currency | Commodity, effect: ProductivityMultiplier | CapacityMultiplier | DemandShock | ExchangeShock, duration: ticks, visibility: Global | Proximate(hops) | Disclosed(specific_nodes) | Hidden, } ``` Visibility modes are defined in D-180. For this sprint, only `Global` and `Proximate` need to be exercised — `Hidden` is Phase 3 territory (requires the player inspect verb). The port must accept events from: (a) the server tick loop (#821), and (b) debug commands (#823). Test: inject a supply shock, verify cascade propagates and prices recover within 200 ticks per D-179 Test 3. ### #821 — Integrate econ-sim into game server tick loop The econ-sim is currently a standalone CLI binary at `tooling/econ-sim/`. This ticket makes it run inside the server process. Approach: 1. Extract the simulation logic from `tooling/econ-sim/src/main.rs` into a reusable library crate (e.g. `tooling/econ-sim/src/lib.rs` or a new `server/src/economy/` module — Tyre to decide the crate boundary). 2. Add a `bevy_ecs` `System` that advances the economy N ticks per game tick (rate TBD — likely 1 economy tick per 10 game ticks given D-031 tick-to-time mapping). 3. Store the current economy state as a `Resource` in bevy_ecs so downstream systems (#822, #823) can query it. 4. Economy state must include all 7 D-181 signals per active node so the bridge can later serialize the relevant subset. Key files: `server/src/simulation/ticker.rs` (where per-tick systems run), `tooling/econ-sim/src/model.rs` (simulation state), `tooling/econ-sim/src/trade.rs` (tâtonnement step). The DB at `server/data/systems.db` is already populated from Sprint 33. Do NOT load the econ DB on every tick — load once at server startup into the bevy_ecs Resource. ### #822 — Expose economy state over IPC bridge to client Extend `ObserverSnapshot` to version 21 with an `economy_snapshot` field: ```rust #[serde(default)] pub economy_snapshot: Option, ``` `EconomySnapshot` carries per-system data for the client's economics panel (#824). Phase 2 deliverable is D-181 signals 1–2 only (price_current, price_trend). Struct sketch: ```rust pub struct EconomySnapshot { pub tick: u64, pub nodes: Vec, } pub struct EconNodeSnapshot { pub system_id: u32, pub commodity_id: u32, pub price_current: f64, pub price_trend: f64, // delta over last N ticks } ``` Add `EconStateQuery` to the `PlayerAction` enum for on-demand pulls — the client does not need economy data every tick (that would balloon snapshot size). The server responds to `EconStateQuery` by populating `economy_snapshot` on the next snapshot. Without a query, `economy_snapshot` is `None`. Update `PROTOCOL_VERSION` to 21 in `server/src/bridge/types.rs`. ### #823 — Economics debug command handler Extend `DebugCommandKind` in `server/src/bridge/types.rs` with three new variants: ```rust /// Inject an economic event into the running simulation. InjectEconEvent { system_id: u32, commodity_id: Option, // None = system-wide effect: EconDebugEffect, magnitude: f64, duration_ticks: u32, }, /// Mutate a tâtonnement parameter at runtime. SetEconParam { param: EconParamKind, // Alpha | Beta | CorridorFriction { system_a, system_b } value: f64, }, /// Return all 7 D-181 signals for a named system. GetEconState { system_id: u32, }, ``` Wire these into the existing debug command dispatch in `server/src/simulation/` (wherever `DebugCommandKind` is matched). Return results via `DebugResponsePayload.text` as a human-readable multi-line string. Blocked by #821 (economy resource must exist to query or mutate). ## Dependency Chain ``` #810 (event port) → #821 (server tick integration) → #822 (IPC exposure) → #823 (debug command handler) ``` #822 and #823 are parallel after #821 completes. ## PR Workflow ```bash tea pr create --repo jpmschweitzer/settled-reach --login schweitz \ --title "feat(simulation): economics in-game tick loop and IPC bridge" \ --description "Sprint 34 server work" \ --base main --head sprint-34/server ```