test(daemon): gate the claim reap on the errno Windows actually reports

The Windows lane now runs daemon-pid-publish-claim-reap.test.ts, but its only
foreign-owner gate injected EPERM — the POSIX errno. Windows reports a live
but unsignalable process as EACCES (isPermissionError in win32-utils treats
EACCES and EPERM as one), so the errno that lane can actually see had no gate.

The fence is already correct there: it reaps only on ESRCH, so every other
errno reads as alive. No production change — this pins that for EACCES too,
so a later broadening to "any kill() error means dead" cannot land unnoticed
and delete a live publisher's claim on Windows.
This commit is contained in:
Brennan Benson
2026-08-28 08:10:26 -07:00
parent 91281c4dd3
commit 753a104d27
@@ -99,6 +99,24 @@ describe('reapOrphanedDaemonPidPublishClaims', () => {
expect(existsSync(foreign)).toBe(true)
})
it('keeps a claim whose owner is live but unsignalable on Windows', () => {
// Why a second errno: Windows reports a live foreign owner as EACCES, not the POSIX
// EPERM above (isPermissionError in win32-utils treats both as one). Only ESRCH reaps.
const foreign = join(dir, `daemon-v7.pid.publish-424242-${CLAIM_UUID}`)
writeFileSync(foreign, '{"pid":1')
const kill = vi.spyOn(process, 'kill').mockImplementation(() => {
throw Object.assign(new Error('permission denied'), { code: 'EACCES' })
})
try {
reapOrphanedDaemonPidPublishClaims(dir)
} finally {
kill.mockRestore()
}
expect(existsSync(foreign)).toBe(true)
})
it('never lets an unremovable claim abort the sweep or the launch', () => {
// Why: reaping is hygiene on the launch funnel, so any failure here — a Windows file
// lock, a permission error, a stray directory under a claim name — must not escape