package contracts import ( "errors" "fmt" "strings" "unicode/utf8" ) const ( MaxDiagnosticReasonCodeBytes = 128 MaxDiagnosticScopeBytes = 512 MaxDiagnosticMessageBytes = 4 * 1024 MaxDiagnosticSamples = 3 MaxProducerDiagnosticGroups = 64 ) // DiagnosticDisposition identifies the operator significance of a producer // finding. Warnings are reserved for process-level degradation or incomplete // configured work. type DiagnosticDisposition string const ( DiagnosticDispositionWarning DiagnosticDisposition = "warning" DiagnosticDispositionAdvisory DiagnosticDisposition = "advisory" DiagnosticDispositionObservation DiagnosticDisposition = "observation" ) // DiagnosticCategory gives a stable, bounded classification for a producer // finding. type DiagnosticCategory string const ( DiagnosticCategoryConfiguration DiagnosticCategory = "configuration" DiagnosticCategoryDegradation DiagnosticCategory = "degradation" DiagnosticCategoryValidationIncomplete DiagnosticCategory = "validation_incomplete" DiagnosticCategoryFallback DiagnosticCategory = "fallback" DiagnosticCategoryDataQuality DiagnosticCategory = "data_quality" DiagnosticCategoryNormalization DiagnosticCategory = "normalization" ) // DiagnosticOriginStage identifies the framework operation that promoted a // diagnostic. It is framework-owned rather than producer-owned. type DiagnosticOriginStage string const ( DiagnosticOriginStageReferences DiagnosticOriginStage = "references" DiagnosticOriginStageChunk DiagnosticOriginStage = "chunk" DiagnosticOriginStageExtract DiagnosticOriginStage = "extract" DiagnosticOriginStageMerge DiagnosticOriginStage = "merge" DiagnosticOriginStageNormalize DiagnosticOriginStage = "normalize" ) // DiagnosticSample is a bounded, safe example of a diagnostic occurrence. // Chunk identity is attached by the framework when it promotes a producer // diagnostic into a final group. type DiagnosticSample struct { Scope string `json:"scope"` Message string `json:"message"` ChunkID string `json:"chunk_id,omitempty"` ChunkIndex *int `json:"chunk_index,omitempty"` } // ProducerDiagnostic is the locally grouped form returned by one producer or // validator. It intentionally has no pipeline origin. type ProducerDiagnostic struct { Disposition DiagnosticDisposition `json:"disposition"` Category DiagnosticCategory `json:"category"` ReasonCode string `json:"reason_code"` OccurrenceCount int `json:"occurrence_count"` Samples []DiagnosticSample `json:"samples"` OmittedSampleCount int `json:"omitted_sample_count"` } // DiagnosticOrigin is framework-owned context used to distinguish findings // from different pipeline locations during final aggregation. type DiagnosticOrigin struct { Stage DiagnosticOriginStage `json:"stage"` StepID string `json:"step_id,omitempty"` LaneID string `json:"lane_id,omitempty"` ModuleKey string `json:"module_key,omitempty"` ValidatorKey string `json:"validator_key,omitempty"` } // DiagnosticGroup is a producer diagnostic after framework origin enrichment. type DiagnosticGroup struct { Disposition DiagnosticDisposition `json:"disposition"` Category DiagnosticCategory `json:"category"` ReasonCode string `json:"reason_code"` Origin DiagnosticOrigin `json:"origin"` OccurrenceCount int `json:"occurrence_count"` Samples []DiagnosticSample `json:"samples"` OmittedSampleCount int `json:"omitted_sample_count"` } // DiagnosticCollection is the grouped collection supplied to later durable // and presentation boundaries. Global aggregation policy is applied by the // framework before it reaches those boundaries. type DiagnosticCollection struct { Groups []DiagnosticGroup `json:"groups"` Truncated bool `json:"truncated"` 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 { return validateDiagnostic( diagnostic.Disposition, diagnostic.Category, diagnostic.ReasonCode, diagnostic.OccurrenceCount, diagnostic.Samples, diagnostic.OmittedSampleCount, false, ) } // ValidateProducerDiagnostics validates the complete set returned by one // producer or validator result. func ValidateProducerDiagnostics(diagnostics []ProducerDiagnostic) error { if len(diagnostics) > MaxProducerDiagnosticGroups { return errors.New("producer diagnostics exceed maximum group count") } for index, diagnostic := range diagnostics { if err := diagnostic.Validate(); err != nil { return fmt.Errorf("producer diagnostic %d: %w", index, err) } } return nil } // Validate checks framework-owned origin fields. func (origin DiagnosticOrigin) Validate() error { switch origin.Stage { case DiagnosticOriginStageReferences, DiagnosticOriginStageChunk, DiagnosticOriginStageExtract, DiagnosticOriginStageMerge, DiagnosticOriginStageNormalize: default: return errors.New("diagnostic origin stage is invalid") } for _, field := range []struct { name string value string }{ {name: "diagnostic origin step ID", value: origin.StepID}, {name: "diagnostic origin lane ID", value: origin.LaneID}, {name: "diagnostic origin module key", value: origin.ModuleKey}, {name: "diagnostic origin validator key", value: origin.ValidatorKey}, } { if field.value != "" && (!utf8.ValidString(field.value) || strings.TrimSpace(field.value) == "") { return fmt.Errorf("%s must be valid nonblank UTF-8 when present", field.name) } } return nil } // Validate checks a final origin-enriched group. func (group DiagnosticGroup) Validate() error { if err := group.Origin.Validate(); err != nil { return err } return validateDiagnostic( group.Disposition, group.Category, group.ReasonCode, group.OccurrenceCount, group.Samples, group.OmittedSampleCount, true, ) } // Validate checks the collection shape without imposing later global // aggregation limits. func (collection DiagnosticCollection) Validate() error { if collection.UnrepresentedOccurrenceCount < 0 { return errors.New("diagnostic collection unrepresented occurrence count must not be negative") } if !collection.Truncated && collection.UnrepresentedOccurrenceCount != 0 { return errors.New("diagnostic collection has unrepresented occurrences without truncation") } seen := make(map[diagnosticGroupKey]struct{}, len(collection.Groups)) for index, group := range collection.Groups { if err := group.Validate(); err != nil { return fmt.Errorf("diagnostic group %d: %w", index, err) } key := diagnosticGroupKeyFromGroup(group) if _, exists := seen[key]; exists { return errors.New("diagnostic collection contains duplicate group identity") } seen[key] = struct{}{} } 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 { return nil } cloned := make([]ProducerDiagnostic, len(diagnostics)) for index, diagnostic := range diagnostics { cloned[index] = cloneProducerDiagnostic(diagnostic) } return cloned } // CloneDiagnosticCollection returns independent collection ownership. func CloneDiagnosticCollection(collection DiagnosticCollection) DiagnosticCollection { groups := collection.Groups collection.Groups = make([]DiagnosticGroup, len(groups)) for index, group := range groups { collection.Groups[index] = cloneDiagnosticGroup(group) } return collection } func validateDiagnostic(disposition DiagnosticDisposition, category DiagnosticCategory, reasonCode string, occurrenceCount int, samples []DiagnosticSample, omittedSampleCount int, allowChunkContext bool) error { if !diagnosticCategoryAllowed(disposition, category) { return errors.New("diagnostic disposition and category combination is invalid") } if err := validateDiagnosticText(reasonCode, MaxDiagnosticReasonCodeBytes, "diagnostic reason code"); err != nil { return err } if occurrenceCount <= 0 { return errors.New("diagnostic occurrence count must be positive") } if len(samples) == 0 { return errors.New("diagnostic samples must not be empty") } if len(samples) > MaxDiagnosticSamples { return errors.New("diagnostic samples exceed maximum count") } seen := make(map[diagnosticSampleKey]struct{}, len(samples)) for index, sample := range samples { if err := validateDiagnosticSample(sample, allowChunkContext); err != nil { return fmt.Errorf("diagnostic sample %d: %w", index, err) } key := diagnosticSampleKeyFromSample(sample) if _, exists := seen[key]; exists { return errors.New("diagnostic samples must be distinct") } seen[key] = struct{}{} } if occurrenceCount < len(samples) { return errors.New("diagnostic occurrence count is smaller than sample count") } if omittedSampleCount != occurrenceCount-len(samples) { return errors.New("diagnostic omitted sample count is inconsistent") } return nil } func diagnosticCategoryAllowed(disposition DiagnosticDisposition, category DiagnosticCategory) bool { switch disposition { case DiagnosticDispositionWarning: return category == DiagnosticCategoryConfiguration || category == DiagnosticCategoryDegradation || category == DiagnosticCategoryValidationIncomplete || category == DiagnosticCategoryFallback case DiagnosticDispositionAdvisory: return category == DiagnosticCategoryDataQuality case DiagnosticDispositionObservation: return category == DiagnosticCategoryNormalization default: return false } } func validateDiagnosticSample(sample DiagnosticSample, allowChunkContext bool) error { if err := validateDiagnosticText(sample.Scope, MaxDiagnosticScopeBytes, "diagnostic sample scope"); err != nil { return err } if err := validateDiagnosticText(sample.Message, MaxDiagnosticMessageBytes, "diagnostic sample message"); err != nil { return err } if !allowChunkContext && (sample.ChunkID != "" || sample.ChunkIndex != nil) { return errors.New("producer diagnostic sample must not include framework chunk context") } if sample.ChunkID != "" && (!utf8.ValidString(sample.ChunkID) || strings.TrimSpace(sample.ChunkID) == "") { return errors.New("diagnostic sample chunk ID must be valid nonblank UTF-8 when present") } if sample.ChunkIndex != nil && *sample.ChunkIndex < 0 { return errors.New("diagnostic sample chunk index must not be negative") } return nil } func validateDiagnosticText(value string, maximum int, name string) error { if !utf8.ValidString(value) { return fmt.Errorf("%s must be valid UTF-8", name) } if strings.TrimSpace(value) == "" { return fmt.Errorf("%s must not be blank", name) } if len(value) > maximum { return fmt.Errorf("%s exceeds maximum length", name) } return nil } func cloneProducerDiagnostic(diagnostic ProducerDiagnostic) ProducerDiagnostic { diagnostic.Samples = cloneDiagnosticSamples(diagnostic.Samples) return diagnostic } func cloneDiagnosticGroup(group DiagnosticGroup) DiagnosticGroup { group.Samples = cloneDiagnosticSamples(group.Samples) 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 } cloned := make([]DiagnosticSample, len(samples)) for index, sample := range samples { if sample.ChunkIndex != nil { chunkIndex := *sample.ChunkIndex sample.ChunkIndex = &chunkIndex } cloned[index] = sample } return cloned } type diagnosticSampleKey struct { scope string message string chunkID string chunkIndex int hasChunkIndex bool } func diagnosticSampleKeyFromSample(sample DiagnosticSample) diagnosticSampleKey { key := diagnosticSampleKey{scope: sample.Scope, message: sample.Message, chunkID: sample.ChunkID} if sample.ChunkIndex != nil { key.chunkIndex = *sample.ChunkIndex key.hasChunkIndex = true } return key } type diagnosticGroupKey struct { disposition DiagnosticDisposition category DiagnosticCategory reasonCode string origin DiagnosticOrigin } func diagnosticGroupKeyFromGroup(group DiagnosticGroup) diagnosticGroupKey { return diagnosticGroupKey{disposition: group.Disposition, category: group.Category, reasonCode: group.ReasonCode, origin: group.Origin} }