Skip to content

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 gets chmod u-w. Untracked paths (node_modules/, target/, .cargo-targets/, playwright-report/) are never touched — builds, npm installs, and cargo still work.
  • chmod applies 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) and src-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:

CommandEffect
lockchmod u-w on all protected tracked files
unlockchmod u+w to restore write access
statusReports 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:

  1. Resolves the canonical repo root even when invoked from a task worktree.
  2. Applies the lock automatically at the end of the bootstrap sequence.
  3. 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):

Terminal window
.paperclip/scripts/unlock-main-clone
# do work
.paperclip/scripts/relock-main-clone

Checking lock status:

Terminal window
.paperclip/scripts/main-clone-lock.sh status

After 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.

  • CAS-2852 — pre-Write soft guard (predecessor, failed 4×)
  • CAS-2949 — launchd plist worktree-path incident (informed the plist guard)