Skip to content

ci: add CI OK aggregate required check with skip-detection (toon-meta#279) - #154

Merged
ALLiDoizCode merged 4 commits into
mainfrom
epic270/279-aggregate-check
Aug 6, 2026
Merged

ci: add CI OK aggregate required check with skip-detection (toon-meta#279)#154
ALLiDoizCode merged 4 commits into
mainfrom
epic270/279-aggregate-check

Conversation

@ALLiDoizCode

Copy link
Copy Markdown

Adds a single aggregate job ci-ok (context name CI OK) to .github/workflows/ci.yml, intended to replace the interim required-check pair (Detect Changed Paths + Dead Token Reference Guard) as the ONE required branch-protection check. Branch protection counts a skipped required check as passing, so requiring the ~20 paths-filtered jobs individually can never catch a job that should have run but didn't. CI OK runs if: always(), needs all 18 other jobs, and produces a real verdict on every PR — including docs-only PRs, which end green with legitimate skips rather than an empty check set.

Three-way verdict logic

For each needed job:

  1. Must-always-run jobschanges (Detect Changed Paths) and dead-token-guard (Dead Token Reference Guard), the only unconditional jobs in ci.yml: any result other than success fails.
  2. Paths-filtered jobssuccess passes; skipped passes ONLY IF the job's own if: condition, mirrored in the aggregate from the exact same needs.changes.outputs.* flags the job consumes (plus github.event_name == 'push'), evaluates false. If the flags say the job should have run but it's skipped, the aggregate fails with an explicit "expected to run but was skipped" error.
  3. failure / cancelled always fail.

Matrix jobs (desktop-smoke-e2e, desktop-e2e-integration-shard, server-cross-compile) surface as one collapsed needs.<job>.result — success only when every leg succeeded — so legs are never required individually. If changes itself fails, its outputs are empty, every mirrored condition reads false, and the must-run check on changes is what turns the run red. The implementation interpolates all workflow context into env vars once, then computes a readable job | result | expected table in pure bash.

Job classification

Must-always-run:

job id display name
changes Detect Changed Paths
dead-token-guard Dead Token Reference Guard

Conditionally expected (skip-allowed only when their detect flags are all false; push events always expect them):

job id display name detect flags
rust-lint Rust Lint rust, desktop-rust
unit-tests Unit Tests rust
desktop-core Desktop Core desktop, desktop-rust, rust
desktop-smoke-e2e Desktop Smoke E2E (matrix) desktop, desktop-rust, rust
desktop Desktop desktop, desktop-rust, rust
desktop-e2e-relay Desktop E2E Relay desktop, desktop-rust, rust
desktop-e2e-integration-shard Desktop E2E Integration (matrix) desktop, desktop-rust, rust
desktop-e2e-integration Desktop E2E Integration desktop, desktop-rust, rust
backend-integration Backend Integration (relay e2e) rust
relay-e2e Relay E2E rust
web Web web
mobile Mobile mobile
security Security rust
server-cross-compile Server Cross-Compile (matrix) rust
windows-rust Windows Rust (x86_64-pc-windows-msvc) rust, desktop-rust
desktop-build-macos Desktop Build (macOS) desktop, desktop-rust, rust

Skippable-by-design on agent PRs (when their paths didn't change — the aggregate enforces that the skip is legitimate): mobile (Flutter), server-cross-compile, windows-rust, desktop-build-macos, and the whole desktop e2e family.

on: pull_request at workflow level has no paths: filter, so CI OK runs on every PR. Existing jobs, their if: conditions, and the detect filters are untouched.

Verification

  • actionlint 1.7.7: clean.
  • Verdict script simulated locally across 8 scenarios: docs-only PR (pass), rust PR all green (pass), rust flag true but job skipped (fail), guard skipped (fail), push all green (pass), push with failure (fail), detect job failed (fail), cancelled job (fail).
  • This PR touches .github/workflows/ci.yml, which is in the rust and mobile detect filters — so the rust family, desktop family, mobile, and the aggregate all run here; only web legitimately skips.

Part of toon-protocol/toon-meta#270
Part of toon-protocol/toon-meta#279

🤖 Generated with Claude Code

ALLiDoizCode and others added 4 commits August 5, 2026 19:30
…#279)

Append a ci-ok job (name: CI OK) that needs every job in ci.yml and
becomes the single required branch-protection check. Branch protection
counts a skipped required check as passing, so requiring the ~20
paths-filtered jobs individually cannot catch a job that should have
run but didn't. CI OK closes that hole: for each needed job it mirrors
the job's own if: condition from the same needs.changes.outputs.* flags,
and a 'skipped' result passes only when that mirrored condition is
false. Unconditional jobs (changes, dead-token-guard) must be 'success'
outright; 'failure'/'cancelled' always fail. Matrix jobs are collapsed
via needs.<job>.result, never required per leg.

Verified with actionlint 1.7.7 and by simulating the verdict script
across docs-only, filtered-run, wrongly-skipped, failed-detect, push,
and cancelled scenarios.

Part of toon-protocol/toon-meta#270
Part of toon-protocol/toon-meta#279

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ALLiDoizCode
ALLiDoizCode merged commit dabd7c8 into main Aug 6, 2026
24 checks passed
@ALLiDoizCode
ALLiDoizCode deleted the epic270/279-aggregate-check branch August 6, 2026 16:05
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