Filed unassigned by the repo:objectui execution seat (session session_01RV6yuVCxymHYE16PL9vQkE) while producing a round report. Not claimed — the fix lands in scripts/pm/, which is not my lane. Grading and routing are triage's.
check-governed-merges.mjs (#9495) is the post-merge audit that replaced the per-PR ADR approval gate. The skill calls it the "事后防线" and the round-report contract says to run it rather than summarise from memory. I ran it this round and hit two things that stop it short of its stated purpose.
1. It audits only objectstack, regardless of where it is run
Run from the objectui checkout, it still enumerates objectstack PRs:
cd /home/user/objectui && node /home/user/objectstack/scripts/pm/check-governed-merges.mjs --since 1d
• PR #9509 … surfaces: .claude/** ×2
• PR #9490 … surfaces: .claude/** ×1
Every entry it returned is an objectstack PR. It never looked at objectui's history.
Why that is now a coverage gap rather than a design choice: on 2026-08-18 the maintainer extended the governed-surface rule across repos — "任何对 agents.md 等文件的修改…包括 objectui cloud仓库" → 「同意」 — and the PM skill's ACCEPT path-fork encodes it: AGENTS.md, CLAUDE.md, .claude/**, skills/** are governed in objectui, cloud and objectos too. objectui has a live skills/** tree (three PRs are queued against it awaiting a human merge right now: PR5124, PR5080, PR4930). So the surfaces are governed in those repos, the seat discipline is the only thing guarding them, and the audit that is supposed to catch a seat violating that discipline is blind to those repos.
The asymmetry is the risk: a governed merge in objectstack shows up in the audit; the identical merge in objectui does not, and nothing else would surface it.
2. merged_by is UNRESOLVED in the container where the audit is actually run
Every entry carried:
merged_by UNRESOLVED (GET https://api.github.com/repos/objectstack-ai/objectstack/pulls/9509 answered HTTP 401)
and the script closed with its own honest warning: attribution incomplete, "does the maintainer recognise every entry" cannot be answered without the who-merged-it column, and incomplete must not read as clean. Provide GITHUB_TOKEN/GH_TOKEN and re-run.
The script's refusal to read as clean is correct and should stay. The problem is that in the PM session container, no GITHUB_TOKEN/GH_TOKEN is exported — GitHub access is through the MCP server, not the raw API — so UNRESOLVED is the default outcome, not an edge case. The audit is structurally unable to answer its question in the environment where round reports are produced. An audit that always degrades to "incomplete" is one a reader learns to skim, which is how a real violation gets waved through.
Why this is worth fixing rather than noting
These two compound. The governed-surface regime traded a per-PR machine gate for human merge as the review record, with a post-merge audit as the backstop. Right now the backstop cannot see three of the four repos it covers, and cannot attribute the merges it does see. That is closer to "no backstop" than the ruling assumed when it retired the pre-merge gate.
Directions (not decided here)
- Scope: take a repo argument, or enumerate the sibling checkouts, so one invocation covers the four governed repos. Sibling repos are not always checked out, so absence must report as unaudited, never as clean.
- Attribution: resolve
merged_by through whatever GitHub channel the session actually has, or make the missing-token case a named, once-per-run line rather than a per-entry UNRESOLVED that buries the list.
Dedup
Searched objectstack for prior art on both halves before filing. Nearest is #9495 — the closed card that created this audit; it scoped the objectstack half and predates the 2026-08-18 cross-repo extension. No open card covers either half.
Filed unassigned by the
repo:objectuiexecution seat (sessionsession_01RV6yuVCxymHYE16PL9vQkE) while producing a round report. Not claimed — the fix lands inscripts/pm/, which is not my lane. Grading and routing are triage's.check-governed-merges.mjs(#9495) is the post-merge audit that replaced the per-PR ADR approval gate. The skill calls it the "事后防线" and the round-report contract says to run it rather than summarise from memory. I ran it this round and hit two things that stop it short of its stated purpose.1. It audits only
objectstack, regardless of where it is runRun from the
objectuicheckout, it still enumerates objectstack PRs:Every entry it returned is an objectstack PR. It never looked at objectui's history.
Why that is now a coverage gap rather than a design choice: on 2026-08-18 the maintainer extended the governed-surface rule across repos — "任何对 agents.md 等文件的修改…包括 objectui cloud仓库" → 「同意」 — and the PM skill's ACCEPT path-fork encodes it:
AGENTS.md,CLAUDE.md,.claude/**,skills/**are governed in objectui, cloud and objectos too. objectui has a liveskills/**tree (three PRs are queued against it awaiting a human merge right now: PR5124, PR5080, PR4930). So the surfaces are governed in those repos, the seat discipline is the only thing guarding them, and the audit that is supposed to catch a seat violating that discipline is blind to those repos.The asymmetry is the risk: a governed merge in objectstack shows up in the audit; the identical merge in objectui does not, and nothing else would surface it.
2.
merged_byis UNRESOLVED in the container where the audit is actually runEvery entry carried:
and the script closed with its own honest warning: attribution incomplete, "does the maintainer recognise every entry" cannot be answered without the who-merged-it column, and incomplete must not read as clean. Provide
GITHUB_TOKEN/GH_TOKENand re-run.The script's refusal to read as clean is correct and should stay. The problem is that in the PM session container, no
GITHUB_TOKEN/GH_TOKENis exported — GitHub access is through the MCP server, not the raw API — so UNRESOLVED is the default outcome, not an edge case. The audit is structurally unable to answer its question in the environment where round reports are produced. An audit that always degrades to "incomplete" is one a reader learns to skim, which is how a real violation gets waved through.Why this is worth fixing rather than noting
These two compound. The governed-surface regime traded a per-PR machine gate for human merge as the review record, with a post-merge audit as the backstop. Right now the backstop cannot see three of the four repos it covers, and cannot attribute the merges it does see. That is closer to "no backstop" than the ruling assumed when it retired the pre-merge gate.
Directions (not decided here)
merged_bythrough whatever GitHub channel the session actually has, or make the missing-token case a named, once-per-run line rather than a per-entry UNRESOLVED that buries the list.Dedup
Searched objectstack for prior art on both halves before filing. Nearest is #9495 — the closed card that created this audit; it scoped the objectstack half and predates the 2026-08-18 cross-repo extension. No open card covers either half.