name: diagnose-ci-failure description: Diagnose a failing CI workflow run (lint, markdown lint, build, or unit tests) — identify which job failed, the cause, and a concrete fix
Diagnose a CI workflow failure
Overview
The CI workflow (.github/workflows/ci.yml) gates every PR and the merge to
main. Unlike the live-API integration suite, a CI failure is almost always
caused by the change under review — a lint violation, a compile warning/error,
a broken unit test, or a Linux-portability gap. Start from the diff, not from
"maybe it's flaky".
CI fans out into four real jobs (plus a ci gate job that only aggregates
results). The diagnosis differs per job, so this skill is a router: identify
the failing job, then follow the matching reference file for that job's causes,
fixes, and local-reproduction command.
Wrong suite? If the Integration workflow (the live-API suite from
integration.yml) failed — not a CI job — use/diagnose-integration-failureinstead. It leads with the opposite assumption: a scheduled/live-API failure is usually backend or data drift, not your change.
Agent Behaviour Contract
- Identify the failing job first —
Lint,Lint Markdown,Build and Test(macOS), orBuild and Test (Linux). Don't guess the cause before you know the job. - Assume the change caused it. CI gates the PR; read the diff and tie the failure to a changed file. Don't open with "transient" or "flaky".
- Treat warnings as errors. Build steps use
-warnings-as-errors/--Werror— a deprecation or unused-binding warning is a real failure. - Reproduce locally before declaring a fix using the matching tool (
/lint,/build-for-testing,/test,make lint-markdown,make build-linux). - Output the three sections (Summary / Cause / Fix) defined below — concise,
tied to
file:line.
Locate the failing run
Use the first that applies:
- A path or run id the caller handed you.
- The current branch's run via the GitHub MCP (owner/repo from the
originremote):mcp__github__actions_listmethodlist_workflow_runs(resource_id: ci.yml,workflow_runs_filter: { branch: <branch> }), thenmcp__github__get_job_logs(run_id: <id>,failed_only: true,return_content: true). (mcp__github__pull_request_readmethodget_check_runsalso shows which job is red.) Headless / no MCP:gh run list --workflow CI --branch "$(git branch --show-current)" --limit 1, thengh run view <id> --log-failed. - CI pipes build/test output through xcsift in
github-actionsformat, so the failing lines are GitHub::error::annotations carryingfile:line— read those first.
Quick decision tree
Once you know which job failed:
- Lint (
swiftlint --strict/swiftformat --lint)? └─references/lint.md— style/format violations + the version-drift gotcha - Lint Markdown (
markdownlint)? └─references/markdown.md— README / DocC markdown rules - Build and Test — the build step failed?
└─
references/build.md— compile errors and--Werrorwarnings - Build and Test — the test step failed?
└─
references/unit-tests.md— failingSuite/test, fixture/model mismatch - Build and Test (Linux) — fails on Linux but passes on macOS?
└─
references/linux.md— Apple-only API gating, Foundation differences
Triage-first playbook
Symptom → next move:
error: … is unavailable/cannot find … in scope, Linux job only →references/linux.mdwarning: … treated as error→references/build.mderror:fromswiftcon macOS build →references/build.md- A
Suite/testrecorded a failure /#expectfailed →references/unit-tests.md - Test fails to decode a fixture (
keyNotFound,valueNotFound) →references/unit-tests.md - SwiftLint rule violation (
error: … (rule_id)) →references/lint.md superfluous_disable_commandon unchanged code →references/lint.md(suspect version drift)- SwiftFormat would reformat a file (
--lintnon-zero) →references/lint.md - markdownlint
MD0xxviolation →references/markdown.md
Output format
Produce exactly these three sections (keep it under ~150 words; if the caller asked for a file, write the markdown there and nothing else, otherwise reply directly):
Summary: which job and step failed, and the specific error (rule /
file:line / failing Suite/test).
Cause: the root cause, tied to a changed file where possible.
Fix: the concrete next step from the relevant reference file.
Reference files
| File | Failing job | Covers |
|---|---|---|
references/_index.md |
— | Navigation index by symptom |
references/lint.md |
Lint | SwiftLint --strict, SwiftFormat --lint, pinned versions, drift |
references/markdown.md |
Lint Markdown | markdownlint on README + DocC .md |
references/build.md |
Build and Test (build step) | compile errors, --Werror warnings, release build |
references/unit-tests.md |
Build and Test (test step) | Swift Testing failures, JSON fixture/model mismatch |
references/linux.md |
Build and Test (Linux) | Apple-only API gating, Foundation portability |