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>
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
- Ring buffer capacity:
_get_buffer_capacity()returns 60. - Buffer pre-allocation: Buffer array has 60 slots immediately after
_ready(), no lazy allocation. - Input push fills buffer: After pushing 10 ticks of inputs, buffer has 10 entries.
- Snapshot push fills buffer: After pushing 10 snapshots, snapshot buffer has 10 entries.
- JSONL format — inputs:
_format_inputs_jsonl()returns N lines for N ticks pushed, each line is valid JSON array. - JSONL format — snapshots:
_format_snapshots_jsonl()returns N lines for N ticks, each line is valid JSON. - JSONL line format matches replay.rs: Each line is a JSON array of PlayerInput objects (
[{"tick":N,"action":"..."}]), parseable bytooling/test-client --replay. - Empty tick flush: An idle tick pushes an empty array
[]to input buffer; flushes as[]line. - seed.txt present:
seed.txtis written to the report directory on capture. - description.txt unchanged: Description, tick, room, stance, facing, position all still present.
- Directory name unchanged:
gauntlet-t{tick}-{timestamp}/format preserved. - Existing files preserved:
snapshot.jsonandrender.txtstill written (MVP files).
Edge cases
- Ring buffer circular overwrite: After pushing 61 ticks, buffer has 60 entries (oldest evicted, newest kept).
- Ring buffer 60 exact: After pushing exactly 60 ticks, all 60 present, none evicted.
- Pre-F12 no inputs: Before any tick inputs are pushed, flush produces empty or correct minimal JSONL.
- Snapshot before any tick: Flush with no snapshots pushed produces empty JSONL or safe fallback.
- Seed missing in snapshot: If server hasn't sent seed yet,
seed.txtis written with "unknown" or zero value (not crash). - Directory creation failure: If
user://bug-reports/is unwritable,push_errorfires but no crash.
Integration tests
- Inputs JSONL → replay roundtrip: JSONL produced by flush is valid input for
tooling/test-client --replay(format matchesreplay.rsparse contract). - 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. - Ring buffer does not affect render.txt: Text render output is unchanged from MVP.
Performance tests
- No per-tick allocation: Pushing inputs in a tight loop does not allocate new Array objects — buffer reuses pre-allocated slots.
- Flush is O(60): Flushing 60 entries completes in < 1ms.
Regression markers
- MVP
_save_report()behavior:snapshot.json,render.txt,description.txtunchanged. - F12 → pause → capture → unpause lifecycle unchanged.
test_anti_tedium.gdtests 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:
- Insert-off hides list: When
insert_active == false, interaction list is not visible. - Insert-on shows list: When
insert_active == trueand verbs are present, list is visible. - 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
- Insert off + weapon mode:
insert_active == falseANDweapon_mode_active == true—should_show_interactions()returns false (not double-false confusion). - Insert off + Shift held:
insert_active == falseAND_shift_held == true— labels STILL suppressed (insert-off trumps shift override). - Insert off at startup: Default state with insert off from the start — no state corruption.
- Rapid toggle: Toggling insert on/off rapidly does not leave state machine in inconsistent state.
- Insert off during active hover: If player is hovering over an NPC and insert goes off — behavior updates correctly next frame.
Integration tests
- Cursor and list agree: When
insert_active == false, BOTH cursor'sshould_show_interactions()AND interaction list'sis_showing()return false. They must be consistent. - GameState.insert_active propagates: Changes to
GameState.insert_activeare picked up by both systems on next update. - Decision amendment recorded: The resolved OQ-07 decision is documented in
decisions/perception.mdordecisions/scope.mdas an amendment to D-056 or D-057.
Regression markers
- Existing cursor state tests pass: All 19 tests in
test_cursor_states.gdmust still pass. - Existing interaction list tests pass: All tests in
test_interaction_list.gdmust still pass, includingtest_insert_off_hides_interaction_list. - Sprint suppression still works:
test_sprint_suppresses_interaction_liststill passes. - Weapon mode suppression unchanged:
test_weapon_mode_suppresses_interactionsstill 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 bufferclient/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.mdor related file updated with OQ-07 resolutioninputs.jsonlformat verified againsttooling/test-client --replaymanuallyseed.txtpresent in captured bug report