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.
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
$ 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