You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(stats): follow artifact redirect so detection verdicts are actually fetched (#893)
* fix(stats): follow artifact redirect so verdicts are actually fetched
The verdict fetcher passed `--no-location-trusted` to curl on the
artifact-zip download, believing it would only disable credential
forwarding on redirects. It also silently disables `--location`, so
curl stopped at the 302 the GitHub API returns and every download was
recorded as `download_failed`. Yesterday's report on github/gh-aw
(555 external-detector runs) reflected this: 377 `download_failed`,
0 runs with a parsed verdict, threat rate reported as 0%.
Drop the flag. Plain `--location` already strips the Authorization
header on the cross-host hop to the signed blob URL, which is exactly
what the blob endpoint needs.
Extend the offline stub to answer artifact zips with a 302 → separate
blob path so the collector has to follow the redirect (verified: the
test now reproduces the production `download_failed` counts when the
flag is restored).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: David Slater <12449447+davidslater@users.noreply.github.com>
* docs(stats): make verdict-availability table self-describing
The verdict-availability table dumped raw internal keys (`present`,
`not_fetched`, `download_failed`, ...) and left readers to guess what
each one meant. In particular:
* `not_fetched` was easy to misread as a fetch failure; it actually
means the detection job was skipped so no artifact was ever
expected. Reviewer of #893 flagged this.
* Successful downloads land under `present`, not a fictional
`download_succeeded`. That was invisible in yesterday's #892 report
only because the redirect bug reclassified every success as
`download_failed`; the fix in #893 puts them back where they belong.
Render an explicit Meaning column with a fixed row order, so both the
healthy state (`present`) and the "skipped, nothing to fetch" state
(`not_fetched`) explain themselves in-place. Unknown states (which the
aggregator is defensive about but should never emit) still round-trip
verbatim.
Assertions in the offline test now verify the Meaning column is
rendered and that `not_fetched` is described as the skipped-job state.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: David Slater <12449447+davidslater@users.noreply.github.com>
* docs(stats): split verdict-availability `not_fetched` into `skipped` vs `not_fetched`
`not_fetched` was overloaded: it counted both detection jobs that were
skipped (never eligible for a verdict artifact) and eligible jobs the
collector never reached (budget exhausted, in-progress at collection
time, etc.). In a healthy run the former is expected and the latter is
a truncation signal, so they should not share a bucket.
Split them in the aggregator:
* `skipped` — `conclusion == "skipped"` or `status != "completed"`. The
detection job was never eligible, so no verdict was ever expected.
* `not_fetched` — anything else without a verdict record. The
collector meant to fetch this run and didn't get to it.
Records and notable_runs use the same split, so downstream views stay
consistent, and the summary now describes each row explicitly. Tests
assert the split (`not_fetched` must be absent when collection is
complete) and that both descriptions are rendered.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: David Slater <12449447+davidslater@users.noreply.github.com>
* chore(stats): give the collector ~2h so a full day fits in the budget
Yesterday's rerun of the fixed collector against 2026-08-17 hit the
`DEADLINE_MINUTES=18` wall-clock ceiling after 147/412 verdict targets
(the collector step ran exactly 18 min). Verdict fetching is currently
serial, so a full day of ~400 real downloads plus rate-limit pauses
needs on the order of an hour, not eighteen minutes.
Extend the collector's wall-clock window to ~2h and give the wrapping
workflow / job timeouts enough headroom to actually reach it:
* workflow timeout: 30 -> 150 (2h collector + ~30 min for the agent job)
* collector job timeout: 25 -> 130 (2h + a small setup/upload margin)
* DEADLINE_MINUTES: 18 -> 120
* MAX_REQUESTS: 3000 -> 8000 (a full day at ~85 req/min plus rate-limit
pauses can reach ~6-7k; leave headroom so the API budget doesn't
bind before the wall-clock deadline does)
This is a temporary buffer — verdict fetching should be parallelized
so the collector finishes in minutes, not hours. Filed as follow-up.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: David Slater <12449447+davidslater@users.noreply.github.com>
---------
Co-authored-by: GitHub Ace <githubnext@users.noreply.github.com>
Co-authored-by: David Slater <12449447+davidslater@users.noreply.github.com>
0 commit comments