Customer + failure mode: an operator dispatches a worker into an isolated worktree with a CapabilityPolicy whose filesystem.write_roots names exactly where it may write. render_worker_settings (worker_worktree.py) path-scopes Write/Edit to those roots, but the same renderer grants whole Bash(*) whenever ANY write root is present, because Claude's Bash permission grammar matches command strings, not paths (see the _WRITE_TOOLS note at worker_worktree.py:62-70). So a worker can cd out of its worktree and write anywhere on the host via Bash, and the loop currently TRUSTS the resulting changed-file set: no code compares the worker's produced diff against the write_roots it was leased. The preventive layer is necessarily incomplete; this epic adds the missing DETECTIVE control. After a worker runs, compute its real changed-file set, compare each path against the leased policy's write_roots, and treat any out-of-bounds path as a sandbox violation that blocks advancement and quarantines the worktree instead of merging it. Decomposes into: (1) a pure write_root_violations predicate; (2) a git-backed changed-file collector; (3) a merge-gate enforcer that fails-and-quarantines on a violation. Each ships as its own PR; only the sub-tickets are dispatchable.
Customer story
An operator dispatching workers on a real repository without trusting their context or code: the worktree allow-list scopes Write/Edit, but Bash escapes path-scoping, so I have no signal when a worker writes outside the roots it was leased — I need the diff itself audited against the lease before it can advance.
Customer + failure mode: an operator dispatches a worker into an isolated worktree with a CapabilityPolicy whose filesystem.write_roots names exactly where it may write. render_worker_settings (worker_worktree.py) path-scopes Write/Edit to those roots, but the same renderer grants whole
Bash(*)whenever ANY write root is present, because Claude's Bash permission grammar matches command strings, not paths (see the_WRITE_TOOLSnote at worker_worktree.py:62-70). So a worker cancdout of its worktree and write anywhere on the host via Bash, and the loop currently TRUSTS the resulting changed-file set: no code compares the worker's produced diff against the write_roots it was leased. The preventive layer is necessarily incomplete; this epic adds the missing DETECTIVE control. After a worker runs, compute its real changed-file set, compare each path against the leased policy's write_roots, and treat any out-of-bounds path as a sandbox violation that blocks advancement and quarantines the worktree instead of merging it. Decomposes into: (1) a pure write_root_violations predicate; (2) a git-backed changed-file collector; (3) a merge-gate enforcer that fails-and-quarantines on a violation. Each ships as its own PR; only the sub-tickets are dispatchable.Customer story
An operator dispatching workers on a real repository without trusting their context or code: the worktree allow-list scopes Write/Edit, but Bash escapes path-scoping, so I have no signal when a worker writes outside the roots it was leased — I need the diff itself audited against the lease before it can advance.