Repository navigation
feat(ui): UI project with every quality gate, on a translated placeholder page (#358) - #374
Merged
Merged
Conversation
React + strict TypeScript on Vite with the React Compiler, TanStack Router, react-i18next, ESLint, Prettier, dependency-cruiser, Vitest with MSW and vitest-axe, and a size-limit budget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…358) ADR 0014 records why views are out of mutation scope and why the route tree is back in. ui-mutation-changed.sh scopes a run to changed UI files, ui-mutation-guard.sh keeps the setup honest, and the hooks run the UI's format, lint, typecheck and dependency rules when UI files are staged and its tests before a push. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#358) Documents the UI's commands, layout rules and mutation rules in CLAUDE.md, and in docs/mutation-testing.md why StrykerJS needs no private TMPDIR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A deleted UI file now makes the scoped mutation run cover the whole scope, literal strings in user-visible attributes fail lint, the unused user-event package is gone, and rationale comments are trimmed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
…changed (#358) devEngines.runtime pins Node 26.13.0 in the lockfile, so the hooks need no Node on PATH. scripts/ui-pre-push.sh skips a push that changes nothing under src/Anichron.UI and runs a frozen install before the tests, so a fresh worktree works. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #358. Part of #344. Decisions made during implementation: comment.
Summary
strict,noUncheckedIndexedAccess,noImplicitOverride). TypeScript 7 is out because typescript-eslint requires<6.1. Also Vite 8 with the React Compiler through Babel (the Rust compiler is marked experimental), TanStack Router, react-i18next, Vitest 5 in jsdom with MSW 3 (onUnhandledFrame: 'error'), and vitest-axe.eslint-plugin-jsx-a11ydeclares peers only up to ESLint 9, andstrictPeerDependenciesis on, so the install fails on a mismatch.browserslistinpackage.json, iOS first, last two versions. Vite'sbuild.targetis derived from it..nvmrcandengines, with pnpm 12.16.1 inpackageManager; CI installs both throughpnpm/setup@v3. The check:engines >=22, but its own CI runs only 22 and 24, so I checked it by running it: the full UI run on Node 26 reports 100% (11 killed), and an earlier run failed at 91.67% on a real survivor.api/callsfetch") is in ESLint: dependency-cruiser cannot see globals. See the Decision comment.react/jsx-no-literalscovers JSX text, andno-restricted-syntaxcovers user-visible attributes (aria-label,alt,title,placeholder, …). At('key')call passes; a literal fails.TMPDIRhazard: does not apply to StrykerJS..stryker-tmp.provide/inject), and its setup file is written inside the sandbox.docs/mutation-testing.md, "The UI".base.css(system font,color-scheme) gives the CSS budget a first caller.Evidence
Seam 2.
renderApp('/')renders the whole app through its real route tree. It finds theAnichronheading and the body text, and axe reports no violations.axe yields through
setTimeout, so it hung under fake timers (the test timed out at 5 s). It now passes:axeResultsdrives axe on the fake clock.StrykerJS proved both ways:
initAsync: falsesurvived; the run reported 91.67% and exited 1. The mutant was equivalent, since i18next initialises synchronously with inline catalogs (measured), so the option was removed rather than suppressed.describe(stryker-js#6265).Each dependency-cruiser rule failing on a deliberate violation (the files were removed afterwards):
Network rule (ESLint):
src/shared/net.tsfails and the same file undersrc/api/passes:Lint and budget:
.tsxcomponent with five branches failscomplexity4.size-limit: 109.32 kB of 150 kB JS and 117 B of 15 kB CSS. Lowering the JS limit to 100 kB exits 1.Hooks, checked in this worktree with
core.hooksPathpointed at it:Script tests:
ui-mutation-changed.test.sh, 13 cases. They cover scoped vs whole scope, deleted files, a types-only change (exit 0, "nothing to mutate"), and a failing run still failing.ui-mutation-guard.test.sh, 17 cases.ui-pre-push.test.sh, 5 cases: skip on a backend-only push, install then test on a UI change, failing tests fail the push.pnpm testdownloaded Node 26.13.0 and passed.mutation-guard.shstill passes.Merge Danger
Door: two-way. No schema, contract or data change. The UI isn't served yet (#359).
Blast Radius: CI-wide.
CI gatenow waits on theUIjob.CodeQLcheck comes from code scanning results, not the job name, so it is unaffected.scripts/ui-pre-push.sh. When the branch changes nothing undersrc/Anichron.UI, it skips, so backend-only pushes are unaffected. Otherwise it runs a frozen install, thenvitest run. Node needs no PATH setup:devEngines.runtimepins 26.13.0 in the lockfile, and pnpm downloads it. The version is stated in.nvmrc,enginesanddevEngines, so bump all three together.dist/assets/index-*.jscounts only the entry chunk. Once Rollup splits a shared chunk that the entry preloads, it undercounts, so revisit it with the first route chunk.🤖 Generated with Claude Code