"""C3 ``CrossDomainMatcher`` error taxonomy (AZ-344).

The family is intentionally narrow: a per-candidate failure is the
normal case (drop-and-continue, INV-4) and is signalled via
``MatchResult.candidates_dropped`` — NOT via an exception. An
exception escapes :meth:`CrossDomainMatcher.match` only when EVERY
candidate fails OR every candidate's inlier count falls below
``config.matcher.min_inliers_threshold``; both surface as
:class:`InsufficientInliersError` which is the C5 → VIO-only
fallback trigger per AC-3.5.

:class:`MatcherBackboneError` is raised INSIDE the per-candidate
loop, caught by the strategy, logged ERROR, FDR-stamped, and the
candidate is dropped. It is exposed publicly so the per-candidate
log + FDR taxonomy is observable and so future matchers using a
different backbone can re-raise the same kind.
"""

from __future__ import annotations

__all__ = [
    "InsufficientInliersError",
    "MatcherBackboneError",
    "MatcherError",
]


class MatcherError(Exception):
    """Base class for the C3 matcher error family.

    Caught at the runtime root only when
    :class:`InsufficientInliersError` fires; per-candidate failures
    stay inside the strategy.
    """


class MatcherBackboneError(MatcherError):
    """Per-candidate backbone forward-pass failure.

    CUDA OOM, TRT engine deserialize mismatch. Logged at ERROR; one
    FDR record per occurrence; the offending candidate is dropped
    from the match set; the surrounding :meth:`match` call continues
    with the remaining candidates (INV-4).
    """


class InsufficientInliersError(MatcherError):
    """Zero survivors after the per-candidate loop, OR every
    candidate's inlier count is below
    ``config.matcher.min_inliers_threshold``.

    Logged at ERROR; FDR record ``kind=matcher.insufficient_inliers``
    or ``kind=matcher.all_failed`` (per the trigger). C5 falls back
    to VIO-only with provenance ``visual_propagated`` (AC-3.5).
    """
