claude-skills/markdown-html/skills/md-review/references/diff_rendering_canon.md
Claude 8f6734a205
feat(markdown-html): add md-review v2.10.2 — code-review markdown→2-col HTML
Adds the fourth skill to the markdown-html/ domain. The Tier-2 use case
from Shihipar's essay ("Code Review and PR Writeups"): a markdown PR
writeup with ```diff blocks and severity callouts becomes a single-file
2-column HTML review with top jump-nav, diff on the left, severity-tagged
annotation cards on the right, and a mandatory named reviewer footer.

Three stdlib tools pipeline together:

1. diff_parser.py — scans markdown for ```diff fenced blocks, parses each
   as a unified diff (--- a/file, +++ b/file, @@ -10,7 +10,8 @@,
   space/+/- body lines), assigns per-line numbers on both old (lo) and
   new (ln) sides, preserves the per-hunk @@ header context. Supports
   --infer-diff for unfenced blocks. Stdlib regex + state machine.

2. annotation_extractor.py — extracts severity callouts (GFM
   > [!BLOCKER] style) and inline markers (nit:, blocker:, etc.).
   Default convention BLOCKER/MAJOR/MINOR/NIT per Google's Code Review
   Developer Guide; overridable via --severity-convention. Attaches each
   annotation to the nearest preceding diff block by source-line index;
   unanchored annotations go to a "general comments" section. Also
   captures LGTM/approve markers separately as approvals.

3. review_html_renderer.py — emits single-file 2-col HTML. Top jump-nav
   lists every annotation with severity badge + 80-char preview + jump
   link + per-tier counts in heading. Each hunk-row is a CSS grid with
   diff on the left (per-line numbers, +/- marks, addition/deletion bg
   tints from --md-success/--md-warn via color-mix) and annotation cards
   on the right. WCAG-1.4.1-compliant severity badges (color + icon +
   aria-label + text — color is NEVER the sole signal); BLOCKER danger
   color computed by hue-rotating the design-system accent 120° toward
   red so it stays brand-coherent. Approval bar when LGTM markers
   present and no findings. Collapses to stacked on viewports < 900px.
   Mandatory --reviewer (refuses exit 3 otherwise — research-ops
   named-owner discipline). Refuses exit 4 if no hunks present (wrong
   skill → route to md-document). No Prism CDN (diff coloring conflicts
   with syntax highlighting).

Plus 3 references each citing 5-7 sources:
  - diff_rendering_canon.md — POSIX diff format + GitHub/GitLab UI +
    difftastic + SWE at Google ch. 9
  - severity_coding.md — WCAG 1.4.1 + Google review taxonomy + Don
    Norman Design of Everyday Things + NN/g color UX
  - pr_annotation_ux.md — convergent 2-col UX from GitHub / GitLab /
    Reviewable / CodeStream + SWE at Google + NN/g F-shape
1 template asset documenting the canonical 2-col review HTML shape.
/cs:md-review slash command with 4 pre-flight gates
(under-100-lines, no-onboarding, missing-reviewer, no-hunks) + pipeline
+ output digest.

Repo-level updates:
- markdown-html/.claude-plugin/plugin.json: skills array adds
  ./skills/md-review; version 2.10.1 → 2.10.2; description updated.
- .claude-plugin/marketplace.json: markdown-html-skills entry version
  and description; top-level counters 341 → 342 skills, 542 → 545 Python
  tools, 685 → 688 references, 88 → 89 slash commands; metadata.version
  2.10.1 → 2.10.2.
- Root CLAUDE.md: v2.10.2 release-notes block above v2.10.1.

Validation:
- check_plugin_json.py → OK
- sync-codex-skills.py --dry-run → 1 new symlink, documentation: 4 skills,
  total 343
- skill_description_validator.py → PASS (all 5 checks: present, length,
  third-person, trigger, action verb)
- skill_review_checklist_runner.py → 5/6 PASS (97 lines passes
  under-100-lines check; minor WARN on "user" vs "developer" terminology
  which are contextually distinct — converter operator vs review subject)
- All 3 tools pass --help and --sample
- Hard rules verified end-to-end:
    no --reviewer → exit 3 with refusal message
    no hunks → exit 4 with refusal message + md-document routing hint
    custom severity convention "critical,important,suggestion,nit" works
- Full pipeline on sample PR (2 diff blocks, 2 callouts) produces 11.3 KB
  single-file HTML with all 14 expected components (reviewer footer, PR
  title, aria-labels per WCAG 1.4.1, --md-danger computed color, modern
  color-mix tints, 2-col grid, 900px responsive collapse, both file
  paths, annotation cards, jump-nav, addition+deletion classes, Findings
  heading).

Coming in v2.10.3: md-slides — slide splitter + presenter-notes parser
+ arrow-key/space-bar nav + @media print for PDF export. Reuses
md-document's renderer scaffolding + design-system/scripts/config_loader.py.

https://claude.ai/code/session_01BK2KoQot1U7J5oSosrCQdc
2026-06-03 05:43:45 +00:00

5 KiB
Raw Permalink Blame History

Diff Rendering Canon

Why this exists: The md-review converter renders unified diffs into a two-column HTML layout. Diff rendering has 50 years of UI history; this document records the conventions it inherits from and where it diverges.

The convention

Unified-diff format (the --- a/file, +++ b/file, @@ -10,7 +10,8 @@ shape) is the lingua franca every modern code-review tool reads:

  • + (green tint): line added in the new version
  • - (red tint): line removed from the old version
  • (no tint): unchanged context line
  • @@ -old_start,old_count +new_start,new_count @@ optional_context: hunk header
  • \ No newline at end of file: meta line (rendered italic, no color)

md-review honors this exactly. The renderer assigns per-line numbers on both the old side (lo) and the new side (ln), with a clear visual separation by border.

Color discipline

WCAG 1.4.1 (Use of Color) requires that color must not be the sole signal. Our diff rendering uses:

  • Tint backgrounds (color-mix(in srgb, var(--md-success) 15%, transparent) for additions; color-mix(... --md-warn 12% ...) for deletions) — derived from the design-system palette, so they automatically follow the user's brand and stay within WCAG-validated contrast on the user's chosen bg.
  • Mark column (+ / − / ) — visible character, redundant with the color, screen-reader-skipped via aria-hidden="true".
  • Line numbers in both columns — provides spatial grounding independent of color.

Result: a deuteranopic reader (red-green color blindness) still distinguishes additions from deletions via the mark column and line-number columns.

What we deliberately don't do

  • Syntax highlighting inside diffs — Prism.js doesn't track per-line edits well, and conflicting addition/deletion backgrounds + token colors produce noisy output. Plain monospace is more legible. (Engineers reviewing diffs spend most attention on the change itself, not the surrounding language.)
  • Word-level diffing — difftastic-style intra-line highlighting is great for tiny edits but ambiguous for refactors. We render whole lines and let the reader compare them visually.
  • Inline-reply threading — md-review is a generator (markdown → HTML); it produces an artifact, not a thread. For threaded discussion, use the host platform (GitHub PR comments, GitLab discussions).
  • Split-pane (old | new) view — the convention this converter targets is the unified diff (sequential, single column), because that's what gets pasted into markdown review notes. Split-pane is a tool for active reviewing in an IDE.

Sources

1. POSIX diff -u (Single Unix Specification, c. 1990)

The format spec. The @@ -A,B +C,D @@ hunk header, the +/-/ prefixes, the --- a/ / +++ b/ file headers — all defined here. Every tool that follows reads the same shape.

2. GitHub PR diff view

The reference UI for two decades. Established:

  • Per-line line numbers on both old and new sides
  • Tinted backgrounds for additions/deletions
  • File-header sticky bar
  • Hunk separator with grey background We mirror the convention; we don't reinvent it.

3. GitLab MR diff view

Same convention as GitHub, with one small refinement: the per-hunk @@ header context (the function name after the @@) is rendered as a sticky element so the reader knows what function they're in. We render this header context in the hunk-head bar.

4. difftastic — semantic diff tool (github.com/Wilfred/difftastic)

Argues for AST-aware intra-line diffing instead of line-based. We acknowledge the case but rejected it for two reasons: (1) parsing every language is out of scope; (2) most agent-generated review markdown contains a few short hunks, where intra-line diff adds noise more than signal.

5. Software Engineering at Google — Tom Manshreck & Hyrum Wright (O'Reilly, 2020), Ch. 9 "Code Review"

The discipline around how diffs get read. Three claims used here:

  • "Reviewers spend most of their attention on a few hunks, not all of them" → jump-nav at top is essential
  • "Comments must reference a specific line" → annotations are attached to hunks, not free-floating
  • "Approval should be explicit and recorded" → LGTM markers are surfaced as the approval bar

6. Google Code Review Developer Guide (google.github.io/eng-practices/review/reviewer)

The taxonomy of severity (blocker, must-fix, nice-to-have, nit) maps to our default BLOCKER / MAJOR / MINOR / NIT convention. The phrase "nit:" specifically is from Google's recommended review vocabulary.

7. GitHub Markdown — fenced code blocks with language hints (```diff)

The convention this converter targets. Agent-generated review markdown wraps every diff in ```diff, which becomes our extraction grammar in diff_parser.py.

Applied to md-review

diff_parser.py extracts the hunks from ```diff fenced blocks. review_html_renderer.py lays them out in the standard unified-diff shape, with the addition/deletion coloring derived from the design-system palette so reviews look on-brand without losing the universal color convention.