CAS-3062 — Main Clone Filesystem Lock
CAS-3062 — Main Clone Filesystem Lock
Status: Shipped (2026-05-15) Priority: Critical PRs: #839 (initial), d92a1956 (Saga selective implementation)
Problem
The soft pre-Write guard introduced in CAS-2852 failed to prevent main-clone contamination four separate times in two days, culminating in a 12,342-line dirty tree with two officers working the main clone simultaneously, abandoned conflict markers, and a stray rebase autostash requiring full forensic rescue.
Root cause: enforcement lived at the Claude Code PreToolUse hook layer, which
Codex runtimes, direct API spawns, and agents shelling out to git bypass
entirely. Every runtime that doesn’t honour the hook is a gap.
Solution
Selective filesystem-level write barrier on the canonical main clone:
~/Projects/casaconomy/casaconomy-app/Design — selective, not blanket:
- Only
git ls-files-tracked hand-authored source getschmod u-w. Untracked paths (node_modules/,target/,.cargo-targets/,playwright-report/) are never touched — builds, npm installs, and cargo still work. chmodapplies to files, never directories — so creating new untracked files/dirs in the main clone still works.- Allowlist keeps tool-generated tracked paths writable:
src/types/bindings/(ts-rs binding regen) andsrc-tauri/gen/(Tauri iOS build artifacts). - Refuses to run anywhere except the canonical main clone — guarded against accidentally locking a worktree.
Components
main-clone-lock.sh
.paperclip/scripts/main-clone-lock.sh — three subcommands:
| Command | Effect |
|---|---|
lock | chmod u-w on all protected tracked files |
unlock | chmod u+w to restore write access |
status | Reports LOCKED / UNLOCKED / PARTIAL with counts |
Protected prefixes: src/, src-tauri/src/, test/, .agents/, .claude/,
.paperclip/scripts/.
Convenience wrappers
.paperclip/scripts/unlock-main-clone— escape hatch for board use.paperclip/scripts/relock-main-clone— re-protect after intentional edits
install.sh integration
install.sh now:
- Resolves the canonical repo root even when invoked from a task worktree.
- Applies the lock automatically at the end of the bootstrap sequence.
- Refuses to load any launchd plist referencing a per-task worktree path
(
/worktrees/CAS-<n>/) — guards against the CAS-2949 class of incident.
Operational notes
Unlocking for intentional work (regent / Vidar):
.paperclip/scripts/unlock-main-clone# do work.paperclip/scripts/relock-main-cloneChecking lock status:
.paperclip/scripts/main-clone-lock.sh statusAfter install.sh re-run: the bootstrap always relocks at the end, so
pulling updates and re-running install.sh restores the barrier automatically.
Why this works where CAS-2852 didn’t
The hook-layer guard requires every runtime to call through Claude Code’s
PreToolUse machinery. The filesystem barrier requires nothing from the
runtime — the OS enforces it at the syscall level. Even a raw sh invocation
or a Codex subprocess gets Permission denied on protected source files.
Related issues
- CAS-2852 — pre-Write soft guard (predecessor, failed 4×)
- CAS-2949 — launchd plist worktree-path incident (informed the plist guard)