.agents/skills/flaky-test-investigator/SKILL.md
Investigate a flaky Scout or FTR test failure and determine what should be done about it.
A link to a GitHub issue with the failed-test label is required. If none is provided, ask for one before proceeding.
Ignore any prior root-cause analyses or fix proposals posted by automations; treat them as if they weren't there and reach your own conclusion. Failure-notification comments from kibanamachine are still useful as a history signal.
kibana-on-merge (local pipeline), on Cloud pipelines, or both?
references/pipelines.mdstep_key (e.g. scout_test_lane_4) to its config list by downloading .scout/test_lane_loads.json from the build's Scout Test Run Builder job (step_key: build_scout_tests). The same key is scheduled separately per <arch>/<server-config>; the job name (e.g. "Scout Lane #4 - stateful-classic / default") disambiguates the physical lane. Parallel configs (parallel.playwright.config.ts, workers > 1) also have multiple workers competing for the same servers, which can surface as transient timeouts under load.
workers to 1.Before you go deep on scope or root-cause hypotheses, look at the artifacts the CI run produced. For UI tests in particular, the screenshot at the moment of failure often resolves the diagnosis in under a minute — and skipping this step is a common reason an investigation ends up in the wrong tier of fix.
For every failure, try to retrieve:
kibana.log, elasticsearch.log when present). Cross-reference the failure timestamp with any errors in the logs — a server-side 500 or unexpected warning is strong evidence the failure is a product bug, not a test bug.Things to specifically check in the artifacts before forming a root-cause hypothesis:
afterEach / afterAll.If artifacts are not available (expired, not uploaded, no read_artifacts token), say so in the report rather than fabricating a hypothesis. "Screenshot would have resolved this; not available" is a valid open question.
bk artifacts list <build> -p <pipeline> --job-uuid <jobId> --json returns a JSON listing of every artifact uploaded for the failing job. Pass --job-uuid <jobId> for the failed attempt (without it, bk only returns the latest attempt and hides retried failures). If a build retried to green, failure artifacts only live on the failed job's listing; don't conclude "no screenshot" until you've scoped to the right job UUID.
Work through all of these questions:
failed-test issue, the flakiness may have already resolved itself — intentionally or as a side effect of unrelated changes.main while it still runs on a release branch. Identify the branch of the most recent failure and inspect the file there, not on main.
main, the failure is branch-local — a fix (if any) belongs on the release branch, and reasoning from main's code will be wrong.main, compare the branches to identify what's different. The branch that passes tells you what main is missing (or what it added).Common best-practice violations that cause flakiness:
docs/extend/scout/best-practices#pick-the-right-test-type). UI tests are notoriously more flaky than component, API, and Jest unit/integration tests.docs/extend/scout/ui-best-practices#prefer-kibana-apis-over-ui-for-setup-and-teardown). Driving setup/teardown through the UI is slower and flakier.docs/extend/scout/ui-best-practices#wait-for-ui-updates-when-the-next-action-requires-it). Confirm the action produced the expected result and the UI has rendered before continuing.docs/extend/scout/ui-best-practices#wait-for-complex-components-to-fully-render).docs/extend/scout/ui-best-practices#dont-use-manual-retry-loops). If a click or type only works "sometimes", don't re-issue it in a retry — that hides an actionability bug a real user would hit. Fix the interaction or wait on a stable readiness signal instead (see the retry pitfall below).Scout and FTR tests should also follow the general best practices in docs/extend/scout/best-practices.md, the UI best practices in docs/extend/scout/ui-best-practices.md, and the API best practices in docs/extend/scout/api-best-practices.md.
Watch out for these pitfalls when investigating the failure:
waitForResponse/waitForSelector upstream.expect / existOrFail in retry() / retry.tryForTime — and the subtler one: re-issuing a click, setValue/type, or goto/navigation inside a retry so a "missed" interaction lands on a later attempt (e.g. retry.tryForTime(() => { await testSubjects.click(x); await testSubjects.existOrFail(y); })). Real users don't click or type the same thing repeatedly, so retrying the interaction hides a genuine actionability bug that a real user would hit (element off-screen or at the viewport edge, the wrong sub-element being targeted, an unstable re-render). Instead, diagnose what specifically fails and fix that: scroll/ensure the element is stably actionable before acting, target the correct element, or wait on an explicit readiness data-test-subj signal.await, waitFor, waitUntil) when there is evidence of a production-side race. This is the most common pattern that looks like a fix but isn't — popular precisely because it appears principled, but it lets the test wait longer without fixing the race.Consider alternatives before recommending a code fix. Once you have a diagnosis, the right next step is not always a code change. Consider:
docs/extend/scout/best-practices.md. A functional test can often become an API, component, or Jest unit/integration test.When you report your conclusion, include these details: