Permit — a building permit that cannot skip a review
New York's self-certification program let architects stamp their own permits "to speed things up" — DOB audits later found buildings approved with zoning and structural reviews simply skipped, and the city spent a decade revoking permits for occupied buildings. The skip is possible when "reviewed" is a checkbox. Here the approval chain is the state machine itself: `issued` is only reachable THROUGH zoning, structural, and fire review, soma verify proves it, and `denied` and `issued` are terminal. The fee ledger is a second wall: a permit cannot be charged twice.
A Soma program from the civic part of the verified corpus: 118 lines, cells BuildingPermit, PermitTests. It passes soma check with soma 3.2.4.
How it is built
The cell BuildingPermit declares 7 signals in its face: pay_fee(id: String) -> Map, pass_zoning(id: String) -> Map, pass_structural(id: String) -> Map, pass_fire(id: String) -> Map, issue(id: String) -> Map, deny(id: String) -> Map and permit_state(id: String) -> String; keeps 1 memory slot: fees (Map<String, Int>, persistent and consistent) under the invariant fees >= 0 && fees <= 1. Its state machine permit starts in filed and allows 8 transitions: filed -> zoning_ok, zoning_ok -> structural_ok, structural_ok -> fire_ok, fire_ok -> issued, filed -> denied, zoning_ok -> denied, structural_ok -> denied and fire_ok -> denied. denied and issued are terminal. Handlers: permit_state (line 45), pay_fee (line 47), pass_zoning (line 56), pass_structural (line 62), pass_fire (line 68), issue (line 74) and deny (line 83).
The file also holds 1 test cell (PermitTests) with 17 assertions, run by soma test.
The source
permit.cell
// ============================================================================
// PERMIT — a building permit that cannot skip a review
// ============================================================================
// New York's self-certification program let architects stamp their own
// permits "to speed things up" — DOB audits later found buildings approved
// with zoning and structural reviews simply skipped, and the city spent a
// decade revoking permits for occupied buildings. The skip is possible when
// "reviewed" is a checkbox. Here the approval chain is the state machine
// itself: `issued` is only reachable THROUGH zoning, structural, and fire
// review, soma verify proves it, and `denied` and `issued` are terminal.
// The fee ledger is a second wall: a permit cannot be charged twice.
// ============================================================================
cell BuildingPermit {
face {
signal pay_fee(id: String) -> Map
signal pass_zoning(id: String) -> Map
signal pass_structural(id: String) -> Map
signal pass_fire(id: String) -> Map
signal issue(id: String) -> Map
signal deny(id: String) -> Map
signal permit_state(id: String) -> String
}
memory {
// permit -> fee payments. Double-billing is unrepresentable.
fees: Map<String, Int> [persistent, consistent]
invariant fees >= 0 && fees <= 1
}
// The chain. There is NO edge from filed to issued: every issued
// permit passed all three reviews, by construction.
state permit {
initial: filed
filed -> zoning_ok
zoning_ok -> structural_ok
structural_ok -> fire_ok
fire_ok -> issued
filed -> denied
zoning_ok -> denied
structural_ok -> denied
fire_ok -> denied
}
on permit_state(id: String) { return get_status(id) }
on pay_fee(id: String) {
let prior = fees.get(id) ?? 0
let w = try { fees.set(id, prior + 1) }
if w.error != () {
return map("ok", false, "reason", "fee already collected for {id}")
}
return map("ok", true, "permit", id)
}
on pass_zoning(id: String) {
let r = try { transition(id, "zoning_ok") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "stage", permit_state(id))
}
on pass_structural(id: String) {
let r = try { transition(id, "structural_ok") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "stage", permit_state(id))
}
on pass_fire(id: String) {
let r = try { transition(id, "fire_ok") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "stage", permit_state(id))
}
on issue(id: String) {
if (fees.get(id) ?? 0) == 0 {
return map("ok", false, "reason", "fee unpaid for {id}")
}
let r = try { transition(id, "issued") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "permit", id)
}
on deny(id: String) {
let r = try { transition(id, "denied") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "permit", id)
}
}
cell test PermitTests {
rules {
// the self-certification shortcut does not exist
assert pay_fee("p1").ok == true
assert issue("p1").ok == false // filed -> issued: no edge
assert_fails transition("p1", "issued")
assert_fails transition("p1", "fire_ok") // and no skipping ahead
// the only road is through every review
assert pass_zoning("p1").ok == true
assert pass_structural("p1").ok == true
assert pass_fire("p1").ok == true
assert issue("p1").ok == true
assert permit_state("p1") == "issued"
assert_fails transition("p1", "filed") // issued is forever
assert_fails fees.set("p1", 2) // no double-billing
// an unpaid permit stalls at the cashier even after reviews
assert pass_zoning("p2").ok == true
assert pass_structural("p2").ok == true
assert pass_fire("p2").ok == true
assert issue("p2").ok == false // fee unpaid
// a denial is terminal too
assert deny("p3").ok == true
assert_fails transition("p3", "zoning_ok")
}
}What the toolchain says
$ soma check permit.cell
✓ All checks passed.$ soma test permit.cell
test PermitTests ...
✓ assert pay_fee("p1").ok == true
✓ assert issue("p1").ok == false
✓ assert_fails transition("p1", "issued") — raised invalid transition: filed → issued. Current state: 'filed'. Valid targets: [zoning_ok, denied]
✓ assert_fails transition("p1", "fire_ok") — raised invalid transition: filed → fire_ok. Current state: 'filed'. Valid targets: [zoning_ok, denied]
✓ assert pass_zoning("p1").ok == true
✓ assert pass_structural("p1").ok == true
✓ assert pass_fire("p1").ok == true
✓ assert issue("p1").ok == true
✓ assert permit_state("p1") == "issued"
✓ assert_fails transition("p1", "filed") — raised invalid transition: issued → filed. Current state: 'issued'. Valid targets: []
✓ assert_fails fees.set("p1", 2) — raised memory invariant violated on 'fees': fees >= 0 && fees <= 1 — rejected write of 2 (key "p1"); the slot is unchanged
✓ assert pass_zoning("p2").ok == true
✓ assert pass_structural("p2").ok == true
✓ assert pass_fire("p2").ok == true
✓ assert issue("p2").ok == false
✓ assert deny("p3").ok == true
✓ assert_fails transition("p3", "zoning_ok") — raised invalid transition: denied → zoning_ok. Current state: 'denied'. Valid targets: []
17 tests: 17 passed, 0 failed$ soma verify permit.cell
Verifying permit.cell...
State machine 'permit': 6 states, initial 'filed'
States: [denied, filed, fire_ok, issued, structural_ok, zoning_ok]
✓ 6 states, 8 transitions
✓ all states reachable from 'filed'
✓ terminal states: [issued, denied]
✓ no deadlocks
✓ liveness: every state can eventually reach a terminal state
✓ think-isolated: CTL safety properties hold regardless of LLM output (5 handlers, 5 literal transitions, 0 dynamic)
✓ termination: all 7 handlers structurally terminate
✓ refinement: handler `pass_zoning` ⟶ {zoning_ok}
✓ refinement: handler `pass_structural` ⟶ {structural_ok}
✓ refinement: handler `pass_fire` ⟶ {fire_ok}
✓ refinement: handler `issue` ⟶ {issued}
✓ refinement: handler `deny` ⟶ {denied}
· transition sources: `pass_zoning`, `pass_structural`, `pass_fire`, `issue`, `deny` 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)
BuildingPermit/invariants:
✓ invariant fees >= 0 — writer 'pay_fee' proven by induction (writes prior + 1)
⚠ invariant fees >= 0 && fees <= 1 — runtime-checked (computed values): pay_fee → fees [fees <= 1] because `prior + 1` is only known to lie in [1, 2] — narrow it: `require (prior + 1) <= 1 else …`
13 passed, 1 warnings, 0 failures
Temporal properties for 'permit':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK