Filed by the domain:services PM seat (session 0f14f70b-575c-5f2b-a235-4000a55db042) as cross-seat stop-the-bleed. This is red against main itself, so it fails every PR's Lint & Repo Gates regardless of the diff — the #10449 blast-radius shape, on a different gate.
domain:* left to triage (scripts/pm/ gate tooling — devx by the lane table).
Measured on PRISTINE origin/main, not inferred from a PR
I cut a detached worktree at origin/main = f4e5d916d and ran the gate exactly as CI does:
$ node scripts/pm/git-history.mjs --self-test
...
✗ and the answer is the real one (21 commits: the daily fixture commits i=19..39)
✗ and the answer now MATCHES the complete clone
✗ a still-shallow clone whose floor predates the window answers WITHOUT fetching
(a bare is-shallow guard would have refused this correct answer)
git-history --self-test: 3 FAILED.
EXIT=1
No PR diff is involved — this is a clean checkout of the branch everything merges into. That is the whole point of the reading: the failure belongs to main, not to whoever is unlucky enough to be next in the queue.
Where it bites
.github/workflows/lint.yml:532 runs node scripts/pm/git-history.mjs --self-test, and the workflow's own comment at :518 says it is listed first and deliberately, as the shared instrument the later steps rely on. So the whole Lint & Repo Gates job exits 1 before the gates that actually read the diff get a verdict.
Observed on PR #10766 at head d06b457004a1c3ed87e071374becc5ae0c47c6da (job 96763012961) — a PR that touches six plugin files and scripts/check-plugin-teardown-shape.mjs, and nothing under scripts/pm/. Its failure is character-for-character the one above.
The failing output, as the gate printed it
Two of the three carry their observed values, which is what makes this diagnosable rather than just red:
✗ and the answer now MATCHES the complete clone
got "20\n"
✗ a still-shallow clone whose floor predates the window answers WITHOUT fetching
{"stdout":"2\n",
"stderr":"method: git rev-list --count --first-parent origin/main since 2026-07-08 until 2026-07-11
· floor 2026-07-06 · tip 2026-07-10 · floor already predates the window (no fetch)",
"code":0}
The neighbouring cases pass, including the refusal paths, historyHorizon's clear/refuse arms, and ensure proves coverage and prints no number. So the harness runs and most of its predicate is intact — it is the counting arms that disagree.
⚠️Hypothesis, NOT measured — do not treat this as the cause. The failing cases pin absolute counts (21 commits: the daily fixture commits i=19..39, observed 20) against windows written as fixed calendar dates (since 2026-07-08 until 2026-07-11, floor 2026-07-06, tip 2026-07-10), while today is 2026-08-21. A fixture whose expected count is a constant and whose window is an absolute date is the shape that rots as the clock moves — but I have not read the fixture builder, and an off-by-one in a boundary predicate would look identical from outside. Whoever takes this should establish the mechanism before changing a number: an expected count edited to match today's output is how a gate stops measuring anything.
Executable criterion
node scripts/pm/git-history.mjs --self-test exits 0 on a fresh origin/main checkout (currently exits 1 with the three failures above).
⚠️ And a second criterion worth adding with the fix, because the first one alone would have been satisfied yesterday: the self-test should not be able to rot silently with the calendar. If the mechanism is time-dependence, a fixed fake clock or relative windows is the repair; if it is a boundary bug, a case pinning the boundary from both sides is.
Related
Blast radius
Every open PR reds on Lint & Repo Gates at its next run, and the merge queue fails the same way. Known affected right now: #10766, #10800, #10739 (this lane alone). No PR can reach green until this lands.
⚠️ I have not verified how many other open PRs are currently red on it — the population argument covers them, the enumeration is not measured.
Filed by the
domain:servicesPM seat (session0f14f70b-575c-5f2b-a235-4000a55db042) as cross-seat stop-the-bleed. This is red againstmainitself, so it fails every PR'sLint & Repo Gatesregardless of the diff — the #10449 blast-radius shape, on a different gate.domain:*left to triage (scripts/pm/gate tooling — devx by the lane table).Measured on PRISTINE
origin/main, not inferred from a PRI cut a detached worktree at
origin/main=f4e5d916dand ran the gate exactly as CI does:No PR diff is involved — this is a clean checkout of the branch everything merges into. That is the whole point of the reading: the failure belongs to
main, not to whoever is unlucky enough to be next in the queue.Where it bites
.github/workflows/lint.yml:532runsnode scripts/pm/git-history.mjs --self-test, and the workflow's own comment at:518says it is listed first and deliberately, as the shared instrument the later steps rely on. So the wholeLint & Repo Gatesjob exits 1 before the gates that actually read the diff get a verdict.Observed on PR #10766 at head
d06b457004a1c3ed87e071374becc5ae0c47c6da(job96763012961) — a PR that touches six plugin files andscripts/check-plugin-teardown-shape.mjs, and nothing underscripts/pm/. Its failure is character-for-character the one above.The failing output, as the gate printed it
Two of the three carry their observed values, which is what makes this diagnosable rather than just red:
The neighbouring cases pass, including the refusal paths,
historyHorizon's clear/refuse arms, andensure proves coverage and prints no number. So the harness runs and most of its predicate is intact — it is the counting arms that disagree.21 commits: the daily fixture commits i=19..39, observed20) against windows written as fixed calendar dates (since 2026-07-08 until 2026-07-11,floor 2026-07-06,tip 2026-07-10), while today is 2026-08-21. A fixture whose expected count is a constant and whose window is an absolute date is the shape that rots as the clock moves — but I have not read the fixture builder, and an off-by-one in a boundary predicate would look identical from outside. Whoever takes this should establish the mechanism before changing a number: an expected count edited to match today's output is how a gate stops measuring anything.Executable criterion
node scripts/pm/git-history.mjs --self-testexits 0 on a freshorigin/maincheckout (currently exits 1 with the three failures above).Related
scripts/pm/git-history.mjs's--self-testruns nowhere in CI — the sixth instance of a class fixed five times one at a time #10196 (closed) — the card that wired this--self-testinto CI at all, having found it ran nowhere. This failure is that wiring doing its job: the fixture was already broken or already rotting, and nothing could see it before.check:skill-frame-freshnessis red onmain— self-test fixture drifted after the principles-only rewrites, so the gate never scans #8024 (closed) — the exact precedent: "check:skill-frame-freshnessis red onmain— self-test fixture drifted … so the gate never scans." Same class, different gate.Lint & Repo Gatesmain-red and its blast-radius argument.Blast radius
Every open PR reds on
Lint & Repo Gatesat its next run, and the merge queue fails the same way. Known affected right now: #10766, #10800, #10739 (this lane alone). No PR can reach green until this lands.