* 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.
64 lines
1.8 KiB
Python
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),
|
|
)
|