Safety Shift Plot: test evidence

Requirement-traced qualification evidence for the safety.viz shift-plot module.

Scope
24 coverage rows34 distinct requirement IDs
Tests executed
130 automated checks22 browser · 108 unit
Result
pass all passing5 evidence screenshots
Generated
2026-07-12 05:50 UTC
Environment
linux 6.17.0-1018-azure · node v22.23.1 · playwright 1.61.1 · chromium 149.0.7827.55

Scope & approach

Traceability for the shift-plot module (#14) — the second full renderer, built on the framework proven by the histogram (#2) — per the convention in CONTRIBUTING.md. Requirement IDs are the SSP-* rows of the 39-row reviewed matrix at safety.agent docs/requirements/safety-shift-plot.md; a few module-scheme IDs (SSP-CHART-002, the module-API SSP-API-001 note) name behavior the matrix does not enumerate. Development follows red-green TDD: matrix row → failing test → minimal implementation.

Each table row traces one requirement to the automated test(s) that evidence it: the requirement ID and its source-matrix rows link back to the reviewed specification, the issue column links the implementing work, and the result column shows the recorded outcome of every matching test from the committed evidence.json with its captured screenshots. Browser evidence is captured at fixed conditions (1280×800, device scale 1) on the canonical Linux CI environment.

Browser evidence (Playwright — tests/e2e/shift-plot.spec.js)

14 requirement rows · 13 tests

RequirementSource matrix rowsIssueTests & evidence
SSP-CTRL-001/SSP-REQ-002/SSP-CTRL-002/SSP-CTRL-003SSP-CTRL-001, SSP-REQ-002, SSP-CTRL-002#14
  • pass SSP-CTRL-001/SSP-REQ-002/SSP-CTRL-002/SSP-CTRL-003: renders measure, baseline/comparison visit, and filter controls (#14)
Evidence screenshot SSP-CTRL-001-baseline-scatter.png
SSP-CHART-002#14
  • pass SSP-CHART-002: the identity line spans a domain shared by both axes (#14)
SSP-COUNT-001/SSP-REG-005SSP-COUNT-001, SSP-REG-005#14
  • pass SSP-COUNT-001/SSP-REG-005: the participant note reports shown-of-total participants (#14)
Evidence screenshot SSP-COUNT-001-participant-count.png
SSP-REG-020SSP-REG-020#14
  • pass SSP-REG-020: missing and non-numeric results are dropped with a reported count and note (#14)
Evidence screenshot SSP-REG-020-invalid-data-note.png
SSP-REG-001SSP-REG-001#14
  • pass SSP-REG-001: changing the measure re-pairs the scatter (#14)
SSP-REG-002/SSP-REG-003SSP-REG-002, SSP-REG-003#14
  • pass SSP-REG-002/SSP-REG-003: changing baseline and comparison visits swaps the axes (#14)
SSP-CTRL-003SSP-CTRL-003#14
  • pass SSP-CTRL-003: applying a filter updates the participant note (#14)
SSP-REG-006SSP-REG-006#14
  • pass SSP-REG-006: the point tooltip reports id, baseline, comparison, change, and percent change (#14)
SSP-REQ-003/SSP-REQ-006/SSP-REQ-007/SSP-REG-004/SSP-REG-012SSP-REQ-003, SSP-REQ-006, SSP-REQ-007, SSP-REG-004, SSP-REG-012#14
  • pass SSP-REQ-003/SSP-REQ-006/SSP-REQ-007/SSP-REG-004/SSP-REG-012: brushing opens the listing, boxes the selection, and de-emphasizes the rest (#14)
Evidence screenshot SSP-REQ-003-brushed-selection.png
SSP-REG-011SSP-REG-011#14
  • pass SSP-REG-011: clearing the selection resets the points and hides the listing (#14)
SSP-REG-008/SSP-REG-009/SSP-REG-010SSP-REG-008, SSP-REG-009, SSP-REG-010#14
  • pass SSP-REG-008/SSP-REG-009/SSP-REG-010: the listing searches, sorts, and exports to CSV (#14)
Evidence screenshot SSP-REG-008-linked-listing.png
SSP-API-003SSP-API-003#14
  • pass SSP-API-003: brushing dispatches participantsSelected with the selected ids (#14)
SSP-API-001 (module scheme)— (see legacy-API note)#14
  • pass SSP-API-001: lifecycle API supports init, setData, setSettings, render, resize, and destroy (#14)
SSP-REG-016/SSP-REG-018SSP-REG-016, SSP-REG-018#14
  • no record shared shell: controls left of the chart, chart above the listing (tests/e2e/site.spec.js)

Unit evidence (Vitest — tests/unit/shift-plot/)

10 requirement rows · 15 tests

RequirementSource matrix rowsIssueTests & evidence
SSP-CFG-004/005/006SSP-CFG-004, SSP-CFG-005, SSP-CFG-006#14

configure.test.js

  • pass shift-plot configure SSP-CFG-004/005: baseline/comparison visits normalize to arrays and stats fall back to mean (#14)
  • pass shift-plot configure SSP-CFG-004/005/006: default settings map the standard measure, result, visit, and id columns (#14)
  • pass shift-plot configure SSP-CFG-006: filter specs normalize strings and objects to value_col/label pairs (#14)
  • pass shift-plot structureData SSP-CFG-005: multiple comparison visits collapse with the comparison statistic (#14)
SSP-REQ-005SSP-REQ-005#14

configure.test.js

  • pass shift-plot configure SSP-REQ-005: details default to id, baseline, comparison, change, and percent change (#14)
  • pass shift-plot structureData SSP-REQ-005/SSP-REG-019: pairs baseline against comparison per participant with change and percent change (#14)
SSP-REG-020SSP-REG-020#14

structureData.test.js

  • pass shift-plot structureData SSP-REG-020: missing and non-numeric results are removed with a reported count (#14)
Evidence screenshot SSP-REG-020-invalid-data-note.png
SSP-DATA-001SSP-DATA-001#14

structureData.test.js

  • pass shift-plot checkInputs SSP-DATA-001: missing required variables throw a clear message (#14)
  • pass shift-plot checkInputs SSP-DATA-001: the JSON schema publishes the data contract with required column mappings (#14)
  • pass shift-plot structureData SSP-DATA-001: measure labels are the raw measure value (#14)
SSP-REG-013/SSP-REG-014SSP-REG-013, SSP-REG-014#14

structureData.test.js

  • pass shift-plot structureData SSP-REG-013/SSP-REG-014: visits order by visit_order_col, else alphanumerically (#14)
SSP-REQ-005/SSP-REG-019SSP-REQ-005, SSP-REG-019#14

structureData.test.js

  • pass shift-plot configure SSP-REQ-005: details default to id, baseline, comparison, change, and percent change (#14)
  • pass shift-plot structureData SSP-REQ-005/SSP-REG-019: pairs baseline against comparison per participant with change and percent change (#14)
SSP-CFG-005SSP-CFG-005#14

structureData.test.js

  • pass shift-plot structureData SSP-CFG-005: multiple comparison visits collapse with the comparison statistic (#14)
SSP-CTRL-001/SSP-CTRL-003SSP-CTRL-001, SSP-CTRL-003#14

structureData.test.js

  • pass shift-plot structureData SSP-CTRL-001: only the selected measure is paired (#14)
  • pass shift-plot structureData SSP-CTRL-003: active filters subset rows by stringified equality (#14)
Evidence screenshot SSP-CTRL-001-baseline-scatter.png
SSP-CHART-002#14

structureData.test.js

  • pass shift-plot structureData SSP-CHART-002: the shared domain spans both axes with padding (#14)
SSP-DATA-001/SSP-DATA-003SSP-DATA-001, SSP-DATA-003#14

checkInputs.test.js

  • pass shift-plot checkInputs SSP-DATA-001: missing required variables throw a clear message (#14)
  • pass shift-plot checkInputs SSP-DATA-001: the JSON schema publishes the data contract with required column mappings (#14)
  • pass shift-plot checkInputs SSP-DATA-003: valid long-format data with optional columns passes (#14)
  • pass shift-plot structureData SSP-DATA-001: measure labels are the raw measure value (#14)

Visual evidence

Every screenshot below is a committed baseline: the same PNG is the visual-regression baseline the browser suite asserts against and the evidence artifact shown here. Click any capture for the full-resolution image.

Source-matrix routing status (39 rows)

Of the 39 reviewed SSP-* rows, 32 are covered by the browser/unit evidence above and 7 are descoped with rationale below (honest routing per the histogram precedent).

Reproducing this report

The evidence set is regenerated from a full test run and committed with the code it qualifies; CI fails when they drift. To verify or rebuild it:

npm ci
npm run evidence:check   # compare a fresh run against the committed evidence
npm run evidence         # regenerate docs/evidence/shift-plot/evidence.json

Screenshot baselines are canonical to the Linux CI runner; the repository's Update evidence baselines workflow is the authoritative way to refresh them. See CONTRIBUTING.md for the traceability convention.