Skip to content

UN-4363 [FEAT] Enforce the frontend v1 rules as their own PR checks: seam, purity, bundle, separation and accessibility - #2434

Merged
johnyrahul merged 18 commits into
mainfrom
UN-4363-v1-ci-gates
Nov 10, 2026
Merged

johnyrahul merged 18 commits into
mainfrom
UN-4363-v1-ci-gates

Conversation

@johnyrahul

@johnyrahul johnyrahul commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Johny · project thread

What

  • P0-T10 (UN-4363), sub-tasks UN-4606 to UN-4611: the frontend v1 rules become PR checks that report apart from v0.
  • New workflow ci-frontend-v1.yaml with one job per guard: v1 · Biome, v1 · Typecheck, v1 · Purity, v1 · Unit tests, v1 · Build, bundle and separation, v1 · Guard fixtures.
  • v1 · Unit tests runs vitest.v1.config.mts, the config of the rig's frontend-v1-unit group, so a run below v1's coverage threshold fails, and uploads the coverage report. test-fixtures/v1-unit-gate/ proves the threshold fails passing tests below it and that CI and tests/groups.yaml name the same config. v1 · Guard fixtures also runs the harness and unit-gate fixtures (UN-4612, folded in from UN-4612 [DEV] Gate v1 unit tests on the frontend-v1-unit group and its coverage threshold #2440).
  • New workflow ci-frontend-v1-seam.yaml: v1 · Seam.
  • The v1 steps move out of the v0 typecheck job in ci-frontend-lint.yaml.

Why

  • The P0-T10 spec (PT page) says the v1 rules must be enforced by CI, not by review, with each guard shown failing by a fixture.
  • Before this, the seam, bundle and separation guards did not exist. Accessibility rules were warnings. v1 results were mixed into the v0 typecheck check.

How

  • Seam (scripts/check-v1-seam.mjs + scripts/v1-seam-allowlist.json):
    • Applies when a change set is v1 work, meaning it touches src/v1/ or v1 tooling (scripts/*v1*, test-fixtures/v1-*).
    • It then fails on any changed v0 file (src/ outside v1, or public/) not in the allowlist. The allowlist covers routes, the root mount and src/index.css.
    • Plain v0 fixes touch no v1 file, so they pass untouched.
    • The v0-change label makes the check list the files instead of failing. The seam check is in its own workflow because it re-runs on label changes.
  • Purity: check-v1.mjs --code plus check-v1-styles.mjs. Adds a fixture showing v1 cannot import the antd shims.
  • Quality:
    • biome.json sets the 11 a11y rules that are warn repo-wide to error under src/v1.
    • lint:v1 and the CI job use --error-on-warnings, so any Biome warning under v1 fails.
  • Bundle (scripts/check-v1-bundle.mjs):
    • Runs the production build with an extra Rollup reporter.
    • Records the module graph Rollup resolved (static and dynamic imports), walks it from every src/v1/ module, and fails on any v0 or antd module reached. It judges imports, not chunk placement, so a package shared with v0 is fine and an inlined v1 entry is still checked.
    • Today the build reaches 0 v1 modules, because nothing imports v1 until P0-T03. The guard then has nothing to check, and the fixtures prove it bites.
  • Separation (scripts/check-v1-separation.mjs): no tracked folder under src/v1/plugins/. The other half, "v1 works with no overlay", is the Typecheck, Biome, Purity and Unit tests jobs, which run on a clean OSS checkout. The Build job covers v1 only once v0 imports it (P0-T03).
  • Seam also: with --base the allowlist is read from the base branch, so a PR cannot widen it and pass in the same change; index.html is guarded; nginx.conf / default.conf are deliberately not (deployment config serving v0 and v1).
  • Fixtures: new rows in boundary.fixtures.mjs. git-case.sh runs the seam and separation guards inside a real git repo rooted above frontend/, as CI does (renames, deletes, non-ASCII paths, a bad ref, an ignored overlay, a committed plugin, a widened allowlist). Real mini Vite builds cover the bundle guard (a shared package, a lazy v0 import, a static mount, a dynamic v0 import). The 11 a11y errors and each v1 CI job's exact commands are pinned. v1-important-css now expects Biome's noImportantStyles first, and runs the styles script directly to keep its own branch covered.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

Database Migrations

  • None.

Env Config

  • None.

Relevant Docs

  • frontend/src/v1/README.md, section "Scripts".
  • P0-T10 plan

Related Issues or PRs

Dependencies Versions

  • None.

Notes on Testing

Screenshots

  • N/A

Checklist

I have read and understood the Contribution Guidelines.


Generated by Claude Code


Generated by Claude Code

…0-T10)

- ci-frontend-v1.yaml: v1 checks as their own jobs (Biome, Typecheck,
  Purity, Unit tests, Build/bundle/separation, Guard fixtures), moved out of
  the v0 typecheck job so v1 reports apart from v0.
- ci-frontend-v1-seam.yaml + scripts/check-v1-seam.mjs: v1 work may change
  v0 (src/ outside v1, public/) only at scripts/v1-seam-allowlist.json. Change
  sets that touch no v1 file pass; the v0-change label turns it into a report.
- scripts/check-v1-separation.mjs: no tracked plugin folder under
  src/v1/plugins (enterprise code stays in unstract-cloud).
- scripts/check-v1-bundle.mjs: production build, then no v1 chunk or chunk
  it loads holds a v0 module or antd.
- biome.json: a11y rules are errors under src/v1; lint:v1 fails on warnings.
- 17 fixture cases proving each new guard fails and passes as specified,
  including two real Vite builds for the bundle guard.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
@johnyrahul johnyrahul self-assigned this Nov 4, 2026
claude and others added 2 commits November 4, 2026 09:23
…ud findings

- chmod +x on the three new shebang scripts (pre-commit
  check-shebang-scripts-are-executable).
- Explicit compare functions for every sort.
- Split the bundle guard's check() into reachable() and describe() to bring
  its cognitive complexity under the limit; output is unchanged.
- git from PATH marked NOSONAR with the reason, as in the fixture runner.
- String.raw in the glob escaper; no nested template literal.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
…ts own configs

Resolves the package.json and v1 README conflicts with #2429. The v1 unit
check now runs vitest.v1.config.mts and vitest.v1-plugins.config.mts with
coverage, and the guard-fixtures check also runs the v1-harness fixtures
(UN-4612).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
…sing under warnings-as-errors

Biome's warnings now fail lint:v1 before check-v1 runs, so the radix
bracket-access row checks check-v1 directly and pins Biome's own warning,
and the require fixture drops a suppression Biome reports as unused.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
…its coverage

Brings over UN-4612 from #2440. The v1 · Unit tests check runs
vitest.v1.config.mts, the config tests/groups.yaml gives the rig's
frontend-v1-unit group, so a run below v1's coverage threshold fails, and it
uploads the coverage report. test-fixtures/v1-unit-gate proves the threshold
fails passing tests below it, and that the CI job and the rig group name the
same config. test:v1 and the Guard fixtures check run those fixtures too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
@johnyrahul
johnyrahul marked this pull request as ready for review November 5, 2026 08:56
@johnyrahul
johnyrahul requested a review from a team as a code owner November 5, 2026 08:56
@greptile-apps

greptile-apps Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

via Greptile

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new actionable issues were found.

Summary

This PR gives frontend v1 its own CI checks instead of running them inside v0's typecheck job.

  • Frontend v1 checks report apart from the v0 checks.
  • The seam check limits v1 pull requests to named v0 files.
  • The production bundle check traces v1 imports and blocks v0 or antd modules.
  • The separation check rejects committed plugin folders in the OSS frontend.
  • Frontend v1 lint checks now fail on Biome warnings and accessibility issues.

Reviews (12) · Last reviewed commit: "Merge branch 'main' into UN-4363-v1-ci-g..." · Reviewed by Greptile

Comment thread frontend/scripts/check-v1-seam.mjs Resolved
Comment thread .github/workflows/ci-frontend-v1.yaml Resolved
…1 checks on their config files

git diff -z keeps a non-ASCII path such as src/pages/Überblick.jsx as
written, so it is matched against the seam instead of slipping past both
rules quoted. The v1 workflow now also runs when only ci-frontend-v1.yaml or
tests/groups.yaml changes, since the unit-gate fixtures read both.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv

@vishnuszipstack vishnuszipstack left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review of PR 2434 — UN-4363 frontend v1 CI gates

Mode: INITIAL. Reviewed head 80035853f3435113749242f4f2a6cfc810cc902b, merge base ed53cfded971d51f7d1ff1096d84c10bb01360b0, base freshened (base_fetch: ok), 39 files, 1119 lines (matches GitHub). Rubric: unstract plugin v2.1.80.
Signals: lenses 11 and 13 raised (CI workflows, tests changed). facts.sh also raised its dependency and auth triggers; package.json changes only scripts, and no dependency moved.
Security deep-dive: done
boundary-sweep: 2 sinks traced, clean (guard output prints repo-relative paths and git stderr to the CI log; the coverage artifact holds source paths and counts from a public repo).

Verdict — REQUEST CHANGES

Summary — Critical: 0 · High: 2 · Medium: 6 · Low: 6 · Lenses run: 19/19 (1 not covered, 4 N/A; see checklist).

The seam, purity, Biome and unit gates behave correctly on every input tried. The problems are concentrated in the bundle guard and in what the fixtures actually prove.

Findings are inline below, numbered as in the summary counts.

Unanchored findings

  • Every guard is advisory until an admin acts. Required checks on main are Greptile Review, SonarCloud Code Analysis, license/cla, pre-commit.ci - pr and report. The PR discloses this as a post-merge step, but it needs a named owner. Moving the v1 steps out of typecheck is not itself a regression, because typecheck is not on that list either.
  • The PR body's testing notes are out of date: "39 vitest tests and 105 fixture tests" against 284 and 130 observed here, and "This PR's own CI run is the first real run", though the workflows have now run and passed.

Lens checklist

  1. Spec & intent — See findings #1, #8
  2. Architectural fit & precedent — See findings #1
  3. Correctness & edge cases — See findings #1, #4, #8, #10, #11
  4. Security — Clean
  5. Data integrity & migrations — N/A — no persisted data or schema
  6. Concurrency — Clean
  7. API & contract compatibility — Clean
  8. Reliability & resilience — Clean
  9. Performance & cost — Clean
  10. Observability — Clean
  11. Operational safety — See findings #14
  12. LLM/agent-specific — N/A — no model, prompt or agent path
  13. Testing — See findings #1, #2, #5, #6, #7, #13
  14. Dependencies & build — Clean
  15. Code quality — Clean
  16. Doc & comment accuracy — See findings #3, #9, #12
  17. Cross-document rule consistency — Not covered — merge-result sweep unavailable: git 2.34 here, the script needs 2.38
  18. On-prem deployment experience — N/A — no chart, values or on-prem surface touched
  19. Scaling & workload lifecycle — N/A — no worker or scaling config touched

Assessed by me rather than an agent: lenses 4, 5, 6, 7, 8, 11, 12, 14, 15, 17, 18, 19. The type-design agent was not dispatched because the diff adds no types or schemas.

  • Lens 4: the deep-dive's find pass reported no candidates, so its filters had nothing to run on. My own read of the workflows agrees: plain pull_request, read-only token, no secrets, persist-credentials: false, and github.base_ref and the label check reach the shell only through env.
  • Lens 7: the changed surface is check names. The PR discloses the branch-protection step, and no workflow depends on the removed steps.
  • Lens 8: changes fails open by design, and a skipped job satisfies a required check.
  • Lens 15: biome ci --error-on-warnings src/v1/ and biome ci on the changed scripts and fixtures pass here.
  • Lens 17: base tip equals the merge base, so the branch is not behind and the merge-result question does not arise today; the branch-side sweep found no disagreement beyond the findings above.

Open questions for the author

  • Do the v1 workflows run when a stacked PR is retargeted to main? types omits edited, and the branch filter excludes the original base, so such a PR could reach main with no v1 · run until its next push. Stacked PRs are in use on this epic. UNVERIFIED — retarget one and see whether a v1 · check appears.
  • Is the bundle rule "no v1 source imports v0" or "loading v1 loads no v0 byte"? That decides how finding 1 gets fixed.

Assumptions made

  • The linked Confluence spec and P0-T10 plan were not read; lens 1 is judged against the PR body and the code's own comments.
  • Probes used private copies with node_modules linked, on the real vite.config.js where stated. The workflows themselves were not executed by this review; their green CI run on this head is the evidence for them.
  • The cloud-mirror statement in finding 9 rests on a local unstract-cloud clone that may be slightly behind.

Test run for this head: bun run test:v1 passes with 284 vitest tests and 130 fixture tests, exit 0.

Unanchored findings

  • .github/workflows/ci-frontend-v1-seam.yaml:44 (outside the diff hunk): [Low] [Lens 11] — The v0-change label does not exist yet (finding 14) — .github/workflows/ci-frontend-v1-seam.yaml:L44. The seam failure tells authors to apply it, GET /labels/v0-change returns 404, and the PR's post-merge steps mention only branch protection. Create it as part of rollout. Confidence: High. VERIFIED — API call.

Comment thread frontend/scripts/check-v1-bundle.mjs Resolved
Comment thread frontend/scripts/check-v1-seam.mjs Resolved
Comment thread .github/workflows/ci-frontend-v1.yaml Resolved
Comment thread frontend/scripts/check-v1-seam.mjs Resolved
Comment thread .github/workflows/ci-frontend-v1.yaml Resolved
Comment thread frontend/scripts/check-v1-seam.mjs Resolved
Comment thread frontend/scripts/v1-seam-allowlist.json Resolved
…y CI runs it

Addresses the review on #2434.

- Bundle guard: walk the module graph from every src/v1 module (static and
  dynamic imports) instead of judging chunk placement, so a package shared
  with v0 no longer fails clean v1 code and a statically mounted v1 entry
  that imports v0 no longer passes.
- Seam guard: read the allowlist from the base branch with --base, guard
  index.html, count top-level v1 files (vitest.v1.config.mts) as v1 work,
  and drop src/setupTests.js from the allowlist.
- Separation guard: ls-files -z, so a non-ASCII name is read as written.
- Fixtures: git-case.sh runs the seam and separation guards in a real
  repository rooted above frontend/ (renames, deletes, non-ASCII paths, a
  bad ref, an ignored overlay, a committed plugin, a widened allowlist);
  real-build bundle cases for a shared package, a static mount and a dynamic
  v0 import; seam glob near-misses; the 11 a11y rules pinned as errors; each
  v1 CI job's exact commands pinned; coverage cases just above and below 80%.
  makeTree leaves out a local cloud overlay.
- Docs: the production build covers v1 only once v0 imports it (P0-T03);
  cloud plugins are for the cloud mirror (UN-4614).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv

Copy link
Copy Markdown
Contributor Author

@vishnuszipstack, thanks for the thorough review. Every finding is addressed in bfa93fb, and each inline thread has a reply. Here are the rest:

  • Finding 14: the v0-change label now exists.
  • Required checks: making the v1 · … checks required is a post-merge step for a repo admin. I've listed it in the PR body with Johny as the owner.
  • Stacked PRs retargeted to main: a retarget doesn't re-run the v1 workflows, the same as ci-frontend-lint.yaml today. But the main ruleset requires the branch to be up to date before merging, and that update is a push, which runs every v1 · … check on the final head. I'd rather not add edited to the triggers. A title edit would then re-run every job, and skipping those jobs would turn earlier failures into a passing skipped.
  • Bundle rule: the intended rule is "no v1 code reaches v0 or antd" in the module graph. If P0-T03 ever needs "loading v1 loads no v0 byte", it can add v1's own chunking then.
  • PR body: the testing notes are updated. Locally, bun run test:v1 passes 284 unit tests and 153 fixture tests.

Generated by Claude Code

…t runs on macOS

BSD sed has no GNU-style `sed -i`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
@johnyrahul johnyrahul added the main-only Stays on main: not backported to a release line label Nov 9, 2026 — with Claude
…he CodeEditor test mock

The v1 lint now fails on warnings. Biome flags loads as unnecessary, but it is
read per render from a mutable mock that the tests flip between renders.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
Run the new v1 icon guard (check-v1-icons) as a step of the v1 Purity check,
keep it in lint:v1 next to warnings-as-errors, and split the escaped-CSS icon
fixture: Biome's noUselessEscapeInString warning now stops lint:v1 first, so
check-v1-icons is also asserted directly. Corrects the bundle:v1 README row
to describe the module-graph check.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
Comment thread frontend/scripts/check-v1-bundle.mjs Resolved
claude and others added 2 commits November 10, 2026 09:09
Rollup reaches a CommonJS module through a virtual "\0<file>?commonjs-..."
module. The guard dropped every virtual id, cutting the chain, so v1 could
reach v0 or antd through a CommonJS package unnoticed. Virtual modules now
stay in the graph, named after the file they wrap (edges merged); ones with no
file behind them are "virtual:<id>" and never count as v1, v0 or antd.
New fixture bundle-v1-cjs-v0 (v1 -> CommonJS lib -> v0) fails as it should.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HzRGGUgsEDiwJ56zKJ4ASv
@github-actions

Copy link
Copy Markdown
Contributor

Frontend Lint Report (Biome)

✅ All checks passed! No linting or formatting issues found.

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
⚪ e2e-agent-kv e2e 0 0 0 1 0.0
✅ e2e-api-deployment e2e 3 0 0 0 15.6
✅ e2e-coowners e2e 1 0 0 0 0.9
✅ e2e-etl e2e 1 0 0 0 16.1
✅ e2e-login e2e 2 0 0 0 0.9
✅ e2e-prompt-studio e2e 1 0 0 0 8.7
✅ e2e-smoke e2e 2 0 0 0 0.7
✅ e2e-workflow e2e 1 0 0 0 18.4
✅ frontend unit 664 0 0 0 11.9
✅ frontend-v1-unit unit 449 0 0 0 9.5
✅ integration-backend integration 1584 0 0 26 69.4
✅ integration-connectors integration 1 0 0 7 7.2
✅ integration-workers integration 181 0 0 1 44.9
❌ ui e2e 0 1 0 0 0.0
✅ unit-agent-kv-schema unit 143 0 0 0 1.1
✅ unit-backend unit 2159 0 0 1 41.3
✅ unit-connectors unit 82 0 0 0 8.2
✅ unit-core unit 289 0 0 0 2.0
✅ unit-filesystem unit 1 0 0 0 2.8
✅ unit-platform-service unit 22 0 0 0 1.9
✅ unit-rig unit 139 0 0 0 3.6
✅ unit-runner unit 12 0 0 0 2.1
✅ unit-sdk1 unit 1356 0 0 0 38.0
✅ unit-tool-sidecar unit 8 0 0 0 1.3
✅ unit-workers unit 1675 0 0 2 113.0
✅ unit-x2text-service unit 116 0 0 0 2.7
TOTAL 8892 1 0 38 422.5

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • mcp-server-auth — covered by integration-backend
  • mcp-platform-auth — covered by integration-backend
  • platform-key-whoami — covered by integration-backend
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

@johnyrahul
johnyrahul merged commit 930da00 into main Nov 10, 2026
29 checks passed
@johnyrahul
johnyrahul deleted the UN-4363-v1-ci-gates branch November 10, 2026 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

main-only Stays on main: not backported to a release line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants