d8c99fb405
Review finding from @kartik-mem0 on this PR, and the most serious one: it loses events, which is what this PR exists to prevent. _claim_parked judged exhaustion before liveness. Claiming a parked file bumps its attempt count and refreshes its mtime, so the moment a sender takes the final attempt the file looks exhausted to every other sender while its owner is actively draining it. The second sender unlinked it, and everything in that batch was gone. The liveness check now runs first, so a batch under a live lease is skipped whatever its attempt count. The cleanup is deferred, not cancelled: once the lease lapses, the same exhausted file is reaped on a later run. Two tests. The first walks a batch to the final attempt and asserts a second sender neither takes it nor deletes it, and that the events are still in it. The second asserts an abandoned exhausted batch is still discarded once its lease lapses, which is the over-correction to guard against. Confirmed the first fails against the previous ordering. 288 passed, 8 skipped. Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb