--- title: "QA Strategy & Test Architecture Workshop — Round 3 Notes" description: "Qatux's synthesis notes from round 3 prioritization and final specifications" type: workshop status: archived workshop: test-architecture agent: "" round: 3 created: 2026-02-17 --- # QA Strategy & Test Architecture Workshop — Round 3 Notes **Workshop:** QA Strategy & Test Architecture **Round:** 3 (Prioritization & Final Specs) **Date:** 2026-02-17 **Documenter:** Qatux **Participants:** Tyre, Dudley, Stig, Hoshe, Justine, Gestalt, Ozzie --- ## Executive Summary Round 3 produced build-ready specifications across all tracks. Every agent delivered implementation-level detail: Dudley's determinism patches are copy-pasteable, Justine's Makefile targets are ready for `make`, Stig's 38 client tests have function names and assertion logic, Hoshe's 59-item prioritized backlog has effort estimates and dependency chains, Tyre's Sprint 8 plan has a critical path and dependency graph, Gestalt's Gauntlet map has 48 entities with coordinate positions, and Ozzie's human tester walkthrough covers start-to-finish with terminal mockups. **Key outcomes:** - **Sprint 8 scope:** 10 implementation items, ~7-8 team-days. Infrastructure only — no Gauntlet rooms, no anti-tedium features. Critical path: `--test-mode` (0.5d) -> test client binary (2-3d) -> Layer 3 test (0.5d). - **Gauntlet map:** 7 rooms + Central Hub, 48 entities, 2 cross-cuts, hub-and-spoke topology. Designed for Sprint 8, room content built Sprint 9+. - **All Round 2 open questions resolved.** 11 questions answered: SetTickRate while paused = bug (reject), entity index recycling = safe (generation counter), canonical room ordering = required, blocked_entities = feasible Sprint 9, test client at `tooling/test-client/` (lead override), 0 cross-cuts Sprint 8 (infrastructure only), content-ron in pre-pr = yes, fixed spawn order in setup function, kill+relaunch for full restart. - **One lead override during Round 3:** Test client binary moved from `server/src/bin/test_client.rs` to `tooling/test-client/` as a separate workspace crate. Dudley verified bridge types are already pub-exported — no server changes needed. **Scope tension resolved:** Tyre scopes Sprint 8 as infrastructure-only. Dudley designs a 5-room Gauntlet loader MVP. Gestalt designs the full 7+Hub map. These are compatible: Tyre's Sprint 8 ships the pipes (flags, binary, test harness), Gestalt's map is the design document, Dudley's loader is the Sprint 9 implementation target. The map design happens now; room building happens Sprint 9. --- ## 1. Sprint 8 Implementation Plan (Tyre) ### Dependency Graph ``` S8-1: Determinism fixes ────────────────────────────┐ ├─> S8-5: make pre-pr S8-2: Content cross-ref validation ─────────────────┤ │ S8-3: --test-mode + --port 0 ──> S8-4: Test client ──┤ binary MVP │ │ │ └─> S8-6: Layer 3 test wiring │ S8-7: Pause guard tests ────────────────────────────┘ (parallel, no deps) S8-8: Determinism regression tests ── (after S8-1) S8-9: EntityRegistry lifecycle tests ── (parallel, no deps) S8-10: Fixture staleness check ── (after S8-5) ``` ### Items | # | Item | Owner | Effort | Depends On | |---|------|-------|--------|------------| | S8-1 | Determinism fixes (A, B, D) | Dudley | 0.5d | Nothing | | S8-2 | Content cross-reference validation (9 checks) | Justine | 1d | Nothing | | S8-3 | `--test-mode` + `--port 0` server flags | Dudley | 0.5d | Nothing | | S8-4 | Test client binary MVP | Dudley | 2-3d | S8-3 | | S8-5 | `make pre-pr` chain | Justine | 0.5d | S8-1, S8-2 | | S8-6 | Layer 3 test wiring | Dudley | 0.5d | S8-3, S8-4 | | S8-7 | Pause guard tests (6 tests) | Dudley | 0.5d | Nothing | | S8-8 | Determinism regression tests | Dudley | 0.5d | S8-1 | | S8-9 | EntityRegistry lifecycle tests (3 tests) | Dudley | 0.25d | Nothing | | S8-10 | Fixture staleness check | Justine | 0.25d | S8-5 | **Critical path:** S8-3 (0.5d) -> S8-4 (2-3d) -> S8-6 (0.5d) = 3-4 days. **Total:** Server (Dudley) ~5-6d, Tooling (Justine) ~1.75d = ~7-8 team-days. ### What Explicitly Does NOT Ship Sprint 8 - Gauntlet room content (rooms 1-14) - Anti-tedium features (room reset, hub teleport, WRONG button) - Crossterm live terminal display - CI automation (Gitea Actions) - Performance baselines - Encoding asymmetry cross-language tests - Client tests (Stig's 38) - Cross-room transition scenarios --- ## 2. Determinism Fixes — Final Patch Specs (Dudley) Three fixes shipping Sprint 8. Fix C was already done (self-corrected in Round 2). Total: ~22 lines production code, 4 regression tests. ### Fix A: BTreeSet for visible_positions + sort visible_tiles **Files:** `server/src/perception/query.rs`, `server/src/perception/observer/mod.rs` - `visible_positions: HashSet<(i32, i32)>` -> `BTreeSet<(i32, i32)>` in `VisibilityGeometry` - `visible_ids: HashSet` -> `BTreeSet` in `filter_visible_entities` - Add `visible_tiles.sort_by_key(|t| (t.x, t.y))` after collection - Update `collect_remembered_entities` signature to accept `&BTreeSet` - `sector_lookup: HashMap` stays as-is (point-lookup only, confirmed safe per OQ-4) **Regression tests:** `snapshot_visible_tiles_are_sorted`, `sprint_anomaly_picks_lowest_stable_id` ### Fix B: Sort visible entities by entity_id **File:** `server/src/perception/observer/mod.rs` Insert `entities.sort_by_key(|e| e.entity_id);` after `collect_remembered_entities`. **Regression test:** `snapshot_entities_sorted_by_id` ### Fix D: Sort movers in validate_movement **File:** `server/src/simulation/movement.rs` Collect movers into Vec, sort by `entity.to_bits()`, then process. Deterministic collision resolution — entity with lower `to_bits()` wins contested tiles. **Regression test:** `validate_movement_deterministic_collision_winner` --- ## 3. Server `--test-mode` Final Spec (Dudley) Complete `main.rs` replacement provided. Key design: | Aspect | Behavior | |--------|----------| | Stdout | `LISTENING:{port}` after TCP bind (test client parses this) | | Stderr | All tracing via `tracing_subscriber::fmt::layer().with_writer(std::io::stderr)` | | Content | Gauntlet content pack (when ready), fallback to proof room | | Seed | `--seed 42` default in test-mode | | Shutdown | Exits after first client disconnect | | Port | `--port 0` for OS-assigned port (uses existing `accept_on(listener)`) | `setup_proof_room()` extracted as reusable function for both modes. --- ## 4. Test Client Binary Final Spec (Tyre + Dudley) ### Lead Override: Crate Location **During Round 3, the lead overruled the Round 2 location.** Test client moves from `server/src/bin/test_client.rs` to `tooling/test-client/` as a separate workspace crate. **Note:** Tyre's Round 3 spec was written before this override and still references `server/src/bin/`. Dudley's addendum confirms the override and verifies all bridge types are already pub-exported — no server changes needed. ### CLI (Sprint 8 MVP) ``` settled-reach-test-client [OPTIONS] Connection: --connect (default: 127.0.0.1:9876) Input: --replay JSONL input file (one JSON array per tick) Output (mutually exclusive): --text Structured text to stdout (default) --json JSON to stdout (for golden files) --quiet No output (CI assertions only) Assertions: --golden Compare final snapshot, exit 1 on diff --ticks Disconnect after N ticks ``` ### Text Output Format ``` === Tick 42 | Player (15,10) facing East | Stance: Walk | TickRate: Full === Game time: Day 0, 04:12 (Morning) Room: Occlusion Corridor Entities (5): npc:100 (18,10) Forward rel:Neutral vis:Visible d=3 ... Tiles: 31 visible Interactions (2): npc:100 [Talk(1), ExamineNpc(2)] distance=3 Inventory: 2/9 [item:300(slot-0), item:301(slot-3)] Monologue: "Something about this manifest doesn't add up." === ``` Entity labels: `kind:entity_id`. Sorted by distance (nearest first), ties broken by entity_id. Sections with no data omitted. ### Text Renderer `server/src/bridge/text_renderer.rs` — library function `format_snapshot_text()` callable by the test client crate and integration tests. Pub-exported from server crate. Full implementation (~100 lines) provided by Tyre. ### Golden File Comparison JSON with sorted keys. Recursive `diff_json_values()` produces field-by-field diff on mismatch. Exit code 1 on diff. ### Replay Format JSONL — one JSON array of `PlayerInput` per line. Empty array `[]` = idle tick. Uses `rmp_serde::to_vec` (NOT `to_vec_named`) to match GDScript encoding. ### Effort Estimate ~2-3 days: binary scaffolding (0.5d), text renderer (0.5-1d), replay loading (0.5d), golden file comparison (0.5d), Layer 3 wiring (0.5d). --- ## 5. Gauntlet Map Specification (Gestalt) ### MVP Room List: 7 rooms + Central Hub | # | Room | Size | Observer | Facing | Entities | |---|------|------|----------|--------|----------| | 0 | Central Hub | 24x24 | (50,58) | -- | 4 signs | | 1 | Fog Theater | 44x32 | (56,18) | South | 4 (3 NPCs, 1 object) | | 2 | Occlusion Corridor | 42x22 | (84,58) | East | 4 NPCs | | 3 | Inventory Warehouse | 30x28 | (17,54) | East | 11 (10 objects, 1 NPC) | | 4 | Interaction Gallery | 24x20 | (14,92) | East | 5 (2 NPCs, 3 objects) | | 5 | Pause Chamber | 16x16 | (50,86) | North | 1 NPC | | 6 | Dialogue Room | 28x20 | (50,114) | North | 4 NPCs | | 7 | Crowd Plaza | 32x32 | (96,94) | West | 15 NPCs | **Total: 48 entities.** Map bounds: 0-116 x 0-124 sim tiles. ### Topology Hub-and-spoke with 2 cross-cuts: - **cross-cut-W:** Inventory Warehouse <-> Interaction Gallery (T3: Full Inventory Interact) - **cross-cut-E:** Occlusion Corridor <-> Crowd Plaza (T1: Sprint Exit) 7 corridors connecting rooms to hub and each other. All 6 tiles wide, 8-14 tiles long. ### StableId Assignment Order Entities receive StableIds in canonical spawn order: 1. Hub entities (signs): StableId 1-4 2. Fog Theater: StableId 5-8 3. Occlusion Corridor: StableId 9-12 4. Inventory Warehouse: StableId 13-23 5. Interaction Gallery: StableId 24-28 6. Pause Chamber: StableId 29 7. Dialogue Room: StableId 30-33 8. Crowd Plaza: StableId 34-48 **Additive-only rule:** Existing rooms and entities are NEVER reordered. New rooms and entities append. This preserves golden file stability. ### Cross-Room Transitions (3 MVP) | # | Transition | Path | Systems Tested | |---|-----------|------|---------------| | T1 | Sprint Exit | Crowd Plaza -> cross-cut-E -> Occlusion | Sprint suppression + LOS recalculation | | T3 | Full Inventory Interact | Inventory -> cross-cut-W -> Interaction Gallery | Inventory limit + verb computation | | T6 | Pause Anywhere | Pause -> Hub -> any room | Pause persistence across teleport/room change | ### Scope Note: Gestalt vs Tyre vs Dudley Gestalt designs 7+Hub rooms for the full Gauntlet. Tyre scopes Sprint 8 as infrastructure-only (no rooms). Dudley designs a 5-room loader MVP as the Sprint 9 implementation target. These are consistent: the map design is complete, room building follows infrastructure. --- ## 6. Client Test Suite — Final 38 Tests (Stig) Deduplicated from 41 candidates (32 original + 6 Tyre additions + 3 Stig R2 additions). | Priority | Count | Sprint | Categories | |----------|-------|--------|-----------| | P0 | 2 | Sprint 8 | Monologue overwrite (Bug #5), camera static during pause (Bug #2) | | P1 | 7 | Sprint 8-9 | Fog shader (4), entity lifecycle (2), pending recognition blob (1) | | P2 | 24 | Sprint 9 | Camera (5), entity alpha/color (5), UI (12), lerp (1), teleport (1) | | P3 | 5 | Sprint 10+ | Z-layer (4), lerp target (1) | Each test includes: function name, category, exact assertions, and setup requirements. ### Fog Constants Added to `client/scripts/autoloads/fog_state.gd`: - `VIS_HIDDEN = 0`, `VIS_PERIPHERAL = 180`, `VIS_FORWARD = 255` - `EXP_UNEXPLORED = 0`, `EXP_EXPLORED = 128`, `EXP_VISIBLE = 255` 5 magic number replacements in `fog_state.gd`. No shader changes needed. --- ## 7. Prioritized Test Backlog — 59 Items (Hoshe) ### Summary by Sprint | Sprint | P0 items | P1 items | Combined effort | |--------|----------|----------|----------------| | Sprint 8 | 10 (~7d) | 15 (~10.75d) | ~17.75d | | Sprint 9 | 10 (~7.5d) | 12 (~12.5d) | ~20d | | Sprint 10+ | -- | 12 (~18.75d) | ~18.75d | ### Sprint 8 P0 (10 items, ~7d) 1. Determinism Fix A (0.5d) 2. Determinism Fix B (0.25d) 3. Determinism Fix D (0.25d) 4. Server `--test-mode` + `--port 0` (1d) 5. `make pre-pr` target (0.5d) 6-8. Pause guard tests: movement_discarded, unpause_accepted, roundtrip (0.75d total) 9. Content cross-reference validation (1.5d) 10. Fixture staleness check (0.25d) ### Bug Catalogue Coverage Every Sprint 6-7 bug has Sprint 8 P0/P1 coverage: - Bug #1 (snapshot delivery): #4 (`--test-mode`), #26 (Layer 3) - Bug #2 (camera startup): #21 (client P0: camera static during pause) - Bug #3 (movement while paused): #6, #7, #8, #13 (pause guard suite) - Bug #4 (MessagePack -128): #15, #16, #17, #18 (boundary value matrix) - Bug #5 (monologue overwrite): #21 (client P0: monologue not lost) - Bug #6 (snapshot spam): #1, #2 (determinism), #29 (golden files) --- ## 8. Tooling Specifications (Justine) ### `make pre-pr` — Final 6-step chain: lint -> build -> test -> validate-content -> check-fact-ids -> fixtures-check. ~90s incremental, ~8min clean cache. Fixture staleness is BLOCKER (not WARNING). Branch-specific variants: `pre-pr-server`, `pre-pr-client`, `pre-pr-content`. Full Makefile provided with failure output examples. ### `make perf-baseline` - Baseline file: `tests/perf/baseline.json` (committed) - Median of 5 runs, thresholds: <15% PASS, 15-30% WARN, >30% FAIL - Machine tag prevents cross-machine comparison - `tooling/perf-compare` and `tooling/perf-update` scripts provided (full bash code) - **Blocked on Gauntlet** — shadowcast bench is the only available benchmark until rooms ship ### Golden File Workflow - Generator: `server/tests/gauntlet_golden_gen.rs` (generates JSON at ticks 0, 10, 100) - Comparator: `server/tests/gauntlet_golden.rs` (field-by-field diff on mismatch) - JSON format: sorted keys, pretty-printed, deterministic - `make golden-diff` / `make golden-update` targets provided - Full Rust code for both (~180 lines combined) ### CI Pipeline Design (Deferred) 3-tier pipeline documented and ready for when lead greenlights: - **Commit tier** (<2min): lint + validate-content + check-fact-ids - **PR tier** (<15min): build + test + fixtures staleness (BLOCKER) - **Nightly tier** (<30min): Layer 3 + golden files + perf benchmarks + content scaling Complete `.gitea/workflows/ci.yaml` provided (~100 lines). Self-hosted runner required. --- ## 9. Content Validation — 9 Checks (Hoshe + Justine merged) Extends `tooling/validate-content` (Python) with a second pass after schema validation. | # | Check | Severity | Source | |---|-------|----------|--------| | 1 | `canonical_id_uniqueness` | ERROR | Hoshe | | 2 | `relationship_target_resolution` | ERROR | Both | | 3 | `location_slug_resolution` | ERROR | Both | | 4 | `dialogue_location_resolution` | ERROR | Both | | 5 | `fact_id_resolution` | ERROR | Both (absorbs `check-fact-ids`) | | 6 | `triangle_membership_resolution` | ERROR | Both | | 7 | `npc_count_accuracy` | WARNING | Hoshe | | 8 | `dialogue_line_id_uniqueness` | ERROR | Hoshe | | 9 | `bidirectional_relationship_consistency` | WARNING | Justine | `ContentIndex` Python class skeleton provided. Phased rollout: Phase 1 (NPC/triangle/district) Sprint 8, Phase 2 (dialogue/fact_ids) Sprint 8, Phase 3 (warnings) Sprint 9. --- ## 10. Anti-Tedium Specifications (Ozzie + Gestalt + Stig + Dudley) ### Sprint 8 Priorities (Ozzie) | Priority | Feature | Effort | Justification | |----------|---------|--------|--------------| | P1 | Room Reset Triggers | 1-1.5d | Can't re-test without it | | P2 | WRONG Button MVP | 1d | Can't report bugs without it | | P3 (Sprint 9) | Hub Teleport | 0.5d | Convenience, not necessity | | P4 (Sprint 9) | Timer + Checklist | 1.5-2d | Engagement, not necessity | **Note:** Tyre's Sprint 8 plan does NOT include anti-tedium features (infrastructure-only scope). Anti-tedium ships Sprint 9 per Tyre's roadmap, Sprint 8 per Ozzie/Gestalt's priority. ### Room Reset — Final Spec - Trigger: Step on ResetPlate + Interact (NOT automatic) - Server: `RoomResetTrigger` component, `RoomSnapshots` resource, 10-tick debounce - Resets: entity positions, KG, fog (room tiles), room-sourced inventory, dialogue state - Does NOT reset: other rooms, player position, session timer, SimRng state - Test-mode only: entities only added with `--test-mode` ### WRONG Button MVP — Final Spec - Hotkey: F12 - Captures: current ObserverSnapshot (JSON), text output, tick/room/seed, tester description - Output: `tests/bug-reports/gauntlet-t{tick}-{timestamp}/` (4 files: report.md, snapshot.json, text_output.txt, description.txt) - Zero server changes needed for MVP - Full version (Sprint 9+): 60-tick ring buffer, input history, replay seed ### Hub Teleport - Home key -> `PlayerAction::TeleportToHub` - Instant camera snap + 0.3s fade-to-black - Gauntlet-only (server rejects in non-Gauntlet maps) ### Client-Side UI (Stig) - `bug_report.gd` autoload: ~80 lines GDScript, F12 handler, ring buffer, modal prompt - `InsertOverlay/FlashRect`: shared by reset flash and teleport fade - `GauntletProgress` overlay: room name, run counter, timer, progress bar (Sprint 9) - Fog constants migration: 6 named constants, 5 line replacements --- ## 11. Human Tester Workflow (Ozzie) ### 6-Phase Walkthrough 1. **Navigate to a Room** — walk from Hub, room name updates, timer starts, checklist loads 2. **Execute the Checklist** — printed checklist or terminal display, auto-tracking for `type: auto` items 3. **Encounter a Bug** — F12 -> pause -> one-line prompt -> 4 files saved -> resume 4. **Reset and Re-Test** — step on reset plate -> room reverts to tick-0 state -> retry 5. **Move to Another Room** — Home -> Hub -> walk to next room 6. **End Session** — Ctrl+C -> session summary (rooms tested, coverage %, times, bug reports) ### Quick-Test Developer Workflow Target: **65 seconds** from fix to verification. Build (10s) -> start server+client (3s) -> navigate (5s) -> test checklist items (45s) -> exit (2s). ### Entity Visibility Symbols | Symbol | State | Meaning | |--------|-------|---------| | `●` | VISIBLE | In clear vision cone | | `◐` | REMEMBERED | In fog, previously seen | | `◌` | FOGGED | Detected but not recognized | | `✕` | BLOCKED | LOS blocked by wall (debug, requires `blocked_entities`) | | `⚡` | RECOGNIZING | Mid-cognitive-delay | ### Test Client Display 10 sections: Header, Player, Entities, Fog, Sound (Sprint 9+), Cognition (Sprint 9+), Interactions, Monologue/Dialogue, Inventory, Status. MVP ships sections 1-4, 7-10. --- ## 12. Checklist YAML Schema (Stig + Ozzie merged) ### Per-Room Format ```yaml # content/gauntlet/rooms/{room_id}/checklist.yaml room: occlusion_corridor checks: - id: occ_01_hidden_not_visible description: "NPC behind wall is NOT visible" type: auto # auto | manual step: "Stand at (45,3), face East" condition: player_near: [45, 3] entity: hidden-1 expected: blocked if_wrong: | LOS leaking through wall. Check shadowcast.rs. ``` ### Condition Grammar (7 types) `player_near`, `player_facing`, `entity` + `expected` (blocked/visible/remembered/recognizing), `expected_sector`, `perception_mode`, `fog_visible_count_min`/`max`, `inventory_count`, `dialogue_active`, `monologue_contains`. ### Cross-Room Checklist `content/gauntlet/cross_room_checks.yaml` at Gauntlet root. Transition scenarios with multi-room paths and structured conditions. ### Auto-Tracking Split | Feature | Godot Client | Test Client | |---------|-------------|-------------| | Room name + timer | Yes | Yes | | Progress bar (X/Y) | Yes (total from YAML) | Yes | | Auto-evaluate conditions | **No** | **Yes** (Rust, type-safe) | | Per-item display | **No** | **Yes** | --- ## 13. Boundary Value Tests — 41 Values (Hoshe) ### Encoding Asymmetry (Resolved) GDScript uses `int_16` for values 256-32767; Rust uses `uint_16`. Both are spec-valid. `rmp_serde` accepts `int_16`-encoded positive values for `u64` fields (Dudley traced through rmp-serde 1.3.1 in Round 2). ### 4-Direction Tests | Direction | What | Location | When | |-----------|------|----------|------| | Rust -> GDScript (fixture) | Snapshots with overlap-zone ticks | `test_msgpack_boundaries.gd` | Every PR | | GDScript -> Rust (fixture) | Inputs with overlap-zone ticks | `serialization.rs` | Every PR | | Rust -> GDScript (raw bytes) | Hand-crafted uint_16/uint_32 bytes | `test_msgpack_boundaries.gd` | Every commit | | GDScript -> Rust (raw bytes) | Hand-crafted int_16/int_32 bytes | `serialization.rs` | Every commit | Full test code provided for all 4 directions. --- ## 14. Layer 3 Test — Final Spec (Hoshe) `server/tests/layer3.rs`, `#[test] #[ignore]`, <10 seconds. - Build server binary - Launch as subprocess with `--test-mode --port 0` - Parse `LISTENING:{port}` from stdout (5-second timeout) - Connect via TCP, send `PlayerInput` via `rmp_serde::to_vec` (not `to_vec_named`) - Receive `ObserverSnapshot`, assert version, tick, entity count, player entity kind - `ServerGuard` drop pattern for cleanup (kill on drop) - Tolerates initial tick=0 snapshot before input processed (Dudley R2 adjustment) Full Rust code (~80 lines) provided. --- ## 15. Resolved Questions ### New Answers from Round 3 | ID | Question | Answer | By | |----|----------|--------|-----| | Q1 (R2-OQ-09) | Canonical room ordering for StableId? | Yes — append-only rule. YAML room order = spawn order = StableId order. | Dudley, Gestalt | | Q2 (R2-OQ-10) | Room reset vs full restart? | Both. Room reset for iteration, kill+relaunch for determinism. | Gestalt | | Q3 | Cross-cuts in Sprint 8? | 0 cross-cuts Sprint 8 (infrastructure only). 2 in map design. Build first 2 Sprint 10. | Tyre, Gestalt | | Q4 (R2-OQ-05) | `blocked_entities` feasibility? | Feasible, ~300 tile lookups/tick. Sprint 9 scope, gated behind `--test-mode`. | Dudley | | Q5 (R2-OQ-07) | Test client binary location? | `tooling/test-client/` (lead override). Bridge types already pub-exported. | Tyre, Dudley | | Q6 (R2-OQ-08) | Cross-room checklist location? | `content/gauntlet/cross_room_checks.yaml` at Gauntlet root. | Gestalt | | Q7 (R2-OQ-01) | SetTickRate while paused? | Bug. Reject. Pause exits only via explicit Unpause. 4-line fix in `input.rs`. | Dudley | | Q8 (R2-OQ-02) | Entity index recycling safe? | Yes (bevy generation counter). Discipline: call `unregister()` on despawn. | Dudley | | R2-OQ-03 | `content-ron` in pre-pr? | Yes, in full `pre-pr` only. Not in `pre-pr-server`. | Tyre | | R2-OQ-06 | Checklist overlay in Godot? | Lightweight overlay (room name + timer). Full tracking test-client-only. | Stig | | R2-OQ-11 (cross-cuts) | 4 cross-cuts too many? | Keep all 4 in design. Build 2 for Sprint 8 map. Don't consolidate Sound Lab. | Tyre, Gestalt | ### Questions Deferred to Implementation | ID | Question | Assigned To | When | |----|----------|-------------|------| | R2-OQ-04 | Fixture staleness separate target? | Justine | Resolved: No. 10-15s cost negligible. | | OQ-11 | Client tests headless stability | Stig | Before making client tests a CI merge gate | --- ## 16. Sprint 9+ Roadmap (Tyre) ### Tier 1: Sprint 9 (~10-12 team-days) R-01: Gauntlet rooms 1-4 (3-4d), R-02: Room reset trigger (1.5d), R-03: Hub teleport (0.5d), R-04: Client tests P0-P1 (2-3d), R-05: Determinism golden files (1d), R-06: Fog byte constants (0.25d), R-07: Encoding asymmetry tests (1.5d). ### Tier 2: Sprint 10 (~15-17 team-days) R-08: WRONG button MVP (2d), R-09: Gauntlet rooms 5-8 (3-4d), R-10: Room timer + PBs (1d), R-11: Checklist auto-tracking (2d), R-12: Performance baselines (1.5d), R-13: Client tests P2 (3d), R-14: Enhanced test client terminal (2d). ### Tier 3: Sprint 11+ (build when needed) Gauntlet rooms 9-14, cross-room transitions, CI automation, content scaling stress, `blocked_entities`, client test headless, client tests P3, additional pause guard tests, WRONG button full capture, bidirectional relationship warnings. ### Risk Register (5 risks) | Risk | Likelihood | Impact | Mitigation | |------|-----------|--------|------------| | Test client takes >3 days | Medium | Delays Layer 3 | MVP scope intentionally minimal | | Proof room too simple for golden files | Low | Golden files don't catch real bugs until rooms exist | Proves toolchain; value comes Sprint 9 | | Content validation finds many existing errors | Medium | Sprint 8 effort bloat | Run as WARNING first sprint | | Client test headless blocks CI | Low | Can't automate client tests | Manual `make pre-pr-client` interim | | Fixture BLOCKER frustrates devs | Low | Devs skip pre-pr | Education; false positives are worse | --- ## 17. Points of Agreement (consensus) 1. **Sprint 8 is infrastructure.** All agents accept Tyre's framing: build the pipes, fill them Sprint 9+. 2. **Determinism fixes are complete.** Copy-pasteable code, 4 regression tests, ~22 lines total. 3. **`make pre-pr` is the developer discipline tool.** Replaces CI until CI is greenlighted. BLOCKER on fixture staleness. 4. **Gauntlet map design is complete.** 7+Hub rooms, 48 entities, 2 cross-cuts. Additive-only constraint. 5. **Test client binary architecture is settled.** `tooling/test-client/` crate (lead override), text renderer in server library, golden file JSON comparison. 6. **38 client tests are prioritized and build-ready.** Function names, assertions, setup — ready for Stig to implement. 7. **Anti-tedium is fully specified.** All 4 features have implementation details. Priority ranked. 8. **All open questions resolved.** Zero questions carry forward to implementation. ## 18. Points of Tension (resolved or minor) 1. **Fixture staleness: BLOCKER.** Tyre's argument accepted by all. Justine updated spec. 2. **Sprint 8 anti-tedium:** Ozzie/Gestalt prioritize room reset + WRONG button for Sprint 8. Tyre defers both to Sprint 9 (infrastructure-only scope). The implementation plan (Tyre) is authoritative for Sprint 8 scope; anti-tedium ships Sprint 9. 3. **Gauntlet room count for Sprint 8:** Dudley (5 rooms), Gestalt (7+Hub). Tyre (0 rooms — infrastructure only). Resolution: map design has 7+Hub, room building is Sprint 9. 4. **Test client location:** Tyre R3 says `server/src/bin/`. Lead overrides to `tooling/test-client/`. Dudley confirms no server changes needed. Lead override is authoritative. 5. **F3 debug overlay:** Deferred indefinitely per Stig. WRONG button captures same data. Ozzie accepts. --- ## 19. Gaps Remaining 1. **Gauntlet content authoring.** Room YAML, entity placement, checklist definitions need writing. No specific agent assigned for content creation. 2. **Client test headless stability (OQ-11).** Still unverified. Must be tested before making client tests a CI merge gate. 3. **Sound events not in ObserverSnapshot.** Required for full test client display (sections 5-6). Not yet designed server-side. 4. **Cognitive delay visual not implemented.** Tyre's tests #33-34 (blob rendering, recognition transition) depend on D-060 client implementation. 5. **Gauntlet map vs Dudley's loader room count.** Gestalt designs 8 rooms (7+Hub). Dudley's loader MVP has 5 rooms. Reconciliation needed during Sprint 9 implementation (which rooms build first).