cad-phase remove treats an unreadable git state as clean and deletes recursively #136
Labels
No labels
already-shipped
bug
documentation
duplicate
enhancement
external-review
good first issue
help wanted
in progress
invalid
needs-decision
proposal
question
security
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: crenshawdev/cadence-archived#136
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Source: deep dive F4
Verdict: AGREE - medium
Claim as reviewed
uncommittedUnderreturns an empty array whenevergit statusfails, and any failure fromgit rm- not only "not a repository" - falls back to a recursivermSync. This converts "unable to prove clean" into "safe to erase".At HEAD
f354864(v3.3.0)cadence-core/bin/planning.mjs:3032-3039- thecatchreturns[]. The doc comment at:3025-3027reasons only about the outside-a-git-repo case, where the fallback is genuinely safe.cadence-core/bin/planning.mjs:3240-3244-try { execFileSync('git', ['rm', '-r', '-q', ...]) } catch { rmSync(..., { recursive: true }) }.Git can fail because it is missing, the repository is unsafe-owned, permissions changed, the index is locked, or configuration is broken. None of those prove the contents are recoverable.
There is also a time-of-check/time-of-use gap: work can become dirty after the preflight
git statusand beforegit rm;git rmthen refuses with "file has local modifications" and the unconditionalrmSyncdeletes it anyway.Note
Bounded by the dry-run gate at
:3225and by needing git to fail for a non-obvious reason.Fix shape: a discriminated preflight result
{state:'clean'|'dirty'|'unprovable'}that refuses onunprovable; determine repository membership once; use filesystem deletion only for a confirmed non-git tree whose contents were listed to the user.Solo milestone by design - this is the only open issue that can destroy uncommitted work, so it gets its own review surface rather than riding with adjacent planning.mjs fixes.
Fix shape from the issue body, restated so a plan does not narrow it: a discriminated preflight result {state:'clean'|'dirty'|'unprovable'} that REFUSES on unprovable. The bug is not that git status can fail; it is that failure and cleanliness return the same value. Note the TOCTOU half too - the preflight can be clean and the tree dirty by the time git rm runs, and the unconditional rmSync fallback at planning.mjs:3240-3244 then destroys it. Fixing only the preflight leaves that arm open.
Fixed in v3.5.4 as PHS-01, merged in #217 and tagged v3.5.4. The fix carries a check watched failing against the unpatched tree first.