Blast furnace top — never open a door against live CO gas
Blast furnace top gas is roughly a quarter carbon monoxide at positive pressure; opening an access door on a live furnace has gassed entire maintenance crews. The kill chain is isolation -> venting -> gas test, and every fatality is a skipped link. Here the door has no edge from any pressurized state: `live -> door_open` and `isolated -> door_open` do not exist, only `vented` reaches the door. The gas-test ledger is the final wall — entry is logged with the measured CO ppm, and the memory itself refuses a reading above the 30 ppm entry limit.
A Soma program from the safety_interlocks part of the verified corpus: 83 lines, cells FurnaceTop, FurnaceTests. It passes soma check with soma 3.2.4.
How it is built
The cell FurnaceTop declares 5 signals in its face: isolate(id: String) -> String, resume_blast(id: String) -> String, vent_and_flare(id: String) -> String, open_door(id: String, co_ppm: Int) -> Map and close_door(id: String) -> String; keeps 1 memory slot: entry_co (Map<String, Int>, persistent and consistent) under the invariant entry_co >= 0 && entry_co <= 30. Its state machine furnace starts in live and allows 6 transitions: live -> isolated, isolated -> live, isolated -> vented, vented -> door_open, door_open -> vented and vented -> live. Handlers: isolate (line 36), resume_blast (line 37), vent_and_flare (line 38), open_door (line 40) and close_door (line 54).
The file also holds 1 test cell (FurnaceTests) with 11 assertions, run by soma test.
The source
blast_furnace_door.cell
// BLAST FURNACE TOP — never open a door against live CO gas.
// Blast furnace top gas is roughly a quarter carbon monoxide at positive
// pressure; opening an access door on a live furnace has gassed entire
// maintenance crews. The kill chain is isolation -> venting -> gas test,
// and every fatality is a skipped link. Here the door has no edge from
// any pressurized state: `live -> door_open` and `isolated -> door_open`
// do not exist, only `vented` reaches the door. The gas-test ledger is
// the final wall — entry is logged with the measured CO ppm, and the
// memory itself refuses a reading above the 30 ppm entry limit.
cell FurnaceTop {
face {
signal isolate(id: String) -> String
signal resume_blast(id: String) -> String
signal vent_and_flare(id: String) -> String
signal open_door(id: String, co_ppm: Int) -> Map
signal close_door(id: String) -> String
}
memory {
// CO at the door on entry, ppm — 30 is the ceiling, structurally
entry_co: Map<String, Int> [persistent, consistent]
invariant entry_co >= 0 && entry_co <= 30
}
state furnace {
initial: live
live -> isolated // blast off, goggle valves shut
isolated -> live // resume without ever opening
isolated -> vented // bleeders open, top gas flared off
vented -> door_open // the ONLY edge to an open door
door_open -> vented
vented -> live // reseal, purge, resume blast
}
on isolate(id: String) { transition(id, "isolated") return get_status(id) }
on resume_blast(id: String) { transition(id, "live") return get_status(id) }
on vent_and_flare(id: String) { transition(id, "vented") return get_status(id) }
on open_door(id: String, co_ppm: Int) {
// gas test FIRST: a hot reading is refused by the ledger itself
let w = try { entry_co.set(id, co_ppm) }
if w.error != () {
return map("ok", false, "state", get_status(id),
"reason", "gas test failed: {co_ppm} ppm CO (limit 30)")
}
let r = try { transition(id, "door_open") }
if r.error != () {
return map("ok", false, "reason", "furnace not vented — door stays shut")
}
return map("ok", true, "state", get_status(id), "co_ppm", co_ppm)
}
on close_door(id: String) { transition(id, "vented") return get_status(id) }
}
cell test FurnaceTests {
rules {
// a live furnace's door does not open — no such edge
assert_fails transition("f1", "door_open")
assert open_door("f1", 5).ok == false
// isolated is NOT vented: still pressurized, still no door
assert isolate("f1") == "isolated"
assert_fails transition("f1", "door_open")
// vented + clean gas test: entry granted
assert vent_and_flare("f1") == "vented"
assert open_door("f1", 8).ok == true
// an open door cannot coexist with a live furnace
assert_fails transition("f1", "live")
assert close_door("f1") == "vented"
// a hot gas test is refused BY THE MEMORY, door stays shut
assert open_door("f1", 250).ok == false
assert_fails entry_co.set("f1", 31)
// reseal and resume
assert resume_blast("f1") == "live"
}
}What the toolchain says
$ soma check blast_furnace_door.cell
✓ All checks passed.$ soma test blast_furnace_door.cell
test FurnaceTests ...
✓ assert_fails transition("f1", "door_open") — raised invalid transition: live → door_open. Current state: 'live'. Valid targets: [isolated]
✓ assert open_door("f1", 5).ok == false
✓ assert isolate("f1") == "isolated"
✓ assert_fails transition("f1", "door_open") — raised invalid transition: isolated → door_open. Current state: 'isolated'. Valid targets: [live, vented]
✓ assert vent_and_flare("f1") == "vented"
✓ assert open_door("f1", 8).ok == true
✓ assert_fails transition("f1", "live") — raised invalid transition: door_open → live. Current state: 'door_open'. Valid targets: [vented]
✓ assert close_door("f1") == "vented"
✓ assert open_door("f1", 250).ok == false
✓ assert_fails entry_co.set("f1", 31) — raised memory invariant violated on 'entry_co': entry_co >= 0 && entry_co <= 30 — rejected write of 31 (key "f1"); the slot is unchanged
✓ assert resume_blast("f1") == "live"
11 tests: 11 passed, 0 failed$ soma verify blast_furnace_door.cell
Verifying blast_furnace_door.cell...
State machine 'furnace': 4 states, initial 'live'
States: [door_open, isolated, live, vented]
✓ 4 states, 6 transitions
✓ all states reachable from 'live'
✓ reactive machine: no terminal state, and every reachable state can return to 'live'
✓ no deadlocks
✓ liveness: every reachable state can return to 'live' (reactive machine)
✓ think-isolated: CTL safety properties hold regardless of LLM output (5 handlers, 5 literal transitions, 0 dynamic)
✓ termination: all 5 handlers structurally terminate
✓ refinement: handler `isolate` ⟶ {isolated}
✓ refinement: handler `resume_blast` ⟶ {live}
✓ refinement: handler `vent_and_flare` ⟶ {vented}
✓ refinement: handler `open_door` ⟶ {door_open}
✓ refinement: handler `close_door` ⟶ {vented}
· transition sources: `isolate`, `resume_blast`, `vent_and_flare`, `open_door`, `close_door` 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)
FurnaceTop/invariants:
⚠ invariant entry_co >= 0 && entry_co <= 30 — runtime-checked (computed values): open_door → entry_co because `co_ppm` is a parameter (narrow it: `require co_ppm >= 0 && co_ppm <= 30 else …`)
12 passed, 1 warnings, 0 failures
Temporal properties for 'furnace':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK