diff --git a/internal/source/codex/golden_test.go b/internal/source/codex/golden_test.go index 567ef28..6ccc071 100644 --- a/internal/source/codex/golden_test.go +++ b/internal/source/codex/golden_test.go @@ -135,6 +135,23 @@ func TestGoldenSpanTree(t *testing.T) { } } + // MCP attribution invariant: Codex emits MCP tool calls with the same + // mcp____ naming as Claude Code, so the pipeline's generic + // ExtractMCPServer/NormalizeMCPToolName must strip the prefix (tool name -> + // "echo") and attribute the server ("everything") with no Codex-specific code. + // Guards the captured mcp__everything__echo pair; fails even if the golden is + // blindly re-blessed with wrong values. + var sawMCP bool + for _, s := range canon { + if s.Attributes["dash0.gen_ai.tool.mcp_server"] == "everything" { + sawMCP = true + assert.Equal(t, "echo", s.Attributes["gen_ai.tool.name"], + "MCP tool name must be normalized (mcp__server__ prefix stripped)") + assert.Equal(t, "execute_tool", s.Attributes["gen_ai.operation.name"]) + } + } + assert.True(t, sawMCP, "expected an MCP tool span with mcp_server attribution") + got := marshalGolden(t, canon) goldenPath := filepath.Join("testdata", "golden_spans.json") diff --git a/internal/source/codex/testdata/captured_events.jsonl b/internal/source/codex/testdata/captured_events.jsonl index dcecdcd..2681b30 100644 --- a/internal/source/codex/testdata/captured_events.jsonl +++ b/internal/source/codex/testdata/captured_events.jsonl @@ -4,6 +4,8 @@ {"session_id":"019f3be8-053a-78c3-9096-e9ab264c13a0","turn_id":"019f3be8-05bd-7fe1-a139-fb244f6c0f04","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-28-09-019f3be8-053a-78c3-9096-e9ab264c13a0.jsonl","cwd":"/private/tmp/claude-501/-Users-guymoses/7b839ad5-bbf3-4646-a79e-824ae1de5baa/scratchpad/codex-exp","hook_event_name":"PostToolUse","model":"gpt-5.5","permission_mode":"bypassPermissions","tool_name":"apply_patch","tool_input":{"command":"*** Begin Patch\n*** Add File: hello.txt\n+hi from codex\n*** End Patch\n"},"tool_response":"Exit code: 0\nWall time: 0.4 seconds\nOutput:\nSuccess. Updated the following files:\nA hello.txt\n","tool_use_id":"call_9pq2ChYkd2XGBYc3HpRZO29b"} {"session_id":"019f3be8-053a-78c3-9096-e9ab264c13a0","turn_id":"019f3be8-05bd-7fe1-a139-fb244f6c0f04","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-28-09-019f3be8-053a-78c3-9096-e9ab264c13a0.jsonl","cwd":"/private/tmp/claude-501/-Users-guymoses/7b839ad5-bbf3-4646-a79e-824ae1de5baa/scratchpad/codex-exp","hook_event_name":"PreToolUse","model":"gpt-5.5","permission_mode":"bypassPermissions","tool_name":"Bash","tool_input":{"command":"wc -c hello.txt"},"tool_use_id":"call_ji8njWEPsfeWE9wGPL5RBT7o"} {"session_id":"019f3be8-053a-78c3-9096-e9ab264c13a0","turn_id":"019f3be8-05bd-7fe1-a139-fb244f6c0f04","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-28-09-019f3be8-053a-78c3-9096-e9ab264c13a0.jsonl","cwd":"/private/tmp/claude-501/-Users-guymoses/7b839ad5-bbf3-4646-a79e-824ae1de5baa/scratchpad/codex-exp","hook_event_name":"PostToolUse","model":"gpt-5.5","permission_mode":"bypassPermissions","tool_name":"Bash","tool_input":{"command":"wc -c hello.txt"},"tool_response":" 14 hello.txt\n","tool_use_id":"call_ji8njWEPsfeWE9wGPL5RBT7o"} +{"session_id":"019f3be8-053a-78c3-9096-e9ab264c13a0","turn_id":"019f3be8-05bd-7fe1-a139-fb244f6c0f04","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-28-09-019f3be8-053a-78c3-9096-e9ab264c13a0.jsonl","cwd":"/private/tmp/claude-501/-Users-guymoses/7b839ad5-bbf3-4646-a79e-824ae1de5baa/scratchpad/codex-exp","hook_event_name":"PreToolUse","model":"gpt-5.5","permission_mode":"bypassPermissions","tool_name":"mcp__everything__echo","tool_input":{"message":"dash0-mcp-probe"},"tool_use_id":"call_ljaDC0sXe6Ys52D2uKiWf0KN"} +{"session_id":"019f3be8-053a-78c3-9096-e9ab264c13a0","turn_id":"019f3be8-05bd-7fe1-a139-fb244f6c0f04","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-28-09-019f3be8-053a-78c3-9096-e9ab264c13a0.jsonl","cwd":"/private/tmp/claude-501/-Users-guymoses/7b839ad5-bbf3-4646-a79e-824ae1de5baa/scratchpad/codex-exp","hook_event_name":"PostToolUse","model":"gpt-5.5","permission_mode":"bypassPermissions","tool_name":"mcp__everything__echo","tool_input":{"message":"dash0-mcp-probe"},"tool_response":{"content":[{"type":"text","text":"Echo: dash0-mcp-probe"}]},"tool_use_id":"call_ljaDC0sXe6Ys52D2uKiWf0KN"} {"session_id":"019f3be8-053a-78c3-9096-e9ab264c13a0","turn_id":"019f3be8-05bd-7fe1-a139-fb244f6c0f04","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-28-09-019f3be8-053a-78c3-9096-e9ab264c13a0.jsonl","cwd":"/private/tmp/claude-501/-Users-guymoses/7b839ad5-bbf3-4646-a79e-824ae1de5baa/scratchpad/codex-exp","hook_event_name":"Stop","model":"gpt-5.5","permission_mode":"bypassPermissions","stop_hook_active":false,"last_assistant_message":"`hello.txt` is 14 bytes."} {"session_id":"019f3bf0-9fe5-7821-b583-cd99b1eb0738","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-37-33-019f3bf0-9fe5-7821-b583-cd99b1eb0738.jsonl","cwd":"/private/tmp/codex-play","hook_event_name":"SessionStart","model":"gpt-5.5","permission_mode":"default","source":"startup"} {"session_id":"019f3bf0-9fe5-7821-b583-cd99b1eb0738","turn_id":"019f3bf0-d15b-7393-a174-85a31f0194a3","transcript_path":"/Users/guymoses/.codex/sessions/2026/07/07/rollout-2026-07-07T12-37-33-019f3bf0-9fe5-7821-b583-cd99b1eb0738.jsonl","cwd":"/private/tmp/codex-play","hook_event_name":"UserPromptSubmit","model":"gpt-5.5","permission_mode":"default","prompt":"\"create foo.txt with hello, then cat it"} diff --git a/internal/source/codex/testdata/golden_spans.json b/internal/source/codex/testdata/golden_spans.json index dc28304..d0beb8f 100644 --- a/internal/source/codex/testdata/golden_spans.json +++ b/internal/source/codex/testdata/golden_spans.json @@ -4,7 +4,7 @@ "kind": 1, "trace": "trace-1", "span": "span-1", - "parent": "span-3", + "parent": "span-4", "durationMs": 1000, "attributes": { "gen_ai.agent.name": "codex", @@ -26,7 +26,7 @@ "kind": 1, "trace": "trace-1", "span": "span-2", - "parent": "span-3", + "parent": "span-4", "durationMs": 1000, "attributes": { "dash0.gen_ai.tool.bash.command_family": "wc", @@ -45,12 +45,35 @@ } }, { - "name": "chat gpt-5.5", + "name": "execute_tool echo", "kind": 1, "trace": "trace-1", "span": "span-3", + "parent": "span-4", + "durationMs": 1000, + "attributes": { + "dash0.gen_ai.tool.mcp_server": "everything", + "gen_ai.agent.name": "codex", + "gen_ai.conversation.id": "019f3be8-053a-78c3-9096-e9ab264c13a0", + "gen_ai.harness.name": "codex", + "gen_ai.operation.name": "execute_tool", + "gen_ai.provider.name": "openai", + "gen_ai.request.model": "gpt-5.5", + "gen_ai.tool.call.arguments": "{\"message\":\"dash0-mcp-probe\"}", + "gen_ai.tool.call.id": "call_ljaDC0sXe6Ys52D2uKiWf0KN", + "gen_ai.tool.call.result": "{\"content\":[{\"text\":\"Echo: dash0-mcp-probe\",\"type\":\"text\"}]}", + "gen_ai.tool.name": "echo", + "gen_ai.tool.type": "function", + "turn_id": "019f3be8-05bd-7fe1-a139-fb244f6c0f04" + } + }, + { + "name": "chat gpt-5.5", + "kind": 1, + "trace": "trace-1", + "span": "span-4", "parent": "", - "durationMs": 5000, + "durationMs": 7000, "attributes": { "gen_ai.agent.name": "codex", "gen_ai.conversation.id": "019f3be8-053a-78c3-9096-e9ab264c13a0", @@ -70,8 +93,8 @@ "name": "execute_tool apply_patch", "kind": 1, "trace": "trace-2", - "span": "span-4", - "parent": "span-6", + "span": "span-5", + "parent": "span-7", "durationMs": 1000, "attributes": { "gen_ai.agent.name": "codex", @@ -92,8 +115,8 @@ "name": "execute_tool Bash", "kind": 1, "trace": "trace-2", - "span": "span-5", - "parent": "span-6", + "span": "span-6", + "parent": "span-7", "durationMs": 1000, "attributes": { "dash0.gen_ai.tool.bash.command_family": "cat", @@ -115,7 +138,7 @@ "name": "chat gpt-5.5", "kind": 1, "trace": "trace-2", - "span": "span-6", + "span": "span-7", "parent": "", "durationMs": 5000, "attributes": { @@ -137,8 +160,8 @@ "name": "execute_tool Agent", "kind": 1, "trace": "trace-3", - "span": "span-7", - "parent": "span-27", + "span": "span-8", + "parent": "span-28", "durationMs": 1000, "attributes": { "gen_ai.agent.id": "019f3bf3-5f80-7ca3-81a0-298149d46129", @@ -160,8 +183,8 @@ "name": "execute_tool Agent", "kind": 1, "trace": "trace-3", - "span": "span-8", - "parent": "span-27", + "span": "span-9", + "parent": "span-28", "durationMs": 1000, "attributes": { "gen_ai.agent.id": "019f3bf3-605d-7393-ac4f-63f8dcc20260", @@ -183,8 +206,8 @@ "name": "execute_tool Agent", "kind": 1, "trace": "trace-3", - "span": "span-9", - "parent": "span-27", + "span": "span-10", + "parent": "span-28", "durationMs": 1000, "attributes": { "gen_ai.agent.id": "019f3bf3-60f7-7db2-8a74-7cf0618742e6", @@ -206,8 +229,8 @@ "name": "execute_tool apply_patch", "kind": 1, "trace": "trace-3", - "span": "span-10", - "parent": "span-8", + "span": "span-11", + "parent": "span-9", "durationMs": 2000, "attributes": { "gen_ai.agent.id": "019f3bf3-605d-7393-ac4f-63f8dcc20260", @@ -229,8 +252,8 @@ "name": "execute_tool apply_patch", "kind": 1, "trace": "trace-3", - "span": "span-11", - "parent": "span-9", + "span": "span-12", + "parent": "span-10", "durationMs": 2000, "attributes": { "gen_ai.agent.id": "019f3bf3-60f7-7db2-8a74-7cf0618742e6", @@ -252,8 +275,8 @@ "name": "execute_tool apply_patch", "kind": 1, "trace": "trace-3", - "span": "span-12", - "parent": "span-7", + "span": "span-13", + "parent": "span-8", "durationMs": 1000, "attributes": { "gen_ai.agent.id": "019f3bf3-5f80-7ca3-81a0-298149d46129", @@ -275,8 +298,8 @@ "name": "invoke_agent worker", "kind": 1, "trace": "trace-3", - "span": "span-13", - "parent": "span-9", + "span": "span-14", + "parent": "span-10", "durationMs": 8000, "attributes": { "gen_ai.agent.id": "019f3bf3-60f7-7db2-8a74-7cf0618742e6", @@ -298,8 +321,8 @@ "name": "execute_tool multi_agent_v1wait_agent", "kind": 1, "trace": "trace-3", - "span": "span-14", - "parent": "span-27", + "span": "span-15", + "parent": "span-28", "durationMs": 8000, "attributes": { "gen_ai.agent.name": "codex", @@ -320,8 +343,8 @@ "name": "execute_tool Bash", "kind": 1, "trace": "trace-3", - "span": "span-15", - "parent": "span-8", + "span": "span-16", + "parent": "span-9", "durationMs": 1000, "attributes": { "dash0.gen_ai.tool.bash.command_family": "wc", @@ -344,8 +367,8 @@ "name": "execute_tool Bash", "kind": 1, "trace": "trace-3", - "span": "span-16", - "parent": "span-7", + "span": "span-17", + "parent": "span-8", "durationMs": 1000, "attributes": { "dash0.gen_ai.tool.bash.command_family": "od", @@ -368,8 +391,8 @@ "name": "invoke_agent worker", "kind": 1, "trace": "trace-3", - "span": "span-17", - "parent": "span-8", + "span": "span-18", + "parent": "span-9", "durationMs": 15000, "attributes": { "gen_ai.agent.id": "019f3bf3-605d-7393-ac4f-63f8dcc20260", @@ -391,8 +414,8 @@ "name": "execute_tool multi_agent_v1wait_agent", "kind": 1, "trace": "trace-3", - "span": "span-18", - "parent": "span-27", + "span": "span-19", + "parent": "span-28", "durationMs": 2000, "attributes": { "gen_ai.agent.name": "codex", @@ -413,8 +436,8 @@ "name": "invoke_agent worker", "kind": 1, "trace": "trace-3", - "span": "span-19", - "parent": "span-7", + "span": "span-20", + "parent": "span-8", "durationMs": 17000, "attributes": { "gen_ai.agent.id": "019f3bf3-5f80-7ca3-81a0-298149d46129", @@ -436,8 +459,8 @@ "name": "execute_tool multi_agent_v1wait_agent", "kind": 1, "trace": "trace-3", - "span": "span-20", - "parent": "span-27", + "span": "span-21", + "parent": "span-28", "durationMs": 1000, "attributes": { "gen_ai.agent.name": "codex", @@ -458,8 +481,8 @@ "name": "execute_tool Bash", "kind": 1, "trace": "trace-3", - "span": "span-21", - "parent": "span-27", + "span": "span-22", + "parent": "span-28", "durationMs": 1000, "attributes": { "dash0.gen_ai.tool.bash.command_family": "od", @@ -481,8 +504,8 @@ "name": "execute_tool Bash", "kind": 1, "trace": "trace-3", - "span": "span-22", - "parent": "span-27", + "span": "span-23", + "parent": "span-28", "durationMs": 2000, "attributes": { "dash0.gen_ai.tool.bash.command_family": "od", @@ -504,8 +527,8 @@ "name": "execute_tool Bash", "kind": 1, "trace": "trace-3", - "span": "span-23", - "parent": "span-27", + "span": "span-24", + "parent": "span-28", "durationMs": 2000, "attributes": { "dash0.gen_ai.tool.bash.command_family": "od", @@ -527,8 +550,8 @@ "name": "execute_tool multi_agent_v1close_agent", "kind": 1, "trace": "trace-3", - "span": "span-24", - "parent": "span-27", + "span": "span-25", + "parent": "span-28", "durationMs": 1000, "attributes": { "gen_ai.agent.name": "codex", @@ -549,8 +572,8 @@ "name": "execute_tool multi_agent_v1close_agent", "kind": 1, "trace": "trace-3", - "span": "span-25", - "parent": "span-27", + "span": "span-26", + "parent": "span-28", "durationMs": 1000, "attributes": { "gen_ai.agent.name": "codex", @@ -571,8 +594,8 @@ "name": "execute_tool multi_agent_v1close_agent", "kind": 1, "trace": "trace-3", - "span": "span-26", - "parent": "span-27", + "span": "span-27", + "parent": "span-28", "durationMs": 1000, "attributes": { "gen_ai.agent.name": "codex", @@ -593,7 +616,7 @@ "name": "chat gpt-5.5", "kind": 1, "trace": "trace-3", - "span": "span-27", + "span": "span-28", "parent": "", "durationMs": 32000, "attributes": {