# Report Spec (WE-R) ## Overview Assembles all collected data into a single Markdown file optimised for Claude to read. Findings are phrased in a pre-interpreted tone: each issue explains what it means and what to do about it, not just that a value is absent or wrong. ## Responsibilities - Accept LighthouseResult[] and DomData as inputs - Produce a single Markdown string - Apply severity grading to Lighthouse scores - Categorise findings as Critical (must fix) / Warning (should fix) / Info - Write the report in the defined section order - Deduplicate findings that appear in both desktop and mobile audits Delegates to: nothing (pure function, no I/O) ## Dependencies Read [lighthouse.md](lighthouse.md) for `LighthouseResult` shape. Read [dom-analysis.md](dom-analysis.md) for `DomData` shape. ## Data Model ### Score grading | Score | Grade | Colour label | |---|---|---| | 90–100 | A | Good | | 75–89 | B | Needs improvement | | 50–74 | C | Poor | | 0–49 | F | Critical | ### Severity rules - **Critical (must fix):** Lighthouse finding with `score === 0` in any preset - **Warning (should fix):** Lighthouse finding with `0 < score < 0.9` in any preset; or DOM issues (missing description, heading skips, missing alt) - **Info:** Minor or informational items ## Requirements **WE-R-1:** The report begins with a level-1 heading: `# Website Evaluation: {hostname}`. Hostname is extracted from the URL (no scheme, no path). **WE-R-2:** A generation line follows: `_Generated: {ISO date} · Audited: {full URL}_` **WE-R-3:** Section order (all sections always present, even if empty): 1. Lighthouse Scores (desktop + mobile tables) 2. Core Web Vitals (desktop + mobile tables) 3. Critical Issues 4. Warnings 5. Info 6. Page Structure 7. Screenshots reference 8. Raw Data reference **WE-R-4:** Lighthouse score tables have columns: Category | Desktop | Mobile | Desktop Grade | Mobile Grade. Why: Side-by-side makes it easy to spot mobile regressions. **WE-R-5:** Core Web Vitals tables have columns: Metric | Desktop | Mobile | Status. Status is the worst of the two presets for that metric (e.g., if desktop is "good" but mobile is "needs-improvement", show "needs-improvement"). **WE-R-6:** Each finding is rendered as a Markdown checkbox list item: ``` - [ ] **{title}** — {pre-interpreted explanation with fix guidance} ``` The title comes from `audit.title`. The explanation is built from `audit.description` (stripped of Markdown links) plus any savings estimate. **WE-R-7:** If the same audit ID appears as a finding in both desktop and mobile results, it appears once in the report (not duplicated). The severity is the worst across both presets. **WE-R-8:** DOM issues (missing meta description, heading skips, missing alt text, missing noopener) are included in the Warnings section with pre-interpreted phrasing. Exact phrasing: - Missing meta description: "Meta description missing — search engines will auto-generate one, often poorly. Add a 155-char summary." - Heading skip: "Heading hierarchy skips {skip} — this confuses screen readers and weakens document structure." - Missing alt: "{n} image(s) lack alt text — WCAG 1.1.1 violation (Level A); screen readers will skip them entirely." - Missing noopener: "{n} link(s) open in a new tab without `rel=\"noopener\"` — the opened page can access `window.opener`." **WE-R-9:** Page Structure section lists: - Title (value + char count + assessment: "good" if 30–65 chars, "too short" / "too long" otherwise) - Meta description (value or "missing") - Canonical (value or "not set") - Heading counts per level (e.g., "H1×1, H2×4, H3×7") - Images (total, missing alt count) - Links (total, external, new-tab-no-opener count) - Structured data (types detected or "none") - Open Graph (present/absent) **WE-R-10:** Screenshots section contains Markdown image references: ```markdown ![Desktop view](screenshots/desktop.png) ![Mobile view](screenshots/mobile.png) ``` **WE-R-11:** If all Critical, Warning, and Info sections are empty, replace each with `_None detected._`. **WE-R-12:** The function signature is: ```js assembleReport(url, lighthouseResults, domData) → string ``` It is a pure function — no file I/O, no side effects. ## Scenarios ### Scenario: Score table format **Given:** Desktop performance 87, mobile performance 62 **When:** Report is assembled **Then:** Score table shows desktop 87 (B), mobile 62 (C) in the same row ### Scenario: Finding deduplication **Given:** `meta-description` audit fails (score 0) in both desktop and mobile results **When:** Report is assembled **Then:** The meta-description finding appears exactly once in Critical Issues ### Scenario: Empty sections **Given:** All Lighthouse audits pass (score ≥ 0.9), no DOM issues **When:** Report is assembled **Then:** Critical Issues, Warnings, and Info sections each contain `_None detected._` ### Scenario: Title assessment **Given:** Page title is 14 chars ("Example Domain") **When:** Page Structure section is built **Then:** Title line shows `"Example Domain" (14 chars — too short)`