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

28 KiB

title, description, type, status, workshop, agent, round, created
title description type status workshop agent round created
QA Strategy & Test Architecture Workshop — Round 3 Notes Qatux's synthesis notes from round 3 prioritization and final specifications workshop archived test-architecture 3 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)
  6. Content cross-reference validation (1.5d)
  7. 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

# 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).