Skip to content

test(ci): add the failsafe for selector jobs - #1422

Draft
auxesis wants to merge 3 commits into
ci/test-eql-selector-jobfrom
ci/failsafe
Draft

auxesis wants to merge 3 commits into
ci/test-eql-selector-jobfrom
ci/failsafe

Conversation

@auxesis

@auxesis auxesis commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This adds the failsafe. It is a test that fails when a workflow's selector job does not decide whether a job runs. The selector job is the first job of a workflow. It compares the files a pull request changes with each check's trigger paths, and each job's if: reads its answer. A job that does not read the answer runs on every change. That costs CI money, and nothing showed it until now.

ADR 0003 in #1416 describes the design. .github/CONTEXT.md on that branch defines "failsafe", "selector job" and "summary job".

Changes

  • scripts/__tests__/failsafe.test.mjs: the new test. pnpm run test:scripts runs it, and the lint job in tests.yml runs that on every pull request.
  • It reads every workflow that runs on pull_request or merge_group. In each one, a job passes when:
    • it is the selector job (id selector) or the summary job (the last job, with if: always() and every other job in its needs:);
    • it needs the selector job and its if: reads an output the selector job declares;
    • it needs a job that passes by the rule above, and its if: calls no always(), failure() or cancelled(), so GitHub skips it whenever that job skips; or
    • it has a written reason in EXEMPT_JOBS.
  • Three lists hold the exemptions. Each entry needs a reason:
    • NOT_CHECKS: claude-review.yml, code-review.yml and impact.yml, for good. The first two are review bots and the third is an advisory report. None is a check, and no branch rule requires them.
    • NOT_YET_CONVERTED: the 24 workflows with no selector job yet. Each conversion removes its entry, so this list shrinks to empty.
    • EXEMPT_JOBS: jobs the selector job does not decide, on purpose. Today these are four jobs in test-eql.yml that run on every change: setup, docs-static, known-failures and doc-anchors. A job that never runs on a pull request, such as a scheduled fuzz campaign, goes here too.
  • A stale exemption fails the test. That covers a workflow or job that no longer exists, a workflow listed as not yet converted that has a selector job, and a job the selector job already decides.

Verification

Related

Review notes

  • The failsafe checks pull request decisions only. In test-eql.yml, a gated job runs on every event other than pull_request, including merge_group. ADR 0003 says the selector should decide in the merge queue too. When it does, this test can check merge_group as well.
  • ci(mutants): decide in a selector job whether the gate runs #1420 adds scripts/__tests__/lib/selector.mjs. Once both land, the failsafe could read selector outputs through selectorOutputsRead from there. I kept its helper names out of this file, so the guard in shared-test-helpers.test.mjs will not fail when they meet.
  • A job added after the summary job, or left out of the summary job's needs:, makes the failsafe report the summary job as undecided. The failure message says how to fix that.

The selector job decides which checks run on a pull request. A job that
does not read its answer runs on every change. That costs money, and
nothing shows it.

The failsafe reads every workflow that runs on pull_request or
merge_group. It fails when the selector job does not decide whether a
job runs, unless the job has a written reason to run on every change.
An exemption that matches nothing also fails, so the lists stay true.

Only test-eql.yml has a selector job so far. Every other workflow starts
as an exemption, and each conversion removes its entry. The two review
bot workflows are exempt for good: they are not checks, and no branch
rule requires them.
@changeset-bot

changeset-bot Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5eb7542

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

impact.yml posts an advisory report on every pull request. It is not a
check, and no branch rule requires it, so it will not get a selector
job. It moves from the temporary "not yet converted" list to the
permanent one, next to the two review bots.
The per-job list was called RUNS_ON_EVERY_CHANGE. Some jobs the
selector job does not decide never run on a pull request at all, such
as a fuzz campaign that runs only on a schedule. EXEMPT_JOBS fits both
kinds. Each entry still needs its reason.

This branch has not been deployed

No deployments
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