soma.cell

Cabin pressurization — Helios 522: the manual-mode takeoff, unrepresentable

On 14 August 2005, Helios Airways Flight 522 took off from Larnaca with the pressurization mode selector still in MANUAL — left there after an overnight maintenance leak check. The cabin never pressurized. As the 737 climbed, the cabin altitude climbed with it; the warning horn was mistaken for the takeoff-config horn; the crew lost consciousness from hypoxia, and 121 people died when the aircraft ran out of fuel. The failure was a MODE that survived a phase change: maintenance state leaked into flight state. Here those phases are one machine. The only path to airborne goes THROUGH auto_verified — the checklist step where the selector is confirmed in AUTO. From manual_maint there is no edge to airborne at all. And the cabin-altitude ledger refuses to record a hypoxic cabin: the controller's setpoint cannot leave the safe band.

A Soma program from the aerospace part of the verified corpus: 106 lines, cells CabinPressure, PressurizationTests. It passes soma check with soma 3.2.4.

How it is built

The cell CabinPressure declares 6 signals in its face: enter_maintenance(id: String) -> Map, restore_auto(id: String) -> Map, confirm_auto(id: String) -> Map, takeoff(id: String) -> Map, set_cabin_alt(id: String, ft: Int) -> Map and press_phase(id: String) -> String; keeps 1 memory slot: cabin_alt_ft (Map<String, Int>, persistent and consistent) under the invariant cabin_alt_ft >= 0 && cabin_alt_ft <= 8000. Its state machine pressurization starts in preflight and allows 5 transitions: preflight -> manual_maint, manual_maint -> preflight, preflight -> auto_verified, auto_verified -> airborne and airborne -> preflight. Handlers: guarded_step (line 50), enter_maintenance (line 56), restore_auto (line 57), confirm_auto (line 58), takeoff (line 60), set_cabin_alt (line 66) and press_phase (line 74).

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

Generated from soma describe on this file.

The source

cabin_pressurization.cell

// ============================================================================
// CABIN PRESSURIZATION — Helios 522: the manual-mode takeoff, unrepresentable
// ============================================================================
//
// On 14 August 2005, Helios Airways Flight 522 took off from Larnaca with
// the pressurization mode selector still in MANUAL — left there after an
// overnight maintenance leak check. The cabin never pressurized. As the
// 737 climbed, the cabin altitude climbed with it; the warning horn was
// mistaken for the takeoff-config horn; the crew lost consciousness from
// hypoxia, and 121 people died when the aircraft ran out of fuel.
//
// The failure was a MODE that survived a phase change: maintenance state
// leaked into flight state. Here those phases are one machine. The only
// path to airborne goes THROUGH auto_verified — the checklist step where
// the selector is confirmed in AUTO. From manual_maint there is no edge
// to airborne at all. And the cabin-altitude ledger refuses to record a
// hypoxic cabin: the controller's setpoint cannot leave the safe band.
// ============================================================================

cell CabinPressure {
    face {
        signal enter_maintenance(id: String) -> Map
        signal restore_auto(id: String) -> Map
        signal confirm_auto(id: String) -> Map
        signal takeoff(id: String) -> Map
        signal set_cabin_alt(id: String, ft: Int) -> Map
        signal press_phase(id: String) -> String
    }

    memory {
        // cabin altitude setpoint, feet — 8000 is the certification
        // ceiling for a pressurized cabin; the hypoxic cabin Helios flew
        // with is not a value this slot can hold
        cabin_alt_ft: Map<String, Int> [persistent, consistent]
        invariant cabin_alt_ft >= 0 && cabin_alt_ft <= 8000
    }

    // ABSENT: manual_maint -> airborne   (the Helios takeoff)
    // ABSENT: preflight -> airborne      (no takeoff without the check)
    state pressurization {
        initial: preflight
        preflight -> manual_maint     // ground leak check, selector MANUAL
        manual_maint -> preflight     // selector restored — back to start,
                                      // the verification must be REDONE
        preflight -> auto_verified    // checklist: selector confirmed AUTO
        auto_verified -> airborne
        airborne -> preflight         // landed: next flight re-verifies
    }

    on guarded_step(id: String, target: String) {
        let r = try { transition(id, target) }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "phase", get_status(id))
    }

    on enter_maintenance(id: String) { return guarded_step(id, "manual_maint") }
    on restore_auto(id: String)      { return guarded_step(id, "preflight") }
    on confirm_auto(id: String)      { return guarded_step(id, "auto_verified") }

    on takeoff(id: String) {
        let r = guarded_step(id, "airborne")
        if r.ok { cabin_alt_ft.set(id, 8000) }   // cruise cabin altitude
        return r
    }

    on set_cabin_alt(id: String, ft: Int) {
        let w = try { cabin_alt_ft.set(id, ft) }
        if w.error != () {
            return map("ok", false, "reason", "cabin altitude {ft} ft is outside the safe band")
        }
        return map("ok", true, "cabin_alt", ft)
    }

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

cell test PressurizationTests {
    rules {
        // THE Helios takeoff: airborne straight out of maintenance mode.
        // The edge does not exist.
        assert enter_maintenance("ac1").ok == true
        assert_fails transition("ac1", "airborne")
        assert takeoff("ac1").ok == false

        // restoring the selector is NOT enough — verification must rerun
        assert restore_auto("ac1").ok == true
        assert_fails transition("ac1", "airborne")

        // only the verified path reaches the air
        assert confirm_auto("ac1").ok == true
        assert takeoff("ac1").ok == true
        assert press_phase("ac1") == "airborne"

        // the hypoxic cabin cannot be recorded as a setpoint:
        // Helios 522's cabin passed 30000 ft — this slot never will
        assert_fails cabin_alt_ft.set("ac1", 30000)
        assert_fails cabin_alt_ft.set("ac1", -100)
        assert set_cabin_alt("ac1", 14000).ok == false
        assert set_cabin_alt("ac1", 7500).ok == true

        // after landing, the next departure re-verifies from scratch
        assert restore_auto("ac1").ok == true
        assert takeoff("ac1").ok == false
    }
}

What the toolchain says

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

$ soma check cabin_pressurization.cell
✓ All checks passed.
$ soma test cabin_pressurization.cell
test PressurizationTests ...
  ✓ assert enter_maintenance("ac1").ok == true
  ✓ assert_fails transition("ac1", "airborne") — raised invalid transition: manual_maint → airborne. Current state: 'manual_maint'. Valid targets: [preflight]
  ✓ assert takeoff("ac1").ok == false
  ✓ assert restore_auto("ac1").ok == true
  ✓ assert_fails transition("ac1", "airborne") — raised invalid transition: preflight → airborne. Current state: 'preflight'. Valid targets: [manual_maint, auto_verified]
  ✓ assert confirm_auto("ac1").ok == true
  ✓ assert takeoff("ac1").ok == true
  ✓ assert press_phase("ac1") == "airborne"
  ✓ assert_fails cabin_alt_ft.set("ac1", 30000) — raised memory invariant violated on 'cabin_alt_ft': cabin_alt_ft >= 0 && cabin_alt_ft <= 8000 — rejected write of 30000 (key "ac1"); the slot is unchanged
  ✓ assert_fails cabin_alt_ft.set("ac1", -100) — raised memory invariant violated on 'cabin_alt_ft': cabin_alt_ft >= 0 && cabin_alt_ft <= 8000 — rejected write of -100 (key "ac1"); the slot is unchanged
  ✓ assert set_cabin_alt("ac1", 14000).ok == false
  ✓ assert set_cabin_alt("ac1", 7500).ok == true
  ✓ assert restore_auto("ac1").ok == true
  ✓ assert takeoff("ac1").ok == false

14 tests: 14 passed, 0 failed
$ soma verify cabin_pressurization.cell
Verifying cabin_pressurization.cell...

State machine 'pressurization': 4 states, initial 'preflight'
  States: [airborne, auto_verified, manual_maint, preflight]

  ✓ 4 states, 5 transitions
  ✓ all states reachable from 'preflight'
  ✓ reactive machine: no terminal state, and every reachable state can return to 'preflight'
  ✓ no deadlocks
  ✓ liveness: every reachable state can return to 'preflight' (reactive machine)
  ⚠ dynamic transition targets: handler `guarded_step` 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 7 handlers structurally terminate
  ⚠ refinement (partial — dynamic targets fall back to runtime check): handler `guarded_step` 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_step` ⟶ <dynamic>

CabinPressure/invariants:

  ✓ invariant cabin_alt_ft >= 0 && cabin_alt_ft <= 8000 — writer 'takeoff' proven (writes 8000)
  ⚠ invariant cabin_alt_ft >= 0 && cabin_alt_ft <= 8000 — runtime-checked (computed values): set_cabin_alt → cabin_alt_ft because `ft` is a parameter (narrow it: `require ft >= 0 && ft <= 8000 else …`)

8 passed, 3 warnings, 0 failures

  Temporal properties for 'pressurization':
  ✓ 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/cabin_pressurization.cell · examples/corpus/aerospace/cabin_pressurization.cell