feat: add learner memory ingestion
This commit is contained in:
@@ -62,6 +62,7 @@ func (StubRunner) GradeInterviewAnswer(_ context.Context, input GradeAnswerInput
|
||||
}
|
||||
|
||||
grade := GradedAnswer{
|
||||
UserID: input.UserID,
|
||||
AnswerID: input.AnswerID,
|
||||
QuestionID: input.QuestionID,
|
||||
Concepts: append([]ConceptRef(nil), input.Concepts...),
|
||||
@@ -96,8 +97,65 @@ func (StubRunner) GradeInterviewAnswer(_ context.Context, input GradeAnswerInput
|
||||
return grade, nil
|
||||
}
|
||||
|
||||
func (StubRunner) ExtractLearningMemory(context.Context, GradedAnswer) (MemoryUpdateCandidate, error) {
|
||||
return MemoryUpdateCandidate{}, ErrNotImplemented
|
||||
func (StubRunner) ExtractLearningMemory(_ context.Context, grade GradedAnswer) (MemoryUpdateCandidate, error) {
|
||||
candidate := MemoryUpdateCandidate{
|
||||
UserID: grade.UserID,
|
||||
SourceAnswerID: grade.AnswerID,
|
||||
Updates: []MemoryUpdate{},
|
||||
}
|
||||
if len(grade.Evidence) == 0 {
|
||||
return candidate, nil
|
||||
}
|
||||
|
||||
state := readinessFromOverall(grade.Overall)
|
||||
durability := DurabilityTentative
|
||||
if grade.Overall == AnswerStrong {
|
||||
durability = DurabilityConfirmed
|
||||
}
|
||||
|
||||
for _, concept := range grade.Concepts {
|
||||
candidate.Updates = append(candidate.Updates, MemoryUpdate{
|
||||
Kind: MemoryConceptMastery,
|
||||
Concept: concept,
|
||||
ProposedState: state,
|
||||
Summary: "Concept readiness updated from diagnostic interview answer.",
|
||||
Evidence: append([]EvidenceRef(nil), grade.Evidence...),
|
||||
Confidence: confidenceFromOverall(grade.Overall),
|
||||
Durability: durability,
|
||||
})
|
||||
if grade.FollowUp.Needed {
|
||||
candidate.Updates = append(candidate.Updates,
|
||||
MemoryUpdate{
|
||||
Kind: MemoryMisconception,
|
||||
Concept: concept,
|
||||
ProposedState: ReadinessFragile,
|
||||
Summary: "Needs more concrete reasoning and tradeoff discussion.",
|
||||
Evidence: append([]EvidenceRef(nil), grade.Evidence...),
|
||||
Confidence: 0.62,
|
||||
Durability: DurabilityTentative,
|
||||
},
|
||||
MemoryUpdate{
|
||||
Kind: MemoryIntervention,
|
||||
Concept: concept,
|
||||
ProposedState: state,
|
||||
Summary: grade.FollowUp.Question,
|
||||
Evidence: append([]EvidenceRef(nil), grade.Evidence...),
|
||||
Confidence: 0.7,
|
||||
Durability: DurabilityTentative,
|
||||
},
|
||||
MemoryUpdate{
|
||||
Kind: MemoryReviewSchedule,
|
||||
Concept: concept,
|
||||
ProposedState: state,
|
||||
Summary: "Review with a concrete production example before raising difficulty.",
|
||||
Evidence: append([]EvidenceRef(nil), grade.Evidence...),
|
||||
Confidence: 0.7,
|
||||
Durability: DurabilityTentative,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
return candidate, nil
|
||||
}
|
||||
|
||||
func (StubRunner) SelectNextChallenge(context.Context, NextChallengeInput) (NextChallenge, error) {
|
||||
@@ -117,3 +175,33 @@ func scoreFromWords(wordCount int, target int) int {
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func readinessFromOverall(overall AnswerOverall) ReadinessState {
|
||||
switch overall {
|
||||
case AnswerMiss:
|
||||
return ReadinessFragile
|
||||
case AnswerPartial:
|
||||
return ReadinessImproving
|
||||
case AnswerSolid:
|
||||
return ReadinessInterviewReady
|
||||
case AnswerStrong:
|
||||
return ReadinessStrongSignal
|
||||
default:
|
||||
return ReadinessUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func confidenceFromOverall(overall AnswerOverall) float64 {
|
||||
switch overall {
|
||||
case AnswerMiss:
|
||||
return 0.58
|
||||
case AnswerPartial:
|
||||
return 0.68
|
||||
case AnswerSolid:
|
||||
return 0.82
|
||||
case AnswerStrong:
|
||||
return 0.9
|
||||
default:
|
||||
return 0.5
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user