Stufe 1 from the core principle: Client calls the Claude Messages API directly over net/http (no SDK dependency, stays consistent with "Go-Standard-Library wo möglich") and forces tool-use with a strict JSON schema instead of parsing free text. Extract() returns rules.Facts directly rather than an intermediate DTO, since producing exactly that is the point of this stage. Platform is supplied by the caller, never guessed by the model. Every failure mode returns an error instead of a zero-value Facts: network errors, non-200 API responses, a missing tool_use block, and — critically — a gegenleistung value outside the four allowed enum values, which would otherwise get silently coerced into a wrong fact. Tested entirely against an httptest fake server, no real API calls. Building this surfaced a real gap in internal/rules: Evaluate() treated Consideration=="unklar" the same as any other value, i.e. it just produced an empty finding list — indistinguishable from "everything's fine". That contradicts the core principle (uncertain extraction should trigger a user clarification, never a judgment). Evaluate() now returns (findings, needsClarification), with a golden case covering it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
40 lines
1.1 KiB
Go
40 lines
1.1 KiB
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.
|
|
//
|
|
// Ist f.Consideration "unklar", wird KEINE Bewertung abgegeben —
|
|
// needsClarification ist dann true und findings ist immer leer. Das ist
|
|
// Absicht (Kernprinzip): eine unsichere Extraktion erzeugt eine
|
|
// Rückfrage an den Nutzer, niemals eine stille "keine Findings"-
|
|
// Bewertung, die wie "alles in Ordnung" aussähe.
|
|
func Evaluate(rules []Rule, f Facts) (findings []Finding, needsClarification bool) {
|
|
if f.Consideration == ConsiderationUnclear {
|
|
return nil, true
|
|
}
|
|
|
|
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, false
|
|
}
|