# QA2 response to V-415 PR https://github.com/chhoumann/PodNotes/pull/415. Head `441eef3a949273e1b42072ff74c860643e4c79a8`. Merged `origin/master` at `3d7cc6e` with merge commit `4b8eed3`. No conflicts. The next commit changes only the bounded playback measurement and the requested nits, plus a held-response regression test. No authored src change remains. ## Finding and nits `playbackOver` samples playing episodes for the same 1.5-second observation window as paused episodes. It no longer waits for the position to catch up. The paused-change early return is guarded with `!first.playing`; deleting only the two specified lines would return immediately whenever playback is playing. Held feed responses complete on both `finish` and `close`. The `defaultData` explanation now sits beside `defaultData`. The two redundant `Updating` assertions were removed because their preceding waits check the same text condition. Episode-order assertions remain. ## Mutation proof On real Obsidian 1.14.4, apply `M5.patch` to PodcastView.svelte. Leaving the player schedules a seek backwards by four seconds, clamped to zero, after 600 ms. Run `npm run test:e2e -- -t '#355 audio keeps playing'` with Node v22.23.2 and TMPDIR=/data/home/tmp/podnotes-qa2. - Merged old helper, exit 0. One test passed and 76 skipped. `mutation-before.log` reproduces the missed regression. - Corrected helper, exit 1. One test failed and 76 skipped. `mutation-after.log` reports `on the podcast grid: seconds advanced: expected 0.245224 to be greater than 1`. - Restored src byte-for-byte from HEAD before committing and before the full suites. `source-restored.txt` records the empty source diff. - The failure screenshot was opened and shows the Journey Playback podcast grid. Runtime errors are empty. The log assertion supplies the playback evidence; the screenshot alone cannot show a rewind. The fixture regression runs a real loopback HTTP request and closes its held connection. Without the close handler, release hangs until Vitest's 5-second timeout. With the handler, both fixture tests pass. Logs are `close-before.log` and `close-after.log`. An initial draft that released immediately after client abort passed without the handler because finish could win that race; the final test closes the server connection before release and was proven red before green. ## Final validation All six gates passed at `441eef3`, plus `npm run test:tooling`, which master added to AGENTS.md. Application tests passed 1,714/1,714 across 99 files. Tooling tests passed 10/10. Both Svelte checks reported zero errors and warnings. Docs internal links and all 112 legacy fragments are valid. The first 1.14.4 Vitest suite passed 77/77 across 12 files in 272.18 seconds, despite its parent driver's exit 143. The 1.13.7 complete command passed 77/77 across 12 files, exit 0, in 252.435 seconds. No individual-test retry was configured or invoked. The single full 1.14.4 command retry finished with 76/77, exit 1, in 244.596 seconds. J-PLAY-11 timed out waiting for a checkpoint before restart; #355 and both #413 journeys passed. All three full invocations ran the same 77 unique tests. Both successful command cleanup and the final explicit dry-run reported no owned PIDs. `runs.json`, `default-retry.json`, `checks.json`, and per-command logs record the results. Commands ran via `fnm exec --using 22 --`, with `TMPDIR=/data/home/tmp/podnotes-qa2`. The floor run sets `PODNOTES_OBSIDIAN_APP=/opt/Obsidian/obsidian`; the retry uses the default app selection. `OBSIDIAN_BIN=/usr/bin/false` verifies that the runner supplies the selected CLI rather than inheriting that bogus value. Environment is headless Linux with an isolated `podnotes-test-e2e-hardening` vault. Runtime version lines confirm 1.14.4 and 1.13.7. The mutation's fixture feed is `http://podnotes.test:41355/playback/feed.xml`, with `Long Listen` at `/playback/1.wav`. It resolves locally through the instance's Chromium host mapping. Current bundle SHA-256 is `7f6eb5a2ee8c7e4ddf474082d2594b74314b8b1e0b0af6ad015e8f838bfcf005`. ## Remaining flake Filed https://github.com/chhoumann/PodNotes/issues/421. The final 1.14.4 run failed at `journey-playback.test.ts:198`, waiting 20 seconds for a checkpoint of at least 5 seconds. The post-timeout capture has 15.064597 seconds persisted and a screenshot around 19 seconds; runtime errors and console messages are empty. This suggests, but does not establish, a checkpoint scheduling or polling-deadline race. No fix or additional test round was attempted. The complete command cleaned up normally. [Full evidence archive](https://files.bagerbach.com/qa2-v415-evidence-tar-hforz1tckx2j.gz) contains the logs, mutation patch, source-restore record, state captures, drivers and SHA-256 manifest. The mutation screenshot and remaining-flake screenshot were both opened and inspected. ## Limits and deviations The outer validation driver received SIGTERM during the first 1.14.4 full run. Its detached Vitest child continued. Preserve the exact result separately from the wrapper exit 143; the surviving Vitest suite was allowed to finish. A subsequent full command retry checks normal wrapper completion. The signal source is unknown. Recovery uses a separate process session and performs explicit instance cleanup. The original approximately three-hour QA2 timebox had already overrun to about six hours before this review round. This review and validation are additional time. No new fix round was started for the remaining flake. One progress update incorrectly said the retry remained green because only the log tail was inspected; the final summary exposed the earlier failure, and that update was corrected immediately. Changes and validation were performed in-thread because the reviewer supplied a narrow contract and mechanical edits. The coordinator will dispatch the fresh independent verifier. Fix Root Causes restored the time-window contract; Encode Lessons in Structure keeps the check in the shared helper and proves closed-response completion with a regression test.