Skip to content

ci: pick tests from the diff for PRs to main; explicit full triggers - #311

Merged
PHPCraftdream merged 1 commit into
mainfrom
jb/ci-tier1-main
Oct 30, 2026
Merged

PHPCraftdream merged 1 commit into
mainfrom
jb/ci-tier1-main

Conversation

@PHPCraftdream

Copy link
Copy Markdown
Owner

What

A pull request to main without the full-ci label used to get a cheap-only lane and a red gate (Full validation not requested for this revision.), so every PR needed a full run. It now goes through the diff selector that other PRs already use (ci_plan.py): tier1 for the closure of the changed packages, or full when the selector's own rules say so (core prefixes, fan-out thresholds, guard files such as .github/scripts/ and .githooks/, see .github/ci-policy.toml). The gate passes on the receipts the plan expects ("Tier 1 validation passed." / "Full validation passed.").

Full validation is an explicit, separate request, any of:

  • the full-ci label on the PR (unchanged);
  • a commit-message line that is exactly CI: full (case-insensitive) in any commit of the PR; for example git commit -m "fix: x" -m "CI: full". It can only add validation;
  • a manual run from the Actions tab with the new boolean input full; without it a manual run goes through the selector;
  • a push to main (unchanged).

Removed: the cheap_only lane, the minimal-plan subcommand and the unlabeled-PR early branch of gate_cli. Documented in .github/ci-structure.md ("Requesting validation", gate truth table).

Unchanged on purpose: job names and graph, run-name (it keeps saying ci [quick] for a run escalated to full by the directive or by the selector; the expression cannot see commit messages), concurrency groups, cancel-full-on-unlabel, ci-tests.yml, ci-windows-shards.yml, ci-security.yml, ci-policy.toml.

Tests

  • python -I -m unittest discover -s .github/scripts: 39 tests; .github/ci-shards: 13; YAML parse and actionlint .github/workflows/ci.yml clean.
  • Revert-checks, each restored byte-identical: bringing back the unlabeled NO_FULL rejection, the cheap_only expression for heavy_allowed, dropping the labeled-PR full check, a case-sensitive directive, search instead of fullmatch, allowing trailing text or dropping the CR allowance in the directive, %s instead of %B in the git log format, disabling the stale-head check, changing the success reasons, the summary row, the "missing jobs" reason - every one makes the tests named for it fail.
  • End to end in the fork, PR opened WITHOUT the label: the selector escalated it to mode: full (the change touches guard files), everything ran, and ci-gate saw only the known security / dependency-review failure (the fork's Dependency graph is off). First attempt (run 41003782502) also had a Windows shard failure, a flaky MCP test, fixed separately in test(mcp): stale-candidate close watcher lives for the test, not for 5 seconds #310; attempt 2 of the same head was green apart from dependency-review.

Known limits

  • The tier1 path (a small PR that the selector does not escalate) is not exercised by this PR, because a change to .github/scripts/ always falls back to full. It is exercised by the next small PR.
  • Local tests and actionlint do not prove live Actions behaviour (the inputs context on dispatch, checkout history for git log BASE..HEAD on pull_request); the fork run above covers the pull_request path, the dispatch input is untested until it is used once.
  • Consequence for upstream: any upstream PR now runs the selected CI in the upstream repository instead of only a cheap check.

🤖 Generated with Claude Code

A pull request to main without the full-ci label no longer gets the cheap-only lane and a red gate. It goes through the diff selector (ci_plan.py) like every other PR: tier1 for the closure of the changed packages, or full when the selector's own rules say so (core prefixes, fan-out, guard files). The gate passes on the receipts the plan expects.

Full validation stays an explicit, separate request: the full-ci label, a commit-message line "CI: full" in any commit of the PR, a manual run from the Actions tab with the new boolean input "full", or a push to main. The directive is parsed by commit_requests_full in ci_gate_decide.py (exact line match, case-insensitive) and can only add validation.

Removed: the cheap_only lane, the minimal-plan subcommand and the unlabeled-PR early branch of gate_cli. Documented in .github/ci-structure.md ("Requesting validation").

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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