Judicial recusal — a conflicted judge cannot sit, and cases aren't shopped
Caperton v. A.T. Massey Coal (2009): while a $50M verdict against Massey was heading to West Virginia's Supreme Court, Massey's CEO spent $3M electing Justice Brent Benjamin to that court. Benjamin refused to recuse himself — twice — and cast the deciding vote to overturn the verdict. The U.S. Supreme Court held the Due Process Clause itself required recusal. The lesson: recusal cannot be left to the conflicted judge's own discretion. Here the conflicts register is consulted by the assignment machinery, not by the judge's conscience. And the second classic abuse — judge shopping, reassigning a case until a friendly bench appears — is a memory invariant: one case, one assignment, ever. The second assignment is a write the docket refuses.
A Soma program from the governance part of the verified corpus: 121 lines, cells Docket, RecusalTests. It passes soma check with soma 3.2.4.
How it is built
The cell Docket declares 5 signals in its face: declare_conflict(judge: String, party: String) -> Map, assign_case(case_id: String, judge: String, party_a: String, party_b: String) -> Map, hear(case_id: String) -> Map, rule(case_id: String) -> Map and bench_of(case_id: String) -> String; keeps 3 memory slots: seatings (Map<String, Int>, persistent and consistent) under the invariant seatings >= 0 && seatings <= 1, conflicts (Map<String, Int>, persistent and consistent) under the invariant conflicts >= 1 && conflicts <= 1 and bench (Map<String, String>, persistent and consistent). Its state machine court_case starts in filed and allows 3 transitions: filed -> assigned, assigned -> heard and heard -> decided. decided is terminal. Handlers: declare_conflict (line 50), assign_case (line 55), hear (line 71), rule (line 77) and bench_of (line 83).
The file also holds 1 test cell (RecusalTests) with 16 assertions, run by soma test.
The source
judicial_recusal.cell
// ============================================================================
// JUDICIAL RECUSAL — a conflicted judge cannot sit, and cases aren't shopped
// ============================================================================
//
// Caperton v. A.T. Massey Coal (2009): while a $50M verdict against
// Massey was heading to West Virginia's Supreme Court, Massey's CEO
// spent $3M electing Justice Brent Benjamin to that court. Benjamin
// refused to recuse himself — twice — and cast the deciding vote to
// overturn the verdict. The U.S. Supreme Court held the Due Process
// Clause itself required recusal. The lesson: recusal cannot be left to
// the conflicted judge's own discretion.
//
// Here the conflicts register is consulted by the assignment machinery,
// not by the judge's conscience. And the second classic abuse — judge
// shopping, reassigning a case until a friendly bench appears — is a
// memory invariant: one case, one assignment, ever. The second
// assignment is a write the docket refuses.
// ============================================================================
cell Docket {
face {
signal declare_conflict(judge: String, party: String) -> Map
signal assign_case(case_id: String, judge: String, party_a: String, party_b: String) -> Map
signal hear(case_id: String) -> Map
signal rule(case_id: String) -> Map
signal bench_of(case_id: String) -> String
}
memory {
// case -> assignments made. ONE. Re-rolling the wheel until a
// friendly judge appears is unrepresentable.
seatings: Map<String, Int> [persistent, consistent]
invariant seatings >= 0 && seatings <= 1
conflicts: Map<String, Int> [persistent, consistent]
invariant conflicts >= 1 && conflicts <= 1
bench: Map<String, String> [persistent, consistent]
}
// filed -> assigned -> heard -> decided (TERMINAL: the ruling stands;
// relief comes from appeal in a HIGHER court, not from re-running this one)
state court_case {
initial: filed
filed -> assigned
assigned -> heard
heard -> decided
}
on declare_conflict(judge: String, party: String) {
conflicts.set("{judge}:{party}", 1)
return map("ok", true, "judge", judge, "party", party)
}
on assign_case(case_id: String, judge: String, party_a: String, party_b: String) {
// the register, not the judge's discretion, decides
if conflicts.get("{judge}:{party_a}") != () || conflicts.get("{judge}:{party_b}") != () {
return map("ok", false, "reason",
"due process: {judge} has a registered conflict in {case_id}")
}
// THE WALL: one seating per case — no judge shopping
let w = try { seatings.set(case_id, (seatings.get(case_id) ?? 0) + 1) }
if w.error != () {
return map("ok", false, "reason", "{case_id} already has its judge; no reshuffling")
}
transition(case_id, "assigned")
bench.set(case_id, judge)
return map("ok", true, "case", case_id, "judge", judge)
}
on hear(case_id: String) {
let r = try { transition(case_id, "heard") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "state", "heard")
}
on rule(case_id: String) {
let r = try { transition(case_id, "decided") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "state", "decided", "judge", bench.get(case_id))
}
on bench_of(case_id: String) {
return bench.get(case_id) ?? "[unassigned]"
}
}
cell test RecusalTests {
rules {
// Massey's CEO funds Benjamin's seat; the register knows
assert declare_conflict("benjamin", "massey").ok == true
// the Caperton assignment: structurally refused
assert assign_case("caperton-v-massey", "benjamin", "caperton", "massey").ok == false
assert get_status("caperton-v-massey") == "filed"
assert bench_of("caperton-v-massey") == "[unassigned]"
// an unconflicted judge sits; the case proceeds
assert assign_case("caperton-v-massey", "starcher", "caperton", "massey").ok == true
// judge shopping: the docket can hold only one seating
assert assign_case("caperton-v-massey", "benjamin", "caperton", "massey").ok == false
assert assign_case("caperton-v-massey", "maynard", "caperton", "massey").ok == false
assert_fails seatings.set("caperton-v-massey", 2)
assert bench_of("caperton-v-massey") == "starcher"
// no hearing before assignment, no ruling before hearing
assert_fails transition("fresh-case", "heard")
assert_fails transition("fresh-case", "decided")
// the case runs to judgment; decided is terminal
assert hear("caperton-v-massey").ok == true
assert rule("caperton-v-massey").judge == "starcher"
assert_fails transition("caperton-v-massey", "heard")
assert_fails transition("caperton-v-massey", "filed")
// a conflict entry is a fact, not a dial: only 1 is representable
assert_fails conflicts.set("benjamin:massey", 0)
}
}What the toolchain says
$ soma check judicial_recusal.cell
✓ All checks passed.$ soma test judicial_recusal.cell
test RecusalTests ...
✓ assert declare_conflict("benjamin", "massey").ok == true
✓ assert assign_case("caperton-v-massey", "benjamin", "caperton", "massey").ok == false
✓ assert get_status("caperton-v-massey") == "filed"
✓ assert bench_of("caperton-v-massey") == "[unassigned]"
✓ assert assign_case("caperton-v-massey", "starcher", "caperton", "massey").ok == true
✓ assert assign_case("caperton-v-massey", "benjamin", "caperton", "massey").ok == false
✓ assert assign_case("caperton-v-massey", "maynard", "caperton", "massey").ok == false
✓ assert_fails seatings.set("caperton-v-massey", 2) — raised memory invariant violated on 'seatings': seatings >= 0 && seatings <= 1 — rejected write of 2 (key "caperton-v-massey"); the slot is unchanged
✓ assert bench_of("caperton-v-massey") == "starcher"
✓ assert_fails transition("fresh-case", "heard") — raised invalid transition: filed → heard. Current state: 'filed'. Valid targets: [assigned]
✓ assert_fails transition("fresh-case", "decided") — raised invalid transition: filed → decided. Current state: 'filed'. Valid targets: [assigned]
✓ assert hear("caperton-v-massey").ok == true
✓ assert rule("caperton-v-massey").judge == "starcher"
✓ assert_fails transition("caperton-v-massey", "heard") — raised invalid transition: decided → heard. Current state: 'decided'. Valid targets: []
✓ assert_fails transition("caperton-v-massey", "filed") — raised invalid transition: decided → filed. Current state: 'decided'. Valid targets: []
✓ assert_fails conflicts.set("benjamin:massey", 0) — raised memory invariant violated on 'conflicts': conflicts >= 1 && conflicts <= 1 — rejected write of 0 (key "benjamin:massey"); the slot is unchanged
16 tests: 16 passed, 0 failed$ soma verify judicial_recusal.cell
Verifying judicial_recusal.cell...
State machine 'court_case': 4 states, initial 'filed'
States: [assigned, decided, filed, heard]
✓ 4 states, 3 transitions
✓ all states reachable from 'filed'
✓ terminal states: [decided]
✓ 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 5 handlers structurally terminate
✓ refinement: handler `assign_case` ⟶ {assigned}
✓ refinement: handler `hear` ⟶ {heard}
✓ refinement: handler `rule` ⟶ {decided}
· transition sources: `assign_case`, `hear`, `rule` 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)
Docket/invariants:
✓ invariant seatings >= 0 — writer 'assign_case' proven by induction (writes (seatings.get(case_id) ?? 0) + 1)
⚠ invariant seatings >= 0 && seatings <= 1 — runtime-checked (computed values): assign_case → seatings [seatings <= 1] because `seatings` has no known range
✓ invariant conflicts >= 1 && conflicts <= 1 — writer 'declare_conflict' proven (writes 1)
12 passed, 1 warnings, 0 failures
Temporal properties for 'court_case':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK