soma.cell

Thrust reverser — Lauda Air 004: in-flight deployment, made structural

On 26 May 1991, Lauda Air Flight 004 — a Boeing 767 climbing out of Bangkok — lost 223 people when the left engine's thrust reverser deployed IN FLIGHT. Reverse thrust at climb power tore the airflow off the wing; the aircraft broke up in seconds. The reverser system had interlocks, but they were plumbing and relays guarding a hydraulic valve — and a fault sequence got past them. Here flight phase and reverser position are ONE state machine. The state {in flight, reverser deployed} is not guarded against — it is not a state. Deployment is reachable only from on_ground (weight on wheels), and the only exit from reverse thrust is stowing: you cannot rotate back into the air with the buckets out either.

A Soma program from the aerospace part of the verified corpus: 100 lines, cells ThrustReverser, ReverserTests. It passes soma check with soma 3.2.4.

How it is built

The cell ThrustReverser declares 5 signals in its face: touchdown_wow(id: String) -> Map, deploy_reverse(id: String) -> Map, stow_reverse(id: String) -> Map, takeoff_roll(id: String) -> Map and reverser_state(id: String) -> String; keeps 1 memory slot: n1_pct (Map<String, Int>, persistent and consistent) under the invariant n1_pct >= 0 && n1_pct <= 104. Its state machine reverser starts in inflight and allows 4 transitions: inflight -> on_ground, on_ground -> reverse_thrust, reverse_thrust -> on_ground and on_ground -> inflight. Handlers: guarded (line 44), touchdown_wow (line 50), deploy_reverse (line 55), stow_reverse (line 61), takeoff_roll (line 66) and reverser_state (line 72).

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

Generated from soma describe on this file.

The source

thrust_reverser.cell

// ============================================================================
// THRUST REVERSER — Lauda Air 004: in-flight deployment, made structural
// ============================================================================
//
// On 26 May 1991, Lauda Air Flight 004 — a Boeing 767 climbing out of
// Bangkok — lost 223 people when the left engine's thrust reverser
// deployed IN FLIGHT. Reverse thrust at climb power tore the airflow off
// the wing; the aircraft broke up in seconds. The reverser system had
// interlocks, but they were plumbing and relays guarding a hydraulic
// valve — and a fault sequence got past them.
//
// Here flight phase and reverser position are ONE state machine. The
// state {in flight, reverser deployed} is not guarded against — it is
// not a state. Deployment is reachable only from on_ground (weight on
// wheels), and the only exit from reverse thrust is stowing: you cannot
// rotate back into the air with the buckets out either.
// ============================================================================

cell ThrustReverser {
    face {
        signal touchdown_wow(id: String) -> Map
        signal deploy_reverse(id: String) -> Map
        signal stow_reverse(id: String) -> Map
        signal takeoff_roll(id: String) -> Map
        signal reverser_state(id: String) -> String
    }

    memory {
        // commanded N1, percent — never outside the engine's rated band
        n1_pct: Map<String, Int> [persistent, consistent]
        invariant n1_pct >= 0 && n1_pct <= 104
    }

    // ABSENT: inflight -> reverse_thrust  (the Lauda Air state)
    // ABSENT: reverse_thrust -> inflight  (lifting off with buckets out)
    state reverser {
        initial: inflight
        inflight -> on_ground          // weight on wheels at touchdown
        on_ground -> reverse_thrust    // deploy: only with WoW
        reverse_thrust -> on_ground    // stow is the ONLY exit
        on_ground -> inflight          // takeoff: only from stowed
    }

    on guarded(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 touchdown_wow(id: String) {
        n1_pct.set(id, 30)                       // idle at touchdown
        return guarded(id, "on_ground")
    }

    on deploy_reverse(id: String) {
        let r = guarded(id, "reverse_thrust")
        if r.ok { n1_pct.set(id, 85) }           // reverse power, on ground only
        return r
    }

    on stow_reverse(id: String) {
        n1_pct.set(id, 25)
        return guarded(id, "on_ground")
    }

    on takeoff_roll(id: String) {
        let r = guarded(id, "inflight")
        if r.ok { n1_pct.set(id, 100) }
        return r
    }

    on reverser_state(id: String) { return get_status(id) }
}

cell test ReverserTests {
    rules {
        // THE Lauda Air transition: deployment in flight. It does not exist.
        assert_fails transition("eng1", "reverse_thrust")
        assert deploy_reverse("eng1").ok == false
        assert reverser_state("eng1") == "inflight"

        // the legal sequence: touchdown, deploy, stow, depart again
        assert touchdown_wow("eng1").ok == true
        assert deploy_reverse("eng1").ok == true
        assert reverser_state("eng1") == "reverse_thrust"

        // with the buckets out, the only exit is stowing — no takeoff
        assert_fails transition("eng1", "inflight")
        assert stow_reverse("eng1").ok == true
        assert takeoff_roll("eng1").ok == true

        // and airborne again, the interlock holds
        assert_fails transition("eng1", "reverse_thrust")

        // commanded N1 can never leave the rated band
        assert_fails n1_pct.set("eng1", 120)
        assert_fails n1_pct.set("eng1", -5)
    }
}

What the toolchain says

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

$ soma check thrust_reverser.cell
✓ All checks passed.
$ soma test thrust_reverser.cell
test ReverserTests ...
  ✓ assert_fails transition("eng1", "reverse_thrust") — raised invalid transition: inflight → reverse_thrust. Current state: 'inflight'. Valid targets: [on_ground]
  ✓ assert deploy_reverse("eng1").ok == false
  ✓ assert reverser_state("eng1") == "inflight"
  ✓ assert touchdown_wow("eng1").ok == true
  ✓ assert deploy_reverse("eng1").ok == true
  ✓ assert reverser_state("eng1") == "reverse_thrust"
  ✓ assert_fails transition("eng1", "inflight") — raised invalid transition: reverse_thrust → inflight. Current state: 'reverse_thrust'. Valid targets: [on_ground]
  ✓ assert stow_reverse("eng1").ok == true
  ✓ assert takeoff_roll("eng1").ok == true
  ✓ assert_fails transition("eng1", "reverse_thrust") — raised invalid transition: inflight → reverse_thrust. Current state: 'inflight'. Valid targets: [on_ground]
  ✓ assert_fails n1_pct.set("eng1", 120) — raised memory invariant violated on 'n1_pct': n1_pct >= 0 && n1_pct <= 104 — rejected write of 120 (key "eng1"); the slot is unchanged
  ✓ assert_fails n1_pct.set("eng1", -5) — raised memory invariant violated on 'n1_pct': n1_pct >= 0 && n1_pct <= 104 — rejected write of -5 (key "eng1"); the slot is unchanged

12 tests: 12 passed, 0 failed
$ soma verify thrust_reverser.cell
Verifying thrust_reverser.cell...

State machine 'reverser': 3 states, initial 'inflight'
  States: [inflight, on_ground, reverse_thrust]

  ✓ 3 states, 4 transitions
  ✓ all states reachable from 'inflight'
  ✓ reactive machine: no terminal state, and every reachable state can return to 'inflight'
  ✓ no deadlocks
  ✓ liveness: every reachable state can return to 'inflight' (reactive machine)
  ⚠ dynamic transition targets: handler `guarded` 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 `guarded` 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 `guarded` ⟶ <dynamic>

ThrustReverser/invariants:

  ✓ invariant n1_pct >= 0 && n1_pct <= 104 — writer 'deploy_reverse' proven (writes 85)
  ✓ invariant n1_pct >= 0 && n1_pct <= 104 — writer 'stow_reverse' proven (writes 25)
  ✓ invariant n1_pct >= 0 && n1_pct <= 104 — writer 'takeoff_roll' proven (writes 100)
  ✓ invariant n1_pct >= 0 && n1_pct <= 104 — writer 'touchdown_wow' proven (writes 30)

11 passed, 2 warnings, 0 failures

  Temporal properties for 'reverser':
  ✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK

Builtins used

get_status, map, transition

Source file: /corpus/aerospace/thrust_reverser.cell · examples/corpus/aerospace/thrust_reverser.cell