Skip to content

Give every PR exactly one Summary check - #787

Merged
ejc3 merged 1 commit into
mainfrom
fix-claude-workflow-ci-gap
Aug 10, 2026
Merged

ejc3 merged 1 commit into
mainfrom
fix-claude-workflow-ci-gap

Conversation

@ejc3

@ejc3 ejc3 commented Aug 10, 2026

Copy link
Copy Markdown
Owner

A PR whose every changed file matches ci.yml's pull_request paths-ignore produces no check runs at all — not a skipped Summary, nothing — and GitHub reports it CLEAN. PR #785 (a two-file actions/setup-node bump touching only .github/workflows/claude*.yml) reached exactly that state: mechanically mergeable on the strength of checks that never ran. Same claim-confusion as PR #752's base-branch filter: "no failing checks" and "the checks ran" are different statements.

What this adds

  • ci-docs-summary.yml — the documented companion pattern for skipped-but-required checks: same workflow name (CI), same job name (Summary), with paths equal to ci.yml's paths-ignore. Every PR now produces a Summary check run, which makes Summary safe to set as a required status check on main (follow-up, after this merges). Required checks also reject direct pushes whose commits lack passing checks — closing the door on accidental pushes to main generally.
  • claude-lint.yml — now triggers on .github/workflows/claude*.yml too, and gains an actionlint job (binary download checksum-pinned to the published v1.7.10 release value, no third-party action) linting every workflow file. A claude-workflow edit finally gets a check that can fail for a YAML defect. shellcheck is off pending cleanup of the pre-existing SC2086/SC2129 findings in claude.yml's run blocks; actionlint's own checks (expressions, action inputs, needs refs, runner labels) apply.
  • Two guard tests in test_ci_workflow_coverage.rs, in the file's existing style: the companion's paths must equal ci.yml's paths-ignore entry-for-entry (drift reopens the hole for exactly the drifted path), and claude-lint must keep covering claude*.yml with a real linter job.

Test evidence

RED (before the workflow changes, tests only):

FAIL fcvm::test_ci_workflow_coverage companion_summary_covers_exactly_what_ci_ignores
     cannot read .github/workflows/ci-docs-summary.yml: No such file or directory
FAIL fcvm::test_ci_workflow_coverage claude_workflow_changes_get_a_relevant_check

GREEN (with the workflows in place):

Summary [   0.013s] 9 tests run: 9 passed, 0 skipped

actionlint -shellcheck= (v1.7.10) passes on all nine workflow files, including the two edited here; the same invocation was verified green against #785's head, so the rebased #785 will pass its new check.

Refs #786 (the "#785 fail-closed" and review-integrity items).

@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@ejc3, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 501b40db-8c99-41ae-9bbf-ab8de1a6d9d2

📥 Commits

Reviewing files that changed from the base of the PR and between 73668a9 and 6980e7b.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • tests/test_ci_workflow_coverage.rs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ejc3
ejc3 force-pushed the fix-claude-workflow-ci-gap branch from 4abf23e to d927aa0 Compare August 10, 2026 06:56

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4abf23edb3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci-docs-summary.yml Outdated
Comment on lines +17 to +18
paths:
- 'scripts/claude-assistant/**'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the fallback Summary out of mixed PRs

GitHub's path-filter semantics run a paths workflow when at least one changed file matches, whereas paths-ignore skips CI only when every changed file matches. A PR changing both src/... and README.md therefore starts this fallback alongside ci.yml, producing two Summary checks from the same app; GitHub explicitly warns that duplicate job names across workflows create ambiguous required-check results and can block merging. Make the fallback mutually exclusive with real CI, or replace both with one always-triggered aggregator.

AGENTS.md reference: AGENTS.md:L188-L198

Useful? React with 👍 / 👎.

Comment thread .github/workflows/ci-docs-summary.yml Outdated
Comment on lines +29 to +30
- name: Gate satisfied without the matrix
run: echo "Every changed file matches ci.yml paths-ignore; the VM matrix does not apply to this PR."

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate fallback Summary on the relevant linters

For a PR changing only .github/workflows/claude.yml, ci.yml is skipped and this required Summary succeeds unconditionally even when the newly added actionlint job fails. Since the stated follow-up is to require Summary, branch protection can accept that green gate without proving the check intended for these ignored files passed; make this Summary depend on the applicable lint work, or expose an always-present required aggregate that includes it.

AGENTS.md reference: AGENTS.md:L188-L198

Useful? React with 👍 / 👎.

ci.yml's pull_request trigger carried a paths-ignore list. A PR whose
every changed file matched it produced no check runs at all - not a
skipped Summary, nothing - and GitHub reported it CLEAN. PR #785, a
two-file actions/setup-node bump touching only claude*.yml, was
mechanically mergeable that way, with nothing configured to stop it.
Same claim-confusion as the base-branch filter that let PR #752 in: "no
failing checks" and "the checks ran" are different claims.

Skipping now happens per job, not per workflow:

- The pull_request trigger has no path filter, so Summary exists on
  every PR and can be made a required check on main. Required checks
  also reject direct pushes whose commits lack them.
- A `changes` job decides whether the VM matrix can say anything about
  the diff, and lint, packaging, fc-mock, host, host-root and container
  are gated on it. Summary already treats a skipped `needs` as
  non-failure and a failed one as failure, so the gate needs no new
  logic. Non-pull_request events and an empty file list both fail toward
  running everything.
- actionlint (binary checksum-pinned to the published v1.7.10 release
  value) lints every workflow file and is in summary.needs. It lives
  here rather than in claude-lint.yml so that Summary gates it: for a
  PR touching only claude*.yml, which skips the matrix, it is the one
  gating job that still runs and can fail.

An earlier version of this change added a second workflow, also named
CI, that emitted its own Summary for the ignored paths. Review found
that structurally cannot work: `paths` fires when ANY file matches while
`paths-ignore` skips only when EVERY file matches, so a PR touching both
src/ and a doc emits two Summary check runs and makes the required-check
result ambiguous - and that fallback Summary passed unconditionally,
including when actionlint failed. Both findings are now regression
tests.

Tested (red first, then green):
- Reinstating paths-ignore, ungating lint, and dropping actionlint from
  summary.needs fails all three new guards:
      FAIL every_pull_request_produces_exactly_one_summary
      FAIL expensive_jobs_are_gated_on_the_changes_job
      FAIL workflow_changes_get_a_relevant_gated_check
  Restoring the change: 10 tests run: 10 passed, 0 skipped
- actionlint -shellcheck= clean on all workflow files
- cargo fmt --check clean
@ejc3 ejc3 changed the title Close the zero-check hole for ci.yml's ignored paths Give every PR exactly one Summary check Aug 10, 2026
@ejc3
ejc3 force-pushed the fix-claude-workflow-ci-gap branch from d927aa0 to 6980e7b Compare August 10, 2026 10:07
@ejc3
ejc3 merged commit 148a86f into main Aug 10, 2026
21 of 22 checks passed
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