A simplified TCP connection state machine (active-open path)
closed -> syn_sent -> established -> fin_wait -> closed. This is a classic protocol automaton; the model checker proves that from any state the connection can return to `closed` (no half-open leaks) and that the handshake order cannot be skipped.
A Soma program from the state_machines part of the verified corpus: 58 lines, cells TcpState, TcpConnection, TcpTests. It passes soma check with soma 3.2.4.
How it is built
The cell TcpConnection declares 6 signals in its face: open_conn(id: String) -> String, syn_ack(id: String) -> String, close_conn(id: String) -> String, timeout(id: String) -> String, reset(id: String) -> String and phase(id: String) -> String. Its state machine conn starts in Closed and allows 6 transitions: Closed -> SynSent, SynSent -> Established, Established -> FinWait, FinWait -> TimeWait, TimeWait -> Closed and * -> Closed. Handlers: open_conn (line 31), syn_ack (line 32), close_conn (line 33), timeout (line 34), reset (line 35) and phase (line 36).
The file also holds 1 test cell (TcpTests) with 9 assertions, run by soma test.
The source
tcp_connection.cell
// A simplified TCP connection state machine (active-open path).
// closed -> syn_sent -> established -> fin_wait -> closed. This is a
// classic protocol automaton; the model checker proves that from any
// state the connection can return to `closed` (no half-open leaks) and
// that the handshake order cannot be skipped.
cell type TcpState {
variants { Closed SynSent Established FinWait TimeWait }
}
cell TcpConnection {
face {
signal open_conn(id: String) -> String
signal syn_ack(id: String) -> String
signal close_conn(id: String) -> String
signal timeout(id: String) -> String
signal reset(id: String) -> String
signal phase(id: String) -> String
}
state conn: TcpState {
initial: Closed
Closed -> SynSent
SynSent -> Established
Established -> FinWait
FinWait -> TimeWait
TimeWait -> Closed
* -> Closed
}
on open_conn(id: String) { transition(id, SynSent) return get_status(id) }
on syn_ack(id: String) { transition(id, Established) return get_status(id) }
on close_conn(id: String) { transition(id, FinWait) return get_status(id) }
on timeout(id: String) { transition(id, TimeWait) return get_status(id) }
on reset(id: String) { transition(id, Closed) return get_status(id) }
on phase(id: String) { return get_status(id) }
}
cell test TcpTests {
rules {
// full lifecycle
assert open_conn("c1") == "SynSent"
assert syn_ack("c1") == "Established"
assert close_conn("c1") == "FinWait"
assert timeout("c1") == "TimeWait"
assert reset("c1") == "Closed"
// a RST from any state returns to Closed (the * arrow)
assert open_conn("c2") == "SynSent"
assert reset("c2") == "Closed"
// illegal: cannot reach Established without sending SYN first
assert_fails syn_ack("c3")
// illegal: cannot close a connection that was never established
assert_fails close_conn("c4")
}
}What the toolchain says
$ soma check tcp_connection.cell
✓ All checks passed.$ soma test tcp_connection.cell
test TcpTests ...
✓ assert open_conn("c1") == "SynSent"
✓ assert syn_ack("c1") == "Established"
✓ assert close_conn("c1") == "FinWait"
✓ assert timeout("c1") == "TimeWait"
✓ assert reset("c1") == "Closed"
✓ assert open_conn("c2") == "SynSent"
✓ assert reset("c2") == "Closed"
✓ assert_fails syn_ack("c3") — raised invalid transition: Closed → Established. Current state: 'Closed'. Valid targets: [SynSent]
✓ assert_fails close_conn("c4") — raised invalid transition: Closed → FinWait. Current state: 'Closed'. Valid targets: [SynSent]
9 tests: 9 passed, 0 failed$ soma verify tcp_connection.cell
Verifying tcp_connection.cell...
State machine 'conn': 5 states, initial 'Closed'
States: [Closed, Established, FinWait, SynSent, TimeWait]
✓ 5 states, 9 transitions
✓ all states reachable from 'Closed'
✓ reactive machine: no terminal state, and every reachable state can return to 'Closed'
✓ no deadlocks
✓ liveness: every reachable state can return to 'Closed' (reactive machine)
✓ wildcard transitions: * -> [Closed]
✓ think-isolated: CTL safety properties hold regardless of LLM output (5 handlers, 5 literal transitions, 0 dynamic)
✓ termination: all 6 handlers structurally terminate
✓ refinement: handler `open_conn` ⟶ {SynSent}
✓ refinement: handler `syn_ack` ⟶ {Established}
✓ refinement: handler `close_conn` ⟶ {FinWait}
✓ refinement: handler `timeout` ⟶ {TimeWait}
✓ refinement: handler `reset` ⟶ {Closed}
· transition sources: `open_conn`, `syn_ack`, `close_conn`, `timeout`, `reset` 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)
13 passed, 0 warnings, 0 failures
Temporal properties for 'conn':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK