name: f0-quality-gate description: Automated post-implementation quality gate for F0 React components. Runs inline commands (typecheck, lint, tests) then spawns parallel subagents for code review, a11y, Storybook documentation coverage, and test coverage. Auto-fixes non-blocking issues and reports blockers to the user.
F0 Quality Gate
Runs a two-phase quality check after any code modification in packages/react/. Execute this workflow automatically — do not wait for the user to ask.
When to Run
Run after completing any of:
- New component created
- Existing component modified
- Hook added or changed
- Bug fix applied
- Refactoring completed
Skip when:
- The user explicitly says to skip checks
- The change is icon generation or other auto-generated files
Note:
.mdxfiles are NOT skip candidates — they go throughoxfmtformatting and must passformat:check.
Step 0 — Gather Changed Files
Before running any phase, collect the list of changed files:
git diff --name-only HEAD
git diff --name-only --cached
Combine both lists, deduplicate, and filter to files under packages/react/src/. Store this as the changed file list — both phases use it.
Also collect the full diff for Phase 2 subagents:
git diff HEAD -- packages/react/src
git diff --cached -- packages/react/src
If there are no changed files under packages/react/src/, skip the quality gate entirely.
Phase 1 — Inline Commands
Run these sequentially in the main agent. If a step fails, attempt auto-fix before proceeding. If auto-fix fails, record the failure and continue to the next step — do not abort the whole gate.
1a. Format
Always run first — applies to all file types including .tsx, .ts, and .mdx.
pnpm format
pnpm format:check
Run format to auto-fix all formatting issues, then format:check to confirm nothing remains.
formatusesoxfmtwhich reformats the entiresrc/directory — this is safe to run always- Key rules enforced: no semicolons, double quotes, 2-space indent, trailing commas (ES5)
- On
format:checkfailure afterformat: record as blocking, continue
1b. TypeScript
pnpm tsc --noEmit
- On failure: attempt to fix type errors directly in the source files
- After fix, re-run
pnpm tsc --noEmitto confirm - If still failing: record as blocking, continue
1c. Lint
pnpm lint-fix
pnpm lint
Run lint-fix first to auto-resolve fixable violations, then lint to catch anything remaining.
- If
lintstill reports errors afterlint-fix: record as blocking, continue - Auto-fixed violations: record count for the summary
1d. Tests
Run only tests for changed files to keep this fast:
pnpm vitest:ci -- --reporter=verbose $(git diff --name-only HEAD --cached | grep '__tests__' | tr '\n' ' ')
If no test files changed directly, run tests for all components whose source files changed:
pnpm vitest:ci -- --reporter=verbose --testPathPattern "<component-name>"
- On failure: record failing test names as blocking, do not attempt auto-fix (test failures require human judgment)
- On pass: record count for the summary
Note: Phase 2 Subagent D performs a deeper behavioral coverage review — the Phase 1 test run only confirms existing tests pass, not that new behavior is covered.
Phase 2 — Parallel Subagent Reviews
After Phase 1 completes (regardless of failures — subagent reviews are independent), spawn four subagents in parallel using the Task tool.
Pass each subagent:
- The changed file list from Step 0
- The full diff content from Step 0
- Its specific instructions below
Subagent A: Code Review
Prompt to pass:
You are a code reviewer for the F0 React component library.
Load the `f0-code-review` skill from `vendor/skills/f0-code-review/SKILL.md`.
Also read `packages/react/AGENTS.md` for full conventions.
Review the following changed files against the skill's checklist.
For each issue found, classify it as:
- BLOCKING: must be fixed before this work is done
- SUGGESTION: improvement, but not required
Changed files:
{changed file list}
Diff:
{full diff}
Return a structured report with this exact format:
## Code Review Report
### Blocking Issues
- {file}:{line} — {description}
### Suggestions
- {file}:{line} — {description}
### Auto-fixable Suggestions
List only suggestions that are safe to auto-fix without changing behavior:
- {file}:{line} — {description} — FIX: {exact change to make}
If no issues found in a category, write "None".
Subagent B: Accessibility
Prompt to pass:
You are an accessibility reviewer for the F0 React component library.
Load the `a11y` skill from `vendor/skills/a11y/SKILL.md`.
Also check `packages/react/AGENTS.md` section on Accessibility.
Review the following changed files for WCAG 2.1/2.2 Level AA compliance.
Focus on:
- Semantic HTML and ARIA usage
- Keyboard accessibility (focus, tab order, Enter/Space handlers)
- Screen reader support (sr-only labels, aria-live, aria-busy)
- Focus ring via focusRing() on all focusable elements
- useReducedMotion() in animated components
For each issue found, classify it as:
- BLOCKING: violates WCAG AA, must be fixed
- SUGGESTION: improvement, but not strictly required
Changed files:
{changed file list}
Diff:
{full diff}
Return a structured report with this exact format:
## A11y Review Report
### Blocking Issues
- {file}:{line} — {description} — WCAG criterion: {criterion}
### Suggestions
- {file}:{line} — {description}
### Auto-fixable Suggestions
List only suggestions that are safe to auto-fix without changing behavior:
- {file}:{line} — {description} — FIX: {exact change to make}
If no issues found in a category, write "None".
Subagent C: Storybook
Prompt to pass:
You are a Storybook and documentation reviewer for the F0 React component library.
Load the `f0-storybook-stories` skill from `vendor/skills/f0-storybook-stories/SKILL.md`.
Load the `f0-storybook-testing` skill from `vendor/skills/f0-storybook-testing/SKILL.md`.
Load the `f0-docs` skill from `vendor/skills/f0-docs/SKILL.md`.
Review the following changed files. For each changed component, read the component
source and its corresponding `__stories__/` directory and verify:
### Structural checks (conventions)
1. A `.stories.tsx` file exists for every changed component
2. Meta uses `satisfies Meta<typeof Component>` (not `as Meta`)
3. Tags include `["autodocs", "stable"]` or `["autodocs", "experimental"]`
4. A `Snapshot` story exists with `parameters: withSnapshot({})`
5. ArgTypes for union props reference the component's const arrays
### MDX documentation checks
6. An MDX file (`__stories__/*.mdx`) exists for every changed component
- If the component is NEW and has no MDX: this is BLOCKING — report it as
"New component F0X has no MDX documentation — load f0-docs skill to create it"
- If the component ALREADY EXISTS but has no MDX: report as SUGGESTION
7. Every new prop added in this diff is documented in the MDX anatomy or props table
- If a new prop has no MDX coverage: BLOCKING
8. Every new variant or state added in this diff is covered by the MDX (variants table or examples)
- If a new variant has no MDX coverage: BLOCKING
9. The MDX `<Canvas of={Stories.X} />` references all reference stories that exist
- If a Canvas references a non-existent story: BLOCKING
### Story coverage checks (new behavior)
10. Every new prop added in this diff has a corresponding story or argType that demonstrates it
11. Every new variant or state (e.g., new size, color, loading state, error state) is represented
in at least one story — and ideally in the Snapshot story so it is visually captured
12. If a prop was removed or renamed, any story referencing the old prop name is updated
13. Interactive components with new interactions have at least one `play` function story
covering the new interaction
For each issue found, classify it as:
- BLOCKING: required by F0 conventions (missing story file, missing Snapshot story,
new component with no MDX, new prop/variant with no MDX coverage)
- SUGGESTION: improvement (incomplete argTypes, new interaction without play function,
existing component missing MDX)
Changed files:
{changed file list}
Diff:
{full diff}
Return a structured report with this exact format:
## Storybook Review Report
### Blocking Issues
- {file}:{line} — {description}
### Suggestions
- {file}:{line} — {description}
### Auto-fixable Suggestions
List only suggestions that are safe to auto-fix without changing behavior:
- {file}:{line} — {description} — FIX: {exact change to make}
If no issues found in a category, write "None".
Subagent D: Test Coverage
Prompt to pass:
You are a test coverage reviewer for the F0 React component library.
Load the `f0-unit-testing` skill from `vendor/skills/f0-unit-testing/SKILL.md`.
Your goal is NOT to check if tests pass — the CI already ran them.
Your goal is to check if the tests cover the new or changed behavior introduced in this diff.
For each changed component or hook, read both the source file and its `__tests__/` file(s).
Then answer these questions:
### Existence checks
1. Does a `.test.tsx` file exist for every changed component? (never `.spec.ts`)
2. Is `zeroRender` used instead of `render` from `@testing-library/react`?
### Behavioral coverage checks
3. For every new prop added: is there at least one test that exercises it?
4. For every new conditional branch (if/else, ternary, switch case): is there a test
that covers the truthy and falsy paths?
5. For every new callback prop (e.g., `onSelect`, `onChange`): is there a test that
verifies it is called with the correct arguments?
6. For every new error/warning thrown or logged: is there a test that verifies it?
7. For every new state transition (e.g., loading → loaded, collapsed → expanded):
is there a test that verifies the before and after states?
8. If a prop or behavior was removed: are the tests that relied on it cleaned up
(no dead tests asserting removed behavior)?
For each issue found, classify it as:
- BLOCKING: new behavior with zero test coverage, or missing test file entirely
- SUGGESTION: partial coverage (e.g., happy path tested but error path missing)
Changed files:
{changed file list}
Diff:
{full diff}
Return a structured report with this exact format:
## Test Coverage Report
### Blocking Issues
- {file}:{line} — {description}
### Suggestions
- {file}:{line} — {description}
If no issues found in a category, write "None".
Note: do not include Auto-fixable Suggestions — test writing requires human judgment.
Step 3 — Collect Results and Auto-fix
Once all four subagents return their reports:
Apply auto-fixes: For every item listed under
Auto-fixable Suggestionsacross all three reports, apply the fix directly. Keep a count.Re-run lint after auto-fixes (if any fixes were applied):
pnpm lint-fix && pnpm lintCompile the summary (see format below).
Step 4 — Present Summary
Always present the summary, even when everything passes. Format:
Quality Gate Results
────────────────────────────────────────────
Phase 1 (Commands)
Format: PASS | FAIL
TypeScript: PASS | FAIL
Lint: PASS ({n} auto-fixed) | FAIL
Tests: PASS ({n} passed) | FAIL ({failing test names})
Phase 2 (Reviews)
Code Review: PASS | {n} blocking, {n} suggestions ({n} auto-fixed)
A11y: PASS | {n} blocking, {n} suggestions ({n} auto-fixed)
Storybook: PASS | {n} blocking, {n} suggestions ({n} auto-fixed)
Tests: PASS | {n} blocking, {n} suggestions
────────────────────────────────────────────
If there are blocking issues, list them after the table:
Blocking issues requiring your attention:
[Code Review]
src/components/F0Example/F0Example.tsx:42
→ Direct Radix import — must use @/ui/ wrapper
[A11y]
src/components/F0Example/F0Example.tsx:78
→ Icon-only button missing sr-only label — WCAG 1.1.1
[Storybook]
src/components/F0Example/__stories__/F0Example.stories.tsx
→ New `variant` prop added but no story demonstrates it
[Tests]
src/components/F0Example/__tests__/F0Example.test.tsx
→ New `onSelect` callback prop has no test verifying it is called
If everything passes (or only auto-fixed suggestions remain), say:
Quality gate passed. All checks green.
Quick Reference
| Phase | Tool | Command / Agent |
|---|---|---|
| Format | Bash | pnpm format && pnpm format:check |
| TypeScript | Bash | pnpm tsc --noEmit |
| Lint | Bash | pnpm lint-fix && pnpm lint |
| Tests | Bash | pnpm vitest:ci |
| Code Review | Task (general) | Loads f0-code-review |
| A11y | Task (general) | Loads a11y |
| Storybook | Task (general) | Loads f0-storybook-stories + f0-storybook-testing |
| Test Coverage | Task (general) | Loads f0-unit-testing |