Repository navigation
ci: the heavy lanes decide their component scope; drop the scope jobs - #8919
Conversation
The canonical setup compositions and the guest fixture contrast need a production browser render, and test-build already installs Playwright on the same runner under the same scope condition. Running them there drops a job from every pull request without changing what runs or when.
Adds the test-scope action: inside the job that owns the work, it reads the pull request's file list from GitHub and the base commit's trusted classifier, and puts everything in scope when it cannot decide (spec:AST-030 FR3, FR4). The interaction proofs and the native Swift build use it, so the interaction-scope and native-swift-scope jobs, the pr-scope-touches helper and its tests go away. Native Swift keeps one named runner-selection pre-job, native-swift-runner, because its macOS runner must be chosen before the job starts. AST-030's path list names the action instead of the helper.
docsite-test, docsite-data, docsite-browser, test-ui, test-node, the test join, registry-contract, build-storybook, size-base, typecheck, build-sandbox and test-build each run the test-scope step first and skip their work, reporting success, when nothing in their scope changed, instead of waiting on check-scope. Required contexts are unchanged (spec:AST-030 FR7). - The action reports whether it decided. docsite-test validates spec records when its own scope is spec-only or undecided, so a failed lookup can never pass the required check unvalidated (FR4). - The test join requires the release bump's own validation on a release-branch pull request, and every owner's success otherwise.
The accessibility, visual and RTL jobs run the test-scope step with `component-audit: true`: it also runs the base's trusted component-audit-scope.cjs and lists the changed files, so each audit still covers only the affected components on a pull request (spec:AST-030 FR13) and skips its work, downloads included, when nothing in its scope changed. Release-check (outside a pull request) stays full scope, and a release-branch pull request applies no audit. With every consumer moved, check-scope and check-components go away. An explicit release check keeps its authority in a small release-authority job, release-bump runs on a release-branch pull request by its base ref, and the RTL join accepts shards that decided their scope and did nothing.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
#8888 is superseded by four atomic PRs; this change now sits on the last of them. The relevance-registry edit drops out: that registry is not on main.
#8888 is superseded by four atomic PRs; this change now sits on the last of them. The relevance-registry edits drop out: that registry is not on main.
There was a problem hiding this comment.
Changes requested: per-job component scope is a sound replacement for the two scope jobs, but a few steps still need gating and tests.
- Gate
pr-visual'sSetup Node and pnpmandInstall Playwrightsteps and eachvisual-scoutleg's setup on the visual scope, so spec-, docs-, tooling-only and release-bump PRs stop running a fullpnpm installand a Chromium download, and extend the out-of-scope routing test to those steps. - Add a test that fails when the scope action's failed-classifier fallback stops running every audit (AST-030 FR9).
- Accept a
skipped/successshard mix as an out-of-scope no-op inpr-rtl, pass the changed-file list to the visual scope step through a file instead of an environment variable, and keep the lab-readiness CI check failing when it cannot find the gate.
[Automated review]
| printf '%s\n' "$FILES" \ | ||
| | node .github/scripts/visual-scope.mjs --github-output "$GITHUB_OUTPUT" "${VISUAL_ARGS[@]}" | ||
|
|
||
| - name: Setup Node and pnpm |
There was a problem hiding this comment.
Setup Node and pnpm here and Install Playwright below (line 2205) have no scope condition, so every PR outside stable visual scope now runs pnpm install --frozen-lockfile and installs Chromium in this job, which the base skipped. Gating both on github.event_name != 'pull_request' || steps.visual-scope.outputs.has_stable_visual == 'true' keeps capture and release-check unchanged. Each visual-scout leg's setup (line 2057) needs the scout's own condition too.
| - name: Decide stable visual scope | ||
| id: visual-scope | ||
| env: | ||
| FILES: ${{ steps.scope.outputs.changed_files }} |
There was a problem hiding this comment.
Passing the file list as an environment variable caps it at Linux's 128 KiB per-string limit: around 2,300 paths (renames count twice) make this step fail to start with Argument list too long. Writing the list to a file under RUNNER_TEMP from the action avoids that. The same applies at line 2040.
| ); | ||
| } catch (error) { | ||
| core.warning(`Component audit scope could not be decided (${error.message}); every audit runs in full.`); | ||
| componentScope = auditAll; |
There was a problem hiding this comment.
No test reaches this fallback: replacing auditAll with auditNone here leaves the scope-action, audit-scope and routing suites green, because the missing-classifier case fails earlier, in the fetch. A case whose base serves a classifier that throws would cover this fail-closed edge, as AST-030 FR9 asks.
| shardResult === 'success' && | ||
| evidence.scopes.length === 0 && | ||
| evidence.reports.length === 0; | ||
| return shardResult === 'skipped' || noOpShards |
There was a problem hiding this comment.
When build-storybook fails on a PR outside RTL scope, pr-rtl-shard is skipped while pr-rtl-merge (always()) succeeds as a no-op, so this receives skipped/success and reports that shards unexpectedly ran. Treating any mix of skipped and success with no evidence as the no-op would keep the base's pass.
| if (filtered) { | ||
| return filtered[1].split('|').map(name => `packages/${name}/src/`); | ||
| } | ||
| return registryRoots; |
There was a problem hiding this comment.
With no recognisable change detection in ci.yml, this now returns the registry roots, so the lab-coverage check can no longer fail when it cannot find the gate. Recognising the registry projection in .github/actions/test-scope/action.yml would keep an unrecognised gate failing.
A head-file lookup that fails for a reason other than 404 keeps the proofs in scope with no notice, and the Storybook guard fails the job when it runs (spec:AST-030 FR9).
check-scope still gates check-components, the heavy lanes and release-check, so the required join keeps failing when it does not succeed; part 4 removes the gate with check-scope itself. The routing tests pin the join's release-bump condition and env, and the heavy lanes' check-scope spec-only condition.
- Drops the test join's check-scope gate again, now that check-scope goes. - The visual jobs install nothing outside their visual scope: visual-scout's setup and pr-visual's setup and Playwright install skip with the rest. - The changed-file list reaches the visual scope through a file, since a large pull request's list can outgrow an environment variable. - The RTL join accepts a skipped/success mix of the shard and merge jobs as an out-of-scope no-op. - A test pins that a failing audit classifier runs every audit in full (spec:AST-030 FR9). - The lab-readiness check recognizes the action's component-audit gate and still fails when ci.yml has no recognizable gate.
There was a problem hiding this comment.
Changes requested: the per-job component scope holds up and the earlier points are addressed, but one new fail-closed edge still lacks the mutation test AST-030 FR9 asks for.
- In
visual-scoutandpr-visual, the newDecide stable visual scopefallback (a pull request without a readable file list, or a non-PR event, gets the full visual plan) can be switched to report no visual work, or lose its! -s "$FILES_PATH"check, with every routing suite still green; a test that runs that step with an emptyFILES_PATHand with a non-PR event would close it. - When the stack merges
main, keepmain'sci:heavy-laneslabel in all eight heavy-lane job conditions, which all conflict, as the description says. - Nit: the
ciComponentRootsdoc comment ininternal/lab-readiness/automated.mjsstill describes the old registry-roots fallback.
[Automated review]
| printf 'has_stable_visual=false\nbroad_stable_visual=false\n' >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
| if [ "${{ github.event_name }}" != pull_request ] || [ ! -s "$FILES_PATH" ]; then |
There was a problem hiding this comment.
This branch is the AST-030 FR4 fallback (no readable file list, or not a pull request, gets the full visual plan), but no test reaches it: printing has_stable_visual=false on the next line, or deleting || [ ! -s "$FILES_PATH" ] here, leaves every routing suite green, and the same holds at line 2158. FR9 asks for a test that fails when it goes; running this step's script with an empty FILES_PATH on pull_request and with a non-PR event, and expecting has_stable_visual=true and broad_stable_visual=true, would cover both jobs.
| * Roots the ci.yml component audits cover. Without change detection in | ||
| * ci.yml (the audits run every registered package in full for release-check) | ||
| * or when it projects the registry, that is every registered package root. |
There was a problem hiding this comment.
Nit: the function returns no roots when it recognises no gate (line 132), so the lab check fails; this clause still describes the earlier fallback to every registered package root.
The a11y guards and specs, the RTL jobs and the visual jobs read the scope step's component-audit outputs; dropping `component-audit: 'true'` from any of them now fails the suite instead of silently skipping its audits (spec:AST-030 FR9).
There was a problem hiding this comment.
Approval recommended: the new routing test fails whenever a job that reads the scope step's audit outputs drops component-audit: 'true', which closes the last gap, and the per-job component scope otherwise follows the CI routing spec. When the stack merges main, keep main's ci:heavy-lanes label in the heavy-lane job conditions, as the description says.
[Automated review]
docsite-test takes main's pull-request gate: the required-context draft skip in its condition and the ci:run first step for outside contributors, and runs on ubuntu-latest like main's docsite build. docsite-data and docsite-browser stay removed, also from ci-duration's needs.
PR Analysis Report📚 Storybook Preview🧪 Sandbox PreviewNo new or modified components detected. Bundle Size SummaryNo component packages changed. Accessibility AuditStatus: The accessibility audit did not run on this pull request. It runs after merges to Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
There was a problem hiding this comment.
Approval recommended: each accessibility, visual and RTL job now decides its own component scope from the base's trusted classifier, the ci:heavy-lanes opt-in and the draft and fork gate survive the merge with main, and every new fail-closed fallback is pinned by a routing or scope-action test. The red docsite-test comes from one docsite-browser case (the canary banner's production link at 390px in light) in code and jobs this change does not touch, so re-run it before merging. The description's "Stacked on #8918" and line count are out of date now that #8918 has merged.
[Automated review]
The scorecard's failure-and-gap tests move to rtl-scorecard-failures.test.mjs; main's rtl-scorecard-summary.test.mjs keeps the declared-exclusion tests.
docsite-test takes over docsite-data's new production registry gate step (node internal/shadcn-registry/verify-production-gate.mjs), and its contract test reads it there. Main dropped ci-duration, so its needs list goes with it.
Who this helps
Everyone opening a pull request: the last two scope jobs (
check-scope,check-components) disappear, so no job waits on a classifier job before starting.What changes
test-scopestep withcomponent-audit: true. It also runs the base's trustedcomponent-audit-scope.cjsand lists the changed files.release-authorityjob, andrelease-bumpruns on a release-branch PR by its base ref.Required contexts are unchanged (FR7).
mainconditions, minuscheck-components. When ci: visual, accessibility and RTL run on main, not on pull request updates #8877 lands, mergingmainkeeps itsci:heavy-lanesopt-in unchanged.Part 4 of 4 of the CI scope consolidation. Stacked on #8918.
Line count
+596 / −370, net +226.
Verification
vitest run --project node .github/scripts internal/shadcn-registry internal/lab-readiness: all pass.