fix(root): report operational remove failure codes - #93
Conversation
|
Codex review: needs maintainer review before merge. Reviewed August 2, 2026, 5:26 PM ET / 21:26 UTC. ClawSweeper reviewWhat this changesThis PR makes Merge readinessThe target-deletion mapping appears correct and is narrowly covered; keep this PR open for a maintainer to explicitly accept the package-wide Priority: P2 Review scores
Verification
How this fits together
flowchart LR
Caller[Application caller] --> Root[Root capability]
Root --> Resolve[Containment and path resolution]
Resolve --> Guard[Parent directory identity guard]
Guard --> Delete[Delete target path]
Delete --> Normalize[Map deletion error]
Normalize --> Result[Public FsSafeError code]
Decision needed
Why: The code-to-category mapping is exported and applies beyond Before merge
Agent review detailsSecurityNone. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Merge the scoped deletion-error repair only after explicitly accepting Do we have a high-confidence way to reproduce the issue? Yes—current main's catch path deterministically normalizes raw deletion failures to Is this the best way to solve the issue? Yes for the remove behavior: the mapping is limited to target deletion syscalls, while parent-directory guard failures remain fail-closed. The remaining question is not technical correctness but whether the package-wide AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 2477f5681f68. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
removePathInRoot() routed every non-FsSafeError through normalizePinnedPathError(), so an ordinary ENOENT or ENOTEMPTY surfaced as the boundary-violation code path-alias. The documented codes not-found, not-empty and not-removable were declared in the exported union and documented in six places but constructed nowhere. The guard stage is separated from the errno mapping so a raw guard failure such as ELOOP is not reported as a removal outcome, and the three codes are now classified as operational rather than policy, so FsSafeError.category stops describing routine filesystem outcomes as safety-policy rejections. Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>
bfea409 to
c6adc3c
Compare
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: fix(root): report operational remove failure codes This is item 1/1 in the current shard. Shard 0/1. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
Summary
This is the maintainer-finished continuation of #84. It preserves @Yigtwxx's two commits and credit, then fixes the remaining public error-category mismatch.
not-found,not-empty, andnot-removablefrom the target deletion stage ofRoot.remove()path-aliasoperational, with regression coverage for both the exported categorizer and constructedFsSafeErrorinstancesCategory decision
All three codes are operational.
not-foundis used package-wide for ordinary absence,not-emptyis a routinermdirresult, andnot-removablerepresents deletion syscall failures such as permissions, a busy device, or a read-only filesystem. None indicates unsafe input, path aliasing, or identity drift.Because category is derived solely from code, this also changes pre-existing
not-founderrors outsideremove()frompolicytooperational. That preserves the invariant that one exported code has one category. No unrelated category was changed: no-clobber outcomes such asalready-existsandsecret-existsremain policy decisions, and target-type, ownership, permission, alias, and identity failures remain safety-policy outcomes.Compatibility
Consumers that caught
path-aliasaroundremove()will now receivenot-found,not-empty, ornot-removable. Consumers branching onFsSafeError.categorywill also observenot-foundasoperationalpackage-wide. The changelog calls out both changes plainly and credits @Yigtwxx.Downstream OpenClaw impact
Sequence the OpenClaw version bump with these changes:
src/infra/fs-safe-remove.test.ts:66-74asserts/ENOTEMPTY|EEXIST|EPERM/againstremovePathWithinRoot; the surfaced code becomesnot-empty.findPathAliasFilesystemCause()atsrc/infra/fs-safe-remove.ts:29-37exists only to unwrap the errno from the former boguspath-alias.workspace-reconcile-derived-paths.ts:60-64,config/mutate.ts:542-546, andplugin-sdk/memory-host-core.ts:51already checknot-found/not-removable; those branches become reachable.CI context
The intermittent red Windows legs on #84 are the sidecar-lock
EPERMflake fixed separately by #92 (fix/sidecar-lock-native). This branch does not attempt to fix or absorb that unrelated change and remains based directly on the contributor's #84 history.Verification
origin/mainregression replay: expected failures reproduced forpolicyvsoperationalandpath-aliasvsnot-foundpnpm check: 59 files passed, 1 skipped; 650 tests passed, 25 skipped; package check passedpnpm test:security: 5 files passed; 64 tests passedgit diff --checkorigin/main: clean, no accepted/actionable findings