Skip to content

fix(gemini): judge and dispatch against the same root (#66's other half) - #82

Merged
kevin-agrology merged 2 commits into
mainfrom
fix/gemini-dispatch-cwd
Aug 12, 2026
Merged

fix(gemini): judge and dispatch against the same root (#66's other half)#82
kevin-agrology merged 2 commits into
mainfrom
fix/gemini-dispatch-cwd

Conversation

@kevin-agrology

Copy link
Copy Markdown
Contributor

TL;DR: Gemini reviews could quietly land in the wrong directory — the tool checked one folder and then launched the reviewer in another. This closes the half of #66 that was fixed for codex but only documented for gemini.

Completes #66.

The gap the file described instead of closing

commands/multi-review.md said, in writing:

Scope: only the codex arm consumes --session-root today. … gemini remains exposed to the same check-cwd-vs-dispatch-cwd drift this fixed for codex.

gemini-cli's workspace is the cwd of the process at launch, and it refuses to read or write outside it. Two things followed from never pinning that.

1. The check judged by its own cwd

The basis was repo_root() — the git toplevel of the check invocation — on the stated reasoning that gemini "runs as a shell command in the CURRENT cwd", so that was correct. The premise holds only if check and dispatch stand in the same place, and nothing enforced that.

So the arm was wrong in both directions, and the suite now asserts both:

case before after
copy outside the root dispatch inherits silent (the #66 failure) hint fires
copy inside that root, check run elsewhere false hint silent

The second was the surprise. A spurious hint is not harmless here — it's how the real one gets ignored, which is precisely the #22 lesson about a warning that fires when it shouldn't.

2. The dispatch pinned nothing at all

The shell branch set no directory, so gemini's workspace was whatever cwd that Bash call happened to inherit:

(( ${#argv[@]} )) && "${argv[@]}"                          # before
(( ${#argv[@]} )) && ( cd "<session-root>" && "${argv[@]}" )   # after

The subshell scopes it to the dispatch and leaves the primary's own cwd alone.

Both halves are needed. Pinning only the check would validate a root the dispatch doesn't use — which is the exact shape of #66, just relocated.

fable needs no basis (in-harness, no workspace of its own), so --session-root is now consumed by both arms that have one, and the scope note claiming otherwise is gone.

Guards

entry mutation what breaks
reviewer/gemini-session-root-basis basis → $rr check judges by cwd again, wrong in both directions
command/gemini-dispatch-cwd-pinned drop the cd dispatch lands wherever the call inherits
command/session-root-scope-claim restore the old note docs revert to describing the bug

All three verified caught. The third is deliberate: a stale claim is how this gap survived — it was written down instead of fixed — so the sentence itself is now guarded.

Verification

check result
scripts/*.test.sh (15 suites) all pass
3 mutation entries all caught
multi-review-version-check.sh 1.22.0 → 1.22.1 (ok)

New assertions: hint fires when the copy is outside the dispatch root; stays advisory (exit 0); stays silent when the copy is inside that root even though the check runs from elsewhere.

Not run locally: shellcheck (not installed here); CI covers it plus the bash 3.2 leg and the full sweep.

Flagged, not fixed

The empty-argv branch two lines above still reads : quarantine <id> "…": is the null builtin, so a primary transcribing it literally does nothing and the failure surfaces later as a wait-bound timeout under the wrong reason. I rewrote the lines around it and deliberately left it alone per §1.3; it wants its own change.


🤖 Generated with Claude Code

https://claude.ai/code/session_01Nm3hNXA4WHbgKjFbxX7VUE

kevin-agrology and others added 2 commits August 11, 2026 18:29
The command file documented this gap rather than closing it: "gemini remains
exposed to the same check-cwd-vs-dispatch-cwd drift this fixed for codex".

gemini-cli's workspace is the cwd of the process at LAUNCH, and it refuses to
read or write outside it. Two things followed from never pinning that:

THE CHECK JUDGED BY ITS OWN CWD. The basis was `repo_root()` — the git toplevel
of the CHECK invocation — on the stated reasoning that gemini "runs as a shell
command in the CURRENT cwd" so that was the right basis. The premise holds only
if check and dispatch stand in the same place, and nothing enforced it. The arm
was therefore wrong in BOTH directions, and the suite now asserts both: it
MISSED a copy outside the root dispatch would inherit (the #66 failure), and it
FALSELY hinted on a copy that was inside that root but outside whatever repo the
check happened to be standing in. The second was the surprise — a spurious hint
teaches the reader to ignore the real one.

THE DISPATCH PINNED NOTHING. The shell branch set no directory at all, so the
workspace was whatever cwd that Bash call inherited. Now `cd "<session-root>"`
inside a subshell, scoped to the dispatch, leaving the primary's own cwd alone.

Both halves are needed: pinning only the check would validate a root the
dispatch does not use, which is exactly the shape of #66.

`fable` needs no basis — it runs in-harness with no workspace of its own — so
`--session-root` is now consumed by both arms that have one, and the scope note
saying otherwise is removed. A stale claim like that is how the gap survived:
written down instead of fixed.

Guards: three entries — the check's basis, the dispatch's cwd, and the scope
claim itself, so the documentation cannot quietly revert to describing the bug.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nm3hNXA4WHbgKjFbxX7VUE
CI caught what my local verification structurally could not. I verified the
three NEW entries with `--only`, which cannot detect that an EXISTING entry
went stale — and rewriting the gemini branch deleted the line
`reviewer/check-doc-gemini-basis` targets, so the sweep failed with
"the target line is not present (stale mutation table?)".

The entry is superseded rather than re-pointed. It asserted the gemini arm must
judge against `repo_root()` and not codex's sandbox — half right, and the wrong
half is exactly the bug this PR fixes: the basis is neither, it is the SESSION
ROOT the dispatch will inherit. Re-pointing it would re-assert the behaviour
just removed.

The property it protected still holds and is still covered: the replacement
entry pins the basis to `$session_root` with `$rr` as fallback, and neither is
`codex_workspace_root`.

Lesson worth recording: `--only` is enough to prove a NEW guard bites, but only
the full sweep proves the table is still consistent with the code. Any change
that edits a line another entry targets needs the sweep, not the subset.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nm3hNXA4WHbgKjFbxX7VUE
@kevin-agrology
kevin-agrology merged commit ddb11d6 into main Aug 12, 2026
4 checks passed
@kevin-agrology
kevin-agrology deleted the fix/gemini-dispatch-cwd branch August 12, 2026 00:33
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