Test evidence
Biomarker screen
Every requirement of this module, the tests named for it, and what each test recorded the last time the evidence was rebuilt.
Summary
- Requirements
- 85
- Tests named for them
- 88 (30 unit, 58 browser)
- Result
- pass every test passing
- Screenshots
- 15
- Recorded
- 2026-10-04 19:02 UTC
- Environment
- linux 6.17.0-1022-azure · node v22.23.3 · playwright 1.61.1 · chromium 149.0.7827.55
The requirements are the rows of the module’s requirement matrix. A test is named for a requirement by starting its name with the requirement’s ID. The results are read from the committed evidence set; continuous integration reruns every test and fails when the committed set no longer matches.
Requirements and their tests
BS-KIT-001 pass
The chart is built from
SafetyViz.kit, found on the page: safety.viz's bundle and bio.viz's are two script tags, and the shell, the sidebar and the controls are the kit's. On a page without safety.viz the chart refuses to be made, with a message saying thatSafetyViz.kitwas not found.BS-KIT-002 pass
bio.viz's committed bundles export
biomarkerScreen, hold none of safety.viz, no Chart.js and no webR, and defining the chart needs no safety.viz.BS-KIT-003 pass
The chart is built from the parts every chart shares, in
src/shared/, and none of them is written a second time in its own files: the paging of a long list, the way back and the reading of participant-level numbers among them, shared with the charts that had them. Of other charts it imports their public functions alone,groupComparison,associationScatterandstratifiedSurvival(bio.viz#62), to open a row; nothing under their folders and nothing of the correlation matrix; and no other chart imports anything of this one.BS-KIT-004 pass
The chart's source holds no statistical inference: no arithmetic of an estimate, an interval, a p-value or an adjustment, and nothing ordered by a key R did not return. What it works out from R's numbers is where a dot and a line sit along the shared axis and how far that axis runs; for a hazard ratio's logarithmic axis, that place is the logarithm of R's number (bio.viz#62).
BS-CFG-001 pass
The chart has the settings the reference lists, with these defaults: the core's column and baseline settings;
comparisondifference(ofdifference,correlationand, with an outcomes table,hazard), withvisit,group_by,levelsandwithnull, so it opens on every biomarker at the first visit between the first two groups of the first column of groups;value_typeraw;methodpearson;adjustmentBH;sortestimate;limit20; andstatisticAnalyze_Screen.BS-CFG-002 pass
A setting that is not known, or a value a setting cannot take, is refused with a
TypeErrorwhose message beginsbio.viz:and names the setting;levelsnames exactly two groups,withis a variable as the core takes one, and the outcomes table's settings name exactly one flag, censored or event (bio.viz#62).BS-DATA-001 pass
The rows are the biomarkers of the Biomarker list, in its order, each at the one visit with the one value type; a baseline value is read with no visit.
BS-DATA-002 pass
For a correlation, a biomarker that is the fixed variable itself is not a row of its own, and the note says so. With no column of two groups, no fixed variable, or a change at the one baseline visit, there is nothing to screen, and the chart says why and what to choose.
BS-DATA-003 pass
The frame is the core's: one row per participant, one column per biomarker named by the biomarker, none required, so a participant missing some is kept with a gap; beside them the column of groups or the fixed variable. A participant with none of the biomarkers is left out and counted; the filters choose participants first; two columns of one name are refused in words.
- pass unit biomarker screen: the rows BS-DATA-003: the frame is the core’s, one column per biomarker named by it with none required, and the column of groups or the fixed variable beside them; a participant with none is left out and counted; the filters choose first; two columns of one name are refused (#36)
BS-DATA-004 pass
A difference's two groups are the two chosen when the column has both, and otherwise the column's first two, in order; the estimate is the first's less the second's.
BS-DATA-005 pass
The rows are ordered by R's estimate, largest first, by name, or by R's adjusted p-value, smallest first; a row R gave no number for comes after those it did, rows that tie keep R's order, and no key is made that R did not return.
BS-DATA-006 pass
Every row is drawn on one axis without units: for a difference it runs symmetrically about nought far enough to hold every interval R returned, with round labels; for a correlation from −1 to 1; nought is always on it.
BS-LIMIT-001 pass
With more rows than
limit, the rows are paged: a page holds at mostlimitof them in the order sorted, a page that does not exist is brought back to the nearest that does, and the note says how many are shown of how many, in what order and how many to a page.BS-LIMIT-002 pass
On the page, Previous and Next go between the pages of rows, which page of how many is said, the rows are the sorted rows of that page, and R is not asked again.
BS-CTRL-001 pass
The sidebar offers what the design asks: the comparison, the value type and the visit; for a difference the column of groups and its first and second group; for a correlation the fixed variable, a participant-level number or a biomarker with its visit, and the method; the adjustment; the order; a filter per category column of the participant table; and Reset chart. A baseline value has no Visit control.
BS-CTRL-002 pass
A change to the comparison, the value, the visit, the column of groups, a group, the fixed variable, the method, the adjustment or a filter draws the screen again for what was chosen and asks R again with it; the same group chosen twice swaps the two; Reset chart returns every control to what the chart opened on.
BS-CTRL-003 pass
A change to the order draws the rows R returned in another order and asks R nothing.
BS-CTRL-004 pass
With the setting
statisticnull the chart has no Statistics controls, asks R for nothing and draws no rows.BS-DRAW-001 pass
The demo's view, every biomarker's change from Baseline to Week 4 between the arms, draws one row per biomarker sorted by R's estimate, largest first, with IL-6 at the top: its estimate a dot and its interval a line where R's numbers put them on the one axis, nought marked, and beside them the estimate with its interval, the unadjusted and the adjusted p-value and each group's count.
BS-DRAW-002 pass
Every row is a button whose name is the whole row in a sentence from the shared formatter: the estimate, its interval, the method, the unadjusted and the adjusted p-value and the counts. A caption says what the estimate is, at what level its interval is, which test the p-values are and by what they were adjusted across how many biomarkers, and the line under the screen says the same of R's answer, once.
BS-DRAW-003 pass
Every p-value is printed with its method and counts and labelled exploratory, the adjusted one with the adjustment by name; no star and no word such as significant is printed anywhere, for either adjustment or comparison.
BS-DRAW-004 pass
A row R could not compute shows R's reason, as R worded it, and no number, no dot and no line, and says it is not in the adjustment; where no row could be computed the line gives R's reason.
BS-DRAW-005 pass
A correlation screen against IL-10 at Baseline draws every other biomarker on an axis from −1 to 1, with TNF-alpha at the top; for Spearman no interval is drawn or printed, none being made up.
BS-DRAW-006 pass
Above the screen the chart says how many participants are in the frame of how many and how many were left out for having none of the biomarkers; under it, that each row is of the participants who have its biomarker, so each row has its own counts, as R counted them.
BS-LIST-001 pass
The rows download as a CSV file under this chart's name, in the order shown, with the estimate, the interval, both p-values, the counts and R's reason where there is no number.
BS-STAT-001 pass
The screen asks R once, whatever the number of rows: the function named in
statistic, the frame, the biomarkers aschrCols, the comparison, the column of groups and the two groups for a difference or the fixed variable's column and the method for a correlation, and the adjustment. The identity of the frame names the chart, the value type, the visit, the baseline settings, the fixed variable and the filters in force.- pass unit biomarker screen: what R is asked BS-STAT-001: one request for the whole screen: the function, the frame, the biomarkers, the comparison with its groups or its variable and method, and the adjustment; an identity that names the chart, the value type, the visit, the baseline, the variable and the filters (#36)
BS-STAT-002 pass
R's answer is described without computing anything: the method as R names it, how many rows R computed of how many, and the adjustment by name across the number of rows R adjusted across; R's notes and warnings as R worded them; R's reason where no row could be computed; R's error as an error; and a result that names no method, or whose rows were not adjusted as one family, is refused.
- pass unit biomarker screen: how R’s answer is described BS-STAT-002: the method, how many rows R computed of how many, and the adjustment across how many; R’s notes; R’s reason where no row could be computed; R’s error; and a result with no method, or rows not adjusted as one family, is refused (#36)
- pass unit biomarker screen: how R’s answer is described BS-STAT-002: with no R the line says statistics are unavailable, with stored results a view not stored says so, and the desk never shows an answer to the question before (#36)
BS-STAT-003 pass
Each row is formatted by the shared formatter, and R's numbers are kept beside it for the dot, the line and the order only for a row R computed; a row is in the adjustment when R says it adjusted across it.
BS-STAT-004 pass
From the moment the screen is asked for until R answers, the line reads that it is waiting, with the page's note until R has answered once, and no rows are drawn: the chart says which biomarkers it will screen. Then the rows and the line are drawn from R's answer.
BS-STAT-005 pass
A change that asks R again clears the rows and the line; an answer to the question before is dropped when it arrives, and is never shown.
BS-STAT-006 pass
With no R attached the line says that statistics are unavailable and no rows are drawn: the chart says which biomarkers it would screen; nothing is fetched to say so.
BS-STAT-007 pass
With R's answers stored in the page the rows are drawn from them with no R and no request; a view no result was stored for says so and draws no rows, never another view's.
BS-STAT-008 pass
chart.statistics()returns what the chart asked R for the screen now drawn and what R answered: one entry, with the function, the arguments, the identity and the number of rows.BS-STAT-009 pass
For every case of the expected results, the function, the arguments, the identity and the row count that R wrote by the recipe in the reference are the ones the chart asks with; handed to a connection as stored results each is found by the chart's request, and by no other view's; and the recipe in the reference is the script's.
- pass unit what desktop R answered, and the key it wrote BS-STAT-009: for every case the function, the arguments, the identity and the row count R wrote by the recipe are the ones the chart asks with, and the recipe in the reference is the script’s (#36)
- pass unit what desktop R answered, and the key it wrote BS-STAT-009: handed to a connection as stored results, each of R’s answers is found by the chart’s request for its view, and by no other view’s (#36)
BS-STAT-010 pass
The frames desktop R is run on are written by the chart's own code from the demo's own tables and settings, and committed; deriving them again gives the committed files. A gap is an empty cell.
- pass unit the frames R is run on BS-STAT-010: a frame is the chart’s: the id, one column per biomarker named by it, the column of groups or the variable, a gap an empty cell; and the demo’s settings read from its own script (#36)
- pass unit the frames R is run on BS-STAT-010: deriving each case’s frame again, with the chart’s own code from the demo’s own tables and settings, gives the committed files (#36)
BS-STAT-011 pass
The expected results name the script, the R version and the vendored statistics file that made them, and hold one result per case: both comparisons and both adjustments, a filter, another column of groups, a participant-level number, and a view whose every row has a group too small, those rows left out of the adjustment as R says.
BS-STAT-012 pass
In desktop R's answers the planted biomarkers are the top rows by estimate: IL-6's change from Baseline to Week 4 between the arms, and TNF-alpha against IL-10 at Baseline, whose interval holds 0.6. A difference row's unadjusted p-value is the group comparison's Welch p-value for that biomarker, and a correlation row's coefficient is the association scatter's, each from that chart's own expected results.
BS-DRILL-001 pass
A click on a row of a difference opens the group comparison for that biomarker in place of the screen, at the same visit and value, with the same column of groups and two groups and Welch's test, and a button back that takes the keyboard's place.
BS-DRILL-002 pass
A click on a row of a correlation opens the association scatter for that biomarker against the fixed variable, with the same method, and a button back.
BS-DRILL-003 pass
From the keyboard a row is reached with Tab and opened with Enter or Space; Enter or Space on the button back returns to the screen.
BS-DRILL-004 pass
The chart a row opens is handed the screen's connection itself, its filters as they are set and the column settings, with the settings
group_comparisonorassociation_scatterbeneath. With results stored in the page, the group comparison's Welch p-value is the difference row's unadjusted p-value, and the scatter's coefficient is the correlation row's estimate.BS-DRILL-005 pass
Returning shows the screen exactly as it was, on the same page in the same order, with the keyboard on the row that was opened, and R is not asked again for the screen.
BS-DRILL-006 pass
chart.open(biomarker)opens a row's chart by the biomarker's name and returns it,chart.opened()gives it while it is open, andchart.close()returns to the screen; a name the screen does not have is refused with the names it has. Drawing the screen again closes a chart that is open.BS-FILTER-001 pass
On the demo, filters with nobody in common leave the chart reading
No participant passes the filters., in the words every chart uses, with the note that none of the participants pass; no rows are drawn, R is asked nothing, the filters and Reset chart stay usable, nothing is written to the console, and loosening a filter draws again.BS-FILTER-002 pass
A filter reads its spec by the rule safety.viz's charts follow, through the kit's
reconcileFilters:startsets what it opens on and All is still offered; onlyall: falseremoves All, and its first value is then the one in force; a value the data lacks falls back to All with a console warning naming the filter; and the selection each control shows is the selection the chart filters by.BS-LIFE-001 pass
init,setData,setSettings,render,resizeanddestroydrive the chart as they drive a safety.viz chart;setSettingsmoves the control of a setting that says what the chart opens on, anddestroytakes down the screen, a chart a row had opened and everything in the element.BS-LIFE-002 pass
Tables the chart cannot read are refused with a
TypeError, and the message is shown in the chart's place.BS-MOBILE-001 pass
At a 390-pixel-wide viewport the chart fills the width with its controls folded away one tap from open; each row stacks its name, its interval on the full width of the axis and its numbers, each named before it, and the page does not scroll sideways.
BS-MOBILE-002 pass
At a 390-pixel-wide viewport a tap on a row opens its chart and its button returns, and the page does not scroll sideways at any point.
BS-SITE-001 pass
The gallery lists the biomarker screen with links to its live demo, its evidence page and its API reference.
BS-SITE-002 pass
The live demo draws the chart on the synthetic study, opening on the planted difference, every biomarker's change from Baseline to Week 4 between the arms, from safety.viz's vendored bundle and bio.viz's committed one, with R attached and gsm.bio's statistics file published beside it. Where R's host cannot be reached it draws no rows, and says that R could not be started.
BS-SITE-003 pass
The live demo holds at a 390-pixel-wide viewport with no horizontal scroll, with the controls open and a row opened in its chart.
BS-SITE-004 pass
The API reference has a table row for every setting the chart has, with the default the code has; the site build fails when one is missing.
BS-SITE-005 pass
The demos point at one another: the screen's page says a row opens the group comparison or the association scatter, and the group comparison's and the scatter's pages point to the screen as the way in.
BS-LIVE-001 pass
The gallery's demo starts R in the browser when the screen first asks, from webR's pinned version and gsm.bio's vendored statistics file, with no R package installed. The line waits, saying what the first start costs, and then every row's estimate, interval, unadjusted and adjusted p-value and counts equal desktop R's within 1 part in 10^8, the rows in the order of R's estimates with IL-6 at the top.
BS-LIVE-002 pass
On the demo, with Holm's adjustment, every row equals desktop R's.
BS-LIVE-003 pass
On the demo, the correlation screen against IL-10 at Baseline, by Benjamini-Hochberg and by Holm, and with Spearman's coefficient, equals desktop R's in every row, with TNF-alpha at the top and 0.6 inside its interval; where R's own wording differs between the versions, both are recorded and nothing else differs.
BS-LIVE-004 pass
On the demo, a change shows the waiting state and then the new screen, which equals desktop R's, and never the old one: with a filter, another column of groups, the result at Baseline, a participant-level number, and a view whose every row has a group too small.
BS-LIVE-005 pass
On the demo, a row of the difference opens the group comparison, whose Welch p-value from the same R, started once, is the row's unadjusted p-value; a row of the correlation opens the scatter, whose coefficient is the row's; returning shows the screen as it was and asks R nothing.
BS-LIVE-006 pass
The megabytes and seconds of the demo's first screen, and the seconds R takes for a screen once started, are measured, printed in the run's log and written to a file with both versions' answers, and the megabytes are what the page tells its reader in the waiting text.
BS-LIVE-007 pass
On a phone the demo draws its rows from R, stacked, and the page does not scroll sideways.
BS-STAT-013 pass
When the connection is replaced (
setSettings({ connection })), an answer that arrives late from the connection it replaced is never shown: it changes neither the statistics line nor whatchart.statistics()reports.BS-FAIL-001 pass
When drawing fails, the biomarker screen says so in its footnote (
This chart could not be drawn:and why), takes away what was drawn of the rows, ends the statistics round, empties the listing and the participant rail, says it in the danger colour and keeps its controls; once drawing works again it draws.BS-DROP-001 pass
With a participant table, a participant the results have and the table does not is left out and counted (
Not in the participant table), and a row of results with no participant id is counted (Row has no participant id); a participant table without the participant id column is refused with a sentence that names the column.BS-NAME-001 pass
A biomarker whose name has a space at either end is screened under its name as written, and R is handed it by that name.
BS-DROP-002 pass
With results for participants the participant table does not have and filters that let nobody through, the chart says
No participant passes the filters., as it does with no such rows.BS-DROP-003 pass
A setting that names a participant id column the participant table does not have (
setSettings({ participant_id_col })) is refused with the same sentence as the tables are, before anything changes, and the chart stays as it was drawn, a chart opened in place included (bio.viz#52).BS-STAT-014 pass
The R recipe run on a data frame with a visit column that holds numbers writes the identity as text, as the chart asks with, so a stored result written that way is found.
BS-STAT-015 pass
For a difference, the statistics line under the rows prints R's own note that the interval is the pooled-variance interval for Hedges' g while the p-value is Welch's, which does not pool; the chart adds no words of its own about R's methods.
- pass browser BS-STAT-015: for a difference the statistics line under the rows prints R’s own note that the interval pools the variances and the p-value does not; the chart adds no words of its own about R’s method (#49, #52)
BS-DROP-004 pass
The participant table and the setting that names its id column change together:
setData(tables, settings)checks the tables against the settings it is given with them, lays the settings over, and draws.BS-HAZ-001 pass
For a hazard ratio the frame holds, beside every biomarker, each participant's time and flag for the endpoint, as the outcomes table reads it, censored or event; a participant with no outcome to use is kept with a gap and counted by reason.
- pass unit biomarker screen: the hazard rows BS-HAZ-001: for a hazard ratio the frame holds, beside every biomarker, each participant’s time and flag for the endpoint as the outcomes table reads it, censored or event; a participant with no outcome to use is kept with a gap and counted by reason (#62)
BS-HAZ-002 pass
R is asked once per screen with
Analyze_Screen's hazard comparison, the time and the flag, and the endpoint in the identity of the frame; for every hazard case the key is the one desktop R wrote, and R's stored answer is found.BS-HAZ-003 pass
Each hazard row is R's hazard ratio of High against Low with its interval, its log-rank p-values unadjusted and adjusted across the rows, and High's and Low's counts; sorted by R's estimate, CRP, the planted biomarker, is the top row; a row R could not compute, a hazard ratio not estimable among them, gives R's reason.
- pass unit biomarker screen: the hazard rows BS-HAZ-003: each row is R’s hazard ratio of High against Low with its interval, its log-rank p-values unadjusted and adjusted, and High’s and Low’s counts; sorted by R’s estimate CRP, the planted biomarker, is the top row; a row R could not compute gives R’s reason (#62)
BS-HAZ-004 pass
Hazard ratios share one logarithmic axis at powers of two, from a half to two at least, with 1, no difference, marked; a ratio sits where its logarithm puts it.
BS-HAZ-005 pass
With an outcomes table the screen offers a hazard ratio, high against low; from R's stored answer every row is drawn on the logarithmic axis, CRP at the top, each with its counts, under a heading, a caption and a hint that say what the rows are, the hint naming 1 as the line the axis marks.
BS-HAZ-006 pass
Without an outcomes table the screen offers only its other two comparisons and says why, and a setting asking for a hazard ratio opens on a difference; given one, it is offered.
BS-HAZ-007 pass
A click on a hazard row opens the stratified survival chart for that biomarker, cut at its median, on the same endpoint, with the screen's connection and filters; its hazard ratio from stored results is the row's; the way back returns, with the keyboard on the row.
BS-HAZ-008 pass
Against R and the survival package in the browser on the demo: every hazard row, by Benjamini-Hochberg and by Holm, for the women alone, with every row too small, with thirty participants' outcomes taken out and with a hazard ratio R cannot estimate, equals desktop R's within 1 part in 10^8, CRP at the top; its row opens the stratified survival chart, whose hazard ratio from the same R is the row's, and the way back returns.
- pass browser BS-HAZ-008: with R and the survival package in this browser, every hazard row, by Benjamini-Hochberg and by Holm, for the women alone, with every row too small, with thirty outcomes taken out and with a ratio R cannot estimate, is desktop R’s, CRP at the top; its row opens the stratified survival chart, whose hazard ratio from the same R is the row’s, and the way back returns (#62)
BS-HAZ-009 pass
With some participants holding a value but no outcome, the row and the stratified survival chart it opens cut at the same median, of the participants with both, with the same participants High and Low and R's same hazard ratio; the participants with no outcome are counted once, under one reason.
- pass unit biomarker screen: the hazard rows BS-HAZ-009: with some participants holding a value but no outcome, the row and the survival chart it opens cut at the same median, of those with both, with the same participants High and Low and R’s same hazard ratio; the participants with no outcome are counted once (#62)
BS-HAZ-010 pass
A hazard ratio R could not estimate, with no event in one half, is a row with R's reason, no number and no place in the adjustment, which is across the rows that have a p-value.
BS-HAZ-011 pass
In the page, with thirty participants holding CRP but no outcome, the row and the survival chart it opens cut at the same median with the same High and Low counts and the same hazard ratio, and the thirty are counted in one note.
BS-HAZ-012 pass
In the page, a hazard ratio R could not estimate is drawn as a row with R's reason and no mark, out of the adjustment, and the statistics line says the adjustment is across the other eleven.
BS-HAZ-013 pass
With two endpoints the Endpoint control offers both by their labels; choosing the second asks R again on its times, names it in the heading and in the identity of the frame, and a row opens the survival chart on it.
BS-HAZ-014 pass
On a wide logarithmic axis, more than seven ticks, the tick labels are thinned to every other one, counted from 1, which is always labelled; each label is written by the shared rule for a value, four significant figures.
- pass browser BS-HAZ-014: on a wide logarithmic axis the tick labels are thinned to every other one, counted from 1, which is always labelled, and each is written by the shared rule for a value (#65 review)
BS-HAZ-015 pass
An endpoint setting the outcomes table does not hold warns in the console, as a visit does, and the screen opens on the first endpoint; without an outcomes table nothing is said about an endpoint.
- pass browser BS-HAZ-015: an endpoint setting the outcomes table does not hold warns in the console, as a visit does, and the screen opens on the first endpoint (#65 review)
Checking this page
npm ci
npm run evidence:check # rerun every test and compare with the committed evidence set
npm run evidence # rebuild docs/evidence/biomarker-screen/evidence.json














