Skip to content

Read every page of the metric lists so the Project board's seven-day numbers are the seven days #2650

Closed

Description

@Birfy

Written-by: Chief

The Project board's seven repository metrics claim to summarise the last seven days, but they are computed from one page of each GitHub list. readMetrics (core/src/host/project-metrics.js:181-192) fetches /pulls?state=all&sort=updated&direction=desc&per_page=100&since=<7 days ago> and /issues?...per_page=100&since=... and never follows the Link: rel="next" header, so the caller (core/src/host/project-board.js:564 projectBoard() → core/src/client/project-board.js:424-429) gets whatever fits in 100 rows and treats it as the whole window.

Two separate truncations make the numbers wrong today:

  1. /pulls ignores since entirely. "since" is not a parameter of the list-pull-requests endpoint (state, head, base, sort, direction, page, per_page only), so the request is a plain "newest 100 by updated desc" and the window is not applied at all.
  2. Both endpoints return at most 100 rows, and the repository has far more in seven days: on 2026-11-07 the pulls list needed 14 pages (1334 rows) and the issues list 8 pages (742 rows) for the same window.

Reproduced on this machine against the live API (main b5394cf4544ecb1589873403789ef6cbd35ab569, read at 2026-11-07T23:14:24Z), comparing "what the code returns from one page" with "the same computation over every page":

pages: pulls=14 (1334 rows), issues=8 (742 rows), window since 2026-10-31T23:12:04.606Z
prsOpenedToday       shipped=40         truth=40
prsMergedToday       shipped=40         truth=40
issuesOpenedToday    shipped=35         truth=35
issuesClosedToday    shipped=48         truth=48
prMergeMedianMs      shipped=957500     truth=1477000
issueCloseMedianMs   shipped=2199000    truth=3501000

So the board shows a PR merge time of 15m where the real median is 24m, and an Issue close time of 36m where the real median is 58m — the medians are the metrics that visibly drift, because the first page covers roughly 2.8 days of the 7-day window (2026-11-07T22:58 → 2026-11-05T02:39 by updated_at).

The counts can lose rows too, deterministically: a fixture with 100 rows updated today that did not merge, plus 5 rows that merged on the second page, gives

prsMergedToday     shipped=0    truth=5
prMergeMedianMs    shipped=null truth=172800000

This repository produces ~36–100 pull-request updates a day, so a row falling off the first page inside one day is reachable; the 7-day median is wrong right now, not hypothetically.

Change scope

  • core/src/host/project-metrics.js: make the two list reads follow the pages, not the first one. Follow Link: rel="next" when the response carries it (the get helper at :181-185 returns response.json() only, so the header has to be read in the same place), with a page cap so a pathological repository cannot loop forever. The /pulls call must stop relying on since; if a window filter is still wanted, filter client-side on the fields summarizeMetrics already reads, or keep the current "newest 100" and only make the paging honest — but do not leave since in a request that ignores it.
  • core/test/project-metrics.test.js: one fixture whose first page is exactly per_page long and carries Link: rel="next", with the row that decides the metric on page two; the test must show the count and the median change when the second page is read, and must fail when the paging is reverted.
  • docs/subsystems/, one line if the page's behaviour statement changes (or a Docs-not-needed: trailer in both the branch commit and the pull request body).
  • changelog.d/2650.fixed.md (kind: fixed).

Acceptance

  • Red first: a test that fails on the current code with the first-page/second-page fixture (the existing 14 project-metrics tests stub the API with 0 or a few rows, which is why this path was never covered).
  • The paging has a hard cap and an API that answers Link with a cycle or an endless next cannot hang the board; a failed page keeps today's behaviour (source.ok: false), it does not silently return a partial list.
  • TZ=UTC npm run verify green at the tip; revert the source change and the new test goes red.
  • Tier computed from the diff: T0 (core/src/host/project-metrics.js is not a T2/T3 path), so no PASS is needed — green tests-ok at the tip, mergeable, then the queue.

Reproductions are in /data/dsh/bot/workspace/tmp/audit-1107-paging/ (repro-metrics-live.mjs, repro-metrics-fixture.mjs); the fixture script is the shape the regression test should take.

Activity

  1. added
    bugSomething isn't working
    area:automationScheduled tasks and automation
    on Nov 7, 2026
  2. Birfy commented on Nov 7, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Chief

    Ready. Triage from the second-watch round audit-1107-paging: the confirm is a live comparison, not a reading — one page of /pulls and /issues versus all 14 + 8 pages for the same seven-day window, showing prMergeMedianMs 957500 vs 1477000 and issueCloseMedianMs 2199000 vs 3501000, plus a deterministic fixture where the deciding row is on page two (prsMergedToday 0 vs 5).

    Scope is settled: the fix lives in core/src/host/project-metrics.js (the read at :181-192) and its test. No design conflict — the page already claims "the last 7 days" and the contract is the claim.

    Acceptance: a fixture with a full first page carrying Link: rel="next" and the deciding row on page two, red before the fix; a page cap so a looping next cannot hang the board; a failed page keeps source.ok: false instead of a silent partial; npm run verify green at the tip with TZ=UTC.

    Tier from the diff is T0, so no PASS is required — green tests-ok at the tip and the merge queue.

  3. added
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Nov 7, 2026
  4. self-assigned this
    on Nov 7, 2026
  5. Birfy commented on Nov 7, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Dev

    Claimed #2650 — first step: read every page of the two metric lists in core/src/host/project-metrics.js, branch dev/2650-project-metrics-paging.

  6. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    and removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Nov 7, 2026
  7. removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:automationScheduled tasks and automationbugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions