package ucca import ( "strings" "unicode" ) // TermResolution is the E2 (Term Resolution) signal in the Advisor Reasoning Stack. // Expanded drives retrieval internally (unambiguous abbreviations are spelled out so // the embedding/concept layer finds them). Ambiguous is surfaced to the FE, which // resolves it via chat context (E1) or asks the user ("Meinst du X oder Y?"). The // lexicon NEVER auto-maps an ambiguous abbreviation (e.g. DSE) — real-life discipline. type TermResolution struct { Expanded string `json:"-"` Ambiguous []TermAmbiguity `json:"ambiguous,omitempty"` } // TermAmbiguity flags one abbreviation the SDK could not resolve deterministically. type TermAmbiguity struct { Abbreviation string `json:"abbreviation"` Candidates []string `json:"candidates"` } // abbreviationLexicon maps a (lowercased) abbreviation to its canonical term(s). // >1 candidate = ambiguous → flagged, not expanded. Start small (User-Spec). var abbreviationLexicon = map[string][]string{ "dse": {"Datenschutzerklärung", "Datenschutz-Folgenabschätzung"}, // ambiguous — context wins, else ask "dsfa": {"Datenschutz-Folgenabschätzung"}, "tom": {"technische und organisatorische Maßnahmen"}, "vvt": {"Verzeichnis von Verarbeitungstätigkeiten"}, "avv": {"Auftragsverarbeitungsvertrag"}, "dsb": {"Datenschutzbeauftragter"}, "dpa": {"Data Processing Agreement", "Datenschutzaufsichtsbehörde"}, // ambiguous } // ResolveAbbreviations expands unambiguous abbreviations into the query and flags // ambiguous ones. Deterministic: iterates query tokens in order (no map-order // dependence). Whole-word match (case-insensitive) so "TOM" hits but "atom" does not. func ResolveAbbreviations(query string) TermResolution { tr := TermResolution{Expanded: query} words := strings.FieldsFunc(query, func(r rune) bool { return !unicode.IsLetter(r) && !unicode.IsNumber(r) }) seen := map[string]bool{} var expansions []string for _, w := range words { lw := strings.ToLower(w) cands, ok := abbreviationLexicon[lw] if !ok || seen[lw] { continue } seen[lw] = true if len(cands) == 1 { expansions = append(expansions, cands[0]) } else { tr.Ambiguous = append(tr.Ambiguous, TermAmbiguity{ Abbreviation: strings.ToUpper(lw), Candidates: cands, }) } } if len(expansions) > 0 { tr.Expanded = query + " " + strings.Join(expansions, " ") } return tr }