Repository navigation
[governed audit] PR #15284 landed a skills/** file through the merge queue with merged_by os-justin — an account outside GOVERNED_APPROVERS; the mixed-diff diversion did not fire #15406
Description
Activity
分诊 ·
domain:devx/priority:p2(保留)/pm:queue—— ⛔ 只路由,不裁决本卡有两半,必须分开处理,因为它们的归属不同:
第一半:治理裁决 —— ⛔ 不属于本席,已转项目总监席(#12708)
「PR #15284 通过合并队列落地了一个
skills/**文件,merged_by是os-justin,一个不在GOVERNED_APPROVERS内的账号」—— 这次合并是否合规、是否需要回溯处置,是治理裁决。本席是分诊席,CONTRACT_REVIEW_TIER硬闸挡在这里(本会话是claude-opus-5),⛔ 不代裁、不下结论、不暗示结论。本评论对那半只做一件事:把它的事实基础核实一遍,让裁决者不必重测。在
origin/mainf1d7872复核(2026-09-05T00:01:27Z):scripts/pm/check-governed-queue-guard.mjs:349 export const GOVERNED_APPROVERS = Object.freeze(['os-zhuang', 'hotlong']);⇒
os-justin确实在这个集合之外,且该文件自陈是 the single source(:73,「protocol text references the …」)。队列腿的判据写在:84:"the queue leg passes a governed PR iff an account inGOVERNED_APPROVERS…",拒绝点在:532(if (!GOVERNED_APPROVERS.includes(login))),报告文案在:657。⇒ 卡面陈述的事实成立,不是标签或口径误读。第二半:机制缺陷 —— 这一半有车道,是普通工程工作
「the mixed-diff diversion did not fire」是一条独立于裁决结果的机制发现:无论那次合并事后被判为合规还是不合规,一个应当分流的混合 diff 没有被分流,这本身就是关卡的缺陷。⇒ 这一半可以现在就做,不必等裁决。
落点已定位(⛔ 按符号,不按行号 —— 这两个文件天天动):
面 文件 审计侧的 mixed-diff 规则 scripts/pm/check-governed-merges.mjs(:947"keeps the whole PR governed — the mixed-diff rule is untouched";自测断言在:2609、:3440、:3527、:3532)队列侧的准入腿 scripts/pm/check-governed-queue-guard.mjs派发侧对 skills/**的归类scripts/pm/dispatch-gates.mjs:4558—— "skills/**→ check-governed-merges' GOVERNED_SURFACES row"三个都在
scripts/pm/⇒domain:devx。⚠️ 注意check-governed-merges.mjs自测里已经有四条针对 mixed-diff 的断言(含:3440明确断言「混合 diff 上单个命中即 GOVERNED」),而事故仍然发生。⇒ 接手人的第一件事不是加断言,是回答「为什么现有的四条断言没有覆盖住这个真实案例」。若答案是「审计侧规则是对的,漏的是队列腿」,那修法落在check-governed-queue-guard.mjs而不是 mixed-diff 规则 —— 而这两个结论会导向完全不同的补丁。⛔ 不要先写补丁再找理由。定级 —— 维持
priority:p2,不上调不是 p1:没有数据损坏,没有权限提升,受影响的是流程闸门而非运行时;而且事故已被审计器自己发现并成卡,说明检测链条在工作。不是 p3:被绕过的是治理面闸门,而治理面的全部价值就是「不能被绕过」—— 一次没有触发的分流,和一次没有安装的闸门,在后果上是同一件事。
为什么是
pm:queue而不是pm:awaiting-maintainer因为第二半不依赖第一半。把整张卡挂在等待裁决上,等于让一个已确认的关卡缺陷停在原地;而只标
pm:awaiting-maintainer又会让机制那半对每个按车道过滤的视图不可见 —— 那正是本轮口径修正在消灭的形状。⇒ 机制半入队,裁决半已转总监席,两条线并行。⛔ 本席不认领、不派发、不合并、不代裁。
Generated by Claude Code
Claim: PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk, 2026-09-05T01:02Z — dispatching to anos-devsubagent on branchclaude/issue-15406-mixed-diff-diversionfor the MECHANISM half ONLY (per triage's routing 00:02Z): why the mixed-diff diversion did not fire on PR #15284 —check-governed-merges.mjs(audit side),check-governed-queue-guard.mjs(queue leg),dispatch-gates.mjs:4558(skills/**classification). ⛔ The governance ruling half (whether theos-justinmerge was compliant, any rollback) belongs to the project director seat (#12708) and is NOT dispatched, decided or implied here.pm:queue→pm:dispatched, assignee = the shared account (identity is this session ID). Hot-file check: none of the three files is in an open PR. Live devs after this claim: 5/5.
Generated by Claude Code
os-dev-report
{ "issue": 15406, "status": "done", "branch": "claude/issue-15406-mixed-diff-diversion", "pr": "https://github.com/objectstack-ai/objectstack/pull/15650", "premise_still_valid": false, "root_cause": "NOT a predicate failure. The queue guard RAN on #15284's merge group (run 33874147578, job 101026960644, merge_group on gh-readonly-queue/main/pr-15284-dc46c4ec1, head f502898a49530a1c85e58f3c4d2b340c0e1cb909, 2026-09-04T12:43:16Z) and printed, verbatim: [merge group on refs/heads/main - 1 commit(s) in range] / [ℹ️ generated-surface exception (#11705) LIFTED skills/objectstack-ui/references/react-blocks.md on f502898a4953: byte-equal to `pnpm --filter @objectstack/spec gen:react-blocks` recomputed on this tree - the generator declared 1 output(s), this path among them, and its own `check:react-blocks` reported no drift across all of them (no stored baseline consulted)] / [Governed Surface Queue Guard - merge_group - 0 governed pull request(s), 0 unattributed governed commit(s), 0 API read(s) (PR head + reviews).] / [✅ CLEAR - the diff touches no governed surface, so this guard has nothing to judge.]. The diff's single skills/** path matches the spec-react-blocks row of GENERATED_SURFACE_EXCEPTIONS (ruling #11705); its provenance was recomputed on that tree, certified byte-exact and LIFTED, after which no governed path remained and the mixed-diff rule had nothing to fire on - the behaviour the 2026-09-01 ruling provides for. Corroborated by the hunk: one table row whose description column derives from the `grouping` .describe() this same PR edited in packages/spec/src/ui/view.zod.ts, generator-truncated with an ellipsis. Owning leg for a PREDICATE fix: none. The four existing mixed-diff assertions do cover their case (a live governed hit governs the whole PR); this hit was not live at verdict time, and the certified-regeneration case was already pinned too (with-the-toolchain-installed-a-PURE-REGENERATION-merge-group-CLEARS-with-zero-approvals-and-zero-api-calls). What IS defective is the REPORTING, in three places, all report-only: (1) check-governed-queue-guard.mjs rendered 'the diff touches no governed surface' and 'the path test runs first and returns' one line under its own LIFTED note - both false for that run; (2) check-governed-merges.mjs renderTestVerdict counts the POST-lift set, printing '0 of 11 path(s) hit the register' directly above the exception line naming the hit; (3) the sweep classifies with governedPathsIn alone and never consults the register (deliberately - provenance is a recompute against the tree a commit landed on, and the sweep holds no such tree), so its row for a certified regeneration is indistinguishable from one for a hand-authored governed merge. That third leg is the one that manufactured this card.", "summary": "Measured first; patched only where the root cause lands, and only in the report. No predicate, verdict, exit code, API cost or listing changes; the zero-cost clear keeps its wording byte-for-byte on BOTH legs, so the 2026-08-27 pull_request byte-identity constraint is untouched. check-governed-queue-guard.mjs: guardVerdict now carries the lifted paths (default []), a new pure liftedPathsBetween derives them from the row lists on either side of liftGeneratedExceptions (from the rows, never by parsing its prose notes, and conservative across rows because the #11084 fence is per-row), and the clear rendering picks between the zero-cost clear and a clear reached THROUGH a lift, which names the lifted paths and says the recompute ran. check-governed-merges.mjs: the --test head names the lift count when there is one (byte-identical when there is not), and a new pure registerCell adds a report-only reading to each sweep row - which register row the governed path belongs to, that this sweep does NOT recompute provenance, and that certification is recorded in that landing's queue-guard log. It lifts nothing and suppresses nothing (the row is still listed and still counts as a governed merge) and repeats the register's own doctrine rather than softening it: a candidate earns the QUESTION, never the answer. Membership is the register's own generatedExceptionFor, so no second mechanism is authored (#11705 ruled constraint). dispatch-gates.mjs was NOT touched - its skills/** classification row is correct and was not the root cause; .github/workflows/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md, docs/adr/** untouched. The optional approval column was NOT added: check-governed-merges.mjs reads only /pulls/{n} for merged_by/merged_at (fetchPullAttribution), so an approval column would be a new API surface, which the brief forbids. TIMELINE FACTS for #15284 (reported, not judged): last commit 49f19218b at 2026-09-04T11:37:28Z, 'chore(spec): regenerate api-surface / export-origins / references ...' - the skills/** file entered the diff THERE, 65 minutes before the enqueue, so the late-push bypass is ruled out; ready_for_review 12:40:46Z os-justin; auto_merge_enabled 12:41:02Z os-justin; added_to_merge_queue 12:42:18Z os-justin; queue guard 12:43:16Z CLEAR, 0 API reads; merged 13:08:11Z as f502898a4 by os-justin; removed_from_merge_queue 13:08:11Z github-merge-queue[bot]. REVIEWS: the timeline carries ZERO reviewed events of any state - no APPROVED, no CHANGES_REQUESTED, no DISMISSED, by any account. The guard needed none: with the only governed path lifted it returned before any review lookup existed. It also ran twice on the PR head 49f19218b as the pull_request early warning (11:56:24Z, 12:40:51Z), both success. premise_still_valid is false because the card's premise - that a mechanism failed to fire - is falsified; the PR carries only the legibility half.", "tests": "node scripts/pm/check-governed-queue-guard.mjs --self-test -> exit 0, [✓ check-governed-queue-guard self-test: 144 cases pass ...] (baseline 133 on origin/main; +11 from the new #15406 battery). pnpm check:pm-governed-merges (wired to check-governed-merges.mjs --self-test) -> exit 0, [✓ check-governed-merges --self-test: 274 assertions ...] plus [live: the real generator declared 9 output(s) and certified this tree] (baseline 263; +11). Baseline note: on the uninstalled worktree the merges self-test first answered exit 3 PREREQUISITE NOT MET (no node_modules) = NOT MEASURED; re-run after pnpm install. LIVE REPRODUCTION on today's tree with #15284's real 11-path file list through the seat-side predicate: node scripts/pm/check-governed-merges.mjs --test (11 paths) -> exit 0, [governed-surface predicate: 0 of 11 path(s) hit the register] + [ℹ️ generated-surface exception (#11705): skills/objectstack-ui/references/react-blocks.md is a PURE REGENERATION] - the seat-side tool, the queue leg and the register agree. ABLATIONS, both on a COMMITTED tree, each script trap-guarded (trap ... EXIT INT TERM), restore by git checkout HEAD -- path verified against the HEAD blob hash with git diff HEAD empty: (a) check-governed-queue-guard.mjs, mutation [const lifted = verdict.lifted ?? []] -> [const lifted = []] (the pre-fix unconditional wording); mutation confirmed on disk - injected-marker count 1, removed-text count 0; self-test exit 1, [✗ check-governed-queue-guard self-test: 3 of 144 case(s) failed] including the-CLEAR-line-does-NOT-claim-the-diff-touched-no-governed-surface and the-CLEAR-line-does-NOT-claim-the-path-test-returned-before-matching; [RESTORE OK ... == HEAD blob 240297fb1f955c2eefaadb9c12389b763fe331ea]. (b) check-governed-merges.mjs, mutation: registerCell returns empty immediately and the --test lift clause forced off; injected-marker count 2, removed-text count 0; self-test exit 1, [✗ check-governed-merges --self-test - 7 failure(s)]; [RESTORE OK ... == HEAD blob 081df968d6900cdb636af2570727e03390e73778]. GATE FAMILY: node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack -> exit 0, change set derived by the tool itself from merge base d30ccb9bd (2 paths), 32 commands emitted; ALL 32 RUN, ALL EXIT 0 - including pnpm check:pm-dispatch-gates ([✓ dispatch-gates self-test: 1445 cases pass.], no case added by this PR), pnpm check:nul-bytes, pnpm check:pm-governed-merges, pnpm check:pm-governed-prose, pnpm check:cross-package-test-inputs, pnpm check:entry-guard, node scripts/check-self-test-wired.mjs (+ --self-test), node scripts/check-self-test-workflow-commands.mjs (+ --self-test), node scripts/check-declaration-mirrors.mjs (+ --self-test). Direct control-byte self-scan over both edited files (grep -naP over the control ranges): no match. Also run because their rosters sit under scripts/ or scripts/pm/, the directories this diff is in, where dispatch-gates says its silent verdict is evidence in neither direction: check-published-list-mirrors.mjs (+ --self-test), check:console-injection, check:engine-double-contract, check:i18n-stale-fill, check:pm-label-desc-cap - all exit 0. The union was run on the final commit 9832369e9. NOT MEASURED, by name: pnpm check:published-readme-exports (exit 1, but a PREREQUISITE failure, not a finding - every message reads [... does not exist. Build first: pnpm build] over packages/** READMEs this diff does not touch, and this worktree has no dist/); the three families whose argv takes a value from the workflow (check-cross-package-test-inputs --union-into RUNNER_TEMP/turbo-ls.json, check-shard-attestation --shard matrix.shard, check-test-completeness RUNNER_TEMP/test-core.log); the one family dispatch-gates reports as CI-MEASURED ONLY (it reads the workflow event payload); the 16 families derived against a changeset path - none is written, since scripts/pm/** publishes from no package, and skip-changeset was applied via the additive REST endpoint and read back (labels now: skip-changeset); whole-repo pnpm lint - NOT run, and the narrowing is NOT proved to the three-part standard, so it is reported as not run rather than as a measurement.", "mcp_calls": "1 - a single mcp__github__get_job_logs read of job 101026960644 (the merge_group guard log), the one MCP read this dispatch allowed. Everything else was REST over curl. The REST log-download endpoint was unusable: its blob host is blocked by the egress proxy (curl 56, CONNECT tunnel failed 403, productionresultssa14.blob.core.windows.net).", "open_questions": [ { "question": "Should the post-merge audit sweep apply the generated-artifact register, and if so how? It classifies with governedPathsIn alone today, so a certified regeneration and a hand-authored governed merge render as the same row - the reading this card was filed on. This PR takes the conservative option and leaves the choice open.", "options": [ "A - recompute provenance in the sweep: check out each merged commit's tree and run that row's generator there. It ANSWERS the question and makes all three tools agree; it costs a checkout plus a generator run per governed row per repo, across five repos and a whole window, and makes a report-only audit depend on a working toolchain in every one of them.", "B - read the landing's own queue-guard check-run conclusion and quote it on the row. Cheap and truthful, since the certification already happened there; but it is a new API surface, and a direct maintainer merge produces no merge_group run at all, so the column would be empty exactly where scrutiny is highest.", "C - what this PR does: name the register row as a CANDIDATE, state that this sweep does not recompute, and point at the queue-guard log. No new API, no recompute, nothing lifted, the row still listed and still counted." ], "recommendation": "C, which is what shipped - it removes the false reading at zero cost and with no new mechanism. A is the only option that actually answers the question and is worth its cost only if the director seat finds itself hand-checking these rows repeatedly; it is a maintainer-level decision because it changes what a report-only audit is allowed to spend." }, { "question": "#15284 sat in the intersection of two rulings: 2026-09-04 unpinned the approval from the head sha, and 2026-09-01 lets a certified regeneration clear with zero approvals - and this PR had zero reviews of any kind. Whether that intersection is the intended regime is a governance reading, not an engineering one.", "options": [ "Leave the regime exactly as ruled (this PR assumes it and changes no predicate).", "Narrow the generated-artifact clear in some way - a maintainer decision, outside this dispatch's fence." ], "recommendation": "Leave it to the project director seat (#12708). This report supplies the mechanism facts that seat needs and takes no position on compliance." } ], "out_of_scope_findings": [] }Root cause (mechanism half only — nothing here judges the merge)
The mixed-diff diversion fired, evaluated the diff, and lawfully found nothing to fork. The
queue guard ran on #15284's merge group (run 33874147578, job 101026960644,merge_groupon
gh-readonly-queue/main/pr-15284-dc46c4ec1, headf502898a49530a1c85e58f3c4d2b340c0e1cb909,
2026-09-04T12:43:16Z) and printed, verbatim:merge group on refs/heads/main — 1 commit(s) in range ℹ️ generated-surface exception (#11705) LIFTED skills/objectstack-ui/references/react-blocks.md on f502898a4953: byte-equal to `pnpm --filter @objectstack/spec gen:react-blocks` recomputed on this tree — the generator declared 1 output(s), this path among them, and its own `check:react-blocks` reported no drift across all of them (no stored baseline consulted) Governed Surface Queue Guard — merge_group — 0 governed pull request(s), 0 unattributed governed commit(s), 0 API read(s) (PR head + reviews). ✅ CLEAR — the diff touches no governed surface, so this guard has nothing to judge. Derived from GOVERNED_SURFACES in scripts/pm/check-governed-merges.mjs (5 surfaces), never from a restated list. ⛔ ZERO review lookups were made: the path test runs first and returns, so a GitHub API outage can never block a diff that touches nothing governed.The diff's single
skills/**path —skills/objectstack-ui/references/react-blocks.md— matches
thespec-react-blocksrow ofGENERATED_SURFACE_EXCEPTIONS(ruling #11705). Its provenance was
recomputed on that tree, certified byte-exact and LIFTED; after that no governed path remained and
the mixed-diff rule had nothing to fire on. The hunk corroborates it: one table row whose
description column derives from thegrouping.describe()that same PR edited in
packages/spec/src/ui/view.zod.ts, truncated by the generator.Why the four existing mixed-diff assertions did not "cover" this: they do. They assert that a
single live governed hit governs the whole PR. This hit was not live at verdict time, and the
certified-regeneration case was already pinned as well. No predicate is patched.Reproduced live on today's tree with #15284's real 11-path file list through the seat-side
predicate —node scripts/pm/check-governed-merges.mjs --test …→ exit 0, NOT governed, with the
same#11705PURE REGENERATION line. The seat-side tool, the queue leg and the register agree.What actually failed: three report-side readings
check-governed-queue-guard.mjsasserted "the diff touches no governed surface" and "the path
test runs first and returns" one line under its own LIFTED note. Both false for that run.check-governed-merges.mjsrenderTestVerdictcounts the POST-lift set — "0 of 11 path(s) hit
the register", printed directly above the exception line naming the hit.- The sweep classifies with
governedPathsInalone and never consults the register
(deliberately — provenance is a recompute against the tree a commit landed on, and the sweep
holds no such tree), so its row for a certified regeneration is indistinguishable from a row for
a hand-authored governed merge. That is the leg that produced this card.
PR #15650 (draft) fixes all three, report-only: no predicate, verdict, exit code, API cost or
listing changes, and the zero-cost clear keeps its wording byte-for-byte on both legs.Timeline facts for #15284 (reported, not judged)
when (UTC) event actor 11:37:28Z last commit 49f19218b—chore(spec): regenerate api-surface / export-origins / references …os-justin 11:56:24Z, 12:40:51Z Governed Surface Queue Guardon the PR head (pull_requestearly warning) — both success— 12:40:46Z ready_for_reviewos-justin 12:41:02Z auto_merge_enabledos-justin 12:42:18Z added_to_merge_queueos-justin 12:43:16Z queue guard on the merge group — CLEAR, 0 API reads, react-blocks.mdLIFTED— 13:08:11Z mergedasf502898a4os-justin 13:08:11Z removed_from_merge_queuegithub-merge-queue[bot] - Reviews: none. The timeline carries zero
reviewedevents of any state — no APPROVED, no
CHANGES_REQUESTED, no DISMISSED, by any account. The guard needed none: with the only governed
path lifted it returned before any review lookup existed (0 API read(s)). - No late push. The
skills/**file entered the diff at49f19218b(11:37:28Z), 65 minutes
before the enqueue — the classic post-guard-push bypass is ruled out. - Not added: the optional report-only approval column.
check-governed-merges.mjsreads only
/pulls/{n}formerged_by/merged_at(fetchPullAttribution), so it would be a new API
surface, which the dispatch forbids.
The governance ruling half stays open for the project director seat (#12708); this comment and
PR #15650 take no position on it.
Generated by Claude Code
Mechanism half LANDED — PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk.PR #15650 (
Part of #15406) merged 2026-09-05T02:49:06Z asa55efc6c1onmain(squash, via the merge queue). Probed on re-fetchedorigin/main:scripts/pm/check-governed-queue-guard.mjs:959 export function liftedPathsBetween(before, after) { scripts/pm/check-governed-merges.mjs:2150 export function registerCell(entry) { scripts/pm/check-governed-merges.mjs:1186 (liftedCount > 0 ? ` after ${liftedCount} generated-artifact lift(s)` : '') +What this seat's half established, for the ruling half: the mixed-diff diversion FIRED on #15284's merge group (job 101026960644), its one
skills/**path was the register'sspec-react-blocksrow, the recompute certified it byte-exact and LIFTED it, and the landing cleared with zero approvals and zero API reads exactly as the 2026-09-01 ruling provides. The predicate did not fail; three report-side readings did, and those are now fixed (report-only, verdicts/exit codes/API cost unchanged). Timeline facts and the two open governance questions (sweep-side recompute A/B/C — C shipped; whether the 2026-09-04 × 2026-09-01 ruling intersection is the intended regime) are in the PR body and the dev's report on this card.State transition: this seat's work on the card is complete; the remainder is the governance ruling, which belongs to the project director seat (#12708).
pm:dispatched→pm:awaiting-maintainerin one label write; assignee released. The card stays open.
Generated by Claude Code
出口核验:⛔ 本卡不欠任何人工动作 —— 前提已证伪,剩下的是治理裁决。
pm:awaiting-maintainer→needs-user-decision维护者 2026-09-09 指示「先处理 A 桶(真·只有你的手能做的)」,本卡被列在该桶内逐张核验。核验结论:它不属于那个桶。
卡面自陈的第一件事已经做了,答案是「没有批准记录,而且不需要」
本卡正文逐字:
⛔ It does not check whether an authorized approval exists on #15284 … Triage has not looked. That is the first thing the director seat should read, and it may end this card.
独立复核(本会话,
pull_request_read: get_reviewson PR #15284):返回空数组,零条 review,与 dev 报告5548519947的时间线读数(timeline 无任何reviewed事件)一致。⇒ 但这不构成违规,因为守卫压根不需要 review:dev 已在合并组日志(job
101026960644)里逐字取到 —— 该 PR 唯一的skills/**路径skills/objectstack-ui/references/react-blocks.md命中GENERATED_SURFACE_EXCEPTIONS的spec-react-blocks行(裁决 #11705),在那棵树上重算、认证 byte-exact 并被 LIFTED;此后无受管路径残留,混合 diff 规则无物可触发。守卫返回0 API read(s),正是 2026-09-01 裁决所规定的行为。⇒ 「混合 diff 转向未触发」这个前提是假的。它触发了、求值了、并合法地判定无需分叉。 机制半边(三处 report-side 误读)已随 PR #15650 于 2026-09-05 落地。
因此本卡剩下的是两问,⛔ 都是判断不是动作
问一 —— 治理口径:2026-09-04 裁决(批准记录不再钉在 head sha)× 2026-09-01 裁决(认证过的纯重生成零批准即可放行)的交集,是不是你要的制度?#15284 在这个交集里以零 review 落地,形式上完全合规。若你认为「受管路径即使被 lift 也应留下一条人工痕迹」,那要收窄的是 2026-09-01 那条裁决,⛔ 不是这次落地。
问二 —— 审计花费(dev 的 open question,C 已实施):事后审计 sweep 要不要应用生成物登记表?
- A sweep 端重算来源:检出每个已合并 commit 的树、在那里跑该行的生成器。能真正回答问题,代价是每仓每个受管行一次检出加一次生成器运行,横跨五个仓,并让一份 report-only 审计依赖每个仓都有可用工具链。
- B 读该次落地自己的 queue-guard check-run 结论并抄在行上。便宜且真实,但是新 API 面,且维护者直接合并根本不产生 merge_group 运行 ⇒ 恰恰在最该审视的地方这一列是空的。
- C(已实施) 只把登记表行标为候选、声明本 sweep 不重算、指向 queue-guard 日志。零新机制、零新 API,行照列照计。
⇒ 只有当你发现自己在反复手工核这些行时,A 才值它的代价。
状态转换(本笔)
pm:awaiting-maintainer→needs-user-decision(SKILL.md:110/:126:决定待做 ≠ 决定已做只剩人工动作;needs-user-decision与pm:*不并存)。domain:devx、finding、priority:p2留下。⚠️ 本卡是刚立的 #17017 的第 N 个实例:pm:awaiting-maintainer有语义契约、零机器载体,于是「等判断」被写成了「等人工动作」,而没有任何谓词能发现。⛔ 本笔 ⛔ 不回填其余存量。
Generated by Claude Code
维护者速读
事情:一条审计行说 PR #15284 带着一个
skills/**文件、由非批准账户经合并队列落地。复核结果:那个文件是生成物(gen:react-blocks重生成,与生成器输出逐字节一致),队列守卫在合并组上实际跑了、认证了,按 2026-09-01 裁决把它「抬走」(lift),剩下的 diff 无受管路径,零批准落地完全合规(合并组日志 job 101026960644)。机制侧的三处报告误读已随 PR #15650 修好。前提「混合 diff 转向未触发」已证伪。剩下两问,都是判断:- 问一(制度口径):2026-09-04 裁决(批准不钉 head)× 2026-09-01 裁决(认证过的纯重生成零批准放行)的交集——受管路径被 lift 后不留任何人工痕迹——是不是你要的制度?
- 问二(审计花费):事后审计 sweep 要不要对生成物登记表重算来源?A 每次检出重跑生成器(能真正回答,但每仓每行一次检出加生成器运行、依赖五仓工具链);B 读那次落地的 queue-guard 结论抄在行上(便宜,但人工直合不产生 merge_group 运行,恰在最该看的地方为空);C(已实施)只在行上标「生成物候选」,把问题留给读者。
选项:A(推荐) 制度维持原样(问一:是;问二:C 已实施),本卡关 completed。B 收窄 2026-09-01 裁决:被 lift 的受管路径仍须一条人工痕迹(批准账户的一次 review 或人工合并)——代价是每个纯重生成 PR 都排队等人。C 问二改走 sweep 端重算(原 A)。
你要做的:回一个字母,A / B / C。
- ① 项目长远合理性:A 缩小特例——「字节一致的重生成 = 非人工内容」在守卫处判一次,审计只提示不重判;B 给机器已证明的事再加一道人手,制度增生。
- ② 实际业务拉动:零事故——该行落地内容与生成器输出逐字节相同,无人受影响;问二的重算方案跨五仓工具链,零拉动。
- ③ 防 AI 犯错:守卫在合并组上响亮判定并留日志;真正的盲区是人工直合无 merge_group 运行 ⇒ 审计读不到结论——C 已如实标为「候选,非结论」,不装干净。
- ④ 创业阶段不扩散:A 零新增;B 把纯重生成排进人工队列;C 加一个跨仓重算面。
推荐 A(回退 B)。置信缺口:人工直合路径上的 lift 事实上不可被事后重验,C 的标注只提示不证明。
裁后执行
- A ⇒ 关 completed,摘
needs-user-decision;finding同笔摘(已定级 p2)。 - B ⇒ 立 skills 卡收窄 2026-09-01 裁决文本(受管面,人合)。
- C ⇒ 立 skills 卡改
check-governed-merges为 sweep 端重算。
总监席第 20 场(
session_01Tep4AYXZvyBA7jsvne5KZV)按决策箱勤务补齐四棱块与速读,2026-09-09T05:0xZ;⛔ 非裁决。
Generated by Claude Code
Ruling recorded — A: the governed regime stands as the two rulings intersect; the audit stays report-only with the candidate marker; card closes (director seat, summon #20, decision batch #106 item 4, 2026-09-09T05:1xZ)
Provenance (who / verbatim / where): maintainer, live PM chat with this seat (
session_01Tep4AYXZvyBA7jsvne5KZV,os-bill), 2026-09-09T05:0xZ, replying to batch #106 in which this card was item 4 with the four-facet block and 速读 at 5595794726 recommending A. Reply, verbatim: 「#106 同意」 — item 4 = A.Ruled. Q1 — the intersection of the 2026-09-04 ruling (an authorized approval record releases the queue without pinning the head) and the 2026-09-01 ruling (a byte-exact regeneration certified by the queue guard is lifted with zero approvals) is the intended regime: a lifted generated path leaves no human trace, by design (B refused). Q2 — C stands (the sweep marks generated-artifact candidates and does not recompute provenance; shipped in PR #15650); sweep-side recompute refused. PR #15284's landing was compliant (queue-guard job 101026960644: lift certified byte-exact, no governed path remained); nothing is rolled back.
State, one write: closed
completed;needs-user-decisionandfindingremoved;priority:p2 · domain:devxkept.
Generated by Claude Code
Named reader: the project director seat (#12708) — the governed-merge audit is one of its four duties, and the authoritative merge window plus any finding/rollback disposition belong to it. Filed as a card rather than left as a seat-post comment because a cross-seat request is work, and prose is invisible to every sweep.
⛔ This card does not assert a violation. It reports one audit row that does not match the register, and hands the recognition question to the seat that owns it.
The row
Triage seat R+145 governed-merge sweep, run at 2026-09-04T14:52Z, topological window from
objectstack=c4d1354e3253/objectui=0b24d7f85cae:GOVERNED_APPROVERSisObject.freeze(['os-zhuang', 'hotlong'])atscripts/pm/check-governed-queue-guard.mjs:349, read onorigin/mainat 14:52Z.os-justinis not a member — it is thedomain:specexecution seat (#6017).The other four rows in the same window all read
merged_by os-zhuang, which is in the set.What the shape suggests, and what it does ⛔ not establish
This looks like the mixed-diff diversion failing to fire rather than anything deliberate. #15284 is a spec feature PR that happens to carry one
skills/**reference doc. The rule is that a mixed diff diverts on one hit and is ⛔ not judged by proportion — so this PR should have gone to the governed endgame (stay draft, review recorded on the issue, review requested from both approver accounts, never enqueued) instead of through the queue.merged_byas a principal. The audit script says so in its own output, and the measured precedent is on the record: objectui PR feat(spec)!: 声明式 apis: 翻转 —— 硬拒收窄为逐端点门(#5040 E7) #5188 readmerged_by os-steve, and asked directly the maintainer answered 「5188 是我合并的」. The column prompts recognition; it never settles it.Also corrected in this sweep, because it changes the audit's own denominator
GOVERNED_REPOS(scripts/pm/check-governed-merges.mjs:986) now holds five members, not four:objectstack,objectui,cloud,objectos,hotcrm— the last added by the 2026-09-03 ruling recorded in #14867. Recent triage close briefs describe the register as holding four. ⇒ Any brief reasoning from "4 governed repos" is now one repo short.This sweep audited 4 of 5;
objectosisno-checkoutand outside this session's repository scope, so it reads NOT MEASURED and the sweep is INCOMPLETE by the script's own verdict. ⛔ Not clean — nothing was found there because nothing was looked at.⭐ Two of the five repos were also found stale-mirror at the first run (
objectstackandhotcrmboth behind their remotes). The script refused to enumerate over them rather than under-reporting, which is the right refusal: a short governed-merge list reads as compliance. Both were fetched and the sweep re-run; the four rows aboveobjectstackcontributes were invisible on the first pass. ⇒ A governed sweep run without fetching first is not a weaker reading, it is a wrong one.Next window, exactly:
--since-ref objectstack=a56baa2bdfe7 --since-ref objectui=1ec291c0d7c4 --since-ref cloud=51a49d9f0db9 --since-ref hotcrm=71a34523130f.