"""grounding — the seam for semantic / factual poisoning (BRIEF §7/§10, PLAN §67/§94). Interface only in the stdlib core. :mod:`lexicon` and :mod:`entropy` see *surface* signals — known injection phrasing, obfuscation, invisible carriers. They are structurally blind to **semantic poisoning**: a factually false or subtly biased claim, in clean prose, carrying no suspicious token. Catching that means grounding the content against a source of truth — an embedding classifier, a retrieval check, an LLM judge — which is a model call, and models never live in this core (BRIEF §7: ML detectors are optional, pluggable extras behind the ``[judge]`` extra). So this module ships exactly two things and no detector logic: * :class:`SourceGroundingCheck` — the ``text -> Report`` protocol a ``[judge]`` implementation must satisfy to plug into a pipeline. Its findings then flow through :mod:`disposition` like any other detector's, with no grounding-specific plumbing. * :func:`no_grounding_check` (bound as :data:`DEFAULT_GROUNDING_CHECK`) — the shipped default: a pass-through returning an empty Report. The honest scope note made structural — *semantic poisoning is not solved at the text layer*, and the deterministic core does not pretend to. A pipeline that needs it installs a ``[judge]`` implementation; one that does not gets a safe no-op that never breaks composition. The default returns *no* finding — not an INFO "unchecked" marker — on purpose. An INFO finding would flip every artifact to :attr:`Report.found` and trip the ``quarantine_default`` floor in :mod:`disposition`, quarantining every upload for a check that never ran. The seam stays silent; the honesty lives here in the contract, not in a finding that pollutes the gate. """ from __future__ import annotations from typing import Protocol, runtime_checkable from .report import Report, Source @runtime_checkable class SourceGroundingCheck(Protocol): """A semantic-grounding detector: ``text -> Report`` (BRIEF §7/§10). Structurally identical to the other detectors so its findings compose with :mod:`disposition` unchanged. A conforming ``[judge]`` implementation may be a plain function or a stateful callable (an object holding a model client or a trusted-corpus retriever) — the grounding *source of truth* is the implementation's concern, never a parameter of this seam. Runtime-checkable for a coarse ``isinstance`` structural gate (callable vs not); the intended ``source`` keyword and return type are enforced by a type checker, not at runtime. """ def __call__(self, text: str, *, source: Source = Source.OUTPUT) -> Report: ... def no_grounding_check(text: str, *, source: Source = Source.OUTPUT) -> Report: """The pass-through default (PLAN §94): return an empty :class:`Report`. The stdlib core cannot judge semantics, so it reports nothing rather than guessing. This is deliberate and **not** an assertion that ``text`` is semantically clean — only that no grounding check ran. Install a ``[judge]`` :class:`SourceGroundingCheck` to actually verify factual grounding. """ return Report() DEFAULT_GROUNDING_CHECK: SourceGroundingCheck = no_grounding_check """The grounding check the core ships: :func:`no_grounding_check`. A pipeline rebinds this to a ``[judge]`` :class:`SourceGroundingCheck` when it needs semantic grounding."""