fix(hooks): guard a nested member clone on any branch #167

Merged
claudiomaradonna merged 1 commit from fix/guard-nested-clone into main 2026-10-29 14:08:22 +01:00
Collaborator

Why

In an umbrella, a user may keep a member's clone on their own feature
branch, or stop it in the middle of a rebase. If an agent slips and
edits the clone instead of opening the member's worktree, the
main-checkout guard lets the edit through. The edit lands among the
user's own work and nothing warns either of them, although
AGENTS.md § Members keeps the member's clone as it was. The guard
refused only while a main worktree was on its main branch. It exempted
every other state so that adoption could work, and a member clone fell
under the same exemption. Fixes #147.

The alternative was to document the gap in § Members. It was set aside
because it leaves the user's branch open to the edit.

What changed

The guard now refuses an edit in a main worktree that lies inside
another repository's working tree, whatever that worktree has checked
out: the main branch, another branch, or a detached HEAD. The refusal
names the enclosing repository and points to a worktree. A main
worktree that sits in no other repository keeps its exemption off its
main branch, as adoption needs. Ignored files still pass in both cases.

How to verify

From a fresh checkout of the branch, run
bash tests/agent-config/main-checkout-guard.sh. All 18 cases pass. The
new cases build an umbrella with an ignored member clone on
feature/x, then on a detached HEAD. In both states an edit of the
clone's README.md is refused, with "lies in the repository
"; on main the same events exit 0. Two pins show that a
non-nested repository still passes on a detached HEAD and that an
ignored file in a nested clone still passes.

To reproduce by hand, put any repository with a commit under an
ignored path of another, switch it to a branch other than main, and
pipe a Claude Code Edit event for one of its tracked files into
.agents/hooks/main-checkout-guard.sh. It exits 2 on this branch and 0
on main.

The README's Maintenance checks pass on d3f36eb, including 303
agent-configuration tests. Run through run-sandboxed.sh on main's code
with this branch's tests, the two regression tests fail at exit 0 and
the other 16 cases pass. Three rounds of change and security review
closed every medium finding. I did not exercise the guard inside a
live Claude Code, Codex or OpenCode session.

Considerations

A repository that sits inside another one without being an umbrella
loses the exemption off its main branch. One example is a home
directory kept as a non-bare Git repository. An adoption there is
refused and told to open a worktree, which it can do instead.

The two pins came in a review fixup rather than in a commit before the
fix. Both pass on main's code.

## Why In an umbrella, a user may keep a member's clone on their own feature branch, or stop it in the middle of a rebase. If an agent slips and edits the clone instead of opening the member's worktree, the main-checkout guard lets the edit through. The edit lands among the user's own work and nothing warns either of them, although `AGENTS.md` § Members keeps the member's clone as it was. The guard refused only while a main worktree was on its main branch. It exempted every other state so that adoption could work, and a member clone fell under the same exemption. Fixes #147. The alternative was to document the gap in § Members. It was set aside because it leaves the user's branch open to the edit. ## What changed The guard now refuses an edit in a main worktree that lies inside another repository's working tree, whatever that worktree has checked out: the main branch, another branch, or a detached HEAD. The refusal names the enclosing repository and points to a worktree. A main worktree that sits in no other repository keeps its exemption off its main branch, as adoption needs. Ignored files still pass in both cases. ## How to verify From a fresh checkout of the branch, run `bash tests/agent-config/main-checkout-guard.sh`. All 18 cases pass. The new cases build an umbrella with an ignored member clone on `feature/x`, then on a detached HEAD. In both states an edit of the clone's `README.md` is refused, with "lies in the repository <umbrella>"; on `main` the same events exit 0. Two pins show that a non-nested repository still passes on a detached HEAD and that an ignored file in a nested clone still passes. To reproduce by hand, put any repository with a commit under an ignored path of another, switch it to a branch other than main, and pipe a Claude Code `Edit` event for one of its tracked files into `.agents/hooks/main-checkout-guard.sh`. It exits 2 on this branch and 0 on `main`. The README's Maintenance checks pass on d3f36eb, including 303 agent-configuration tests. Run through `run-sandboxed.sh` on main's code with this branch's tests, the two regression tests fail at exit 0 and the other 16 cases pass. Three rounds of change and security review closed every medium finding. I did not exercise the guard inside a live Claude Code, Codex or OpenCode session. ## Considerations A repository that sits inside another one without being an umbrella loses the exemption off its main branch. One example is a home directory kept as a non-bare Git repository. An adoption there is refused and told to open a worktree, which it can do instead. The two pins came in a review fixup rather than in a commit before the fix. Both pass on main's code.
The main-checkout guard passed every main worktree off its main branch
or on a detached HEAD, an exemption meant for adoption, so an agent
could edit a member clone of an umbrella while the user had it on a
feature branch or mid-rebase, though the policy keeps that clone as it
was. The guard now refuses an edit in a main worktree that lies inside
another repository's working tree, whatever it has checked out, naming
that repository; one nested in none keeps the exemption.

Fixes #147
motoko force-pushed fix/guard-nested-clone from d3f36eb419 to b47921f4b1 2026-10-29 14:07:17 +01:00 Compare
claudiomaradonna deleted branch fix/guard-nested-clone 2026-10-29 14:08:27 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
claudiomaradonna/agent-foundry!167
No description provided.