Harden diagnostic handling and warning presentation

This commit is contained in:
2026-08-27 18:41:59 +00:00
parent 1025001f20
commit 079d5af337
67 changed files with 518 additions and 318 deletions

View File

@@ -126,6 +126,9 @@ func (candidate ModelCandidate) Validate() error {
}
func ValidateValidationResult(result ValidationResult) error {
if err := ValidateProducerDiagnostics(result.Diagnostics); err != nil {
return fmt.Errorf("validation diagnostics: %w", err)
}
if !result.Approved && result.ReasonCode == "" {
return errors.New("validation rejection reason code must not be empty")
}

View File

@@ -75,6 +75,9 @@ func TestCorrectionContractsRejectInvalidContent(t *testing.T) {
{"oversized correction guidance", func() error {
return ValidateValidationResult(ValidationResult{ReasonCode: "invalid", CorrectionGuidance: tooLongValidationGuidance})
}},
{"invalid diagnostics", func() error {
return ValidateValidationResult(ValidationResult{Approved: true, Diagnostics: []ProducerDiagnostic{{}}})
}},
} {
t.Run(test.name, func(t *testing.T) {
if err := test.call(); err == nil {

View File

@@ -102,6 +102,16 @@ type DiagnosticCollection struct {
UnrepresentedOccurrenceCount int `json:"unrepresented_occurrence_count"`
}
// DiagnosticProjection is the validated warning/non-warning view used by
// durable and presentation boundaries. Occurrence totals are checked before
// they leave the framework contract.
type DiagnosticProjection struct {
Warnings []DiagnosticGroup
Diagnostics []DiagnosticGroup
WarningOccurrenceCount int
DiagnosticOccurrenceCount int
}
// Validate checks a producer-local diagnostic against the public safety and
// classification contract.
func (diagnostic ProducerDiagnostic) Validate() error {
@@ -192,6 +202,41 @@ func (collection DiagnosticCollection) Validate() error {
return nil
}
// ProjectDiagnosticCollection validates, partitions, and totals one finalized
// collection. Unrepresented occurrences belong to the non-warning projection.
func ProjectDiagnosticCollection(collection DiagnosticCollection) (DiagnosticProjection, error) {
if err := collection.Validate(); err != nil {
return DiagnosticProjection{}, err
}
projection := DiagnosticProjection{
Warnings: make([]DiagnosticGroup, 0),
Diagnostics: make([]DiagnosticGroup, 0),
}
for _, group := range collection.Groups {
if group.Disposition == DiagnosticDispositionWarning {
count, err := addDiagnosticOccurrences(projection.WarningOccurrenceCount, group.OccurrenceCount)
if err != nil {
return DiagnosticProjection{}, fmt.Errorf("warning occurrences: %w", err)
}
projection.WarningOccurrenceCount = count
projection.Warnings = append(projection.Warnings, cloneDiagnosticGroup(group))
continue
}
count, err := addDiagnosticOccurrences(projection.DiagnosticOccurrenceCount, group.OccurrenceCount)
if err != nil {
return DiagnosticProjection{}, fmt.Errorf("diagnostic occurrences: %w", err)
}
projection.DiagnosticOccurrenceCount = count
projection.Diagnostics = append(projection.Diagnostics, cloneDiagnosticGroup(group))
}
count, err := addDiagnosticOccurrences(projection.DiagnosticOccurrenceCount, collection.UnrepresentedOccurrenceCount)
if err != nil {
return DiagnosticProjection{}, fmt.Errorf("diagnostic occurrences: %w", err)
}
projection.DiagnosticOccurrenceCount = count
return projection, nil
}
// CloneProducerDiagnostics returns independent diagnostic slice ownership.
func CloneProducerDiagnostics(diagnostics []ProducerDiagnostic) []ProducerDiagnostic {
if len(diagnostics) == 0 {
@@ -305,6 +350,13 @@ func cloneDiagnosticGroup(group DiagnosticGroup) DiagnosticGroup {
return group
}
func addDiagnosticOccurrences(current, incoming int) (int, error) {
if incoming > int(^uint(0)>>1)-current {
return 0, errors.New("occurrence count overflow")
}
return current + incoming, nil
}
func cloneDiagnosticSamples(samples []DiagnosticSample) []DiagnosticSample {
if len(samples) == 0 {
return nil

View File

@@ -146,6 +146,47 @@ func TestCloneDiagnosticCollectionOwnsGroupsAndChunkIndex(t *testing.T) {
}
}
func TestProjectDiagnosticCollectionPartitionsAndChecksTotals(t *testing.T) {
warning := validDiagnosticGroup(DiagnosticDispositionWarning, DiagnosticCategoryFallback, "fallback", 2)
diagnostic := validDiagnosticGroup(DiagnosticDispositionAdvisory, DiagnosticCategoryDataQuality, "quality", 3)
collection := DiagnosticCollection{
Groups: []DiagnosticGroup{warning, diagnostic},
Truncated: true,
UnrepresentedOccurrenceCount: 4,
}
projection, err := ProjectDiagnosticCollection(collection)
if err != nil {
t.Fatal(err)
}
if len(projection.Warnings) != 1 || len(projection.Diagnostics) != 1 || projection.WarningOccurrenceCount != 2 || projection.DiagnosticOccurrenceCount != 7 {
t.Fatalf("projection = %#v, want partitioned exact totals", projection)
}
collection.Groups[0].Samples[0].Message = "mutated"
if projection.Warnings[0].Samples[0].Message != "message" {
t.Fatal("projection retained caller-owned sample storage")
}
overflow := DiagnosticCollection{Groups: []DiagnosticGroup{
validDiagnosticGroup(DiagnosticDispositionWarning, DiagnosticCategoryFallback, "first", int(^uint(0)>>1)),
validDiagnosticGroup(DiagnosticDispositionWarning, DiagnosticCategoryFallback, "second", 1),
}}
if _, err := ProjectDiagnosticCollection(overflow); err == nil {
t.Fatal("ProjectDiagnosticCollection() overflow error = nil")
}
}
func validDiagnosticGroup(disposition DiagnosticDisposition, category DiagnosticCategory, reason string, occurrences int) DiagnosticGroup {
return DiagnosticGroup{
Disposition: disposition,
Category: category,
ReasonCode: reason,
Origin: DiagnosticOrigin{Stage: DiagnosticOriginStageNormalize, StepID: "step", LaneID: "lane", ModuleKey: "module"},
OccurrenceCount: occurrences,
Samples: []DiagnosticSample{{Scope: "scope", Message: "message"}},
OmittedSampleCount: occurrences - 1,
}
}
func validProducerDiagnostic() ProducerDiagnostic {
return ProducerDiagnostic{
Disposition: DiagnosticDispositionWarning,