Skip to content

Commit f3831d8

Browse files
authored
fix: add engine_counts to logs summary using aw_info.json, preventing false-positive Copilot classification (#26359)
1 parent 091b907 commit f3831d8

3 files changed

Lines changed: 73 additions & 0 deletions

File tree

.github/workflows/audit-workflows.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ Use the agentic-workflows MCP tool `logs` with parameters:
6666
Output is saved to: /tmp/gh-aw/aw-mcp/logs
6767
```
6868

69+
**Engine Classification**: Use `summary.engine_counts` from the `logs` tool output to report engine usage. Each run also has an `agent` field (e.g., `"copilot"`, `"claude"`, `"codex"`). Both are derived from the `engine_id` field in `aw_info.json`, which is the authoritative source for engine type.
70+
71+
**IMPORTANT**: Do NOT infer engine type by scanning `.lock.yml` files. Lock files contain the word `copilot` in allowed-domains lists and workflow source paths regardless of which engine the workflow uses, causing false positives.
72+
6973
**Analyze**: Review logs for:
7074
- Missing tools (patterns, frequency, legitimacy)
7175
- Errors (tool execution, MCP failures, auth, timeouts, resources)

pkg/cli/logs_report.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ type LogsSummary struct {
6767
TotalEpisodes int `json:"total_episodes" console:"header:Total Episodes"`
6868
HighConfidenceEpisodes int `json:"high_confidence_episodes" console:"header:High Confidence Episodes"`
6969
TotalGitHubAPICalls int `json:"total_github_api_calls,omitempty" console:"header:Total GitHub API Calls,format:number,omitempty"`
70+
// EngineCounts maps engine_id (from aw_info.json) to the number of runs using that engine.
71+
// Use this field to accurately classify engine types — do NOT infer engines by scanning
72+
// lock files, which contain the word "copilot" in allowed-domains and workflow-source paths
73+
// regardless of which engine the workflow actually uses.
74+
EngineCounts map[string]int `json:"engine_counts,omitempty" console:"-"`
7075
}
7176

7277
// RunData contains information about a single workflow run
@@ -134,6 +139,11 @@ func buildLogsData(processedRuns []ProcessedRun, outputDir string, continuation
134139
var totalMissingData int
135140
var totalSafeItems int
136141
var totalGitHubAPICalls int
142+
// engineCounts tracks the number of runs per engine_id, sourced from aw_info.json.
143+
// This is the authoritative engine classification — do not infer engine type from
144+
// lock file contents, which contain "copilot" in allowed-domains and source paths
145+
// regardless of which engine the workflow uses.
146+
engineCounts := make(map[string]int)
137147

138148
// Build runs data
139149
// Initialize as empty slice to ensure JSON marshals to [] instead of null
@@ -175,6 +185,10 @@ func buildLogsData(processedRuns []ProcessedRun, outputDir string, continuation
175185
if awContext == nil {
176186
awContext = pr.AwContext
177187
}
188+
// Accumulate engine counts from aw_info.json data (authoritative source).
189+
if agentID != "" {
190+
engineCounts[agentID]++
191+
}
178192

179193
comparison := buildAuditComparisonForProcessedRuns(pr, processedRuns)
180194

@@ -255,6 +269,9 @@ func buildLogsData(processedRuns []ProcessedRun, outputDir string, continuation
255269
TotalSafeItems: totalSafeItems,
256270
TotalGitHubAPICalls: totalGitHubAPICalls,
257271
}
272+
if len(engineCounts) > 0 {
273+
summary.EngineCounts = engineCounts
274+
}
258275

259276
episodes, edges := buildEpisodeData(runs, processedRuns)
260277
for _, episode := range episodes {

pkg/cli/logs_report_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
package cli
44

55
import (
6+
"os"
7+
"path/filepath"
68
"testing"
79
"time"
810
)
@@ -908,3 +910,53 @@ func TestDeriveRunClassification(t *testing.T) {
908910
})
909911
}
910912
}
913+
914+
// TestBuildLogsDataEngineCountsFromAwInfo verifies that engine_counts in the summary
915+
// is populated from aw_info.json data (the authoritative engine source), not from
916+
// lock file string matching.
917+
func TestBuildLogsDataEngineCountsFromAwInfo(t *testing.T) {
918+
createRunDir := func(engineID string) string {
919+
dir := t.TempDir()
920+
awInfo := `{"engine_id":"` + engineID + `","engine_name":"Test","workflow_name":"test","created_at":"2024-01-01T00:00:00Z"}`
921+
if err := os.WriteFile(filepath.Join(dir, "aw_info.json"), []byte(awInfo), 0600); err != nil {
922+
t.Fatalf("Failed to write aw_info.json: %v", err)
923+
}
924+
return dir
925+
}
926+
927+
claudeDir := createRunDir("claude")
928+
claudeDir2 := createRunDir("claude")
929+
copilotDir := createRunDir("copilot")
930+
931+
processedRuns := []ProcessedRun{
932+
{Run: WorkflowRun{DatabaseID: 1, WorkflowName: "wf-claude-1", LogsPath: claudeDir}},
933+
{Run: WorkflowRun{DatabaseID: 2, WorkflowName: "wf-claude-2", LogsPath: claudeDir2}},
934+
{Run: WorkflowRun{DatabaseID: 3, WorkflowName: "wf-copilot", LogsPath: copilotDir}},
935+
}
936+
937+
data := buildLogsData(processedRuns, "/tmp/logs", nil)
938+
939+
if data.Summary.EngineCounts == nil {
940+
t.Fatal("EngineCounts should not be nil when runs have aw_info.json")
941+
}
942+
if got := data.Summary.EngineCounts["claude"]; got != 2 {
943+
t.Errorf("Expected 2 claude runs, got %d", got)
944+
}
945+
if got := data.Summary.EngineCounts["copilot"]; got != 1 {
946+
t.Errorf("Expected 1 copilot run, got %d", got)
947+
}
948+
// Verify individual RunData.Agent fields also reflect the engine from aw_info.json
949+
agentsByID := make(map[int64]string)
950+
for _, run := range data.Runs {
951+
agentsByID[run.DatabaseID] = run.Agent
952+
}
953+
if agentsByID[1] != "claude" {
954+
t.Errorf("Run 1: expected agent=claude, got %q", agentsByID[1])
955+
}
956+
if agentsByID[2] != "claude" {
957+
t.Errorf("Run 2: expected agent=claude, got %q", agentsByID[2])
958+
}
959+
if agentsByID[3] != "copilot" {
960+
t.Errorf("Run 3: expected agent=copilot, got %q", agentsByID[3])
961+
}
962+
}

0 commit comments

Comments
 (0)