Safety Results Over Time: test evidence
Requirement-traced qualification evidence for the safety.viz results-over-time module.
Requirement matrix ↗ — the reviewed source specification these tests trace to.
- Scope
- 25 coverage rows44 distinct requirement IDs
- Tests executed
- 130 automated checks24 browser · 106 unit
- Result
- pass all passing10 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- Test run
- Actions run #29181741704
Scope & approach
Traceability for the results-over-time module (a Chart.js reimplementation of RhoInc/safety-results-over-time, under #27), per the convention in CONTRIBUTING.md. Requirement IDs (SROT-*) come from the reviewed 58-row matrix at safety.agent docs/requirements/safety-results-over-time.md, whose Evidence Type column routes rows (unit → Vitest, browser → Playwright).
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/results-over-time.spec.js)
15 requirement rows · 15 tests
| Requirement | Source matrix rows | Issue | Tests & evidence |
|---|---|---|---|
| SROT-FUNC-001/SROT-FUNC-002 | SROT-FUNC-001, SROT-FUNC-002 | #27 |
|
| SROT-FUNC-003/SROT-REG-001 | SROT-FUNC-003, SROT-REG-001 | #27 |
|
| SROT-DATA-002 | SROT-DATA-002 | #27 |
|
| SROT-FUNC-008/SROT-REG-009 | SROT-FUNC-008, SROT-REG-009 | #27 |
|
| SROT-REG-002/SROT-REG-003 | SROT-REG-002, SROT-REG-003 | #27 |
|
| SROT-REG-010/SROT-REG-012 | SROT-REG-010, SROT-REG-012 | #27 |
|
| SROT-REG-011 | SROT-REG-011 | #27 |
|
| SROT-REG-014/SROT-REG-015 | SROT-REG-014, SROT-REG-015 | #27 |
|
| SROT-FUNC-004/SROT-REG-016/SROT-REG-017 | SROT-FUNC-004, SROT-REG-016, SROT-REG-017 | #27 |
|
| SROT-FUNC-005/SROT-REG-020 | SROT-FUNC-005, SROT-REG-020 | #27 |
|
| SROT-REG-018 | SROT-REG-018 | #27 |
|
| SROT-FUNC-006/SROT-REG-004/SROT-REG-005 | SROT-FUNC-006, SROT-REG-004, SROT-REG-005 | #27 |
|
| SROT-FUNC-007/SROT-REG-006/SROT-REG-007 | SROT-FUNC-007, SROT-REG-006, SROT-REG-007 | #27 |
|
| SROT-REG-023/SROT-REG-024 | SROT-REG-023, SROT-REG-024 | #27 |
|
| SROT-API | — (see legacy-API note) | #27 |
|
Unit evidence (Vitest — tests/unit/results-over-time/)
10 requirement rows · 25 tests
| Requirement | Source matrix rows | Issue | Tests & evidence |
|---|---|---|---|
| SROT-CFG-004/005/006/007/009 | SROT-CFG-004, SROT-CFG-005, SROT-CFG-007, SROT-CFG-009 | #27 |
|
| SROT-CFG-008/012/013/014/015 | SROT-CFG-008, SROT-CFG-012, SROT-CFG-013, SROT-CFG-014 | #27 |
|
| SROT-CFG-017/018/019, SROT-DATA-003 | SROT-CFG-017, SROT-CFG-019, SROT-DATA-003 | #27 |
|
| SROT-DATA-001/002 | SROT-DATA-001, SROT-DATA-002 | #27 |
|
| SROT-CFG-005/006 | SROT-CFG-005, SROT-CFG-006 | #27 |
|
| SROT-REG-010/012 | SROT-REG-010, SROT-REG-012 | #27 |
|
| SROT-REG-002/010 (grouping-change regression) | SROT-REG-002, SROT-REG-010 | #27 |
|
| SROT-REG-021 | SROT-REG-021 | #27 |
|
| SROT-REG-015/016/017/020 | SROT-REG-015, SROT-REG-016, SROT-REG-017, SROT-REG-020 | #27 |
|
| SROT-REG-003/011/014/015 | SROT-REG-003, SROT-REG-011, SROT-REG-014, SROT-REG-015 | #27 |
|
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.

SROT DATA 002 invalid data note 
SROT FUNC 001 control panel 
SROT FUNC 003 participant count 
SROT FUNC 004 y limits 
SROT FUNC 006 visits without data 
SROT FUNC 007 unscheduled visits 
SROT FUNC 008 box plots 
SROT REG 002 grouped box plots 
SROT REG 010 outliers 
SROT REG 018 log scale
Source-matrix routing status (58 rows)
Covered: 44 of 58 rows (the browser and unit tables above). The remaining 14 rows are descoped, honestly, for the reasons below.
- Violin plots —
SROT-FUNC-009,SROT-REG-008(2 rows): descoped. Violin (kernel-density) marks are off by default in the original renderer and add little over the box-and-whisker distribution summary; Chart.js has no violin primitive, so they would be a large custom-SVG effort for a non-default feature. Box-and-whisker + outliers deliver the population distribution. - Legacy Webcharts / CAT / API rows —
SROT-CFG-001,SROT-CFG-002,SROT-API-001,SROT-REG-022,SROT-REG-025(5 rows): descoped. These describe the legacy Webcharts configuration object, thesafetyResultsOverTime()Webcharts-chart factory, and CAT-specific settings workflows. The module ships the shared nextgen lifecycle API instead (SROT-API, module scheme) with explicit settings, matching the histogram precedent; the reviewed matrix flags these rowsneeds-jeremy-review. - Normal-range mappings —
SROT-CFG-010,SROT-CFG-011(2 rows): descoped.normal_col_low/normal_col_highexist in the original settings but the results-over-time view does not draw a normal range (unlike the histogram), so these mappings are not part of this renderer's contract. missingValues—SROT-CFG-016(1 row): descoped. Missing/non-numeric results are removed by numeric cleaning with a reported count (SROT-DATA-002); the explicit missing-value token list is not reproduced.- Enrolled/randomized denominator —
SROT-REG-013(1 row): adapted. The participant note reports "shown of total (%)" for the current measure; the enrolled/randomized population denominator is not present in the trimmed example data contract, so it is not shown. - Log-axis tick overlap —
SROT-REG-019(1 row): delegated. Log-scale tick selection and label spacing are handled by Chart.js's logarithmic scale; the module does not add a custom de-duplication pass, so this is not separately asserted. - Group-variable validation —
SROT-REG-026,SROT-REG-027(2 rows): descoped. Filters whose column is absent from the data are dropped with a warning, but group options are taken from settings as-is (missing-column dropping and duplicate-label de-duplication for the Group-by control are not implemented). A follow-up could extend the filter validation to groups.
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/results-over-time/evidence.jsonScreenshot 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.