Core Concepts
Every command — scan, static, bundle — and every MCP tool ultimately
produces the same two shapes: a Report containing Issue[]. Understanding
these up front makes every other page easier to read.
Report
Section titled “Report”One Report is written per scan run, to
.local/frontend-qa/runs/<runId>/report.json:
interface Report { schemaVersion: '1'; runId: string; startedAt: string; finishedAt: string; target: { url: string; framework?: string }; config: unknown; routesScanned: string[]; issues: Issue[]; artifacts: { screenshots: string[]; har?: string };}schemaVersion exists so future changes to the shape are detectable by
consumers (including the MCP server) rather than silently breaking them.
Every finding — from every collector, and from static/bundle too — is
normalized to the same Issue shape:
interface Issue { id: string; collector: string; category: string; severity: Severity; route: string; title: string; description: string; evidence: EvidenceType; source?: { url?: string; line?: number; column?: number }; element?: { selector?: string; snippet?: string }; metadata: Record<string, unknown>; suggestedNextStep?: string;}One shape means a console error, a failed network request, a missing alt
attribute, and an oversized JS chunk all show up the same way — sortable,
filterable, and readable by the same MCP tools regardless of which collector
found them.
Evidence types
Section titled “Evidence types”Every issue is tagged with how it was found, so a guess never reads like a fact:
| Evidence type | Meaning |
|---|---|
Measured |
A concrete value was captured (a real HTTP status, a timing number) |
Observed |
Something was directly witnessed happening (a console error firing) |
StaticAnalysis |
Found by parsing source code, not by running it |
Heuristic |
A pattern-based signal that’s often but not always meaningful |
Inferred |
A conclusion drawn from indirect signals |
Unavailable |
The check couldn’t run (e.g. a required flag was off) |
This is why frontend-qa never presents a heuristic as a certainty — see
Non-negotiable principles for why this
matters to the project.
Severity
Section titled “Severity”type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';Used both for display and for --fail-on — the CLI exits non-zero when any
issue is at or above the threshold you set (default high).
Collectors and engines
Section titled “Collectors and engines”An Issue’s collector field identifies what produced it — browser.console,
browser.network, browser.a11y, static.alt-text, bundle.chunk-size, and
so on. Runtime collectors (console, network, screenshot, timing) always run
during a scan; accessibility, performance, and visual diffing are opt-in via
flags because they’re slower and not every project wants them on every run.
See Basic Usage for the full list.