Context
Observed on PR #16070. CodeQL extraction guard failed after 25s with:
check-codeql-extraction: could not read an Analyze-leg log —
refusing to certify clean from an unread surface. exit 2
The same run's Analyze (javascript) leg had succeeded (22:56:35→22:58:49), and the guard ran 22:58:57→22:59:22 — 8 seconds after it completed. Re-running only the failed leg passed with no code change. The identical guard passed on PR #16073 in the same window.
The Problem
The guard fetches the Analyze leg's raw log through the Actions API. GitHub does not guarantee a job's log is retrievable the instant the job reports completion, and 8 seconds is inside that window. fetchAnalyzeJobLogs treats any fetch failure as terminal — deliberately, per its own contract:
A single leg's fetch failure throws — an unread leg is an uncertified leg, never a silent pass.
That contract is correct and must not be weakened. A guard that passed here would be certifying a surface it never read, which is the failure class the guard exists to prevent. This ticket is not "make it lenient".
The defect is narrower: a transient fetch is indistinguishable from an absent one, and the guard treats both as terminal. So a correct guard produces a red check on a healthy PR, and the remedy is a manual re-run — which trains readers to re-run red checks reflexively, which is exactly how a real drop would get waved through.
The Architectural Reality
buildScripts/util/check-codeql-extraction.mjs → fetchAnalyzeJobLogs({repo, runId, token, jobNameMatch}). It lists the run's jobs, then fetches each matching leg's log. The jobs listing succeeded here (it found the leg); the log fetch is what came back unreadable.
The distinction the code needs is one it already has the information for: a retryable transport/availability response (404 or 5xx immediately after completion) versus a terminal one (403, malformed body, a leg that never completed). Only the first deserves a retry, and only for a bounded window.
The Fix
- Bounded retry with backoff on the log fetch for retryable statuses only — a few attempts over a handful of seconds, not a long poll.
- After the retries are exhausted, fail exactly as it does now, with the same message and exit code. The fail-closed contract is unchanged; it simply stops firing on a race it can wait out.
- The failure message should say the log was unavailable after N attempts over M seconds, so a reader can tell "we waited and it never appeared" from "we asked once at a bad moment".
Acceptance Criteria
Out of Scope
- Weakening the fail-closed contract in any form, including an "assume clean if unreadable" escape.
- The CodeQL configuration itself, or what counts as a dropped file.
Avoided Traps
- Retrying everything. A 403 is a permission answer, not a timing one; retrying it just delays the same red by the backoff window.
- Treating this as flakiness to route around. The guard is behaving correctly; the reflex to re-run a red check is the actual hazard, because it is indistinguishable from re-running a real drop.
Related
- PR #16070 — where it fired; run
30312473302
- #16068 — the adjacent CI-ownership lane (
@neo-gpt); fold in if that lane touches this file
Live latest-open sweep: checked latest 6 open issues at 2026-07-28T00:03:45Z plus a keyword search for an existing codeql/extraction ticket; none found.
Origin Session ID: c038696f-94a6-4788-82bf-747c5672908c
Retrieval Hint: query_raw_memories("codeql extraction guard could not read Analyze-leg log race")
Context
Observed on PR #16070.
CodeQL extraction guardfailed after 25s with:The same run's
Analyze (javascript)leg had succeeded (22:56:35→22:58:49), and the guard ran 22:58:57→22:59:22 — 8 seconds after it completed. Re-running only the failed leg passed with no code change. The identical guard passed on PR #16073 in the same window.The Problem
The guard fetches the Analyze leg's raw log through the Actions API. GitHub does not guarantee a job's log is retrievable the instant the job reports completion, and 8 seconds is inside that window.
fetchAnalyzeJobLogstreats any fetch failure as terminal — deliberately, per its own contract:That contract is correct and must not be weakened. A guard that passed here would be certifying a surface it never read, which is the failure class the guard exists to prevent. This ticket is not "make it lenient".
The defect is narrower: a transient fetch is indistinguishable from an absent one, and the guard treats both as terminal. So a correct guard produces a red check on a healthy PR, and the remedy is a manual re-run — which trains readers to re-run red checks reflexively, which is exactly how a real drop would get waved through.
The Architectural Reality
buildScripts/util/check-codeql-extraction.mjs→fetchAnalyzeJobLogs({repo, runId, token, jobNameMatch}). It lists the run's jobs, then fetches each matching leg's log. The jobs listing succeeded here (it found the leg); the log fetch is what came back unreadable.The distinction the code needs is one it already has the information for: a retryable transport/availability response (404 or 5xx immediately after completion) versus a terminal one (403, malformed body, a leg that never completed). Only the first deserves a retry, and only for a bounded window.
The Fix
Acceptance Criteria
Out of Scope
Avoided Traps
Related
30312473302@neo-gpt); fold in if that lane touches this fileLive latest-open sweep: checked latest 6 open issues at 2026-07-28T00:03:45Z plus a keyword search for an existing codeql/extraction ticket; none found.
Origin Session ID: c038696f-94a6-4788-82bf-747c5672908c
Retrieval Hint:
query_raw_memories("codeql extraction guard could not read Analyze-leg log race")