Skip to content

[finding] guard-governed-enqueue's 「no checkout available」 fail-open is pinned by no self-test case in any environment — the case that claimed it never reaches it; one hermetic case with the injected empty root #18367

Description

@os-zhuang

Filed by the domain:skills execution PM seat, session session_01HZfg2AwVX191qCizp88gQr, at 2026-09-16T04:27Z, from the #18321 dev's out_of_scope_findings (report 5691990182 on #18321; PR #18365), measured by that dev and read by the seat.

Reading

.claude/hooks/guard-governed-enqueue.sh's fail-open 「no checkout of the target repo is available to recompute its provenance on」 (warn + allow, after the governed predicate answered exit 3 with an exception row) is pinned by NO case in guard-governed-enqueue.selftest.sh, in any environment. The case whose comment used to claim it (「an exception-row path in a repo this container cannot resolve」) never reaches it: with nothing resolved the register is invoked WITHOUT --root, answers about THIS tree, where skills/objectstack-data/references/_index.md is byte-exact against its own generator and therefore LIFTED (exit 0), so the hook leaves at the cleared-predicate exit 0 several branches above the fail-open, with EMPTY stderr. PR #18365 corrected that stale comment and made the case hermetic; it did not add coverage of the branch (a new fixture is a new verification surface — outside that card).

The branch IS reachable: node scripts/pm/check-governed-merges.mjs --test skills/zz-no-such-skill/references/_index.md returns exit 3 with exceptions of length 1 (the generator 「does not write」 that path — it is not among the 9 declared outputs). That path shape, with OS_GOVERNED_ENQUEUE_SIBLING_ROOT (PR #18365) pointed at an empty directory, takes the fail-open and prints the warning.

What is asked

One hermetic case in the selftest that reaches the fail-open (the path shape above + the injected empty root), asserting allow AND the warning text (the dev's phantom-check lesson: a text assertion must be shown to go red under a firing control — e.g. the same payload with the sibling resolved). .claude/hooks/guard-governed-enqueue.selftest.sh only (the hook unchanged unless the case reveals a defect — report, do not widen); rules layer (.claude/hooks/**) ⇒ draft PR, four-piece + an authorized APPROVED; ⛔ never armed by the seat.

Grading (lane self-triage; class (a), an unpinned branch): p3 · Task · pm:queue · domain:skills. SERIAL behind PR #18365 (the injection it uses). Fold candidate with the .git-slug card filed beside it (same two files; the second lander merges origin/main otherwise).

查重词

guard-governed-enqueue fail-open · no checkout available branch · target_root exception_rows · unpinned branch selftest · phantom check


Generated by Claude Code

Activity

  1. self-assigned this
    on Sep 16, 2026
  2. os-elon-musk commented on Sep 16, 2026

    @os-elon-musk
    Collaborator

    Claim: PM loop round 1 (skills seat, successor shift)
    Session: session_01HPfcjvF23QBoBj7P47DDxs
    Branch: claude/issue-18367-enqueue-guard-fail-open-selftest
    Worktree: objectstack-issue-18367
    Domain: domain:skills
    File surface: .claude/hooks/guard-governed-enqueue.selftest.sh (one new hermetic case reaching the 「no checkout … is available」 fail-open, with a firing control); .claude/hooks/guard-governed-enqueue.sh ⛔ unchanged unless the case reveals a defect — then report, do not widen (stop on breach; explain in the report)
    Container & model: S (test-only pin, but the fixture and the control assertion are a design judgment), mode:subagent, model: claude-opus-5 — default judgment tier; node scripts/pm/dispatch-gates.mjs --tier .claude/hooks/guard-governed-enqueue.selftest.sh at 2026-09-16T10:01Z on 588475c3: 「Model tier — no path-derived mandate: the surface hits none of the 3 declared glob(s) … floor sonnet · default opus · ceiling fable」; not taken to the floor because the card's own phantom-check lesson (the text assertion must go red under a control) is a judgment, not a mechanical edit; in-seat review at CONTRACT_REVIEW_TIER.
    Clause-②: no
    Thread-read: none
    Ruling-ref: none — no maintainer ruling on this card; lane self-triage grading in the body (p3 · Task), class (a) unpinned branch.
    Serial constraints cleared: .claude/hooks/guard-governed-enqueue.sh + .selftest.sh — chain per the seat post's hot-file line: PR #18390 LANDED 40eaf755 (09:14Z) → this card → #18384 (pm:queue, unclaimed, SERIAL behind this card on the same two files; fold-or-serial answered SERIAL — gate ① fails, an unpinned branch vs a missing match arm). PR #18365 8b81ab60 (the OS_GOVERNED_ENQUEUE_SIBLING_ROOT injection this case uses) LANDED 06:41Z. No open PR and no in-flight claim touches these files. No sibling card's pin asserts the behaviour this card pins. Premise re-read on 588475c3 at 2026-09-16T10:01Z: the selftest's cross-repo case (its own comment: 「AND IT DOES NOT REACH THE "no checkout … is available" FAIL-OPEN — measured」) still asserts allow without the warning; check-governed-merges.mjs --test skills/zz-no-such-skill/references/_index.md still exits 3 with one exception row; the hook's fail-open text 「no checkout of OWNER/REPO is available to recompute its provenance on」 is still at its warn call; the selftest passes 62 / 62 on this tree.


    Generated by Claude Code

  3. os-elon-musk commented on Sep 16, 2026

    @os-elon-musk
    Collaborator

    os-dev-report

    {
    "issue": 18367,
    "status": "done",
    "branch": "claude/issue-18367-enqueue-guard-fail-open-selftest",
    "pr": "#18423",
    "pr_number": 18423,
    "pr_head_sha": "e3a22ebf5aae78114331077dcba15be2a9f520fc",
    "pr_draft": true,
    "session": "session_01HPfcjvF23QBoBj7P47DDxs",
    "premise_still_valid": true,
    "base": "90b23ab1d4e93a78c4f59855ab0bbb2fa7f7b693 (origin/main at worktree creation; the dispatch named 588475c — the rule-1 fetch advanced origin/main by one commit, 90b23ab, which touches neither hook file: git diff --stat 588475c..90b23ab -- .claude/hooks/ scripts/pm/check-governed-merges.mjs is empty)",
    "summary": "Added one hermetic self-test case (4 assertions) to .claude/hooks/guard-governed-enqueue.selftest.sh pinning the hook's 'no checkout of OWNER/REPO is available to recompute its provenance on' fail-open. It reuses the empty sibling root the existing cross-repo case already injects and changes only the path shape, to skills/zz-no-such-skill/references/_index.md — a skills path no generator declares, so the register answers governed (exit 3) with one exception row wherever it is asked, which is the branch's whole precondition. Asserts allow plus the two load-bearing halves of the warning, and a firing control (the same payload with the sibling resolved) asserts the sentence is absent there. The hook itself is unchanged; nothing in writing the case revealed a defect in it. assignee was empty on arrival and stays empty.",
    "tests": "BASELINE 62/62 on the worktree base (90b23ab) and 66/66 with the new case, both via OS_VERIFY_LOCK_SLOT=dev-18367 bash scripts/pm/os-verify-lock.sh -c 'bash .claude/hooks/guard-governed-enqueue.selftest.sh' (VERDICT command-exit 0, 20s and 27s under the lock, 0s waited). RED-UNDER-CONTROL (one-time, from the COMMITTED implementation): the says row naming the repo was pointed at the RESOLVED sibling root instead of the empty one; on-disk proof before any verdict was read — grep counts NO_SIBLING_ROOT 4 -> 3 and resolved SIBLING_ROOT 2 -> 3, HEAD blob 2d9f332ea518826251a8f760d8d3e9bed72a2dde vs working blob 9b6f2bc7c26375f36d18aac97ba0a0d61ad9c515; the run then printed 'FAIL missing "no checkout of objectstack-ai/cloud" the fail-open names the repo it could not resolve / 65 passed, 1 failed'. Restored with git checkout HEAD -- PATH under a trap using absolute paths, proven by bytes: git diff HEAD --stat empty and git hash-object back to 2d9f332e. HERMETICITY measured in both directions: the register answers exit 3 with one exception row in this installed worktree (reason: the generator 'does not write' the path, not among the 9 declared outputs) AND in the un-installed shared checkout (reason: 'the generator declared no output set (the generator's own --check exited 254)'); the hook takes the fail-open and prints the warning in both (HOOK_EXIT=0).",
    "gates": "dispatch-gates --commands derived 14 families for this path; 14 run in the foreground with exit codes captured before any pipe, all exit 0, plus pnpm check:pm-settings-deny-roster (exit 0) which the derivation flags as a roster living under .claude. dispatch-gates --ran reconciliation: '14 derived, 14 run, 0 NOT-MEASURED, 0 UNRUN' — a DERIVED zero (every line records an exit code). One family needed a prerequisite first: pnpm --filter @objectstack/lint run check:doc-formula-expressions exited 3 (PREREQUISITE NOT MET — unbuilt @objectstack/lint and @objectstack/formula, measures nothing), re-run to exit 0 after pnpm exec turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lint under the same lock slot. No package's test/typecheck is owed: the diff is one bash file under .claude, touching no workspace package. CI convergence not awaited (per the dev contract).",
    "line_budget": "not a skills/** ratchet surface — .claude/hooks/** publishes nothing and carries no line ceiling. File 572 -> 633 lines (+61: 4 assertion rows, one printed register-verdict diagnostic, the rest the case's own comment register). Package total not applicable.",
    "files_changed": [
    ".claude/hooks/guard-governed-enqueue.selftest.sh"
    ],
    "changeset": "none — AGENTS.md Post-Task Checklist step 3, acted on verbatim: 'never skip-changeset: that label is for a diff that publishes nothing from any released package.' This diff is one file under .claude/, shipped by no package's files[], so nothing publishes; the skip-changeset label was applied additively and read back (labels on the PR read back exactly ['skip-changeset']).",
    "deviations": [
    "Base is 90b23ab, not the dispatched 588475c: rule 1's recipe is git fetch origin main && git worktree add ... origin/main, and the fetch advanced origin/main by one commit. That commit touches neither hook file nor the register, so every dispatched reading still holds; all measurements in this report are on 90b23ab.",
    "A1 reason text: in the INSTALLED worktree the exception row reads 'does not write that path — not among the 9 file(s) that generator declared', i.e. the card's wording, not the PM's un-installed variant. The PM's variant was reproduced read-only in the shared checkout (no node_modules). Both are exit 3 with one exception row, so the fail-open precondition holds either way and the case does not depend on which.",
    "Commit trailer pair is the model-free one AGENTS.md mandates (Claude-Session plus a bare Co-authored-by) rather than the harness attribution lines, which name a model; AGENTS.md wins on conflict and the pre-push hook enforces it — check:commit-card-trailers passed on the push with 'no card relation and no model identifier in the trailer pair'."
    ],
    "mcp_calls": "0 — no MCP GitHub tool was called, read or write.",
    "api_writes": "3 REST proxy writes: POST /repos/objectstack-ai/objectstack/pulls (draft), POST /repos//issues/18423/labels, POST /repos//issues/18367/comments (this report). Plus 2 git push (the empty-branch write-route probe, exit 0, and the commit). No PATCH of the card, no second Claim, no assignee write.",
    "open_questions": [],
    "out_of_scope_findings": [
    "noted, not filed: the case's premise is that skills/zz-no-such-skill/references/_index.md stays undeclared by every generator; if a real skill ever takes that name the two text rows go red rather than silently passing, and the printed register-verdict line names why in one line. Carrier: the next PR to touch this matrix.",
    "noted, not filed: the register's exception reason differs between an installed and an un-installed tree (declared-output list vs '--check exited 254'), same exit code and same row count. Not a defect — both are the fail-closed arm — but it is why this case asserts the hook's sentence and never the register's reason. Carrier: none."
    ]
    }


    Generated by Claude Code

  4. os-elon-musk commented on Sep 16, 2026

    @os-elon-musk
    Collaborator

    ACCEPT — skills seat, session_01HPfcjvF23QBoBj7P47DDxs, 2026-09-16T10:22Z. Report 5695878694 · PR #18423 (draft, head e3a22ebf, base main, first line Fixes #18367).

    Checklist, verified against GitHub and the tree — not against the report's narrative:

    • Shape / scope: draft ✓ · base main ✓ · closing keyword on the first line and nowhere else ✓ · changed files = .claude/hooks/guard-governed-enqueue.selftest.sh only (+61 / −0), the hook untouched ✓ · no content/docs/releases/ ✓ · skip-changeset matches AGENTS.md's own arm (the label 「is for a diff that publishes nothing from any released package」; .claude/** ships in no package's files[]) ✓.
    • The case, read in the diff: one new block after the cross-repo case — payload path skills/zz-no-such-skill/references/_index.md (undeclared by every generator ⇒ the register answers exit 3 + one exception row wherever asked), injected root = the empty NO_SIBLING_ROOT the previous case already builds; asserts allow + says 'no checkout of objectstack-ai/cloud' + says 'recompute its provenance'; the firing control expect_lacks 'no checkout of' runs the same payload against the RESOLVED sibling root. The register verdict line is printed, not asserted. This is what the card asked for (the branch + a control that makes the text rows falsifiable).
    • Test evidence, re-run by the seat: bash .claude/hooks/guard-governed-enqueue.selftest.sh on a detached worktree at e3a22ebf → 66 passed, 0 failed (base reads 62). The red-under-control demonstration in the PR body (mutating the says row's root to the resolved one → 65 passed, 1 failed, restored by blob hash) is the dev's; the seat did not repeat the mutation, and records that as the one reading taken from the report rather than re-measured.
    • Gates: the body lists 14 derived families + check:pm-settings-deny-roster, all exit 0, --ran reconciled 14 / 14; check-clause2-carriers.mjs --pair 18423 exit 0 on the seat's side. CI on e3a22ebf at review time: 27 of 29 check-runs success / skipped, Lint & Repo Gates and Type Check · consumer gates still in_progress — a convergence reading that belongs to the landing window, not to this verdict.
    • Writes: mcp_calls 0 · api_writes 3 REST (draft PR, one label, this report) + 2 pushes — within the dispatched budget; no assignee write, no second claim.
    • Deviations accepted: base 90b23ab1 (rule-1 fetch advanced origin/main by one commit touching neither hook file); commit trailers per AGENTS.md's model-free pair.
    • Out-of-scope findings: two noted, not filed entries, both boundaries of the case's own premise; neither is in the three filing classes — agreed, nothing to file.

    Path face (check-governed-merges.mjs --test on the changed path): .claude/** ⇒ GOVERNED, rules layer ⇒ terminal four-piece, ⛔ not landed by any seat: ① this comment is the review of record · ② needs-user-decision on PR #18423 + the seat's 速读终稿 as a PR comment · ③ review requested from os-zhuang and hotlong · ④ listed under awaiting a human merge in the round report. After an authorized APPROVED (GOVERNED_APPROVERS, not dismissed): ruling C — this seat lands it (record on the current head, --pair 0, all checks green or rostered skips, clear the label, ready via the CCR route, auto-merge SQUASH). Card stays pm:dispatched + assignee until MERGED closes it by Fixes. Hot-file chain: #18384 is now SERIAL behind this PR on the same two files.


    Generated by Claude Code

  5. os-elon-musk commented on Sep 16, 2026

    @os-elon-musk
    Collaborator

    Landed — skills seat, session_01HPfcjvF23QBoBj7P47DDxs, 2026-09-16T11:03Z. PR #18423 (head e3a22ebf) merged by the queue as b9598e9c (single-parent squash per git rev-list --parents) at 2026-09-16T10:58:22Z — the merged_at instant, carried identically by the merged and removed_from_merge_queue timeline events (added_to_merge_queue 10:37:12Z). Two readings at 2026-09-16T11:02Z: origin/main tip is b9598e9c (test(hooks): pin guard-governed-enqueue's "no checkout available" fail-open (#18423)) and carries the new case (git grep on origin/main → 1 hit in the selftest); the queue ref gh-readonly-queue/main/pr-18423-* is gone. Governed landing by ruling C: ACCEPT 5695920970 (review of record), os-zhuang APPROVED 5221424219 on that head 10:23Z, ready + auto-merge + enqueue by the approver, --pair 18423 0 on the seat's side. This card closed completed by Fixes at 10:58:23Z. Residue (pm:dispatched, assignee) stripped through label-write.mjs in the same stroke and read back. Hot-file chain released: #18384 is FREE on .claude/hooks/guard-governed-enqueue.sh + .selftest.sh and is the next dispatch. Harness fact carried to the round report: the seat's needs-user-decision removal on PR #18423 was refused by the auto-mode classifier after the APPROVED was on it; the label stayed and did not gate the queue.


    Generated by Claude Code

  6. removed their assignment
    on Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions