soma.cell

Disaster aid — one emergency grant per household, however many times asked

After Katrina, GAO estimated roughly $1 billion of FEMA individual assistance was improper — much of it duplicate registrations: the same household applying through different names, addresses, or call centers, each application paid because the dedup ran AFTER the checks went out. Here the duplicate is unrepresentable: a household's grant count is a memory invariant capped at 1, so the second disbursement is refused at the write, whichever intake channel it arrived through. The aid program also has a one-way lifecycle — once the program is audited, soma verify proves it never re-opens for "supplemental" off-book payments.

A Soma program from the civic part of the verified corpus: 116 lines, cells DisasterAid, DisasterAidTests. It passes soma check with soma 3.2.4.

How it is built

The cell DisasterAid declares 7 signals in its face: declare_disaster() -> Map, disburse(household: String, amount: Int) -> Map, close_registration() -> Map, complete_audit() -> Map, grants_to(household: String) -> Int, outlay_total() -> Int and phase() -> String; keeps 2 memory slots: granted (Map<String, Int>, persistent and consistent) under the invariant granted >= 0 && granted <= 1 and outlay (Map<String, Int>, persistent and consistent) under the invariant outlay >= 0 && outlay <= 5000. Its state machine program starts in declared and allows 3 transitions: declared -> registration_open, registration_open -> registration_closed and registration_closed -> audited. audited is terminal. Handlers: phase (line 43), declare_disaster (line 45), disburse (line 51), close_registration (line 72), complete_audit (line 78), grants_to (line 84) and outlay_total (line 86).

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

Generated from soma describe on this file.

The source

disaster_aid.cell

// ============================================================================
// DISASTER AID — one emergency grant per household, however many times asked
// ============================================================================
// After Katrina, GAO estimated roughly $1 billion of FEMA individual
// assistance was improper — much of it duplicate registrations: the same
// household applying through different names, addresses, or call centers,
// each application paid because the dedup ran AFTER the checks went out.
// Here the duplicate is unrepresentable: a household's grant count is a
// memory invariant capped at 1, so the second disbursement is refused at the
// write, whichever intake channel it arrived through. The aid program also
// has a one-way lifecycle — once the program is audited, soma verify proves
// it never re-opens for "supplemental" off-book payments.
// ============================================================================

cell DisasterAid {
    face {
        signal declare_disaster() -> Map
        signal disburse(household: String, amount: Int) -> Map
        signal close_registration() -> Map
        signal complete_audit() -> Map
        signal grants_to(household: String) -> Int
        signal outlay_total() -> Int
        signal phase() -> String
    }

    memory {
        // household -> emergency grants. A second grant is unrepresentable.
        granted: Map<String, Int> [persistent, consistent]
        invariant granted >= 0 && granted <= 1

        outlay: Map<String, Int> [persistent, consistent]
        invariant outlay >= 0 && outlay <= 5000
    }

    // audited is terminal: a closed program pays no one, ever again.
    state program {
        initial: declared
        declared -> registration_open
        registration_open -> registration_closed
        registration_closed -> audited
    }

    on phase() { return get_status("program") }

    on declare_disaster() {
        let r = try { transition("program", "registration_open") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true)
    }

    on disburse(household: String, amount: Int) {
        if phase() != "registration_open" {
            return map("ok", false, "reason", "program is {phase()}")
        }
        if amount <= 0 { return map("ok", false, "reason", "amount must be positive") }
        let prior = granted.get(household) ?? 0
        // WALL 1: the duplicate registration, refused at the write —
        // a different call center is still the same household key.
        let g = try { granted.set(household, prior + 1) }
        if g.error != () {
            return map("ok", false, "reason", "{household} already assisted")
        }
        // WALL 2: the per-household statutory cap on the check itself.
        let w = try { outlay.set(household, amount) }
        if w.error != () {
            granted.set(household, prior)                 // roll the grant back
            return map("ok", false, "reason", "amount {amount} exceeds the 5000 cap")
        }
        return map("ok", true, "household", household, "amount", amount)
    }

    on close_registration() {
        let r = try { transition("program", "registration_closed") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "outlay", outlay_total())
    }

    on complete_audit() {
        let r = try { transition("program", "audited") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "outlay", outlay_total())
    }

    on grants_to(household: String) { return granted.get(household) ?? 0 }

    on outlay_total() {
        let names = outlay.keys()
        let n = 0
        for h in names { n = n + (outlay.get(h) ?? 0) }
        return n
    }
}

cell test DisasterAidTests {
    rules {
        assert disburse("hh-12", 3000).ok == false        // no declaration yet
        assert declare_disaster().ok == true
        assert disburse("hh-12", 3000).ok == true
        // the duplicate registration, through a "different" call center
        assert disburse("hh-12", 3000).ok == false
        assert_fails granted.set("hh-12", 2)              // unrepresentable
        assert grants_to("hh-12") == 1
        // the oversized check bounces and leaves no phantom grant behind
        assert disburse("hh-77", 9000).ok == false
        assert grants_to("hh-77") == 0
        assert_fails outlay.set("hh-77", 9000)
        assert disburse("hh-77", 5000).ok == true         // the cap itself is fine
        assert outlay_total() == 8000
        assert close_registration().ok == true
        assert disburse("hh-99", 100).ok == false         // registration closed
        assert complete_audit().ok == true
        assert_fails transition("program", "registration_open")  // audited forever
        assert_fails transition("program", "registration_closed")
    }
}

What the toolchain says

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

$ soma check disaster_aid.cell
✓ All checks passed.
$ soma test disaster_aid.cell
test DisasterAidTests ...
  ✓ assert disburse("hh-12", 3000).ok == false
  ✓ assert declare_disaster().ok == true
  ✓ assert disburse("hh-12", 3000).ok == true
  ✓ assert disburse("hh-12", 3000).ok == false
  ✓ assert_fails granted.set("hh-12", 2) — raised memory invariant violated on 'granted': granted >= 0 && granted <= 1 — rejected write of 2 (key "hh-12"); the slot is unchanged
  ✓ assert grants_to("hh-12") == 1
  ✓ assert disburse("hh-77", 9000).ok == false
  ✓ assert grants_to("hh-77") == 0
  ✓ assert_fails outlay.set("hh-77", 9000) — raised memory invariant violated on 'outlay': outlay >= 0 && outlay <= 5000 — rejected write of 9000 (key "hh-77"); the slot is unchanged
  ✓ assert disburse("hh-77", 5000).ok == true
  ✓ assert outlay_total() == 8000
  ✓ assert close_registration().ok == true
  ✓ assert disburse("hh-99", 100).ok == false
  ✓ assert complete_audit().ok == true
  ✓ assert_fails transition("program", "registration_open") — raised invalid transition: audited → registration_open. Current state: 'audited'. Valid targets: []
  ✓ assert_fails transition("program", "registration_closed") — raised invalid transition: audited → registration_closed. Current state: 'audited'. Valid targets: []

16 tests: 16 passed, 0 failed
$ soma verify disaster_aid.cell
Verifying disaster_aid.cell...

State machine 'program': 4 states, initial 'declared'
  States: [audited, declared, registration_closed, registration_open]

  ✓ 4 states, 3 transitions
  ✓ all states reachable from 'declared'
  ✓ terminal states: [audited]
  ✓ no deadlocks
  ✓ liveness: every state can eventually reach a terminal state
  ✓ think-isolated: CTL safety properties hold regardless of LLM output (3 handlers, 3 literal transitions, 0 dynamic)
  ✓ termination: all 7 handlers structurally terminate
  ✓ refinement: handler `declare_disaster` ⟶ {registration_open}
  ✓ refinement: handler `close_registration` ⟶ {registration_closed}
  ✓ refinement: handler `complete_audit` ⟶ {audited}
  · transition sources: `declare_disaster`, `close_registration`, `complete_audit` 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)

DisasterAid/invariants:

  ✓ invariant granted >= 0 — writer 'disburse' proven by induction (writes prior + 1)
  ✓ invariant granted >= 0 && granted <= 1 — writer 'disburse' proven by induction (writes prior)
  ⚠ invariant granted >= 0 && granted <= 1 — runtime-checked (computed values): disburse → granted [granted <= 1] because `prior + 1` is only known to lie in [1, 2] — narrow it: `require (prior + 1) <= 1 else …`
  ✓ invariant outlay >= 0 — writer 'disburse' proven by induction (writes amount)
  ⚠ invariant outlay >= 0 && outlay <= 5000 — runtime-checked (computed values): disburse → outlay [outlay <= 5000] because `amount` is only known to lie in [1, ∞) — narrow it: `require amount <= 5000 else …`

13 passed, 2 warnings, 0 failures

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

Builtins used

get_status, map, transition

Source file: /corpus/civic/disaster_aid.cell · examples/corpus/civic/disaster_aid.cell