Skip to content

Surface Copilot CLI execution step exit code as an error annotation - #53656

Merged
pelikhan merged 6 commits into
mainfrom
copilot/fix-copilot-cli-exit-issue
Aug 18, 2026
Merged

Surface Copilot CLI execution step exit code as an error annotation#53656
pelikhan merged 6 commits into
mainfrom
copilot/fix-copilot-cli-exit-issue

Conversation

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

The Execute GitHub Copilot CLI step can terminate non-zero while the job log looks clean — the agent stream and its post-processing (rpc-messages.jsonl, gateway.md, token-usage.jsonl, AI Credits) complete normally and no ##[error] is emitted anywhere, making failure indistinguishable from success.

The step's EXIT trap already captured $? and persisted it to /tmp/gh-aw/agent_execution_exit_code.txt for the OTLP conclusion span, but never surfaced it in the log. This adds that missing signal on the shared invocation path.

Changes

  • buildCopilotSettingsCleanupAndExitCodeTrap (pkg/workflow/copilot_engine_execution.go): emits a GitHub Actions error annotation when the exit code is non-zero. Applies to both generated command paths (direct and firewall/AWF), so every Copilot workflow gets it — no per-workflow logic touched. Exit-code persistence and settings cleanup are unchanged; successful runs stay silent.
  • copilotExecutionStepName constant: used for both the step's name: and the annotation text so the two cannot drift.
  • Tests (copilot_exit_code_annotation_test.go): string-level pin of the trap, plus bash integration tests that execute the real trap (success silent; exit 3 and a failing pipefail pipeline surface the true code and still write the exit-code file), following the existing style in copilot_home_expansion_test.go.
  • Regenerated: wasm golden fixtures and .lock.yml workflow files — diff is the trap line only.

Generated trap:

trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf "%s" "$gh_aw_exit_code" > /tmp/gh-aw/agent_execution_exit_code.txt || true; rm -f "$HOME/.copilot/settings.json"; if [ "$gh_aw_exit_code" -ne 0 ]; then echo "::error::Execute GitHub Copilot CLI exited with code $gh_aw_exit_code"; fi' EXIT

Scope

This covers remediation item 1 (explicit exit-code/error line on termination), which is the prerequisite for diagnosing the three affected runs. Item 2 — auditing the safe-outputs post-processing for a swallowed exception — is deliberately not attempted here: with the exit code now visible, a subsequent failure will identify whether the fault is in that path or upstream, rather than guessing.


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.5 AIC · ⌖ 10.2 AIC · ⊞ 6.4K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix GitHub Copilot CLI execution wrapper to prevent early exit Surface Copilot CLI execution step exit code as an error annotation Aug 18, 2026
Copilot AI requested a review from pelikhan August 18, 2026 12:05
@pelikhan
pelikhan marked this pull request as ready for review August 18, 2026 12:06
Copilot AI balanced review requested due to automatic review settings August 18, 2026 12:06

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

Surfaces non-zero Copilot CLI exit codes as GitHub Actions error annotations, making silent execution failures diagnosable.

Changes:

  • Adds a shared non-zero exit annotation to direct and firewall execution paths.
  • Reuses the execution-step name in generated annotations.
  • Adds Bash integration coverage and regenerates workflow fixtures.
Show a summary per file
File Description
pkg/workflow/copilot_engine_execution.go Generates the exit-code annotation.
pkg/workflow/copilot_exit_code_annotation_test.go Tests success, failure, pipefail, and execution paths.
pkg/workflow/testdata/**/*.golden Updates generated golden fixtures.
.github/workflows/*.lock.yml Propagates the generated trap to compiled workflows.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 189/189 changed files
  • Comments generated: 0
  • Review effort level: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

PR Triage

Category: bug | Risk: medium | Priority: high (score 78)

  • Impact 40/50 — surfaces silent Copilot CLI non-zero exit as an error annotation, improving failure visibility
  • Urgency 22/30 — CI green (26 success, 4 skipped)
  • Quality 16/20 — large diff (189 files) but CI passing, reviewer commented

Recommended action: fast_track

Generated by 🔧 PR Triage Agent · auto · 53.1 AIC · ⌖ 2.52 AIC · ⊞ 8.3K ·

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Ponytail review: source diff (pkg/workflow/copilot_engine_execution.go + new copilot_exit_code_annotation_test.go) is a single-line trap addition with a named constant to prevent name drift, reusing existing test helpers (runBashWithHome, requireCopilotExecutionStep). No speculative abstractions, unused flexibility, or hand-rolled stdlib replacements found. Lean already. Ship.

Generated by Ponytail Reviewer for #53656

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

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

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-18T00:00:00Z
review_event: COMMENT
top_themes:
  - no actionable issues in changed lines
  - generated workflow trap update is consistent with tests and goldens
files_reviewed:
  - pkg/workflow/copilot_engine_execution.go
  - pkg/workflow/copilot_exit_code_annotation_test.go
  - .github/workflows/*.lock.yml
comment_count: 0

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 8.59 AIC · ⌖ 6.79 AIC · ⊞ 7K ·
Comment /review to run again

@github-actions github-actions Bot 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.

Verdict

COMMENT — I don't see a changed-line issue here that should block merge.

Why I'm not blocking this

The trap change is narrowly scoped, preserves the existing exit-code persistence and settings cleanup, and the added tests cover the important failure modes: silent success, explicit non-zero exit, and a pipefail-driven command failure. The generated workflow diffs are the expected mechanical propagation of the shared trap string.

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 8.59 AIC · ⌖ 6.79 AIC · ⊞ 7K
Comment /review to run again

@github-actions github-actions Bot 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.

The implementation is clean and correct. The ::error:: annotation is emitted exclusively on non-zero exit, the step name is DRYed into a copilotExecutionStepName constant shared with buildCopilotExecutionStep, tests cover unit pinning + bash integration + both command paths, and all lock files are consistently regenerated. No actionable issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 36.5 AIC · ⌖ 8.77 AIC · ⊞ 5.7K

@github-actions github-actions Bot 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.

Skills-Based Review 🧠

Applied /diagnosing-bugs — approving with one minor suggestion.

📋 Key Themes & Highlights

Positive Highlights

  • ✅ Root cause properly addressed: the EXIT trap now surfaces the non-zero exit code as a ::error:: annotation, making failure visible where it was previously silent
  • copilotExecutionStepName constant ties the step name: and annotation text together — drift between the two is impossible
  • ✅ Test coverage is thorough: string-level pin (TestCopilotExitCodeTrap_EmitsErrorAnnotation), bash integration tests covering success/failure/pipefail, and end-to-end step generation tests for both direct and firewall paths
  • ✅ Follows existing test helpers (runBashWithHome, requireCopilotExecutionStep) rather than inventing new patterns
  • ✅ Silent on success — no noise in the happy path

One suggestion

The ::error:: annotation embeds the step name in the message body. GitHub Actions also supports title= which renders it as a distinct header in the annotation panel (see inline comment). Minor quality-of-life improvement, not a correctness issue.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 48.6 AIC · ⌖ 9.94 AIC · ⊞ 7.8K
Comment /matt to run again

agentExecutionExitCodePath,
copilotSettingsPath,
copilotExecutionStepName,
)

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.

[/diagnosing-bugs] The ::error:: annotation format works, but GitHub Actions also supports a title= parameter that renders the step name as a separate header in the annotation panel — cleaner than embedding it in the message text.

💡 Suggested improvement

Instead of:

echo "::error::Execute GitHub Copilot CLI exited with code $gh_aw_exit_code"

Consider:

echo "::error title=Execute GitHub Copilot CLI::exited with code $gh_aw_exit_code"

The title= parameter makes the step name a distinct heading in the Checks UI, so the message body can focus on the actionable detail (exited with code N). This avoids the slight redundancy of the step name appearing both as the derived context and in the message text.

This is a quality-of-life improvement — the current form is already a meaningful correctness gain over the status quo.

@copilot please address this.

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.

Applied in f2fb816438: the trap now emits ::error title=Execute GitHub Copilot CLI::exited with code N, using the shared step-name constant. Updated tests and regenerated fixtures validate the title and exit code.

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (132 new lines in pkg/workflow/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/53656-surface-copilot-cli-exit-code-as-error-annotation.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete the missing sections — add context the AI couldn't infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-53656: Surface Copilot CLI Exit Code as a GitHub Actions Error Annotation

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 0042-use-postgresql.md for PR #42).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · sonnet46 · 69.7 AIC · ⌖ 20.4 AIC · ⊞ 9.1K ·
Comment /review to run again

… error annotation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Please address the remaining merge blockers on this PR, then run the pr-finisher skill and report back with validation results and any remaining blockers.

  • The main remaining blocker is the ADR gate comment: complete the drafted ADR, commit it, and link it from the PR body so the gate can re-run.
  • No failed checks were listed in the compact queue for this run.
  • Please refresh the branch if needed and include the validation commands/results in your follow-up.

Run: https://github.com/github/gh-aw/actions/runs/32140009662

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.5 AIC · ⌖ 10.2 AIC · ⊞ 6.4K ·
Comment /souschef to run again

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot consider applying fix to all agentic engine generated code

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Please address the remaining merge blockers on this PR, then run the pr-finisher skill and report back with validation results and any remaining blockers.

  • The main remaining blocker is t...

Completed in f2fb816438: ADR-53656 is Accepted and linked in the updated PR progress body. Validation passed: make fmt, make lint, targeted Copilot annotation tests, make update-wasm-golden, make recompile, and BASE_REF=origin/main make agent-report-progress. The referenced Sous Chef run had no failed jobs. Remaining blocker: CI on this new agent-pushed HEAD must be re-triggered by a maintainer; the current Copilot check was in progress when inspected.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

@copilot consider applying fix to all agentic engine generated code

Applied in e6134f4. The shared trap now covers Claude, Codex, Gemini, Pi, behavior-defined, and universal CLI execution generators, with regenerated fixtures and workflow locks.

@pelikhan
pelikhan merged commit e47124a into main Aug 18, 2026
2 of 3 checks passed
@pelikhan
pelikhan deleted the copilot/fix-copilot-cli-exit-issue branch August 18, 2026 14:47
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.87.1

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[aw-failures] [P1] Execute GitHub Copilot CLI silently exits early — 3 unrelated workflows same day

4 participants