MnemoCore / tests /test_confidence.py
Granis87's picture
Upload folder using huggingface_hub
c3a3710 verified
"""
Tests for Phase 5.0 Confidence Calibration Module.
Tests ConfidenceEnvelopeGenerator for all confidence levels and edge cases.
"""
import pytest
from datetime import datetime, timezone, timedelta
from unittest.mock import MagicMock
from mnemocore.core.confidence import (
ConfidenceEnvelopeGenerator,
build_confidence_envelope,
LEVEL_HIGH,
LEVEL_MEDIUM,
LEVEL_LOW,
LEVEL_CONTRADICTED,
LEVEL_STALE,
)
from mnemocore.core.provenance import ProvenanceRecord
# ------------------------------------------------------------------ #
# Helpers #
# ------------------------------------------------------------------ #
def _make_node(
ltp_strength: float = 0.9,
access_count: int = 10,
days_old: float = 5.0,
bayes_mean: float | None = None,
):
"""Create a minimal mock MemoryNode."""
node = MagicMock()
node.ltp_strength = ltp_strength
node.access_count = access_count
now = datetime.now(timezone.utc)
node.last_accessed = now - timedelta(days=days_old)
# Optionally inject a Bayesian state mock
if bayes_mean is not None:
bayes = MagicMock()
bayes.mean = bayes_mean
node._bayes = bayes
else:
# Remove _bayes attribute so hasattr returns False
del node._bayes
return node
# ------------------------------------------------------------------ #
# ConfidenceEnvelopeGenerator #
# ------------------------------------------------------------------ #
class TestConfidenceEnvelopeGenerator:
def test_high_confidence(self):
node = _make_node(ltp_strength=0.92, access_count=8, days_old=3)
prov = ProvenanceRecord.new(origin_type="observation")
env = ConfidenceEnvelopeGenerator.build(node, prov)
assert env["level"] == LEVEL_HIGH
assert env["reliability"] >= 0.80
def test_medium_confidence_low_reliability(self):
node = _make_node(ltp_strength=0.65, access_count=3, days_old=5)
env = ConfidenceEnvelopeGenerator.build(node)
assert env["level"] == LEVEL_MEDIUM
def test_low_confidence_insufficient_access(self):
node = _make_node(ltp_strength=0.75, access_count=1, days_old=2)
env = ConfidenceEnvelopeGenerator.build(node)
assert env["level"] == LEVEL_LOW
def test_low_confidence_poor_reliability(self):
node = _make_node(ltp_strength=0.35, access_count=10, days_old=2)
env = ConfidenceEnvelopeGenerator.build(node)
assert env["level"] == LEVEL_LOW
def test_stale_overrides_high_reliability(self):
"""A memory last verified 40 days ago should be STALE even if reliable."""
node = _make_node(ltp_strength=0.98, access_count=20, days_old=40)
env = ConfidenceEnvelopeGenerator.build(node)
assert env["level"] == LEVEL_STALE
assert env["staleness_days"] >= 30
def test_contradicted_overrides_everything(self):
"""Contradicted memories take priority over any reliability score."""
node = _make_node(ltp_strength=0.99, access_count=100, days_old=1)
prov = ProvenanceRecord.new(origin_type="observation")
prov.mark_contradicted("cg_999")
env = ConfidenceEnvelopeGenerator.build(node, prov)
assert env["level"] == LEVEL_CONTRADICTED
assert env["is_contradicted"] is True
def test_source_type_observation(self):
node = _make_node(ltp_strength=0.9, access_count=6)
prov = ProvenanceRecord.new(origin_type="observation")
env = ConfidenceEnvelopeGenerator.build(node, prov)
assert env["source_type"] == "observation"
assert env["source_trust"] == 1.0
def test_source_type_dream_lower_trust(self):
node = _make_node(ltp_strength=0.9, access_count=6)
prov = ProvenanceRecord.new(origin_type="dream")
env = ConfidenceEnvelopeGenerator.build(node, prov)
assert env["source_type"] == "dream"
# Dream trust is 0.6, should not reach HIGH level
assert env["level"] != LEVEL_HIGH
def test_verified_event_resets_staleness(self):
"""A fresh verification event should make staleness very short."""
node = _make_node(ltp_strength=0.9, access_count=8, days_old=50)
prov = ProvenanceRecord.new(origin_type="observation")
prov.mark_verified(success=True)
env = ConfidenceEnvelopeGenerator.build(node, prov)
# Verified just now → staleness should be near 0
assert env["staleness_days"] < 1.0
assert env["level"] != LEVEL_STALE
def test_bayesian_state_used_over_ltp(self):
"""If node has _bayes, reliability = bayes.mean, not ltp_strength."""
node = _make_node(ltp_strength=0.3, access_count=6, bayes_mean=0.95)
env = ConfidenceEnvelopeGenerator.build(node)
assert env["reliability"] == pytest.approx(0.95, abs=0.01)
def test_no_provenance_uses_last_accessed(self):
node = _make_node(ltp_strength=0.85, access_count=7, days_old=5)
env = ConfidenceEnvelopeGenerator.build(node, provenance=None)
assert env["source_type"] == "unknown"
assert "level" in env
def test_envelope_keys_present(self):
node = _make_node()
env = build_confidence_envelope(node)
expected_keys = {
"level", "reliability", "access_count",
"staleness_days", "source_type", "source_trust", "is_contradicted",
}
assert expected_keys.issubset(env.keys())
def test_module_shortcut_same_result(self):
node = _make_node(ltp_strength=0.88, access_count=6)
prov = ProvenanceRecord.new()
r1 = ConfidenceEnvelopeGenerator.build(node, prov)
r2 = build_confidence_envelope(node, prov)
assert r1["level"] == r2["level"]
assert r1["reliability"] == r2["reliability"]