Skip to content

fix(scripts): stop an empty ci run list reading as ten unverified commits - #6477

Merged
macanderson merged 1 commit into
mainfrom
worktree-a4d2e0f6-main-verified
Sep 9, 2026
Merged

fix(scripts): stop an empty ci run list reading as ten unverified commits#6477
macanderson merged 1 commit into
mainfrom
worktree-a4d2e0f6-main-verified

Conversation

@macanderson

@macanderson macanderson commented Sep 9, 2026

Copy link
Copy Markdown
Owner

What this fixes

scripts/check-main-verified.sh reads the CI history with one gh run list
call, then defaults each commit to missing when no run in that list matches
it. An empty list matches nothing, so all ten commits it checks become ten
separate findings at once.

gh returns [] with exit 0 for a transient API fault as readily as for a
genuinely empty history. On 2026-09-09 one such read failed main-canary.yml's
main carries no unverified commit job and filed #6475, which named ten
commits as unverified — while ci run 34379997528 on the tip it named,
cd7d53c, had already concluded success. Every one of those ten commits has a
completed ci run, then and now.

An auth or permission failure was already handled: gh exits non-zero there
and the script takes its unknown path. I checked that directly — the same
query under an invalid token exits 1, which is why this run cannot have been a
permission problem and must have been an empty answer with exit 0.

The fix

An empty run list becomes an unknown: reported loudly, exit 0. That is the
discipline the script's own header already states for every other unanswerable
read, and the header now names this one.

The two cases are separable rather than conflated. The read asks for the last
60 ci runs on main whatever their age, and an outage creates no runs and
destroys none, so it cannot empty that list — older runs stay in it. Empty
therefore means this run could not see the history at all.

The fix does not buy its safety with the coverage it exists to provide: a
commit absent from a populated list is still reported, and a new case pins
that direction alongside the three new ones.

Witness

The three new cases in scripts/test-main-verified.sh fail on the previous
script and pass on this one. Checked by restoring HEAD's copy of the script
and running the new suite against it:

FAIL an empty run list is an unknown, not a finding — expected exit 0, got 1
FAIL ...and says the list is what came back empty — expected exit 0, got 1
FAIL an empty run list filed an issue
main-verified: 35 passed, 3 failed

With the fix in place: main-verified: 38 passed, 0 failed.

guard-self-tests.yml runs this suite on pull_request with no paths filter,
so the witness runs in CI.

Checks run locally

  • ./scripts/test-main-verified.sh — 38 passed, 0 failed
  • shellcheck on both changed scripts — clean
  • make prose — OK, none added
  • make line-citations — OK, none added
  • make guards-fast — green

Nothing compiled: this change is two shell scripts.

Why this closes #6475

#6475 is the false report itself, filed by the defect this PR removes. Its
Definition of done — every recent commit on main has a completed ci run —
was already true when the issue was filed and is true now; I re-ran the fixed
checker against the real repository to confirm before ticking the box:

check-main-verified: OK — each of the last 10 commit(s) on main has a completed ci run.

Not in this PR

main also has a second, unrelated red: the docs workflow's
deploy stella.oxagen.sh job fails with

AccessDeniedException ... assumed-role/gha-deploy-stella/GitHubActions is not
authorized to perform: ssm:SendCommand on ... instance/i-094fcb34c7e715cf8

That is IAM drift in AWS account 916294258235, not a defect in this tree —
docs.yml names the same instance id the infra's terraform.tfvars declares,
and the Terraform does grant ssm:SendCommand on it. Repairing it needs a
production apply in an account this repository cannot reach, so it is filed as a handoff
in #6478 rather than fixed here.

Closes #6475

…mits

`check-main-verified.sh` reads the run history with one `gh run list` call
and defaults every commit to `missing` when no run in that list matches it.
An empty list therefore matches nothing, and each of the ten commits it
checks becomes a separate finding.

`gh` returns `[]` with exit 0 for a transient API fault as readily as for a
genuinely empty history. On 2026-09-09 one such read failed the canary's
`main carries no unverified commit` job and filed a tracking issue saying
nothing had verified ten commits — while `ci` on the tip, cd7d53c, had
already concluded success. An auth or permission failure exits non-zero and
was already caught as an unknown; this shape was not.

The two cases are separable: the read asks for the last 60 `ci` runs on
`main` whatever their age, and an outage creates no runs and destroys none,
so it cannot empty that list. Empty means the run could not see the history,
which is an unknown and exits 0 — the discipline this script's own header
already states. A commit absent from a populated list is still reported,
which is the gap the script watches, and a case pins that so the fix cannot
buy its safety with the coverage.

Witness: the three new cases in scripts/test-main-verified.sh fail on the
previous script (exit 1, "FAILED — main carries commits nothing verified")
and pass on this one. Suite: 38 passed, 0 failed.

Closes #6475

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @macanderson, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 4 days and 1 hour by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

The checker now distinguishes an empty, successful API response from a populated run history: empty results are treated as a loud, fail-open unknown and cannot generate false findings, while missing runs in populated results remain reportable. The test suite adds regression coverage for both behaviors.

Flow diagram for empty CI run list handling

flowchart TD
    A["Read CI runs with gh run list"] --> B{"gh command succeeded?"}
    B -- "No" --> C["Report unknown"]
    B -- "Yes" --> D{"run list empty?"}
    D -- "Yes" --> C
    D -- "No" --> E["Check commits against populated history"]
    E --> F{"completed run found?"}
    F -- "Yes" --> G["Commit verified"]
    F -- "No" --> H["Report missing commit"]
Loading

File-Level Changes

Change Details Files
Treat an empty successful CI run-list response as an unknown read failure instead of interpreting every checked commit as unverified.
  • Document empty-list behavior in the script’s fail-open contract.
  • Add an early empty-result guard that reports loudly and exits successfully without filing an issue.
  • Preserve missing-commit detection when the returned run list is populated.
scripts/check-main-verified.sh
Add regression coverage for empty-list handling and retain coverage for genuine gaps in populated history.
  • Verify empty results produce an UNKNOWN result and the expected diagnostic.
  • Verify empty results do not trigger issue creation in announce mode.
  • Verify a commit absent from a populated list remains a failure.
scripts/test-main-verified.sh

Assessment against linked issues

Issue Objective Addressed Explanation
#6475 Ensure the main verification check does not report commits as unverified when the CI run-history query returns an empty result that may represent an API or read failure.
#6475 Continue reporting genuinely unverified commits when the CI run list is populated but does not contain a completed run for those commits.
#6475 Resolve the currently missing verification runs on main by redispatching them and ensuring every recent commit has a completed CI run. The PR changes the checker and tests, but it does not redispatch or create any CI runs. It relies on the issue's stated condition that all commits were already verified and only prevents a transient empty API response from producing a false incident.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@macanderson

Copy link
Copy Markdown
Owner Author

Answering Sourcery's ❌ row

Objective: Resolve the currently missing verification runs on main by
redispatching them and ensuring every recent commit has a completed CI run.

This row asks for work that is not owed, because the condition it names never
existed. There were no missing verification runs on main.

That objective was read out of the "How to fix" section of #6475. The
script writes that section into every issue of this kind from a fixed
template, before it knows anything about the cause. On this occasion the
finding it accompanied was false, so its suggested remedy — re-dispatch the
missing runs — describes a repair with nothing to repair.

Here is the run history for the exact ten commits #6475 named. The canary
evaluated them at 16:58:16 UTC on 2026-09-09:

Commit ci conclusion Concluded (UTC) Run
cd7d53c success 17:20:12 34379997528
a3a6294 success 07:33:52 34322650858
bfc63d0 success 06:46:17 34318425719
8c10e91 success 02:08:28 34300557854
508b6a0 success 01:21:47 34298861144
c5c9e17 success 01:01:18 34296210150
778919f success 00:41:04 34294550435
42c5e7f success 2026-09-09 00:17:00 34292729785
bb77ca5 success 2026-09-09 00:02:14 34290615804
7760b66 success 2026-09-08 23:29:51 34290609476

Nine of the ten had already concluded success when the canary looked. The
tenth, the tip cd7d53c, had a run created at 16:57:59 — seventeen seconds
before the check — which went on to conclude success at 17:20:12.

So the correct verdict at that moment was nine verified and one pending, which
the script reports as PENDING and exits 0 on, filing nothing. It instead
reported ten as missing and filed an issue. That gap between the two is the
whole defect, and it is what this PR fixes.

Re-dispatching anything now would spend CI runs re-asking a question that has
ten success answers already. The two rows Sourcery marked ✅ are the actual
objectives, and the box on #6475 is ticked on the strength of the table above
rather than on this PR having run anything.

@macanderson
macanderson merged commit 55d9ce3 into main Sep 9, 2026
25 checks passed
@macanderson
macanderson deleted the worktree-a4d2e0f6-main-verified branch September 9, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

main carries a commit nothing verified

1 participant