Ticket 097: Opt-in Return-to-Home Reserve Feasibility Gate¶
Status¶
Implemented.
Goal¶
Allow a mission to declare that return-to-home (RTH) reserve must hold at every
leg, and have the estimator treat a violation as a first-class feasibility
failure — gating status, the CLI exit code, the JSON envelope diagnostics, the
checklist GO/NO-GO verdict, and the one-line summary — rather than the current
advisory-only treatment.
Why This Is High Impact¶
Ticket 063 added the RTH reserve timeline and called it "the single most common
pre-flight question asked by real operators." Today it is computed but kept
purely advisory: a mission whose vehicle cannot fly home with reserve intact
from an intermediate leg still reports FEASIBLE, exits 0, and shows
Status: GO on the checklist (with only an advisory RTH row). For an operator
filing a flight authorisation, "can I always get home with reserve?" is a hard
gate, not a footnote.
Making the gate opt-in via a mission constraint preserves the existing
advisory behaviour for everyone who does not set it (no golden-fixture churn,
no contract break) while letting safety-conscious operators get an honest
NO-GO and a non-zero exit code when RTH reserve cannot be guaranteed.
Current gap¶
MissionEstimate.rth_is_feasibleexists but never influencesstatus,failure, the exit code, orchecklist._is_go.- The advisory checklist row (added alongside this ticket's predecessor work)
and the summary
RTH infeasiblefield surface the condition but cannot flip the verdict, producing the confusingRTH infeasible ... Status: GOpairing for operators who actually require the gate. - There is no
FailureCodefor an RTH reserve breach.
Scope¶
New schema field (MissionConstraints)¶
constraints:
min_landing_reserve_percent: 25.0
require_rth_reserve: true # new; default false (advisory-only, unchanged)
New FailureCode¶
Enforcement logic¶
- When
constraints.require_rth_reserveis true and an RTH reserve timeline is computed (i.e.planned_homeis present), a timeline with anyis_feasible == Falsepoint produces anINFEASIBLEresult withRTH_RESERVE_BELOW_THRESHOLD, attributing the failure to the first failing leg (leg_index,route_item_index,route_item_id) with the margin in the failure context. - When
require_rth_reserveis false (default), behaviour is unchanged: the timeline is advisory and does not affectstatus. - The check is provider-independent (it reuses the already-computed timeline) and deterministic.
Output integration¶
- Add
RTH_RESERVE_BELOW_THRESHOLDto_STATIC_FEASIBILITY_FAILURE_CODEShandling inadapters/envelope.pysoresult_validityis computed correctly, and add an RTH field-path group so the failure maps toresult.energy. adapters/checklist_markdown.py: when the gate is active, the RTH row becomes a real✓ PASS/✗ FAILrow and feeds_is_go; when inactive it remains the advisoryINFOrow. The summary keeps theRTH infeasiblefield.- Add
estimate.energy.rth_is_feasible(orestimate.rth_is_feasible) toSUPPORTED_ASSERTION_FIELD_PATHSand the scenario field resolvers.
Files to create or modify¶
| File | Change |
|---|---|
schemas/mission.py |
Add require_rth_reserve: bool = False to MissionConstraints |
estimator/core/enums.py |
Add RTH_RESERVE_BELOW_THRESHOLD failure code |
estimator/execution/energy.py |
Emit RTH failure when the gate is active and a timeline point is infeasible |
estimator/execution/engine.py |
Thread the RTH failure into the result status/failure |
adapters/envelope.py |
Classify the new failure code; result-validity field paths |
adapters/checklist_markdown.py |
Make the RTH row gating when require_rth_reserve is set |
estimator/execution/scenario_assertions.py |
Add an rth_is_feasible resolver |
schemas/scenario.py |
Add the RTH path to SUPPORTED_ASSERTION_FIELD_PATHS |
tests/test_estimator_energy.py |
RTH gate feasible/infeasible/opt-out tests |
tests/test_checklist_markdown.py |
Gating row + GO/NO-GO tests |
docs/USAGE.md |
Document the opt-in gate and new failure code |
Acceptance criteria¶
- A mission with
constraints.require_rth_reserve: trueand a route where RTH reserve is breached at an intermediate leg returnsINFEASIBLEwithRTH_RESERVE_BELOW_THRESHOLDin the diagnostics, attributed to the first failing leg, and the CLI exits with the infeasible exit code. - The same mission with
require_rth_reserveunset (or false) is unchanged:statusis unaffected and the RTH row stays advisoryINFO. - With the gate active,
--format checklistshows✗ RTH reserve FAILandStatus: NO-GO; with a feasible RTH it shows✓ PASSand does not block GO. RTH_RESERVE_BELOW_THRESHOLDappears inestimator.FailureCodepublic exports, and the RTH feasibility field is assertable from scenarios.- Existing golden fixtures are unchanged (the gate is opt-in and defaults off).