From e8caa29da61182c894759ee5b52a3c8de9f19456 Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Fri, 29 May 2026 11:48:09 +0300 Subject: [PATCH] [AZ-943] [AZ-951] [AZ-952] Pause AZ-943 on OKVIS2 telemetry gap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AZ-943 implementation attempt confirmed the C++ binding cannot satisfy AC-4 without upstream OKVIS2 patches. The spec's "approach (a) in-binding subclass workaround" is structurally impossible: - ThreadedSlam::estimator_ is `private` (not `protected`) - ViSlamBackend has no public covariance / counts / parallax / MRE accessor in the v2 upstream headers - TrackingState carries only id / isKeyframe / TrackingQuality enum / recognisedPlace / isFullGraphOptimising / currentKeyframeId — none of the five tracking-stats fields the binding needs Filed the spec-documented "approach (b)" fallback as two sibling tickets, both linked Jira-side as `is blocked by` against AZ-943: - AZ-951 (3 SP): upstream patch — expose 6x6 pose covariance accessor (+ ADR-XXX for the AZ-332 Plan-phase pin deviation) - AZ-952 (3 SP): upstream patch — expose tracking-stats accessor (feature counts + parallax + MRE) AZ-943 transitioned In Progress -> To Do in Jira, full audit comment attached. Local AZ-943 spec moved todo/ -> backlog/ with PAUSED preamble; original AC list preserved for the post-unblock turn. Per user 2026-05-29 confirmation: cycle-4 Derkachi demo target stays KLT/RANSAC (tests/e2e/replay/conftest.py line 159 c1_vio: strategy: klt_ransac), so AZ-951 + AZ-952 + AZ-943 chain is correctly deferred. Pivoting next batch to AZ-897 (replay UI form). Touches: _docs/02_tasks/_dependencies_table.md (preamble + table rows for AZ-943 paused / AZ-951 / AZ-952 added; totals bumped to 142 product + 41 blackbox-test = 183, 448 product + 133 blackbox = 581), _docs/_autodev_state.md (sub_step pivot to AZ-897). Co-authored-by: Cursor --- _docs/02_tasks/_dependencies_table.md | 10 +-- .../AZ-943_okvis2_threadedslam_binding.md | 17 +++++ ...AZ-951_okvis2_upstream_covariance_patch.md | 65 +++++++++++++++++ ...52_okvis2_upstream_tracking_stats_patch.md | 70 +++++++++++++++++++ _docs/_autodev_state.md | 6 +- 5 files changed, 161 insertions(+), 7 deletions(-) rename _docs/02_tasks/{todo => backlog}/AZ-943_okvis2_threadedslam_binding.md (91%) create mode 100644 _docs/02_tasks/backlog/AZ-951_okvis2_upstream_covariance_patch.md create mode 100644 _docs/02_tasks/backlog/AZ-952_okvis2_upstream_tracking_stats_patch.md diff --git a/_docs/02_tasks/_dependencies_table.md b/_docs/02_tasks/_dependencies_table.md index 09d7581..afae8ea 100644 --- a/_docs/02_tasks/_dependencies_table.md +++ b/_docs/02_tasks/_dependencies_table.md @@ -1,8 +1,8 @@ # Dependencies Table -**Date**: 2026-05-29 (cycle-4 Step 10 Implement — OKVIS2 production-default pivot per user 2026-05-27 directive: AZ-592 placeholder split into 3 properly-sized sub-tickets per PBI rule, all three filed Jira-side then; local-spec import for AZ-943 happens this session before implement batch starts. **AZ-943** (5pt, todo/, c1_vio, OKVIS2 binding wiring; replaces AZ-332 skeleton; deps AZ-332 + AZ-592; epic AZ-254). Sibling tickets remain Jira-only this session: **AZ-944** (3pt, Linux CI build env + DBoW2 small_voc + Tier-1 EuRoC smoke; Blocks chain AZ-943→AZ-944) and **AZ-945** (3pt, Jetson L4T + Tier-2 Derkachi `--vio-strategy okvis2` e2e; Blocks chain AZ-944→AZ-945). Local specs for AZ-944 + AZ-945 will be authored when their Implement turns come up. Earlier 2026-05-26 (cycle-4 Step 10 Implement — AZ-895 batch 3 user complexity decision: chose Option A "minimum deprecation" path. Filed **AZ-908** (3pt, backlog/, replay: hard removal of deprecated auto-sync surface — AZ-895 follow-up; deps AZ-895 HARD + AZ-842 HARD; no epic) to track the cycle-5+ physical removal that AZ-895's minimum-path explicitly defers. AZ-895 ships the no-op stubs + CLI deprecation warnings; AZ-908 will delete the stub files, drop the DTOs from `replay_input/interface.py`, remove the deprecated CLI flags, and drop the `auto_sync` config block. No SP change to cycle-4 totals (AZ-908 is cycle-5+ backlog, not cycle-4 active scope). Earlier same-day at Step 9 New Task — scope adjustments: (a) AZ-841 (1pt, un-xfail AZ-777 Tier-2 tests) moved from todo/ to backlog/ due to hard conflict with AZ-895 AC-4 (test_derkachi_real_tlog.py stays @xfail in cycle 4 because AZ-848 is backlogged) + partial overlap with AZ-894 AC-3 (CSV-path adapter covers the test_derkachi_1min.py un-xfail target); Jira comment added to AZ-841 documenting the deferral. (b) AZ-842 (2pt → **3pt**, +1 SP rescope) — dropped AZ-841 soft dependency, expanded replay_protocol.md scope to add new Invariant 13 covering single-canonical-clock model + cycle-4 CSV-driven replay narrative (AZ-894 + AZ-895 + AZ-896), plus architecture.md replay-input section updates. New deps: AZ-894 HARD + AZ-895 HARD + AZ-896 SOFT. (c) +**AZ-899** (1pt, product, todo/, land architecture_compliance_baseline.md — cycle-3 retro Top-3 #3 third try; deps None; no epic). (d) +**AZ-900** (1pt, product, todo/, autodev cycle-N+1 Step-9 retro-existence gate — cycle-3 retro Top-3 #2 + 2026-05-26 LESSONS process entry; deps None; no epic). (e) +**AZ-901** (1pt, product, todo/, fix EVIDENCE_OUT default path in e2e/runner/conftest.py:56 — closes 2026-05-26 leftover; deps None; no epic). Cycle-4 active scope: 6 product tickets in todo/ totaling **17 SP** = AZ-842 (3, docs) + AZ-894 (3, CSV adapter) + AZ-895 (2, auto-sync deprecation) + AZ-896 (1, format docs) + AZ-897 (5, replay UI) + AZ-899 (1) + AZ-900 (1) + AZ-901 (1). Dependency order: AZ-894 blocks AZ-895 + AZ-842 + AZ-897; AZ-896 blocks AZ-897 + AZ-842. AZ-899/AZ-900/AZ-901 standalone (no internal blockers). AZ-848 (5) + AZ-883 (2) + AZ-908 (3) remain in backlog/ (cycle-3 retro Top-3 #1 + AZ-895 follow-up deferred to cycle-5+; CSV-bypass strategy supersedes their fixes for the demo path). Earlier 2026-05-23 (cycle-3 Step 10 Implement, refactor run 02-az507-routespec-relocation — added AZ-844 (Epic, run dir `_docs/04_refactoring/02-az507-routespec-relocation/`) + AZ-845 (C01, 2pt relocate `RouteSpec` from `replay_input/tlog_route.py` to `_types/route.py`, deps None, epic AZ-844) + AZ-846 (C02, 2pt refresh `module-layout.md` cycle-3 entries — c11 + replay_input + `_types/route`, deps AZ-845, epic AZ-844) + AZ-847 (C03, 2pt widen `test_az270_compose_root` lint to enforce full rule-9 allow-list, deps AZ-845, epic AZ-844). Resolves cycle-3 cumulative review FAIL verdict (F1 High Architecture, F2 Medium Architecture, F3 Medium Maintainability) per `_docs/03_implementation/cumulative_review_batches_104-109_cycle3_report.md`. Jira "Blocks" links recorded: AZ-845 → AZ-846, AZ-845 → AZ-847. Earlier same-day at start of Step 10 Implement — Epic AZ-835 decomposed into 4 leaf tasks + AZ-777 closed: AZ-839 (C3, 5pt operator_pre_flight_setup real fixture, deps AZ-836+AZ-838+AZ-777Phase1+AZ-322+AZ-316+AZ-306, epic AZ-835), AZ-840 (C4, 3pt e2e orchestrator test (tlog,video,calibration), deps AZ-839+AZ-836+AZ-838+AZ-699+AZ-405+AZ-702+AZ-696, epic AZ-835), AZ-841 (C5, 1pt un-xfail AZ-777 AC-4+AC-5, deps AZ-839+AZ-840, epic AZ-835), AZ-842 (C6, 2pt docs — replay_protocol.md Invariant 12 + architecture.md + orchestrator README, soft dep AZ-841, epic AZ-835). AZ-777 transitioned to Done in Jira: Phases 1+2 shipped (batch 104 + between batches 104 and 106); Phases 3-5 superseded by Epic AZ-835 children per 2026-05-22 user directive. AZ-777 spec moved to done/. Earlier 2026-05-21 (cycle-3 Step 9 New Task — added AZ-776 (3pt open-loop ESKF composition profile via `c4_pose.enabled` flag, no deps, epic AZ-602) + AZ-777 (5pt Derkachi C6 reference tile cache + FAISS descriptor index from OSM/CARTO basemap, depends on AZ-776, epic AZ-602). Both unblock the 7 currently-`@xfail`-masked Derkachi e2e tests on Jetson; AZ-776 unblocks 5 (AC-1, AC-2, AC-5, AC-6 realtime, AC-6 asap), AZ-777 unblocks the remaining 2 (AC-3 + AZ-699 real-flight verdict). Earlier 2026-05-19 (refreshed late-morning after 11:27 Jetson Tier-2 e2e run for AZ-618 — surfaced a NEW gap: replay-mode `Config` lacks `c6_tile_cache` block, so `build_pre_constructed → _build_c6_descriptor_index → _c6_config` raises `KeyError` for AC-1/2/5/6. Follow-up filed as AZ-687 (2pt) under E-AZ-602 with guard at the bootstrap layer (NOT silent fallback in `_c6_config`). Earlier same-day mid-day after AZ-618 split: per the spec author's own Sizing-note recommendation + user-rule cap on PBI complexity, AZ-618 was split into 6 subtasks AZ-619..AZ-624 in Jira (subtasks of AZ-618; epic AZ-602 stays grandparent). AZ-618 retained at 0pt as the umbrella tracker; aggregate actionable work is 16pt across the subtasks (vs. AZ-618's original 5pt filing — author's "likely a true 8" caveat was understated due to c5_isam2_graph_handle ordering + GPU builder unknowns). Earlier same-day refresh at start of Step-7 rewind for AZ-618 — Step-11 Jetson tier-2 e2e gate identified missing internal product implementation: `runtime_root.main()` does not build the airborne `pre_constructed` infrastructure dict before `compose_root()`; AZ-618 = 5pt cross-cutting follow-up to AZ-591, lives under E-AZ-602; all 12 dep tasks are in `done/`. Earlier 2026-05-16 (cycle-1 completeness-gate post-mortem): AZ-589 + AZ-590 closed Won't Fix — were wrong abstraction (OKVIS v1 `ThreadedKFVio` API doesn't exist in OKVIS2 upstream; VINS-Mono `cpp/vins_mono/upstream/` submodule never existed; the actual production gap is the empty central `_STRATEGY_REGISTRY` affecting EVERY component with a strategy-selecting config field, not just c1_vio); replaced by AZ-591 (cross-cutting compose_root per-binary bootstrap, todo/, 5pt) + AZ-592 (AZ-332 Tier-2 validation bundle, backlog/, 5pt placeholder) + AZ-593 (AZ-333 Tier-2 validation bundle, backlog/, 5pt placeholder); AZ-332 + AZ-333 re-classified in gate report from FAIL to BLOCKED-on-Tier-2 per the original tasks' Implementation Notes deferral handles; earlier same-day after end of cycle-1 gate: AZ-589 + AZ-590 created (now closed); 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**: 181 (140 product + 41 blackbox-test) — 2026-05-29 cycle-4 Step 10 bump (OKVIS2 binding session): +AZ-943 (1 product task, todo/, 5pt). AZ-944 + AZ-945 remain Jira-only at the time of this update (sibling tickets, local specs deferred to their own Implement turns); their Total-Tasks impact will be reconciled when their specs land. Prior 2026-05-26 cycle-4 Step 10 bump (AZ-895 batch 3 follow-up): 180 (139 product + 41 blackbox-test) — +AZ-908 (1 product task, backlog/, 3pt). Prior 2026-05-26 cycle-4 Step 9 bump: +AZ-899 + AZ-900 + AZ-901 (3 product tasks). AZ-841 moved todo/ → backlog/ (no count change; backlog tickets are still in the table). Prior 2026-05-23 refactor-run bump: 176 (135 product + 41 blackbox-test) — +AZ-844 (Epic, 0pt umbrella for refactor run 02) + AZ-845 + AZ-846 + AZ-847 (3 product tasks). Prior 2026-05-23 bump (Epic AZ-835 decomposition): 173 (132 product + 41 blackbox-test) = +AZ-835 (Epic) + AZ-836 (C1) + AZ-837 (test-stack hardening, not this Epic) + AZ-838 (C2) added 2026-05-22→2026-05-23 prior to that update; +AZ-839 (C3) + AZ-840 (C4) + AZ-841 (C5) + AZ-842 (C6) added in that update. AZ-777 stays in the table (now closed in Jira; spec at `done/AZ-777_derkachi_c6_reference_fixture.md` retains 8pt credit for Phases 1+2 shipped). Earlier counts: 165 (124 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 + AZ-590 closed Won't Fix (kept in table as 0pt audit-trail rows); AZ-591 = 5pt cross-cutting compose_root bootstrap (todo/); AZ-592 = 5pt OKVIS2 Tier-2 placeholder (backlog/); AZ-593 = 5pt VINS-Mono Tier-2 placeholder (backlog/); AZ-618 = 0pt umbrella (split into AZ-619..AZ-624 on 2026-05-19); AZ-619..AZ-624 = 6 subtasks of AZ-618 covering Phase A..F of the airborne `pre_constructed` assembly, summing to 16pt actionable work; AZ-687 = 2pt replay-mode guard follow-up surfaced by AZ-618 Tier-2 run on 2026-05-19 -**Total Complexity Points**: 575 (442 product + 133 blackbox-test) — 2026-05-29 cycle-4 Step 10 bump (OKVIS2 binding session): +5pt AZ-943. AZ-944 (3pt) + AZ-945 (3pt) sibling tickets are filed Jira-side but not yet imported as local specs; their +6pt will land when AZ-944 / AZ-945 specs are authored. Prior 2026-05-26 cycle-4 Step 10 bump (AZ-895 batch 3 follow-up): 570 (437 product + 133 blackbox-test) — +3pt AZ-908. Prior 2026-05-26 cycle-4 Step 9 bump: +1pt AZ-899 + 1pt AZ-900 + 1pt AZ-901 + 1pt AZ-842 rescope (2→3) = +4 product pts. Prior 2026-05-23 refactor-run bump: 563 (430 product + 133 blackbox-test) — +2pt AZ-845 + 2pt AZ-846 + 2pt AZ-847 = +6 product pts on top of prior reconciled total (AZ-844 epic itself is 0pt umbrella). Prior 2026-05-23 reconciled total: 557 (424 product + 133 blackbox-test) — +5pt AZ-839 + 3pt AZ-840 + 1pt AZ-841 + 2pt AZ-842 = +11 product pts on top of prior reconciled total. AZ-836 (3pt) + AZ-838 (3pt) were added 2026-05-22→2026-05-23 prior to that update; AZ-837 (test-stack hardening, not this Epic) is unaccounted in that delta and should be folded in at the next preamble reconciliation. Earlier baseline: 546 (413 product + 133 blackbox-test) — +3pt AZ-776 + 8pt AZ-777 (5→8 override 2026-05-21 cycle-3 batch 104; see `_docs/_process_leftovers/2026-05-21_az777_complexity_override.md` for rationale + the spec refresh that pulled e2e-runner wiring + C11 contract adapt + Derkachi catalog seed + fixture replacement + un-xfail into one ticket) — AZ-523 = 3pt, AZ-524 = 2pt, AZ-526 = 2pt, AZ-527 = 2pt, AZ-528 = 3pt, AZ-558 = 3pt, AZ-589 + AZ-590 retained at 5pt each but closed Won't Fix (treated as 0 effective pts going forward), AZ-591 = 5pt, AZ-592 = 5pt placeholder, AZ-593 = 5pt placeholder, AZ-618 = 0pt umbrella post-split, AZ-619 = 2pt, AZ-620 = 3pt, AZ-621 = 3pt, AZ-622 = 3pt, AZ-623 = 3pt, AZ-624 = 2pt, AZ-687 = 2pt +**Date**: 2026-05-29 (cycle-4 Step 10 Implement — AZ-943 implementation attempt paused mid-batch on spec-reality gap: OKVIS2 v2 public API does NOT expose 6×6 pose covariance, feature counts, mean parallax, or MRE; the AZ-943 spec's "approach (a) in-binding subclass workaround" is structurally impossible because `ThreadedSlam::estimator_` is `private` and `ViSlamBackend` has no public telemetry accessor. The spec-documented "approach (b) upstream patch" fallback filed as **AZ-951** (3pt, backlog/, OKVIS2 v2 upstream patch: expose 6×6 pose covariance accessor + ADR for pin deviation; deps AZ-332 + AZ-592; epic AZ-254) + **AZ-952** (3pt, backlog/, OKVIS2 v2 upstream patch: expose tracking-stats accessor — feature counts + parallax + MRE; deps AZ-332 + AZ-592 + AZ-951 SOFT; epic AZ-254). Both linked Jira-side as `is blocked by` against AZ-943; AZ-943 transitioned In Progress → To Do with full audit comment. **AZ-943** moved todo/ → backlog/ with PAUSED preamble preserving original AC list for audit. Per user 2026-05-29 confirmation, cycle-4 Derkachi demo target stays KLT/RANSAC (per `tests/e2e/replay/conftest.py` line 159 `c1_vio: strategy: klt_ransac`); OKVIS2 chain (AZ-943 → AZ-944 → AZ-945 + AZ-951/952 blockers) deferred to cycle-5+ alongside AZ-945's Tier-2 `--vio-strategy okvis2` Jetson variant. Pivot to AZ-897 (replay UI web form). Earlier this session: OKVIS2 production-default pivot per user 2026-05-27 directive: AZ-592 placeholder split into 3 properly-sized sub-tickets per PBI rule, all three filed Jira-side then; local-spec import for AZ-943 happens this session before implement batch starts. **AZ-943** (5pt, **NOW backlog/** with PAUSED preamble, c1_vio, OKVIS2 binding wiring; replaces AZ-332 skeleton; deps AZ-332 + AZ-592 + **AZ-951 + AZ-952 (blockers)**; epic AZ-254). Sibling tickets remain Jira-only this session: **AZ-944** (3pt, Linux CI build env + DBoW2 small_voc + Tier-1 EuRoC smoke; Blocks chain AZ-943→AZ-944) and **AZ-945** (3pt, Jetson L4T + Tier-2 Derkachi `--vio-strategy okvis2` e2e; Blocks chain AZ-944→AZ-945). Local specs for AZ-944 + AZ-945 will be authored when their Implement turns come up. Earlier 2026-05-26 (cycle-4 Step 10 Implement — AZ-895 batch 3 user complexity decision: chose Option A "minimum deprecation" path. Filed **AZ-908** (3pt, backlog/, replay: hard removal of deprecated auto-sync surface — AZ-895 follow-up; deps AZ-895 HARD + AZ-842 HARD; no epic) to track the cycle-5+ physical removal that AZ-895's minimum-path explicitly defers. AZ-895 ships the no-op stubs + CLI deprecation warnings; AZ-908 will delete the stub files, drop the DTOs from `replay_input/interface.py`, remove the deprecated CLI flags, and drop the `auto_sync` config block. No SP change to cycle-4 totals (AZ-908 is cycle-5+ backlog, not cycle-4 active scope). Earlier same-day at Step 9 New Task — scope adjustments: (a) AZ-841 (1pt, un-xfail AZ-777 Tier-2 tests) moved from todo/ to backlog/ due to hard conflict with AZ-895 AC-4 (test_derkachi_real_tlog.py stays @xfail in cycle 4 because AZ-848 is backlogged) + partial overlap with AZ-894 AC-3 (CSV-path adapter covers the test_derkachi_1min.py un-xfail target); Jira comment added to AZ-841 documenting the deferral. (b) AZ-842 (2pt → **3pt**, +1 SP rescope) — dropped AZ-841 soft dependency, expanded replay_protocol.md scope to add new Invariant 13 covering single-canonical-clock model + cycle-4 CSV-driven replay narrative (AZ-894 + AZ-895 + AZ-896), plus architecture.md replay-input section updates. New deps: AZ-894 HARD + AZ-895 HARD + AZ-896 SOFT. (c) +**AZ-899** (1pt, product, todo/, land architecture_compliance_baseline.md — cycle-3 retro Top-3 #3 third try; deps None; no epic). (d) +**AZ-900** (1pt, product, todo/, autodev cycle-N+1 Step-9 retro-existence gate — cycle-3 retro Top-3 #2 + 2026-05-26 LESSONS process entry; deps None; no epic). (e) +**AZ-901** (1pt, product, todo/, fix EVIDENCE_OUT default path in e2e/runner/conftest.py:56 — closes 2026-05-26 leftover; deps None; no epic). Cycle-4 active scope: 6 product tickets in todo/ totaling **17 SP** = AZ-842 (3, docs) + AZ-894 (3, CSV adapter) + AZ-895 (2, auto-sync deprecation) + AZ-896 (1, format docs) + AZ-897 (5, replay UI) + AZ-899 (1) + AZ-900 (1) + AZ-901 (1). Dependency order: AZ-894 blocks AZ-895 + AZ-842 + AZ-897; AZ-896 blocks AZ-897 + AZ-842. AZ-899/AZ-900/AZ-901 standalone (no internal blockers). AZ-848 (5) + AZ-883 (2) + AZ-908 (3) remain in backlog/ (cycle-3 retro Top-3 #1 + AZ-895 follow-up deferred to cycle-5+; CSV-bypass strategy supersedes their fixes for the demo path). Earlier 2026-05-23 (cycle-3 Step 10 Implement, refactor run 02-az507-routespec-relocation — added AZ-844 (Epic, run dir `_docs/04_refactoring/02-az507-routespec-relocation/`) + AZ-845 (C01, 2pt relocate `RouteSpec` from `replay_input/tlog_route.py` to `_types/route.py`, deps None, epic AZ-844) + AZ-846 (C02, 2pt refresh `module-layout.md` cycle-3 entries — c11 + replay_input + `_types/route`, deps AZ-845, epic AZ-844) + AZ-847 (C03, 2pt widen `test_az270_compose_root` lint to enforce full rule-9 allow-list, deps AZ-845, epic AZ-844). Resolves cycle-3 cumulative review FAIL verdict (F1 High Architecture, F2 Medium Architecture, F3 Medium Maintainability) per `_docs/03_implementation/cumulative_review_batches_104-109_cycle3_report.md`. Jira "Blocks" links recorded: AZ-845 → AZ-846, AZ-845 → AZ-847. Earlier same-day at start of Step 10 Implement — Epic AZ-835 decomposed into 4 leaf tasks + AZ-777 closed: AZ-839 (C3, 5pt operator_pre_flight_setup real fixture, deps AZ-836+AZ-838+AZ-777Phase1+AZ-322+AZ-316+AZ-306, epic AZ-835), AZ-840 (C4, 3pt e2e orchestrator test (tlog,video,calibration), deps AZ-839+AZ-836+AZ-838+AZ-699+AZ-405+AZ-702+AZ-696, epic AZ-835), AZ-841 (C5, 1pt un-xfail AZ-777 AC-4+AC-5, deps AZ-839+AZ-840, epic AZ-835), AZ-842 (C6, 2pt docs — replay_protocol.md Invariant 12 + architecture.md + orchestrator README, soft dep AZ-841, epic AZ-835). AZ-777 transitioned to Done in Jira: Phases 1+2 shipped (batch 104 + between batches 104 and 106); Phases 3-5 superseded by Epic AZ-835 children per 2026-05-22 user directive. AZ-777 spec moved to done/. Earlier 2026-05-21 (cycle-3 Step 9 New Task — added AZ-776 (3pt open-loop ESKF composition profile via `c4_pose.enabled` flag, no deps, epic AZ-602) + AZ-777 (5pt Derkachi C6 reference tile cache + FAISS descriptor index from OSM/CARTO basemap, depends on AZ-776, epic AZ-602). Both unblock the 7 currently-`@xfail`-masked Derkachi e2e tests on Jetson; AZ-776 unblocks 5 (AC-1, AC-2, AC-5, AC-6 realtime, AC-6 asap), AZ-777 unblocks the remaining 2 (AC-3 + AZ-699 real-flight verdict). Earlier 2026-05-19 (refreshed late-morning after 11:27 Jetson Tier-2 e2e run for AZ-618 — surfaced a NEW gap: replay-mode `Config` lacks `c6_tile_cache` block, so `build_pre_constructed → _build_c6_descriptor_index → _c6_config` raises `KeyError` for AC-1/2/5/6. Follow-up filed as AZ-687 (2pt) under E-AZ-602 with guard at the bootstrap layer (NOT silent fallback in `_c6_config`). Earlier same-day mid-day after AZ-618 split: per the spec author's own Sizing-note recommendation + user-rule cap on PBI complexity, AZ-618 was split into 6 subtasks AZ-619..AZ-624 in Jira (subtasks of AZ-618; epic AZ-602 stays grandparent). AZ-618 retained at 0pt as the umbrella tracker; aggregate actionable work is 16pt across the subtasks (vs. AZ-618's original 5pt filing — author's "likely a true 8" caveat was understated due to c5_isam2_graph_handle ordering + GPU builder unknowns). Earlier same-day refresh at start of Step-7 rewind for AZ-618 — Step-11 Jetson tier-2 e2e gate identified missing internal product implementation: `runtime_root.main()` does not build the airborne `pre_constructed` infrastructure dict before `compose_root()`; AZ-618 = 5pt cross-cutting follow-up to AZ-591, lives under E-AZ-602; all 12 dep tasks are in `done/`. Earlier 2026-05-16 (cycle-1 completeness-gate post-mortem): AZ-589 + AZ-590 closed Won't Fix — were wrong abstraction (OKVIS v1 `ThreadedKFVio` API doesn't exist in OKVIS2 upstream; VINS-Mono `cpp/vins_mono/upstream/` submodule never existed; the actual production gap is the empty central `_STRATEGY_REGISTRY` affecting EVERY component with a strategy-selecting config field, not just c1_vio); replaced by AZ-591 (cross-cutting compose_root per-binary bootstrap, todo/, 5pt) + AZ-592 (AZ-332 Tier-2 validation bundle, backlog/, 5pt placeholder) + AZ-593 (AZ-333 Tier-2 validation bundle, backlog/, 5pt placeholder); AZ-332 + AZ-333 re-classified in gate report from FAIL to BLOCKED-on-Tier-2 per the original tasks' Implementation Notes deferral handles; earlier same-day after end of cycle-1 gate: AZ-589 + AZ-590 created (now closed); 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**: 183 (142 product + 41 blackbox-test) — 2026-05-29 cycle-4 Step 10 second bump (AZ-943 paused, dependency PBIs filed): +AZ-951 + AZ-952 (2 product tasks, both backlog/, 3pt each). AZ-943 (5pt) moved todo/ → backlog/ (no count change). Prior same-day 2026-05-29 bump (OKVIS2 binding session start): 181 (140 product + 41 blackbox-test) → 182 (141 product) — +AZ-943 (1 product task, originally todo/, 5pt). AZ-944 + AZ-945 remain Jira-only at the time of this update (sibling tickets, local specs deferred to their own Implement turns); their Total-Tasks impact will be reconciled when their specs land. Prior 2026-05-26 cycle-4 Step 10 bump (AZ-895 batch 3 follow-up): 180 (139 product + 41 blackbox-test) — +AZ-908 (1 product task, backlog/, 3pt). Prior 2026-05-26 cycle-4 Step 9 bump: +AZ-899 + AZ-900 + AZ-901 (3 product tasks). AZ-841 moved todo/ → backlog/ (no count change; backlog tickets are still in the table). Prior 2026-05-23 refactor-run bump: 176 (135 product + 41 blackbox-test) — +AZ-844 (Epic, 0pt umbrella for refactor run 02) + AZ-845 + AZ-846 + AZ-847 (3 product tasks). Prior 2026-05-23 bump (Epic AZ-835 decomposition): 173 (132 product + 41 blackbox-test) = +AZ-835 (Epic) + AZ-836 (C1) + AZ-837 (test-stack hardening, not this Epic) + AZ-838 (C2) added 2026-05-22→2026-05-23 prior to that update; +AZ-839 (C3) + AZ-840 (C4) + AZ-841 (C5) + AZ-842 (C6) added in that update. AZ-777 stays in the table (now closed in Jira; spec at `done/AZ-777_derkachi_c6_reference_fixture.md` retains 8pt credit for Phases 1+2 shipped). Earlier counts: 165 (124 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 + AZ-590 closed Won't Fix (kept in table as 0pt audit-trail rows); AZ-591 = 5pt cross-cutting compose_root bootstrap (todo/); AZ-592 = 5pt OKVIS2 Tier-2 placeholder (backlog/); AZ-593 = 5pt VINS-Mono Tier-2 placeholder (backlog/); AZ-618 = 0pt umbrella (split into AZ-619..AZ-624 on 2026-05-19); AZ-619..AZ-624 = 6 subtasks of AZ-618 covering Phase A..F of the airborne `pre_constructed` assembly, summing to 16pt actionable work; AZ-687 = 2pt replay-mode guard follow-up surfaced by AZ-618 Tier-2 run on 2026-05-19 +**Total Complexity Points**: 581 (448 product + 133 blackbox-test) — 2026-05-29 cycle-4 Step 10 second bump (AZ-943 paused, dependency PBIs filed): +3pt AZ-951 + 3pt AZ-952 = +6 product pts. AZ-943 stays counted at 5pt (moved todo/ → backlog/, not deleted). Prior same-day 2026-05-29 bump (OKVIS2 binding session start): 580 (447 product + 133 blackbox-test) — +5pt AZ-943. AZ-944 (3pt) + AZ-945 (3pt) sibling tickets are filed Jira-side but not yet imported as local specs; their +6pt will land when AZ-944 / AZ-945 specs are authored. Prior 2026-05-26 cycle-4 Step 10 bump (AZ-895 batch 3 follow-up): 570 (437 product + 133 blackbox-test) — +3pt AZ-908. Prior 2026-05-26 cycle-4 Step 9 bump: +1pt AZ-899 + 1pt AZ-900 + 1pt AZ-901 + 1pt AZ-842 rescope (2→3) = +4 product pts. Prior 2026-05-23 refactor-run bump: 563 (430 product + 133 blackbox-test) — +2pt AZ-845 + 2pt AZ-846 + 2pt AZ-847 = +6 product pts on top of prior reconciled total (AZ-844 epic itself is 0pt umbrella). Prior 2026-05-23 reconciled total: 557 (424 product + 133 blackbox-test) — +5pt AZ-839 + 3pt AZ-840 + 1pt AZ-841 + 2pt AZ-842 = +11 product pts on top of prior reconciled total. AZ-836 (3pt) + AZ-838 (3pt) were added 2026-05-22→2026-05-23 prior to that update; AZ-837 (test-stack hardening, not this Epic) is unaccounted in that delta and should be folded in at the next preamble reconciliation. Earlier baseline: 546 (413 product + 133 blackbox-test) — +3pt AZ-776 + 8pt AZ-777 (5→8 override 2026-05-21 cycle-3 batch 104; see `_docs/_process_leftovers/2026-05-21_az777_complexity_override.md` for rationale + the spec refresh that pulled e2e-runner wiring + C11 contract adapt + Derkachi catalog seed + fixture replacement + un-xfail into one ticket) — AZ-523 = 3pt, AZ-524 = 2pt, AZ-526 = 2pt, AZ-527 = 2pt, AZ-528 = 3pt, AZ-558 = 3pt, AZ-589 + AZ-590 retained at 5pt each but closed Won't Fix (treated as 0 effective pts going forward), AZ-591 = 5pt, AZ-592 = 5pt placeholder, AZ-593 = 5pt placeholder, AZ-618 = 0pt umbrella post-split, AZ-619 = 2pt, AZ-620 = 3pt, AZ-621 = 3pt, AZ-622 = 3pt, AZ-623 = 3pt, AZ-624 = 2pt, AZ-687 = 2pt Dependencies columns list only the tracker-ID portion (descriptive tail text in each task spec is omitted here for table-readability). The @@ -199,7 +199,9 @@ are all declared and documented below under **Cycle Check**. | AZ-900 | Autodev: gate cycle-N+1 Step-9 entry on previous-cycle retro existence | 1 | None | (none) | | AZ-901 | Fix EVIDENCE_OUT default path in e2e/runner/conftest.py:56 | 1 | None | (none) | | AZ-908 | Replay: hard removal of deprecated auto-sync surface (AZ-895 follow-up; cycle-5+ backlog) | 3 | AZ-895; AZ-842 | (none) | -| AZ-943 | OKVIS2 binding: real ThreadedSlam wiring (AZ-592 split 1/3) | 5 | AZ-332; AZ-592 | AZ-254 | +| AZ-943 | OKVIS2 binding: real ThreadedSlam wiring (AZ-592 split 1/3) — PAUSED, blocked on AZ-951+AZ-952 | 5 | AZ-332; AZ-592; **AZ-951 (blocker)**; **AZ-952 (blocker)** | AZ-254 | +| AZ-951 | OKVIS2 v2 upstream patch: expose 6×6 pose covariance accessor (+ ADR for pin deviation) | 3 | AZ-332; AZ-592 | AZ-254 | +| AZ-952 | OKVIS2 v2 upstream patch: expose tracking-stats accessor (counts + parallax + MRE) | 3 | AZ-332; AZ-592; AZ-951 (SOFT) | AZ-254 | ## Notes diff --git a/_docs/02_tasks/todo/AZ-943_okvis2_threadedslam_binding.md b/_docs/02_tasks/backlog/AZ-943_okvis2_threadedslam_binding.md similarity index 91% rename from _docs/02_tasks/todo/AZ-943_okvis2_threadedslam_binding.md rename to _docs/02_tasks/backlog/AZ-943_okvis2_threadedslam_binding.md index 6ea9106..2eb1f34 100644 --- a/_docs/02_tasks/todo/AZ-943_okvis2_threadedslam_binding.md +++ b/_docs/02_tasks/backlog/AZ-943_okvis2_threadedslam_binding.md @@ -1,5 +1,22 @@ # C1 OKVIS2 Binding — Real ThreadedSlam Wiring (AZ-592 split 1/3) +> **STATUS (2026-05-29): PAUSED — BLOCKED on AZ-951 + AZ-952.** +> +> Implementation attempt on 2026-05-29 confirmed AC-4 is structurally unreachable without upstream OKVIS2 patches: +> +> - `ThreadedSlam::estimator_` is `private` (not `protected`) → in-binding subclass workaround proposed in Implementation Notes "approach (a)" is impossible. +> - `ViSlamBackend` has no public accessor for 6×6 pose covariance, feature counts, mean parallax, or MRE. +> - `TrackingState` (callback arg) only carries id / isKeyframe / TrackingQuality enum / recognisedPlace / isFullGraphOptimising / currentKeyframeId — none of the AC-4 telemetry fields. +> +> The "approach (b) upstream patch" fallback documented in this file + AZ-592 has been filed as two sibling tickets and linked as `is blocked by` against AZ-943: +> +> - **AZ-951** (3 SP): upstream patch — expose 6×6 pose covariance accessor (+ ADR for pin deviation). +> - **AZ-952** (3 SP): upstream patch — expose tracking-stats accessor (feature counts + parallax + MRE). +> +> Jira AZ-943 reverted to To Do. This local file moved from `todo/` → `backlog/`. The AC list + Implementation Notes below are PRESERVED unchanged for audit; once AZ-951 + AZ-952 land, AC-4 implementation will call `backend().computeCovariance6x6(state.id)` + `backend().getLatestTrackingStats(state.id, ...)` and the file moves back to `todo/`. +> +> Audit reference: AZ-943 Jira comment "Implementation paused: spec gap discovered (2026-05-29)" — full root-cause + decision rationale. + **Task**: AZ-943_okvis2_threadedslam_binding **Name**: OKVIS2 binding: replace AZ-332 skeleton with real `okvis::ThreadedSlam` wiring **Description**: Sub-ticket 1 of 3 from the AZ-592 placeholder split (per state file 2026-05-27 split rationale). Replaces the AZ-332 skeleton in `src/gps_denied_onboard/components/c1_vio/_native/okvis2_binding.cpp` (`_build_estimator()` no-op, `_drive_estimator()` raises `OkvisFatalException`) with the real `okvis::ThreadedSlam` v2 pipeline: `ViParametersReader(yaml).getParameters(...)` → `ThreadedSlam(parameters, dBowDir)` → `setOptimisedGraphCallback(...)`. Without this wiring, `Okvis2Strategy` (AZ-332) is the production-default per architecture but throws on first `add_frame` — the production VIO is unusable. CI build env + Jetson validation are tracked in sibling tickets AZ-944 (3pt, Linux CI + DBoW2 vocab + Tier-1 smoke) and AZ-945 (3pt, Jetson L4T + Tier-2 Derkachi e2e); the Blocks chain in Jira is AZ-943 → AZ-944 → AZ-945. This ticket touches ONLY the C++ binding and the Python facade fake-binding fixture; it does NOT flip `BUILD_OKVIS2=ON` in CI (that's AZ-944's deliverable). diff --git a/_docs/02_tasks/backlog/AZ-951_okvis2_upstream_covariance_patch.md b/_docs/02_tasks/backlog/AZ-951_okvis2_upstream_covariance_patch.md new file mode 100644 index 0000000..5b11f9a --- /dev/null +++ b/_docs/02_tasks/backlog/AZ-951_okvis2_upstream_covariance_patch.md @@ -0,0 +1,65 @@ +# OKVIS2 v2 upstream patch: expose 6×6 pose covariance accessor (+ ADR for pin deviation) + +**Task**: AZ-951_okvis2_upstream_covariance_patch +**Name**: OKVIS2 v2 upstream patch — expose 6×6 pose covariance accessor (+ ADR for pin deviation) +**Description**: Land the documented "approach (b) upstream patch" escape hatch from AZ-592 (line 30) and AZ-943 (Implementation Notes "Tiny upstream patch"). AZ-943's implementation attempt on 2026-05-29 confirmed that the proposed "approach (a) in-binding subclass workaround" is structurally impossible: `ThreadedSlam::estimator_` is declared `private` (not `protected`), and `ViSlamBackend` has no public covariance accessor anywhere in the v2 upstream headers. +**Complexity**: 3 SP +**Dependencies**: AZ-332 (the AZ-332 Plan-phase pin this work deviates from), AZ-592 (parent placeholder that originally offered this approach as option (a) in its line 30-31) +**Component**: c1_vio (epic AZ-254 / E-C1); also touches `cpp/okvis2/` (upstream wrapper) and `_docs/03_implementation/architecture/decisions/` (ADR) +**Tracker**: AZ-951 (https://denyspopov.atlassian.net/browse/AZ-951) +**Parent Epic**: AZ-254 (E-C1) +**Blocks**: AZ-943 AC-4 (pose_covariance_6x6 field) + +Jira AZ-951 is the authoritative spec; this file is the in-workspace mirror. + +## Goal + +Land the documented "approach (b) upstream patch" escape hatch. **Blocks AZ-943 AC-4** (`pose_covariance_6x6` field). The Python facade (`okvis2.py` `_build_vio_output`) shape-checks the 6×6 covariance; downstream EKF in C2 treats it as Kalman gain weight, so an identity placeholder would lie about VIO uncertainty (contradicts AZ-848 ESKF out-of-order analysis). + +## Scope + +1. **ADR-XXX (pin deviation rationale)** under `_docs/03_implementation/architecture/decisions/`: + - Title: "OKVIS2 v2 upstream patch — expose ViSlamBackend pose-covariance accessor for Okvis2Backend C++ binding" + - Decision: deviate from AZ-332 Plan-phase fixed pin to land a small, surgical, documented patch. + - Alternatives considered: (1) keep pin + ship placeholder covariance (violates meta-rule "Real Results, Not Simulated Ones"); (2) hard fork OKVIS2 (rejected — too much surface); (3) upstream the patch as a follow-up contribution to the OKVIS2 maintainers (recommended). + - Consequences: future upstream rebases must reapply; patch is small and self-contained to minimise that cost. + +2. **Patch file** under `cpp/okvis2/patches/expose_covariance.patch`: + - Make `ThreadedSlam::estimator_` reachable from the binding: either add `public okvis::ViSlamBackend& backend()` to `ThreadedSlam` OR change `estimator_` from `private` to `protected`. Recommend the public accessor — cleaner API surface, less invasive. + - Add `Eigen::Matrix ViSlamBackend::computeCovariance6x6(StateId id) const` — wraps `ceres::Covariance::Compute` over the `realtimeGraph_`'s ceres::Problem for the pose parameter block at `id`. Returns a documented failure-sentinel (identity * large scale + warning log) when the covariance computation is rank-deficient; binding then flags the output as low-confidence. + +3. **CMake glue** in `cpp/okvis2/CMakeLists.txt`: apply the patch via the chosen mechanism (decided at scheduling — see Open Decisions). + +4. **Verification path**: compile-clean evidence comes via AZ-944 (Linux CI BUILD_OKVIS2=ON flip). Local macOS gets no compile evidence (project policy). + +## Acceptance Criteria + +- **AC-1**: ADR-XXX exists under `_docs/03_implementation/architecture/decisions/`, follows the project's existing ADR template, and cites AZ-332 (Plan-phase pin), AZ-592 (parent placeholder), AZ-943 (the blocked binding ticket), and this ticket's Jira key. +- **AC-2**: `cpp/okvis2/patches/expose_covariance.patch` exists, applies cleanly to the vendored upstream at `cpp/okvis2/upstream/`, and the patch surface is ≤ 100 lines of diff (keeps future rebase cost low). +- **AC-3**: After patch application, `okvis::ThreadedSlam` has a public method that returns a reference / pointer to its `okvis::ViSlamBackend` member. +- **AC-4**: After patch application, `okvis::ViSlamBackend` has a public `Eigen::Matrix computeCovariance6x6(StateId id) const` method backed by `ceres::Covariance::Compute`. Behaviour: + - Success: returns the 6×6 marginalised pose covariance. + - Failure (rank-deficient / non-converged / wrong state ID): returns a documented failure sentinel and emits a single warning log per occurrence — NO exception thrown into the binding (the binding layer decides whether to surface this as an OkvisOptimizationException). +- **AC-5**: Patch mechanism (in-place `git apply` vs vendored header overrides vs forked submodule) is chosen at scheduling and documented in the patch's commit message + ADR-XXX. +- **AC-6**: Local task spec for AZ-943 is updated to call `backend().computeCovariance6x6(state.id)` inside the `setOptimisedGraphCallback` lambda (the AZ-943 implementation, post-unblock). + +## Open Decisions (resolve at scheduling) + +1. **Patch application mechanism**: in-place `git apply` (simplest, but touches vendored source) vs vendored header overrides under `cpp/okvis2/include_overrides/` (most transparent in code review) vs forked submodule (heaviest, only if patch grows large). Default proposal: vendored header overrides. +2. **Covariance failure semantics**: silent identity sentinel + log (proposed default; binding flags output as low-confidence) vs raise an OKVIS2-side exception (then binding rethrows as `OkvisOptimizationException`). + +## Out of scope + +- Tracking-stats telemetry (tracked/new/lost feature counts, mean_parallax, mre_px) — separate sibling ticket (AZ-952); this one is covariance-only because the two pieces have different upstream surface area and risk profiles. +- Submitting the patch to upstream OKVIS2 maintainers (tracked as a follow-up issue on the upstream GitHub mirror after this lands locally). +- The downstream AZ-943 binding update — owned by AZ-943, which is currently blocked-by this ticket. + +## References + +- AZ-943 implementation attempt (2026-05-29): proved "approach (a) subclass workaround" infeasible — `ThreadedSlam::estimator_` is `private`, `ViSlamBackend` has no public covariance accessor. +- AZ-592 line 30-31: offered this exact approach as fallback when (a) fails. +- AZ-943 Implementation Notes "Tiny upstream patch": defers to this approach explicitly. +- `cpp/okvis2/upstream/okvis_multisensor_processing/include/okvis/ThreadedSlam.hpp` line 254: `private: okvis::ViSlamBackend estimator_;` +- `cpp/okvis2/upstream/okvis_ceres/include/okvis/ViSlamBackend.hpp`: no public covariance accessor anywhere. +- meta-rule.mdc "Real Results, Not Simulated Ones" — the constraint that forces this path over a placeholder. +- Sibling ticket: AZ-952 (tracking-stats accessor). diff --git a/_docs/02_tasks/backlog/AZ-952_okvis2_upstream_tracking_stats_patch.md b/_docs/02_tasks/backlog/AZ-952_okvis2_upstream_tracking_stats_patch.md new file mode 100644 index 0000000..e7177c1 --- /dev/null +++ b/_docs/02_tasks/backlog/AZ-952_okvis2_upstream_tracking_stats_patch.md @@ -0,0 +1,70 @@ +# OKVIS2 v2 upstream patch: expose tracking-stats accessor (feature counts + parallax + MRE) + +**Task**: AZ-952_okvis2_upstream_tracking_stats_patch +**Name**: OKVIS2 v2 upstream patch — expose tracking-stats accessor (feature counts + parallax + MRE) +**Description**: Sibling to AZ-951 (covariance + ADR). AZ-943's implementation attempt on 2026-05-29 confirmed that the four tracking-stats fields the `Okvis2Backend` C++ binding must fill have no source in OKVIS2 v2's public `setOptimisedGraphCallback` arg list. `TrackingState` (`okvis/ViInterface.hpp` lines 167-174) carries only `id`, `isKeyframe`, `trackingQuality` (enum: Good/Marginal/Lost), `recognisedPlace`, `isFullGraphOptimising`, `currentKeyframeId` — NONE of the five tracking-stats fields the binding needs. +**Complexity**: 3 SP +**Dependencies**: AZ-951 (SOFT — same ADR, same patch-mechanism decision; can land in either order, but combining patches is easier if scheduled together), AZ-332 (the AZ-332 Plan-phase pin this work deviates from alongside AZ-951), AZ-592 (parent placeholder) +**Component**: c1_vio (epic AZ-254 / E-C1); also touches `cpp/okvis2/` (upstream wrapper) +**Tracker**: AZ-952 (https://denyspopov.atlassian.net/browse/AZ-952) +**Parent Epic**: AZ-254 (E-C1) +**Blocks**: AZ-943 AC-4 (tracked/new/lost feature counts + mean_parallax + mre_px fields) + +Jira AZ-952 is the authoritative spec; this file is the in-workspace mirror. + +## Goal + +**Blocks AZ-943 AC-4** (the five tracking-stats fields). The Python facade (`okvis2.py` `_build_vio_output`) consumes all five (line 393-399: `FeatureQuality(tracked=..., new=..., lost=..., mean_parallax=..., mre_px=...)`). The `tracked` field also feeds the `_classify_state(vio_output.feature_quality)` DEGRADED-state classifier (line 241) — placeholders would systematically misclassify health. + +Five fields with no source in the public callback surface: + +- `tracked_features` (int) — not in callback args; computed inside `okvis::Frontend` during matching. +- `new_features` (int) — same. +- `lost_features` (int) — same. +- `mean_parallax` (double, px) — not in callback args; computed inside `okvis::Frontend` keyframe selection. +- `mre_px` (double, mean reprojection error) — not in callback args; ceres optimisation byproduct on the realtimeGraph. + +## Scope + +1. **Patch file** under `cpp/okvis2/patches/expose_tracking_stats.patch` (or merge into a single combined patch with AZ-951's covariance patch — scheduler decides): + - Add `void ViSlamBackend::getLatestTrackingStats(StateId id, int& tracked, int& newCount, int& lost, double& meanParallaxPx, double& mreReprojectionPx) const` — reads from the relevant private members (`frontend_` / `realtimeGraph_` / `multiFrames_`) via a single batched accessor. + - `tracked` = count of landmark observations for state `id` that were also observed in the most recent prior keyframe. + - `newCount` = count of landmark observations for state `id` that were NOT observed in any prior frame. + - `lost` = count of landmarks observed in the prior keyframe but absent from `id`. + - `meanParallaxPx` = mean keypoint pixel displacement between `id` and the most recent prior keyframe, over the `tracked` matched set. + - `mreReprojectionPx` = mean per-observation reprojection residual from the realtimeGraph optimisation, over all observations attached to `id`. + +2. **CMake glue**: same mechanism as AZ-951's covariance patch (vendored header overrides vs in-place git apply vs forked submodule — decided at AZ-951 scheduling). If AZ-951 lands first, this ticket reuses that mechanism; if scheduled in parallel, mechanism is decided together. + +3. **Verification path**: compile-clean evidence comes via AZ-944 (Linux CI BUILD_OKVIS2=ON flip). Local macOS gets no compile evidence (project policy). + +## Acceptance Criteria + +- **AC-1**: `cpp/okvis2/patches/expose_tracking_stats.patch` (or the combined patch with AZ-951's content) exists, applies cleanly to the vendored upstream at `cpp/okvis2/upstream/`, and the total patch surface across this + AZ-951 stays ≤ 200 lines of diff (keeps future rebase cost low). +- **AC-2**: After patch application, `okvis::ViSlamBackend::getLatestTrackingStats(...)` is a public method that fills the five out-params with finite values for any valid `StateId` of a state that has been through realtimeGraph optimisation. For state IDs that have not yet been optimised, all five are set to documented sentinel values (zeros + warning log). +- **AC-3**: All five values are computed from the realtimeGraph's actual matched-observation set; no placeholders, no defaults. Code comment in the patch explains the derivation for each field. +- **AC-4**: ADR-XXX from AZ-951 is updated to cite this ticket alongside the covariance accessor work, so the deviation-from-pin rationale documents the FULL telemetry exposure surface. +- **AC-5**: Local task spec for AZ-943 is updated to call `backend().getLatestTrackingStats(state.id, ...)` inside the `setOptimisedGraphCallback` lambda (the AZ-943 implementation, post-unblock). + +## Open Decisions (resolve at scheduling) + +1. **Combined vs separate patch file**: ship as `expose_telemetry.patch` (one file covering both AZ-951's covariance + this ticket's tracking-stats) or as two separate `.patch` files. Default proposal: one combined patch with two logical commits inside it. +2. **Sentinel semantics for unoptimised states**: zeros + warning log (proposed default) vs raise OKVIS2-side exception (binding rethrows as `OkvisOptimizationException`). +3. **Parallax denominator edge case**: when `tracked == 0` (no matches at all), `meanParallaxPx` is undefined. Proposed default: emit NaN + warning log; binding then short-circuits to DEGRADED health state. Scheduler may choose 0.0 instead. + +## Out of scope + +- 6×6 pose covariance accessor — covered by AZ-951 (sibling ticket; same ADR, same patch mechanism). +- The ADR creation itself — owned by AZ-951; this ticket extends the ADR's scope rather than creating a separate one. +- Submitting the patch to upstream OKVIS2 maintainers (tracked as a follow-up issue after both tickets land locally). +- The downstream AZ-943 binding update — owned by AZ-943, which is currently blocked-by this ticket. + +## References + +- AZ-943 implementation attempt (2026-05-29): proved the five tracking-stats fields have no source in OKVIS2 v2's public callback surface. +- AZ-592 line 24 (incorrect spec assumption): "derive tracked_features + mean_parallax from TrackingState" — superseded by this ticket; TrackingState does NOT carry these. +- `cpp/okvis2/upstream/okvis_common/include/okvis/ViInterface.hpp` lines 167-174: TrackingState definition (only 6 fields, none of them tracking-stats). +- `cpp/okvis2/upstream/okvis_ceres/include/okvis/ViSlamBackend.hpp`: no public tracking-stats accessor anywhere. +- AZ-848 (jetson_eskf_out_of_order_regression): downstream EKF assumes finite, computed VIO telemetry; placeholders would mislead its diagnostic surface. +- meta-rule.mdc "Real Results, Not Simulated Ones" — the constraint that forces this path over a placeholder. +- Sibling ticket: AZ-951 (covariance + ADR). diff --git a/_docs/_autodev_state.md b/_docs/_autodev_state.md index d827158..761a1e4 100644 --- a/_docs/_autodev_state.md +++ b/_docs/_autodev_state.md @@ -6,9 +6,9 @@ step: 10 name: Implement status: in_progress sub_step: - phase: 7 - name: batch-loop - detail: "batch 4 closed (AZ-842); next: AZ-897 or AZ-943" + phase: 6 + name: implement-tasks + detail: "batch 5 of N: AZ-897 replay UI web form (pivoted from AZ-943 — paused, blocked on AZ-951+AZ-952 per 2026-05-29 spec-reality gap)" retry_count: 0 cycle: 4 tracker: jira