fix: make ScannerSession disposal terminal - #49
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Terminal lifecycle audit resultAll code, API, browser, benchmark, package, native, soak, tracking, industrial, and device-evidence checks passed for da4976c. Fail-closed blocker: Stable Release Gate failed twice (initial run and one retry) before any stable verifier or publication action. Both attempts reached Verify required npm publication credentials and npm whoami returned E401 Unauthorized for registry.npmjs.org. This is an external repository-secret credential failure, not a ScannerSession test or stable-artifact integrity failure. Local stable:manifest:verify and stable:publication:verify both pass. No release, publication, manifest, or physical evidence was changed. Issue #13 remains OPEN with POST_RELEASE_VALIDATION_PENDING and zero physical counts. Final stage verdict while the required remote gate is red: SCANLY_SCANNER_TERMINAL_LIFECYCLE_NO_GO. |
Base
BASE_MAIN_SHA: fa6c51a
HEAD_SHA: da4976c
Base: main
The branch was created directly from the fetched origin/main. develop was not merged or cherry-picked.
Reproduction
On the unmodified base implementation, the new scanner lifecycle test file produced 7 failures out of 19 tests. ScannerSession start -> dispose -> start resolved successfully and returned to scanning even though its default owned BrowserScannerFrameDecoder had already been permanently disposed. Dispose from idle, reset after dispose, switchSource after dispose, repeated decoder disposal, and injected-decoder session reuse exposed the same terminal-boundary gap.
Root cause
ScannerSession.dispose() stopped the source/scheduler, disposed only an owned decoder, and cleared listeners, but ScannerSession itself had no terminal lifecycle identity. start() treated stopped as restartable and called reset(), so the public session could re-enter scanning with a permanently disposed owned decoder.
Existing tests covered late completion of a pending start during stop/dispose, but did not attempt to reuse the object after dispose. They also did not distinguish ScannerSession lifecycle ownership from injected decoder resource ownership or assert coalesced repeated disposal.
Ownership distinction
ScannerSession lifecycle and decoder resource ownership are now independent:
Fix design
Regression tests
LIFE-D1 through LIFE-D10 cover owned-decoder restart, idle disposal, restart after stop, idempotent concurrent disposal, pending start, active decode drain, source switching, reset, injected decoder preservation/session terminality, late callbacks, listener cleanup, frame release, scheduler counters, worker/task counters, and controlled memory. A separate dispose-from-stopped case completes the lifecycle matrix.
Red evidence before production changes: 12 passed / 7 failed.
Final targeted evidence: 7 files / 72 tests passed, including 20 scanner-lifecycle and 16 scanner-session tests.
Public API
npm run api:snapshot: PASS. No ScannerSessionOptions, ScannerSessionState, ScannerFrameDecoder, mandatory property, or public declaration snapshot change.
Commands executed
The first browser benchmark attempt was correctly rejected by three stale ignored local tracking JSON files from an older source identity. They were isolated without modifying tracked evidence; the clean-source rerun passed 48/48, and the original ignored files were restored byte-for-byte by SHA-256.
Resource cleanup evidence
The active-decode disposal regression asserts decoder cancel once, owned frame dispose once, no result/observation/diagnostic/state publication after terminal entry, activeDecodeCount=0, pendingFrameCount=0, activeTaskCount=0, emittedEvents=0, and finalControlledMemory=0. Worker client/scanner worker tests also verify cancelled work drains and worker activeTaskCount returns to zero.
Stable artifact and physical truth integrity
No v2.0.0 tag, GitHub Release, npm package, Android AAR, stable manifest, publication record, RC evidence, or physical evidence was modified. Stable manifest and publication verification both pass.
Issue #13 remains OPEN and untouched. All physical rows remain POST_RELEASE_VALIDATION_PENDING and all physical counts remain zero; no physical PASS is claimed.