soma.cell

Recloser — a trip is permanent until a human walks the line

A distribution recloser that trips on a fault will, by default, try to re-energize the line a few seconds later — most faults are a branch brushing a phase and clear themselves. But a conductor lying on the ground is the OTHER kind of fault: every reclose attempt pumps thousands of amps into whatever the wire is touching — a dry field, a car, a person. Reclosing into downed lines has electrocuted bystanders and started wildfires; after 2020, utilities in California fire country (PG&E's "fast trip" program) disabled automatic reclosing outright. Here the rule is structural, not procedural: from `tripped` the ONLY exit is `patrolling` — a crew dispatched to walk the span. `closed` is reachable from `tripped` by no path that skips the patrol, and a line the patrol condemns can never be energized again: `condemned` is terminal, and `soma verify` proves it.

A Soma program from the energy part of the verified corpus: 94 lines, cells Recloser, RecloseTests. It passes soma check with soma 3.2.4.

How it is built

The cell Recloser declares 3 signals in its face: operate(id: String, cmd: String) -> Map, breaker_state(id: String) -> String and trip_count(id: String) -> Int; keeps 1 memory slot: trips (Map<String, Int>, persistent and consistent) under the invariant trips >= 0. Its state machine recloser starts in closed and allows 5 transitions: closed -> tripped, tripped -> patrolling, patrolling -> cleared, cleared -> closed and patrolling -> condemned. condemned is terminal. Handlers: operate (line 43), breaker_state (line 54) and trip_count (line 58).

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

Generated from soma describe on this file.

The source

breaker_reclose.cell

// ============================================================================
// RECLOSER — a trip is permanent until a human walks the line
// ============================================================================
//
// A distribution recloser that trips on a fault will, by default, try to
// re-energize the line a few seconds later — most faults are a branch
// brushing a phase and clear themselves. But a conductor lying on the
// ground is the OTHER kind of fault: every reclose attempt pumps thousands
// of amps into whatever the wire is touching — a dry field, a car, a
// person. Reclosing into downed lines has electrocuted bystanders and
// started wildfires; after 2020, utilities in California fire country
// (PG&E's "fast trip" program) disabled automatic reclosing outright.
//
// Here the rule is structural, not procedural: from `tripped` the ONLY
// exit is `patrolling` — a crew dispatched to walk the span. `closed` is
// reachable from `tripped` by no path that skips the patrol, and a line
// the patrol condemns can never be energized again: `condemned` is
// terminal, and `soma verify` proves it.
// ============================================================================

cell Recloser {
    face {
        signal operate(id: String, cmd: String) -> Map
        signal breaker_state(id: String) -> String
        signal trip_count(id: String) -> Int
    }

    memory {
        // lifetime fault interruptions — duty accumulates, never reverses
        trips: Map<String, Int> [persistent, consistent]
        invariant trips >= 0
    }

    state recloser {
        initial: closed
        closed -> tripped          // protection operates — always allowed
        tripped -> patrolling      // crew dispatched to walk the line
        patrolling -> cleared      // span confirmed intact
        cleared -> closed          // only NOW may the breaker close
        patrolling -> condemned    // conductor down — terminal, forever
    }

    on operate(id: String, cmd: String) {
        let r = try { transition(id, cmd) }
        if r.error != () {
            return map("ok", false, "state", get_status(id), "reason", "{r.error}")
        }
        if cmd == "tripped" {
            trips.set(id, trip_count(id) + 1)
        }
        return map("ok", true, "state", get_status(id))
    }

    on breaker_state(id: String) {
        return get_status(id)
    }

    on trip_count(id: String) {
        return trips.get(id) ?? 0
    }
}

cell test RecloseTests {
    rules {
        // a fault trips the breaker
        assert operate("r1", "tripped").ok == true
        assert trip_count("r1") == 1

        // THE KILLER: auto-reclose straight back into the fault.
        // The transition does not exist — it raises.
        assert_fails transition("r1", "closed")

        // the only path back is through a patrol
        assert operate("r1", "patrolling").ok == true
        assert operate("r1", "cleared").ok == true
        assert operate("r1", "closed").ok == true
        assert breaker_state("r1") == "closed"

        // a second fault, and this time the patrol finds wire on the ground
        assert operate("r1", "tripped").ok == true
        assert operate("r1", "patrolling").ok == true
        assert operate("r1", "condemned").ok == true

        // condemned is TERMINAL: no command ever re-energizes this line
        assert_fails transition("r1", "closed")
        assert_fails transition("r1", "cleared")
        assert_fails transition("r1", "tripped")

        // the duty ledger cannot be rolled back
        assert_fails trips.set("r1", -1)
        assert trip_count("r1") == 2
    }
}

What the toolchain says

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

$ soma check breaker_reclose.cell
✓ All checks passed.
$ soma test breaker_reclose.cell
test RecloseTests ...
  ✓ assert operate("r1", "tripped").ok == true
  ✓ assert trip_count("r1") == 1
  ✓ assert_fails transition("r1", "closed") — raised invalid transition: tripped → closed. Current state: 'tripped'. Valid targets: [patrolling]
  ✓ assert operate("r1", "patrolling").ok == true
  ✓ assert operate("r1", "cleared").ok == true
  ✓ assert operate("r1", "closed").ok == true
  ✓ assert breaker_state("r1") == "closed"
  ✓ assert operate("r1", "tripped").ok == true
  ✓ assert operate("r1", "patrolling").ok == true
  ✓ assert operate("r1", "condemned").ok == true
  ✓ assert_fails transition("r1", "closed") — raised invalid transition: condemned → closed. Current state: 'condemned'. Valid targets: []
  ✓ assert_fails transition("r1", "cleared") — raised invalid transition: condemned → cleared. Current state: 'condemned'. Valid targets: []
  ✓ assert_fails transition("r1", "tripped") — raised invalid transition: condemned → tripped. Current state: 'condemned'. Valid targets: []
  ✓ assert_fails trips.set("r1", -1) — raised memory invariant violated on 'trips': trips >= 0 — rejected write of -1 (key "r1"); the slot is unchanged
  ✓ assert trip_count("r1") == 2

15 tests: 15 passed, 0 failed
$ soma verify breaker_reclose.cell
Verifying breaker_reclose.cell...

State machine 'recloser': 5 states, initial 'closed'
  States: [cleared, closed, condemned, patrolling, tripped]

  ✓ 5 states, 5 transitions
  ✓ all states reachable from 'closed'
  ✓ terminal states: [condemned]
  ✓ no deadlocks
  ✓ liveness: every state can eventually reach a terminal state
  ⚠ dynamic transition targets: handler `operate` uses a dynamic (computed) transition target — the state these handlers move to is computed at run time (from input or an LLM answer), so the machine's safety is checked at run time for them, not proven
  ✓ termination: all 3 handlers structurally terminate
  ⚠ refinement (partial — dynamic targets fall back to runtime check): handler `operate` calls transition() with a computed target — which edge it takes is checked at run time (invalid_transition), not proven; write the target as a literal state to have it verified
  ✓ refinement (partial — dynamic targets fall back to runtime check): handler `operate` ⟶ <dynamic>

Recloser/invariants:

  ✓ invariant trips >= 0 — writer 'operate' proven (writes trip_count(id) + 1)

8 passed, 2 warnings, 0 failures

  Temporal properties for 'recloser':
  ✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK

Builtins used

get_status, map, transition

Source file: /corpus/energy/breaker_reclose.cell · examples/corpus/energy/breaker_reclose.cell