Files
settled-reach/docs/workshops/planet-down-cascade/burnelli-sheldon-round2.md
T
jpmschweitzerandClaude Opus 4.6 b9fd75b840 docs(workshops): planet-down cascade workshop + misc stray files
Planet-down cascade workshop (3 rounds, 5 agents): layer-by-layer
generation from empty world through population overlay, city planning,
and street rendering. Includes consultant review by Troblum.

Also commits: pre-Sprint-35 DB backup, Claude Code team-mode tmux
test log (team-test.md).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-03 20:18:30 +02:00

31 KiB
Raw Blame History

title, description, type, status, workshop, agent, round, created
title description type status workshop agent round created
Round 2 — Burnelli-Sheldon: Economics Algorithm Proposals Full specification of the three-component district mix model, attractor-matching compatibility matrix, latent settlement generalization under fully generative placement, and TerritorialStatus threshold convergence. workshop active planet-down-cascade burnelli-sheldon 2 2026-05-01

Round 2 — Burnelli-Sheldon: Economics Algorithm Proposals

This document provides concrete algorithm specifications for the four economics assignments from the Round 1 notes. No positions are hedged — these are proposals for convergence.


1. Three-Component District Mix Model — Full Specification

1.1 Component 1: Population Tier Guarantees

The population tier guarantees establish a mandatory district set that is allocated before the economic role weight table distributes remaining slots. These are derived from the sub-settlement hierarchy in the brief, mapped to the D-C4 district count formula.

Guaranteed district set by population tier:

Sub-settlement tier Population Guaranteed types Notes
Waypoint < 50 1× Mixed All functions fused into one district
Outpost 50999 Residential + Mixed Two functional zones
Town 1,0009,999 Residential + Commercial Entertainment present inside Commercial character
City 10,00099,999 Residential + Commercial + Entertainment Dedicated entertainment justified by population
Large City 100,000+ Residential + Commercial + Entertainment + Administrative Bureaucratic complexity requires dedicated admin

BS-Q1 resolution (9,999-person Town without dedicated Entertainment): Confirmed plausible. A Town's Commercial district contains the entertainment function — the pub, the social hall, the gambling den — as a character property of that district. When the settlement grows to City tier (10,000+), specialization makes a dedicated Entertainment district economically viable. The function always exists; the dedicated district is the marker of scale.

WorldTier exception — domed/cave settlements: Always 1 district regardless of population. Single district type = Mixed, carrying all functions.

Capital city bonus: +1 district slot (as per D-C4 rule) distributed by the weight table after guarantees are placed.

When D-C4 count is less than the guaranteed set size:

D-C4 can produce fewer total district slots than the guaranteed set requires. When this occurs, the overflow guaranteed types collapse into Mixed:

if D_total < len(guaranteed_set):
    collapse_to_mixed():
        1 district if D_total == 1  →  type = Mixed (all functions)
        2 districts if D_total == 2  →  Residential + Mixed (remaining functions)

This correctly handles outposts with D-C4 = 1 that the formula would label Passage-tier.

1.2 Component 2: Economic Role Multiplier Table

The weight table distributes the remaining district slots after the guaranteed set is placed. It also applies to the guaranteed set as a character modifier for which variant of each type the settlement gets — but it does not remove guaranteed types.

No weight is ever zero. Minimum value is 3 (not 0.2 as I wrote in Round 1 — I converted to integer weights summing to 100 per row for implementation clarity). This means every district type has some non-zero probability of appearing in any settlement's non-guaranteed slots, while the character differences between economic roles remain pronounced.

Full weight table (integer weights, each row sums to 100):

economic_role Res Com Ind Adm Log Ent Mix Trn Spe
manufacturing 18 8 30 6 18 5 8 5 2
agricultural 22 12 5 10 20 5 15 5 6
extraction 16 7 28 4 24 5 9 5 2
transit 10 18 5 5 20 12 14 14 2
research 16 6 5 14 5 7 10 3 34
commercial 14 30 5 6 10 14 14 5 2
service_mixed 20 18 5 10 6 14 18 7 2
mining 16 7 22 3 28 6 9 7 2
frontier 26 10 10 5 18 8 16 5 2
energy 10 3 18 6 24 3 6 6 24

How to read this table:

The mining row has Log = 28, Ind = 22 as dominant weights. After placing guaranteed Residential + Commercial (at Town) or + Entertainment (at City), remaining slots almost always produce Industrial and Logistics districts. Entertainment weight = 6 means occasionally a second Entertainment appears in a large mining city — a second drinking district for a city that grew big enough to support it. This is correct.

The energy row has Spe = 24, Log = 24 as dominant. Energy installations need Specialized facilities (reactors, control centers, research wings) and Logistics (heavy transport for fuel and output). Entertainment = 3 and Commercial = 3 are minimal but non-zero — large energy cities have a company canteen and a gym, which earns each a district representation at high enough population.

BS-Q3 resolution (energy Entertainment weight): At Outpost/Town scale (1-2 districts), energy settlements don't get a dedicated Entertainment slot from the weight table — Entertainment is present inside the Mixed/Commercial district instead. At City scale (10,000+), the guaranteed Entertainment takes effect, producing a dedicated district with rough-canteen character. The weight = 3 only applies to additional Entertainment districts beyond the guarantee, which are rare. This is the correct behavior.

Political archetype modifiers stacked on top: These remain as described in the brief. They're additive modifiers to the weight table row before normalization:

CompanyTown:   Adm -= 10, Ind += 10, Log += 5, Res += 5  (production-heavy, thin governance)
AdminCapital:  Adm += 20, Ent += 5, Spe += 5, Ind -= 15  (governance-heavy, civic services)
FreePort:      Com += 15, Trn += 10, Mix += 5, Adm -= 15  (commerce-heavy, light governance)
Contested:     no modifier (both political forces fight over what to build; neither wins)
OrganicGrowth: Mix += 15, Res += 10, Ind -= 10, Adm -= 5  (unplanned, service-led growth)

1.3 Component 3: Settlement Age Modifier

Where founding_age_years comes from:

For named cities: bodies.founding_age_years (INTEGER, already in the bodies schema). For sub-settlements without a direct bodies row, derive from parent body age:

Sub-settlement type Derived age
Mining camp max(5, parent_body.founding_age_years - 20)
Trade waypoint max(5, parent_body.founding_age_years / 3)
Agricultural node max(5, parent_body.founding_age_years - 10)
Shadow node 10 (always nascent — informal, lacks permanence by definition)

BS-Q2 resolution: Age modifier applies only at Backwater tier and above. Waypoint and Passage settlements are too structurally simple to differentiate by age; they get nascent character regardless of founding date.

Age bracket classification:

founding_age_years Age bracket Name
049 nascent Raw production focus
50149 young Functional
150349 established Differentiated
350+ mature Layered

What age bracket affects:

Age modifies the character class of each district. This propagates to three DistrictSkeleton fields:

  • perimeter_treatment: nascent → Open; young → Fenced; established → Walled; mature → variable (can be any)
  • density_pct of commercial/entertainment blocks: nascent = 0.40.6; young = 0.50.7; established = 0.60.8; mature = 0.60.9 (wide range — old cities have both dense cores and thin outskirts)
  • Content system character selector: nascent entertainment = "bare supply function"; mature entertainment = "institutional legacy"

What age bracket does NOT affect: District count. District type. Prosperity baseline. These are determined by Components 1 and 2 alone.

Age × WorldTier cap interaction:

effective_age_bracket = 
    if world_tier in (Waypoint, Passage): nascent  # always
    elif founding_age_years < 50:          nascent
    elif founding_age_years < 150:         young
    elif founding_age_years < 350:         established
    else:                                  mature

A 400-year-old Waypoint is still nascent. A 10-year-old Epicenter city is still nascent. The cap ensures structural simplicity wins over chronological age for small settlements.

1.4 The Combined Algorithm — Full Formula

Algorithm: compute_district_distribution(city, body, system, terrain)

Inputs (all from systems.db or session DB Layer 1-2 output):
  city.population, city.world_tier, city.political_archetype
  body.economic_role, body.founding_age_years, body.settlement_pattern
  system.economic_tier, system.distribution_index
  terrain.topographic_gradient_direction   # from Layer 1 output
  seed = child_seed(world_seed, city_id)   # SeedChain

Returns: Vec<DistrictSpec>
  where DistrictSpec = { type: DistrictType, prosperity_baseline: f32,
                          character_class: CharacterClass, density_pct: f32,
                          perimeter_treatment: PerimeterTreatment }

──────────────────────────────────────────────────────────────

Step 1: Total district count
  D_raw = max(1, floor(city.population / 50_000))  # log-scaled for pop > 500k
  D_total = min(D_raw, WorldTier_cap[city.world_tier])
  if city.is_capital: D_total = min(D_total + 1, WorldTier_cap[city.world_tier])
  if body.settlement_pattern in (domed, cave): D_total = 1

Step 2: Mandatory districts from population tier
  mandatory_types = guaranteed_set(city.population, city.world_tier)
  # Apply D_total cap: if len(mandatory_types) > D_total, collapse to Mixed
  mandatory = place_guaranteed_types(mandatory_types, D_total)
  remaining_slots = D_total - len(mandatory)
  # NOTE: computation is purely local — NO queries about neighboring cities.
  # Each settlement is computed independently from its own fields and seed.

Step 3: Fill remaining slots from economic role weight table
  if remaining_slots > 0:
    weights = ROLE_WEIGHT_TABLE[body.economic_role]         # 9-element, all > 0
    weights = apply_archetype_modifiers(weights, city.political_archetype)
    weights = renormalize_to_100(weights)
    # Sample without replacement — can produce duplicate types (second Ind, second Log)
    additional_types = seeded_weighted_sample(weights, remaining_slots, seed)
    all_types = mandatory + additional_types
  else:
    all_types = mandatory

Step 4: Assign age character class
  age_bracket = effective_age_bracket(body.founding_age_years, city.world_tier)
  for d in all_types:
    d.character_class = AGE_CHARACTER_TABLE[d.type][age_bracket]
    d.density_pct = age_density_range(d.type, d.character_class)[seeded_float(seed)]
    d.perimeter_treatment = age_perimeter(d.type, age_bracket)

Step 5: Assign prosperity gradients
  base_prosperity = economic_tier / 5.0 + ROLE_PROSPERITY_MODIFIER[body.economic_role]
  gradient_direction = terrain.topographic_gradient_direction  # high point = high prosperity
  gradient_magnitude = DISTRIBUTION_INDEX_SCALE[system.distribution_index]
  # Paula's topographic modifier is additive to the base, direction set by terrain:
  #   hilltop district (top 30% elevation): +0.05
  #   flood-adjacent district (bottom 20% vs. sea level): -0.05
  for (i, d) in enumerate(all_types):
    positional_rank = rank_in_gradient_direction(d.grid_position, gradient_direction, len(all_types))
    topo_modifier = topo_offset(d, terrain)
    d.prosperity_baseline = clamp(
      base_prosperity + (positional_rank - 0.5) × gradient_magnitude + topo_modifier,
      0.05, 0.95
    )

──────────────────────────────────────────────────────────────

ROLE_PROSPERITY_MODIFIER (from L3-Q5 brief formula):
  extraction:    -0.10
  research:      +0.15
  service_mixed: +0.10
  frontier:      -0.20
  (all others: 0.00)

DISTRIBUTION_INDEX_SCALE:
  "stratified": 0.7 (steep gradient — 0.7 × positional rank ± 0.35 spread)
  "moderate":   0.2 (shallow gradient — ≈ Gaussian around base, σ = 0.1)

Self-contained confirmation: The algorithm references only local city/body/system fields. There are no lookups into neighboring city data, no distance calculations to adjacent settlements, no regional density queries. Each city generates its district distribution independently from its seed and the fields above. This satisfies the SeedChain isolation property from D-C10.


2. Attractor-Matching: Full Compatibility Matrix

2.1 The Compatibility Matrix

Scale 010 where 0 = incompatible/excluded and 10 = preferred/ideal match. Geographic attractor types: the seven tags from the brief (Section 1, Layer 1 minimum viable) plus two additional tags identified by Paula (CoastalLowland, RiverValley) that emerged in Round 1 discussion.

economic_role RiverConfl CoastalHarbor MtnPass ArablePlain ResourceConc Defensible NaturalBarrier CoastalLowland RiverValley
agricultural 8 5 2 10 1 2 0 7 8
extraction 3 3 5 2 10 3 1 2 3
mining 2 2 6 1 10 4 1 1 2
transit 9 9 10 3 1 3 0 5 7
commercial 8 9 6 4 2 2 0 6 7
research 4 4 4 4 6 8 3 3 4
manufacturing 7 6 3 5 5 2 0 6 6
service_mixed 6 6 4 6 2 3 0 6 6
frontier 5 5 5 4 5 6 3 4 4
energy 4 5 3 2 8 4 2 4 3

2.2 Forbidden Combinations (score = 0)

These are not just low-probability — they are implausible enough that the generator should flag them for review rather than place silently:

Economic role Forbidden attractor Reason
agricultural NaturalBarrier No farming in impassable terrain
transit NaturalBarrier Transit hubs do not sit at physical barriers — they use gaps in them (MtnPass)
commercial NaturalBarrier Commerce requires accessible flow of goods and people
manufacturing NaturalBarrier Heavy industry requires accessible logistics
service_mixed NaturalBarrier Services require customers who can reach them

Note on NaturalBarrier: This attractor type is a settlement exclusion zone for most roles. The only roles with non-zero scores there are extraction (1), mining (1), research (3), frontier (3), energy (2) — all roles whose economic activities specifically exploit inaccessibility or operate in remote terrain.

2.3 Preferred Combinations (score = 910)

These are the "inevitable placements" Ozzie flagged — a player seeing a transit hub at a mountain pass should feel the placement was obvious:

Economic role Preferred attractor Score Narrative
transit MountainPass 10 The pass is the reason the city exists
transit CoastalHarbor 9 Port = transit nexus
transit RiverConfluence 9 River junction = historic trade/ferry crossing
agricultural ArablePlain 10 The land is the reason for the city
extraction ResourceConcentration 10 The deposit is the reason for the city
mining ResourceConcentration 10 Same
commercial CoastalHarbor 9 Ports = commercial centers historically

2.4 Full Attractor-Matching Algorithm (reconciled from four Round 1 proposals)

The four Round 1 proposals (Gestalt, Tyre, Burnelli-Sheldon, Paula) are structurally equivalent; they differ in ordering and handling edge cases. This is the convergence:

Algorithm: attractor_matching(cities, attractors, body, systems_db, seed)

──────────────────────────────────────────────────────────────

Phase 0: Build score matrix and validate HQ constraints
  For each city_i and attractor_j:
    S[i,j] = compat_score(city_i.economic_role, attractor_j.type)
           × quality_bonus(attractor_j)
           × population_weight(city_i.population)

  where:
    quality_bonus = 1.2 if attractor_j is highest-quality of its type on this body
    population_weight = 1.0 + min(log10(city_i.population / 1000) × 0.10, 0.30)

  HQ hard constraints (corp cross-references in systems.db):
    for each corp with headquarters_body = this body:
      matching_city = city with matching name in atlas_city_names
      compatible_attractors = attractors where compat_score ≥ 6
      if no compatible_attractor exists:
        FLAG for lead review: "[city_name] has no compatible attractor for [corp_role]"
        assign to best available attractor (highest score, even below 6)
      else:
        force S[matching_city, incompatible_attractor] = 0 for all incompatible

──────────────────────────────────────────────────────────────

Phase 1: Priority ordering
  Sort cities into tiers:
    Tier A: cities with HQ corp cross-reference (locked, must-place)
    Tier B: remaining named cities, sorted by population descending
    Tier C: unnamed cities (population budget, sorted by population descending)

──────────────────────────────────────────────────────────────

Phase 2: Assign Tier A cities (hard constraints first — Paula's ordering)
  For each corp in extraction-order (most geographically constrained roles first):
    economic role constraint order: extraction → mining → energy → agricultural
                                    → manufacturing → transit → commercial → research
                                    → service_mixed → frontier
  Assign each Tier A city to its highest-scoring available compatible attractor.
  Mark attractor as consumed.

──────────────────────────────────────────────────────────────

Phase 3: Assign Tier B and Tier C cities (Hungarian algorithm)
  Build sub-matrix S' for unassigned cities × remaining attractors.
  Solve maximum-weight bipartite matching.
  O(N³) where N ≤ 30: negligible compute.

  Derive FoundingOrientation from assigned attractor_type:
    RiverConfluence → RiverCrossing
    CoastalHarbor   → PortFacing
    MountainPass    → PassControl
    ArablePlain     → AgriculturalExpanse
    ResourceConc.   → ExtractionTether
    Defensible      → DefenseFacing
    NaturalBarrier  → (fortress pattern within MountainPass or Defensible)
    CoastalLowland  → AgriculturalExpanse (coastal variant)
    RiverValley     → RiverCrossing (valley variant)

──────────────────────────────────────────────────────────────

Phase 4: Overflow handling
  If N_cities > M_attractors after Phase 3:
    For each unmatched city (sorted by population descending):
      Place synthetic attractor:
        position = seed_derived offset from nearest NameLocked settlement
                   distance ∈ [15%, 40%] × body_scale
                   biased toward nearest road corridor (if road graph available)
        type = nearest_attractor.type
        (inherits the dominant attractor character of the region)
      geographically_triggered = false
      FoundingOrientation = AdminFacing (Paula's OrganicGrowth resolution)

──────────────────────────────────────────────────────────────

Phase 5: Produce SettlementRecord per city
  settlement_class = NameLocked      if Tier A
                   = PopulationBudget if Tier B/C, geographically_triggered = true
                   = OrganicGrowth    if overflow, geographically_triggered = false

Ozzie's constraint enforced: Any placement that triggers a compat_score = 0 (forbidden combination) is blocked at Phase 0. The generator cannot silently place a fishing port in the mountains — it either finds a compatible attractor or flags for lead review. This satisfies the "feels inevitable, not arbitrary" requirement.


3. Latent Settlements Under Fully Generative Placement

3.1 What Changed

Under the old model, wiki-authored cities were always active. Sub-settlements were latent. Under Amendment 3, ALL settlements are generator-placed. The latent concept must generalize.

The key economic insight: latency tracks economic justification, not authoring method. A settlement is latent if its continued existence depends on economic conditions that can change. A settlement is non-latent if it exists for structural reasons that don't change with economics (a mountain pass town exists because the pass exists; that doesn't change).

3.2 Settlement Classes and Active Status Logic

Introduce a SettlementClass enum on all generated settlement records:

pub enum SettlementClass {
    /// Placed by HQ corp cross-reference. The corp's HQ exists as long as the
    /// corp exists. Active if corp health_metric > 0.0 (any presence).
    NameLocked,

    /// Placed by population budget — geographic attractor exists but name is
    /// generator-assigned. Active if nearest NameLocked settlement is economically
    /// healthy (its sponsoring corp health > 0.4). Becomes ghost if the anchor corp
    /// collapses and no other corp moves in.
    PopulationBudget,

    /// Sub-settlements placed by economic trigger conditions:
    /// mining camps, trade waypoints, agricultural nodes.
    /// Active if triggering corp health_metric > 0.4.
    EconomicTriggered,

    /// Overflow settlements placed at Province centroids without geographic attractor.
    /// Active if provincial avg corp health > 0.5 (needs regional economic density).
    OrganicGrowth,
}

Why NameLocked is not always-active: If the corp dissolves entirely (corp_lifecycle_events.event_type = Dissolved), the HQ city loses its economic anchor. The city doesn't vanish spatially (the streets and buildings remain), but it becomes a ghost: dark, unmaintained, repopulated by scavengers and squatters. The physical city persists; the economic life drains out. This is the only case where a NameLocked settlement becomes ghost.

Why this is stronger than the old latent concept: The old model had named cities as unconditionally active and sub-settlements as optionally latent. The new model correctly identifies that a city's activity is always economically contingent — it just has different trigger conditions by class. The full active/ghost spectrum applies to all settlement types.

3.3 Schema Addition

Add settlement_class and geographically_triggered to the generated settlement records in BodyWorldState:

pub struct GeneratedSettlement {
    pub city_id: String,
    pub position: (f32, f32),              // body-local normalized coords
    pub founding_orientation: FoundingOrientation,
    pub settlement_class: SettlementClass,
    pub geographically_triggered: bool,    // Paula's NEW-Q2 disambiguation flag
    pub activating_corp: Option<String>,   // corp_id for EconomicTriggered
    pub activating_condition: Option<String>, // description for OrganicGrowth
}

geographically_triggered = false is the OrganicGrowth disambiguation flag Paula identified. It answers "was this settlement placed because of a geographic attractor or because of population pressure alone?" FoundingOrientation = AdminFacing when false.

3.4 The Latent Settlement Table in Systems.db

My Round 1 recommendation was option (b): store latent settlement positions in a systems.db Phase 3 output table. Under Amendment 1 (three-tier execution), this shifts: latent settlement positions are runtime background generation output stored in session DB (as part of BodyWorldState), not systems.db.

The economic SIM still reads from systems.db for its aggregate calculations (corp_presence, corp_financial_state). It does not need the spatial settlement positions to compute economics — it just needs to emit health_metric updates that the renderer reads to determine active/ghost status per settlement.

The handoff: The sim emits corp_health_changed(corp_id, new_metric) events. The Layer 3-4 generator, when processing a city, queries: is the activating corp's health_metric above or below the threshold for this settlement class? This query is a single lookup into the economic sim's current state. No full re-generation is needed.


4. TerritorialStatus Economic Thresholds — Convergence Proposal

The Round 1 notes show three proposals (Paula, Tyre, Burnelli-Sheldon). This section proposes convergence thresholds that satisfy all three agents' requirements.

Note on Province dimensions: Tyre's ARCH-1 through ARCH-4 blockers include confirmation of Province scale. The thresholds below use Province-relative quantities (fraction of Province cells) to remain valid regardless of absolute Province dimensions. When ARCH-1 is resolved, the fractions convert to concrete cell counts.

4.1 Convergence Table

TerritorialStatus Threshold Economic signal
CoreTerritory ≥ 2 named settlements (City or Town) within Province boundaries AND road_coverage_fraction ≥ 0.55 across Province cells AND ≥ 1 active corp (health_metric ≥ 0.5) with presence in Province Economically integrated, actively maintained
FrontierTerritory ≥ 1 settlement (any tier) in Province AND (road_coverage_fraction < 0.55 OR road_quality < 0.5 at Province boundary edges) Settled but underdeveloped; economic reach doesn't fill the Province
ExtractiveZone ≥ 1 ResourceConcentration geographic feature tag in Province AND ≥ 1 corp_presence with extraction/mining primary_operation commodity AND road corridor from resource site to nearest City (even if narrow) Productive but not balanced; the corridor is the territory
ContestZone ≥ 2 settlements from different political_archetype types within Province AND overlapping MaintenanceAuthority on shared road segments (or road networks crossing Province internal boundary without single authority) Competing claims with no resolution
WildernessBuffer 0 settlements placed + 0 roads + no ResourceConcentration tag Untouched; no economic vector yet
AbandonedZone ≥ 1 settlement with placed_at_generation = true in Province AND 0 active settlements at current sim evaluation (all occupying corps have health_metric < 0.2) Was settled; economic basis collapsed

4.2 What Changed vs. Round 1 (My Position)

  • CoreTerritory: Added "≥ 1 active corp with health_metric ≥ 0.5" as a third condition. My Round 1 threshold was purely structural (settlement count + road maintenance). Paula's version required the economic health signal. She's right — a ghost city Province with intact roads but zero active corps is not CoreTerritory; it's AbandonedZone.

  • FrontierTerritory: Adopted Paula's road quality threshold at Province edges. My Round 1 version was vague about what "road density < 0.5" meant. Road quality < 0.5 at Province boundary is more testable.

  • ContestZone: Adopted Tyre's "two CoreTerritory zones from different political archetypes overlapping" framing as the primary test. My Round 1 threshold (competing road networks) is now a diagnostic signal rather than the definition.

  • AbandonedZone: Added Paula's placed_at_generation = true flag as the necessary condition to distinguish "abandoned" from "never settled." My Round 1 version would mis-classify a WildernessBuffer Province where a corp briefly established presence and then left; the flag provides the correct disambiguation.

4.3 Runtime Derivation

TerritorialStatus can be re-derived at runtime from the economic simulation's state without re-running the Layer 1-2 generator. The inputs are:

  • settlement_active_state per settlement (from SettlementClass + corp health query)
  • road_coverage_fraction per Province (from Layer 2 session cache — does not change)
  • corp_presence + corp_financial_state.health_metric (from economic sim)

This means TerritorialStatus is a render parameter like prosperity_current — it reflects the current economic state and updates when the sim changes, but it does not trigger a layout regeneration. The Province boundaries don't move; only the status label changes.


5. Open Positions and Requests for Other Agents

5.1 BS-Q1 — Final Resolution (no further input needed)

A 9,999-person Town without a dedicated Entertainment district is economically correct. Entertainment is functional inside the Commercial district at Town scale. Gestalt validated this in Round 1 notes (no objection to the threshold).

5.2 Topographic Modifier to prosperity_baseline (Paula + Burnelli-Sheldon)

Paula proposed a topographic modifier (+0.05 hilltop, -0.05 flood-adjacent). This is included in the formula at Step 5 of §1.4 as an additive offset on the base gradient. No incompatibility with my gradient direction/magnitude split. Confirmed compatible.

5.3 Gestalt: Character table feedback needed

The age character classes in §1.3 (AGE_CHARACTER_TABLE) propagate to DistrictSkeleton fields (perimeter_treatment, density_pct). I need Gestalt to confirm whether these fields are sufficient to express the character differences, or whether additional fields on DistrictSkeleton are needed. Specifically: does a "nascent entertainment district" vs. a "mature entertainment district" need a named field, or does density_pct + prosperity alone carry it?

5.4 Tyre: ARCH-3 schema question

The attractor-matching algorithm requires atlas_city_names with fields: body_id, city_name, economic_role, population, hq_for_corp_id (nullable). Does this replace or extend atlas_cities? My recommendation: extend with additional columns. atlas_cities currently stores authored pixel positions (which become obsolete under Amendment 3) plus name + population + kind (which are still needed). The new columns are: hq_for_corp_id (nullable FK to corporations) and assigned_attractor_id (nullable, written by Layer 2 generator to session DB, not systems.db).

5.5 Threshold for "abandoned body" condition on NameLocked settlements

My SettlementClass model has NameLocked cities becoming ghost when their founding corp dissolves. I need confirmation from Paula: does corp dissolution in the economics sim produce a corp_lifecycle_events.event_type = Dissolved record? The rendering system needs a way to read this state. Alternatively: corp_financial_state.health_metric = 0.0 as a proxy. Which is the correct signal to read?