--- title: "Round 3 — Burnelli-Sheldon: Economics as Generator Input" description: "Mapping systems.db economic fields to spatial generator parameters across all scales" type: workshop status: active workshop: generation-cascade agent: burnelli-sheldon round: 3 created: 2026-04-30 --- # Round 3 — Burnelli-Sheldon: Economics as Generator Input The economics layer is built. The question is what the spatial pipeline should read from it. My job here is to be the bridge: not to redesign the economics model, but to map its concrete, queryable fields to concrete, actionable generator parameters. I'll work scale by scale, then address differentiation, corporate footprint, dynamic settlements, and what the simulation needs back. --- ## Preliminary: What Economic Data Actually Exists Before prescribing anything, I surveyed what is actually in systems.db. The picture is richer than the schema alone suggests. **Per inhabited body (bodies table, 275 inhabited rows):** - `economic_role`: 10 distinct values — `manufacturing`, `agricultural`, `extraction`, `transit`, `research`, `commercial`, `service_mixed`, `mining`, `frontier`, `energy` - `settlement_pattern`: 15+ values — `urban_concentrated`, `dispersed`, `dispersed_rural`, `domed`, `underground_concentrated`, `cave`, `village_network`, `town_network`, etc. - `industrial_corridor`: `MVG`, `Gate_Corp`, `DSMC`, `Prometheus`, `Agricultural_Syndic` (null for many bodies — absence is meaningful) - `population` (range: ~800 to 8.5B), `planet_class`, `atmosphere`, `surface_gravity` **Per system (system_economy, system_factions, system_culture):** - `economic_tier` (1–5), `economic_base_primary/secondary`, `distribution_index` (stratified/moderate) - `currency_zone`: TRACTUS_PRIMARY | MARK_PRIMARY | MIXED - `gate_energy_connected`: boolean - `governance_type`, `dominant_faction`, `primary/secondary_fault_line` - `cultural_register`, `ambient_anxiety`, `active_situation` **Corporations (275 rows, `corp_presence` cross-reference):** - `scope`: reach-wide, sector, system, local (many nulls — needs cleanup) - `behavioral_archetype`: Monopolist | Distributor | Producer | Specialist | Cooperative | Intermediary - `supply_chain_role`, `shadow_economy_access` - `headquarters_system`, `headquarters_body` **Corp presence per location:** The `corp_presence` table records which corps operate at each body/station with `primary_operation` (commodity). Locations range from 1 corp (frontier outpost) to 13 corps (GJ380c/Lendel — the Groombridge Settlement House hub). This distribution is the single most useful signal for district composition. **Commodities (36 types) and production chains (21 chains):** `production_ubiquity` (monopolistic → ubiquitous) and `location_bound` (currently all 0, but the field is load-bearing for future extractive operations). **Brand products:** `brand_category`, `scarcity_class`, `base_premium_multiplier`, `brand_tier` (halo/volume). These are spatial differentiators — halo brands require physical presence; volume brands are ubiquitous. **What is NOT yet queryable:** `behavioral_archetype` is mostly null. `scope` field on corporations is a mixed bag (some are text prose, not enum values). The generator will need to gracefully handle nulls on both. --- ## 1. Economic Data by Scale ### Regional Scale (planet → city hinterlands) Regional subdivision is essentially hinterland characterization — what lies between cities on a body. Economic signals at this scale: **Primary input:** `bodies.economic_role` → hinterland type | economic_role | Hinterland character | What fills the space | |---|---|---| | agricultural | Farmland belts, processing nodes | Field tiles, irrigation channels, silos | | extraction / mining | Resource zones, access corridors | Open pits, pipeline corridors, camp clusters | | manufacturing | Industrial fringe, supply chains | Warehousing strips, rail freight yards | | transit | Corridor infrastructure | Road/rail density, relay stations | | research | Campus periphery, exclusion zones | Restricted zones, observatory sites | | commercial | Suburban sprawl, trade routes | Mixed low-density blocks, markets | | service_mixed | Residential spread | Generic residential, civic amenities | **Secondary input:** `atlas_roads`, `atlas_railroads` — road and rail count/density on the body determines whether hinterland is connected or isolated. A body with 5+ rail lines has industrial corridors linking cities; one with no rail has regional isolation. **Tertiary input:** `system_economy.economic_tier` — tier 1–2 bodies have sparse hinterland infrastructure regardless of `economic_role`. A tier-1 extraction world looks like isolated mining camps; a tier-4 extraction world (Witwatersrand, GJ3522c) has the industrial capacity to fill the hinterland. **Recommendation:** The regional hinterland generator needs two parameters per body: 1. `HinterlandType` — derived from `economic_role` 2. `InfrastructureDensity` (0.0–1.0) — derived from `(economic_tier + rail_count + road_count) / normalization` ### City Scale (city → district decomposition) The D-C4 decomposition formula (district count from population) is correct. The economic question is: once you have N districts, what types are they? **The mapping I propose is three-column: economic_role × settlement_pattern × distribution_index:** #### economic_role → DistrictType distribution I'll express this as a probability weight vector across the 9 confirmed DistrictType values from Round 1/2 notes (Residential, Commercial, Industrial, Administrative, LogisticsHub, Entertainment, MixedUse, Transit, Specialized): | economic_role | Res | Com | Ind | Adm | Log | Ent | Mix | Trn | Spe | |---|---|---|---|---|---|---|---|---|---| | manufacturing | 25 | 5 | 35 | 5 | 20 | 2 | 5 | 3 | 0 | | agricultural | 30 | 15 | 5 | 10 | 25 | 3 | 10 | 2 | 0 | | extraction | 20 | 5 | 30 | 5 | 30 | 0 | 5 | 5 | 0 | | transit | 10 | 20 | 5 | 5 | 25 | 10 | 15 | 10 | 0 | | research | 20 | 5 | 5 | 15 | 5 | 5 | 10 | 0 | 35 | | commercial | 15 | 35 | 5 | 5 | 10 | 15 | 15 | 0 | 0 | | service_mixed | 25 | 20 | 5 | 10 | 5 | 15 | 20 | 0 | 0 | | mining | 20 | 5 | 25 | 0 | 35 | 0 | 10 | 5 | 0 | | frontier | 35 | 10 | 10 | 5 | 20 | 5 | 15 | 0 | 0 | | energy | 10 | 0 | 20 | 5 | 30 | 0 | 5 | 5 | 25 | These are not final tuning targets — they are the prior that seed generation should use before corp-presence and governance modifiers are applied (see §3 below). #### settlement_pattern modifier `settlement_pattern` is a strong secondary signal. It doesn't change DistrictType distribution — it changes *how districts are arranged*: - `urban_concentrated`: compact grid, high-density blocks, minimal green space - `dispersed` / `dispersed_rural`: districts smaller and more separated, low-density building tiles, road-separated rather than contiguous - `domed`: maximum 1 district (hardcoded — entire settlement is one pressurized dome); DistrictType is always Specialized - `underground_concentrated` / `cave`: vertical stacking matters; single large district with strong perimeter treatment (Checkpoint or Walled) - `village_network` / `town_network`: each "city" entry in atlas represents a network of small settlements rather than one city — decompose into many Residential + small Commercial; no Industrial districts unless industrial_corridor is set #### distribution_index → prosperity gradient `system_economy.distribution_index` gives the city-level prosperity shape: - `stratified`: prosperity_index spans full range. A stratified manufacturing capital has elite executive districts (0.8+) adjacent to worker housing (0.2). This creates visible class geography. - `moderate`: prosperity_index clusters around 0.4–0.6. The city is more economically homogeneous — no dramatic wealth contrasts. Concrete formula: if `distribution_index = stratified`, assign prosperity_index as `0.1 + (district_rank / N) * 0.8` where district_rank is sorted by DistrictType prestige (Administrative > Specialized > Commercial > Entertainment > Residential > MixedUse > Industrial > LogisticsHub > Transit). If `moderate`, all districts draw from N(0.5, 0.1) clipped to [0.2, 0.8]. ### District Composition Once district types are assigned, the generator needs to fill each district. Economic data drives two things here: **tile density** and **building character**. **Tile density from economic_role + DistrictType:** A Commercial district on a manufacturing world differs from the same DistrictType on a transit hub. The former is a small company store; the latter is a major trading floor. Use this rule: `base_density = district_type_density[DistrictType] × role_multiplier[economic_role]` Role multipliers (examples): transit on Commercial = ×1.8; manufacturing on Commercial = ×0.5; research on Specialized = ×1.5; agricultural on LogisticsHub = ×1.4. **Commodity signal → building archetype:** The `corp_presence.primary_operation` field tells us what commodity each corp at this location primarily deals in. Cross-referencing with `commodities.bulk_class`: | bulk_class | Physical form → building archetype | |---|---| | bulk | Open yards, conveyor structures, grain silos | | liquid | Tank farms, pipe corridors | | precision | Clean-room buildings, elevated access points | | perishable | Cold storage blocks, loading docks with shade cover | | non_physical | Office towers, transmission arrays, no loading dock | | standard | Generic warehouse / distribution | This mapping is queryable: `SELECT cp.primary_operation, c.bulk_class FROM corp_presence cp JOIN commodities c ON cp.primary_operation = c.commodity_id WHERE cp.location_id = ?` ### Infrastructure: Roads, Rail, Ports **Road quality:** `economic_tier + settlement_pattern → road_quality` | tier | urban_concentrated | dispersed | domed | |---|---|---|---| | 1 | narrow_unpaved | tracks | internal_only | | 2 | narrow_paved | gravel_road | internal_only | | 3 | medium_paved | narrow_paved | internal_only | | 4 | boulevard | medium_paved | internal_only | | 5 | boulevard | boulevard | N/A | **Rail placement:** Query `atlas_railroads` — if a body has railroad entries, the generator should anchor rail yards in LogisticsHub districts and place station tiles in Transit districts. No authoring needed; the atlas already marks rail presence. **Port/spaceport location:** Transit and LogisticsHub districts should be placed at the city edge closest to the body's orbital station (if `stations.orbits_body_id` matches). If no station exists, spaceport tiles go at the district with highest `logistics` weight. Port capacity is a direct read from `stations.docking_class`. --- ## 2. Economic Differentiation: Concrete Examples Theory is cheap. Let me walk through three real bodies in systems.db to show how economic fields produce spatially distinct results. ### Case A: Tributarium (GJ251c/city_0) — Manufacturing Capital ``` body.economic_role = manufacturing body.settlement_pattern = urban_concentrated body.industrial_corridor = Gate_Corp body.population = 5B system.distribution_index = stratified (GJ 251 — inferred from tier 5) system.economic_tier = (reached via GJ251 system_economy) corp_presence at GJ251c = gate-corporation (HQ system), kalten-assembly, precision-works... ``` **Generator output:** - District composition: ~35% Industrial, ~20% LogisticsHub, ~25% Residential, ~5% Administrative - Prosperity: sharply stratified — Gate Corp executive district at 0.9, worker housing at 0.15 - Gate Corp `behavioral_archetype = Monopolist` → one dominant industrial district type; consistent building footprint - `industrial_corridor = Gate_Corp` → gate component manufacturing tiles dominate Industrial districts - `gate_components` commodity: `bulk_class = precision` → clean-room buildings, not open yards - Road network: tier 5 → boulevards; but industrial zones have dedicated freight lanes ### Case B: Bluebank (GJ3522c/city_0) — Extraction Capital ``` body.economic_role = extraction body.settlement_pattern = urban_concentrated body.industrial_corridor = DSMC body.population = 1.5B system.distribution_index = stratified corp_presence = dsmc (DSMC HQ system) ``` **Generator output:** - District composition: ~30% Industrial, ~30% LogisticsHub, ~20% Residential, ~5% Administrative, ~5% Transit - `metallic_ore` + `rare_minerals` → bulk_class = bulk → open pit adjacency, conveyor structures, slag heap tiles - DSMC = reach-wide Monopolist → single employer city; company housing blocks (uniform, low prosperity) - No Entertainment districts. Very low prosperity (worker housing at 0.15–0.25) - LogisticsHub → ship loading yards (bulk cargo configuration), railway terminus **Contrast with Tributarium:** Both are industrial. Tributarium has precision manufacturing (implants, gate components) → clean-room aesthetic, corporate towers. Bluebank has raw extraction (ore, rare minerals) → open yard aesthetic, functional brutalism. The aesthetic difference is entirely derivable from `production_ubiquity` and `bulk_class`. ### Case C: Strata (GJ280Ad/city_0) — Service Mixed Capital ``` body.economic_role = service_mixed body.settlement_pattern = urban_concentrated body.industrial_corridor = NULL body.population = 1.8B system.distribution_index = stratified corp_presence = rare-vein-survey (HQ), adams-ford-publishing (HQ) ``` **Generator output:** - District composition: ~25% Residential, ~20% Commercial, ~10% Administrative, ~15% Entertainment, ~20% MixedUse - No industrial corridor → no dominant building archetype; district types are heterogeneous - Two reach-wide HQ corps → two landmark buildings (publisher HQ, survey company HQ) - `non_physical` services (financial, legal, entertainment) → office towers, no loading docks - `distribution_index = stratified` + `service_mixed` → gentrified commercial district (prosperity 0.75) adjacent to mid-tier residential (prosperity 0.45) **Contrast with Bluebank:** Strata has negligible Industrial districts. Its LogisticsHub equivalents handle information rather than cargo — server banks, archive towers. The physical infrastructure (roads, buildings) looks wealthy but not industrial. --- ## 3. The Corporation Footprint Corporations are the most underutilized signal in the current bridge-gap. The `corp_presence` table is already populated and queryable. Here is how it maps to space. ### Corporate Presence Tier Derive a `CorpPresenceTier` per city from the corp_presence query: ```sql SELECT COUNT(DISTINCT cp.corp_id) as corp_count, COUNT(DISTINCT CASE WHEN co.scope = 'reach-wide' THEN cp.corp_id END) as halo_count, SUM(CASE WHEN co.headquarters_system = b.system_id THEN 1 ELSE 0 END) as hq_count FROM corp_presence cp JOIN corporations co ON cp.corp_id = co.corp_id JOIN bodies b ON cp.location_id = b.body_id WHERE cp.location_id = ? ``` | corp_count | halo_count | tier | District effect | |---|---|---|---| | 1–2 | 0 | Company Town | Single employer → uniform district character | | 3–5 | 0–1 | Local Economy | Mixed district types, small commercial | | 6–10 | 1–2 | Regional Hub | Commercial district expands, entertainment emerges | | 11+ | 3+ | System Nexus | Full district variety, landmark buildings | GJ380c (Lendel) has 13 corps including 2 reach-wide HQs → System Nexus. GJ1111b has 5 corps, 0 HQs → Local Economy. This difference is real and pre-populated. ### HQ Presence → Corporate District When `corporations.headquarters_system = atlas_city.body.system_id` AND `headquarters_body = atlas_city.body_id` (or close enough), that city gets a corporate district. Rules: - One corporate district per reach-wide HQ corp at this city - The corporate district's DistrictType is Administrative (if Monopolist) or Commercial (if Distributor/Specialist) - `base_premium_multiplier` from brand_products by this corp → scales the landmark building height (halo ×18 brands get the skyline) ### Behavioral Archetype → District Shape Where `behavioral_archetype` is populated: | archetype | District character | |---|---| | Monopolist | Large uniform blocks, single building type, minimal commercial variety | | Distributor | Dense transit + logistics districts; loading infrastructure heavy | | Producer | Industrial districts with process-flow layout (input → process → output) | | Specialist | One Specialized district with restricted perimeter; premium prosperity | | Cooperative | Residential more integrated with commercial; lower wealth disparity | | Intermediary | Commercial + financial services; mixed-use preferred | Where `behavioral_archetype = NULL` (most corps currently), fall back to `supply_chain_role` if populated, or derive from `primary_operation` commodity tier. ### Shadow Economy `corporations.shadow_economy_access = 1` → this location has a shadow market. Physical manifestation: one MixedUse district at the city fringe with reduced perimeter treatment (Open instead of Gated), elevated tile decay (prosperity 0.15–0.25), and elevated building density (informal construction = wasted space is illegal). `system_fiscal.collection_efficiency < 0.7` at the system level → amplify shadow zone size by `(1 - collection_efficiency) × 2` as a district probability weight modifier. --- ## 4. Dynamic Settlements (Off-Atlas) The atlas marks cities. But economic pressure creates settlements the atlas doesn't know about. These are procedural — generated from economic conditions, not authored. ### Trigger Conditions **Mining camps** (highest frequency): - Condition: `bodies.economic_role IN ('extraction', 'mining')` AND body has `corp_presence` entries with `primary_operation IN ('metallic_ore', 'rare_minerals', 'lattice_grade_material')` - Generator action: place 1 satellite settlement per 2 qualifying corps, at randomized distance from nearest atlas city (15%–40% of map scale) - Settlement type: single LogisticsHub district + minimal Residential; no Commercial - Size: 1 district, population ~1,000–50,000 **Trade route waypoints**: - Condition: `atlas_roads.kind IN ('highway', 'commercial')` with point_count > 5 (long road connecting two distant cities) - Generator action: place a waypoint settlement at the geometric midpoint of roads longer than a threshold - Settlement type: Transit district (fueling stop, overnight), small Commercial - Size: 1 district, population ~500–5,000 **Agricultural dispersed nodes**: - Condition: `bodies.settlement_pattern IN ('dispersed', 'dispersed_rural')` AND `bodies.economic_role = 'agricultural'` - Generator action: scatter farm clusters at interval proportional to `1/economic_tier` (lower tier = fewer, sparser farms) - Each farm cluster: 1 Residential district + 1 LogisticsHub, no perimeter treatment - Size: sub-district scale **Shadow economy nodes**: - Condition: `system_fiscal.collection_efficiency < 0.6` AND system has shadow-viable corps in `corp_presence` - Generator action: place 1 informal settlement per system, adjacent to a major city but not on its district grid - Settlement type: MixedUse fringe; elevated decay, low prosperity ### What the Generator Needs Per Dynamic Settlement Unlike atlas cities, dynamic settlements do not have authored names or economic roles. The generator should derive: - `settlement_seed = child_seed(body_seed, trigger_type_hash + location_hash)` — FNV-1a per D-010 - `economic_role` = inferred from trigger condition (mining camp → extraction, etc.) - `prosperity_index` = base 0.15 for camps; 0.25–0.4 for waypoints - `district_count` = always 1 - Name = procedural suffix of nearest atlas city ("Bluebank Camp 3", "Kallast Waypoint") --- ## 5. What the Economic Simulation Needs Back from the Spatial World This is the other side of the bridge. Once districts exist, the simulation's trade cost model gets better data. ### Transport Distance The D-C4 formula places districts at city-local coordinates `(col × 512, row × 512)`. After generation, the simulation needs: ``` city_transport_cost_modifier(from_city_id, to_city_id) → f32 ``` Derived from: `atlas_roads` + `atlas_railroads` point_count between two cities on the same body. Cities connected by rail get a 0.4× cost multiplier (per D-178 gate edge 5–12%); road-only cities get 1.0×; no infrastructure gets 2.5×. This does not require the spatial world to be generated — it's derivable from atlas data alone. The generator does not need to feed this back; it's a pre-generation query. ### Port Capacity `stations.docking_class` (major/standard/restricted/none) is already in systems.db. After generation, the port district's physical size (tile count in Transit districts) should be reported back as `effective_port_size: u32`. This feeds the trade flow capacity constraint: a Restricted port can't handle bulk cargo regardless of economic_role. Concrete mapping: - `docking_class = major` → Transit district tile budget = 256 tiles; throughput_coefficient = 1.0 - `docking_class = standard` → 128 tiles; throughput_coefficient = 0.5 - `docking_class = restricted` → 32 tiles; throughput_coefficient = 0.2 - `docking_class = none` → no Transit district; throughput_coefficient = 0.0 ### Infrastructure Quality `settlement_pattern` + `economic_tier` → road quality (derived above). The simulation should read `road_quality: RoadQuality` per body as a trade cost multiplier: | road_quality | intra-city cost multiplier | |---|---| | narrow_unpaved | 3.0 | | gravel_road | 2.0 | | narrow_paved | 1.5 | | medium_paved | 1.0 | | boulevard | 0.7 | This is already derivable from `economic_tier` + `settlement_pattern` without running the generator — another pre-generation query, not a feedback dependency. ### What Actually Requires Generator Feedback Most simulation needs are pre-generation derivable. The only fields that genuinely require post-generation reporting: 1. **Effective port tile count** — physical district layout determines actual cargo throughput, not just declared docking class 2. **Corp district allocation** — which DistrictType a given corp actually occupies, once the district assignment algorithm runs (needed for corp financial state updates) 3. **Shadow economy footprint** — whether a shadow zone was generated, and its prosperity floor (informs `collection_efficiency` updates) These are three narrow feedback fields, not a broad data exchange. The simulation should not depend on generator re-runs for routine tick processing. --- ## Responses to Round 2 Open Questions ### OQ-R2-1: Should `prosperity_index` be in the minimum slice? **Yes.** And here is the economic argument for inclusion rather than deferral: `prosperity_index` is not a decorative field — it is a readability signal derived entirely from data we already query: `distribution_index` + `economic_role` + `economic_tier`. The computation is trivial (one formula, no authoring). The cost of deferral is not "decorative refinement later" — it is "all districts look equally prosperous until a retrofit pass." Retrofit changes Phase 2 tile generation. Include it in Stage 1 classification as a derived field; it costs 0.5 dev-days. Concrete derivation formula: ``` base_prosperity = economic_tier / 5.0 role_modifier: manufacturing=0.0, extraction=-0.1, research=+0.15, service_mixed=+0.1, commercial=+0.05, agricultural=-0.05, transit=-0.05, frontier=-0.2 if distribution_index = stratified: district_prosperity[i] = (base + role_modifier) + (district_prestige_rank(i) - 0.5) * 0.7 else: # moderate district_prosperity[i] = clamp(N(base + role_modifier, 0.1), 0.2, 0.8) ``` ### OQ-R2-2: Should `political_archetype` be a formal authored field? **Derive it; do not author it separately.** From an economist's perspective, this is the classic "add a variable or derive it from existing ones" tradeoff. The answer is always: derive unless you have reason to believe the derivation fails. Derivation rules: - `corp_presence` where one `behavioral_archetype = Monopolist` corp accounts for >60% of corps → `CompanyTown` - `governance_type = assembly` AND `commission_presence` high → `AdminCapital` - `economic_role = transit` AND `corp_count > 6` → `FreePort` - `primary_fault_line` AND `secondary_fault_line` both populated and active → `Contested` - Else → `OrganicGrowth` If a named city fails this derivation in a way that's clearly wrong (the lead decides this), add a one-field override in `atlas_cities` schema. But the starting position should be: trust the data. ### OQ-R2-5: Naming register lookup table — before Phase 2? **After walkable.** This is a pure naming question that has zero effect on tile layout. The register taxonomy is correct and useful; the lookup table determines what *kind* of name a district gets, not what tiles it contains. It can be authored once a district exists and is legible. Defer. --- ## D-Record Candidates ### D-C9 (proposed by Burnelli-Sheldon): Economic Fields → Generator Parameter Mapping The spatial generator's primary input from systems.db is the following read-only query set, executed once per city at generation time: ```sql -- All queries execute against server/data/systems.db (read-only) -- City economic context SELECT b.economic_role, b.settlement_pattern, b.industrial_corridor, b.population, b.planet_class, b.atmosphere FROM bodies b JOIN atlas_cities ac ON ac.body_id = b.body_id WHERE ac.city_id = ?; -- System-level modifiers SELECT se.economic_tier, se.distribution_index, sf.dominant_faction, sf.governance_type, ss.currency_zone, ss.gate_energy_connected FROM system_economy se JOIN system_factions sf ON se.system_id = sf.system_id JOIN star_systems ss ON se.system_id = ss.system_id WHERE se.system_id = (SELECT system_id FROM bodies b JOIN atlas_cities ac ON b.body_id = ac.body_id WHERE ac.city_id = ?); -- Corporate presence at this body SELECT co.corp_id, co.behavioral_archetype, co.scope, co.shadow_economy_access, cp.primary_operation, c.bulk_class FROM corp_presence cp JOIN corporations co ON cp.corp_id = co.corp_id LEFT JOIN commodities c ON cp.primary_operation = c.commodity_id WHERE cp.location_id = (SELECT body_id FROM atlas_cities WHERE city_id = ?); ``` This data is sufficient to derive: - `DistrictType` distribution weights per city - `prosperity_index` per district - `CorpPresenceTier` and corporate district placement - `political_archetype` (derived, not authored) - `perimeter_treatment` per district - Infrastructure quality parameters - Dynamic settlement trigger conditions ### D-C10 (proposed by Burnelli-Sheldon): economic_role → DistrictType Weight Table The mapping table in §1 above (manufacturing → 35% Industrial, etc.) should be a confirmed D-record, not just a design note. It is the foundational prior that all district composition derives from. Corp-presence modifiers apply on top of it. The table should live in Rust as a const array, keyed by `EconomicRole` enum. It can be tuned later, but a locked canonical default prevents every sprint from relitigating the same question. --- ## Summary: The Minimum Read Set If the generator can only read one thing from systems.db per city, it should read `bodies.economic_role`. Every other field is a refinement multiplier. The full minimum read set for a differentiated Phase 1 district skeleton: 1. `bodies.economic_role` — district type distribution 2. `bodies.settlement_pattern` — district layout and density mode 3. `system_economy.economic_tier` — infrastructure quality and wealth floor 4. `system_economy.distribution_index` — prosperity gradient shape 5. `corp_presence` count at this body — corporate district intensity 6. `corporations.headquarters_system` match — HQ landmark flag Everything else (behavioral_archetype, shadow economy, bulk_class, brand premiums, currency zone) is Phase 2 enrichment — meaningful, but not required for the minimum walkable world. The pipeline will produce economically differentiated worlds on those six fields alone. Everything else makes them richer.