open.gismo · loading your own data · mockup 1 of 2

Loading HEP-204, step by step

Eight steps from a CRO folder to a running study. Steps 3 to 6 are live — answer a finding and the ledger moves, the diff grows and the diagnostic changes its mind. Step 3 is the one that matters: it is the moment the data is wrong, and nothing in open.gismo today would tell you.

What is real here and what is not

The contract is real. The 42 consumers, which raw domain each one needs, which four literal strings the hepatic displays demand, and which single line of gsm.mapping does the mapping were all read out of the installed packages and demo-301's own workflow files this morning.

The delivery is constructed — demo-301's own data re-cut the way a CRO and an EDC vendor would send it, so the row counts are real counts of a study that exists. open.gismo has no such screen today; this is a design, not a recording.

the user · two commands

The folder arrives exactly as somebody else made it

HEP-204 is a Phase 2 study with a hepatic safety question. The CRO sends a SAS transport and an event listing; the EDC vendor sends a site list; the labs come from three vendors in two vocabularies. Nothing carries a gsm column name. Nobody is going to rename these files, and any design that assumes they will has lost before it starts.

zsh — ~/deliveries/hep204-2026-08-24
$ ls -1lh
dm.xpt                  SAS transport   1,005 × 16   subject level, ADaM-flavoured
ae_listing.csv          EDC export      2,583 × 15   no toxicity grade column
lab_central.csv         central lab    28,600 × 11   8 analytes
lab_specialty.csv       specialty lab   7,150 × 10   TBILI, GGT — bilirubin in µmol/L
lab_haem.csv            haematology    21,450 ×  9   no reference range at all
sites_20260824.csv      EDC export        150 ×  9   site list

60,938 rows · 70 columns · no define.xml · no ECG · no deviations

$ og init ~/hep-204
 project created at ~/hep-204
    config/       3 files
    workflows/    44 workflow YAMLs snapshotted from the installed gsm packages
    input/        empty
  Next: put your data in input/, then og_read("~/hep-204")

$ cp ~/deliveries/hep204-2026-08-24/* ~/hep-204/input/
$ git -C ~/hep-204 init -q && git -C ~/hep-204 add -A && git -C ~/hep-204 commit -qm "delivery 2026-08-24"
What happens if you do this today

og_validate() answers with twelve lines of file not found and names not one of the six files that are sitting in the folder. It is looking for input/Raw_AE.csv, input/Raw_LB.csv and ten more of the same. It could have opened dm.xpthaven is installed in this stack and never called.

R — open.gismo v0.2.0, today
> og_validate("~/hep-204")
✖ Raw_AE        file not found: input/Raw_AE.csv
✖ Raw_DATACHG   file not found: input/Raw_DATACHG.csv
✖ Raw_DATAENT   file not found: input/Raw_DATAENT.csv
… nine more …
✖ Raw_SUBJ      file not found: input/Raw_SUBJ.csv

The folder contains 60,938 rows of this study. None of them are mentioned.
the product · reads, and changes nothing

The read

og_read() opens the folder as delivered and writes one document. It never fails. Every finding in it is priced in displays — the charts and metrics somebody asked for — and never in column names, because the person reading this did not choose the column names and should not have to learn them.

~/hep-204/intake/report.html
open.gismo
HEP-204
  • Overview
  • Displays
  • Intake report
  • Snapshots
  • Workflows
  • Provenance
Intake report · read 2026-08-27 09:14 · og_read()
I read six files and understood most of them.

~/hep-204/input · 60,938 rows · 70 columns · 4.1 MB · nothing in this folder was modified

0
Will render, complete
Everything they need is present and unambiguous.
16
Will render, wrong
Output that looks fine and is not. Nobody goes looking for these.
0
One answer away
Waiting on a column nothing carries and everything is here to build.
23
Cannot render
Six extracts were not supplied. No answer here changes that.
Not run Readiness is a statement about what came out, not about how many boxes are filled. This mapping has never executed against these files.
Unpriceable 3 displays declare no spec: at allsrs0001, report_kri_site, report_kri_country. They run over whatever produced results, so the site risk score's denominator moves with your answers rather than failing. Nothing on this page can price them, and this line is the only honest thing to do about it.

1 · What I found

FileRead withRowsColsWhat I think it is
dm.xpthaven1,00516Subject level. ✔ confident USUBJID, SITEID, ARM, one row per participant.
ae_listing.csvread.csv2,58315Adverse events. ✔ confident Verbatim term, MedDRA, seriousness, start and end dates.
lab_central.csvread.csv28,60011Laboratory results, 8 analytes. ◐ one of three
lab_specialty.csvread.csv7,15010Laboratory results, 2 analytes. ◐ one of three
lab_haem.csvread.csv21,4509Laboratory results, 6 analytes. ⚠ no reference range
sites_20260824.csvread.csv1509Sites. ✔ confident One row per invid, with country.

Six of six read, including the transport. Expanding a row gives the column profile: distinct values, type, completeness and two real values from the file.

Why the second number is the one that matters

Sixteen displays will render output that looks entirely normal and is entirely wrong. Zero will render correctly. That ordering — wrong ahead of missing — is the whole argument for this direction: a display that does not render gets noticed, and a display that renders wrongly gets read.

the product · and it refuses

The identifiers do not join, and today nothing would tell you

This is the moment the product earns trust or loses it. Every column is present. Every type checks. og_validate() is all green. og_run() completes without an error — and sixteen displays report zero at every site while the site risk score quietly reweights over the ones that survived. Measured on demo-301's own data this morning.

~/hep-204/intake/report.html — finding 1 of 5
open.gismo
HEP-204
  • Overview
  • Displays
  • Intake report
  • Snapshots
2 · What needs an answer — ranked by what it costs, not by how sure I am
Your participant identifiers are written three ways, and the joins return nothing ■ blocking 16 displays

The mapping joins labs and events to participants with an inner join. As delivered, two of the three joins return zero rows. Both columns are present, both are character, both are complete. There is no check anywhere in open.gismo today that would catch this.

1,005 identifiers in dm.xpt USUBJID AA-AA-000-0000-S384 · AA-AA-000-0000-S4476 · AA-AA-000-0000-S1000 765 enrolled participants join against: ae_listing.csv SUBJID S384 overlap 0.00 (0 of 765) lab_central.csv SUBJECT S384 overlap 0.00 (0 of 765) lab_specialty.csv PT_ID S384 overlap 0.00 (0 of 765) lab_haem.csv SUBJID 0301-S384 overlap 0.00 (0 of 765) every dm.xpt value is "AA-AA-000-0000-" + a value the other five carry lab_haem.csv additionally prefixes "0301-", and is the only file that does after stripping both affixes ......................... 765 of 765 (1.00) rows recovered ......... labs 57,200 events 2,583 joined by, in your own project: workflows/1_mappings/LB.yaml:76 dplyr::inner_join by: subjid workflows/1_mappings/AE.yaml:71 dplyr::inner_join by: subjid

What it costs if you run anyway.

Mapped_LB and Mapped_AE become empty. 9 displays go to zero on the labs cou0005 kri0005 saf0001 hep_explorer safety_delta_delta safety_histogram safety_outlier_explorer safety_results_over_time safety_shift_plot 7 displays go to zero on the events cou0001 cou0002 kri0001 kri0002 saf0003 ae_explorer ae_timelines and srs0001, which declares no spec, re-normalises the site risk score over the 3 analyses that still ran. Nothing errors. The study will look exemplary.
How do you want these reconciled?

A repair is offered as a rule you can read, argue with and re-use next month — not as 765 identifiers somebody silently rewrote.

Unanswered. og_run() will refuse to start.
Measured, not asserted

This session reproduced the failure on demo-301's real input/Raw_SUBJ.csv and input/Raw_LB.csv: build USUBJID as studyid-subjid and the overlap with the lab file's bare identifier is 0 of 765; the inner join the study actually runs returns 0 rows from 57,200. Strip the constant prefix and it is 765 of 765, all 57,200 rows. Two other sessions found the same thing from two other angles the same night.

The grafted rule from the convention direction is the one that matters here: this finding is blocking, not advisory. A key with zero overlap is not a preference.

the product · says the consequence before the run, not after

Three laboratories, one domain

config/data-config.yaml maps one domain to one file. A liver panel split across three vendors is currently inexpressible, which is a real limitation of open.gismo v0.2.0 and not a hypothetical one.

~/hep-204/intake/report.html — finding 2 of 5
open.gismo
HEP-204
  • Overview
  • Intake report
Three files look like one laboratory domain 9 displays

They share a shape — a participant identifier, an analyte name, a numeric result, a visit — and between them they cover the whole panel with no analyte appearing twice.

proposed Raw_LB = lab_central ∪ lab_specialty ∪ lab_haem lab_central.csv 28,600 8 analytes ALT AST ALKP ALB CREAT GLUC K NA lab_specialty.csv 7,150 2 analytes TBILI GGT lab_haem.csv 21,450 6 analytes HGB HCT PLT WBC NEUT LYMPH 57,200 16 analytes no analyte appears twice reference range present lab_central yes lab_specialty yes lab_haem no columns at all → six haematology analytes will carry a null normal range. They get no derived toxicity grade in finding 3, and the reference band on the histogram is blank for those measures. Saying this now rather than after the run. units TBILI is µmol/L against a µmol/L limit; the eDISH cut-points are multiples of the upper limit, so the mismatch with the other files is safe. Recorded.
Stack the three into Raw_LB?
Unanswered. Only lab_central.csv would be read as Raw_LB — 8 of 16 analytes, and no bilirubin at all.
The graft on this screen

Disclosing the missing reference range before the run, rather than letting six analytes quietly arrive with null limits, is the intake direction's own rule. What was grafted on is the price: nine displays, named, so the answer is not a preference but a trade.

the product · orders candidates, never fills a blank

The chart asks for four words your laboratory does not use

Three displays do not ask for a column — they ask for four literal strings inside a column. Every column check on the lab files passes. The values were compared instead, and none of the four matched.

~/hep-204/intake/report.html — finding 3 of 5
open.gismo
HEP-204
  • Overview
  • Intake report
Your hepatic displays will draw empty charts, and nothing else will say so 3 displays
the three displays that pin literal analyte names: hep_explorer workflows/4_modules/hep_explorer.yaml measure_values: saf0001 gsm.safety::Input_HysLaw R/Input_HysLaw.R:67 — same four defaults safety_delta_delta workflows/4_modules/safety_delta_delta.yaml:14 ALT → "Alanine Aminotransferase" TB → "Bilirubin" AST → "Aspartate Aminotransferase" ALP → "Alkaline Phosphatase" your three lab files hold 16 distinct analyte names: lab_central.csv TEST ALT AST ALKP ALB CREAT GLUC K NA lab_specialty.csv ANALYTE TBILI GGT lab_haem.csv LBTEST HGB HCT PLT WBC NEUT LYMPH matched: 0 of 4 — the charts render, with no series on them
Four bindings. Ordered by how well the values fit, never scored.
  • 1ALT3,575 results, median 24 U/L, range 7–41 on every row of its own file→ ALT
  • 2AST3,575 results, its own reference range, same units→ AST
  • 3TBILIin lab_specialty.csv, µmol/L against a µmol/L limit→ TB
  • 4ALKP3,575 results, its own reference range→ ALP
Unanswered. The three displays render with no series on them, and the study site says so where they would have been.
Two grafts, visible on one screen

The candidates are ordered and never scored. The guided-setup session built a value profiler that scored 9 of 9 on a CRO lab extract where the published name detector managed 3 of 9 — and then scored 1.000 on a wrong answer and 0.849 on a right one against demo-301's own file. There is no threshold that separates those, so the number is never shown and the binding is never applied.

TBILI → Bilirubin is also a clinical assertion about total versus direct bilirubin. A person clicks it. Nothing here pre-applies it, at any confidence.

the user · says something the product never thought to ask

Declining, with a price

Two displays want a toxicity grade the protocol never collected. This is the graft from the mapping bench, and the data-manager lens is the reason it is here: today her spreadsheet says N/A in a cell and that judgement dies there. In December, when somebody asks why there is no Grade 3+ KRI, "the tool didn't ask me" is not an answer she can give.

~/hep-204/intake/report.html — findings 4 and 5 of 5
open.gismo
HEP-204
  • Overview
  • Intake report
No laboratory toxicity grade — but I can build one from what you sent 3 displays
Raw_LB.toxgrg_nsv CTCAE v5 band from result ÷ upper limit covered 10 of 16 analytes — the ten that arrive with a reference range not covered 6 analytes — lab_haem.csv carries no limits (finding 2) worked on ALT, 3,575 results: G0 2,838 G1 465 G2 79 G3 173 G4 20 sums to 3,575 consumers: cou0005 kri0005 safety_outlier_explorer
Derive it?
Unanswered. Three displays stay dark.
No adverse-event toxicity grade, and the only substitute is lossy 1 display
Raw_AE.aetoxgr wanted by saf0003 · Serious / Related AE (Subject) your file carries aesev MILD MODERATE SEVERE 2,583 of 2,583, complete the display wants aetoxgr 1 2 3 4 5 severity is not toxicity grade. Three levels standing in for five. If you substitute, every display built on it carries the mark, on the display itself, where somebody reads it — not only in this report.
Four ways to answer this. The fourth is the one no wizard offers.
Unanswered. One display stays dark, and next month this question comes back.
Why Declined is a state and not a blank

A blank is indistinguishable from work nobody has got to yet, so next month the product asks again and the month after that as well. A decline carries a reason, a date and a price; the study site prints not collected on this protocol where the tile would have been; and the next read does not raise it. That is the only difference between a tool that records a judgement and one that nags.

the user · reads a diff

Everything you answered is a diff in your own repository

There is no product database. Every answer above is text in the study's own files, in the study's own git, reviewed in the tool the reviewer already uses to review things. Go back and change an answer and this grows or shrinks with it.

git diff — workflows/1_mappings/LB.yaml
Nothing written yet. Answer a finding on steps 3 to 6.
git diff — config/data-config.yaml · config/setup-log.md
Nothing written yet.
Two grafts and one bug fix, all on this screen

The comments survive. demo-301's own LB.yaml opens with a thirteen-line note explaining that toxgrg_nsv must be cast to character or the Grade 3+ KRI's WHERE toxgrg_nsv IN ('3','4') matches nothing. open.gismo's current YAML writer round-trips that file from 80 lines to 70 and from 13 comment lines to 0 — measured this morning. The writer specified here edits the file as text and re-parses to check it wrote what it meant.

The plain English is kept beside the machine-readable spec. config/setup-log.md is where the user's own sentence lives, so the person reading this diff in December can see why, not just what.

Only two keys are ever written into the spec. gsm.mapping::ApplySpec reads source_col and type and nothing else. Everything that is not a rename — the affix rule, the analyte vocabulary, the derived grade — arrives as generated RunQuery steps, which is this design's admitted weakness rather than a feature. It is shown, not hidden.

the product · the whole interface

It refuses, then it runs — and next month it costs minutes

og doctor is the diagnostic behind the document: the same findings, ordered the same way, in the terminal, for the person who never opens a browser. Every finding names the file, the line and the literal text that fixes it.

zsh — og doctor ~/hep-204
$ og doctor ~/hep-204
open.gismo doctor — HEP-204
~/hep-204   14 domains · 126 columns · 42 displays

  ✖ 1 blocking   the run will not start
  ⚠ 4 costed     the run will start; here is what each one costs
  ✔ 4 domains ready
──────────────────────────────────────────────────────────────
✖ BLOCKING · identifiers do not join

  Raw_LB.subjid and Raw_SUBJ.subjid share 0 of 765 sampled values.
  Raw_AE.subjid and Raw_SUBJ.subjid share 0 of 765 sampled values.

  Fix — one line, because dm.xpt carries both forms:
    workflows/1_mappings/SUBJ.yaml:23
      subjid:
        type: character
  +     source_col: SUBJID

  Or, if the vendors genuinely disagree, the rule:
    config/vocab/subjid.rules.csv
      pattern,replacement,domains
      ^AA-AA-000-0000-,,Raw_SUBJ
      ^0301-,,Raw_LB

  Cost if you run anyway: 16 of 42 displays report zero at every
  site, and srs0001 re-weights over the 3 that ran. Nothing errors.
──────────────────────────────────────────────────────────────
og_run() refused. Fix the blocking finding, or --force it and own the result.
~/hep-204/output/site/index.html — after og_run()
open.gismo
HEP-204
  • Overview
  • Displays
  • Snapshots
  • Intake report
  • Provenance
Overview · snapshot 2026-08-27 09:41
HEP-204
Not run The mapping has not executed against these files yet.
0
Rendered
Live on this site.
16
Rendered wrongly
Output that looks fine and is not.
0
One answer away
Still waiting on you.
23
Not supplied
Printed where the tile would have been, with the reason.

What the site prints where a display is missing

DisplayStateWhat the tile says
kri0003 · kri0004✖ not suppliedProtocol deviations were not part of this delivery.
qt_explorer · saf0002✖ not suppliedNo ECG dataset was delivered.
saf0003✖ declined
srs0001⚠ unpriceableSite Risk Score is normalised over the analyses that ran, and this study ran a subset. The denominator moved.

And the transfer after this one

zsh — one month later, same study, same vendors
$ cp ~/deliveries/hep204-2026-09-24/* ~/hep-204/input/
$ og_read("~/hep-204")
replaying 11 answers from workflows/ and config/ — every assumption re-measured, not trusted

    affix rules still apply 765 → 812 participants, overlap 1.00
    4 analyte bindings still resolve
    toxicity grade derivable for 10 of 16 analytes
    saf0003 declined 2026-08-27 — not asked again

  ⚠  1 new finding
     lab_specialty.csv now carries a 17th analyte: "DBILI"
     No display asks for it. Nothing breaks. Recorded, and that is all.

 ready — og_run() will start
The graft with the least evidence behind it

Replay is the one idea on these pages that no direction designed and no session measured. It exists because the data-manager lens said month two costing what month one cost was the worst call in the session, and because the answers are already files, so replay is not a new store. It is the first thing to challenge.

Step 1 of 8