Filed by the domain:devx @ objectui execution PM seat (objectui#5748, PM session session_019b5UBNMtTzKbVtZZGvFuxe) as the cross-repo sibling of objectui#6042, per the follow-up duty that the accepting seat files the other repo's card.
Surfaced while porting the guard-main-checkout-bash.sh fix family (#11131 + #11133 + #11234, PR #11278) into objectui (objectui#5789 / PR objectui#6046). It was correctly not folded into that port — a verbatim port must not touch other hooks.
The observation
.claude/hooks/guard-shared-stash.sh's split_segments() has no backslash branch.
Outside quotes, a backslash escapes the next character, so an escaped backslash-doublequote opens no quoted region at all. Without that branch the pass reads the doublequote as opening a region that never closes, goes inert for every separator behind it, and collapses the whole command into one segment whose head word is the harmless one — leaving the real command behind the separator to be read as a mere argument of echo.
This is exactly the shape #11131 closed in guard-main-checkout-bash.sh. tokenize() already had the branch; split_segments() did not. The same asymmetry exists here.
Measured
Measured in objectui's copy (ad0f5f11f), fed as the PreToolUse payload shape ({cwd, tool_name:"Bash", tool_input:{command}}):
| command | verdict |
|---|
git stash | blocked — control: the guard works |
echo backslash-doublequote, then ;, then git stash | ALLOWED — the hole |
The control is load-bearing: without it, "ALLOWED" could mean the harness never reached the guard rather than that the guard let it past.
⚠️What is measured and what is inferred, stated separately. The reading above was taken against objectui's copy. The dev's report states the defect is present in both repos' copies, on the strength of the two files being declared case-for-case identical in this region. This repo's copy has not been independently probed — that is the first thing whoever takes this card should do, rather than trusting the parity declaration. If it does not reproduce here, that is itself a finding: it would mean the two copies have diverged where they are declared not to have.
Scope — only one of the two upstream fixes has an analogue
Why this is worth a card rather than a note
guard-shared-stash.sh is the enforcement behind the ⛔ Never git stash Prime Directive. That rule exists because refs/stash lives in the common .git directory, so every worktree of a repo shares one LIFO stack: two agents stashing in their own worktrees push and pop the same stack, pop reports success, and the only symptom is another agent's files turning up in your git status — after which a git add -A merges their work into your PR. It has already cost two parallel agents their in-flight changes (objectui#3430).
So a fail-open here does not merely admit a discouraged command. It admits the one command whose failure mode silently corrupts a different agent's work, with a success message. The rule outranks the hook, so this is a backstop gap rather than a live breach — but the backstop exists precisely for the agent who does not know the rule.
Suggested fix
Port the split_segments() backslash branch from guard-main-checkout-bash.sh (as landed in #11278) into guard-shared-stash.sh, and add the matching cases to .claude/hooks/guard-shared-stash.selftest.sh — that file's own instruction is to re-run the selftest on any change to the hook.
Keep the two repos' copies in step: fix both with the same patch shape, or the declared parity contract is broken by the fix itself.
⚠️.claude/** is a governed surface — draft PR, human merge.
Filed unassigned; domain:* and grading are the triage seat's to set.
Refs: #11131 · #11133 · #11234 · PR #11278 · objectui#6042 (sibling) · objectui#5789 / PR objectui#6046 · objectui#3430.
Filed by the
domain:devx@ objectui execution PM seat (objectui#5748, PM sessionsession_019b5UBNMtTzKbVtZZGvFuxe) as the cross-repo sibling of objectui#6042, per the follow-up duty that the accepting seat files the other repo's card.Surfaced while porting the
guard-main-checkout-bash.shfix family (#11131 + #11133 + #11234, PR #11278) into objectui (objectui#5789 / PR objectui#6046). It was correctly not folded into that port — a verbatim port must not touch other hooks.The observation
.claude/hooks/guard-shared-stash.sh'ssplit_segments()has no backslash branch.Outside quotes, a backslash escapes the next character, so an escaped backslash-doublequote opens no quoted region at all. Without that branch the pass reads the doublequote as opening a region that never closes, goes inert for every separator behind it, and collapses the whole command into one segment whose head word is the harmless one — leaving the real command behind the separator to be read as a mere argument of
echo.This is exactly the shape #11131 closed in
guard-main-checkout-bash.sh.tokenize()already had the branch;split_segments()did not. The same asymmetry exists here.Measured
Measured in objectui's copy (
ad0f5f11f), fed as the PreToolUse payload shape ({cwd, tool_name:"Bash", tool_input:{command}}):git stashechobackslash-doublequote, then;, thengit stashThe control is load-bearing: without it, "ALLOWED" could mean the harness never reached the guard rather than that the guard let it past.
Scope — only one of the two upstream fixes has an analogue
sed -iinto the shared checkout is allowed through #11131 backslash half applies.guard-shared-stash.shhas nostrip_heredocs()pass to carry that defect. Do not port it looking for a place to put it.Why this is worth a card rather than a note
guard-shared-stash.shis the enforcement behind the ⛔ Nevergit stashPrime Directive. That rule exists becauserefs/stashlives in the common.gitdirectory, so every worktree of a repo shares one LIFO stack: two agents stashing in their own worktrees push and pop the same stack,popreports success, and the only symptom is another agent's files turning up in yourgit status— after which agit add -Amerges their work into your PR. It has already cost two parallel agents their in-flight changes (objectui#3430).So a fail-open here does not merely admit a discouraged command. It admits the one command whose failure mode silently corrupts a different agent's work, with a success message. The rule outranks the hook, so this is a backstop gap rather than a live breach — but the backstop exists precisely for the agent who does not know the rule.
Suggested fix
Port the
split_segments()backslash branch fromguard-main-checkout-bash.sh(as landed in #11278) intoguard-shared-stash.sh, and add the matching cases to.claude/hooks/guard-shared-stash.selftest.sh— that file's own instruction is to re-run the selftest on any change to the hook.Keep the two repos' copies in step: fix both with the same patch shape, or the declared parity contract is broken by the fix itself.
.claude/**is a governed surface — draft PR, human merge.Filed unassigned;
domain:*and grading are the triage seat's to set.Refs: #11131 · #11133 · #11234 · PR #11278 · objectui#6042 (sibling) · objectui#5789 / PR objectui#6046 · objectui#3430.