Safety Delta-Delta: test evidence

Requirement-traced qualification evidence for the safety.viz delta-delta module.

Scope
30 coverage rows44 distinct requirement IDs
Tests executed
147 automated checks25 browser · 122 unit
Result
pass all passing6 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 delta-delta module (a Chart.js reimplementation of RhoInc/safety-delta-delta, matching behavior), built under #25 per the convention in CONTRIBUTING.md. Requirement IDs come from the reviewed 48-row matrix at safety.agent docs/requirements/safety-delta-delta.md, whose Evidence Type column routes rows (unit → Vitest, browser → Playwright). The renderer flattens long-format results (one row per measurement at a visit) to one point per participant: change in measure X (comparison-visit mean − baseline-visit mean) against change in measure Y.

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/delta-delta.spec.js)

16 requirement rows · 16 tests

RequirementSource matrix rowsIssueTests & evidence
SDD-FUNC-001/SDD-FUNC-002/SDD-FUNC-003SDD-FUNC-001, SDD-FUNC-002, SDD-FUNC-003#25
  • pass SDD-FUNC-001/SDD-FUNC-002/SDD-FUNC-003: renders visit, measure, filter, and display controls (#25)
Evidence screenshot SDD-FUNC-001-control-panel.pngEvidence screenshot SDD-FUNC-002-baseline-scatter.png
SDD-FUNC-002/SDD-REG-003SDD-FUNC-002, SDD-REG-003#25
  • pass SDD-FUNC-002/SDD-REG-003: defaults to the first/second measure and first/last visit, plotting one point per participant (#25)
Evidence screenshot SDD-FUNC-002-baseline-scatter.png
SDD-FUNC-004SDD-FUNC-004#25
  • pass SDD-FUNC-004: the participant-count note reports the total and percentage shown (#25)
SDD-REG-008SDD-REG-008#25
  • pass SDD-REG-008: missing/non-numeric results are dropped with a reported count and visible note (#25)
Evidence screenshot SDD-REG-008-invalid-data-note.png
SDD-REG-001SDD-REG-001#25
  • pass SDD-REG-001: changing the Y measure changes the plotted distribution (#25)
SDD-REG-002SDD-REG-002#25
  • pass SDD-REG-002: changing the comparison visit changes the plotted distribution (#25)
SDD-REG-006/SDD-REG-005SDD-REG-005, SDD-REG-006#25
  • pass SDD-REG-006/SDD-REG-005: a filter narrows the plotted points and updates the count (#25)
SDD-FUNC-005SDD-FUNC-005#25
  • pass SDD-FUNC-005: the tooltip reports the participant ID and both change values (#25)
SDD-FUNC-006/SDD-REG-011/016/018/019/020/024SDD-FUNC-006, SDD-REG-011, SDD-REG-016, SDD-REG-018, SDD-REG-019, SDD-REG-020, SDD-REG-024#25
  • pass SDD-FUNC-006/SDD-REG-011/SDD-REG-016/SDD-REG-018/SDD-REG-019/SDD-REG-020/SDD-REG-024: clicking a point opens the linked measure table (#25)
Evidence screenshot SDD-FUNC-006-measure-table.png
SDD-REG-021/022/025SDD-REG-021, SDD-REG-022, SDD-REG-025#25
  • pass SDD-REG-021/SDD-REG-022/SDD-REG-025: change values are signed and colored, with axis tags (#25)
SDD-REG-012/SDD-REG-013SDD-REG-012, SDD-REG-013#25
  • pass SDD-REG-012/SDD-REG-013: the clicked point is highlighted and clicking another redraws the table (#25)
Evidence screenshot SDD-REG-012-point-selected.png
SDD-REG-014SDD-REG-014#25
  • pass SDD-REG-014: changing a control removes the detail table (#25)
SDD-REG-026SDD-REG-026#25
  • pass SDD-REG-026: the regression line toggles with an equation and R² note (#25)
Evidence screenshot SDD-REG-026-regression-line.png
SDD-REG-007SDD-REG-007#25
  • pass SDD-REG-007: a filter for a non-existent variable logs a console warning (#25)
SDD-REG-010SDD-REG-010#25
  • pass SDD-REG-010: a non-existent required column errors into the container and tears the chart down (#25)
SDD-API-001 (module scheme)— (see legacy-API note)#25
  • pass SDD-API-001: lifecycle API supports init, setData, setSettings, render, resize, and destroy (#25)

Unit evidence (Vitest — tests/unit/delta-delta/)

14 requirement rows · 30 tests

RequirementSource matrix rowsIssueTests & evidence
SDD-CFG-004..008SDD-CFG-004, SDD-CFG-005, SDD-CFG-006, SDD-CFG-007, SDD-CFG-008#25

configure.test.js

  • pass delta-delta configure SDD-CFG-004/005/006/007/008: default column mappings match the data contract (#25)
  • pass delta-delta structureData SDD-CFG-004: getMeasures returns the sorted distinct measures (#25)
  • pass delta-delta structureData SDD-CFG-008: getVisits orders visits by the numeric visit column (#25)
SDD-CFG-009..013SDD-CFG-009, SDD-CFG-010, SDD-CFG-011, SDD-CFG-012, SDD-CFG-013#25

configure.test.js

  • pass delta-delta configure SDD-CFG-009/010/011/012/013: measure and visit selections default to data-driven (#25)
  • pass delta-delta configure SDD-CFG-012/013: baseline/comparison visit scalars are coerced to arrays (#25)
SDD-CFG-014/SDD-CFG-015SDD-CFG-014, SDD-CFG-015#25

configure.test.js

  • pass delta-delta configure SDD-CFG-014: arrayify and fieldSpec normalize helpers behave (#25)
  • pass delta-delta configure SDD-CFG-014: filters accept strings and objects, normalized to { value_col, label } (#25)
  • pass delta-delta configure SDD-CFG-015: details default to Participant ID plus the filter columns (#25)
  • pass delta-delta configure SDD-CFG-015: supplied details extend the defaults without duplicating (#25)
SDD-REG-003 (delta math)SDD-REG-003#25

structureData.test.js

  • pass delta-delta getScales SDD-REG-003: axis labels describe the change in the selected measure (#25)
  • pass delta-delta structureData SDD-REG-003: plotted deltas are comparison minus baseline per measure (#25)
SDD-FUNC-001/SDD-REG-004 (average)SDD-FUNC-001, SDD-REG-004#25

structureData.test.js

  • pass delta-delta structureData SDD-FUNC-001/SDD-REG-004: multiple baseline visits are averaged (#25)
Evidence screenshot SDD-FUNC-001-control-panel.png
SDD-REG-008 (removal)SDD-REG-008#25

structureData.test.js

  • pass delta-delta structureData SDD-REG-008: missing/non-numeric results are removed with a count (#25)
Evidence screenshot SDD-REG-008-invalid-data-note.png
SDD-REG-019/022/023/025SDD-REG-019, SDD-REG-022, SDD-REG-023, SDD-REG-025#25

structureData.test.js

  • pass delta-delta getScales SDD-REG-022: a missing change value renders as NA (#25)
  • pass delta-delta structureData SDD-REG-019/025: measure rows sort X-measure, Y-measure, then alphabetical, tagged by axis (#25)
  • pass delta-delta structureData SDD-REG-022: a participant missing the comparison result yields a non-plottable NaN delta (#25)
  • pass delta-delta structureData SDD-REG-023: sparkline records are visit-ordered and role-colored (#25)
SDD-REG-006 (filters)SDD-REG-006#25

structureData.test.js

  • pass delta-delta structureData SDD-REG-006: filters keep only the participants whose metadata matches (#25)
SDD-REG-021/022 (format/color)SDD-REG-021, SDD-REG-022#25

getScales.test.js

  • pass delta-delta getScales SDD-REG-021: change values format with an explicit sign and two decimals (#25)
  • pass delta-delta getScales SDD-REG-021/022: change values are colored by sign, gray for zero/NA (#25)
  • pass delta-delta getScales SDD-REG-022: a missing change value renders as NA (#25)
  • pass delta-delta structureData SDD-REG-022: a participant missing the comparison result yields a non-plottable NaN delta (#25)
SDD-REG-015 (axis padding)SDD-REG-015#25

getScales.test.js

  • pass delta-delta getScales SDD-REG-015: an empty or flat domain falls back to a finite window (#25)
  • pass delta-delta getScales SDD-REG-015: the delta domain includes 0 and pads beyond the data extent (#25)
SDD-REG-026 (regression)SDD-REG-026#25

getPlugins.test.js

  • pass delta-delta getPlugins SDD-REG-026: linear regression matches a hand-computed non-trivial fit (#25)
  • pass delta-delta getPlugins SDD-REG-026: linear regression recovers a perfect fit (#25)
  • pass delta-delta getPlugins SDD-REG-026: regression is null without a resolvable fit (#25)
Evidence screenshot SDD-REG-026-regression-line.png
SDD-FUNC-004 (count text)SDD-FUNC-004#25

getPlugins.test.js

  • pass delta-delta getPlugins SDD-FUNC-004: participant count text reports total and percentage to one decimal (#25)
SDD-REG-012 (selection)SDD-REG-012#25

getPlugins.test.js

  • pass delta-delta getPlugins SDD-REG-012: selection borders thicken and blacken the selected point only (#25)
Evidence screenshot SDD-REG-012-point-selected.png
SDD-DATA-001/SDD-REG-010 (guard)SDD-DATA-001, SDD-REG-010#25

checkInputs.test.js

  • pass delta-delta checkInputs SDD-DATA-001: valid long-format data with the required columns passes (#25)
  • pass delta-delta checkInputs SDD-REG-010: an empty dataset reports every required column missing (#25)
  • pass delta-delta checkInputs SDD-REG-010: missing a required mapped column throws a named error (#25)

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 (48 rows)

Legacy-API note: source-matrix SDD-API-001 ("a factory to create a custom Webcharts chart object") describes the legacy Webcharts API, which the designs intentionally do not preserve. The module ships the histogram's proven lifecycle API instead — deltaDelta(element, settings) returning an instance with init/setData/setSettings/render/resize/destroy — evidenced as SDD-API-001 in the module scheme above.

Removed/merged upstream (AI review): SDD-CFG-003, SDD-CFG-016, SDD-API-002, SDD-REQ-001, and SDD-REQ-002 were dropped in the safety.agent matrix review as introductory/aggregate text or navigation artifacts, and are not counted in the 48 rows.

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/delta-delta/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.