mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 05:41:13 +00:00
[autodev] Step 13 partial: c3_5/c4/c5 cycle-1 doc sync
Batch 2 of the cycle-1 component-doc sync. For each of C3.5 (AdHoP), C4 (Pose), C5 (State): - Append "Cycle-1 operational reality" paragraph to § 1 documenting the _STRATEGY_REGISTRY wiring, the AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS slot, and the composition-time errors raised on missing seeds. - Relax the OpenCV pin in § 5 to >=4.11.0.86,<4.12 with a pointer to the D-CROSS-CVE-1 leftover (C5 adds a new row for the AZ-389 orthorectifier subsystem's cv2 import). - Add "Cycle-1 Tier-2 follow-up dependencies" subsection in § 7 where applicable: C3.5 calls out the airborne registry's omission of PassthroughRefiner; C5 calls out the AZ-389 orthorectifier wiring (default OFF) and the AZ-624 operator-supplied flight metadata that must land before flipping orthorectifier.enabled=True. C4 has no parked Tier-2 (only opencv_gtsam is defined). Also refresh the D-CROSS-CVE-1 leftover replay timestamp (condition still upstream-gated: gtsam wheels remain numpy<2) and bump the autodev state's sub_step.detail to record "batch 2/~5 done (c3_5/c4/c5); 7 components + 8 helpers + tests/ remain". Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
|
||||
**Architectural Pattern**: Strategy with two concrete implementations: `AdHoPRefiner` (real refinement) and `PassthroughRefiner` (no-op for the non-conditional baseline / smoke tests). Selection at startup by config (ADR-001); both implementations linked into the deployment binary by default (refinement is conditionally invoked at runtime, not gated at build time).
|
||||
|
||||
**Cycle-1 operational reality**: the airborne binary wires C3.5 through `_STRATEGY_REGISTRY` + `register_airborne_strategies()` (AZ-591). The `c3_5_adhop` airborne slot's `_C3_5_ADHOP_STRATEGIES` tuple in `runtime_root/airborne_bootstrap.py` registers **only `adhop`** — `PassthroughRefiner` is linked into the binary (no `BUILD_REFINER_*` gate; see `C3_5RefinerConfig.KNOWN_STRATEGIES = {"adhop", "passthrough"}`) and is freely selectable in non-airborne composition (unit tests, IT-12 baseline), but selecting `strategy="passthrough"` via the airborne config currently raises `StrategyNotLinkedError` from the `_STRATEGY_REGISTRY` lookup. Constructor injection flows through the `pre_constructed` dict passed to `compose_root(config, pre_constructed=...)` (AZ-618 umbrella → AZ-621 c3 helpers phase + AZ-623 c7 inference phase). The `c3_5_adhop` slot lists `("c282_ransac_filter", "c7_inference")` in `AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS`; `clock` and `c13_fdr` are optional. Missing required keys raise `AirborneBootstrapError` at composition time, naming the consumer and missing key. The `c282_ransac_filter` and `c3_lightglue_runtime` helper instances are identity-shared with C3 / C4 (R14 / AZ-282).
|
||||
|
||||
**Upstream dependencies**:
|
||||
- C3 → `MatchResult`.
|
||||
- C7 InferenceRuntime — AdHoP backbone forward pass when invoked.
|
||||
@@ -61,7 +63,7 @@ No additional caching.
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| OrthoLoC AdHoP (research code drop) | upstream HEAD pinned per Plan-phase | Conditional refinement |
|
||||
| OpenCV | ≥ 4.12.0 | Reprojection residual computation, perspective transforms |
|
||||
| OpenCV (via shared `RansacFilter` / reprojection helpers) | `>=4.11.0.86,<4.12` (cycle-1 relaxed pin; D-CROSS-CVE-1 deferred — see `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`) | Reprojection residual computation, perspective transforms, RANSAC re-filtering of AdHoP-preconditioned correspondences |
|
||||
| TensorRT | matches C7 | AdHoP backbone engine when invoked |
|
||||
|
||||
**Error Handling Strategy**:
|
||||
@@ -86,6 +88,9 @@ No additional caching.
|
||||
**Performance bottlenecks**:
|
||||
- AdHoP invocation is the variable cost in the F3 budget. NFT-PERF-01 measures the invocation rate; an invocation rate above ~30% suggests the threshold needs revisiting.
|
||||
|
||||
**Cycle-1 Tier-2 follow-up dependencies**:
|
||||
- `PassthroughRefiner` — the module + `register()` hook + `C3_5RefinerConfig.KNOWN_STRATEGIES` entry are all in place, but `c3_5_adhop`'s `_C3_5_ADHOP_STRATEGIES` tuple in `runtime_root/airborne_bootstrap.py` registers only `adhop`. Selecting `strategy="passthrough"` via airborne config currently raises `StrategyNotLinkedError`. Tier-2 follow-up: extend the airborne registration tuple if the IT-12 baseline comparison or a smoke-test deployment needs the passthrough path on a flight binary (today it's available via unit-test composition only).
|
||||
|
||||
## 8. Dependency Graph
|
||||
|
||||
**Must be implemented after**: C3 (input), C7 (inference runtime).
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
**Architectural Pattern**: single concrete implementation `OpenCVGtsamPoseEstimator` behind the `PoseEstimator` interface. The pose estimator and the state estimator (C5) **share the GTSAM substrate**; the C4 factor is added directly to C5's iSAM2 graph rather than computed in isolation.
|
||||
|
||||
**Cycle-1 operational reality**: the airborne binary wires C4 through `_STRATEGY_REGISTRY` + `register_airborne_strategies()` (AZ-591) with a single strategy slot (`opencv_gtsam` — `C4PoseConfig.KNOWN_POSE_STRATEGIES = {"opencv_gtsam"}`). Constructor injection flows through the `pre_constructed` dict passed to `compose_root(config, pre_constructed=...)` (AZ-618 umbrella → AZ-623 c5 helpers phase + AZ-625 eager iSAM2 handle phase). The `c4_pose` slot lists `("c282_ransac_filter", "c5_wgs_converter", "c5_se3_utils", "c5_isam2_graph_handle")` in `AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS`; `c13_fdr` and `clock` are optional. The `c5_isam2_graph_handle` slot is the **shared GTSAM substrate seam** — `build_pre_constructed` eagerly invokes `build_state_estimator` once (AZ-625 / Phase E.5) so the (`StateEstimator`, `ISam2GraphHandle`) tuple is constructed BEFORE either the C4 or C5 wrapper runs (C4 runs first in topo order via `_C4_POSE_DEPENDS_ON = ("c1_vio", "c3_matcher")`, then C5 short-circuits on the prebuilt estimator via the internal `_c5_prebuilt_estimator` key). The cross-seam identity invariant (`c4_pose._isam2_handle is c5_state._isam2_handle`) is verified by AC-625.3. Missing required keys raise `AirborneBootstrapError` at composition time, naming the consumer and missing key.
|
||||
|
||||
**Upstream dependencies**:
|
||||
- C3.5 → `MatchResult` (refined or passthrough).
|
||||
- C5 StateEstimator — supplies the GTSAM iSAM2 handle so C4 can add its factor in-graph (architecture principle: shared substrate per ADR-003).
|
||||
@@ -65,7 +67,7 @@ Stateless w.r.t. persistent storage; reads camera calibration once at constructi
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| OpenCV | ≥ 4.12.0 (CVE-2025-53644 mitigation) | `solvePnPRansac` with `SOLVEPNP_IPPE` flag; D-C4-1 = (b) |
|
||||
| OpenCV (`cv2`) | `>=4.11.0.86,<4.12` (cycle-1 relaxed pin; D-CROSS-CVE-1 deferred — see `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`) | `solvePnPRansac` with `SOLVEPNP_IPPE` flag in `opencv_gtsam_estimator.py`; D-C4-1 = (b) |
|
||||
| GTSAM (Python + C++) | per Plan-phase pin | `Marginals.marginalCovariance(pose_key)` for native 6×6 covariance |
|
||||
| Eigen | matches GTSAM | Lie-algebra math |
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
**Architectural Pattern**: Strategy with two concrete implementations: `GtsamIsam2StateEstimator` (production-default) and `EskfStateEstimator` (mandatory simple-baseline). Selection at startup (ADR-001), `BUILD_*` gating (ADR-002), composition-root wired (ADR-009).
|
||||
|
||||
**Cycle-1 operational reality**: the airborne binary wires C5 through `_STRATEGY_REGISTRY` + `register_airborne_strategies()` (AZ-591) on top of the `BUILD_STATE_*` build-flag matrix (`runtime_root/airborne_bootstrap.py::C5_STATE_BUILD_FLAGS = {"gtsam_isam2": "BUILD_STATE_GTSAM_ISAM2", "eskf": "BUILD_STATE_ESKF"}`). Both strategies appear in `_C5_STATE_STRATEGIES`; the `gtsam_isam2` flag defaults ON-when-unset and `eskf` defaults OFF-when-unset (mirrors `state_factory._STATE_BUILD_FLAGS`). Strategy registration is lazy: `_ensure_state_strategy_registered` imports the concrete module (`gtsam_isam2_estimator` or `eskf_baseline`) only when the configured strategy's `BUILD_STATE_*` flag is ON, so a binary configured for `eskf` never imports gtsam. Constructor injection flows through the `pre_constructed` dict passed to `compose_root(config, pre_constructed=...)` (AZ-618 umbrella → AZ-623 c5 helpers phase + AZ-625 eager `(estimator, handle)` pair phase). The `c5_state` slot lists `("c5_imu_preintegrator", "c5_se3_utils", "c5_wgs_converter", "c13_fdr")` in `AIRBORNE_REQUIRED_PRE_CONSTRUCTED_KEYS`; `c6_tile_store`, `camera_calibration`, `flight_id`, and `companion_id` are optional (consumed only when `c5_state.orthorectifier.enabled` is True — see AZ-389 / § 7 below). Missing required keys raise `AirborneBootstrapError` at composition time, naming the consumer and missing key. The `c5_imu_preintegrator` is per-process-cached keyed by `config.runtime.camera_calibration_path` (AC-623.2) so two `build_pre_constructed` invocations return the SAME instance — protecting its bias / sample accumulator from a silent reset on re-invocation. AZ-625 short-circuit: `build_pre_constructed` eagerly invokes `build_state_estimator` and stashes the `StateEstimator` under the private `_c5_prebuilt_estimator` key; `_c5_state_wrapper` returns the prebuilt instance so `c4_pose._isam2_handle` and `c5_state._isam2_handle` reference ONE object across the C4 / C5 seam (AC-625.3). AZ-687 replay-mode guard: when `config.mode == "replay"` and the minimal replay `Config` omits the `c5_state` block, the bootstrap skips the eager `(estimator, handle)` build to avoid forcing the gtsam import on the replay binary (the C5 wrapper itself never runs without the block).
|
||||
|
||||
**Upstream dependencies**:
|
||||
- C1 → `VioOutput` (relative pose + IMU bias).
|
||||
- C4 → `PoseEstimate` (absolute satellite-anchored pose); C4 adds factors directly to C5's iSAM2 graph (shared substrate).
|
||||
@@ -88,6 +90,7 @@ C5 is bounded by design — no unbounded growth.
|
||||
| GTSAM (Python + C++) | per Plan-phase pin | iSAM2 + `CombinedImuFactor` + `BetweenFactorPose3` + `GenericProjectionFactorCal3DS2` + `Marginals` |
|
||||
| `gtsam_unstable.IncrementalFixedLagSmoother` | per Plan-phase pin | Bounded keyframe window (D-C5-3 K=10–20) |
|
||||
| Eigen | matches GTSAM | Lie-algebra math |
|
||||
| OpenCV (`cv2`, AZ-389 orthorectifier subsystem only) | `>=4.11.0.86,<4.12` (cycle-1 relaxed pin; D-CROSS-CVE-1 deferred — see `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`) | Imported by `_orthorectifier.py` for warp / JPEG encode when `c5_state.orthorectifier.enabled = True`; default OFF means the import is loaded but the cv2 code path is unreached in cycle-1 |
|
||||
|
||||
**Error Handling Strategy**:
|
||||
- `StateEstimatorConfigError`: `set_takeoff_origin` called with a malformed `LatLonAlt` (out of WGS-84 bounds / non-finite) OR with non-positive / non-finite sigmas, OR re-called inside the cold-start window with conflicting args. `EstimatorAlreadyStartedError` (a `StateEstimatorConfigError` subclass): `set_takeoff_origin` called after the first `add_*` call sealed the cold-start window. Caller must surface to operator; takeoff blocked.
|
||||
@@ -116,6 +119,10 @@ C5 is bounded by design — no unbounded growth.
|
||||
**Performance bottlenecks**:
|
||||
- `Marginals.marginalCovariance(pose_key)` is the per-frame hot spot. D-CROSS-LATENCY-1 hybrid degrades C4's covariance recovery (not C5's) under thermal throttle.
|
||||
|
||||
**Cycle-1 Tier-2 follow-up dependencies**:
|
||||
- AZ-389 **orthorectifier wiring** — `_orthorectifier.py` + `OrthorectifierConfig` (`enabled`, `cov_norm_threshold`, `inlier_floor`, `tile_size_meters`, `tile_size_pixels`, `zoom_level`, `jpeg_quality`) are wired into `C5StateConfig` and `build_state_estimator`. The default is `enabled: bool = False`, which preserves the existing smoke-test wiring that does not provide a `TileStore` — when False the runtime root skips orthorectifier construction entirely. Production enablement is parked pending AZ-624: the airborne `pre_constructed` dict must populate `camera_calibration`, `flight_id`, `companion_id`, and `c6_tile_store` from the operator-supplied manifest / takeoff orchestrator before flipping `orthorectifier.enabled=True`; until AZ-624 lands those four pre-constructed slots, only the test fixture path (`tests/unit/c5_state/test_az389_*.py`) exercises the orthorectifier subsystem.
|
||||
- AZ-624 **operator-supplied flight metadata** — the `_c5_state_wrapper` and `_build_c5_state_estimator_pair` already accept `flight_id` and `companion_id` kwargs and forward them to `build_state_estimator`. In cycle-1 the airborne `build_pre_constructed` only seeds the `tile_store` slot from `_build_c6_tile_store(config)`; the other three (`camera_calibration`, `flight_id`, `companion_id`) are passed as `None`. Tier-2 follow-up: AZ-624 production `main()` wiring populates these from the manifest + takeoff orchestrator handshake (currently their `None` value means orthorectifier disablement is the only safe runtime state — see prior bullet).
|
||||
|
||||
## 8. Dependency Graph
|
||||
|
||||
**Must be implemented after**: C1 (input), C4 (input + shared graph), C8 inbound (FC IMU prior).
|
||||
|
||||
@@ -8,7 +8,7 @@ status: in_progress
|
||||
sub_step:
|
||||
phase: 6
|
||||
name: component-doc-updates
|
||||
detail: "items 1-2 done; item 3 batch 1/~5 done (c2/c2_5/c3); 10 components + 8 helpers + tests/ remain"
|
||||
detail: "item 3 batch 2/~5 done (c3_5/c4/c5); 7 components + 8 helpers + tests/ remain"
|
||||
retry_count: 0
|
||||
cycle: 1
|
||||
tracker: jira
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# D-CROSS-CVE-1 opencv-python pin deferred — gtsam/numpy ABI block
|
||||
|
||||
**Recorded**: 2026-05-11T02:55+03:00 (Europe/Kyiv)
|
||||
**Last replay attempt**: 2026-05-19T12:43+03:00 (Europe/Kyiv) — PyPI still shows
|
||||
`gtsam==4.2.1` as the latest stable (`requires_dist: numpy<2.0.0,>=1.11.0`).
|
||||
Replay condition (numpy>=2 stable wheels) still NOT met. Leftover remains open.
|
||||
**Last replay attempt**: 2026-05-19T17:00+03:00 (Europe/Kyiv) — replay attempted
|
||||
during `/autodev` invocation; condition unchanged since the 12:43 PyPI check
|
||||
(`gtsam==4.2.1` latest, `requires_dist: numpy<2.0.0,>=1.11.0`). Replay
|
||||
condition (numpy>=2 stable wheels) still NOT met. Leftover remains open.
|
||||
**Status**: deferred-non-user (replay when upstream gtsam wheels target numpy>=2)
|
||||
|
||||
## What is blocked
|
||||
|
||||
Reference in New Issue
Block a user