Pressure relief valve — a live vessel can never lose its relief path
Williams Olefins, Geismar 2013: a reboiler was isolated from its relief valve, heat crept in, and the blocked-in vessel ruptured — 2 dead, 167 injured. The century-old version is the gagged boiler safety valve. Here the joint state (vessel pressure x relief path) is one machine, and the state {in service, relief blocked} does not exist: you can only block the relief valve for maintenance from the cold, offline state, and a blocked-relief vessel has no edge into service. The gauge ledger independently refuses pressure above MAWP.
A Soma program from the safety_interlocks part of the verified corpus: 88 lines, cells ReliefInterlock, ReliefTests. It passes soma check with soma 3.2.4.
How it is built
The cell ReliefInterlock declares 5 signals in its face: commission(id: String, psi: Int) -> Map, take_offline(id: String) -> String, block_relief_for_test(id: String) -> String, restore_relief(id: String) -> String and gauge(id: String) -> Int; keeps 1 memory slot: psi_now (Map<String, Int>, persistent and consistent) under the invariant psi_now >= 0 && psi_now <= 150. Its state machine vessel starts in offline_relief_open and allows 4 transitions: offline_relief_open -> in_service, in_service -> offline_relief_open, offline_relief_open -> relief_blocked_cold and relief_blocked_cold -> offline_relief_open. Handlers: commission (line 36), take_offline (line 49), block_relief_for_test (line 55), restore_relief (line 56) and gauge (line 57).
The file also holds 1 test cell (ReliefTests) with 12 assertions, run by soma test.
The source
pressure_relief.cell
// PRESSURE RELIEF VALVE — a live vessel can never lose its relief path.
// Williams Olefins, Geismar 2013: a reboiler was isolated from its
// relief valve, heat crept in, and the blocked-in vessel ruptured —
// 2 dead, 167 injured. The century-old version is the gagged boiler
// safety valve. Here the joint state (vessel pressure x relief path) is
// one machine, and the state {in service, relief blocked} does not
// exist: you can only block the relief valve for maintenance from the
// cold, offline state, and a blocked-relief vessel has no edge into
// service. The gauge ledger independently refuses pressure above MAWP.
cell ReliefInterlock {
face {
signal commission(id: String, psi: Int) -> Map
signal take_offline(id: String) -> String
signal block_relief_for_test(id: String) -> String
signal restore_relief(id: String) -> String
signal gauge(id: String) -> Int
}
memory {
// vessel pressure, psi; MAWP is 150 — the wall the gauge enforces
psi_now: Map<String, Int> [persistent, consistent]
invariant psi_now >= 0 && psi_now <= 150
}
// What is ABSENT is the proof: no state pairs pressure with a
// blocked relief path.
state vessel {
initial: offline_relief_open
offline_relief_open -> in_service // pressurize: relief armed
in_service -> offline_relief_open // depressurize first, always
offline_relief_open -> relief_blocked_cold // valve test: vessel cold only
relief_blocked_cold -> offline_relief_open
}
on commission(id: String, psi: Int) {
let r = try { transition(id, "in_service") }
if r.error != () {
return map("ok", false, "reason", "relief path not proven open")
}
let w = try { psi_now.set(id, psi) }
if w.error != () {
transition(id, "offline_relief_open")
return map("ok", false, "reason", "gauge refused {psi} psi (MAWP 150)")
}
return map("ok", true, "state", get_status(id), "psi", psi)
}
on take_offline(id: String) {
psi_now.set(id, 0) // vent BEFORE the state moves
transition(id, "offline_relief_open")
return get_status(id)
}
on block_relief_for_test(id: String) { transition(id, "relief_blocked_cold") return get_status(id) }
on restore_relief(id: String) { transition(id, "offline_relief_open") return get_status(id) }
on gauge(id: String) { return psi_now.get(id) ?? 0 }
}
cell test ReliefTests {
rules {
// a commissioned vessel runs at pressure with relief armed
assert commission("v1", 120).ok == true
// THE Geismar move: blocking the relief on a LIVE vessel.
// The edge does not exist — it raises.
assert_fails transition("v1", "relief_blocked_cold")
// the gauge itself refuses pressure past MAWP, and a vacuum
assert_fails psi_now.set("v1", 200)
assert_fails psi_now.set("v1", -10)
// legal maintenance: vent, go offline, THEN block the relief
assert take_offline("v1") == "offline_relief_open"
assert gauge("v1") == 0
assert block_relief_for_test("v1") == "relief_blocked_cold"
// a blocked-relief vessel has no road into service
assert_fails transition("v1", "in_service")
assert commission("v1", 100).ok == false
assert restore_relief("v1") == "offline_relief_open"
// overpressure commissioning is refused and the vessel stays safe
assert commission("v2", 151).ok == false
assert gauge("v2") == 0
}
}What the toolchain says
$ soma check pressure_relief.cell
✓ All checks passed.$ soma test pressure_relief.cell
test ReliefTests ...
✓ assert commission("v1", 120).ok == true
✓ assert_fails transition("v1", "relief_blocked_cold") — raised invalid transition: in_service → relief_blocked_cold. Current state: 'in_service'. Valid targets: [offline_relief_open]
✓ assert_fails psi_now.set("v1", 200) — raised memory invariant violated on 'psi_now': psi_now >= 0 && psi_now <= 150 — rejected write of 200 (key "v1"); the slot is unchanged
✓ assert_fails psi_now.set("v1", -10) — raised memory invariant violated on 'psi_now': psi_now >= 0 && psi_now <= 150 — rejected write of -10 (key "v1"); the slot is unchanged
✓ assert take_offline("v1") == "offline_relief_open"
✓ assert gauge("v1") == 0
✓ assert block_relief_for_test("v1") == "relief_blocked_cold"
✓ assert_fails transition("v1", "in_service") — raised invalid transition: relief_blocked_cold → in_service. Current state: 'relief_blocked_cold'. Valid targets: [offline_relief_open]
✓ assert commission("v1", 100).ok == false
✓ assert restore_relief("v1") == "offline_relief_open"
✓ assert commission("v2", 151).ok == false
✓ assert gauge("v2") == 0
12 tests: 12 passed, 0 failed$ soma verify pressure_relief.cell
Verifying pressure_relief.cell...
State machine 'vessel': 3 states, initial 'offline_relief_open'
States: [in_service, offline_relief_open, relief_blocked_cold]
✓ 3 states, 4 transitions
✓ all states reachable from 'offline_relief_open'
✓ reactive machine: no terminal state, and every reachable state can return to 'offline_relief_open'
✓ no deadlocks
✓ liveness: every reachable state can return to 'offline_relief_open' (reactive machine)
✓ think-isolated: CTL safety properties hold regardless of LLM output (4 handlers, 5 literal transitions, 0 dynamic)
✓ termination: all 5 handlers structurally terminate
✓ refinement: handler `commission` ⟶ {in_service, offline_relief_open [if w.error != ()]}
✓ refinement: handler `take_offline` ⟶ {offline_relief_open}
✓ refinement: handler `block_relief_for_test` ⟶ {relief_blocked_cold}
✓ refinement: handler `restore_relief` ⟶ {offline_relief_open}
· transition sources: `commission`, `take_offline`, `block_relief_for_test`, `restore_relief` 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)
ReliefInterlock/invariants:
✓ invariant psi_now >= 0 && psi_now <= 150 — writer 'take_offline' proven (writes 0)
⚠ invariant psi_now >= 0 && psi_now <= 150 — runtime-checked (computed values): commission → psi_now because `psi` is a parameter (narrow it: `require psi >= 0 && psi <= 150 else …`)
12 passed, 1 warnings, 0 failures
Temporal properties for 'vessel':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK