Worktree Artifact Path Mismatch — Prevention and Cleanup
Build and Verify agents run in worktrees but Claude Code's Write tool resolves absolute paths against the main tree. The agent writes `build_report.md` to the main tree. `artifact save` detects this but errors with manual recovery instructions instead of fixing it, leaving a stale copy on main. When `work complete` pulls the merged PR, git refuses because the untracked file would be overwritten. In re-build scenarios (verify FAIL, fix, new artifacts), the stale copy diverges from the PR content, and the existing content-match auto-clean (`be3374f`) can't help.
verdict PASSscore 16 / 16findings 6 (1 risk · 3 debt · 2 obs)duration 1h 15mrejection cycles 0shipped May 8, 2026surface cli
Pipeline timeline
Intent to proven code in 1h 15m across Think, Plan, Build, and Verify.
Think9m
Plan19m
Build12m
Verify5m
Assertion ledger
16 claims, each independently verified. Showing 8 — show all →
| ID | Says | Matcher | |
|---|---|---|---|
| A001 | Saving an artifact that was written to the wrong tree auto-moves it to the correct location | verified | ok |
| A002 | The data companion file moves alongside its report automatically | verified | ok |
| A003 | After auto-move, no stale copy remains on the main tree | verified | ok |
| A004 | Files that are tracked by git on the main tree are never auto-moved | verified | ok |
| A005 | Cross-filesystem moves fall back to copy-then-delete | verified | ok |
| A006 | After a successful worktree save, stale copies on the main tree are deleted | verified | ok |
| A007 | Post-save sweep only removes untracked files | verified | ok |
| A008 | A cleanup failure during post-save sweep does not fail the save | verified | ok |
Findings 6 total
debtpackages/cli/tests/commands/artifact.test.ts→ closed
A005 EXDEV test doesn't exercise moveFileCrossFs — tests Node.js copyFileSync/unlinkSync directly instead of mocking renameSync to throw EXDEV
debtpackages/cli/tests/commands/artifact.test.ts→ closed
A008 sweep-failure test is a no-op — tests absence of sweep (no main tree copy), not an actual cleanup failure
obspackages/cli/src/commands/artifact.ts→ closed
moveFileCrossFs copy-then-delete is not atomic — if copyFileSync succeeds but unlinkSync fails, source file persists as a stale duplicate
riskpackages/cli/src/commands/work.ts→ closed
Layer 3 planning artifact content-match reads file without try-catch — if file is deleted between filter and readFileSync, unhandled ENOENT crashes completeWork
debtpackages/cli/src/commands/artifact.ts→ closed
Layer 2 post-save sweep calls getMainTreeRoot a second time — already computed in Layer 1 block but not threaded through
+1more findings
Integrity seal
scopesha256:f3bfd904fd1df...
contractsha256:ad3fa95025a39...
plansha256:30416c541d660...
specsha256:0061ca1bed907...
build-reportsha256:a5844792d9ec8...
build-datasha256:237bdc4adbce5...
verify-reportsha256:bdfa0868f04ed...
verify-datasha256:119ef4fcffd33...
audit cmd$ ana proof audit worktree-artifact-cleanup → all hashes match