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>
143 lines
8.1 KiB
Markdown
143 lines
8.1 KiB
Markdown
---
|
|
title: "Sprint 11 Combine — #507 and #522"
|
|
description: "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."
|
|
type: test-plan
|
|
status: active
|
|
ticket: "#507, #522"
|
|
created: 2026-02-19
|
|
updated: 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
|
|
13. **Ring buffer circular overwrite**: After pushing 61 ticks, buffer has 60 entries (oldest evicted, newest kept).
|
|
14. **Ring buffer 60 exact**: After pushing exactly 60 ticks, all 60 present, none evicted.
|
|
15. **Pre-F12 no inputs**: Before any tick inputs are pushed, flush produces empty or correct minimal JSONL.
|
|
16. **Snapshot before any tick**: Flush with no snapshots pushed produces empty JSONL or safe fallback.
|
|
17. **Seed missing in snapshot**: If server hasn't sent seed yet, `seed.txt` is written with "unknown" or zero value (not crash).
|
|
18. **Directory creation failure**: If `user://bug-reports/` is unwritable, `push_error` fires but no crash.
|
|
|
|
### Integration tests
|
|
19. **Inputs JSONL → replay roundtrip**: JSONL produced by flush is valid input for `tooling/test-client --replay` (format matches `replay.rs` parse contract).
|
|
20. **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`.
|
|
21. **Ring buffer does not affect render.txt**: Text render output is unchanged from MVP.
|
|
|
|
### Performance tests
|
|
22. **No per-tick allocation**: Pushing inputs in a tight loop does not allocate new Array objects — buffer reuses pre-allocated slots.
|
|
23. **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
|
|
7. **Insert off + weapon mode**: `insert_active == false` AND `weapon_mode_active == true` — `should_show_interactions()` returns false (not double-false confusion).
|
|
8. **Insert off + Shift held**: `insert_active == false` AND `_shift_held == true` — labels STILL suppressed (insert-off trumps shift override).
|
|
9. **Insert off at startup**: Default state with insert off from the start — no state corruption.
|
|
10. **Rapid toggle**: Toggling insert on/off rapidly does not leave state machine in inconsistent state.
|
|
11. **Insert off during active hover**: If player is hovering over an NPC and insert goes off — behavior updates correctly next frame.
|
|
|
|
### Integration tests
|
|
12. **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.
|
|
13. **GameState.insert_active propagates**: Changes to `GameState.insert_active` are picked up by both systems on next update.
|
|
14. **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
|
|
|
|
```bash
|
|
make test-client
|
|
```
|
|
|
|
Or headless via gdUnit4:
|
|
```bash
|
|
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
|