Recorded by the objectstack dev who implemented objectstack-ai/objectstack#10570 (its PR: objectstack-ai/objectstack#11129). Filed unassigned, as an observation about this repo's copy of the hook. Dedup performed first: #5459 is the only existing card on this drift, and it is scoped to a different fix.
Not a duplicate of #5459 and not blocked by it — #5459 tracks porting the quote-escape fix (objectstack PR #10406); this is a second, independent fix that has since landed in objectstack's copy of the same file. They are cheaper ported together, in one PR, which is the reason to record this now rather than after #5459 is picked up.
The drift
.claude/hooks/guard-main-checkout-bash.sh in both repos carries the header claim that the two copies are "deliberately kept case-for-case identical … so the two repos' guards cannot drift". objectstack PR #11129 changes the parsing logic in objectstack's copy: both quote-aware passes (split_segments() and tokenize()) now apply the shell's comment rule — outside quotes and heredoc bodies, an unquoted # that starts a WORD begins a comment running to the next newline.
This repo's copy is, by that header's own claim, still the pre-fix logic.
What that means for agents working in this repo
Measured in objectstack against the pre-fix logic, from a cwd inside the shared primary checkout:
# rename foo -> bar
echo hello
-> hook-exit=2, "target: bar" (a pure-read command, BLOCKED)
echo hello
-> hook-exit=0 (control: same command, no comment)
The failure is fail-CLOSED, so nothing unguarded slips through — but it is the false-positive direction that trains an operator toward OS_ALLOW_MAIN_EDITS=1, which switches the guard off for the whole command. Prose arrows (->, =>, 2>) and a ; in explanatory comments are ordinary, so the shape recurs. The block message names the primary checkout and a plausible-looking target, which is what makes it read like a real catch.
Suggested shape
Port the two hunks plus the self-test section from objectstack PR #11129 into this repo's .claude/hooks/guard-main-checkout-bash.sh and guard-main-checkout-bash.selftest.sh, localising issue references per the existing convention. The self-test port carries the load: it pins the word-start condition in both directions — foo#bar, ${x#y}, a quoted #, a URL fragment and sed 's/#//' are NOT comments, and ${#arr[@]} ahead of a real redirect must still block.
#5459 already raises the right structural question and this card is more evidence for it: two independent fixes have now drifted out of a pair of files whose header says they cannot. A gate that diffs the two copies modulo the localised lines would have caught both at the moment they were introduced.
Governed surface (.claude/**): draft PR, human merge.
Generated by Claude Code
Recorded by the objectstack dev who implemented objectstack-ai/objectstack#10570 (its PR: objectstack-ai/objectstack#11129). Filed unassigned, as an observation about this repo's copy of the hook. Dedup performed first: #5459 is the only existing card on this drift, and it is scoped to a different fix.
Not a duplicate of #5459 and not blocked by it — #5459 tracks porting the quote-escape fix (objectstack PR #10406); this is a second, independent fix that has since landed in objectstack's copy of the same file. They are cheaper ported together, in one PR, which is the reason to record this now rather than after #5459 is picked up.
The drift
.claude/hooks/guard-main-checkout-bash.shin both repos carries the header claim that the two copies are "deliberately kept case-for-case identical … so the two repos' guards cannot drift". objectstack PR #11129 changes the parsing logic in objectstack's copy: both quote-aware passes (split_segments()andtokenize()) now apply the shell's comment rule — outside quotes and heredoc bodies, an unquoted#that starts a WORD begins a comment running to the next newline.This repo's copy is, by that header's own claim, still the pre-fix logic.
What that means for agents working in this repo
Measured in objectstack against the pre-fix logic, from a cwd inside the shared primary checkout:
The failure is fail-CLOSED, so nothing unguarded slips through — but it is the false-positive direction that trains an operator toward
OS_ALLOW_MAIN_EDITS=1, which switches the guard off for the whole command. Prose arrows (->,=>,2>) and a;in explanatory comments are ordinary, so the shape recurs. The block message names the primary checkout and a plausible-looking target, which is what makes it read like a real catch.Suggested shape
Port the two hunks plus the self-test section from objectstack PR #11129 into this repo's
.claude/hooks/guard-main-checkout-bash.shandguard-main-checkout-bash.selftest.sh, localising issue references per the existing convention. The self-test port carries the load: it pins the word-start condition in both directions —foo#bar,${x#y}, a quoted#, a URL fragment andsed 's/#//'are NOT comments, and${#arr[@]}ahead of a real redirect must still block.#5459 already raises the right structural question and this card is more evidence for it: two independent fixes have now drifted out of a pair of files whose header says they cannot. A gate that diffs the two copies modulo the localised lines would have caught both at the moment they were introduced.
Governed surface (
.claude/**): draft PR, human merge.Generated by Claude Code