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>
9.6 KiB
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.md—c3_matcherPer-Component Mapping (aliked_lightglue.pyInternal);BUILD_MATCHER_ALIKED_LIGHTGLUErow._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.pydefining:AlikedLightGlueMatcherclass implementing theCrossDomainMatcherProtocol.- 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). matchmethod: identical control flow to AZ-345'smatch— drop-and-continue, RANSAC + median residual, deterministic best-candidate selection,RollingHealthWindow.update, FDRmatcher.frame_done. The ONLY difference is the keypoint+descriptor extraction step calls the ALIKED engine instead of DISK.health_snapshot()delegates to the constructor-injectedRollingHealthWindow.- Module-level
create(config, lightglue_runtime, ransac_filter, inference_runtime, health_window) -> CrossDomainMatcher:aliked_weights_path = config.matcher.aliked_weights_path(TRT engine produced by AZ-321).- Load ALIKED engine via
inference_runtime.load_engine(...). - Construct
AlikedLightGlueMatcher(...).
- Composition-root wiring path for
config.matcher.strategy == "aliked_lightglue". BUILD_MATCHER_ALIKED_LIGHTGLUEflag 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
AlikedLightGlueMatcherimplementation per theCrossDomainMatcherProtocol.- 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.updateinvocation pattern. - Composition-root wiring path.
- ALIKED-specific preprocessor inline.
- Unit tests covering Invariants 1–9 + drop-and-continue + below-threshold + deterministic ordering, parametrised so they share fixtures with AZ-345's tests where possible.
BUILD_MATCHER_ALIKED_LIGHTGLUEflag wiring.
Excluded
- The Protocol + DTOs + errors + factory +
RollingHealthWindow— owned by AZ-344. LightGlueRuntime(AZ-278) andRansacFilter(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:
matchp95 ≤ 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,
InsufficientInliersErrortriggers 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
createtime,RollingHealthWindow.updatecalled exactly once permatch. - 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.strategyselects which is instantiated. NOT mutually exclusive at build time (operator-tooling excludes both viaBUILD_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— secondaryCrossDomainMatcher(architecture / E-C3 /solution.md/ AC-1.1 partition). - Production code that must exist: real
AlikedLightGlueMatchercalling real C7InferenceRuntimewith real TRT-compiled ALIKED engine; same sharedLightGlueRuntime+RansacFilter+RollingHealthWindowinvocation 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.updateon all-failed path; using mean residual instead of median.