refactor(go/ucca): split policy_engine, legal_rag, ai_act, nis2, financial_policy, dsgvo_module

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>
This commit is contained in:
Sharang Parnerkar
2026-04-19 09:48:41 +02:00
parent e0b3c54212
commit c293d76e6b
23 changed files with 3089 additions and 3415 deletions

View File

@@ -13,135 +13,14 @@ import (
// Financial Regulations Policy Engine
// ============================================================================
//
// This engine evaluates financial use-cases against DORA, MaRisk, and BAIT rules.
// It extends the base PolicyEngine with financial-specific logic.
// Evaluates financial use-cases against DORA, MaRisk, and BAIT rules.
//
// Key regulations:
// - DORA (Digital Operational Resilience Act) - EU 2022/2554
// - MaRisk (Mindestanforderungen an das Risikomanagement) - BaFin
// - BAIT (Bankaufsichtliche Anforderungen an die IT) - BaFin
// Split into:
// - financial_policy_types.go — all struct/type definitions and result types
// - financial_policy.go — engine implementation (this file)
//
// ============================================================================
// DefaultFinancialPolicyPath is the default location for the financial policy file
var DefaultFinancialPolicyPath = "policies/financial_regulations_policy.yaml"
// FinancialPolicyConfig represents the financial regulations policy structure
type FinancialPolicyConfig struct {
Metadata FinancialPolicyMetadata `yaml:"metadata"`
ApplicableDomains []string `yaml:"applicable_domains"`
FactsSchema map[string]interface{} `yaml:"facts_schema"`
Controls map[string]FinancialControlDef `yaml:"controls"`
Gaps map[string]FinancialGapDef `yaml:"gaps"`
StopLines map[string]FinancialStopLine `yaml:"stop_lines"`
Rules []FinancialRuleDef `yaml:"rules"`
EscalationTriggers []FinancialEscalationTrigger `yaml:"escalation_triggers"`
}
// FinancialPolicyMetadata contains policy header information
type FinancialPolicyMetadata struct {
Version string `yaml:"version"`
EffectiveDate string `yaml:"effective_date"`
Author string `yaml:"author"`
Jurisdiction string `yaml:"jurisdiction"`
Regulations []FinancialRegulationInfo `yaml:"regulations"`
}
// FinancialRegulationInfo describes a regulation
type FinancialRegulationInfo struct {
Name string `yaml:"name"`
FullName string `yaml:"full_name"`
Reference string `yaml:"reference,omitempty"`
Authority string `yaml:"authority,omitempty"`
Version string `yaml:"version,omitempty"`
Effective string `yaml:"effective,omitempty"`
}
// FinancialControlDef represents a control specific to financial regulations
type FinancialControlDef struct {
ID string `yaml:"id"`
Title string `yaml:"title"`
Category string `yaml:"category"`
DORARef string `yaml:"dora_ref,omitempty"`
MaRiskRef string `yaml:"marisk_ref,omitempty"`
BAITRef string `yaml:"bait_ref,omitempty"`
MiFIDRef string `yaml:"mifid_ref,omitempty"`
GwGRef string `yaml:"gwg_ref,omitempty"`
Description string `yaml:"description"`
WhenApplicable []string `yaml:"when_applicable,omitempty"`
WhatToDo string `yaml:"what_to_do"`
EvidenceNeeded []string `yaml:"evidence_needed,omitempty"`
Effort string `yaml:"effort"`
}
// FinancialGapDef represents a compliance gap
type FinancialGapDef struct {
ID string `yaml:"id"`
Title string `yaml:"title"`
Description string `yaml:"description"`
Severity string `yaml:"severity"`
Escalation string `yaml:"escalation,omitempty"`
When []string `yaml:"when,omitempty"`
Controls []string `yaml:"controls,omitempty"`
LegalRefs []string `yaml:"legal_refs,omitempty"`
}
// FinancialStopLine represents a hard blocker
type FinancialStopLine struct {
ID string `yaml:"id"`
Title string `yaml:"title"`
Description string `yaml:"description"`
Outcome string `yaml:"outcome"`
When []string `yaml:"when,omitempty"`
Message string `yaml:"message"`
}
// FinancialRuleDef represents a rule from the financial policy
type FinancialRuleDef struct {
ID string `yaml:"id"`
Category string `yaml:"category"`
Title string `yaml:"title"`
Description string `yaml:"description"`
Condition FinancialConditionDef `yaml:"condition"`
Effect FinancialEffectDef `yaml:"effect"`
Severity string `yaml:"severity"`
DORARef string `yaml:"dora_ref,omitempty"`
MaRiskRef string `yaml:"marisk_ref,omitempty"`
BAITRef string `yaml:"bait_ref,omitempty"`
MiFIDRef string `yaml:"mifid_ref,omitempty"`
GwGRef string `yaml:"gwg_ref,omitempty"`
Rationale string `yaml:"rationale"`
}
// FinancialConditionDef represents a rule condition
type FinancialConditionDef struct {
Field string `yaml:"field,omitempty"`
Operator string `yaml:"operator,omitempty"`
Value interface{} `yaml:"value,omitempty"`
AllOf []FinancialConditionDef `yaml:"all_of,omitempty"`
AnyOf []FinancialConditionDef `yaml:"any_of,omitempty"`
}
// FinancialEffectDef represents the effect when a rule triggers
type FinancialEffectDef struct {
Feasibility string `yaml:"feasibility,omitempty"`
ControlsAdd []string `yaml:"controls_add,omitempty"`
RiskAdd int `yaml:"risk_add,omitempty"`
Escalation bool `yaml:"escalation,omitempty"`
}
// FinancialEscalationTrigger defines when to escalate
type FinancialEscalationTrigger struct {
ID string `yaml:"id"`
Trigger []string `yaml:"trigger,omitempty"`
Level string `yaml:"level"`
Reason string `yaml:"reason"`
}
// ============================================================================
// Financial Policy Engine Implementation
// ============================================================================
// FinancialPolicyEngine evaluates intakes against financial regulations
type FinancialPolicyEngine struct {
config *FinancialPolicyConfig
@@ -194,13 +73,10 @@ func NewFinancialPolicyEngineFromPath(path string) (*FinancialPolicyEngine, erro
}
// GetPolicyVersion returns the financial policy version
func (e *FinancialPolicyEngine) GetPolicyVersion() string {
return e.config.Metadata.Version
}
func (e *FinancialPolicyEngine) GetPolicyVersion() string { return e.config.Metadata.Version }
// IsApplicable checks if the financial policy applies to the given intake
func (e *FinancialPolicyEngine) IsApplicable(intake *UseCaseIntake) bool {
// Check if domain is in applicable domains
domain := strings.ToLower(string(intake.Domain))
for _, d := range e.config.ApplicableDomains {
if domain == d {
@@ -224,12 +100,10 @@ func (e *FinancialPolicyEngine) Evaluate(intake *UseCaseIntake) *FinancialAssess
PolicyVersion: e.config.Metadata.Version,
}
// If not applicable, return early
if !result.IsApplicable {
return result
}
// Check if financial context is provided
if intake.FinancialContext == nil {
result.MissingContext = true
return result
@@ -239,7 +113,6 @@ func (e *FinancialPolicyEngine) Evaluate(intake *UseCaseIntake) *FinancialAssess
controlSet := make(map[string]bool)
needsEscalation := ""
// Evaluate each rule
for _, rule := range e.config.Rules {
if e.evaluateCondition(&rule.Condition, intake) {
triggered := FinancialTriggeredRule{
@@ -250,31 +123,19 @@ func (e *FinancialPolicyEngine) Evaluate(intake *UseCaseIntake) *FinancialAssess
Severity: parseSeverity(rule.Severity),
ScoreDelta: rule.Effect.RiskAdd,
Rationale: rule.Rationale,
}
// Add regulation references
if rule.DORARef != "" {
triggered.DORARef = rule.DORARef
}
if rule.MaRiskRef != "" {
triggered.MaRiskRef = rule.MaRiskRef
}
if rule.BAITRef != "" {
triggered.BAITRef = rule.BAITRef
}
if rule.MiFIDRef != "" {
triggered.MiFIDRef = rule.MiFIDRef
DORARef: rule.DORARef,
MaRiskRef: rule.MaRiskRef,
BAITRef: rule.BAITRef,
MiFIDRef: rule.MiFIDRef,
}
result.TriggeredRules = append(result.TriggeredRules, triggered)
result.RiskScore += rule.Effect.RiskAdd
// Track severity
if parseSeverity(rule.Severity) == SeverityBLOCK {
hasBlock = true
}
// Override feasibility if specified
if rule.Effect.Feasibility != "" {
switch rule.Effect.Feasibility {
case "NO":
@@ -286,7 +147,6 @@ func (e *FinancialPolicyEngine) Evaluate(intake *UseCaseIntake) *FinancialAssess
}
}
// Collect controls
for _, ctrlID := range rule.Effect.ControlsAdd {
if !controlSet[ctrlID] {
controlSet[ctrlID] = true
@@ -307,14 +167,12 @@ func (e *FinancialPolicyEngine) Evaluate(intake *UseCaseIntake) *FinancialAssess
}
}
// Track escalation
if rule.Effect.Escalation {
needsEscalation = e.determineEscalationLevel(intake)
}
}
}
// Check stop lines
for _, stopLine := range e.config.StopLines {
if e.evaluateStopLineConditions(stopLine.When, intake) {
result.StopLinesHit = append(result.StopLinesHit, FinancialStopLineHit{
@@ -328,7 +186,6 @@ func (e *FinancialPolicyEngine) Evaluate(intake *UseCaseIntake) *FinancialAssess
}
}
// Check gaps
for _, gap := range e.config.Gaps {
if e.evaluateGapConditions(gap.When, intake) {
result.IdentifiedGaps = append(result.IdentifiedGaps, FinancialIdentifiedGap{
@@ -345,23 +202,17 @@ func (e *FinancialPolicyEngine) Evaluate(intake *UseCaseIntake) *FinancialAssess
}
}
// Set final feasibility
if hasBlock {
result.Feasibility = FeasibilityNO
}
// Set escalation level
result.EscalationLevel = needsEscalation
// Generate summary
result.Summary = e.generateSummary(result)
return result
}
// evaluateCondition evaluates a condition against the intake
func (e *FinancialPolicyEngine) evaluateCondition(cond *FinancialConditionDef, intake *UseCaseIntake) bool {
// Handle composite all_of
if len(cond.AllOf) > 0 {
for _, subCond := range cond.AllOf {
if !e.evaluateCondition(&subCond, intake) {
@@ -371,7 +222,6 @@ func (e *FinancialPolicyEngine) evaluateCondition(cond *FinancialConditionDef, i
return true
}
// Handle composite any_of
if len(cond.AnyOf) > 0 {
for _, subCond := range cond.AnyOf {
if e.evaluateCondition(&subCond, intake) {
@@ -381,7 +231,6 @@ func (e *FinancialPolicyEngine) evaluateCondition(cond *FinancialConditionDef, i
return false
}
// Handle simple field condition
if cond.Field != "" {
return e.evaluateFieldCondition(cond.Field, cond.Operator, cond.Value, intake)
}
@@ -389,7 +238,6 @@ func (e *FinancialPolicyEngine) evaluateCondition(cond *FinancialConditionDef, i
return false
}
// evaluateFieldCondition evaluates a single field comparison
func (e *FinancialPolicyEngine) evaluateFieldCondition(field, operator string, value interface{}, intake *UseCaseIntake) bool {
fieldValue := e.getFieldValue(field, intake)
if fieldValue == nil {
@@ -408,7 +256,6 @@ func (e *FinancialPolicyEngine) evaluateFieldCondition(field, operator string, v
}
}
// getFieldValue extracts a field value from the intake
func (e *FinancialPolicyEngine) getFieldValue(field string, intake *UseCaseIntake) interface{} {
parts := strings.Split(field, ".")
if len(parts) == 0 {
@@ -492,7 +339,6 @@ func (e *FinancialPolicyEngine) getAIApplicationValue(field string, ctx *Financi
return nil
}
// compareEquals compares two values for equality
func (e *FinancialPolicyEngine) compareEquals(fieldValue, expected interface{}) bool {
if bv, ok := fieldValue.(bool); ok {
if eb, ok := expected.(bool); ok {
@@ -507,18 +353,15 @@ func (e *FinancialPolicyEngine) compareEquals(fieldValue, expected interface{})
return false
}
// compareIn checks if fieldValue is in a list
func (e *FinancialPolicyEngine) compareIn(fieldValue, expected interface{}) bool {
list, ok := expected.([]interface{})
if !ok {
return false
}
sv, ok := fieldValue.(string)
if !ok {
return false
}
for _, item := range list {
if is, ok := item.(string); ok && strings.EqualFold(is, sv) {
return true
@@ -527,12 +370,10 @@ func (e *FinancialPolicyEngine) compareIn(fieldValue, expected interface{}) bool
return false
}
// evaluateStopLineConditions evaluates stop line conditions
func (e *FinancialPolicyEngine) evaluateStopLineConditions(conditions []string, intake *UseCaseIntake) bool {
if intake.FinancialContext == nil {
return false
}
for _, cond := range conditions {
if !e.parseAndEvaluateSimpleCondition(cond, intake) {
return false
@@ -541,12 +382,10 @@ func (e *FinancialPolicyEngine) evaluateStopLineConditions(conditions []string,
return len(conditions) > 0
}
// evaluateGapConditions evaluates gap conditions
func (e *FinancialPolicyEngine) evaluateGapConditions(conditions []string, intake *UseCaseIntake) bool {
if intake.FinancialContext == nil {
return false
}
for _, cond := range conditions {
if !e.parseAndEvaluateSimpleCondition(cond, intake) {
return false
@@ -555,9 +394,7 @@ func (e *FinancialPolicyEngine) evaluateGapConditions(conditions []string, intak
return len(conditions) > 0
}
// parseAndEvaluateSimpleCondition parses "field == value" style conditions
func (e *FinancialPolicyEngine) parseAndEvaluateSimpleCondition(condition string, intake *UseCaseIntake) bool {
// Parse "field == value" or "field != value"
if strings.Contains(condition, "==") {
parts := strings.SplitN(condition, "==", 2)
if len(parts) != 2 {
@@ -571,7 +408,6 @@ func (e *FinancialPolicyEngine) parseAndEvaluateSimpleCondition(condition string
return false
}
// Handle boolean values
if value == "true" {
if bv, ok := fieldVal.(bool); ok {
return bv
@@ -582,7 +418,6 @@ func (e *FinancialPolicyEngine) parseAndEvaluateSimpleCondition(condition string
}
}
// Handle string values
if sv, ok := fieldVal.(string); ok {
return strings.EqualFold(sv, value)
}
@@ -591,7 +426,6 @@ func (e *FinancialPolicyEngine) parseAndEvaluateSimpleCondition(condition string
return false
}
// determineEscalationLevel determines the appropriate escalation level
func (e *FinancialPolicyEngine) determineEscalationLevel(intake *UseCaseIntake) string {
if intake.FinancialContext == nil {
return ""
@@ -599,15 +433,12 @@ func (e *FinancialPolicyEngine) determineEscalationLevel(intake *UseCaseIntake)
ctx := intake.FinancialContext
// E3: Highest level for critical cases
if ctx.AIApplication.AlgorithmicTrading {
return "E3"
}
if ctx.ICTService.IsCritical && ctx.ICTService.IsOutsourced {
return "E3"
}
// E2: Medium level
if ctx.AIApplication.RiskAssessment || ctx.AIApplication.AffectsCustomerDecisions {
return "E2"
}
@@ -615,7 +446,6 @@ func (e *FinancialPolicyEngine) determineEscalationLevel(intake *UseCaseIntake)
return "E1"
}
// generateSummary creates a human-readable summary
func (e *FinancialPolicyEngine) generateSummary(result *FinancialAssessmentResult) string {
var parts []string
@@ -631,15 +461,12 @@ func (e *FinancialPolicyEngine) generateSummary(result *FinancialAssessmentResul
if len(result.StopLinesHit) > 0 {
parts = append(parts, fmt.Sprintf("%d kritische Stop-Lines wurden ausgelöst.", len(result.StopLinesHit)))
}
if len(result.IdentifiedGaps) > 0 {
parts = append(parts, fmt.Sprintf("%d Compliance-Lücken wurden identifiziert.", len(result.IdentifiedGaps)))
}
if len(result.RequiredControls) > 0 {
parts = append(parts, fmt.Sprintf("%d regulatorische Kontrollen sind erforderlich.", len(result.RequiredControls)))
}
if result.EscalationLevel != "" {
parts = append(parts, fmt.Sprintf("Eskalation auf Stufe %s empfohlen.", result.EscalationLevel))
}
@@ -666,69 +493,3 @@ func (e *FinancialPolicyEngine) GetAllStopLines() map[string]FinancialStopLine {
func (e *FinancialPolicyEngine) GetApplicableDomains() []string {
return e.config.ApplicableDomains
}
// ============================================================================
// Financial Assessment Result Types
// ============================================================================
// FinancialAssessmentResult represents the result of financial regulation evaluation
type FinancialAssessmentResult struct {
IsApplicable bool `json:"is_applicable"`
MissingContext bool `json:"missing_context,omitempty"`
Feasibility Feasibility `json:"feasibility"`
RiskScore int `json:"risk_score"`
TriggeredRules []FinancialTriggeredRule `json:"triggered_rules"`
RequiredControls []FinancialRequiredControl `json:"required_controls"`
IdentifiedGaps []FinancialIdentifiedGap `json:"identified_gaps"`
StopLinesHit []FinancialStopLineHit `json:"stop_lines_hit"`
EscalationLevel string `json:"escalation_level,omitempty"`
Summary string `json:"summary"`
PolicyVersion string `json:"policy_version"`
}
// FinancialTriggeredRule represents a triggered financial regulation rule
type FinancialTriggeredRule struct {
Code string `json:"code"`
Category string `json:"category"`
Title string `json:"title"`
Description string `json:"description"`
Severity Severity `json:"severity"`
ScoreDelta int `json:"score_delta"`
DORARef string `json:"dora_ref,omitempty"`
MaRiskRef string `json:"marisk_ref,omitempty"`
BAITRef string `json:"bait_ref,omitempty"`
MiFIDRef string `json:"mifid_ref,omitempty"`
Rationale string `json:"rationale"`
}
// FinancialRequiredControl represents a required control
type FinancialRequiredControl struct {
ID string `json:"id"`
Title string `json:"title"`
Category string `json:"category"`
Description string `json:"description"`
WhatToDo string `json:"what_to_do"`
EvidenceNeeded []string `json:"evidence_needed,omitempty"`
Effort string `json:"effort"`
DORARef string `json:"dora_ref,omitempty"`
MaRiskRef string `json:"marisk_ref,omitempty"`
BAITRef string `json:"bait_ref,omitempty"`
}
// FinancialIdentifiedGap represents an identified compliance gap
type FinancialIdentifiedGap struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Severity Severity `json:"severity"`
Controls []string `json:"controls,omitempty"`
LegalRefs []string `json:"legal_refs,omitempty"`
}
// FinancialStopLineHit represents a hit stop line
type FinancialStopLineHit struct {
ID string `json:"id"`
Title string `json:"title"`
Message string `json:"message"`
Outcome string `json:"outcome"`
}