Phase 3 launch sprint. 13 tickets across server, client, copy. Atlas generation pipeline (terrain_reference, generate_atlas.py, Gemma naming), brand layer DB schema, Atlas implant panel (3 levels + heightmap viewer + overlays), hand-authored templates for Lendel + 4 core systems, brand corp TOML, brand_templates.toml (120-130 archetypes), wiki glossary, world seed wiring. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
7.9 KiB
Sprint 35: Atlas — Server Tasks
Goal: Launch Phase 3 — build the atlas generation pipeline (terrain population, city placement, Gemma naming) and lay the brand layer DB schema, so all inhabited bodies have generated markers and the economics simulation uses world-seeded randomness.
Branch: sprint-35/server
Agents: Dudley (simulation/tooling), Tyre (architecture)
New Tickets
| # | Title | Blocked by |
|---|---|---|
| #826 | Thread world seed from StartupMessage into economy simulation | — |
| #827 | Add brand_products, brand_inputs, system_fiscal schema and Phase 2 demand stubs | — |
| #839 | Batch populate terrain_reference column in systems.db bodies table | — |
| #832 | Build generate_atlas.py — terrain-aware sequential city placement and infrastructure generation | #839 |
| #833 | Gemma 2 batch naming pipeline for atlas geographic features | #832 |
Key Decisions
decisions/architecture.md— D-188 (biome_summary → planet_class rename, affects pipeline scripts), D-191 (Atlas Phase 3 scope — full pipeline spec: city placement algorithm, infrastructure gen, naming, markers.json schema)decisions/economics.md— D-189 (brand layer architecture — DB schema per section 5), D-190 (brand volume calibration — population-relative scale), D-185 (brands are not commodities — brand corps are commodity demand nodes), D-175 (corp taxonomy — Tier 1 brand corps), D-182 (TOML source of truth — make economy-db extends to brand tables)
Notes
#826 — Thread world seed into economy simulation
Small, self-contained. server/src/simulation/mod.rs initializes EconSimResource with try_load_economy(0) — the 0 is a hardcoded seed. Wire in the world_seed from StartupMessage (received during the IPC handshake). The seed is already available in the simulation startup path; find where StartupMessage is handled and thread the value through to try_load_economy(). Start here — it unblocks nothing else but is low-risk and closes the Sprint 34 loose end.
#827 — Brand layer DB schema and Phase 2 demand stubs
Per D-189 section 5, add five new tables to db/schema.sql (or server/data/systems-schema.sql if that is the brand-layer schema file — check which file make economy-db reads):
brand_products— full column list in D-189 section 5brand_inputs—brand_product_id,commodity_id,quantitysystem_fiscal—system_id,corp_tax_rate,collection_efficiencycorp_financial_state— passive tracking (Phase 2: health metric only)corp_lifecycle_events— Phase 3 lifecycle state machine (Phase 2: stub table with correct schema)
Add composite index on brand_products(corp_id, brand_category) for UI queries (D-189 section 5).
Also author wiki/economics/corporations/brands.toml (new file) with TOML records for the 4 canonical brand corps: Calloway Distillery, Vins de Grand Vide, thrds, Bífröst Marmor. Each record registers those corps as commodity demand stubs at their home market nodes — they consume generic commodity inputs (per D-185: brands consume commodities, not the reverse). The copy team (#830) is authoring these same entries to tier1.toml; coordinate — the brand corps should appear in tier1.toml (copy) AND have separate brand_products entries (this ticket). Do not duplicate data; confirm the split before writing.
Extend make economy-db to compile brand tables alongside the existing pipeline. Add validation rules V-B01 through V-B05 (defined in the ticket description).
#839 — Batch populate terrain_reference
The bodies table in server/data/systems.db has a terrain_reference column that is NULL for all 273 inhabited bodies. Write a batch script (Python fits alongside the existing tooling/planet-gen/ scripts) that:
- Queries all body rows with NULL
terrain_reference - Constructs the expected wiki heightmap path:
wiki/star-systems/{system_slug}/bodies/{body_id}/heightmap.png - Verifies the file exists
- Updates the column
Log any bodies where the heightmap is missing so they can be flagged. This is the prerequisite for #832 — generate_atlas.py reads terrain_reference to find the heightmap. Keep the script simple; it's a data population pass, not logic.
#832 — Build generate_atlas.py
New Python pipeline at tooling/planet-gen/generate_atlas.py. Reuses planet_simulation.simulate() for terrain data. Per D-191 section 3 and 9:
Pipeline order:
- Load heightmap via
terrain_reference(populated by #839) - Analyze terrain: continent detection (flood-fill), habitability scoring (temperature + moisture + slope), river mouth identification
- Place cities sequentially:
- Capital first: ~50% at river mouths, scored by habitability + coastal access + flat hinterland
- Rail corridor growth: cities 2-N follow the capital's terrain corridor
- New continent ports at cities 3-4 (cross-continent expansion)
- Generate infrastructure: A* pathfinding for roads and rail on terrain cost grid, MST network connecting cities
- Apply quadrant distribution constraint (cities should not all cluster in one area)
- Apply ±25% noise for variation
- Compute city count from population:
floor(log10(pop / 1_000_000)), modified bysettlement_patternfrom systems.db - Write
markers.jsonper body (schema per D-191 section 8: cities with lat/lon/population_tier/primary_function/gate_terminal/continent_id, roads, railroads, POIs)
make target: make atlas-generate — incremental, skips bodies where markers.json already populated. Deterministic per seed.
Naming step is NOT in this ticket — city names will be blank strings in this pass; #833 fills them. Gate terminal POI: place at largest population center, occasionally scatter to a smaller one (per D-191).
Existing files to reuse: tooling/planet-gen/planet_simulation.py, tooling/planet-gen/biome_config.py. The generate.py script already calls _build_markers() for rivers/oceans/mountains — extend that structure rather than replacing it.
#833 — Gemma 2 batch naming pipeline
Extend generate_atlas.py with tooling/planet-gen/gemma_naming.py — a batch client for the sr-voice binary. Per D-191 and D-191 cross-reference to D-138 (Gemma 2 voice pipeline):
For each body, send corridor-appropriate naming prompts:
- Prompt context:
planet_class,cultural_corridor,settlement_pattern,atmospheric_tone+ corridor palette - Name: rivers, oceans, mountain ranges, regions, city names (already placed by #832, just unnamed)
- Naming patterns per D-189:
north_reach→ British/Australian inflection,east_reach→ Korean/Japanese,west_reach→ German/Dutch/Nordic,south_reach→ Portuguese/Swahili,inner_corridor→ pan-corridor neutral,frontier→ founder surname + noun
Post-processing:
- Earth-name blocklist (filter obvious Earth names that slip through)
- Dedup check against full name corpus per body
- Estimated runtime: ~80 min for all 2,394 bodies — make this batch incremental
This ticket serves dual purpose: Phase 3 content delivery AND a quality test of the Gemma 2 naming pipeline ahead of its broader use.
The sr-voice binary lives in server/src/voice/ — check existing voice pipeline callers in the codebase for the batch invocation pattern before writing new code.
Dependency Chain
#826 (seed wiring) — standalone, start first (small)
#827 (brand schema + demand stubs) — standalone, parallel track
#839 (terrain_reference populate) → #832 (generate_atlas.py) → #833 (Gemma naming)
#839 → #832 → #833 are sequential. #826 and #827 are fully parallel to the atlas chain. Atlas pipeline is the sprint's critical path.
PR Workflow
tea pr create --repo jpmschweitzer/settled-reach --login schweitz \
--title "feat(simulation): atlas generation pipeline and brand schema" \
--description "Sprint 35 server work: terrain_reference population, generate_atlas.py, Gemma naming, brand DB schema, world seed wiring" \
--base main --head sprint-35/server