soma.cell

Parachute sequence — Genesis: the drogue that never fired

On 8 September 2004 the Genesis sample-return capsule hit the Utah desert at 311 km/h. The G-switch that should have sensed deceleration and started the parachute sequence had been installed BACKWARDS — a drawing error that sailed through review. No drogue, no main, just a crater and three years of solar-wind samples shattered. (Its sister design on Stardust, wired correctly, landed perfectly.) The deeper defect: the deploy sequence lived in event timers keyed off one sensor, with nothing structural forcing the order. Here descent is a LINEAR machine — drogue, then main, then touchdown, terminal. Main deployment from entry (a chute shredded at Mach 1.4) does not exist as a transition, touchdown without chutes does not exist as a transition, and the deploy-altitude ledger refuses values outside the corridor.

A Soma program from the aerospace part of the verified corpus: 105 lines, cells ParachuteSequence, SequenceTests. It passes soma check with soma 3.2.4.

How it is built

The cell ParachuteSequence declares 4 signals in its face: fire_drogue(id: String, alt_m: Int) -> Map, fire_main(id: String, alt_m: Int) -> Map, confirm_touchdown(id: String) -> Map and descent_phase(id: String) -> String; keeps 1 memory slot: deploy_alt_m (Map<String, Int>, persistent and consistent) under the invariant deploy_alt_m >= 0 && deploy_alt_m <= 35000. Its state machine descent starts in entry_interface and allows 3 transitions: entry_interface -> drogue_deployed, drogue_deployed -> main_deployed and main_deployed -> touchdown. touchdown is terminal. Handlers: fire_drogue (line 43), fire_main (line 55), confirm_touchdown (line 67) and descent_phase (line 73).

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

Generated from soma describe on this file.

The source

parachute_sequence.cell

// ============================================================================
// PARACHUTE SEQUENCE — Genesis: the drogue that never fired
// ============================================================================
//
// On 8 September 2004 the Genesis sample-return capsule hit the Utah
// desert at 311 km/h. The G-switch that should have sensed deceleration
// and started the parachute sequence had been installed BACKWARDS — a
// drawing error that sailed through review. No drogue, no main, just a
// crater and three years of solar-wind samples shattered. (Its sister
// design on Stardust, wired correctly, landed perfectly.)
//
// The deeper defect: the deploy sequence lived in event timers keyed off
// one sensor, with nothing structural forcing the order. Here descent is
// a LINEAR machine — drogue, then main, then touchdown, terminal. Main
// deployment from entry (a chute shredded at Mach 1.4) does not exist as
// a transition, touchdown without chutes does not exist as a transition,
// and the deploy-altitude ledger refuses values outside the corridor.
// ============================================================================

cell ParachuteSequence {
    face {
        signal fire_drogue(id: String, alt_m: Int) -> Map
        signal fire_main(id: String, alt_m: Int) -> Map
        signal confirm_touchdown(id: String) -> Map
        signal descent_phase(id: String) -> String
    }

    memory {
        // recorded deploy altitude, meters above ground — the corridor
        deploy_alt_m: Map<String, Int> [persistent, consistent]
        invariant deploy_alt_m >= 0 && deploy_alt_m <= 35000
    }

    // ABSENT: entry_interface -> main_deployed  (main at Mach 1.4 shreds)
    // ABSENT: entry_interface -> touchdown      (the Genesis crater)
    state descent {
        initial: entry_interface
        entry_interface -> drogue_deployed
        drogue_deployed -> main_deployed
        main_deployed -> touchdown        // terminal
    }

    on fire_drogue(id: String, alt_m: Int) {
        // drogue corridor: high, supersonic-capable
        if alt_m < 20000 {
            return map("ok", false, "reason", "drogue window missed: {alt_m} m is below 20000")
        }
        let w = try { deploy_alt_m.set("{id}:drogue", alt_m) }
        if w.error != () { return map("ok", false, "reason", "altitude outside corridor") }
        let r = try { transition(id, "drogue_deployed") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "phase", get_status(id), "alt", alt_m)
    }

    on fire_main(id: String, alt_m: Int) {
        // main corridor: low and slow, under a drogue
        if alt_m > 8000 {
            return map("ok", false, "reason", "too fast/high for main: {alt_m} m")
        }
        let w = try { deploy_alt_m.set("{id}:main", alt_m) }
        if w.error != () { return map("ok", false, "reason", "altitude outside corridor") }
        let r = try { transition(id, "main_deployed") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "phase", get_status(id), "alt", alt_m)
    }

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

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

cell test SequenceTests {
    rules {
        // main without drogue: the transition does not exist
        assert_fails transition("cap1", "main_deployed")
        assert fire_main("cap1", 6000).ok == false

        // the Genesis impact — touchdown straight from entry — is
        // equally unrepresentable
        assert_fails transition("cap1", "touchdown")

        // the correct sequence: drogue high, main low, touchdown
        assert fire_drogue("cap1", 33000).ok == true
        assert descent_phase("cap1") == "drogue_deployed"
        assert fire_main("cap1", 6000).ok == true
        assert confirm_touchdown("cap1").ok == true

        // touchdown is terminal — no re-entry into the sequence
        assert_fails transition("cap1", "entry_interface")
        assert_fails transition("cap1", "drogue_deployed")

        // window gates: a drogue call at main altitude is refused
        assert fire_drogue("cap2", 5000).ok == false
        assert descent_phase("cap2") == "entry_interface"

        // the altitude ledger refuses values outside the corridor
        assert_fails deploy_alt_m.set("cap2:drogue", -50)
        assert_fails deploy_alt_m.set("cap2:drogue", 90000)
    }
}

What the toolchain says

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

$ soma check parachute_sequence.cell
✓ All checks passed.
$ soma test parachute_sequence.cell
test SequenceTests ...
  ✓ assert_fails transition("cap1", "main_deployed") — raised invalid transition: entry_interface → main_deployed. Current state: 'entry_interface'. Valid targets: [drogue_deployed]
  ✓ assert fire_main("cap1", 6000).ok == false
  ✓ assert_fails transition("cap1", "touchdown") — raised invalid transition: entry_interface → touchdown. Current state: 'entry_interface'. Valid targets: [drogue_deployed]
  ✓ assert fire_drogue("cap1", 33000).ok == true
  ✓ assert descent_phase("cap1") == "drogue_deployed"
  ✓ assert fire_main("cap1", 6000).ok == true
  ✓ assert confirm_touchdown("cap1").ok == true
  ✓ assert_fails transition("cap1", "entry_interface") — raised invalid transition: touchdown → entry_interface. Current state: 'touchdown'. Valid targets: []
  ✓ assert_fails transition("cap1", "drogue_deployed") — raised invalid transition: touchdown → drogue_deployed. Current state: 'touchdown'. Valid targets: []
  ✓ assert fire_drogue("cap2", 5000).ok == false
  ✓ assert descent_phase("cap2") == "entry_interface"
  ✓ assert_fails deploy_alt_m.set("cap2:drogue", -50) — raised memory invariant violated on 'deploy_alt_m': deploy_alt_m >= 0 && deploy_alt_m <= 35000 — rejected write of -50 (key "cap2:drogue"); the slot is unchanged
  ✓ assert_fails deploy_alt_m.set("cap2:drogue", 90000) — raised memory invariant violated on 'deploy_alt_m': deploy_alt_m >= 0 && deploy_alt_m <= 35000 — rejected write of 90000 (key "cap2:drogue"); the slot is unchanged

13 tests: 13 passed, 0 failed
$ soma verify parachute_sequence.cell
Verifying parachute_sequence.cell...

State machine 'descent': 4 states, initial 'entry_interface'
  States: [drogue_deployed, entry_interface, main_deployed, touchdown]

  ✓ 4 states, 3 transitions
  ✓ all states reachable from 'entry_interface'
  ✓ terminal states: [touchdown]
  ✓ 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 4 handlers structurally terminate
  ✓ refinement: handler `fire_drogue` ⟶ {drogue_deployed}
  ✓ refinement: handler `fire_main` ⟶ {main_deployed}
  ✓ refinement: handler `confirm_touchdown` ⟶ {touchdown}
  · transition sources: `fire_drogue`, `fire_main`, `confirm_touchdown` 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)

ParachuteSequence/invariants:

  ✓ invariant deploy_alt_m >= 0 — writer 'fire_drogue' proven by induction (writes alt_m)
  ✓ invariant deploy_alt_m >= 0 — writer 'fire_drogue' proven by induction (writes alt_m)
  ✓ invariant deploy_alt_m <= 35000 — writer 'fire_main' proven by induction (writes alt_m)
  ✓ invariant deploy_alt_m <= 35000 — writer 'fire_main' proven by induction (writes alt_m)
  ⚠ invariant deploy_alt_m >= 0 && deploy_alt_m <= 35000 — runtime-checked (computed values): fire_drogue → deploy_alt_m [deploy_alt_m <= 35000] because `alt_m` is only known to lie in [20000, ∞) — narrow it: `require alt_m <= 35000 else …`, fire_main → deploy_alt_m [deploy_alt_m >= 0] because `alt_m` is only known to lie in (-∞, 8000] — narrow it: `require alt_m >= 0 else …`

14 passed, 1 warnings, 0 failures

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