Landing gear — weight-on-wheels interlock, made unrepresentable
Gear-retraction-on-the-ground is an old, recurring accident: a crew or mechanic commands "gear up" while the aircraft is sitting on its wheels, the squat-switch wiring is faulted or bypassed, and the airframe drops onto its belly — people under the wings die. The classic fix is a weight-on-wheels (WoW) microswitch that an interlock relay reads. The classic failure is that the switch and the gear lever are TWO separate signals that can disagree. Here ground contact and gear position are ONE state. There is no edge from ground_down to airborne_up: retraction on the ground is not a guarded command, it is a transition that does not exist. The symmetric hazard — calling a gear-up arrival a normal touchdown — is equally absent. A memory invariant keeps the hydraulic system inside its burst rating no matter what the pump controller writes.
A Soma program from the aerospace part of the verified corpus: 99 lines, cells GearInterlock, GearTests. It passes soma check with soma 3.2.4.
How it is built
The cell GearInterlock declares 5 signals in its face: lift_off(id: String) -> Map, retract(id: String) -> Map, extend(id: String) -> Map, touch_down(id: String) -> Map and gear_report(id: String) -> Map; keeps 1 memory slot: hyd_psi (Map<String, Int>, persistent and consistent) under the invariant hyd_psi >= 0 && hyd_psi <= 3200. Its state machine gear starts in ground_down and allows 4 transitions: ground_down -> airborne_down, airborne_down -> airborne_up, airborne_up -> airborne_down and airborne_down -> ground_down. Handlers: attempt_move (line 47), lift_off (line 53), retract (line 55), extend (line 60), touch_down (line 65) and gear_report (line 67).
The file also holds 1 test cell (GearTests) with 13 assertions, run by soma test.
The source
gear_interlock.cell
// ============================================================================
// LANDING GEAR — weight-on-wheels interlock, made unrepresentable
// ============================================================================
//
// Gear-retraction-on-the-ground is an old, recurring accident: a crew or
// mechanic commands "gear up" while the aircraft is sitting on its wheels,
// the squat-switch wiring is faulted or bypassed, and the airframe drops
// onto its belly — people under the wings die. The classic fix is a
// weight-on-wheels (WoW) microswitch that an interlock relay reads. The
// classic failure is that the switch and the gear lever are TWO separate
// signals that can disagree.
//
// Here ground contact and gear position are ONE state. There is no edge
// from ground_down to airborne_up: retraction on the ground is not a
// guarded command, it is a transition that does not exist. The symmetric
// hazard — calling a gear-up arrival a normal touchdown — is equally
// absent. A memory invariant keeps the hydraulic system inside its burst
// rating no matter what the pump controller writes.
// ============================================================================
cell GearInterlock {
face {
signal lift_off(id: String) -> Map
signal retract(id: String) -> Map
signal extend(id: String) -> Map
signal touch_down(id: String) -> Map
signal gear_report(id: String) -> Map
}
memory {
// gear hydraulic pressure, psi — rated 3000, burst margin 3200
hyd_psi: Map<String, Int> [persistent, consistent]
invariant hyd_psi >= 0 && hyd_psi <= 3200
}
// Gear position and weight-on-wheels are ONE state, never two flags.
// ABSENT: ground_down -> airborne_up (retraction on the ground)
// ABSENT: airborne_up -> ground_down (gear-up arrival called "normal")
state gear {
initial: ground_down
ground_down -> airborne_down // rotation: weight leaves the wheels
airborne_down -> airborne_up // retract: only with weight OFF
airborne_up -> airborne_down // extend before any landing
airborne_down -> ground_down // touchdown: gear down, locked
}
on attempt_move(id: String, target: String) {
let r = try { transition(id, target) }
if r.error != () { return map("ok", false, "reason", "{r.error}") }
return map("ok", true, "state", get_status(id))
}
on lift_off(id: String) { return attempt_move(id, "airborne_down") }
on retract(id: String) {
hyd_psi.set(id, 3000) // pump up to actuate
return attempt_move(id, "airborne_up")
}
on extend(id: String) {
hyd_psi.set(id, 3000)
return attempt_move(id, "airborne_down")
}
on touch_down(id: String) { return attempt_move(id, "ground_down") }
on gear_report(id: String) {
return map("id", id, "state", get_status(id), "psi", hyd_psi.get(id) ?? 0)
}
}
cell test GearTests {
rules {
// THE accident: gear-up commanded on the ground. The transition
// does not exist, so it raises — and the signal reports refusal.
assert_fails transition("g1", "airborne_up")
assert retract("g1").ok == false
assert gear_report("g1").state == "ground_down"
// a normal flight cycle proceeds
assert lift_off("g1").ok == true
assert retract("g1").ok == true
assert extend("g1").ok == true
assert touch_down("g1").ok == true
// back on the ground the interlock holds again
assert_fails transition("g1", "airborne_up")
// a gear-up touchdown is equally unrepresentable
assert lift_off("g2").ok == true
assert retract("g2").ok == true
assert_fails transition("g2", "ground_down")
// hydraulics never see a pressure outside the burst rating
assert_fails hyd_psi.set("g1", 5000)
assert_fails hyd_psi.set("g1", -1)
}
}What the toolchain says
$ soma check gear_interlock.cell
✓ All checks passed.$ soma test gear_interlock.cell
test GearTests ...
✓ assert_fails transition("g1", "airborne_up") — raised invalid transition: ground_down → airborne_up. Current state: 'ground_down'. Valid targets: [airborne_down]
✓ assert retract("g1").ok == false
✓ assert gear_report("g1").state == "ground_down"
✓ assert lift_off("g1").ok == true
✓ assert retract("g1").ok == true
✓ assert extend("g1").ok == true
✓ assert touch_down("g1").ok == true
✓ assert_fails transition("g1", "airborne_up") — raised invalid transition: ground_down → airborne_up. Current state: 'ground_down'. Valid targets: [airborne_down]
✓ assert lift_off("g2").ok == true
✓ assert retract("g2").ok == true
✓ assert_fails transition("g2", "ground_down") — raised invalid transition: airborne_up → ground_down. Current state: 'airborne_up'. Valid targets: [airborne_down]
✓ assert_fails hyd_psi.set("g1", 5000) — raised memory invariant violated on 'hyd_psi': hyd_psi >= 0 && hyd_psi <= 3200 — rejected write of 5000 (key "g1"); the slot is unchanged
✓ assert_fails hyd_psi.set("g1", -1) — raised memory invariant violated on 'hyd_psi': hyd_psi >= 0 && hyd_psi <= 3200 — rejected write of -1 (key "g1"); the slot is unchanged
13 tests: 13 passed, 0 failed$ soma verify gear_interlock.cell
Verifying gear_interlock.cell...
State machine 'gear': 3 states, initial 'ground_down'
States: [airborne_down, airborne_up, ground_down]
✓ 3 states, 4 transitions
✓ all states reachable from 'ground_down'
✓ reactive machine: no terminal state, and every reachable state can return to 'ground_down'
✓ no deadlocks
✓ liveness: every reachable state can return to 'ground_down' (reactive machine)
⚠ dynamic transition targets: handler `attempt_move` uses a dynamic (computed) transition target — the state these handlers move to is computed at run time (from input or an LLM answer), so the machine's safety is checked at run time for them, not proven
✓ termination: all 6 handlers structurally terminate
⚠ refinement (partial — dynamic targets fall back to runtime check): handler `attempt_move` calls transition() with a computed target — which edge it takes is checked at run time (invalid_transition), not proven; write the target as a literal state to have it verified
✓ refinement (partial — dynamic targets fall back to runtime check): handler `attempt_move` ⟶ <dynamic>
GearInterlock/invariants:
✓ invariant hyd_psi >= 0 && hyd_psi <= 3200 — writer 'extend' proven (writes 3000)
✓ invariant hyd_psi >= 0 && hyd_psi <= 3200 — writer 'retract' proven (writes 3000)
9 passed, 2 warnings, 0 failures
Temporal properties for 'gear':
✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK