Repository navigation
[finding] guard-governed-enqueue's slug reader keeps a .git suffix — a sibling cloned with the conventional URL never resolves, and a bare gh pr merge N on such a clone derives a slug the API 404s on, so the guard fails OPEN #18366
Description
Activity
- addedbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3
on Sep 16, 2026 os-elon-musk commented
on Sep 16, 2026 CollaboratorMore actionsClaim: PM loop round 1
Session:session_01Bz6hxDBqK62NP2W1LATvnt(skills seat; claimed at 2026-09-16T07:43Z)
Branch:claude/issue-18366-governed-enqueue-slug-git-suffix
Worktree:objectstack-issue-18366
Domain:domain:skills
File surface:.claude/hooks/guard-governed-enqueue.sh(the slug reader single-sourced at both call sites — theslug_offunction and the inlined copy in the baregh pr merge NUMBERsegment — and made to strip or anchor the trailing.git) +.claude/hooks/guard-governed-enqueue.selftest.sh(two new cases: a sibling with the.gitremote resolves and is audited; a baregh pr merge NUMBERon a.git-URL clone derives the right slug) — nothing else (stop on breach; explain in the report)
Container & model:S,mode:subagent,model: default tier (TIER_DEFAULT)—dispatch-gates.mjs --tierat 2026-09-16T07:29Z derives no path mandate for.claude/hooks/**(floor sonnet · default opus · ceiling fable); a bounded bash fix with one design choice (strip vs anchor) and two self-test cases ⇒ the default judgment tier, not the floor; seat review in-seat atCONTRACT_REVIEW_TIER
Clause-②: no
Thread-read: none (no comment on this card at claim time; the grading is the body's own 「Grading」 line)
Fold-or-serial: NOT FOLDED with #18367 — gate ① fails (a slug-reader defect and an unpinned branch's missing case are different defect shapes with different fixes); #18367 is SERIAL behind this card's PR on the same selftest file; #18384 (finding, graded this round) touches the same hook and queues behind both. Rules layer (.claude/**) ⇒ draft PR, four-piece + an authorized APPROVED; ⛔ never armed by this seat.
Serial constraints cleared: PR #18365 (the same two files) LANDED8b81ab60at 2026-09-16T07:05Z; none of the six open PRs touches either hook file (pulls/N/filesread at 2026-09-16T07:41Z); no remote branchclaude/issue-18366-*(ls-remoteat 2026-09-16T07:28Z, 255 branches, controlissue-17359hit); verify lock free, queue empty at 2026-09-16T07:28Z; devs in flight after this claim 1/3
Generated by Claude Code
os-elon-musk commented
on Sep 16, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 18366, "status": "done", "branch": "claude/issue-18366-governed-enqueue-slug-git-suffix", "worktree": "/home/user/objectstack-issue-18366", "pr": "https://github.com/objectstack-ai/objectstack/pull/18390", "head_sha": "1696da61", "base": "8b81ab60d7b02e5540e8a36917cc86478bfbf899", "session": "session_01Bz6hxDBqK62NP2W1LATvnt (subagent; the dispatching seat's id)", "premise_still_valid": true, "claim_check": "the newest Claim: on #18366 (comment 5693845992, os-elon-musk) names claude/issue-18366-governed-enqueue-slug-git-suffix — it matches this branch. Assignee left untouched (os-elon-musk, set by the PM).", "files_changed": [ ".claude/hooks/guard-governed-enqueue.sh — +28 / -4", ".claude/hooks/guard-governed-enqueue.selftest.sh — +82 / -2" ], "summary": "slug_of and the inlined copy of the same sed in segment_target's bare `gh pr merge N` target derivation are now ONE function called from both sites, and it strips a trailing .git after the match (the path character class owns the dot and is greedy, so the optional group matched empty). PM mechanism assumption 1 held: the two occurrences were byte-identical and content-located, not line-located. The strip route was chosen over anchoring the group because the class still has to own the dot (objectstack.ai is a legitimate repo name) and because GNU and BSD sed are free to settle the class-vs-group race differently, while ${slug%.git} is the same in bash 3.2 everywhere. The self-test pins both shapes the card asks for: four previously unpinned origin spellings of the sibling (https/ssh x with and without .git, plus a trailing slash) resolve and are audited as AGREEMENT with the register, and a bare `gh pr merge N` run from a checkout whose origin carries the suffix derives objectstack-ai/objectstack#13794.", "tests": "SELF-TEST BASELINE on origin/main 8b81ab60 (bash .claude/hooks/guard-governed-enqueue.selftest.sh): '56 passed, 0 failed', exit 0 — measured twice, before pnpm install and after (the regen branch flips from 'NOT lifted' to 'LIFTED' between them; the totals do not). PRE-FIX REPRODUCTION, the card's own two halves: the same fixture and payload with a sibling whose origin is https://github.com/objectstack-ai/cloud answers exit 2 (audited) and with .../cloud.git answers exit 0 (never resolved); a bare `gh pr merge 13794` run from a checkout whose origin carries .git printed 'Blocked: objectstack-ai/objectstack.git#13794' — the slug it would have put in the API URL. AFTER: '62 passed, 0 failed', exit 0 (six new rows). Identical under all three OS_GOVERNED_ENQUEUE_SIBLING_ROOT states (unset / an empty dir / a dir that does not exist): 62/0 each. Also 62/0 in a second worktree of this branch with NO node_modules, which is the file header's own claim about itself. ABLATION 1 (the pre-fix reader restored: old sed, no suffix strip): '57 passed, 5 failed', selftest exit 1 — FAIL rows: the two `gh pr merge N` text rows ('missing objectstack-ai/objectstack#13794', 'still says objectstack.git') and the three .git spelling rows (https .git, ssh .git, trailing slash), each want=block got=allow. ABLATION 2 (a colon dropped from the separator character class): '60 passed, 2 failed', exit 1 — exactly the two git@github.com: rows. Every one of the six new rows is red under one of the two controls; none is a phantom. ABLATION MECHANICS, both runs: absolute REPO_ROOT, a trap on EXIT INT TERM calling the restore function, mutation proven on disk before reading any result (grep counts strip=1/oldsed=0 became strip=0/oldsed=1; blob 3c25d9cfbd6bc12eb8e8183ce1b9a9ab36f3ce66 became 13e739e3e326e49d3facf0420c45b4be7acca452, and a no-op mutation exits 1 as FAILURE), restore by `git checkout HEAD -- path` and proven by blob-hash equality with the HEAD blob PLUS an empty `git diff HEAD` (3c25d9cfbd6bc12eb8e8183ce1b9a9ab36f3ce66 both times). Both controls ran from the COMMITTED state. No build or dist is involved (two bash scripts), so the dist preflight does not apply. Working tree clean after both; no temporary file left in the repo.", "gates": [ "node scripts/check-closing-keyword-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0", "node scripts/check-comment-mask-corpus.mjs :: exit 0", "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 3 first (PREREQUISITE NOT MET — unbuilt @objectstack/formula and @objectstack/lint, 'Nothing was measured'), then exit 0 after `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2` under os-verify-lock.sh (VERDICT command-exit 0, waited 18s, held 169s, slot issue-18366)", "pnpm check:agent-test-spelling :: exit 0", "pnpm check:bash32-floor :: exit 0", "pnpm check:doc-authoring :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:pm-governed-merges :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:skill-frame-sync :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "RECONCILIATION — node scripts/pm/dispatch-gates.mjs --ran FILE --repo objectstack-ai/objectstack :: exit 0, '13 derived, 13 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero — all 13 recorded an exit code and none of them is 3)'. The derivation (--commands, no paths, --repo asserted and held) named the same 13 the dispatch did; nothing new appeared for the real diff.", "EXTRAS — bash -n on both files :: exit 0 / exit 0; the selftest under three injection states :: 0 / 0 / 0 (62 passed each); node scripts/pm/check-governed-merges.mjs --test .claude/hooks/guard-governed-enqueue.sh :: exit 3 (GOVERNED, as expected for this surface); node scripts/pm/check-clause2-carriers.mjs --pair 18390 :: exit 0 ('the clause-② declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell'); pnpm check:pm-settings-deny-roster :: exit 0 — run deliberately because the derivation marks its roster as living under .claude, where silence is evidence in neither direction; grep -naP for control bytes over both files :: no hit.", "NOT MEASURED — shellcheck: not present in this tree (nothing in package.json invokes it, none on PATH). `bash -n` on both files plus the 62-case matrix is what stands in for it; CI runs no shellcheck on these paths either.", "NOT MEASURED — CI on PR #18390: not awaited, per the dispatch (report at the end of local verification; CI convergence is the seat's read). No repo-wide scan (pnpm lint) was run: that is CI's run, and the two paths are .sh files eslint does not read." ], "labels": "skip-changeset applied by add-only POST /repos/objectstack-ai/objectstack/issues/18390/labels (HTTP 200) and read back: label set before = [], after = ['skip-changeset'] = union(read, target). needs:contract-review is NOT on the PR — neither applied nor removed by me, as dispatched. No changeset file: .claude/** publishes nothing from any released package (fast-track path, not a grep measurement).", "deviations": [ "The bare `gh pr merge N` case asserts NO allow/block verdict, only the derived slug in the refusal text. Measured reason: OS_GOVERNED_ENQUEUE_FIXTURE answers every path, so the 404 that makes the real guard fail open cannot be reproduced without the network — under the fixture a wrong slug blocks exactly like a right one and a verdict row would be a phantom. The text rows do go red under ablation 1.", "That case runs a COPY of the hook (symlinked, with scripts/ symlinked too) from a throwaway checkout it builds, because the hook derives its repo root from BASH_SOURCE and nothing injects it. The selftest's run/stderr_of helpers now read $hook_under_test (defaulting to $hook), set for those two rows and restored on the next line.", "The two git@github.com: rows pass `-u GIT_CONFIG_COUNT -u GIT_CONFIG_PARAMETERS`. Measured: this container injects url.https://github.com/.insteadOf git@github.com: through GIT_CONFIG_KEY_n/VALUE_n, and `git remote get-url` honours it, so without the unset the ssh rows are silent duplicates of the https ones — they were, on the first revision, and stayed green under ablation 2 until the unset was added, which is how it was found. This is the #18365 lesson applied: the rows own their premise instead of inheriting the box's git config.", "The four spelling rows reuse $sibling_want from the neighbouring resolved-sibling case instead of asking the register four more times: every tree in the loop is built exactly as that one is (git init plus an origin), so the question and the content are identical — the verdict still comes from the register, not from a word copied into the file.", "The dead optional .git group was removed from the sed rather than left in place beside the strip; a group that can only ever match empty reads as a second, contradictory reader of the same suffix." ], "mcp_calls": "0 — no MCP GitHub tool was called, read or write. Every GitHub read and write went through the REST proxy with curl.", "api_writes": "3 REST writes: POST /repos/objectstack-ai/objectstack/pulls (HTTP 201, draft true, base main) · POST /repos/objectstack-ai/objectstack/issues/18390/labels (HTTP 200, skip-changeset) · POST /repos/objectstack-ai/objectstack/issues/18366/comments (this report). Plus git push on claude/issue-18366-governed-enqueue-slug-git-suffix three times (the empty-branch routing probe, then one per commit). No PATCH of any body; the PR body was final at creation and read back byte-identical (6394 sent / 6393 stored, one footer, no angle-bracket mutation).", "open_questions": [], "out_of_scope_findings": [ "noted, already filed: #18367 — the hermetic case for the fail-open branch. Not touched here; it remains open and serial behind this PR on the same selftest file.", "noted, already filed: #18384 — the ccr auto_merge route arm on the same hook. Not touched here; it remains open.", "noted, not filed: the hook's repo_root is not injectable the way OS_GOVERNED_ENQUEUE_SIBLING_ROOT made the sibling root injectable, which is why the new bare-`gh pr merge N` case has to build a checkout and run a copy of the hook out of it. Class: none of the three (not a reproducible defect — the hook behaves correctly; not a declared-contract breach; not an AI-metadata trap) — a test-shape cost only. Who would hit it: #18367's dev, the next PR on this same selftest file, which is the PR that would carry it if the copy-and-symlink shape ever stops paying for itself.", "noted, not filed: this container rewrites git@github.com: to https:// for every git command through GIT_CONFIG_KEY_n/VALUE_n injection, so any test anywhere in this repo that asserts on an ssh remote URL is silently asserting on an https one. Class: none of the three (a property of the box, not of the tree). Who would hit it: any dev writing a git-remote fixture here; the one instance I could see is now pinned in place. No repo-wide sweep was run for other instances — that would be a second card's work." ] }
Generated by Claude Code
os-elon-musk commented
on Sep 16, 2026 CollaboratorMore actionsACCEPT — skills seat, session
session_01Bz6hxDBqK62NP2W1LATvnt, 2026-09-16T08:23Z. Report 5694306324 on PR #18390 (head1696da61) reviewed by the checklist on GitHub readings and this seat's own re-runs: draft, basemain,Fixes #18366alone; changed files = the two hook files exactly (+110 / −6), the claim's surface;skip-changesetread back;mcp_calls0;api_writes3, budget met; path face GOVERNED (rules layer);--pair 183900; the diff read whole — oneslug_ofat both sites, the suffix stripped after the match, the dead optional group gone; selftest re-run by this seat62 passed, 0 failedon the head and56 / 0onmain; gates 13 / 13 / 0 by--ran; two declared deviations accepted with their measured reasons (the slug-text rows in place of a verdict the fixture cannot discriminate; the ssh rows unsetting the container'sinsteadOfinjection); shellcheck NOT MEASURED (not wired). CI on the head:Lint & Repo GatesandType Check · workspacein progress at the reading. Contract-review record + 速读终稿 on the PR;needs-user-decisionon the PR; reviewersos-zhuangandhotlongrequested. The card stayspm:dispatcheduntil ruling C after an authorized APPROVED. Serial chain: #18367 (the fail-open case) and #18384 (the ccr arm) follow on the same files.
Generated by Claude Code
os-elon-musk commented
on Sep 16, 2026 CollaboratorMore actionsLanded — skills seat, session
session_01Bz6hxDBqK62NP2W1LATvnt, 2026-09-16T09:36Z. PR #18390 (head1696da61,.claude/hooks/guard-governed-enqueue.sh+.selftest.sh— rules layer) merged by the queue as40eaf755be01410d4c0a9c61c3c7ea95981c542c(single-parent squash pergit rev-list --parents, parent7c8d6d98) at 2026-09-16T09:35Z — themerged_atinstant. Readings:git log origin/maincarries(#18390)at the tip;git log origin/main -- .claude/hooks/guard-governed-enqueue.shnames it as the file's latest touch and the hook's header now documents the.git-suffix slug reading it strips; the queue refrefs/heads/gh-readonly-queue/main/pr-18390-*is gone from origin. Governed landing by ruling C with the maintainer's own hand on the last three steps: four-piece at 2026-09-16T08:23Z (record + 速读终稿 5694395229, ACCEPT 5694396286,needs-user-decisionon the PR, reviewers requested);os-zhuangAPPROVED at 2026-09-16T09:14Z (review 5220756379, an authorizedGOVERNED_APPROVERSaccount), then turned the PR ready, enabled auto-merge and it wasadded_to_merge_queueat 2026-09-16T09:14Z; this seat's part was clearingneeds-user-decisionon the PR at 2026-09-16T09:17Z.Fixes #18366closed this card at the merge; residue (pm:dispatched) stripped throughlabel-write.mjsand read back. Serial unlock: #18367 (the fail-open hermetic case) and #18384 (p2, the ccr enqueue spelling) on the same hook are now free — next in this lane's total order once a dev slot opens (3 / 3 in flight at this record).
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Filed by the
domain:skillsexecution PM seat, sessionsession_01HZfg2AwVX191qCizp88gQr, at 2026-09-16T04:27Z, from the #18321 dev'sout_of_scope_findings(report 5691990182 on #18321; PR #18365), measured by that dev on its head and read by the seat.Reading
.claude/hooks/guard-governed-enqueue.sh'sslug_ofreads a checkout's origin withsed -n 's#.*github\.com[:/]\([A-Za-z0-9._-]*/[A-Za-z0-9._-]*\)\(\.git\)\{0,1\}/*$#\1#p'. The path character class owns.and is greedy, so the optional\(\.git\)group matches EMPTY andhttps://github.com/objectstack-ai/cloud.gityieldsobjectstack-ai/cloud.git— a slug that equals noowner/repothe guard is ever asked about. Measured on PR #18365's head: a throwaway sibling whoseorigincarries the.gitsuffix answersallowwhere the identical tree with the bare URL answersblock. The real/home/user/cloudhappens to carry the bare form, which is the only reason the #18321 reproduction worked at all; PR #18365's new self-test case uses the bare URL deliberately and says so in place.The SAME expression is inlined a second time in the hook's
segment_targetto derive the slug for a baregh pr merge NUMBER(no-R): a non-matching slug makes the API read 404 and the guard FAILS OPEN — on any clone made with the conventional.gitURL, that spelling of the merge command is unguarded.What is asked
Single-source the slug reader (one function, both call sites), make it strip a trailing
.gitbefore the path class can swallow it (or anchor the group so it cannot match empty), and pin both shapes inguard-governed-enqueue.selftest.sh: a sibling with the.gitremote resolves (and is audited), and a baregh pr merge Non a.git-URL clone derives the right slug (the guard reads the PR instead of 404-ing open)..claude/hooks/guard-governed-enqueue.sh+ its selftest only; rules layer (.claude/hooks/**) ⇒ draft PR, four-piece + an authorized APPROVED; ⛔ never armed by the seat.Grading (lane self-triage; class (a), a guard that fails open on the conventional clone URL): p2 · Bug ·
pm:queue·domain:skills. SERIAL behind PR #18365 (the same two files; its injection is what makes the new cases hermetic).查重词
guard-governed-enqueue slug_of·.git suffix origin url·sibling checkout not resolved·gh pr merge slug derivation·fail open 404Generated by Claude Code