fix(pm): time-cap H8's merged window, add the seat-staleness leg and the closed pm:* census - #13601
Merged
Merged
Conversation
…me repair on main
This was referenced Aug 31, 2026
zhuangjianguo
marked this pull request as ready for review
August 31, 2026 03:03
zhuangjianguo
enabled auto-merge
August 31, 2026 03:03
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 free
to 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 #13499
Fixes #13493
Fixes #13526
Three blindness defects in the patrol instrument
scripts/pm/check-half-states.mjs, folded into one PR because all three land in that one file and are the same class: a patrol that reported nothing and was read as finding nothing.Pure code. No
.mdin the diff.1. H8's merged-PR window: a COUNT cap becomes a TIME cap (#13499)
Premise correction first, because the card's mechanism quote is stale. #13499 was filed against
page 2and a~18 merges/daycomment. Neither is onmainany more — #11118 had already widened the cap to 4 pages and replaced the comment with a measured, executableMEASURED_MERGES_PER_DAY = 137.5. So repair ② was half-landed before this PR started.The defect the card names is nevertheless live, and it is the half that did not land: the boundary was still a page cap, and a page cap only becomes a statement about time after dividing by a rate nobody watches. Measured on the same endpoint, same cap, eight days apart:
Same cap, 64% more window, because the observed rate fell from 137.5/day to ~82/day. Nothing in the file changed and nothing could have reported it. Note the direction: a page cap is not a conservative bound that occasionally underdelivers — it is an unmanaged quantity, and the run where it is too small looks exactly like the run where it is too big.
MERGED_WINDOW_DAYS = 8, derived from the longest measured unexecuted-verdict latency: finding: H8 的 merged-PR 窗口按「~18 merges/day」定成两页,实测已达 ~196/day —— 超过约 24 小时的交付对巡查结构性不可见(本轮实测 14 张滞留 4–6 天) #13499's census found 14 deliveries stranded 4.6–6.0 days, worst objectui#5174 at 6.0d. 8 = that floor plus a weekend, because a Friday merge has its paired write looked at on Monday at the earliest.MERGED_WINDOW_PAGE_CEILING = 30is a quota backstop only, and announces itself: the summary line sayshorizon reachedorTRUNCATED, so a ceiling-bound pass can never read as a completed time window.updated_at; row selection readsmerged_at— deliberately different fields. The listing issort=updated, so "stop when this row's merge is old" would be wrong. Merging updates a PR, soupdated_at >= merged_at; once a page's oldestupdated_atpredates the horizon, no later page can hold an in-window merge. That monotonicity is what makes the bound exact.Repair ② completed — the rate premise is now self-checking. Every sweep derives the observed rate from rows it already holds and compares it to the pinned constant, which now carries its measurement date.
classifyRatePremisereportsdrifted(outside a 2x band),expired(pin older than 30 days regardless of drift),unobserved(⛔ not agreement — #4690), orok. ⛔ The pinned constant is deliberately not self-updated: a premise nobody reviews is the thing being fixed.Live:
rate premise OK — observed ~120.5/day against pinned 137.5/day, measured 2026-08-23 (8d ago) (factor 0.88, band 2x).Adjacent #11036 (Refs-spelling blindness) is not addressed here — out of scope: H8's delivery-recognition logic is untouched.
2. H38 — a seat post a whole shift ran behind (#13493, half ① only)
New report-only leg.
T_seatis the post's last event (body edit or newest comment); if the newestClaim:on that seat's lane is newer, the post is stale. An ordering, not a threshold — no tuned constant.Claim:predicate is reused, not re-spelled:latestClaimComment, the established machine criterion. The card says do not widen it; it is equally important not to narrow it, or H2 would call a card claimed while H38 called the same comment invisible.labelsfilters are OR not AND, so the lane is intersected locally.It fired on its first live run, on the exact seat post the card was filed from:
H38 #6021 pm:seat post is STALE — its lane domain:services carries a Claim: on #13551 written 9.8h AFTER this post's last event. The card predicted precisely this ("whether other seat posts show the same signature is exactly what the proposed check would answer on its first run").Half ② (a 收班中 marker) is a protocol change and stays out, per the card's own boundary.
3. H39 — the closed
pm:*residue census (#13526)Leg ① (runnability) was landed by #13574 while this branch was open — the same repair, a re-exec routing node's
fetchthrough the session proxy. This PR mergesmainand drops its own duplicate implementation; that mechanism here is entirely #13574's. What this PR keeps is the sentence the card asked for, now in the gate's own refusal output, carrying the real numbers below instead of a slogan.Leg ② is new: the first honest census. Fully paginated, one label per request with local intersection, PRs filtered out, plus the control the card prescribed. Measured at this PR's head:
pm:dispatchedpm:queuepm:blockingpm:blockedpm:on-holdpm:awaiting-maintainer555 closed cards carry
pm:queueandpm:dispatched. The filing seat could only say "at least 100 per lane per label" because a first page is not a count and the gate could not be run to get one; it also dated the oldest at 2026-08-05, and the real floor is three days earlier.⛔ A page cap is never rendered as a count. A truncated corpus renders
≥N (PAGE CAP … NOT a count),censusIsCountablegates the claim, and an empty control makes the whole census refuse the "clean" reading. This run was fully paginated, so the figures above are real counts.⛔ No relabel rides this PR. Census only; the cleanup is a maintainer decision on its own card, per the grading.
Survey (reported, not fixed): the sibling page-capped windows
#13499 asked whether the other windows carry the same premise-rot shape. They do, but less acutely, and none is fixed here:
CLOSED_ISSUE_WINDOW_PAGES = 4(H22) — same shape, and worse divisor confusion: it is ordered byupdated, so its rows are consumed by issue activity, not closures. Its own docblock already records that surprise.COMMIT_WINDOW_PAGES = 3(H23) and the 10-pagelistIssues/listAllOpenIssues/listOpenPullRequestscaps — page caps whose reach moves with the board's tempo.listRecentIssueEvents(H35) is already time-bounded with a page cap behind it and reports truncation; it is the shape the H8 repair converges on.They are not converted here because the shared-helper refactor does not fall out naturally — H22's divisor is a different quantity — and widening this diff past its fence is not worth it. Worth its own card.
Verification
git hash-objectagainst the HEAD blob plus an emptygit diff HEAD:check-partof-closing-keyword.mjsrun bare has noPR_BODY/PR_NUMBER("a wiring or usage failure, NOT a verdict"; itspnpm check:partof-closing-keywordsibling passes), andcheck-test-completeness.mjswas handed no turbo log ("⛔ It is not a red, and there is nothing here to fix").bare-root-worklist --self-testandcheck:pm-dispatch-gates.eslint.config.mjsstates this repo "never enables type-aware linting … for ANY file", so no untouched file's verdict can depend on this diff;--format jsonreports 1 file linted, 0 errors, 0 warnings.check-nul-bytesgreen over 7,535 files; a separate control-byte scan of the changed file is clean.Generated by Claude Code