[AZ-621] Phase C: build_pre_constructed seeds c7_inference

Third subtask of AZ-618. Extends airborne_bootstrap.build_pre_constructed
additively with c7_inference (GPU InferenceRuntime). Wraps the existing
inference_factory.build_inference_runtime so a BUILD_TENSORRT_RUNTIME /
BUILD_PYTORCH_FP16_RUNTIME mismatch surfaces a clear operator-facing
AirborneBootstrapError naming BOTH airborne C7 flags plus the consuming
component slug, rather than bubbling up RuntimeNotAvailableError with no
context.

New public const C7_AIRBORNE_BUILD_FLAGS pairs each airborne runtime
with its gating env flag (onnx_trt_ep deliberately omitted — research
only). Tests stub at the factory boundary; real GPU/TensorRT load
remains Tier-2 only (consolidated at AZ-624). AZ-619 and AZ-620 test
files extended with a _stub_c7_inference_builder autouse fixture
mirroring the AZ-620 pattern for _build_c6_*.

18/18 runtime_root unit tests pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-19 06:47:05 +03:00
parent 1ab93fe0c7
commit 680ba29ae6
8 changed files with 398 additions and 11 deletions
@@ -57,6 +57,7 @@ from gps_denied_onboard.clock.wall_clock import WallClock
from gps_denied_onboard.fdr_client.client import make_fdr_client
from gps_denied_onboard.runtime_root import register_strategy
from gps_denied_onboard.runtime_root.errors import RuntimeNotAvailableError
from gps_denied_onboard.runtime_root.inference_factory import build_inference_runtime
from gps_denied_onboard.runtime_root.matcher_factory import build_matcher_strategy
from gps_denied_onboard.runtime_root.pose_factory import build_pose_estimator
from gps_denied_onboard.runtime_root.refiner_factory import build_refiner_strategy
@@ -75,6 +76,7 @@ if TYPE_CHECKING:
__all__ = [
"AIRBORNE_MAIN_PRODUCER_ID",
"AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS",
"C7_AIRBORNE_BUILD_FLAGS",
"FAISS_BUILD_FLAG",
"AirborneBootstrapError",
"build_pre_constructed",
@@ -92,6 +94,26 @@ flag is OFF but a consuming component still requires the index.
"""
C7_AIRBORNE_BUILD_FLAGS: Final[tuple[tuple[str, str], ...]] = (
("tensorrt", "BUILD_TENSORRT_RUNTIME"),
("pytorch_fp16", "BUILD_PYTORCH_FP16_RUNTIME"),
)
"""Airborne-buildable C7 inference runtimes paired with their gating env flags.
Production-default for the airborne binary is ``tensorrt`` (TensorRT FP16);
``pytorch_fp16`` is the Tier-0 / workstation fallback (per
``module-layout.md`` build-time exclusion table and the AZ-621 task spec).
``onnx_trt_ep`` is deliberately omitted — it is research-only and not built
into the airborne binary, even though
:mod:`gps_denied_onboard.runtime_root.inference_factory` supports the label.
Surfaced here so :func:`_build_c7_inference` can name BOTH airborne flags
in an :class:`AirborneBootstrapError` (AC-621.2) — the operator sees which
flag must be flipped ON to enable the configured runtime AND which fallback
flag would unblock the bootstrap with a different runtime selection.
"""
AIRBORNE_MAIN_PRODUCER_ID: Final[str] = "airborne_main"
"""Producer ID for the per-binary shared FdrClient placed under
``pre_constructed['c13_fdr']``.
@@ -474,22 +496,71 @@ def _build_c6_tile_store(config: Config) -> Any:
return build_tile_store(config)
def _build_c7_inference(config: Config) -> Any:
"""Build ``pre_constructed['c7_inference']`` via the C7 factory.
Wraps :func:`inference_factory.build_inference_runtime` so a
:class:`RuntimeNotAvailableError` (raised when the configured
runtime's ``BUILD_*`` flag is OFF) surfaces as an
:class:`AirborneBootstrapError` naming:
* the missing key (``c7_inference``);
* BOTH airborne-buildable runtimes and their gating flags
(:data:`C7_AIRBORNE_BUILD_FLAGS`), so the operator sees the
production-default (``tensorrt`` /
``BUILD_TENSORRT_RUNTIME``) AND the Tier-0 fallback
(``pytorch_fp16`` / ``BUILD_PYTORCH_FP16_RUNTIME``);
* the consuming component slug(s) — narrowed to configured
consumers when available, else the full theoretical set.
The original factory error is preserved via ``raise ... from`` so
operators still see the upstream cause (e.g., "runtime 'tensorrt'
requires BUILD_TENSORRT_RUNTIME=ON in this binary; the flag is
OFF.").
AC-621.2: this is the path the test exercises when both airborne C7
flags are OFF and a configured consumer (c2_vpr / c3_matcher /
c3_5_adhop) still needs ``c7_inference``.
"""
try:
return build_inference_runtime(config)
except RuntimeNotAvailableError as exc:
consumers = _configured_consumers_of_pre_constructed_key(
config, "c7_inference"
)
flag_options = ", ".join(
f"{flag}=ON for runtime {runtime!r}"
for runtime, flag in C7_AIRBORNE_BUILD_FLAGS
)
raise AirborneBootstrapError(
f"airborne_bootstrap: cannot construct "
f"pre_constructed['c7_inference'] because no airborne C7 "
f"inference runtime is buildable. Consuming components: "
f"{list(consumers)}. Set one of: {flag_options}, and ensure "
f"config.components['c7_inference'].runtime matches the "
f"enabled flag. Upstream error: {exc}"
) from exc
def build_pre_constructed(config: Config) -> dict[str, Any]:
"""Build the airborne ``pre_constructed`` dict for :func:`compose_root`.
AZ-619 (Phase A) seeded ``c13_fdr`` and ``clock``. AZ-620 (Phase B)
adds the two C6 storage entries (``c6_descriptor_index`` +
``c6_tile_store``). Phases C..F (AZ-621..AZ-624) will extend this
function to populate the remaining keys in
added the two C6 storage entries (``c6_descriptor_index`` +
``c6_tile_store``). AZ-621 (Phase C) adds ``c7_inference``
(PyTorch FP16 vs. TensorRT, gated by
:data:`C7_AIRBORNE_BUILD_FLAGS`). Phases D..F (AZ-622..AZ-624) will
extend this function to populate the remaining keys in
:data:`AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS`.
Returns a fresh dict on each call. The ``c13_fdr`` instance is cached
inside :func:`make_fdr_client` (per-producer cache) so two calls within
the same process return dicts where ``pre_constructed['c13_fdr']`` is
the SAME object — AC-619.2. ``clock`` is a fresh :class:`WallClock`
each call (stateless; the cache would be a no-op). The C6 entries are
constructed via the existing :mod:`storage_factory` builders without
additional caching at this layer.
each call (stateless; the cache would be a no-op). The C6 + C7
entries are constructed via the existing :mod:`storage_factory` and
:mod:`inference_factory` builders without additional caching at this
layer.
Replay-mode override: :func:`compose_root` merges ``replay_components``
over ``pre_constructed`` so the :class:`WallClock` here is replaced by
@@ -500,14 +571,19 @@ def build_pre_constructed(config: Config) -> dict[str, Any]:
AirborneBootstrapError: if ``BUILD_FAISS_INDEX`` is OFF and any
configured consumer (per
:data:`AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS`) requires
``c6_descriptor_index`` — surfaces with the consuming
component slug(s) and the gating flag.
``c6_descriptor_index``; OR if no airborne C7 inference
runtime is buildable (both ``BUILD_TENSORRT_RUNTIME`` and
``BUILD_PYTORCH_FP16_RUNTIME`` OFF, or the configured
runtime's matching flag is OFF) and any configured consumer
requires ``c7_inference``. The message names the consuming
component slug(s) and the relevant gating flag(s).
"""
return {
"c13_fdr": make_fdr_client(AIRBORNE_MAIN_PRODUCER_ID, config),
"clock": WallClock(),
"c6_descriptor_index": _build_c6_descriptor_index(config),
"c6_tile_store": _build_c6_tile_store(config),
"c7_inference": _build_c7_inference(config),
}