Split 6 oversized files (719–882 LOC each) into focused files under 500 LOC: - policy_engine.go → types, loader, eval, gen (4 files) - legal_rag.go → types, client, http, context, scroll (5 files) - ai_act_module.go → module, yaml, obligations (3 files) - nis2_module.go → module, yaml, obligations + shared obligation_yaml_types.go (3+1 files) - financial_policy.go → types, engine (2 files) - dsgvo_module.go → module, yaml, obligations (3 files) All in package ucca, zero exported symbol renames, go test ./internal/ucca/... passes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
131 lines
4.0 KiB
Go
131 lines
4.0 KiB
Go
package ucca
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// generateSummary creates a human-readable summary
|
|
func (e *PolicyEngine) generateSummary(result *AssessmentResult, intake *UseCaseIntake) string {
|
|
var parts []string
|
|
|
|
switch result.Feasibility {
|
|
case FeasibilityYES:
|
|
parts = append(parts, "Der Use Case ist aus DSGVO-Sicht grundsätzlich umsetzbar.")
|
|
case FeasibilityCONDITIONAL:
|
|
parts = append(parts, "Der Use Case ist unter Auflagen umsetzbar.")
|
|
case FeasibilityNO:
|
|
parts = append(parts, "Der Use Case ist in der aktuellen Form nicht DSGVO-konform umsetzbar.")
|
|
}
|
|
|
|
blockCount := 0
|
|
warnCount := 0
|
|
for _, r := range result.TriggeredRules {
|
|
if r.Severity == SeverityBLOCK {
|
|
blockCount++
|
|
} else if r.Severity == SeverityWARN {
|
|
warnCount++
|
|
}
|
|
}
|
|
|
|
if blockCount > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d kritische Regelverletzung(en) identifiziert.", blockCount))
|
|
}
|
|
if warnCount > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d Warnungen erfordern Aufmerksamkeit.", warnCount))
|
|
}
|
|
|
|
if result.DSFARecommended {
|
|
parts = append(parts, "Eine Datenschutz-Folgenabschätzung (DSFA) wird empfohlen.")
|
|
}
|
|
|
|
return strings.Join(parts, " ")
|
|
}
|
|
|
|
// generateRecommendation creates actionable recommendations
|
|
func (e *PolicyEngine) generateRecommendation(result *AssessmentResult, intake *UseCaseIntake) string {
|
|
if result.Feasibility == FeasibilityYES {
|
|
return "Fahren Sie mit der Implementierung fort. Beachten Sie die empfohlenen Architektur-Patterns für optimale DSGVO-Konformität."
|
|
}
|
|
|
|
if result.Feasibility == FeasibilityCONDITIONAL {
|
|
if len(result.RequiredControls) > 0 {
|
|
return fmt.Sprintf("Implementieren Sie die %d erforderlichen Kontrollen vor dem Go-Live. Dokumentieren Sie alle Maßnahmen für den Nachweis der Rechenschaftspflicht (Art. 5 DSGVO).", len(result.RequiredControls))
|
|
}
|
|
return "Prüfen Sie die ausgelösten Warnungen und implementieren Sie entsprechende Schutzmaßnahmen."
|
|
}
|
|
|
|
return "Der Use Case erfordert grundlegende Änderungen. Prüfen Sie die Lösungsvorschläge."
|
|
}
|
|
|
|
// generateAlternative creates alternative approach suggestions
|
|
func (e *PolicyEngine) generateAlternative(result *AssessmentResult, intake *UseCaseIntake, triggeredRules map[string]bool) string {
|
|
var suggestions []string
|
|
|
|
for _, ps := range e.config.ProblemSolutions {
|
|
for _, trigger := range ps.Triggers {
|
|
if triggeredRules[trigger.Rule] {
|
|
if trigger.WithoutControl != "" {
|
|
hasControl := false
|
|
for _, ctrl := range result.RequiredControls {
|
|
if ctrl.ID == trigger.WithoutControl {
|
|
hasControl = true
|
|
break
|
|
}
|
|
}
|
|
if hasControl {
|
|
continue
|
|
}
|
|
}
|
|
if len(ps.Solutions) > 0 {
|
|
sol := ps.Solutions[0]
|
|
suggestions = append(suggestions, fmt.Sprintf("%s: %s", sol.Title, sol.TeamQuestion))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(suggestions) == 0 {
|
|
if intake.ModelUsage.Training && intake.DataTypes.PersonalData {
|
|
suggestions = append(suggestions, "Nutzen Sie nur RAG statt Training mit personenbezogenen Daten")
|
|
}
|
|
if intake.Automation == AutomationFullyAutomated && intake.Outputs.LegalEffects {
|
|
suggestions = append(suggestions, "Implementieren Sie Human-in-the-Loop für Entscheidungen mit rechtlichen Auswirkungen")
|
|
}
|
|
if intake.DataTypes.MinorData && intake.Purpose.EvaluationScoring {
|
|
suggestions = append(suggestions, "Verzichten Sie auf automatisches Scoring von Minderjährigen")
|
|
}
|
|
}
|
|
|
|
if len(suggestions) == 0 {
|
|
return "Überarbeiten Sie den Use Case unter Berücksichtigung der ausgelösten Regeln."
|
|
}
|
|
|
|
return strings.Join(suggestions, " | ")
|
|
}
|
|
|
|
// ============================================================================
|
|
// Helper Functions
|
|
// ============================================================================
|
|
|
|
func parseSeverity(s string) Severity {
|
|
switch strings.ToUpper(s) {
|
|
case "BLOCK":
|
|
return SeverityBLOCK
|
|
case "WARN":
|
|
return SeverityWARN
|
|
default:
|
|
return SeverityINFO
|
|
}
|
|
}
|
|
|
|
func categorizeControl(id string) string {
|
|
technical := map[string]bool{
|
|
"C_ENCRYPTION": true, "C_ACCESS_LOGGING": true,
|
|
}
|
|
if technical[id] {
|
|
return "technical"
|
|
}
|
|
return "organizational"
|
|
}
|