@@ -173,6 +173,34 @@ func ValidScaleTypeValues() []string {
173173 }
174174}
175175
176+ // ValidIntegerScoreValues returns all valid integer score values (1-5).
177+ func ValidIntegerScoreValues () []int {
178+ return []int {1 , 2 , 3 , 4 , 5 }
179+ }
180+
181+ // ValidReasonCodes returns all registered reason codes.
182+ func ValidReasonCodes () []string {
183+ codes := make ([]string , 0 , len (ReasonCodeRegistry ))
184+ for code := range ReasonCodeRegistry {
185+ codes = append (codes , string (code ))
186+ }
187+ return codes
188+ }
189+
190+ // isValidIntegerScore checks if an integer score is valid (1-5).
191+ func isValidIntegerScore (s IntegerScore ) bool {
192+ return s >= 1 && s <= 5
193+ }
194+
195+ // isValidReasonCode checks if a reason code is registered.
196+ func isValidReasonCode (code ReasonCode ) bool {
197+ if code == "" {
198+ return true // Empty is allowed
199+ }
200+ _ , exists := ReasonCodeRegistry [code ]
201+ return exists
202+ }
203+
176204// isValidScore checks if a score value is valid.
177205func isValidScore (s ScoreValue ) bool {
178206 switch s {
@@ -220,6 +248,22 @@ func ValidateReport(r *Rubric) *ValidationResult {
220248 result .addError ("reviewType" , "REQUIRED_FIELD" , "reviewType is required" )
221249 }
222250
251+ // Validate v2 fields
252+ if r .IntScore != 0 && ! isValidIntegerScore (r .IntScore ) {
253+ result .addError ("intScore" , "INVALID_INT_SCORE" ,
254+ fmt .Sprintf ("integer score must be 1-5, got %d" , r .IntScore ))
255+ }
256+ if r .Confidence < 0 || r .Confidence > 1 {
257+ result .addError ("confidence" , "INVALID_CONFIDENCE" ,
258+ fmt .Sprintf ("confidence must be 0.0-1.0, got %.2f" , r .Confidence ))
259+ }
260+ for i , code := range r .Blocking {
261+ if ! isValidReasonCode (code ) {
262+ result .addWarning (fmt .Sprintf ("blocking[%d]" , i ), "UNKNOWN_REASON_CODE" ,
263+ fmt .Sprintf ("unknown reason code %q" , code ))
264+ }
265+ }
266+
223267 // Validate categories
224268 for i , cat := range r .Categories {
225269 path := fmt .Sprintf ("categories[%d]" , i )
@@ -240,6 +284,22 @@ func ValidateReport(r *Rubric) *ValidationResult {
240284 result .addError (path + ".category" , "REQUIRED_FIELD" , "category ID is required" )
241285 }
242286
287+ // Validate v2 fields
288+ if cat .IntScore != 0 && ! isValidIntegerScore (cat .IntScore ) {
289+ result .addError (path + ".intScore" , "INVALID_INT_SCORE" ,
290+ fmt .Sprintf ("integer score must be 1-5, got %d" , cat .IntScore ))
291+ }
292+ if cat .Confidence < 0 || cat .Confidence > 1 {
293+ result .addError (path + ".confidence" , "INVALID_CONFIDENCE" ,
294+ fmt .Sprintf ("confidence must be 0.0-1.0, got %.2f" , cat .Confidence ))
295+ }
296+ for j , code := range cat .ReasonCodes {
297+ if ! isValidReasonCode (code ) {
298+ result .addWarning (fmt .Sprintf ("%s.reasonCodes[%d]" , path , j ), "UNKNOWN_REASON_CODE" ,
299+ fmt .Sprintf ("unknown reason code %q" , code ))
300+ }
301+ }
302+
243303 // Validate findings within category
244304 for j , finding := range cat .Findings {
245305 findingPath := fmt .Sprintf ("%s.findings[%d]" , path , j )
@@ -299,6 +359,12 @@ func validateFinding(f Finding, path string, result *ValidationResult) {
299359 if f .Title == "" {
300360 result .addError (path + ".title" , "REQUIRED_FIELD" , "finding title is required" )
301361 }
362+
363+ // Validate reason code if present
364+ if f .Code != "" && ! isValidReasonCode (f .Code ) {
365+ result .addWarning (path + ".code" , "UNKNOWN_REASON_CODE" ,
366+ fmt .Sprintf ("unknown reason code %q" , f .Code ))
367+ }
302368}
303369
304370// validateCounts verifies that reported counts match actual data.
0 commit comments