From be5c6d20aa3caab1f6f482c3dbdfaa587202fa1b Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Sat, 16 May 2026 10:24:38 +0300 Subject: [PATCH] [AZ-589] [AZ-590] Close completeness gate cycle 1: VIO remediation tasks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Product Implementation Completeness Gate (cycle 1, 2026-05-16) audited 107 done product tasks. 105 PASS / 0 BLOCKED / 2 FAIL. FAIL findings — both AZ-332 (OKVIS2) and AZ-333 (VINS-Mono) ship a real Python facade + AC-tested fake backend, but their native pybind11 bindings (_native/okvis2_binding.cpp, _native/vins_mono_binding.cpp) are skeletons: _build_estimator() sets estimator_built_ = false; the first add_frame() raises *FatalException("estimator not yet wired"). Production-default VIO and the comparative-study path both crash on the first nav-camera frame. Remediation tasks created in _docs/02_tasks/todo/: - AZ-589 remediate_okvis2_threadedkfvio_wiring (5pt) - AZ-590 remediate_vins_mono_estimator_wiring (5pt) Both tasks also seed the per-binary bootstrap register_strategy() call sites — the existing strategy registry in runtime_root/__init__.py is never invoked in src/ today. Artifacts: - _docs/03_implementation/implementation_completeness_cycle1_report.md - _docs/02_tasks/todo/AZ-589_remediate_okvis2_threadedkfvio_wiring.md - _docs/02_tasks/todo/AZ-590_remediate_vins_mono_estimator_wiring.md - _docs/02_tasks/_dependencies_table.md (+2 rows; totals refreshed) - _docs/_autodev_state.md (Step 7 phase 1 parse; current_batch: 66) Returning to implement-skill Step 1 to parse Batch 66 against these remediation tasks (per Step 15 option A). Co-authored-by: Cursor --- _docs/02_tasks/_dependencies_table.md | 8 +- ...9_remediate_okvis2_threadedkfvio_wiring.md | 106 +++++ ...90_remediate_vins_mono_estimator_wiring.md | 104 +++++ ...plementation_completeness_cycle1_report.md | 377 ++++++++++++++++++ _docs/_autodev_state.md | 10 +- 5 files changed, 597 insertions(+), 8 deletions(-) create mode 100644 _docs/02_tasks/todo/AZ-589_remediate_okvis2_threadedkfvio_wiring.md create mode 100644 _docs/02_tasks/todo/AZ-590_remediate_vins_mono_estimator_wiring.md create mode 100644 _docs/03_implementation/implementation_completeness_cycle1_report.md diff --git a/_docs/02_tasks/_dependencies_table.md b/_docs/02_tasks/_dependencies_table.md index 92ffcfb..44914a5 100644 --- a/_docs/02_tasks/_dependencies_table.md +++ b/_docs/02_tasks/_dependencies_table.md @@ -1,8 +1,8 @@ # Dependencies Table -**Date**: 2026-05-16 (refreshed at end of Batch 64: AZ-558 implementation closed — `MavlinkTransport` seam now routes every C8 outbound MAVLink byte; AZ-401 AC-9 + AZ-404 AC-4b unskipped together; encoder helpers extracted to `_outbound_mavlink_payloads.py`; live-mode `compose_root` injection deferred to whichever future batch registers AP/iNav strategies in an airborne binary; earlier 2026-05-14: refreshed at start of Batch 63: AZ-559 closed Won't Fix — gap was illusory; `TileSource.ONBOARD_INGEST` + `TileMetadata.quality_metadata` + `write_tile`'s `FreshnessRejectionError` already cover the AZ-389 mid-flight ingest semantic without any new API; AZ-389 dep restored to AZ-303; earlier same-day after Batch 61: AZ-558 follow-up added — routes C8 outbound encoder bytes through `MavlinkTransport` seam; closes AZ-401 AC-9 deferred during batch 61 due to encoder-side routing not being in the AZ-401 task envelope; earlier same-day after cumulative review batches 52-54: AZ-528 hygiene PBI added for c1_vio strategy facade orchestration-spine 3-way duplication (Medium); earlier same-day after Batch 53: AZ-333 VINS-Mono landed — first c1_vio strategy after the AZ-332 OKVIS2 production-default; consolidation hygiene for the strategy-facade duplication deferred to a post-AZ-334 PBI; earlier same-day after Batch 51: AZ-527 hygiene PBI added from cumulative review batches 49-51 F1; 2026-05-13: AZ-526 hygiene PBI added from cumulative review batches 46-48 F1+F3; same-day refresh after Batch 44 SRP refactor: AZ-317 superseded; AZ-329 + AZ-330 specs rewritten; AZ-523 + AZ-524 audit-trail tickets added; E-C12 epic renamed `Operator Pre-flight Tooling` → `Operator Pre-flight Orchestrator`; earlier same-day refresh: AZ-507 + AZ-508 hygiene PBIs from cumulative review batches 31-33; 2026-05-11: AZ-489 + AZ-490 ADR-010 operator-origin path) -**Total Tasks**: 150 (109 product + 41 blackbox-test) — AZ-317 retained in the table marked SUPERSEDED for audit; AZ-523 (C11 gate removal) + AZ-524 (C12 rename) added as 2 closed audit-trail tasks; AZ-526 = 2pt clock-helper hygiene; AZ-527 = 2pt c2 engine-dim helper hygiene; AZ-528 = 3pt c1_vio facade-spine hygiene; AZ-558 = 3pt MavlinkTransport routing follow-up; AZ-559 closed Won't Fix -**Total Complexity Points**: 497 (364 product + 133 blackbox-test) — AZ-523 = 3pt, AZ-524 = 2pt, AZ-526 = 2pt, AZ-527 = 2pt, AZ-528 = 3pt, AZ-558 = 3pt +**Date**: 2026-05-16 (refreshed at end of Product Implementation Completeness Gate cycle 1: 2 FAIL items (AZ-332, AZ-333) → AZ-589 + AZ-590 remediation tasks added; spec files `_docs/02_tasks/todo/AZ-58[9-90]_remediate_*.md`; gate report `_docs/03_implementation/implementation_completeness_cycle1_report.md`; earlier same-day after end of Batch 64: AZ-558 implementation closed — `MavlinkTransport` seam now routes every C8 outbound MAVLink byte; AZ-401 AC-9 + AZ-404 AC-4b unskipped together; encoder helpers extracted to `_outbound_mavlink_payloads.py`; live-mode `compose_root` injection deferred to whichever future batch registers AP/iNav strategies in an airborne binary; earlier 2026-05-14: refreshed at start of Batch 63: AZ-559 closed Won't Fix — gap was illusory; `TileSource.ONBOARD_INGEST` + `TileMetadata.quality_metadata` + `write_tile`'s `FreshnessRejectionError` already cover the AZ-389 mid-flight ingest semantic without any new API; AZ-389 dep restored to AZ-303; earlier same-day after Batch 61: AZ-558 follow-up added — routes C8 outbound encoder bytes through `MavlinkTransport` seam; closes AZ-401 AC-9 deferred during batch 61 due to encoder-side routing not being in the AZ-401 task envelope; earlier same-day after cumulative review batches 52-54: AZ-528 hygiene PBI added for c1_vio strategy facade orchestration-spine 3-way duplication (Medium); earlier same-day after Batch 53: AZ-333 VINS-Mono landed — first c1_vio strategy after the AZ-332 OKVIS2 production-default; consolidation hygiene for the strategy-facade duplication deferred to a post-AZ-334 PBI; earlier same-day after Batch 51: AZ-527 hygiene PBI added from cumulative review batches 49-51 F1; 2026-05-13: AZ-526 hygiene PBI added from cumulative review batches 46-48 F1+F3; same-day refresh after Batch 44 SRP refactor: AZ-317 superseded; AZ-329 + AZ-330 specs rewritten; AZ-523 + AZ-524 audit-trail tickets added; E-C12 epic renamed `Operator Pre-flight Tooling` → `Operator Pre-flight Orchestrator`; earlier same-day refresh: AZ-507 + AZ-508 hygiene PBIs from cumulative review batches 31-33; 2026-05-11: AZ-489 + AZ-490 ADR-010 operator-origin path) +**Total Tasks**: 152 (111 product + 41 blackbox-test) — AZ-317 retained in the table marked SUPERSEDED for audit; AZ-523 (C11 gate removal) + AZ-524 (C12 rename) added as 2 closed audit-trail tasks; AZ-526 = 2pt clock-helper hygiene; AZ-527 = 2pt c2 engine-dim helper hygiene; AZ-528 = 3pt c1_vio facade-spine hygiene; AZ-558 = 3pt MavlinkTransport routing follow-up; AZ-559 closed Won't Fix; AZ-589 = 5pt OKVIS2 ThreadedKFVio remediation; AZ-590 = 5pt VINS-Mono estimator remediation +**Total Complexity Points**: 507 (374 product + 133 blackbox-test) — AZ-523 = 3pt, AZ-524 = 2pt, AZ-526 = 2pt, AZ-527 = 2pt, AZ-528 = 3pt, AZ-558 = 3pt, AZ-589 = 5pt, AZ-590 = 5pt Dependencies columns list only the tracker-ID portion (descriptive tail text in each task spec is omitted here for table-readability). The @@ -164,6 +164,8 @@ are all declared and documented below under **Cycle Check**. | AZ-528 | Hygiene — consolidate c1_vio strategy facade orchestration spine | 3 | AZ-334 | AZ-254 | | AZ-523 | Batch 44 — C11 internal flight-state gate removal (SRP refactor; audit-trail; closed) | 3 | AZ-317, AZ-319, AZ-329 | AZ-251 | | AZ-524 | Batch 44 — C12 package rename: c12_operator_tooling → c12_operator_orchestrator (audit; closed)| 2 | AZ-263, AZ-326, AZ-327, AZ-328, AZ-329, AZ-330, AZ-489 | AZ-253 | +| AZ-589 | Remediate AZ-332 — wire `okvis::ThreadedKFVio` inside OKVIS2 pybind11 binding | 5 | AZ-332, AZ-276, AZ-277 | AZ-254 | +| AZ-590 | Remediate AZ-333 — wire VINS-Mono estimator inside pybind11 binding | 5 | AZ-333, AZ-276, AZ-277 | AZ-254 | ## Notes diff --git a/_docs/02_tasks/todo/AZ-589_remediate_okvis2_threadedkfvio_wiring.md b/_docs/02_tasks/todo/AZ-589_remediate_okvis2_threadedkfvio_wiring.md new file mode 100644 index 0000000..8963b08 --- /dev/null +++ b/_docs/02_tasks/todo/AZ-589_remediate_okvis2_threadedkfvio_wiring.md @@ -0,0 +1,106 @@ +# Remediate AZ-332 — wire `okvis::ThreadedKFVio` inside the OKVIS2 pybind11 binding + +**Task**: AZ-589_remediate_okvis2_threadedkfvio_wiring +**Name**: AZ-332 ThreadedKFVio wiring (production-default VIO) +**Description**: Replace the AZ-332 skeleton `_native/okvis2_binding.cpp` `_build_estimator()` / `_drive_estimator()` paths with the real `okvis::ThreadedKFVio` estimator wiring. Without this, the airborne deployment binary cannot process a single nav-camera frame (`Okvis2Backend.add_frame` throws `OkvisFatalException("OKVIS2 estimator not yet wired — this binding is the AZ-332 skeleton")` on the first call). +**Complexity**: 5 points +**Dependencies**: AZ-332, AZ-276 (ImuPreintegrator), AZ-277 (SE3Utils) +**Component**: c1_vio (epic AZ-254 / E-C1) +**Tracker**: AZ-589 +**Epic**: AZ-254 (E-C1) + +## Problem + +The Product Implementation Completeness Gate (cycle 1, 2026-05-16) classified AZ-332 as **FAIL**: + +- `src/gps_denied_onboard/components/c1_vio/_native/okvis2_binding.cpp` lines 251–272: `_build_estimator()` always sets `estimator_built_ = false`; `_drive_estimator()` throws `OkvisFatalException("Okvis2Backend: OKVIS2 estimator not yet wired ...")`. +- The OKVIS2 upstream headers are still commented out (line 48 `// #include `). +- AZ-332's `Runtime Completeness` section forbids "a pre-built deterministic-fallback `VioOutput` while OKVIS2 is 'compiled out'"; the current binding violates that contract. + +AZ-332's own `Implementation Notes (2026-05-12, batch 23)` flagged this for the gate and named the follow-up `AZ-332_tier2_validation`. This task discharges that contract. + +Production-default VIO must operate before F3 (Steady-state per-frame estimation) can run end-to-end on the airborne binary. + +## Outcome + +- `_native/okvis2_binding.cpp::_build_estimator()` instantiates `okvis::ThreadedKFVio` from `yaml_config_`. The real OKVIS2 upstream headers (`okvis/ThreadedKFVio.hpp`, `okvis/Estimator.hpp`, `okvis/VioParametersReader.hpp`) are uncommented and linked. +- Output callback attached to `ThreadedKFVio` fills `latest_output_` (under `output_mtx_`) with the real `EstimatorOutput`: SE(3) pose, marginalised 6×6 covariance, accel/gyro biases, feature counts, mean parallax, per-frame MRE. +- `_drive_estimator(image)` forwards the frame to the real estimator, returns `true` on a new keyframe output and `false` otherwise. NO `throw` after first frame on the happy path. +- `add_imu(ts_ns, accel, gyro)` pushes IMU into `ThreadedKFVio` via the real upstream API (no longer just caching `last_accel_` / `last_gyro_`). +- `reset(...)` reinitialises the estimator from the seed pose / velocity / biases via the upstream reset surface; bias propagation goes through the AZ-276 substrate where the Python facade owns it. +- CMake glue at `cpp/okvis2/CMakeLists.txt` is upgraded so `BUILD_OKVIS2=ON` actually links the upstream library (Ceres, Brisk, OpenGV, OKVIS2 itself); the Linux Tier-1 CI workflow comment `-DBUILD_OKVIS2=OFF` can be flipped to `ON` once the build succeeds in the GitHub Actions runner image. +- The existing AC-1..AC-8 + AC-10 unit-test suite (`tests/unit/c1_vio/test_okvis2_strategy.py` + `conftest.py`'s `FakeOkvis2Backend`) continues to pass — the Python facade contract is unchanged. +- A new Tier-1-runnable integration test exercises the real binding against a small fixture (`tests/integration/c1_vio/test_okvis2_real_binding.py`, marked `@pytest.mark.tier1_real_okvis2 + @pytest.mark.skipif(not _okvis2_binding_present())` so Tier-1 CI without OKVIS2 still passes). +- The `runtime_root` per-binary bootstrap module registers the `okvis2` strategy via `register_strategy("c1_vio", "okvis2", ...)` so the deployment binary can actually resolve it (currently the registry is empty — see § Notes below). + +## Scope + +### Included + +- `_native/okvis2_binding.cpp` wiring of `okvis::ThreadedKFVio` (`_build_estimator`, `_drive_estimator`, `add_imu`, `reset`, output callback). +- `cpp/okvis2/CMakeLists.txt` upstream link + transitive Ceres/Brisk/OpenGV dependency declaration. +- One Tier-1-runnable integration test against a tiny fixture. +- A short `_docs/04_refactoring/runtime_bootstrap_register_okvis2/` note describing the per-binary bootstrap registration call site (the registry seam already exists in `runtime_root/__init__.py`; this task adds the actual `register_strategy(...)` call inside the deployment binary's bootstrap). + +### Excluded + +- AC-9 honest-covariance Tier-2 validation against Derkachi-class fixtures on real Jetson hardware — separate Tier-2 perf task (`tier2_AZ-332_honest_covariance_validation`). +- Comparative-study (IT-12) test suite changes — owned by `AZ-444_tier2_jetson_harness` and downstream test tasks. +- OKVIS2 upstream-source modifications — pinned per Plan-phase; deviations require a separate ADR. +- VINS-Mono wiring — separate remediation task (`remediate_vins_mono_estimator_wiring`). + +## Acceptance Criteria + +**AC-1: `_drive_estimator` returns without raising on a valid nav-camera frame** +Given a real `Okvis2Backend` constructed with the test fixture's YAML + intrinsics +When `add_frame("uuid-abc", ts_ns=…, image=…)` is called on a well-formed image +Then the call returns a `bool` (true on keyframe output, false otherwise); no `OkvisFatalException` is raised on the "estimator not yet wired" path + +**AC-2: Output callback populates `latest_output_` after the first keyframe** +Given a sequence of N frames feeding a normal-segment fixture +When `get_latest_output()` is called after a keyframe is emitted +Then the returned dict contains `pose_T_world_body` (4×4 finite float64), `pose_covariance_6x6` (6×6 SPD float64), `accel_bias` + `gyro_bias` (length-3 finite float64), and integer feature counts — all values reflect the real estimator state, not seed zeros + +**AC-3: Python facade unit tests stay green** +Given the existing `Okvis2Strategy` AC-1..AC-8 + AC-10 unit tests (which use `FakeOkvis2Backend`) +When `pytest tests/unit/c1_vio/test_okvis2_strategy.py` runs +Then 100% pass (the facade contract is preserved) + +**AC-4: `BUILD_OKVIS2=OFF` still produces an importable package** +Given a build with `BUILD_OKVIS2=OFF` +When `import gps_denied_onboard.components.c1_vio` runs +Then the package imports without ever touching `_native.okvis2_binding`; `gps_denied_onboard.components.c1_vio.okvis2` is not auto-imported; the AZ-331 factory raises `StrategyNotAvailableError("okvis2", missing_flag="BUILD_OKVIS2")` if `okvis2` is requested + +**AC-5: Composition-root strategy registration is live** +Given the deployment binary's per-binary bootstrap module +When `compose_root(config)` runs with `config.components["c1_vio"].strategy == "okvis2"` +Then `register_strategy("c1_vio", "okvis2", build_okvis2_strategy, tier="airborne", depends_on=(…))` has been called at module import time; `_resolve_strategy` returns the registration without raising `StrategyNotLinkedError` + +## Non-Functional Requirements + +**Performance** +- `_drive_estimator` first-call construction cost ≤ 5 s (one-time, swallowed by AC-NEW-1 boot budget). +- Steady-state `_drive_estimator` per-frame cost ≤ 80 ms p95 on Tier-2 (AC-9 / NFR-perf validation is the separate Tier-2 task; this task only verifies the wiring is not introducing an obviously broken path). + +**Reliability** +- No raw OKVIS2 / Ceres / Eigen exceptions cross the pybind11 boundary; everything is caught and rewrapped into `OkvisInitException` / `OkvisOptimizationException` / `OkvisFatalException`. + +## Constraints + +- Per `ADR-002`, the `BUILD_OKVIS2=OFF` deployment binary must still build and pass all non-OKVIS2 tests after this change. +- OKVIS2 upstream is pinned per Plan-phase; the build must use the pinned commit, not HEAD. +- AZ-276 `ImuPreintegrator` remains a *separate* substrate for E-C5's fusion graph; OKVIS2's internal IMU integration is owned by `ThreadedKFVio`. The single-IMU-truth invariant operates at the IMU sample-stream level, NOT at the integrator-instance level (resolved in AZ-332 § Implementation Notes). + +## Risks & Mitigation + +**Risk 1: OKVIS2 upstream build fails on the GitHub Actions Linux runner image** +- *Risk*: Ceres / Brisk / OpenGV require specific system packages (Eigen ≥ 3.4, gflags, glog, suitesparse, …). The default `ubuntu-latest` image may be missing dependencies. +- *Mitigation*: lift the `apt install` block from `cpp/okvis2/README` (or upstream's `INSTALL.md`) into `.github/workflows/ci.yml`'s "Setup C++ deps" step before invoking CMake. Document the dependency list in the task report. + +**Risk 2: ABI conflict between OKVIS2's Ceres pin and the project's GTSAM pin** +- *Risk*: GTSAM uses its own internal Ceres-less optimisation; OKVIS2 needs Ceres. If both libraries pull in conflicting Eigen versions, the airborne binary will segfault at link time. +- *Mitigation*: vendor OKVIS2's third-party dependencies under `cpp/_third_party/okvis2/` with strict version pinning; verify `objdump -T` or equivalent that the Eigen symbol set matches between GTSAM-compiled and OKVIS2-compiled objects. + +## Notes + +This remediation also incidentally exposes a cross-cutting gap noted in the cycle-1 completeness report: `runtime_root/__init__.py` defines a strategy registry but no module currently calls `register_strategy(...)` — meaning even with this wiring complete, `compose_root` would still raise `StrategyNotLinkedError` on the deployment binary until a per-binary bootstrap module is added. AC-5 above ensures this task lands at least the `c1_vio` slot's registration; the broader cross-component registration sweep is tracked as a separate cross-cutting task (proposed `cross_cutting_per_binary_bootstrap`). diff --git a/_docs/02_tasks/todo/AZ-590_remediate_vins_mono_estimator_wiring.md b/_docs/02_tasks/todo/AZ-590_remediate_vins_mono_estimator_wiring.md new file mode 100644 index 0000000..ed9d09b --- /dev/null +++ b/_docs/02_tasks/todo/AZ-590_remediate_vins_mono_estimator_wiring.md @@ -0,0 +1,104 @@ +# Remediate AZ-333 — wire VINS-Mono estimator inside the pybind11 binding + +**Task**: AZ-590_remediate_vins_mono_estimator_wiring +**Name**: AZ-333 VINS-Mono estimator wiring (research / comparative VIO) +**Description**: Replace the AZ-333 skeleton `_native/vins_mono_binding.cpp` `_build_estimator()` / `_drive_estimator()` paths with the real VINS-Mono estimator wiring. Without this, the `VinsMonoStrategy` cannot produce a single pose update at runtime — the binding throws `VinsMonoFatalException("VINS-Mono estimator not yet wired ... AZ-333 skeleton")` on the first frame. +**Complexity**: 5 points +**Dependencies**: AZ-333, AZ-276 (ImuPreintegrator), AZ-277 (SE3Utils) +**Component**: c1_vio (epic AZ-254 / E-C1) +**Tracker**: AZ-590 +**Epic**: AZ-254 (E-C1) + +## Problem + +The Product Implementation Completeness Gate (cycle 1, 2026-05-16) classified AZ-333 as **FAIL**: + +- `src/gps_denied_onboard/components/c1_vio/_native/vins_mono_binding.cpp` exhibits the identical skeleton pattern as `okvis2_binding.cpp`: `_build_estimator()` sets `estimator_built_ = false`; `_drive_estimator()` throws `VinsMonoFatalException("VinsMonoBackend: VINS-Mono estimator not yet wired — this binding is the AZ-333 skeleton")`. +- VINS-Mono upstream headers (`estimator/estimator.h`, `feature_tracker.h`) are commented out. +- AZ-333's `Runtime Completeness` section explicitly requires "a real pybind11 binding around upstream VINS-Mono" and "real per-frame estimator update" — both currently unmet. + +VINS-Mono is the **research / comparative VIO strategy** (`tier=research`), used by IT-12 comparative-study runs and the Tier-2 Jetson harness. Until wired, all OKVIS2-vs-VINS-Mono comparison runs would crash on the VINS-Mono branch. + +## Outcome + +- `_native/vins_mono_binding.cpp::_build_estimator()` instantiates the upstream `Estimator` and `FeatureTracker`, wired with the AZ-333 YAML config and intrinsics. +- `_drive_estimator(image)` calls `feature_tracker_.readImage(image, ts)` followed by `estimator_.processMeasurements(...)`, returning `true` on a new keyframe output and `false` otherwise. +- `add_imu(ts_ns, accel, gyro)` pushes IMU into the estimator's IMU queue (no longer just caching). +- Output extraction reads the estimator's most recent `Vector` pose + bias state and the marginalisation block's covariance. +- `reset(...)` reinitialises the estimator via VINS-Mono's `clearState() + setParameter()` surface from a seed pose / velocity / biases. +- CMake glue at `cpp/vins_mono/CMakeLists.txt` is upgraded so `BUILD_VINS_MONO=ON` actually links upstream VINS-Mono (Ceres, OpenCV ≥ 4.2, Eigen ≥ 3.4); the Tier-2 perf workflow can flip `-DBUILD_VINS_MONO=OFF` to `ON`. +- The existing AC-1..AC-9 unit-test suite (`tests/unit/c1_vio/test_vins_mono_strategy.py` + `conftest.py`'s `FakeVinsMonoBackend`) continues to pass — the Python facade contract is unchanged. +- A new Tier-1-runnable integration test exercises the real binding against a small fixture, gated behind `@pytest.mark.tier1_real_vins_mono + @pytest.mark.skipif(not _vins_mono_binding_present())`. +- The per-binary bootstrap module's strategy registry now includes a `register_strategy("c1_vio", "vins_mono", ...)` call for the research / comparative-study binary. + +## Scope + +### Included + +- `_native/vins_mono_binding.cpp` wiring of the real `Estimator` + `FeatureTracker` (`_build_estimator`, `_drive_estimator`, `add_imu`, `reset`, pose / covariance extraction). +- `cpp/vins_mono/CMakeLists.txt` upstream link + transitive Ceres / OpenCV / Eigen dependency declaration. +- One Tier-1-runnable integration test against a tiny fixture. +- `runtime_root` registration call site for the `vins_mono` strategy (added inside the research / comparative-study binary's bootstrap, NOT the airborne binary). + +### Excluded + +- AZ-444 Tier-2 Jetson comparative-study harness changes — that task owns the IT-12 run orchestration. +- VINS-Mono upstream-source modifications — pinned per Plan-phase; deviations require a separate ADR. +- OKVIS2 wiring — sibling remediation task (`remediate_okvis2_threadedkfvio_wiring`). +- Replacing VINS-Mono with VINS-Fusion or VINS-RGBD — pinned upstream variant is monocular VINS-Mono. + +## Acceptance Criteria + +**AC-1: `_drive_estimator` returns without raising on a valid nav-camera frame** +Given a real `VinsMonoBackend` constructed with the test fixture's YAML + intrinsics +When `add_frame("uuid-abc", ts_ns=…, image=…)` is called on a well-formed image +Then the call returns a `bool` (true on keyframe output, false otherwise); no `VinsMonoFatalException` is raised on the "estimator not yet wired" path + +**AC-2: Output callback populates `latest_output_` after the first keyframe** +Given a sequence of N frames feeding a normal-segment fixture +When `get_latest_output()` is called after a keyframe is emitted +Then the returned dict contains `pose_T_world_body` (4×4 finite float64), `pose_covariance_6x6` (6×6 SPD float64), `accel_bias` + `gyro_bias` (length-3 finite float64), and integer feature counts — all values reflect the real estimator state, not seed zeros + +**AC-3: Python facade unit tests stay green** +Given the existing `VinsMonoStrategy` AC-1..AC-9 unit tests (which use `FakeVinsMonoBackend`) +When `pytest tests/unit/c1_vio/test_vins_mono_strategy.py` runs +Then 100% pass (the facade contract is preserved) + +**AC-4: `BUILD_VINS_MONO=OFF` still produces an importable package** +Given a build with `BUILD_VINS_MONO=OFF` +When `import gps_denied_onboard.components.c1_vio` runs +Then the package imports without ever touching `_native.vins_mono_binding`; `gps_denied_onboard.components.c1_vio.vins_mono` is not auto-imported; the AZ-331 factory raises `StrategyNotAvailableError("vins_mono", missing_flag="BUILD_VINS_MONO")` if `vins_mono` is requested + +**AC-5: Research binary's strategy registration is live** +Given the comparative-study / research binary's per-binary bootstrap module +When `compose_root(config)` runs with `config.components["c1_vio"].strategy == "vins_mono"` +Then `register_strategy("c1_vio", "vins_mono", build_vins_mono_strategy, tier="research", depends_on=(…))` has been called at module import time; `_resolve_strategy` returns the registration without raising `StrategyNotLinkedError` + +## Non-Functional Requirements + +**Performance** +- `_drive_estimator` first-call construction cost ≤ 5 s (one-time, swallowed by the boot budget). +- Steady-state `_drive_estimator` per-frame cost ≤ 100 ms p95 on Tier-2 (NFR-perf validation lives in the Tier-2 Jetson harness; this task only verifies the wiring is not obviously broken). + +**Reliability** +- No raw VINS-Mono / Ceres / Eigen exceptions cross the pybind11 boundary; everything is caught and rewrapped into `VinsMonoInitException` / `VinsMonoOptimizationException` / `VinsMonoFatalException`. + +## Constraints + +- Per `ADR-002`, the `BUILD_VINS_MONO=OFF` deployment binary must still build and pass all non-VINS-Mono tests after this change. +- VINS-Mono upstream is pinned per Plan-phase; build against the pinned commit, not HEAD. +- The research binary's bootstrap must not auto-load on the airborne `BUILD_OKVIS2=ON, BUILD_VINS_MONO=OFF` deployment binary — that would defeat the build-flag isolation invariant. + +## Risks & Mitigation + +**Risk 1: VINS-Mono's ROS-isms in its upstream source** +- *Risk*: Upstream VINS-Mono carries ROS/Catkin assumptions (rosbag input, ROS-flavoured visualisation). These need to be either stripped or stubbed; otherwise the link step pulls in ROS, which the project intentionally does not depend on. +- *Mitigation*: vendor a minimal-ROS-stub layer under `cpp/_third_party/vins_mono_ros_stub/` (already a documented pattern in the AZ-444 Plan notes); pre-process the upstream sources to compile against this stub. + +**Risk 2: Eigen ABI conflict with GTSAM / OKVIS2** +- *Risk*: VINS-Mono, OKVIS2, and GTSAM all transitively depend on Eigen; if their Eigen pins disagree, ABI breakage at link time. +- *Mitigation*: enforce a single Eigen pin across `cpp/_third_party/` via the top-level `CMakeLists.txt`; verify the shared Eigen symbol set matches. + +## Notes + +Identical structural defect to AZ-332. Mitigations and gotchas overlap heavily, so the two remediation tasks should ideally be scheduled in the same batch (the CMake / dependency-management work shares a lot of surface area). The composition-root registry gap (`runtime_root/__init__.py::register_strategy(...)` is never called in `src/`) is also touched by both tasks; coordinate the per-binary bootstrap module so both remediations land their `register_strategy` call in the right binary (airborne for OKVIS2, research/comparative for VINS-Mono). diff --git a/_docs/03_implementation/implementation_completeness_cycle1_report.md b/_docs/03_implementation/implementation_completeness_cycle1_report.md new file mode 100644 index 0000000..dd7c45e --- /dev/null +++ b/_docs/03_implementation/implementation_completeness_cycle1_report.md @@ -0,0 +1,377 @@ +# Product Implementation Completeness Gate — Cycle 1 + +**Date**: 2026-05-16 +**Cycle**: 1 +**Tasks audited**: 107 done product tasks under `_docs/02_tasks/done/` (the +six hygiene-only specs and AZ-525-class follow-ups are included as PASS +because they don't promise new runtime behavior). +**Audit scope**: every task spec's `Description` / `Outcome` / +`Scope.Included` / `Acceptance Criteria` / `Non-Functional Requirements` / +`Constraints` / `Runtime Completeness` block against actual source under +`src/gps_denied_onboard/`. + +## Verdict + +**FAIL — Step 7 must not advance.** + +Two product tasks (AZ-332 OKVIS2, AZ-333 VINS-Mono) shipped a *Python +facade + pybind11 binding skeleton* but DID NOT wire the actual upstream +estimator (`okvis::ThreadedKFVio` / `vins_estimator::Estimator`). The +binding compiles and loads, then throws a fatal exception on the first +`add_frame` call. The production-default C1 VioStrategy therefore cannot +process a single nav-camera frame on a real binary. + +Both task specs explicitly anticipated this split — AZ-332 § +`Implementation Notes (2026-05-12, batch 23)` names the follow-up +`AZ-332_tier2_validation` and states that this gate (Step 15) is the +designated creator. AZ-333 carries the same skeleton pattern but no +self-deferral note. This report executes that contract. + +Per `implement/SKILL.md` § 15 ("If any product task is `FAIL`, STOP. Do +not write the final product implementation report and do not proceed to +any downstream autodev step."), Step 7 stays `in_progress`; remediation +tasks are proposed below; the original task files remain in `done/` and +do NOT regress to `todo/`. + +## FAIL findings + +### AZ-332 — C1 OKVIS2 Strategy (production-default VIO) + +**Promised capability**: "production-default `VioStrategy` ... Python +facade over the OKVIS2 C++ tightly-coupled keyframe-based VIO core" +(`AZ-332_c1_okvis2_strategy.md` § Description). `Runtime Completeness` +explicitly lists "real per-frame OKVIS2 estimator update; real covariance +read from OKVIS2's internal Hessian" as required, and explicitly forbids +"a pre-built deterministic-fallback `VioOutput` while OKVIS2 is 'compiled +out'". + +**Evidence**: + +- `src/gps_denied_onboard/components/c1_vio/okvis2.py` — 339-line Python + facade. Conforms to the AZ-331 `VioStrategy` Protocol. PASS. +- `src/gps_denied_onboard/components/c1_vio/_native/okvis2_binding.cpp` + — pybind11 module compiles + loads but `_build_estimator()` always + sets `estimator_built_ = false`. `_drive_estimator()` (called on the + first `add_frame`) throws `OkvisFatalException("OKVIS2 estimator not + yet wired — this binding is the AZ-332 skeleton")`. FAIL. +- OKVIS2 upstream is never `#include`'d (the `#include + ` line is commented out, line 48 of the + binding). + +**Self-documentation**: AZ-332 task spec, Implementation Notes (2026-05-12, +batch 23) — "This batch — production-quality Python facade ... pybind11 +binding source that compiles + loads but throws ... ; Tier-2 follow-up — +actual `okvis::ThreadedKFVio` wiring ... The follow-up task is named +`AZ-332_tier2_validation` and will be created by the Product +Implementation Completeness Gate at end-of-cycle (Step 15) per +`implement/SKILL.md`." + +**Blast radius**: the deployment binary (`config.vio.strategy = "okvis2"`, +`BUILD_OKVIS2=ON`) cannot run F3 (Steady-state per-frame estimation) — +the first nav-camera frame raises `VioFatalError`. C5 fusion, C8 +outbound, GCS telemetry, mid-flight tile gen all sit on top of this. + +### AZ-333 — C1 VINS-Mono Strategy (research-only VIO) + +**Promised capability**: `Runtime Completeness` requires "real `VinsMonoStrategy` +class implementing the AZ-331 Protocol; real pybind11 binding to +`cpp/vins_mono/` (real VINS-Mono upstream, de-ROSified); real per-frame +estimator update". + +**Evidence**: + +- `src/gps_denied_onboard/components/c1_vio/vins_mono.py` — 448-line + Python facade. Conforms to the AZ-331 Protocol. PASS. +- `src/gps_denied_onboard/components/c1_vio/_native/vins_mono_binding.cpp` + — same skeleton pattern as OKVIS2. `_drive_estimator()` throws + `VinsMonoFatalException("VINS-Mono estimator not yet wired — this + binding is the AZ-333 skeleton")`. FAIL. + +**Self-documentation**: no explicit Implementation Notes block (unlike +AZ-332), but the binding's source comment names "AZ-333's tier2 +deliverable bundle". + +**Blast radius**: limited — VINS-Mono is research-only +(`BUILD_VINS_MONO=ON`) and not linked into the deployment binary +(ADR-002). The IT-12 comparative-study research binary cannot run today; +the deployment binary is unaffected by AZ-333 specifically. + +## PASS — by component + +107 audited tasks, 105 PASS, 0 BLOCKED, 2 FAIL. + +Tasks classified as PASS have at least one of: + +- A substantial Python/C++ source artifact under the task's owned + component (`module-layout.md` ownership envelope). +- A self-contained pure-Python implementation backed by the named + third-party dependency (OpenCV, GTSAM, FAISS, TensorRT, ONNX-Runtime, + PyTorch, pymavlink, psycopg, atomicwrites, httpx). +- For "Implementation Notes" tasks (AZ-300 / AZ-301 / AZ-302), the named + capability is implemented and the deferral covers either a warm-up + optimization, a Tier-2 NVML test skip, or a Tier-2 hot-path perf + microbench — none of which materially block runtime behavior. + +### Foundation + cross-cutting (10 tasks) — all PASS + +| Task | Title | Evidence | +|------|-------|----------| +| AZ-263 | initial structure | `src/` skeleton present; package importable. | +| AZ-266 | log module | `gps_denied_onboard.logging` package. | +| AZ-267 | fdr log bridge | producer-id-tagged log → FDR records. | +| AZ-268 | log schema contract test | shipped in tests. | +| AZ-269 | config loader | `gps_denied_onboard.config` (env + YAML). | +| AZ-270 | compose root | `runtime_root/__init__.py` (`compose_root`, `compose_operator`). | +| AZ-271 | config precedence tests | shipped. | +| AZ-507 | hygiene module-layout AZ-270 alignment | lint test `tests/unit/test_az270_compose_root.py`. | +| AZ-508 / AZ-526 | iso-timestamp consolidation | `helpers/iso_timestamps.py`. | +| AZ-527 | engine-dim assertion consolidation | `components/c2_vpr/_engine_dim_assertion.py` + sibling under c3. | +| AZ-528 | c1 vio facade spine consolidation | `_facade_spine.py`. | + +### FDR / FdrClient (4 tasks) — all PASS + +| AZ-272 | fdr record schema | `fdr_client/records.py`. | +| AZ-273 | fdr client ringbuf | `fdr_client/client.py`. | +| AZ-274 | fdr overrun emission | producer-side overrun records. | +| AZ-275 | fake fdr sink | test fixture, used by every component's unit tests. | + +### Shared helpers (8 tasks) — all PASS + +| AZ-276 | imu_preintegrator | `helpers/imu_preintegrator.py` (real GTSAM `CombinedImuFactor` substrate). | +| AZ-277 | se3_utils | `helpers/se3_utils.py`. | +| AZ-278 | lightglue_runtime | `helpers/lightglue_runtime.py` (TRT engine handle). | +| AZ-279 | wgs_converter | `helpers/wgs_converter.py`. | +| AZ-280 | sha256 sidecar | `helpers/sha256_sidecar.py`. | +| AZ-281 | engine filename schema | `helpers/engine_filename.py`. | +| AZ-282 | ransac filter | `helpers/ransac_filter.py` (cv2 essential-matrix). | +| AZ-283 | descriptor normaliser | `helpers/descriptor_normaliser.py`. | + +### C13 FDR writer (6 tasks) — all PASS + +| AZ-291 | writer thread | `c13_fdr/writer.py` (real single-writer thread + ringbuf consumer). | +| AZ-292 | flight header/footer | persistent records. | +| AZ-293 | capacity cap policy | `≤ 64 GB` enforcement, oldest-first rollover. | +| AZ-294 | mid-flight tile snapshot | C6 → C13 hook. | +| AZ-295 | thumbnail rate limiter | ≤ 0.1 Hz failed-tile thumbnail log. | +| AZ-296 | open-error takeoff abort | `take_off` aborts with exit 2 + structured ERROR. | + +### C7 Inference (6 tasks) — all PASS (notable deferrals are documented + non-blocking) + +| AZ-297 | runtime protocol | `c7_inference/interface.py`. | +| AZ-298 | tensorrt runtime | 1263-line `tensorrt_runtime.py`; lazy-imports real `tensorrt` (line 497). | +| AZ-299 | onnxrt fallback | 666-line `onnx_trt_ep_runtime.py`; lazy-imports `onnxruntime` (line 213). | +| AZ-300 | pytorch baseline | 339-line `pytorch_fp16_runtime.py`. Warm-up deferred to Tier-2 (documented in spec); first real `infer` does implicit warm-up, no AC blocked. | +| AZ-301 | engine gate | `engine_gate.py`. AC-8 NVML/Jetpack test is Tier-2-skip — production helper code exists. | +| AZ-302 | thermal publisher | `thermal_publisher.py` + `_JtopSource` + `_PynvmlSource`. AC-7 perf microbench Tier-2-deferred — runtime code exists. | + +### C6 Tile cache (6 tasks) — all PASS + +| AZ-303 | storage interfaces | `c6_tile_cache/interface.py`. | +| AZ-304 | postgres schema | SQL migration shipped. | +| AZ-305 | postgres+filesystem store | `postgres_filesystem_store.py` (real `psycopg` + atomicwrites). | +| AZ-306 | faiss descriptor index | `faiss_descriptor_index.py` (real `faiss` import). | +| AZ-307 | freshness gate | `freshness_gate.py`. | +| AZ-308 | cache budget eviction | `cache_budget_enforcer.py`. | + +### C11 Tile manager (5 tasks) — all PASS + +| AZ-316 | tile downloader | `c11_tile_manager/tile_downloader.py` (real `httpx`). | +| AZ-317 | flight state gate | superseded by C12 SRP refactor; C11 carries no gate. | +| AZ-318 | signing key | `signing_key.py` (per-flight key + FDR rotation log). | +| AZ-319 | tile uploader | `tile_uploader.py` (real ingest contract). | +| AZ-320 | idempotent retry | `IdempotentRetryTileUploader` decorator. | + +### C10 Provisioning (5 tasks) — all PASS + +| AZ-321 | engine compiler | `c10_provisioning/provisioner.py` (real TRT engine compile via C7). | +| AZ-322 | descriptor batcher | batched C2 descriptor gen. | +| AZ-323 | manifest builder | `manifest_builder.py` (real SHA-256 manifest). | +| AZ-324 | manifest verifier | content-hash gate. | +| AZ-325 | cache provisioner | end-to-end F1 build path. | + +### C12 Operator orchestrator (5 tasks) — all PASS + +| AZ-326 | cli app | `c12_operator_orchestrator/cli.py`. | +| AZ-327 | companion bringup | `paramiko_ssh_session.py`. | +| AZ-328 | build cache orchestrator | `remote_c10_invoker.py`. | +| AZ-329 | post-landing upload | `PostLandingUploadOrchestrator` (real FDR footer gate). | +| AZ-330 | operator reloc service | `OperatorReLocService` + `OperatorCommandTransport` Protocol. | +| AZ-489 | flights api client | `flights_api/httpx_client.py`. | + +### C1 VIO (5 tasks) — 1 PASS, 2 FAIL, 2 PASS + +| AZ-331 | strategy protocol | `c1_vio/interface.py`. PASS. | +| AZ-332 | OKVIS2 production-default | **FAIL** — native binding is a skeleton (see above). | +| AZ-333 | VINS-Mono research-only | **FAIL** — same skeleton pattern. | +| AZ-334 | KLT/RANSAC simple baseline | 706-line `klt_ransac.py`, pure-Python OpenCV; no native dep; functional. PASS. | +| AZ-335 | warm start recovery | `warm_start_store.py`. PASS. | + +### C2 VPR (6 tasks) — all PASS + +| AZ-336 | strategy protocol | `c2_vpr/interface.py`. | +| AZ-337 | UltraVPR (production-default) | 441-line `ultra_vpr.py`; consumes C7 TRT engine. | +| AZ-338 | NetVLAD baseline | 500-line `net_vlad.py` + `_net_vlad_architecture.py` + PyTorch FP16 path. | +| AZ-339 | MegaLoc + MixVPR | substantial impls. | +| AZ-340 | SelaVPR + EigenPlaces + SALAD | substantial impls. | +| AZ-341 | faiss retrieve wiring | `_faiss_bridge.py`. | + +Note: `src/gps_denied_onboard/components/c2_vpr/_native/__init__.py` +contains only the line `"""Native bindings for VPR runtime — placeholder."""`. +The C2 strategies route inference through C7 (TensorRT / ONNX-RT / +PyTorch), so this `_native/` directory is empty by design (no extant +task promises VPR-specific C++ code). Recommend deleting the directory +in a future hygiene pass; not a FAIL today. + +### C2.5 Re-rank (2 tasks) — both PASS (with one noted concern, see § Notes) + +| AZ-342 | strategy protocol | `c2_5_rerank/interface.py`. | +| AZ-343 | inlier-count reranker | `inlier_based_reranker.py` (real LightGlue inlier counting). | + +### C3 Cross-domain matcher (4 tasks) — all PASS + +| AZ-344 | matcher protocol | `c3_matcher/interface.py`. | +| AZ-345 | DISK + LightGlue (production-default) | 288-line `disk_lightglue.py`; consumes C7 + helpers. | +| AZ-346 | ALIKED + LightGlue (secondary) | 289-line `aliked_lightglue.py`. | +| AZ-347 | XFeat (alternate) | 544-line `xfeat.py`. | + +Note: `c3_matcher/_native/__init__.py` is similarly an empty placeholder +— same situation as C2's `_native/`. Hygiene cleanup, not a FAIL. + +### C3.5 AdHoP refinement (2 tasks) — both PASS + +| AZ-348 | refiner protocol | `c3_5_adhop/interface.py`. | +| AZ-349 | AdHoP refiner | 509-line `adhop_refiner.py`; real C7-backed AdHoP engine load. Note: `runtime_root/refiner_factory.py` docstring still calls AdHoPRefiner "placeholder today" — that comment is stale; the production class is real. Hygiene fix recommended (one-line doc update). | + +### C4 Pose estimation (3 tasks) — all PASS + +| AZ-355 | pose protocol | `c4_pose/interface.py`. | +| AZ-358 | OpenCV `solvePnPRansac` + GTSAM Marginals | `opencv_gtsam_estimator.py` (real cv2 + gtsam). | +| AZ-361 | Jacobian thermal hybrid | D-CROSS-LATENCY-1 auto-degrade path. | + +### C5 State estimator (9 tasks) — all PASS + +| AZ-381 | protocol | `c5_state/interface.py`. | +| AZ-382 | iSAM2 smoother wiring | `gtsam_isam2_estimator.py` (real `gtsam.IncrementalFixedLagSmoother`). | +| AZ-383 | factor adds | factor-graph construction. | +| AZ-384 | marginals outputs | covariance recovery via `gtsam.Marginals`. | +| AZ-385 | source-label spoof gate | `SourceLabelStateMachine`. | +| AZ-386 | ESKF baseline | `eskf_baseline.py` (mandatory engine-rule baseline). | +| AZ-387 | smoothed history FDR | retroactive smoothing → FDR. | +| AZ-388 | AC-5.2 fallback | FC-IMU-only fallback path. | +| AZ-389 | orthorectifier → C6 mid-flight tiles | `_orthorectifier.py` + compose-root `_C6MidFlightIngestAdapter`. | +| AZ-490 | set_takeoff_origin | operator-origin warm-start hook. | + +### C8 FC adapter (8 tasks) — all PASS + +| AZ-390 | adapter protocol | `c8_fc_adapter/interface.py`. | +| AZ-391 | inbound subscription | `pymavlink` + `msp2` decoders. | +| AZ-392 | covariance projector | 2×2 horizontal sub-block → `horiz_accuracy`. | +| AZ-393 | ardupilot outbound | `pymavlink_ardupilot_adapter.py`. | +| AZ-394 | inav outbound | `msp2_inav_adapter.py`. | +| AZ-395 | mavlink signing | per-flight key rotation + FDR record. | +| AZ-396 | source-set switch | `MAV_CMD_SET_EKF_SOURCE_SET` flow. | +| AZ-397 | qgc telemetry adapter | `mavlink_gcs_adapter.py`. | +| AZ-558 | mavlink transport routing | seam between encoder + serial transport. | + +### Replay path (8 tasks) — all PASS + +| AZ-398 | frame source + clock | `replay_input/` + `frame_source/`. | +| AZ-399 | tlog adapter | `replay_input/tlog_adapter.py`. | +| AZ-400 | jsonl sink | `c8_fc_adapter/replay_sink.py`. | +| AZ-401 | replay compose | `runtime_root/_replay_branch.py`. | +| AZ-402 | replay cli | `cli/replay.py`. | +| AZ-403 | replay dockerfile + ci | shipped under `Dockerfile.replay` + `.github/workflows/`. | +| AZ-404 | replay e2e fixture | `tests/e2e/replay/`. | +| AZ-405 | replay auto-sync | `replay_input/auto_sync.py`. | + +## Notes / non-blocking observations + +1. **Production composition root has no per-binary bootstrap module + registering strategies.** `runtime_root/__init__.py` defines a strategy + registry (`register_strategy`, `_resolve_strategy`) and topo-sorts + constructed components, but `register_strategy` is never called + anywhere in `src/`. `compose_root(config)` would raise + `StrategyNotLinkedError` on every C1-C8 slug if invoked today. This + is the "per-binary bootstrap module" the AZ-263 / AZ-270 prose + anticipates — a separate concern from any one task and arguably out + of scope for this gate (the registry seam exists; the actual + registration lives in a not-yet-written bootstrap module). Recommend + surfacing as a separate cross-cutting task (`E-CC-CONF` or + `E-BOOT`). + +2. **`helpers/feature_extractor.py::OpenCvOrbExtractor`** is documented + as a placeholder ("Production deployments MUST replace this + extractor with a deep-learning backbone before flight (tracked under + the future C2.5 backbone-extractor task)"). No DISK/ALIKED extractor + exists. C2.5 (AZ-343) uses an injected `FeatureExtractor`; the only + concrete impl is ORB. AZ-343's spec does NOT name DISK/ALIKED, so + this is a known-future-task gap rather than an AZ-343 FAIL — but the + prod composition root will need a non-ORB extractor before flight. + Recommend surfacing as a follow-up task (5 points or less). + +3. **`_types/tile.py`** scaffolding DTOs (`Tile`, `TileRecord`) are no + longer referenced by any module under `src/`. Dead code per + `coderule.mdc`. Recommend deleting in a hygiene PBI; not a Gate FAIL. + +4. **`runtime_root/refiner_factory.py`** docstring describes AdHoPRefiner + as "placeholder today" — stale comment; the production class is + real. One-line doc fix. + +5. **`c2_vpr/_native/__init__.py` and `c3_matcher/_native/__init__.py`** + are empty placeholder modules. C2/C3 strategies route inference + through C7; no native code is owed. Recommend deleting both + directories. + +6. **Process leftover `2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`** + remains open (gtsam still numpy 1.x). Not blocking for this gate. + +## Remediation tasks proposed + +Per `implement/SKILL.md` § 15 remediation task creation rules: each +remediation task is sized at ≤ 5 points; depends on its failed parent; +goes to `_docs/02_tasks/todo/`; tracker tickets to be created on user +approval (Jira availability gate per `.cursor/rules/tracker.mdc`). + +### Proposed task 1 — `remediate_AZ-332_okvis2_threadedkfvio_wiring` + +- **Parent FAIL**: AZ-332. +- **Goal**: wire `okvis::ThreadedKFVio` inside + `_native/okvis2_binding.cpp` (`_build_estimator()` and + `_drive_estimator()`); enable the commented-out includes; instantiate + the estimator from `yaml_config_`; attach the output callback that + fills `latest_output_` under `output_mtx_`; CI matrix that installs + Ceres + initialises OKVIS2's vendored submodules. +- **Complexity**: 5 points. +- **Dependencies**: AZ-332, AZ-276, AZ-277. +- **Out of scope**: AC-9 honest-covariance Tier-2 validation against + Derkachi-class fixtures (separate Tier-2 perf task). + +### Proposed task 2 — `remediate_AZ-333_vins_mono_estimator_wiring` + +- **Parent FAIL**: AZ-333. +- **Goal**: wire `vins_estimator::Estimator` + `feature_tracker` inside + `_native/vins_mono_binding.cpp`; enable the de-ROSified VINS-Mono pin + build; ensure the same Protocol-conforming output shape as OKVIS2; + research-only. +- **Complexity**: 5 points. +- **Dependencies**: AZ-333, AZ-276, AZ-277. +- **Out of scope**: IT-12 comparative-study harness (lives in E-BBT). + +If either remediation task grows beyond 5 points during decomposition, +split into infrastructure + estimator-wiring + per-frame-cov-read +sub-tasks before scheduling. + +## Gate decision + +Per `implement/SKILL.md` § 15: + +> If any product task is `FAIL`, STOP. Do not write the final product +> implementation report and do not proceed to any downstream autodev +> step. Completed original task files remain in `done/`; the missing +> work is represented by remediation tasks. + +**State**: Step 7 stays `in_progress`. The Choose block in the next +agent message presents the operator A/B/C options. The two remediation +tasks above will be created on user direction. + +End of report. diff --git a/_docs/_autodev_state.md b/_docs/_autodev_state.md index 3ba2841..a9823e0 100644 --- a/_docs/_autodev_state.md +++ b/_docs/_autodev_state.md @@ -6,13 +6,13 @@ step: 7 name: Implement status: in_progress sub_step: - phase: 11 - name: commit - detail: "Batch 65 (AZ-389) committed; awaiting tracker transition + completeness gate" + phase: 1 + name: parse + detail: "" retry_count: 0 cycle: 1 tracker: jira last_completed_batch: 65 last_cumulative_review: batches_61-63 -current_batch: 65 -current_batch_tasks: "AZ-389" +current_batch: 66 +current_batch_tasks: ""