From 9d9ea96be17ba3f17defd4befd5a9dcbdb6ff9e7 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 8 Apr 2026 16:20:29 +0200 Subject: [PATCH] chore(meta): plan Sprint 34: Pulse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- docs/backups/settledreach.db.backup | Bin 962560 -> 962560 bytes docs/sprints/sprint-34/client.md | 92 +++++++++++++++++++++ docs/sprints/sprint-34/copy.md | 61 ++++++++++++++ docs/sprints/sprint-34/joint.md | 115 ++++++++++++++++++++++++++ docs/sprints/sprint-34/planning.md | 103 +++++++++++++++++++++++ docs/sprints/sprint-34/server.md | 123 ++++++++++++++++++++++++++++ 6 files changed, 494 insertions(+) create mode 100644 docs/sprints/sprint-34/client.md create mode 100644 docs/sprints/sprint-34/copy.md create mode 100644 docs/sprints/sprint-34/joint.md create mode 100644 docs/sprints/sprint-34/planning.md create mode 100644 docs/sprints/sprint-34/server.md diff --git a/docs/backups/settledreach.db.backup b/docs/backups/settledreach.db.backup index e34f5f09c2955c05e34d38971158639321a78215..316b8a9d31291c8e3f622179129441717edc31bf 100644 GIT binary patch delta 6730 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 WUb>^^{4!xaQ0*&r@NmuNwf_s>IQcIC delta 2367 zcmZuz4Nz3q6~6bqd*9!EZ-33y7fm$C9j~nAne%drJJb4uVkAwl7*uXzCQXw}o4>ZkWG1yuNQiCHv~i|0PREvJ3cdUITPE3= zdv?xw=R4;+KljaR8;P`yM2?uoQ2@YKlPBw^g=O&Q3pJ;m${u4oH-e$Ko^tKHt75-? zzCOEU4)nx7S?YnIsL%4jA)kQWgP&f+;!^0ATji(a&z1R#t~4t@R}QNuH53$dn_#mcNPOEA3gevOLM;m2ve&Ir0G==T8bq_Y|-YKRfEAC_^Liev+%?(*v5AzCa8loAZ+uujWbkWYCq0SQ<)xQjnwwe@{}xMafDbeO3{N zGm}jv$x1QfHPv^cu<$EDwHl#_1$x9BfmWXq7sWFxR#A7JgxKq+#M}M{w=>*>;*gy> zi9(Rx-HU2iaWDFz0ITAziuJVZX@sbD6FJ!EGe|8GTi|Af-$P$Qcptrf1zo1EypN92 z8`U_Q?f(EB(#2xoO)8I|eXMN+^4J4(K*X4R zEaJku&}p$#V9I*DS|~P_7==cTk!7SCDTZbseN6w4enY>mf1!`)e>R4Ub4JM6Vf?{( z%XpneH{g%y_A2aS9UF12N{^pL{smYBf|zT|99w#9>9*xU8rq8EcZO^wXv=^t(*dym z4Py*wiH)1oCEJPEaUGw@4lX5`D4@Hw*d`-H+o9Hg$oqdmqRBve+lyWbzSQnP`4b z*UdQQN8(53M`1VPsv`@1B+;pjIj0_k=Uo+lLbPT`mDsT%b;nCGx)bK3j0H?-(pCr# z^Z?30rO1O8qm{UsJHG+x!G|@Kxtp~wmdzap(o?trr8%B3>d5cmxcZLV&z(MpEc=3X z7SHX->}*H@X+pbcdCfH5!C(+DZBY9wq{n(Sg$}%|sofVe#R!%JO5OfoByeja7-sLh zq=l{X?uub2U##3YhB^c=92MaxsY3V3!+4bE_#4zawpu@Y;b-QAw6-c=4?^tQFwVTKmIPKQAnH0`TxcTZDcGWjF$7-w)=L_1Mok5co zSCbPnzL&QVukH(Tei2_;-R`DG+3;ra5ftEY&gN&3RsDe6EkJ?3b_Q+jbyo;OH3X)l zNg|Lzy{Nt|twB5V9LI~otDrvas;D$NHd)>jkRi0gt^$*}_L8(2`s2@$jJf`RFAy&A zg-U#7?#a9%w!4))57~|bknn$b9tpk?Z$)i1VP&Jv*LY9luMV{*;>Ga-K zVq{InDSNnn?<4hlJHBr%On_>;)|sq-AIX@-Ae|2HC&uiOGan;sAp!v2#f!cJ>e1C! zZX&{#Sc%DYHWM_{FFS4LKH{7eVW^Fu6h&~X0nQbUH9W{N2WfBisK6gn0m!E1$H^6? zsiC&9aaZF`y7&b7a4GpNzpZ%yUq;)6Pv8TNAM0HpPaf1lYN7-7FS^1iPS7Zim78?= z^JHwg_!a%cJ1==^(PnE=!u2~H*(Tj{hNLp*Gi2c`+VkkzGla}^D>Tuq=wnu40=bzZ z8AmRg1M_Rl_2G|PW}{<CF-b>PRCV;+3C_FX3 z7_f>GkaZnpb{5v!OYVTTPp>scgd?Sah(G)-rio4%=u@D8tH?0OJoON`s;JUW&|d`V zs?lC!R|biU_%Z^-t`3n>$;COk?CYy`ZkZr?{Tz95f~1?@qf)o;7M?8<3MM6-GBNoT z^4}ZIL^$CR6fP<4j;Q_>Fa9}!T^iKiBChD8on>}-7~3}y{(CRzw@vn-dr(hx1xx&8 zZofamTj;yRen*VIs$(DWIt~N6q)A)L!!38P!(;j*d&EA)OXVixYsNo-MkW5HE9&yL V7|h$^xK@Bo&f_A}dmR6A{vWkphc^HK diff --git a/docs/sprints/sprint-34/client.md b/docs/sprints/sprint-34/client.md new file mode 100644 index 000000000..7a2fbd2f6 --- /dev/null +++ b/docs/sprints/sprint-34/client.md @@ -0,0 +1,92 @@ +# Sprint 34: Pulse — Client 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/client` +**Agents:** Stig (UI), Tyre (architecture) + +## New Tickets + +| # | Title | Blocked by | +|---|-------|------------| +| #785 | Add system population and GDP to star map info panel | — | +| #824 | Economics insert panel — price history charts and GDP display | #822 (server) | +| #825 | Economics debug console commands — event triggers and param sliders | #823 (server) | + +## Key Decisions + +- `decisions/economics.md` — D-181 (7-signal vocabulary — signals 1-2 are Phase 2: price_current, price_trend), D-180 (event port — the commands #825 fires) +- `decisions/architecture.md` — D-169 (implant UI component library — compose from client/ui/implant/), D-170 (HUD visibility groups — economics panel lives in INSERT mode), D-020 (IPC — EconomySnapshot arrives in ObserverSnapshot) + +## Notes + +### #785 — System population and GDP to star map info panel + +When a system is selected in the star map (`client/ui/star_map.gd`, `client/ui/star_map.tscn`), the popup built with ImplantPanel components shows: name, star type, hop distance, corridor, GTTR excerpt, bodies, adjacents. Add two new `ImplantDataRow` entries: `POPULATION` and `GDP`. Data is already in `res://data/star_map_data.json` (regenerated by `tooling/generate-star-map-data.py` from `systems.db`). Check whether population and GDP fields are present in the JSON; if not, update the generation script as part of this ticket. This is standalone — no server dependency. Good warmup ticket; complete it first. + +### #824 — Economics insert panel + +New implant panel: **Economics Monitor**. Lives in INSERT mode (D-170), accessible via implant navigation alongside the star map. + +Scene: `client/ui/implant/economics_panel.tscn` + `client/ui/implant/economics_panel.gd` + +Compose strictly from the existing component library (`client/ui/implant/`): +- `ImplantPanel` — root container +- `ImplantHeader` — "ECONOMICS MONITOR" title + selected system subtitle +- `ImplantSeparator` — section dividers +- `ImplantDataRow` — key/value rows for price and GDP data +- `ImplantTextBlock` — top commodity summary text + +Layout (three sections): +1. **System selector** — searchable/scrollable list of systems (can reuse star map system data). Selecting a system triggers an `EconStateQuery` PlayerAction to the server. +2. **Price table** — top 6 commodities for selected system, each as an `ImplantDataRow` with `price_current` and a directional trend indicator (▲ / ▼ / —) derived from `price_trend`. +3. **GDP strip** — total economic activity for the system displayed as a single row. Update each time a new `EconomySnapshot` arrives. + +Data flow: `snapshot_handler.gd` receives ObserverSnapshot v21. When `economy_snapshot` is present, forward to `economics_panel.gd` via a signal or direct call. The panel caches the last 20 ticks of price data per system for trend display (ring buffer in GDScript Dictionary). + +Do NOT draw custom canvas sparklines unless time allows — `ImplantDataRow` with a trend arrow is the MVP. The price chart can be a follow-on. + +Register the panel in `client/scripts/autoloads/hud_groups.gd` under path `implant/economics`. Add a keyboard shortcut (e.g. `E` in implant mode) and an entry in the implant navigation menu. + +Blocked by #822 (server must expose EconomySnapshot before the panel has real data). Build the panel with placeholder data first; wire live data once #822 ships. + +### #825 — Economics debug console commands + +The debug console exists at `client/ui/debug_console.gd` + `client/ui/debug_console.tscn`. The console already dispatches `DebugCommandKind` variants via `PlayerAction::DebugCommand` through the IPC bridge. + +Add three new command parsers in `_parse_command()` / `_dispatch_command()`: + +``` +econ inject [commodity_id] [ticks] + → InjectEconEvent { system_id, commodity_id, effect, magnitude, duration_ticks } + +econ param [system_a] [system_b] + → SetEconParam { param, value } + +econ inspect + → GetEconState { system_id } +``` + +`econ inspect` returns all 7 D-181 signals for the system; display in console output log as a multi-line block. `econ inject` and `econ param` print a confirmation + the server's `DebugResponsePayload.text`. + +Update `_print_help()` to include the `econ` command family. Blocked by #823 (server must handle the variants before the client can send them meaningfully, though client-side parsing can be built in parallel). + +## Dependency Chain + +``` +#785 (star map GDP) — standalone, start here + +#822 (server IPC, Sprint 34/server) → #824 (economics insert panel) +#823 (server debug handler, Sprint 34/server) → #825 (debug console commands) + +#824 and #825 are parallel after their respective server blockers clear. +``` + +## PR Workflow + +```bash +tea pr create --repo jpmschweitzer/settled-reach --login schweitz \ + --title "feat(ui): economics insert panel and debug console econ commands" \ + --description "Sprint 34 client work" \ + --base main --head sprint-34/client +``` diff --git a/docs/sprints/sprint-34/copy.md b/docs/sprints/sprint-34/copy.md new file mode 100644 index 000000000..a42258a1a --- /dev/null +++ b/docs/sprints/sprint-34/copy.md @@ -0,0 +1,61 @@ +# Sprint 34: Pulse — Copy 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/copy` +**Agents:** Mellanie (author), Paula (narrative) + +## New Tickets + +| # | Title | Blocked by | +|---|-------|------------| +| #814 | Rail infrastructure corporation gap | — | +| #695 | Author overheard conversations for remaining 24 zone types | — | + +## Key Decisions + +- `decisions/economics.md` — D-182 (TOML source of truth — all economics content lives in `wiki/economics/`), D-175 (corporation taxonomy — Tier 1/2/3 structure) +- `decisions/content.md` — D-142 (zone-type template architecture — 31 zone types defined), D-139 (composable behavior primitives — overheard conversations are Layer 2 cultural flavor) + +## Notes + +### #814 — Rail infrastructure corporation gap + +**Context:** The corporation validation pipeline (`tooling/economy-db/import_economics.py`) flagged a gap: no existing wiki corporation produces the `rail_infrastructure` commodity. This is a lore-world gap as much as a data gap — rail is the primary intra-continental transit system on inhabited worlds (see `decisions/architecture.md` D-093 for Sova Transit context, `wiki/economics/production_chains.toml` for chain definitions). + +**Deliverable:** Either (a) assign `rail_infrastructure` production to an existing Tier 1 or Tier 2 corporation (MVG — Marvian Gravity Works — is the most plausible candidate given its Tier 1 infrastructure mandate) or (b) create a new corporation if no existing corp fits. Update: +- `wiki/economics/corporations.toml` — add production entry +- Corresponding wiki corporation page (if new corp: `wiki/corporations/.md`) +- Verify `make economy-db` passes after the change + +Do not assign to a Tier 3 regional corp — rail infrastructure is a systemic commodity that should have Tier 1 or Tier 2 backing. + +### #695 — Overheard conversations for remaining 24 zone types + +**Context:** `server/content/global/overheard.ron` currently covers 5 of 29 zone types (~17% coverage). The remaining 24 types need 2-4 role-pair conversations each. These are the passive ambient dialogue lines that play when NPCs are overheard by the player without direct engagement (D-078). + +**Format:** Each conversation entry in `overheard.ron` follows the existing pattern — two role slugs, a setting line (terse, 1 sentence describing where/when), and 3-5 lines of dialogue. Lines should feel naturalistic for the zone type; the NPC pair should be plausible co-workers or passers-by given the zone's economic activity. + +**Zone types to cover:** Check `server/content/global/zone-types/` for the full list. Currently covered: the 5 types already in `overheard.ron` (verify by reading the file). Write 2-4 conversations per remaining zone type. Prioritize the zone types most likely to be visited first in a playthrough: `residential_dense`, `commercial_retail`, `transit_hub`, `office_district`, `industrial_light`. + +**Lore anchors:** Use the wiki cultural pages (`wiki/cultures/`) for voice and slang. Zone types that map to specific planetary environments (agricultural, wilderness) should reflect the relevant culture. Avoid generic SF clichés — these lines should feel like they belong in the Reach. + +**Volume:** 24 zone types × 3 conversations average × 4 lines each = ~288 lines total. Work zone-type by zone-type; commit partial coverage. Do not block on completing all 24 before committing. + +## Dependency Chain + +``` +#814 (rail corp gap) — standalone +#695 (overheard conversations) — standalone, parallel +``` + +Both tickets are independent and can run in parallel. + +## PR Workflow + +```bash +tea pr create --repo jpmschweitzer/settled-reach --login schweitz \ + --title "content(economics): rail corp gap and overheard conversation coverage" \ + --description "Sprint 34 copy work" \ + --base main --head sprint-34/copy +``` diff --git a/docs/sprints/sprint-34/joint.md b/docs/sprints/sprint-34/joint.md new file mode 100644 index 000000000..22e85dd50 --- /dev/null +++ b/docs/sprints/sprint-34/joint.md @@ -0,0 +1,115 @@ +# Sprint 34: Pulse — Joint Briefing + +**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. + +--- + +## Pre-Sprint: Decisions and Schema + +No blocking pre-sprint decisions required. All economic architecture decisions (D-178 through D-188) are confirmed. #810 (event port) is the technical gate for the full chain — it must be the first ticket the server team starts. + +| Item | Owner | Status | +|------|-------|--------| +| D-178: Economic Model Architecture | decisions/economics.md | Confirmed | +| D-179: Stability Acceptance Criteria | decisions/economics.md | Confirmed | +| D-180: Event Input Port | decisions/economics.md | Confirmed | +| D-181: Signal Vocabulary | decisions/economics.md | Confirmed | +| ObserverSnapshot v21 schema | Server → client | New this sprint (#822) | + +--- + +## Sprint Ticket Map + +### Server (sprint-34/server) +``` +#810 Event port implementation + → #821 Integrate econ-sim into server tick loop + → #822 Expose economy state over IPC (ObserverSnapshot v21) + → #823 Economics debug command handler +``` + +### Client (sprint-34/client) +``` +#785 Star map: system population + GDP (standalone) +#822 (server, blocker) → #824 Economics insert panel +#823 (server, blocker) → #825 Debug console econ commands +``` + +### Copy (sprint-34/copy) +``` +#814 Rail infrastructure corporation gap (standalone) +#695 Overheard conversations — 24 zone types (standalone, parallel) +``` + +### Planning (sprint-34/planning) +``` +#811 Brand layer design (early sprint) +#748 Phase 3 breakdown workshop (after server tickets in_progress) +``` + +--- + +## Cross-Team Integration Points + +**ObserverSnapshot v21 (server → client)** +- Server: `server/src/bridge/types.rs` — add `EconomySnapshot` struct, bump `PROTOCOL_VERSION` to 21 +- Client: `client/scripts/snapshot_handler.gd` — parse `economy_snapshot` field, route to economics panel +- Coordination: Server team defines the struct; client team consumes it. Server team ships #822 first; client team builds #824 with placeholder data in the meantime. + +**Debug command flow (both teams)** +- Server: `server/src/bridge/types.rs` — add `InjectEconEvent`, `SetEconParam`, `GetEconState` to `DebugCommandKind` +- Client: `client/ui/debug_console.gd` — add `econ inject`, `econ param`, `econ inspect` command parsers +- Coordination: Server team ships #823 before client team wires #825. Client team can build command parsing and help text independently; just gate the send path on #823 being merged. + +**Star map GDP (#785)** +- Client-only ticket. Check whether `res://data/star_map_data.json` already includes `population` and `gdp` fields. If not, update `tooling/generate-star-map-data.py` to include them from `server/data/systems.db`. This is a self-contained warmup — complete before #824. + +--- + +## Cascade Enforcement + +**No Phase 4 tickets.** This sprint closes Phase 2 and initiates Phase 3 planning via #748 and #811. The following are explicitly out of scope and must not be started, designed, or discussed: + +- Character creation (#618, #619, #694, #606) +- Tycoon starting states (#615) +- Bookmark system (#614) +- NPC personality surface area (#621) +- Apartment generator (#617, #681) +- Any ticket under Phase 4 epic #749 + +Phase 4 cannot start until Phase 3 delivers (Atlas of the Reach). Phase 3 planning workshop (#748) runs this sprint — but Phase 3 implementation tickets do not start until Sprint 35+. + +--- + +## Sprint Completion Proof + +The sprint is done when a developer can do all three of the following in the running game: + +1. **Open the implant economics panel** — select any system, see live price data (price_current and price_trend for at least 6 commodities) updating in real time as the economy runs. +2. **Trigger a supply shock from the debug console** — type `econ inject shock 0.5 200`, observe the price_current values shift in the economics panel within a few ticks, then recover toward equilibrium over the next 200 ticks. +3. **Mutate α from the debug console** — type `econ param alpha 0.01`, observe slower price adjustment in the panel; type `econ param alpha 0.06`, observe faster adjustment. + +None of the above require a character. The economics panel and debug console can be exercised from the main game loop without entering the simulation world — they operate via the IPC bridge on whatever player session is active. + +--- + +## Test Plan + +**Phase alignment:** Sprint 34 is Phase 2 delivery infrastructure. Test focus is economic state correctness over IPC, not simulation model correctness (that was Sprint 33 / D-179 stability tests). + +| Test | Tier | Owner | +|------|------|-------| +| ObserverSnapshot v21 roundtrip — serialize/deserialize EconomySnapshot | Tier 1 (fixture) | Server | +| EconStateQuery → economy_snapshot present in next snapshot | Tier 2 (bridge) | Server | +| `econ inject` → DebugResponsePayload.success true + price shift observable | Tier 2 (bridge) | Server | +| Economics insert panel renders with fixture EconomySnapshot | Tier 3 (client live) | Client | +| Debug console parses `econ inject` without error | Tier 3 (client live) | Client | +| Star map popup shows population + GDP fields | Tier 3 (client live) | Client | + +--- + +## Open Questions + +None blocking implementation. One design question in-flight: + +- **Q: Brand layer architecture** (#811 planning) — not blocking Sprint 34 implementation work. Resolved by planning team this sprint; produces Phase 3 tickets for Sprint 35. diff --git a/docs/sprints/sprint-34/planning.md b/docs/sprints/sprint-34/planning.md new file mode 100644 index 000000000..9ed6fa860 --- /dev/null +++ b/docs/sprints/sprint-34/planning.md @@ -0,0 +1,103 @@ +# Sprint 34: Pulse — Planning 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/planning` +**Agents:** Gestalt (systems), Burnelli-Sheldon (economics), Tyre (technical), Miri (worldbuilding), Qatux (documenter), SI (project manager) + +## Tickets + +| # | Title | Blocked by | +|---|-------|------------| +| #748 | Phase 3: Planetary/moon maps and station layouts — Atlas of the Reach | #747 (in progress → closes this sprint) | +| #811 | Brand layer design | — | + +## Context to Read Before Discussion + +For **#811 (Brand layer design):** +- `decisions/economics.md` — D-185 (Brands Are Not Commodities), D-184 (Commodity Catalog — what exists), D-173 (Commodity Taxonomy — three-tier structure) +- `decisions/scope.md` — D-131 (broad economic verb vocabulary), D-118 (small business owner starting state — brands are the Phase 3 player layer) +- `wiki/economics/commodities.toml`, `wiki/economics/production_chains.toml` + +For **#748 (Phase 3 breakdown):** +- `CLAUDE.md` — Development cascade table (Phase 3 = Planetary/moon maps, deliverable = Atlas of the Reach) +- `decisions/architecture.md` — D-093 (Sova Transit District spatial layout), D-094 (district spatial hierarchy), D-095 (Horizon stations and gate infrastructure) +- Sprint 33 deliverable: `server/data/systems.db` populated with 300+ systems, gate links, currency zones +- `docs/atlas/` — existing atlas content + +--- + +## #811 — Brand Layer Design + +**Type:** Planning discussion — produces a D-record in `decisions/economics.md` + +**What this is:** The brand/luxury goods system sits on top of the commodity layer (D-185 confirms brands are NOT commodities). Brands consume commodities as inputs. Brand pricing is driven by cultural/emotional/want mechanics, not tâtonnement. This design work answers the Phase 3 question: how does a player engage with the economy as a participant (producer/trader/brand-builder) rather than an observer? + +**Discussion rounds:** + +**Round 1 — Inventory (what exists, what is missing)** +- What is the full design space of "brand" in the Reach? (Gestalt, Miri) +- What D-records already constrain brand design? (Tyre reads economics.md, scope.md) +- What is the player's economic verb set when brands exist? (Burnelli-Sheldon, Gestalt) + +**Round 2 — Proposals** +- Brand representation: is a brand a DB entity, a modifier on a commodity, or a separate production chain layer? (Tyre, Burnelli-Sheldon) +- Cultural pricing model: how does a brand's cultural origin affect demand across currency zones? (Miri, Gestalt) +- Player access: what verbs does a player have toward an existing brand vs. founding one? (Gestalt) + +**Round 3 — Convergence** +- Draft one D-record covering: brand representation in the data model, cultural demand pricing, player access verbs, and the boundary with Phase 2 commodity tâtonnement +- SI creates follow-up implementation tickets for Phase 3 sprint + +**Output:** D-NNN in `decisions/economics.md` (claim ID via `tooling/db/decision claim D economics "Brand layer architecture"`). Qatux files the record. SI creates 2-4 Phase 3 implementation tickets from the decision. + +**CONSTRAINT:** This design session covers brand layer architecture only. No character creation, no tycoon states, no apartment generators. Phase 4 work is out of scope until Phase 3 delivers. + +--- + +## #748 — Phase 3 Planetary Maps Breakdown Workshop + +**Type:** Planning discussion — produces a sprint-ready ticket breakdown for Phase 3 + +**What this is:** Phase 3 deliverable is the Atlas of the Reach (implant app) — region-level maps at hundreds-of-km scale. Cities, rivers, mountains, rail lines, gate/portal locations, road hierarchy, named areas. This workshop answers: what is the minimal scope for a shippable Phase 3, and what tickets does it generate? + +**Timing:** This discussion runs AFTER the server team confirms Phase 2 is closing (economics in-game, IPC bridge live). Do not start this discussion until Sprint 34 server tickets are at least in_progress. + +**Discussion rounds:** + +**Round 1 — Inventory** +- What does Phase 3 require that does not exist? Read `docs/atlas/`, existing world data in `server/data/systems.db`. (Miri, Tyre) +- What systems from Phase 2 does Phase 3 build on (gate network, system data, planet_class)? (Gestalt, Tyre) +- What is the rendering target? (Implant app panel — same component library as economics panel?) (Tyre) + +**Round 2 — Scope definition** +- Define the MVP Atlas: which systems get maps first? (Miri — Sova/Krenn as canonical first-system per D-036) +- Data authoring pipeline: how are planetary maps authored? Hand-drawn overlays on procedural heightmaps? Pure procedural? (Miri, Gestalt) +- Implant app design: what does the Atlas panel look like? Click-through from the star map? (Tyre) + +**Round 3 — Ticket breakdown** +- Break Phase 3 into 4-8 implementation tickets across server, client, copy, visual teams +- Assign team and priority to each +- SI creates the tickets and blocks them appropriately under #748 + +**Output:** 4-8 new tickets (server + client + copy + visual) with team assignments, priorities, and explicit dependencies. SI creates them immediately at round end. + +--- + +## Dependency Chain + +``` +#811 (brand layer design) — run early in sprint, unblocks Phase 3 planning +#748 (Phase 3 breakdown) — run after server Sprint 34 tickets are in_progress +``` + +## PR Workflow + +Planning branch produces decisions and ticket updates only — no code. Commit decisions and close tickets: + +```bash +tea pr create --repo jpmschweitzer/settled-reach --login schweitz \ + --title "planning(economics): brand layer design and Phase 3 breakdown" \ + --description "Sprint 34 planning work" \ + --base main --head sprint-34/planning +``` diff --git a/docs/sprints/sprint-34/server.md b/docs/sprints/sprint-34/server.md new file mode 100644 index 000000000..6f6562763 --- /dev/null +++ b/docs/sprints/sprint-34/server.md @@ -0,0 +1,123 @@ +# 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 +```