Skip to content

OTLP conclusion: mark non-zero Copilot CLI exits as run failures when conclusion/error signals are absent#47268

Merged
pelikhan merged 9 commits into
mainfrom
copilot/otel-fix-agent-conclusion-status
Jul 22, 2026
Merged

OTLP conclusion: mark non-zero Copilot CLI exits as run failures when conclusion/error signals are absent#47268
pelikhan merged 9 commits into
mainfrom
copilot/otel-fix-agent-conclusion-status

Conversation

Copilot AI commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

gh-aw.agent.conclusion could emit gh-aw.run.status=success / STATUS_CODE_OK when the Copilot CLI execution step failed non-zero but agent_output.json contained no errors. This made a real class of agent-job failures invisible to OTel queries and failure dashboards.

  • Persist Copilot CLI execution exit code for post-step telemetry

    • Updated Copilot execution step generation to write the step exit code to /tmp/gh-aw/agent_execution_exit_code.txt from an EXIT trap.
    • Applied this in both direct and firewall execution paths so setup post-step can read failure state in a fresh environment.
  • Extend conclusion span failure inference

    • In send_otlp_span.cjs, added exit-code file parsing and integrated it into run status derivation.
    • When GH_AW_AGENT_CONCLUSION / workflow conclusion are absent and persisted exit code is non-zero, the conclusion span now sets:
      • gh-aw.run.status = "failure"
      • OTLP status.code = STATUS_CODE_ERROR
      • status.message = "copilot cli exited with code <n>"
  • Expose explicit execution signal in span attributes

    • Added gh-aw.agent.execution.exit_code attribute when the persisted value is available, improving diagnosability and filtering.
  • Add regression coverage for the zero-error/non-zero-exit gap

    • Added a focused test case for: conclusion absent + error_count=0 + non-zero persisted exit code ⇒ failure/ERROR conclusion span.
if (!rawRunStatus && hasAgentExecutionFailureExitCode) {
  runStatus = "failure";
  statusCode = 2;
  statusMessage = `copilot cli exited with code ${agentExecutionExitCode}`;
}


✨ PR Review Safe Output Test - Run 29923680952

💥 [THE END] — Illustrated by Smoke Claude · sonnet46 90.2 AIC · ⌖ 19.5 AIC · ⊞ 6.1K ·
Comment /smoke-claude to run again

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

Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

Copilot AI changed the title [WIP] Fix otel agent conclusion status reporting for GitHub Actions OTLP conclusion: mark non-zero Copilot CLI exits as run failures when conclusion/error signals are absent Jul 22, 2026
Copilot AI requested a review from pelikhan July 22, 2026 11:33
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review July 22, 2026 11:46
Copilot AI review requested due to automatic review settings July 22, 2026 11:46
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

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

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

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

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

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

📊 Metrics (1 test)
Metric Value
Analyzed 1 (Go: 0, JS: 1)
✅ Design 1 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (100%)
Duplicate clusters 0
Inflation No
🚨 Violations 0
Test File Classification Issues
sets gh-aw.run.status=failure when exit code is non-zero send_otlp_span.test.cjs:5131 design_test · behavioral_contract · high_value none

Verdict

Passed. 0% implementation tests (threshold: 30%). The single new test directly validates the PR's behavioral contract — non-zero Copilot CLI exit with no explicit conclusion or output errors must produce gh-aw.run.status=failure, STATUS_CODE_ERROR (2), and a descriptive status message. 5 assertions cover span status code, run status attribute, error_count, exit_code attribute, and message text. No mock violations, no inflation (34 test lines vs 35 production lines), and the edge case is the primary scenario under test.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 46.6 AIC · ⌖ 7.69 AIC · ⊞ 7.1K ·
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.

✅ Test Quality Sentinel: 100/100. 0% implementation tests (threshold: 30%). The new test is a direct behavioral contract for the PR's core change.

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

Persists Copilot CLI exit codes and uses them to correctly mark OTLP conclusion spans as failures when other conclusion signals are unavailable.

Changes:

  • Records direct and firewall execution exit codes through an EXIT trap.
  • Adds exit-code-based OTLP status inference and diagnostics.
  • Adds regression coverage and recompiles affected workflows.
Show a summary per file
File Description
pkg/workflow/copilot_engine_execution.go Generates the exit-code persistence trap.
actions/setup/js/send_otlp_span.cjs Reads exit codes and derives OTLP failure status.
actions/setup/js/send_otlp_span.test.cjs Tests non-zero exit failure inference.
.github/workflows/ace-editor.lock.yml Regenerated Copilot execution trap.
.github/workflows/agent-performance-analyzer.lock.yml Regenerated Copilot execution trap.
.github/workflows/agentic-token-audit.lock.yml Regenerated Copilot execution trap.
.github/workflows/agentic-token-optimizer.lock.yml Regenerated Copilot execution trap.
.github/workflows/agentic-token-trend-audit.lock.yml Regenerated Copilot execution trap.
.github/workflows/architecture-guardian.lock.yml Regenerated Copilot execution trap.
.github/workflows/archie.lock.yml Regenerated Copilot execution trap.
.github/workflows/artifacts-summary.lock.yml Regenerated Copilot execution trap.
.github/workflows/bot-detection.lock.yml Regenerated Copilot execution trap.
.github/workflows/brave.lock.yml Regenerated Copilot execution trap.
.github/workflows/breaking-change-checker.lock.yml Regenerated Copilot execution trap.
.github/workflows/ci-coach.lock.yml Regenerated Copilot execution trap.
.github/workflows/cli-consistency-checker.lock.yml Regenerated Copilot execution trap.
.github/workflows/code-scanning-fixer.lock.yml Regenerated Copilot execution trap.
.github/workflows/code-simplifier.lock.yml Regenerated Copilot execution trap.
.github/workflows/constraint-solving-potd.lock.yml Regenerated Copilot execution trap.
.github/workflows/contribution-check.lock.yml Regenerated Copilot execution trap.
.github/workflows/copilot-centralization-drilldown.lock.yml Regenerated Copilot execution trap.
.github/workflows/copilot-centralization-optimizer.lock.yml Regenerated Copilot execution trap.
.github/workflows/copilot-cli-deep-research.lock.yml Regenerated Copilot execution trap.
.github/workflows/copilot-opt.lock.yml Regenerated Copilot execution trap.
.github/workflows/copilot-pr-merged-report.lock.yml Regenerated Copilot execution trap.
.github/workflows/copilot-pr-nlp-analysis.lock.yml Regenerated Copilot execution trap.
.github/workflows/copilot-pr-prompt-analysis.lock.yml Regenerated Copilot execution trap.
.github/workflows/craft.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-ambient-context-optimizer.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-architecture-diagram.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-assign-issue-to-user.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-byok-ollama-test.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-cli-performance.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-cli-tools-tester.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-community-attribution.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-compiler-quality.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-credit-limit-test.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-experiment-report.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-file-diet.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-firewall-report.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-formal-spec-verifier.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-geo-optimizer.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-issues-report.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-malicious-code-scan.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-max-ai-credits-test.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-mcp-concurrency-analysis.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-model-inventory.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-model-resolution.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-performance-summary.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-regulatory.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-repo-chronicle.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-safe-output-integrator.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-security-observability.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-secrets-analysis.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-semgrep-scan.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-sentrux-report.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-skill-optimizer.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-spdd-spec-planner.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-syntax-error-quality.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-team-status.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-testify-uber-super-expert.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-windows-terminal-integration-builder.lock.yml Regenerated Copilot execution trap.
.github/workflows/daily-workflow-updater.lock.yml Regenerated Copilot execution trap.
.github/workflows/dataflow-pr-discussion-dataset.lock.yml Regenerated Copilot execution trap.
.github/workflows/dead-code-remover.lock.yml Regenerated Copilot execution trap.
.github/workflows/delight.lock.yml Regenerated Copilot execution trap.
.github/workflows/dependabot-burner.lock.yml Regenerated Copilot execution trap.
.github/workflows/dependabot-go-checker.lock.yml Regenerated Copilot execution trap.
.github/workflows/deployment-incident-monitor.lock.yml Regenerated Copilot execution trap.
.github/workflows/designer-drift-audit.lock.yml Regenerated Copilot execution trap.
.github/workflows/dev-hawk.lock.yml Regenerated Copilot execution trap.
.github/workflows/dictation-prompt.lock.yml Regenerated Copilot execution trap.
.github/workflows/discussion-task-miner.lock.yml Regenerated Copilot execution trap.
.github/workflows/docs-noob-tester.lock.yml Regenerated Copilot execution trap.
.github/workflows/draft-pr-cleanup.lock.yml Regenerated Copilot execution trap.
.github/workflows/eslint-miner.lock.yml Regenerated Copilot execution trap.
.github/workflows/eslint-monster.lock.yml Regenerated Copilot execution trap.
.github/workflows/example-failure-category-filter.lock.yml Regenerated Copilot execution trap.
.github/workflows/example-permissions-warning.lock.yml Regenerated Copilot execution trap.
.github/workflows/firewall-escape.lock.yml Regenerated Copilot execution trap.
.github/workflows/firewall.lock.yml Regenerated Copilot execution trap.
.github/workflows/functional-pragmatist.lock.yml Regenerated Copilot execution trap.
.github/workflows/github-remote-mcp-auth-test.lock.yml Regenerated Copilot execution trap.
.github/workflows/glossary-maintainer.lock.yml Regenerated Copilot execution trap.
.github/workflows/gpclean.lock.yml Regenerated Copilot execution trap.
.github/workflows/impeccable-skills-reviewer.lock.yml Regenerated Copilot execution trap.
.github/workflows/issue-monster.lock.yml Regenerated Copilot execution trap.
.github/workflows/issue-triage-agent.lock.yml Regenerated Copilot execution trap.
.github/workflows/jsweep.lock.yml Regenerated Copilot execution trap.
.github/workflows/layout-spec-maintainer.lock.yml Regenerated Copilot execution trap.
.github/workflows/lint-monster.lock.yml Regenerated Copilot execution trap.
.github/workflows/linter-miner.lock.yml Regenerated Copilot execution trap.
.github/workflows/mattpocock-skills-reviewer.lock.yml Regenerated Copilot execution trap.
.github/workflows/mcp-inspector.lock.yml Regenerated Copilot execution trap.
.github/workflows/mergefest.lock.yml Regenerated Copilot execution trap.
.github/workflows/metrics-collector.lock.yml Regenerated Copilot execution trap.
.github/workflows/notion-issue-summary.lock.yml Regenerated Copilot execution trap.
.github/workflows/objective-impact-report.lock.yml Regenerated Copilot execution trap.
.github/workflows/org-health-report.lock.yml Regenerated Copilot execution trap.
.github/workflows/outcome-collector.lock.yml Regenerated Copilot execution trap.
.github/workflows/pdf-summary.lock.yml Regenerated Copilot execution trap.
.github/workflows/plan.lock.yml Regenerated Copilot execution trap.
.github/workflows/poem-bot.lock.yml Regenerated Copilot execution trap.
.github/workflows/pr-code-quality-reviewer.lock.yml Regenerated Copilot execution trap.
.github/workflows/pr-description-caveman.lock.yml Regenerated Copilot execution trap.
.github/workflows/pr-nitpick-reviewer.lock.yml Regenerated Copilot execution trap.
.github/workflows/pr-sous-chef.lock.yml Regenerated Copilot execution trap.
.github/workflows/pr-triage-agent.lock.yml Regenerated Copilot execution trap.
.github/workflows/python-data-charts.lock.yml Regenerated Copilot execution trap.
.github/workflows/q.lock.yml Regenerated Copilot execution trap.
.github/workflows/refactoring-cadence.lock.yml Regenerated Copilot execution trap.
.github/workflows/refiner.lock.yml Regenerated Copilot execution trap.
.github/workflows/release.lock.yml Regenerated Copilot execution trap.
.github/workflows/repo-audit-analyzer.lock.yml Regenerated Copilot execution trap.
.github/workflows/repo-tree-map.lock.yml Regenerated Copilot execution trap.
.github/workflows/repository-quality-improver.lock.yml Regenerated Copilot execution trap.
.github/workflows/research.lock.yml Regenerated Copilot execution trap.
.github/workflows/schema-consistency-checker.lock.yml Regenerated Copilot execution trap.
.github/workflows/security-compliance.lock.yml Regenerated Copilot execution trap.
.github/workflows/security-review.lock.yml Regenerated Copilot execution trap.
.github/workflows/sighthound-security-scan.lock.yml Regenerated Copilot execution trap.
.github/workflows/skillet.lock.yml Regenerated Copilot execution trap.
.github/workflows/slide-deck-maintainer.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-ci.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot-aoai-apikey.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot-aoai-entra.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot-arm.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot-mai.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot-sdk.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot-small.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot-sub-agents.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-copilot.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-create-cross-repo-pr.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-multi-pr.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-otel-backends.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-pi.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-project.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-service-ports.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-temporary-id.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-test-tools.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-update-cross-repo-pr.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-workflow-call-with-inputs.lock.yml Regenerated Copilot execution trap.
.github/workflows/smoke-workflow-call.lock.yml Regenerated Copilot execution trap.
.github/workflows/spec-enforcer.lock.yml Regenerated Copilot execution trap.
.github/workflows/spec-extractor.lock.yml Regenerated Copilot execution trap.
.github/workflows/spec-librarian.lock.yml Regenerated Copilot execution trap.
.github/workflows/stale-pr-cleanup.lock.yml Regenerated Copilot execution trap.
.github/workflows/stale-repo-identifier.lock.yml Regenerated Copilot execution trap.
.github/workflows/sub-issue-closer.lock.yml Regenerated Copilot execution trap.
.github/workflows/super-linter.lock.yml Regenerated Copilot execution trap.
.github/workflows/technical-doc-writer.lock.yml Regenerated Copilot execution trap.
.github/workflows/terminal-stylist.lock.yml Regenerated Copilot execution trap.
.github/workflows/test-quality-sentinel.lock.yml Regenerated Copilot execution trap.
.github/workflows/tidy.lock.yml Regenerated Copilot execution trap.
.github/workflows/ubuntu-image-analyzer.lock.yml Regenerated Copilot execution trap.
.github/workflows/uk-ai-operational-resilience.lock.yml Regenerated Copilot execution trap.
.github/workflows/unbloat-docs.lock.yml Regenerated Copilot execution trap.
.github/workflows/update-astro.lock.yml Regenerated Copilot execution trap.
.github/workflows/video-analyzer.lock.yml Regenerated Copilot execution trap.
.github/workflows/visual-regression-checker.lock.yml Regenerated Copilot execution trap.
.github/workflows/weekly-blog-post-writer.lock.yml Regenerated Copilot execution trap.
.github/workflows/weekly-editors-health-check.lock.yml Regenerated Copilot execution trap.
.github/workflows/weekly-issue-summary.lock.yml Regenerated Copilot execution trap.
.github/workflows/weekly-safe-outputs-spec-review.lock.yml Regenerated Copilot execution trap.
.github/workflows/workflow-generator.lock.yml Regenerated Copilot execution trap.
.github/workflows/workflow-health-manager.lock.yml Regenerated Copilot execution trap.
.github/workflows/workflow-normalizer.lock.yml Regenerated Copilot execution trap.
.github/workflows/workflow-skill-extractor.lock.yml Regenerated Copilot execution trap.

Review details

Tip

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

  • Files reviewed: 170/170 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment on lines +102 to +107
func buildCopilotSettingsCleanupAndExitCodeTrap() string {
return fmt.Sprintf(
"trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf \"%%s\" \"$gh_aw_exit_code\" > %s || true; rm -f \"%s\"' EXIT\n",
agentExecutionExitCodePath,
copilotSettingsPath,
)

@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.

LGTM

The fix correctly addresses the silent-failure gap in sendJobConclusionSpan.

Key points verified:

  • Trap correctness: Single-quoted trap body captures exit code at fire-time before cleanup. HOME expansion also works correctly at evaluation time.
  • Priority ordering: Exit-code check takes precedence over error-count check, which is the exact gap being fixed.
  • Zero-exit safety: The agentExecutionExitCode !== 0 guard prevents false positives on successful runs.
  • Both execution paths covered: Both buildCopilotAWFPathSetup and buildCopilotDirectCommand now use the new trap.
  • Test coverage: The new test case directly exercises the regression scenario (exit code 22, zero errors, absent conclusion maps to failure/STATUS_CODE_ERROR).
  • Lock files: Consistently regenerated across all 167 workflows.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 46.7 AIC · ⌖ 5.18 AIC · ⊞ 5K

@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 and /tdd — requesting changes on two issues.

📋 Key Themes & Highlights

Key Issues

  1. Signal loss when exit code + errors coexist (send_otlp_span.cjs:2080): The hasAgentExecutionFailureExitCode branch takes full priority over outputErrors, silently discarding richer error context. No test covers this case.

  2. Dead code + stale tests (copilot_engine_execution.go:89–95): buildCopilotSettingsCleanupTrap() is no longer called in production but was not deleted. Three tests in copilot_home_expansion_test.go continue to test it, giving false confidence. The important $HOME-at-trap-fire-time property is not asserted for the new buildCopilotSettingsCleanupAndExitCodeTrap.

  3. Missing edge-case tests (send_otlp_span.test.cjs): readIntegerIfExists gracefully handles malformed content, but no test locks this in as a regression guard.

Positive Highlights

  • ✅ Correct root-cause fix: EXIT trap → persisted file → post-step span reads it. Clean and reliable across fresh shell environments.
  • readIntegerIfExists is a well-isolated helper with solid null/error handling.
  • ✅ The new gh-aw.agent.execution.exit_code attribute improves OTel query surface.
  • ✅ Regression test is well-structured with clear Arrange/Act/Assert and good assertions.

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

// agent job's own post-step where needs.<job>.result is not yet visible), fall back to
// observable failure evidence so gh-aw.run.status and status.code are accurate.
if (!rawRunStatus && outputErrors.length > 0) {
if (!rawRunStatus && hasAgentExecutionFailureExitCode) {

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] When hasAgentExecutionFailureExitCode is true AND outputErrors is non-empty, the error messages are silently discarded — the span says only "copilot cli exited with code N" with no hint of actual errors. This makes the non-zero-exit case less diagnosable than the errors-only path.

💡 Suggestion

Combine both signals when both are present:

if (!rawRunStatus && hasAgentExecutionFailureExitCode) {
  runStatus = "failure";
  statusCode = 2;
  const errSuffix = errorMessages.length > 0 ? `; errors detected: ${errorMessages[0]}` : "";
  statusMessage = `copilot cli exited with code ${agentExecutionExitCode}${errSuffix}`.slice(0, 256);
} else if (!rawRunStatus && outputErrors.length > 0) {

Also add a test: non-zero exit + errors present → message includes both signals.

@copilot please address this.

// time (matching buildCopilotSettingsCleanupTrap behavior).
func buildCopilotSettingsCleanupAndExitCodeTrap() string {
return fmt.Sprintf(
"trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf \"%%s\" \"$gh_aw_exit_code\" > %s || true; rm -f \"%s\"' EXIT\n",

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.

[/tdd] buildCopilotSettingsCleanupTrap() is now dead code — both call sites in production were replaced by buildCopilotSettingsCleanupAndExitCodeTrap(), but the old function was left in place. The three tests in copilot_home_expansion_test.go (lines 106, 308, 444) still test the removed behaviour and give false confidence.

💡 Suggestion

Either:

  1. Delete buildCopilotSettingsCleanupTrap and migrate those 3 tests to cover buildCopilotSettingsCleanupAndExitCodeTrap (preferred — ensures the new trap is tested for the $HOME-expansion-at-fire-time property), or
  2. Keep it as a private helper called by the new function to reduce duplication.

The $HOME-at-fire-time property tested in TestBuildCopilotSettingsCleanupTrap_SingleQuotedSoHomeExpandsAtTrapFire is equally important for the new trap — add an equivalent assertion.

@copilot please address this.

@@ -5127,6 +5127,34 @@ describe("sendJobConclusionSpan", () => {
expect(attrs["gh-aw.run.status"]).toBe("success");

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.

[/tdd] The new test only covers the "happy path" of the new feature (exit code 22, no errors). The case where agentExecutionExitCode file contains non-integer content (e.g. empty string, "abc", whitespace) is not covered — readIntegerIfExists handles it, but a test would lock that in as a regression guard.

💡 Missing test cases

Add at minimum:

  • agent_execution_exit_code.txt contains "abc" → treated as absent, falls back to error-count logic
  • agent_execution_exit_code.txt contains " \n" (whitespace only) → same
  • File absent (already covered by ENOENT in other tests, but explicit is better)

@copilot please address this.

…t-conclusion-status

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

@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.

Review: OTLP conclusion exit-code fix — mostly correct, several gaps

The core fix (EXIT trap + readIntegerIfExists fallback when both conclusion signals are absent) is sound and closes the original bug. However there are correctness issues that leave residual blind spots.

Blocking issues (2)
  1. Non-zero exit code ignored when rawRunStatus is present (line 2080) — the fix only applies when agentConclusion AND workflowRunConclusion are both absent. If workflowRunConclusion=success is visible in the post-step environment while the CLI actually exited non-zero, the status is still reported as success. This is the most likely scenario on the class of runs the PR intends to fix.

  2. Stale exit-code file on self-hosted/reused runners (line 41 in Go) — the trap writes but never deletes the file, and the setup step does not clear it before the run. A prior non-zero exit code survives into the next run and will falsely flag a successful run as failed.

Medium issues (3)
  • parseInt permissiveness in readIntegerIfExists combined with a non-atomic printf > write (line 1516)
  • else if discards outputErrors detail when both failure signals are present (line 2084)
  • gh-aw.agent.execution.exit_code attribute is absent when file is missing — 0 vs "trap never fired" are indistinguishable (line 2060)
Low issues (1)
  • buildCopilotSettingsCleanupTrap is dead production code; its tests give false coverage confidence (line 92)

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 176.5 AIC · ⌖ 5.56 AIC · ⊞ 5.7K
Comment /review to run again

Comments that could not be inline-anchored

actions/setup/js/send_otlp_span.cjs:2080

Exit code ignored when rawRunStatus is present — a non-zero Copilot CLI exit still reports run.status=success if workflowRunConclusion is set.

<details>
<summary>💡 Details and suggested fix</summary>

The fix correctly handles the case where both agentConclusion and workflowRunConclusion are absent. But it misses the inverse: when workflowRunConclusion returns &quot;success&quot; (or any value other than &quot;failure&quot;) while the Copilot CLI actually exited non-zero, rawRunStatus i…

actions/setup/js/send_otlp_span.cjs:2084

else if discards error detail when both exit-code failure and output errors are presentstatusMessage will be &quot;copilot cli exited with code N&quot; even when outputErrors contain more specific diagnostics.

<details>
<summary>💡 Details</summary>

The branch order is:

if (!rawRunStatus &amp;&amp; hasAgentExecutionFailureExitCode) {
  statusMessage = `copilot cli exited with code ${agentExecutionExitCode}`;
} else if (!rawRunStatus &amp;&amp; outputErrors.length &gt; 0) {
  statusMessage = `errors d…

</details>

<details><summary>actions/setup/js/send_otlp_span.cjs:1516</summary>

**`parseInt` accepts partially-numeric content** — `readIntegerIfExists(&quot;22abc&quot;)` silently returns `22`, potentially reading a partially-written exit-code file as a valid exit code.

&lt;details&gt;
&lt;summary&gt;💡 Details&lt;/summary&gt;

`parseInt(&quot;22abc&quot;, 10)` returns `22`. `Number.isInteger(22)` is `true`. So if the write

```sh
printf &quot;%s&quot; &quot;$gh_aw_exit_code&quot; &gt; /tmp/gh-aw/agent_execution_exit_code.txt

is interrupted mid-write under disk pressure (unlikely but possible), a partial file like &quot;2&quot; or `"…

pkg/workflow/copilot_engine_execution.go:41

Stale exit-code file on self-hosted/reused runners will falsely mark a good run as failed — the setup step does not clear this file before the agent runs.

<details>
<summary>💡 Details</summary>

The EXIT trap only writes /tmp/gh-aw/agent_execution_exit_code.txt — it never deletes it. GitHub-hosted runners are ephemeral, but self-hosted runners and matrix jobs on cached runners reuse the same /tmp between runs. If a prior run left a non-zero exit code in this file and the next run's Co…

pkg/workflow/copilot_engine_execution.go:92

buildCopilotSettingsCleanupTrap is now dead production code — it is never called outside of tests, which still assert against its old output and give false confidence.

<details>
<summary>💡 Details</summary>

All production call sites now use buildCopilotSettingsCleanupAndExitCodeTrap. The old function exists at line 92 with three test cases in copilot_home_expansion_test.go that assert against its single-cleanup-only trap body. Those tests are now testing a code path that is never e…

actions/setup/js/send_otlp_span.cjs:2060

gh-aw.agent.execution.exit_code absent when file is missing makes 0 vs missing ambiguous — consumers cannot tell whether the agent exited cleanly or the trap never fired.

<details>
<summary>💡 Details</summary>

The attribute is only emitted when the file exists and contains a valid integer:

if (Number.isInteger(agentExecutionExitCode)) {
  attributes.push(buildAttr(&quot;gh-aw.agent.execution.exit_code&quot;, agentExecutionExitCode));
}

Absence means either:

  • Agent step was skipped (t…

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions

Copy link
Copy Markdown
Contributor

📰 BREAKING: Smoke Copilot - AOAI (apikey) is now investigating this pull request. Sources say the story is developing...

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot Small completed successfully!

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot MAI completed successfully!

@github-actions

Copy link
Copy Markdown
Contributor

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions

Copy link
Copy Markdown
Contributor

📰 BREAKING: Smoke Copilot - AOAI (Entra) is now investigating this pull request. Sources say the story is developing...

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Smoke OTEL completed successfully!

@github-actions

Copy link
Copy Markdown
Contributor

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.54.0
jq 1.7
yq v4.53.3
curl 8.5.0
gh 2.96.0
node v20.20.2
python3 3.11.15 (PyPy 7.3.23)
go 1.24.13
java 10.0.301
dotnet 10.0.301

Result: 12/12 tools available ✅

Overall Status: PASS

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.

🔧 Tool validation by Agent Container Smoke Test · sonnet46 9.56 AIC · ⌖ 5.59 AIC · ⊞ 4.9K ·
Comment /smoke-test-tools to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: FAIL\n\n✅ GitHub MCP Testing\n✅ Web Fetch Testing\n✅ File Writing Testing\n✅ Bash Tool Testing\n❌ Build gh-aw\n\nOverall status: FAIL

Warning

Firewall blocked 1 domain

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

  • localhost

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

network:
  allowed:
    - defaults
    - "localhost"

See Network Configuration for more information.

Smoke Gemini — Powered by Gemini · age00 8.19 AIC · ⌖ 1.59 AIC · ⊞ 9.3K ·
Comment /smoke-gemini to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke test FAIL

  • ✅ gh CLI
  • ✅ web fetch
  • ✅ file write
  • ✅ bash verify
  • ❌ build

Warning

Firewall blocked 1 domain

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

  • proxy.golang.org

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

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🥧 Smoke Pi — Powered by Pi · gpt54 2.13 AIC · ⌖ 6.68 AIC · ⊞ 4.5K ·
Comment /smoke-pi to run again

@github-actions

Copy link
Copy Markdown
Contributor

Merged PRs: #47288 feat(linters): add stringsjoinone analyzer; #47287 refactor(pkg/workflow): break up 5 large functions exceeding 60-line lint limit
1: ✅ 2: ✅ 3: ✅ 4: ❌ 5: ✅ 6: ✅ 7: ✅ 8: ✅ 9: ✅ 10: skipped
Overall: FAIL

Warning

Firewall blocked 1 domain

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

  • aus5.mozilla.org

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

network:
  allowed:
    - defaults
    - "aus5.mozilla.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · gpt54 2.11 AIC · ⌖ 1.17 AIC · ⊞ 29.2K ·
Comment /smoke-codex to run again

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

Dawn static and bright
Silent checks hum through the shell
Tests leave faint footprints

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

Warning

Firewall blocked 1 domain

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

  • aus5.mozilla.org

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

network:
  allowed:
    - defaults
    - "aus5.mozilla.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · gpt54 2.11 AIC · ⌖ 1.17 AIC · ⊞ 29.2K ·
Comment /smoke-codex to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke test 29923969749
PRs: OTLP conclusion: mark non-zero Copilot CLI exits as run failures when conclusion/error signals are absent; feat(linters): add stringsjoinone analyzer; refactor(pkg/workflow): break up 5 large functions exceeding 60-line lint limit
1❌ 2✅ 3✅ 4❌ 5❌ 6✅ 7✅ 8✅
9✅ 10❌ 11✅ 12✅ 13✅ 14✅ 15✅ 16✅
Overall: FAIL
Author: app/copilot-swe-agent
Assignees: pelikhan, Copilot

📰 BREAKING: Report filed by Smoke Copilot · gpt54 87.5 AIC · ⌖ 8.14 AIC · ⊞ 19.4K ·
Comment /smoke-copilot to run again
Add label smoke to run again

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

Bots drum tiny tests
Night run taps the workflow gate
Green sparks wake the forge

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

📰 BREAKING: Report filed by Smoke Copilot · gpt54 87.5 AIC · ⌖ 8.14 AIC · ⊞ 19.4K ·
Comment /smoke-copilot to run again
Add label smoke 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.

Smoke pass walk done. Me leave two tiny inline notes.

📰 BREAKING: Report filed by Smoke Copilot · gpt54 87.5 AIC · ⌖ 8.14 AIC · ⊞ 19.4K
Comment /smoke-copilot to run again
Add label smoke 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.

💥 Automated smoke test review - all systems nominal! — Run 29923680952

💥 [THE END] — Illustrated by Smoke Claude · sonnet46 90.2 AIC · ⌖ 19.5 AIC · ⊞ 6.1K
Comment /smoke-claude to run again

const outputItems = Array.isArray(agentOutput.items) ? agentOutput.items : [];
const errorMessages = outputErrors.map(getErrorMessage).filter(Boolean).slice(0, 5);
const agentExecutionExitCode = readIntegerIfExists(AGENT_EXECUTION_EXIT_CODE_PATH);
const hasAgentExecutionFailureExitCode = Number.isInteger(agentExecutionExitCode) && agentExecutionExitCode !== 0;

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.

👍 Good use of Number.isInteger() for null safety here. Consider also documenting the fallback behavior when the file is absent (returns null) in a JSDoc comment above readIntegerIfExists to make this contract explicit. — Smoke Test Run 29923680952

//
// The body is single-quoted so $HOME in copilotSettingsPath is expanded at trap-fire
// time (matching buildCopilotSettingsCleanupTrap behavior).
func buildCopilotSettingsCleanupAndExitCodeTrap() string {

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 buildCopilotSettingsCleanupAndExitCodeTrap() function nicely captures the exit code before cleanup. One suggestion: consider using || : instead of || true for POSIX portability in the trap body. — Smoke Test Run 29923680952

@github-actions

Copy link
Copy Markdown
Contributor

Smoke tests results:

  1. GitHub PR review: ✅
  2. mcpscripts GH PR list: ✅
  3. Serena find_symbol: ✅
  4. Playwright CLI: ❌
  5. Web-fetch: ✅
  6. File creation & cat: ✅
  7. Discussion comment: ✅
  8. Build: ✅
  9. Artifact upload: ❌
  10. Discussion creation: ✅
  11. Workflow dispatch: ✅
  12. PR review tools: ❌
  13. Comment memory: ✅
  14. File summarizer: ✅
  15. Check run creation: ✅

Overall Status: FAIL

📰 BREAKING: Report filed by Smoke Copilot - AOAI (apikey) · o40mini 53.9 AIC · ⌖ 3.33 AIC · ⊞ 18.2K ·
Comment /smoke-copilot-aoai-apikey to run again
Add label smoke to run again

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

Smoke tests ignite
Promises and failures burn
Lessons in ashes

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

📰 BREAKING: Report filed by Smoke Copilot - AOAI (apikey) · o40mini 53.9 AIC · ⌖ 3.33 AIC · ⊞ 18.2K ·
Comment /smoke-copilot-aoai-apikey to run again
Add label smoke to run again

@pelikhan
pelikhan merged commit 3fc72ac into main Jul 22, 2026
255 checks passed
@pelikhan
pelikhan deleted the copilot/otel-fix-agent-conclusion-status branch July 22, 2026 13:54
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.83.0

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.

otel: gh-aw.agent.conclusion reports run.status=success / STATUS_CODE_OK when the Copilot CLI step exits non-zero (error_count=0)

3 participants