Follow-up from CodeRabbit review of #665, filed rather than folded in because the code belongs to #664 (approved, awaiting merge) and #665 is deliberately one behavior change.
Owner files can be orphaned forever
Two branches in lib/runtime/app-bind.ts remove a helper status file without checking helperOwnershipMatches:
lib/runtime/app-bind.ts:1560-1563 — dead PID in a running record
lib/runtime/app-bind.ts:1592-1597 — any non-running record
Both then gate removeHelperOwner on helperOwnershipMatches. When the status token and the owner token disagree, unbind deletes the status file and keeps runtime-rotation-app-helper-owner.<pid>.json. The next unbind iterates status paths only, so nothing ever rediscovers that owner file. It accumulates under the multi-auth root indefinitely.
Two coherent policies; the codebase should pick one deliberately:
- Conservative — treat a mismatched record as not ours, preserve both files, warn.
- Decisive — treat the PID as dead and remove both.
Suggested regression coverage in test/app-bind.test.ts: mismatched-token non-running record (both files preserved), dead-PID running record (both files removed), and readdir failing with a non-ENOENT code (warning emitted, legacy path still checked).
Helper unlinks are not retried on Windows
helperCleanupPaths feeds a best-effort unlinkIfExists loop that swallows every error. On Windows, a status file for a helper killed milliseconds earlier can still fail with EBUSY/EPERM, and the record survives unbind. The readdir above it (lib/runtime/app-bind.ts:1512) and the rm below it (:1662) both use withFileOperationRetry; the unlink loop is the remaining gap.
Credit: CodeRabbit, on #665.
Follow-up from CodeRabbit review of #665, filed rather than folded in because the code belongs to #664 (approved, awaiting merge) and #665 is deliberately one behavior change.
Owner files can be orphaned forever
Two branches in
lib/runtime/app-bind.tsremove a helper status file without checkinghelperOwnershipMatches:lib/runtime/app-bind.ts:1560-1563— dead PID in arunningrecordlib/runtime/app-bind.ts:1592-1597— any non-running recordBoth then gate
removeHelperOwneronhelperOwnershipMatches. When the status token and the owner token disagree, unbind deletes the status file and keepsruntime-rotation-app-helper-owner.<pid>.json. The next unbind iterates status paths only, so nothing ever rediscovers that owner file. It accumulates under the multi-auth root indefinitely.Two coherent policies; the codebase should pick one deliberately:
Suggested regression coverage in
test/app-bind.test.ts: mismatched-token non-running record (both files preserved), dead-PID running record (both files removed), andreaddirfailing with a non-ENOENTcode (warning emitted, legacy path still checked).Helper unlinks are not retried on Windows
helperCleanupPathsfeeds a best-effortunlinkIfExistsloop that swallows every error. On Windows, a status file for a helper killed milliseconds earlier can still fail withEBUSY/EPERM, and the record survives unbind. Thereaddirabove it (lib/runtime/app-bind.ts:1512) and thermbelow it (:1662) both usewithFileOperationRetry; the unlink loop is the remaining gap.Credit: CodeRabbit, on #665.