Files
settled-reach/docs/workshops/generation-cascade/burnelli-sheldon-round4.md
T
jpmschweitzerandClaude Opus 4.6 42ee1f0a0e docs(workshops): generation cascade workshop — 4 rounds, D-194 through D-218
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>
2026-05-03 20:18:17 +02:00

25 KiB
Raw Blame History

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_index per 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_metric from corp_financial_state drives 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_presence against body. Every body with economic_role IN ('extraction', 'mining') and 2+ corps operating metallic_ore or rare_minerals gets N seed-derived camp positions (N = corp count / 2).
  • Active status at runtime: corp_financial_state.health_metric > 0.4 for 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_roads entries with point_count > 5 (long roads) get a seed-derived waypoint at the geometric midpoint.
  • Active status: gate_links trade 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') AND economic_role = 'agricultural' → scatter farm cluster positions at interval derived from 1/economic_tier.
  • Active status: corp_presence corp with primary_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.6 on 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:

  1. All atlas-city hinterland characterizations
  2. All latent dynamic settlement positions (with type tag and activating corp/condition)
  3. 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.40.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_archetypesupply_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_index to 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:

  1. 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).

  2. The determinism split is: Layer 4 street/building layout is seed-locked. Economic sim updates prosperity_index per district (render parameter, not tile mutation). Regional land use (Layer 2) CAN update at biome-cell resolution.

  3. 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.

  4. 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.

  5. The minimum economics read set for Layer 3 is the same 6-field set from Round 3, now delivered via the CityGenerationContext struct rather than direct DB queries at generation time. This is already captured in D-C12.

  6. prosperity_index is 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).

  7. Data quality pre-work: import_economics.py should add a behavioral_archetype backfill pass from commodity tier before generate_regional.py runs. scope field normalization is recommended but not blocking.