Bayesian Causal Atlas · Data-Harness Engineering Note

NHANES → ICES Harness Port
Required datasets & 3-million-record batching

Two deliverables for mimic_mortality_harness.html: (A) the exact ICES Data & Analytic Services (DAS) holdings that reproduce — and exceed — the reporting the harness currently derives from the harmonized NHANES 1988–2018 data, and (B) a bounded-memory modification that ingests 3,000,000+ records by incremental batching instead of loading all rows into memory.

AWhich ICES data files you need

The harness consumes seven NHANES variable domains. Each maps to one or more ICES holdings from the DAS third-party-research catalogue. The linkage spine changes from NHANES SEQN to the ICES IKN (encrypted key number); the harness's SEQN-merge logic maps 1:1 onto IKN-merge.

Harness domain (NHANES)Use in harnessICES dataset(s) — DAS library codeNotes & caveats
Demographics — SEQN, RIDAGEYR, RIAGENDRCohort spine; age; sex; §05 periodRPDB (Registered Persons Database); denominator/eligibility via CAPE, CONTACT, PCPOPRPDB is the spine — IKN, age, sex, DOB, fact/date of death to Jul 2026. This is the "demographics + partial mortality" module.
Race / ethnicity — RIDRETH1Descriptive strataSURNAMES (surname-based ethnicity); area-level ONMARG, CENSUSNo self-reported race in admin data. Surname + neighbourhood proxies only; interpret cautiously.
Survey cycle — SDDSRVYR§05 per-period breakdownfiscal-year field on any claims dataset (DAD/OHIP service date)Replace survey cycle with service/discharge fiscal year; key the §05 buckets on that.
Self-report conditions — MCQ*/DIQ010/KIQ022oracle routingRoute each person to a mortality oracleValidated ICES-derived cohorts: ODD (diabetes), CHF, COPD, ASTHMA, HYPER, DEMENTIA, ORAD (RA), HIV, OCCC (Crohn's/colitis); registries OCR (cancer), OMID (MI), ORRS/CORR (renal/ESRD); general Dx via DAD, NACRS, OHIP, SDSBetter than NHANES: whole-population, longitudinal, validated algorithms rather than self-report → less misclassification. Spirometry (GOLD) has no admin source → use the COPD cohort as the pulmonary router.
Linked mortality — MORTSTAT, PERMTH_EXMObserved outcome; follow-up survivalORGD (Vital Statistics – Deaths) + RPDB; overdose deaths DDARDORGD fact of death to Mar 2024, cause to Dec 2022 (cause lags ~2–3 y); RPDB fact-of-death is current. Follow-up months = index → death/censor.
Medications — RXDDRUG/RXDDRGID + drug dictionary§06 doctor-prescribed vs ParetoODB (Ontario Drug Benefit) + NMS (Narcotics Monitoring System) + NDFP (IV cancer drugs); code lookups DIN/DPDODB is age-restricted (65+, ODSP/OW/LTC/Trillium) — under-65 non-narcotic coverage is incomplete. NMS captures controlled substances all-payer. DIN/DPD replace dictionary_drug_codes.csv.
Response-module labs — creatinine, A1c, glucose, AST/ALT, platelets, HDL, TG, urate, TSH/T4, Hgb, ACR, LDL → staging§04b/§04c KDIGO · FIB-4 · ADA staging; §08 LDLOLIS (Ontario Laboratories Information System); legacy SW-Ontario CERNEROLIS starts Oct 2007; community-lab completeness rises over time. Delivers creatinine→eGFR/KDIGO, A1c/glucose→ADA, AST/ALT/platelets→FIB-4, lipids→LDL.
Blood pressure BPX*; anthropometry BMXBMI/BMXWAISTMetabolic-syndrome / HTN stagingHYPER cohort (validated HTN); measured BP/BMI via survey OHS, CLSA or primary-care EMR CHCNot in administrative data. Use the validated HTN cohort, or linked survey/EMR for measured vitals.
PHQ-9 DPQ* → §08 depressionNon-mortality endpointOMHRS (inpatient psychiatry) + OHIP/DAD psych Dx + ODB antidepressants; PROMs ESAS, PROMS; population mood OHS/CLSANo population PHQ-9; substitute a validated depression algorithm or a linked-survey score.
Behavioural — smoking, alcohol, diet (NHANES questionnaire)Risk-factor contextSurveys: OHS (Ontario Health Study), CLSA, HCES; (StatCan CCHS is linkable)Self-reported behaviours live in the linkable survey holdings, not admin data.

Minimal viable request (runs the harness's mortality + staging + Rx + §08 reporting)

Core: RPDB · ORGD · DAD · NACRS · OHIP · OLIS · ODB · NMS · OCR
Routing cohorts: ODD · CHF · COPD · ASTHMA · HYPER · DEMENTIA · ORAD · HIV · OCCC · ORRS
Optional (to exceed NHANES): OHS/CLSA (measured BMI/BP + behaviours) · ESAS/PROMS (PROMs) · ONMARG/CENSUS (SES) · CIC (immigration) · NDFP (cancer drugs) · DDARD (overdose deaths) · DIN/DPD (drug lookups)

Why this is "same or better". ICES is whole-population and longitudinal (not a cross-sectional sample), so condition ascertainment uses validated algorithms instead of self-report, follow-up is continuous rather than periodic linkage, and a routine cohort extract is millions of rows — which is exactly why the batching in Part B is required. Data live inside the ICES secure environment; extracts are governed, not downloadable, and the harness's existing <6 small-cell suppression already mirrors ICES release rules.

B3-million-record batching modification

The bottleneck (as-shipped)

The stock harness already streams each file, but it then (1) pushes every kept row into an in-memory rows[], (2) merges all persons on SEQN into five maps DATA.nhanes.{demo,cond,mort,lab,rx}, and (3) builds a per-person RESULTS[] in runAll(). Peak memory is O(N persons) — fine at NHANES scale (~10⁵), fatal at 3×10⁶.

The fix — bounded-memory batched fold (harness_batch.js)

Process records in fixed-size batches; fold each person directly into O(#oracles × #stages) running aggregates; then discard the raw rows before the next batch. Peak memory = O(BATCH_SIZE + aggregates), independent of total record count. The fold reuses the harness's own routeNHANES, computeStage and survivalLE/lifeYearsGained on a self-contained person record, so the numbers are identical to the stock path.

3,000,000
rows folded (smoke test)
50,000
peak rows retained (= batch)
203 MB
peak RSS — flat vs N
16.8 s
wall time (Node, 1 core)

Verified by smoke_batch.mjs: 3M synthetic joined rows streamed in 60 batches; peak retained rows never exceeded the batch size; every aggregate (per-oracle counts, life-years, observed deaths, KDIGO/ADA stage breakdown, PHQ-9/LDL non-mortality endpoints) matched an independent single-pass reference exactly; all cells <6 suppressed. A naive all-in-memory pass on 3M rows would hold multiple GB (3M row-objects + five SEQN maps + RESULTS[]) and crash a browser tab.

Public API

HarnessBatch.streamFold(source, {
  batchSize,           // rows held at once (default 50 000)
  keepFn,              // column whitelist (reuse the harness nhanesKeep)
  onBatch(rows),       // fold callback; rows are DISCARDED after it returns
  onProgress(bytes,n)  // UI progress
}) -> {rows, bytes, batches, peakBatchRows}   // peakBatchRows <= batchSize (guaranteed)

HarnessBatch.makeAggregator({route, stage, maxRR, lifeYears})
  .foldPerson(personRecord)   // O(1); no per-person retention
  .aggregateRows()            // §04 rows, <6 suppressed
  .stageRows()                // §04b/§04c stage breakdown, <6 suppressed
  .nonMort()                  // §08 depression + LDL

// source = browser File (uses File.stream()) OR a Node async-iterable of chunks.

Wiring it into mimic_mortality_harness.html (four edits)

  1. Add <script src="harness_batch.js"></script> (flat root — respects the bundle's no-subdirectory rule).
  2. Add a "Batched (3M+) mode" checkbox + a BATCH_SIZE input + a progress bar to §01. Auto-enable when a single file's .size exceeds a threshold (e.g. 200 MB).
  3. In batched mode, replace the streamExtractColumns → ingestNHANES → runAll path with: const agg = HarnessBatch.makeAggregator({route:routeNHANES, stage:stageInline, maxRR:oracleMaxRR, lifeYears:lifeYearsGained}); await HarnessBatch.streamFold(file, {batchSize, keepFn:nhanesKeep, onBatch:rows=>rows.forEach(r=>agg.foldPerson(toPerson(r)))});
  4. Point the existing renderers (§04 renderAgg, §04b/§04c, §08) at agg.aggregateRows() / agg.stageRows() / agg.nonMort() instead of iterating DATA.nhanes.demo. §03 per-person rows are already withheld under enclave rules, so nothing there changes.

Multi-file inputs under streaming (the SEQN/IKN-merge question)

A single-pass fold needs each row to be a complete person. Two supported modes:

ICES adaptation notes

Bayesian Causal Atlas · data-harness engineering note · files: harness_batch.js (module) · smoke_batch.mjs (3M-row test). ICES dataset names/date ranges from the ICES Data Dictionary (DAS – Third Party Research), retrieved for this note. Effect on release rules: none — small-cell suppression preserved.