Files
settled-reach/docs/workshops/test-architecture/gestalt-round2.md
T
jpmschweitzerandClaude Opus 4.6 a87c95a6eb docs(workshops): complete QA test architecture workshop
3-round workshop with 7 agents (Tyre, Dudley, Stig, Hoshe,
Justine, Gestalt, Ozzie) plus Qatux documenting. Produced:

- 59-item prioritized test backlog (60 tickets under epic #455)
- Gauntlet test world spec: 7 rooms + hub, 48 entities
- Test client binary spec (tooling/test-client/)
- Determinism fixes (3 patches, ~22 lines)
- Server --test-mode + --port 0 design
- Content cross-reference validation (9 checks)
- make pre-pr pipeline (6-step)
- 38 client tests prioritized
- Anti-tedium features (reset plate, hub teleport, WRONG button)
- Human tester walkthrough
- CI pipeline design (deferred but documented)

Sprint 8 scope: ~17.75 team-days across 26 tickets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 14:00:15 +01:00

419 lines
32 KiB
Markdown

# Gestalt — Round 2: Coverage Audit, Anti-Tedium Mechanics, Transition Scenarios, Invariant Prioritization
**Workshop:** QA Strategy & Test Architecture
**Track:** 1 (Test World Design)
**Date:** 2026-02-17
**Inputs:** All Round 1 outputs (Gestalt, Ozzie, Tyre, Dudley, Stig, Hoshe, Justine)
**Lead decisions:** Room count rolling, anti-tedium full suite approved, determinism confirmed.
---
## 1. Final Room Coverage Audit
I mapped every mechanical system from `decisions/*.md` to the complete Gauntlet room list (8 original + 6 proposed in Round 1). The goal: every system that creates a player decision is tested by at least one room.
### Complete Room List (14 rooms)
| # | Room | Source | Primary Systems |
|---|------|--------|----------------|
| 1 | Inventory Warehouse | Brief | Pickup, CarriedBy, inventory grid, 9-slot limit |
| 2 | Occlusion Corridor | Brief | LOS, shadowcasting, vision cone, perception modes |
| 3 | Interaction Gallery | Brief | ObjectType verbs, multi-verb NPC, sprint suppression |
| 4 | Crowd Plaza | Brief | Entity density, relationship colors, cognitive delay overlap |
| 5 | Fog Theater | Brief | Fog layer transitions, peripheral dimming, exploration persistence |
| 6 | Dialogue Room | Brief | Trust tiers, contradiction, walk-away, monologue during dialogue |
| 7 | Pause Chamber | Brief | TickRate toggle, state transitions, pause/unpause |
| 8 | Zone Gate | Brief (reserved) | Zone transition (future contract) |
| 9 | Eavesdrop Alcove | Gestalt R1 | ListeningFocus, zone ambient, Careful stance, conversation eavesdrop |
| 10 | Confrontation Stage | Gestalt R1 | Cognitive vulnerability, audio dip, graduated SFX suppression |
| 11 | Sprint Gauntlet | Gestalt R1 | Sprint suppression, anomaly survival, stance transitions |
| 12 | Sound Lab | Gestalt R1 | Three-range sound, sound pings, recognition chime sequence |
| 13 | Decay Observatory | Gestalt R1 | Knowledge decay, stale state, fog representation degradation |
| 14 | Shift Change | Gestalt R1 | Stress test: all systems simultaneously at density |
### Coverage Matrix: System -> Room -> Key Assertion
Each row is a mechanical system drawn from a confirmed decision. The matrix shows which room exercises it and the primary assertion.
#### Pillar 1: Characters & Information
| System | Decision | Room(s) | Key Assertion |
|--------|----------|---------|---------------|
| Knowledge graph — confidence levels | D-041 | Dialogue Room, Decay Observatory | Suspects < KnowsOf < KnowsDetails < Direct. Each level gates different verbs/dialogue. |
| Knowledge graph — decay | D-041 | Decay Observatory | Confidence downgrades once per game-minute (10 ticks). Direct -> KnowsDetails -> KnowsOf -> Suspects on schedule. |
| Knowledge graph — contradiction | D-041 | Dialogue Room | Two conflicting entries produce Contradicted state. Monologue fires. D-033 color shifts to PersonOfInterest. |
| Knowledge graph — event queue | D-041 | Shift Change | 15 entities generating KnowledgeEvents simultaneously. Queue drains completely per tick. No dropped events. |
| Entity color = relationship | D-033 | Crowd Plaza, Dialogue Room | Color maps to RelationshipState, not objective property. Unknown=#4a9ebb, Friendly=#6bc9a6, POI=#e8c547, Hostile=#d45d5d. |
| Entity color transitions | D-033 | Dialogue Room | 0.5s fade on relationship change. Contradiction shifts green -> amber. |
| Monologue — core system | D-016 | Sprint Gauntlet, Confrontation Stage, Eavesdrop Alcove | Fires as perception bridge, atmosphere, diegetic hint. Character voice varies by archetype. |
| Monologue — separate pools | D-032 | Dialogue Room | Smuggler and detective monologue pools are hard-partitioned. Same trigger, different pool. |
| Monologue — trigger types | D-016/D-032 | Multiple (see sub-table) | Each trigger type exercised at least once. |
| Invisible locked options | D-062 | Dialogue Room | No grayed-out options. No lock icons. Options appear only when unlocked. |
| Confrontation — same box | D-063 | Confrontation Stage | Confrontation uses same dialogue UI. Weight from italics + pre-delivery beat + world response. |
| Walk-away consequences | D-064 | Dialogue Room, Confrontation Stage | 300ms fade, NPC reacts, KG records incompleteness. Per-seed tolerance variation. |
| Inventory — physical items | D-065 | Inventory Warehouse | 9-slot limit (smuggler 3-4, detective 2). Take/Place verbs. CarriedBy component. |
**Monologue trigger sub-table:**
| Trigger Type | Room | Scenario |
|-------------|------|----------|
| `enter_location` | Hub (entering any room) | Player crosses room threshold, location monologue fires |
| `observe_npc` | Crowd Plaza | First observation of NPC triggers character assessment monologue |
| `hear_sound` | Sound Lab | Sound from behind wall triggers "Footsteps behind me..." |
| `observe_anomaly` | Sprint Gauntlet, Confrontation Stage | NPC in wrong location triggers anomaly monologue |
| `post_conversation` | Dialogue Room | After dialogue ends, reflective monologue fires |
| `discover_evidence` | Dialogue Room (contradiction) | Contradiction discovery triggers "Wait — they said..." |
| `witness_interaction` | Eavesdrop Alcove | Witnessing NPC-to-NPC conversation triggers interpretation |
| `time_idle` | Eavesdrop Alcove (30+ tick wait) | Idle in alcove triggers reflective monologue |
| `return_visit` | Decay Observatory (return from Part B) | Returning to Part A triggers "Last time I was here..." |
#### Pillar 2: Perception
| System | Decision | Room(s) | Key Assertion |
|--------|----------|---------|---------------|
| Fog of perception | D-011 | Fog Theater, Occlusion Corridor | LOS-based, not radius. Walls block. Fog returns on departure. |
| Camera locked to character | D-015 | All rooms | No panning. Vision cone: forward=full, peripheral=reduced, behind=fog. |
| Vision cone — forward/peripheral/behind | D-015 | Fog Theater, Occlusion Corridor | Forward: full LOS, full detail. Peripheral: reduced range, dimmed. Behind: blind. |
| Perception modes | D-017 | Occlusion Corridor | Mode switch reveals different information. Same entity, different ObserverSnapshot per mode. |
| Three-range sound | D-018 | Sound Lab | Close=stereo, high accuracy. Medium=directional indicator+monologue. Long=insert alert (deferred). |
| Shadowcasting — symmetric | D-035 | Occlusion Corridor, Fog Theater | If A sees B, B sees A. Verified with entities on both sides of LOS boundary. |
| Fog — 5 layers | D-059 | Fog Theater | Clear, light fog, deep fog, unexplored+maps, unexplored. Each layer tested for correct visual properties. |
| Fog — sound pings | D-059 | Sound Lab | 2-3 concentric expanding rings. Loud=3 bright fast. Quiet=1 faint slow. Fade 1.5s. |
| Fog — recognized vs unrecognized entity | D-059 | Sound Lab, Decay Observatory | Known: D-033 color glow + silhouette + 0.8s pulse + position drift. Unknown: grey blob. |
| Cognitive delay | D-060 | Fog Theater, Sound Lab, Crowd Plaza | 0.6s base, 0.3s urgent. Monologue fires DURING delay. Visual: blob -> color+silhouette over ~0.3s. |
| Recognition chime timing | D-067 | Sound Lab | Chime at ONSET of delay (not completion). 300-400ms. Sequence: detect -> chime -> delay -> monologue -> visual transition -> done. |
| Cognitive vulnerability (confrontation) | D-070 | Confrontation Stage | Emotional focus reduces ambient perception. Audio dip. Loud events break through, quiet don't. Post-confrontation delayed monologue. |
| ListeningFocus | D-071 | Eavesdrop Alcove | Stationary 30+ ticks -> +2 to +3dB World SFX. Far conversations become audible. |
| Zone ambient vs conversation | D-072 | Eavesdrop Alcove | High ambient hides conversations. Low ambient makes them conspicuous. |
| Insert overlay independence | D-048 | Fog Theater | Insert data (z-layer 6) renders regardless of fog state (z-layer 5). |
#### Pillar 3: Movement & Interaction
| System | Decision | Room(s) | Key Assertion |
|--------|----------|---------|---------------|
| Stance toggle — Sprint/Walk/Careful/Crouch | D-053 | Sprint Gauntlet, Eavesdrop Alcove | Each stance: correct tick/tile speed, monologue rate, footstep volume, interaction availability. |
| Sprint — interaction suppression | D-055 | Sprint Gauntlet, Interaction Gallery | Interaction buffer EMPTY during sprint. Anomaly monologue survives (sprint double-take). |
| Sprint — monologue at 40% | D-053 | Sprint Gauntlet | Run 10 times: monologue fires ~4 times (statistical via SimRng). |
| Careful — tell notice bonus | D-053 | Eavesdrop Alcove | Careful stance monologue at 150%. Observation monologue fires for Tier 2 NPC behavior. |
| Tile-based movement | D-054 | All rooms | Discrete positions. Client Tween hides grid. TilePresence layers. |
| Same-tile occupancy | D-054 | Crowd Plaza | Multiple entities on one tile in different posture layers (Standing + Seated). |
| Dual-scale grid | D-066 | Occlusion Corridor, Fog Theater | 0.5m sim tiles, 1m visual tiles. 2x2 geometry minimum. Cover maps 1:1 at visual scale. |
| Entity interaction — vertical list | D-057 | Interaction Gallery | Two-phase verb computation. Phase 1 (ObjectType), Phase 2 (KG filter). Max 4 options. |
| Cursor states | D-056 | Interaction Gallery | Default/entity hover/object hover/(weapon aim future). 150ms transitions. D-033 color on hover. |
| World menu — radial | D-058 | Interaction Gallery | Right-click: 4 spokes. v0.1: 2 spokes (Observe + Insert). |
| Dialogue box | D-061 | Dialogue Room | Bottom screen, max 20%, no portraits. Max 3 response options. Monologue floats ABOVE. |
#### Pillar 4: Audio
| System | Decision | Room(s) | Key Assertion |
|--------|----------|---------|---------------|
| 5-bus audio | D-068 | Sound Lab, Eavesdrop Alcove | Music, Ambient, World SFX, Player Actions, UI Sounds — all routable, independent sliders. |
| Audio dip — dialogue | D-069 | Dialogue Room | Ambient -6 to -8dB during dialogue. 300ms ease-in, 500ms ease-out. |
| Audio dip — confrontation | D-069 | Confrontation Stage | Ambient -10 to -12dB + low-pass 20kHz->800Hz. World SFX graduated. 500ms in, 1000ms out. |
| ListeningFocus boost | D-069 | Eavesdrop Alcove | World SFX +2 to +3dB when stationary 30+ ticks. |
| Zone crossfade | D-073 | Hub corridors (between rooms) | Hard tile boundary, 1.5-2s audio crossfade tween. |
| Audio aesthetic — insert-tech vs organic | D-074 | Sound Lab | Chimes = synthetic/precise. Footsteps = warm/breathy. Two sonic families. |
#### Pillar 5: Simulation & Architecture
| System | Decision | Room(s) | Key Assertion |
|--------|----------|---------|---------------|
| Client-server separation | D-020 | All rooms (Layer 3 test) | ObserverSnapshot is the only data crossing boundary. PlayerInput is semantic actions. |
| Deterministic simulation | D-010 p4 | Shift Change (determinism test) | Same seed + same inputs = identical world state at tick N. INV-T01 master invariant. |
| Pause/unpause | D-031, Bug #3 | Pause Chamber | Movement discarded. No state changes. UI responsive. Round-trip preserves state. |
| Tick budget | D-026 | Shift Change | <=100ms per tick with 15+ active entities. Measured per tick, not averaged. |
| Snapshot delivery | D-020, Bug #1 | Shift Change (Layer 3) | Every tick produces exactly one ObserverSnapshot. No drops. No duplicates. In order. |
| SimRng determinism | D-030 #7 | Shift Change | RNG consumed in fixed system order. Explicit `.after()` constraints on all consumers. |
| Time system | D-031 | Decay Observatory | 10 ticks = 1 game-minute. Day phases drive routine transitions. |
| Simulation tiers | D-026 | Shift Change | Active tier: full sim. Entities within scope tags stay fully simulated. |
| MessagePack serialization | D-020 | Cross-language fixture tests (Hoshe) | Boundary values roundtrip. Bug #4 class prevented. |
| StableId/EntityRegistry | D-041 | All rooms with NPCs | Unique IDs. Bidirectional mapping. No dangling references. |
#### Content Systems
| System | Decision | Room(s) | Key Assertion |
|--------|----------|---------|---------------|
| NPC 10-axis model | D-024 | Crowd Plaza, Dialogue Room | Want, Secret, Relationships, Tolerance, Routine, Information, Contentment, Personality, Tell, Skill. |
| Social site as unit | D-025 | Crowd Plaza | 4-8 NPCs in connected space with sightlines. |
| Dialogue — tagged pools | D-028 | Dialogue Room | 4 layers: access tier, relationship history, trust-gated gossip, unprompted disclosure. |
| Tag taxonomy | D-035 | Dialogue Room | 6 structural + 3 selection tags per line. Tag filtering produces valid line selection. |
| Two-tier animation | D-047 | Eavesdrop Alcove, Confrontation Stage | Tier 1 (clear activities) instantly readable. Tier 2 (ambiguous behaviors) observable but intention unclear. |
| Population ratio | D-029 | Crowd Plaza | ~30% flat, ~50% mundane triangles, ~20% entangled. Signal requires noise floor. |
### Coverage Gaps: Systems With NO Room Coverage
| System | Decision | Gap | Recommendation |
|--------|----------|-----|----------------|
| ~~Weather affecting vision cones~~ | D-050 | v0.1 deferred | No action needed |
| ~~Perception mode switching cost~~ | D-017 soft degradation | D-059 scan-line interference at high load | Could test in Occlusion Corridor by toggling modes rapidly. Low priority — soft visual effect. |
| Favorite colors — object identification | D-052 | No room tests object-layer color as identification mechanic | **Add to Inventory Warehouse**: place personal objects (mug, cushion) with NPC favorite colors. Assert saturation below D-033 entity color. v0.1.2+ system — defer room addition. |
| News ticker | D-039 wow #5 | No room tests dual-character ticker reactions | Not a Gauntlet room — this is content-level, tested via the line previewer. No room needed. |
| Idle reflective monologue | D-039 wow #6 | Partially covered by Eavesdrop Alcove (time_idle trigger) | Eavesdrop Alcove covers the mechanic. The "wow moment" quality is a content concern, not a systems test. |
| Diegetic insert/POI navigation | D-013 | No room tests POI discovery or insert minimap | **Add to Hub**: place POI markers that appear/disappear based on knowledge state. Low priority — insert UI is v0.1 stretch. |
| Environmental neutrality | D-045 | No room verifies that world layer DOESN'T change with narrative state | **Assertion on Dialogue Room**: pre-confrontation and post-confrontation CanvasModulate values are identical. Zone lighting unchanged. Add as assertion, not a room. |
**Verdict: 3 minor gaps, all addressable as assertions on existing rooms. No new rooms needed for coverage.**
---
## 2. Anti-Tedium Feature Mechanics
Ozzie proposed 6 anti-tedium features. All approved by the lead. Let me map each to concrete game mechanics.
### 2.1 Room Reset Trigger
**Mechanic: Reset Plate — a special TileKind at each room entrance.**
**Implementation:**
- **Tile type:** `TileKind::ResetPlate` — a new variant in the tile enum. Rendered as a floor plate with a distinct visual (pulsing outline, insert-style geometric pattern).
- **Trigger:** Player steps onto the ResetPlate tile AND presses the Interact key (not automatic — prevents accidental resets during sprint-throughs).
- **Server-side behavior:**
1. Identify the room boundary (room_id from ResetPlate's associated metadata)
2. For all entities within the room boundary:
- Reset position to tick-0 spawn position (stored in `GauntletSpawnPosition` component)
- Reset KnowledgeGraph to tick-0 state (stored in `GauntletKnowledgeBaseline` component)
- Reset relationship state to tick-0 baseline
- Reset inventory to tick-0 baseline (for Inventory Warehouse)
- Reset any active cognitive delays, monologue queues, dialogue state
3. Reset fog exploration state for tiles within the room boundary to unexplored
4. Reset the player's KnowledgeGraph entries that reference entities in this room only
5. Do NOT reset: player position (they're standing on the plate), global game time, player inventory items from other rooms
**What resets (per room type):**
| Room | Entity positions | Entity KG | Player KG (room refs) | Player inventory | Fog | Dialogue state |
|------|-----------------|-----------|----------------------|-----------------|-----|---------------|
| Inventory Warehouse | Yes | N/A | Yes | YES (clear room items) | Yes | N/A |
| Occlusion Corridor | Yes | N/A | Yes | No | Yes | N/A |
| Interaction Gallery | Yes | N/A | Yes | No | Yes | N/A |
| Crowd Plaza | Yes | N/A | Yes | No | Yes | N/A |
| Fog Theater | Yes | N/A | Yes | No | YES (critical) | N/A |
| Dialogue Room | Yes | Yes (trust tiers) | Yes | No | Yes | YES (reset tree) |
| Confrontation Stage | Yes | Yes | Yes | No | Yes | YES |
| All others | Yes | If applicable | Yes | No | Yes | If applicable |
**ECS implementation sketch:**
```rust
// New components for Gauntlet entities
#[derive(Component)]
pub struct GauntletSpawnPosition(pub TilePosition);
#[derive(Component)]
pub struct GauntletKnowledgeBaseline(pub KnowledgeGraph);
#[derive(Component)]
pub struct GauntletRoomId(pub u8);
// Reset system — triggered by player input on ResetPlate tile
fn reset_gauntlet_room(
room_id: u8,
entities: Query<(&GauntletRoomId, &GauntletSpawnPosition, &mut TilePosition, ...)>,
mut player_kg: Query<&mut KnowledgeGraph, With<PlayerCharacter>>,
) { ... }
```
**Why Interact, not automatic:** Automatic reset on step creates chaos during cross-room transitions. Sprint through the Hub into the Occlusion Corridor — you DON'T want the corridor to reset just because you crossed the plate. The deliberate Interact press is the "I want to try this again" signal.
### 2.2 Hub Teleport
**Mechanic: Debug command, not a gameplay mechanic.**
**Implementation:**
- **Trigger:** Keyboard shortcut (Home key or backtick). NOT an in-game interaction — this is a testing tool.
- **Behavior:**
1. Immediately move player entity to Hub center position (`GAUNTLET.hub_center`)
2. Clear any active dialogue/monologue state
3. Clear interaction buffer
4. Do NOT reset any room state (rooms maintain their current state — the tester left, they didn't reset)
5. Do NOT affect game time or tick count
- **Server-side:** New `PlayerAction::TeleportToHub` variant. The server validates this is a Gauntlet-only action (rejected in non-Gauntlet maps).
- **Game state impact:** Position changes. That's it. No KG changes, no relationship changes, no inventory changes. The player just "walked really fast" back to the Hub.
**Why debug command, not gameplay:** Hub teleport breaks the information model (instant position change violates D-015 camera lock and D-011 fog progression). It exists for testing efficiency, not gameplay. The `--gauntlet` server flag enables it; production builds reject it.
### 2.3 WRONG Button (F12)
**Mechanic: State capture system with minimal human input.**
**What gets captured:**
| Layer | Data | Size estimate |
|-------|------|--------------|
| **ObserverSnapshot** | Full current snapshot (what the client sees) | ~5-20 KB (MessagePack) |
| **World digest** (per Dudley's spec) | Entity count, registry count, RNG position, NPC positions | ~1-2 KB (JSON) |
| **Input history** | Last 100 ticks of PlayerInput | ~2-5 KB (JSON) |
| **Tick number + room ID** | Current tick, current room (from player position) | ~50 bytes |
| **Text render** | `format_snapshot_text()` output (per Tyre's spec) | ~2-5 KB (text) |
| **Human description** | One-line text from tester | ~100 bytes |
**Minimum viable capture (Sprint 8):**
1. ObserverSnapshot (already exists — just serialize current buffer)
2. Tick number + player position
3. Text render output (once Tyre's formatter exists)
4. Human description prompt
**Full capture (Sprint 9+):**
Add world digest, input history, and deterministic replay seed.
**Output directory:** `tests/bug-reports/gauntlet-{tick}-{timestamp}/`
```
tests/bug-reports/gauntlet-0142-20260217T141523/
snapshot.msgpack # ObserverSnapshot
snapshot.json # Human-readable JSON
text-render.txt # Formatted text output
digest.json # World digest (Sprint 9+)
inputs.json # Last 100 ticks of input (Sprint 9+)
description.txt # "NPC behind wall was visible"
```
**Why this is the minimum:** The snapshot + text render + human description gives a developer everything they need to understand WHAT was wrong. The input history + seed (Sprint 9+) gives them everything they need to REPRODUCE it. Minimum viable = understand. Full = reproduce.
**Server-side:** New `PlayerAction::BugReport { description: String }`. Server serializes state to the output directory. This is a Gauntlet-only action.
---
## 3. Cross-Room Transition Scenarios (Refined for Hub-and-Spoke)
Ozzie's hub-and-spoke layout with cross-cuts defines which rooms physically connect. Let me refine my Round 1 transition scenarios based on the actual topology.
### Physical Layout (from Ozzie R1)
```
[Fog Theater]
|
[Inventory] --- [CENTRAL HUB] --- [Occlusion Corridor]
| | |
[Interaction [Pause Chamber] [Crowd Plaza]
Gallery] |
[Dialogue Room]
|
[Zone Gate (reserved)]
```
**Cross-cut corridors (Ozzie R1):**
- Crowd Plaza <-> Occlusion Corridor
- Fog Theater <-> Dialogue Room
- Inventory Warehouse <-> Interaction Gallery
**New rooms to add to layout:**
```
[Fog Theater]----[Sound Lab]
| |
[Inventory] --- [CENTRAL HUB] --- [Occlusion Corridor]
| | |
[Interaction [Pause Chamber] [Crowd Plaza]
Gallery] | |
| [Dialogue Room] [Shift Change]
| |
[Sprint [Confrontation [Eavesdrop
Gauntlet] Stage] Alcove]
|
[Decay Observatory]
|
[Zone Gate (reserved)]
```
**New connections (proposed cross-cuts for system combination testing):**
- Sprint Gauntlet <-> Interaction Gallery (sprint suppression into interaction range)
- Confrontation Stage <-> Eavesdrop Alcove (confrontation vulnerability into listening)
- Sound Lab <-> Fog Theater (sound pings across fog boundaries)
- Shift Change <-> Crowd Plaza (density stress into density observation)
### Refined Transition Scenarios
All scenarios now reference physically connected rooms via corridors or cross-cuts.
| # | Scenario | Path | System Combination | Expected Behavior | Testable? |
|---|----------|------|-------------------|-------------------|-----------|
| T1 | Sprint Exit | Crowd Plaza -> (cross-cut) -> Occlusion Corridor | D-055 + D-035 | Interaction buffer cleared during sprint. LOS recalculated at corridor entrance. No stale verbs from Plaza NPCs leak into Corridor snapshot. | YES — direct cross-cut exists |
| T2 | Fog into Dialogue | Fog Theater -> (cross-cut) -> Dialogue Room | D-059 + D-061 + D-060 | Player in light fog, initiates dialogue. Fog state preserved (entity in fog still tracked). Cognitive delay for fog entity completes during dialogue. Monologue from recognition appears ABOVE dialogue box (z-layer 7 vs dialogue at bottom). | YES — direct cross-cut exists |
| T3 | Full Inventory Interact | Inventory Warehouse -> (cross-cut) -> Interaction Gallery | D-065 + D-057 | Carry 9/9 inventory into interaction range. Take verb still offered by server (Phase 1). Client greys it out (Phase 2 filter: inventory full). Other verbs (Talk, Observe) unaffected. | YES — direct cross-cut exists |
| T4 | Sprint into Interaction | Sprint Gauntlet -> (cross-cut) -> Interaction Gallery | D-055 + D-057 | Sprint clears buffer. Arriving at Interaction Gallery entity in Walk stance: verbs repopulate within 1 tick. No buffer corruption from stance transition. | YES — proposed cross-cut |
| T5 | Confrontation to Eavesdrop | Confrontation Stage -> (cross-cut) -> Eavesdrop Alcove | D-070 + D-071 | Post-confrontation: audio dip releasing (1000ms ease-out). Enter Eavesdrop Alcove before dip fully releases. ListeningFocus not yet active (need 30 ticks stationary). Verify: dip release and ListeningFocus activation don't conflict. | YES — proposed cross-cut |
| T6 | Pause Anywhere | Pause Chamber -> Hub -> any room | D-031 + any system | Pause in Pause Chamber. Hub teleport. Enter any room. Unpause. All room systems resume correctly. No state corruption from pause during room transition. | YES — Hub connects all rooms |
| T7 | Sound across Fog | Sound Lab -> (cross-cut) -> Fog Theater | D-018 + D-059 | Sound events from Sound Lab NPCs propagate through wall into Fog Theater. Sound pings render in fog. Cognitive delay fires for recognized entity based on sound alone. | YES — proposed cross-cut |
| T8 | Walk-away Sprint | Dialogue Room -> Hub -> Sprint Gauntlet | D-064 + D-053 | Walk-away from dialogue (300ms fade). Walk to Hub. Sprint to Sprint Gauntlet. KG incompleteness recorded. NPC reaction in Dialogue Room occurs during player's Hub transit. Sprint suppresses any post-dialogue monologue. | YES — Hub path |
**Scenarios dropped from Round 1:**
- "Peripheral Interact" (Fog Theater -> Interaction Gallery): No direct cross-cut. Covered by Interaction Gallery's own peripheral-entity test. Peripheral interaction range is a geometry question, not a cross-room question.
### Corridor Design for Transition Testing
The corridors between rooms aren't just hallways — they're testing infrastructure:
- **Length:** 10-15 sim tiles (~5-7.5 visual tiles) per Ozzie's spec. Long enough to test stance transitions, short enough to not waste time.
- **Zone boundaries:** Each corridor has a zone_id transition at its midpoint. Tests D-073 zone crossfade (1.5-2s audio tween).
- **Fog behavior:** Corridor enters deep fog within 5-6 tiles of leaving a room (D-059 fog gradient over 6-8 sim tiles). Tests fog re-engagement.
- **Reset plates:** At each room entrance (room side of corridor, not hub side). Tester walks corridor, hits plate, room resets.
---
## 4. Invariant Prioritization: Top 10 for Sprint 8
Ranked by: (1) does it catch a bug class we've actually seen? (2) how many systems does it protect? (3) implementation cost.
| Rank | ID | Invariant | Bug Catalogue Match | Systems Protected | Implementation | Sprint 8? |
|------|-----|-----------|-------------------|------------------|----------------|-----------|
| **1** | INV-T04 | Pause coherence | Bug #3 (movement while paused) | Pause, movement, state transitions | Dudley's 8 test cases exist. Just wire up. | YES — direct regression guard |
| **2** | INV-T01 | Deterministic replay | Bug #1 class (state divergence) | ALL systems | Tyre's determinism test spec + 4 fixes. Core value of the Gauntlet. | YES — Gauntlet's raison d'etre |
| **3** | INV-T03 | Snapshot delivery | Bug #1 (no snapshots), Bug #5 (overwrite) | IPC, bridge, client-server | Layer 3 subprocess test (Hoshe's spec). Catches the exact bug class. | YES — prevents #1 recurrence |
| **4** | INV-T05 | Input ordering | Bug #1 (blocking read stalls schedule) | IPC, input processing, tick ordering | Covered by Layer 3 test + Dudley's pause tests. | YES — part of Layer 3 |
| **5** | INV-S01 | Player spawn reachable | No bug yet, but SOFTLOCK risk | Pathfinding, map loading, content validation | Single pathfind check at map load. ~10 lines. | YES — trivial, high value |
| **6** | INV-C03 | StableId uniqueness | No bug yet, but CORRUPTION risk | Knowledge graph, entity lifecycle, save/load | Dudley's 4 registry lifecycle tests. | YES — direct from Dudley R1 |
| **7** | INV-C07 | Dialogue pool non-empty | No bug yet, but PLAYER-FACING failure | Dialogue, tag filtering, content pipeline | Load-time validation (Tyre's cross-reference validator). | YES — part of content validation |
| **8** | INV-T02 | Tick budget | Bug #6 class (rate mismatch) | Performance, entity density, all tick systems | Shift Change room perf assertion (p95 < 20ms per Tyre). | YES — performance gate |
| **9** | INV-P02 | LOS symmetry | No bug yet, but FAIRNESS guarantee | Shadowcasting, NPC perception, information boundaries | Property-based test: random positions, verify A sees B iff B sees A. | YES — D-035 mandates symmetry |
| **10** | INV-S05 | No entity inside geometry | No bug yet, but content scaling risk | Content loading, entity spawning, map geometry | Check at map load: every entity spawn position is walkable. | YES — trivial, prevents softlocks |
### Deferred to Sprint 9+
| Rank | ID | Invariant | Reason for deferral |
|------|-----|-----------|-------------------|
| 11 | INV-T06 | SimRng consumption order | Depends on determinism fixes landing first (Sprint 8 P0) |
| 12 | INV-T07 | Cognitive delay monotonicity | Cognitive delay system not yet implemented |
| 13 | INV-T08 | Knowledge decay timing | Decay system implemented but not yet connected to fog rendering |
| 14 | INV-S06 | 2x2 geometry minimum | Requires map validation tooling not yet built |
| 15 | INV-P03 | Fog layer ordering | Fog shader is client-side; needs gdUnit4 test (Stig's domain) |
| 16 | INV-P04 | Insert independence | Insert overlay not yet implemented |
| 17 | INV-S07 | Zone boundary coherence | Zone system not yet implemented |
| 18 | INV-P05 | Sound propagation coherence | Sound propagation not yet implemented |
| 19 | INV-C06 | Monologue trigger reachability | Requires monologue system + content cross-reference |
| 20 | INV-S04 | NPC routine paths valid | Requires NPC routine system + pathfinding integration |
### Bug Catalogue Mapping
Every Sprint 6-7 bug is now covered:
| Bug | Root Cause | Invariant(s) | Room(s) | Test Type |
|-----|-----------|-------------|---------|-----------|
| #1 Server never sends snapshots | read_framed() blocking | INV-T03, INV-T05 | Layer 3 subprocess test | Integration |
| #2 Camera doesn't center | No snapshot until keystroke | INV-T03 | Layer 3 + client gdUnit4 | Integration + unit |
| #3 Player moves while paused | process_player_input ignores TickRate | INV-T04 | Pause Chamber | Unit (Dudley's 8 tests) |
| #4 MessagePack -128 for 128 | Signed int8 branch boundary | Hoshe's BV matrix (41 values) | Fixture tests | Unit + cross-language |
| #5 Monologue lost on overwrite | Snapshot buffer drops one-shots | INV-T03 | Shift Change (density) | Integration |
| #6 Snapshot overwrite warning | Server faster than client | INV-T02, INV-T03 | Shift Change (perf) | Performance |
---
## Summary
### Deliverables
1. **Coverage matrix**: 50+ system-to-room mappings. 3 minor gaps identified (favorite colors, POI navigation, environmental neutrality assertions) — all addressable without new rooms.
2. **Anti-tedium mechanics**: Reset Plate (Interact-triggered, per-room state rollback), Hub Teleport (debug command, position-only), WRONG Button (MVP: snapshot + text render + description; full: + input history + replay seed).
3. **8 transition scenarios**: Refined for hub-and-spoke layout with cross-cuts. All physically testable. Corridor design specified (10-15 tiles, zone boundary at midpoint, reset plate at room entrance).
4. **Top 10 invariants for Sprint 8**: Prioritized by bug catalogue match. Every Sprint 6-7 bug class covered. INV-T04 (pause) and INV-T01 (determinism) are #1-#2.
### Open Questions for Round 3
1. **Room ordering in Gauntlet YAML**: Should rooms have a canonical ordering in the content pack? Affects entity StableId assignment (lower room = lower IDs). Determinism depends on consistent entity spawn order.
2. **Reset Plate vs full server restart**: Is per-room reset sufficient, or do some tests require a clean server state? If the latter, the Gauntlet needs a "full reset" command alongside per-room resets.
3. **Cross-cut corridor count**: I proposed 4 new cross-cuts (Sprint Gauntlet<->Interaction Gallery, Confrontation Stage<->Eavesdrop Alcove, Sound Lab<->Fog Theater, Shift Change<->Crowd Plaza). Is this too many? Each cross-cut adds map complexity. Could consolidate Sound Lab into Occlusion Corridor as a sub-area instead of a separate room+cross-cut.