Skip to content

fix(guard): cd is a read verb — a leading cd defeated the git-read exemption - #121

Merged
Dygreens merged 1 commit into
mainfrom
fix/guard-cd-is-a-read-verb
Aug 18, 2026
Merged

fix(guard): cd is a read verb — a leading cd defeated the git-read exemption#121
Dygreens merged 1 commit into
mainfrom
fix/guard-cd-is-a-read-verb

Conversation

@Dygreens

Copy link
Copy Markdown
Collaborator

is_pure_read_command splits a command on | ; & \n ( ) , takes the **first** token of each segment as that segment's verb, and returns false as soon as one verb isn't in READ_ONLY_VERBS`.

cd wasn't in that list. cd cannot modify anything, so this isn't a judgement call.

Measured on the shipped function

cd /tmp                                 -> is_pure_read=false   (wrong)
cd /tmp && cat f.md                     -> false                (wrong)
cd /repo && git show origin/main:file   -> false                (wrong)
git show origin/main:file               -> true                 (works alone)

The last two are the point. The AMUX-3128 follow-up added GIT_READ_SUBCMDS precisely so a peer reading a file isn't minted as its co-author, and its comment states the harm:

the harder a peer checks your output, the more it blocks you, which trains toward GN=1 where the guard stops protecting anything

That exemption works for a bare git show and is defeated by a leading cd — the most common prefix in this repo's own workflow. It shipped and was silently inert in the majority of real invocations.

It blocked a real commit

2026-08-17 19:17, and again at 19:57:

amux blocked commit in /Users/dorongreenspan/Developer/amux —
per-path: frustrations.md ... owner=amux-errors-and-bugs ... in_firsthand=false

in_firsthand=false is the tell: the ownership that blocked that session was inferred, never a firsthand Edit/Write. Five blocks in 40 minutes.

191 distinct inferred-edit records in 24h (220 raw, 29 near-duplicate pairs from the two server processes), 117 of them verb=cd. The warning was self-diagnosing the whole time and nobody read it:

A READ verb here means is_pure_read_command missed a reader and it may be minting false co-authorship.

Not all of it was a false positive

verb=cat (56 records) is correct — those are cat > f <<EOF heredoc writes, caught by the output-redirection check, and they really are edits. The defect is specifically the verbs that cannot mutate.

The safety half of the test is the load-bearing half

Adding a verb to READ_ONLY_VERBS widens what the guard treats as harmless, and a widening that goes too far stops the guard protecting anything while leaving every other test green. All still non-read after the change:

cd x && echo y > f      cd x && cat > f <<EOF     cd x && rm f
cd x && sed -i          cd x && git commit        cd x && git add

Verified to fail against the pre-fix function.

cargo clippy --workspace --all-targets -- -D warnings exit 0; cargo test --workspace 39 result lines, 0 failed.

Noted, not fixed here

Two records carried impossible verbs — verb=scratchpad, verb=amux.log — where the "verb" is a path fragment. The splitter cuts through heredoc bodies (they contain parens and backticks), so a path merely mentioned in prose can be minted as an edit. 4 records in 24h, blast radius unclear, and a real fix means not splitting inside heredocs — a parser change rather than a list entry. Recorded on AEAB-24.

🤖 Generated with Claude Code

https://claude.ai/code/session_01B4vuEScunv4K6RMwQoT9xx

…emption (AEAB-24)

`is_pure_read_command` splits a command on `| ; & \n ( ) ` `, takes the FIRST
token of each segment as that segment's verb, and returns false as soon as one
verb is not in READ_ONLY_VERBS. `cd` was not in that list. `cd` cannot modify
anything, so this is not a judgement call.

Measured on the shipped function rather than reasoned about:

  cd /tmp                                 -> is_pure_read=false   (wrong)
  cd /tmp && cat f.md                     -> false                (wrong)
  cd /repo && git show origin/main:file   -> false                (wrong)
  git show origin/main:file               -> true                 (works alone)

The last two are the point. The AMUX-3128 follow-up added GIT_READ_SUBCMDS
precisely so a peer READING a file is not minted as its co-author, and its comment
states the harm plainly: "the harder a peer checks your output, the more it blocks
you, which trains toward GN=1 where the guard stops protecting anything." That
exemption works for a bare `git show` and is defeated by a leading `cd` — the most
common prefix in this repo's own workflow. It shipped and was silently inert in the
majority of real invocations.

It blocked a real commit, measured not inferred. 2026-08-17 19:17 and again 19:57:

  amux blocked commit in /Users/dorongreenspan/Developer/amux —
  per-path: frustrations.md ... owner=amux-errors-and-bugs ... in_firsthand=false

`in_firsthand=false` is the tell: the ownership that blocked that session was
INFERRED, never a firsthand Edit/Write. Five blocks in 40 minutes.

191 distinct inferred-edit records in 24h (220 raw, 29 near-duplicate pairs from
the two server processes), 117 of them verb=cd. The warning was self-diagnosing the
whole time and nobody read it: "A READ verb here means is_pure_read_command missed
a reader and it may be minting false co-authorship."

Not all of it is a false positive, and saying so matters: verb=cat (56) is CORRECT
— those are `cat > f <<EOF` heredoc writes, caught by the output-redirection check,
and they really are edits. The defect is specifically the verbs that cannot mutate.

The SAFETY half of the test is the load-bearing half. Adding a verb to
READ_ONLY_VERBS widens what the guard treats as harmless, and a widening that goes
too far stops the guard protecting anything while leaving every other test green.
Still non-read after the change: `cd x && echo y > f`, `cd x && cat > f <<EOF`,
`cd x && rm f`, `cd x && sed -i`, `cd x && git commit`, `cd x && git add`.
Verified to FAIL against the pre-fix function.

CI's exact commands: clippy --workspace --all-targets -D warnings exit 0;
test --workspace 39 result lines, 0 failed.

NOT fixed here, recorded on the card: two records carried impossible verbs
(`verb=scratchpad`, `verb=amux.log`) where the "verb" is a path fragment — the
splitter cuts through heredoc BODIES, so a path merely MENTIONED in prose can be
minted as an edit. 4 records in 24h, blast radius unclear, and a real fix means not
splitting inside heredocs — a parser change rather than a list entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4vuEScunv4K6RMwQoT9xx

Amux-Session: amux-errors-and-bugs
@Dygreens
Dygreens merged commit 5d985e3 into main Aug 18, 2026
3 checks passed
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