Infusion pump — the programmed rate can never exceed the drug's hard limit ("guardrails") A nurse programming an IV pump types the rate by hand
A misplaced decimal — 250 mL/h instead of 25, or a 10x insulin/heparin overdose — has killed patients; the infamous cases turn on a keypad slip that the pump dutifully obeyed. The fix the industry settled on is a "drug library" with hard maximums (Guardrails): the pump simply REFUSES to run faster than the ceiling for that drug, no override. Here the programmed rate lives in a memory slot whose invariant is the hard guardrail — a write above the maximum (or a negative rate) is rejected and the pump keeps its last safe setting. The cumulative volume infused is a second bounded ledger, so a runaway pump cannot silently deliver more than the bag holds.
A Soma program from the medical part of the verified corpus: 113 lines, cells InfusionPump, InfusionTests. It passes soma check with soma 3.2.4.
How it is built
The cell InfusionPump declares 5 signals in its face: program(line: String, rate: Int) -> Map, infuse(line: String, minutes: Int) -> Map, rate_of(line: String) -> Int, volume_of(line: String) -> Int and demo() -> String; keeps 2 memory slots: rate (Map<String, Int>, persistent and consistent) under the invariant rate >= 0 && rate <= 200 and volume (Map<String, Int>, persistent and consistent) under the invariant volume >= 0 && volume <= 1000. Handlers: program (line 48), infuse (line 61), rate_of (line 74), volume_of (line 75) and demo (line 77).
The file also holds 1 test cell (InfusionTests) with 12 assertions, run by soma test.
The source
infusion_pump.cell
// ============================================================================
// INFUSION PUMP — the programmed rate can never exceed the drug's hard
// limit ("guardrails")
// ============================================================================
//
// A nurse programming an IV pump types the rate by hand. A misplaced
// decimal — 250 mL/h instead of 25, or a 10x insulin/heparin overdose —
// has killed patients; the infamous cases turn on a keypad slip that the
// pump dutifully obeyed. The fix the industry settled on is a "drug
// library" with hard maximums (Guardrails): the pump simply REFUSES to run
// faster than the ceiling for that drug, no override.
//
// Here the programmed rate lives in a memory slot whose invariant is the
// hard guardrail — a write above the maximum (or a negative rate) is
// rejected and the pump keeps its last safe setting. The cumulative volume
// infused is a second bounded ledger, so a runaway pump cannot silently
// deliver more than the bag holds.
//
// soma check examples/corpus/medical/infusion_pump.cell
// soma test examples/corpus/medical/infusion_pump.cell
// soma run examples/corpus/medical/infusion_pump.cell demo
// ============================================================================
cell InfusionPump {
face {
signal program(line: String, rate: Int) -> Map
signal infuse(line: String, minutes: Int) -> Map
signal rate_of(line: String) -> Int
signal volume_of(line: String) -> Int
signal demo() -> String
}
memory {
// Programmed rate in mL/h. The invariant IS the drug-library
// guardrail: a keypad slip to 999 mL/h is rejected at the write,
// the pump never accepts it. (Demo ceiling: 200 mL/h.)
rate: Map<String, Int> [persistent, consistent]
invariant rate >= 0 && rate <= 200
// Cumulative volume infused, mL. Bounded by the bag size — a
// runaway total is a rejected write.
volume: Map<String, Int> [persistent, consistent]
invariant volume >= 0 && volume <= 1000
}
// Program a rate. The guardrail is the invariant; a slip above the
// ceiling raises and the previous safe rate stands.
on program(line: String, rate_ml_h: Int) {
let w = try { rate.set(line, rate_ml_h) }
if w.error != () {
let cur = rate.get(line) ?? 0
return map("ok", false,
"reason", "rate {rate_ml_h} mL/h exceeds guardrail — refused",
"rate", cur)
}
return map("ok", true, "rate", rate_ml_h)
}
// Run for some minutes at the programmed rate, adding to the volume
// ledger. The ledger refuses to overflow the bag.
on infuse(line: String, minutes: Int) {
let r = rate.get(line) ?? 0
if r == 0 { return map("ok", false, "reason", "no rate programmed") }
let added = idiv(r * minutes, 60)
let cur = volume.get(line) ?? 0
let w = try { volume.set(line, cur + added) }
if w.error != () {
return map("ok", false, "reason", "bag exhausted — infusion halted: {w.error}",
"volume", cur)
}
return map("ok", true, "added", added, "volume", cur + added)
}
on rate_of(line: String) { return rate.get(line) ?? 0 }
on volume_of(line: String) { return volume.get(line) ?? 0 }
on demo() {
program("line-1", 25) // intended rate
let slip = program("line-1", 250) // decimal slip — REFUSED
infuse("line-1", 60) // 25 mL/h for 1h => 25 mL
let r = rate_of("line-1")
let v = volume_of("line-1")
print("decimal slip: {slip}")
print("held rate: {r}") // still 25, not 250
print("infused mL: {v}")
return "demo done"
}
}
cell test InfusionTests {
rules {
// a safe rate programs and runs
assert program("a", 50).ok == true
assert rate_of("a") == 50
assert infuse("a", 60).ok == true // 50 mL in an hour
assert volume_of("a") == 50
// the guardrail refuses an over-ceiling rate; the safe rate stands
assert program("a", 999).ok == false
assert rate_of("a") == 50 // unchanged
assert_fails rate.set("a", 201)
assert_fails rate.set("a", -10)
// the volume ledger refuses to overflow the bag
assert program("b", 200).ok == true
assert_fails volume.set("b", 1001)
assert_fails volume.set("b", -1)
// no rate, no infusion
assert infuse("c", 30).ok == false
}
}What the toolchain says
$ soma check infusion_pump.cell
warning: parameter 2 of `program`: the face calls it `rate`, the handler `rate_ml_h` — an HTTP JSON body is matched by NAME (the handler's), and `soma describe` publishes the face's: use one name
--> infusion_pump.cell:26:9
|
26 | signal program(line: String, rate: Int) -> Map
| ^
✓ 1 warning(s), no errors.$ soma test infusion_pump.cell
test InfusionTests ...
✓ assert program("a", 50).ok == true
✓ assert rate_of("a") == 50
✓ assert infuse("a", 60).ok == true
✓ assert volume_of("a") == 50
✓ assert program("a", 999).ok == false
✓ assert rate_of("a") == 50
✓ assert_fails rate.set("a", 201) — raised memory invariant violated on 'rate': rate >= 0 && rate <= 200 — rejected write of 201 (key "a"); the slot is unchanged
✓ assert_fails rate.set("a", -10) — raised memory invariant violated on 'rate': rate >= 0 && rate <= 200 — rejected write of -10 (key "a"); the slot is unchanged
✓ assert program("b", 200).ok == true
✓ assert_fails volume.set("b", 1001) — raised memory invariant violated on 'volume': volume >= 0 && volume <= 1000 — rejected write of 1001 (key "b"); the slot is unchanged
✓ assert_fails volume.set("b", -1) — raised memory invariant violated on 'volume': volume >= 0 && volume <= 1000 — rejected write of -1 (key "b"); the slot is unchanged
✓ assert infuse("c", 30).ok == false
12 tests: 12 passed, 0 failed$ soma verify infusion_pump.cell
Verifying infusion_pump.cell...
InfusionPump/invariants:
⚠ invariant rate >= 0 && rate <= 200 — runtime-checked (computed values): program → rate because `rate_ml_h` is a parameter (narrow it: `require rate_ml_h >= 0 && rate_ml_h <= 200 else …`)
⚠ invariant volume >= 0 && volume <= 1000 — runtime-checked (computed values): infuse → volume because `added` = idiv() — a builtin the prover does not bound
0 passed, 2 warnings, 0 failures
Temporal: 0 passed, 0 failed
VERIFY OK$ soma run infusion_pump.cell demo
decimal slip: {"ok": false, "reason": "rate 250 mL/h exceeds guardrail — refused", "rate": 25}
held rate: 25
infused mL: 25
demo done