Skip to content

[rendering-scripts] fix(copilot-parser): render bash command from data.command in SDK events#43750

Open
github-actions[bot] wants to merge 1 commit into
mainfrom
fix/copilot-parser-bash-command-render-415e18e0931af062
Open

[rendering-scripts] fix(copilot-parser): render bash command from data.command in SDK events#43750
github-actions[bot] wants to merge 1 commit into
mainfrom
fix/copilot-parser-bash-command-render-415e18e0931af062

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

The Copilot engine log parser drops bash commands from the rendered step-summary. Tool calls show the tool name (bash) and their output, but not the command that actually ran — losing the most important detail of every bash step.

Trigger

  • Run ID: §28779380421Daily Syntax Error Quality Check
  • Engine: copilot (claude-sonnet-4.6 via Copilot SDK)
  • Date: 2026-07-06

Root cause

Real Copilot SDK events (serialised to events.jsonl and echoed to agent-stdio.log) carry the executed command as a top-level data.command field on tool.execution_start:

{"type":"tool.execution_start","data":{"toolName":"bash","mcpServerName":"","command":"cat /tmp/gh-aw/agent/candidates.txt"}}

But convertCopilotEventsToLegacyLogEntries in log_parser_shared.cjs built the tool_use input with data.input || data.parameters || {} — neither of which exists for these events — so input was {} and the command was never rendered. The existing event-format tests only used tool.execution_start events without a command field, so the gap was untested.

Changes

  • Add a buildToolInput(data) helper that falls back to data.command (and merges it into structured input when absent), used at both tool_use construction sites in the events→legacy normalizer.
  • Add a regression test asserting a bash tool.execution_start with data.command renders the command in the markdown summary.
Verification method

The parser harness and JS test suite could not be executed in this scheduled sandbox run — node, npx, and make require interactive approval that is unavailable here. The defect and fix were validated by static tracing of the parser against the real run-28779380421 agent-stdio.log:

  1. parseLogEntries correctly extracts the JSONL events (infra [INFO]/[copilot-harness] lines are skipped because they do not start with {).
  2. isCopilotEventLogEntries detects the tool./assistant./user. event prefixes.
  3. convertCopilotEventsToLegacyLogEntries mapped tool.execution_starttool_use with input = data.input || data.parameters || {} = {} (command dropped).
  4. formatToolUse then renders only bash with output, no command.

With the fix, input = { command: "cat ..." }, and the formatToolUse default case renders bash: cat ... plus a Parameters section. CI must run the full JS test suite to confirm no regressions.

Test Results

  • Parser harness: NOT RUN (node execution unavailable in sandbox)
  • Render template tests: NOT RUN (node execution unavailable in sandbox)
  • Added regression test: renders the bash command from data.command in Copilot CLI events.jsonl — to be validated by CI

References: §28779380421

Generated by ✅ Daily Rendering Scripts Verifier · 481.5 AIC · ⌖ 37.6 AIC · ⊞ 9.1K ·

  • expires on Jul 9, 2026, 1:13 AM UTC-08:00

Copilot SDK tool.execution_start events carry the executed command as a
top-level data.command field, not nested under data.input/data.parameters.
The events->legacy normalizer only read data.input || data.parameters, so
bash commands were dropped from the rendered step-summary (tool name and
output showed, but not the command that ran).

Add a buildToolInput helper that falls back to (and merges in) data.command,
and a regression test covering a bash tool.execution_start with data.command.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added automated-fix javascript Pull requests that update javascript code rendering labels Jul 6, 2026
@pelikhan pelikhan marked this pull request as ready for review July 6, 2026 09:42
Copilot AI review requested due to automatic review settings July 6, 2026 09:42
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ PR Code Quality Reviewer failed to deliver outputs during code quality review.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #43750 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Copilot SDK (events.jsonl) parsing so tool.execution_start events for bash no longer drop the executed command when rendering the step summary, by populating the legacy tool_use.input from data.command when data.input / data.parameters are absent.

Changes:

  • Add buildToolInput(data) in convertCopilotEventsToLegacyLogEntries() to fall back to data.command (and merge it into structured input when needed).
  • Use buildToolInput(data) at both tool_use construction sites for tool.execution_start and the tool.execution_complete fallback path.
  • Add a regression test asserting the bash command from data.command appears in the rendered markdown.
Show a summary per file
File Description
actions/setup/js/log_parser_shared.cjs Preserves bash command text from Copilot SDK tool events by building tool_use.input from data.command.
actions/setup/js/parse_copilot_log.test.cjs Adds coverage for rendering data.command from SDK tool.execution_start events into the markdown summary.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Low

@github-actions github-actions Bot mentioned this pull request Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

🧪 Test Quality Sentinel Report

Test Quality Score: 85/100 — Excellent

Analyzed 1 test: 1 design, 0 implementation, 0 violation(s).

📊 Metrics (1 test)
Metric Value
Analyzed 1 (JS: 1)
✅ Design 1 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (100%)
Duplicate clusters 0
Inflation No (ratio: 0.81)
🚨 Violations 0
Test File Classification Notes
"renders the bash command from data.command in Copilot CLI events.jsonl" parse_copilot_log.test.cjs:141 design_test Verifies correct parsing of top-level data.command in SDK events; uses realistic event structure; 3 assertions covering tool name, command, and output

Verdict

Passed. 0% implementation tests (threshold: 30%). Test quality is excellent—behavioral contract is well-covered with realistic SDK event data and clear comments explaining the bug fix.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 17.1 AIC · ⌖ 10.3 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 85/100. 0% implementation tests (threshold: 30%).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

The fix correctly addresses the root cause: buildToolInput now falls back to data.command when data.input and data.parameters are absent, and merges data.command into structured input when the key is missing. Both call sites in convertCopilotEventsToLegacyLogEntries are updated consistently.

Logic is sound:

  • Array.isArray guard correctly prevents treating array-valued data.input as an object to spread.
  • Merge path only fires when base.command is not already set, so existing structured inputs are not clobbered.
  • tool.execution_complete orphan-entry fallback also receives the fix.

Test coverage is appropriate: the new test exercises the real event shape from the production log, asserting that the command and output both appear in the rendered markdown.

No security, correctness, or reliability issues found in the changed lines.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 27.1 AIC · ⌖ 5.96 AIC · ⊞ 4.9K

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — fix is correct and targeted; approving with two minor suggestions.

📋 Key Themes & Highlights

Key Themes

  • Orphaned-completion path: buildToolInput is called at line 948 with tool.execution_complete data, but completion events never carry data.command. The call always resolves to {} correctly, but intent would be clearer with a comment or plain {}.
  • Missing merge-branch test: the regression test covers the pure data.command fallback path but not the branch where both data.input/data.parameters and data.command coexist and the command needs to be merged in.

Positive Highlights

  • ✅ Root cause precisely identified; fix is minimal — single helper replaces two identical inline expressions.
  • buildToolInput handles all three cases (merge, bare command, empty) with clear conditional structure.
  • ✅ Regression test uses the exact real-world SDK event format from the triggering run — good fidelity.
  • ✅ PR description includes a thorough static-trace walkthrough, making the fix easy to audit.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 38.6 AIC · ⌖ 5.45 AIC · ⊞ 6.7K
Comment /matt to run again

type: "assistant",
message: {
content: [{ type: "tool_use", id: resolvedToolId, name: toolName, input: data.input || data.parameters || {} }],
content: [{ type: "tool_use", id: resolvedToolId, name: toolName, input: buildToolInput(data) }],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The buildToolInput(data) call here uses data from a tool.execution_complete event (orphaned completion path). Real SDK completion events do not carry a command field, so this will always return {} — the logic is harmless but could mislead future maintainers.

💡 Suggestion

Consider making the intent explicit with an inline comment or a plain {}:

// Orphaned completion: no matching start event; command is unavailable
content: [{ type: "tool_use", id: resolvedToolId, name: toolName, input: {} }],

A small test for the orphaned-completion path would also document this behaviour as a spec.

@copilot please address this.

const result = parseCopilotLog(eventsLog);

expect(result.markdown).toContain("bash");
expect(result.markdown).toContain("cat /tmp/gh-aw/agent/candidates.txt");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The regression test covers the happy path (command present on tool.execution_start), but misses the merge case: when both data.input (or data.parameters) and data.command are present and base.command is undefined. Adding a test for that branch would prevent a silent regression if the merge logic changes.

💡 Suggested additional test
it('merges data.command into existing data.input when base.command is absent', () => {
  const eventsLog = [
    '{"type":"user.message","data":{}}',
    '{"type":"tool.execution_start","data":{"toolName":"bash","mcpServerName":"","input":{"cwd":"/tmp"},"command":"ls"}}',
    '{"type":"tool.execution_complete","data":{"toolName":"bash","mcpServerName":"","success":true,"result":{"content":"out"}}}',
    '{"type":"assistant.message","data":{"content":"Done"}}',
  ].join('\n');

  const result = parseCopilotLog(eventsLog);
  expect(result.markdown).toContain('ls');
  expect(result.markdown).toContain('/tmp'); // cwd from input preserved
});

@copilot please address this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated-fix javascript Pull requests that update javascript code rendering

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant