Standardized YAML frontmatter on all 38 files with title, description, type, workshop, agent, and round fields. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
24 KiB
title, description, type, status, workshop, agent, round, created
| title | description | type | status | workshop | agent | round | created |
|---|---|---|---|---|---|---|---|
| Gestalt Round 4 — Final Convergence | Open question resolution, guarantee amendments, and D-record sign-off | workshop | archived | generator-architecture | gestalt | 4 | 2026-02-27 |
Generator Architecture Workshop — Round 4: Gestalt
Role: Systems Design / Gameplay Loop Requirements Date: 2026-02-27 Workshop: Generator Architecture (#562) Round: 4 — Final Convergence
Framing
Four tasks this round. Three open questions to close. One guarantee to amend. Twelve D-records to sign off. The lead has already settled the major architectural splits (WorldTier, entity-carried chunks, DramaDensity as runtime). My job is to close the remaining mechanical questions with concrete answers and lock the D-records.
Let me crack my knuckles.
1. OQ-R4-C: Assassination Difficulty Descriptor — Definitive Answer
Miri proposed assassination_difficulty: low/medium/high/extreme derived from:
observation density × information liquidity × aftermath engagement
The question: where does it live? DistrictSkeleton, SocietyProfile, or computed on demand?
Answer: Computed on demand. Never stored.
Here's why this is the only defensible answer mechanically:
The inputs are not all static
assassination_difficulty is a function of three input streams, only two of which are stable:
| Input stream | Source | Stability |
|---|---|---|
| Observation density | SocietyProfile (heritage root, institutional coverage) | Stable (generator output) |
| Information liquidity | SocietyProfile (heritage root, settlement density) | Stable (generator output) |
| Aftermath engagement | SocietyProfile (heritage root, faction presence) | Stable (generator output) |
| Current NPC distribution | Storyteller state (DramaDensity, activated triangles) | Dynamic |
| Spatial audit satisfaction | A-1 through A-4 guarantee flags | Stable (generator output) |
| Active guard state | Simulation tick (faction events, alert level) | Dynamic |
The dynamic inputs mean a stored assassination_difficulty on any struct would be stale the moment the storyteller fires an event. A political crisis event spikes guard coverage; aftermath engagement goes from medium to extreme. A faction purge reduces community observation. The stored value would be wrong within a single session.
Storing it causes incorrect player expectations
If the player sees an assassination_difficulty assessment that was baked at district generation, they're reading a stale number. The immersive sim promise is that the world responds. If the player INCREASED guard presence by burning down the safe house two districts over, the difficulty should reflect that. A stored value can't.
The correct integration point
assassination_difficulty =
fn(
society_profile: &SocietyProfile, // from SocietyProfile (stable)
spatial_audit: &SpatialGuarantees, // from DistrictSkeleton (stable)
active_state: &StorytellerState, // from runtime (dynamic)
) -> DifficultyDescriptor
This function is called:
- At contract acceptance (player sees their pre-op assessment)
- During pre-op planning phase (player can see how conditions change by day-phase)
- NOT stored anywhere persistent
What the D-record should specify
The D-record for assassination_difficulty should specify:
- The formula/weighting for the three input components
- The four output levels (
low/medium/high/extreme) and their thresholds - The integration points where the computation is invoked
- That it is explicitly not a struct field on DistrictSkeleton or SocietyProfile — it is a derived computation
The reason to canonicalize the formula in a D-record: other systems (NPC routing, faction responses, storyteller module selection) may want to consume the same computation. Having it defined once prevents different systems from computing it differently.
Verdict: OQ-R4-C is resolved. No persistent storage. Computed on demand from SocietyProfile + spatial audit + runtime state.
2. OQ-R4-F: Soft Re-Generation — The Concrete Example
Ozzie's principle: destruction must be caused, not random. The question: does original_seed XOR event_seed satisfy this, or do we need structured damage parameters?
I'm going to show you the actual output of both approaches for the same event. Then we'll know.
The Scenario
District X: district_seed = 0xA3F8C21B_7E64D509
- Heritage root: Iron (dense residential, workshop clusters)
- Block layout: 4×4 grid, SMALL complexity
- Block (2,3): Worker residential block, ~60 tiles
- Floors 1-3: apartment units, corridor, shared kitchen
- Sub-level (z=-1): utility tunnel, gas line infrastructure
- Event: gas line rupture at (tile 2,3,38) at sim tick 47,302
Approach A: XOR Reseeding
event_seed = hash(EventType::GasExplosion, TilePosition(2,3,38), SimTick(47302))
= 0x5B7E349A_1C82A7F3
reseeded = 0xA3F8C21B_7E64D509 XOR 0x5B7E349A_1C82A7F3
= 0xF886F6816AE672FA
The chunk fill re-runs on block (2,3) with reseeded. What does this produce?
| Tile position | Before | After (XOR reseed) |
|---|---|---|
| (2,3,1) — entry corridor | Corridor tile, N-S orientation | Corridor tile, E-W orientation |
| (2,3,4) — apartment 1A | Residential interior | Workshop space (RNG diverged at zone assignment) |
| (2,3,12) — shared kitchen | Kitchen fixture cluster | Storage room |
| (2,3,38) — explosion origin | Gas line junction (sub-level) | Open floor tile |
| (2,3,40) — adjacent unit | Apartment interior | Wall (block subdivision changed) |
| (2,3,55) — block corner | Exterior wall | Exterior wall (stable, geometric) |
The result: The block has been replaced, not damaged. Tile (2,3,4) changed from a residential apartment to a workshop — not because the explosion destroyed residential use and workers moved in; the generator just made different decisions with the new seed. The zone assignment diverged at the first RNG call that governs zone type selection.
The explosion origin tile (2,3,38) lost its gas line fixture — but so did tiles across the entire block, because the fixture placement logic runs from a different RNG stream now. There's no spatial logic to the changes. The modifications don't radiate from the explosion center.
Diagnosis: XOR reseeding is a blender, not a bomb. It mixes the content uniformly rather than concentrating disruption at a source. The result looks replaced rather than damaged. This fails Ozzie's test — the destruction has no cause visible in the output.
XOR reseeding is appropriate only for era-scale discontinuities, where the settlement genuinely rebuilt from scratch (decades passed, original structures gone, new generation built different). It is wrong for in-playthrough events.
Approach B: Structured Damage Parameters
struct GasExplosionEvent {
origin: TilePosition, // (2, 3, 38)
blast_radius: u16, // 8 tiles primary, 14 tiles secondary
intensity: f32, // 0.85 (high pressure rupture)
propagation_dir: Option<Dir>, // None (omnidirectional rupture)
ignition: bool, // true (gas ignites)
}
Application: the generator output is unchanged. The chunk maintains original_seed = 0xA3F8C21B_7E64D509. The damage event is appended to the ChunkMutations overlay:
ChunkMutations {
structural_changes: [
// Primary blast zone (radius ≤ 8 tiles): damage proportional to distance
StructuralChange { tile: (2,3,38), change: TileType::Rubble { debris_density: 1.0 } },
StructuralChange { tile: (2,3,37), change: TileType::Rubble { debris_density: 0.9 } },
StructuralChange { tile: (2,3,39), change: WallState::Breached { gap_size: 3 } },
StructuralChange { tile: (2,3,36), change: TileType::Rubble { debris_density: 0.7 } },
StructuralChange { tile: (2,3,4), change: TileType::Rubble { debris_density: 0.4 } },
// Floor above (if loaded): ceiling collapse
StructuralChange { tile: (2,3,38+floor), change: FloorState::PartialCollapse },
// Secondary zone (radius 8–14): soot, scorch marks, broken fixtures
TileOverride { tile: (2,3,50), visual_state: VisualMod::Scorched },
TileOverride { tile: (2,3,51), visual_state: VisualMod::SootLayer },
// ...
],
removed_objects: [gas_line_fixture_38, apartment_door_36, ...],
placed_objects: [
PlacedObject { pos: (2,3,42), object_type: DebrisPile, seed: derived },
PlacedObject { pos: (2,3,35), object_type: FireScorch, seed: derived },
],
}
The result:
| Tile position | Before | After (structured overlay) |
|---|---|---|
| (2,3,1) — entry corridor | Corridor, N-S | Corridor, N-S (unchanged) |
| (2,3,4) — apartment 1A | Residential interior | Residential interior, debris scattered (within blast radius but low intensity at distance) |
| (2,3,12) — shared kitchen | Kitchen fixtures | Kitchen fixtures, scorched (secondary zone) |
| (2,3,38) — explosion origin | Gas line junction | Rubble, debris_density 1.0 |
| (2,3,40) — adjacent unit | Apartment interior | Rubble, debris_density 0.8 |
| (2,3,55) — block corner | Exterior wall | Exterior wall, soot marks (secondary zone) |
The block is recognizably itself — a worker residential block that has been damaged. You can see the block's original structure through the destruction. The explosion origin is identifiable. The damage radiates outward. The adjacent block at (2,4) is untouched.
This is caused destruction. The spatial logic is legible.
Decision: Regeneration Strategy Enum
enum RegenerationStrategy {
/// For localized in-playthrough events: explosions, fires, structural collapse
/// Generator output unchanged; damage applied as ChunkMutations overlay
LocalOverlay(DamageParameters),
/// For district-scale temporal changes: rebuilding after war, years of neglect
/// Modify seed slightly; re-run generator for significant structural changes
/// Appropriate when player returns to a district 10+ years later (between scenarios)
SoftReseed { seed_modifier: u64 },
/// For era-level discontinuities: orbital strike, catastrophic flood, decades of war
/// Appropriate between major time-skip scenarios, not within playthrough
FullReseed,
}
Rule: In-playthrough events are ALWAYS LocalOverlay. SoftReseed and FullReseed only apply during scenario setup (between playthroughs or at major time-skip boundaries). The generator never re-runs for events the player witnesses or causes.
This resolves OQ-R4-F. The D-record should canonicalize these three strategies and explicitly prohibit XOR reseeding for in-playthrough events.
Verdict: OQ-R4-F is resolved. LocalOverlay for in-playthrough events. XOR/soft reseed only at scenario boundaries.
3. Rooftop Bar Clause — Amended Guarantee
The Original Guarantee (Round 3)
"Every tall structure (z_band_count ≥ 3) must have a roof zone classified
InsiderorBreachOnlyaccessible by non-obvious route."
The Problem
This forces ALL rooftops to be secret or restricted. But the setting has:
- Commission-era arcologies with public observation galleries
- Commercial towers with rooftop restaurants
- Religious structures with sky gardens
- A transit hub's roof terrace where residents watch shuttle departures
The guarantee as written would require the rooftop restaurant to be an unauthorized trespass destination. That's wrong. Some rooftops are meant to be a public destination — a reason to climb, not a secret discovered by climbing.
What the guarantee was trying to protect: the discovery element. Rooftops should never be structurally irrelevant. They should always offer something — either a restricted secret, or a public destination with a hidden layer.
The Revised Guarantee — Vertical Discovery
For every tall structure (z_band_count ≥ 3), at least one of the following must be true:
Option A — Restricted Rooftop (Discovery Through Access)
The primary roof zone is classified Insider or BreachOnly, accessible by non-obvious route. The discovery is the access itself.
Option B — Public Rooftop with Hidden Layer (Discovery Within Destination)
The primary roof zone is publicly accessible (Social Hub, Economic Node, or equivalent). A secondary zone within the same z-band is classified Insider or BreachOnly. This could be:
- A maintenance level behind an access panel
- A restricted transmitter array within the rooftop space
- A private penthouse cluster separated by
Semi-Privatepartition - A service stairwell to a sub-roof level
The inviolable rule across both options: Every tall structure must have something at the top that is not fully accessible from below. The discovery layer is mandatory. The public/private split of the primary space is not.
Generator Implementation
enum RooftopConfig {
Restricted {
zone_class: AccessTier, // must be Insider or BreachOnly
access_route: RouteObviousness, // must be NonObvious
},
PublicWithHiddenLayer {
primary_zone: ZoneType, // Social Hub, Economic Node, etc.
secondary_restricted: ZoneSpec, // always present; Insider or BreachOnly
},
}
struct MultiBlockReservation {
// ... existing fields ...
rooftop: RooftopConfig, // replaces the old "roof zone guaranteed restricted" constraint
}
The Guarantee Audit Change
Old check:
"Does this tall structure have a roof zone classified Insider or BreachOnly?"
New check:
"Does this tall structure have a
RooftopConfig::Restrictedor aRooftopConfig::PublicWithHiddenLayerwith a non-emptysecondary_restricted?"
Both options satisfy the audit. The key: the generator must choose one at district generation time based on the building's zone palette and heritage root. Commission-institutional buildings: PublicWithHiddenLayer (observation gallery + restricted records floor). Iron-heritage trade towers: Restricted (the roof belongs to the guild leadership). Frost-heritage isolated structures: Restricted (the roof is where the heating systems live and no one else goes up).
Verdict: Rooftop guarantee amended. Rooftop bars are valid. The discovery layer remains mandatory.
4. D-Record Sign-Off — All 12
Going through each. I'm flagging amendments where the D-record needs additional language beyond what the Round 3 notes contain.
| # | Item | Status | My Position |
|---|---|---|---|
| D-READY-1 | DistrictLayoutMode: Grid / Organic | SIGNED OFF | No amendments. Canonical. |
| D-READY-2 | Guarantee Tier System | SIGNED OFF | Amendment below. |
| D-READY-3 | TrianglePurpose Enum | SIGNED OFF | No amendments. |
| D-READY-4 | WallBackside / TileBehindState | SIGNED OFF | Amendment below. |
| D-READY-5 | Dynamic Modification via Overlay | SIGNED OFF | Amendment below (from OQ-R4-F). |
| D-READY-6 | ZonePalette Modifier System | SIGNED OFF | No amendments. |
| D-READY-7 | Horizon View Corridor | SIGNED OFF | No amendments. |
| D-READY-8 | Assassin Lens Spatial Guarantees | SIGNED OFF | Amendment below. |
| D-READY-9 | Heritage Grammar Overlay | SIGNED OFF | No amendments. |
| D-READY-10 | Non-Urban Informal Zone Typology | SIGNED OFF | No amendments. |
| D-READY-11 | Vertical Scale Architecture | SIGNED OFF | Amendment below (Rooftop Bar Clause). |
| D-READY-12 | Trauma Events as EraModification | SIGNED OFF | Amendment below (from OQ-R4-F integration). |
D-READY-2 Amendment: Guarantee Tier System
The D-record should include explicit naming for the three tiers:
- Tier 1 — Universal Inhabited Guarantees (all inhabited districts, any complexity)
- Social Hub, Informal Zone, Encounter Corridor
- Tier 2 — Full-Complexity Guarantees (Full-complexity only)
- Traffic Chokepoint, Institutional Space, Insider Space, Economic Node
- Horizon View Corridor (coastal Full-complexity)
- BreachOnly Zone (≥1 per Full-complexity)
- Tier 3 — Conditional Parameter Guarantees (depend on district parameter values)
- Elevated Vantage, Egress Multiplicity, Temporal Opacity Window (A-1/A-2/A-3)
- Non-Institutional Access Route (A-4 — applies to all Full-complexity)
- Economic Asymmetry Signal (when
economic_disparityflag present) - Power Gradient Visibility (when
faction_controlfield is non-null)
The audit runs all applicable checks. A Minimal farmstead gets 3 checks. A Full-complexity coastal urban hub gets up to 12. The D-record should specify which checks are mandatory vs. which are triggered by parameter flags.
D-READY-4 Amendment: Dual Classification System
The D-record should clearly establish that TileBehindState and WallBackside serve complementary roles and both are canonical:
| Enum | Scope | Purpose |
|---|---|---|
WallBackside (Tyre) |
Structural | What is physically behind this wall tile (for generation and LOS) |
TileBehindState (Gestalt) |
Gameplay | What kind of space this represents for gameplay systems |
These are not duplicates. A wall with WallBackside::ServiceVoid has TileBehindState::Interstitial. A wall with WallBackside::AdjacentSpace has TileBehindState::HiddenRoom OR TileBehindState::StructuralFill depending on access tier configuration. The D-record should canonicalize both enums and document the mapping between them.
D-READY-5 Amendment: RegenerationStrategy Integration
Add to the D-record:
enum RegenerationStrategy {
LocalOverlay(DamageParameters), // in-playthrough events; generator output unchanged
SoftReseed { seed_modifier: u64 }, // scenario-boundary temporal changes only
FullReseed, // era-level discontinuities only
}
Explicit constraint in the D-record: In-playthrough events must use LocalOverlay. SoftReseed and FullReseed are scenario-setup tools, not event responses. The generator does not re-run for player-witnessed events.
D-READY-8 Amendment: A-1 through A-4 as Tier 3 Conditional
The assassin spatial guarantees (A-1: Elevated Vantage, A-2: Egress Multiplicity, A-3: Temporal Opacity Window, A-4: Non-Institutional Route) should be positioned explicitly as Tier 3 Conditional Guarantees, not as an assassin-specific subsystem.
The D-record language should be:
"A-1, A-2, and A-3 are conditional guarantees triggered when
complexity_tier == Full. A-4 is a mandatory Full-complexity guarantee (all playstyles benefit from non-institutional routes). These are derived properties of the existing spatial configuration, validated by the guarantee audit. They are not spatial features tagged for the assassin — they are properties that any playstyle can discover and exploit."
This framing prevents scope creep where assassin-specific content gets its own generation budget. The guarantees audit against existing spatial output; they don't add generation cost.
D-READY-11 Amendment: Rooftop Bar Clause
The D-record should replace the original guarantee with the amended RooftopConfig model from Section 3 above. Specifically:
"Every tall structure (z_band_count ≥ 3) must specify a
RooftopConfig. IfRestricted, the roof zone must beInsiderorBreachOnlywith a non-obvious access route. IfPublicWithHiddenLayer, the primary public zone must be accompanied by a secondary restricted zone within the same z-band. The discovery layer is mandatory in both configurations. Heritage root and building zone palette determine which configuration the generator assigns."
D-READY-12 Amendment: Trauma Event + RegenerationStrategy
Trauma events trigger LocalOverlay, not reseeding. The D-record should explicitly state:
"
ModificationType::TraumaEventapplies structural changes viaChunkMutations::LocalOverlay. The generator output (original_seed) is preserved. Cultural aftermath decays toward baseline at heritage-root-dependent rates, tracked in simulation state. Physical destruction and cultural aftermath are separate tracks — the wall being rubble is aStructuralChange; the community's altered NPC weight distribution is simulation state that decays."
5. Lead Decisions — Acknowledged
The following lead decisions are received and incorporated:
WorldTier wins over SignificanceTier
Acknowledged. WorldTier correctly describes what this parameter measures: the simulation fidelity budget allocated to this location. SignificanceTier implied narrative importance, which is wrong — a politically significant backwater still gets Minimal complexity if the generator didn't budget for it. The field is now world_tier: WorldTier on the DistrictSkeleton.
Entity-carried chunks are CORE architecture
Acknowledged. MobileChunk as entity-carried ChunkData. Vessels exist as persistent world entities — docked at port, visible from the dock, present on the world map. The exterior is a scrolling visual buffer in InTransit state. Miri's cultural grammar applies fully to both static and mobile chunk types. The arrival-deadline temporal pressure is core gameplay.
DramaDensity is runtime state, NOT on DistrictSkeleton
Acknowledged and confirmed from my own Round 3 position. The DistrictSkeleton carries the capacity ceiling. The storyteller carries the current value. The D-records should explicitly state this constraint.
Final Pipeline Statement — Locked
Three-layer model, canonicalized:
GENERATOR STATE (immutable after Phase 1)
├── Phase 1: DistrictSkeleton
│ ├── world_tier: WorldTier (simulation fidelity budget)
│ ├── complexity_tier: ComplexityTier (content budget)
│ ├── layout_mode: DistrictLayoutMode (Grid | Organic)
│ ├── spatial guarantees: Tier 1/2/3 audit flags
│ ├── rooftop: RooftopConfig (Restricted | PublicWithHiddenLayer)
│ └── society_profile: SocietyProfile (heritage root, institutional coverage, etc.)
└── Phase 2: PreparedDistrict
├── SocialSitePlacement (triangles with Vec<TrianglePurpose>)
├── NpcManifest (seeded from society_profile)
├── ZonePalette assignments (base + modifiers)
└── ChunkMutations pending (pre-queued from simulation events)
SIMULATION STATE (runtime storyteller)
├── DramaDensity (per-district, storyteller-controlled)
├── ActivatedTriangles (subset of SocialSitePlacement)
├── assassination_difficulty (computed on demand from SocietyProfile + audit + runtime)
└── StorytellerModules (fired events, fragility triggers)
DELTA LAYER (post-generation)
├── ChunkMutations applied (LocalOverlay for in-playthrough)
├── NpcRemoved / NpcStateChanged
├── AccessTierChanged (factions seal or open zones)
└── WorldStateDelta (composed from all active mutations)
These three layers compose at render time. The generator never re-runs. The pipeline is locked.
Open Questions Remaining
None.
- OQ-R4-A: Entity-carried chunks selected by lead. Resolved.
- OQ-R4-B: WorldTier selected by lead. Resolved.
- OQ-R4-C: Computed on demand. Resolved (Section 1).
- OQ-R4-D: Heritage grammar overlay — this is OQ-R4-D which is Araminta's domain (representation in chunk fill assets vs. modifier objects). I'm waiting on Araminta's response; it doesn't block D-record production since the content of the heritage grammar (Miri) and the integration point (modifier system, D-READY-6) are both locked.
- OQ-R4-E: One NPC, five lenses — Nigel's domain. Doesn't affect my output.
- OQ-R4-F: LocalOverlay for in-playthrough events. Resolved (Section 2).
Round 4 closes from my side. Twelve D-records ready. Three open questions resolved. Pipeline locked.