project-ci-failure-signatures
Installation
SKILL.md
CI Triage - turn a red pipeline into a verdict and a route
A red check is not automatically a code bug. The highest-value call in CI triage is the red-in-CI, green-locally delta: is this a real defect CI merely surfaced first, or an environment / pin / config / workflow failure that never touched the code? Route a config or runner failure to a code fix and you thrash on code that was never wrong. This is the single-chat form of the ci-failure-diagnoser seat - match the failure to a signature, make that call, and route it, all in the current context. It is the CI sibling of project-failure-signatures (a crash on your own machine) and runs on the superpowers:systematic-debugging method.
First: pull the right log, read the right line
- Confirm it is actually red before spending the triage -
gh pr checks; a re-run or a later push may already be green. - Resolve the failing run from the PR head branch, then pull only the failed step:
gh run list --branch <head> --json databaseId,conclusion, thengh run view <id> --log-failed. When--log-failedis empty or unrevealing (a fatal warning promoted in an earlier green step is invisible to it), fall back to the full step log. - Read the FIRST error, not the tail - the first
error CS####/ compile line is the signal; theBuild FAILEDblock and the final count just restate it. On GitHub Actions the real error is often an##[error]line inside a collapsed group, timestamp-prefixed and colorized - grep loose (a substring, not an exact string).
The signatures - what each means and where the fix lives
- Compile / restore. A CS/NG/TS compile error is code - fix it. A restore red is usually NOT the code: a lockfile out of sync with the manifest (
NU1301/NU1101, npmERESOLVE/ETARGET) -packages.lock.json/package-lock.jsondrifted, so a locked restore fails where a loose install would silently update; a private feed the runner cannot auth to; a rate-limited registry; or a stale cache key replaying an old package set. Fix the lockfile or the feed, not the code. - Green locally, red only on the runner (reach here first when your local run passed). Case-sensitivity - a Linux runner is case-sensitive, so an import whose casing differs from the file builds on mac/Windows and fails only in CI. A file present locally but never committed, so the clean checkout lacks it. A Debug-vs-Release gap (a Release-only analyzer, a DEBUG-conditional path). A missing CI-only secret or env var. Tool-version skew -
global.jsonrollForward,.nvmrc/ engines, the JDK or Xcode the runner image pins, a floating vs SHA-pinned action. The fix is the workflow or a pin, not the code. - Quality gate. The .NET gate is a build with warnings promoted to errors plus a formatter check (
dotnet-code-quality); a red here is committed formatting drift or a newly-promoted analyzer, not a compile break. The fix is the code - and any instinct to silence the warning or downgrade the severity is the reward-hack to resist. - Signing / release (mobile). An expired distribution cert or provisioning profile, a rotated store API key, a non-incrementing build number, a keystore-secret decode failure, or native built off a stale bundle because the sync step was skipped (
capacitor-releaseowns these). Pipeline config, not app code. - Workflow-config drift. The YAML itself - a renamed job, a broken
needs:or matrix leg, a wrong working-directory, a bumped action. A red check whose log shows the tool never ran is config; it routes back to you, never to a code fix. - Infra flake (name the non-determinism, never bare 'flaky'). Test-ordering or shared static state (passes isolated, fails in the full parallel run); real-clock or real-network timing (a real HTTP call, a real timer that needed fake time, an implicit wait); or infra (
exit 137= OOM/SIGKILL,exit 143= SIGTERM/timeout, disk-full, a container-pull blip). Proof is a re-run with no code change passing (gh run rerun --failed).