Problem
Warden/gate invocations (GPT codex_warden, edit-gate, verification-gate) resolve their target (diff source, verdict-store bucket) from the invoking process's cwd. When an agent's mental model of "which worktree am I in" drifts across a cd/EnterWorktree boundary mid-session, this produces two silent failure modes rather than a loud error:
- Empty-change abstain - running the GPT warden from the main-repo cwd instead of the target worktree reads an empty diff and abstains, which looks identical to "nothing to review."
- Co-gate bucket mismatch - a
cd moves the hook event's cwd mid-session without the agent noticing, so a SHIP verdict gets written to the wrong bucket (flat vs. per-worktree), and the gate that reads the other bucket reports "not run yet" even though it was.
Both are a correctly-written fail-closed gate silently no-op'ing - the one case where silence reads as "protection is off," not as an error.
Where it shows up
Surfaced repeatedly across a multi-day session retrospective (3 separate incidents in one window: two wrong-cwd GPT warden runs, one mid-session bucket split). Root cause is the same in all three: nothing asserts/echoes the invocation context (worktree identity + non-empty diff) before the gate call fires.
Fix applied downstream (fork)
Landed as a doc-only preflight habit in the fork (liam-cyberpro/Deus#31, commit 6714c85): before invoking any warden/gate command, run git rev-parse --show-toplevel + git status --short and eyeball both, so drift is caught before the call instead of after a confusing abstain/mismatch. Added as a new "Gate Invocation Preflight" section in .claude/rules/orchestration-rules.md, cross-referencing the existing "Warden Co-Gate Verdict Marking" section.
This is intentionally the cheap fix, not the complete one - it's a habit, not an enforcement. A more durable version would be mechanical: codex_warden refusing to run on an empty diff instead of silently abstaining, or the gate/hook itself printing the resolved toplevel + bucket at invocation time so a mismatch is visible immediately rather than discovered later via the existing "co-gate bucket mismatch" diagnostic message. Flagging both here for visibility - not opening a PR, since fork/upstream sync here is issues-only by convention on this end.
Suggested next step
Worth deciding whether:
(a) pull the doc-only preflight line into upstream orchestration-rules.md (or wherever the canonical version lives) as-is, or
(b) skip straight to the mechanical fix (empty-diff hard-refuse in codex_warden, or an invocation-time context print in the gate hook) and treat the doc line as superseded.
Happy to provide the exact diff from the fork commit if useful.
Problem
Warden/gate invocations (GPT
codex_warden, edit-gate, verification-gate) resolve their target (diff source, verdict-store bucket) from the invoking process's cwd. When an agent's mental model of "which worktree am I in" drifts across acd/EnterWorktreeboundary mid-session, this produces two silent failure modes rather than a loud error:cdmoves the hook event's cwd mid-session without the agent noticing, so a SHIP verdict gets written to the wrong bucket (flat vs. per-worktree), and the gate that reads the other bucket reports "not run yet" even though it was.Both are a correctly-written fail-closed gate silently no-op'ing - the one case where silence reads as "protection is off," not as an error.
Where it shows up
Surfaced repeatedly across a multi-day session retrospective (3 separate incidents in one window: two wrong-cwd GPT warden runs, one mid-session bucket split). Root cause is the same in all three: nothing asserts/echoes the invocation context (worktree identity + non-empty diff) before the gate call fires.
Fix applied downstream (fork)
Landed as a doc-only preflight habit in the fork (
liam-cyberpro/Deus#31, commit6714c85): before invoking any warden/gate command, rungit rev-parse --show-toplevel+git status --shortand eyeball both, so drift is caught before the call instead of after a confusing abstain/mismatch. Added as a new "Gate Invocation Preflight" section in.claude/rules/orchestration-rules.md, cross-referencing the existing "Warden Co-Gate Verdict Marking" section.This is intentionally the cheap fix, not the complete one - it's a habit, not an enforcement. A more durable version would be mechanical:
codex_wardenrefusing to run on an empty diff instead of silently abstaining, or the gate/hook itself printing the resolved toplevel + bucket at invocation time so a mismatch is visible immediately rather than discovered later via the existing "co-gate bucket mismatch" diagnostic message. Flagging both here for visibility - not opening a PR, since fork/upstream sync here is issues-only by convention on this end.Suggested next step
Worth deciding whether:
(a) pull the doc-only preflight line into upstream
orchestration-rules.md(or wherever the canonical version lives) as-is, or(b) skip straight to the mechanical fix (empty-diff hard-refuse in
codex_warden, or an invocation-time context print in the gate hook) and treat the doc line as superseded.Happy to provide the exact diff from the fork commit if useful.