Repository navigation
fix(source-control): the verdict reader's full artifact listing skips live artifacts at page boundaries, FAILs included #10486
Description
Problem
The pr-verify verdict reader's full artifact listing (babysit_verify_evidence.py Reader._read_listing, GET repos/{repo}/actions/artifacts?per_page=100 paged through babysit_gh._run_pages) can skip a live artifact, a FAIL verdict included. It reads 69 pages over 50 to 58 s. When an artifact on an earlier page expires while later pages are read, every later artifact moves up one place, and the artifact at the next page boundary is never returned. An upload in the same window pushes artifacts down instead, and shows up as a duplicate.
A FAIL the listing skips does not count. The gate can then allow a pull request that verify:fail, verify:earlier-fail or the repeated-fail cap would refuse.
Evidence (2026-10-27, read-only probes against this repository)
Each full listing was taken right after an incremental listing whose size equalled the first page's live total_count:
| Probe (UTC) | Full listing rows / unique | Live artifacts the full listing lacked | Index each should have been at |
|---|---|---|---|
| 15:49 | 6,860 / 6,855 (5 duplicates, each at a page boundary) | pr-verify-8172-31a67e97…-fail (12247626604) |
6100 |
| 15:53 | 6,862 / 6,862 | none | n/a |
| 16:02 | 6,863 / 6,863 | pr-verify-9476-56282b92…-fail-i7152 (12525406048), pr-verify-10024-e471ea68…-pass (12601608922), patch-work-resolve-issue-resolve-issue-1 (12606360050) |
4600, 3500, 3400 |
GET repos/{repo}/actions/artifacts/{id} answered each missing id with expired: false after the probe. Every missing index is a multiple of 100, which is a page boundary.
Scope
#10488 closes this. The reader keeps no listing, whole or incremental, whose unique artifact ids are not exactly the live total_count. A whole listing is deduplicated by id, added to the whole listings read before it, and checked by a top-up read from page 1. After three whole listings that never hold the count, the pull request refuses verify:unreadable; it never allows. The refresh before an allow reads the same way.
Options
- Check the full listing against
total_counttoo: re-read when the unique count differs. Under steady churn this may need several reads (UNVERIFIED how often). - Read the next page from an id cursor rather than a page number, if the API offers one. The docs list no such parameter (UNVERIFIED).
- Overlap each page with the previous one, and check that the boundary artifacts match.
Activity
github-actions commentedon Oct 27, 2026
Proposed work class: work-class: scoped
Basis: automated intake triage; the lanes App applied this class.
Size: Small
Complexity: High
Uncertainty: Knowable
Flags: none
Blocked by: none
Understood: the pr-verify verdict reader's full artifact listing pages through
actions/artifactsover about a minute. Artifacts that expire or are uploaded mid-read shift the pages, so an artifact at a page boundary can be skipped, including a FAIL verdict. The gate may then miss a FAIL. Your evidence shows the missing artifacts sit at multiples of 100. The three options you list are approaches to check, not open intent questions. Which one works depends on what the API supports, and reading or testing would settle that. I found no open duplicate.Automated triage, applied by the lanes App.
melodic-automation-lanes commentedon Oct 27, 2026
Not admitted to the issue lane: no trusted-human acceptance criteria: a listed human must put the confirmed
- [ ]criteria in the body or post them as their own comment, or, on an issue a listed human filed, intake's newest refinement comment must hold them unedited. Admission takes the issue once each of those is met, when intake triages it again (.github/actions/resolve-config/admission-rules.json).melodic-automation-lanes commentedon Oct 27, 2026
The latest triage verdict holds nothing: admission moved the issue to
status: confirmed; its comment says why.melodic-automation-lanes commentedon Oct 27, 2026
Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.
Intended outcome: The full artifact listing is checked against the live total_count, and is re-read or refused as unreadable when it is incomplete, so a skipped FAIL cannot pass the gate.
Related work
Open questions
RECOMMENDED: Fail closed: raise _Unreadable so the gate refuses, as it does for other unreadable listings. Basis: plugins/source-control/skills/babysit-prs/scripts/babysit_verify_evidence.py:805
RECOMMENDED: Option 1 with a small fixed cap of 2 re-reads. Dedup by artifact id first, then compare to the first page's total_count. Keep the whole read inside LISTING_TIMEOUT_SECONDS, because each read takes about 55 s. Basis: judgment
RECOMMENDED: No. The docs list no cursor parameter for actions/artifacts, so drop option 2 unless a docs page shows one. Basis: judgment
Sources read
To answer, post a comment that starts with this line:
Automated refinement by the lanes App. Answer with a comment whose first line is
**Decision recorded.**.fix(source-control): never judge on a whole listing short of the live…