Report schema validation and normalization results

This commit is contained in:
2026-05-11 00:16:50 +00:00
parent e2ae7f77d8
commit aeb9c4f062
3 changed files with 234 additions and 35 deletions

View File

@@ -23,27 +23,27 @@ type processInvocation struct {
Config config.Config
}
var processRunner = func(inv processInvocation, stdout io.Writer) error {
var processRunner = func(inv processInvocation, stdout io.Writer) (*normalization.NormalizationSummary, error) {
transcriptBytes, err := io.ReadRequiredFile(inv.TranscriptPath, "transcript")
if err != nil {
return err
return nil, fmt.Errorf("transcript_read: %w", err)
}
glossaryBytes, err := io.ReadRequiredFile(inv.GlossaryPath, "glossary")
if err != nil {
return err
return nil, fmt.Errorf("glossary_read: %w", err)
}
// Parse and validate transcript using typed schema
transcript, err := schema.ParseSourceTranscriptJSON(transcriptBytes)
if err != nil {
return fmt.Errorf("invalid transcript: %w", err)
return nil, fmt.Errorf("transcript_schema: %w", err)
}
// Parse and validate glossary using typed schema
glossary, err := schema.ParseGlossaryYAML(glossaryBytes)
if err != nil {
return fmt.Errorf("invalid glossary: %w", err)
return nil, fmt.Errorf("glossary_schema: %w", err)
}
// Convert to canonical transcript format for normalization
@@ -73,25 +73,25 @@ var processRunner = func(inv processInvocation, stdout io.Writer) error {
MaxSegmentTokens: inv.Config.Normalization.MaxSegmentTokens,
})
normalizedTranscript, _ = normalizer.Normalize(normalizedTranscript)
normalizedTranscript, normalizationSummary := normalizer.Normalize(normalizedTranscript)
// Serialize normalized transcript to JSON
outputBytes, err := schema.TranscriptToJSON(normalizedTranscript)
if err != nil {
return fmt.Errorf("failed to serialize transcript: %w", err)
return nil, fmt.Errorf("failed to serialize transcript: %w", err)
}
if strings.TrimSpace(inv.OutputPath) != "" {
if err := io.WriteFile(inv.OutputPath, outputBytes); err != nil {
return err
return nil, err
}
return nil
return normalizationSummary, nil
}
if _, err := stdout.Write(outputBytes); err != nil {
return fmt.Errorf("failed to write transcript to stdout: %w", err)
return nil, fmt.Errorf("failed to write transcript to stdout: %w", err)
}
return nil
return normalizationSummary, nil
}
// Run executes the Audita CLI with the provided arguments and streams.
@@ -233,17 +233,47 @@ func runProcess(args []string, stdout, stderr io.Writer) int {
Config: cfg,
}
if err := processRunner(inv, stdout); err != nil {
if normalizationSummary, err := processRunner(inv, stdout); err != nil {
completedAt := time.Now().UTC()
// Extract error phase from error message if present
errorPhase := ""
errorMsg := err.Error()
if strings.Contains(errorMsg, ": ") {
parts := strings.SplitN(errorMsg, ": ", 2)
if len(parts) == 2 {
errorPhase = parts[0]
errorMsg = parts[1]
}
}
if strings.TrimSpace(inv.ReportJSONPath) != "" {
report := buildProcessReport("failed", inv, startedAt, completedAt, err.Error())
report := buildProcessReport("failed", inv, startedAt, completedAt, errorMsg, errorPhase, nil)
if reportErr := reporting.WriteProcessReport(inv.ReportJSONPath, report); reportErr != nil {
fmt.Fprintf(stderr, "audita process: %v\n", reportErr)
return 1
}
}
fmt.Fprintf(stderr, "audita process: %v\n", err)
return 1
}
}
fmt.Fprintf(stderr, "audita process: %v\n", err)
return 1
}
completedAt := time.Now().UTC()
if strings.TrimSpace(inv.ReportJSONPath) != "" {
report := buildProcessReport("success", inv, startedAt, completedAt, "", "", normalizationSummary)
if err := reporting.WriteProcessReport(inv.ReportJSONPath, report); err != nil {
fmt.Fprintf(stderr, "audita process: %v\n", err)
return 1
}
}
}
fmt.Fprintf(stderr, "audita process: %v\n", err)
return 1
}
if strings.TrimSpace(inv.ReportJSONPath) != "" {
completedAt := time.Now().UTC()
@@ -257,9 +287,9 @@ func runProcess(args []string, stdout, stderr io.Writer) int {
return 0
}
func buildProcessReport(status string, inv processInvocation, startedAt, completedAt time.Time, errorMessage string) reporting.ProcessReport {
func buildProcessReport(status string, inv processInvocation, startedAt, completedAt time.Time, errorMessage string, errorPhase string, normalizationSummary *normalization.NormalizationSummary) reporting.ProcessReport {
report := reporting.ProcessReport{
Phase: "phase1-minimal",
Phase: "phase2-normalization",
Status: status,
Operation: "process",
TranscriptPath: inv.TranscriptPath,
@@ -268,10 +298,21 @@ func buildProcessReport(status string, inv processInvocation, startedAt, complet
Modules: append([]string(nil), inv.Config.Modules...),
StartedAt: startedAt,
CompletedAt: &completedAt,
ErrorPhase: errorPhase,
}
if errorMessage != "" {
report.ErrorMessage = errorMessage
}
if normalizationSummary != nil {
report.InputSegmentCount = &normalizationSummary.InputSegmentCount
report.NormalizedSegmentCount = &normalizationSummary.OutputSegmentCount
report.NormalizationMerges = &normalizationSummary.MergesPerformed
report.NormalizationIDReassignments = &normalizationSummary.IDsReassigned
report.NormalizationSkipped.DifferentSpeakers = &normalizationSummary.SkippedMerges.DifferentSpeakers
report.NormalizationSkipped.GapTooLarge = &normalizationSummary.SkippedMerges.GapTooLarge
report.NormalizationSkipped.DurationExceeded = &normalizationSummary.SkippedMerges.DurationExceeded
report.NormalizationSkipped.TokenLimitExceeded = &normalizationSummary.SkippedMerges.TokenLimitExceeded
}
return report
}