Skip to content
Back to skills

Evidence

ASecurity

Use when a PR, bug fix or UI acceptance criterion needs browser proof: records a captioned MP4, a per-step storyboard PNG, a state trace JSON and a ready-to-paste PR evidence section whose rows match the storyboard tiles 1:1. Good for keyboard/focus flows, multi-step interactions, loading states, bug before/after, or when asked for \"video evidence\", \"record the flow\", \"storyboard\" or \"screenshots for the PR\". Portable: Node + playwright-core + ffmpeg.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 3, 2026
developmentgobashnodetestinggit

Works with

  • cli

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 5 files and shows the line behind each finding

Scanned October 5, 2026

npx -y skills add ltlongtma/solo-sdlc --skill evidence --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Evidence?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Evidence
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ltlongtma-evidence/badge)](https://www.skillsdirectory.com/skills/ltlongtma-evidence)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: evidence
description: "Use when a PR, bug fix or UI acceptance criterion needs browser proof: records a captioned MP4, a per-step storyboard PNG, a state trace JSON and a ready-to-paste PR evidence section whose rows match the storyboard tiles 1:1. Good for keyboard/focus flows, multi-step interactions, loading states, bug before/after, or when asked for \"video evidence\", \"record the flow\", \"storyboard\" or \"screenshots for the PR\". Portable: Node + playwright-core + ffmpeg."
---

# Browser evidence

Three artifacts that must tell the same story, plus the PR text built from them. Default output: `docs/qa/evidence/<A-id or slug>/` (the place `qa-ui` expects; pass `outDir` to override).

| File | For | Built from |
|---|---|---|
| `<slug>.mp4` | Inline video player in the PR | Playwright `recordVideo`, trimmed to the first step |
| `<slug>.storyboard.png` | Inline image in the PR | **One screenshot per step**, taken right after that step's probe |
| `<slug>.trace.json` | Proof of claims the eye can't check | `probe()` after every step |
| `<slug>.captions.png` | Your own check | Caption bar of the MP4 sampled at 4 fps |
| `<slug>.pr.md` | Paste into the PR | Trace diff per step, one row per storyboard tile |

Static end states don't need this; a screenshot is enough.

## Rules

A time-sampled storyboard can silently drop a step (a caption with 0 video frames shows tiles 1, 2, 4 while the table says 4 steps). These rules make that impossible:

1. **Storyboard = per-step screenshots**, never evenly time-sampled video frames. (Time-sampled grids only for motion claims: scroll, drag, animation, and then in addition.)
2. **Hard assert:** steps == trace entries == storyboard tiles, numbered 1..N with no gap. The script throws otherwise.
3. **Hold >= 1000 ms per step** so every caption lands in the video.
4. **Read back `captions.png`**: every caption `1..N` must appear. Read back the storyboard: each tile shows what its caption claims.
5. **One table row per tile.** A claim the screen can't show (native file dialog in headless, a network call) is marked `trace only (<reason>)`, never implied by a frame.
6. **Captions are user-facing text:** proofread. Phrase as the user acts: "Press Tab: focus moves to the button".

## Setup (once per machine)

```bash
cd <this skill>/scripts && npm i            # playwright-core
npx playwright-core install ffmpeg           # Playwright's video encoder
which ffmpeg                                 # system ffmpeg for trim/tile (brew install ffmpeg)
```

Uses installed Google Chrome (`channel: 'chrome'`). Set `EVIDENCE_CHANNEL=chromium` after `npx playwright-core install chromium` if Chrome is absent.

## Workflow

1. **Write claims first.** One step per user action, each with the claim it proves and the state field(s) that prove it. In the sdlc pipeline, tie the slug to the acceptance id (`a3-keyboard`).
2. **Start the app** and note its URL (e.g. `http://localhost:3000`).
3. **Write a spec** in a scratch dir (not the repo), modelled on `examples/keyboard-flow.mjs`:
   - `ready`: selector scoped to the app root, so hidden markup can't match.
   - `setup`: init-script to instrument what headless can't show (see Gotchas).
   - `probe`: return only the fields the claims are about.
   - `steps`: `{ caption, claim, act?, traceOnly? }`. Real input only (`page.keyboard`, `page.mouse`); never set state via `evaluate` to fake an interaction.
4. **Run:** `node spec.mjs [outDir]`. It throws on any step/trace/tile mismatch.
5. **Verify** before citing anything:
   - Open `<slug>.storyboard.png`: N tiles, captions 1..N, each tile shows its claim.
   - Open `<slug>.captions.png`: every caption present.
   - `ffprobe -v error -show_entries format=duration:stream=width,height -of compact <slug>.mp4`.
   - Check frames for secrets / personal data before anything leaves the machine.
6. **Host the trace** (ask the user before any commit/push): commit `<slug>.trace.json` to a dedicated branch (never the PR's code branch), push, and use the pinned commit URL as `{BASE}`, e.g. `https://github.com/<org>/<repo>/blob/<sha>/docs/qa/evidence/<slug>`. Never host the MP4 this way: GitHub shows a repo-blob `.mp4` as a download link, not a player.
7. **Fill the PR** from the output directory, uploading the media with GitHub CLI >= 2.102 (needs push access to the repo):
   ```bash
   gh pr edit <n> --body-file <slug>.pr.md --attach ./<slug>.storyboard.png --attach ./<slug>.mp4
   ```
   `--attach` uploads each file to `github.com/user-attachments/assets/…` (the drag-drop store, the only host GitHub renders as a video player) and swaps the matching `./<slug>.*` reference for the uploaded URL. If you adapt the section into a repo template, keep each `![](./<slug>.mp4)` alone in its own paragraph; inside a sentence or list item it renders as a link. Size cap: 10 MB per video on free plans, 100 MB on paid. Without `gh --attach`, drag-drop the MP4 into the PR editor instead; never fall back to a blob link.
   Re-read the body (`gh pr view <n> --json body`): every video line must be a lone `https://github.com/user-attachments/assets/…` URL.
8. **Ledger (sdlc):** reference the files from `docs/qa/ledger.tsv` evidence column (e.g. `docs/qa/evidence/a3-keyboard/a3-keyboard.storyboard.png`).

## PR evidence section

`<slug>.pr.md` generates this generic section; paste it where the repo wants evidence, or adapt it to the repo's own PR template (keep the template's sections and order, fill only its screenshots/testing parts):

```markdown
## PR evidence

![Storyboard: …](./<slug>.storyboard.png)

![](./<slug>.mp4)

- State trace (JSON, read after each step): {BASE}/<slug>.trace.json

| Step | Claim | Trace result | Where to see it |
|---|---|---|---|
| 1 | … | `field: value` | frame 1, ~0.3s |
| 3 | … | `fileInputClickCount: 0 → 1` | trace only (headless has no native file dialog) |
```

If some rows are trace-only, add one line saying why those frames look identical.

## Gotchas

- **Native file dialog:** headless can't show it. In `setup`, wrap `HTMLInputElement.prototype.click` and count calls where `this.type === 'file'`; mark those rows `traceOnly`.
- **Focus ring:** probe `el.matches(':focus-visible')`, not a class name.
- **First load can be slow.** The MP4 is trimmed to the first step, so load time doesn't matter; the `ready` selector does.
- **Trace timing** comes from the wall clock; video offsets in the table are approximate (`~`). Timing claims cite the trace.
- **Navigation** removes the caption bar; the script re-applies it after each `act`.
- **Motion claims:** add mid-transition probes inside `act` and, if useful, a time-sampled grid (`ffmpeg -i <slug>.mp4 -vf "fps=12/<D>,scale=400:-1,tile=4x3" -frames:v 1 motion.png`) *in addition to* the per-step storyboard.

Files in this skill

  • SKILL.md6 KB
  • examples/keyboard-flow.mjs1.6 KB
  • scripts/evidence.mjs7.5 KB
  • scripts/package-lock.json641 B
  • scripts/package.json130 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…