Appearance
qa-ui
qa-ui
qawriteshands-off
Use this when: a UI page needs its quality + test coverage checked
QA UI (quality + coverage)
The frontend safety net (epic #250): does this page render the real state, behave on every surface, and is that behaviour proven? The standard — the checklist, the craft tests, the report shape, the test-layer split — is docs/agents/qa-ui-contract.md. That doc is the source of truth; this skill is the how and does not restate it. Read it first, audit against it.
Scope — what's under audit
A selector: one page (Someday.vue), a feature (the task chat), or the changed UI (git diff main... -- resources/js). Default to the diff before a PR; take a named page when asked. Partition per-page — non-overlapping files — so a fan-out can't collide (the worktree rule).
The audit pass — this is the skill
Loading the contract + the page is setup; the value is turning each page into a pre-audit read then a gap list mapped to the layer whose proof is missing. Per page, in order:
- Pre-audit read — one line who / what / feel (page kind · audience · the calm
design.mdread), so a finding is judged against intent, not generic taste. - Run the checklist (contract §"The checklist") — console cleanliness, render-correctness through the DTO layer, interaction/state-propagation across every derived view, observability (success/failure/empty), guideline conformance, surface coverage.
- Run the craft tests (contract §"Craft tests") — swap, squint, signature, token-drift. By eye; assert where mechanisable (token-drift greps for off-scale
[#…]/shadow-[…]). - Name the missing layer for each gap — Vitest (props→DOM), Pest feature (guard paths — the gate's teeth), or Pest browser (interaction +
assertNoSmoke()- propagation). The contract §"Test-layer split" is the map; a guard path a browser test proves needs a feature-level twin or
ci:checknever sees it (the browser group is excluded from the gate).
- propagation). The contract §"Test-layer split" is the map; a guard path a browser test proves needs a feature-level twin or
The mechanics that make each layer deterministic — Agent::fake() for AI/tool flows, FakeTodoistClient::failGetTask() for partial outage, data-test hooks and attribute-selector counts — are in the contract; reuse them, don't reinvent.
Surface coverage — the page-surface manifest
resources/js/__tests__/page-manifest.test.ts fails ci:check for any Inertia page lacking a browser smoke test (unless grandfathered). A grandfathered page is itself a finding. To close one: write a real tests/Browser/<Page>Test.php (visits, renders the expected surface, assertNoSmoke() — a real assertion, never a hollow pass) and remove it from GRANDFATHERED in the same change, so the gate stays green. Never add a new page to the grandfathered set.
Output — surface, then fix
Per the contract §"Report + handoff shape":
- Severity-tiered findings — Critical / High / Medium / Low, each with
file:line. - Tag each real-gap vs subjective-preference + a confidence, so taste is triageable from defect. Name the cost before the severity word.
- Surface-then-confirm — diagnose first; on confirm, apply the fix and write the missing tests. Never a silent UI rewrite.
- A clean page is a valid result — say "passes" and stop.
Visual regression — out of scope here
The contract's tripwire is tripped, so a pixel-diff layer is recommended-forward and tracked as its own build — qa-ui does not build it. Until it lands, a pure-appearance gap (height-shift, badge styling) is reported as a real-gap the current layers can't cheaply assert, not silently dropped. Tooling choice lives in the contract.
Orchestration (opt-in)
When the gap-filling is large and disjoint — independent pages across non-overlapping files — fan out per-page across cheap-model workers per docs/agents/orchestration.md, then re-gate (ci:check) in-thread. A few pages, or gaps in shared files, stay in-thread.
Gate
composer ci:check green before the PR — including the page-manifest Vitest test and the smoke/Vitest/feature tests this pass added.
Where it sits
- Not
design-taste-frontend— that judges visual taste; this checks UI quality + assertable coverage against the contract. - Not
qa-code(rule conformance on a diff) orqa-tests(backend ZOMBIES/mutation). It's the UI arm ofqa-everything— fires when the change touchesresources/js/**/ a UI route.