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>
25 KiB
title, description, type, status, workshop, agent, round, created
| title | description | type | status | workshop | agent | round | created |
|---|---|---|---|---|---|---|---|
| Round 4 — Burnelli-Sheldon: Economics Integration for Planet-Down Cascade | Economics domain requirements for the planet-down brief: layer entry points, determinism split, dynamic settlement latency, and per-layer DB field mapping | workshop | active | generation-cascade | burnelli-sheldon | 4 | 2026-04-30 |
Round 4 — Burnelli-Sheldon: Economics Integration for Planet-Down Cascade
The lead has reframed the cascade as planet-down. This changes the framing, not the economics. My job this round is to map my accepted contributions from Round 3 into the new four-layer model and answer the specific questions the lead flagged.
1. Where Does Economic Data First Enter?
Answer: Layer 1, weakly. Layer 2, in full.
Layer 1 — Empty World (weak influence)
The lead defines Layer 1 as "natural world, no civilization." That is exactly right. Economics does not shape terrain. But there is one legitimate economics-adjacent influence at this layer: biome quality distribution.
A planet was settled because it was worth settling. The body's economic_role in
systems.db is not a cause of its terrain — it is the outcome of someone deciding
this terrain was worth exploiting. That selection creates a plausibility constraint:
an agricultural world had to have arable soil; an extraction world had to have
accessible ore. If the Layer 1 generator produces a volcanic hellscape for a body
with economic_role = agricultural, the world is self-contradictory.
The fix is not to have economics drive terrain geometry. It is to use
bodies.economic_role + bodies.planet_class as a biome probability prior in
the sub-biome refinement step:
| economic_role | Sub-biome quality bias |
|---|---|
| agricultural | More temperate/arable cells, gentler slopes, fewer badlands |
| extraction / mining | More rugged terrain, higher mineral-rich designations |
| research | More terrain variety (observable geography = research value) |
| transit | More navigable terrain, natural passes and harbors |
| frontier | Unconstrained — hostile terrain is plausible |
| manufacturing | Near-neutral; manufacturing follows settlement, not terrain |
This is a prior, not a hard constraint. The biome generator can still produce a
difficult agricultural world (thin soil, reclamation history) — but the prior nudges
it toward plausibility. If this is too complicated for Layer 1, the alternative is
simply to trust that planet_class encodes this well enough already (temperate
planets are already the natural home of agricultural worlds) and leave Layer 1
fully physics-driven.
Either approach is defensible. I flag it because the contradiction risk is real and cheap to address at Layer 1 rather than later.
Economic fields at Layer 1:
bodies.economic_role— biome probability prior (optional)bodies.planet_class,bodies.atmosphere,bodies.surface_gravity— primary physical inputs
Layer 2 — Population Overlay (primary entry point)
This is where economics enters in full force and where my Round 3 work connects most directly. The lead's description — "economics onto geography, settlements anchor where geography supports them, felled forests → farmland, road/rail networks, anchored by wiki population counts" — is precisely what the economics data enables.
The atlas_cities table provides wiki-anchored city positions and populations. The
bodies table provides the economic character. The corp_presence table shows which
corporations cluster where. The atlas_roads and atlas_railroads tables provide
infrastructure. All of this is pre-computed and stored in systems.db.
Layer 2 is not city-internal planning — it is the hinterland: what fills the space between cities. Economic role determines hinterland character:
| economic_role | Hinterland fill | Notes |
|---|---|---|
| agricultural | Cleared farmland, irrigation networks, processing nodes | "Felled forests → farmland" lives here |
| extraction | Access corridors, mining infrastructure, stockpile areas | Extends to resource deposit locations |
| manufacturing | Industrial fringe, rail freight yards, supply zones | Follows logistics corridors |
| transit | Dense road/rail, relay stations, fuel depots | The infrastructure IS the hinterland |
| research | Exclusion zones, observatory sites, quiet buffer | Sparse, low-density |
| service_mixed | Suburban residential spread, civic infrastructure | Generic low-density |
Economic fields at Layer 2 (full list):
From bodies: economic_role, settlement_pattern, industrial_corridor, population, planet_class
From atlas_* tables: city positions and populations, road/rail presence, POI kinds
From system_economy: economic_tier (infrastructure density), economic_base_primary/secondary
From system_gates: gate_connections (trade route intensity → transport infrastructure density)
From corp_presence: which corps operate here, primary_operation commodity
Dynamic settlement triggers (see §3 below) are also evaluated at Layer 2.
2. The Determinism Rule — Layout vs. Appearance
The lead's rule is economically clean and I agree with it completely:
Economic sim's rolling state affects RENDERING (prosperity, repair) NOT LAYOUT (streets locked by seed).
This is how real cities work. Detroit's street grid did not change when its industrial base collapsed. Buenos Aires' Palermo grid was not rezoned during financial crisis. The buildings aged and emptied; the streets persisted.
Here is the full split as I see it:
Seed-Locked (Layout) — Generated Once, Never Changed
These are determined by (world_seed + CityGenerationContext) at generation time:
- Street grid pattern and block geometry
- Building footprints and lot parcels
- District boundaries
- Perimeter treatment type (Open / Fenced / Walled / Gated / Checkpoint)
- Access point positions
- Settlement positions — including LATENT settlements (see §3)
- Corporate campus footprints (the campus exists even if the corp is failing)
- Port infrastructure physical extent
- Road quality tier (narrow_unpaved through boulevard)
Economic-Sim-Dynamic (Appearance) — Updated at Runtime
These are driven by the economic simulation's rolling state:
prosperity_indexper district — the sim updates this; rendering reads it to choose tile variants- Building repair state — prosperity below threshold triggers decay tiles (ChunkMutations record explicit player damage; general decay is a rendering parameter)
- Active vs. ghost status of latent settlements (see §3)
- Corporate signage and branding presence — corp
health_metricfromcorp_financial_statedrives whether branded signage renders - Stockpile visibility in logistics districts — active trade → visible cargo tiles; depressed trade → empty yard tiles
- Lighting state — prosperity floor affects illumination (powered vs. dark windows)
The Key Insight: Prosperity Is a Render Parameter, Not a Tile Mutation
The most important implication of this split is that prosperity_index should NOT
be implemented as tile-level ChunkMutations for routine decay. It is a single float
per district. The renderer reads it and applies a decay probability to tile selection.
When prosperity drops from 0.6 to 0.3:
- The streets don't change
- The building footprints don't change
- The tile SELECTION changes (cracked pavement variant instead of clean; boarded window instead of lit; rust on the facade)
- This happens purely in the rendering path, with no world mutation
ChunkMutations remain reserved for player-caused or explicit-event damage — a specific building explosion, a player-placed barricade. General economic decay is a render parameter. This distinction matters for performance: prosperity changes don't generate millions of tile mutations.
The "Felled Forest → Farmland" Exception
The lead specifically mentioned this as a Layer 2 dynamic. It seems to contradict the layout-lock rule. Reconciliation:
"Felled forests → farmland" is regional-scale land use (Layer 2), not city-scale tile layout (Layer 4). The lock rule applies to city-internal geometry (streets, buildings). Regional land use — what biome category fills the hinterland between cities — CAN change as a Layer 2 update when economic conditions shift.
Concretely: if the agriculture corp expands, new farmland clears adjacent to existing cities. This is a land-use tile change at biome-cell resolution (large tiles covering hectares), not a building-by-building tile mutation. The distinction:
- Layer 2 regional land use: coarse-resolution, economics-driven, can update
- Layer 4 city street/building layout: fine-resolution, seed-locked, never changes
This is not a contradiction. It is a resolution boundary.
3. Dynamic Settlements in the Planet-Down Model
In Round 3, I proposed four types of economically-triggered dynamic settlements: mining camps, trade route waypoints, agricultural dispersed nodes, and shadow economy nodes. The planet-down model changes how these work.
The Latency Principle
Under the determinism rule, settlement POSITIONS must be seed-locked at generation time. But economic conditions change — a mine depletes, a trade route shifts. The reconciliation is latent settlements:
The generator places ALL economically plausible settlement positions at Layer 2. Whether each settlement is ACTIVE is determined by the economic sim's running state. An inactive settlement exists spatially — as ruins, as empty structures, as cleared ground — but it is dark, unmaintained, and depopulated.
This is economically accurate. Ghost towns exist. The buildings are there; no one lives in them. The road to the closed mine still exists.
How This Works Per Settlement Type
Mining camps:
- At Layer 2 generation: evaluate
corp_presenceagainst body. Every body witheconomic_role IN ('extraction', 'mining')and 2+ corps operatingmetallic_oreorrare_mineralsgets N seed-derived camp positions (N = corp count / 2). - Active status at runtime:
corp_financial_state.health_metric > 0.4for the operating corp → camp is active (populated, lit, maintained). Corp distressed or dissolved → camp becomes ghost state (dark, decayed render variants). - Why this is seed-locked: the geological deposit that caused the camp to be placed is geological fact, not economic contingency. The deposit doesn't move when the corp fails; the camp's position doesn't either.
Trade route waypoints:
- At Layer 2 generation:
atlas_roadsentries withpoint_count > 5(long roads) get a seed-derived waypoint at the geometric midpoint. - Active status:
gate_linkstrade flow proxy (nearby system still connected and populated) → active. If the terminal system is abandoned, the waypoint becomes a ruin. - Seed-locked because: the road was built; the physical clearing was made. Even abandoned trade routes leave ruins.
Agricultural dispersed nodes:
- At Layer 2 generation:
settlement_pattern IN ('dispersed', 'dispersed_rural')ANDeconomic_role = 'agricultural'→ scatter farm cluster positions at interval derived from1/economic_tier. - Active status:
corp_presencecorp withprimary_operation = 'agricultural_produce'health_metric → active or fallow. - Fallow farms look different from ghost towns: cleared land, overgrown structures, but the clearing and track remain. These are the richest "economic decay visible in the world" cases.
Shadow economy nodes:
- At Layer 2 generation:
system_fiscal.collection_efficiency < 0.6on the parent system → place one informal settlement adjacent to the largest atlas city, position seed-derived. - Active status: shadow viability is a structural condition, not a corp health metric. If collection_efficiency recovers (enforcement crackdown), the settlement is still there but its character changes (from busy informal market to quiet derelict cluster).
What This Means for the Layer 2 Implementation
Layer 2 must query the full economics dataset and produce:
- All atlas-city hinterland characterizations
- All latent dynamic settlement positions (with type tag and activating corp/condition)
- Regional land use grid (farmland, industrial fringe, wilderness, etc.)
None of this requires the economic sim to be running. It is all derived from the snapshot in systems.db at world generation time. The sim then drives the active/ghost flag as its rolling state changes.
4. Economic Data Per Cascade Layer — Full Mapping
Layer 1 — Empty World
| Field | Source table | Usage |
|---|---|---|
economic_role |
bodies | Biome probability prior (optional) |
planet_class |
bodies | Primary terrain generation input |
atmosphere |
bodies | Surface physics input |
surface_gravity |
bodies | Terrain height ceiling |
Economics is a soft advisory at this layer. The primary inputs are physical.
Layer 2 — Population Overlay
| Field | Source table | Usage |
|---|---|---|
city_id, center_row, center_col, population, kind |
atlas_cities | Settlement anchor positions and sizes |
economic_role |
bodies | Hinterland character |
settlement_pattern |
bodies | Population distribution mode |
industrial_corridor |
bodies | Corridor-specific infrastructure character |
economic_tier |
system_economy | Infrastructure density floor |
economic_base_primary/secondary |
system_economy | System-level hinterland bias |
gate_connections, gate_topology |
system_gates | Trade route intensity → transport density |
corp_id, location_id, primary_operation |
corp_presence | Corporate cluster positions |
behavioral_archetype |
corporations | HQ layout character |
road_* entries |
atlas_roads | Existing road network |
railroad_* entries |
atlas_railroads | Rail corridors |
collection_efficiency |
system_fiscal | Shadow node trigger condition |
health_metric |
corp_financial_state | Settlement active/ghost status at generation |
Dynamic settlement triggers are evaluated from this field set.
Layer 3 — City-Level Planning (zoning)
This is where the 10×9 matrix applies. The City-Level Planning layer receives a
CityGenerationContext (the Phase 3 → Phase 5 handoff struct from Round 3 consensus)
and produces a zoning map — land-use assignments per parcel, constrained by
topography from Layer 1 and infrastructure from Layer 2.
| Field | Source | Usage |
|---|---|---|
political_archetype |
atlas_cities (Phase 3 derived) | Zoning mix character |
prosperity_index |
atlas_cities (Phase 3 derived) | Base wealth gradient for zoning |
founding_orientation |
atlas_cities (Phase 3 derived) | Grid orientation, oldest district direction |
road_entry_directions |
atlas_road_edges (Phase 3 derived) | Commercial spine anchor |
surrounding_biome |
atlas_regional_biomes (Phase 3 derived) | Topographic zoning constraints |
district_count |
CityGenerationContext | How many zones to carve |
economic_role |
bodies | 10×9 weight matrix row selector |
distribution_index |
system_economy | Prosperity gradient shape (stratified vs. moderate) |
corp_presence count |
corp_presence (query) | Corporate district intensity |
behavioral_archetype |
corporations | District layout shape (Monopolist → homogeneous) |
shadow_economy_access |
corporations | Informal district placement trigger |
collection_efficiency |
system_fiscal | Informal district size multiplier |
currency_zone |
star_systems | Regulatory character (Commission presence) |
governance_type, dominant_faction |
system_factions | Administrative district character |
The 10×9 matrix in this context:
The matrix from Round 3 still applies at Layer 3, but the framing shifts from "assign district types" to "weight zoning categories." Topography from Layer 1 and infrastructure from Layer 2 interact with the matrix weights:
- Industrial zones: weighted toward flat terrain near logistics access (road/rail from Layer 2). If the only flat terrain is already occupied by the commercial spine, Industrial zones shift to city fringe.
- Residential zones: weighted against flood plains (Layer 1 biome data), toward terrain above the industrial elevation.
- LogisticsHub: always adjacent to road/rail entry points from Layer 2.
- Specialized (research): weighted toward elevated or secluded terrain.
The matrix provides the prior. Topography and infrastructure provide the constraints. The product is a zoning map that is economically motivated AND geographically sensible.
Prosperity gradient at Layer 3:
distribution_index = stratified → the zoning map assigns a monotonic prosperity
gradient across district types. Highest prosperity zones go at the end of the road
spine (historic center); lowest at the industrial fringe. This is the "Cities
Skylines" version of the formula I proposed in Round 3.
distribution_index = moderate → zones cluster in the 0.4–0.6 prosperity band with
less variation. The zoning map is flatter economically.
Layer 4 — Street-Level Rendering
Layer 4 receives the zoning map from Layer 3 and produces tile grids. Most of Layer 4 is seed-derived (street pattern, building footprints). Economics enters at two points:
At generation time (seed-locked):
| Field | Source | Usage |
|---|---|---|
bulk_class |
commodities (via corp_presence.primary_operation) | Building archetype (open yard vs. clean room vs. office) |
base_premium_multiplier |
brand_products | Landmark building height/prominence |
prosperity_index |
Per-district from Layer 3 | Initial tile variant selection |
scarcity_class |
brand_products | Frequency of branded signage tiles |
At runtime (dynamic, no tile mutation):
| Signal | Source | Render effect |
|---|---|---|
prosperity_index (updated by sim) |
Economic simulation | Tile variant selection (clean vs. decayed vs. ruined) |
corp_financial_state.health_metric |
Economic simulation | Corporate signage presence, maintenance appearance |
| Active/ghost settlement status | Economic simulation | Lighting, activity, population density rendering |
collection_efficiency |
Economic simulation | Shadow market visual density |
The runtime signals do not change tile positions. They change which tile variant renders
at each position. The implementation is: the rendering system reads prosperity_index
per district from the sim's current state and applies a decay curve to tile selection.
5. Data Quality Issues That Must Be Resolved Before Layer 3
I flagged two data quality issues in Round 3. They become blockers at Layer 3:
Issue 1: behavioral_archetype is mostly NULL
Of the 275 corporation rows I surveyed, behavioral_archetype is NULL on most records.
The fallback chain I proposed in Round 3 still applies:
behavioral_archetype → supply_chain_role → commodity tier derivation from
primary_operation.
But supply_chain_role is also sparse. The realistic near-term fallback is
commodity tier: a corp whose primary_operation = 'metallic_ore' is a Producer;
'financial_services' is an Intermediary; 'gate_components' is a Specialist.
This derivation should be added to import_economics.py as a backfill step — it can
fill NULL behavioral_archetype rows from commodity tier with a low confidence flag.
This is not required for the minimum viable slice but it enriches Layer 3 zoning
quality significantly.
Issue 2: scope field is mixed-type text
Corporation scope values are a mix of enum-ish text ("reach-wide", "local") and
prose descriptions ("GJ 338B local; north corridor secondary"). The generator cannot
reliably parse prose scope descriptions.
For Layer 3 corporate district intensity, I use corp_count as the proxy (not scope).
But for landmark building placement, I need to identify reach-wide HQ corps. A cleanup
pass on scope to normalize it to an enum (reach_wide | sector | system | local) would
be the right fix. Until then, the generator should treat any scope value that doesn't
exactly match a known enum string as system-tier.
6. Open Questions This Round Raises
The planet-down model introduces new questions that Round 3 didn't address:
OQ-R4-B1: Who owns the latent settlement active/ghost flag?
I've proposed that settlement active/ghost status is driven by the economic sim at runtime. But the sim needs to know which settlements are latent and what conditions activate them. Does this flag live:
- (a) In the generated world state as a sim-readable component on each settlement entity?
- (b) In a systems.db Phase 3 output table (settlement positions + trigger conditions)?
- (c) Computed entirely at runtime from corp presence + health?
Option (b) is cleanest — Phase 3 stores latent settlement positions and trigger
conditions, and the sim reads them alongside corp_financial_state. This integrates
naturally with the generate_regional.py pipeline.
OQ-R4-B2: Does the "felled forests → farmland" change generate ChunkMutations?
I argued above that this is a Layer 2 regional-scale change (large cells, biome-level),
not a Layer 4 tile mutation. But practically: when an agricultural corp expands and new
farmland appears, does this register as ChunkMutations in the save file, or as a biome
grid update to systems.db (requiring make regen-db)?
I lean toward: regional land use changes are coarse enough that they update a
regional_land_use column in the biome grid at runtime (not a full regen-db), and
the Layer 4 renderer reads the coarse grid to determine what large-scale tile type
fills undeveloped hinterland cells. This is not ChunkMutations — it's a different
resolution.
This needs an answer before Phase 3 and Phase 5 teams start building their respective land-use systems with incompatible resolution assumptions.
OQ-R4-B3: Does prosperity_index apply at district-level or block-level?
In Round 3 I defined it at district level (one float per district). Under the planet-down model, with topography-constrained zoning, a single district might span dramatically different terrain (the industrial hillside vs. the commercial valley floor). Should prosperity be a per-district scalar, or a per-block modifier?
Per-district is simpler and consistent with the Phase 5 architecture (DistrictSkeleton
has one prosperity_index). Per-block would enable richer decay gradients (a district
where prosperity collapses from the periphery inward). I recommend per-district for
now with a note that the field can be moved to BlockSkeleton in a later pass if the
single-value model proves too coarse.
OQ-R4-B4: How does distribution_index = stratified interact with topography?
In a stratified system, the wealth gradient is steep — executive district at 0.9, worker housing at 0.15. In the planet-down model, topography often already encodes wealth geography (hilltops are historically desirable; industrial lowlands are not).
Do we:
- (a) Let the topographic constraint drive the gradient independently of distribution_index?
- (b) Use
distribution_indexto set gradient magnitude and topography to set direction? - (c) Only apply distribution_index when topography is flat (no natural gradient)?
Option (b) is my recommendation: topography tells us WHICH end is high-prosperity; distribution_index tells us HOW STEEP the gradient is. A stratified city on a hill has elite zones at the top; a moderate city on a hill has mixed zoning across all elevations.
Summary: Requirements for the Brief
The brief should specify:
-
Economics enters weakly at Layer 1 (biome probability prior from economic_role — optional but recommended) and fully at Layer 2 (hinterland character, settlement placement, infrastructure density).
-
The determinism split is: Layer 4 street/building layout is seed-locked. Economic sim updates
prosperity_indexper district (render parameter, not tile mutation). Regional land use (Layer 2) CAN update at biome-cell resolution. -
Dynamic settlements are latent at generation: All economically plausible settlement positions are placed seed-derived at Layer 2. Active/ghost status is driven by economic sim. Ghost settlements exist spatially — they just look abandoned.
-
The 10×9 matrix applies at Layer 3 (City-Level Planning), modified by topographic constraints from Layer 1 and infrastructure access from Layer 2. The matrix provides the zoning prior; terrain provides the spatial constraints.
-
The minimum economics read set for Layer 3 is the same 6-field set from Round 3, now delivered via the
CityGenerationContextstruct rather than direct DB queries at generation time. This is already captured in D-C12. -
prosperity_indexis a Layer 3 output (derived from economics data, stored in CityGenerationContext / atlas_cities) and a Layer 4 runtime parameter (the sim updates it; the renderer reads it for tile variant selection). -
Data quality pre-work:
import_economics.pyshould add abehavioral_archetypebackfill pass from commodity tier beforegenerate_regional.pyruns.scopefield normalization is recommended but not blocking.