buildAuditData creates structured audit data from workflow run information
(processedRun ProcessedRun, metrics LogMetrics, mcpToolUsage *MCPToolUsageData)
| 259 | |
| 260 | // buildAuditData creates structured audit data from workflow run information |
| 261 | func buildAuditData(processedRun ProcessedRun, metrics LogMetrics, mcpToolUsage *MCPToolUsageData) AuditData { |
| 262 | run := processedRun.Run |
| 263 | auditReportLog.Printf("Building audit data for run ID %d", run.DatabaseID) |
| 264 | |
| 265 | // Extract experiment data once so it can be used in both the overview and |
| 266 | // the dedicated Experiments section without reading the file twice. |
| 267 | // Note: AuditWorkflowRun may also call extractExperimentData earlier when an |
| 268 | // --experiment filter is active, but that read is guarded by the filter flag so |
| 269 | // it only occurs when filtering is requested. This call here is always required |
| 270 | // to populate the Experiments section of the report. |
| 271 | expData := extractExperimentData(run.LogsPath) |
| 272 | |
| 273 | // Build overview |
| 274 | overview := OverviewData{ |
| 275 | RunID: run.DatabaseID, |
| 276 | WorkflowName: run.WorkflowName, |
| 277 | Status: run.Status, |
| 278 | Conclusion: run.Conclusion, |
| 279 | CreatedAt: run.CreatedAt, |
| 280 | StartedAt: run.StartedAt, |
| 281 | UpdatedAt: run.UpdatedAt, |
| 282 | Event: run.Event, |
| 283 | Branch: run.HeadBranch, |
| 284 | URL: run.URL, |
| 285 | Experiment: formatExperimentLabel(expData), |
| 286 | } |
| 287 | |
| 288 | if run.LogsPath != "" { |
| 289 | overview.LogsPath = run.LogsPath |
| 290 | } |
| 291 | |
| 292 | if run.Duration > 0 { |
| 293 | overview.Duration = timeutil.FormatDuration(run.Duration) |
| 294 | } |
| 295 | |
| 296 | if run.LogsPath != "" { |
| 297 | awInfoPath := filepath.Join(run.LogsPath, "aw_info.json") |
| 298 | if awInfo, err := parseAwInfo(awInfoPath, false); err == nil && awInfo != nil { |
| 299 | overview.AwContext = awInfo.Context |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | // Build metrics |
| 304 | metricsData := MetricsData{ |
| 305 | TokenUsage: run.TokenUsage, |
| 306 | Turns: run.Turns, |
| 307 | ErrorCount: run.ErrorCount, |
| 308 | WarningCount: run.WarningCount, |
| 309 | } |
| 310 | if run.Conclusion == "failure" && metricsData.ErrorCount == 0 { |
| 311 | metricsData.ErrorCount = 1 |
| 312 | } |
| 313 | |
| 314 | needsFallbackMetrics := metricsData.TokenUsage == 0 || metricsData.Turns == 0 |
| 315 | needsFallbackEngineConfig := run.LogsPath != "" && findAwInfoPath(run.LogsPath) == "" |
| 316 | var fallbackMetrics LogMetrics |
| 317 | var inferredEngineID string |
| 318 | if run.LogsPath != "" && (needsFallbackMetrics || needsFallbackEngineConfig) { |