Files
Oleksandr Bezdieniezhnykh abe8c5cd2c [AZ-345] [AZ-346] [AZ-347] [AZ-349] Archive batch 57 task specs
Move completed task specs from _docs/02_tasks/todo/ to
_docs/02_tasks/done/ now that the four tickets are In Testing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 04:10:34 +03:00

9.6 KiB
Raw Permalink Blame History

C3 ALIKED+LightGlue Secondary Matcher

Task: AZ-346_c3_aliked_lightglue Name: C3 ALIKED+LightGlue Secondary Matcher Description: Implement AlikedLightGlueMatcher, the secondary CrossDomainMatcher. Same architecture as DiskLightGlueMatcher (AZ-345) — DISK is replaced by ALIKED for the per-frame keypoint+descriptor extraction step; LightGlue + RANSAC stages are unchanged. Selectable via config.matcher.strategy = "aliked_lightglue". ALIKED is the candidate alternative if D-C3-1 IT-12 verdict shifts away from DISK; until then it ships as the secondary path linked into airborne / research binaries (per ADR-002, both backbones can be linked; only one is selected at runtime). Complexity: 3 points Dependencies: AZ-344 (Protocol + factory + DTOs + errors + RollingHealthWindow), AZ-263_initial_structure, AZ-269_config_loader, AZ-278_lightglue_runtime, AZ-282_ransac_filter, AZ-298_c7_tensorrt_runtime, AZ-299_c7_onnxrt_fallback, AZ-303_c6_storage_interfaces, AZ-281_engine_filename_schema (ALIKED engine self-describing filename), AZ-321_c10_engine_compiler (ALIKED engine compile path), AZ-266_log_module, AZ-272_fdr_record_schema Component: c3_matcher (epic AZ-257 / E-C3) Tracker: AZ-346 Epic: AZ-257 (E-C3)

Document Dependencies

  • _docs/02_document/contracts/c3_matcher/cross_domain_matcher_protocol.md — Protocol contract (every invariant satisfied; mirrors AZ-345's contract behavior).
  • _docs/02_document/components/04_c3_matcher/description.md — § 1 ALIKED secondary; § 5 same error handling; § 9 logging.
  • _docs/02_document/module-layout.mdc3_matcher Per-Component Mapping (aliked_lightglue.py Internal); BUILD_MATCHER_ALIKED_LIGHTGLUE row.
  • _docs/02_document/contracts/shared_helpers/lightglue_runtime.md.
  • _docs/02_document/contracts/shared_helpers/ransac_filter.md.
  • _docs/02_document/contracts/c2_5_rerank/rerank_strategy_protocol.md.
  • _docs/02_document/contracts/c7_inference/inference_runtime_protocol.md.

Problem

Without this task: D-C3-1 IT-12 evaluation has no comparison point against DISK; if a future cycle's IT-12 verdict shifts the production-default to ALIKED, the airborne binary cannot be re-configured without a new task; the ADR-002 build-time exclusion machinery is under-tested (only one matcher would exist). ALIKED is also the documented fallback if DISK's licensing or upstream maintenance changes mid-cycle.

Outcome

  • src/gps_denied_onboard/components/c3_matcher/aliked_lightglue.py defining:
    • AlikedLightGlueMatcher class implementing the CrossDomainMatcher Protocol.
    • Constructor identical shape to DiskLightGlueMatcher (AZ-345); the only differences are: ALIKED engine loaded instead of DISK, matcher_label = "aliked_lightglue", ALIKED-specific preprocessor (resize / normalise per the upstream ALIKED contract).
    • match method: identical control flow to AZ-345's match — drop-and-continue, RANSAC + median residual, deterministic best-candidate selection, RollingHealthWindow.update, FDR matcher.frame_done. The ONLY difference is the keypoint+descriptor extraction step calls the ALIKED engine instead of DISK.
    • health_snapshot() delegates to the constructor-injected RollingHealthWindow.
    • Module-level create(config, lightglue_runtime, ransac_filter, inference_runtime, health_window) -> CrossDomainMatcher:
      1. aliked_weights_path = config.matcher.aliked_weights_path (TRT engine produced by AZ-321).
      2. Load ALIKED engine via inference_runtime.load_engine(...).
      3. Construct AlikedLightGlueMatcher(...).
  • Composition-root wiring path for config.matcher.strategy == "aliked_lightglue".
  • BUILD_MATCHER_ALIKED_LIGHTGLUE flag wiring (per ADR-002): ON in airborne + research binaries; OFF in operator-tooling.
  • ALIKED-specific preprocessor lives next to the strategy in the same module (NOT in helpers/ — preprocessing parameters are weights-coupled per the same rule applied in AZ-337 / AZ-345).
  • All logging + FDR records identical structure to AZ-345 with matcher_label = "aliked_lightglue".

Scope

Included

  • AlikedLightGlueMatcher implementation per the CrossDomainMatcher Protocol.
  • ALIKED forward via C7 InferenceRuntime.
  • LightGlue matching via shared helper.
  • RANSAC + median residual via RansacFilter.
  • Same drop-and-continue + below-threshold + best-candidate selection semantics as AZ-345.
  • Same RollingHealthWindow.update invocation pattern.
  • Composition-root wiring path.
  • ALIKED-specific preprocessor inline.
  • Unit tests covering Invariants 19 + drop-and-continue + below-threshold + deterministic ordering, parametrised so they share fixtures with AZ-345's tests where possible.
  • BUILD_MATCHER_ALIKED_LIGHTGLUE flag wiring.

Excluded

  • The Protocol + DTOs + errors + factory + RollingHealthWindow — owned by AZ-344.
  • LightGlueRuntime (AZ-278) and RansacFilter (AZ-282) helpers.
  • C7 runtime stack (AZ-297..AZ-300).
  • ALIKED engine compile (AZ-321).
  • Component-internal acceptance tests beyond Protocol + invariants smoke: deferred to Step 9 / E-BBT.
  • DISK matcher (AZ-345) and XFeat matcher (AZ-347).

Acceptance Criteria

AC-1 through AC-12: identical contract to AZ-345 AC-1..AC-12 with matcher_label = "aliked_lightglue" and ALIKED-specific tile preprocessing. The Protocol invariants are the same; the implementation is the same modulo backbone. Tests parametrise across both backbones so any divergence is caught.

AC-special-1: ALIKED engine output schema is asserted at create time Given a TRT engine whose ALIKED output dimensionality differs from the upstream-published value (e.g., descriptor_dim != expected) When AlikedLightGlueMatcher.create(...) is called Then ConfigurationError is raised with the offending shape; the strategy is NOT instantiated.

AC-special-2: Strategy selection — config.matcher.strategy == "aliked_lightglue" Given the runtime composition with config.matcher.strategy = "aliked_lightglue" AND BUILD_MATCHER_ALIKED_LIGHTGLUE = ON When compose_root(config) runs Then an AlikedLightGlueMatcher is instantiated; ONE INFO log kind="c3.matcher.ready" with {strategy: "aliked_lightglue", ...} is emitted; _lightglue_runtime identity-equal to the runtime root's shared helper.

Non-Functional Requirements

Performance (deferred validation to C3-PT-01):

  • Same envelope as AZ-345: match p95 ≤ 180 ms; per-candidate ≤ 60 ms; GPU mem ≤ 800 MB.

Compatibility

  • ALIKED engine file format owned by C10 + C7; consumed via config.matcher.aliked_weights_path.

Reliability

  • Same as AZ-345: drop-and-continue, single-thread by contract, InsufficientInliersError triggers VIO-only fallback.

Unit Tests

AC Ref What to Test Required Outcome
AC-1..AC-12 Identical to AZ-345 AC-1..AC-12 with ALIKED label Same outcomes; matcher_label = "aliked_lightglue"
AC-special-1 ALIKED engine output shape mismatch ConfigurationError at create time
AC-special-2 compose_root(config="aliked_lightglue") Wired; INFO log emitted; helper identity-shared
Parametrised drop-and-continue Run AZ-345's drop-and-continue tests against ALIKED matcher fixture Same drop-and-continue semantics

Constraints

  • Same constraints as AZ-345 — drop-and-continue mandatory, median residual, constructor injection, helpers constructor-injected, ALIKED engine load at create time, RollingHealthWindow.update called exactly once per match.
  • ALIKED-specific preprocessing parameters are hard-coded — weights-coupled (same rule as DISK and UltraVPR); making them config-knobs would let an operator silently break the AC-1.1 inlier floor.
  • Both DISK and ALIKED engines may be linked into the same binary — ADR-002 allows multiple backbones at link time; only config.matcher.strategy selects which is instantiated. NOT mutually exclusive at build time (operator-tooling excludes both via BUILD_MATCHER_* flags OFF).

Risks & Mitigation

Risk 1: ALIKED upstream code drop preprocessing differs from DISK in non-obvious ways

  • Mitigation: ALIKED preprocessor lives next to the strategy with hard-coded parameters; tests assert the preprocessor matches the upstream-published values; engine compile (AZ-321) consumes the same parameters.

Risk 2: ALIKED's keypoint count distribution differs from DISK (e.g., ALIKED returns more or fewer keypoints by default)

  • Mitigation: LightGlue and RANSAC are agnostic to keypoint count distribution; the median residual + inlier count metrics are normalised. C3-IT-01 (deferred) measures this empirically.

Risk 3: Switching from DISK to ALIKED at runtime requires a corpus rebuild

  • Mitigation: NO. C2's descriptor index (built by C10) is for VPR retrieval, not for cross-domain matching. C3 operates per-frame on raw tile pixels; switching matcher backbones does not require corpus rebuild. Documented in description.md § 8 (independent paths).

Runtime Completeness

  • Named capability: AlikedLightGlueMatcher — secondary CrossDomainMatcher (architecture / E-C3 / solution.md / AC-1.1 partition).
  • Production code that must exist: real AlikedLightGlueMatcher calling real C7 InferenceRuntime with real TRT-compiled ALIKED engine; same shared LightGlueRuntime + RansacFilter + RollingHealthWindow invocation pattern as AZ-345.
  • Allowed external stubs: same as AZ-345 — FakeInferenceRuntime, FakeLightGlueRuntime, FakeRansacFilter, FakeFdrClient.
  • Unacceptable substitutes: same as AZ-345 — Python+NumPy ALIKED forward; per-strategy RANSAC; skipping RollingHealthWindow.update on all-failed path; using mean residual instead of median.