Skip to content

Evidence Templates

Cindy Zhang edited this page Aug 26, 2026 · 5 revisions

Reviewer evidence templates

Complementary data a reviewer produces so a human can judge fast. Not the review — this is a separate bot-attributed comment, tables only, no prose.

Gap-filler rule: skip anything CI already reports (the PR Analysis Report already posts bundle size, a11y audit, Storybook + sandbox preview links) and anything the PR description already says. Post only what is missing.


Screenshot sensor receipt — required for every frame

A screenshot is not evidence until the capture proves it is the intended render. Emit this table with every screenshot matrix; one row may cover a batch only when every value except state is identical.

Sensor Expected Observed Pass?
Build before/head SHA + server/worktree
Story exact Storybook story id
Theme astryxTheme global + rendered data-astryx-theme
Color mode colorMode global + computed root color-scheme + surface luminance class
Direction direction global + computed direction on the subject
Viewport/media CSS width×height, DPR, forced-colors, reduced-motion, pointer/hover mode
Rendered state role/name/value/ARIA/text/count that uniquely identifies the intended state
Subject geometry selector count, visible, non-zero box, intended clipping/viewport relationship
Settled render fonts loaded; expected animation state; no Storybook error screen/page error
Image output path, pixel dimensions, non-blank hash

The state sensor is the most important row. #storybook-root * or “a button exists” is not a state sensor. Assert something unique to the build and case: the error toast is persistent and has exactly one dismiss control; the selected row has aria-selected=true; the narrow card actually wraps; the theme override moved the target property.

Before/after pairs must have matching receipts for story, theme, mode, direction, viewport/media and state. Only Build may differ. If another sensor differs, the pair is not a comparison.

Fail closed:

  • unknown Storybook globals are ignored silently, so assert their rendered effect
  • a URL parameter is not evidence that the decorator applied it
  • networkidle is not readiness under Storybook dev
  • a generic DOM selector can match the previous HMR render
  • byte-identical light/dark frames require proving that identical output is expected; otherwise treat them as a sensor failure
  • a screenshot captured during an unintended transition is invalid; either wait for stable pixels or record the exact animation time/state intentionally captured

Use captureWithSensors() from ~/astryx/probe-kit/lib.cjs; it writes a .sensors.json receipt beside the PNG and throws before capture when a required expectation does not match.


Template: LAYOUT / CSS change

A layout change is never proved by one before/after at one width. Parents and grandparents change how an element renders, so the evidence has to name the containment assumptions being relied on.

1. Containment assumptions

State what the fix depends on. Each row is a claim a human can challenge.

Assumption This change relies on Verified
Parent display e.g. flex row yes/no
Which element shrinks e.g. the <button> flex child, not the inner span yes/no
Width source container-defined / children auto-size both tested?
Min-size defaults e.g. flex children default min-width: auto yes/no
Ancestor constraints any overflow, contain, grid track, or fixed height above it yes/no

The #5035 lesson: minWidth: 0 on the inner span does nothing while its parent flex child is unshrinkable. Always say which box is being constrained.

2. Render matrix

One row per case, before and after. Include at least one case where the change is visible, and say plainly when a case is unchanged.

Case Before After What changed
Baseline (short content, wide) identical / …
Long content, container-defined width
Long content, auto-sized container
Component's own layout variants (e.g. hug vs fill)
Narrow viewport (320px)
Mixed: one long child + short siblings
RTL
Text zoom 200%
Forced colors
Icon-only / label-hidden path

Drop rows that genuinely do not apply — say why, do not silently omit.

3. Probe (when the fix is incomplete)

If the change does not achieve its stated goal, add a third column showing the minimal delta that does, and name the one-line diff. That is what turns "this looks wrong" into an actionable review.


Template: API / new surface change

Added Nearest sibling precedent Matches?
propName?: Type Sibling.tsx:123 uses otherName for the same axis yes/no

Plus: prop-overlap count against the base component if it wraps one; whether the new surface is reachable from the components that motivate it (a Calendar prop the date inputs cannot forward is a gap); exports added to the public barrel.

Template: BEHAVIOR / interaction change

Path Covered by the change Covered by a test
pointer click
keyboard (Enter/Space/Escape/arrows)
IME composition
paste
AT / synthetic activation
programmatic call

Interaction fixes cannot be proved in jsdom (no popover light dismiss, no invokers) — say so, and drive real Chromium when it matters.


Always state

  • What was not verified, and why.
  • Which claims are read off source versus observed in a browser.

Clone this wiki locally