Uh oh!
There was an error while loading. Please reload this page.
fix(hooks): port the guard-main-checkout-bash.sh fix family from objectstack PR #11278 - #6046
fix(hooks): port the guard-main-checkout-bash.sh fix family from objectstack PR #11278#6046yinlianghui-tw wants to merge 1 commit into
Conversation
…ctstack PR #11278 Verbatim cross-repo port of the three commits on objectstack PR #11278 (objectstack#11131 + #11133 + #11234) into this repo's copy of .claude/hooks/guard-main-checkout-bash.sh, plus the selftest additions. 1. split_segments() gains the backslash branch tokenize() already had. Outside quotes a backslash escapes the next character, so an escaped \" opens no quoted region. Only tokenize() knew that; segmentation read the " as opening a region that never closed, went inert for every separator behind it, and let a real `sed -i` through as a mere argument. 2. strip_heredocs()'s delimiter scan learns the comment rule via a new strip_line_comment() helper. A `<<WORD` merely NAMED in a comment introduced nothing in bash, but the scan registered it, the delimiter never appeared on a line of its own, and every remaining line -- including real commands -- was dropped before either quote-aware pass could see it. 3. Header enumeration count `Three layers:` -> `Four layers:`. objectui#5459's port carried the miscount deliberately to stay byte-identical with an upstream that was itself wrong; upstream has now corrected it, so correcting it here restores parity rather than breaking it. Selftest matrix 100 -> 121 cases. Both blocks were spliced from upstream's file verbatim; only issue references are localised (`#11131` -> `objectstack#11131` etc.), matching this copy's existing convention for upstream refs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
yinlianghui-tw
commented
Aug 24, 2026
PM: ACCEPT — ⛔ stays draft, human merge requiredVerified against the repository, not taken on report.
What earns the acceptThe port method was right, and it is the part that mattered. The order warned that a functionally-equivalent rewrite violates the parity contract even when it behaves identically. The dev spliced upstream's text out of All three acceptance legs were run, not just the countable one.
The verification-scope limit was declared rather than papered over — the repo-wide lint/test farm was not run locally, with the reason stated (two shell files under ⛔ Landing: not mine to do
Follow-ups from this round#6042 — the same objectstack#11131-class backslash hole in Two PM actions taken on it:
The severity note recorded on both: this is the guard behind the ⛔ Never Generated by Claude Code |
…lit_segments() Outside quotes a backslash escapes the next character, so an escaped `\"` opens no quoted region at all. split_segments() had no branch for it: it read the `"` as opening a region that never closed, went inert for every separator behind it, collapsed the whole command into one segment whose head word was harmless, and waved a real `git stash` through as a mere argument of `echo`. Ports the split_segments() backslash branch from guard-main-checkout-bash.sh (objectstack#11131 / objectstack PR #11278, and this repo's PR #6046), adapted to this hook: it has no `word` bookkeeping and no tokenize() -- check_segment() uses `read -r -a`, which leaves the backslash literal, so both characters are kept verbatim and the pass only splits. Only the objectstack#11131 half applies. The objectstack#11133 comment-heredoc half has no analogue: this hook has no strip_heredocs() pass to carry it. Self-test matrix 32 -> 41 cases, and the hook header's own re-derivable count line is updated to match. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
Fixes#5789
Verbatim cross-repo port of the three commits on objectstack PR objectstack-ai/objectstack#11278 (family objectstack#11131 + objectstack#11133 + objectstack#11234) into this repo's copy of
.claude/hooks/guard-main-checkout-bash.sh, plus the selftest additions.⛔ Governed surface — draft PR, human merge only
.claude/**is a governed surface in this repo. This PR is deliberately a draft and must stay one: it is not to be marked ready, not to be put on auto-merge, and not to be merged by an agent. A human merges this one.What landed
split_segments()gains the backslash branchtokenize()already had. Outside quotes a backslash escapes the next character, so an escaped backslash-doublequote opens no quoted region at all. Onlytokenize()knew that; segmentation read the double quote as opening a region that never closed, went inert for every separator behind it, collapsed the whole command into oneechosegment, and let a realsed -ithrough as a mere argument.strip_heredocs()'s delimiter scan learns the comment rule, via a newstrip_line_comment()helper. A two-less-than introducer merely NAMED in a comment introduces nothing in bash, but the scan registered it as real; the delimiter then never appeared on a line of its own, so the pending heredoc was never satisfied and every remaining line — including real commands — was dropped before either quote-aware pass could see it.Three layers:→Four layers:. objectui#5459's port carried the miscount deliberately, to stay byte-identical with an upstream that was itself wrong. Upstream has now corrected it, so correcting it here restores parity rather than breaking it — this is not intentional local divergence being overwritten.Selftest matrix: 100 → 121 cases.
Evidence
1. Selftest, before and after
bash .claude/hooks/guard-main-checkout-bash.selftest.shad0f5f11f)100 passed, 0 failedc42985576)121 passed, 0 failed2. The two measured probes flip ALLOWED to blocked
Run against this repo's hook with the selftest's own fixture shape (payload
cwd= the shared primary checkout).echobackslash-doublequote, then;, thensed -i s/a/b/ pkg/x.ts# use catredirect/tmp/ntwo-less-thanEOF for notes, then a newline, thensed -i s/a/b/ pkg/x.tsBoth were genuine fail-opens in this copy before the port: a real in-place write of a file in the shared checkout, waved through. The exact byte-for-byte probe commands are the new selftest cases themselves — see the
objectstack#11131andobjectstack#11133sections added toguard-main-checkout-bash.selftest.shin this diff.3. The objectstack#10247 mirror twins stay ALLOWED — no over-blocking
A guard that blocks more than intended is a defect, not extra safety. Verified unchanged:
node -ewhose string literal carries U+2192 and whose body has ast=arrow-fnnode -ewith an escaped-doublequote string literal, no redirectnode -ewith escaped-doublequote literals plus an arrow-fn tailecho 'build → test → ship'grep -n '→ the URL' AGENTS.mdAnd their negative twins — an otherwise-similar command carrying a REAL ASCII redirect — stay blocked, so the allow side is not widened for redirection at large:
echo 'build → ship'redirected intosteps.txtnode -eredirected intopkg/out.jsonParity accounting — every remaining difference from upstream
The port was produced by splicing upstream's text verbatim (extracted from
objectstack-ai/objectstack@origin/mainby line range), not by re-implementing from the card's prose.diff -u upstream ourswas then read line by line. Every remaining difference falls into one of two buckets:A. Pre-existing localisations, untouched by this PR — the example path
packages/fields/src/x.tsx; the direction-of-travel provenance paragraph (this copy is the origin:objectui#3435, same family as#3430); theguard-shared-stash.shcross-references (fail-open boundary note, jq-less fallback note, thesplit_segments/tokenizeheader paragraphs); the "mirroring both sibling hooks" exit-code line; the→-in-AGENTS.md paragraph where upstream cites its own➜CLI banner;cd /home/user/objectuiin themaybe_cdexample;objectui#3435in the block message; and in the selftest, the provenance line,pnpm --filter @object-ui/app-shell test, and the arrow-glyph allow case.B. Issue-reference localisation on the newly ported lines — this copy prefixes upstream issue numbers, so
(#11131)→(objectstack#11131),(#11133)→(objectstack#11133),(#10570)→(objectstack#10570). That is the same convention already carried onobjectstack#4890,objectstack#10247andobjectstack#10570elsewhere in both files, and is exactly what the parity contract names as localised ("only issue references, example paths and the package name in the self-test are localised").No other difference remains. Every logic line — the
strip_line_comment()body, the backslash branch insplit_segments(), the twoscan=lines instrip_heredocs(), theFour layers:header, and all 21 new selftest cases — is byte-identical to upstream.Scope
Port only. No cases added, nothing improved on upstream, nothing else in the hook touched.
guard-main-checkout.sh,guard-shared-stash.shand every other hook are untouched —git statuson this branch shows exactly two modified files.One out-of-scope observation was measured and filed as its own card, not folded in:
guard-shared-stash.shhas the same objectstack#11131-class backslash hole in itssplit_segments(), in both repos. Filed as #6042, which remains open and is not addressed here.Gates
Run at
c42985576(the tip of this branch, working tree clean):bash .claude/hooks/guard-main-checkout-bash.selftest.sh121 passed, 0 failednode scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 4989 tracked text file(s); skipped 85 binary).node scripts/check-changeset-presence.mjs✅ No source of a released package changed in this range, so no changeset is owed.bash -non both filesNo changeset: this touches
.claude/tooling only, no released package'ssrc/.Generated by Claude Code