[AZ-344] C3 CrossDomainMatcher Protocol + factory + RollingHealthWindow

Defines the public `CrossDomainMatcher` Protocol (PEP 544
@runtime_checkable, two methods: `match` + `health_snapshot`),
the three frozen+slotted DTOs (`CandidateMatchSet`, `MatchResult`,
`MatcherHealth`) in the L1 `_types/matcher.py` layer, the
`MatcherError` family (`MatcherBackboneError`,
`InsufficientInliersError`), and the composition-root
`build_matcher_strategy` factory with lazy-import +
`BUILD_MATCHER_<variant>` gating per ADR-002.

`RollingHealthWindow` accumulator (60 s, amortised O(1) update,
strict O(1) snapshot) is constructed by the factory and injected
into every concrete matcher so all backbones share window
semantics; this is what backs C5's spoof-promotion gate.

Legacy placeholder `MatchResult` removed from `_types/matching.py`;
import-only consumers (`c4_pose.interface`, `c3_5_adhop.interface`)
repointed at the new `_types/matcher.py` home — zero behavioural
change to those components.

AC-9 (single-thread binding) and AC-10 (LightGlueRuntime
identity-share with C2.5) deferred to AZ-270 runtime-root
composition, mirroring the AZ-342 Risk-4 escape clause. All other
ACs + NFRs covered by 70 new conformance tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-12 05:43:33 +03:00
parent d6756f1855
commit 89c223882b
16 changed files with 1404 additions and 50 deletions
+9 -6
View File
@@ -70,15 +70,18 @@ Bootstrap reference: `_docs/02_tasks/todo/AZ-263_initial_structure.md`. Architec
- **Epic**: AZ-257 (E-C3 Cross-Domain Matcher)
- **Directory**: `src/gps_denied_onboard/components/c3_matcher/`
- **Public API**:
- `__init__.py` (re-exports `CrossDomainMatcher`, `MatchResult`)
- `__init__.py` (re-exports `CrossDomainMatcher`, `MatchResult`, `MatcherHealth`, `CandidateMatchSet`, `MatcherError`, `MatcherBackboneError`, `InsufficientInliersError`, `C3MatcherConfig`)
- `interface.py` (`CrossDomainMatcher` Protocol)
- `config.py` (`C3MatcherConfig`)
- `errors.py` (error hierarchy)
- **Internal**:
- `disk_lightglue.py` (DISK + LightGlue)
- `aliked_lightglue.py` (ALIKED + LightGlue)
- `xfeat.py`
- `_health_window.py` (`RollingHealthWindow` accumulator; constructor-injected into every concrete matcher)
- `disk_lightglue.py` (DISK + LightGlue, AZ-345)
- `aliked_lightglue.py` (ALIKED + LightGlue, AZ-346)
- `xfeat.py` (XFeat, AZ-347)
- `_native/`
- **Owns**: `src/gps_denied_onboard/components/c3_matcher/**`, `tests/unit/c3_matcher/**`
- **Imports from**: `_types`, `helpers.lightglue_runtime` (R14: SHARED with C2.5 — owned by helper, NOT by C3), `helpers.descriptor_normaliser`, `helpers.se3_utils`, `components.c7_inference`, `config`, `logging`, `fdr_client`
- **Owns**: `src/gps_denied_onboard/components/c3_matcher/**`, `tests/unit/c3_matcher/**`, `src/gps_denied_onboard/runtime_root/matcher_factory.py`
- **Imports from**: `_types`, `helpers.lightglue_runtime` (R14: SHARED with C2.5 — owned by helper, NOT by C3), `helpers.ransac_filter`, `helpers.descriptor_normaliser`, `helpers.se3_utils`, `components.c7_inference`, `config`, `logging`, `fdr_client`
- **Consumed by**: `c3_5_adhop`, `runtime_root`
### Component: c3_5_adhop