feat: add learner memory ingestion
This commit is contained in:
91
internal/learnermemory/service_test.go
Normal file
91
internal/learnermemory/service_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package learnermemory
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"tutor/internal/workflows"
|
||||
)
|
||||
|
||||
func TestApplyCandidateIgnoresUpdatesWithoutEvidence(t *testing.T) {
|
||||
service := NewService(NewMemoryStore())
|
||||
if _, err := service.EnsureProfile(ProfileInput{
|
||||
UserID: "user-1",
|
||||
TargetRole: "junior backend developer",
|
||||
Stack: []string{"go"},
|
||||
}); err != nil {
|
||||
t.Fatalf("EnsureProfile error: %v", err)
|
||||
}
|
||||
|
||||
err := service.ApplyCandidate(workflows.MemoryUpdateCandidate{
|
||||
UserID: "user-1",
|
||||
Updates: []workflows.MemoryUpdate{
|
||||
{
|
||||
Kind: workflows.MemoryConceptMastery,
|
||||
Concept: workflows.ConceptRef{ID: "http-idempotency", Label: "HTTP idempotency"},
|
||||
ProposedState: workflows.ReadinessImproving,
|
||||
Summary: "No evidence should not persist.",
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyCandidate error: %v", err)
|
||||
}
|
||||
|
||||
snapshot, err := service.Snapshot("user-1")
|
||||
if err != nil {
|
||||
t.Fatalf("Snapshot error: %v", err)
|
||||
}
|
||||
if len(snapshot.Mastery) != 0 {
|
||||
t.Fatalf("mastery entries = %d, want 0", len(snapshot.Mastery))
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCandidateStoresEvidenceBackedMemory(t *testing.T) {
|
||||
service := NewService(NewMemoryStore())
|
||||
if _, err := service.EnsureProfile(ProfileInput{
|
||||
UserID: "user-1",
|
||||
TargetRole: "junior backend developer",
|
||||
Stack: []string{"go"},
|
||||
}); err != nil {
|
||||
t.Fatalf("EnsureProfile error: %v", err)
|
||||
}
|
||||
|
||||
evidence := []workflows.EvidenceRef{{Kind: workflows.EvidenceAnswer, ID: "answer-1", Confidence: 1}}
|
||||
err := service.ApplyCandidate(workflows.MemoryUpdateCandidate{
|
||||
UserID: "user-1",
|
||||
Updates: []workflows.MemoryUpdate{
|
||||
{
|
||||
Kind: workflows.MemoryConceptMastery,
|
||||
Concept: workflows.ConceptRef{ID: "http-idempotency", Label: "HTTP idempotency"},
|
||||
ProposedState: workflows.ReadinessInterviewReady,
|
||||
Summary: "Evidence-backed concept mastery.",
|
||||
Evidence: evidence,
|
||||
Confidence: 0.8,
|
||||
},
|
||||
{
|
||||
Kind: workflows.MemoryReviewSchedule,
|
||||
Concept: workflows.ConceptRef{ID: "http-idempotency", Label: "HTTP idempotency"},
|
||||
Summary: "Review later.",
|
||||
Evidence: evidence,
|
||||
Confidence: 0.7,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyCandidate error: %v", err)
|
||||
}
|
||||
|
||||
snapshot, err := service.Snapshot("user-1")
|
||||
if err != nil {
|
||||
t.Fatalf("Snapshot error: %v", err)
|
||||
}
|
||||
if len(snapshot.Mastery) != 1 {
|
||||
t.Fatalf("mastery entries = %d, want 1", len(snapshot.Mastery))
|
||||
}
|
||||
if len(snapshot.ReviewSchedule) != 1 {
|
||||
t.Fatalf("review entries = %d, want 1", len(snapshot.ReviewSchedule))
|
||||
}
|
||||
if len(snapshot.Mastery[0].Evidence) != 1 {
|
||||
t.Fatal("expected mastery evidence")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user