Skip to content

Commit 1dbe78a

Browse files
grokifyclaude
andcommitted
feat(rubric): enhance Finding with Code and Location fields
Add v2 evaluation fields to Finding: - Code: standardized ReasonCode for automated repair workflows - Location: reference to where issue was found (e.g., "REQ-12", "Section 3.2") Add factory functions and fluent setters: - NewFinding() and NewFindingWithCode() constructors - SetCode(), SetLocation(), SetRecommendation(), SetEvidence() - SetOwner(), SetEffort() for workflow integration Add analysis utilities: - GetCodeInfo() returns ReasonCodeInfo from registry - GetRepairPrompt() returns AI repair prompt for automated fixes - CountFindingsByCode() aggregates by reason code - GetBlockingCodes() extracts codes from blocking findings Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fae0a2b commit 1dbe78a

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

rubric/finding.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ type Finding struct {
88
// Category is the evaluation category this relates to.
99
Category string `json:"category"`
1010

11+
// Code is the standardized reason code for this finding.
12+
// Enables automated repair workflows.
13+
Code ReasonCode `json:"code,omitempty"`
14+
1115
// Severity indicates the impact level.
1216
Severity Severity `json:"severity"`
1317

@@ -20,6 +24,9 @@ type Finding struct {
2024
// Recommendation explains how to fix the issue.
2125
Recommendation string `json:"recommendation"`
2226

27+
// Location is a reference to where the issue was found (e.g., "REQ-12", "Section 3.2").
28+
Location string `json:"location,omitempty"`
29+
2330
// Evidence provides specific examples or references.
2431
Evidence string `json:"evidence,omitempty"`
2532

@@ -75,3 +82,110 @@ func (c FindingCounts) BlockingCount() int {
7582
func (c FindingCounts) HasBlocking() bool {
7683
return c.BlockingCount() > 0
7784
}
85+
86+
// NewFinding creates a new finding with the required fields.
87+
func NewFinding(id, category string, severity Severity, title, description string) *Finding {
88+
return &Finding{
89+
ID: id,
90+
Category: category,
91+
Severity: severity,
92+
Title: title,
93+
Description: description,
94+
}
95+
}
96+
97+
// NewFindingWithCode creates a new finding with a reason code.
98+
func NewFindingWithCode(id, category string, code ReasonCode, title, description string) *Finding {
99+
info := GetReasonCodeInfo(code)
100+
severity := SeverityMedium
101+
if info != nil {
102+
severity = info.DefaultSeverity
103+
}
104+
return &Finding{
105+
ID: id,
106+
Category: category,
107+
Code: code,
108+
Severity: severity,
109+
Title: title,
110+
Description: description,
111+
}
112+
}
113+
114+
// SetCode sets the reason code on the finding.
115+
func (f *Finding) SetCode(code ReasonCode) *Finding {
116+
f.Code = code
117+
return f
118+
}
119+
120+
// SetLocation sets the location reference on the finding.
121+
func (f *Finding) SetLocation(location string) *Finding {
122+
f.Location = location
123+
return f
124+
}
125+
126+
// SetRecommendation sets the recommendation on the finding.
127+
func (f *Finding) SetRecommendation(recommendation string) *Finding {
128+
f.Recommendation = recommendation
129+
return f
130+
}
131+
132+
// SetEvidence sets the evidence on the finding.
133+
func (f *Finding) SetEvidence(evidence string) *Finding {
134+
f.Evidence = evidence
135+
return f
136+
}
137+
138+
// SetOwner sets the owner on the finding.
139+
func (f *Finding) SetOwner(owner string) *Finding {
140+
f.Owner = owner
141+
return f
142+
}
143+
144+
// SetEffort sets the effort estimate on the finding.
145+
func (f *Finding) SetEffort(effort string) *Finding {
146+
f.Effort = effort
147+
return f
148+
}
149+
150+
// GetCodeInfo returns the reason code info for this finding's code.
151+
func (f *Finding) GetCodeInfo() *ReasonCodeInfo {
152+
return GetReasonCodeInfo(f.Code)
153+
}
154+
155+
// GetRepairHint returns the repair hint from the reason code registry.
156+
// Deprecated: Use GetRepairPrompt instead.
157+
func (f *Finding) GetRepairHint() string {
158+
return f.GetRepairPrompt()
159+
}
160+
161+
// GetRepairPrompt returns the AI repair prompt from the reason code registry.
162+
func (f *Finding) GetRepairPrompt() string {
163+
if info := f.GetCodeInfo(); info != nil {
164+
return info.RepairPrompt
165+
}
166+
return f.Recommendation
167+
}
168+
169+
// CountFindingsByCode counts findings by reason code.
170+
func CountFindingsByCode(findings []Finding) map[ReasonCode]int {
171+
counts := make(map[ReasonCode]int)
172+
for _, f := range findings {
173+
if f.Code != "" {
174+
counts[f.Code]++
175+
}
176+
}
177+
return counts
178+
}
179+
180+
// GetBlockingCodes returns the reason codes from blocking findings.
181+
func GetBlockingCodes(findings []Finding) []ReasonCode {
182+
var codes []ReasonCode
183+
seen := make(map[ReasonCode]bool)
184+
for _, f := range findings {
185+
if f.IsBlocking() && f.Code != "" && !seen[f.Code] {
186+
codes = append(codes, f.Code)
187+
seen[f.Code] = true
188+
}
189+
}
190+
return codes
191+
}

0 commit comments

Comments
 (0)