Skip to content

Commit 7c288b5

Browse files
grokifyclaude
andcommitted
feat(rubric): add validation for v2 schema fields
Extend ValidateReport() to validate v2 fields: - IntScore: must be in 1-5 range - Confidence: must be 0.0-1.0 - Blocking codes: warn if reason code not in registry - Category IntScore and Confidence validation - Category ReasonCodes validation - Finding Code validation Add helper functions: - ValidIntegerScoreValues() returns [1,2,3,4,5] - ValidReasonCodes() returns all registered codes - isValidIntegerScore() checks 1-5 range - isValidReasonCode() checks registry lookup Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent c455da4 commit 7c288b5

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

rubric/validate.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
177205
func 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

Comments
 (0)