// pagespeed-audit findings document v1 — generated from /docs/findings.schema.json. Do not edit by hand. // Join runs on run.url + run.date + run.strategy; join findings across runs on findings[].slug, never on findings[].id. export interface AdjudicationCounts { confirmed: number; false_positive: number; deprioritized: number; platform_blocked: number; readout: number; } export interface RunInfo { run_id: string; generated_at: string; skill_version: string; site: string; url: string; final_url?: string | null; strategy: "mobile" | "desktop"; date: string; lighthouse_version?: string | null; data_sources?: string[]; field_available: boolean; binding_constraint: string; missing_from_psi?: string | null; adjudication_counts: AdjudicationCounts; /** Public naming layer applied to this run's report, e.g. 'noise-silence/four-verdicts@1' (Real=confirmed, Wrong=false_positive, Trivial=deprioritized, Locked=platform_blocked) */ framework?: string; /** Noise & Silence framework: (false_positive + deprioritized + platform_blocked) / adjudicated flags, readout excluded */ noise_rate?: number | null; } export interface MetricRow { metric: "LCP" | "INP" | "CLS" | "FCP" | "TTFB"; source: "field_page" | "field_origin" | "lab"; value: number | null; unit?: "ms" | ""; category?: string | null; good?: number | null; poor?: number | null; } export interface HistoryRow { date: string; metric: "LCP" | "INP" | "CLS" | "FCP" | "TTFB"; p75: number | null; unit?: "ms" | ""; } export interface QuickFix { lang?: string; code?: string; note?: string; } export interface Adjudication { audit_id: string; disposition: "confirmed" | "false_positive" | "deprioritized" | "platform_blocked" | "readout"; claim: string; evidence: string; finding_ref?: string | null; metric_savings?: Record | null; has_quick_fix?: boolean; fix?: QuickFix | null; } export interface Coupling { finding: string; kind: "invalidates" | "invalidated_by" | "depends_on" | "required_by" | "co-requisite" | "interacts"; note?: string | null; /** true = generated from the other finding's declaration, not authored here */ mirrored?: boolean; } export interface FindingFix { lang?: string; before?: string | null; after?: string; note?: string | null; } export interface Impact { narrative: string; arithmetic?: string | null; metric?: "LCP" | "INP" | "CLS" | "FCP" | "TTFB" | null; unit?: "ms" | "" | null; min?: number | null; max?: number | null; direction?: "decrease" | "increase" | null; confidence?: "HIGH" | "MEDIUM-HIGH" | "MEDIUM" | "LOW" | null; } export interface Finding { /** Positional in-report anchor, re-assigned every run (F1, F2, …) and the target of adjudications[].finding_ref. NOT stable across runs — never join on it. Use slug for that. */ id: string; /** Stable cross-run identifier for the PROBLEM CLASS, not the wording: the same underlying problem on the same site produces the same slug in every future audit, even when title, prose, severity or measured numbers change. Never encodes run-specific data (no values, dates, run numbers, ordering, Lighthouse version). Unique within a run; a class that legitimately recurs is disambiguated with a stable discriminator derived from the resource itself, e.g. 'render-blocking-css:fonts.googleapis.com' — never a positional counter. Join findings across runs on run.url (or run.final_url) + findings[].slug. Authoring vocabulary and the fallback rule live in SKILL.md. */ slug: string; title: string; severity: "CRITICAL" | "HIGH" | "MEDIUM" | "LOW"; confidence: "HIGH" | "MEDIUM-HIGH" | "MEDIUM" | "LOW"; effort?: string | null; tags?: string[]; evidence?: string; /** What the defect was VERIFIED to affect, in the words of what was tested: 'origin-wide (verified on / /pricing /blog)' or 'this route only (tested / only)'. Never an inference from a single route. */ scope?: string | null; /** Human-readable falsification note. When the graded arrays below are present this is their flattened rendering ('Measured: … | Reasoned (inference): … | Verify before shipping: …'), so a v1 consumer that only reads this field keeps working. */ falsification?: string | null; /** Claims the audit OBSERVED — header, byte count, snippet, response. Optional; added additively to @1. */ falsification_measured?: string[] | null; /** Claims the audit INFERRED from those observations. Presenting an inference as a confirmed check overstates the evidence grade, so the two are carried apart. Optional; added additively to @1. */ falsification_reasoned?: string[] | null; /** The concrete test that settles a reasoned inference. REQUIRED (validate_findings) whenever falsification_reasoned is non-empty on a finding that ships a fix. */ verify_before_shipping?: string | null; /** Interactions with other findings in this run: one finding's fix changing a precondition another rests on, a prerequisite, or a co-requisite. Mirrored onto the other finding by the renderer and re-checked for symmetry by validate_findings — an interaction stated on only one side is an error. Optional; added additively to @1. */ coupling?: Coupling[] | null; chain?: string | null; fix?: FindingFix | null; impact: Impact; sequencing?: string | null; /** Noise & Silence: true = platform-owned / outside operator control. A locked finding carries NO fix; the renderer shows the redirect instead, and validate_findings rejects a locked finding that has a fix. */ locked?: boolean | null; /** For a locked finding: the controllable equivalent (merchant-side lever) or an explicit stop-trying note shown in place of a fix. */ redirect?: string | null; } export interface Deliverable { title: string; lang?: string; code: string; } export interface DoneWellItem { item: string; evidence?: string | null; } export interface PlanItem { bucket: "today" | "sprint" | "architectural"; position: number; item: string; } /** Machine-readable twin of the audit report. Long-form arrays (metrics, history, adjudications, findings, plan) map 1:1 onto SQL tables; join runs on run.url + run.date + run.strategy, join flags across runs on adjudications[].audit_id (stable Lighthouse IDs), and join findings across runs on findings[].slug (stable problem-class ID; findings[].id is positional and re-assigned every run). */ export interface FindingsDocument { schema: "pagespeed-audit/findings@1"; run: RunInfo; metrics: MetricRow[]; history?: HistoryRow[]; adjudications: Adjudication[]; findings: Finding[]; deliverables?: Deliverable[]; done_well?: DoneWellItem[]; plan?: PlanItem[]; }