Close Phase 2 — wire econ-sim into game server tick loop, expose price history and trade flows via implant insert panel, add economics debug console commands for runtime event injection and parameter mutation. New tickets: #821 (server tick integration), #822 (IPC bridge v21), #823 (debug command handler), #824 (economics insert panel), #825 (debug console econ commands). Existing: #810, #785, #811, #748, #814, #695. 11 tickets total across server, client, copy, planning. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
5.5 KiB
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:
- Extract the simulation logic from
tooling/econ-sim/src/main.rsinto a reusable library crate (e.g.tooling/econ-sim/src/lib.rsor a newserver/src/economy/module — Tyre to decide the crate boundary). - Add a
bevy_ecsSystemthat 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). - Store the current economy state as a
Resourcein bevy_ecs so downstream systems (#822, #823) can query it. - 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:
#[serde(default)]
pub economy_snapshot: Option<EconomySnapshot>,
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:
pub struct EconomySnapshot {
pub tick: u64,
pub nodes: Vec<EconNodeSnapshot>,
}
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:
/// Inject an economic event into the running simulation.
InjectEconEvent {
system_id: u32,
commodity_id: Option<u32>, // 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
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