Repository navigation
Commit 0b5ab8b
fix(pm): the queue guard's pull_request leg attributes to the payload PR and reads the net diff (#26568)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8QLWm3LrvmyaxGxb5T2J2Qf)_
Fixes #26316
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:`scripts/pm/check-governed-queue-guard.mjs` 的 `pull_request`
腿不再按提交拆行:整段 diff 读成一行「合并基点 → head 的净差异」,归到事件载荷里的 PR 号。`merge_group`
腿(按首父提交拆、按标题 `(#N)` 归属、各种拒绝)一字不改。自测加 8 例,两组电池下限按实测抬高。
- **为什么改**:提交标题写的是 issue 号时,预警去读那个 issue 的 reviews(404),报「review list
could NOT be read」;分支合过 `origin/main` 时,合并提交的首父 diff 把 main
已落地的几十个路径算进预警,且每行都是「无归属」。预警本来就不会变红,但读的人会被误导。
- **风险与回滚**:只改 PR 上的预警输出,队列腿的输出在两个夹具上逐字节相同(下方附哈希);回滚即 revert 本 PR。
- **先看**:① `enumerateRows`(L2386 起)新的 `pull_request` 分支;②
`readEventDiff` 那一行调用(L2794)把事件传进去;③ 自测 decomposition 电池里的 7 个新用例。
- **两分钟验证**:`node scripts/pm/check-governed-queue-guard.mjs --self-test`
→ 末行 `✓ check-governed-queue-guard self-test: 401 cases pass`(改前 393)。
- **需要你做的**:无,席位落地。
## What changes
Card #26316's 「Wanted」, and nothing wider. One file,
`scripts/pm/check-governed-queue-guard.mjs`:
1. **`enumerateRows` reads by event.** The `merge_group` reading is the
old one, byte for byte: one row per first-parent commit, attributed by
`pullNumberFromSubject`, with the `head_ref` fallback only for a
one-commit group. On the `pull_request` leg it now returns ONE row:
`diff-tree baseSha headSha` (the caller already hands in the
merge-base), attributed to the payload's own pull request number,
carrying `commits` = the range's first-parent count. Shape chosen: the
single net row, because it makes both negatives provable with no
intersection logic. The subject is not read for attribution on this leg
at all; a subject naming an issue cannot redirect the review read, and a
merge of `origin/main` cannot add a path the net diff does not hold.
2. **`readEventDiff` passes `{ event: context.event }`** to it. The
merge-base call it already made (L2793) is unchanged; the premise
reading in the claim held: the missing piece was the per-commit
enumeration, not a merge-base.
3. **`commitsInRange(rows)`** keeps the header line honest: `pull
request #N — 3 commit(s) in range` still counts the range's commits. On
`merge_group` rows carry no `commits`, so it equals `rows.length`, the
old count.
4. **A `runGit(args)` seam** on `enumerateRows`, default `null`
(production reads the checkout as before), so the self-test drives the
enumeration offline, as its header promises (no network, no git).
5. A header paragraph under *Multi-PR merge groups* states that the
`pull_request` leg is not decomposed, and why.
Not touched: `.github/workflows/governed-surface-guard.yml`,
`REQUIRED_CONTEXTS`, the register, any refusal text,
`decomposeGovernedWork`, `queuedPullsInGroup`, `runSizeGuard`.
## Tests
Self-test 393 → 401 cases, exit 0. Eight new cases, all driven through
the `runGit` seam:
- **Battery `decomposition, and the multi-PR group trap`** (floor 6 →
13, measured 13):
- `⭐ pull_request-leg:
a-subject-naming-an-ISSUE-is-attributed-to-the-PAYLOAD-pr-never-the-issue`:
the PR #25965 shape (one commit, subject ends `(#25770)`, payload PR
25965) gives one row with PR 25965, governed entry 25965, zero
unattributed.
- `⛔ CONTROL merge_group-leg:
the-same-subject-still-attributes-by-its-trailing-number-unchanged`: the
same range on `merge_group` still reads 25770 from the subject.
- `⭐ pull_request-leg:
a-branch-that-merged-origin-main-carries-ONLY-its-net-rows-against-the-merge-base`:
the PR #26311 shape (own commit, merge of main carrying
`.github/workflows/lint.yml`, `AGENTS.md`, `packages/core/src/x.ts`, own
commit) gives one governed entry, PR 26311, paths exactly
`.github/workflows/governed-surface-guard.yml`.
-
`and-it-reads-the-net-diff-base-to-head-never-a-per-commit-first-parent-diff`:
the recorded git reads hold the two-tree `diff-tree` and no
`--first-parent` `diff-tree`.
- `and-the-header-still-counts-the-ranges-three-commits`.
- `⛔ CONTROL merge_group-leg:
the-same-range-is-still-one-row-per-first-parent-commit-unattributed-without-a-subject-number`:
three rows, all PR null, the merge row still carries `AGENTS.md`.
- `and-an-empty-pull_request-range-is-no-rows`.
- **Battery `the pull_request leg is an EARLY WARNING and never
reddens`** (floor 5 → 6, measured 6):
- `⭐
the-early-warning-names-the-payloads-pull-request-and-never-the-issue-its-subject-names`:
the rendered warning carries `#25965 — governed` and no `#25770`.
Floor binding checked once: with the decomposition floor at 14 the run
exits 1 naming `registered 13 case(s), below its pinned floor of 14`.
The self-test's success line is otherwise identical before and after;
only the count moves (393 → 401). `SELF_TEST_BATTERY_FLOOR` (29) is
unchanged: no battery added.
## Acceptance notes
The card's three acceptance lines:
- *A `pull_request` run on a PR whose commit subjects name an issue
number prints the PR's own review state*: yes, the fixture run below
prints `#25965 — governed` where it printed `#25770 — governed` before.
- *A PR whose branch merged `origin/main` prints only the PR's net
rows*: yes, 3 unattributed rows (one of them the merge commit's 7
workflow paths) became 1 governed entry with 1 path.
- *`--self-test` green; the `merge_group` cases unchanged*: 401 pass;
every pre-existing case passes unedited; the live `merge_group` output
on both fixtures is byte-identical before and after (below).
This PR's own `pull_request` run is a live case of the second line: its
branch carries a merge of `origin/main` (25 commits of main), so the
guard's check-run on this PR should read `pull request #THIS — 2
commit(s) in range` and name no governed path (the diff touches none).
## Verification
Fixtures: a throwaway worktree off `d2ca7079` with two branches built to
the card's shapes; payloads point the guard at them; reviews unreachable
on purpose (API URL at a closed local port) so the output is
deterministic. "Before" = the guard at `d2ca7079`; "after" = this
branch.
<details><summary>PR #25965 shape: one commit, subject names issue
25770</summary>
Before:
```text
pull request #25965 — 1 commit(s) in range
Governed Surface Queue Guard — pull_request — 1 governed pull request(s), 0 unattributed governed commit(s), 1 review lookup(s).
#25770 — governed:
AGENTS.md ×1 — the repo-root agent instruction file
```
After:
```text
pull request #25965 — 1 commit(s) in range
Governed Surface Queue Guard — pull_request — 1 governed pull request(s), 0 unattributed governed commit(s), 1 review lookup(s).
#25965 — governed:
AGENTS.md ×1 — the repo-root agent instruction file
```
</details>
<details><summary>PR #26311 shape: own commit, merge of main, own
commit</summary>
Before:
```text
pull request #26311 — 3 commit(s) in range
Governed Surface Queue Guard — pull_request — 0 governed pull request(s), 3 unattributed governed commit(s), 0 review lookup(s).
⛔ UNATTRIBUTED — commit 18743a82d8c2 … the workflow commit
- .github/workflows/governed-surface-guard.yml
⛔ UNATTRIBUTED — commit d08da36b536b … Merge commit 'd2ca7079…' into fx-b
- .github/workflows/board-snapshot.yml
- .github/workflows/fleet-patrols.yml
- .github/workflows/lint.yml
- .github/workflows/platform-checklist-watchdog.yml
- .github/workflows/release-coverage-patrol.yml
- .github/workflows/required-set-patrol.yml
- .github/workflows/governed-surface-guard.yml
⛔ UNATTRIBUTED — commit 57cfc2aac768 … pin the self-test step
- .github/workflows/governed-surface-guard.yml
```
After:
```text
pull request #26311 — 3 commit(s) in range
Governed Surface Queue Guard — pull_request — 1 governed pull request(s), 0 unattributed governed commit(s), 1 review lookup(s).
#26311 — governed:
.github/workflows/** ×1 — CI, deploy and release workflows: what runs on every push, what deploys, what gates the queue
- .github/workflows/governed-surface-guard.yml
```
</details>
<details><summary>merge_group leg, same two ranges:
byte-identical</summary>
`cmp` of before and after, each run with a `merge_group` payload over
the same range (`head_ref` naming the PR):
```text
merge_group fixture a: byte-identical (7529 bytes, sha256 04261d5a4b8e70cb)
merge_group fixture b: byte-identical (7666 bytes, sha256 dd83c48111ca9ab5)
```
Fixture b on the queue leg still reads `3 commit(s) in range` and `3
unattributed governed commit(s)`: the queue's decomposition and its
refusal are untouched.
</details>
<details><summary>--toolchain-needed on the pull_request leg</summary>
```text
Governed Surface Queue Guard — generator toolchain not needed: 1 commit(s) in range touch no register path the lift recomputes
Governed Surface Queue Guard — generator toolchain not needed: 3 commit(s) in range touch no register path the lift recomputes
```
</details>
<details><summary>Local gates on 64d0d4f: 32 derived, 32 run, all exit
0</summary>
Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` on `64d0d4fd` (branch with `origin/main` at
`a3009cbf` merged in, so the tree is not stale against the families).
Each run's exit code captured before any pipe; `check:pm-dispatch-gates`
ran under `os-verify-lock.sh` (slot `issue-26316`): `VERDICT
command-exit 0 · held the lock 380s`.
- `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
- `node scripts/check-declaration-mirrors.mjs` → exit 0
- `node scripts/check-declaration-mirrors.mjs --self-test` → exit 0
- `node scripts/check-self-test-wired.mjs` → exit 0
- `node scripts/check-self-test-wired.mjs --self-test` → exit 0
- `node scripts/check-self-test-workflow-commands.mjs` → exit 0
- `node scripts/check-self-test-workflow-commands.mjs --self-test` →
exit 0
- `node scripts/check-whole-set-label-write.mjs` → exit 0
- `node scripts/check-whole-set-label-write.mjs --self-test` → exit 0
- `node scripts/ci/plan-test-core-shards.mjs --self-test` → exit 0
- `node scripts/pm/bare-root-worklist.mjs --self-test` → exit 0
- `node scripts/pm/check-governed-queue-guard.mjs --self-test` → exit 0
- `pnpm check:agent-test-spelling` → exit 0
- `pnpm check:bash32-floor` → exit 0
- `pnpm check:ci-filter-parity` → exit 0
- `pnpm check:cli-command-ids` → exit 0
- `pnpm check:closing-target-claim` → exit 0
- `pnpm check:cross-package-test-inputs` → exit 0
- `pnpm check:driver-memory-census` → exit 0
- `pnpm check:entry-guard` → exit 0
- `pnpm check:gitlink-declared` → exit 0
- `pnpm check:nul-bytes` → exit 0
- `pnpm check:parse-guard` → exit 0
- `pnpm check:pm-dispatch-gates` → exit 0
- `pnpm check:pnpm-filter-targets` → exit 0
- `pnpm check:pnpm-flag-spellings` → exit 0
- `pnpm check:ratchet-remedy-authority` → exit 0
- `pnpm check:refd-timer-probe` → exit 0
- `pnpm check:scripts-symbol-anchors` → exit 0
- `pnpm check:watch-hint-literal` → exit 0
`--ran` reconciliation (exit codes recorded): `Run reconciliation — 32
derived, 32 run, 0 NOT-MEASURED, 0 UNRUN.` · `✓ dispatch-gates --ran: 32
derived famil(ies) accounted for — 32 run, 0 NOT-MEASURED (a DERIVED
zero — all 32 recorded an exit code and none of them is 3).` That
reading was taken with `origin/main` at `1c632311`, 2 commits past the
merge; the one derived-from file those moved is
`scripts/engine-double-contract.pinned.json`, which no family on this
card's list reads.
Left to CI, as the derivation names: the workflow-payload families
(`check:closing-target-claim`'s live leg), `ci.yml · Plan Test Core
shards`, the type-check program steps, the repo-wide `pnpm lint`. No
package was touched, so there is no build closure and no package test or
typecheck to run; this script has no `*.test.ts` beside it, and its own
`--self-test` is the suite.
</details>
## Human Minimum
Each item is one rule from [CONTRIBUTING.md › Human
Minimum](https://github.com/objectstack-ai/objectstack/blob/main/CONTRIBUTING.md#human-minimum).
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(No schema change.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` is CI's run (repo-wide scan).
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. Nothing publishes (`scripts/pm/**`, `skip-changeset`); both
declaration lines are filled in above.
- [x] 6. `packages/spec` not touched.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English (the 维护者速读 block is the
required exception).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxba3WdR4pYYA7CdMgAJ)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 5d2935a commit 0b5ab8b
1 file changed
Lines changed: 143 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
234 | 234 | | |
235 | 235 | | |
236 | 236 | | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
237 | 244 | | |
238 | 245 | | |
239 | 246 | | |
| |||
606 | 613 | | |
607 | 614 | | |
608 | 615 | | |
609 | | - | |
| 616 | + | |
610 | 617 | | |
611 | | - | |
| 618 | + | |
612 | 619 | | |
613 | 620 | | |
614 | 621 | | |
| |||
2376 | 2383 | | |
2377 | 2384 | | |
2378 | 2385 | | |
2379 | | - | |
2380 | | - | |
2381 | | - | |
2382 | | - | |
| 2386 | + | |
| 2387 | + | |
| 2388 | + | |
| 2389 | + | |
| 2390 | + | |
| 2391 | + | |
| 2392 | + | |
| 2393 | + | |
| 2394 | + | |
| 2395 | + | |
| 2396 | + | |
| 2397 | + | |
| 2398 | + | |
| 2399 | + | |
| 2400 | + | |
| 2401 | + | |
| 2402 | + | |
| 2403 | + | |
| 2404 | + | |
2383 | 2405 | | |
2384 | | - | |
2385 | | - | |
| 2406 | + | |
| 2407 | + | |
| 2408 | + | |
2386 | 2409 | | |
2387 | 2410 | | |
2388 | 2411 | | |
2389 | 2412 | | |
2390 | 2413 | | |
2391 | 2414 | | |
2392 | 2415 | | |
| 2416 | + | |
| 2417 | + | |
| 2418 | + | |
| 2419 | + | |
| 2420 | + | |
| 2421 | + | |
| 2422 | + | |
| 2423 | + | |
| 2424 | + | |
| 2425 | + | |
| 2426 | + | |
| 2427 | + | |
| 2428 | + | |
| 2429 | + | |
2393 | 2430 | | |
2394 | 2431 | | |
2395 | 2432 | | |
2396 | 2433 | | |
2397 | 2434 | | |
2398 | 2435 | | |
2399 | | - | |
| 2436 | + | |
2400 | 2437 | | |
2401 | 2438 | | |
2402 | 2439 | | |
2403 | 2440 | | |
2404 | 2441 | | |
| 2442 | + | |
| 2443 | + | |
| 2444 | + | |
| 2445 | + | |
| 2446 | + | |
| 2447 | + | |
| 2448 | + | |
| 2449 | + | |
| 2450 | + | |
| 2451 | + | |
2405 | 2452 | | |
2406 | 2453 | | |
2407 | 2454 | | |
| |||
2744 | 2791 | | |
2745 | 2792 | | |
2746 | 2793 | | |
2747 | | - | |
| 2794 | + | |
2748 | 2795 | | |
2749 | 2796 | | |
2750 | 2797 | | |
| |||
2775 | 2822 | | |
2776 | 2823 | | |
2777 | 2824 | | |
2778 | | - | |
| 2825 | + | |
2779 | 2826 | | |
2780 | 2827 | | |
2781 | 2828 | | |
| |||
2840 | 2887 | | |
2841 | 2888 | | |
2842 | 2889 | | |
2843 | | - | |
| 2890 | + | |
2844 | 2891 | | |
2845 | 2892 | | |
2846 | 2893 | | |
| |||
3176 | 3223 | | |
3177 | 3224 | | |
3178 | 3225 | | |
| 3226 | + | |
| 3227 | + | |
| 3228 | + | |
| 3229 | + | |
| 3230 | + | |
| 3231 | + | |
| 3232 | + | |
| 3233 | + | |
| 3234 | + | |
| 3235 | + | |
| 3236 | + | |
| 3237 | + | |
| 3238 | + | |
| 3239 | + | |
| 3240 | + | |
| 3241 | + | |
| 3242 | + | |
| 3243 | + | |
| 3244 | + | |
| 3245 | + | |
| 3246 | + | |
| 3247 | + | |
| 3248 | + | |
| 3249 | + | |
| 3250 | + | |
| 3251 | + | |
| 3252 | + | |
| 3253 | + | |
| 3254 | + | |
| 3255 | + | |
| 3256 | + | |
| 3257 | + | |
| 3258 | + | |
| 3259 | + | |
| 3260 | + | |
| 3261 | + | |
| 3262 | + | |
| 3263 | + | |
| 3264 | + | |
| 3265 | + | |
| 3266 | + | |
| 3267 | + | |
| 3268 | + | |
| 3269 | + | |
| 3270 | + | |
| 3271 | + | |
| 3272 | + | |
| 3273 | + | |
| 3274 | + | |
| 3275 | + | |
| 3276 | + | |
| 3277 | + | |
| 3278 | + | |
| 3279 | + | |
| 3280 | + | |
| 3281 | + | |
| 3282 | + | |
| 3283 | + | |
| 3284 | + | |
| 3285 | + | |
| 3286 | + | |
| 3287 | + | |
| 3288 | + | |
| 3289 | + | |
| 3290 | + | |
| 3291 | + | |
| 3292 | + | |
| 3293 | + | |
| 3294 | + | |
| 3295 | + | |
| 3296 | + | |
3179 | 3297 | | |
3180 | 3298 | | |
3181 | 3299 | | |
| |||
3230 | 3348 | | |
3231 | 3349 | | |
3232 | 3350 | | |
| 3351 | + | |
| 3352 | + | |
| 3353 | + | |
| 3354 | + | |
| 3355 | + | |
| 3356 | + | |
| 3357 | + | |
| 3358 | + | |
| 3359 | + | |
| 3360 | + | |
| 3361 | + | |
| 3362 | + | |
| 3363 | + | |
3233 | 3364 | | |
3234 | 3365 | | |
3235 | 3366 | | |
| |||
0 commit comments