safety.viz · release 1.11 · filed 9 October 2026

The objective and requirements for release 1.11, as filed

One objective, seven requirements and twenty-five tasks that turn the approved design for release 1.11 into work a session can run. The issues on GitHub are the record; this page shows them in one place, with the prompt that starts the build.

In three lines

The tree, in session order

  1. Objective: A demo app ready to show obot.roadmap#401 · text
  2. Requirement 1: Every tab has a colour, and the first screen says where you are obot.roadmap#402 · text
  3. Requirement 2: One status ladder obot.roadmap#403 · text
  4. Requirement 3: One R control obot.roadmap#404 · text
  5. Requirement 4: The RBQM tab reads at a glance obot.roadmap#405 · text
  6. Requirement 5: All files come in on the Data tab obot.roadmap#406 · text
  7. Requirement 6: Nothing looks broken obot.roadmap#407 · text
  8. Requirement 7: The standards this release set are written into the scaffold obot.roadmap#408 · text
RequirementYour feedback it answersMockupIf the calendar slips
1. Tabs and the first screenA module brings its own hex colour; otherwise the app picks an open one1Its phone-width task and welcome line go second
2. The status ladderEverything is exploratory; nothing is qualified; one label1, 2Not cut
3. The R controlStreamline, minimise once loaded, and reuse the biomarker pattern3The details behind the chip go third
4. The RBQM tabA subheader like the other tabs, icons, capped columns, the log folded4, 5Not cut
5. Files on the Data tabRemove data loading from the RBQM tab6Goes first; the file box then stays where it is
6. Nothing looks brokenThe defects from the review, and a test that walks the demo pathReviewNot cut
7. The standards in the scaffoldMake sure the design principles land in the scaffold, in the skills and agentsNoneIts safety.viz task follows the code; the other two come first

Decided on 9 October

Worth knowing

Starting the build

gh issue comment 401 -R jwildfire/obot.roadmap --body "Tree signed off: the seven requirements (#402 to #408) and their tasks, as filed on 2026-10-09."
Build safety.viz v1.11.0: the demo app made ready for the keynote on Wednesday 21 October. The objective is "A demo app ready to show" (jwildfire/obot.roadmap#401). Its tree is filed, and my sign-off comment is on the objective; if you cannot find one from my account, stop and ask.

Run /requirement-session 402. When a requirement closes with its proof, go on to the next in the objective's order, one requirement at a time, each as its own requirement session with its own goal:

1. Tabs and the first screen (#402)
2. The status ladder (#403)
3. The R control (#404)
4. The RBQM tab (#405)
5. Files on the Data tab (#406)

Requirement 6, nothing looks broken (#407), touches no file of the app's shell. Run it alongside from the start in its own worktree, and close its demo-path task (safety.viz#287) last, since its steps depend on the others.

Requirement 7, the standards written into the scaffold (#408), is documents and one skill. Do its hub task (obot.roadmap#409) and its session-skill task (obot.agent#361) first, before any build, so that the rest of this build runs under them, and show me the hub diff. Write its safety.viz task (safety.viz#288) last, once the code it describes has merged.

Read before building:
- The objective's Boundaries, which hold the order, the cut line and what is left out.
- The design. It is approved and it is the reference: https://jwildfire.github.io/obot.roadmap/reports/sv-v1.11-design-2026-10-09/ . Its source is in the obot.roadmap clone at reports/sv-v1.11-design-2026-10-09/index.html; the mockups are built from the app's own styles, so their markup and CSS can be read there.
- The review behind it, for the causes of each finding by file and line at the v1.10.0 tag: https://jwildfire.github.io/obot.roadmap/reports/sv-demo-design-review-2026-10-09/

What matters most:
- Extreme focus on UX and usability. Build what the mockup shows, and look at the result in a browser at 1,280 pixels wide before calling a task done. Where a mockup cannot be built as drawn, say so on the requirement and ask me; do not redesign.
- No chart and no metric is added, and nothing the app computes changes. The test that holds every RBQM metric's Results rows to desktop R's, and the network tests, pass unchanged at every merge.
- Nothing is labelled Qualified.
- Three things the design could not verify. Check each first, before building on it, and tell me if one fails: the 100-pixel column rule on the live table that gsm.viz draws (safety.viz#278); an address for each metric (safety.viz#279); whether the biomarker library's R can report its version (safety.viz#276).
- The file box leaves the RBQM tab only in the pull request that makes the Data tab take raw files (safety.viz#282). Until then it sits at the foot of the tab's Overview page.
- The status label lives in src/shell.js, so every chart's evidence changes once: refresh it through the evidence-update dispatch, never locally, and open the pull request after that commit.
- Reading gsm raw files is an interim path. Build the least that moving it to the Data tab needs.

If time runs short, cut in the objective's order: the Data tab requirement first (#406), then the phone-width task and the welcome line of the first requirement (safety.viz#271, part of safety.viz#269), then the details behind the R chip. The status label, the RBQM tab and the defects are not cut.

When the last requirement closes, open the v1.11.0 release candidate, run the review gate, build its demo page on the hub, and bring it to me by Thursday 15 October. At the end of every turn, list each task with its state.

The issues, as filed

Each opens to the text filed on 9 October. If an issue is edited later, the issue is right and this page is history.

ObjectiveA demo app ready to showthe safety.viz demo app, clear to a first-time visitor and ready for the keynote
Title as filed

Objective: A demo app ready to show — the safety.viz demo app, clear to a first-time visitor and ready for the keynote

objectivemilestone 2026-10-talk1126 words

<!-- objective-slug: demo-ready -->

Intent

@jwildfire, 2026-10-09, after reading the design review of release 1.10: "Goal is to have this next version ready for demo at keynote and good enough for people to play with, so need extreme focus on UX and usability."

Release 1.10 put everything in the app: eighteen charts, the biomarker statistics and the RBQM tab, the last two run by R in the browser. This objective adds no chart and no metric. It makes what is there read clearly to someone who has never seen it, on a shared screen at the R/Pharma keynote on Wednesday 21 October 2026 and on a stranger's laptop afterwards. The design is one published page of six desktop mockups with every change numbered (design for release 1.11), which he approved in the session of 2026-10-09 after three rounds. It rests on his feedback:

  • The R control is one slim control, the same wherever R runs, and shrinks to a chip once R is ready.
  • "All of this is 'exploratory' - nothing is qualified. All results should be confirmed." The status ladder is Qualified, Exploratory, Experimental, Prototype. Nothing is Qualified. The app carries one Exploratory label.
  • The RBQM tab has a row of names under the header like every other tab, with the metrics as its items and R started from the same control as the biomarker charts. It uses icons for metric status, a table whose columns fit their numbers, and a log that stays folded until asked for. Files are loaded on the Data tab and nowhere else.
  • Every tab has a colour. A module names its own; one that names none is given an open one, never grey.

Definition of done

End state: on the released demo app (https://jwildfire.github.io/safety.viz/demo/) at 1,280 pixels wide, the header carries one Exploratory label that opens the disclaimer and the four-rung ladder on a click; each of the five Experimental charts and the RBQM tab carries the same label with its own reason; no tab's hex is graphite; R is started from the same control on the Biomarkers tab and the RBQM tab, and that control is a chip once R is ready; the RBQM tab has a row of metrics under the header with a status icon on each, has no file box, draws the site overview with number columns no more than 100 pixels wide, and keeps its log folded until asked for; gsm raw files dropped on the Data tab are recognised there and the RBQM tab runs on them; and the four defects found in the review of release 1.10 are gone.

Proof: a browser test in safety.viz's CI walks the keynote's demo path on the deployed dev demo at 1,280 by 720 pixels with no console error, and its screenshots are in the evidence set; every metric's Results rows still match desktop R's on the RBQM demo study; the network tests still show the study's rows are sent nowhere; every requirement below is closed with its proof comment; safety.viz v1.11.0 is tagged and its demo page is on the hub.

Ships in: safety.viz v1.11.0, milestone 2026-10-talk.

Requirements

In session order:

  1. Every tab has a colour, and the first screen says where you are (#402).
  2. One status ladder, with one label for the app and one for anything below it (#403).
  3. One R control, slim, in the same place on both tabs that use R, and a chip once R is ready (#404).
  4. The RBQM tab reads at a glance: a row of metrics like every other tab, status icons, a table that fits its numbers, the log folded away (#405).
  5. All files come in on the Data tab: gsm raw files recognised there, and the file box gone from the RBQM tab (#406).
  6. Nothing looks broken: the defects found in the review, and the keynote's demo path walked by a test (#407).
  7. The standards this release set are written into the scaffold: the status ladder, the app's conventions and how a design is made (#408).

Boundaries

  • The design page is the reference. A session builds what its mockup shows; where the mockup cannot be built as drawn, the session says so on its requirement and asks, and does not redesign.
  • No chart and no metric is added, and nothing the app computes changes. R computes every number, as now. Files never leave the browser, and the footer's sentence stays true.
  • Nothing is labelled Qualified. The build refuses the word until there is a qualification record to point at.
  • Requirements 1 to 5 all change the app's page and style files (src/app/page.js, src/app/styles.js), so their sessions run one at a time, in order. Requirement 6 changes chart files and the docs site's styles and can run alongside any of them. Requirement 7 changes documents and a skill only: its hub and obot.agent tasks can be done at any time, and its safety.viz task is written last, once the code it describes has merged.
  • The file box leaves the RBQM tab in the same pull request that makes the Data tab take raw files, never before, so that a reader's own raw files work at every commit.
  • The release candidate is opened by the session of the last requirement to close, with release notes through the release-notes skill and a demo page on the hub. The target is a release candidate in front of @jwildfire by Thursday 15 October, the hub milestone's date.
  • The cut line if the calendar slips, first to go first: raw files on the Data tab (requirement 5, leaving the file box where it is); the welcome line and the phone-width navigation items of requirement 1; the details behind the R chip in requirement 3. The status label, the RBQM tab and the defects are not cut.
  • Left out, each filed as a follow-up on the backlog milestone when its requirement closes: one R shared by the Biomarkers and RBQM tabs (unproven, and it needs a release of the biomarker library); one set of treatment-arm colours across the QT, time-to-event and biomarker charts; one casing for chart names; the status label in gsm.safety's R widgets, which arrives when that package next copies the chart library.
  • Reading gsm raw files in the app is an interim path (@jwildfire, 2026-10-09: "I'm hoping to move to RAW -> SDTM -> ADaM for everything. Not in this releases though"). This objective moves that loading to the Data tab and invests no further in it.
  • The RBQM follow-ups already on the backlog (more metrics, country level, the time series chart, the report, mapping non-standard column names) are not part of this objective.

This issue was drafted by Claude Code using Opus 5.5 from @jwildfire's feedback of 2026-10-09. The tree is signed off only by his comment here.

Requirement 1Every tab has a colour, and the first screen says where you aretab colours, counts, a welcome line and the way back to the docs
Title as filed

Requirement: every tab has a colour, and the first screen says where you are — tab colours, counts, a welcome line and the way back to the docs

requirementsafetystatus: backlogmilestone 2026-10-talk875 words

Objective

#401

Business Requirement

Someone opening the demo app for the first time should know within a few seconds whose data they are looking at, how much is here, and where to go. Today two of the six tabs have a near-black hex and read as switched off, a tab's "9 of 9" has to be worked out, nothing names the study on screen, and the only way back to the docs is a link in the footer. On a shared screen at the keynote the header is what the audience reads first.

Overview

Give every tab a colour by rule: a module that names a colour for its tab gets it, and one that names none is given the first open colour from a fixed list, so no tab is ever grey (@jwildfire, 2026-10-09: "I like modules bringing their own hex color… If they don't provide one, the app should pick an open one (not default to gray)"). Then make the header and first screen say where the reader is: the Data tab names the loaded study, a tab shows one number when every chart draws, a one-line welcome on first open says whose data this is and where to load your own, the wordmark links to the docs, and the browser tab's title follows the open view. Mockup 1 of the design shows all of it (design for release 1.11, the first screen).

Repositories: safety.viz

Data Requirement

Not applicable: no data is involved.

Design

Summary, from the design page's "Tab colours and navigation" group:

  • The colour rule. A module's entry in the app's list of libraries may name a tab colour. A module that names none gets the first open colour from a fixed list (pink, then amber, then green), where open means no tab in the header uses it. Modules are taken in the order the app's build lists them, so the same module has the same colour on every load and a module added later moves nobody. Red is never given out: it means "missing" and "did not draw" everywhere in the app. When the list runs out the app goes round again with each colour mixed 40 percent toward ink. Under the rule today, Biomarkers is pink (#c67bb6) and RBQM is amber (#c78a3b); naming a colour for either is one line (src/app/libraries.js, src/app/page.js, src/app/styles.js, scripts/app-libraries.mjs).
  • The module's colour is used for its tab, its chart names and its file cards.
  • A tab's count reads "9" when every chart draws, "5 of 9" when some cannot, and "0" beside a hollow hex when none can. The Data tab names the loaded study ("Pilot study", "Your 3 files").
  • A one-line welcome on first open: whose data, how much, and where to load your own. It closes with a cross and nothing is stored.
  • The wordmark links to the docs home. The browser tab's title follows the open view ("RBQM · safety.viz demo"). The docs site and the app use one favicon, the hex mark.
  • The RBQM tab ends with the same footnote line of links every chart has.
  • Phone width: a direct link to a tab scrolls that tab into view, and tabs and chart names are at least 44 pixels tall.

Settled by @jwildfire in the session of 2026-10-09: the rule chooses the colours of Biomarkers and RBQM, pink and amber; neither is named.

Definition of done

End state: on https://jwildfire.github.io/safety.viz/dev/demo/ at 1,280 pixels wide no tab's hex is graphite (#4a525c); Biomarkers and RBQM carry the colours the rule gives them, and the biomarker chart names use the same colour as their tab; a tab shows "9", "5 of 9" or "0" with a hollow hex as described; the Data tab names the loaded study; the first open shows the one-line welcome, which closes and does not come back in that visit; the wordmark is a link to the docs home; the browser tab's title names the open view; the app and the docs site show the same favicon; the RBQM tab ends with its footnote links. At 390 pixels wide a direct link to the RBQM tab opens with that tab in view, and every tab and chart name is at least 44 pixels tall.

Proof: unit tests of the colour rule pass, covering a named colour kept, the first open colour given, the same answer on a second build, a module added at the end moving nobody, and the list running out without grey; the browser tests in tests/e2e/basic-app.spec.js cover each sentence of the end state; the demo app's requirement matrix (requirements/demo-app.md) has a row for each behaviour, with evidence refreshed by the evidence-update dispatch; a screenshot of the first screen at 1,280 pixels is in docs/evidence/basic-app/.

Ships in: safety.viz v1.11.0. Each pull request adds its line to the release notes through the release-notes skill and its checker.

Tasks

  • Give every tab a colour by rule (safety.viz#268)
  • Say where the reader is: tab counts, the study's name and a welcome line (safety.viz#269)
  • Link the wordmark to the docs, name the open view in the browser tab, and use one favicon (safety.viz#270)
  • Give the RBQM tab its footnote links, and keep the open tab in view at phone width (safety.viz#271)

This issue was drafted by Claude Code using Opus 5.5.

Requirement 2One status ladderQualified, Exploratory, Experimental, Prototype — with one label for the app and one for anything below it
Title as filed

Requirement: one status ladder — Qualified, Exploratory, Experimental, Prototype — with one label for the app and one for anything below it

requirementsafetystatus: backlogmilestone 2026-10-talk1111 words

Objective

#401

Business Requirement

Anyone who opens the app, or is shown it, should be told plainly how far to trust it, in one place and one form. @jwildfire, 2026-10-09: "All of this is 'exploratory' - nothing is qualified. All results should be confirmed. That is the overall app-level disclaimer… Maybe we should add that label to charts as well. So Qualified > Exploratory > Experimental > Prototype. Nothing in this project is qualified right now." Today status shows in four looks with three wordings, four of the six Experimental things carry no mark in the app at all, and every explanation is a hover tooltip, which a phone does not have.

Overview

Replace the three tiers (unmarked, Experimental, Prototype) with a four-rung ladder and draw it with one component everywhere. The app's header carries one label, Exploratory, which gives a one-line disclaimer on hover and the full disclaimer with the four rungs on a click. A chart or tab below the app's rung carries the same label on the corner of its card, with a one-sentence reason. The docs site uses the same four words and the same component. The banners and pills that say status today are retired. Mockups 1 and 2 of the design show the label closed and open (design for release 1.11, the labels).

Repositories: safety.viz

Data Requirement

Not applicable: no data is involved.

Design

Summary, from the design page's "Status ladder and labels" group:

  • Storage. In site/config.json each chart and each app tab takes one field, tier, with one of qualified, exploratory, experimental, prototype, and an optional tierNote holding the one-sentence reason. The default when tier is absent is exploratory, so the thirteen unmarked charts need no edit; the five Experimental charts, the RBQM tab and the one Prototype change a flag into the field. status stays as it is: it says whether a chart exists yet. A chart from another library is Exploratory unless that library's own list says otherwise by the same field.
  • The build stops with a sentence if any entry says qualified.
  • The app does not know a chart's rung today; only the docs site reads the flags. The app build hands each chart's rung and note to the page.
  • The component. A small label, ink on white: the word in a pill with no mark, picked by @jwildfire on 2026-10-09 over five marked styles. The pill's outline tells the rung: filled ink for Qualified, solid for Exploratory, dashed for Experimental, dotted grey for Prototype. Hover shows one line. A click or tap opens a panel and keeps it open; Escape, the cross or a second click closes it; it is reachable by keyboard. The panel holds the reason (for a chart), then the four rungs with the current one marked.
  • Placement. One label in the app header. One more, at most, on the open view: on the corner of the card of a chart or tab below Exploratory.
  • The docs site. Gallery cards and the title of each chart's pages use the same component and words: Exploratory, Experimental or Prototype.
  • Retired: the amber banner drawn inside the Hepatic ALT Waterfall and one view of the Hepatic Explorer, the pill inside the RBQM tab and the one in its opening sentence, the width rule that hides it, and every hover-only tooltip.
  • A chart drawn with no page around it, as the R widgets in gsm.safety draw it, must still say when it is below Exploratory. The chart draws the label itself unless its host says it is showing one.
  • The label lives in the charts' shared shell (src/shell.js), so every chart's evidence changes: plan one refresh through the evidence-update dispatch, and open the pull request after its commit.
  • Prototype is unchanged as a rule: on the docs site only, not in the app, not counted.

Settled by @jwildfire in the session of 2026-10-09:

  • A chart or tab carries its own label only when it is below the app's rung. An Exploratory chart shows none.
  • The drafted words ship, and he corrects them at the release candidate. Hover line: "Nothing in this app is qualified. Confirm every result." Panel: "Nothing here is qualified. The charts, statistics and site metrics are tested and documented, but none has been through qualification. Confirm every result in a qualified system before you rely on it." The six reasons are the sentences in the design page's table: one is from the docs site and five are drafts.

The hub requirement to remove the Experimental marking from the Time-to-Event Explorer after its external clinical review (#182) is unchanged in substance: under the ladder that chart moves up to Exploratory.

Definition of done

End state: on https://jwildfire.github.io/safety.viz/dev/demo/ the header shows one label reading Exploratory. Hovering it shows the one-line disclaimer; clicking it opens a panel with the disclaimer and the four rungs, the app's rung marked; Escape closes it; it can be reached and opened from the keyboard. Opening each of the five Experimental charts, and the RBQM tab, shows the same label on the card with that chart's reason; opening an Exploratory chart shows no second label. No chart draws a status banner inside itself in the app, and the RBQM tab carries no pill. On the docs site every gallery card and chart page title shows its rung with the same component, and its detail opens on a click. site/config.json holds tier and no experimental or prototype flag, and the build fails with a sentence when an entry says qualified. A chart below Exploratory drawn alone, with no host, still shows its label. The label and its panel hold at a 390-pixel viewport.

Proof: unit tests pass for the default rung, the refused qualified, and the component's open, close and keyboard behaviour; browser tests in tests/e2e/basic-app.spec.js and tests/e2e/site.spec.js cover the app label, each of the six labels below it with its reason, an Exploratory chart with none, and the docs pages; npm run evidence:check passes after the evidence-update dispatch has refreshed every chart; the demo app's requirement matrix has a row for each behaviour. The closing comment quotes the disclaimer and the six reasons as shipped.

Ships in: safety.viz v1.11.0. Each pull request adds its line to the release notes through the release-notes skill and its checker.

Tasks

  • Store each chart's rung as one tier field and hand it to the app (safety.viz#272)
  • Add the status label and put the app's Exploratory label in the header (safety.viz#273)
  • Show the label on a chart or tab below Exploratory, and retire the banners and pills (safety.viz#274)
  • Use the status label on the docs site's cards and page titles (safety.viz#275)

This issue was drafted by Claude Code using Opus 5.5.

Requirement 3One R controlslim, in the same place on both tabs that use R, and a chip once R is ready
Title as filed

Requirement: one R control — slim, in the same place on both tabs that use R, and a chip once R is ready

requirementsafetystatus: backlogmilestone 2026-10-talk1074 words

Objective

#401

Business Requirement

Starting R should look and read the same wherever the app does it, take almost no room, and get out of the way once R is running. Today R is started in two places that were built one release apart: a pill at the front of the row of chart names on the Biomarkers tab and a button in a box on the RBQM tab, with two wordings, two button styles, two ways of reporting a failure, and a greyed "R started" pill that never leaves. @jwildfire on the first proposal, 2026-10-09: "The R strip is a little heavy. Streamline. Minimize once it's loaded. The approach is ok though." And on the second: "I like the R workflow in Bio.viz and would like to re-use that."

Overview

Build one R control with four states (off, starting, ready, did not start) and one set of sentences, and put it in the same place on both tabs: the right end of the chart-name row, outside the scrolling list of names. Once R is ready the control shrinks to a quiet chip that opens the details on a click. This requirement delivers the control on the Biomarkers tab and makes the component and its contract ready for the RBQM tab, whose chart-name row the RBQM requirement adds next; until then the RBQM tab's existing button takes the new sentences and failure state where it stands. R still starts only when the reader asks, and the app still starts two separate copies of R: one shared copy is left out of this release. Mockup 3 of the design shows the five states (design for release 1.11, the R control).

Repositories: safety.viz

Data Requirement

Not applicable: no data is involved.

Design

Summary, from the design page's "R presentation" group:

  • One module for the control, replacing the pill built in src/app/page.js and the states in src/app/r-on-request.js, with the two button styles in src/app/styles.js made one. It is placed at the right end of the chart-name row, outside the scrolling list; on a phone it stays first in the row so that it shows without scrolling.
  • The contract a tab gives the control (src/app/libraries.js): its phase, the step it is on when starting takes long, and what its details panel holds. The Biomarkers tab gives it a phase only; the RBQM tab will give it all three.
  • Off: a few words for why, the cost in megabytes, one button. The whole sentence is on hover.
  • Starting, on the Biomarkers tab: a spinner and a count of seconds, with no list of steps, because R there was ready in 1.5 to 4.6 seconds in every run measured. A tab whose start is long names and counts the step, with segments filling.
  • Ready: a chip. A click opens R's version, the size of the download and where R runs, and whatever else the tab puts in its details.
  • Did not start: the words, in the app's alarm colour, with Try again beside them and the browser's own message one click away. The same sentence on both tabs, with one prefix and no raw error in the first line.
  • One set of sentences for both tabs (src/app/r-on-request.js, src/app/rbqm.js). The sentence inside a biomarker chart, where the statistics will go, is cut to one short line that points at the control; the app owns that sentence, so the biomarker library does not change.
  • An R that stops answering. The open task to give up on an R that stops answering (safety.viz#261) is done here: after a stated limit the control says R stopped answering, closes that R and offers to try again.
  • The message logged in the console on each R start ("Refused to get unsafe header Content-Encoding") is looked at here: removed if the app causes it, and recorded on the task if it is the R runtime's own.
  • The footer's sentence about where R is downloaded from, and the two network tests behind it, do not change.
  • Left out, and filed as a follow-up when this closes: one R shared by both tabs. It looks possible from the code, but nobody has run the biomarker statistics and gsm's packages in one R in a browser, and it needs a release of the biomarker library.

Not verified in the design: whether the biomarker library's R can be asked for its version without a release of that library. If it cannot, the chip's details on that tab show what they can and the release notes say so.

Definition of done

End state: on https://jwildfire.github.io/safety.viz/dev/demo/, a biomarker chart shows the R control at the right end of the chart-name row, outside the scrolling list of chart names. Before a press it reads its short reason, its cost and Start R. Pressing it shows a spinner and seconds, then a chip that says R is ready; clicking the chip opens R's version, download size and where it runs. No disabled "R started" pill is left in the row, and the line inside the chart is one short sentence pointing at the control. With R's host blocked, both tabs show the same "R did not start" sentence with Try again beside it and the browser's message behind a disclosure. An R that does not answer within the stated limit leaves the tab saying so, with a control that starts R again. The control holds at a 390-pixel viewport.

Proof: unit tests pass for the four states, for the contract a tab gives the control, and for the one set of sentences; browser tests in tests/e2e/basic-app.spec.js cover a start on the Biomarkers tab, the chip and its details, a blocked host on each tab, and an R that stops answering; the network tests pass unchanged; the demo app's requirement matrix has a row for each behaviour, with evidence refreshed by the evidence-update dispatch. The closing comment names the follow-up filed for one shared R and says what was found about the console message.

Ships in: safety.viz v1.11.0. Each pull request adds its line to the release notes through the release-notes skill and its checker.

Tasks

  • Build one R control and place it at the right end of the chart-name row (safety.viz#276)
  • Use one set of sentences and one failure state wherever R starts (safety.viz#277)
  • Give up on an R that stops answering in the RBQM tab (safety.viz#261), filed earlier and moved to the v1.11.0 milestone

This issue was drafted by Claude Code using Opus 5.5.

Requirement 4The RBQM tab reads at a glancea row of metrics like every other tab, status icons, a table that fits its numbers, and the log folded away
Title as filed

Requirement: the RBQM tab reads at a glance — a row of metrics like every other tab, status icons, a table that fits its numbers, and the log folded away

requirementsafetystatus: backlogmilestone 2026-10-talk1523 words

Objective

#401

Business Requirement

The RBQM tab is the centre of the keynote's demonstration, and what it does is right. How it reads is not yet. It is the one tab with no row of names under the header, so it looks like a different kind of page; it opens on a paragraph and an empty page; its run box holds a paragraph of timings and versions that outweighs the results; the site overview spreads three columns of numbers across the whole card; and each metric's state is a word in capitals. @jwildfire, 2026-10-09: "Use icons for the Metric status… Give max widths to the chart columns… the logging component is way over-emphasized. minimize unless user wants to expand it." And on the next round: "I feel like RBQM needs a subheader (like the other modules). I like the R workflow in Bio.viz and would like to re-use that." Someone watching a shared screen should see the result first and the machinery only when they ask.

Overview

Give the tab the same chart-name row every other tab has, with the metrics as its items, and start R from the same control in the same place as the biomarker charts. This is option A of the three he was shown, picked on 2026-10-09: the row holds Overview and then one item per metric, each with its status icon; the body shows one thing at a time, the site overview or one metric's two charts. One press of Start R starts R and the metrics then run by themselves, as today. Nothing the tab computes or draws changes. The run box leaves the body: progress shows in the control and as six steps ticking off in the body, the outcome is one line above the table, and the full log is behind Run details. The site overview's number and flag columns are capped at 100 pixels. Mockups 4 and 5 of the design show the tab before, during and after a run (design for release 1.11, the RBQM tab).

Repositories: safety.viz

Data Requirement

Not applicable: the tab runs on the same files as in release 1.10, and its data loading is the subject of the Data tab requirement.

Design

Summary, from the design page's "RBQM tab" group and its option A:

  • The row (src/app/page.js, src/app/libraries.js, src/app/rbqm-view.js). A tab may bring its own items for the chart-name row. RBQM's are Overview, then one per metric in scope, each with its status icon where a chart has its hex. Each item has an address, so a link can open the tab on one metric. With eight metrics at 1,280 pixels the items take about 610 pixels and the R control at most 427, of 1,216.
  • The body shows one page at a time. Overview is the site overview table. A metric's page is its scatter plot and bar chart. The buttons that choose a metric in the middle of the page today are removed, and clicking a cell of the overview opens that metric's page.
  • A metric that cannot run is in the row from the start with a grey bar; its page is R's own sentence saying what it needs and a link to the Data tab.
  • The R control is the one from the R control requirement, which closes first, at the right end of the row. Before R the body says one short line, "Site metrics need R. Start R, at the top right.", and what the loaded study supports. One press starts R and the metrics then run by themselves; a study loaded later runs by itself. While it runs the control names the step, fills six segments and counts seconds, and the body ticks off the six steps; only one step is called the long one. After the run the control is the "R ready" chip.
  • The outcome is one line above the table: "R ran 3 of 8 metrics on the Pilot study in 3.1 seconds. The other 5 need data it does not have", with a link to the Data tab and a link to Run details.
  • Run details and Run again live in the chip's panel: the steps, what R was handed, why any metric did not run, the versions of R and the gsm packages, and R's warnings. Notes about a load and notes from R, which sit in two places today, both go there.
  • Status icons: a filled green hex with a tick for ran; a grey outlined hex with a bar for did not run, grey because missing data is not an error; a turning ring for running, still when the reader asks for reduced motion; a dashed outlined hex for not started. An item's accessible name carries the metric and its state in words.
  • The site overview. Every number and flag column is at most 100 pixels wide and the table fits its content, so with three metrics adjacent numbers sit 100 pixels apart; with eight metrics the columns shrink evenly and the table fills the card with no sideways scroll. The heading counts the sites ("17 sites, 12 shown here"). The table's height is a whole number of rows. A key to the flags sits beside the table when there is room and under it when not, with one line saying a cell opens its metric.
  • The tab's status label sits at the corner of its card once the status ladder requirement has landed. Column headings at phone width are at least 10 pixels.
  • Until the Data tab requirement lands, the file box stays on the tab, at the foot of the Overview page only, in every state, and works as in release 1.10. Until then the three links that say to change the data (before R, in the outcome line, and on the page of a metric that did not run) point down to the file box, since the Data tab of today misreads raw files; the Data tab requirement repoints them.
  • Left out: a time for each step in Run details.

Not verified in the design, and checked first by the session: the 100-pixel rule on the live table that the gsm.viz library draws (it was measured on the mockup's own table with the app's styles); that per-metric addresses extend cleanly from the app's handling of an address; and how the row behaves at phone width, where it should scroll like any other tab's.

Definition of done

End state: on https://jwildfire.github.io/safety.viz/dev/demo/ at 1,280 pixels wide, the RBQM tab on the pilot study has a chart-name row reading Overview and then the eight metrics, each with a status icon, with the R control at its right end. Before R the body says its one line and what the study supports. Pressing Start R runs the metrics with no second press; the control names the step and counts, and the body ticks off six steps. After the run the control is a chip, one line above the table says what ran and how long it took, and Run details and Run again are in the chip's panel, which is closed until opened. Choosing a metric in the row, or clicking its cell in the overview, shows that metric's two charts and nothing else; a metric that did not run shows R's sentence and a link to the Data tab. Each row item has an accessible name of the form "Adverse Event Rate: ran", and a link to a metric's address opens the tab on that metric. No buttons for choosing a metric remain in the body. In the site overview no number or flag column is wider than 100 pixels, the table is narrower than its card with three metrics, and on the RBQM demo study with eight metrics the row and the table both fit with no sideways scroll; the heading counts the sites; the last visible row is whole; the key to the flags is shown. The tab holds at a 390-pixel viewport.

Proof: the browser test that holds every metric's Results rows to desktop R's on the RBQM demo study passes unchanged, which is the proof that nothing computed has changed; browser tests in tests/e2e/basic-app.spec.js cover the row and its icons on both studies, one press to results, a metric's page from the row and from a cell, a metric that did not run, a direct link to a metric, the chip's panel, and the measured column and table widths; unit tests pass; the demo app's requirement matrix has a row for each behaviour, with evidence refreshed by the evidence-update dispatch; screenshots of the tab before, during and after a run at 1,280 pixels are in docs/evidence/basic-app/.

Ships in: safety.viz v1.11.0. Each pull request adds its line to the release notes through the release-notes skill and its checker.

Tasks

  • Fit the site overview to its numbers: 100-pixel columns, a site count, whole rows and a key (safety.viz#278)
  • Give the RBQM tab a chart-name row: Overview and one item per metric, with status icons (safety.viz#279)
  • Start R from the row's control on the RBQM tab and fold the run box away (safety.viz#280)

This issue was drafted by Claude Code using Opus 5.5.

Requirement 5All files come in on the Data tabgsm raw files recognised there, and the file box gone from the RBQM tab
Title as filed

Requirement: all files come in on the Data tab — gsm raw files recognised there, and the file box gone from the RBQM tab

requirementsafetystatus: backlogmilestone 2026-10-talk1247 words

Objective

#401

Business Requirement

There should be one place in the app to load files. Today there are two: the Data tab for a study's standard files, and a file box on the RBQM tab for gsm's raw files. A reader who drops raw files where every other file goes gets the wrong answer: on release 1.10, Raw_SUBJ.csv dropped on the Data tab is read as the subject-level file, Raw_AE.csv as the adverse events file, Raw_PD.csv is not placed, and the RBQM tab then reads "0 of 8". @jwildfire, 2026-10-09: "Just remove the data loading from that component. People should load data in the data tab."

Overview

Make the Data tab recognise gsm raw files and keep them as they are, show there which RBQM metrics the loaded data supports, and take the file box off the RBQM tab, which keeps one line and a link. Almost everything needed is already shared: the app, not the RBQM tab, holds the raw files; the Data tab already draws a card for each; the RBQM demo study already arrives through the Data tab's study menu; and everything that decides what a file is lives in one module with no page code in it. The one real change in behaviour is routing: the Data tab's drop zone has to ask whether a file is raw before it reads it as a standard file. Mockup 6 of the design shows the Data tab in three states (design for release 1.11, the Data tab).

Repositories: safety.viz

Data Requirement

Required domains: gsm's nine raw domains as in release 1.10, none of them required for the tab to open: Raw_SUBJ, Raw_AE, Raw_PD, Raw_LB, Raw_STUDCOMP and Raw_SDRGCOMP for the metrics; Raw_SITE, Raw_STUDY and Raw_ENROLL for the Groups table.

Required columns: what each mapping workflow's spec names, read from the copied workflow files as now and not written into the app.

Telling a raw file from a standard one: a file is a gsm raw file only when its name starts with Raw_ or its columns match exactly one raw domain. The RBQM tab's rule today places a file by its name alone, which is safe on a tab where every file is raw and wrong on a shared drop zone: it would turn the ae.csv of the "Renamed columns" demo study into Raw_AE (confirmed in the design by running the placing function on that file). Raw files are CSV; the Data tab also takes JSON, so the CSV-only rule and its sentence move with the routing.

Availability: Confirmed. The RBQM demo study and the pilot study ship with the app; a set of three raw files for the tests is cut from the RBQM demo study.

Design

Summary, from the design page's "Data loading for RBQM on the Data tab" group:

  • Routing (src/app/page.js, src/app/rbqm-files.js). The Data tab's drop zone asks first whether a file is raw, by the rule above, and sends it to the loader that keeps a file as it is. A mixed drop clears a loaded demo study once and says so once. A raw file still wins over the table R would make from a standard file.
  • The seam (src/app/libraries.js, src/app/rbqm-view.js). A tab may say "these files are mine, and here is what the loaded data supports", so the Data tab calls two functions the RBQM tab hands it and holds no RBQM knowledge of its own. The raw path can then be removed with the tab's own code when raw files go.
  • The Data tab (src/app/data-panel.js). One card for RBQM says how many metrics the loaded data supports, with the same status icons as the tab and the reasons in R's own words, and a button that opens the tab. A raw file keeps the card it has today, with the raw domain it was read as named in its tag; no new table of raw files is built. For a study of standard files the card says which raw tables R makes from which file. Step three of the workflow reads "Open the RBQM tab" when raw files are loaded and no chart is ready. The drop zone says it takes both kinds of file.
  • The RBQM tab. The drop zone, the file box and its three lists are removed from the foot of its Overview page; the line above the table keeps its link to the Data tab.
  • The sentences that say why a metric cannot run are held word for word to desktop R by a unit test. They are drawn in a new place and not reworded.
  • Tests are the larger half of the work: the RBQM tab's unit tests mention the file box on 32 lines, and the browser tests that cover a reader's own files on that tab are rewritten for the Data tab along with the requirement rows they prove.
  • Out, and not a follow-up: a picker to read a file the other way, as raw or as standard. Reading gsm raw files is an interim path.

Settled by @jwildfire in the session of 2026-10-09: the stricter rule, as an interim path. His words: "Stricter rule is fine for now, but I honestly don't want to support that process long-term. In the future, I'm hoping to move to RAW -> SDTM -> ADaM for everything. Not in this releases though." So this requirement builds the least that moving the loading needs, and nothing that only makes sense if raw files stay.

Definition of done

End state: on https://jwildfire.github.io/safety.viz/dev/demo/, dropping Raw_SUBJ.csv, Raw_AE.csv and Raw_PD.csv on the Data tab shows a card for each of the three with the raw domain it was read as; the RBQM card reads "This data supports 4 of 8 metrics" with a status icon for each metric and R's sentence for each that cannot run; step three reads "Open the RBQM tab"; and pressing the run button on the RBQM tab runs those four metrics. Choosing the RBQM demo study shows nine raw file cards and 8 of 8; choosing the pilot study shows 3 of 8 and which raw tables R makes from which file. The "Renamed columns" demo study's ae.csv is still read as a standard file and its charts still draw. A raw file that is not CSV is refused with a sentence. The RBQM tab has no drop zone and no file box, and links to the Data tab from the line above its table. Nothing in the tab's results has changed.

Proof: a browser test drops the three raw files on the Data tab, runs the RBQM tab and holds each metric's Results rows to desktop R's on the same three files; browser tests cover the three Data tab states, the "Renamed columns" study and a mixed drop; the unit test that holds the sentences to desktop R passes unchanged; the network tests still show no row of the study is sent anywhere; the demo app's requirement matrix carries the moved rows, with evidence refreshed by the evidence-update dispatch. The closing comment says what the Data tab of release 1.10 did with the same three files, beside what it does now.

Ships in: safety.viz v1.11.0. Each pull request adds its line to the release notes through the release-notes skill and its checker.

Tasks

  • Show on the Data tab which RBQM metrics the loaded data supports (safety.viz#281)
  • Take gsm raw files on the Data tab and remove the file box from the RBQM tab (safety.viz#282)

This issue was drafted by Claude Code using Opus 5.5.

Requirement 6Nothing looks brokenthe defects found in the review of release 1.10, and the keynote's demo path walked by a test
Title as filed

Requirement: nothing looks broken — the defects found in the review of release 1.10, and the keynote's demo path walked by a test

requirementsafetystatus: backlogmilestone 2026-10-talk831 words

Objective

#401

Business Requirement

Nothing in a live demonstration should look broken, and nothing a stranger opens afterwards should either. The design review of release 1.10 found four things that are defects and not matters of taste: on the pilot study the Hepatic ALT Waterfall's two arm titles print on top of each other; at phone width the QT Explorer's table pushes the whole page sideways; at phone width three kinds of page on the docs site have content cut off where it cannot be reached; and the docs home page still describes itself as nine charts. Separately, nothing today checks that the path the keynote will walk works from end to end on the deployed site.

Overview

Fix the four defects, each in the chart or the site file that causes it, and add one browser test that walks the keynote's demo path on the deployed dev demo at the size of a shared screen. None of this touches the app's shell, so the session can run alongside the other requirements of the objective. The findings and their causes are in the review (design review of release 1.10, defects).

Repositories: safety.viz

Data Requirement

Not applicable: the fixes run on the demo studies that ship with the app.

Design

Summary, from the design page's "Defects and phone-width fixes" group:

  • Hepatic ALT Waterfall (src/hep-waterfall.js, where the panel titles are set). On the pilot study the active arm's title is every non-placebo arm joined together, too long for its panel. The titles are made to fit: shortened, wrapped or moved, with the full text still available. The chart's evidence is refreshed.
  • QT Explorer (src/qt-explorer.js). The table under the chart is 529 pixels wide in a 340-pixel space at phone width. It scrolls inside its own box.
  • The docs site at phone width (site/site.css). The site hides sideways overflow, so content wider than the screen is cut off. The open task to hold the chart API reference pages at a 390-pixel viewport (safety.viz#162) is done here, with the same fix for the QT Explorer's and the Hepatic Explorer's demo pages.
  • The docs home page's description (scripts/site.mjs) says "Nine classic clinical-safety graphics". The count is taken from the site's configuration and not typed.
  • The demo path test. One browser test, run against the deployed dev demo at 1,280 by 720 pixels, in the order the talk will use: the app opens on the pilot study; a chart is opened; the app's status label is opened and closed; an Experimental chart's label is opened; a biomarker chart starts R and shows a statistic; the RBQM tab runs on the pilot study; the RBQM demo study is chosen on the Data tab and the RBQM tab runs its eight metrics. It fails on any console error or failed request and keeps a screenshot of each step. The steps that depend on the other requirements are added as those land; the order of the path is @jwildfire's to change.
  • Two smaller items from the same list, the RBQM table's 8-pixel headings on a phone and the two steps that each claim to be the longest, are done by the RBQM tab requirement, which rewrites those lines.

Definition of done

End state: on https://jwildfire.github.io/safety.viz/dev/demo/ at 1,280 pixels wide, on the pilot study, the Hepatic ALT Waterfall's two panel titles do not overlap and each can be read. At a 390-pixel viewport the QT Explorer in the app, and on its docs page, lays out 390 pixels wide with its table scrolling inside its own box; a chart's API reference page and the Hepatic Explorer's demo page show all their content with none cut off. The docs home page's description names the number of charts the site's configuration lists. The demo path test exists and passes on the deployed dev demo.

Proof: a browser test measures the two waterfall titles' boxes on the pilot study and finds them apart; browser tests at 390 pixels hold the QT Explorer, one API reference page and the Hepatic Explorer's demo page to the viewport's width with their content reachable; a unit test holds the home page's description to the configuration's count; npm run evidence:check passes after the evidence-update dispatch; the demo path test's run on the deployed dev demo is linked in the closing comment, with its screenshots in docs/evidence/basic-app/demo-path/.

Ships in: safety.viz v1.11.0. Each pull request adds its line to the release notes through the release-notes skill and its checker.

Tasks

  • Fit the Hepatic ALT Waterfall's panel titles when an arm's name is long (safety.viz#283)
  • Let the QT Explorer's table scroll inside its own box at phone width (safety.viz#284)
  • Hold the Hepatic Explorer's demo page at a 390-pixel viewport (safety.viz#285)
  • Take the docs home page's chart count from the site's configuration (safety.viz#286)
  • Add a browser test that walks the keynote's demo path (safety.viz#287)
  • Hold the chart API reference pages at a 390-pixel viewport (safety.viz#162), filed earlier and moved to the v1.11.0 milestone

This issue was drafted by Claude Code using Opus 5.5.

Requirement 7The standards this release set are written into the scaffoldthe status ladder, the app's conventions and how a design is made, where the next session will read them
Title as filed

Requirement: the standards this release set are written into the scaffold — the status ladder, the app's conventions and how a design is made, where the next session will read them

requirementinfrastructurestatus: backlogmilestone 2026-10-talk999 words

Objective

#401

Business Requirement

What release 1.11 decided about how the app should look and read is, today, written in one design page and six requirements. The next chart, tab or app will be built by a session that reads none of those: it reads the hub's standards, the repository's contributing guide and its skills. @jwildfire, 2026-10-09: "Make sure that these new design principles land in the scaffold. Are there tasks filed to make sure the skills/agents are updated". Until they are written where a session looks, the same things get decided again, or built the old way: a fifth look for a status label, a third way to start R, a tab with a grey hex, a status called "stable".

Overview

Write the principles into the three places a session reads, each in the repository that owns it. The hub's developer guidelines take the program-wide ones: the status ladder and its words, and how anything a person looks at is designed and checked. safety.viz's contributing guide and its port-a-renderer skill take the demo app's own conventions, written after the code that makes them true has merged. The requirement-session skill in obot.agent takes the working rule: a task that changes what a person sees is built from its mockup and looked at in a browser before it closes. One piece is already in: the hub's requirement-design skill names the annotated mockup as the recommended form for a design (added 2026-10-09).

Repositories: obot.roadmap, safety.viz, obot.agent

Data Requirement

Not applicable: no data is involved.

Design

The principles, each from @jwildfire's feedback in the session of 2026-10-09 on the design for release 1.11:

  • Say how far to trust it, once, in one form. The ladder is Qualified, Exploratory, Experimental, Prototype. Nothing in the program is Qualified. The best anything is today is Exploratory, so nothing is called stable, validated or qualified. One label component carries the rung everywhere.
  • One way to do a thing across an app: one control that starts R, in one place; one place where files come in; one status label.
  • Every module looks like the others: a tab with a colour of its own, never grey, and a row of names under the header.
  • The result first, the machinery folded: a log, a list of versions or a run's steps stays closed until asked for, and a control shrinks once it has done its job.
  • Status is an icon with its words in the accessible name; grey means missing, and red is kept for an error.
  • A table takes the width its content needs.
  • An interim path gets the least that it needs.
  • Anything a person looks at is designed before it is built: whole-page mockups at desktop width with the changes numbered and today's page one click away, options shown as mockups, and rounds until he approves. It is judged as a first-time visitor on a shared screen would see it, and it still holds at a 390-pixel viewport.
  • A task that changes what a person sees is built from its mockup and looked at in a browser at the design's width before it closes. Where the mockup cannot be built as drawn, the session asks; it does not redesign.

Where each goes:

  • The hub's developer guidelines (docs/developer-guidelines.md): a section for the status ladder beside the GxP stance, a line in the definition of done for a chart saying a chart states its rung, and a short section on designing and checking what people look at, pointing at the requirement-design skill for the form. The wording is the session's draft of his words above; he reads the diff.
  • safety.viz (CONTRIBUTING.md, .claude/skills/port-a-renderer/SKILL.md): a section on the demo app's conventions, and the renderer definition of done and the porting procedure both say how a chart's rung is set. Written after the status ladder, R control, RBQM tab and Data tab requirements have merged, so that it describes the code as it is.
  • obot.agent (skills/requirement-session/SKILL.md): the working rule for tasks that change what a person sees, with the screenshot going into the pull request's evidence.
  • Already covered, with nothing to file: bio.viz, gsm.bio and gsm.safety each carry the Standards block in their CLAUDE.md, which points at the hub's guidelines, so the hub change reaches them.
  • Not covered, and his call: safety.viz has no CLAUDE.md at its root, so a session there is pointed at the hub's standards only by the workspace's own file. The open issue that records this (safety.viz#224) says no agent should add the file on its own.

Definition of done

End state: the hub's developer guidelines on main name the four rungs, say nothing is Qualified and that nothing is called stable, validated or qualified, and say how a design of something people look at is made and checked; safety.viz's CONTRIBUTING.md on dev has a section on the demo app's conventions that matches the released behaviour, and its renderer definition of done and port-a-renderer skill say how a chart's rung is set; the requirement-session skill on obot.agent's main tells a session to build a visible change from its mockup, look at it in a browser at the design's width and put the screenshot in the pull request.

Proof: the three merged changes are linked in the closing comment, each with the sentences it added quoted; grep -n -i "exploratory" docs/developer-guidelines.md in the hub, and the same in safety.viz's CONTRIBUTING.md, print the new lines; a search of the three documents for "stable" as a chart's status finds none; @jwildfire has been shown the hub diff in a comment on this requirement.

Ships in: the hub's main for the guidelines, safety.viz v1.11.0, and obot.agent v0.7.0.

Tasks

  • Write the status ladder and how a design is made into the developer guidelines (obot.roadmap#409)
  • Write the demo app's conventions and the status ladder into the contributing guide and the porting skill (safety.viz#288)
  • Tell a requirement session to build a visible change from its mockup and look at it in a browser (obot.agent#361)

This issue was drafted by Claude Code using Opus 5.5.

Written by Claude Code using Opus 5.5 from @jwildfire's feedback of 9 October 2026. He approved the design and the filing in that session; the tree is signed off only by his comment on the objective.