# QA3 response to V-446 PR https://github.com/chhoumann/PodNotes/pull/446, branch `test/e2e-reliability`. This record supersedes the initial QA3 acceptance report at `76d3fa9`. That head passed the author's four full runs but failed the verifier's four unmutated full runs. Both sets remain evidence; the failures required this round of fixes. ## Independent failures on the prior head | Obsidian | Condition | Result | | --- | --- | --- | | 1.14.4 | Fresh vault, six CPU workers | 112/113 | | 1.14.4 | Reused vault, two other plugins enabled | 111/113 | | 1.14.4 | Reused vault, six CPU workers | 112/113 | | 1.13.7 | Reused vault | 112/113 | V-446 separately proved the individual QA3 fixes, three planted product defects remained detectable, and 24 `jsLiteral` round trips passed. Its PR CodeQL analysis had zero results against **14** on master (12-22 and 28-30). No alert was dismissed. ## Settings failure mechanism `app.json` truncation at restart loses `settingsPopoutWindow: false`. Obsidian then defaults to opening Settings in a popout, while the tests look for its controls in the main window. V-446 observed the file change from the three provisioned settings to `{}` at the renderer-shutdown fixture's restart. The following test and 26 later tests failed, with the new diagnostic naming the lost config. Copies of its before/after files and full report are included here. This identifies the failure mechanism and matches V-427d's missing main-window Settings controls. The exact interrupted write that originally emptied the file remains unobserved. A native keyring Notice does not explain all eight historical screenshots. QuickAdd prior art `65dcf2f3` also links late app-config writes to settings popout cascades. Restoration therefore must restore runtime config and prevent pending app-config writes from replacing the exact saved bytes, as well as saving the file itself. ## Revised implementation and focused verification Head `ebf88bbe806242a396c7e076030b27df9221483b` contains the fixes. `origin/master` was fetched and merged first; it remained `e3243c4`, already merged. - `closePopoutAndReload` keeps its original local reload and 15-second limit, then consumes exactly `POPOUT_RESIZE_LOOP`. J-TS-09 uses the same constant through a popout-only reload helper. General reloads accept no exempt message. The injected loop fails both player variants before and passes both after. A simultaneous unrelated error still fails. - Stale-recorder recovery compares disk config against the exact seeding output minus the recorder id. Both enabled/disabled variants failed with another plugin enabled before, then passed after. - Snapshots include `app.json` and the runtime vault config. Cleanup cancels delayed config saves, restores memory, then restores exact file bytes. Restart repairs the three runner-required settings after the app exits and before relaunch, without resetting the plugin list. The two regression cases empty the file or remove required keys while keeping an unrelated key. They then open Settings in the main window and assert restoration. Both fail before and pass after. Removing save cancellation, runtime restoration, or byte restoration individually makes the regression fail. - The suite hook timeout is restored to 60 seconds. The new regression's 2.5-second observation window exposes a pending one-second app-config save; it does not extend a product wait or retry a failed action. - `jsLiteral` rejects non-finite numbers and negative zero at any depth. All 12 primitive, array, and object probes silently changed values before; all 12 now throw. Existing valid quoting round trips remain covered. The combined focused run passed 22/22 with another plugin enabled. J-TS-09 passed separately. Before/after hashes matched for app.json, community-plugins.json, core-plugins.json, and workspace.json. `SUMMARY.md` indexes the focused evidence. The first regression draft had a test cleanup-order error; its discarded log is retained as `appjson-before-draft.log`. All seven local gates passed on the exact tree subsequently committed as `ebf88bb`: lint, format:check, typecheck, build, test (2132 tests in 114 files), test:tooling (11 tests), and docs:build (18 pages and 112 legacy fragments). `gates-results.json` records the pre-commit base SHA; `final-delta.patch` is the full tested delta with SHA-256 `bc4223d749e4539b0befa4400b91a17c51f996a677b5156211fd08d19faaaa04`. ## Full acceptance on the revised head | Run | Result | Vitest duration | Full command duration | | --- | --- | --- | --- | | 1.14.4, reused with another plugin enabled | 115/115, 16 files | 421.07 s | 423.7 s | | 1.14.4, four CPU workers | 115/115, 16 files | 387.65 s | 392.7 s | | 1.14.4, fresh vault and profile | 115/115, 16 files | 423.43 s | 428.0 s | | 1.13.7, /opt/Obsidian/obsidian | 115/115, 16 files | 422.80 s | 427.3 s | All four full runs used the unchanged head `ebf88bbe806242a396c7e076030b27df9221483b`, with no focused runs or code edits between them. The two new restart cases account for the increase from 113 to 115 tests. These durations record reliability runs, not a performance comparison. The reused run kept `qa3-acceptance-user-tool` enabled and loaded through completion; the post-run inspection verifies this before removing the stand-in. Four CPU workers ran throughout the loaded run, all were alive at completion, and all were terminated and reaped. For the fresh run, the prior vault was moved aside and the instance profile removed. The prior vault was restored after the final run. Final stop and dry-run logs confirm no matching Obsidian instance remains. All five required GitHub checks passed on the new head. [CodeQL JavaScript/TypeScript analysis](https://github.com/chhoumann/PodNotes/actions/runs/38386905200/job/115260833662) `1942647618` ran 87 rules with zero findings, errors, or warnings. Actions analysis `1942645231` ran 17 rules with zero findings. The open-alert query for `refs/pull/446/head` returned an empty list. No alert was dismissed. The first acceptance setup attempt failed before any tests ran because its evidence script required Obsidian's plugin-only module from global eval. The script now uses the CLI version command; the failed setup logs remain in `acceptance-setup-attempt-1/`.