scripts/pm/git-history.mjs --self-test is red on main right now, and it fails Lint & Repo Gates on every PR in the repo. It is not a code regression — the same commits that CI passed this morning fail this afternoon. The self-test passes before 12:00 UTC each day and fails after it.
Measured
| where | result |
|---|
origin/mainf4e5d916d6, run at ~12:05Z | git-history --self-test: 3 FAILED |
01c50322a1, run at ~12:06Z | 3 FAILED — the same commit CI reported green at 10:47:13Z today |
CI agrees, and pins the transition to the top of the hour:
Same code either side of ~12:00Z. Nothing merged in that window touches scripts/pm/.
Root cause: git approxidate resolves a bare date at the CURRENT time of day
The fixture builds 40 commits, one per day, each stamped 12:00:00Z:
constd=newDate(Date.parse('2026-06-01T12:00:00Z')+i*day).toISOString();and the assertion asks for an absolute-looking window:
runCliAllowFail(['count','--since=2026-06-20','--until=2026-07-11'],full)t('and the answer is the real one (21 commits: the daily fixture commits i=19..39)',…==='21')That window is not absolute. git rev-list --since=2026-06-20 has no time component, and git's approxidate fills it with the current wall-clock time, not midnight. So the --since boundary sweeps across the fixture's 12:00Z commits once each day:
- before 12:00 UTC →
--since ≈ 2026-06-20T11:5x → c19 included → 21 ✅ - after 12:00 UTC →
--since ≈ 2026-06-20T12:0x → c19 excluded → 20 ❌
Reproduced standalone, outside the gate, at ~12:07Z — a fresh 40-commit fixture with the identical stamps and the identical window:
$ git rev-list --count --first-parent --since=2026-06-20 --until=2026-07-11 main
20
$ git rev-list --first-parent --since=2026-06-20 --until=2026-07-11 --format='%s %cI' main | tail -2
c21 2026-06-22T12:00:00+00:00
c20 2026-06-21T12:00:00+00:00 <- oldest in window
$ git log --format='%s %cI' main | grep '^c19 '
c19 2026-06-20T12:00:00+00:00 <- the dropped boundary commit
The window holds c20..c39. c19 is the one that falls out, and it is exactly the --since boundary.
All three failures share this shape — each is off by one in a counted window:
✗ and the answer is the real one (21 commits: the daily fixture commits i=19..39)
got "20"
✗ and the answer now MATCHES the complete clone
got "20"
✗ a still-shallow clone whose floor predates the window answers WITHOUT fetching
{"stdout":"2
", "stderr":"… since 2026-07-08 until 2026-07-11 · floor 2026-07-06 · tip 2026-07-10 …"}
Why this is worse than an ordinary flake
It does not look like one. A flake that fires at random gets re-run and forgotten; this one is deterministic within a day — red for twelve hours, green for twelve — so the first person to look after noon sees a solid, reproducible failure and goes hunting for the regression that is not there. Every PR opened this afternoon inherits it, and re-queuing cannot clear it.
It is also silent about its own cause: the assertion says "21 commits" and gets 20, which reads as an off-by-one in the tool under test rather than in the question the test asked.
Direction, not a prescription
The fixture's stamps and the window are both the test's own inputs, so this is fixable without touching the tool:
- Give the window a time component —
--since=2026-06-20T00:00:00Z. Smallest change; check whether the CLI's --since parsing accepts it (Date.parse at :352 does, but the value is also handed to git). - Move the fixture stamps off 12:00 — e.g.
00:00:01Z — so no boundary can sweep them. Weaker: it moves the collision rather than removing it, and a stamp at midnight is one timezone away from the same bug. - Assert a window whose boundaries sit strictly between commit stamps, so no commit is ever within a day of an edge.
⚠️ Whichever is chosen, the fix must be proven by running the self-test on both sides of 12:00 UTC, or by a mechanism that makes the time of day irrelevant. A green run at 11:00 proves nothing about this defect — which is exactly how it shipped.
⚠️ Worth checking while in there: whether any other self-test or gate in the repo passes a bare YYYY-MM-DD to git. The same approxidate rule applies everywhere, and this one was invisible for ~10 hours after landing.
Provenance
The self-test landed in #10506 (7f8b36086f, 2026-08-21T02:10:05Z), which wired node scripts/pm/git-history.mjs --self-test into lint.yml's Shallow-history guard self-tests step. Filed by the domain:devx PM seat; the diagnosis above is measured, the remedy is not chosen.
Generated by Claude Code
scripts/pm/git-history.mjs --self-testis red onmainright now, and it failsLint & Repo Gateson every PR in the repo. It is not a code regression — the same commits that CI passed this morning fail this afternoon. The self-test passes before 12:00 UTC each day and fails after it.Measured
origin/mainf4e5d916d6, run at ~12:05Zgit-history --self-test: 3 FAILED01c50322a1, run at ~12:06Z3 FAILED— the same commit CI reported green at 10:47:13Z todayCI agrees, and pins the transition to the top of the hour:
Lint & Repo GatesSame code either side of ~12:00Z. Nothing merged in that window touches
scripts/pm/.Root cause: git approxidate resolves a bare date at the CURRENT time of day
The fixture builds 40 commits, one per day, each stamped 12:00:00Z:
and the assertion asks for an absolute-looking window:
That window is not absolute.
git rev-list --since=2026-06-20has no time component, and git's approxidate fills it with the current wall-clock time, not midnight. So the--sinceboundary sweeps across the fixture's 12:00Z commits once each day:--since≈2026-06-20T11:5x→ c19 included → 21 ✅--since≈2026-06-20T12:0x→ c19 excluded → 20 ❌Reproduced standalone, outside the gate, at ~12:07Z — a fresh 40-commit fixture with the identical stamps and the identical window:
The window holds c20..c39. c19 is the one that falls out, and it is exactly the
--sinceboundary.All three failures share this shape — each is off by one in a counted window:
Why this is worse than an ordinary flake
It does not look like one. A flake that fires at random gets re-run and forgotten; this one is deterministic within a day — red for twelve hours, green for twelve — so the first person to look after noon sees a solid, reproducible failure and goes hunting for the regression that is not there. Every PR opened this afternoon inherits it, and re-queuing cannot clear it.
It is also silent about its own cause: the assertion says "21 commits" and gets 20, which reads as an off-by-one in the tool under test rather than in the question the test asked.
Direction, not a prescription
The fixture's stamps and the window are both the test's own inputs, so this is fixable without touching the tool:
--since=2026-06-20T00:00:00Z. Smallest change; check whether the CLI's--sinceparsing accepts it (Date.parseat:352does, but the value is also handed to git).00:00:01Z— so no boundary can sweep them. Weaker: it moves the collision rather than removing it, and a stamp at midnight is one timezone away from the same bug.YYYY-MM-DDto git. The same approxidate rule applies everywhere, and this one was invisible for ~10 hours after landing.Provenance
The self-test landed in #10506 (
7f8b36086f, 2026-08-21T02:10:05Z), which wirednode scripts/pm/git-history.mjs --self-testintolint.yml's Shallow-history guard self-tests step. Filed by thedomain:devxPM seat; the diagnosis above is measured, the remedy is not chosen.Generated by Claude Code