mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 21:01:13 +00:00
[AZ-342] C2.5 ReRankStrategy: Protocol + DTOs + factory + composition
Foundational scaffolding for the InlierCountReRanker (AZ-343) and the future C3 CrossDomainMatcher consumer (AZ-344). No concrete re-ranker is implemented here. * ReRankStrategy Protocol (single rerank(frame, vpr_result, n, calibration) -> RerankResult method) with all 8 invariants in the docstring — notably INV-8 drop-and-continue (per-candidate failure NEVER propagates unless every candidate fails). * DTOs moved to L1 _types/rerank.py — RerankCandidate, RerankResult; frozen+slots; tuple-not-list for RerankResult.candidates; tile_id encoded as (zoom_level, lat, lon) tuple to keep _types/ free of any c6_tile_cache (L3) import per module-layout.md. * Error family: RerankError + RerankBackboneError + RerankAllCandidatesFailedError. Only RerankAllCandidatesFailedError escapes rerank(); RerankBackboneError is caught inside the per- candidate loop, logged ERROR, FDR-stamped, candidate dropped. * C2_5RerankConfig (strategy enum default "inlier_count", top_n int default 3) with strict validation at load; registered into Config.components on c2_5_rerank import. * build_rerank_strategy(config, *, tile_store, lightglue_runtime) factory: 1-strategy resolution table, lazy import, BUILD_RERANK_<variant> gate, ImportError → StrategyNotAvailableError mapping. The shared LightGlueRuntime is constructor-injected (R14 fix: neither C2.5 nor C3 owns its lifecycle). Renamed the Protocol from the existing stub "RerankStrategy" to "ReRankStrategy" to match the contract; updated module-layout.md. Removed the legacy RerankResult shape from _types/vpr.py — the v1.0.0 shape lives in _types/rerank.py. Excluded per task spec: * Concrete InlierCountReRanker (AZ-343). * C3 matcher protocol task (AZ-344, next in batch). * AC-9 single-thread binding + AC-10 LightGlueRuntime identity-share between C2.5/C3 — deferred per task spec Risk 3 until the generic compose_root thread-binding registry and the C3 factory both land. Tests: AC-1..AC-8 + AC-11 + NFR-perf-factory in tests/unit/c2_5_rerank/test_protocol_conformance.py. The legacy smoke test is removed. Full sweep: 997 passed (one pre-existing flake in test_az296_takeoff_abort, subprocess timing, unrelated to this commit; passes in isolation). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""C2.5 ReRankStrategy config block (AZ-342).
|
||||
|
||||
Registered into ``config.components['c2_5_rerank']`` by the package
|
||||
``__init__.py``. The composition-root factory
|
||||
:func:`gps_denied_onboard.runtime_root.rerank_factory.build_rerank_strategy`
|
||||
reads this block to select the strategy and configure the top-N cut.
|
||||
|
||||
``top_n`` is the strategy-side cap on the returned
|
||||
:attr:`RerankResult.candidates` length; the composition root binds
|
||||
``n`` per-frame from this value (default 3 per the epic's K=10 → N=3
|
||||
spec).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Final
|
||||
|
||||
from gps_denied_onboard.config.schema import ConfigError
|
||||
|
||||
__all__ = [
|
||||
"C2_5RerankConfig",
|
||||
"KNOWN_STRATEGIES",
|
||||
]
|
||||
|
||||
KNOWN_STRATEGIES: Final[frozenset[str]] = frozenset({"inlier_count"})
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class C2_5RerankConfig:
|
||||
"""Per-component config for C2.5 ReRank.
|
||||
|
||||
``strategy`` selects exactly one of the registered re-rankers
|
||||
(today only ``inlier_count``); the composition-root factory
|
||||
respects compile-time ``BUILD_RERANK_<variant>`` gating on top
|
||||
of this label.
|
||||
|
||||
``top_n`` is the per-frame N cap (1..K-1). Default 3 (the epic's
|
||||
K=10 → N=3 spec).
|
||||
"""
|
||||
|
||||
strategy: str = "inlier_count"
|
||||
top_n: int = 3
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.strategy not in KNOWN_STRATEGIES:
|
||||
raise ConfigError(
|
||||
f"C2_5RerankConfig.strategy={self.strategy!r} not in "
|
||||
f"{sorted(KNOWN_STRATEGIES)}"
|
||||
)
|
||||
if self.top_n < 1:
|
||||
raise ConfigError(
|
||||
f"C2_5RerankConfig.top_n must be >= 1; got {self.top_n}"
|
||||
)
|
||||
Reference in New Issue
Block a user