Spillway gates — a dam may never lose its last release path
February 2017, Oroville, California: the tallest dam in the US lost its main spillway to erosion mid-flood, the emergency spillway began to fail within hours of first use, and 188,000 people downstream were evacuated. The lesson generalized by every dam-safety review since: release capacity is life-safety equipment, and maintenance scheduling is where it silently disappears — gate 3 is down for seal replacement, gate 5's hoist motor is out, a contractor asks to isolate gate 7 "just for the afternoon", and suddenly the dam cannot pass the inflow it was built for. Two structural walls below. The fleet ledger `gates_avail` carries an invariant floor of ONE: the write that would take the last operable gate out of service is rejected by the memory, whatever the work order says. And each gate's overhaul is a state machine: an overhauled gate returns to service only through `wet_tested` — an untested gate back on the flood roster is a transition that does not exist. soma verify proves it.
A Soma program from the energy part of the verified corpus: 121 lines, cells Spillway, SpillwayTests. It passes soma check with soma 3.2.4.
How it is built
The cell Spillway declares 6 signals in its face: isolate_gate(dam: String, gate: String) -> Map, begin_overhaul(gate: String) -> Map, finish_overhaul(gate: String) -> Map, wet_test_passed(dam: String, gate: String) -> Map, gates_in_service(dam: String) -> Int and gate_state(gate: String) -> String; keeps 1 memory slot: gates_avail (Map<String, Int>, persistent and consistent) under the invariant gates_avail >= 1 && gates_avail <= 8. Its state machine overhaul starts in in_service and allows 5 transitions: in_service -> isolated, isolated -> stripped, stripped -> reassembled, reassembled -> wet_tested and wet_tested -> in_service. Handlers: gates_in_service (line 47), isolate_gate (line 49), begin_overhaul (line 64), finish_overhaul (line 70), wet_test_passed (line 76) and gate_state (line 85).
The file also holds 1 test cell (SpillwayTests) with 19 assertions, run by soma test.
The source
spillway_gates.cell
// ============================================================================
// SPILLWAY GATES — a dam may never lose its last release path
// ============================================================================
//
// February 2017, Oroville, California: the tallest dam in the US lost its
// main spillway to erosion mid-flood, the emergency spillway began to fail
// within hours of first use, and 188,000 people downstream were evacuated.
// The lesson generalized by every dam-safety review since: release
// capacity is life-safety equipment, and maintenance scheduling is where
// it silently disappears — gate 3 is down for seal replacement, gate 5's
// hoist motor is out, a contractor asks to isolate gate 7 "just for the
// afternoon", and suddenly the dam cannot pass the inflow it was built for.
//
// Two structural walls below. The fleet ledger `gates_avail` carries an
// invariant floor of ONE: the write that would take the last operable gate
// out of service is rejected by the memory, whatever the work order says.
// And each gate's overhaul is a state machine: an overhauled gate returns
// to service only through `wet_tested` — an untested gate back on the
// flood roster is a transition that does not exist. soma verify proves it.
// ============================================================================
cell Spillway {
face {
signal isolate_gate(dam: String, gate: String) -> Map
signal begin_overhaul(gate: String) -> Map
signal finish_overhaul(gate: String) -> Map
signal wet_test_passed(dam: String, gate: String) -> Map
signal gates_in_service(dam: String) -> Int
signal gate_state(gate: String) -> String
}
memory {
// operable gates per dam — the floor of 1 is the life-safety wall
gates_avail: Map<String, Int> [persistent, consistent]
invariant gates_avail >= 1 && gates_avail <= 8
}
state overhaul {
initial: in_service
in_service -> isolated // dewatered, stop-logs in, hoist locked
isolated -> stripped // seals/hoist under overhaul
stripped -> reassembled
reassembled -> wet_tested // full-travel test UNDER HEAD
wet_tested -> in_service // only a tested gate rejoins the roster
}
on gates_in_service(dam: String) { return gates_avail.get(dam) ?? 8 }
on isolate_gate(dam: String, gate: String) {
// the fleet wall first: taking this gate may not strand the dam
let w = try { gates_avail.set(dam, gates_in_service(dam) - 1) }
if w.error != () {
return map("ok", false, "reason",
"refused: would leave {dam} without an operable release path")
}
let r = try { transition(gate, "isolated") }
if r.error != () {
gates_avail.set(dam, gates_in_service(dam) + 1) // roll back
return map("ok", false, "reason", "{r.error}")
}
return map("ok", true, "gates_in_service", gates_in_service(dam))
}
on begin_overhaul(gate: String) {
let r = try { transition(gate, "stripped") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "state", get_status(gate))
}
on finish_overhaul(gate: String) {
let r = try { transition(gate, "reassembled") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "state", get_status(gate))
}
on wet_test_passed(dam: String, gate: String) {
let r = try { transition(gate, "wet_tested") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
transition(gate, "in_service")
gates_avail.set(dam, gates_in_service(dam) + 1)
return map("ok", true, "state", get_status(gate),
"gates_in_service", gates_in_service(dam))
}
on gate_state(gate: String) { return get_status(gate) }
}
cell test SpillwayTests {
rules {
// the dam starts with 8 operable gates; isolate seven of them
assert isolate_gate("oro", "g1").ok == true
assert isolate_gate("oro", "g2").ok == true
assert isolate_gate("oro", "g3").ok == true
assert isolate_gate("oro", "g4").ok == true
assert isolate_gate("oro", "g5").ok == true
assert isolate_gate("oro", "g6").ok == true
assert isolate_gate("oro", "g7").ok == true
assert gates_in_service("oro") == 1
// THE LAST GATE: the work order that strands the dam is refused
assert isolate_gate("oro", "g8").ok == false
assert gates_in_service("oro") == 1
assert gate_state("g8") == "in_service"
assert_fails gates_avail.set("oro", 0)
// an overhauled gate cannot rejoin the roster untested:
// reassembled -> in_service is not a transition
assert begin_overhaul("g1").ok == true
assert finish_overhaul("g1").ok == true
assert_fails transition("g1", "in_service")
// tested under head, it returns — and frees the next work order
assert wet_test_passed("oro", "g1").ok == true
assert gates_in_service("oro") == 2
assert isolate_gate("oro", "g8").ok == true
// a gate in service cannot be "stripped" without isolation
assert_fails transition("g1", "stripped")
}
}What the toolchain says
$ soma check spillway_gates.cell
✓ All checks passed.$ soma test spillway_gates.cell
test SpillwayTests ...
✓ assert isolate_gate("oro", "g1").ok == true
✓ assert isolate_gate("oro", "g2").ok == true
✓ assert isolate_gate("oro", "g3").ok == true
✓ assert isolate_gate("oro", "g4").ok == true
✓ assert isolate_gate("oro", "g5").ok == true
✓ assert isolate_gate("oro", "g6").ok == true
✓ assert isolate_gate("oro", "g7").ok == true
✓ assert gates_in_service("oro") == 1
✓ assert isolate_gate("oro", "g8").ok == false
✓ assert gates_in_service("oro") == 1
✓ assert gate_state("g8") == "in_service"
✓ assert_fails gates_avail.set("oro", 0) — raised memory invariant violated on 'gates_avail': gates_avail >= 1 && gates_avail <= 8 — rejected write of 0 (key "oro"); the slot is unchanged
✓ assert begin_overhaul("g1").ok == true
✓ assert finish_overhaul("g1").ok == true
✓ assert_fails transition("g1", "in_service") — raised invalid transition: reassembled → in_service. Current state: 'reassembled'. Valid targets: [wet_tested]
✓ assert wet_test_passed("oro", "g1").ok == true
✓ assert gates_in_service("oro") == 2
✓ assert isolate_gate("oro", "g8").ok == true
✓ assert_fails transition("g1", "stripped") — raised invalid transition: in_service → stripped. Current state: 'in_service'. Valid targets: [isolated]
19 tests: 19 passed, 0 failed$ soma verify spillway_gates.cell
Verifying spillway_gates.cell...
State machine 'overhaul': 5 states, initial 'in_service'
States: [in_service, isolated, reassembled, stripped, wet_tested]
✓ 5 states, 5 transitions
✓ all states reachable from 'in_service'
✓ reactive machine: no terminal state, and every reachable state can return to 'in_service'
✓ no deadlocks
✓ liveness: every reachable state can return to 'in_service' (reactive machine)
✓ think-isolated: CTL safety properties hold regardless of LLM output (4 handlers, 5 literal transitions, 0 dynamic)
✓ termination: all 6 handlers structurally terminate
✓ refinement: handler `isolate_gate` ⟶ {isolated}
✓ refinement: handler `begin_overhaul` ⟶ {stripped}
✓ refinement: handler `finish_overhaul` ⟶ {reassembled}
✓ refinement: handler `wet_test_passed` ⟶ {wet_tested, in_service}
· transition sources: `isolate_gate`, `begin_overhaul`, `finish_overhaul`, `wet_test_passed` 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)
Spillway/invariants:
✓ invariant gates_avail <= 8 — writer 'isolate_gate' proven (writes gates_in_service(dam) - 1)
✓ invariant gates_avail >= 1 — writer 'isolate_gate' proven (writes gates_in_service(dam) + 1)
✓ invariant gates_avail >= 1 — writer 'wet_test_passed' proven (writes gates_in_service(dam) + 1)
⚠ invariant gates_avail >= 1 && gates_avail <= 8 — runtime-checked (computed values): isolate_gate → gates_avail [gates_avail >= 1] because `gates_in_service(dam) - 1` is only known to lie in [0, 7] — narrow it: `require (gates_in_service(dam) - 1) >= 1 else …`, isolate_gate → gates_avail [gates_avail <= 8] because `gates_in_service(dam) + 1` is only known to lie in [2, 9] — narrow it: `require (gates_in_service(dam) + 1) <= 8 else …`, wet_test_passed → gates_avail [gates_avail <= 8] because `gates_in_service(dam) + 1` is only known to lie in [2, 9] — narrow it: `require (gates_in_service(dam) + 1) <= 8 else …`
14 passed, 1 warnings, 0 failures
Temporal properties for 'overhaul':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK