Summary
Snapshot lifecycle inventory can fail with ENOENT when a concurrent publisher removes or renames a staging directory after inventory reads its name. This is inherited from #289 and was found during ClickHouse/ai#4173.
Evidence
packages/code/src/snapshot-lifecycle.ts calls lstat(directory) in manifest() without handling disappearance.
publishDependencySnapshot() creates staging outside the maintenance lock and removes it in finally outside that lock. Publishing also renames staging into the final entry.
- Prune inventories names before attempting the owner's key lock, so it can observe the staging name and then
lstat it after the publisher removes it.
- This propagates through preparation because only
SnapshotBudgetFullError is swallowed, even though the checkout is valid.
Expected fix and regression coverage
Treat disappeared entries/manifests as cache misses during inventory and revalidation, preserving failures for real permission or I/O errors. Add a deterministic test removing/renaming staging after inventory but before manifest inspection; prune and preparation should continue safely without deleting active data.
Summary
Snapshot lifecycle inventory can fail with
ENOENTwhen a concurrent publisher removes or renames a staging directory after inventory reads its name. This is inherited from #289 and was found during ClickHouse/ai#4173.Evidence
packages/code/src/snapshot-lifecycle.tscallslstat(directory)inmanifest()without handling disappearance.publishDependencySnapshot()creates staging outside the maintenance lock and removes it infinallyoutside that lock. Publishing also renames staging into the final entry.lstatit after the publisher removes it.SnapshotBudgetFullErroris swallowed, even though the checkout is valid.Expected fix and regression coverage
Treat disappeared entries/manifests as cache misses during inventory and revalidation, preserving failures for real permission or I/O errors. Add a deterministic test removing/renaming staging after inventory but before manifest inspection; prune and preparation should continue safely without deleting active data.