internal/contributor-info/ci-optimization.md
This document explains the React on Rails PR CI policy for humans and agents.
CI should give fast feedback during review without weakening merge safety:
ci-required / required-pr-gate.main, on release/* pushes, on same-repository non-Dependabot
release-target PRs, or by explicit manual dispatch.script/ci-changes-detector.paths or paths-ignore
filters that can leave branch protection waiting on a skipped workflow..github/workflows/ci-required.yml is the branch-protection-friendly gate. It
always starts for PR updates, label changes, merge queue, and manual dispatch.
The required-pr-gate job intentionally stays lightweight:
bin/lint-mirrored-blocksscript/ci-changes-detectormerge_group, waits for the package JS minimum Node check
(JS unit tests for Renderer package / build (20)) when JS tests are relevantRepository branch protection should require ci-required / required-pr-gate.
Do not require heavyweight hosted jobs for ordinary review pushes unless the
repository intentionally wants every PR update to allocate hosted runners.
Generator-sensitive changes are the standing exception: when
script/ci-changes-detector sets run_generators=true, the required gate
blocks ordinary pull requests until +ci-run-hosted, bin/request-hosted-ci,
or a maintainer/user-token ready-for-hosted-ci label requests hosted CI.
Merge queue, push-to-main, release/* pushes, and same-repository
non-Dependabot release-target PRs already satisfy hosted eligibility.
Dependabot release-target PRs require trusted current-head +ci-run-hosted or
+ci-force-full dispatch proof before hosted jobs are enabled.
Hosted workflows start cheap detector jobs, then use job-level conditions.
Optimized hosted CI runs when one of these is true:
mainrelease/*merge_grouprelease/*,
releases/*, or release-*)ready-for-hosted-ciforce-full-hosted-ciDependabot PRs are the exception: hosted CI labels and release-target base
branches are honored only after a write/admin maintainer uses +ci-run-hosted
or +ci-force-full and the selector sees the current-head dispatch success
comment.
Optimized hosted CI still uses script/ci-changes-detector to decide which
suites are applicable. This is the normal remote confirmation path after local
validation.
Force-full hosted CI runs when one of these is true:
force-full-hosted-ciforce_full_hosted: trueForce-full hosted CI bypasses optimized selection and marks every hosted suite as applicable. Use it only when a maintainer intentionally wants broad matrix coverage or when path selection itself is part of the risk.
| Profile | Force-full hosted | Latest local CI |
|---|---|---|
| Ruby versions | 3.3, 4.0 | 4.0 only |
| Node versions | 20, 22 | 22 only |
| Dependencies | minimum, latest | latest only |
Choose the request path that matches the actor making the request.
Human or local user token:
bin/request-hosted-ci
Human or local user token:
gh pr edit <number> --add-label ready-for-hosted-ci
Maintainer PR comment:
+ci-run-hosted
The comment command dispatches hosted workflows for the current head SHA before
adding ready-for-hosted-ci, because labels added by a workflow's
GITHUB_TOKEN do not start new pull_request workflow runs by themselves.
To request the broad hosted matrix:
+ci-force-full
This dispatches workflows with force_full_hosted: true and adds both
ready-for-hosted-ci and force-full-hosted-ci.
To stop hosted CI on future commits:
+ci-stop-hosted
To stop only the force-full override while leaving optimized hosted CI enabled:
+ci-stop-full
To record a SHA-bound hosted-CI waiver:
+ci-skip-hosted docs-only change; markdown checks are enough
For fork PRs, comment-command hosted CI does not dispatch same-repository workflows or add persistent labels. A maintainer should push a trusted branch in the base repository when release-target, Pro, or secret-backed CI is required.
Before pushing review-comment fixes or CI-sensitive changes, run:
bin/ci-local
bin/ci-local defaults to optimized local CI. It auto-detects the current PR's
base branch via gh pr view when available and falls back to origin/main or
main.
For narrow changes, this accepted alias documents the default intent:
bin/ci-local --changed
For broad local coverage where practical:
bin/ci-local --all
Use the detector directly only when you need to inspect routing:
script/ci-changes-detector origin/main
ready-for-hosted-ci is persistent. Once present, future commits keep running
optimized hosted CI until +ci-stop-hosted removes it.force-full-hosted-ci is persistent. Once present, future commits bypass
optimized selection until +ci-stop-full or +ci-stop-hosted removes it.+ci-skip-hosted [reason] is a SHA-bound waiver comment. It does not skip the
fast required gate and does not apply after another push.Merge queue is a repository setting, not a file in this PR. The repo-local
required gate enforces selected merge-group-only checks that run in separate
workflows by polling the current merge-group SHA. Today that includes the
package JS minimum Node lane, so a failing
JS unit tests for Renderer package / build (20) check blocks ci-required / required-pr-gate and therefore blocks the merge queue even when branch
protection requires only the stable required gate context. The gate maps check
runs back to Actions workflow runs by check_suite_id; a bare build (20) from
another workflow does not satisfy this gate.
Directly requiring every hosted full-matrix check context remains an administrator branch-protection setting. Use that setting only when maintainers want GitHub branch protection itself, rather than the repo-local required gate, to enumerate each heavyweight job.
If merge queue is not yet enabled, maintainers should request optimized hosted
CI with +ci-run-hosted before merging PRs that need remote confirmation. Use
+ci-force-full only when broad matrix coverage is intentionally required.
Branch protection should still require ci-required / required-pr-gate so every
PR update has a stable required check.
Use:
bin/ci-rerun-failures
The script maps common GitHub check names to local commands, including the
required PR gate. Some Pro dummy-app checks do not have exact local equivalents;
use the matching GitHub workflow or bin/ci-local --all when local reproduction
is not precise.
When adding or changing an expensive PR workflow, keep the workflow, command dispatcher, and docs in sync:
pull_request events for normal PR updates and label changes:
opened, synchronize, reopened, ready_for_review, labeled, and
unlabeled.push to main, merge_group, and workflow_dispatch when the
workflow is part of merge or release confidence.paths or paths-ignore when branch protection or
hosted CI policy depends on the workflow starting. Use job-level conditions
after checkout and change detection instead..github/actions/hosted-ci-selectors in the detector job and grant
issues: read so it can list PR labels.should_run_hosted_ci, should_force_full_hosted_ci, and
should_use_full_matrix from the detector job when downstream jobs need
them.should_run_hosted_ci == 'true' && run_js_tests == 'true'.should_use_full_matrix only for matrix breadth. Do not treat
ready-for-hosted-ci as a request to bypass optimized selection.+ci-run-hosted or +ci-force-full should dispatch the workflow for the
exact current head SHA, add it to .github/workflows/ci-commands.yml..github/read-me.md, CONTRIBUTING.md, AGENTS.md, and
.agents/workflows/pr-processing.md when the request or readiness process
changes.After this change merges, post a short maintainer comment on open PRs that were using or discussing the old CI command vocabulary:
CI process update: this repo now uses `+ci-run-hosted` / `ready-for-hosted-ci`
for optimized hosted CI, and `+ci-force-full` / `force-full-hosted-ci` only when
a maintainer intentionally wants to bypass optimized selection. The old
`+ci-run-full`, `+ci-skip-full`, and slash aliases have been removed.
Do not create a cleanup issue just to rebase every open PR. Rebase active PRs when they next need code changes, CI reruns, or merge-readiness work.
.github/workflows/ci-required.yml - fast required gate.github/actions/hosted-ci-selectors/action.yml - shared hosted/force-full selector.github/workflows/ci-commands.yml - PR comment command dispatcherscript/ci-changes-detector - changed-file classificationbin/ci-local - local optimized CI runnerbin/request-hosted-ci - adds ready-for-hosted-cibin/ci-rerun-failures - maps failed checks to local commands