internal/rules implements Stufe 2 from the core principle: the LLM extracts facts, this deterministic engine judges them against versioned YAML rules. Facts/Condition/Rule/Finding types, a loader that refuses to load on a missing id/version or a duplicate rule id rather than silently skipping a bad file, and Evaluate() matching facts against rules. Two real rules grounded in verified research (see rules/OPEN.md for the open questions that surfaced along the way): - WK-001: no disclosure at all despite consideration (§ 5a Abs. 4 UWG, § 22 Abs. 1 MStV) - WK-004: disclosure present but hidden behind a "mehr anzeigen" cut (§ 5a Abs. 4 UWG, Leitfaden der Medienanstalten, LG Köln 12.05.2026) The two are deliberately disjoint (WK-004 requires disclosure_present= true) so a post with no disclosure at all doesn't double-fire both rules. Golden suite in testdata/golden/ covers both rules plus two clean cases; it's this suite, not the UI, that's the actual asset per CLAUDE.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
31 lines
725 B
Go
31 lines
725 B
Go
package rules
|
|
|
|
// Finding ist das Ergebnis einer einzelnen zutreffenden Regel.
|
|
type Finding struct {
|
|
RuleID string
|
|
RuleVersion int
|
|
Severity Severity
|
|
Title string
|
|
Fix string
|
|
Sources []string
|
|
}
|
|
|
|
// Evaluate prüft alle Regeln gegen f und liefert ein Finding für jede
|
|
// zutreffende Regel. Reihenfolge folgt der Reihenfolge von rules.
|
|
func Evaluate(rules []Rule, f Facts) []Finding {
|
|
var findings []Finding
|
|
for _, r := range rules {
|
|
if r.Condition.Matches(f) {
|
|
findings = append(findings, Finding{
|
|
RuleID: r.ID,
|
|
RuleVersion: r.Version,
|
|
Severity: r.Severity,
|
|
Title: r.Title,
|
|
Fix: r.Fix,
|
|
Sources: r.Sources,
|
|
})
|
|
}
|
|
}
|
|
return findings
|
|
}
|