Implement the three concrete C3 CrossDomainMatcher strategies plus the
C3.5 production-default AdHoPRefiner.
C3 (AZ-345/346/347):
- DiskLightGlueMatcher + AlikedLightGlueMatcher share a single shared
_pipeline.run_lightglue_pipeline orchestrator (decode -> query
extract -> per-candidate loop -> RANSAC sort -> health update ->
FDR emit) so the only per-backbone delta is the keypoint+descriptor
extractor closure. ALIKED adds a create-time engine output-schema
probe (AC-special-1).
- XFeatMatcher owns its own per-candidate loop (single forward fuses
extraction + matching); it re-uses the shared FDR emission helpers
to keep telemetry byte-identical across strategies. lightglue_runtime
parameter accepted by factory but discarded (AC-special-1).
- All three consume the shared LightGlueRuntime / RansacFilter /
RollingHealthWindow helpers; no helper forks. InferenceRuntimeCut
consumer-side Protocol added per AZ-507.
C3.5 (AZ-349):
- AdHoPRefiner implements the <= conditional gate, runs the OrthoLoC
AdHoP TRT engine over best-candidate correspondences, re-runs RANSAC
on the perspective-preconditioned set, and emits an enriched
MatchResult with refinement_label="adhop".
- Invariant 4 passthrough fall-through: any RefinerBackboneError (TRT
failure, OOM, NaN, bad shape) is caught, logged ERROR, FDR-emitted
with error: true, and converted to passthrough that still counts
against the rolling invocation-rate window. MemoryError and other
non-listed exceptions propagate by design (AC-5 closed-set
semantics).
- Rolling 60-s invocation-rate window + rate-limited WARN log
(configurable via ratelimited_warn_window_ns; default 60 s).
Shared changes:
- C3MatcherConfig + C3_5RefinerConfig extended with the new
weights/threshold/window fields.
- matcher_factory + refiner_factory optionally forward clock +
fdr_client to the strategy's create(); backward-compatible.
- fdr_client.records registers five new kinds: matcher.frame_done,
matcher.backbone_error, matcher.insufficient_inliers,
matcher.all_failed, refiner.frame_done.
Tests: 66 new (43 C3 parametrised + 23 AdHoP) covering 47/47 ACs;
focused suite green; full project test suite green except for one
pre-existing flaky CLI cold-start timing test unrelated to this batch.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>