Files
Agent-System/internal/archtest/evaluate.go
T
weichenandCursor 312578ccd1 chore(arch): classify production writers and path rules
Replace whole-repo grep with four production-only gates so Goose and tests stop looking like writer debt, and so new SQL, path, or event crossings fail immediately.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:49:54 +00:00

83 lines
2.4 KiB
Go

package archtest
import (
"fmt"
"sort"
"strings"
"time"
)
type Evaluation struct {
Unmatched []Finding
Excepted []Finding
BadExceptions []string
Counts map[string]int
CountRegressed []string
}
func Evaluate(findings []Finding, b *Boundaries, now time.Time) Evaluation {
ev := Evaluation{Counts: map[string]int{}}
used := make([]bool, len(b.Exceptions))
for i, ex := range b.Exceptions {
if err := ex.validate(now); err != nil {
ev.BadExceptions = append(ev.BadExceptions, fmt.Sprintf("exception[%d] %s %s %s: %v", i, ex.Kind, ex.File, ex.Symbol, err))
}
}
for _, f := range findings {
ev.Counts[f.Kind]++
matched := false
for i, ex := range b.Exceptions {
if !ex.matches(f) {
continue
}
if err := ex.validate(now); err != nil {
continue
}
used[i] = true
matched = true
ev.Excepted = append(ev.Excepted, f)
break
}
if !matched {
ev.Unmatched = append(ev.Unmatched, f)
}
}
sort.Slice(ev.Unmatched, func(i, j int) bool { return ev.Unmatched[i].Key() < ev.Unmatched[j].Key() })
sort.Slice(ev.Excepted, func(i, j int) bool { return ev.Excepted[i].Key() < ev.Excepted[j].Key() })
for kind, baseline := range b.BaselineCounts {
if ev.Counts[kind] > baseline {
ev.CountRegressed = append(ev.CountRegressed, fmt.Sprintf("%s: %d > baseline %d", kind, ev.Counts[kind], baseline))
}
}
sort.Strings(ev.CountRegressed)
return ev
}
func (ev Evaluation) Failed() bool {
return len(ev.Unmatched) > 0 || len(ev.BadExceptions) > 0 || len(ev.CountRegressed) > 0
}
func (ev Evaluation) Report() string {
var b strings.Builder
fmt.Fprintf(&b, "archtest findings=%d excepted=%d unmatched=%d\n",
ev.Counts[KindImport]+ev.Counts[KindSQLWrite]+ev.Counts[KindPath]+ev.Counts[KindEvent],
len(ev.Excepted), len(ev.Unmatched))
for _, kind := range []string{KindImport, KindSQLWrite, KindPath, KindEvent} {
fmt.Fprintf(&b, " %s=%d\n", kind, ev.Counts[kind])
}
for _, msg := range ev.BadExceptions {
fmt.Fprintf(&b, "BAD_EXCEPTION %s\n", msg)
}
for _, msg := range ev.CountRegressed {
fmt.Fprintf(&b, "REGRESSION %s\n", msg)
}
for _, f := range ev.Unmatched {
fmt.Fprintf(&b, "NEW %s %s %s %s (%s)\n", f.Kind, f.Package, f.File, f.Symbol, f.Detail)
}
for _, f := range ev.Excepted {
fmt.Fprintf(&b, "BASELINE %s %s %s %s (%s)\n", f.Kind, f.Package, f.File, f.Symbol, f.Detail)
}
return b.String()
}