@@ -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 {
7582func (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