Skip to content

Diagnose unavailable models and add code-specific debugging playbook - #69467

Merged
pelikhan merged 8 commits into
mainfrom
pelikhan-ci-failure-investigation
Oct 16, 2026
Merged

pelikhan merged 8 commits into
mainfrom
pelikhan-ci-failure-investigation

Conversation

@pelikhan

@pelikhan pelikhan commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Teach gh aw audit to recognize Pi's fatal model-not-advertised startup error and analyze the exact model against the same run's completed, matching provider inventory. Emit stable model_unavailable or model_availability_unknown findings, bounded same-family inspection candidates with endpoint metadata, and actionable recommendations without automatic substitution or global-retirement claims.
  • Add playbook_url to audit findings and print relevant playbook links in console output, Actions agent-error logs, and safe-output diagnostic logs/step summaries. Preserve successful and intentionally skipped outcomes.
  • Consolidate model-availability instructions into .github/aw/debug-playbook.md#model-availability, remove the standalone guide, and update all entry links. Cover gh-aw-owned audit, runtime, safe-output, merge, parser/ledger, and queue diagnostic codes with evidence/remedy mappings; handle open-ended external codes explicitly.
  • Add source-driven code-coverage contracts, eight synthetic routing regression cases, and a minor changeset. Bump the audit cache schema so older findings are recomputed.

Validation

  • make fmt and make agent-report-progress passed; final consolidated snapshot also passed make agent-report-progress-no-test.
  • Focused audit/model/cache Go regressions passed.
  • Runtime diagnostic suites: 217 tests passed; runtime typecheck passed.
  • Playbook code-coverage and routing contract tests passed.
  • Independent mini LLM routing evaluation: 8/8 scenarios passed, rerun after consolidation. Cases cover unavailable models, endpoint mismatch, missing publication, protected-file skip, invocation cap, threat verdict, pending projection, and a caught warning followed by fatal rejection with incomplete model evidence.
  • Replayed saved run 38948906270: audit confirms missing claude-opus-5, lists same-run claude-opus-5.5 as an inspection candidate, and links the consolidated model section. Verified cached gh aw models output separately.
  • All 344 workflow lock files remain in sync. No workflows were dispatched.

The complete guidance suite retains two pre-existing link-format assertion failures in test_routing_and_evidence_links (local/embedded skill routers use absolute GitHub URLs while assertions require relative links). New guidance checks pass; unrelated routing formats were not changed.

Related investigation

The rootless /run/awf-config-audit publication warning is separate from the fatal model rejection. Upstream issue filed as requested: github/gh-aw-firewall#10131. No upstream implementation changes are included.

pelikhan and others added 2 commits October 16, 2026 12:21
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add same-run reflected model inventory analysis, diagnostic playbook coverage, consolidated model guidance, and runtime/audit playbook links.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan pelikhan changed the title docs: add artifact-first model availability diagnosis playbook Diagnose unavailable models and add code-specific debugging playbook Oct 16, 2026
pelikhan and others added 6 commits October 16, 2026 13:00
Use current audit finding routes, bounded cached evidence collection, and consolidated model-availability guidance.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Deduplicate model routing, shorten diagnostic lookups, require explicit investigation inputs, and bound playbook size without removing code coverage or safety constraints.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Include debug-playbook.md in the offline fallback list to match the new playbook and generated skill index.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Include the optional playbook_url in audit, grouped audit and cached logs JSONL output schemas. Exercise populated playbook links in each affected command output shape.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Great work @pelikhan 👋 — the audit model-availability diagnostics and playbook consolidation look well tested and ready for review.

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

Generated by ✅ Contribution Check · copilot · auto · 45.2 AIC · ⌖ 0.636 AIC · ⊞ 10.6K · ◷

@pelikhan
pelikhan marked this pull request as ready for review October 16, 2026 21:07
Copilot AI max review requested due to automatic review settings October 16, 2026 21:07
@pelikhan
pelikhan merged commit 064246a into main Oct 16, 2026
47 checks passed
@pelikhan
pelikhan deleted the pelikhan-ci-failure-investigation branch October 16, 2026 21:07
Copilot stopped reviewing on behalf of pelikhan due to an error October 16, 2026 21:07
@github-actions

github-actions Bot commented Oct 16, 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

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

✅ Ponytail Reviewer completed successfully!

Ponytail Reviewer

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Ponytail Reviewer · gpt56 · 16.7 AIC · ⌖ 5.34 AIC · ⊞ 14.6K · ◷

Generated by Ponytail Reviewer for #69467

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Design Decision Gate 🏗️ is checking for design decision records on this pull request...

@github-actions

github-actions Bot commented Oct 16, 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 Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Test Quality Sentinel · sonnet50 · 13.2 AIC · ⌖ 15 AIC · ◇ 6.53 AIC · ⊞ 12.6K · ◷

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (553 new lines in pkg/) but has no linked Architecture Decision Record (ADR).

📄 Draft ADR generated: docs/adr/69467-diagnose-unavailable-models-from-same-run-inventory.md. I couldn't commit it automatically because the PR head ref isn't available in the gate's checkout. Copy it from the section below, review it, and commit it to your branch.

🔒 This PR can't merge until an ADR is linked in the PR body.

📄 Draft ADR content (docs/adr/69467-diagnose-unavailable-models-from-same-run-inventory.md)
# ADR-69467: Diagnose Unavailable Models from Same-Run Inventory and Link Findings to a Consolidated Debug Playbook

**Date**: 2026-10-16
**Status**: Draft
**Deciders**: pelikhan, Copilot (PR #69467) [TODO: verify]

---

### Context

Pi-engine runs can fail at startup with a fatal `[gh-aw/pi-models-json] ... Pi model "X" is not advertised by the configured <provider> proxy endpoint` error, which happens before any inference. Before this PR, `gh aw audit` did not recognize the error. Users had to read raw logs and guess a fix, often by assuming the model was retired everywhere or by switching to some other model. The run artifacts already include the firewall's `awf-reflect.json`, which records the model inventory each configured endpoint advertised during that run. The guidance for model availability and other diagnostic codes was also split across several debugging documents, so audit output, Actions logs, and safe-output summaries had no single, stable place to link to.

### Decision

We will have `gh aw audit` detect the Pi model-not-advertised error and check it only against the **same run's** completed inventory for the **matching configured provider** in `sandbox/firewall/awf-reflect.json`. It will report a stable `model_unavailable` finding only when that evidence confirms the model is absent. Otherwise it reports `model_availability_unknown`, for example when discovery was incomplete, the endpoint is ambiguous or missing, entries are invalid, or the model is actually advertised. The finding lists a bounded set of same-family models as candidates to inspect, with their endpoint metadata. It never picks a replacement automatically and never claims a model is retired globally. Audit findings get a `playbook_url` field that points to sections of a single consolidated `.github/aw/debug-playbook.md`. The same links appear in console output, `detect_agent_errors.cjs` logs, and safe-output diagnostic summaries. The audit cache schema version is bumped so older cached reports are recomputed.

### Alternatives Considered

#### Alternative 1: Query the live provider/model catalog at audit time

Audit could call the provider's models API (or `gh aw models`) when the audit runs to check whether the model exists. This was rejected because the live catalog may have changed since the failed run. It would also need credentials and network access at audit time, and it could not show what the run itself saw. Same-run reflection is the evidence that applies to the failure being diagnosed.

#### Alternative 2: Automatically substitute or recommend a single replacement model

Audit could pick the "closest" advertised model and recommend it, or rewrite the workflow to use it. This was rejected because models in the same family can differ in capabilities, supported endpoints, and cost. A wrong substitution could quietly change agent behavior. The PR lists candidates for inspection and leaves the choice to the author.

#### Alternative 3: Keep model guidance in a standalone guide and per-surface ad-hoc messages

Each surface (audit, runtime JS, safe-output summary) could keep its own wording and link to the existing standalone model-availability guide. This was rejected because the guidance was already drifting across documents and nothing tied finding codes to remedies. A single playbook with code-coverage contract tests keeps codes and documentation in sync.

### Consequences

#### Positive
- Failures from a model that isn't advertised get a stable, machine-readable finding code with evidence from the run, instead of a raw log line.
- The diagnosis is conservative: it separates "confirmed absent on this endpoint in this run" from "unknown". This avoids false claims of model retirement.
- One playbook URL scheme links every surface to the same remedies, and contract tests check that gh-aw-owned diagnostic codes are covered.

#### Negative
- Detection depends on the exact text of the Pi fatal error. If that message changes, detection breaks silently unless the regex and tests are updated.
- The diagnosis depends on the `awf-reflect.json` artifact format from gh-aw-firewall. Schema changes there will push results toward `model_availability_unknown`.
- Bumping the cache schema makes all previously cached audits recompute, which costs time and API calls once.
- `playbook_url` values point to `main`-branch anchors. Renaming playbook sections breaks links in previously emitted findings.

#### Neutral
- `playbook_url` is a new optional field in `schemas/audit.schema.json` and `schemas/logs-jsonl.schema.json`. Consumers must tolerate it.
- The standalone model-availability guide is removed in favor of the `#model-availability` section of `debug-playbook.md`.

---

*ADR created by [adr-writer agent]. Review and finalize before changing status from Draft to Accepted.*
📋 What to do next
  1. Review the draft ADR above. It was generated from the PR diff (pkg/cli/audit_model_availability.go, audit_finding_codes.go, .github/aw/debug-playbook.md, schemas).
  2. Complete the missing sections: confirm the deciders, refine the rationale, and adjust the alternatives you actually considered.
  3. Commit the finalized ADR to docs/adr/ on your branch.
  4. Reference the ADR in this PR body, for example:

    ADR: ADR-69467: Diagnose Unavailable Models from Same-Run Inventory

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

📋 Michael Nygard ADR Format Reference

A complete ADR has these four sections:

  • 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)?

ADRs are stored in docs/adr/ as Markdown files named by PR number.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · opus55 · 30.3 AIC · ⌖ 34.5 AIC · ⊞ 1.9K · ◷
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

Peek at saved memory (pr-code-quality-reviewer)
reviewed_at: 2026-10-16T21:10:30.557+00:00
review_event: REQUEST_CHANGES
top_themes:
  - wrong-provider model inventory selection
  - unreliable model availability diagnosis
files_reviewed:
  - pkg/cli/audit_model_availability.go
  - pkg/cli/audit_report_analysis.go
  - pkg/cli/audit_finding_codes.go
  - actions/setup/js/detect_agent_errors.cjs
  - actions/setup/js/safe_output_summary.cjs
comment_count: 1

Note

This comment is managed by comment memory.

Expand the saved memory block to view or edit the persistent context for this thread.
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 · copilot · gpt54 · 93.3 AIC · ⌖ 5.78 AIC · ⊞ 12.4K · ◷
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.

Request changes

The new model-availability audit path has a real correctness bug: provider selection stores a pointer to the range variable, so multi-provider reflections can be analyzed against the wrong endpoint.

Blocking theme
  • parseModelAvailabilityInventory can end up reading models and routing metadata from the wrong provider when the match is not the last endpoint in inventory.Endpoints.
  • That makes the new model_unavailable / model_availability_unknown findings unreliable, which is too risky for a debugging feature whose whole job is root-cause accuracy.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 93.3 AIC · ⌖ 5.78 AIC · ⊞ 12.4K
Comment /review to run again

if endpoint != nil {
return nil, nil, "Multiple configured endpoints match the provider"
}
endpoint = &candidate

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.

Taking &candidate here captures the range variable, so if the matching provider is followed by any other endpoint this pointer ends up referring to the wrong entry and the audit can report model availability from the wrong provider.

💡 Why this is blocking

inventory.Endpoints usually contains several providers. In Go, for _, candidate := range ... reuses the same variable on each iteration, so storing &candidate does not keep a stable pointer to the matched slice element. A shape like [copilot(match), openai] will leave endpoint pointing at the final openai copy, which can flip a real model_unavailable into model_availability_unknown (or vice versa) and corrupt the candidate list.

Please take the address of the slice element instead, e.g. candidate := &inventory.Endpoints[i] / endpoint = candidate, and add a regression test where the matching configured provider is followed by an unrelated endpoint.

@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 /codebase-design and /tdd - this is a well-structured addition with deep modules (narrow public surface on audit_model_availability.go, rich internal validation), consistent reuse of existing helpers (normalizeModelProvider, modelNameWithoutProvider), symlink-safe file reads matching existing codebase conventions, and strong table-driven test coverage (15+ scenarios). Two minor, non-blocking suggestions posted inline.

📋 Key Themes & Highlights

Key Themes

  • Magic number: the same-family candidate cap of 5 in modelAvailabilityCandidates lacks a named constant (pkg/cli/audit_model_availability.go:152).
  • Heuristic coupling: the new playbook-link trigger in detect_agent_errors.cjs reuses buildOutputLines wholesale, which includes soft/already-handled flags like missing_model_pricing_error; the new tests don't pin down behavior for that ambiguous overlap.

Positive Highlights

  • ✅ generateModelAvailabilityFindings correctly scopes evidence to the failing run only (verified by TestAuditModelAvailabilityDoesNotUseOtherRunEvidence) and rejects symlinked artifact paths.
  • ✅ Findings carefully distinguish confirmed absence (model_unavailable) from inconclusive evidence (model_availability_unknown), avoiding false claims of model retirement.
  • ✅ Consolidated debug-playbook.md is backed by its own code-coverage contract tests (test_guidance.py) that scan source registries for undocumented diagnostic codes - a nice guard against documentation drift.
  • ✅ Schema (audit.schema.json, logs-jsonl.schema.json) and cache-version bump correctly updated alongside the new playbook_url field.

@copilot please address the review comments above.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 98.3 AIC · ⌖ 16 AIC · ⊞ 10.1K
Comment /matt to run again

}
}
candidates = append(candidates, candidate)
if len(candidates) == 5 {

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.

[/codebase-design] The candidate cap 5 is a bare magic number with no named constant or doc comment explaining the choice.

💡 Suggestion

Extract const maxModelAvailabilityCandidates = 5 near the top of the file (alongside the regex vars) so the bound is self-documenting and easy to tune/reference from tests, consistent with how maxBytes parameters are already named explicitly elsewhere in this file.

@copilot please address this.


persistAgentExecution(logContent, results, rootDir);

if (buildOutputLines(results).some(line => line.endsWith("=true")) || process.env.GH_AW_AGENTIC_EXECUTION_OUTCOME === "failure") {

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] This condition reuses buildOutputLines, which includes missing_model_pricing_error=true - a soft/already-handled case that prints its own informational message at line 320, not necessarily a failure worth a playbook link.

� Why this matters

buildOutputLines is also used to build GITHUB_OUTPUT values (line 123) and categories (line 235), so coupling the playbook-link heuristic to it means any future addition to that output list silently changes when the link is printed, without a dedicated test asserting the full truth table. The new test (detect_agent_errors.test.cjs) only covers 4 cases (empty/success, denial/success, empty/failure, model-not-supported/failure) - it doesn't test a scenario where only missing_model_pricing_error or shell_expansion_guard_rejected is true with a successful outcome, which is exactly the ambiguous case this coupling creates.

Consider either: (a) defining an explicit allowlist of hard-failure flags for the link trigger, or (b) adding a test case that pins down the expected behavior for soft/warning-only flags like missing_model_pricing_error with outcome success.

@copilot please address this.

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.

🟡 Changes recommended

Unresolved correctness issues can produce misleading or incomplete audit diagnostics.

4 open issues
What changed in this PR

Extends gh-aw’s run diagnostics with model-availability analysis and centralized troubleshooting guidance.

Changes:

  • Diagnose Pi model rejection using same-run provider inventories.
  • Link audit and runtime diagnostics to debugging playbooks.
  • Update schemas, cache versioning, regression coverage, and release metadata.
File Description
schemas/​logs-jsonl.schema.json Allow finding playbook URLs.
schemas/​audit.schema.json Extend audit finding schemas.
pkg/​cli/​json_schema_command_test.go Cover playbook URLs in schema fixtures.
pkg/​cli/​data/​agentic_workflows_fallback_aw_files.json Include the consolidated playbook.
pkg/​cli/​audit_report.go Add the finding URL field and close-error logging.
pkg/​cli/​audit_report_render.go Print finding playbook links.
pkg/​cli/​audit_report_analysis.go Integrate model findings and recommendations.
pkg/​cli/​audit_model_availability.go Analyze startup rejection and inventory evidence.
pkg/​cli/​audit_model_availability_test.go Cover evidence handling, rendering, and caching.
pkg/​cli/​audit_finding_codes.go Define model codes and playbook routes.
pkg/​cli/​audit_cache.go Bump the audit cache version.
pkg/​cli/​audit_cache_test.go Reject older cached audits.
docs/​src/​content/​docs/​reference/​audit.md Document findings and diagnostic links.
actions/​setup/​js/​safe_output_summary.test.cjs Cover diagnostic links and preserved outcomes.
actions/​setup/​js/​safe_output_summary.cjs Link diagnostic summaries to guidance.
actions/​setup/​js/​detect_agent_errors.test.cjs Cover runtime playbook-link conditions.
actions/​setup/​js/​detect_agent_errors.cjs Print runtime troubleshooting links.
.github/​skills/​agentic-workflows/​tests/​test_guidance.py Enforce guidance coverage and routing contracts.
.github/​skills/​agentic-workflows/​tests/​fixtures.json Add eight diagnostic-routing cases.
.github/​skills/​agentic-workflows/​SKILL.md List the new playbook.
.github/​aw/​debug-playbook.md Consolidate code-specific diagnostic guidance.
.github/​aw/​debug-model-engine-misconfiguration.md Link same-run availability checks.
.github/​aw/​debug-agentic-workflow.md Update evidence collection and diagnostic routing.
.changeset/​minor-audit-model-availability-playbook.md Record the minor release change.

Review effort: Max

"strings"
)

var piModelUnavailablePattern = regexp.MustCompile(`(?m)^\[gh-aw/pi-models-json\] fatal: Pi model "([a-zA-Z0-9][a-zA-Z0-9._/?=+-]{0,199})" is not advertised by the configured ([a-zA-Z0-9_-]{1,64}) proxy endpoint;`)
}
return nil
}
match := piModelUnavailablePattern.FindSubmatch(logData)
Comment on lines +72 to +73
requested := modelNameWithoutProvider(strings.ToLower(model))
requested, _, _ = strings.Cut(requested, "?")
Comment on lines +41 to +43
for i := range findings {
findings[i].PlaybookURL = auditFindingPlaybookURL(findings[i].Code)
}
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.92.5

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants