This document enumerates every condition that controls whether a task appears, is hidden, or changes behaviour in the CodeRunner app. It is intended for external validation of the clinical decision logic.
Primary sources:
src/data.ts—crNextTasks()task generation engine (lines 391–793)src/utils.ts— state reconstruction and implicit field transitions (lines 17–199)src/components/patient.tsx— task execution handlers and UI visibility guards
crNextTasks() in src/data.ts inspects the reconstructed patient state s
and returns an ordered list of recommended tasks. Tasks omitted from the return
value are not shown to the user.
Before any pathway logic runs, several values are derived from the log:
shockable = rhythm ∈ {VF, VT, VF_pVT}
aedDone = doneTasks["get-aed"] === true
shockCount = number of "shock" doses given
shockDoses = timestamps of every shock
epiDoses = timestamps of every epinephrine dose
amioDoses = timestamps of every amiodarone dose
lidoDoses = timestamps of every lidocaine dose
adenoDoses = timestamps of every adenosine dose
atropineDoses = timestamps of every atropine dose
lastLogAt = timestamp of the most recent log entry
isRecent = now − lastLogAt < 5 min
refTime = isRecent || cpr.active ? now : lastLogAt
roscDone = doneTasks["rosc"] === true
refTime is used instead of now for timing checks when the case has been
idle for more than 5 minutes, preventing stale sessions from producing
incorrect "medication due" states.
These appear before any pathway is entered to establish baseline information.
| Task | Condition to show |
|---|---|
check-alert |
alert === "?" |
check-breath |
breathing === "?" |
check-pulse |
pulse === "?" && !cpr.active && alert !== "Yes" |
check-rate |
pulse === "Yes" && rate === "?" |
check-rhythm |
pulse === "Yes" && rate ∈ {Fast, Slow} && rhythm === "?" |
check-symptomatic |
pulse === "Yes" && rate ∈ {Fast, Slow} && alert ∉ {No, Altered} && symptomatic === "?" |
check-weight |
type === "pediatric" && weightKg == null |
Entry condition: pulse === "No" || cpr.active
| Task | Condition |
|---|---|
get-aed |
!aedDone |
Epinephrine (epi)
epiReady =
epiDoses.length === 0
? (!shockable || shockCount >= 2) // first dose: no shock needed unless shockable (requires 2 shocks)
: refTime − epiDoses[last] >= 3 min // repeat: ≥ 3 min since last dose
Shown when: epiReady && !roscDone
Amiodarone (amio)
amioReady =
amioDoses.length === 0
|| refTime − amioDoses[last] >= 5 min
Shown when: shockable && shockCount >= 3 && amioReady
Dose logic:
- First dose → 300 mg
- Repeat dose → 150 mg
Lidocaine (lido) (alternative antiarrhythmic)
lidoReady =
lidoDoses.length === 0
|| refTime − lidoDoses[last] >= 5 min
Shown when: shockable && shockCount >= 3 && lidoReady
| Task | Condition |
|---|---|
shock |
shockable && aedDone |
start-cpr |
Always; label changes to "Single Rescuer" when rescuers === "Two" && !aedDone |
The paused state follows three mutually exclusive branches evaluated in order:
Branch 1 — ROSC detected (pulse === "Yes"):
| Task | Notes |
|---|---|
rosc |
Only task shown in this branch |
Branch 2 — Pulse or rhythm unknown (pulse === "?" || rhythm === "?"):
| Task | Notes |
|---|---|
pulse-rhythm-check |
Shown unless shock-during-pause suppression applies |
resume-cpr |
Shown instead of pulse-rhythm-check when a shock was delivered in this pause window and pulse === "No" |
Shock-during-pause suppression rule (src/data.ts lines 566–573):
If lastShockDose > cpr.pausedAt && pulse === "No", skip the rhythm check and
show resume-cpr directly (ACLS protocol: resume CPR immediately after shock).
Branch 3 — Pulse No, rhythm known (all other cases):
| Task | Condition |
|---|---|
shock |
shockable && aedDone |
epi / amio / lido |
Per medication readiness rules (§ 1.3.2) |
reversible (H's & T's) |
Always — recurring: true |
airway |
breathing !== "ETT" |
access |
!doneTasks["access"] |
resume-cpr |
Always |
shockBeforeCpr = shockDoses.some(d => d < cpr.cycleStartAt)
| Task | Condition |
|---|---|
pause-to-shock |
shockable && aedDone && !shockBeforeCpr |
pause-pulse-check |
pulse === "Yes" — label: "Pause CPR (Patient responsive)" if alert === "Yes", else "Pause CPR (Pulse detected)" |
pause-pulse-check |
rhythm === "NSR" && pulse !== "Yes" — label: "Pause for Pulse Check" (same task ID, different label) |
pause-pulse-check |
now − cpr.cycleStartAt >= 120 000 ms && pulse !== "Yes" && rhythm !== "NSR" && !(shockable && aedDone && !shockBeforeCpr) — label: "Pause for Rhythm Check" (2-minute ACLS cycle) |
airway |
breathing !== "ETT" |
access |
!doneTasks["access"] |
epi / amio / lido |
pulse === "No" && rhythm !== "?" — per medication readiness rules (§ 1.3.2) |
reversible (H's & T's) |
Always — recurring: true |
check-rescuers is evaluated outside all three CPR sub-states and can appear
even before CPR starts:
| Task | Condition |
|---|---|
check-rescuers |
rescuers === "?" && breathing !== "ETT" && epiDoses.length === 0 |
Entry condition: breathing === "No" && pulse !== "No" && !cpr.active
| Task | Condition |
|---|---|
opioid-reversal |
Always |
rescue-breaths |
pulse === "Yes" — recurring: true, kind: "critical" |
Condition: rate === "Fast" && given("pace") % 2 === 1
The modulo-2 check determines if pacing is currently active (odd start/stop count = running).
- Task:
wean-pacing—recurring: true
Entry condition: pulse === "Yes" && rate === "Fast" && symptomatic === "Yes"
These tasks appear for all rhythms when the entry condition is met:
| Task | Condition |
|---|---|
ecg |
Always |
access |
!doneTasks["access"] |
NSR sub-pathway (rhythm === "NSR"):
| Task | Condition | Recurring | Popup |
|---|---|---|---|
sinusTachDiff |
Always | Yes | sinusTachDiff |
sepsisBloodCx |
sepsisSuspected === "Yes" |
No | — |
sepsisAbx |
sepsisSuspected === "Yes" |
No | — |
sepsisLactate |
sepsisSuspected === "Yes" |
No | — |
sepsisIVF |
sepsisSuspected === "Yes" |
No | — |
The sinusTachDiff popup shows a two-section differential: Shock Causes (sepsis, hemorrhage, PE, anaphylaxis, transfusion reaction, tension pneumo, tamponade, neurogenic) and Other Causes (hypoxia, pain/anxiety, fever, hyperthyroidism, drug effect).
SVT sub-pathway (rhythm === "SVT"):
adenoGiven = adenoDoses.length
| Task | Condition |
|---|---|
adenosine |
adenoGiven < 3 — dose: 6 mg (1st), 12 mg (2nd+) |
cardiovert |
rhythm ∈ {AF, SVT, WideTach} |
Wide tachycardia sub-pathway (rhythm === "WideTach"):
amioReadyTach =
amioDoses.length === 0
|| refTime − amioDoses[last] >= 5 min
| Task | Condition | Dose |
|---|---|---|
amio |
amioReadyTach |
150 mg over 10 min (both 1st and repeat doses — slower rate than arrest amio) |
cardiovert |
rhythm ∈ {AF, SVT, WideTach} |
— |
AF sub-pathway (rhythm === "AF"): only cardiovert shown.
Entry condition: pulse === "Yes" && rate === "Slow" && symptomatic === "Yes"
atropineReady =
atropineDoses.length === 0
|| now − atropineDoses[last] >= 3 min
| Task | Condition |
|---|---|
access |
Always |
atropine |
given("atropine") < 3 && atropineReady |
pace |
given("pace") === 0 |
dopamine |
given("dopamine") === 0 |
Entry condition: alert === "Altered" && pulse !== "No"
| Task | Condition |
|---|---|
glucose |
glucose === "?" |
d50 |
glucose === "Low" |
check-stroke-sx |
strokeSx === "?" |
fast |
strokeSx === "Yes" |
ct |
strokeSx === "Yes" |
Entry condition: breathing === "Choking"
| Task | Condition | Recurring |
|---|---|---|
choking-cycles |
Always | Yes |
reassess-responsiveness |
Always | Yes |
After all pathways generate their task lists:
filtered = tasks.filter(t => t.recurring || !doneTasks[t.id])
Recurring tasks always remain visible. Non-recurring tasks are hidden once
doneTasks[taskId] === true.
Priority order (lower index = higher priority, src/data.ts lines 327–375):
- Cardiac arrest actions:
shock,cardiovert,pause-to-shock,start-cpr,rosc,resume-cpr,pause-pulse-check,pause-nsr-check,pulse-rhythm-check - Respiratory arrest:
rescue-breaths,opioid-reversal - Cardiac support:
get-aed,airway,epi,amio,lido,access,reversible,check-rescuers,meds-support - Tachycardia:
ecg,adenosine - Bradycardia:
atropine,pace,dopamine,wean-pacing - Altered/stroke:
glucose,d50,check-stroke-sx,fast,ct - Choking:
choking-cycles,reassess-responsiveness - Assessment:
check-alert,check-breath,check-pulse,check-rate,check-rhythm,check-symptomatic - Lowest:
check-weight
Tasks not found in the priority list are appended after all prioritised tasks, preserving their relative order.
The patient state is fully reconstructed by replaying the log. Several status field changes trigger automatic secondary changes.
New alert value |
Secondary effect |
|---|---|
"No" or "Altered" (from "Yes") |
pulse = "?" |
"Sedated" |
Only set implicitly when breathing is set to "ETT" |
New breathing value |
Secondary effect |
|---|---|
"ETT" |
alert = "Sedated" |
New pulse value |
Secondary effect |
|---|---|
"Yes" |
rhythm = "?" |
"?" or "No" |
rate = "?" |
"No" |
Also rhythm = "?" |
| Trigger | Secondary effect |
|---|---|
rate changes to a new value |
rhythm = "?" |
New rhythm value |
Secondary effect |
|---|---|
VT, VF, VF_pVT, PEA, or Asystole |
pulse = "No" |
Giving a shock always resets rhythm = "?".
Alert "Yes" override:
if alert === "Yes" → force pulse = "Yes"
Symptomatic auto-promotion:
if pulse === "Yes" && rate ∈ {Fast, Slow}:
if alert ∈ {No, Altered}: symptomatic = "Yes" // patient cannot self-report
else:
symptomatic = "?" // reset when not applicable
Medications are categorised as either discrete or continuous:
| Category | Medications | Valid action |
|---|---|---|
| Discrete | epi, amio, lido, adenosine, atropine, d50, naloxone | "give" |
| Continuous | dopamine, norepinephrine, vasopressin, procainamide, pacing (pace) |
"start" / "stop" |
Log entries that use the wrong action for a medication type are ignored during reconstruction.
| Log event | State change |
|---|---|
cpr.start |
cpr.active = true, cpr.cycleNumber = 1, resets pulse = "?", rhythm = "?", sets cycleStartAt |
cpr.resume |
cpr.cycleNumber++, clears pausedAt, resets pulse = "?", rhythm = "?" |
cpr.pause |
Sets pausedAt timestamp, preserves active = true |
cpr.sync |
Updates metronome anchor timestamp |
cpr.rosc / cpr.end |
cpr.active = false, clears pausedAt |
| Task completed | Side effects |
|---|---|
airway |
breathing = "ETT", alert = "Sedated" |
| Any other task | doneTasks[taskId] = true |
Continuous medications use start/stop log entries. Active state is determined by:
isActive = isContinuous && count % 2 === 1
- Odd count (1, 3, 5…) → medication is currently running
- Even count (0, 2, 4…) → medication is currently stopped
Pacing special case (on each pace log entry):
- If pacing is being stopped (
isActivebefore the stop), or ifrate !== "Fast": resetrate = "?"andrhythm = "?"
Adenosine/Atropine special case (on each give entry):
- Immediately reset
rate = "?"andrhythm = "?"(patient re-assessed after bolus)
getCprGuidance() in src/components/patient.tsx determines the compression/ventilation
ratio label displayed during CPR:
| Condition | Displayed guidance |
|---|---|
breathing === "ETT" && type === "pediatric" |
"Continuous · 1 breath/2-3s" |
breathing === "ETT" && type !== "pediatric" |
"Continuous · 1 breath/6s" |
rescuers === "Team" |
(empty — team manages own ratio) |
type === "pediatric" && rescuers === "Two" |
"Ratio = 15:2" |
| All other cases | "Ratio = 30:2" |
The CPR overlay tracks elapsed time within the current cycle:
elapsed = cpr.active && !cpr.pausedAt
? Date.now() − cpr.cycleStartAt
: cpr.pausedAt ? cpr.pausedAt − cpr.cycleStartAt : 0
near = !paused && elapsed >= 1 min 45 s // warning state
past = !paused && elapsed >= 2 min // alert state; triggers auto-collapse + 2-tone beep
The following table summarises when each editable status field is rendered in the UI:
| Field | Visible when | Disabled when |
|---|---|---|
alert |
Always | — |
breathing |
Always | — |
pulse |
alert !== "Yes" |
cpr.active && !cpr.pausedAt |
rate |
pulse === "Yes" |
— |
symptomatic |
pulse === "Yes" && rate ∈ {Fast,Slow} && alert ∉ {No, Altered} |
— |
rhythm (arrest options) |
pulse !== "Yes" && (pulse === "No" || cpr.active) && (aedDone || cpr.active) |
— |
rhythm (pulse options) |
pulse === "Yes" && rate !== "?" && rate !== "Normal" |
— |
rescuers |
(pulse === "No" || cpr.active) && breathing !== "ETT" && epiDoses.length === 0 |
— |
weightKg |
type === "pediatric" |
— |
glucose |
alert === "Altered" && pulse !== "No" |
— |
strokeSx |
alert === "Altered" && pulse !== "No" |
— |
sepsisSuspected |
pulse === "Yes" && rate === "Fast" && rhythm === "NSR" |
— |
Rhythm option sets by context:
- Arrest rhythm options: VF/VT, PEA, Asystole, NSR
- Fast pulse options: NSR, SVT, AF, Wide VT, TdP
- Slow pulse options: NSR, Sinus Bradycardia, 1° AVB, 2° AVB, 3° AVB
- Normal pulse options: NSR, AF
sepsisSuspected resets to "?" whenever rate changes (alongside rhythm reset).
| Task | Pathway entry | Additional guards | Recurring |
|---|---|---|---|
check-alert |
alert === "?" |
— | No |
check-breath |
breathing === "?" |
— | No |
check-pulse |
pulse === "?" && alert !== "Yes" |
!cpr.active |
No |
check-rate |
pulse === "Yes" |
rate === "?" |
No |
check-rhythm |
pulse === "Yes" && rate ∈ {Fast,Slow} |
rhythm === "?" |
No |
check-symptomatic |
pulse === "Yes" && rate ∈ {Fast,Slow} |
alert ∉ {No,Altered} && symptomatic === "?" |
No |
check-weight |
type === "pediatric" |
weightKg == null |
No |
get-aed |
pulse === "No" || cpr.active |
!aedDone |
No |
start-cpr |
pulse === "No" || cpr.active |
!cpr.active |
No |
shock (pre-CPR) |
pulse === "No" || cpr.active |
shockable && aedDone && !cpr.active |
No |
shock (paused) |
cpr.pausedAt |
shockable && aedDone && pulse === "No" |
No |
pause-to-shock |
cpr.active && !cpr.pausedAt |
shockable && aedDone && !shockBeforeCpr |
No |
pause-pulse-check |
cpr.active && !cpr.pausedAt |
pulse === "Yes" |
No |
pause-pulse-check (NSR) |
cpr.active && !cpr.pausedAt |
rhythm === "NSR" && pulse !== "Yes" — same task ID as above, label: "Pause for Pulse Check" |
No |
pause-pulse-check (2-min) |
cpr.active && !cpr.pausedAt |
now − cpr.cycleStartAt >= 120 000 ms && pulse !== "Yes" && rhythm !== "NSR" && !(shockable && aedDone && !shockBeforeCpr) — label: "Pause for Rhythm Check" |
No |
resume-cpr |
cpr.pausedAt (branch 3 only) |
pulse === "No" && rhythm !== "?" |
No |
rosc |
cpr.pausedAt (branch 1) |
pulse === "Yes" |
No |
pulse-rhythm-check |
cpr.pausedAt (branch 2) |
pulse === "?" || rhythm === "?" (suppressed if shock-during-pause with pulse "No") |
No |
epi |
pulse === "No" || cpr.active |
epiReady && !roscDone |
No |
amio (arrest) |
pulse === "No" || cpr.active |
shockable && shockCount >= 3 && amioReady |
No |
lido |
pulse === "No" || cpr.active |
shockable && shockCount >= 3 && lidoReady |
No |
reversible |
cpr.active (both running and paused branch 3) |
Paused: always in branch 3; Running: always | Yes |
airway |
cpr.active (both running and paused branch 3) |
breathing !== "ETT" |
No |
access |
cpr.active (both running and paused branch 3); also tach and brady pathways |
!doneTasks["access"] (arrest); always (tach/brady) |
No |
check-rescuers |
pulse === "No" || cpr.active (all cardiac arrest states, including pre-CPR) |
rescuers === "?" && breathing !== "ETT" && epiDoses.length === 0 |
No |
rescue-breaths |
breathing === "No" && pulse !== "No" && !cpr.active |
pulse === "Yes" |
Yes |
opioid-reversal |
breathing === "No" && pulse !== "No" && !cpr.active |
— | No |
wean-pacing |
rate === "Fast" |
given("pace") % 2 === 1 |
Yes |
ecg |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
Always within tach pathway | No |
access (tach) |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
Always within tach pathway | No |
sinusTachDiff |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm === "NSR" |
Yes |
sepsisBloodCx |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm === "NSR" && sepsisSuspected === "Yes" |
No |
sepsisAbx |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm === "NSR" && sepsisSuspected === "Yes" |
No |
sepsisLactate |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm === "NSR" && sepsisSuspected === "Yes" |
No |
sepsisIVF |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm === "NSR" && sepsisSuspected === "Yes" |
No |
adenosine |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm === "SVT" && adenoGiven < 3 |
No |
amio (tach) |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm === "WideTach" && amioReadyTach |
No |
cardiovert |
pulse === "Yes" && rate === "Fast" && symptomatic === "Yes" |
rhythm ∈ {AF, SVT, WideTach} |
No |
access (brady) |
pulse === "Yes" && rate === "Slow" && symptomatic === "Yes" |
Always within brady pathway | No |
atropine |
pulse === "Yes" && rate === "Slow" && symptomatic === "Yes" |
given < 3 && atropineReady |
No |
pace |
pulse === "Yes" && rate === "Slow" && symptomatic === "Yes" |
given("pace") === 0 |
No |
dopamine |
pulse === "Yes" && rate === "Slow" && symptomatic === "Yes" |
given("dopamine") === 0 |
No |
glucose |
alert === "Altered" && pulse !== "No" |
glucose === "?" |
No |
d50 |
alert === "Altered" && pulse !== "No" |
glucose === "Low" |
No |
check-stroke-sx |
alert === "Altered" && pulse !== "No" |
strokeSx === "?" |
No |
fast |
alert === "Altered" && pulse !== "No" |
strokeSx === "Yes" |
No |
ct |
alert === "Altered" && pulse !== "No" |
strokeSx === "Yes" — note: task ID is ct, not ct-stroke |
No |
choking-cycles |
breathing === "Choking" |
— | Yes |
reassess-responsiveness |
breathing === "Choking" |
— | Yes |