soma.cell

Surgical safety checklist — no incision before time-out, and the count

must reconcile before you close The WHO Surgical Safety Checklist exists because of two recurring disasters: wrong-site surgery (operating on the wrong knee, the wrong patient) and retained foreign objects (a sponge or instrument left inside, requiring a second operation, sometimes fatal sepsis). The defenses are a pre-incision "time-out" (confirm patient, site, procedure) and a final instrument/sponge COUNT that must match before the surgeon closes. Here the operation is a state machine: you physically cannot reach `incision` without passing through `timeout_done`, and you cannot reach `closed` without `count_correct`. A memory invariant makes the count a conserved equation — sponges out must equal sponges in — so "close with one still inside" is a rejected write, not a postoperative X-ray surprise.

A Soma program from the medical part of the verified corpus: 146 lines, cells Surgery, SurgeryTests. It passes soma check with soma 3.2.4.

How it is built

The cell Surgery declares 8 signals in its face: book(op: String, sponges: Int) -> Map, timeout(op: String) -> Map, incise(op: String) -> Map, recover_sponge(op: String) -> Map, close(op: String) -> Map, op_state(op: String) -> String, sponges_out(op: String) -> Int and demo() -> String; keeps 2 memory slots: placed (Map<String, Int>, persistent and consistent) under the invariant placed >= 0 && placed <= 200 and recovered (Map<String, Int>, persistent and consistent) under the invariant recovered >= 0 && recovered <= 200. Its state machine operation starts in booked and allows 4 transitions: booked -> timeout_done, timeout_done -> incision, incision -> count_correct and count_correct -> closed. closed is terminal. Handlers: book (line 60), timeout (line 67), incise (line 75), recover_sponge (line 83), close (line 92), op_state (line 105), sponges_out (line 106) and demo (line 108).

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

Generated from soma describe on this file.

The source

surgical_checklist.cell

// ============================================================================
// SURGICAL SAFETY CHECKLIST — no incision before time-out, and the count
// must reconcile before you close
// ============================================================================
//
// The WHO Surgical Safety Checklist exists because of two recurring
// disasters: wrong-site surgery (operating on the wrong knee, the wrong
// patient) and retained foreign objects (a sponge or instrument left
// inside, requiring a second operation, sometimes fatal sepsis). The
// defenses are a pre-incision "time-out" (confirm patient, site,
// procedure) and a final instrument/sponge COUNT that must match before
// the surgeon closes.
//
// Here the operation is a state machine: you physically cannot reach
// `incision` without passing through `timeout_done`, and you cannot reach
// `closed` without `count_correct`. A memory invariant makes the count a
// conserved equation — sponges out must equal sponges in — so "close with
// one still inside" is a rejected write, not a postoperative X-ray
// surprise.
//
//   soma verify examples/corpus/medical/surgical_checklist.cell
//   soma test   examples/corpus/medical/surgical_checklist.cell
//   soma run    examples/corpus/medical/surgical_checklist.cell demo
// ============================================================================

cell Surgery {
    face {
        signal book(op: String, sponges: Int) -> Map
        signal timeout(op: String) -> Map
        signal incise(op: String) -> Map
        signal recover_sponge(op: String) -> Map
        signal close(op: String) -> Map
        signal op_state(op: String) -> String
        signal sponges_out(op: String) -> Int
        signal demo() -> String
    }

    memory {
        // Sponges placed in the field, and sponges recovered. The closing
        // count must reconcile: out == in. Both are bounded and never
        // negative — a count of -1 or 9999 is a rejected write.
        placed: Map<String, Int> [persistent, consistent]
        invariant placed >= 0 && placed <= 200

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

    // The checklist as structure. `incision` is unreachable without
    // `timeout_done`; `closed` is unreachable without `count_correct`.
    // verify proves these are the only paths.
    state operation {
        initial: booked
        booked        -> timeout_done    // WHO time-out completed
        timeout_done  -> incision        // ONLY now may the scalpel cut
        incision      -> count_correct   // sponge/instrument count reconciled
        count_correct -> closed          // safe to close — terminal
    }

    on book(op: String, sponges: Int) {
        let w = try { placed.set(op, sponges) }
        if w.error != () { return map("ok", false, "reason", "{w.error}") }
        recovered.set(op, 0)
        return map("ok", true, "state", get_status(op), "sponges", sponges)
    }

    on timeout(op: String) {
        let r = try { transition(op, "timeout_done") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "state", get_status(op))
    }

    // Cutting is gated by the machine: from `booked` (no time-out) this
    // transition raises. Wrong-site surgery's defense, made structural.
    on incise(op: String) {
        let r = try { transition(op, "incision") }
        if r.error != () {
            return map("ok", false, "reason", "NO time-out — incision blocked: {r.error}")
        }
        return map("ok", true, "state", get_status(op))
    }

    on recover_sponge(op: String) {
        let cur = recovered.get(op) ?? 0
        recovered.set(op, cur + 1)
        return map("ok", true, "recovered", cur + 1)
    }

    // Close ONLY if the count reconciles. The retained-object defense:
    // sponges out must equal sponges in, or the count_correct transition
    // is never attempted and closing is impossible.
    on close(op: String) {
        let inn = placed.get(op) ?? 0
        let out = recovered.get(op) ?? 0
        if out != inn {
            return map("ok", false, "reason",
                "COUNT MISMATCH: {out} recovered of {inn} — object retained")
        }
        let c = try { transition(op, "count_correct") }
        if c.error != () { return map("ok", false, "reason", "{c.error}") }
        transition(op, "closed")
        return map("ok", true, "state", get_status(op))
    }

    on op_state(op: String) { return get_status(op) }
    on sponges_out(op: String) { return recovered.get(op) ?? 0 }

    on demo() {
        book("knee-L", 2)
        let early = incise("knee-L")           // REFUSED — no time-out yet
        timeout("knee-L")
        incise("knee-L")
        recover_sponge("knee-L")
        let short = close("knee-L")            // REFUSED — 1 of 2 recovered
        recover_sponge("knee-L")
        let done = close("knee-L")             // count reconciles — close
        print("incise early: {early}")
        print("close short:  {short}")
        print("close done:   {done}")
        return "demo done"
    }
}

cell test SurgeryTests {
    rules {
        // the happy path: book -> timeout -> incise -> count -> close
        assert book("a", 1).ok == true
        assert_fails transition("a", "incision")       // no cutting before time-out
        assert timeout("a").ok == true
        assert incise("a").ok == true
        assert close("a").ok == false                  // 0 of 1 recovered
        assert recover_sponge("a").ok == true
        assert close("a").ok == true
        assert op_state("a") == "closed"

        // closed is terminal — no re-opening, no second incision
        assert_fails transition("a", "incision")
        assert_fails transition("a", "timeout_done")

        // the count slot itself refuses an impossible value
        assert book("b", 3).ok == true
        assert_fails placed.set("b", -1)
        assert_fails recovered.set("b", 9999)
    }
}

What the toolchain says

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

$ soma check surgical_checklist.cell
✓ All checks passed.
$ soma test surgical_checklist.cell
test SurgeryTests ...
  ✓ assert book("a", 1).ok == true
  ✓ assert_fails transition("a", "incision") — raised invalid transition: booked → incision. Current state: 'booked'. Valid targets: [timeout_done]
  ✓ assert timeout("a").ok == true
  ✓ assert incise("a").ok == true
  ✓ assert close("a").ok == false
  ✓ assert recover_sponge("a").ok == true
  ✓ assert close("a").ok == true
  ✓ assert op_state("a") == "closed"
  ✓ assert_fails transition("a", "incision") — raised invalid transition: closed → incision. Current state: 'closed'. Valid targets: []
  ✓ assert_fails transition("a", "timeout_done") — raised invalid transition: closed → timeout_done. Current state: 'closed'. Valid targets: []
  ✓ assert book("b", 3).ok == true
  ✓ assert_fails placed.set("b", -1) — raised memory invariant violated on 'placed': placed >= 0 && placed <= 200 — rejected write of -1 (key "b"); the slot is unchanged
  ✓ assert_fails recovered.set("b", 9999) — raised memory invariant violated on 'recovered': recovered >= 0 && recovered <= 200 — rejected write of 9999 (key "b"); the slot is unchanged

13 tests: 13 passed, 0 failed
$ soma verify surgical_checklist.cell
Verifying surgical_checklist.cell...

State machine 'operation': 5 states, initial 'booked'
  States: [booked, closed, count_correct, incision, timeout_done]

  ✓ 5 states, 4 transitions
  ✓ all states reachable from 'booked'
  ✓ terminal states: [closed]
  ✓ no deadlocks
  ✓ liveness: every state can eventually reach a terminal state
  ✓ think-isolated: CTL safety properties hold regardless of LLM output (3 handlers, 4 literal transitions, 0 dynamic)
  ✓ termination: all 8 handlers structurally terminate
  ✓ refinement: handler `timeout` ⟶ {timeout_done}
  ✓ refinement: handler `incise` ⟶ {incision}
  ✓ refinement: handler `close` ⟶ {count_correct, closed}
  · transition sources: `timeout`, `incise`, `close` call transition(id, target) without declaring the source — the runtime refuses a move the graph forbids, but the proof does not see where the handler starts; `transition(id, from, to)` names the edge (checked by `soma check`, refused at run time from any other state)

Surgery/invariants:

  ⚠ invariant placed >= 0 && placed <= 200 — runtime-checked (computed values): book → placed because `sponges` is a parameter (narrow it: `require sponges >= 0 && sponges <= 200 else …`)
  ✓ invariant recovered >= 0 && recovered <= 200 — writer 'book' proven (writes 0)
  ✓ invariant recovered >= 0 — writer 'recover_sponge' proven by induction (writes cur + 1)
  ⚠ invariant recovered >= 0 && recovered <= 200 — runtime-checked (computed values): recover_sponge → recovered [recovered <= 200] because `cur + 1` is only known to lie in [1, 201] — narrow it: `require (cur + 1) <= 200 else …`

12 passed, 2 warnings, 0 failures

  Temporal properties for 'operation':
  ✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK
$ soma run surgical_checklist.cell demo
incise early: {"ok": false, "reason": "NO time-out — incision blocked: invalid transition: booked → incision. Current state: 'booked'. Valid targets: [timeout_done]"}
close short:  {"ok": false, "reason": "COUNT MISMATCH: 1 recovered of 2 — object retained"}
close done:   {"ok": true, "state": "closed"}
demo done

Builtins used

get_status, map, print, transition

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