simulator/tools/emergency-stress-report.mjs
#!/usr/bin/env node
// Emergency-rescue stress matrix — full run + report (writes simulator/EMERGENCY_STRESS.md).
// EDUCATIONAL SIMULATION — fictional patients — not a medical device. All vitals are illustrative model output.
//
// node tools/emergency-stress-report.mjs full matrix → EMERGENCY_STRESS.md
// node tools/emergency-stress-report.mjs --json F also write every run record to F (JSON)
// node tools/emergency-stress-report.mjs --workers N (default: CPU count, max 8; results do not depend on N)
// node tools/emergency-stress-report.mjs --from-json F re-render the report from records saved with --json
//
// Deterministic: every run is a pure function of its case (patient, emergency, arm, timing, seed, combo); the
// case list is fixed and results are merged in case order, so the report is identical for any worker count.
import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads';
import { readFileSync, writeFileSync } from 'node:fs';
import { availableParallelism, cpus } from 'node:os';
import { fileURLToPath } from 'node:url';
const HERE = fileURLToPath(import.meta.url);
/** Keep what the report needs (the run records are large because of the dose lists). */
function slim(r) {
const { doses, ...rest } = r;
return { ...rest, doseFlags: (doses || []).filter((d) => d.ok && d.flags.length).map((d) => `${d.drugId}:${d.route || d.kind}:${d.flags.join('+')}`), refusals: (doses || []).filter((d) => d.blocked).map((d) => `${d.drugId}:${d.kind}${d.route ? `:${d.route}` : ''}: ${String(d.reason).replace(/[\d.]+/g, '#')}`) };
}
async function main() {
const args = process.argv.slice(2);
const opt = (k) => { const i = args.indexOf(k); return i >= 0 ? args[i + 1] : null; };
const D = await import('../tests/emergency-stress.mjs');
const cases = [
...D.matrixCases(),
...D.matrixCases({ emergencies: ['light_anesthesia_stimulus'], timings: ['early'] }).map((c) => ({ ...c, variant: 'lightened' })),
...D.comboCases(),
];
if (opt('--from-json')) {
const records = JSON.parse(readFileSync(opt('--from-json'), 'utf8'));
writeFileSync(new URL('../EMERGENCY_STRESS.md', import.meta.url), renderReport(D, records));
console.log(`emergency-stress: re-rendered from ${records.length} saved records`);
return;
}
const nW = Math.max(1, Math.min(Number(opt('--workers')) || (typeof availableParallelism === 'function' ? availableParallelism() : cpus().length), 8));
const t0 = Date.now();
const chunks = Array.from({ length: nW }, () => []);
cases.forEach((c, i) => chunks[i % nW].push({ i, c }));
const parts = await Promise.all(chunks.map((ch) => new Promise((resolve, reject) => {
const w = new Worker(HERE, { workerData: { cases: ch.map((x) => x.c) } });
w.once('message', (recs) => resolve(recs.map((r, k) => ({ i: ch[k].i, r }))));
w.once('error', reject);
})));
const records = parts.flat().sort((a, b) => a.i - b.i).map((x) => x.r);
const wallSec = Math.round((Date.now() - t0) / 1000);
if (opt('--json')) writeFileSync(opt('--json'), JSON.stringify(records));
const md = renderReport(D, records);
writeFileSync(new URL('../EMERGENCY_STRESS.md', import.meta.url), md);
const viol = records.filter((r) => !r.ok);
console.log(`emergency-stress: ${records.length} runs (${D.matrixCases().length} matrix + ${cases.length - D.matrixCases().length - D.comboCases().length} lightened-variant + ${D.comboCases().length} fault/hold combinations), ${viol.length} with safety violations, ${records.filter((r) => r.exception).length} exceptions; ${wallSec} s wall, ${nW} workers → EMERGENCY_STRESS.md`);
for (const r of viol.slice(0, 20)) console.log(` VIOLATION ${r.id}: ${r.violations.slice(0, 3).join(' | ')}`);
if (viol.length) process.exitCode = 1;
}
// ------------------------------------------------------------------------------------------------ report
const fmtT = (s) => (s === null || s === undefined ? '—' : s === Infinity ? 'not recovered' : `${Math.round(s)} s`);
const pct = (x) => `${Math.round(x * 100)} %`;
const n0 = (x) => (x === null || x === undefined || !Number.isFinite(x) ? '—' : String(Math.round(x)));
function renderReport(D, records) {
const L = [];
const matrix = records.filter((r) => !r.combo && !r.variant);
const light = records.filter((r) => r.variant === 'lightened');
const combos = records.filter((r) => r.combo);
const eff = D.efficacy([...matrix, ...light]);
const C = D.DRIVER_CONVENTIONS;
L.push('# Emergency-rescue stress matrix (2026-11)', '');
L.push('> **SIMULATION — fictional patients — educational use only. Not a medical device. Not medical advice.** Every vital sign below is *illustrative model output* of the simulator (engine/physiology.js, engine/pd.js); nothing here is a clinical efficacy claim or a validation.', '');
L.push('Generated by `node tools/emergency-stress-report.mjs` (driver: `tests/emergency-stress.mjs`; a representative subset runs in `npm test`, `tests/emergency-stress-2026-11.test.mjs`). Do not edit by hand — regenerate.', '');
L.push('Question: do the rescue interventions the engine offers work in its scripted emergencies across extreme fictional patients, and do the safety rules hold in every run, including deliberately abusive dosing?', '');
// ---- size
const viol = records.filter((r) => !r.ok);
L.push('## Matrix size', '');
L.push('| block | runs | definition |', '|---|---|---|');
L.push(`| main matrix | ${matrix.length} | ${D.EMERGENCIES.length} emergencies × ${D.STRESS_PATIENTS.length} patients × arms (control, rescue, aggressive; + rescue_im for anaphylaxis) × ${D.TIMINGS.length} onset times × ${D.SEEDS.length} seeds |`);
L.push(`| light-anaesthesia "lightened" variant | ${light.length} | light_anesthesia_stimulus with the maintenance hypnotic at the bottom of its label range, ${D.STRESS_PATIENTS.length} patients × 3 arms × early × ${D.SEEDS.length} seeds |`);
L.push(`| fault / hold combinations | ${combos.length} | rescue arm, seed 1, early onset: emergency + MAP sensor fault, + HR sensor fault, + SpO2 probe off, during a latched hold, and in automatic mode with "Continue with hold latched" (laryngospasm: fault combinations only) |`);
L.push(`| **total** | **${records.length}** | |`, '');
// ---- safety
L.push('## Safety assertions (every run, including the aggressive arm)', '');
const count = (f) => records.filter(f).length;
const allFlags = records.flatMap((r) => r.doseFlags || []);
const allRef = records.flatMap((r) => r.refusals || []);
L.push('| assertion | result |', '|---|---|');
L.push(`| no exception | ${count((r) => r.exception) === 0 ? 'PASS' : 'FAIL'} (${count((r) => r.exception)} runs with an exception) |`);
L.push(`| no NaN / Infinity in vitals (NaN only on a faulted sensor channel; internal PaO2/PaCO2/SaO2 and drug states finite) | ${viol.some((r) => r.violations.some((v) => /NaN|Infinity|not finite|internal/.test(v))) ? 'FAIL' : 'PASS'} |`);
L.push(`| vitals within plausible bounds (MAP ${D.BOUNDS.map.join('–')}, HR ${D.BOUNDS.hr.join('–')}, SpO2 ${D.BOUNDS.spo2.join('–')}, SBP ${D.BOUNDS.sbp.join('–')}, RR ${D.BOUNDS.rr.join('–')}, EtCO2 ${D.BOUNDS.etco2.join('–')}, index ${D.BOUNDS.depthIndex.join('–')}) | ${viol.some((r) => r.violations.some((v) => /bounds/.test(v))) ? 'FAIL' : 'PASS'} |`);
L.push(`| every accepted dose ≤ every hard limit (per dose, per route, cumulative; label/guideline ceilings, interpretCeilings) and given exactly as ordered (no silent clamping) | ${viol.some((r) => r.violations.some((v) => /above|clamped/.test(v))) ? 'FAIL' : 'PASS'} |`);
L.push(`| every refused dose logged "BLOCKED" with nothing given | ${viol.some((r) => r.violations.some((v) => /blocked/.test(v))) ? 'FAIL' : 'PASS'} (${allRef.length} refusals) |`);
const sumDS = (f) => records.reduce((a, r) => a + Object.values(r.doseSummary || {}).reduce((b, x) => b + f(x), 0), 0);
const repeatRefused = sumDS((x) => x.repeatRefused || 0); const aboveConfirmed = sumDS((x) => x.aboveTeachingConfirmed || 0);
const teachTot = (k, f) => records.reduce((a, r) => a + ((r.teaching || []).filter((x) => x.key === k).reduce((b, x) => b + f(x), 0)), 0);
const confAll = records.reduce((a, r) => a + (r.confirmationsGiven || 0), 0); const confAgg = records.filter((r) => r.arm === 'aggressive').reduce((a, r) => a + (r.confirmationsGiven || 0), 0);
L.push(`| every accepted dose outside the sourced regimen range carries a warning | ${viol.some((r) => r.violations.some((v) => /WITHOUT a warning/.test(v))) ? 'FAIL' : 'PASS'} (${allFlags.filter((x) => /outside_regimen_range/.test(x)).length} such doses, all in the aggressive arm) |`);
L.push(`| zero clinician-entered (manual or advisory) repeats accepted inside the label repeat interval (phenylephrine 60 s, glycopyrrolate 120 s outside emergence, IM/SC epinephrine 300 s): each is REFUSED, logged with the interval and time remaining | ${viol.some((r) => r.violations.some((v) => /must be refused/.test(v))) ? 'FAIL' : 'PASS'} (${repeatRefused} refusals) |`);
L.push(`| no accepted dose takes a total above a simulator teaching ceiling without the clinician's confirmation action (one dose per confirmation) | ${viol.some((r) => r.violations.some((v) => /teaching ceiling/.test(v))) ? 'FAIL' : 'PASS'} (refused until confirmed: epinephrine IV ${teachTot('epinephrine_iv', (x) => x.refusals)}, glycopyrrolate ${teachTot('glycopyrrolate', (x) => x.refusals)}, crystalloid boluses ${teachTot('crystalloid', (x) => x.refusals)}; confirmations ${confAll}: ${confAgg} the aggressive arm's single deliberate probe per run, ${confAll - confAgg} by the rescue-arm clinician (the rescue strategies stay below every ceiling: ≤ 4 × 500 mL, ≤ 0.4 mg IV epinephrine); ${aboveConfirmed} drug doses and ${teachTot('crystalloid', (x) => x.used)} fluid boluses given after a confirmation; the control arm and the automatic runner never confirm) |`);
L.push(`| running rates ≤ label rate/dial ceilings every second; controlled infusions ≤ Python simulation ceilings while interlocks are on; direct state write re-validated | ${viol.some((r) => r.violations.some((v) => /rate|ceiling|direct/.test(v))) ? 'FAIL' : 'PASS'} |`);
L.push(`| interlock hold latches one control iteration after MAP < 60 / HR < 48 / unusable reading, held infusions stay at 0, never released without resume_hold | ${viol.some((r) => r.violations.some((v) => /hold|held/.test(v))) ? 'FAIL' : 'PASS'} (${count((r) => r.interlock && r.interlock.holdLatchedEver)} runs latched a hold; resume_hold was never pressed by the driver) |`);
L.push(`| no vasopressor without an explicit accept in advisory runs (advisory doses = accepted advisories = "ADVISORY accepted" log lines; control arm: zero vasopressor doses, zero accepts) | ${viol.some((r) => r.violations.some((v) => /advisor|vasopressor/.test(v))) ? 'FAIL' : 'PASS'} (${records.reduce((a, r) => a + ((r.advisory && r.advisory.accepted) || 0), 0)} accepted, ${records.reduce((a, r) => a + ((r.advisory && r.advisory.shown) || 0), 0)} shown) |`);
L.push(`| plan-safety check passes for every patient's plan | ${viol.some((r) => r.violations.some((v) => /plan-safety/.test(v))) ? 'FAIL' : 'PASS'} |`);
L.push(`| fault / hold combinations: rescue path available (FiO2, fluids, rescue bolus accepted during the fault or hold), held infusions cannot restart | ${combos.every((r) => r.ok) ? 'PASS' : 'FAIL'} (${combos.length} runs) |`);
L.push(`| **runs with any violation** | **${viol.length}** |`, '');
if (viol.length) { L.push('Violations:', ''); for (const r of viol.slice(0, 40)) L.push(`- \`${r.id}\`: ${r.violations.slice(0, 3).join('; ')}`); L.push(''); }
const refByKind = tally(allRef);
L.push('Refusals by drug and reason (numbers masked as #):', '', '| refusal | count |', '|---|---|');
for (const [k, v] of refByKind.slice(0, 20)) L.push(`| ${k.replace(/\|/g, '/')} | ${v} |`);
L.push('');
L.push('Accepted with a warning or after a confirmation (engine policy, SPEC §5.2/§6: the regimen range is a warning; drug.ceiling values and label repeat intervals refuse; simulator teaching ceilings refuse until confirmed):', '', '| drug:route:flag | count |', '|---|---|');
for (const [k, v] of tally(allFlags)) L.push(`| ${k} | ${v} |`);
L.push('');
const agg = matrix.filter((r) => r.arm === 'aggressive');
const aggMax = (k) => Math.max(...agg.map((r) => r.metrics[k]).filter(Number.isFinite));
const totals = (key) => agg.map((r) => (r.doseSummary[key] ? r.doseSummary[key].total : 0));
L.push(`Aggressive arm extremes (${agg.length} runs): max MAP ${aggMax('maxMap')} mmHg, max HR ${aggMax('maxHr')} /min; seconds at a physiology clamp (MAP/HR 25 or 200, SpO2 40): MAP ${sum(agg.map((r) => r.metrics.clampSec.map))}, HR ${sum(agg.map((r) => r.metrics.clampSec.hr))} (in ${agg.filter((r) => r.metrics.clampSec.hr > 0).length} runs: ${[...new Set(agg.filter((r) => r.metrics.clampSec.hr > 0).map((r) => r.patientId))].join(', ')}), SpO2 ${sum(agg.map((r) => r.metrics.clampSec.spo2))}; all arms: ${sum(records.filter((r) => r.metrics).map((r) => r.metrics.clampSec.map + r.metrics.clampSec.hr + r.metrics.clampSec.spo2))} clamp-seconds (${tally(records.filter((r) => r.metrics).flatMap((r) => Object.entries(r.metrics.clampSec).flatMap(([k, v]) => Array(v).fill(`${r.arm} ${k} ${r.emergency}`)))).map(([k, v]) => `${k}: ${v}`).join('; ')}). Per run, accepted within ${C.AGGRESSIVE_FOR_SEC} s: phenylephrine bolus ≤ ${Math.max(...totals('phenylephrine:bolus:IV'))} mcg, ephedrine ≤ ${Math.max(...totals('ephedrine:bolus:IV'))} mg, epinephrine IV ≤ ${round2(Math.max(...totals('epinephrine:bolus:IV')))} mg, epinephrine IM ≤ ${round2(Math.max(...totals('epinephrine:bolus:IM')))} mg, glycopyrrolate ≤ ${round2(Math.max(...totals('glycopyrrolate:bolus:IV')))} mg, crystalloid ordered up to ${Math.round(C.AGGRESSIVE_FOR_SEC / C.AGGRESSIVE_EVERY_SEC + 1) * C.FLUID_BOLUS_ML / 1000} L.`, '');
// ---- efficacy
L.push('## Efficacy (directional, illustrative)', '');
L.push(`Recovery = the emergency's **primary** vital sign(s) back inside the limits for ≥ ${D.RECOVERY.SUSTAIN_SEC} s, timed from the onset, counted only after the first deranged sample (a run that never deranges counts as recovered at 0 s). Primary criteria: hemorrhage MAP ≥ ${D.RECOVERY.MAP_MIN}; vagal bradycardia HR ≥ ${D.RECOVERY.HR_MIN}; bronchospasm SpO2 ≥ ${D.RECOVERY.SPO2_MIN} and internal PaCO2 < ${D.PACO2_MAX} mmHg; laryngospasm SpO2 ≥ ${D.RECOVERY.SPO2_MIN}; anaphylaxis MAP ≥ ${D.RECOVERY.MAP_MIN} and SpO2 ≥ ${D.RECOVERY.SPO2_MIN}; light anaesthesia MAP ≤ ${D.RECOVERY.MAP_MAX}, HR ≤ ${D.RECOVERY.HR_MAX} and processed-EEG index ≤ 60. All thresholds are reused simulator values (alarm thresholds, GA band, model hypercapnia threshold). The composite (MAP ≥ 65, HR ≥ 50, SpO2 ≥ 92 together) is in the per-patient table. Observation window ${C.OBSERVE_SEC} s (laryngospasm ${C.OBSERVE_LARYNGOSPASM_SEC} s after extubation).`, '');
const ems = [...D.EMERGENCIES, 'light_anesthesia_stimulus:lightened'];
L.push('| emergency | arm | runs | recovered | median time to recovery (recovered runs; 0 s = never deranged) | deranged runs | median s primary deranged | median deficit | rescue vs control (patients: better / no difference / worse / never deranged) |', '|---|---|---|---|---|---|---|---|---|');
const verdicts = {};
for (const em of ems) {
const rows = eff.filter((c) => c.emergency === em);
for (const arm of ['control', 'rescue', 'rescue_im', 'aggressive']) {
const cs = rows.filter((c) => c.arm === arm); if (!cs.length) continue;
const n = sum(cs.map((c) => c.n)); const rec = sum(cs.map((c) => c.recovered)); const der = sum(cs.map((c) => c.deranged));
const times = cs.flatMap((c) => c.times); const secs = cs.flatMap((c) => c.secPrimary);
let v = '';
if (arm !== 'control') {
const cmp = D.compareArms(rows, arm); const t = tallyObj(cmp.map((x) => x.verdict));
verdicts[`${em}|${arm}`] = cmp;
v = `${(t.better || 0) + (t.better_time_deranged || 0) + (t.better_deficit || 0)} / ${t.no_difference || 0} / ${t.worse || 0} / ${t.no_derangement || 0}`;
}
L.push(`| ${em} | ${arm} | ${n} | ${rec}/${n} (${pct(rec / n)}) | ${fmtT(D.median(times))} | ${der} | ${n0(D.median(secs))} | ${n0(D.median(cs.flatMap((c) => c.deficit)))} | ${v} |`);
}
}
L.push('', '"better" = recovers more often, or as often and faster (median), or spends less time with the primary sign deranged, or has a smaller median deficit (shortfall beyond the primary limit summed over the window, e.g. mmHg·s below MAP 65). The aggressive arm is a cap probe, not a treatment; its "efficacy" mostly reflects overshoot.', '');
L.push('### Per patient: control vs rescue', '');
L.push('| emergency | patient | control: rec / median / worst | rescue: rec / median / worst | verdict |', '|---|---|---|---|---|');
for (const em of ems) {
const cmp = verdicts[`${em}|rescue`] || [];
for (const x of cmp) {
const w = (c) => (em.startsWith('light') ? `MAP ≤${n0(c.worstMaxMap)}, index ≤${n0(c.worstMaxDepth)}` : em === 'vagal_bradycardia' ? `HR ≥${n0(c.worstMinHr)}` : em === 'bronchospasm' ? `PaCO2 ≤${n0(c.worstMaxPaco2)}, SpO2 ≥${n0(c.worstMinSpo2)}` : em.startsWith('laryngo') ? `SpO2 ≥${n0(c.worstMinSpo2)}` : `MAP ≥${n0(c.worstMinMap)}`);
L.push(`| ${em} | ${x.patientId} | ${x.control.recovered}/${x.control.n} / ${fmtT(x.control.medianTime)} / ${w(x.control)} | ${x.rescue.recovered}/${x.rescue.n} / ${fmtT(x.rescue.medianTime)} / ${w(x.rescue)} | ${x.verdict} |`);
}
}
L.push('');
// ---- combos
L.push('## Emergencies combined with faults and holds (rescue arm)', '');
L.push('| combination | runs | safety violations | rescue path available during fault/hold (of which a probe bolus was refused only by the label repeat interval since the strategy\'s own previous dose) | held infusion restart refused | primary recovered | hold latched at end |', '|---|---|---|---|---|---|---|');
for (const cb of D.COMBOS) {
const rs = combos.filter((r) => r.combo === cb);
const pr = rs.map((r) => r.probes.fault || r.probes.hold).filter(Boolean);
const rescueOk = pr.filter((p) => p.results.filter((x) => !/restart/.test(x.what)).every((x) => x.ok || x.repeatRefused || /Cumulative|cumulative|Total bolus/.test(x.reason || ''))).length;
const repeatOnly = pr.filter((p) => p.results.some((x) => !x.ok && x.repeatRefused)).length;
const restarts = pr.flatMap((p) => p.results.filter((x) => /restart/.test(x.what)));
L.push(`| ${cb} | ${rs.length} | ${rs.filter((r) => !r.ok).length} | ${rescueOk}/${pr.length} (${repeatOnly}) | ${restarts.filter((x) => !x.ok).length}/${restarts.length} | ${rs.filter((r) => r.metrics && r.metrics.recovered).length}/${rs.length} | ${rs.filter((r) => r.interlock && r.interlock.holdLatchedAtEnd).length}/${rs.length} |`);
}
L.push('');
L.push(renderNotes(D, records, eff));
return `${L.join('\n')}\n`;
}
/** Narrative sections with numbers computed from this run (findings, gaps, conventions, patients). */
function renderNotes(D, records, eff) {
const L = [];
const matrix = records.filter((r) => !r.combo && !r.variant);
const C = D.DRIVER_CONVENTIONS;
const pre = new Map(); for (const r of matrix.filter((x) => x.arm === 'control' && x.emergency === 'hemorrhage' && x.timing === 'early' && x.seed === 1)) pre.set(r.patientId, r.preOnset);
const preLow = [...pre.entries()].filter(([, v]) => v.map < 65);
const cell = (em, pid, arm) => eff.find((c) => c.emergency === em && c.patientId === pid && c.arm === arm);
const notRecovered = (em, arm) => eff.filter((c) => c.emergency === em && c.arm === arm && c.recovered < c.n).map((c) => `${c.patientId} ${c.recovered}/${c.n} (worst MAP ${n0(c.worstMinMap)})`);
const lightDefault = eff.filter((c) => c.emergency === 'light_anesthesia_stimulus' && c.arm === 'control');
const vag = eff.filter((c) => c.emergency === 'vagal_bradycardia');
const vagC = vag.filter((c) => c.arm === 'control'); const vagR = vag.filter((c) => c.arm === 'rescue');
const bron = eff.filter((c) => c.emergency === 'bronchospasm');
const lary = eff.filter((c) => c.emergency === 'laryngospasm_on_extubation' && c.arm === 'control');
const ana = (arm) => eff.filter((c) => c.emergency === 'anaphylaxis_hypotension' && c.arm === arm);
const agg = matrix.filter((r) => r.arm === 'aggressive');
const aggTot = (key) => Math.max(...agg.map((r) => (r.doseSummary[key] ? r.doseSummary[key].total : 0)));
L.push('## Findings (illustrative model behaviour; reported, not tuned)', '');
L.push(`1. **Model limit — pre-emergency hypotension at the default plan (documented only; no dose or physiology change, owner decision).** With the ga_opioid template (label-default fentanyl, propofol induction, 1.0 × age-adjusted MAC sevoflurane, or propofol TIVA when sevoflurane is locked), MAP was already < 65 just before the onset in ${preLow.length}/${pre.size} patients (seed 1, early onset): ${preLow.map(([id, v]) => `${id} ${v.map}`).join(', ')} mmHg (processed-EEG index ${[...pre.values()].map((v) => v.depth).sort((a, b) => a - b)[0]}–${[...pre.values()].map((v) => v.depth).sort((a, b) => b - a)[0]}). Consistent with the documented deep reading of the illustrative depth model at label-default maintenance (TIMING_CONFIG DEPTH_LOW_ADVISORY note). Many hemorrhage/anaphylaxis "recoveries" therefore start from a pre-existing derangement; arms are still compared on the same pre-onset state.`);
L.push(`2. **Hemorrhage: fluids + accepted label vasopressor advisories do not restore MAP ≥ 65 in every patient class.** Not recovered within ${C.OBSERVE_SEC} s in: ${notRecovered('hemorrhage', 'rescue').join('; ') || 'none'}. The bleeding never stops in the scenario (holdSec null; surgical control is not modelled), crystalloid offsets at most 80 % of the loss (FLUID_MODEL), the driver gives at most ${C.FLUID_MAX_BOLUSES} × ${C.FLUID_BOLUS_ML} mL, and the advisory stops at the phenylephrine 200 mcg / ephedrine 50 mg cumulative label maxima ("label maximum reached — escalate; not simulated"). Control: ${eff.filter((c) => c.emergency === 'hemorrhage' && c.arm === 'control').reduce((a, c) => a + c.recovered, 0)}/${eff.filter((c) => c.emergency === 'hemorrhage' && c.arm === 'control').reduce((a, c) => a + c.n, 0)} runs recovered.`);
L.push(`3. **Vagal bradycardia: the scenario resolves by itself; glycopyrrolate 0.1 mg (label rescue dose [S8]) helps only a little.** Control median time to HR ≥ 50: ${fmtT(D.median(vagC.flatMap((c) => c.times)))}; rescue ${fmtT(D.median(vagR.flatMap((c) => c.times)))}. Median seconds with HR < 50: control ${n0(D.median(vagC.flatMap((c) => c.secPrimary)))}, rescue ${n0(D.median(vagR.flatMap((c) => c.secPrimary)))}; worst nadir HR control ${Math.min(...vagC.map((c) => c.worstMinHr))}, rescue ${Math.min(...vagR.map((c) => c.worstMinHr))} /min. Cause: the event lasts 10 s ramp + 90 s + 30 s resolve, and glycopyrrolate uses the generic illustrative PK (no label onset statement; ke0 0.3 /min, effect-site half-time ≈ 2.3 min), so its effect arrives as the event ends. The largest benefit is in the beta-blocker patient (control ${fmtT(cell('vagal_bradycardia', 'beta_blocker_brady', 'control') && cell('vagal_bradycardia', 'beta_blocker_brady', 'control').medianTime)} vs rescue ${fmtT(cell('vagal_bradycardia', 'beta_blocker_brady', 'rescue') && cell('vagal_bradycardia', 'beta_blocker_brady', 'rescue').medianTime)}). "Stop the stimulus" cannot be modelled (gap).`);
L.push(`4. **Bronchospasm does not desaturate a ventilated patient at FiO2 ${C.FIO2_MAINTENANCE}.** Worst SpO2 across all arms ${Math.min(...bron.map((c) => c.worstMinSpo2))} %; the scenario shows as hypercapnia (control worst internal PaCO2 ${Math.max(...bron.filter((c) => c.arm === 'control').map((c) => c.worstMaxPaco2))} mmHg, rescue ${Math.max(...bron.filter((c) => c.arm === 'rescue').map((c) => c.worstMaxPaco2))} mmHg). The rescue (FiO2 1.0, deepen once, IV epinephrine 50 mcg when EtCO2 > ${C.ETCO2_HIGH_MMHG} or SpO2 < 90) keeps PaCO2 below ${D.PACO2_MAX} mmHg; deepening alone does little because the hypnotic effect is already near maximal (bronchospasm is countered by 0.4 × hypnosis). The IV epinephrine dose is the perioperative-anaphylaxis guideline dose [S44, S45] — no bronchospasm-specific IV regimen is in the library.`);
L.push(`5. **Laryngospasm desaturates only the obese patients** (FiO2 left at ${C.FIO2_EMERGENCE} through extubation): control worst SpO2 ${lary.map((c) => `${c.patientId} ${c.worstMinSpo2}`).filter((x) => Number(x.split(' ')[1]) < 92).join(', ') || 'none < 92'}; every other patient stays ≥ 92 % during the 120-s spasm. Rescue (FiO2 1.0, jaw thrust, positive-pressure mask ventilation, which breaks the spasm after ${45} s in the scenario) prevents the desaturation. With FiO2 1.0 before extubation (checked while building the matrix) no patient desaturated.`);
const lt = (arm) => eff.filter((c) => c.emergency === 'light_anesthesia_stimulus:lightened' && c.arm === arm);
const ltRuns = records.filter((r) => r.variant === 'lightened');
const ltDer = (arm) => ltRuns.filter((r) => r.arm === arm && r.metrics.deranged);
L.push(`6. **Light anaesthesia / strong stimulus is fully blunted at the default maintenance.** Control: no patient exceeded MAP 120, HR 120 or index 60 (worst MAP ${Math.max(...lightDefault.map((c) => c.worstMaxMap))}, worst HR ${Math.max(...eff.filter((c) => c.emergency === 'light_anesthesia_stimulus' && c.arm === 'control').map((c) => c.worstMaxHr))}, worst index ${Math.max(...lightDefault.map((c) => c.worstMaxDepth))}), so efficacy cannot be tested there ("never deranged"). In the "lightened" variant (hypnotic at the bottom of its label range ${C.LIGHTEN_BEFORE_SEC} s before the stimulus, every arm) the index exceeded 60 in ${ltDer('control').length}/${ltRuns.filter((r) => r.arm === 'control').length} control runs (worst index ${Math.max(...lt('control').map((c) => c.worstMaxDepth))}), while MAP stayed ≤ ${Math.max(...lt('control').map((c) => c.worstMaxMap))} and HR ≤ ${Math.max(...lt('control').map((c) => c.worstMaxHr))}; of those deranged runs the control recovered in ${ltDer('control').filter((r) => r.metrics.recovered).length} (the anaesthetic stays light), the rescue (fentanyl maintenance boluses [S13], deepen once within the regimen range) in ${ltDer('rescue').filter((r) => r.metrics.recovered).length}/${ltDer('rescue').length} (median ${fmtT(D.median(ltDer('rescue').map((r) => r.metrics.timeToRecoverySec).filter((x) => x !== null)))}). The model's stimulus response (GAINS.STIM_MAP_GAIN 0.4 × stimulus blunted by analgesia and hypnosis) cannot take MAP above 120 from these baselines once label-default analgesia is present.`);
L.push(`7. **Anaphylaxis: IV epinephrine 50 mcg [S44, S45] + fluids recovers fastest; IM 0.3 mg [S40] is slower; the control recovers only when the scripted event ends** (control median ${fmtT(D.median(ana('control').flatMap((c) => c.times)))}, rescue IV ${fmtT(D.median(ana('rescue').flatMap((c) => c.times)))}, rescue IM ${fmtT(D.median(ana('rescue_im').flatMap((c) => c.times)))}). Slowest rescue: ${ana('rescue').sort((a, b) => (b.medianTime ?? 1e9) - (a.medianTime ?? 1e9)).slice(0, 3).map((c) => `${c.patientId} ${fmtT(c.medianTime)}`).join(', ')}. The phenylephrine/ephedrine advisory is suppressed during anaphylaxis by design.`);
const aggS = (key, f) => sum(agg.map((r) => (r.doseSummary[key] ? f(r.doseSummary[key]) : 0)));
L.push(`8. **Aggressive arm after the owner decisions (repeat refusal, teaching ceilings).** Before (commit 21637da) every too-close repeat was accepted with a warning: up to 60.5 mg IM epinephrine, 6.05 mg IV epinephrine and 12.1 mg glycopyrrolate per run (104,616 warned-and-accepted doses in 432 runs). Now, in ${agg.length} runs: repeats refused — phenylephrine ${aggS('phenylephrine:bolus:IV', (x) => x.repeatRefused)}, epinephrine IM ${aggS('epinephrine:bolus:IM', (x) => x.repeatRefused)}, glycopyrrolate ${aggS('glycopyrrolate:bolus:IV', (x) => x.repeatRefused)}; teaching-ceiling refusals (confirmation required) — epinephrine IV ${aggS('epinephrine:bolus:IV', (x) => x.teachingRefused)}, crystalloid ${sum(agg.map((r) => ((r.teaching || []).find((x) => x.key === 'crystalloid') || {}).refusals || 0))}; per run at most epinephrine IM ${round2(aggTot('epinephrine:bolus:IM'))} mg (one 0.5 mg injection per 5 min), IV ${round2(aggTot('epinephrine:bolus:IV'))} mg (0.5 mg ceiling + the one deliberately confirmed dose), glycopyrrolate ${round2(aggTot('glycopyrrolate:bolus:IV'))} mg. Per-injection caps, the phenylephrine 200 mcg / ephedrine 50 mg cumulative caps and all rate ceilings held as before. Ephedrine ("as needed") and IV epinephrine ("titrated") still have no label interval; ephedrine is limited by its 50 mg label total, IV epinephrine by the teaching ceiling. Midazolam's repeat rule stays warn-only (owner decision; its label wording — "wait an additional 2 or more minutes to fully evaluate the sedative effect" — is titration guidance rather than a stated dosing interval).`);
L.push('');
L.push('## Fixes and owner decisions', '');
L.push('- **Label repeat intervals of rescue boluses were not checked at all (silent).** A phenylephrine, glycopyrrolate (rescue) or IM/SC epinephrine bolus repeated sooner than the label interval was accepted with no warning and no record (only the advisory knew the phenylephrine interval). Fix: `engine/timing.js` TIMING_CONFIG `PHENYLEPHRINE_REPEAT_MIN_SEC` 60 s [S18], `GLYCOPYRROLATE_RESCUE_REPEAT_MIN_SEC` 120 s [S8] (not in emergence, where glycopyrrolate goes with neostigmine), `EPINEPHRINE_IM_REPEAT_MIN_SEC` 300 s [S40] (lower bounds of the label intervals), read by `repeatBolusHold` / `labelRepeatHold` (first a warning for manual repeats in commit 21637da, now a refusal — next item); the bolus route is now recorded in the dose log so IM and IV epinephrine are gated separately. Ephedrine ("as needed") and IV epinephrine ("titrated to effect") have no stated interval and are not gated.');
L.push('- **Owner decision: too-close clinician-entered repeats are refused.** `sim.administer` refuses (BLOCKED, logged with the label interval and the seconds remaining) a manual or accepted-advisory repeat of phenylephrine IV < 60 s, glycopyrrolate IV < 120 s outside emergence or IM/SC epinephrine < 300 s after the previous one (`engine/timing.js` `labelRepeatHold`); planned repeats keep waiting. Midazolam and the rocuronium top-up stay warn-only.');
L.push('- **Owner decision: simulator teaching ceilings** (`engine/teaching-ceilings.js`, provenance simulator convention, no sourceIds; searched 2026-11-06 — no label or guideline states a cumulative maximum for intraoperative glycopyrrolate or perioperative IV epinephrine boluses; crystalloid has no label dose): IV epinephrine boluses 0.5 mg total (10 × the 50-mcg guideline titration step; = the label IM per-injection maximum), glycopyrrolate 1 mg total (10 × the 0.1 mg rescue dose; = the top of the emergence regimen range), crystalloid 30 mL/kg TBW total (the Surviving Sepsis 2021 initial volume already shown by the fluid model). A dose that would exceed one is refused until the clinician presses "Confirm dose above the simulator teaching ceiling" (`confirm_teaching_ceiling:<key>`, logged; covers one dose within 60 s). Guided/automatic modes never confirm (a planned step above the ceiling is refused and skipped). The Run screen shows the ceiling and running total next to the dose form and the fluid buttons, with the confirm button after a refusal; the debrief has a "Simulator teaching ceilings" table.');
L.push('');
L.push('## Gaps the engine cannot model (not invented here)', '');
L.push('- Stopping the trigger (anaphylaxis: no causative drug is modelled; vagal bradycardia: the surgical stimulus cannot be stopped — both events run on their scripted time course).');
L.push('- Surgical control of bleeding and blood products (hemorrhage never stops; fluids temporise only).');
L.push('- Anticholinergic other than glycopyrrolate (no atropine regimen in the library); glycopyrrolate onset uses generic illustrative PK.');
L.push('- Inhaled bronchodilators, airway pressure / peak pressure, and a bronchospasm-specific epinephrine regimen; only the anaphylaxis guideline IV dose is available.');
L.push('- A laryngospasm-specific propofol or succinylcholine dose: the scenario resolves on any propofol/succinylcholine dose, but the library has only induction/sedation regimens, so the rescue arm uses airway manoeuvres and oxygen only.');
L.push('- A sourced antihypertensive (MAP > 120 advisory is text only) and a vasopressor infusion in the advisory (phenylephrine infusion exists in the library but is a manual choice).');
L.push('- A sourced cumulative maximum for IV epinephrine boluses, glycopyrrolate and crystalloid (simulator teaching ceilings stand in for them); fluid overload.');
L.push('');
L.push('## Patients, plans and strategies', '');
L.push('Fictional patients, each built through `derivePatient` (validation applies). Plans: `ga_opioid` technique template via `buildTemplatePlan` (sevoflurane → propofol TIVA fallback for the MH-susceptible patient); hold combinations use `ga_opioid_free` (dexmedetomidine, ketamine, lidocaine infusions). Every plan passes the plan-safety check.', '');
L.push('| id | patient | BMI | flags | plan substitutions |', '|---|---|---|---|---|');
for (const sp of D.STRESS_PATIENTS) {
const p = D.stressPatient(sp.id); const r = matrix.find((x) => x.patientId === sp.id);
L.push(`| ${sp.id} | ${sp.label} | ${Math.round(p.bmi * 10) / 10} | ${(p.flags || []).join(', ')} | ${r && r.plan.substitutions.length ? r.plan.substitutions.join(', ') : '—'} |`);
}
L.push('');
L.push('Arms (every dose from `recommend()`; label/guideline sources in brackets):', '');
L.push('- **control** — nothing; the rescue advisor is attached but never accepted (it must never dose by itself).');
L.push(`- **rescue** — hemorrhage: lactated Ringer's ${C.FLUID_BOLUS_ML} mL when MAP < 65 (one at a time, ≤ ${C.FLUID_MAX_BOLUSES}) + every phenylephrine/ephedrine advisory accepted [S18, S19]; vagal bradycardia: glycopyrrolate 0.1 mg IV when HR < 50, ≥ 120 s apart [S8] + advisories; bronchospasm: after ${C.RECOGNITION_SEC} s FiO2 1.0 and deepen once (sevoflurane +${C.DEEPEN_VOLATILE_STEP_PCT} % or propofol +${C.DEEPEN_PROPOFOL_STEP} mcg/kg/min, within the regimen range), epinephrine 50 mcg IV when EtCO2 > ${C.ETCO2_HIGH_MMHG} or SpO2 < 90, ≥ ${C.NO_LABEL_INTERVAL_REPEAT_SEC} s apart [S44, S45]; laryngospasm: 5 s after extubation FiO2 1.0, jaw thrust, positive-pressure mask ventilation until resolved and SpO2 ≥ 94 for 30 s; light anaesthesia: when MAP > 120, HR > 120 or index > 60, fentanyl maintenance bolus (≤ ${C.FENTANYL_MAX_DOSES}, ≥ ${C.FENTANYL_REPEAT_SEC} s apart) [S13] and deepen once; anaphylaxis: FiO2 1.0, fluids as hemorrhage, epinephrine 50 mcg IV when MAP < 65 ≥ ${C.NO_LABEL_INTERVAL_REPEAT_SEC} s apart, after ${C.EPI_INFUSION_AFTER_BOLUSES} boluses an epinephrine infusion from 0.05 mcg/kg/min IBW, +0.05 every ${C.EPI_INFUSION_STEP_SEC / 60} min while MAP < 65 [S40, S41, S44, S45].`);
L.push('- **rescue_im** (anaphylaxis) — as rescue but epinephrine 0.3 mg IM when MAP < 65, ≥ 300 s apart (label [S40]); no IV epinephrine.');
L.push(`- **aggressive** — every ${C.AGGRESSIVE_EVERY_SEC} s for ${C.AGGRESSIVE_FOR_SEC} s: the regimen-maximum bolus of phenylephrine, ephedrine, epinephrine IV and IM, glycopyrrolate, a 500 mL fluid bolus and a refused 1000 mL bolus; every 30 s twice a hard cap (phenylephrine cumulative, epinephrine per IV and IM injection, ephedrine cumulative) and twice the ephedrine regimen maximum; at the onset every infusion at twice and at exactly its rate ceiling (epinephrine, phenylephrine, propofol, dexmedetomidine) and the sevoflurane dial at twice its ceiling; at 60 s a direct state write of an epinephrine rate (must be re-validated).`);
L.push('');
L.push('Driver conventions (simulated clinician; not clinical recommendations):', '', '| name | value |', '|---|---|');
for (const [k, v] of Object.entries(C)) L.push(`| ${k} | ${typeof v === 'object' ? JSON.stringify(v) : v} |`);
L.push('');
L.push(`Plausible bounds: the physiology clamps MAP and HR to ${D.MODEL_CLAMPS.map.join('–')} and SpO2 to ${D.MODEL_CLAMPS.spo2.join('–')} (engine/physiology.js); the asserted bounds are a little wider than these clamps (so a clamp failure would be caught) and everything outside them is non-physiological. Seconds spent at a clamp are reported above as a sign of model saturation, not a pass/fail criterion. Timeline: premed ${C.PREMED_SEC} s, induction ${C.INDUCTION_SEC} s (FiO2 1.0), airway secured, maintenance FiO2 ${C.FIO2_MAINTENANCE}, incision after ${C.PRE_INCISION_SEC} s, onset ${C.ONSET_AFTER_INCISION_SEC.early} s (early) or ${C.ONSET_AFTER_INCISION_SEC.late} s (late) after incision; laryngospasm is armed at that time and starts at extubation (at readiness, or readiness + 180 s for "late"), after ${C.SURGERY_SEC_BEFORE_EMERGENCE} s of surgery.`);
L.push('');
return L.join('\n');
}
function tally(arr) { const m = new Map(); for (const x of arr) m.set(x, (m.get(x) || 0) + 1); return [...m.entries()].sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1)); }
function tallyObj(arr) { const o = {}; for (const x of arr) o[x] = (o[x] || 0) + 1; return o; }
function sum(a) { return a.reduce((x, y) => x + (Number(y) || 0), 0); }
function round2(x) { return Math.round(x * 100) / 100; }
// Entry point last (the helpers above are initialised before main() runs).
if (!isMainThread) {
const D = await import('../tests/emergency-stress.mjs');
parentPort.postMessage(workerData.cases.map((c) => slim(D.runCase(c))));
} else {
await main();
}