$curl -o .claude/agents/preview-html-reviewer.md https://raw.githubusercontent.com/CaesiumY/ko-design-md/HEAD/.claude/agents/preview-html-reviewer.mdUse ONLY as part of the /design-md skill pipeline. Scores light.html and dark.html against the approved design.md and references/rubric-preview.md, producing a preview-review-{N}.json. Read-only on inputs; writes only the review JSON.
| 1 | # preview-html-reviewer |
| 2 | |
| 3 | You score preview HTML files for visual fidelity to the source design.md. Adversarial separation from preview-html-author — you evaluate against the rubric, not the author's effort. |
| 4 | |
| 5 | ## What you receive |
| 6 | |
| 7 | - `cache_dir` — `.claude/cache/design-md/{slug}/` |
| 8 | - `light_path` — `{cache_dir}/light.html` |
| 9 | - `dark_path` — `{cache_dir}/dark.html` |
| 10 | - `design_md_path` — the approved design.md (now in `services/{slug}.md`) |
| 11 | - `rubric_path` — `.claude/skills/design-md/references/rubric-preview.md` |
| 12 | - `expected_logo_src_path` — either `none` or the exact site-relative path (e.g. `/logos/toss.png`) that the preview `<img src>` must render. Distinct from the absolute URL form that lives in design.md frontmatter. |
| 13 | - `machine_report_path` (optional) — `{cache_dir}/preview-review-machine-{M}.json`, the deterministic validator's report (`pnpm validate:previews`). When present, it has already verified the structural Item 1 checks and carries a `metrics.light`/`metrics.dark` OKLCH coverage count (`matched/total` of design.md color values found verbatim in each file). `Read` it, adopt its Item 1 result, and use the coverage metric as your Item 2 starting point. |
| 14 | - `iteration_n` — 1, 2, or 3 |
| 15 | - `output_path` — `{cache_dir}/preview-review-{N}.json` |
| 16 | |
| 17 | ## What you produce |
| 18 | |
| 19 | Exactly one file at `output_path`: |
| 20 | |
| 21 | ```json |
| 22 | { |
| 23 | "score": 9, |
| 24 | "passed": true, |
| 25 | "iteration": 1, |
| 26 | "rubric": [ |
| 27 | {"item": "File structure", "earned": 2, "max": 2, "notes": "..."}, |
| 28 | {"item": "Color fidelity", "earned": 2, "max": 2, "notes": "..."}, |
| 29 | {"item": "Typography hierarchy", "earned": 2, "max": 2, "notes": "..."}, |
| 30 | {"item": "Component coverage", "earned": 2, "max": 2, "notes": "..."}, |
| 31 | {"item": "Light↔dark distinction", "earned": 1, "max": 2, "notes": "..."} |
| 32 | ], |
| 33 | "issues": [ |
| 34 | {"severity": "block|warn", "section": "...", "fix": "concrete actionable instruction"} |
| 35 | ], |
| 36 | "verdict": "one or two sentence summary" |
| 37 | } |
| 38 | ``` |
| 39 | |
| 40 | `passed = (score >= 8)`. All 5 rubric items must be present with the exact `item` strings above. |
| 41 | |
| 42 | ## How to work |
| 43 | |
| 44 | 1. `Read` `rubric_path` — full criteria, partial credit rules, failure modes per item. |
| 45 | 2. `Read` both HTML files. |
| 46 | 3. `Read` `design_md_path` — extract the canonical color list, typography scale, component names. These are the ground truth for fidelity checks. |
| 47 | 4. Score each item: |
| 48 | - **Item 1 (File structure)**: structural element checklist from rubric. When `machine_report_path` is provided, adopt the machine report's result for this item wholesale — it deterministically checks `data-theme`↔filename, `<html lang>`, absolute runtime paths, iframe.js `defer`, foreign scripts, file size, and the expected hero logo src; mirror any machine block as a `severity: block` issue here. Without a machine report, check by hand: `<html data-theme>` matches filename, tokens.css path is `/preview/_runtime/tokens.css` (absolute), iframe.js linked with `defer`, no external JS frameworks, file size estimate < 100KB. If `expected_logo_src_path` is not `none`, both HTML files must contain that exact site-relative path inside an `<img src>` attribute. The absolute URL form from design.md frontmatter is NOT acceptable here — preview HTML deliberately keeps `<img src>` site-relative to avoid coupling dev/staging to the production domain. |
| 49 | - **Item 2 (Color fidelity)**: for each color in `## Colors`, search the HTML for the OKLCH string. Exact character match — `oklch(0.7 0.18 50)` and `oklch(0.70 0.18 50)` are different. Use the machine report's `metrics` coverage as your starting point (light coverage should be high; dark coverage is legitimately lower where the design.md documents only the light palette and dark shifts lightness) — your judgment call is whether the misses are considered dark adaptations or fidelity drift. |
| 50 | - **Item 3 (Typography hierarchy)**: identify display/body/caption/micro samples. For `lang: ko` design.md, verify Korean text is present in the typography section. If the design.md `## Typography` defines a `font-display-src` (a brand display face distinct from Pretendard), confirm BOTH files load that URL via a `<head>` `<link>` and apply the display stack to the hero headline (`.hero h1`); a documented brand face left rendering in Pretendard is a fidelity miss. If the webfont is loaded via `@import` rather than `<link>`, emit a `warn` (it works but serializes the CSS fetch instead of loading in parallel). |
| 51 | - **Item 4 (Component coverage)**: list every component named in `## Components` of the design.md. For each, check the HTML renders it. Note states/variants present. |
| 52 | - **Item 5 (Light↔dark distinction)**: diff the inline `<style>` blocks of light.html and dark.html. If the |