package reporting import ( "encoding/json" "fmt" "os" "time" "gitea.maximumdirect.net/eric/audita/internal/framework/proposals" stagewarnings "gitea.maximumdirect.net/eric/audita/internal/framework/warnings" ) type ProcessReport struct { ReportMetadata ReportMetadata `json:"report_metadata"` Phase string `json:"phase"` Status string `json:"status"` Operation string `json:"operation"` TranscriptPath string `json:"transcript_path"` GlossaryPath string `json:"glossary_path"` OutputPath string `json:"output_path,omitempty"` Modules []string `json:"modules"` StartedAt time.Time `json:"started_at"` CompletedAt *time.Time `json:"completed_at,omitempty"` ErrorMessage string `json:"error_message,omitempty"` ErrorPhase string `json:"error_phase,omitempty"` InputSegmentCount *int `json:"input_segment_count,omitempty"` NormalizedSegmentCount *int `json:"normalized_segment_count,omitempty"` NormalizationMerges *int `json:"normalization_merges,omitempty"` NormalizationIDReassignments *int `json:"normalization_id_reassignments,omitempty"` NormalizationSkipped NormalizationSkipped `json:"normalization_skipped,omitempty"` Chunking *ChunkingSummary `json:"chunking,omitempty"` Diagnostics *DiagnosticsMetadata `json:"diagnostics,omitempty"` ModulesSummary *ModulesSummary `json:"modules_summary,omitempty"` ModuleResults []ModuleReport `json:"module_results,omitempty"` } const ( DefaultProcessReportSchemaName = "audita-process-report" DefaultProcessReportSchemaVersion = "v1" ) type ReportMetadata struct { ReportSchemaName string `json:"report_schema_name"` ReportSchemaVersion string `json:"report_schema_version"` OutputSchema string `json:"output_schema"` ConfigVersion *int `json:"config_version,omitempty"` } type ModuleReport struct { ModuleKey string `json:"module_key"` ModuleInstance string `json:"module_instance"` ReplacementPolicy string `json:"replacement_policy,omitempty"` Status string `json:"status"` ProposalCount int `json:"proposal_count"` Warnings []stagewarnings.StageWarning `json:"warnings,omitempty"` ValidatorDecisions []ValidatorDecisionReport `json:"validator_decisions,omitempty"` ValidatorRejected []ValidatorRejectedReport `json:"validator_rejected,omitempty"` AppliedChanges []proposals.AppliedChange `json:"applied_changes,omitempty"` SkippedChanges []proposals.SkippedChange `json:"skipped_changes,omitempty"` ErrorMessage string `json:"error_message,omitempty"` StartedAt *time.Time `json:"started_at,omitempty"` CompletedAt *time.Time `json:"completed_at,omitempty"` } type ValidatorDecisionReport struct { ValidatorName string `json:"validator_name"` ProposalIndex int `json:"proposal_index"` Approved bool `json:"approved"` ReasonCode string `json:"reason_code"` Message string `json:"message"` DiagnosticArtifactPath string `json:"diagnostic_artifact_path,omitempty"` } type ValidatorRejectedReport struct { ValidatorName string `json:"validator_name"` ProposalIndex int `json:"proposal_index"` ModuleKey string `json:"module_key"` ModuleInstance string `json:"module_instance"` TargetSegmentID int `json:"target_segment_id"` OriginalText string `json:"original_text"` CorrectedText string `json:"corrected_text"` ReasonCode string `json:"reason_code"` Message string `json:"message"` } type ModulesSummary struct { ModuleCount int `json:"module_count"` TotalAppliedChanges int `json:"total_applied_changes"` TotalSkippedChanges int `json:"total_skipped_changes"` FailedModuleInstance string `json:"failed_module_instance,omitempty"` } type DiagnosticsMetadata struct { DirectoryPath string `json:"directory_path,omitempty"` SourceTranscriptPath string `json:"source_transcript_path,omitempty"` ParsedSourceTranscriptPath string `json:"parsed_source_transcript_path,omitempty"` NormalizedTranscriptPath string `json:"normalized_transcript_path,omitempty"` NormalizationSummaryPath string `json:"normalization_summary_path,omitempty"` ChunkingSummaryPath string `json:"chunking_summary_path,omitempty"` UtilizationSummaryPath string `json:"utilization_summary_path,omitempty"` CorrectionLedgerPath string `json:"correction_ledger_path,omitempty"` InvocationMetadataPath string `json:"invocation_metadata_path,omitempty"` RedactedEffectiveConfigPath string `json:"redacted_effective_config_path,omitempty"` ErrorLogPath string `json:"error_log_path,omitempty"` } type NormalizationSkipped struct { DifferentSpeakers *int `json:"different_speakers,omitempty"` GapTooLarge *int `json:"gap_too_large,omitempty"` DurationExceeded *int `json:"duration_exceeded,omitempty"` TokenLimitExceeded *int `json:"token_limit_exceeded,omitempty"` } type ChunkingSummary struct { ChunkCount int `json:"chunk_count"` MinEstimatedTokens int `json:"min_estimated_chunk_tokens"` MaxEstimatedTokens int `json:"max_estimated_chunk_tokens"` TotalEstimatedTokens int `json:"total_estimated_transcript_tokens"` TargetSections *int `json:"target_sections,omitempty"` MaxSectionTokens int `json:"max_section_tokens"` MinSectionTokens int `json:"min_section_tokens"` } func WriteProcessReport(path string, report ProcessReport) error { payload, err := json.MarshalIndent(report, "", " ") if err != nil { return fmt.Errorf("failed to marshal process report JSON: %w", err) } payload = append(payload, '\n') if err := os.WriteFile(path, payload, 0o644); err != nil { return fmt.Errorf("failed to write report JSON file %q: %w", path, err) } return nil }