Transport structured diagnostics through the pipeline

This commit is contained in:
2026-08-27 15:29:10 +00:00
parent acb04954eb
commit ba569594a1
20 changed files with 578 additions and 65 deletions

View File

@@ -30,12 +30,14 @@ type validationRecord struct {
message string
diagnosticPath string
warnings []contracts.Warning
diagnostics []contracts.ProducerDiagnostic
correctionGuidance string
failure error
}
func (record validationRecord) clone() validationRecord {
record.warnings = cloneWarnings(record.warnings)
record.diagnostics = contracts.CloneProducerDiagnostics(record.diagnostics)
return record
}
@@ -62,6 +64,24 @@ func (report validationReport) Warnings() []contracts.Warning {
return warnings
}
func (report validationReport) Diagnostics() []validationDiagnosticRecord {
var diagnostics []validationDiagnosticRecord
for _, record := range report.records {
if record.outcome != validationApproved && record.outcome != validationRejected {
continue
}
for _, diagnostic := range record.diagnostics {
diagnostics = append(diagnostics, validationDiagnosticRecord{validatorName: record.validatorName, diagnostic: cloneProducerDiagnostics([]contracts.ProducerDiagnostic{diagnostic})[0]})
}
}
return diagnostics
}
type validationDiagnosticRecord struct {
validatorName string
diagnostic contracts.ProducerDiagnostic
}
func (report validationReport) FirstRejection() *validationRecord {
for _, record := range report.records {
if record.outcome == validationRejected {
@@ -187,14 +207,14 @@ func executeValidationChain(ctx context.Context, chain preparedValidatorChain, i
continue
}
if invocation.result.Approved {
report.records = append(report.records, validationRecord{validatorName: binding.Module, outcome: validationApproved, attemptCount: attempt, warnings: cloneWarnings(invocation.result.Warnings), diagnosticPath: invocation.result.DiagnosticArtifactPath})
report.records = append(report.records, validationRecord{validatorName: binding.Module, outcome: validationApproved, attemptCount: attempt, warnings: cloneWarnings(invocation.result.Warnings), diagnostics: cloneProducerDiagnostics(invocation.result.Diagnostics), diagnosticPath: invocation.result.DiagnosticArtifactPath})
break
}
message := invocation.result.Message
if message == "" {
message = "output rejected"
}
report.records = append(report.records, validationRecord{validatorName: binding.Module, outcome: validationRejected, attemptCount: attempt, reasonCode: invocation.result.ReasonCode, message: message, diagnosticPath: invocation.result.DiagnosticArtifactPath, warnings: cloneWarnings(invocation.result.Warnings), correctionGuidance: invocation.result.CorrectionGuidance})
report.records = append(report.records, validationRecord{validatorName: binding.Module, outcome: validationRejected, attemptCount: attempt, reasonCode: invocation.result.ReasonCode, message: message, diagnosticPath: invocation.result.DiagnosticArtifactPath, warnings: cloneWarnings(invocation.result.Warnings), diagnostics: cloneProducerDiagnostics(invocation.result.Diagnostics), correctionGuidance: invocation.result.CorrectionGuidance})
break
}
}