[AZ-343] C2.5 InlierCountReRanker + shared FeatureExtractor helper

Implements the production-default ReRankStrategy: K=10 → N=3 by
single-pair LightGlue inlier count, with strict drop-and-continue
(INV-8) on per-candidate TileFetch / backbone / zero-inlier failures
and RerankAllCandidatesFailedError on zero survivors. Composition
root injects the shared LightGlueRuntime + Clock + the new
FeatureExtractor helper (an L1 placeholder OpenCvOrbExtractor that
unblocks AZ-343 and future C3 strategies — task scope expansion).

Architectural notes:
- Cross-component imports stay banned; tile_store types as `object`
  and the C6 TileCacheError family is duck-typed by class module
  prefix (same workaround AZ-348 adopted for c7_inference; proper
  fix is to relocate TileCacheError to _types/ in a follow-up).
- Clock injection follows the replay contract (AZ-398 Invariant 2);
  reranked_at is sourced from clock.monotonic_ns().
- AZ-342 factory grew `feature_extractor` + `clock` + `fdr_client`
  parameters; existing AZ-342 conformance tests updated.

Tests: 19 new AC-1..AC-12 + mixed-failure scenarios in
test_inlier_count_reranker.py; existing AZ-342 suite (26) still
green. Full repo sweep 1093 passed / 2 skipped (cmake/actionlint
not on PATH).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-12 06:22:40 +03:00
parent 9a605c8514
commit 48ea1e2fc2
10 changed files with 1739 additions and 13 deletions
@@ -70,11 +70,46 @@ class _FakeLightGlueRuntime:
raise NotImplementedError
class _FakeFeatureExtractor:
def descriptor_dim(self):
return 256
def extract(self, image_bgr):
raise NotImplementedError
class _FakeClock:
def __init__(self) -> None:
self._t = 1_000_000_000
def monotonic_ns(self):
self._t += 1
return self._t
def time_ns(self):
return self._t
def sleep_until_ns(self, target_ns):
return None
class _FullReRankStrategy:
def __init__(self, config, *, tile_store, lightglue_runtime) -> None:
def __init__(
self,
config,
*,
tile_store,
lightglue_runtime,
feature_extractor=None,
clock=None,
fdr_client=None,
) -> None:
self._config = config
self._tile_store = tile_store
self._lightglue_runtime = lightglue_runtime
self._feature_extractor = feature_extractor
self._clock = clock
self._fdr_client = fdr_client
self._label = config.components["c2_5_rerank"].strategy
def rerank(self, frame, vpr_result, n, calibration):
@@ -127,6 +162,7 @@ def test_ac1_rerank_strategy_conformance_full() -> None:
_config_with_strategy(),
tile_store=_FakeTileStore(),
lightglue_runtime=_FakeLightGlueRuntime(),
clock=_FakeClock(),
)
assert isinstance(instance, ReRankStrategy)
@@ -201,6 +237,8 @@ def test_ac3_factory_rejects_missing_build_flag(
config,
tile_store=_FakeTileStore(),
lightglue_runtime=_FakeLightGlueRuntime(),
feature_extractor=_FakeFeatureExtractor(),
clock=_FakeClock(),
)
assert "BUILD_RERANK_INLIER_COUNT is OFF" in str(exc_info.value)
assert any(
@@ -219,6 +257,8 @@ def test_ac3_factory_does_not_load_module_when_flag_off(
config,
tile_store=_FakeTileStore(),
lightglue_runtime=_FakeLightGlueRuntime(),
feature_extractor=_FakeFeatureExtractor(),
clock=_FakeClock(),
)
assert module_name not in sys.modules
@@ -256,6 +296,8 @@ def test_ac5_factory_emits_info_log_on_success(
config,
tile_store=_FakeTileStore(),
lightglue_runtime=_FakeLightGlueRuntime(),
feature_extractor=_FakeFeatureExtractor(),
clock=_FakeClock(),
)
assert isinstance(instance, ReRankStrategy)
records = [
@@ -281,6 +323,8 @@ def test_ac6_strategy_resolution(monkeypatch, strategy_module_cleanup) -> None:
config,
tile_store=_FakeTileStore(),
lightglue_runtime=_FakeLightGlueRuntime(),
feature_extractor=_FakeFeatureExtractor(),
clock=_FakeClock(),
)
assert isinstance(instance, fake_cls)
assert isinstance(instance, ReRankStrategy)
@@ -373,12 +417,18 @@ def test_nfr_perf_factory_under_50ms_p99(
config = _config_with_strategy(strategy)
tile_store = _FakeTileStore()
lightglue_runtime = _FakeLightGlueRuntime()
feature_extractor = _FakeFeatureExtractor()
clock = _FakeClock()
durations_ms: list[float] = []
for _ in range(100):
t0 = time.perf_counter()
build_rerank_strategy(
config, tile_store=tile_store, lightglue_runtime=lightglue_runtime
config,
tile_store=tile_store,
lightglue_runtime=lightglue_runtime,
feature_extractor=feature_extractor,
clock=clock,
)
durations_ms.append((time.perf_counter() - t0) * 1000.0)