soma.cell

Controlled substance cabinet — the narcotic count must reconcile, always

Diversion of controlled drugs (fentanyl, morphine, oxycodone) from hospital cabinets is a real and deadly problem: nurses have overdosed stealing from the supply, and patients have been undertreated when their dose was diverted and saline charted instead. The DEA requires a perpetual inventory where every dispense, every waste, every return is accounted for and the physical count matches the record. Here the cabinet count is a CONSERVED quantity. You cannot dispense a vial that isn't there (count can't go negative), and a "waste" of a partial dose must be witnessed — recorded as its own ledger entry — so the on-hand plus dispensed plus wasted always reconciles. The invariant makes an impossible count (negative, or more than ever stocked) a rejected write, turning diversion-by-miscount into a hard error.

A Soma program from the medical part of the verified corpus: 133 lines, cells Cabinet, CabinetTests. It passes soma check with soma 3.2.4.

How it is built

The cell Cabinet declares 7 signals in its face: stock(drug: String, units: Int) -> Map, dispense(drug: String, nurse: String) -> Map, waste(drug: String, witness: String) -> Map, on_hand(drug: String) -> Int, dispensed_total(drug: String) -> Int, reconciles(drug: String) -> Bool and demo() -> String; keeps 4 memory slots: on_hand_slot (Map<String, Int>, persistent and consistent) under the invariant on_hand_slot >= 0 && on_hand_slot <= 1000, stocked (Map<String, Int>, persistent and consistent) under the invariant stocked >= 0 && stocked <= 1000, dispensed (Map<String, Int>, persistent and consistent) under the invariant dispensed >= 0 && dispensed <= 1000 and wasted (Map<String, Int>, persistent and consistent) under the invariant wasted >= 0 && wasted <= 1000. Handlers: stock (line 53), dispense (line 65), waste (line 78), on_hand (line 84), dispensed_total (line 85), reconciles (line 90) and demo (line 97).

The file also holds 1 test cell (CabinetTests) with 14 assertions, run by soma test.

Generated from soma describe on this file.

The source

controlled_substance.cell

// ============================================================================
// CONTROLLED SUBSTANCE CABINET — the narcotic count must reconcile, always
// ============================================================================
//
// Diversion of controlled drugs (fentanyl, morphine, oxycodone) from
// hospital cabinets is a real and deadly problem: nurses have overdosed
// stealing from the supply, and patients have been undertreated when their
// dose was diverted and saline charted instead. The DEA requires a
// perpetual inventory where every dispense, every waste, every return is
// accounted for and the physical count matches the record.
//
// Here the cabinet count is a CONSERVED quantity. You cannot dispense a
// vial that isn't there (count can't go negative), and a "waste" of a
// partial dose must be witnessed — recorded as its own ledger entry — so
// the on-hand plus dispensed plus wasted always reconciles. The invariant
// makes an impossible count (negative, or more than ever stocked) a
// rejected write, turning diversion-by-miscount into a hard error.
//
//   soma check examples/corpus/medical/controlled_substance.cell
//   soma test  examples/corpus/medical/controlled_substance.cell
//   soma run   examples/corpus/medical/controlled_substance.cell demo
// ============================================================================

cell Cabinet {
    face {
        signal stock(drug: String, units: Int) -> Map
        signal dispense(drug: String, nurse: String) -> Map
        signal waste(drug: String, witness: String) -> Map
        signal on_hand(drug: String) -> Int
        signal dispensed_total(drug: String) -> Int
        signal reconciles(drug: String) -> Bool
        signal demo() -> String
    }

    memory {
        // Physical units in the cabinet. Conserved: never negative, never
        // above the cabinet capacity. A dispense that would underflow is a
        // rejected write — diversion-by-miscount cannot be charted.
        on_hand_slot: Map<String, Int> [persistent, consistent]
        invariant on_hand_slot >= 0 && on_hand_slot <= 1000

        // Audit ledger: how many ever stocked, dispensed, wasted.
        stocked: Map<String, Int> [persistent, consistent]
        invariant stocked >= 0 && stocked <= 1000

        dispensed: Map<String, Int> [persistent, consistent]
        invariant dispensed >= 0 && dispensed <= 1000

        wasted: Map<String, Int> [persistent, consistent]
        invariant wasted >= 0 && wasted <= 1000
    }

    on stock(drug: String, units: Int) {
        let cur = on_hand_slot.get(drug) ?? 0
        let everstock = stocked.get(drug) ?? 0
        let w = try { on_hand_slot.set(drug, cur + units) }
        if w.error != () { return map("ok", false, "reason", "{w.error}") }
        stocked.set(drug, everstock + units)
        return map("ok", true, "on_hand", cur + units)
    }

    // Dispense one unit. If the cabinet is empty the count would go
    // negative — the invariant refuses, so you cannot chart a dose that
    // physically isn't there.
    on dispense(drug: String, nurse: String) {
        let cur = on_hand_slot.get(drug) ?? 0
        let w = try { on_hand_slot.set(drug, cur - 1) }
        if w.error != () {
            return map("ok", false, "reason", "cabinet empty — cannot dispense: {w.error}")
        }
        let d = dispensed.get(drug) ?? 0
        dispensed.set(drug, d + 1)
        return map("ok", true, "nurse", nurse, "on_hand", cur - 1)
    }

    // Witnessed waste of a partial dose — its own ledger entry so the
    // count still reconciles.
    on waste(drug: String, witness: String) {
        let wst = wasted.get(drug) ?? 0
        wasted.set(drug, wst + 1)
        return map("ok", true, "witness", witness, "wasted", wst + 1)
    }

    on on_hand(drug: String) { return on_hand_slot.get(drug) ?? 0 }
    on dispensed_total(drug: String) { return dispensed.get(drug) ?? 0 }

    // The reconciliation equation: everything stocked is either still on
    // hand or accounted for as dispensed. (Waste is tracked separately for
    // the audit trail.) If this is ever false, there is diversion.
    on reconciles(drug: String) {
        let stk = stocked.get(drug) ?? 0
        let oh = on_hand_slot.get(drug) ?? 0
        let dsp = dispensed.get(drug) ?? 0
        return stk == oh + dsp
    }

    on demo() {
        stock("fentanyl", 5)
        dispense("fentanyl", "RN-Jones")
        waste("fentanyl", "RN-Smith")
        let rec = reconciles("fentanyl")
        let oh = on_hand("fentanyl")
        print("on hand:     {oh}")
        print("reconciles:  {rec}")
        return "demo done"
    }
}

cell test CabinetTests {
    rules {
        assert stock("morphine", 3).ok == true
        assert on_hand("morphine") == 3

        // each dispense decrements and the ledger reconciles
        assert dispense("morphine", "RN-A").ok == true
        assert on_hand("morphine") == 2
        assert reconciles("morphine") == true
        assert dispensed_total("morphine") == 1

        // drain to empty, then the next dispense is REFUSED (no negative)
        assert dispense("morphine", "RN-A").ok == true
        assert dispense("morphine", "RN-A").ok == true
        assert on_hand("morphine") == 0
        assert dispense("morphine", "RN-A").ok == false
        assert on_hand("morphine") == 0                  // still 0, not -1
        assert reconciles("morphine") == true

        // the count slot itself refuses an impossible value
        assert_fails on_hand_slot.set("morphine", -1)
        assert_fails on_hand_slot.set("morphine", 1001)
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check controlled_substance.cell
✓ All checks passed.
$ soma test controlled_substance.cell
test CabinetTests ...
  ✓ assert stock("morphine", 3).ok == true
  ✓ assert on_hand("morphine") == 3
  ✓ assert dispense("morphine", "RN-A").ok == true
  ✓ assert on_hand("morphine") == 2
  ✓ assert reconciles("morphine") == true
  ✓ assert dispensed_total("morphine") == 1
  ✓ assert dispense("morphine", "RN-A").ok == true
  ✓ assert dispense("morphine", "RN-A").ok == true
  ✓ assert on_hand("morphine") == 0
  ✓ assert dispense("morphine", "RN-A").ok == false
  ✓ assert on_hand("morphine") == 0
  ✓ assert reconciles("morphine") == true
  ✓ assert_fails on_hand_slot.set("morphine", -1) — raised memory invariant violated on 'on_hand_slot': on_hand_slot >= 0 && on_hand_slot <= 1000 — rejected write of -1 (key "morphine"); the slot is unchanged
  ✓ assert_fails on_hand_slot.set("morphine", 1001) — raised memory invariant violated on 'on_hand_slot': on_hand_slot >= 0 && on_hand_slot <= 1000 — rejected write of 1001 (key "morphine"); the slot is unchanged

14 tests: 14 passed, 0 failed
$ soma verify controlled_substance.cell
Verifying controlled_substance.cell...

Cabinet/invariants:

  ✓ invariant on_hand_slot <= 1000 — writer 'dispense' proven by induction (writes cur - 1)
  ⚠ invariant on_hand_slot >= 0 && on_hand_slot <= 1000 — runtime-checked (computed values): dispense → on_hand_slot [on_hand_slot >= 0] because `cur - 1` is only known to lie in [-1, 999] — narrow it: `require (cur - 1) >= 0 else …`, stock → on_hand_slot because `units` is a parameter (narrow it: `require (cur + units) >= 0 && (cur + units) <= 1000 else …`)
  ⚠ invariant stocked >= 0 && stocked <= 1000 — runtime-checked (computed values): stock → stocked because `units` is a parameter (narrow it: `require (everstock + units) >= 0 && (everstock + units) <= 1000 else …`)
  ✓ invariant dispensed >= 0 — writer 'dispense' proven by induction (writes d + 1)
  ⚠ invariant dispensed >= 0 && dispensed <= 1000 — runtime-checked (computed values): dispense → dispensed [dispensed <= 1000] because `d + 1` is only known to lie in [1, 1001] — narrow it: `require (d + 1) <= 1000 else …`
  ✓ invariant wasted >= 0 — writer 'waste' proven by induction (writes wst + 1)
  ⚠ invariant wasted >= 0 && wasted <= 1000 — runtime-checked (computed values): waste → wasted [wasted <= 1000] because `wst + 1` is only known to lie in [1, 1001] — narrow it: `require (wst + 1) <= 1000 else …`

3 passed, 4 warnings, 0 failures
Temporal: 0 passed, 0 failed
VERIFY OK
$ soma run controlled_substance.cell demo
on hand:     4
reconciles:  true
demo done

Builtins used

map, print

Source file: /corpus/medical/controlled_substance.cell · examples/corpus/medical/controlled_substance.cell