mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 21:11:13 +00:00
[AZ-776] Open-loop ESKF composition profile via c4_pose.enabled
ADR-012: add c4_pose.enabled (default True) and enforce the (c4_pose.enabled, c5_state.strategy) 2x2 pairing matrix at compose time. When enabled=false, compose_root removes c4_pose from the selection map and build_pre_constructed omits c5_isam2_graph_handle. Replay protocol Invariant 13 owns the gate. Tier-2 conftest YAML writes the open-loop profile; un-xfails AC-1/2/5 and both AC-6 variants in Derkachi (AC-3 stays xfailed for AZ-777). 319/319 runtime_root + c4_pose + c5_state tests green. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1135,6 +1135,33 @@ def _build_c3_feature_extractor(config: Config) -> FeatureExtractor:
|
||||
return OpenCvOrbExtractor()
|
||||
|
||||
|
||||
def _c4_pose_disabled(config: Config) -> bool:
|
||||
"""True iff the airborne open-loop ESKF composition profile is active.
|
||||
|
||||
AZ-776 / ADR-012: when ``config.components["c4_pose"].enabled`` is
|
||||
explicitly ``False`` the composition root strips ``c4_pose`` from
|
||||
the component graph and the C4 wrapper never runs. The eager
|
||||
``(estimator, handle)`` build inside :func:`build_pre_constructed`
|
||||
therefore has no consumer for the iSAM2 graph handle slot
|
||||
(``c5_isam2_graph_handle``); leaving the slot absent makes the
|
||||
"no C4" property visible at the pre-bootstrap layer too.
|
||||
|
||||
Returns ``False`` when the block is absent or when ``enabled`` is
|
||||
missing / true — the full GTSAM profile (ADR-003 steady state)
|
||||
remains the default airborne pipeline. Replay-mode component-block
|
||||
omission is handled separately by
|
||||
:func:`_replay_omits_component_block`.
|
||||
"""
|
||||
components = getattr(config, "components", None) or {}
|
||||
if not isinstance(components, Mapping):
|
||||
return False
|
||||
block = components.get("c4_pose")
|
||||
if block is None:
|
||||
return False
|
||||
enabled = getattr(block, "enabled", True)
|
||||
return not bool(enabled)
|
||||
|
||||
|
||||
def _replay_omits_component_block(config: Config, block_name: str) -> bool:
|
||||
"""True iff replay-mode :class:`Config` has no ``components[block_name]`` entry.
|
||||
|
||||
@@ -1301,7 +1328,14 @@ def build_pre_constructed(config: Config) -> dict[str, Any]:
|
||||
fdr_client=constructed["c13_fdr"],
|
||||
tile_store=constructed.get("c6_tile_store"),
|
||||
)
|
||||
constructed["c5_isam2_graph_handle"] = handle
|
||||
# AZ-776 / ADR-012 open-loop ESKF profile: c4_pose.enabled=False
|
||||
# strips c4_pose from the composition graph, so the
|
||||
# c5_isam2_graph_handle slot has no consumer. ESKF returns
|
||||
# handle=None by design; omitting the slot makes the open-loop
|
||||
# property visible at the pre_constructed layer and refuses the
|
||||
# invariant "handle is None means C4 will crash on read".
|
||||
if not _c4_pose_disabled(config):
|
||||
constructed["c5_isam2_graph_handle"] = handle
|
||||
constructed[_C5_PREBUILT_ESTIMATOR_KEY] = estimator
|
||||
return constructed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user