Land the C10 per-model engine compile + cache-reuse orchestrator.
`EngineCompiler.compile_engines_for_corpus(request)` walks the
corpus, computes the canonical engine filename via AZ-281
`EngineFilenameSchema.build`, and either reuses the cached binary
(cache hit, AZ-280 `Sha256Sidecar.verify` returns True) or delegates
to the AZ-297 `compile_engine` on the injected runtime (cache miss;
the runtime owns the write path). Returns one `EngineCompileResult`
per backbone carrying the canonical `EngineCacheEntry`, outcome
(BUILT / REUSED), and `compile_duration_s` (None on reuse).
Hardware-tied reuse (D-C10-6 / D-C10-7) falls out of the filename
schema — a host change rebuilds at the new path and leaves the old
files untouched (AC-4).
Design corrections vs. the task spec body:
- The spec proposed a c10-local `EngineCacheEntry` carrying outcome
and duration; that name is already taken by the AZ-297 canonical
DTO. The wrapper is renamed `EngineCompileResult`; the canonical
shape wins.
- The spec called `InferenceRuntime.host_info()`, which is not in
the AZ-297 Protocol. `HostCapabilities` is threaded through
`EngineCompileRequest` instead so the composition root owns host
probing and the compiler stays decoupled.
- The c10 layer cannot import `components.c7_inference` (arch rule
`test_az270_compose_root.test_ac6`). `engine_compiler.py` defines
`CompileEngineCallable` — a structural Protocol cut of
`InferenceRuntime` exposing only `compile_engine` — and catches
broad `Exception` (re-raising preserves the original type;
`error_class` is recorded in the ERROR log payload).
Production
- engine_compiler.py: `CompileOutcome` enum, `BackboneSpec`,
`EngineCompileRequest`, `EngineCompileResult`,
`EngineCompileSummary` DTOs; `CompileEngineCallable` Protocol;
`EngineCompiler` with the single public method.
- config.py: `BackboneConfig` + `C10ProvisioningConfig`
(`workspace_mb` default 4 GiB to match C7 NFT-LIM-01); validate
positive shape dims and duplicate model_name detection in
`__post_init__`.
- runtime_root/c10_factory.py: `build_engine_compiler(config)` wires
the existing `build_inference_runtime` factory through;
`build_backbone_specs(config)` materialises the `BackboneSpec`
tuple from the config block.
- components/c10_provisioning/__init__.py: re-exports the AZ-321
surface and registers the new config block.
Tests
- test_engine_compiler.py: covers AC-1..AC-10 + missing-sidecar
sibling case for AC-5. Tier-1 via fake runtime that writes through
the REAL `Sha256Sidecar.write_atomic_and_sidecar`. Tier-2
placeholders for the cache-hit p99 NFR (200 MB engine sweep) and
kill-during-compile atomic-write NFR.
Docs
- module-layout.md: c10_provisioning Per-Component Mapping lists the
new internal modules (engine_compiler.py, config.py), the
composition-root c10_factory.py, the AZ-321 public re-export
surface, and the registered config block.
- batch_33_cycle1_report.md + reviews/batch_33_review.md:
PASS_WITH_WARNINGS (4 Low findings accepted).
Tests run: c10_provisioning 13 passing + 2 Tier-2 skips; combined
unit suite (excluding pending components) 543 passing, 21
env-skipped.
Co-authored-by: Cursor <cursoragent@cursor.com>
Land the fallback InferenceRuntime strategy that satisfies C7-IT-05:
when the TRT-direct path (AZ-298) cannot deserialise a cached engine
or when the operator explicitly selects ORT, the system stays in the
air at degraded latency rather than dropping the request. Conforms to
the AZ-297 Protocol; current_runtime_label() == "onnx_trt_ep".
Production
- onnx_trt_ep_runtime.py: compile_engine is a no-op returning an
EngineCacheEntry pointing at the source .onnx; deserialize_engine
is gate-first for .engine entries and gate-skip for .onnx, builds
an ORT InferenceSession with the provider list
[TensorrtExecutionProvider, CUDAExecutionProvider,
CPUExecutionProvider], stages cached engines into the ORT TRT EP
cache directory via symlink-or-copy, warms up with one session.run
after construction, and honours config.inference.ort_disallow_cpu_
fallback by raising EngineDeserializeError when the active provider
resolves to CPU; infer emits a one-shot c7.fallback_to_onnx_trt_ep
WARN log plus gcs_alert callback on first call when is_fallback=
True; release_engine is idempotent. _build_provider_args is the
single point that pins TRT EP option-key names (Risk-3) and caps
trt_max_workspace_size at gpu_memory_budget_bytes // 4 (AC-8).
- config.py: adds ort_trt_cache_dir (validated non-empty) and
ort_disallow_cpu_fallback to C7InferenceConfig.
- fdr_client/records.py: adds c7.fallback_to_onnx_trt_ep and
c7.cpu_fallback FDR record kinds.
Tests
- test_onnx_trt_ep_runtime.py: covers AC-1..AC-8 + Risk-2 CPU-fallback
alert + Risk-3 option-key pin + NFR-reliability error rewrap; Tier-1
via fake ORT session; Tier-2 placeholders skip on macOS dev for
numerical FP16 comparison and session-creation perf NFR.
- test_protocol_conformance.py: drops onnx_trt_ep from the missing-
module parametrize now that the module ships.
- test_az272_fdr_record_schema.py: extends per-kind fixture builder
to cover the two new C7 FDR kinds in the roundtrip / schema-version
AC tests.
Docs
- module-layout.md: replaces the pending onnx_trt_runtime row with
the shipped onnx_trt_ep_runtime row + capabilities list.
- batch_32_cycle1_report.md + reviews/batch_32_review.md: full batch
+ self-review (PASS_WITH_WARNINGS, 4 Low findings accepted).
Tests run: c7_inference 139 passing + 17 Tier-2 skips; combined unit
suite (excluding pending components) 529 passing, 19 env-skipped.
Co-authored-by: Cursor <cursoragent@cursor.com>
Implement the production-default InferenceRuntime strategy on JetPack
6.2 + TensorRT 10.3 (per D-C7-9). The runtime owns the full TRT
lifecycle: compile_engine via the Polygraphy + trtexec + IBuilderConfig
hybrid (FP16 / INT8 / Mixed precision), deserialize_engine with
EngineGate-first ordering and a pre-allocation GPU memory budget gate,
infer via H2D -> enqueueV3 -> D2H -> stream sync on the owned CUDA
stream, idempotent release_engine, and an injected
ThermalStatePublisher delegation for thermal_state.
INT8 calibration cache trust (D-C10-6, AC-2/3/4) is enforced by a
.calib_cache.sha256 file-integrity sidecar (AZ-280) plus a new
.calib_cache.dataset_sha256 sidecar that records the dataset content
hash at compile time; reuse only when both agree, rebuild silently on
dataset hash mismatch, raise CalibrationCacheError on corrupt sidecar
(never silently overwritten).
GPU memory budget (NFT-LIM-01, default 4 GiB) is checked BEFORE any
TRT call beyond the gate (AC-6); a pre-allocation refusal raises
OutOfMemoryError and leaves the resident state unchanged.
TensorRT 10.3 / Polygraphy / PyCUDA are lazy-imported inside the
methods that need them so the module loads cleanly on Tier-0 hosts.
A standalone CLI entry (python -m
gps_denied_onboard.components.c7_inference.tensorrt_runtime compile
<onnx> <build_config.json>) is wired for C10 CacheProvisioner
(AZ-321) to invoke pre-flight without holding a runtime instance.
C7InferenceConfig gains gpu_memory_budget_bytes (default 4 GiB) and
trtexec_timeout_s (default 600 s, Risk 4 mitigation), both validated
in __post_init__.
Tests: 26 active + 6 Tier-2-gated skips; AC-1 / AC-3 / AC-4 / AC-5
/ AC-6 / AC-7 / AC-10 + NFR-reliability fully covered on Tier-1
via fake CUDA / TRT modules; AC-2 / AC-8 / AC-9 / NFR-perf-deserialize
placeholders skip with prerequisite reason and live in the AZ-298
Tier-2 microbench harness. Code review verdict
PASS_WITH_WARNINGS (1 Medium hot-path hoist fix auto-applied).
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds the C8 inbound producer side:
- TelemetryRing[T]: bounded drop-oldest ring; first-overflow INFO log
+ monotonic dropped_count.
- SubscriptionBus + SubscriptionHandle: synchronous fan-out, lock-
released-before-callback to avoid deadlock; subscriber crash caught
+ DEBUG-logged so one bad subscriber cannot kill the decode loop.
- PymavlinkInboundDecoder: pymavlink-based AP decoder for RAW_IMU,
SCALED_IMU2, ATTITUDE, GPS_RAW_INT, GPS2_RAW, HEARTBEAT, STATUSTEXT.
Out-of-order drop (Invariant 7) per-kind WARN. STATUSTEXT spoofing
sentinel promotes subsequent GPS to GpsStatus.SPOOFED within 5 s.
AC-5.1 warm-start hint cached on first 3D+ fix; embedded into
every FlightStateSignal.
- Msp2InavInboundDecoder: YAMSPy-based iNav polling decoder for IMU /
attitude / GPS / flight-state. signed=False always (RESTRICT-COMM-2);
GpsStatus.SPOOFED is unreachable on iNav.
Adds yamspy>=0.3.3 + pyserial>=3.5 to pyproject.toml.
Tests: 443 pass / 2 skip / 0 fail (+33 in batch 9).
Contract: no drift on fc_adapter_protocol.md v1.0.0; this batch
implements the inbound producer side without changing signatures.
Co-authored-by: Cursor <cursoragent@cursor.com>
AZ-294: MidFlightTileSnapshotSink writes orthorectified tile JPEGs
atomically to flight_root/<flight_id>/tiles/<tile_id>.jpg, emits a
kind="mid_flight_tile_snapshot" pointer record, and evicts the oldest
tile when the per-flight 64 MiB cap is exceeded. Adds optional
frame_id to the snapshot payload (fdr_record_schema bump).
AZ-295: RecordKindPolicy with two paired gates:
- enforce_or_raise (producer-side) raises RawFrameWriteForbiddenError
for raw_nav_frame / raw_ai_cam_frame at the call site, defending
AC-8.5 / RESTRICT-UAV-4.
- gate_for_writer (writer-side) tumbling-window rate-caps
failed_tile_thumbnail records at <= 0.1 Hz; over-cap drops are
coalesced into kind="overrun" records with the originating
producer slug.
AZ-296: take_off() composition-root sequence with strict ordering
(writer.__init__ -> start -> open_flight -> fc_adapter.__init__ ->
fc_adapter.open). On FdrOpenError, logs ERROR record, calls
writer.stop(), prints the documented FATAL line to stderr, and
sys.exit(EXIT_FDR_OPEN_FAILURE=2). composition_root_protocol bumped
to v1.1.0 with the new constants + takeoff-sequence section.
29 new tests; full suite 356 passed / 2 skipped / 0 failures.
No new dependencies (stdlib only).
Co-authored-by: Cursor <cursoragent@cursor.com>
AZ-291 — FileFdrWriter: single writer thread draining every registered
FdrClient SPSC ring buffer to per-flight segment files; per-segment
size rotation; cross-process fcntl.flock filelock on flight_root;
ENOSPC degraded mode with rate-capped ERROR logs and one GCS alert.
AZ-292 — FlightHeader/FlightFooter dataclasses + open_flight /
close_flight lifecycle methods; four per-flight monotonic counters
(records_written, records_dropped_overrun, bytes_written,
rollover_count) reported by the footer; flight_id mismatch and
close-without-open are typed errors.
AZ-293 — CapacityCapPolicy (post-rotation hook): walks the flight
directory, drops the oldest CLOSED segment when total > cap (default
64 GiB), emits a kind="segment_rollover" record per drop. Never drops
the currently-open segment or segment 0 alone; cap_misconfigured path
logs ERROR + GCS alert. No config flag disables emission (C13-ST-01).
Schema: bumped fdr_record_schema flight_header / flight_footer payload
key sets to match the AZ-292 task spec (effective 1.0.0 -> 1.1.0; no
prior producer); KNOWN_PAYLOAD_KEYS updated. Added FdrWriterConfig
nested in FdrConfig (segment_size_bytes, batch_size, flight_cap_bytes,
debug_log_per_record).
Tests: 29 new unit tests (8 AC + 1 invariant per task); full suite
323 passed, 2 pre-existing skips, 0 regressions.
Co-authored-by: Cursor <cursoragent@cursor.com>
E-CC-HELPERS closes with the three remaining Layer-1 helpers and
E-CC-CONF closes with the env > YAML > defaults precedence test
gate. All four tickets ship with frozen public surfaces, hermetic
unit tests, and no upward (components.*) imports.
* AZ-271 — tests/unit/shared/config/test_precedence.py (5 ACs + smoke
test + helper that names the layer in failure messages).
* AZ-282 — helpers/ransac_filter.py: static RansacFilter +
RansacResult; cv2.setRNGSeed(0) for byte-equal determinism;
median residual semantics pinned by contract.
* AZ-276 — helpers/imu_preintegrator.py + make_imu_preintegrator;
GTSAM PreintegratedCombinedMeasurements; strict-monotonic ts_ns
guard runs before any state mutation. Adjacent hygiene:
_types/nav.py ImuSample/ImuWindow now use ts_ns:int and the
spec-mandated ImuBias dataclass.
* AZ-278 — helpers/lightglue_runtime.py: structural R14 fix.
LightGlueRuntime + non-blocking concurrent-access guard that
raises rather than serialising. EngineHandle Protocol in
_types/manifests.py + KeypointSet/CorrespondenceSet in
_types/matching.py (Protocol surface adds approved by spec).
Dependency conflict (Finding 1, user-approved): gtsam 4.2 (PyPI) is
numpy-1.x-ABI only; opencv-python>=4.12 needs numpy>=2 at runtime.
Resolution: opencv-python pin relaxed to >=4.11.0.86,<4.12. The
D-CROSS-CVE-1 ratchet at ci/opencv_pin_gate.py is held at 4.11.0
with the original 4.12.0 floor restored once a numpy-2-compatible
gtsam wheel ships. Full replay procedure in
_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md.
Tests: 294 passed, 2 skipped (cmake/actionlint env-skips,
pre-existing). 43 new tests added for batch 5. Ruff check + format
clean.
Co-authored-by: Cursor <cursoragent@cursor.com>
AZ-273: lock-free SPSC ring buffer with pre-allocated slots, power-of-
two capacity, opt-in SPSC guard, and EnqueueResult / FdrSpscViolationError
on the public surface. make_fdr_client caches one client per producer_id
and reads capacity from config.fdr.per_producer_capacity with fallback
to queue_size.
AZ-274: default_overrun_policy implements drop-oldest + retry + immediate
marker emission, with prior-marker dropped_count folding via _evict_one
so user-loss info is never lost across iterations. ERROR diagnostic is
rate-limited to <=1/sec per producer.
AZ-275: FakeFdrSink mirrors the FdrClient public surface and reuses the
production default_overrun_policy via a duck-typed _PolicyAdapter. The
test-only records/all_records_ever properties let component tests assert
both in-buffer and lifetime state. tests/conftest.py registers the
fake_fdr_sink fixture and an AST architecture lint forbids production
imports of fakes.
AZ-267: FdrLogBridgeHandler installs on the root logger via wire_log_bridge
and forwards only WARN+ERROR records into the FDR with kind="log".
Thread-local recursion guard short-circuits internal logging; saturated-
queue diagnostics go to stderr every N=1000 drops.
AZ-268: tests/contract/log_schema.py covers every row of the schema's
Test Cases table plus the "DEBUG+INFO never reach FDR" invariant.
pyproject.toml registers the contract pytest marker and the
contract-mandated log_schema.py file-name.
251 unit + contract tests pass (48 new). Review verdict:
PASS_WITH_WARNINGS; findings are NFR-perf deferrals + documented
relaxation of AZ-274 AC-2 coalescing under permanently-stalled consumer.
Co-authored-by: Cursor <cursoragent@cursor.com>
AZ-270: composition root with strategy registry, tier-gated lookup,
topo-order construction, all-or-nothing teardown, StrategyNotLinkedError
payload.
AZ-272: orjson-backed FdrRecord serialise/parse with forward-compat for
unknown payload + top-level fields and canonical overrun-record shape.
AZ-279: pyproj-backed WGS84/ECEF/ENU + OSM slippy-map tile math with
WgsConversionError for shape/range/zoom guards.
AZ-281: strict EngineFilenameSchema build/parse/matches_host with
anchored regex + enum validation; round-trip identity by construction.
AZ-283: dtype-preserving (fp16/fp32) single + batch L2 normaliser with
zero-norm safety and descriptor_metric() source-of-truth.
pyproject.toml pins pyproj>=3.6 and orjson>=3.9 (named-backend deps per
the AZ-272 / AZ-279 contracts). New DTOs LatLonAlt + BoundingBox and
EngineCacheKey + HostCapabilities land in _types/ to back the helper
contracts.
203 unit tests pass (64 new). Review verdict: PASS_WITH_WARNINGS;
findings are perf-NFR deferrals + dep amendment + minor docstring polish.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Refined task decomposition steps to ensure implementation tasks are atomic and complexity does not exceed 5 points.
- Enhanced the product implementation process with a completeness gate to verify task outcomes against architecture promises before proceeding to testing.
- Updated dependencies table to reflect new tasks and their relationships, ensuring all test tasks are linked to product remediation tasks.
- Adjusted workflow documentation to clarify entry points for task decomposition and implementation contexts.
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep generated tiles auditable and untrusted onboard while preserving
covariance, quality, and sidecar metadata for post-flight sync.
Co-authored-by: Cursor <cursoragent@cursor.com>
Implement the first runtime component boundaries around the shared
contracts so downstream batches can consume typed frame, MAVLink, tile,
and FDR behavior with focused tests and batch evidence.
Co-authored-by: Cursor <cursoragent@cursor.com>
Provide deterministic geometry/time-sync helpers and structured config, error, health, and telemetry primitives for downstream runtime components.
Co-authored-by: Cursor <cursoragent@cursor.com>
Implement the shared DTO contract surface with validation so runtime components consume one public model set instead of duplicating shapes.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add the initial source, test, infrastructure, CI, configuration, and evidence-path scaffold so dependent implementation tasks have stable package and runtime boundaries.
Co-authored-by: Cursor <cursoragent@cursor.com>