Skip to content

ci: the heavy lanes decide their component scope; drop the scope jobs - #8919

Merged
cixzhang merged 30 commits into
mainfrom
ci/test-scope-heavy-lanes
Oct 31, 2026
Merged

cixzhang merged 30 commits into
mainfrom
ci/test-scope-heavy-lanes

Conversation

@cixzhang

Copy link
Copy Markdown
Contributor

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

  • The heavy lanes decide their own component scope.
    • 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.
    • Each audit still covers only the affected components on a PR (spec:AST-030 FR13), and skips its work, downloads included, when nothing in its scope changed.
    • Release-check, which runs outside a PR, stays full scope.
    • A release-branch PR applies no audit.
  • The RTL join accepts shards that decided their scope and did nothing.
  • The scope jobs are removed. An explicit release check keeps its authority in a small release-authority job, and release-bump runs on a release-branch PR by its base ref.

Required contexts are unchanged (FR7).

Part 4 of 4 of the CI scope consolidation. Stacked on #8918.

Line count

+596 / −370, net +226.

  • The added lines are the per-job component-audit scope, its routing tests, and the action's audit cases.
  • Across the 4 parts: +1,719 / −1,582, net +137. The follow-up that drops off-PR checks removes more than 1,000 lines.

Verification

  • vitest run --project node .github/scripts internal/shadcn-registry internal/lab-readiness: all pass.
  • Routing tests cover:
    • a labelled out-of-scope change, which leaves the RTL shards as no-ops and the join green;
    • each heavy lane's analysis download, which is gated;
    • a release bump, which gets no component audit.

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.
@vercel

vercel Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 31, 2026 5:56am UTC

Request Review

@astracat-bot

astracat-bot Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Oct 31, 2026, 6:07 AM UTC

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 30, 2026
cixzhang added a commit that referenced this pull request Oct 30, 2026
#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.
cixzhang added a commit that referenced this pull request Oct 30, 2026
#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.
cixzhang added a commit that referenced this pull request Oct 30, 2026
…csite-test

#8888 was split into #8916-#8919 on main. This carries the one-job
docsite-test change onto #8919 as a 3-way merge against its v8: the
docsite jobs are identical there, so the delta applies unchanged.
cixzhang added a commit that referenced this pull request Oct 30, 2026
…t's base

#8888 was split into four pull requests; this one now stacks on #8919.
The tree is #8919 plus this pull request's own changes, re-applied to
its job layout: the per-author heavy caps (FR16), the draft and
outside-contributor gate (FR17), CONTRIBUTING and the tests.

@astracat-bot astracat-bot 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.

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's Setup Node and pnpm and Install Playwright steps and each visual-scout leg's setup on the visual scope, so spec-, docs-, tooling-only and release-bump PRs stop running a full pnpm install and 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/success shard mix as an out-of-scope no-op in pr-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]

Comment thread .github/workflows/ci.yml
printf '%s\n' "$FILES" \
| node .github/scripts/visual-scope.mjs --github-output "$GITHUB_OUTPUT" "${VISUAL_ARGS[@]}"

- name: Setup Node and pnpm

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread .github/workflows/ci.yml Outdated
- name: Decide stable visual scope
id: visual-scope
env:
FILES: ${{ steps.scope.outputs.changed_files }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread internal/lab-readiness/automated.mjs Outdated
if (filtered) {
return filtered[1].split('|').map(name => `packages/${name}/src/`);
}
return registryRoots;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

@astracat-bot astracat-bot 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.

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-scout and pr-visual, the new Decide stable visual scope fallback (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 empty FILES_PATH and with a non-PR event would close it.
  • When the stack merges main, keep main's ci:heavy-lanes label in all eight heavy-lane job conditions, which all conflict, as the description says.
  • Nit: the ciComponentRoots doc comment in internal/lab-readiness/automated.mjs still describes the old registry-roots fallback.

[Automated review]

Comment thread .github/workflows/ci.yml
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread internal/lab-readiness/automated.mjs Outdated
Comment on lines +100 to +102
* 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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).

@astracat-bot astracat-bot 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.

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]

@cixzhang
cixzhang changed the base branch from ci/test-scope-owners to main October 31, 2026 05:48
cixzhang added a commit that referenced this pull request Oct 31, 2026
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.
@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

🧪 Sandbox Preview

View Sandbox for this PR

No new or modified components detected.

Bundle Size Summary

No component packages changed.

Accessibility Audit

Status: The accessibility audit did not run on this pull request. It runs after merges to main and before each release; pull requests that touch components run it with the ci:heavy-lanes label.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

@astracat-bot astracat-bot 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.

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]

@cixzhang
cixzhang merged commit 8361437 into main Oct 31, 2026
98 of 100 checks passed
cixzhang added a commit that referenced this pull request Oct 31, 2026
cixzhang added a commit that referenced this pull request Oct 31, 2026
cixzhang added a commit that referenced this pull request Oct 31, 2026
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.
cixzhang added a commit that referenced this pull request Oct 31, 2026
cixzhang added a commit that referenced this pull request Oct 31, 2026
cixzhang added a commit that referenced this pull request Oct 31, 2026
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.

This branch was successfully deployed

1 active deployment
Preview — d90d4485 Deployed Oct 31, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant