triage-ci-flake
A structured workflow for investigating and fixing CI test failures and flaky tests on the main branch.
Install
mkdir -p .claude/skills/triage-ci-flake && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/6235" && unzip -o skill.zip -d .claude/skills/triage-ci-flake && rm skill.zipInstalls to .claude/skills/triage-ci-flake
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when CI tests fail on main branch after PR merge, when investigating flaky test failures, or when user provides a PR URL/number to aggregate all failing testsKey capabilities
- →Aggregate failing CI status checks
- →Fetch PR-specific test logs
- →Categorize intermittent test failures
- →Generate summary tables of failed suites
How it works
It queries GitHub's PR status checks API to extract failing test IDs, then scrapes logs to consolidate error patterns into a categorized format.
Inputs & outputs
When to use triage-ci-flake
- →Investigating CI failures after PR merge
- →Triaging intermittent flaky tests
- →Summarizing failing test suites for PRs
About this skill
Triage CI Failure
Overview
Systematic workflow designed specifically for triaging and fixing end-to-end (e2e) test failures in CI, especially flaky Playwright tests that pass locally but fail in CI. E2E tests that made it to main are usually flaky due to timing, bundling, or environment differences.
CRITICAL RULE: You MUST run the reproduction workflow before proposing any fixes. No exceptions.
When to Use
- CI test fails on
mainbranch after PR was merged - Test passes locally but fails in CI
- Test failure labeled as "flaky" or intermittent
- E2E test timing out in CI only
- User provides a PR URL/number with failing checks
PR-Based Workflow (When PR URL/Number Provided)
When the user provides a PR URL (e.g., https://github.com/payloadcms/payload/pull/16701) or PR number:
Step 1: Fetch PR Status Checks
First, use tool_search with query "github pull request status checks" to load the GitHub tools.
Then use the github-pull-request_pullRequestStatusChecks tool to get all failing checks:
Tool: github-pull-request_pullRequestStatusChecks
Parameters:
pullRequestNumber: <extracted from URL or provided>
repo: { owner: "payloadcms", name: "payload" }
Step 2: Aggregate Failing Tests
Parse the status checks response and create a summary table:
| Suite | Check Status | Target URL |
|---|---|---|
| admine2elist-view | failed | [link] |
| plugin-import-export | failed | [link] |
For each failing check, the context field contains the test suite name (e.g., admin__e2e__list-view).
Step 3: Extract Failure Details from Each Check
For each failing check:
- Visit the
targetUrlto get detailed failure logs - Extract the specific test name and error message
- Add to the aggregated failure list
Present a consolidated summary:
## Failing Tests Summary
### 1. admin**e2e**list-view (3/4)
- **Test**: "should use custom pagination limit"
- **Error**: Locator `.per-page__button` not found
- **File**: test/admin/e2e/list-view/e2e.spec.ts:1495
### 2. plugin-import-export
- **Test**: "should inherit limit from list view URL"
- **Error**: Locator `.per-page__button` not found
- **File**: test/plugin-import-export/e2e.spec.ts:150
Step 4: Identify Common Patterns
Look for patterns across failures:
- Same selector errors → likely a component change needing test updates
- Same test file → localized issue
- Different errors in same suite → may be test pollution
Step 5: Proceed with Triage
For each unique failure, follow the standard reproduction workflow below.
MANDATORY First Steps
YOU MUST EXECUTE THESE COMMANDS. Reading code or analyzing logs does NOT count as reproduction.
- Extract suite name, test name, and error from CI logs
- EXECUTE: Kill port 3000 to avoid conflicts
- EXECUTE:
pnpm dev $SUITE_NAME(use run_in_background=true) - EXECUTE: Wait for server to be ready (check with curl or sleep)
- EXECUTE: Run the specific failing test with Playwright directly (npx playwright test test/TEST_SUITE_NAME/e2e.spec.ts:31:3 --headed -g "TEST_DESCRIPTION_TARGET_GOES_HERE")
- If test passes, EXECUTE:
pnpm prepare-run-test-against-prod - EXECUTE:
pnpm dev:prod $SUITE_NAMEand run test again
Only after EXECUTING these commands and seeing their output can you proceed to analysis and fixes.
"Analysis from logs" is NOT reproduction. You must RUN the commands.
Core Workflow
digraph triage_ci {
"CI failure reported" [shape=box];
"Extract details from CI logs" [shape=box];
"Identify suite and test name" [shape=box];
"Run dev server: pnpm dev $SUITE" [shape=box];
"Run specific test by name" [shape=box];
"Did test fail?" [shape=diamond];
"Debug with dev code" [shape=box];
"Run prepare-run-test-against-prod" [shape=box];
"Run: pnpm dev:prod $SUITE" [shape=box];
"Run specific test again" [shape=box];
"Did test fail now?" [shape=diamond];
"Debug bundling issue" [shape=box];
"Unable to reproduce - check logs" [shape=box];
"Fix and verify" [shape=box];
"CI failure reported" -> "Extract details from CI logs";
"Extract details from CI logs" -> "Identify suite and test name";
"Identify suite and test name" -> "Run dev server: pnpm dev $SUITE";
"Run dev server: pnpm dev $SUITE" -> "Run specific test by name";
"Run specific test by name" -> "Did test fail?";
"Did test fail?" -> "Debug with dev code" [label="yes"];
"Did test fail?" -> "Run prepare-run-test-against-prod" [label="no"];
"Run prepare-run-test-against-prod" -> "Run: pnpm dev:prod $SUITE";
"Run: pnpm dev:prod $SUITE" -> "Run specific test again";
"Run specific test again" -> "Did test fail now?";
"Did test fail now?" -> "Debug bundling issue" [label="yes"];
"Did test fail now?" -> "Unable to reproduce - check logs" [label="no"];
"Debug with dev code" -> "Fix and verify";
"Debug bundling issue" -> "Fix and verify";
}
Step-by-Step Process
1. Extract CI Details
From CI logs or GitHub Actions URL, identify:
- Suite name: Directory name (e.g.,
i18n,fields,lexical) - Test file: Full path (e.g.,
test/i18n/e2e.spec.ts) - Test name: Exact test description
- Error message: Full stack trace
- Test type: E2E (Playwright)
2. Reproduce with Dev Code
CRITICAL: Always run the specific test by name, not the full suite.
SERVER MANAGEMENT RULES:
- ALWAYS kill all servers before starting a new one
- NEVER assume ports are free
- ALWAYS wait for server ready confirmation before running tests
# ========================================
# STEP 2A: STOP ALL SERVERS
# ========================================
lsof -ti:3000 | xargs kill -9 2>/dev/null || echo "Port 3000 clear"
# ========================================
# STEP 2B: START DEV SERVER
# ========================================
# Start dev server with the suite (in background with run_in_background=true)
pnpm dev $SUITE_NAME
# ========================================
# STEP 2C: WAIT FOR SERVER READY
# ========================================
# Wait for server to be ready (REQUIRED - do not skip)
until curl -s http://localhost:3000/admin > /dev/null 2>&1; do sleep 1; done && echo "Server ready"
# ========================================
# STEP 2D: RUN SPECIFIC TEST
# ========================================
# Run ONLY the specific failing test using Playwright directly
# For E2E tests (DO NOT use pnpm test:e2e as it spawns its own server):
pnpm exec playwright test test/$SUITE_NAME/e2e.spec.ts -g "exact test name"
Did the test fail?
- ✅ YES: You reproduced it! Proceed to debug with dev code.
- ❌ NO: Continue to step 3 (bundled code test).
3. Reproduce with Bundled Code
If test passed with dev code, the issue is likely in bundled/production code.
IMPORTANT: You MUST stop the dev server before starting prod server.
# ========================================
# STEP 3A: STOP ALL SERVERS (INCLUDING DEV SERVER FROM STEP 2)
# ========================================
lsof -ti:3000 | xargs kill -9 2>/dev/null || echo "Port 3000 clear"
# ========================================
# STEP 3B: BUILD AND PACK FOR PROD
# ========================================
# Build all packages and pack them (this takes time - be patient)
pnpm prepare-run-test-against-prod
# ========================================
# STEP 3C: START PROD SERVER
# ========================================
# Start prod dev server (in background with run_in_background=true)
pnpm dev:prod $SUITE_NAME
# ========================================
# STEP 3D: WAIT FOR SERVER READY
# ========================================
# Wait for server to be ready (REQUIRED - do not skip)
until curl -s http://localhost:3000/admin > /dev/null 2>&1; do sleep 1; done && echo "Server ready"
# ========================================
# STEP 3E: RUN SPECIFIC TEST
# ========================================
# Run the specific test again using Playwright directly
pnpm exec playwright test test/$SUITE_NAME/e2e.spec.ts -g "exact test name"
Did the test fail now?
- ✅ YES: Bundling or production build issue. Look for:
- Missing exports in package.json
- Build configuration problems
- Code that behaves differently when bundled
- ❌ NO: Unable to reproduce locally. Proceed to step 4.
4. Unable to Reproduce
If you cannot reproduce locally after both attempts:
- Review CI logs more carefully for environment differences
- Check for race conditions (run test multiple times:
for i in {1..10}; do pnpm test:e2e...; done) - Look for CI-specific constraints (memory, CPU, timing)
- Consider if it's a true race condition that's highly timing-dependent
Common Flaky Test Patterns
Race Conditions
- Page navigating while assertions run
- Network requests not settled before assertions
- State updates not completed
Fix patterns:
- Use Playwright's web-first assertions (
toBeVisible(),toHaveText()) - Wait for specific conditions, not arbitrary timeouts
- Use
waitForFunction()with condition checks
Test Pollution
- Tests leaving data in database
- Shared state between tests
- Missing cleanup in
afterEach
Fix patterns:
- Track created IDs and clean up in
afterEach - Use isolated test data
- Don't use
deleteAllthat affects other tests
Timing Issues
setTimeout/sleepinstead of condition-based waiting- Not waiting for page stability
- Animations/transitions not complete
Fix patterns:
- Use
waitForPageStability()helper - Wait for specific DOM states
- Use Playwright's built-in waiting mechanisms
Linting Considerations
When fixing e2e tests, be aware of these eslint rules:
playwright/no-networkidle- AvoidwaitForLoadState('networkidle')(use condition-based waiting instead)
Content truncated.
When not to use it
- →Direct local bug fixing without CI reproduction
- →Non-PR related code errors
Prerequisites
Limitations
- →Depends on availability of remote logs
- →Limited to PRs with configured status checks
How it compares
It mandates a reproduction workflow as a hard rule, preventing guesses at the root cause of flaky tests.
Compared to similar skills
triage-ci-flake side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| triage-ci-flake (this skill) | 1 | 2mo | Review | Intermediate |
| analyze-failures | 1 | 6mo | Caution | Intermediate |
| moai-workflow-testing | 1 | 2mo | Review | Intermediate |
| debug-ci | 1 | 6mo | Review | Beginner |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by payloadcms
View all by payloadcms →You might also like
analyze-failures
saleor
Analyze Playwright E2E test failure reports from CI. Parses merged blob reports, groups similar errors, and delegates to specialized subagents for investigation and fixes. Use when CI tests fail or when asked to fix E2E test failures.
moai-workflow-testing
modu-ai
Comprehensive development workflow specialist combining DDD testing, debugging, performance optimization, code review, PR review, and quality assurance into unified development workflows
debug-ci
Sovereign-Labs
Debug failed CI tests by fetching workflow logs from GitHub Actions and analyzing failures. Use when the user mentions CI failures, test failures, or wants to understand why their PR's CI is failing.
cts-triage
gfx-rs
Run CTS test suites and investigate failures
detect-flaky-tests
Sovereign-Labs
Identify flaky tests by comparing failures across multiple CI runs. Use when the user suspects flaky tests, sees intermittent failures, or wants to analyze test reliability.
ci-loop
hyodotdev
Run the full CI pipeline locally and iterate until all tests pass.