Four-round workshop (Gestalt, Tyre, Paula, Burnelli-Sheldon, Miri) mapping the full generation pipeline from planetary heightmap to walkable tile. 25 D-records produced. Ticket dependency chain for Tier 0-4 implementation identified. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
20 KiB
title, description, type, status, workshop, agent, round, created
| title | description | type | status | workshop | agent | round | created |
|---|---|---|---|---|---|---|---|
| Gestalt — Round 1: Systems Inventory | Pipeline inventory from the systems design perspective: layer states, system interactions, economics integration, and ticket dependency analysis | workshop | active | generation-cascade | gestalt | 1 | 2026-04-30 |
Generation Cascade — Round 1: Gestalt Inventory
Focus: System interactions across pipeline layers. Where does economics enter? Where do social sites, NPC population, and zone palettes enter? What's the minimum viable viewable world? What tickets formally block the right work?
Pipeline Inventory — Layer by Layer
Overview
| Layer | Name | Status | Input | Output | Key Code |
|---|---|---|---|---|---|
| 1 | Galaxy / System definitions | DONE | Wiki markdown frontmatter | systems.db (star_systems, bodies) |
tooling/economy-db/import_economics.py |
| 2 | Planetary terrain simulation | DONE | Body definition (planet_class, biome) | Elevation/temp/moisture/water grids (in-memory) | tooling/planet-gen/planet_simulation.py |
| 3 | Atlas markers (city placement) | DONE | Terrain grids + systems.db (population, settlement_pattern) | markers.json (cities, roads, rail, rivers, mountains, POIs) |
tooling/planet-gen/generate_atlas.py |
| 4 | City naming | DONE | markers.json (empty name fields) + cultural_corridor | markers.json (named cities and features) | tooling/planet-gen/gemma_naming.py |
| 5 | Economics layer | DONE | Wiki TOMLs + brand templates + Rust binary | systems.db (corps, brands, supply chains, trade flows) | tooling/economy-db/import_economics.py |
| 6 | City → District decomposition | MISSING | City entry from markers.json (position, population, kind) | N district stubs with WorldTier/ComplexityTier/SettingType | Nothing exists |
| 7 | Phase 1: DistrictSkeleton generation | STUB | District classification from Layer 6 | Filled DistrictSkeleton (block grid, reservations, social sites, zone palette) | server/src/simulation/generator.rs — types only |
| 8 | Society profile resolution | PARTIAL | cultural_corridor + heritage roots from body/system | SocietyProfileRef → cultural behavioral inputs | #679 (done) but not wired to DistrictSkeleton |
| 9 | Phase 2: ChunkData tile generation | MISSING | DistrictSkeleton Phase 1 output | Filled 64×64 tile grid (WalkabilityMap + tile types) | Nothing connects generator to tile data |
| 10 | Heritage grammar application | MISSING | SocietyProfileRef + zone palette + chunk skeleton | Culturally modified tile layout | HeritageGrammarOverlay not implemented |
| 11 | NPC population (Phase 2) | PARTIAL | DistrictSkeleton.society_profile + social_sites | NpcManifest → NPC pool with triangle assignments | Triangle/template system is FULL (#107, #108 done); NpcManifest seeding from skeleton is missing |
| 12 | Chunk streaming to generator hookup | STUB | Player position → on-demand load request | Generator-filled ChunkData delivered to WalkabilityMap | chunk_streaming.rs — load/unload works but calls static v0.1 data, not generator |
Layer Details
Layer 1–5: What's Done
These layers are genuinely complete and pipeline-capable. Layer 3 (atlas generator) deserves particular attention — it does real terrain-aware computation: continent flood-fill, habitability scoring, river mouth detection, A* road routing, MST rail generation. The output is rich and the data is in systems.db. The atlas is the last fully-working pipeline layer.
The economics layer (Layer 5) is likewise complete: corporations, brands, supply chains, trade flows, fiscal systems are all in systems.db. There is no code bridging this data downstream to district/zone generation yet.
Layer 6: City → District Decomposition — MISSING (Critical Gap)
This is the first entirely missing layer. The atlas produces city markers (position, population, kind: capital/city, economic_role). Converting a city into N districts with appropriate classifications requires:
- Population tier → district count formula (e.g. population ÷ 50,000 per district, min 1)
- city.kind + body.economic_role → DistrictType assignments
- body.planet_class + city position → SettingType (Urban/Agricultural/Maritime/etc.)
- system WorldTier → ComplexityTier ceiling
No ticket formally covers this. #899 (District skeleton generator — Phase 1) assumes this decomposition as a prerequisite input but does not scope it. This layer needs its own ticket.
Layer 7: Phase 1 DistrictSkeleton — STUB, with a Critical Data Model Discrepancy
server/src/simulation/generator.rs has a complete DistrictSkeleton struct with all fields the workshop designed. Types compile. But:
-
No generation logic exists. Every field that requires reasoning (block grid ZoningType assignments, social site placement, reservation generation, zone palette selection) has stub type aliases:
ZoneDefinition = StringSocietyProfileRef = StringDistrictContext = StringEra = StringAccessPoint = StringGuaranteeAuditResult = String
-
WorldTier enum does not match the workshop decision. The code has:
enum WorldTier { Peripheral, Connected, Core }The workshop (D-READY-2, workshop-outcomes.md) locked:
enum WorldTier { Epicenter, Regional, Backwater, Passage, Waypoint }This is a blocker. #899 cannot be implemented correctly against the current enum. Must be fixed before any generation logic touches WorldTier.
Layer 8: Society Profile Resolution — Partial
Ticket #679 (location-to-culture resolution system) is done. This means we can resolve cultural_corridor → heritage_root for any location. But this output is not yet wired into DistrictSkeleton.society_profile. The SocietyProfileRef field is a String stub — the culture system exists but isn't connected to the generation path.
This is a wiring gap, not a design gap. Relatively cheap to fix once Phase 1 generation logic exists.
Layer 9: Phase 2 ChunkData Tile Generation — MISSING (Critical Gap)
This is the other critical missing layer. chunk_streaming.rs has a solid streaming architecture — load/unload around player position works correctly. But walkability.load_chunk(coord) creates empty chunks; it doesn't call any generator.
The v0.1 world tiles come from YAML files authored by hand (#577) — server/data/locations/. The generator never produces tiles. There is no pipeline from DistrictSkeleton → actual walkable tile data.
For Phase 2 to work:
- ChunkData needs a tile layer (beyond the walkability bool grid)
- A generator function must take BlockSkeleton + DistrictSkeleton and fill a 64×64 tile grid
- chunk_streaming.rs needs to call this generator on
ZLevelLoadState::Ungeneratedchunks
Existing pre-workshop tickets (#100 "Ungenerated → instantiation", #156 "Procedural district filler", #160 "Tier 3 procedural generator") pre-date the confirmed architecture. They need re-scoping against DistrictSkeleton/ChunkData.
Layer 10: Heritage Grammar — MISSING
HeritageGrammarOverlay is designed (D-READY-9 from workshop) but no Rust type exists. This is Phase 2+ — it applies at chunk fill time. Not a blocker for the minimum viable slice, but it IS what makes tiles culturally distinguishable.
Layer 11: NPC Population — Partial (More Done Than Expected)
The triangle system (server/src/simulation/triangle.rs) is substantially implemented — the workshop brief calls it "stubs" but the file is extensive: template schemas, triangle escalation tick system, NPC spawn patterns. Intra-template (#107) and cross-template (#108) triangle generation are both done.
What's missing is the Phase 2 pipeline connection: NpcManifest seeding from DistrictSkeleton.society_profile + social_sites. But the machinery to run NPCs once they're spawned exists. This means NPC population is a wiring problem, not a design or implementation gap.
Layer 12: Chunk Streaming Hookup — Stub
chunk_streaming.rs has the right architecture for v0.3+ on-demand loading (commented explicitly in the file: "For v0.3+, the generator fills newly loaded chunks with terrain data"). The radius=8 default covers the entire v0.1 district, so nothing unloads. The system is ready for the generator hookup; it just needs the generator to exist.
System Interactions Analysis
Economics Layer → Generation Pipeline
The economics layer is rich but its connections downstream are all implicit data, no code.
| Economics Output | Where It Should Enter | Current State |
|---|---|---|
bodies.economic_role (Agriculture/Refining/Transit/etc.) |
Layer 6: district decomposition → DistrictType | Not wired |
bodies.cultural_corridor |
Layer 8: society profile → SocietyProfileRef | #679 done but not wired to skeleton |
| Corporation presence in system | Phase 1: DistrictSkeleton zone_palette modifiers (FactionModifier) | ZoneDefinition is a String stub |
| Supply chain density | Phase 1: DistrictType (Commercial/Industrial/Logistics) weighting | No connection |
| Brand presence | Phase 2 / Heritage grammar: signage, storefronts | HeritageGrammarOverlay not implemented |
| Trade flow volume | WorldTier assignment (high-traffic → higher tier) | No connection |
Key design principle for Round 2: The economics → generation bridge should be explicit in Layer 6. When we decompose a city into districts, the economic_role should directly drive DistrictType proportions:
economic_role=Agriculture→ mostly Agricultural setting + Industrial blocks for processingeconomic_role=Refining→ Industrial + Specializedeconomic_role=Transit→ Transit + Commercial + Logistics
This is a systems design decision that should produce D-records.
Where Social Sites, NPC Population, and Zone Palettes Enter
| System | Entry Layer | Entry Mechanism | Current State |
|---|---|---|---|
| Zone palettes | Phase 1 (Layer 7) | DistrictSkeleton.zone_palette (Vec) | ZoneDefinition = String stub |
| Social sites | Phase 1 (Layer 7) | DistrictSkeleton.social_sites (Vec) | SocialSitePlacement struct exists; no generation code fills it |
| NPC pool | Phase 2 (Layer 11) | NpcManifest seeded from society_profile | NpcManifest not yet a type; society_profile is a String |
| Triangle assignments | Phase 1 (Layer 7) | DistrictSkeleton.social_sites[i].triangles | No generation code |
| Heritage grammar | Phase 2 (Layer 10) | HeritageGrammarOverlay applied at chunk fill time | Not implemented |
Critical ordering constraint: Zone palettes must be determined at Phase 1 before chunk tiles can be generated in Phase 2. Social sites must be placed before NPC positions can be assigned. The dependency chain inside Phase 1 is:
Classification (WorldTier, ComplexityTier, SettingType)
→ Block grid assignment (ZoningType per block)
→ Zone palette selection (economics + era + culture)
→ Social site placement (template + block assignment)
→ Triangle assignment (TrianglePurpose per site)
→ Guarantee audit (3-tier checks)
The Phase 2 chain continues:
DistrictSkeleton (immutable)
→ ChunkData tile fill (floor/wall/zone tile types)
→ Heritage grammar overlay (cultural modifier)
→ NpcManifest instantiation (society_profile → NPC pool)
→ Triangle → NPC assignments (existing triangle system)
Minimum Viable "Viewable World"
The thinnest vertical slice from heightmap to rendered tiles:
Inputs available now: One city entry from markers.json (position, population, kind). Body's planet_class, economic_role, cultural_corridor from systems.db.
Minimum code to write:
-
Layer 6 stub: Fixed formula
n_districts = max(1, population / 50_000). Assign one SettingType from planet_class. Assign WorldTier from system lookup. Output: N (WorldTier, ComplexityTier, SettingType) tuples. -
Layer 7 minimal: Generate DistrictSkeleton with real block grid. Simple deterministic ZoningType assignment from DistrictType (e.g. Commercial district → mostly Commercial blocks, some Mixed). No social sites. No reservations. No guarantee audit. Zone palettes as named constants only.
-
Layer 9 minimal: For each BlockSkeleton, fill 4 chunks (2×2) with simple tile layout: exterior walls + floor interior + one door per edge. No rooms, no objects, no heritage grammar. Pure structural.
-
Wiring: In chunk_streaming.rs, on
load_chunk()when no YAML data exists, call the Phase 2 generator instead of returning empty. The existing tilemap renderer already handles ChunkData.
What this produces: A player standing in a procedurally-generated city block. Walls are walls. Floor is floor. No cultural character. No NPCs. No social sites. But it's walkable, streaming, and fully pipeline-driven — which is what the cascade deliverable requires.
Estimated effort for minimum viable slice: ~5–7 dev-days of focused server work (Layer 6: 0.5 days, Layer 7 minimal: 2 days, Layer 9 minimal: 2 days, wiring: 1 day, WorldTier enum fix: 0.5 days).
Ticket Dependency Chain
Current State of Referenced Tickets
| Ticket | Title | Status | Current Blockers | My Assessment |
|---|---|---|---|---|
| #897 | Generation pipeline cascade (this workshop) | backlog | — | Active; blocks #899 |
| #899 | District skeleton generator — Phase 1 | backlog | #897 | Correct scope, but misses Layer 6 and WorldTier fix |
| #615 | Tycoon small business owner starting state | backlog | — | Game content design, not generation-dependent |
| #616 | Broad economic verb vocabulary design | backlog | — | Pure content design, no generation dependency |
| #619 | Full character customisation | backlog | — | Phase 4 cosmetic UI, NOT generation-dependent |
| #681 | Apartment generator logic (server) | backlog | #615, #679(done) | Needs cascade blocker: Phase 1 skeleton + cultural context |
| #682 | Apartment visual rendering (client) | backlog | #681 | Correct — blocked by #681 |
| #694 | Character creation screen | backlog | #685(done) | Phase 4 UI, NOT generation-dependent |
Character and Apartment Work: What Actually Needs Blocking
#619 (Character customization) and #694 (Character creation screen): These are cosmetic UI tickets for Phase 4 (Player Control Scheme). Character visual appearance is independent of world generation. These should NOT be formally blocked behind generation pipeline work. The player needs to look like something before the world needs to be generated. Do not add generation blockers here.
#681 (Apartment generator): This IS generation-dependent and needs additional blockers. The apartment:
- Lives in a building in a district → needs that district's zone context
- Uses cultural context → #679 done, but the wiring to DistrictSkeleton is not done
- Uses economic position → #615 (tycoon starting state) is a real dependency
Recommended: add formal blocker on #681 behind Phase 1 district skeleton working. The apartment generator cannot produce culturally-appropriate tile layouts without knowing the district's society_profile and zone_palette.
#682 (Apartment visual rendering): Correctly blocked by #681. No changes needed.
New Tickets Needed
| Priority | Ticket | Scope | Blocked By |
|---|---|---|---|
| Blocker | Fix WorldTier enum — Peripheral/Connected/Core → Epicenter/Regional/Backwater/Passage/Waypoint | Rename enum values in generator.rs to match workshop-locked decision | #897 |
| Critical | Layer 6: City → District decomposition | Convert atlas city markers to district count + classification stubs | None (can start after WorldTier fix) |
| Critical | Phase 2: Basic chunk tile generator | Fill 64×64 chunk from BlockSkeleton: walls + floor, no rooms | #899 |
| High | Connect chunk_streaming to Phase 2 generator | On load_chunk() for Ungenerated chunks, invoke Phase 2 generator |
Phase 2 chunk tile generator |
| High | Wire society profile to DistrictSkeleton | Connect #679 location-to-culture output → DistrictSkeleton.society_profile | #899 |
| Medium | Re-scope #156 (Procedural district filler) | Align pre-workshop ticket to DistrictSkeleton architecture | Phase 2 chunk tile generator |
| Medium | Re-scope #100 (Ungenerated → instantiation) | Align to chunk_streaming + Phase 2 on-demand fill pattern | Phase 2 chunk tile generator |
Formal Cascade Blocker Chain
#897 (this workshop — D-records)
└─▶ WorldTier enum fix
└─▶ Layer 6: City → District decomposition (new ticket)
└─▶ #899 Phase 1 DistrictSkeleton generation
└─▶ Phase 2: Basic chunk tile generator (new ticket)
└─▶ Connect chunk_streaming to generator (new ticket)
└─▶ Wire society profile to skeleton (new ticket)
└─▶ #681 Apartment generator (ADD formal block here)
└─▶ #682 Apartment visual rendering
#694 Character creation screen — NOT in this chain (Phase 4 UI work)
#619 Character customization — NOT in this chain (Phase 4 cosmetic work)
#616 Verb vocabulary — NOT in this chain (content design)
#615 Tycoon starting state — feeds #681, not generation pipeline
Key Flags for Round 2 Discussion
1. WorldTier enum mismatch is a hard blocker
Before #899 can be correctly implemented, WorldTier in generator.rs must be renamed. This is a small code change but touches a core enum — it needs a D-record confirming the canonical values before the rename happens, to prevent the same drift occurring again.
2. The apartment generator dependency chain is currently incomplete
#681 is blocked only by #615 and #679. It should also be blocked by Phase 1 district skeleton generation. The apartment exists in a district — without district skeleton generation working, we can't produce the zone context that makes an apartment feel culturally appropriate vs. just a random room.
3. Layer 6 (City → District decomposition) has no ticket
This is the first link in the chain from atlas markers to walkable tiles, and it has no ticket and no code. Without it, #899 has no valid input. New ticket needed before #899 can be effectively scoped.
4. Phase 2 tile generation is the real gate on "viewable world"
Phase 1 skeletons are useful for planning and NPC/economic pre-computation. But the cascade deliverable is "walkable generated world" — that requires Phase 2 tile generation. The thinnest slice that produces rendered tiles requires Phase 2, even if that Phase 2 is initially just "floor tiles inside block boundaries, wall tiles at edges." The existing rendering pipeline will handle it.
5. The economics layer is rich and available — use it at Layer 6
We have economic_role, cultural_corridor, trade flow data, corporation presence — all in systems.db. Layer 6 (city → district decomposition) is the natural integration point where this data should shape district character. The design principle: economics drives district type; culture drives zone palette; both come from systems.db data that already exists.
Summary Table
| Gap | Severity | Effort | Notes |
|---|---|---|---|
| WorldTier enum mismatch | Blocker | 0.5 days | Rename enum values, update all references |
| Layer 6: City → District decomposition | Critical | 0.5–1 day | New ticket, no design gaps just missing code |
| Phase 1 generation logic | Critical | ~2–3 days | #899, blocked by this workshop's D-records |
| Phase 2 chunk tile generator | Critical | ~2 days | New ticket, blocked by #899 |
| Chunk streaming → generator hookup | High | ~1 day | New ticket |
| Society profile → skeleton wiring | High | 0.5 days | Design done (#679), wiring only |
| Heritage grammar overlay (Rust type + logic) | Medium | ~3–4 days | Phase 2+, not on critical path for minimum slice |
| NpcManifest seeding from skeleton | Medium | ~1 day | Machinery exists, connection missing |
| Guarantee audit implementation | Low | ~2 days | Can defer until Phase 1 generation is stable |