Design document for Requirement #2 · obot.roadmap · depends on #1 design
STATUS: Signed off 2026-07-04 · drafted 2026-07-02, ported to obot.roadmap 2026-07-03, updated 2026-07-04 (qcthat alignment) · drafted by Claude Code using Fable 5, reviewed by @jwildfireThe histogram is the pilot for the renderer-migration recipe. Its inputs are already in place:
docs/requirements/safety-histogram.md (125 source-backed rows).dev @ a3ff9f7 with build + Playwright 10/10 evidence
(slice ① — done 2026-07-02). The implementation is a single ~680-line
src/index.js plus a browser test page.This document designs the two remaining slices: ② extract the pilot into a safety.viz module, and ③ bind it as an htmlwidget in gsm.safety.
The monolithic pilot decomposes into the module layout defined in 1_design.html. Mapping of existing pilot code:
| safety.viz file | From the pilot (src/index.js) |
|---|---|
src/histogram.js | Public entry + the lifecycle API (init, setData, setSettings, render, resize, destroy) — kept verbatim in shape (SH-API-001). |
src/histogram/checkInputs.js | New — validates data/settings against the JSON schema (below); replaces ad-hoc guards. |
src/histogram/configure.js | Settings defaults + merge (measure/value/participant column mapping, filters, bin config). |
src/histogram/structureData.js | Filtering, missing/non-numeric removal + counts (SH-DATA-002), binning algorithms (SH-CTRL-006), grouping (SH-CHART-004). |
src/histogram/getPlugins.js | Tooltip/footnote behavior (SH-CHART-002), normal-range overlay region (SH-CTRL-004), p-value annotations + disclaimer (SH-CHART-005), bar-selection highlighting. |
src/histogram/getScales.js | X-axis domain/limits (SH-CTRL-005), tick modes — bin centers vs boundaries (SH-CTRL-007). |
src/histogram/listing.js | Linked participant listing: pagination, search, sort, CSV export (SH-LIST-001..004). |
tests/e2e/histogram.spec.js | Port of the pilot's 10 Playwright specs, renamed to requirement-ID keys, then extended to the remaining browser-evidence matrix rows. |
Controls (measure select, filters, normal-range checkbox, axis inputs, binning, group-by) stay part of the module — the legacy tool's control panel is in scope for feature parity (SH-CTRL-001..007), rendered by the module into its container.
| Field | Required | Source rows |
|---|---|---|
measure, result | yes | SH-DATA-001 — one record per measurement, long format. |
participant, unit, normalLow, normalHigh | optional | SH-DATA-003; normal-range behavior degrades gracefully when absent (SH-FUNC-004C). |
filters[], details[] | optional | SH-DATA-003 — configured filter and listing columns. |
Missing/non-numeric results are removed with a reported count (console + page note), per SH-DATA-002 — the pilot's behavior is the accepted resolution of the matrix's open invalid-data question.
unit
rows (binning, data prep, config merge) → Vitest; browser rows → Playwright.(#N) style (see 1_design.html, Traceability).docs/.Widget_Histogram in gsm.safetyinst/htmlwidgets/Widget_Histogram.js +
Widget_Histogram.yaml, with the safety.viz bundle vendored at
inst/htmlwidgets/lib/safety.viz-{version}/ (see
1_design.html, Distribution).Widget_Histogram() R function maps a long lab-results data.frame
(subjid-keyed, per gsm column conventions) plus a settings list onto the
module's JSON contract, then calls the lifecycle API from the widget's
renderValue/resize hooks.| Item | Disposition |
|---|---|
| Invalid-data handling (matrix open item) | Resolved: adopt the pilot's behavior — drop with reported count and visible note (SH-DATA-002). |
| p-value annotations (blocked rows) | Deferred: ship the pilot's approximate screening annotations with the validation disclaimer (as merged); exact-method rows stay blocked pending method + fixtures and become a follow-up requirement if pursued. |
| Visual regression + accessibility hardening | Out of scope for the pilot (flagged in the pilot's coverage matrix); explicit follow-up gates before the renderer batch. |
| Legacy Webcharts API | Not preserved (SH-API-002) — already replaced by the lifecycle API. |
| qcthat integration for JS test evidence | Interim: test names reference GitHub issues now (qcthat's (#N) style) to future-proof the evidence; full qcthat-compatible reporting is backlog Requirement #15. |