Diagnose a flaky CI test from its error payloads

Group test failures across CI runs by error pattern. Get a verdict — real bug or timing — without the manual archaeology.

Updated · published

markdown for agents →

difficulty intermediate · time to value 1 minute · execution on demand

Start from this

The test `checkout flow > submits valid card` failed 4 times in CI this week. Pull the error payloads, find what's common across runs, and tell me if it's a real bug or just timing.

Why this matters

Flaky tests are the worst kind of bug because they masquerade as not-bugs. You re-run, it passes, you merge, you forget. Two weeks later it’s failing on production for a real reason and you can’t tell because everyone learned to ignore that test.

The fix is to treat each CI failure as a data point and look for patterns across runs. If 4 failures all happen in the same useEffect ordering issue, it’s a race condition. If they happen at random points across the test body, it’s flake (network, timing, GC pauses). You can usually tell within a minute — if you have the failure data structured.

Most CI runners throw failure logs in a tar.gz no one reads. Agentry pulls them into a searchable event store so the agent can group them.

What you get

  • All recent failures of one test (or test pattern) grouped together
  • A verdict: real bug (with root cause) vs flake (with suggested mitigation)
  • An option to mark known-flaky tests so they don’t page on each future failure

Walk through it

You

The Cypress test checkout flow > submits valid card failed 4 times this week in CI. Pull the failure payloads, find what’s common, and tell me if it’s a real race or just timing.

Agent

Let me find those failures.

Endpoint: GET /v1/projects/:project_id/cases
Exact shape: /v1/openapi.json?path=%2Fv1%2Fprojects%2F%7Bproject_id%7D%2Fcases&method=get
Use query parameters, not a JSON body.
Query/filter concept:
  environment: "ci",
  query: "checkout flow > submits valid card",
  status: "open",
  since: "7d"
{
  "cases": [
    { "id": "c_ci0", "fingerprint": "f_ci0",
      "message": "AssertionError: expected #checkout-success to be visible",
      "event_count": 4,
      "last_seen_at": 1747320000,
      "first_seen_at": 1746748800 }
  ]
}
Agent

Same fingerprint all 4 times — that’s a clean signal, all failures hit the same assertion. Let me pull the individual events to compare timing.

Endpoint: GET /v1/cases/:case_id
Exact shape: /v1/openapi.json?path=%2Fv1%2Fcases%2F%7Bcase_id%7D&method=get
Use query parameters, not a JSON body.
Query/filter concept:
  include_recent_events: 4
{
  "events": [
    { "received_at": 1746748800,
      "stack": "AssertionError at cy.get(#checkout-success) timeout 4000ms",
      "extra": { "ci_run_id": "abc1", "duration_ms": 4012, "retry": 0 } },
    { "received_at": 1747001200,
      "stack": "AssertionError at cy.get(#checkout-success) timeout 4000ms",
      "extra": { "ci_run_id": "abc2", "duration_ms": 4008, "retry": 0 } },
    { "received_at": 1747186400,
      "stack": "AssertionError at cy.get(#checkout-success) timeout 4000ms",
      "extra": { "ci_run_id": "abc3", "duration_ms": 4015, "retry": 0 } },
    { "received_at": 1747320000,
      "stack": "AssertionError at cy.get(#checkout-success) timeout 4000ms",
      "extra": { "ci_run_id": "abc4", "duration_ms": 4011, "retry": 0 } }
  ]
}
Agent

Verdict: likely timing, not a bug.

Evidence:

  • All 4 failures hit the same assertion (#checkout-success not visible)
  • All 4 hit the 4000ms timeout exactly (4008–4015ms — that’s the test’s defaultCommandTimeout)
  • Stripe’s test-mode latency is typically 200-3000ms but spikes occasionally to 5-8s

The success page renders after Stripe returns. Your timeout is just a bit too tight for the long tail of Stripe responses.

Two fixes, depending on intent:

  1. Increase timeout (5 min effort, no risk): cy.get('#checkout-success', { timeout: 10000 }).should('be.visible')
  2. Stub Stripe in CI (1h effort, removes flake entirely + makes test 5x faster): Use cy.intercept('POST', '**/charges', { fixture: 'stripe-success.json' })

Want me to draft the PR for option 1?

The output

🧪 Flaky test analysis: "checkout flow > submits valid card"

4 failures in 7 days · Same fingerprint each time · Same assertion

VERDICT: Timing (Stripe latency spike), not a code bug
  Evidence: all failures hit defaultCommandTimeout (4000ms) exactly
            Stripe test-mode p99 latency ≈ 6s

FIXES:
  Quick:  cy.get('#checkout-success', { timeout: 10000 })…
  Right:  cy.intercept('POST', '**/charges', { fixture: ... })

NEXT: ask your agent to open a PR ("increase checkout test timeout")
   OR ask your agent to open a PR ("stub Stripe in cypress checkout tests")
   OR POST /v1/projects/:project_id/suppressions  (mark as known-flaky, stop paging on it)

Setting it up

CI runners need to post test failures to Agentry. Three lines of YAML for GitHub Actions:

- name: Report test failures to Agentry
  if: failure()
  run: |
    cat test-results.json | jq -c '.failures[] | {
      message: .title,
      stack: .error.stack,
      environment: "ci",
      tags: { ci_run_id: env.GITHUB_RUN_ID, test_file: .file }
    }' | while read -r payload; do
      curl -X POST https://api.agentry.sh/v1/logs/ \
        -H "Authorization: Bearer $AGENTRY_SERVER_API_KEY" \
        -H "Content-Type: application/json" \
        -H "User-Agent: myapp-ci/1.0" \
        -d "$payload"
    done

Use a dedicated server_ingest credential stored in this CI reporter as AGENTRY_SERVER_API_KEY; the CI deploy credential remains limited to deploys, sourcemaps, and provider proof. The environment: "ci" tag keeps these signals separate from production errors. Use any structured test output your runner produces (Jest, Vitest, Cypress, Playwright all support JSON output).

Variations

  • “Across all my CI failures this week, which test is the most flaky? Rank by failure count.”
  • “Compare CI failures on main vs feature/* branches — is something broken on main that we’re masking with re-runs?”
  • “Mark checkout flow > submits valid card as known-flaky for the next 7 days. If it’s still failing then, escalate.”
  • “Find tests that are slow but not flaky — taking 30s+ on average.”

Adapt this workflow in your own agent.

Ask your agent to map the starter prompt to your saved signal map, live events, and the current HTTP API before answering.

Agentry gives coding agents production context from errors, product analytics, and deploys through one HTTP API. Fetch and read https://agentry.sh/install.md completely, then install Agentry's full first-time telemetry baseline in this repository. I authorize device-code login, saving the owner key only to ~/.agentry/credentials.json, creating one Agentry project for this repository, and read-only inspection of shipped source plus hidden CI/provider configuration. Deeply analyze the product's business logic and complete value flow before choosing telemetry. Save the complete source-backed plan and show me its exact contents and hash. Until I explicitly approve that plan or request a replacement, do not edit app/CI source, place runtime/CI credentials, commit, exercise product traffic, start proof, push, or deploy. After approval, I authorize only the reviewed targets: place the required scoped browser/server/CI credentials through the established environment or secret mechanism, preserve existing telemetry, implement and test the baseline, commit it, push that reviewed commit when the shipped CI/provider path requires it, exercise safe proof paths with test/non-customer data, and perform one deployment through the reviewed shipped CI/provider path. Ask first if proof would charge money, contact a third party, change real customer data, or require new external access. After the plan is saved, immediately before every onboarding state-changing POST, GET current onboarding state, perform only its single returned next_action, then read state again; do not batch or infer later stages. Continue until status is verified, installation_complete is true, and next_action is null. Keep all secrets, source snapshots, proof markers, and scratch files outside the repository.

+ Full access
5.5 Extra High
  1. 1. Open your repo in Codex, Claude Code, Cursor etc.
  2. 2. Paste the install prompt.
  3. 3. Your agent reads the install doc and shows you an implementation plan for approval.