Skip to content

Don't hand a worktree writer the LLM auto-approver - #748

Merged
yogthos merged 1 commit into
mainfrom
fix-worktree-approver-inherit
Aug 3, 2026
Merged

Don't hand a worktree writer the LLM auto-approver#748
yogthos merged 1 commit into
mainfrom
fix-worktree-approver-inherit

Conversation

@yogthos

@yogthos yogthos commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Closes dirge-4wpc (PR #670 follow-up).

PermissionChecker::for_working_dir drops the session allowlist on purpose — a grant the user made against the parent checkout doesn't mean the same thing under a worktree root — but it kept approval_fn.

Those two together invert the trust model. Concretely: you press a on cargo test in the parent, creating a session grant. A worktree writer runs cargo test; your grant is gone, so it falls through to Ask; try_auto_approve hands it to the inherited evaluator; Allow short-circuits the human prompt (src/agent/tools/mod.rs:895-899). Your explicit decision is dropped while the LLM's authority is kept, so the background writer ends up more auto-approved than the session you're sitting in.

Dropping the evaluator makes a worktree writer strictly no more permissive than its parent, and there is a human to reach — ask_tx is threaded through build_rooted_writer_tools into these tools, so the Ask prompts you rather than failing.

Prompt deny-lists still propagate: terminal, un-loosenable, and path-independent, so they carry no cross-root ambiguity.

Tests: one asserting the derived checker has no approval_fn (fails on main with "worktree writer inherited the auto-approver") and a companion pinning the rest of the contract — deny-list propagates, worktree root adopted, session grants stay behind.

Docs: docs/permissions.md now states the evaluator's scope explicitly, since "it stands in for the human on each Ask" read as unconditional.

for_working_dir drops the session allowlist on purpose — a grant made
against the parent checkout doesn't mean the same thing under a worktree
root — but it kept approval_fn. Together those invert the trust model:
the user's own "allow always" decisions vanish while the thing that can
auto-allow without asking them survives. Calls they'd already settled
came back as Ask and the evaluator answered on their behalf, so a
background writer ran with a weaker human backstop than the session that
spawned it.

Drop the evaluator. A worktree writer is now strictly no more permissive
than its parent, and there is a human to reach — ask_tx is threaded
through build_rooted_writer_tools. Prompt deny-lists still propagate;
they're terminal and path-independent.
@yogthos
yogthos force-pushed the fix-worktree-approver-inherit branch from 460304b to 2c241dc Compare August 3, 2026 19:25
@yogthos
yogthos merged commit dfd1657 into main Aug 3, 2026
14 checks passed
@yogthos
yogthos deleted the fix-worktree-approver-inherit branch August 3, 2026 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant