package domain import ( "errors" "strings" "git.cin.su/m/Assistant/contracts/epistemics" "git.cin.su/m/Assistant/platform/ids" ) var ErrInvalidExperience = errors.New("invalid experience") var ErrInvalidExpectation = errors.New("invalid expectation") var ErrInvalidReflectionCandidate = errors.New("invalid reflection candidate") func NewSystemExpectation(value epistemics.SystemExpectation) (epistemics.SystemExpectation, error) { if value.ID == "" { id, err := ids.New() if err != nil { return epistemics.SystemExpectation{}, err } value.ID = epistemics.SystemExpectationID(id) } if value.OriginalIntentID == "" || value.SourceUtteranceID == "" || value.ExpectedOutcome == "" || strings.TrimSpace(value.ExpectedEffect) == "" || value.ConfidenceMillis < 0 || value.ConfidenceMillis > 1000 || value.RecordedAtUnixMillis < 1 { return epistemics.SystemExpectation{}, ErrInvalidExpectation } if value.EvidenceBasis == nil { value.EvidenceBasis = []epistemics.EvidenceRef{} } return value, nil } func NewExperienceRecord(value epistemics.ExperienceRecord) (epistemics.ExperienceRecord, error) { if value.ID == "" { id, err := ids.New() if err != nil { return epistemics.ExperienceRecord{}, err } value.ID = epistemics.ExperienceRecordID(id) } if value.SourceKind == "" || value.OriginalIntentID == "" || value.SourceUtteranceID == "" || value.HelpMethod == "" || value.ExpectedOutcome == "" || value.ActualOutcome == "" || value.ConfidenceMillis < 0 || value.ConfidenceMillis > 1000 || value.RecordedAtUnixMillis < 1 { return epistemics.ExperienceRecord{}, ErrInvalidExperience } if value.ContextRefs == nil { value.ContextRefs = []epistemics.ContextRef{} } if value.VerificationEvidence == nil { value.VerificationEvidence = []epistemics.EvidenceRef{} } return value, nil } func ReflectionForExperience(value epistemics.ExperienceRecord) (epistemics.ReflectionCandidate, bool, error) { normalized, err := NewExperienceRecord(value) if err != nil { return epistemics.ReflectionCandidate{}, false, err } value = normalized trigger, ok := reflectionTrigger(value) if !ok { return epistemics.ReflectionCandidate{}, false, nil } id, err := ids.New() if err != nil { return epistemics.ReflectionCandidate{}, false, err } candidate := epistemics.ReflectionCandidate{ ID: epistemics.ReflectionCandidateID(id), Trigger: trigger, State: epistemics.ReflectionCandidateOpen, SourceExperienceID: value.ID, OriginalIntentID: value.OriginalIntentID, SourceUtteranceID: value.SourceUtteranceID, Summary: reflectionSummary(trigger, value), EvidenceRefs: reflectionEvidence(value), RequiresCognition: reflectionNeedsCognition(trigger), RecordedAtUnixMillis: value.RecordedAtUnixMillis, Revision: 1, } if err := ValidateReflectionCandidate(candidate); err != nil { return epistemics.ReflectionCandidate{}, false, err } return candidate, true, nil } func reflectionNeedsCognition(trigger epistemics.ReflectionTriggerKind) bool { switch trigger { case epistemics.ReflectionUserCorrection, epistemics.ReflectionUnexpectedOutcome, epistemics.ReflectionFailure, epistemics.ReflectionLowConfidence, epistemics.ReflectionContradiction, epistemics.ReflectionRepeatedDegradation: return true default: return false } } func ValidateReflectionCandidate(value epistemics.ReflectionCandidate) error { if value.ID == "" || value.Trigger == "" || value.State == "" || value.SourceExperienceID == "" || value.OriginalIntentID == "" || value.SourceUtteranceID == "" || strings.TrimSpace(value.Summary) == "" || value.RecordedAtUnixMillis < 1 || value.Revision < 1 { return ErrInvalidReflectionCandidate } if value.EvidenceRefs == nil { value.EvidenceRefs = []epistemics.EvidenceRef{} } return nil } func FastPathDeclineExperience(intent epistemics.OriginalIntentRef, utterance epistemics.SourceUtteranceRef, skill epistemics.SkillRef, reason string, millis int64) (epistemics.ExperienceRecord, error) { outcome := epistemics.OutcomeNotApplicable switch reason { case string(epistemics.OutcomeLowConfidence): outcome = epistemics.OutcomeLowConfidence case string(epistemics.OutcomeOutOfDistribution): outcome = epistemics.OutcomeOutOfDistribution case string(epistemics.OutcomeConflict): outcome = epistemics.OutcomeConflict case string(epistemics.OutcomeStale): outcome = epistemics.OutcomeStale } return NewExperienceRecord(epistemics.ExperienceRecord{ SourceKind: epistemics.ExperienceSourceInteraction, OriginalIntentID: intent, SourceUtteranceID: utterance, HelpMethod: epistemics.HelpMethodDeterministicFastPath, SkillRef: skill, ExpectedOutcome: epistemics.OutcomeSuccess, ActualOutcome: outcome, OutcomeDetail: "fast path declined and returned to broader reasoning: " + reason, ConfidenceMillis: 1000, RecordedAtUnixMillis: millis, VerificationEvidence: []epistemics.EvidenceRef{"fast-path-decline"}, }) } func reflectionTrigger(value epistemics.ExperienceRecord) (epistemics.ReflectionTriggerKind, bool) { switch value.ActualOutcome { case epistemics.OutcomeUserCorrected: return epistemics.ReflectionUserCorrection, true case epistemics.OutcomeUnexpected: return epistemics.ReflectionUnexpectedOutcome, true case epistemics.OutcomeFailed: return epistemics.ReflectionFailure, true case epistemics.OutcomeLowConfidence: return epistemics.ReflectionLowConfidence, true case epistemics.OutcomeOutOfDistribution, epistemics.OutcomeConflict, epistemics.OutcomeStale: return epistemics.ReflectionSampledAudit, true default: return "", false } } func reflectionSummary(trigger epistemics.ReflectionTriggerKind, value epistemics.ExperienceRecord) string { if value.OutcomeDetail != "" { return string(trigger) + ": " + value.OutcomeDetail } return string(trigger) + " for experience " + string(value.ID) } func reflectionEvidence(value epistemics.ExperienceRecord) []epistemics.EvidenceRef { refs := append([]epistemics.EvidenceRef{}, value.VerificationEvidence...) if value.HumanResponseRef != "" { refs = append(refs, epistemics.EvidenceRef("continuity:human-response:"+value.HumanResponseRef)) } if value.CorrectionUtteranceID != "" { refs = append(refs, epistemics.EvidenceRef("interaction:correction:"+value.CorrectionUtteranceID)) } if value.CapabilityUsageObservationRef != "" { refs = append(refs, epistemics.EvidenceRef("capability:usage:"+value.CapabilityUsageObservationRef)) } if value.CapabilityGapRef != "" { refs = append(refs, epistemics.EvidenceRef("capability:gap:"+value.CapabilityGapRef)) } return refs }