Independent education · Sources and limitations documented
Portfolio / Smart NOA simulation

Software simulation

Source snapshot · 5 November 2026

simulator/tests/depth-advisory-runs.mjs

// Shared real-run driver for the depth-low advisory suites (not a test file itself: it is imported by
// tests/depth-advisory-2026-11.test.mjs and tests/depth-advisory-full-2026-11.test.mjs, which node --test
// runs in parallel). EDUCATIONAL SIMULATION — fictional patients — not a medical device.
//
// drive(..., withAdvisor = true) also instruments the advisor (audit 05l, finding 1), at no extra simulation cost:
//   - every update() call is recorded with its kind (post-step / refresh-only) and whether it ran inside
//     sim._substep, and the time counters before/after (lastT, runSec, episodeSec, totalBelowSec, entries);
//   - a SHADOW advisor (same class, reading the same simulation, its log discarded) is updated only after each
//     sim.step(1) — the "step-only path", never refreshed after an action — for comparison with the real one.
import assert from 'node:assert/strict';
import { REAL, clinicianResolves } from './helpers.mjs';
import { derivePatient } from '../engine/patient.js';
import { createSimulation } from '../engine/sim.js';
import { EXAMPLE_PATIENTS, EXAMPLE_PLANS, buildPlan } from '../data/scenarios.js';
import { createAutoRunner } from '../engine/autorun.js';
import { TIMING_CONFIG } from '../engine/timing.js';
import { DepthLowAdvisor, createDepthAdvisor, depthLowArmed } from '../engine/depth-advisory.js';

export const DONE = ['completed', 'stopped', 'manual'];
export const P = (id) => derivePatient(EXAMPLE_PATIENTS.find((x) => x.id === id).patient, { library: REAL });
const LO = TIMING_CONFIG.GA_DEPTH_BAND.value[0];

const counters = (a) => ({ lastT: a.lastT, runSec: a.runSec, episodeSec: a.episodeSec, totalBelowSec: a.totalBelowSec, entries: a.entries.length, active: a.active });

function instrument(sim, adv) {
  const calls = []; let inSub = false;
  const sub = sim._substep.bind(sim);
  sim._substep = (h) => { inSub = true; try { return sub(h); } finally { inSub = false; } };
  const orig = adv.update.bind(adv);
  adv.update = (opts) => {
    const before = counters(adv); const t = sim.state.tSec;
    const r = orig(opts);
    calls.push({ t, refreshOnly: !!(opts && opts.refreshOnly), inSubstep: inSub, before, after: counters(adv) });
    return r;
  };
  // Step-only shadow: reads the same simulation; its log lines go nowhere (the real log is untouched).
  const view = Object.create(sim, { logNote: { value: () => {} } });
  const shadow = new DepthLowAdvisor(view); shadow.update();
  return { calls, shadow };
}

export function drive(tpl, mode, seed, withAdvisor) {
  const p = P(tpl.patientId); const { plan } = buildPlan(tpl, p, REAL);
  const sim = createSimulation({ patient: p, plan, library: REAL, seed });
  const adv = withAdvisor ? createDepthAdvisor(sim) : null;
  const probe = adv ? instrument(sim, adv) : null;
  const runner = createAutoRunner({ sim, mode });
  const started = runner.start();
  let pauses = 0; let surgeryAt = null; const alarmIds = new Set(); let shownBeforeIncision = 0; let shownOutsideArm = 0;
  if (started.ok) {
    for (let i = 0; i < 14000 && !DONE.includes(runner.state); i++) {
      if (runner.state === 'paused') {
        pauses++;
        for (const a of sim.state.alarms) if (a.priority === 'high' && !a.acknowledged) sim.action(`acknowledge:${a.id}`);
        if (sim.core.holdLatched) sim.action('resume_hold');
        clinicianResolves(runner);
        if (runner.status().pauseDetails.some((d) => d.item === 'sedation')) runner.clinicianAction('acknowledge_sedation_below_target');
        runner.resume(); continue;
      }
      if (mode === 'guided') {
        const st = runner.status();
        if (st.current && st.current.gate) {
          clinicianResolves(runner);
          if (st.current.items && st.current.items.some((x) => x.id === 'sedation' && x.clinician && !x.met)) runner.clinicianAction('acknowledge_sedation_below_target');
          if (runner.status().current.enabled) runner.approve(st.current.id);
        }
      }
      const before = adv ? adv.entries.length : 0;
      sim.step(1);
      if (probe) probe.shadow.update(); // step-only path: same point as the real post-step update
      runner.tick();
      if (surgeryAt === null && sim.stim.surgeryStartAt !== null) surgeryAt = sim.stim.surgeryStartAt;
      for (const a of sim.state.alarms) alarmIds.add(a.id);
      if (adv && adv.entries.length > before) { if (surgeryAt === null) shownBeforeIncision++; if (!depthLowArmed(sim).armed) shownOutsideArm++; }
    }
  }
  return {
    sim, adv, runner, probe, started: started.ok, pauses, alarmIds, shownBeforeIncision, shownOutsideArm,
    outcome: { state: runner.state, stopReason: runner.stopReason || null, t: sim.state.tSec, phase: sim.state.phase, extubated: sim.stats.extubation ? sim.stats.extubation.tSec : null },
    doses: JSON.stringify(sim.doseLog), alarms: JSON.stringify(sim.alarmMgr.history), history: JSON.stringify(runner.history),
    rates: JSON.stringify(Object.fromEntries(Object.entries(sim.state.drugs).map(([id, d]) => [id, [d.cumulative, d.infusionRate]]))),
  };
}

// With-advisor runs kept for reuse by later tests in the same file (DA-R reuses DA7's full-auto runs).
const cache = new Map();
export function driveCached(tpl, mode, seed) {
  const k = `${tpl.id}|${mode}|${seed}`;
  if (!cache.has(k)) cache.set(k, drive(tpl, mode, seed, true));
  return cache.get(k);
}

/** DA7 for one mode: example plans × seeds 1–20, without vs with the advisor (assertions unchanged from 05k/05l). */
export function checkDA7(t, mode) {
  const freq = [];
  for (const tpl of EXAMPLE_PLANS) {
    let cases = 0; let shown = 0; let below = 0;
    for (let seed = 1; seed <= 20; seed++) {
      const a = drive(tpl, mode, seed, false); const b = driveCached(tpl, mode, seed);
      const tag = `${tpl.id} ${mode} seed ${seed}`;
      assert.deepEqual(b.outcome, a.outcome, `${tag}: completion outcome`);
      assert.equal(b.doses, a.doses, `${tag}: every dose and rate change identical`);
      assert.equal(b.rates, a.rates, `${tag}: final cumulative amounts and rates identical`);
      assert.equal(b.alarms, a.alarms, `${tag}: alarm history identical (no alarm added, none acknowledged by it)`);
      assert.equal(b.pauses, a.pauses, `${tag}: guided/automatic pauses identical`);
      assert.equal(b.history, a.history, `${tag}: runner history identical`);
      assert.ok(![...b.alarmIds].some((id) => /depth_low/.test(id)), `${tag}: no depth-low alarm`);
      assert.equal(b.shownBeforeIncision, 0, `${tag}: never before incision`);
      assert.equal(b.shownOutsideArm, 0, `${tag}: only while armed`);
      const rec = b.sim.summary().depthAdvisories;
      assert.equal(rec.used, true);
      if (tpl.mode === 'MAC') assert.equal(rec.shown, 0, `${tag}: never in MAC`);
      if (rec.shown) cases++;
      shown += rec.shown; below += rec.totalBelowBandSec;
      for (const x of rec.entries) assert.ok(x.shownAtSec >= b.sim.stim.surgeryStartAt || b.sim.stim.surgeryStartAt === null, tag);
      assert.equal(rec.dismissed, 0, `${tag}: nothing dismisses it automatically`);
      assert.ok(!b.sim.state.log.some((e) => /ADVISORY dismissed/.test(e.message) && /DEPTH-/.test(e.message)), tag);
    }
    freq.push(`${tpl.id}/${mode}: ${cases}/20 runs, ${shown} cards, mean ${Math.round(below / 20)} s below ${LO}`);
  }
  t.diagnostic(`depth-low advisory frequency (seeds 1–20): ${freq.join('; ')}`);
}
Source and scope

Published from Smart-NOA-Controller/simulator/tests/depth-advisory-runs.mjs at revision 6e5b205e3843. Full source text is retained; HTML presentation does not establish independent clinical review. In-memory simulation with no patient, monitor or pump interface; not clinically validated.