Detect unknown_model_ai_credits failure in conclusion job#38610
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves failure reporting when max-ai-credits is enabled and the requested model is not present in the built-in AI credits pricing table by surfacing an unknown_model_ai_credits signal to the conclusion job and ensuring it can be rendered in the failure comment/issue templates.
Changes:
- Expose
unknown_model_ai_creditsas an agent job output sourced fromparse-mcp-gateway, and forward it to the conclusion job viaGH_AW_UNKNOWN_MODEL_AI_CREDITS. - Update agent failure templates to include
{unknown_model_ai_credits_context}alongside existing AI-credits failure contexts. - Add a focused compiler/lockfile assertion test and refresh golden/lockfile fixtures to include the new output wiring.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/compiler_main_job.go | Adds unknown_model_ai_credits to the agent job outputs map, sourced from the parse-mcp-gateway step. |
| pkg/workflow/notify_comment.go | Passes GH_AW_UNKNOWN_MODEL_AI_CREDITS into the conclusion job environment from agent outputs. |
| pkg/workflow/unknown_model_ai_credits_test.go | Adds a regression test asserting the output/env-var plumbing appears in compiled lock output. |
| actions/setup/md/agent_failure_comment.md | Includes {unknown_model_ai_credits_context} in the failure comment template insertion point. |
| actions/setup/md/agent_failure_issue.md | Includes {unknown_model_ai_credits_context} in the failure issue template insertion point. |
| pkg/workflow/testdata/TestWasmGolden_CompileFixtures/basic-copilot.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_CompileFixtures/with-imports.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_CompileFixtures/smoke-copilot.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_CompileFixtures/playwright-cli-mode.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_AllEngines/pi.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_AllEngines/copilot.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_AllEngines/codex.golden | Updates golden to include the new agent output. |
| pkg/workflow/testdata/TestWasmGolden_AllEngines/claude.golden | Updates golden to include the new agent output. |
| .github/workflows/*.lock.yml | Regenerates workflow lockfiles to propagate the new agent output and conclusion env var wiring across locked workflows. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 265/265 changed files
- Comments generated: 0
|
✅ PR Code Quality Reviewer completed the code quality review. |
|
✅ Design Decision Gate 🏗️ completed the design decision gate check. No ADR enforcement needed: PR #38610 does not have the "implementation" label (has_implementation_label=false) and has only 40 new lines of code in business logic directories, below the 100-line threshold (requires_adr_by_default_volume=false). |
|
🧠 Matt Pocock Skills Reviewer was skipped during the skills-based review. |
|
🧪 Test Quality Sentinel completed test quality analysis. |
🧪 Test Quality Sentinel Report
📊 Metrics & Test Classification (11 tests analyzed)
Test Classification Details
Language SupportTests analyzed:
|
There was a problem hiding this comment.
REQUEST_CHANGES — One critical correctness bug must be fixed before merge.
Blocking issues
Critical: writeStepSummaryWithTokenUsage deleted from main path (parse_mcp_gateway_log.cjs ~line 994)
The new setUnknownModelAICreditsOutput line replaced writeStepSummaryWithTokenUsage instead of being inserted alongside it. On every normal workflow run (the main code path through main()), this means:
core.summary.write()is never called → the step summary is silently discardedtoken-usage.jsonlis never read →GH_AW_AIC,aic,ambient_contextoutputs are never set- The unified event timeline is never appended
All three early-return paths (~lines 903, 934, 973) were updated correctly; only the terminal path at the bottom of main() was missed.
Medium: Redundant disk reads in hasUnknownModelAICreditsError (parse_mcp_gateway_log.cjs ~line 269)
The function unconditionally falls through to parseUnknownModelAICreditsFromAuditLog() when the in-memory pattern does not match, causing up to 5 sequential disk reads of the same audit log file (once per content source). This is inconsistent with hasAICreditsRateLimitError, which is content-only. See inline comment for the recommended refactor.
🔎 Code quality review by PR Code Quality Reviewer · ⌖ 21.9 AIC
| } | ||
| setAICreditsRateLimitOutput(core, aiCreditsRateLimitError); | ||
| writeStepSummaryWithTokenUsage(core); | ||
| setUnknownModelAICreditsOutput(core, unknownModelAICredits); |
There was a problem hiding this comment.
Dropped writeStepSummaryWithTokenUsage call breaks the main execution path: the step summary is never flushed, token usage (GH_AW_AIC, aic, ambient_context) is never exported, and the unified event timeline is never appended — silently, on every normal workflow run.
💡 Suggested fix
The new line was intended to be added alongside the existing call, not instead of it. All three early-return paths (lines ~903, ~934, ~973) already do this correctly. The final path was missed:
setAICreditsRateLimitOutput(core, aiCreditsRateLimitError);
setUnknownModelAICreditsOutput(core, unknownModelAICredits);
+ writeStepSummaryWithTokenUsage(core); // <-- must be re-added
} catch (error) {Without this call, core.summary.write() is never invoked, so any content queued with core.summary.addRaw() in the main path is silently discarded. Token-usage.jsonl is never read, so downstream jobs that depend on aic / ambient_context outputs will receive empty values.
| function hasUnknownModelAICreditsError(contents) { | ||
| const joined = contents.filter(Boolean).join("\n"); | ||
| if (joined && UNKNOWN_MODEL_AI_CREDITS_PATTERNS.some(pattern => pattern.test(joined))) return true; | ||
| return parseUnknownModelAICreditsFromAuditLog(); |
There was a problem hiding this comment.
hasUnknownModelAICreditsError reads the audit log from disk on every call: it unconditionally falls through to parseUnknownModelAICreditsFromAuditLog() when the in-memory pattern check fails. Because the function is called for each content source (gateway.jsonl, rpc-messages.jsonl, gateway.md, gateway.log, stderr.log), this means up to 5 sequential disk reads of the audit log when no error is detected — inconsistent with hasAICreditsRateLimitError, which is content-only.
💡 Suggested fix
Read the audit log once outside the per-source loop, using ||= to latch the result:
// Before the content-source loop, read audit log once
unknownModelAICredits ||= parseUnknownModelAICreditsFromAuditLog();Then simplify hasUnknownModelAICreditsError to only check in-memory content (matching the shape of hasAICreditsRateLimitError):
function hasUnknownModelAICreditsError(contents) {
const joined = contents.filter(Boolean).join("\n");
return joined ? UNKNOWN_MODEL_AI_CREDITS_PATTERNS.some(p => p.test(joined)) : false;
}This mirrors the existing architecture where audit-log parsing is centralised and done once, not embedded inside a per-content-block helper.
When
max-ai-creditsis active and the requested model isn't in the built-in pricing table, the AWF API proxy returns HTTP 400 with typeunknown_model_ai_credits. Previously this produced only a generic fallback message in the conclusion comment. Reference: run 27346208956Detection pipeline
Follows the same pattern as
ai_credits_rate_limit_error:ai_credits_context.cjs—parseUnknownModelAICreditsFromAuditLogwalks firewall audit JSONL for"type": "unknown_model_ai_credits"parse_mcp_gateway_log.cjs— detects across all log paths (gateway.jsonl, rpc-messages.jsonl, gateway.md, legacy logs), emitsunknown_model_ai_creditsstep outputcompiler_main_job.go— exposes it as an agent job output fromparse-mcp-gatewaynotify_comment.go— passesGH_AW_UNKNOWN_MODEL_AI_CREDITSenv var to the conclusion jobFailure message
New template
unknown_model_ai_credits.mdexplains the error is a non-transient config failure (not worth retrying) and offers three remediation paths:handle_agent_failure.cjs— reads env var, addsunknown_model_ai_creditsfailure category, newbuildUnknownModelAICreditsContextwired into both comment and issue template contextsagent_failure_comment.md/agent_failure_issue.md— insert{unknown_model_ai_credits_context}after{ai_credits_rate_limit_error_context}