Didactopus/tests/test_weighted_evidence.py

85 lines
2.8 KiB
Python

from didactopus.adaptive_engine import LearnerProfile
from didactopus.evidence_engine import (
EvidenceItem,
EvidenceState,
add_evidence_item,
confidence_from_weight,
evidence_weight,
ingest_evidence_bundle,
)
def test_evidence_weighting_by_type_and_recency() -> None:
item = EvidenceItem("c1", "project", 0.9, is_recent=True)
w = evidence_weight(
item,
{"explanation": 1.0, "problem": 1.5, "project": 2.5, "transfer": 2.0},
1.35,
)
assert abs(w - 3.375) < 1e-9
def test_confidence_increases_with_weight() -> None:
assert confidence_from_weight(0.0) == 0.0
assert confidence_from_weight(1.0) < confidence_from_weight(3.0)
def test_weighted_summary_promotes_mastery() -> None:
profile = LearnerProfile(learner_id="u1")
state = ingest_evidence_bundle(
profile,
[
EvidenceItem("c1", "project", 0.9, is_recent=True),
EvidenceItem("c1", "problem", 0.85, is_recent=False),
],
mastery_threshold=0.8,
resurfacing_threshold=0.55,
confidence_threshold=0.75,
type_weights={"explanation": 1.0, "problem": 1.5, "project": 2.5, "transfer": 2.0},
recent_multiplier=1.35,
)
assert "c1" in profile.mastered_concepts
assert state.summary_by_concept["c1"].weighted_mean_score >= 0.8
assert state.summary_by_concept["c1"].confidence >= 0.75
def test_recent_weak_evidence_can_resurface() -> None:
profile = LearnerProfile(learner_id="u1", mastered_concepts={"c1"})
state = ingest_evidence_bundle(
profile,
[
EvidenceItem("c1", "project", 0.3, is_recent=True),
EvidenceItem("c1", "explanation", 0.5, is_recent=True),
],
mastery_threshold=0.8,
resurfacing_threshold=0.55,
confidence_threshold=0.75,
type_weights={"explanation": 1.0, "problem": 1.5, "project": 2.5, "transfer": 2.0},
recent_multiplier=1.35,
)
assert "c1" not in profile.mastered_concepts
assert "c1" in state.resurfaced_concepts
def test_dimension_means_present() -> None:
profile = LearnerProfile(learner_id="u1")
state = ingest_evidence_bundle(
profile,
[
EvidenceItem(
"c1",
"problem",
0.8,
rubric_dimensions={"correctness": 0.9, "clarity": 0.7},
)
],
mastery_threshold=0.8,
resurfacing_threshold=0.55,
confidence_threshold=0.1,
type_weights={"explanation": 1.0, "problem": 1.5, "project": 2.5, "transfer": 2.0},
recent_multiplier=1.35,
)
summary = state.summary_by_concept["c1"]
assert abs(summary.dimension_means["correctness"] - 0.9) < 1e-9
assert abs(summary.dimension_means["clarity"] - 0.7) < 1e-9