core/language_packs/evidence.py
Shay a45eab1fe3
fix(epistemic): Phase 2 known bug repairs (#219)
* fix(epistemic): make empty resonance evidence undetermined

* fix(evals): classify verified realizer failures separately

* fix(packs): treat absent domain manifests as valid noop

* test(packs): cover missing manifests and scope boundary domains

* test(epistemic): cover phase 2 known bug fixes

* fix(vault): make FALSIFIED exclusion explicit in _status_admits

FALSIFIED entries previously fell through to the ADMISSIBLE_AS_EVIDENCE
set-check, which excluded them correctly but left the distinction between
CONTRADICTED (FALSIFIED) and UNVERIFIED-POSSIBLE (SPECULATIVE) implicit.
Add an early guard so FALSIFIED is explicitly rejected before the tier
filter, matching the CONTRADICTED semantics from the epistemic taxonomy.
2026-05-24 11:20:32 -07:00

64 lines
1.8 KiB
Python

"""Measured holonomy-resonance evidence helpers for ADR-0015."""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from algebra.cga import cga_inner
from algebra.holonomy import holonomy_encode
UNDETERMINED_SCORE: float = float("nan")
"""Numeric sentinel for evidence that could not be computed.
An empty evidence-pair set is not neutral evidence. Returning ``0.0``
made "no evidence" indistinguishable from a real measured zero. ``NaN``
keeps the return type stable while forcing callers to treat the score as
UNDETERMINED rather than as weak/negative evidence.
"""
@dataclass(frozen=True, slots=True)
class ResonanceEvidence:
case_id: str
aligned_score: float
contrast_score: float
@property
def passes(self) -> bool:
if not np.isfinite(self.aligned_score) or not np.isfinite(self.contrast_score):
return False
return self.aligned_score > self.contrast_score
def encode_clause(manifold, tokens: tuple[str, ...] | list[str]) -> np.ndarray:
return holonomy_encode([manifold.get_versor(token) for token in tokens])
def mean_pair_score(manifold, pairs: tuple[tuple[str, str], ...]) -> float:
if not pairs:
return UNDETERMINED_SCORE
return float(
np.mean(
[
cga_inner(manifold.get_versor(left), manifold.get_versor(right))
for left, right in pairs
]
)
)
def resonance_evidence(
*,
case_id: str,
manifold,
aligned_pairs: tuple[tuple[str, str], ...],
contrast_pairs: tuple[tuple[str, str], ...],
) -> ResonanceEvidence:
return ResonanceEvidence(
case_id=case_id,
aligned_score=mean_pair_score(manifold, aligned_pairs),
contrast_score=mean_pair_score(manifold, contrast_pairs),
)