// Package diagnostics provides bounded local grouping for producer and // validator diagnostic results. package diagnostics import ( "errors" "fmt" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" ) // Collector merges local producer diagnostics by their semantic identity. Its // zero value is ready for use. type Collector struct { diagnostics []contracts.ProducerDiagnostic indices map[key]int } // NewCollector returns an empty local diagnostic collector. func NewCollector() *Collector { return &Collector{} } // Add validates and merges one producer diagnostic. Every occurrence remains // counted, while the first three distinct samples in input order are retained. func (collector *Collector) Add(diagnostic contracts.ProducerDiagnostic) error { if err := diagnostic.Validate(); err != nil { return fmt.Errorf("producer diagnostic: %w", err) } if collector.indices == nil { collector.indices = make(map[key]int) } diagnosticKey := key{disposition: diagnostic.Disposition, category: diagnostic.Category, reasonCode: diagnostic.ReasonCode} index, exists := collector.indices[diagnosticKey] if !exists { if len(collector.diagnostics) >= contracts.MaxProducerDiagnosticGroups { return errors.New("producer diagnostics exceed maximum group count") } collector.indices[diagnosticKey] = len(collector.diagnostics) collector.diagnostics = append(collector.diagnostics, contracts.CloneProducerDiagnostics([]contracts.ProducerDiagnostic{diagnostic})[0]) return nil } current := &collector.diagnostics[index] if diagnostic.OccurrenceCount > maximumInt()-current.OccurrenceCount { return errors.New("producer diagnostic occurrence count overflow") } current.OccurrenceCount += diagnostic.OccurrenceCount for _, sample := range diagnostic.Samples { if len(current.Samples) == contracts.MaxDiagnosticSamples || containsSample(current.Samples, sample) { continue } current.Samples = append(current.Samples, cloneSample(sample)) } current.OmittedSampleCount = current.OccurrenceCount - len(current.Samples) return nil } // Diagnostics returns an independently owned snapshot in first-occurrence // order. func (collector *Collector) Diagnostics() []contracts.ProducerDiagnostic { if collector == nil { return nil } return contracts.CloneProducerDiagnostics(collector.diagnostics) } func containsSample(samples []contracts.DiagnosticSample, candidate contracts.DiagnosticSample) bool { for _, sample := range samples { if sample.Scope == candidate.Scope && sample.Message == candidate.Message { return true } } return false } func cloneSample(sample contracts.DiagnosticSample) contracts.DiagnosticSample { if sample.ChunkIndex != nil { chunkIndex := *sample.ChunkIndex sample.ChunkIndex = &chunkIndex } return sample } func maximumInt() int { return int(^uint(0) >> 1) } type key struct { disposition contracts.DiagnosticDisposition category contracts.DiagnosticCategory reasonCode string }