Files
settled-reach/docs/test-plans/sprint-11-combine.md
T
jpmschweitzerandClaude Opus 4.6 9d2ab53302 docs(docs): add frontmatter to test plans, test reports, and audits
Standardized YAML frontmatter on 7 files across docs/test-plans/,
docs/test-reports/, and docs/audits/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:55:30 +01:00

8.1 KiB

title, description, type, status, ticket, created, updated
title description type status ticket created updated
Sprint 11 Combine — #507 and #522 Test plan for Sprint 11 combining WRONG button ring buffer (#507) and OQ-07 no-insert interaction behaviour (#522), covering happy paths, edge cases, integration, and performance tests. test-plan active #507, #522 2026-02-19 2026-02-19

Test Plan: Sprint 11 Combine — #507 and #522

  • Date: 2026-02-19
  • Sprint: 11 (Combine)
  • Spec references: D-056, D-057, D-030, D-020
  • Tickets: #507 (WRONG button ring buffer), #522 (OQ-07 no-insert behavior)
  • QA Engineer: Hoshe

#507: WRONG Button Full Captures

Spec reference

D-030 (testability), D-020 (ObserverSnapshot boundary). Sprint 11 client.md §Notes #507.

What's changing from MVP (#495)

MVP (done Sprint 9): F12 → pause → single snapshot → render.txt + snapshot.json + description.txt. Upgrade: 60-tick rolling ring buffers (inputs + snapshots), seed file, replay compatibility.

Happy path tests

  1. Ring buffer capacity: _get_buffer_capacity() returns 60.
  2. Buffer pre-allocation: Buffer array has 60 slots immediately after _ready(), no lazy allocation.
  3. Input push fills buffer: After pushing 10 ticks of inputs, buffer has 10 entries.
  4. Snapshot push fills buffer: After pushing 10 snapshots, snapshot buffer has 10 entries.
  5. JSONL format — inputs: _format_inputs_jsonl() returns N lines for N ticks pushed, each line is valid JSON array.
  6. JSONL format — snapshots: _format_snapshots_jsonl() returns N lines for N ticks, each line is valid JSON.
  7. JSONL line format matches replay.rs: Each line is a JSON array of PlayerInput objects ([{"tick":N,"action":"..."}]), parseable by tooling/test-client --replay.
  8. Empty tick flush: An idle tick pushes an empty array [] to input buffer; flushes as [] line.
  9. seed.txt present: seed.txt is written to the report directory on capture.
  10. description.txt unchanged: Description, tick, room, stance, facing, position all still present.
  11. Directory name unchanged: gauntlet-t{tick}-{timestamp}/ format preserved.
  12. Existing files preserved: snapshot.json and render.txt still written (MVP files).

Edge cases

  1. Ring buffer circular overwrite: After pushing 61 ticks, buffer has 60 entries (oldest evicted, newest kept).
  2. Ring buffer 60 exact: After pushing exactly 60 ticks, all 60 present, none evicted.
  3. Pre-F12 no inputs: Before any tick inputs are pushed, flush produces empty or correct minimal JSONL.
  4. Snapshot before any tick: Flush with no snapshots pushed produces empty JSONL or safe fallback.
  5. Seed missing in snapshot: If server hasn't sent seed yet, seed.txt is written with "unknown" or zero value (not crash).
  6. Directory creation failure: If user://bug-reports/ is unwritable, push_error fires but no crash.

Integration tests

  1. Inputs JSONL → replay roundtrip: JSONL produced by flush is valid input for tooling/test-client --replay (format matches replay.rs parse contract).
  2. F12 capture → file structure: Full F12 flow produces expected directory with all 5 files: snapshot.json, render.txt, description.txt, inputs.jsonl, snapshots.jsonl, seed.txt.
  3. Ring buffer does not affect render.txt: Text render output is unchanged from MVP.

Performance tests

  1. No per-tick allocation: Pushing inputs in a tight loop does not allocate new Array objects — buffer reuses pre-allocated slots.
  2. Flush is O(60): Flushing 60 entries completes in < 1ms.

Regression markers

  • MVP _save_report() behavior: snapshot.json, render.txt, description.txt unchanged.
  • F12 → pause → capture → unpause lifecycle unchanged.
  • test_anti_tedium.gd tests must still pass.

#522: Resolve OQ-07 — No-Insert Interaction Behavior

Spec reference

D-056 (cursor states), D-057 (entity interaction). OQ-07 resolution.

Decision context

Three options were proposed. Expected resolution: (a) cursor reverts to default shape only, no verb labels — "the character still physically orients to the target, but receives no information from their insert." This is the most diegetically consistent option per D-056's "diegetic test" framing.

Spec contract regardless of which option is chosen: "If the insert is off, labels disappear."

Happy path tests

Interaction list (z-layer 6) — diegetic test:

  1. Insert-off hides list: When insert_active == false, interaction list is not visible.
  2. Insert-on shows list: When insert_active == true and verbs are present, list is visible.
  3. Re-enable restores list: Toggling insert off then on with verbs present shows the list again.

Cursor (option a — shape changes, labels suppressed): 4. Insert-off still transitions cursor shape: With insert_active == false, hovering over an NPC sets cursor to EntityHover state (shape changes, character physically orients). 5. Insert-off suppresses should_show_interactions(): cursor.should_show_interactions() returns false when insert_active == false. 6. Insert-on restores interactions: After set_insert_active(true), should_show_interactions() returns true (unless in weapon mode).

Cursor (option b — full suppression, if chosen instead): 4b. Insert-off locks cursor to Default: With insert_active == false, hovering over an NPC does NOT change cursor state. 5b. Same should_show_interactions() behavior.

Edge cases

  1. Insert off + weapon mode: insert_active == false AND weapon_mode_active == trueshould_show_interactions() returns false (not double-false confusion).
  2. Insert off + Shift held: insert_active == false AND _shift_held == true — labels STILL suppressed (insert-off trumps shift override).
  3. Insert off at startup: Default state with insert off from the start — no state corruption.
  4. Rapid toggle: Toggling insert on/off rapidly does not leave state machine in inconsistent state.
  5. Insert off during active hover: If player is hovering over an NPC and insert goes off — behavior updates correctly next frame.

Integration tests

  1. Cursor and list agree: When insert_active == false, BOTH cursor's should_show_interactions() AND interaction list's is_showing() return false. They must be consistent.
  2. GameState.insert_active propagates: Changes to GameState.insert_active are picked up by both systems on next update.
  3. Decision amendment recorded: The resolved OQ-07 decision is documented in decisions/perception.md or decisions/scope.md as an amendment to D-056 or D-057.

Regression markers

  • Existing cursor state tests pass: All 19 tests in test_cursor_states.gd must still pass.
  • Existing interaction list tests pass: All tests in test_interaction_list.gd must still pass, including test_insert_off_hides_interaction_list.
  • Sprint suppression still works: test_sprint_suppresses_interaction_list still passes.
  • Weapon mode suppression unchanged: test_weapon_mode_suppresses_interactions still passes.
  • D-045 invariance: Cursor behavior does NOT change by zone or narrative state.

Test Files

  • client/tests/test_bug_report_ring_buffer.gd — automated tests for #507 ring buffer
  • client/tests/test_insert_off_behavior.gd — automated tests for #522 insert-off behavior

Run Command

make test-client

Or headless via gdUnit4:

cd client && godot --headless --quit --path . addons/gdUnit4/bin/GdUnitCmdTool.gd \
  --testsuites "tests/test_bug_report_ring_buffer.gd,tests/test_insert_off_behavior.gd"

Verification Checklist (fill in after implementations land)

  • All happy path tests pass
  • All edge case tests pass
  • All integration tests pass
  • Regression: test_cursor_states.gd — unchanged
  • Regression: test_interaction_list.gd — unchanged
  • Regression: test_anti_tedium.gd — unchanged
  • decisions/perception.md or related file updated with OQ-07 resolution
  • inputs.jsonl format verified against tooling/test-client --replay manually
  • seed.txt present in captured bug report