Canonical-root invariant: paths reclaim can never delete #2
+192
−12
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What
Adds a canonical-root invariant to
reclaim.py: a capability-level guard that sits above the advisory holds list. A path declared canonical (via repeatable--canonical-root, orFORTRESS_CANONICAL_ROOTS) can never be deleted, and there is deliberately no flag to override it.Why
Today the only thing protecting the curated repository from
reclaim.pyis a substring match in a holds file — advisory config. If that file is wrong, missing, or a different invocation drops it, the protection is gone. The deleter also currently runs as a group member with full delete rights. This adds a guard that says "can't", not just "shouldn't."How — two independent enforcement points
verify()returns a newCANONICALverdict first, so a canonical source never enters the SAFE/deletable set — regardless of archive, hold, or drift state.safe_to_rm()(re-checked at the actualrmtreesite) refuses the path, so even a directdelete_source()call with--yes --allow-no-snapshotleaves the data untouched.is_canonical()is a path-boundary match on the normalized absolute path (not a substring), so a root protects itself and all descendants but never a sibling like..._repository-staging.Tests
7 new tests (helper merge/normalize/dedupe, path-boundary matching,
verify()marking CANONICAL over a would-be-SAFE source and over a hold,safe_to_rmrefusal, anddelete_sourceno-bypass under the strongest delete invocation). All 26 tests pass (7 new, 19 existing).Companion change in florasense-tools wires
fs-reclaim-reportto pass the curated repository as a canonical root.🤖 Generated with Claude Code