Skip to content

ci: report scheduled-workflow failures as a tracking issue - #702

Merged
nh13 merged 1 commit into
mainfrom
nh/ci-report-cron-failures
Aug 6, 2026
Merged

nh13 merged 1 commit into
mainfrom
nh/ci-report-cron-failures

Conversation

@nh13

@nh13 nh13 commented Aug 1, 2026 •

Copy link
Copy Markdown
Member

Summary

A failing cron notifies nobody. GitHub emails only the person who last touched the workflow file — private, easy to filter, invisible to the rest of the team. miri.yml failed on every one of its 13 runs over two weeks and that surfaced nowhere. It was found by chance, by manually dispatching the workflow for an unrelated reason.

This adds a composite action that opens a tracking issue when a scheduled workflow fails, wired into both crons as an if: failure() step.

The dedupe is the point

A naive "file an issue on failure" would have produced fourteen issues for the outage above, which is just as easy to tune out as producing none — the same silence reached by a different route.

So: one open issue per workflow, reused. The first failure files it; every subsequent failure comments on it. The comment count then reads as how long this has been broken. Closing the issue once the workflow is green means the next failure opens a fresh one.

Matching is on the exact issue title (Scheduled workflow failing: <name>) rather than gh's full-text --search, which would also match issues that merely mention the workflow — and would let the two crons adopt each other's issue.

Scope

Both cron workflows, not just the broken one. stress.yml has the identical blind spot; it has simply been green every day so far, so its blind spot is untested rather than absent.

Permissions

Both workflows gain issues: write, used only by the reporting step. Neither writes to repository contents, and persist-credentials: false on checkout is unchanged — the step authenticates gh through github.token in the environment, not through git credentials.

The ci-failure label is created on demand inside the action (idempotent, failure tolerated), so this needs no out-of-band setup and no manual step before the first failure can be reported.

No third-party action is introduced — gh and jq are both preinstalled on GitHub-hosted runners, so there is nothing new to pin by commit hash.

Verification

The failure path is the one that never runs in normal operation, which is exactly how the original bug survived, so I tested it directly rather than by inspection. I extracted the action's script and ran it against a stubbed gh across three cases:

Case Expected Result
No open issue with the label file a new issue 1 create, 0 comments
Open issue with this workflow's exact title comment, don't duplicate 1 comment on that issue, 0 creates
Open issue with the other workflow's title file its own issue 1 create

Also confirmed the issue body renders flush-left — indented heredoc content would have turned the whole body into a Markdown code block.

What this does not solve

miri.yml failed on its very first run, so there was never a green baseline to regress from. Notification would have caught it on day one, which is enough here. But nothing automatable enforces "confirm a new gate actually passes before trusting it" — that stays a review-time habit.

Related

Risk: command output changes: yes, issue reporting is pinned by exact workflow-title matching; unsafe: none, CLAUDE.md allowlist: unchanged; memory, queue, and thread/backpressure policy: none.

Fix: The composite action reports scheduled miri.yml and stress.yml failures through one open tracking issue per workflow. It creates the ci-failure label when needed, comments on an existing exact-title issue, or creates a new issue after closure. Both workflows now grant issues: write.

@nh13
nh13 temporarily deployed to github-actions August 1, 2026 22:30 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6876dc4e-58e4-45b0-9082-871fa3873c0b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The pull request adds a composite action that creates or updates tracking issues for scheduled workflow failures. The Miri and stress workflows invoke it for failed or cancelled scheduled runs with scoped issue-write permission.

Changes

Scheduled failure reporting

Layer / File(s) Summary
Failure tracking action
.github/actions/report-cron-failure/action.yml
The composite action defines token and label inputs, creates the label, finds an exact-title open issue, comments on an existing issue, or creates a tracking issue with run details.
Workflow failure integration
.github/workflows/miri.yml, .github/workflows/stress.yml
The workflows add separate reporting jobs with scoped permissions. The jobs report failed or cancelled scheduled runs and exclude manual dispatches. The stress workflow also sets a five-minute timeout.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ScheduledWorkflow
  participant ReportCronFailure
  participant GitHubIssues
  ScheduledWorkflow->>ReportCronFailure: invoke after scheduled failure
  ReportCronFailure->>GitHubIssues: ensure label and query open issues
  GitHubIssues-->>ReportCronFailure: return exact-title match
  alt matching issue exists
    ReportCronFailure->>GitHubIssues: add failure comment
  else no matching issue
    ReportCronFailure->>GitHubIssues: create tracking issue
  end
Loading

Possibly related PRs

Suggested labels: continuous-integration

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title uses the valid ci type, clearly describes the main change, starts with a lowercase imperative verb, and has no trailing period.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@nh13

nh13 commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

@codecov

codecov Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.03%. Comparing base (9c7a0d0) to head (e3284d9).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #702      +/-   ##
==========================================
- Coverage   94.04%   94.03%   -0.01%     
==========================================
  Files         178      178              
  Lines      108835   108835              
==========================================
- Hits       102353   102347       -6     
- Misses       6482     6488       +6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nh13

nh13 commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/actions/report-cron-failure/action.yml:
- Around line 50-54: Update the gh issue list invocation used by the existing
issue lookup to retrieve all relevant open issues, either by setting an explicit
limit covering the expected maximum or by paginating through results. Preserve
the exact-title jq matching and existing variable flow so tracking issues are
still identified without creating duplicates.

In @.github/workflows/miri.yml:
- Around line 87-95: Replace the inline “Report failure” steps in
.github/workflows/miri.yml lines 87-95 and .github/workflows/stress.yml lines
60-68 with separate reporting jobs. Each job must independently check out the
repository, depend on its corresponding miri or stress-tests job, and run only
when always() && needs.<job>.result == 'failure' && github.event_name ==
'schedule', while preserving the report-cron-failure action and github.token
input.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: acc3181e-f430-469d-84ea-2826ac33f505

📥 Commits

Reviewing files that changed from the base of the PR and between a954af9 and 3efb8ec.

📒 Files selected for processing (3)
  • .github/actions/report-cron-failure/action.yml
  • .github/workflows/miri.yml
  • .github/workflows/stress.yml

Comment thread .github/actions/report-cron-failure/action.yml
Comment thread .github/workflows/miri.yml
@nh13
nh13 force-pushed the nh/ci-report-cron-failures branch from 3efb8ec to 02cbcbb Compare August 6, 2026 15:22
@nh13
nh13 temporarily deployed to github-actions August 6, 2026 15:22 — with GitHub Actions Inactive
@nh13

nh13 commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

A failing cron notifies nobody. GitHub emails only the person who last
touched the workflow file, which is private, easy to filter, and invisible
to everyone else. `miri.yml` failed on every one of its runs for two weeks
without that surfacing anywhere.

Add a composite action that opens a tracking issue when a scheduled
workflow fails, and wire it into both crons as a dedicated reporting job.

A job rather than a final step in the job that failed, because the two
failures most worth reporting are the ones a step could not report on. A
step `uses: ./.github/actions/...`, which only resolves once the repository
is on disk, so a failed checkout takes the reporting down with it; and
`timeout-minutes` *cancels* the job, which skips `if: failure()` steps
entirely — so the hang that bound exists to catch would go unreported. The
reporting job checks out for itself and reads the outcome from `needs`,
which survives both.

It matches `cancelled` as well as `failure`. GitHub documents a
`timeout-minutes` overrun as cancelling the job and does not state which of
the two it then reports, so matching both is what makes a hang reportable
either way. The cost is that a deliberately cancelled scheduled run also
files — but a human cancelling a nightly cron was watching it, and the
dedupe folds that into one issue they can close. A hang has nobody
watching, which is the whole problem. The issue text says "did not succeed"
rather than "failed" for the same reason.

It is gated on `github.event_name == 'schedule'`, not on failure alone. A
`workflow_dispatch` failure is already in front of whoever dispatched it,
and if either workflow later also runs on `pull_request` a failure there
shows up in that PR's checks. Only the unwatched trigger needs an issue;
filing one for the other two would reintroduce the noise the dedupe exists
to avoid.

The dedupe is the substance: a persistent failure comments on the existing
open issue for that workflow rather than filing a new one each night. One
issue per fortnight-long outage is a signal; fourteen issues is the same
silence reached by a different route. Matching is on the exact issue title,
so the two workflows never adopt each other's issue. The lookup passes
`--limit` because `gh issue list` returns only the first 30 by default — a
match paged out of that window would file the duplicate the dedupe exists
to prevent.

`stress.yml` gets the same job. It has been green every day so far, which
means its blind spot is untested rather than absent.

`issues: write` is scoped to the reporting job alone rather than the whole
workflow; neither workflow writes to repository contents, and
`persist-credentials: false` on checkout is unchanged. The `ci-failure`
label is created on demand so a fresh checkout needs no out-of-band setup.

Verified by extracting the script and running it against a stubbed `gh`:
files an issue when none is open, comments when a matching one exists, does
not confuse an issue belonging to the other workflow for its own, and finds
a match sitting past the default page.
@nh13
nh13 force-pushed the nh/ci-report-cron-failures branch from 02cbcbb to e3284d9 Compare August 6, 2026 23:49
@nh13
nh13 temporarily deployed to github-actions August 6, 2026 23:49 — with GitHub Actions Inactive
@nh13
nh13 merged commit ee177c3 into main Aug 6, 2026
15 checks passed
@nh13
nh13 deleted the nh/ci-report-cron-failures branch August 6, 2026 23:53
@nh13 nh13 mentioned this pull request Aug 6, 2026
@nh13 nh13 mentioned this pull request Aug 15, 2026

This branch was previously deployed

1 inactive deployment
github-actions — e3284d9b Deployed Aug 6, 2026 by nh13 via coverage #3341
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.

1 participant