Stock and orders — two skeletons, and what one may ask of the other
Frames are not transitive: `Orders.place` says `calls Stock.take`, not `writes items` — the slot belongs to Stock, and `take` has its own frame. So the skeleton answers "who can change the stock?" in one glance: the signals of Stock whose frame says `writes items`, reached only through the calls the other frames list. Writing `items.set(…)` inside an Orders body is refused twice over: another cell's slot, and outside the frame.
A Soma program from the skeleton part of the verified corpus: 133 lines, cells Stock, Orders, StockAndOrders. It passes soma check with soma 3.2.4.
How it is built
The cell Stock declares 3 signals in its face: add(sku: String, n: Int) -> Int, level(sku: String) -> Int and take(sku: String, n: Int) -> Bool; keeps 1 memory slot: items (Map<String, Int>, persistent) under the invariant items >= 0. Handlers: add (line 65), level (line 71) and take (line 75).
The cell Orders declares 4 signals in its face: place(id: String, sku: String, n: Int) -> String, ship(id: String) -> String, cancel(id: String) -> String and state_of(id: String) -> String; keeps 2 memory slots: lines (Map<String, String>, persistent) and counts (Map<String, Int>, persistent) under the invariant counts >= 1. Its state machine order starts in open and allows 4 transitions: open -> packed, open -> refused, packed -> shipped and packed -> cancelled. cancelled, refused and shipped are terminal. Handlers: place (line 84), ship (line 96), cancel (line 101) and state_of (line 107).
The file also holds 1 test cell (StockAndOrders) with 15 assertions, run by soma test.
The source
stock_and_orders.cell
// STOCK AND ORDERS — two skeletons, and what one may ask of the other.
//
// Frames are not transitive: `Orders.place` says `calls Stock.take`, not
// `writes items` — the slot belongs to Stock, and `take` has its own frame.
// So the skeleton answers "who can change the stock?" in one glance: the
// signals of Stock whose frame says `writes items`, reached only through
// the calls the other frames list. Writing `items.set(…)` inside an Orders
// body is refused twice over: another cell's slot, and outside the frame.
//
// soma check stock_and_orders.cell
// soma skeleton stock_and_orders.cell Stock.take who calls it, what it owes
// soma verify stock_and_orders.cell
// soma test stock_and_orders.cell
skeleton Stock {
memory {
items: Map<String, Int> [persistent]
invariant items >= 0
}
face {
signal add(sku: String, n: Int) -> Int
requires n >= 1
writes items
calls level
signal level(sku: String) -> Int reads items
signal take(sku: String, n: Int) -> Bool
requires n >= 1
writes items
calls level
}
}
skeleton Orders {
memory {
lines: Map<String, String> [persistent] // order -> sku
counts: Map<String, Int> [persistent] // order -> units
invariant counts >= 1
}
state order {
initial: open
open -> packed
open -> refused // not enough stock
packed -> shipped
packed -> cancelled // the units go back
}
face {
signal place(id: String, sku: String, n: Int) -> String
requires n >= 1
writes lines, counts
moves open -> packed, open -> refused
calls Stock.take
signal ship(id: String) -> String moves packed -> shipped
signal cancel(id: String) -> String
reads lines, counts
moves packed -> cancelled
calls Stock.add
signal state_of(id: String) -> String reads order
}
}
flesh Stock {
on add(sku, n) {
let now_has = level(sku) + n
items.set(sku, now_has)
return now_has
}
on level(sku) {
return items.get(sku) ?? 0
}
on take(sku, n) {
let have = level(sku)
if have < n { return false }
items.set(sku, have - n)
return true
}
}
flesh Orders {
on place(id, sku, n) {
require lines.get(id) == () else Taken "order '{id}' exists"
if !take(sku, n) {
transition(id, "open", "refused")
return "refused"
}
lines.set(id, sku)
counts.set(id, n)
transition(id, "open", "packed")
return "packed"
}
on ship(id) {
transition(id, "packed", "shipped")
return "shipped"
}
on cancel(id) {
transition(id, "packed", "cancelled")
add(lines.get(id), counts.get(id))
return "cancelled"
}
on state_of(id) {
return get_status(id) ?? "open"
}
}
cell test StockAndOrders {
rules {
assert add("bolt", 10) == 10
assert place("o1", "bolt", 4) == "packed"
assert level("bolt") == 6
assert place("o2", "bolt", 7) == "refused" // 6 left: nothing is taken
assert level("bolt") == 6
assert state_of("o2") == "refused"
assert_fails ship("o2") // refused is terminal
assert cancel("o1") == "cancelled" // the 4 units come back
assert level("bolt") == 10
assert_fails ship("o1")
assert place("o3", "bolt", 10) == "packed"
assert ship("o3") == "shipped"
assert_fails cancel("o3") // shipped is terminal
assert level("bolt") == 0
assert_fails take("bolt", 0) // the contract: n >= 1
}
}What the toolchain says
$ soma check stock_and_orders.cell
✓ All checks passed.$ soma test stock_and_orders.cell
test StockAndOrders ...
✓ assert add("bolt", 10) == 10
✓ assert place("o1", "bolt", 4) == "packed"
✓ assert level("bolt") == 6
✓ assert place("o2", "bolt", 7) == "refused"
✓ assert level("bolt") == 6
✓ assert state_of("o2") == "refused"
✓ assert_fails ship("o2") — raised invalid transition: refused → shipped — transition(id, "packed", "shipped") declares its source, and 'o2' is in 'refused', not 'packed'
✓ assert cancel("o1") == "cancelled"
✓ assert level("bolt") == 10
✓ assert_fails ship("o1") — raised invalid transition: cancelled → shipped — transition(id, "packed", "shipped") declares its source, and 'o1' is in 'cancelled', not 'packed'
✓ assert place("o3", "bolt", 10) == "packed"
✓ assert ship("o3") == "shipped"
✓ assert_fails cancel("o3") — raised invalid transition: shipped → cancelled — transition(id, "packed", "cancelled") declares its source, and 'o3' is in 'shipped', not 'packed'
✓ assert level("bolt") == 0
✓ assert_fails take("bolt", 0) — raised take(): the face requires `n >= 1` — called with n = 0
15 tests: 15 passed, 0 failed$ soma verify stock_and_orders.cell
Verifying stock_and_orders.cell...
State machine 'order': 5 states, initial 'open'
States: [cancelled, open, packed, refused, shipped]
✓ 5 states, 4 transitions
✓ all states reachable from 'open'
✓ terminal states: [refused, shipped, cancelled]
✓ no deadlocks
✓ liveness: every state can eventually reach a terminal state
✓ think-isolated: CTL safety properties hold regardless of LLM output (3 handlers, 4 literal transitions, 0 dynamic)
✓ termination: all 4 handlers structurally terminate
✓ refinement: handler `place` ⟶ {open → refused [if !take(sku, n)], open → packed}
✓ refinement: handler `ship` ⟶ {packed → shipped}
✓ refinement: handler `cancel` ⟶ {packed → cancelled}
Stock/invariants:
✓ invariant items >= 0 — writer 'add' proven by induction (writes now_has)
✓ invariant items >= 0 — writer 'take' proven by induction (writes have - n)
Orders/invariants:
✓ invariant counts >= 1 — writer 'place' proven by induction (writes n)
Stock/contracts:
✓ add: requires n >= 1 — proven at 1 call site (cancel); a call from outside is checked at run time
✓ take: requires n >= 1 — proven at 1 call site (place); a call from outside is checked at run time
Orders/contracts:
· place: requires n >= 1 — no call site in the program; checked at run time on every call from outside (kind `requires`)
15 passed, 0 warnings, 0 failures
Temporal properties for 'order':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
note: state machines are verified per cell. A value crosses a cell boundary by a face contract (`requires` / `ensures` on the signal); a rule between two cells' machines is proven when soma.toml states it — `[verify.before."Pay.paid"] requires = ["Approval.signed_off"]` explores the product of the machines.
VERIFY OK