Skip to content

Harden Claude startup failure handling for empty-log Avenger runs#44332

Open
pelikhan with Copilot wants to merge 9 commits into
mainfrom
copilot/aw-fix-avenger-startup-issue
Open

Harden Claude startup failure handling for empty-log Avenger runs#44332
pelikhan with Copilot wants to merge 9 commits into
mainfrom
copilot/aw-fix-avenger-startup-issue

Conversation

Copilot AI commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Claude-engine Avenger runs were failing at startup with zero structured log entries, collapsing distinct startup conditions into a generic ERR_CONFIG and providing little actionable context. This change improves startup observability, adds bounded recovery for transient empty-start exits, and aligns empty-log classification with existing inference/rate-limit outputs.

  • Startup failure diagnostics (empty structured logs)

    • Added Claude-specific startup diagnostics extraction in log_parser_bootstrap.cjs when logEntries is empty.
    • Emits exit-code-aware context and a concise stderr-tail section into step summary before failing.
    • Keeps safe-output-backed post-completion behavior unchanged (still non-fatal warning path).
  • Failure classification alignment

    • Distinguishes startup/config failures from transient inference availability signals.
    • Sets existing outputs on empty-log startup failures when matched:
      • inference_access_error=true
      • ai_credits_rate_limit_error=true
    • Uses ERR_API for transient inference availability signatures; retains ERR_CONFIG for true startup/config cases.
  • Bounded startup retry for zero-output exits

    • Added fresh-run startup retries in claude_harness.cjs for no-output startup failures (non---continue path).
    • Default startup retry budget: 1; configurable via GH_AW_CLAUDE_STARTUP_RETRIES (clamped to 0..2).
    • Existing partial-execution retry semantics remain intact.
  • Targeted parser/harness updates

    • Extended tests to cover:
      • empty-log failure message/diagnostics behavior,
      • transient classification + output flags on empty-startup signatures,
      • bounded no-output startup retry behavior and config clamping.
if (parserName === "Claude" && (!logEntries || logEntries.length === 0)) {
  const diagnostics = buildClaudeStartupDiagnostics(content);
  if (diagnostics.inferenceAccessError) core.setOutput("inference_access_error", "true");
  if (diagnostics.aiCreditsRateLimitError) core.setOutput("ai_credits_rate_limit_error", "true");

  const errorCode =
    diagnostics.inferenceAccessError || diagnostics.transientInferenceAvailabilityError
      ? ERR_API
      : ERR_CONFIG;
  core.setFailed(`${errorCode}: Claude execution failed: no structured log entries were produced. ${diagnostics.summaryLine}`);
}

Copilot AI and others added 8 commits July 8, 2026 15:47
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Avenger's Claude engine startup failure due to missing log entries Harden Claude startup failure handling for empty-log Avenger runs Jul 8, 2026
Copilot AI requested a review from pelikhan July 8, 2026 16:16
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category bug
Risk 🟡 medium
Score 53/100 (impact:28 urgency:15 quality:10)
Action ⚡ fast_track

Status: DRAFT — needs undraft + CI before review.

Improves Claude/Avenger startup observability and adds bounded recovery for empty-log failures. Complements #44354 — both target the same failure mode from different layers. Small diff (185+/6-) across 5 files.

Run §28966928999

Generated by 🔧 PR Triage Agent · 106.9 AIC · ⌖ 10.9 AIC · ⊞ 5.4K ·

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category bug (error handling)
Risk 🟡 Medium
Priority Score 60 / 100
Action 🚀 fast_track

Score breakdown: Impact 32 + Urgency 20 + Quality 8

Rationale: DRAFT. Hardens Claude startup failure handling for empty-log Avenger runs — prevents silent failures from propagating. Medium risk; behaviour-protective. Needs undraft + CI.

Run §28986426320

Generated by 🔧 PR Triage Agent · 74.6 AIC · ⌖ 8.8 AIC · ⊞ 5.4K ·

@pelikhan pelikhan marked this pull request as ready for review July 9, 2026 01:17
Copilot AI review requested due to automatic review settings July 9, 2026 01:17

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

Improves observability and classification for Claude-engine “empty structured log” startup failures in gh-aw’s setup action code, and adds a bounded “fresh run” retry for no-output startup exits to reduce flakiness.

Changes:

  • Added Claude-specific startup diagnostics extraction and failure classification when logEntries is empty, including step-summary diagnostics and ERR_API vs ERR_CONFIG selection.
  • Added bounded startup retry handling for no-output exits in claude_harness.cjs, configurable via GH_AW_CLAUDE_STARTUP_RETRIES (clamped to 0..2).
  • Expanded JS tests to cover the new messages, transient classification/output flags, and startup retry behavior/clamping.
Show a summary per file
File Description
actions/setup/js/parse_claude_log.test.cjs Updates expectations for Claude empty-structured-log failure messaging.
actions/setup/js/log_parser_bootstrap.test.cjs Adds coverage for empty-log diagnostics classification and output flags (e.g., rate-limit signatures).
actions/setup/js/log_parser_bootstrap.cjs Implements Claude startup diagnostics extraction, step-summary emission, output flagging, and error-code classification when no structured logs are parsed.
actions/setup/js/claude_harness.test.cjs Adds tests for default startup retry behavior and env var clamping.
actions/setup/js/claude_harness.cjs Implements bounded fresh-run startup retries for no-output startup failures and adds retry-limit parsing/clamping.

Review details

Tip

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

  • Files reviewed: 5/5 changed files
  • Comments generated: 3
  • Review effort level: Low

Comment on lines +32 to +33
const startupLines = lines.filter(line => line.includes("[claude-harness]") || STARTUP_DIAGNOSTIC_LINE_PATTERN.test(line));
const diagnosticLines = startupLines.length > 0 ? startupLines : lines;
Comment on lines +61 to +62
const summaryLine = `Claude startup failed before structured logging (exitCode=${exitCode}).`;
const summaryMarkdown = tailText ? `<details><summary>Claude startup diagnostics</summary>\n\n\`\`\`text\n${tailText}\n\`\`\`\n</details>` : "";
Comment on lines +425 to +426
const errorCode = diagnostics.inferenceAccessError || diagnostics.transientInferenceAvailabilityError ? ERR_API : ERR_CONFIG;
const failureKind = diagnostics.inferenceAccessError || diagnostics.transientInferenceAvailabilityError ? "transient inference availability signal detected" : "startup/configuration failure detected";
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

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

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

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer is reviewing this pull request using Matt Pocock's engineering skills...

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

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

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

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

📊 Metrics (3 tests)
Metric Value
Analyzed 3 (Go: 0, JS: 3)
✅ Design 3 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 3 (100%)
Duplicate clusters 0
Inflation No
🚨 Violations 0
Test File Classification Issues
retries one no-output startup failure as a fresh run by default claude_harness.test.cjs:449 design_test / behavioral_contract None
uses startup retry default and clamps overrides to [0..2] claude_harness.test.cjs:578 design_test / behavioral_contract None
should classify Claude empty-log startup rate-limit signatures as transient inference availability log_parser_bootstrap.test.cjs:278 design_test / behavioral_contract None

Modified tests (string-literal updates only — not newly scored):

  • 3 tests in log_parser_bootstrap.test.cjs updated expected error message string to match new format
  • 1 test in parse_claude_log.test.cjs updated expected error message string

Verdict

Passed. 0% implementation tests (threshold: 30%). All 3 new tests verify user-visible behavioral contracts with edge-case and error-path coverage:

  • Retry-as-fresh-run integration test exercises the actual harness subprocess with a first-call-fails stub, asserting exit 0, call count 2, absence of --continue in second call, and the correct stderr message.
  • resolveStartupRetryLimit unit test validates the configuration API contract: default, upper clamp, lower clamp, and non-numeric fallback — all edge cases covered.
  • Rate-limit classification test verifies the 429-signature routing produces ERR_API (not ERR_CONFIG) and sets the ai_credits_rate_limit_error output flag.

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 · 50.8 AIC · ⌖ 11.3 AIC · ⊞ 6.8K ·
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%).

@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: Harden Claude startup failure handling

Overall the change is well-structured and the startup-retry mechanism is correctly bounded. Two issues need addressing before merge.

Blocking

  1. failureKind is semantically wrong for inferenceAccessError (line 426, log_parser_bootstrap.cjs): When the matched pattern is Access denied by policy settings|invalid access to inference, the error message says "transient inference availability signal detected" — but a policy denial is not transient. Operators and downstream tooling may incorrectly expect a retry to resolve it. See the inline comment for a 3-way fix.

Non-blocking (but worth fixing)

  1. Raw log content injected into markdown code fence (line 62, log_parser_bootstrap.cjs): If a log line contains triple-backticks the step-summary code block breaks, leaking remaining content as rendered markdown. Escaping or replacing triple-backtick sequences in tailText before embedding would prevent this.

Everything else (retry loop logic, clamping, ERR_API vs ERR_CONFIG classification, output flag routing, test coverage) looks correct.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 149.6 AIC · ⌖ 6.37 AIC · ⊞ 4.8K

}

const errorCode = diagnostics.inferenceAccessError || diagnostics.transientInferenceAvailabilityError ? ERR_API : ERR_CONFIG;
const failureKind = diagnostics.inferenceAccessError || diagnostics.transientInferenceAvailabilityError ? "transient inference availability signal detected" : "startup/configuration failure detected";

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.

Misleading failureKind for inferenceAccessError — policy denial is not transient

When inferenceAccessError is true the combined condition fires and sets:

failureKind = "transient inference availability signal detected";

But INFERENCE_ACCESS_ERROR_PATTERN matches Access denied by policy settings|invalid access to inference — these are non-transient policy denials. Labelling them "transient" misleads operators (and any downstream automation parsing the error message) into expecting a retry will self-resolve the problem.

Suggested fix — split the two cases:

const failureKind = diagnostics.inferenceAccessError
  ? "inference access denied by policy"
  : diagnostics.transientInferenceAvailabilityError
    ? "transient inference availability signal detected"
    : "startup/configuration failure detected";

The errorCode = ERR_API for both is fine; only the human-readable failureKind string needs to be differentiated.

@copilot please address this.

const aiCreditsRateLimitError = CLAUDE_RATE_LIMIT_PATTERN.test(content) || CLAUDE_OVERLOAD_PATTERN.test(content);
const transientInferenceAvailabilityError = aiCreditsRateLimitError || CLAUDE_HTTP_5XX_STATUS_PATTERN.test(content);
const summaryLine = `Claude startup failed before structured logging (exitCode=${exitCode}).`;
const summaryMarkdown = tailText ? `<details><summary>Claude startup diagnostics</summary>\n\n\`\`\`text\n${tailText}\n\`\`\`\n</details>` : "";

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.

Embedded triple-backtick fences in raw log content can break the summaryMarkdown code block

tailText is raw log content inserted directly into a fenced code block:

const summaryMarkdown = tailText
  ? `<details>...\n\`\`\`text\n${tailText}\n\`\`\`\n</details>`
  : "";

If any log line itself contains ```` the fence closes prematurely, leaking the rest of the log content as rendered markdown in the GitHub Actions step summary. While this doesn't affect control flow, it can expose unescaped content in the step summary view.

Consider stripping or escaping triple-backtick sequences from tailText before embedding:

const safeTailText = tailText.replace(/```/g, "'''");\n// then use safeTailText in the template

@copilot please address this.

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

Projects

None yet

3 participants