Uh oh!
There was an error while loading. Please reload this page.
fix(pm): convert the patrol's remaining count windows to announced time horizons - #13628
Merged
Merged
Conversation
…me horizons H22's closed-card window and H23's commit window become TIME horizons with announcing quota ceilings, following H8's conversion and H35's shape. H22's divisor is named honestly: its rows are consumed by closed-issue UPDATE activity (~188/day measured) rather than by closures (~11/day), which is why its four-page cap covered a ragged 2.1 days of update-recency while reading as a closure window — it missed 19 residue carriers closed within 3 days, 40 within 4, 265 within 7. The three bare 10-page caps convert to the OTHER half of the shape. Measured: none of them binds, and none is a recency window — each pages to exhaustion, newest-created first. A time horizon there would discard the OLDEST open rows, which is the population every row in this file exists for (an 8-day created horizon drops 104 of 354 open cards; the oldest open card is 76.9 days old, the oldest open P0 52.9). So they keep exhaustive paging and gain the announcement they were actually missing. What fell out as shared is the DISCLOSURE, not the paging: the divisors and termination arguments genuinely differ, but "which of the two bounds ended this pass" is one question in every case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
zhuangjianguo
marked this pull request as ready for review
August 31, 2026 04:03
zhuangjianguo
enabled auto-merge
August 31, 2026 04:04
Uh oh!
There was an error while loading. Please reload this page.
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#13606
Converts the half-states patrol's remaining COUNT-shaped windows to announced time horizons, following the two in-file precedents: H8's conversion (landed in PR #13601) and H35's pre-existing shape.
All measurements below were taken live in this container at 2026-08-31T03:33-03:36Z. Nothing here is copied from an earlier report — the board's tempo had moved, and re-measuring is what produced the two premise corrections.
H22 — the worst one, and its divisor named honestly
CLOSED_ISSUE_WINDOW_PAGES = 4becomesCLOSED_ISSUE_WINDOW_DAYS = 3withCLOSED_ISSUE_WINDOW_PAGE_CEILING = 12behind it as an announcing quota backstop.The divisor, named: this window's rows are consumed by closed-issue UPDATE ACTIVITY, not by closures. Measured on the live endpoint:
The consequence was not a slightly-wrong number but a ragged frontier: 28 of 225 adjacent card pairs in the window were out of closure order. A card closed 3 days ago and untouched since fell out while a card closed 3 weeks ago that got one comment today sat at the front. What that cost, measured the same instant — findings the row should have reported and structurally could not:
Why 3 days, bounded on both sides by measurement: the floor is that the window must not lose what four pages already delivered (it covered closures within ~2 days completely, 199 of 199). The ceiling is the docblock's own anti-drowning argument, in numbers: residue density measured 28-35% at every horizon, so findings are roughly linear in the horizon — 3d = 96, 5d = 175, 7d = 342, 8d = 370. The sibling install's experience is the calibration: at ~347 rows H22 exhausted the anchor body budget and trimmed every other predicate out of the report, which is why that install shipped with the reader switched OFF. A horizon that turns this row into the report is not a wider window, it is a disabled patrol.
The residual, stated rather than papered over: H8's window is 8 days and this one is 3, so a card that closed between 3 and 8 days ago carrying
pm:*residue is visible to neither row. That band is the price of the anti-drowning ceiling; closing it needs a counting shape like H39's census, not a wider list.H23 — a page cap kept honest by hand, and still the wrong shape
COMMIT_WINDOW_PAGES = 3becomesCOMMIT_WINDOW_DAYS = 3withCOMMIT_WINDOW_PAGE_CEILING = 12.This docblock was the only one that derived its cap from a measured rate rather than a remembered one, and the only one that survived a re-measure — so it is the strongest case that hand-maintenance works, and it still drifted:
Same three pages, 25% more window, eight days apart. N = 3 days comes from this row's own overlap argument (it targeted ~9x; 3 days is 12 consecutive runs at the 6-hourly cadence) and is close to what the cap delivers today, so the conversion barely moves the window now — the point is that it stays 3 days when the rate moves.
The three bare 10-page caps — premise falsified, and the repair is the other half
This is the one place I did not do what the card's survey line proposed, and the measurement is why. The card asked for a time horizon here too. Measured:
None binds the cap, and none is a recency window: each pages to exhaustion and the 10 is a pure quota backstop that has never been reached. There is no coverage in days to state, because the boundary is the end of the population, not an instant.
A time horizon here would be a defect, not a repair. These streams come back newest-created first, so a created-time horizon truncates the OLDEST open rows — precisely the population every predicate in this file exists for, per H8's own damage model ("the paired write NOBODY noticed correlates with how long nobody noticed it"). Measured:
The oldest open card is 76.9 days old; the oldest open
priority:p0is 52.9. An 8-day horizon — the obvious number to copy from H8 — would make a 52-day-old open P0 invisible to the entire patrol.So these three get the half of the target shape they were actually missing: exhaustive paging kept, the ceiling named as
OPEN_LISTING_PAGE_CEILING, and truncation ANNOUNCED, with the ceiling-bound listings named individually on the summary line. A ceiling-bound inventory must never read as the whole board.The shared-helper question, re-derived after the conversion
PR #13601's report measured, before converting anything, that a shared window helper "does not fall out naturally". That holds and is confirmed: the divisors are genuinely different (merges/day, closed-issue updates/day, commits/day) and so are the paging shapes — H8 and H22 order by
updated_atwhile selecting onmerged_at/closed_at; H23 and H35 order by the field they select on; the open listings have no horizon at all.What the conversion makes visible is a different commonality, and it is the one this card is about: every bounded pass ends for exactly one of two reasons, and that sentence is the same sentence every time. So what is factored is the DISCLOSURE (
describeWindowBound), not the paging. Three hand-copies of an announce clause is the likelier failure mode — hand-copied disclosures drift, and a report where one window says TRUNCATED and another silently says nothing is worse than either wording alone.One genuine paging abstraction did fall out for two real callers:
pageExhaustsWindow. This is the only line of #13601's landed repair this PR touches —mergedPageExhaustsWindownow delegates to it. Same name, same export, same signature, byte-identical behaviour; #13601's own direction cases pin it unchanged and still pass.Note the deliberate wording split: the shared helper says "boundary reached" where H8 says "horizon reached". #13601 pinned H8's truncated case with a whole-line substring check, written when H8 was the only window that spoke. Reusing its exact phrase on the now-shared line would satisfy that check from a neighbouring clause and quietly retire it — a check that cannot fail, which is the defect this family is about.
Verification
The file's own self-test —
pnpm check:pm-half-states, its own verdict line:Baseline on
origin/mainwas1685 cases pass, so this adds 64 cases.Ablation, one per repair leg. Predictions were fixed in the harness before any leg ran. Each leg: mutate by exact anchor, prove the mutation on disk by RE-READING the file and counting the exact multi-line anchor, run, then restore with
git checkout HEAD --(absolute path) and prove the restore by emptygit diff HEADand blob hash equal to the HEAD blob. No build step exists for this leg (node runs the script directly), so a mutation is live the moment it is on disk; the on-disk proof is still unconditional.H22 window: a 4-day-old closure is outside,H22 divisor: a stale closure bumped by today's activity is NOT admittedH23 window: a 4-day-old commit is outsideopen listings: a ceiling-bound listing is named, not just countedRestore proof after every leg:
git diff HEAD EMPTYandblob 109b59158c8075e6f147dc06fc927fa9a9fe7244 == HEAD blob.One prediction was wider than the result and is reported as such: leg D also predicted the two open-summary truncation cases would redden. They did not, correctly — those cases feed
summaryLinea fixture directly and so pin the renderer, which leg C covers, while leg D pins the recorder. The legs are independent, which is the better outcome, but the prediction overstated the blast radius.Gate families, derived from the ACTUAL diff via
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(17 path-derived + 2 convention-triggered for editing a gate script). 16 ran and passed; each gate's own verdict line is in the run log. A sample:Two did NOT run and are reported as NOT MEASURED rather than as passes or failures, in each case quoting the gate's own words:
node scripts/check-test-completeness.mjs—PREREQUISITE NOT MET ... the local reading for this gate is NOT MEASURED. It is not a red, and there is nothing here to fix.(exit 3; it grades a savedturbo run testlog that only CI produces.)node scripts/check-partof-closing-keyword.mjs—NOT WIRED — neither PR_BODY nor PR_NUMBER is set. Re-run against this PR body withPR_BODYset; result quoted in the report comment. Itspnpmspelling passed:✓ check-partof-closing-keyword self-test: 28 cases pass.Repo-wide ESLint:
pnpm lint(eslint . --no-inline-config) run in full rather than narrowed —LINT_EXIT=0. No narrowing justification is needed because no narrowing was applied.NUL bytes:
check-nul-bytes: OK (scanned 7541 text file(s) ... no raw ASCII control bytes), plus a direct control-byte scan of the changed file: 0 hits.Live fire (read-only) at the final commit
d440445c, the summary line's new disclosures:Page costs match the derivation exactly (H22 predicted ~6, read 6; H23 predicted ~4, read 4). H8's untouched clause still reads
TIME cap of 8 day(s), read in 10 page(s) (horizon reached ...).The anti-drowning constraint, verified end-to-end on the live board — same board, baseline vs this branch:
The finding count lands within 2 of what the residue-density measurement predicted before the code was written, and stays far below the ~347 flood that disabled the row on the sibling install.
Scope
scripts/pm/check-half-states.mjsonly — self-tests live in the same file. Report-only legs stay report-only; no relabelling, no behaviour changes beyond the window boundaries and their disclosure. No.mdfiles in the diff. No changeset: PM tooling underscripts/pm/**publishes nothing from any package, soskip-changesetapplies.Left DRAFT deliberately for PM self-review at contract-review tier, per the direct-landing lane.
Generated by Claude Code
Generated by Claude Code