Safety Outlier Explorer: test evidence

Requirement-traced qualification evidence for the safety.viz outlier-explorer module.

Scope
24 coverage rows62 distinct requirement IDs
Tests executed
124 automated checks22 browser · 102 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 outlier-explorer module (a Chart.js reimplementation of RhoInc/safety-outlier-explorer matching its behavior, under #24), per the convention in CONTRIBUTING.md. Two requirement-ID schemes appear:

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

13 requirement rows · 13 tests

RequirementSource matrix rowsIssueTests & evidence
SOE-CTRL-001SOE-FUNC-001, SOE-FUNC-002, SOE-FUNC-004, SOE-FUNC-005, SOE-FUNC-006, SOE-FUNC-007#24
  • pass SOE-FUNC-001/SOE-FUNC-002/SOE-FUNC-004/SOE-FUNC-005/SOE-FUNC-006/SOE-FUNC-007: renders the full control panel (#24)
Evidence screenshot SOE-FUNC-001-control-panel.pngEvidence screenshot SOE-FUNC-007-normal-range-band.png
SOE-COUNT-003SOE-FUNC-003, SOE-REG-001, SOE-REG-002#24
  • pass SOE-FUNC-003/SOE-REG-001/SOE-REG-002: participant note reports N and % and updates on filter (#24)
SOE-DATA-037SOE-REG-037, SOE-REG-038#24
  • pass SOE-REG-037/SOE-REG-038: missing and non-numeric results are dropped with a reported count and note (#24)
Evidence screenshot SOE-REG-037-invalid-data-note.png
SOE-SELECT-010SOE-FUNC-010, SOE-FUNC-012, SOE-FUNC-013, SOE-REG-013, SOE-REG-014, SOE-REG-016, SOE-REG-022, SOE-REG-023#24
  • pass SOE-FUNC-010/SOE-FUNC-012/SOE-REG-013/SOE-REG-014/SOE-REG-016: clicking a point highlights the participant and opens a linked listing (#24)
Evidence screenshot SOE-FUNC-010-participant-detail.png
SOE-SELECT-020SOE-FUNC-010, SOE-REG-020#24
  • pass SOE-FUNC-010/SOE-REG-020: clicking the background clears the selection and listing (#24)
Evidence screenshot SOE-FUNC-010-participant-detail.png
SOE-NORM-007SOE-FUNC-007, SOE-REG-025, SOE-REG-026, SOE-REG-027#24
  • pass SOE-FUNC-007/SOE-REG-025/SOE-REG-026/SOE-REG-027: normal-range methods drive the band and conditional inputs (#24)
Evidence screenshot SOE-FUNC-007-normal-range-band.png
SOE-YAXIS-005SOE-FUNC-005, SOE-FUNC-006, SOE-REG-004, SOE-REG-005, SOE-REG-006#24
  • pass SOE-FUNC-005/SOE-FUNC-006/SOE-REG-004/SOE-REG-005/SOE-REG-006: y-axis limits redraw, normalize, and reset (#24)
SOE-GROUP-049SOE-REG-048, SOE-REG-049, SOE-REG-050#24
  • pass SOE-REG-048/SOE-REG-049/SOE-REG-050: grouping colors the marks and renders a legend (#24)
Evidence screenshot SOE-REG-049-color-by-group.png
SOE-XAXIS-004SOE-FUNC-004, SOE-REG-003#24
  • pass SOE-FUNC-004/SOE-REG-003: the x-axis toggle switches between the visit and study-day axes (#24)
SOE-TIP-011SOE-REG-011#24
  • pass SOE-REG-011: point tooltips list participant, result, and time (#24)
SOE-EVENT-003SOE-API-003#24
  • pass SOE-API-003: participantsSelected fires on select and clear (#24)
SOE-FILT-051SOE-REG-051, SOE-REG-052, SOE-REG-053#24
  • pass SOE-REG-051/SOE-REG-052/SOE-REG-053: a filter with a start value initializes filtered and offers no All option (#24)
SOE-API-001— (see legacy-API note)#24
  • pass SOE-API-001: lifecycle API supports init, setData, setSettings, render, resize, and destroy (#24)

Unit evidence (Vitest — tests/unit/outlier-explorer/)

11 requirement rows · 26 tests

RequirementSource matrix rowsIssueTests & evidence
SOE-CFG-004/005/006/013/014SOE-CFG-004, SOE-CFG-005, SOE-CFG-006, SOE-CFG-013, SOE-CFG-014#24

configure.test.js

  • pass outlier-explorer configure SOE-CFG-004: filter specs normalize strings and objects and preserve a start value (#24)
  • pass outlier-explorer configure SOE-CFG-005: details default to time, id, result, normal limits, and unit when unset (#24)
  • pass outlier-explorer configure SOE-CFG-006/013/014: tooltip_cols normalize and mark attributes merge over defaults (#24)
  • pass outlier-explorer getPlugins SOE-CFG-006/SOE-REG-012: pointTooltip appends configured tooltip_cols when present (#24)
SOE-CFG-007/008/009 (defaults)SOE-CFG-007, SOE-CFG-008, SOE-CFG-009#24

configure.test.js

  • pass outlier-explorer configure SOE-FUNC-007/SOE-CFG-007..009: normal-range method defaults to LLN-ULN with sd and quantile defaults (#24)
  • pass outlier-explorer structureData SOE-FUNC-007/SOE-CFG-007: Standard Deviation normal range uses mean +/- k*sd (#24)
  • pass outlier-explorer structureData SOE-FUNC-007/SOE-CFG-008: Quantiles normal range uses the configured quantiles (#24)
Evidence screenshot SOE-FUNC-007-normal-range-band.png
SOE-FUNC-004/SOE-REG-048SOE-FUNC-004, SOE-REG-048#24

configure.test.js

  • pass outlier-explorer configure SOE-FUNC-004: time_cols default to a derived Measurement axis and normalize ordinal specs (#24)
  • pass outlier-explorer configure SOE-REG-048: groups always offer a leading None option and honor group_by (#24)
  • pass outlier-explorer structureData SOE-FUNC-004: assignSequence derives a 1-based per-participant measurement index (#24)
SOE-REG-037/038, SOE-REG-029/031SOE-REG-037, SOE-REG-038, SOE-REG-029, SOE-REG-031#24

structureData.test.js

  • pass outlier-explorer structureData SOE-REG-029/SOE-REG-031: measureLabel appends the unit when present (#24)
  • pass outlier-explorer structureData SOE-REG-037/SOE-REG-038: cleanData drops missing and non-numeric results with a count (#24)
Evidence screenshot SOE-REG-037-invalid-data-note.png
SOE-FUNC-004/SOE-REG-028 (axis)SOE-FUNC-004, SOE-REG-028#24

structureData.test.js

  • pass outlier-explorer configure SOE-FUNC-004: time_cols default to a derived Measurement axis and normalize ordinal specs (#24)
  • pass outlier-explorer getScales SOE-REG-028: buildXScale rotates ordinal visit ticks and keeps linear ticks upright (#24)
  • pass outlier-explorer structureData SOE-FUNC-004: assignSequence derives a 1-based per-participant measurement index (#24)
  • pass outlier-explorer structureData SOE-REG-028: orderedCategories sorts ordinal visits by their order column (#24)
SOE-FUNC-007/SOE-CFG-007/008 (stats)SOE-FUNC-007, SOE-CFG-007, SOE-CFG-008, SOE-REG-025#24

structureData.test.js

  • pass outlier-explorer configure SOE-FUNC-007/SOE-CFG-007..009: normal-range method defaults to LLN-ULN with sd and quantile defaults (#24)
  • pass outlier-explorer structureData SOE-FUNC-007: countInliers counts observations inside the band (#24)
  • pass outlier-explorer structureData SOE-FUNC-007/SOE-CFG-007: Standard Deviation normal range uses mean +/- k*sd (#24)
  • pass outlier-explorer structureData SOE-FUNC-007/SOE-CFG-008: Quantiles normal range uses the configured quantiles (#24)
  • pass outlier-explorer structureData SOE-FUNC-007/SOE-REG-025: LLN-ULN normal range is the median of the limit columns; None is null (#24)
Evidence screenshot SOE-FUNC-007-normal-range-band.png
SOE-FUNC-005/006, SOE-REG-004/033SOE-FUNC-005, SOE-FUNC-006, SOE-REG-004, SOE-REG-033#24

getScales.test.js

  • pass outlier-explorer getScales SOE-FUNC-005: resolveYDomain honors user lower/upper and falls back to default (#24)
  • pass outlier-explorer getScales SOE-FUNC-005/SOE-REG-004: normalizeYDomain swaps inverted limits in place (#24)
  • pass outlier-explorer getScales SOE-FUNC-005/SOE-REG-034: default y-domain pads the measure extent so points are not clipped (#24)
  • pass outlier-explorer getScales SOE-REG-033: axisStep snaps ~1/15 of the range to a power of ten (#24)
SOE-REG-028 (x-scale)SOE-REG-028#24

getScales.test.js

  • pass outlier-explorer getScales SOE-REG-028: buildXScale rotates ordinal visit ticks and keeps linear ticks upright (#24)
  • pass outlier-explorer structureData SOE-REG-028: orderedCategories sorts ordinal visits by their order column (#24)
SOE-REG-011/049, SOE-CFG-006SOE-REG-011, SOE-REG-049, SOE-CFG-006#24

getPlugins.test.js

  • pass outlier-explorer configure SOE-CFG-006/013/014: tooltip_cols normalize and mark attributes merge over defaults (#24)
  • pass outlier-explorer getPlugins SOE-CFG-006/SOE-REG-012: pointTooltip appends configured tooltip_cols when present (#24)
  • pass outlier-explorer getPlugins SOE-REG-011: pointTooltip lists participant, result, and time (#24)
  • pass outlier-explorer getPlugins SOE-REG-049: groupColorScale maps distinct group values to palette colors and cycles (#24)
Evidence screenshot SOE-REG-049-color-by-group.png
SOE-DATA-001/003 (schema)SOE-DATA-001, SOE-DATA-003#24

checkInputs.test.js

  • pass outlier-explorer checkInputs SOE-DATA-001: missing required measure/value columns throw a naming error (#24)
  • pass outlier-explorer checkInputs SOE-DATA-001: valid long-format data with the required columns passes (#24)
  • pass outlier-explorer checkInputs SOE-DATA-003: an empty settings object initializes from the defaults (#24)
SOE-API-001 (module export)#24

export.test.js

  • pass outlier-explorer module export SOE-API-001: the public collection exposes the outlierExplorer factory (#24)

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

The matrix carries 84 rows; this module implements the core product surface — roughly 50 rows, evidenced by the tests above — and descopes the remaining exotic, legacy, or data-unsupported rows honestly.

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/outlier-explorer/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.