---
name: "pr_visual_evidence"
description: "Build visual evidence for a pull request: run the app on the base branch and the change branch against the same seeded data, capture before and after screenshots at desktop and mobile sizes with changed regions boxed and labeled, record a short captioned demo for multi-step flows, redact real data before capture, check the pack against GitHub size limits, and embed the pack in the PR description so a reviewer can verify the change without checking out the branch. Use when a PR changes UI, layout, or a multi-step flow, when a reviewer asks for screenshots, or when setting up a PR template with an evidence section."
---

# Purpose

A reviewer should be able to verify a visual change from the pull request description alone, without checking out the branch, starting the app, or guessing which part of a screenshot changed. This skill produces one evidence pack: paired before and after captures on identical data and viewports, annotated after shots, an optional short clip for a flow, a redaction pass, a size report, and the Markdown that embeds it all.

Screenshots and video belong in the same workflow. Splitting them into separate habits is how a PR ends up with stills for one route, a clip for another, and no common data or viewport between them.

# Workflow

## 1. Freeze the comparison

- Name the base branch and the head branch, the routes in scope, and the exact claim each capture has to prove. One claim per pair, written in plain words, for example: the Save button moved into the header and nothing else on the page moved.
- Seed both servers with the same demo data from the same seed script. Never capture the base on one account and the head on another, and never capture against a real customer account.
- Fix the environment for both sides: same browser and version, same OS or container, same viewports, same device pixel ratio of 1, same window size, animations disabled or reduced motion on. Playwright documents that rendering varies by OS, browser, and headless mode, so a mixed pair proves nothing.
- Use desktop 1280 by 800 and mobile 390 by 844 unless the project already has a viewport set. Record the set in the pack notes.

## 2. Capture pairs

- Preferred route, Playwright: run `python3 scripts/capture_pairs.py --base-url http://127.0.0.1:3000 --head-url http://127.0.0.1:3001 --routes routes.json --out pack/` from the skill folder. It visits each route on both servers, runs the same optional steps on both, and writes `name-desktop-before.png`, `name-desktop-after.png`, `name-mobile-before.png`, `name-mobile-after.png`, plus a starting `manifest.json`.
- A routes file is a JSON list. Each entry has a `name`, a `path`, and optional `steps` with `click`, `fill`, or `wait_ms`. Keep steps short and identical for both sides. If a step needs real credentials, stop and reseed instead.
- Manual route: start the base branch, capture the route at both viewports, then start the head branch on the same data and repeat in the same order with the same file names. Do not crop one side tighter than the other.
- Capture the viewport by default. Use a full page capture only when the change is below the fold, and say so in the caption, because full page shots hide scroll position.
- If the change also needs an automated guard, add Playwright `toHaveScreenshot()` in the test suite as a regression check. That is a separate job from the PR pack: the suite keeps a baseline in the repo, the pack shows a human the before and after.

## 3. Annotate and pair

- Box only what changed on the after shot. One to three boxes per image, each with a short label that names the change, not the element type. "New Save button in header" beats "button".
- Build the annotated after shot and the side by side pair with the bundled tool. Coordinates are pixels on the after image:

```
cat > boxes.json << 'JSON'
[{"x": 300, "y": 200, "w": 200, "h": 60, "label": "new save button"}]
JSON
python3 scripts/pr_evidence.py annotate --before pack/settings-desktop-before.png --after pack/settings-desktop-after.png --boxes boxes.json --out-pair pack/settings-desktop-pair.png
```

- Check the pair at full size. If a reader has to hunt for the difference, the box or the caption is wrong, not the reader.
- Keep the unannotated after shot in the pack too. The annotated version argues the point, the clean version lets a reviewer disagree.

## 4. Record a clip only for a flow

- Record a clip when the change is a sequence: a multi-step form, a drag, a state change, an animation, or an error and recovery path. A static layout change gets stills, not a clip.
- Keep one flow per clip, start from a named state, narrate the steps in the caption with seconds, for example: watch the error appear at 0:04 after an empty submit, then clear at 0:09 after typing.
- Export MP4 with H.264 when a reviewer needs to scrub or hear sound. Use a short GIF only for a silent loop. Convert and shrink a GIF with the FFmpeg palette command in `references/checklists.md`.
- Caption the clip in the PR text under the embed. Do not rely on burned in text alone, because it cannot be searched or read by a screen reader.

## 5. Redact before anyone sees the pack

- First control is upstream: seeded demo data, a demo account, and a clean browser profile with no real tabs, bookmarks, or notifications in frame.
- Second control is the exported file: cover anything real that still slipped in with a solid, fully opaque black box, then save a flattened copy with no edit history and no EXIF. Blur, mosaic, and translucent marker are not redaction for secrets, names, emails, tokens, keys, card details, or account ids. They obscure pixels, they do not remove them.
- Apply boxes and flatten with the bundled tool, then reopen the exported file and check the edges at full size:

```
cat > redact.json << 'JSON'
[{"x": 15, "y": 15, "w": 260, "h": 25}]
JSON
python3 scripts/pr_evidence.py redact --image pack/settings-desktop-after.png --boxes redact.json --out pack/settings-desktop-after-redacted.png
```

- Run the text scan and the by eye check in `references/checklists.md`. The scan covers file names, captions, and text files. It does not read pixels inside images, so it never replaces the visual check:

```
python3 scripts/pr_evidence.py scan pack/
```

- If a frame is mostly real data, do not redact it into shape. Reseed and recapture. Also remember GitHub Docs warns that uploads to public repositories can be viewed without authentication, so treat every attached file as public unless the repository is private.

## 6. Check the size budget

- Run the budget check and fix every failure before embedding:

```
python3 scripts/pr_evidence.py budget pack/ --max-total 10485760
```

- Hard limits from GitHub Docs: 10 MB per image or GIF, 10 MB per video on a free plan and 100 MB on a paid plan, 25 MB per other file. The working pack budget, each still under 1 MB and the whole pack under 10 MB, is a team choice in `references/checklists.md`, with the fix order for oversize files.
- Attach files to the PR itself so they live with the review record. Do not link a chat upload or a personal drive file as the evidence of record. With GitHub CLI, `gh pr create --attach ./pack/settings-desktop-pair.png` and the edit and comment forms accept the same flag, with alt text after a `#` in the attach argument.

## 7. Embed the pack

- Generate the description snippet from the manifest, fill in the captions and notes, then paste it into the PR description:

```
python3 scripts/pr_evidence.py markdown pack/manifest.json --out pack/pr-snippet.md
```

- The snippet uses a Before and After table with `<img width="420">` so GitHub does not render bare screenshots at full width stacked down the page, plus alt text that states the finding for each image.
- Put the strongest pair first, at the top of the evidence section. Fold extra routes and extra viewports into a `<details>` block below it so the description stays readable.
- State, in one line above the pairs, the base branch, the head branch, the seed, the browser, and the viewports. A pair with no provenance is an opinion.

# Output Contract

Deliver all of the following, or say plainly which item is missing and why:

1. An evidence pack folder with paired before and after PNGs at desktop and mobile for each route in scope, an annotated after shot per pair, and the clean after shot.
2. For any multi-step flow, one short clip per flow with a written caption that names what to watch for and when.
3. A `manifest.json` listing each pair and clip with title, file names, and caption, plus notes naming branches, seed, browser, and viewports.
4. A budget report from the bundled tool showing no hard limit failures, and a scan report with every flag resolved or explicitly confirmed as seeded demo data.
5. A `pr-snippet.md` ready to paste into the PR description, with alt text on every image and the checklist line filled in honestly.

# Operating Rules

1. Same data, same route, same steps, same viewport, same browser on both sides. Any difference besides the code change invalidates the pair. Recapture, do not explain it away.
2. Never publish a capture that contains real personal data, credentials, tokens, or customer records. Reseed first, redact second, and if neither works, leave the capture out and describe the change in words.
3. Redact with solid opaque boxes on a flattened export only. Never call a blurred or highlighted image redacted.
4. Never invent a limit, a viewport standard, or a tool behavior. GitHub limits and Playwright behavior in this skill trace to GitHub Docs and Playwright Docs listed in `references/checklists.md` and the source notes kept with the pack.
5. Keep the pack small enough to review. If evidence needs more than about six pairs, the PR is probably too large. Say so and suggest splitting the PR instead of building a bigger pack.
6. Do not commit evidence images into the repository by default. Attach them to the PR. Commit a capture only when it becomes a maintained visual regression baseline, in the snapshot folder the test tool owns.
7. A screenshot shows what rendered, not that the behavior is correct. Pair visual evidence with the test result or the manual steps that produced the state in the shot.
