Files
settled-reach/docs/workshops/test-architecture/round-3-notes.md
T
jpmschweitzerandClaude Opus 4.6 563a295a90 docs(docs): add frontmatter to test-architecture workshop
Standardized YAML frontmatter on all 20 files.

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

602 lines
28 KiB
Markdown

---
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<u64>` -> `BTreeSet<u64>` 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 <host:port> (default: 127.0.0.1:9876)
Input:
--replay <file.jsonl> 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 <file.json> Compare final snapshot, exit 1 on diff
--ticks <N> 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).