safety.viz documentation site

Design document for Requirement #21 · obot.roadmap · supersedes the examples-site deferral in the #1 design · interim artifact for #15

STATUS: Signed off 2026-07-08 · drafted 2026-07-08, updated same day (dual-purpose screenshot baselines; dev/main branch model — review Q&A) · drafted by Claude Code using Fable 5, reviewed by @jwildfire

Context

Requirement #21 (filed 2026-07-08) makes documentation the delivery bar for the renderer migration: a GitHub Pages site for safety.viz with three pillars per renderer — a live example-gallery demo, a test-evidence page (requirements → tests → screenshots), and an API reference — plus the process rule that a renderer is not done, and its migration requirement not Released, until all three are published.

Inputs already in place: the merged library scaffold (safety.viz PR #3), the histogram module extraction (PR #4) with its requirement-keyed test suite (32 Vitest + 15 Playwright), the coverage table docs/histogram-coverage.md, the JSON data contract src/data/schema/histogram.json, and the fixture demo page the Playwright harness already uses.

Four scoping decisions were made with @jwildfire on 2026-07-08 and are treated as settled inputs to this design:

DecisionChoice
Site toolingPlain Node build script — no static-site framework; mirrors the hub's hand-rolled-HTML precedent and the library's esbuild-minimal stack.
Evidence screenshotsCommitted to the repo — reviewable in PR diffs, stable, and available offline; regeneration is deliberate (see Evidence pipeline). Dual-purpose (review Q&A, 2026-07-08): the committed screenshots are simultaneously Playwright visual-regression baselines.
API referenceGenerated from JSDoc in source — docs cannot drift from code; the JSON schema feeds the data-contract section directly.
Publish cadenceEvery merge to main, plus PR-specific preview builds published under {site}/pr/{N}/.
Branch model (added in review)Protected main + dev integration branch: feature PRs target dev; release PRs go devmain; the site builds a third tier from dev at {site}/dev/.

Architecture overview

src/ (JSDoc)          docs/<module>-coverage.md      docs/evidence/<module>/   site/ (templates,
  │ jsdoc -X                    │                      (committed json + png)     config, css)
  ▼                             ▼                              ▼                     ▼
  └────────────────────► scripts/site.mjs ◄──────────────────────────────────────────┘
                        (plain Node, no framework)
                                │ emits relative-URL static pages
                                ▼
                             _site/  ──►  gh-pages branch  ──►  https://jwildfire.github.io/safety.viz/
                                             ├── /          (deployed from main — releases)
                                             ├── /dev/      (deployed from dev — integration)
                                             └── /pr/{N}/   (deployed per open PR, removed on close)

Repo layout additions (safety.viz)

safety.viz/
├── site/
│   ├── shell.html              # shared page shell: header, nav, footer, styles
│   ├── config.json             # per-renderer metadata: title, blurb, status
│   │                           #   (available / in-migration / planned), hero evidence ID
│   └── site.css                # one stylesheet for the whole site
├── scripts/
│   ├── site.mjs                # assembles _site/ from templates + generated data
│   └── evidence.mjs            # runs the suites with JSON reporters + screenshot
│                               #   capture and (re)writes docs/evidence/<module>/
├── docs/evidence/<module>/     # committed: evidence.json + <REQ-ID>[_slug].png
├── _site/                      # build output — gitignored, never committed
└── .github/workflows/pages.yml # build → verify → publish (main + PR previews)

The site pages per renderer: index.html (gallery), <module>/index.html (live demo), <module>/evidence.html, <module>/api.html. All internal links and asset paths are relative, so the same build works at the site root and under /pr/{N}/.

Pillar 1 — Example gallery

Pillar 2 — Test evidence

Evidence pipeline (npm run evidence)

Canonical rendering environment

Pixel comparison is only stable within one rendering stack (fonts and canvas antialiasing differ across OSes), so baselines are canonical to the Playwright Linux container CI already uses. npm run evidence:update regenerates baselines inside that container (locally via Docker, or as a manually-triggered workflow that commits the refresh); a plain local npm run evidence still runs the suites and captures screenshots for eyeballing, but never writes canonical baselines. Playwright browser bumps that shift pixels are absorbed the same way — one deliberate refresh, which updates the site images in the same commit.

Freshness guard (CI)

Two layers, both in the regular CI workflow: (1) the browser suite's toHaveScreenshot assertions enforce the pixel baselines natively; (2) a step compares test IDs and pass/fail statuses against the committed evidence.json — a mismatch fails the build with "evidence stale — run npm run evidence:update and commit".

Evidence page

Generated per renderer by joining the coverage table (docs/<module>-coverage.md) with evidence.json: requirement ID → source matrix rows (linked to the safety.agent matrix) → evidencing test(s) → status chip → screenshot(s). Unrouted/manual matrix rows render in the same routing-status sections the coverage table already carries, so the page tells the whole story — covered, superseded, deferred, and pending rows alike.

Pillar 3 — API reference

Branch and release model

safety.viz adopts the gsm-style two-branch model (added in review, 2026-07-08 — already applied to the repo):

Publishing model

The single-artifact deploy-pages flow replaces the whole site on every deploy, which cannot host persistent PR previews — so Pages serves from a gh-pages branch written incrementally by pages.yml, with three tiers:

TriggerAction
push to main (release)build _site/ → sync to the gh-pages root, preserving dev/ and pr/.
push to dev (integration)build → sync to gh-pages /dev/ — the always-current integration preview.
pull_request (same-repo)build → sync to gh-pages /pr/{N}/; a sticky bot comment on the PR links the preview. Review of a renderer's site entry happens here, per the deployed-review workflow.
pull_request closedremove /pr/{N}/ from gh-pages.

The site build also runs as a check in the regular CI workflow (build must succeed, internal links and referenced screenshots must resolve), alongside the evidence freshness guard. Repo settings change: Pages source = gh-pages branch (one-time manual step).

Done-gate mechanics

Relationship to existing requirements

ItemDisposition
#1 design — "examples-site scope deferred until 2–3 modules exist"Superseded by this design (decision 2026-07-08): the site ships with the histogram as its first entry.
#15 — qcthat-compatible JS reportingInterim artifact: the evidence pages are the human-readable issue-linked qualification view; evidence.json (test ↔ requirement ↔ issue ↔ status) is designed to be trivially translatable to a qcthat matrix when #15 leaves the backlog. #15's scope is unchanged.
#2 — Safety Histogram migrationAdopts the done-gate retroactively: Released only after the histogram site entry deploys (see Done-gate mechanics).
gsm.safety#30 — Widget_HistogramSequenced after this requirement's histogram entry (agreed 2026-07-08); the widget's docs will link to the module's site pages.
Visual regression + accessibility hardeningVisual regression: now partially in scope (review Q&A 2026-07-08) — the committed evidence screenshots double as Playwright baselines, giving regression protection at every documented evidence point (not exhaustive visual coverage). Accessibility hardening remains out of scope (per the #1/#2 designs).

Candidate decomposition

Sub-issues to be filed via requirement-tasks after sign-off (all in safety.viz unless noted):

  1. Evidence pipeline — evidence.mjs, toHaveScreenshot baselines in docs/evidence/, canonical-container evidence:update flow, JSON reporters, committed histogram evidence set, CI freshness guard.
  2. API reference — JSDoc annotations on the histogram module + jsdoc -X → page generation in site.mjs.
  3. Site build — site.mjs, shell/templates/config, gallery + histogram demo + evidence page assembly, link/asset validation, CONTRIBUTING done-gate checklist.
  4. Publishing — pages.yml (main root + /dev/ tier + PR previews + close cleanup), Pages settings, preview-link bot comment.

Open questions

Sign-off: recorded on #21 (2026-07-08). The work decomposes per Candidate decomposition into safety.viz sub-issues.