Uh oh!
There was an error while loading. Please reload this page.
fix(pm): the governed-merges audit covers all four governed repos, attributes through the channel the session has, and answers the pre-arm question - #9713
Merged
os-support-ai merged 2 commits intoAug 18, 2026
Conversation
…utes through the channel it has, and answers the pre-arm question Three deliverables in the one audit script: 1. Multi-repo scope (#9619). One invocation sweeps objectstack, objectui, cloud and objectos, resolved from the script's own root rather than the working directory, so the answer no longer depends on where it is run. An absent or wrong-origin checkout reports as UNAUDITED and exits 2 — never as a clean repo (#4690). 2. Attribution through a channel the session actually has (#9619). Channels are tried in order (env token, then anonymous REST) and the transport trap is fixed with them: node's fetch does not read HTTPS_PROXY, so a proxied run read 401/403 on every channel and looked like a credential problem. Sweep mode re-execs once with --use-env-proxy. When every channel fails the reason is stated ONCE per repo as a named line instead of a per-entry UNRESOLVED that buried the list. 3. The --test pre-arm predicate (#9550). `--test <paths...>` answers "would a PR touching these be governed?" from GOVERNED_SURFACES: exit 3 governed, exit 0 not governed, exit 1 on an empty path list. The incident it comes from was recall in place of derivation; derivation is now one command. The header gains #9550's measured timeline and the reading that merged_by names an account, not a principal — the maintainer also operates the seat accounts, so a resolved column prompts recognition and never settles it. Self-test: 25 -> 77 assertions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WswfK2yNYT9hNnMH6TzAwL
…nel as a named failure The channel-shape assertion indexed both[1] directly, so an ablation that removes the anonymous channel crashed the self-test with a TypeError instead of naming which pin broke. Red either way; only one of them tells the reader what is wrong. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WswfK2yNYT9hNnMH6TzAwL
os-support-ai
marked this pull request as ready for review
August 18, 2026 16:37
Uh oh!
There was an error while loading. Please reload this page.
os-support-ai
deleted the
claude/issue-9619-governed-audit-scope-attr-test
branch
August 18, 2026 16:57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#9619
Fixes#9550
One file changed:
scripts/pm/check-governed-merges.mjs(the self-test lives inside it). No changeset — internal PM audit tooling, nothing published;skip-changesetapplied.What landed, in three parts
1. Multi-repo scope (#9619)
One invocation now sweeps all four governed repos. The register of repos is declared beside the register of surfaces:
objectstack-ai/objectstackobjectstack-ai/objectuiobjectstack-ai/cloudobjectstack-ai/objectos--repo-root ID=PATHrelocates any of them;--repos a,bnarrows the sweep. A checkout whoseoriginremote is not the expected slug is treated as absent, never audited under the wrong name.An absent, wrong-origin, or unreadable checkout reports as UNAUDITED and the sweep exits 2. It never renders as a clean repo — nothing was found there because nothing was looked at (#4690). Live on this container, where
cloudis not checked out:That sweep surfaces two objectui and two objectos governed merges that no audit output could previously see at all.
2. Attribution through a channel the session actually has (#9619)
Channels are tried in order and the first success wins: env token (
GITHUB_TOKEN/GH_TOKEN), then anonymous REST — noauthorizationheader, which is what makes a container with no usable token resolvable for the public repos. When every channel fails, the entry still prints (markedUNAVAILABLE, never silently blank) and the reason is stated once per repo as a named line instead of the per-entryUNRESOLVEDthat used to bury the list it was attached to:A measured correction to the dispatch premise. The assumption was that anonymous REST through the session proxy already works, verified with
curl. It does — forcurl. It does not for this script, because node's global fetch does not readHTTPS_PROXY, and that transport gap is the actual cause of the 401 the card reported. Four readings on the same URL, same container, 2026-08-18:curl(readsHTTPS_PROXY)merged_bypresentNODE_OPTIONS=--use-env-proxymerged_bypresentSo a
curlprobe proves nothing about what this script sees, and the env token in an agent container is the literal placeholder stringproxy-injectedthat the proxy swaps for a real credential — bypass the proxy and it is a bad token.scripts/check-required-contexts.mjshit the identical trap under #9642 and its header already names this file as sharing it; that reading is now acted on rather than only warned about. The flag has to be present at process start (assigningprocess.env.NODE_USE_ENV_PROXYfrom inside is too late — measured, still 403), so sweep mode re-execs itself once with--use-env-proxy, guarded byprocess.allowedNodeEnvironmentFlagsso an older node prints the hint instead of crashing on a bad option.--testand--self-testnever re-exec; they touch no network.Result, same window as above: 17 of 17 entries attributed, 0
UNAVAILABLE. Both channels verified live —(via env-token)normally, and(via anonymous)with both token variables unset.What this deliberately does not claim.#9619's second comment measured that
merged_bycannot distinguish a maintainer merge from a seat merge, because the maintainer also operates the seat accounts — objectui PR #5188 readmerged_by os-steveand the maintainer's answer was 「5188 是我合并的」. A resolved column that reads as authoritative would be worse than the honest gap. So every sweep that resolves anything now prints:The three options for giving merges a real discriminator stay recorded on the card; none is taken here.
3. The
--testpre-arm predicate (#9550)node scripts/pm/check-governed-merges.mjs --test PATH...answers "would a PR touching these paths be governed?" fromGOVERNED_SURFACES— the derivation primitive for the standing rule the reporting seat adopted. The incident's root cause was recall in place of derivation; derivation is now one command:Usable as
--test $(gh pr diff --name-only PR), and--jsonfor scripting. The register is repo-agnostic, so it answers for a PR in any of the four repos.Exit codes
The refusal-to-read-as-clean contract survives unchanged; code 2's stated cause widens to cover the new "unaudited repo" case, which is the same class of incompleteness.
--since-ref, not one checkout resolved--test--test--testHeader case law
#9550's measured timeline is added to the institutional-memory section the header collects — the widening at 07:32:55Z, the ready flip at 07:51:53Z (+19 min), the enqueue 13 s later, and the merge-queue removal on a conflict against the very commit that had made the file governed. The existing entries are preserved verbatim, along with the note that it was the conflict and not the discipline that stopped it.
Verification
All at
31818e0, the branch head.pnpm check:pm-governed-merges— 77 assertions, up from 25 onmain. New coverage: four-repo resolution (absent / wrong-origin / relocated), the proxy re-arm plan in all five directions, the channel chain and its single named fallback line, the--testpredicate (governed, mixed, not-governed, six near misses, one case per surface), and the exit table.pnpm check:cross-package-test-inputs— 33 self-test cases, 12 packages OK.pnpm check:pm-dispatch-gates— 284 cases. Not named by the path derivation, run because its own self-test reads this file for watch hints; theskills/**hint assertion still holds.pnpm check:nul-bytes— 6203 files, no raw control bytes; plus a direct control-character scan of the changed file.node scripts/pm/dispatch-gates.mjson the real change set (1 path).Reverse verification — three ablations, each restored and confirmed byte-identical afterwards, with the restored leg re-run green. No rebuild is involved: this script is executed directly as source and its self-test exercises the same file, so there is no
dist/for a stale artifact to hide in.audited--testnever answers governedDraft, and it stays draft:
scripts/pm/is not a governed surface (--test scripts/pm/check-governed-merges.mjsanswers exit 0, pinned in the self-test), so this takes an ordinary queue landing after PM review — but the PM lands it, not this seat.Generated by Claude Code