soma.cell

Jury — strikes are counted by the bench, not by the honor system

Curtis Flowers was tried six times; the prosecutor's pattern of striking Black jurors finally reached the Supreme Court (Flowers v. Mississippi, 2019). Peremptory strikes are abusable partly because nothing mechanical stops a side from burning more than its allotment — the count lives in a clerk's margin notes. Here 28 U.S.C. § 1870's three peremptory challenges per side is a memory invariant: the fourth strike is refused at the write. A juror can be seated at most once, and a sworn panel is terminal — soma verify proves no one reshuffles the box after jeopardy attaches.

A Soma program from the civic part of the verified corpus: 118 lines, cells JurySelection, JuryTests. It passes soma check with soma 3.2.4.

How it is built

The cell JurySelection declares 6 signals in its face: seat_juror(juror: String) -> Map, peremptory_strike(side: String, juror: String) -> Map, swear_panel() -> Map, seated_count() -> Int, strikes_used(side: String) -> Int and phase() -> String; keeps 2 memory slots: seated (Map<String, Int>, persistent and consistent) under the invariant seated >= 0 && seated <= 1 and strikes (Map<String, Int>, persistent and consistent) under the invariant strikes >= 0 && strikes <= 3. Its state machine panel starts in voir_dire and allows 1 transition: voir_dire -> sworn. sworn is terminal. Handlers: phase (line 40), seat_juror (line 42), peremptory_strike (line 54), swear_panel (line 71), seated_count (line 80) and strikes_used (line 87).

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

Generated from soma describe on this file.

The source

jury.cell

// ============================================================================
// JURY — strikes are counted by the bench, not by the honor system
// ============================================================================
// Curtis Flowers was tried six times; the prosecutor's pattern of striking
// Black jurors finally reached the Supreme Court (Flowers v. Mississippi,
// 2019). Peremptory strikes are abusable partly because nothing mechanical
// stops a side from burning more than its allotment — the count lives in a
// clerk's margin notes. Here 28 U.S.C. § 1870's three peremptory challenges
// per side is a memory invariant: the fourth strike is refused at the write.
// A juror can be seated at most once, and a sworn panel is terminal — soma
// verify proves no one reshuffles the box after jeopardy attaches.
// ============================================================================

cell JurySelection {
    face {
        signal seat_juror(juror: String) -> Map
        signal peremptory_strike(side: String, juror: String) -> Map
        signal swear_panel() -> Map
        signal seated_count() -> Int
        signal strikes_used(side: String) -> Int
        signal phase() -> String
    }

    memory {
        // juror -> times seated. Seating someone twice is unrepresentable.
        seated: Map<String, Int> [persistent, consistent]
        invariant seated >= 0 && seated <= 1

        // side -> peremptory strikes burned. The fourth does not exist.
        strikes: Map<String, Int> [persistent, consistent]
        invariant strikes >= 0 && strikes <= 3
    }

    // sworn has no exit: once the panel is sworn, jeopardy attaches.
    state panel {
        initial: voir_dire
        voir_dire -> sworn
    }

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

    on seat_juror(juror: String) {
        if phase() != "voir_dire" {
            return map("ok", false, "reason", "panel is {phase()}")
        }
        let prior = seated.get(juror) ?? 0
        let w = try { seated.set(juror, prior + 1) }
        if w.error != () {
            return map("ok", false, "reason", "{juror} already in the box")
        }
        return map("ok", true, "juror", juror, "seated", seated_count())
    }

    on peremptory_strike(side: String, juror: String) {
        if phase() != "voir_dire" {
            return map("ok", false, "reason", "panel is {phase()}")
        }
        if (seated.get(juror) ?? 0) == 0 {
            return map("ok", false, "reason", "{juror} is not in the box")
        }
        let used = strikes.get(side) ?? 0
        // THE WALL: strike four refuses, whatever the lawyer argues.
        let w = try { strikes.set(side, used + 1) }
        if w.error != () {
            return map("ok", false, "reason", "{side} has no peremptories left")
        }
        seated.set(juror, 0)
        return map("ok", true, "struck", juror, "used", used + 1)
    }

    on swear_panel() {
        if seated_count() < 6 {
            return map("ok", false, "reason", "panel short: {seated_count()} of 6")
        }
        let r = try { transition("panel", "sworn") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "jurors", seated_count())
    }

    on seated_count() {
        let names = seated.keys()
        let n = 0
        for j in names { n = n + (seated.get(j) ?? 0) }
        return n
    }

    on strikes_used(side: String) { return strikes.get(side) ?? 0 }
}

cell test JuryTests {
    rules {
        assert seat_juror("j1").ok == true
        assert seat_juror("j1").ok == false               // one seat per juror
        assert_fails seated.set("j1", 2)                  // unrepresentable
        assert seat_juror("j2").ok == true
        assert seat_juror("j3").ok == true
        assert seat_juror("j4").ok == true
        // the defense burns its three peremptories...
        assert peremptory_strike("defense", "j2").ok == true
        assert peremptory_strike("defense", "j3").ok == true
        assert peremptory_strike("defense", "j4").ok == true
        // ...and the fourth strike does not exist
        assert peremptory_strike("defense", "j1").ok == false
        assert_fails strikes.set("defense", 4)
        assert seated_count() == 1                        // j1 survived
        assert swear_panel().ok == false                  // panel short of six
        assert seat_juror("j5").ok == true
        assert seat_juror("j6").ok == true
        assert seat_juror("j7").ok == true
        assert seat_juror("j8").ok == true
        assert seat_juror("j9").ok == true
        assert swear_panel().ok == true
        assert seat_juror("j10").ok == false              // box is sealed
        assert peremptory_strike("state", "j1").ok == false
        assert_fails transition("panel", "voir_dire")     // jeopardy attached
    }
}

What the toolchain says

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

$ soma check jury.cell
✓ All checks passed.
$ soma test jury.cell
test JuryTests ...
  ✓ assert seat_juror("j1").ok == true
  ✓ assert seat_juror("j1").ok == false
  ✓ assert_fails seated.set("j1", 2) — raised memory invariant violated on 'seated': seated >= 0 && seated <= 1 — rejected write of 2 (key "j1"); the slot is unchanged
  ✓ assert seat_juror("j2").ok == true
  ✓ assert seat_juror("j3").ok == true
  ✓ assert seat_juror("j4").ok == true
  ✓ assert peremptory_strike("defense", "j2").ok == true
  ✓ assert peremptory_strike("defense", "j3").ok == true
  ✓ assert peremptory_strike("defense", "j4").ok == true
  ✓ assert peremptory_strike("defense", "j1").ok == false
  ✓ assert_fails strikes.set("defense", 4) — raised memory invariant violated on 'strikes': strikes >= 0 && strikes <= 3 — rejected write of 4 (key "defense"); the slot is unchanged
  ✓ assert seated_count() == 1
  ✓ assert swear_panel().ok == false
  ✓ assert seat_juror("j5").ok == true
  ✓ assert seat_juror("j6").ok == true
  ✓ assert seat_juror("j7").ok == true
  ✓ assert seat_juror("j8").ok == true
  ✓ assert seat_juror("j9").ok == true
  ✓ assert swear_panel().ok == true
  ✓ assert seat_juror("j10").ok == false
  ✓ assert peremptory_strike("state", "j1").ok == false
  ✓ assert_fails transition("panel", "voir_dire") — raised invalid transition: sworn → voir_dire. Current state: 'sworn'. Valid targets: []

22 tests: 22 passed, 0 failed
$ soma verify jury.cell
Verifying jury.cell...

State machine 'panel': 2 states, initial 'voir_dire'
  States: [sworn, voir_dire]

  ✓ 2 states, 1 transitions
  ✓ all states reachable from 'voir_dire'
  ✓ terminal states: [sworn]
  ✓ no deadlocks
  ✓ liveness: every state can eventually reach a terminal state
  ✓ think-isolated: CTL safety properties hold regardless of LLM output (1 handlers, 1 literal transitions, 0 dynamic)
  ✓ termination: all 6 handlers structurally terminate
  ✓ refinement: handler `swear_panel` ⟶ {sworn}
  · transition sources: `swear_panel` calls 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)

JurySelection/invariants:

  ✓ invariant seated >= 0 && seated <= 1 — writer 'peremptory_strike' proven (writes 0)
  ✓ invariant seated >= 0 — writer 'seat_juror' proven by induction (writes prior + 1)
  ⚠ invariant seated >= 0 && seated <= 1 — runtime-checked (computed values): seat_juror → seated [seated <= 1] because `prior + 1` is only known to lie in [1, 2] — narrow it: `require (prior + 1) <= 1 else …`
  ✓ invariant strikes >= 0 — writer 'peremptory_strike' proven by induction (writes used + 1)
  ⚠ invariant strikes >= 0 && strikes <= 3 — runtime-checked (computed values): peremptory_strike → strikes [strikes <= 3] because `used + 1` is only known to lie in [1, 4] — narrow it: `require (used + 1) <= 3 else …`

11 passed, 2 warnings, 0 failures

  Temporal properties for 'panel':
  ✓ 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/jury.cell · examples/corpus/civic/jury.cell