---
title: "Gestalt Round 4 — Final Convergence"
description: "Open question resolution, guarantee amendments, and D-record sign-off"
type: workshop
status: archived
workshop: generator-architecture
agent: "gestalt"
round: 4
created: 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:
1. The formula/weighting for the three input components
2. The four output levels (`low/medium/high/extreme`) and their thresholds
3. The integration points where the computation is invoked
4. 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
```rust
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
, // 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:
```rust
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
```rust
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 `Insider` or `BreachOnly` accessible 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-Private` partition
- 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
```rust
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::Restricted` or a `RooftopConfig::PublicWithHiddenLayer` with a non-empty `secondary_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_disparity` flag present)
- Power Gradient Visibility (when `faction_control` field 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:
```rust
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`. If `Restricted`, the roof zone must be `Insider` or `BreachOnly` with a non-obvious access route. If `PublicWithHiddenLayer`, 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::TraumaEvent` applies structural changes via `ChunkMutations::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 a `StructuralChange`; 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)
├── 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.**