From ed67fd7ba904dd52a13b3bf27e3d2dcfa6c7d48d Mon Sep 17 00:00:00 2001 From: Mikhail Date: Fri, 21 Aug 2026 01:19:10 +0300 Subject: [PATCH] fix: validate cognitive interpretation boundary --- cmd/cognitive-worker/interpretation.go | 27 +++++++++++++++++ cmd/cognitive-worker/interpretation_test.go | 33 +++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 cmd/cognitive-worker/interpretation_test.go diff --git a/cmd/cognitive-worker/interpretation.go b/cmd/cognitive-worker/interpretation.go index 4c01924..c3d814c 100644 --- a/cmd/cognitive-worker/interpretation.go +++ b/cmd/cognitive-worker/interpretation.go @@ -112,6 +112,9 @@ func parseInterpretationCandidate(text string) (cognitive.GatewayInterpretationC if candidate.SecondarySpeechAct != "" && !validSpeechAct(candidate.SecondarySpeechAct) { return cognitive.GatewayInterpretationCandidate{}, false } + if candidate.SecondarySpeechAct == "" { + candidate.SecondarySpeechAct = "UNKNOWN" + } switch candidate.Applicability { case cognitive.InterpretationApplicable, cognitive.InterpretationLowConfidence, cognitive.InterpretationMixedIntent, cognitive.InterpretationNeedsBroader, cognitive.InterpretationClarificationRequired: default: @@ -120,6 +123,11 @@ func parseInterpretationCandidate(text string) (cognitive.GatewayInterpretationC if candidate.Clarification != "NOT_REQUIRED" && candidate.Clarification != "REQUIRED" { return cognitive.GatewayInterpretationCandidate{}, false } + for _, hint := range candidate.CapabilityHints { + if !validCapabilityKind(hint) { + return cognitive.GatewayInterpretationCandidate{}, false + } + } return candidate, true } @@ -131,6 +139,25 @@ func validSpeechAct(value string) bool { return false } +func validCapabilityKind(value capability.CapabilityKind) bool { + switch value { + case capability.CapabilityKindReadEmail, + capability.CapabilityKindSendEmail, + capability.CapabilityKindReadDatabase, + capability.CapabilityKindQueryLogs, + capability.CapabilityKindInspectProject, + capability.CapabilityKindModifyCode, + capability.CapabilityKindRunTests, + capability.CapabilityKindWebResearch, + capability.CapabilityKindCognitiveReasoning, + capability.CapabilityKindScheduleReminder, + capability.CapabilityKindVerifyFact: + return true + default: + return false + } +} + func writeInterpretationResponse(w http.ResponseWriter, response cognitive.GatewayInterpretationResponse) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(response) diff --git a/cmd/cognitive-worker/interpretation_test.go b/cmd/cognitive-worker/interpretation_test.go new file mode 100644 index 0000000..ab36ba8 --- /dev/null +++ b/cmd/cognitive-worker/interpretation_test.go @@ -0,0 +1,33 @@ +package main + +import ( + "testing" + + "git.cin.su/m/Assistant/contracts/capability" +) + +func TestParseInterpretationCandidateNormalizesOmittedSecondarySpeechAct(t *testing.T) { + candidate, ok := parseInterpretationCandidate(`{"primary_speech_act":"QUESTION","confidence_millis":800,"applicability":"APPLICABLE","clarification":"NOT_REQUIRED"}`) + if !ok { + t.Fatal("expected valid candidate") + } + if candidate.SecondarySpeechAct != "UNKNOWN" { + t.Fatalf("expected omitted secondary speech act to normalize to UNKNOWN, got %q", candidate.SecondarySpeechAct) + } +} + +func TestParseInterpretationCandidateRejectsUnknownCapabilityHint(t *testing.T) { + _, ok := parseInterpretationCandidate(`{"primary_speech_act":"QUESTION","confidence_millis":800,"applicability":"APPLICABLE","clarification":"NOT_REQUIRED","capability_hints":["INVENTED_CAPABILITY"]}`) + if ok { + t.Fatal("expected unknown capability hint to be rejected") + } +} + +func TestValidCapabilityKindMatchesContractEnum(t *testing.T) { + if !validCapabilityKind(capability.CapabilityKindCognitiveReasoning) { + t.Fatal("expected cognitive reasoning capability to be valid") + } + if validCapabilityKind(capability.CapabilityKind("INVENTED_CAPABILITY")) { + t.Fatal("invented capability must be invalid") + } +}