Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
655135d
UN-4363 [FEAT] Enforce the frontend v1 rules as separate PR checks (P…
claude Nov 4, 2026
9aa63fc
UN-4363 [FIX] Make the v1 guard scripts executable and clear SonarClo…
claude Nov 4, 2026
0d41712
Merge branch 'main' into UN-4363-v1-ci-gates
johnyrahul Nov 4, 2026
b0b20d9
UN-4363 Merge main (v1 test harness) and run the v1 unit gate under i…
claude Nov 5, 2026
69db2f3
UN-4363 Merge main (P1-T13 feedback) and keep its notify fixtures pas…
claude Nov 5, 2026
8921b8f
UN-4363 Merge main (release tooling, runner port fix)
claude Nov 5, 2026
1422fa7
UN-4363 Gate v1 unit tests on the frontend-v1-unit config and upload …
claude Nov 5, 2026
8003585
UN-4363 [FIX] Read changed paths unquoted in the seam guard and run v…
claude Nov 5, 2026
bfa93fb
UN-4363 [FIX] Judge the bundle by imports and test every guard the wa…
claude Nov 5, 2026
5612885
UN-4363 [FIX] Widen the allowlist with node in the seam fixture, so i…
claude Nov 5, 2026
aa5a70c
Merge branch 'main' into UN-4363-v1-ci-gates
johnyrahul Nov 9, 2026
40d7fc7
UN-4363 [FEAT] Suppress a false-positive hook-dependency warning in t…
claude Nov 9, 2026
f3caee0
UN-4363 [FEAT] Merge main into UN-4363-v1-ci-gates
claude Nov 10, 2026
48c8045
Merge branch 'main' into UN-4363-v1-ci-gates
johnyrahul Nov 10, 2026
af64c11
Merge branch 'main' into UN-4363-v1-ci-gates
johnyrahul Nov 10, 2026
082c95a
UN-4363 [FEAT] Follow CommonJS wrapper modules in the v1 bundle guard
claude Nov 10, 2026
476a7cd
Merge branch 'main' into UN-4363-v1-ci-gates
johnyrahul Nov 10, 2026
fc4d49d
Merge branch 'main' into UN-4363-v1-ci-gates
johnyrahul Nov 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 2 additions & 25 deletions .github/workflows/ci-frontend-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,35 +133,12 @@ jobs:
# esbuild ship per-platform binaries as optionalDependencies).
run: bun install --frozen-lockfile --ignore-scripts

# src/v1 is excluded here: its checks run, and report, separately in
# ci-frontend-v1.yaml and ci-frontend-v1-seam.yaml.
- name: Run TypeScript typecheck
working-directory: frontend
run: bun run typecheck

# src/v1 is excluded from the step above and checked under its own
# stricter tsconfig, after scripts/check-v1.mjs checks file types,
# placement, symlinks and the folder taxonomy.
- name: Run v1 typecheck
working-directory: frontend
run: bun run typecheck:v1

# Biome on src/v1, then scripts/check-v1.mjs: the folder import
# contract, v0 reaching v1 only through `@v1`, PropTypes and `ant-`.
- name: Run v1 lint
working-directory: frontend
run: bun run lint:v1

# The guardrail fixtures run under `node --test` (Node 22 APIs).
- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

# v1 unit tests, then the fixtures proving each guard above fails and
# passes when it should.
- name: Run v1 tests
working-directory: frontend
run: bun run test:v1

# ci-test.yaml runs the same suite as the rig's `frontend` group, but its
# tiers skip frontend-only PRs; this job is what gates those.
vitest:
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/ci-frontend-v1-seam.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Frontend v1 seam

# Seam guard (P0-T10, UN-4363): until Phase 9, a PR that is frontend v1 work
# may change v0 only at the files in frontend/scripts/v1-seam-allowlist.json.
# A PR that touches no v1 file is v0 work and passes untouched.
#
# The `v0-change` label lets v1 work that genuinely needs a v0 change through;
# the guard then lists the files instead of failing. Its own workflow, because
# it re-runs on label changes and nothing else needs to.

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
branches: [main]

permissions:
contents: read

jobs:
seam:
name: v1 · Seam
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
# The merge base with the PR's base branch must be reachable.
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

# Node built-ins only, so no install step.
- name: Run the seam guard
working-directory: frontend
env:
BASE_REF: ${{ github.base_ref }}
OVERRIDE: ${{ contains(github.event.pull_request.labels.*.name, 'v0-change') && '--override' || '' }}
run: node scripts/check-v1-seam.mjs --base "origin/$BASE_REF" $OVERRIDE
252 changes: 252 additions & 0 deletions .github/workflows/ci-frontend-v1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
name: Frontend v1 checks

# The frontend v1 rules as PR checks (P0-T10, UN-4363), reported apart from
# v0's checks in ci-frontend-lint.yaml. Each guard is its own job so a PR shows
# which rule failed by name. Every guard has fixture cases in
# frontend/test-fixtures/v1-boundary/ proving it fails when it should; the
# "Guard fixtures" job runs them.
#
# The seam guard reads PR labels, so it lives in ci-frontend-v1-seam.yaml:
# re-running these jobs on every label change would cost minutes for nothing.
#
# This workflow runs on a clean checkout of the public repository, with no
# cloud overlay, so green Typecheck, Biome, Purity and Unit tests jobs are the
# separation guard's "v1 works with no overlay" half. The Build job covers v1
# only once v0 imports it (the version switch, P0-T03).

on:
push:
branches:
- main
paths:
- "frontend/**"
# The guard fixtures also read these (the unit-gate drift check).
- ".github/workflows/ci-frontend-v1.yaml"
- "tests/groups.yaml"
# No `paths` on pull_request: an untriggered workflow reports no check run,
# so a required check would wait forever on non-frontend PRs. Filtering is
# done by the `changes` job instead; a job skipped via `if:` reports
# `skipped`, which satisfies a required check. Same as ci-frontend-lint.yaml.
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches: [main]

permissions:
contents: read

jobs:
# Gating jobs run when `changes` finds frontend files, AND whenever `changes`
# itself did not succeed: a broken filter must fail open (run the checks),
# never skip them. `!cancelled()` lets them run past a failed dependency.
changes:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
permissions:
contents: read
# dorny/paths-filter lists PR files via the API.
pull-requests: read
outputs:
# Push is already path-filtered by its trigger, so force true off-PR.
frontend: ${{ github.event_name != 'pull_request' || steps.filter.outputs.frontend == 'true' }}
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Check for frontend changes
if: github.event_name == 'pull_request'
uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
id: filter
with:
filters: |
frontend:
- "frontend/**"
Comment thread
johnyrahul marked this conversation as resolved.
Resolved
- ".github/workflows/ci-frontend-v1.yaml"
- "tests/groups.yaml"

# Biome's recommended rules and the accessibility rules as errors: biome.json
# raises the a11y rules for src/v1, and --error-on-warnings turns every
# remaining warning under src/v1 into a failure.
biome:
name: v1 · Biome
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Biome
uses: biomejs/setup-biome@4c91541eaada48f67d7dbd7833600ce162b68f51 # v2.7.1
with:
version: "2.3.13"

- name: Run Biome on src/v1
working-directory: frontend
run: biome ci --error-on-warnings src/v1/

typecheck:
name: v1 · Typecheck
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Install dependencies
working-directory: frontend
# No dependency lifecycle scripts: nothing here needs them.
run: bun install --frozen-lockfile --ignore-scripts

# scripts/check-v1.mjs --files (TypeScript only, styles only in styles/,
# allowed file types, no symlinks, folder taxonomy), then strict tsc.
- name: Run v1 typecheck
working-directory: frontend
run: bun run typecheck:v1

# No shim, antd, `ant-` class, CSS file, inline style, PropTypes or JS file
# under v1, plus the folder import contract and the styling policy. The JS
# and CSS-file rules run in the Typecheck job (check-v1 --files).
purity:
name: v1 · Purity
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Run the import and purity checks
working-directory: frontend
run: node scripts/check-v1.mjs --code

- name: Run the styling policy
working-directory: frontend
run: node scripts/check-v1-styles.mjs

- name: Run the icon rules
working-directory: frontend
run: node scripts/check-v1-icons.mjs

# The v1 unit tests: the rig's `frontend-v1-unit` group (tests/groups.yaml),
# run with the same config so CI and the rig cannot disagree. The config
# fails the run below v1's coverage threshold. Run here rather than through
# ci-test.yaml because its tiers skip frontend-only PRs. Cloud v1 plugins
# (vitest.v1-plugins.config.mts) are for the cloud mirror (UN-4614), not here:
# OSS has none.
Comment thread
johnyrahul marked this conversation as resolved.
Resolved
unit:
name: v1 · Unit tests
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Run v1 unit tests
working-directory: frontend
# The lockfile's vitest, never a fetched one.
run: ./node_modules/.bin/vitest run --config vitest.v1.config.mts

# The summary is in the log; the lcov report is for reading what a
# failed threshold missed.
- name: Upload v1 coverage
if: ${{ !cancelled() }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: frontend-v1-coverage
path: frontend/coverage/v1/
if-no-files-found: ignore
retention-days: 7

# One production build, then the bundle guard (no v1 module reaches v0 or
# antd) and the separation guard (no enterprise plugin code in this repo).
build:
name: v1 · Build, bundle and separation
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Build and run the bundle guard
working-directory: frontend
run: node scripts/check-v1-bundle.mjs

- name: Run the separation guard
working-directory: frontend
run: node scripts/check-v1-separation.mjs

# Proves every guard above fails and passes when it should, and that the
# unit harness (src/v1/test) fails a test that sends an unmocked request,
# and that the Unit tests check fails below the coverage threshold and runs
# the rig group's config (node --test, Node 22 APIs). Spawns the real tools, two small
# Vite builds included.
guard-fixtures:
name: v1 · Guard fixtures
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Run the guard fixtures
working-directory: frontend
run: node --test test-fixtures/v1-boundary/boundary.fixtures.mjs test-fixtures/v1-harness/harness.fixtures.mjs test-fixtures/v1-unit-gate/unit-gate.fixtures.mjs
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ lib64/
!frontend/src/lib/
!frontend/src/v1/**/lib/
!frontend/test-fixtures/**/lib/
# The v1 guard fixtures drive git through shell scripts (test-fixtures/v1-boundary).
!frontend/test-fixtures/v1-boundary/**/*.sh
parts/
sdist/
var/
Expand Down
13 changes: 13 additions & 0 deletions frontend/biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,19 @@
}
}
},
"a11y": {
"noLabelWithoutControl": "error",
"noNoninteractiveElementInteractions": "error",
"noRedundantRoles": "error",
"noStaticElementInteractions": "error",
"useAriaPropsSupportedByRole": "error",
"useButtonType": "error",
"useFocusableInteractive": "error",
"useGenericFontNames": "error",
"useKeyWithClickEvents": "error",
"useSemanticElements": "error",
"useValidAnchor": "error"
},
"suspicious": {
"noExplicitAny": "error"
}
Expand Down
7 changes: 5 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@
"typecheck": "tsc --noEmit",
"tokens:v1": "bun scripts/build-v1-tokens.mjs",
"typecheck:v1": "node scripts/check-v1.mjs --files && tsc -p src/v1/tsconfig.json",
"lint:v1": "biome lint src/v1/ && node scripts/check-v1.mjs --code && node scripts/check-v1-styles.mjs && node scripts/check-v1-icons.mjs",
"test:v1": "vitest run --config vitest.v1.config.mts --coverage && vitest run --config vitest.v1-plugins.config.mts --coverage && node --test test-fixtures/v1-boundary/boundary.fixtures.mjs test-fixtures/v1-harness/harness.fixtures.mjs"
"lint:v1": "biome lint --error-on-warnings src/v1/ && node scripts/check-v1.mjs --code && node scripts/check-v1-styles.mjs && node scripts/check-v1-icons.mjs",
"test:v1": "vitest run --config vitest.v1.config.mts --coverage && vitest run --config vitest.v1-plugins.config.mts --coverage && node --test test-fixtures/v1-boundary/boundary.fixtures.mjs test-fixtures/v1-harness/harness.fixtures.mjs test-fixtures/v1-unit-gate/unit-gate.fixtures.mjs",
"seam:v1": "node scripts/check-v1-seam.mjs --base origin/main",
"separation:v1": "node scripts/check-v1-separation.mjs",
"bundle:v1": "node scripts/check-v1-bundle.mjs"
},
"browserslist": {
"production": [
Expand Down
Loading
Loading