Seasonal ladder — decay you cannot dodge, ratings that cannot underflow
Two real ladder failures. One: integer underflow on rating loss minted players with astronomical "unsigned" MMR on early third-party CS ladders. Two: operators quietly editing ARCHIVED seasons, retroactively changing who earned rewards. Here the rating lives behind a 0..3000 memory invariant — no underflow, no injected over-cap — and the season is a machine soma verify proves: gains only while `active`, decay only inside the `decaying` window, and `archived` is terminal. History cannot be edited.
A Soma program from the games_economy part of the verified corpus: 98 lines, cells Ladder, LadderTests. It passes soma check with soma 3.2.4.
How it is built
The cell Ladder declares 7 signals in its face: open_season() -> Map, start_decay() -> Map, archive_season() -> Map, award_points(player: String, pts: Int) -> Map, decay_tick(player: String) -> Map, rating_of(player: String) -> Int and season_phase() -> String; keeps 1 memory slot: rating (Map<String, Int>, persistent and consistent) under the invariant rating >= 0 && rating <= 3000. Its state machine season starts in preseason and allows 3 transitions: preseason -> active, active -> decaying and decaying -> archived. archived is terminal. Handlers: season_phase (line 37), open_season (line 39), award_points (line 45), start_decay (line 52), decay_tick (line 58), archive_season (line 65) and rating_of (line 71).
The file also holds 1 test cell (LadderTests) with 16 assertions, run by soma test.
The source
season_ladder.cell
// ============================================================================
// SEASONAL LADDER — decay you cannot dodge, ratings that cannot underflow
// ============================================================================
// Two real ladder failures. One: integer underflow on rating loss minted
// players with astronomical "unsigned" MMR on early third-party CS ladders.
// Two: operators quietly editing ARCHIVED seasons, retroactively changing
// who earned rewards. Here the rating lives behind a 0..3000 memory
// invariant — no underflow, no injected over-cap — and the season is a
// machine soma verify proves: gains only while `active`, decay only inside
// the `decaying` window, and `archived` is terminal. History cannot be
// edited.
// ============================================================================
cell Ladder {
face {
signal open_season() -> Map
signal start_decay() -> Map
signal archive_season() -> Map
signal award_points(player: String, pts: Int) -> Map
signal decay_tick(player: String) -> Map
signal rating_of(player: String) -> Int
signal season_phase() -> String
}
memory {
rating: Map<String, Int> [persistent, consistent]
invariant rating >= 0 && rating <= 3000
}
state season {
initial: preseason
preseason -> active
active -> decaying
decaying -> archived
}
on season_phase() { return get_status("season") }
on open_season() {
let r = try { transition("season", "active") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true)
}
on award_points(player: String, pts: Int) {
if season_phase() != "active" { return map("ok", false, "reason", "season not active") }
let w = try { rating.set(player, (rating.get(player) ?? 0) + pts) }
if w.error != () { return map("ok", false, "reason", "rating must stay in 0..3000") }
return map("ok", true, "rating", rating.get(player))
}
on start_decay() {
let r = try { transition("season", "decaying") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true)
}
on decay_tick(player: String) {
if season_phase() != "decaying" { return map("ok", false, "reason", "no decay outside the window") }
let cur = rating.get(player) ?? 0
rating.set(player, max(0, cur - 100)) // floors at 0 — the invariant agrees
return map("ok", true, "rating", rating.get(player))
}
on archive_season() {
let r = try { transition("season", "archived") }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true)
}
on rating_of(player: String) { return rating.get(player) ?? 0 }
}
cell test LadderTests {
rules {
// no points before the season opens
assert award_points("kay", 100).ok == false
assert open_season().ok == true
assert award_points("kay", 2950).ok == true
// over-cap and underflow are unrepresentable
assert award_points("kay", 100).ok == false
assert rating_of("kay") == 2950
assert_fails rating.set("kay", 3001)
assert_fails rating.set("kay", -1)
// decay runs only inside the decay window, and floors at zero
assert decay_tick("kay").ok == false
assert start_decay().ok == true
assert award_points("kay", 10).ok == false
assert decay_tick("kay").ok == true
assert rating_of("kay") == 2850
// ARCHIVED IS FOREVER — no retroactive season edits
assert archive_season().ok == true
assert_fails transition("season", "active")
assert_fails transition("season", "decaying")
assert decay_tick("kay").ok == false
}
}What the toolchain says
$ soma check season_ladder.cell
✓ All checks passed.$ soma test season_ladder.cell
test LadderTests ...
✓ assert award_points("kay", 100).ok == false
✓ assert open_season().ok == true
✓ assert award_points("kay", 2950).ok == true
✓ assert award_points("kay", 100).ok == false
✓ assert rating_of("kay") == 2950
✓ assert_fails rating.set("kay", 3001) — raised memory invariant violated on 'rating': rating >= 0 && rating <= 3000 — rejected write of 3001 (key "kay"); the slot is unchanged
✓ assert_fails rating.set("kay", -1) — raised memory invariant violated on 'rating': rating >= 0 && rating <= 3000 — rejected write of -1 (key "kay"); the slot is unchanged
✓ assert decay_tick("kay").ok == false
✓ assert start_decay().ok == true
✓ assert award_points("kay", 10).ok == false
✓ assert decay_tick("kay").ok == true
✓ assert rating_of("kay") == 2850
✓ assert archive_season().ok == true
✓ assert_fails transition("season", "active") — raised invalid transition: archived → active. Current state: 'archived'. Valid targets: []
✓ assert_fails transition("season", "decaying") — raised invalid transition: archived → decaying. Current state: 'archived'. Valid targets: []
✓ assert decay_tick("kay").ok == false
16 tests: 16 passed, 0 failed$ soma verify season_ladder.cell
Verifying season_ladder.cell...
State machine 'season': 4 states, initial 'preseason'
States: [active, archived, decaying, preseason]
✓ 4 states, 3 transitions
✓ all states reachable from 'preseason'
✓ terminal states: [archived]
✓ 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 `open_season` ⟶ {active}
✓ refinement: handler `start_decay` ⟶ {decaying}
✓ refinement: handler `archive_season` ⟶ {archived}
· transition sources: `open_season`, `start_decay`, `archive_season` 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)
Ladder/invariants:
✓ invariant rating >= 0 && rating <= 3000 — writer 'decay_tick' proven by induction (writes max(0, cur - 100))
⚠ invariant rating >= 0 && rating <= 3000 — runtime-checked (computed values): award_points → rating because `pts` is a parameter (narrow it: `require ((rating.get(player) ?? 0) + pts) >= 0 && ((rating.get(player) ?? 0) + pts) <= 3000 else …`); `rating` has no known range
11 passed, 1 warnings, 0 failures
Temporal properties for 'season':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK