Pop: claim, stream, commit
pop -- specified in SPEC.md 6 and shipping at milestone M5 -- is therefore a claim, stream, commit cycle, so a failed read never destroys data by default.The three steps
Claim: atomically move the entry to a claimed state, so two concurrent pops race on the rename and exactly one wins -- the loser gets RefClaimed, enforced by the filesystem rather than an in-process lock. Stream: read from the claimed path, verifying the digest incrementally. Commit: only when the stream fully drains and the digest matches does the delete happen.
When the read fails
A stream error, a premature destroy, or a digest mismatch applies the onPopFailure policy. The default, restore, renames the entry back so the read can be retried -- losing data by default is hostile. The opt-in alternative, burn, deletes anyway: for the paranoid drop that must assume any read attempt means the bytes were observed.
Crash recovery
A process that dies mid-pop leaves a claimed entry orphaned. On the first operation after construction, claims older than the claim timeout are found and resolved per the same onPopFailure policy -- lazily, because constructors do not do I/O.