@clipboard-health/ai-rules 2.30.0 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/cb-babysit/SKILL.md +4 -4
- package/skills/cb-babysit/scripts/_sentinel.sh +1 -1
- package/skills/cb-ship/references/pr-template.md +1 -1
- package/skills/cb-ship/references/simplify.md +9 -8
- package/skills/flaky-critic/SKILL.md +68 -0
- package/skills/flaky-critic/references/rubric.md +224 -0
- package/skills/{flaky-test-debugger → flaky-debug}/SKILL.md +6 -17
- package/skills/{flaky-test-debugger → flaky-debug}/references/fix.md +3 -3
- package/skills/{flaky-test-debugger/references/plan.md → flaky-debug/references/plan-e2e.md} +8 -150
- package/skills/flaky-debug/references/plan-fast-path.md +44 -0
- package/skills/flaky-debug/references/plan.md +93 -0
- package/skills/flaky-triage/SKILL.md +79 -0
- package/skills/humanize-prose/SKILL.md +7 -8
- /package/skills/{flaky-test-debugger → flaky-debug}/references/datadog-apm-traces.md +0 -0
- /package/skills/{flaky-test-debugger → flaky-debug}/scripts/fetch-llm-report.sh +0 -0
package/package.json
CHANGED
|
@@ -19,9 +19,9 @@ Resolve bundled "./scripts" paths relative to SKILL.md.
|
|
|
19
19
|
|
|
20
20
|
The skill uses two sentinels with visible footer lines.
|
|
21
21
|
|
|
22
|
-
**Addressed sentinel**: `<sub>🤖 <code>cb-babysit:addressed v1 core@3.
|
|
22
|
+
**Addressed sentinel**: `<sub>🤖 <code>cb-babysit:addressed v1 core@3.13.0</code></sub>`. Appended on its own line at the end of every reply the skill posts so re-runs know which threads and review-body comments are already handled. Dedupe also recognizes the legacy `babysit-pr:addressed v1` prefix from before this skill was renamed.
|
|
23
23
|
|
|
24
|
-
**Follow-up sentinel**: `<sub>🤖 <code>cb-babysit:followup v1 core@3.
|
|
24
|
+
**Follow-up sentinel**: `<sub>🤖 <code>cb-babysit:followup v1 core@3.13.0</code></sub>`. Attached to replies that defer an out-of-scope comment as a tracked follow-up. The sentinel is additive: the post-reply scripts still append the `addressed` sentinel at the end.
|
|
25
25
|
|
|
26
26
|
**Sentinel recency rules.** The script emits a per-thread `activityState` with three values. Step 6a owns the handling rules for each state.
|
|
27
27
|
|
|
@@ -247,7 +247,7 @@ Body templates (the script appends the `addressed` sentinel if missing):
|
|
|
247
247
|
- **Agree**: `Addressed in <commit-url>. <one-line what-changed>.`
|
|
248
248
|
- **Disagree**: `Leaving current behavior. <reasoning>.`
|
|
249
249
|
- **Already fixed**: `Already handled by <commit-url-or-file:line>. <brief pointer>.`
|
|
250
|
-
- **Defer**: `Out of scope for this PR; this looks like follow-up work rather than something introduced or required by this change. <one-line rationale or pointer if useful>.\n\n<sub>🤖 <code>cb-babysit:followup v1 core@3.
|
|
250
|
+
- **Defer**: `Out of scope for this PR; this looks like follow-up work rather than something introduced or required by this change. <one-line rationale or pointer if useful>.\n\n<sub>🤖 <code>cb-babysit:followup v1 core@3.13.0</code></sub>`
|
|
251
251
|
|
|
252
252
|
For Defer replies, include the follow-up sentinel on its own line as shown. The script will append the `addressed` sentinel after it on its own line, so the final body ends with the follow-up sentinel followed by a blank line followed by the `addressed` sentinel. `grep cb-babysit:followup` finds the deferral and `grep cb-babysit:addressed` still marks the thread handled for dedupe.
|
|
253
253
|
|
|
@@ -263,7 +263,7 @@ The PR-level summary should:
|
|
|
263
263
|
|
|
264
264
|
- Group by source. Use `## Review-body findings` for step-7 work and `## Conversation-tab comments` for step-6b work. Omit a section if its list is empty.
|
|
265
265
|
- Inside each section, group verdicts under **Agree / Disagree / Already fixed / Deferred (out of scope)** subheadings. Omit a subheading if its list is empty.
|
|
266
|
-
- Under **Deferred (out of scope)**, list each deferred item as a bullet, followed on its own line by `<sub>🤖 <code>cb-babysit:followup v1 core@3.
|
|
266
|
+
- Under **Deferred (out of scope)**, list each deferred item as a bullet, followed on its own line by `<sub>🤖 <code>cb-babysit:followup v1 core@3.13.0</code></sub>` so grep catches them individually.
|
|
267
267
|
- Include the commit URL for fixes.
|
|
268
268
|
- End with a fenced fingerprint block listing every current fingerprint (addressed and deferred) one per line. Include both `reviewBodyComments[].fingerprint` (whole-body, one per automated review) and `activeIssueComments[].fingerprint` (per Conversation-tab comment). Future runs dedupe by matching these against `priorBabysitSentinels`.
|
|
269
269
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
SENTINEL_PREFIX='cb-babysit:addressed v1 '
|
|
12
12
|
LEGACY_SENTINEL_PREFIX='babysit-pr:addressed v1 '
|
|
13
|
-
SENTINEL='<sub>🤖 <code>cb-babysit:addressed v1 core@3.
|
|
13
|
+
SENTINEL='<sub>🤖 <code>cb-babysit:addressed v1 core@3.13.0</code></sub>'
|
|
14
14
|
|
|
15
15
|
# Bot author allowlist (JSON array literal). Used by unresolvedPrComments.sh
|
|
16
16
|
# as a fallback when GraphQL's `author.__typename == "Bot"` misses a GitHub
|
|
@@ -17,5 +17,5 @@ Concisely explain the user intent from session history and the meaningful behavi
|
|
|
17
17
|
|
|
18
18
|
Optional, don't fabricate: ticket links, rollout plan, residual risk, or specific areas for reviewers to focus.
|
|
19
19
|
|
|
20
|
-
<sub>🤖 <code>cb-ship:created v1 core@3.
|
|
20
|
+
<sub>🤖 <code>cb-ship:created v1 core@3.13.0</code></sub>
|
|
21
21
|
```
|
|
@@ -18,15 +18,16 @@ Review each change for hacky patterns:
|
|
|
18
18
|
|
|
19
19
|
1. **Redundant state** that duplicates existing state, cached values that could be derived, observers/effects that could be direct calls.
|
|
20
20
|
2. **Parameter sprawl**: Adding new parameters to a function instead of generalizing or restructuring existing ones.
|
|
21
|
-
3. **Copy-paste with slight variation**: near-duplicate code blocks that should be unified with a shared abstraction.
|
|
21
|
+
3. **Copy-paste with slight variation**: near-duplicate code blocks that should be unified with a shared abstraction. Exempt intentional, structurally-parallel repetition that aids readability — test arrange/act/assert blocks are the common case.
|
|
22
22
|
4. **Leaky abstractions**: exposing internal details that should be encapsulated, or breaking existing abstraction boundaries.
|
|
23
|
-
5. **
|
|
24
|
-
6. **
|
|
25
|
-
7. **
|
|
26
|
-
8. **
|
|
27
|
-
9. **
|
|
28
|
-
10. **
|
|
29
|
-
11. **
|
|
23
|
+
5. **Premature abstraction (YAGNI)**: an interface, wrapper, or config object introduced for a single caller — inline it until a second caller justifies it.
|
|
24
|
+
6. **Stringly-typed code**: using raw strings where constants, enums (string unions), or branded types already exist in the codebase.
|
|
25
|
+
7. **Unnecessary JSX nesting**: wrapper Boxes/elements that add no layout value. Check if inner component props (flexShrink, alignItems, etc.) already provide the needed behavior.
|
|
26
|
+
8. **Nested conditionals**: ternary chains (`a ? x : b ? y : ...`), nested if/else, or nested switch 3+ levels deep. Flatten with early returns, guard clauses, a lookup table, or an if/else-if cascade.
|
|
27
|
+
9. **Unnecessary comments**: Delete comments explaining WHAT the code does (well-named identifiers already do that), narrating the change, or referencing the task/caller. Keep only non-obvious WHY (hidden constraints, subtle invariants, workarounds).
|
|
28
|
+
10. **Defensive code on trusted inputs**: null/empty/type guards on inputs already guaranteed upstream (a validated DTO, the type system, a controller that already checked), optional chaining where the types guarantee presence, fallbacks that mask bugs (`?? ''`, `|| []`, `?? 0` on values that should never be absent), and try/catch that only logs and rethrows or guards an impossible state. Leave guards at genuine trust boundaries (raw request bodies, webhook payloads, third-party responses) and any error handling around real I/O, network, parsing, or payments — removing those changes behavior.
|
|
29
|
+
11. **Type escapes**: `as any`, `: any`, `as unknown as X`, gratuitous non-null `!`, `@ts-ignore`/`@ts-expect-error` added to dodge a type error — replace with the real type when it is determinable from the call site, the imported type, or the shape in use; if it is not, leave it and flag it rather than deleting it (breaks the build) or swapping in a TODO (more clutter).
|
|
30
|
+
12. **Dead & leftover code**: unreachable branches and stray debug statements (`console.log`/print-style output) — delete outright rather than commenting out; keep intentional logging that goes through the repo's logger. Unused exports/symbols with no remaining references are already covered by `.rules/common/typeScript.md`'s Dead Code Cleanup rule.
|
|
30
31
|
|
|
31
32
|
### 3: Efficiency review
|
|
32
33
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flaky-critic
|
|
3
|
+
description: Adversarial reviewer for flaky-test fix plans and PRs, enforcing the flaky-fix rubric. Gates implementation tickets from Triage to Todo (shadow mode posts verdicts without moving tickets). Use when running the recurring flaky-critic task, when asked to review a flaky-fix plan or PR against the rubric, or to backtest verdicts against historical tickets.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The quality gate of the flaky-test pipeline. Implementation tickets created by investigation agents land in the **Triage** state; this skill reviews each plan against `references/rubric.md` and decides whether it dispatches. It replaces per-plan human review; the human sees only disagreements, bounces, and the audit sample.
|
|
7
|
+
|
|
8
|
+
Your job is adversarial: assume the plan papers over the root cause until its evidence proves otherwise. You route and gate — you never redesign the fix yourself.
|
|
9
|
+
|
|
10
|
+
## Modes
|
|
11
|
+
|
|
12
|
+
- **shadow** (default): post the verdict comment only. Never change ticket state. The human still gates; agreement between your verdicts and their actions is the promotion metric.
|
|
13
|
+
- **enforce**: act on verdicts per Phase 3. Only when the task description explicitly says enforce.
|
|
14
|
+
- **backtest**: verdicts on historical plans provided as files or ticket IDs; write nothing anywhere. Judge ONLY from the plan content — never look up ticket states, comments after the plan, linked PRs, or how things actually resolved.
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
|
|
18
|
+
- Load `references/rubric.md` (relative to this SKILL.md) before judging anything. Every rejection MUST cite rule IDs and quote the offending plan sentence or diff hunk. Every approval MUST name the fix class (A1–A7, C1–C5, D1–D5) and the evidence that satisfies its requirements.
|
|
19
|
+
- One verdict per ticket per content-state: skip tickets whose latest `<!-- flaky-critic:` marker is newer than the last substantive edit/comment.
|
|
20
|
+
- Findings from automated reviewers (Mendral, CodeRabbit) are advisory inputs, never binding (rubric §1).
|
|
21
|
+
- A plan outside the rubric's taxonomy is **needs-human**, not a guess. Uncertainty bounces up, never through.
|
|
22
|
+
- Verdicts are about the plan in front of you; do not penalize brevity when the required evidence is present, and do not reward thoroughness that lacks it.
|
|
23
|
+
|
|
24
|
+
## Phase 1: Queue (shadow/enforce only)
|
|
25
|
+
|
|
26
|
+
Linear: Groundcrew project, label `flaky-implementation`, state `Triage`. Skip already-marked tickets per the rule above. For shadow/enforce runs, fetch the linked investigation ticket (the plan's evidence usually lives there) and note any linked PRs. Use `list_issues` only to enumerate; fetch plan content with `get_issue` — list results truncate descriptions.
|
|
27
|
+
|
|
28
|
+
In backtest mode, skip the live queue and linked metadata lookups. Use only the supplied historical plan content or ticket snapshot; do not fetch linked investigation tickets, linked PRs, current ticket state, comments after the plan, or how the work actually resolved.
|
|
29
|
+
|
|
30
|
+
If the queue is empty, skip to the digest. Fetch linked investigation tickets and linked PR metadata in parallel when the available tooling supports it.
|
|
31
|
+
|
|
32
|
+
## Phase 2: Verdict per ticket
|
|
33
|
+
|
|
34
|
+
1. **Classify** the proposed fix into the rubric taxonomy. Multi-part plans get classified per part; the worst verdict wins.
|
|
35
|
+
2. **B-rules first** (any violation → reject): B1–B7, per rubric §2.
|
|
36
|
+
3. **A/C requirements**: the named fix class's "Required evidence" must be present (A-rules), or the conditional justification stated verbatim (C-rules). A1 has a shared-helper carve-out that's easy to miss — check it explicitly before approving.
|
|
37
|
+
4. **D dispositions**: a no-code plan must carry the disposition's required evidence (D1–D5).
|
|
38
|
+
5. **Verdict**: `approve` / `reject` / `needs-human`, with confidence high/moderate/low. Low confidence → needs-human.
|
|
39
|
+
|
|
40
|
+
## Phase 3: Act
|
|
41
|
+
|
|
42
|
+
Post the verdict comment on the implementation ticket:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
[shadow] VERDICT: reject — B2, B6
|
|
46
|
+
- B2: "increase the navigation timeout to 30s" — timeout inflation without a root-cause statement of why the operation is legitimately slow.
|
|
47
|
+
- B6: plan states confidence 3/5 but has no observability-to-reach-5/5 section.
|
|
48
|
+
Fix class claimed: A1 (readiness gate). Missing required evidence: polled signal is not shown to be the one the failing UI path uses.
|
|
49
|
+
<!-- flaky-critic: verdict=reject mode=shadow -->
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **shadow**: comment only, prefixed `[shadow]`.
|
|
53
|
+
- **enforce**: approve → move the ticket to Todo and assign it to the Linear API user. Reject → comment and leave in Triage; the investigating flow gets one bounce. A second reject on the same ticket → comment `needs-human` and stop touching it.
|
|
54
|
+
- **needs-human**: comment with what the rubric cannot answer; never move the ticket.
|
|
55
|
+
|
|
56
|
+
## Phase 4: Taste capture
|
|
57
|
+
|
|
58
|
+
When you encounter a ticket where a human's action contradicts your prior verdict (you rejected, they released; you approved, they bounced), post a follow-up comment containing a drafted rubric amendment — the rule change that would have made your verdict match theirs — marked `<!-- flaky-critic: amendment-proposal -->`. The human approves or discards; you never edit the rubric yourself.
|
|
59
|
+
|
|
60
|
+
## Phase 5: Digest
|
|
61
|
+
|
|
62
|
+
End with: tickets reviewed, verdicts by type with rule-ID counts, agreement events observed (human actions vs prior verdicts), amendment proposals drafted, and tickets skipped as already-current. When run as a recurring task, this digest is the run's final message.
|
|
63
|
+
|
|
64
|
+
## PR checkpoint (when the task description asks for it)
|
|
65
|
+
|
|
66
|
+
Sweep open pipeline-authored flaky-fix PRs the same way, using the rubric's diff-level detection heuristics: B-rule patterns on the diff itself, the claimed A-class's required evidence in the PR body, attempt-to-fix key present, current-main status stated (B7). Shadow = review comment only. Never merge; merge rights are out of scope.
|
|
67
|
+
|
|
68
|
+
When posting PR feedback, follow `../simple-review/references/posting-pr-review.md`: use one GitHub Review with event `COMMENT`, anchor actionable comments to changed lines, and keep approval decisions for humans.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Flaky-Fix Rubric
|
|
2
|
+
|
|
3
|
+
Mined from the [Groundcrew project](https://linear.app/clipboardhealth/project/groundcrew-4c31c63c5ed4), `flaky-test-fix` PRs across ClipboardHealth repos, and the `flaky-debug` / `flaky-test-bulk-debugger` skill docs.
|
|
4
|
+
|
|
5
|
+
## 1. Purpose & how the critic uses this doc
|
|
6
|
+
|
|
7
|
+
This rubric turns Rocky's observed review standards into checkable rules for flaky-test fix plans and PRs. When rejecting or flagging, the critic MUST cite the specific rule ID (e.g., "violates B1") and quote the offending diff hunk or plan sentence. A plan/PR that violates any B-rule is rejected; A-rules with their required evidence are auto-merge candidates; C-rules require the stated justification to be present verbatim in the plan or PR body.
|
|
8
|
+
|
|
9
|
+
Findings from automated reviewers (Mendral, CodeRabbit, etc.) are **advisory inputs, not binding rules**: the critic evaluates each on rubric merits and may decline one with stated reasoning, exactly as cb-babysit's Disagree replies do.
|
|
10
|
+
|
|
11
|
+
**Statement-missing vs substance-missing (backtest amendment, 2026-06-11):** B5/B6/B7 each require an explicit statement in the plan (dedup-check results, confidence score plus observability section, current-main status). When the _statement_ is absent but the violation is not demonstrated — no actual duplicate found, no actual low-confidence code fix, no actual staleness — the verdict is reject with disposition **amend-and-resubmit**: one bounce asking for exactly the missing sections, never escalation. A demonstrated violation (a real duplicate, a real ≤2/5 code fix) is a substantive reject. The 2026-06-11 backtest showed 6 of 7 false rejections were statement-missing on plans predating these conventions; live plans carry the sections by template, but the distinction stays load-bearing for the agreement metric.
|
|
12
|
+
|
|
13
|
+
## 2. Banned patterns
|
|
14
|
+
|
|
15
|
+
### B1 — Naked retry (retry without failure classification)
|
|
16
|
+
|
|
17
|
+
Adding retries that repeat on _any_ failure, or on a failure class that includes genuine errors.
|
|
18
|
+
|
|
19
|
+
**Why:** "Do not solve this by adding frontend waits or Playwright retries; that increases duplicate token setup and makes the Cognito throttle worse." (STAFF-1122). Org reviewer pushback on PR cbh-admin-frontend#6974: retrying all 422s means "a real validation error will now spin for 90s before timing out instead of failing fast" — the fix was narrowed so only opaque 500s retry while 422s stay gated on the specific readiness message. The skill's idempotency check (plan.md "Decide Fix Approach") must pass before any retry/wait change: safe to repeat, same scenario, doesn't amplify the root cause, no deterministic signal available instead.
|
|
20
|
+
|
|
21
|
+
**Detection heuristic:** diff adds `retry`, `retries:`, `toPass`, `async-retry`, a retry loop, or `page.reload()` inside a loop, AND the retry predicate does not discriminate transient failures (matches any error / any non-2xx / bare `catch`), OR the PR body lacks (a) why the retried operation is idempotent and (b) why no deterministic signal exists. Special case: retrying token minting, one-time credentials, seed-data creation, or rate-limited APIs without a concurrency cap is an automatic reject (retry amplification).
|
|
22
|
+
|
|
23
|
+
### B2 — Timeout/sleep inflation
|
|
24
|
+
|
|
25
|
+
Increasing a numeric timeout, adding `waitForTimeout`/`sleep`, or extending a fixed delay as the fix.
|
|
26
|
+
|
|
27
|
+
**Why:** plan.md: "Is there a deterministic signal to wait on instead of a longer timeout?" Accepted plan STAFF-1010 explicitly chose a readiness poll "over increasing the existing fixed CDC sleep." The one approved "increase timeout" PR (cbh-mobile-app#11242) was approved only after the diff morphed into removing the slow operation (`user.type()` of ~95 keystrokes → `fireEvent.change`) instead of raising the timeout. Human reviewer pushback on closed #11456: "I am seeing a lot of timeout overrides, waitForResponse should have handled this by itself."
|
|
28
|
+
|
|
29
|
+
**Detection heuristic:** diff increases any numeric timeout value, adds `waitForTimeout`, `setTimeout`-based sleeps, or `timeout:` overrides in test code, without a root-cause explanation in the PR body that states why the operation is legitimately slow and bounded. Multiple per-call timeout overrides in one spec is a strong reject signal.
|
|
30
|
+
|
|
31
|
+
### B3 — Assertion loosening
|
|
32
|
+
|
|
33
|
+
Weakening an assertion (exact → substring, visible → attached, removing an assertion, widening a match set, `force: true` clicks) to make the test pass.
|
|
34
|
+
|
|
35
|
+
**Why:** the corpus moves in the opposite direction: merged fixes made locators _exact_ (#5940), scoped assertions to the target (#6930), and asserted "durable UI state instead of transient toast visibility" (#6641). `force: true` was removed once the product bug was fixed (#6757, reviewer: "Since we made changes to the src code, I don't think we'd need the force: true anymore, right?"). fix.md: "Do not convert an infrastructure, backend, auth/data, or product-state root cause into a frontend timeout or locator retry."
|
|
36
|
+
|
|
37
|
+
**Detection heuristic:** diff removes/weakens an `expect`, replaces a specific matcher with a broader one, adds `force: true`, `exact: false`, `.first()`, or regex-broadens a locator, without evidence that the previous assertion was wrong about intended UX (e.g., genuinely duplicate toast as in #5941). Deleting an assertion is allowed only under A6 (whole-test removal with coverage proof) or with UX-drift evidence.
|
|
38
|
+
|
|
39
|
+
### B4 — Fixing the assertion site instead of the diagnosed surface
|
|
40
|
+
|
|
41
|
+
Editing the test where the failure surfaced when the evidence points to CI setup, auth/test-data, backend, or product code.
|
|
42
|
+
|
|
43
|
+
**Why:** SKILL.md: "avoid editing the test just because that is where the failure surfaced." fix.md: "The proposed fix targets the diagnosed failure surface, not only the final assertion." Self-correction example: "Backed out the interviews-list readiness retry. That was chasing the later symptom." (cbh-mobile-app#11338). The fix-locus decision order is: shared setup/CI → backend/data → product → test harness/data → assertion/locator _last_.
|
|
44
|
+
|
|
45
|
+
**Detection heuristic:** plan's stated failure surface (or the error evidence: 5xx bodies, throttle exceptions, setup-helper stack frames) is backend/setup/infra, but the diff touches only the spec file's waits/assertions. Reject and require the fix at the diagnosed surface or an explicit reason it is out of reach.
|
|
46
|
+
|
|
47
|
+
### B5 — Per-sighting fixes for a shared root cause (duplicate plans)
|
|
48
|
+
|
|
49
|
+
Opening one plan/PR per failing test when the failures share one mechanism (same run/burst, same helper, same error shape).
|
|
50
|
+
|
|
51
|
+
**Why:** Rocky closed five sibling "recover lazy chunk failure" PRs in seven minutes (cbh-admin-frontend #5645–#5649) and merged one canonical fix (#5650). Bulk-debugger skill: "Prefer one implementation ticket per root cause, not one per sighting" and "Do not create per-test fixes for a shared failure." Dedup comments: "No new implementation ticket needed; linking to STAFF-1010 and closing this investigation as a duplicate" (STAFF-1217); PR #6682 was closed as a no-op because the same pin already landed via #6680.
|
|
52
|
+
|
|
53
|
+
**Detection heuristic:** plan/PR does not state the results of the dedup check (open `flaky-test-fix` PRs touching the same file/helper, recent main commits, canonical Linear ticket for the fingerprint family). If the failing error line matches an existing canonical ticket's fingerprint family or an open sibling PR, reject as duplicate and route to the canonical.
|
|
54
|
+
|
|
55
|
+
**Prior-sibling signal (backtest amendment, 2026-06-11):** sibling PRs for the same mechanism that were closed _unmerged_ are a strong reject signal, not mere context. A plan citing closed-unmerged siblings must explain what is materially different this time — narrower scope alone is not an answer (the backtest's one genuine false approval cited prior wontfix siblings and explained them away).
|
|
56
|
+
|
|
57
|
+
### B6 — Code fix on low-confidence diagnosis
|
|
58
|
+
|
|
59
|
+
Proposing a code change when root-cause confidence is ≤2/5, or any plan below 5/5 that omits observability follow-ups.
|
|
60
|
+
|
|
61
|
+
**Why:** plan.md: confidence ≤2 → "do not propose a code fix. Instead, recommend specific instrumentation or reproduction steps." Skill PR core-utils#686 (May 25) made it mandatory that "any fix plan below 5/5 confidence must include the frontend and/or backend observability changes that would make the next occurrence diagnosable at 5/5 confidence," spanning repositories if needed. Merged example of diagnostics-as-the-fix: #12109 "add Cognito SMS OTP diagnostics."
|
|
62
|
+
|
|
63
|
+
**Detection heuristic:** plan lacks a confidence score; or score ≤2 with a code diff attached; or score 3–4 without an "Observability to reach 5/5" section; or evidence section lacks the minimum artifacts (error artifact + network/lifecycle artifact + specific code path).
|
|
64
|
+
|
|
65
|
+
### B7 — Stale plan applied without re-verification
|
|
66
|
+
|
|
67
|
+
Implementing a plan against code that has changed on `main`, or for a flake already fixed.
|
|
68
|
+
|
|
69
|
+
**Why:** fix.md preflight requires "the failing commit's code path still exists on current `main`." STAFF-1122's canonical comment models this: "Main status: **not fixed on `main`** as of `<sha>`" with code citations. Closed PR #6682 (pin already landed on main) is the failure mode.
|
|
70
|
+
|
|
71
|
+
**Detection heuristic:** PR body lacks a "current main status" statement; or the diff conflicts with/duplicates a commit already on main touching the same lines.
|
|
72
|
+
|
|
73
|
+
**Staleness clause (backtest amendment, 2026-06-11):** a plan more than ~14 days old, or one whose fingerprint has new sightings since the plan was written, requires re-verification against current main before approval — treat unverified staleness as B7. (Two backtest "rejections" were plans that sat unworked until a sweep canceled them; freshness is part of a plan being gateable.)
|
|
74
|
+
|
|
75
|
+
## 3. Allowed/safe patterns
|
|
76
|
+
|
|
77
|
+
These have strong precedent (counts from the 74 merged `flaky-test-fix` PRs; classification approximate) and are auto-merge candidates **only** when the listed evidence is present in the PR body.
|
|
78
|
+
|
|
79
|
+
### A1 — Deterministic readiness gate (poll a real signal, fail loud)
|
|
80
|
+
|
|
81
|
+
Wait for the same API/state the UI consumes (or a page-ready signal) before acting; bounded attempts; on exhaustion, throw with the last status/body/IDs.
|
|
82
|
+
|
|
83
|
+
- **When:** fresh entities not yet visible through a read model/CDC lag; route or dialog needs data before interaction. (~16 merged PRs: #6211, #6912, #12005, #6792, #11365, …)
|
|
84
|
+
- **Required evidence:** the polled signal is the one the failing UI path actually uses (STAFF-1010 polled "the same offer-estimate path used by the dialog"); a bounded timeout; the exhaustion error includes last status/body/request metadata; explicitly NOT a fixed sleep.
|
|
85
|
+
- **Shared-helper rule:** when the repo already has a readiness gate for the same mechanism (e.g., CDC/read-model lag), a new per-spec gate is **rejected** — the fix must use, extend, or extract a shared per-repo helper instead (STAFF-1010 already proposed "extracting a shared fresh-shift offer/readiness helper"). The ~16-gate sprawl in six weeks is the failure mode this prevents. Auto-merge therefore additionally requires: no prior gate for this mechanism exists in the repo, OR the diff goes through the shared helper.
|
|
86
|
+
|
|
87
|
+
### A2 — Test-data isolation & uniqueness
|
|
88
|
+
|
|
89
|
+
Stronger unique identities, removal of hardcoded values that interact badly with system constants, per-test state reset, documented service-test app lifecycle (`createTestApp()` + `reset()`).
|
|
90
|
+
|
|
91
|
+
- **When:** collisions (phone/email/IDs), cross-test state leakage, boundary interaction of seeded values. (~8 merged: #6931, #25161, #24184, #25859, #11662, open-shifts#5188.)
|
|
92
|
+
- **Required evidence:** the collision/leak mechanism named with the artifact that proves it (open-shifts#5188 cited the audit log showing `windowWorkers: []` and quantified the flake probability); fix matches sibling tests' existing pattern where one exists.
|
|
93
|
+
|
|
94
|
+
### A3 — Clock/time determinism
|
|
95
|
+
|
|
96
|
+
Fake timers or frozen clocks for tests asserting time-boundary logic; remove weekday/timezone dependence.
|
|
97
|
+
|
|
98
|
+
- **When:** failures cluster at day/period boundaries or depend on run time. (~3 merged: #25464, #25362, #25003.)
|
|
99
|
+
- **Required evidence:** the time-dependence is identified (which boundary), timers restored in `afterEach`.
|
|
100
|
+
|
|
101
|
+
### A4 — Assertion/locator hardening (tightening, never loosening)
|
|
102
|
+
|
|
103
|
+
Exact/scoped locators, assert durable state instead of transient toasts, assert the action's observable outcome.
|
|
104
|
+
|
|
105
|
+
- **When:** app state is correct and the selector/assertion is the only broken part — the _last_ resort in the fix decision order. (~8 merged: #5940, #6930, #6641, #11409, …)
|
|
106
|
+
- **Required evidence:** artifact showing app state was correct (screenshot/network); the new assertion is strictly more specific or more durable than the old one.
|
|
107
|
+
|
|
108
|
+
### A5 — Product fix for a real race surfaced by the test
|
|
109
|
+
|
|
110
|
+
Fix the remount/race/cache/error-handling bug users can also hit; then remove any test workaround.
|
|
111
|
+
|
|
112
|
+
- **When:** real users can hit the same state. Highest-value class (~14 merged: #6962 remount, #6961 401-redirect loop, #5650 chunk-load recovery, #6173 cache keys, #6757 menu close).
|
|
113
|
+
- **Required evidence:** the user-facing failure mode described (STAFF-1417: "removes the logout loop for real users"); accompanying test workarounds (e.g., `force: true`) removed in the same PR.
|
|
114
|
+
|
|
115
|
+
### A6 — Test removal when coverage is duplicated
|
|
116
|
+
|
|
117
|
+
Delete an E2E that re-tests logic covered deterministically at a lower level.
|
|
118
|
+
|
|
119
|
+
- **When:** failure artifacts show correct app/backend state and a focused lower-level test covers the behavior. (3 merged: #11753, #11612, #11613.)
|
|
120
|
+
- **Required evidence:** PR body names the surviving covering test and shows the artifacts proving the E2E's failure was harness-timing, not product. Auto-merge eligible like other A-rules when that evidence is present; a deletion whose test is the only coverage of the user flow does not qualify as A6 at all.
|
|
121
|
+
|
|
122
|
+
### A7 — Setup/auth hot-path de-stressing
|
|
123
|
+
|
|
124
|
+
Remove stateful writes from per-test setup, serialize/cache shared-credential acquisition, pre-provision invariants.
|
|
125
|
+
|
|
126
|
+
- **When:** throttling errors (`TooManyRequestsException`, rate limits) in setup across shards. (~7 merged: #6697, #11751, #6738, #5733.)
|
|
127
|
+
- **Required evidence:** backend telemetry showing the throttle source (STAFF-1122 cited CloudTrail: 980 `AdminUpdateUserAttributes` throttles); the fix reduces call volume or concurrency rather than just retrying it; validation re-runs the affected specs "with Playwright retries disabled once to prove the root cause is gone rather than hidden."
|
|
128
|
+
|
|
129
|
+
## 4. Conditional patterns
|
|
130
|
+
|
|
131
|
+
### C1 — Bounded, classified retry
|
|
132
|
+
|
|
133
|
+
Allowed only when ALL of: the retried operation is idempotent and preserves the test scenario; the retry predicate matches _only_ transient failure signatures (named errors/status codes — opaque 500s yes, validation 422s no, per #6974's resolution); attempts are bounded; exhaustion reports attempts + last stdout/stderr/status/body; the retry cannot amplify the root cause (rate limits, one-time credentials, duplicate writes). Precedent: #6442 ("retries only transient CLI/network/rate-limit failures … reports attempts/stdout/stderr"), #25431, #11662. A retry as a _bridge_ during a migration must be labeled "a migration guard, not the final design" (STAFF-1122) with the follow-up named.
|
|
134
|
+
|
|
135
|
+
For uniqueness-collision retries, the retry form must match the error semantics, and the plan must state which case applies: regenerate a _fresh_ identity when the failure is a constraint violation on the identity itself (#11662 regenerated OTP phone numbers); re-attempt the _same_ identity only when the failure is transient (timeout, 5xx) rather than a collision.
|
|
136
|
+
|
|
137
|
+
### C2 — Polling/web-first assertions (`expect().toPass`, poll-until)
|
|
138
|
+
|
|
139
|
+
Allowed only when the asserted behavior is genuinely asynchronous/event-driven (eventual consistency, background job) and the poll wraps a _specific_ assertion with a bounded timeout — not a page-reload-until-green loop around a whole flow. The plan must state why no single deterministic completion signal exists.
|
|
140
|
+
|
|
141
|
+
### C3 — Network mocking / mock fidelity changes
|
|
142
|
+
|
|
143
|
+
Allowed when the mock is corrected to match the real contract (e.g., #11692 PDF CORS headers, #11936 required `modificationReason`) or when third-party nondeterminism must be removed (#5989 Google Maps autocomplete). Not allowed to mock away the system under test in an E2E whose purpose is to exercise that path.
|
|
144
|
+
|
|
145
|
+
### C4 — CI/tooling pin or environment guard
|
|
146
|
+
|
|
147
|
+
Allowed when many tests fail before user-flow code and the evidence is a tool/version/deploy drift (STAFF-1320: deployed UI didn't match `E2E_CHECKOUT_REF`; fix = fail fast or assert deployed commit). Requires: run-level evidence (not single-test), and a dedup check — two such PRs were closed because the pin already landed (#6682) or the approach was superseded (#6824).
|
|
148
|
+
|
|
149
|
+
### C5 — Cross-repo/backend recommendation
|
|
150
|
+
|
|
151
|
+
When the root cause is in another team's service, the plan may ship the local resilience fix and must route a recommendation to the owning team (STAFF-1413: frontend rethrow fix + "backend follow-up recommendation (… 503 instead of 401) is noted in the ticket for the owning team"). It may not silently absorb a backend bug into test code.
|
|
152
|
+
|
|
153
|
+
## 5. Dispositions that need no code
|
|
154
|
+
|
|
155
|
+
### D1 — Infra blip / environment incident (close as Canceled)
|
|
156
|
+
|
|
157
|
+
Required evidence (model: STAFF-1419/STAFF-1420 CDC-lag burst):
|
|
158
|
+
|
|
159
|
+
- A bounded incident window with telemetry: error-count spike (before/during/after), monitor Triggered/Recovered timestamps, deploy/Watchdog version-change correlation.
|
|
160
|
+
- Cross-checks: same-minute failures across repos/shards; affected tests "all passed on retry."
|
|
161
|
+
- A statement that existing harness behaved correctly ("The readiness helpers did their job: they polled … classified the failure, and emitted shift IDs + status + body").
|
|
162
|
+
- Why code can't help: "An ~8-minute backend replication outage isn't fixable in test code."
|
|
163
|
+
- Re-arm note: "The next intake run will create per-test tickets for any contained fingerprint that flakes again outside this burst."
|
|
164
|
+
|
|
165
|
+
### D2 — Duplicate (close as Duplicate, link canonical)
|
|
166
|
+
|
|
167
|
+
Required evidence: fingerprint/test/file plus error shape matches an existing investigation family ("the same file/test and HTTP 422 shape were investigated in STAFF-1001"); link both the canonical investigation and its implementation ticket/PR; explicitly state "No new implementation ticket needed." ~25% of the Linear corpus (156/636) closed this way — the critic should _expect_ duplicates and check before approving any new plan.
|
|
168
|
+
|
|
169
|
+
### D3 — Already fixed / stale
|
|
170
|
+
|
|
171
|
+
Required evidence: the merged PR/commit on main that covers the flake (e.g., "covered by merged PR #6697"), and confirmation the failing sighting predates the fix. Recurrences after the fix go to the canonical ticket ("Still failing in CI; flake-intake deduplicated this sighting to the canonical fix ticket"), not a new one.
|
|
172
|
+
|
|
173
|
+
### D4 — Burst with no shared cause identified
|
|
174
|
+
|
|
175
|
+
Per the flake-intake burst template: "If no shared cause is identifiable, comment with the reason and close this ticket as Won't Do" — per-test tickets regenerate automatically on recurrence outside the burst.
|
|
176
|
+
|
|
177
|
+
### D5 — Upstream/owning-team bug
|
|
178
|
+
|
|
179
|
+
Close-out comment must name the owning service/team, the trace/log evidence, and the recommendation handed off (see C5). No test-side band-aid in lieu of the handoff.
|
|
180
|
+
|
|
181
|
+
## 6. Resolved decisions (Rocky, 2026-06-10)
|
|
182
|
+
|
|
183
|
+
All seven open questions from the mining pass were answered; the substantive ones are folded into the rules above. Kept here as provenance for the living doc:
|
|
184
|
+
|
|
185
|
+
1. **Corpus span:** the ~6-week labeled corpus (2026-04-30 onward) is sufficient; no mining of older SYN-/ACT-/ALCH-prefixed history before the critic enforces auto-merge.
|
|
186
|
+
2. **B3 (assertion loosening):** confirmed as written, including hard-reject on `exact: false`/`.first()`; adjust from experience if it over-fires.
|
|
187
|
+
3. **A6 (test removal):** auto-merge eligible when its required evidence is present — no standing human-review carve-out.
|
|
188
|
+
4. **A1 (readiness-gate sprawl):** critic rejects new per-spec gates when a shared helper for the mechanism exists or should be extracted (now A1's shared-helper rule).
|
|
189
|
+
5. **Automated reviewer findings (Mendral/CodeRabbit):** advisory, never binding (now in §1).
|
|
190
|
+
6. **Closed PRs #6824/#6572:** confirmed supersession, not approach rejections; C4's reading stands.
|
|
191
|
+
7. **C1 collision retries:** form depends on identity type and error semantics — regenerate on constraint violations, re-attempt only on transient failures (now in C1).
|
|
192
|
+
|
|
193
|
+
## 7. Appendix: corpus stats
|
|
194
|
+
|
|
195
|
+
**Read:** 753 Linear issues enumerated (636 flaky-labeled; statuses: Done 431, Duplicate 156, Canceled 37, open 12); comments read on ~35 sampled issues (weighted to Canceled/canonical/impl tickets — most per-test tickets have only bot sighting comments). 88 `flaky-test-fix` PRs enumerated (74 merged, 13 closed, 1 open); bodies/diffs/review threads read on ~25; Rocky-authored review/issue comments harvested across all 88 (79 inline + 37 conversation comments, mostly cb-babysit); 4 skill-update PRs in core-utils; flake-intake pipeline templates in ClipboardHealth/clipboard.
|
|
196
|
+
|
|
197
|
+
**Pattern frequency (merged PRs, approximate title+body classification):**
|
|
198
|
+
|
|
199
|
+
| Pattern | Count |
|
|
200
|
+
| --------------------------------------------------- | ----- |
|
|
201
|
+
| Readiness gate / deterministic wait | ~16 |
|
|
202
|
+
| Product fix surfaced by flake | ~14 |
|
|
203
|
+
| Assertion/locator tightening | ~8 |
|
|
204
|
+
| Auth/setup throttle removal, serialization, caching | ~7 |
|
|
205
|
+
| Bounded classified retry | ~6 |
|
|
206
|
+
| Test-data isolation/uniqueness | ~6 |
|
|
207
|
+
| Mock fidelity | ~4 |
|
|
208
|
+
| Clock/time determinism | ~3 |
|
|
209
|
+
| Test removal (duplicated coverage) | 3 |
|
|
210
|
+
| Diagnostics-only | ~2 |
|
|
211
|
+
| Service-test lifecycle isolation | ~2 |
|
|
212
|
+
|
|
213
|
+
**Ten most instructive examples:**
|
|
214
|
+
|
|
215
|
+
1. STAFF-1122 + cbh-admin-frontend#6697 — canonical throttling cluster; "Do not solve this by adding frontend waits or Playwright retries."
|
|
216
|
+
2. STAFF-1419/STAFF-1420 — gold-standard infra-blip no-code disposition.
|
|
217
|
+
3. cbh-admin-frontend#5645–#5650 — duplicate-PR consolidation; one root cause, one merge.
|
|
218
|
+
4. STAFF-1010 — accepted plan format; readiness poll over CDC sleep.
|
|
219
|
+
5. cbh-admin-frontend#6974 — retry-classification pushback (500 vs 422).
|
|
220
|
+
6. cbh-admin-frontend#6442 (STAFF-942) — anatomy of an acceptable retry.
|
|
221
|
+
7. cbh-mobile-app#11242 — timeout-inflation PR converted to root-cause fix before approval.
|
|
222
|
+
8. cbh-mobile-app#11753 (STAFF-922) — test removal with coverage proof.
|
|
223
|
+
9. open-shifts#5188 (SYN-1919) — test-data fix with quantified evidence (Monte Carlo, audit log).
|
|
224
|
+
10. STAFF-1413 + cbh-admin-frontend#6961 — incident-window diagnosis producing a product fix plus owning-team handoff.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: flaky-
|
|
3
|
-
description: Debug and fix flaky tests including Playwright E2E, NestJS service/integration, React component, and unit tests.
|
|
2
|
+
name: flaky-debug
|
|
3
|
+
description: Debug and fix flaky tests including Playwright E2E, NestJS service/integration, React component, and unit tests.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Phases run in order. Skip a phase if you already have the information it produces. Phase 3 runs only in fix mode.
|
|
@@ -20,18 +20,7 @@ Both modes share the same diagnosis path; the plan is the artifact you hand to a
|
|
|
20
20
|
|
|
21
21
|
## Phase 1: Classify Failure Surface and Test Type
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Common E2E failure surfaces:
|
|
26
|
-
|
|
27
|
-
- **CI/job setup:** dependency installation, CLI/tooling, environment setup, build/deploy, artifact download.
|
|
28
|
-
- **Test setup/auth/data:** token minting, login bootstrap, seeded users/entities, one-time credentials, external service setup.
|
|
29
|
-
- **App bootstrap/navigation:** static assets, route load, hydration, browser console/page errors before the user action.
|
|
30
|
-
- **User action:** click/input completed but the expected request, dialog, route change, or state transition did not start.
|
|
31
|
-
- **Backend request:** request emitted; backend returned error, stale data, unexpected shape, or excessive latency.
|
|
32
|
-
- **Assertion/locator:** app state is correct, but the assertion/selector is brittle or out of sync with the intended UX.
|
|
33
|
-
|
|
34
|
-
Then determine the test type from the user's input. The type dictates the detailed investigation path.
|
|
23
|
+
Determine the test type from the user's input. The type dictates the detailed investigation path.
|
|
35
24
|
|
|
36
25
|
| Type | Signals |
|
|
37
26
|
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -42,6 +31,8 @@ Then determine the test type from the user's input. The type dictates the detail
|
|
|
42
31
|
|
|
43
32
|
If the type is ambiguous, check the test file extension and imports to confirm.
|
|
44
33
|
|
|
34
|
+
If the type is E2E, also classify where the failure surfaced in the lifecycle -- see [Classify the E2E Failure Surface](./references/plan-e2e.md#classify-the-e2e-failure-surface) in `plan-e2e.md`. The failure surface dictates how broadly to investigate before reading or editing the test.
|
|
35
|
+
|
|
45
36
|
## Phase 1b: Check for Existing Fixes
|
|
46
37
|
|
|
47
38
|
Before investigating, check whether someone (or another agent) has already fixed this flake.
|
|
@@ -64,9 +55,7 @@ If no existing fix is found, proceed to Phase 2.
|
|
|
64
55
|
|
|
65
56
|
## Phase 2: Produce a plan
|
|
66
57
|
|
|
67
|
-
Follow [`references/plan.md`](./references/plan.md)
|
|
68
|
-
|
|
69
|
-
If the plan's confidence is less than 5/5, it must include the frontend and/or backend observability changes needed to reach 5/5 confidence next time. The plan may request changes across multiple repositories; assume we have access to all code.
|
|
58
|
+
Follow [`references/plan-e2e.md`](./references/plan-e2e.md) for E2E tests, or [`references/plan-fast-path.md`](./references/plan-fast-path.md) for service, component, and unit tests. Both converge on [`references/plan.md`](./references/plan.md) for the fix decision and plan output format, and produce a structured plan with a confidence score.
|
|
70
59
|
|
|
71
60
|
If you are in plan mode, present the plan and stop here.
|
|
72
61
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Apply a Flaky Test Fix
|
|
2
2
|
|
|
3
|
-
Apply phase of the flaky-
|
|
3
|
+
Apply phase of the flaky-debug skill. Takes a plan produced by the planning phase ([`plan-e2e.md`](./plan-e2e.md) or [`plan-fast-path.md`](./plan-fast-path.md), finished by [`plan.md`](./plan.md)) and applies it.
|
|
4
4
|
|
|
5
5
|
## Preflight
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@ Do not convert an infrastructure, backend, auth/data, or product-state root caus
|
|
|
20
20
|
|
|
21
21
|
## Fix Sibling Instances
|
|
22
22
|
|
|
23
|
-
After fixing the root cause, search for other tests that exhibit the same anti-pattern
|
|
23
|
+
After fixing the root cause, search for other tests that exhibit the same anti-pattern. Flaky patterns often have siblings nearby, but do not turn a one-test plan into broad repo churn.
|
|
24
24
|
|
|
25
25
|
### When to search
|
|
26
26
|
|
|
@@ -47,7 +47,7 @@ Skip this step when the fix is **specific to one test's logic** -- for example a
|
|
|
47
47
|
|
|
48
48
|
2. Scope the search to the same area of the codebase first (same package or directory), then widen if the pattern is pervasive.
|
|
49
49
|
|
|
50
|
-
3. Apply the same fix to each sibling. Keep changes minimal; fix the anti-pattern, nothing else.
|
|
50
|
+
3. Apply the same fix to each sibling named in the plan or directly confirmed as the same root cause. Keep changes minimal; fix the anti-pattern, nothing else. Report broader candidates instead of editing them unless they clearly share the root cause.
|
|
51
51
|
|
|
52
52
|
4. List the sibling files you fixed in the output so reviewers can verify them.
|
|
53
53
|
|
package/skills/{flaky-test-debugger/references/plan.md → flaky-debug/references/plan-e2e.md}
RENAMED
|
@@ -1,60 +1,6 @@
|
|
|
1
|
-
# Plan a Flaky Test Fix
|
|
1
|
+
# Plan a Flaky Test Fix -- E2E (Playwright)
|
|
2
2
|
|
|
3
|
-
Diagnosis and planning phase of the flaky-
|
|
4
|
-
|
|
5
|
-
Route by the test type identified in Phase 1 of SKILL.md:
|
|
6
|
-
|
|
7
|
-
- **E2E (Playwright):** start with [E2E Triage Snapshot](#e2e-triage-snapshot)
|
|
8
|
-
- **Service, React component, or Unit:** start with [Fast Path (non-E2E)](#fast-path-non-e2e)
|
|
9
|
-
|
|
10
|
-
## Fast Path (non-E2E)
|
|
11
|
-
|
|
12
|
-
For service, component, and unit tests, the failure information plus the test source code is usually sufficient to diagnose the flake. Do not over-investigate -- read the evidence, read the code, plan the fix.
|
|
13
|
-
|
|
14
|
-
### Gather Failure Context
|
|
15
|
-
|
|
16
|
-
Capture from the user's input (ask if missing):
|
|
17
|
-
|
|
18
|
-
- **Test file and name** -- exact file path and test title
|
|
19
|
-
- **Error message and stack trace** -- the raw failure output
|
|
20
|
-
- **Framework** -- Jest, Vitest, etc.
|
|
21
|
-
- **Failure metadata** -- branch, pipeline URL, duration, shard, timestamp (when available)
|
|
22
|
-
|
|
23
|
-
### Read the Test and Code Under Test
|
|
24
|
-
|
|
25
|
-
1. Read the failing test file. Focus on the specific failing test and its surrounding `describe`/`beforeEach`/`afterEach`/`afterAll` blocks.
|
|
26
|
-
2. Read the production code that the test exercises -- follow imports from the test file.
|
|
27
|
-
3. For service tests: also read the test module setup (the `Test.createTestingModule(...)` or app bootstrap code), and check for `afterAll` cleanup that closes the app/database connections.
|
|
28
|
-
|
|
29
|
-
### Classify the Flake Pattern
|
|
30
|
-
|
|
31
|
-
| Category | Test Types | Signal |
|
|
32
|
-
| ------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
33
|
-
| **Connection lifecycle** | Service | "connection closed", "topology destroyed", socket errors in stack -- app/DB not fully ready or torn down too early |
|
|
34
|
-
| **Port conflict** | Service | EADDRINUSE -- multiple test files bootstrapping on the same port |
|
|
35
|
-
| **Async teardown race** | Service | Errors appear after test passes -- `afterAll` closes the app while background work is still running |
|
|
36
|
-
| **Database state leakage** | Service | Test depends on DB state that a parallel/prior test modified |
|
|
37
|
-
| **Unresolved async work** | Component | "not wrapped in act()" warnings, state updates after unmount |
|
|
38
|
-
| **Timer/animation not flushed** | Component | Test asserts before `setTimeout`/`requestAnimationFrame` fires, or `useFakeTimers` not advanced |
|
|
39
|
-
| **Mock not restored** | Component, Unit | `jest.spyOn` or `jest.mock` bleeds into the next test -- missing `mockRestore`/`restoreAllMocks` |
|
|
40
|
-
| **Shared mutable state** | Unit | Module-level variable or singleton mutated by one test, observed by another |
|
|
41
|
-
| **Date/time sensitivity** | Unit | Test assumes a specific date, time zone, or `Date.now()` value that shifts across runs |
|
|
42
|
-
| **Test ordering dependency** | All | Passes in isolation, fails when run with other tests (or vice versa) |
|
|
43
|
-
|
|
44
|
-
### Diagnose with Evidence
|
|
45
|
-
|
|
46
|
-
Before proposing a fix, gather:
|
|
47
|
-
|
|
48
|
-
- The **error message and stack trace** from the failure
|
|
49
|
-
- The **specific code path** in the test or production code that caused the flake
|
|
50
|
-
- A brief **explanation** of why the flake is intermittent (what timing or state condition triggers it)
|
|
51
|
-
- A **confidence score** (1-5, see [Confidence Score](#confidence-score))
|
|
52
|
-
|
|
53
|
-
If confidence is less than 5/5, the plan must include the frontend and/or backend observability changes that would provide enough evidence for 5/5 confidence next time. Do not limit that recommendation to the current repository -- the plan may request changes in multiple repositories because we have access to all code.
|
|
54
|
-
|
|
55
|
-
If confidence is 2 or below, the plan is to gather more data: recommend specific reproduction steps or instrumentation rather than a code fix.
|
|
56
|
-
|
|
57
|
-
If >2, continue to [Decide Fix Approach](#decide-fix-approach).
|
|
3
|
+
Diagnosis and planning phase of the flaky-debug skill for Playwright E2E tests. Produces a structured plan that the user reviews. Ends at [`plan.md`](./plan.md) for the fix decision and plan output format.
|
|
58
4
|
|
|
59
5
|
## E2E Triage Snapshot
|
|
60
6
|
|
|
@@ -69,8 +15,10 @@ Capture these details first so the investigation is reproducible. If the user ha
|
|
|
69
15
|
|
|
70
16
|
Downloads the `playwright-llm-report` artifact from a GitHub Actions run.
|
|
71
17
|
|
|
18
|
+
Resolve the bundled `scripts/` path relative to `SKILL.md`; do not use a target repository's `scripts/` directory.
|
|
19
|
+
|
|
72
20
|
```bash
|
|
73
|
-
bash scripts/fetch-llm-report.sh "<github-actions-url>"
|
|
21
|
+
bash "<flaky-debug-skill-dir>/scripts/fetch-llm-report.sh" "<github-actions-url>"
|
|
74
22
|
```
|
|
75
23
|
|
|
76
24
|
This downloads and extracts to `/tmp/playwright-llm-report-{runId}/`. The report is a single `llm-report.json` file.
|
|
@@ -86,7 +34,7 @@ Before reading the failing test as if it is isolated, check whether the failure
|
|
|
86
34
|
|
|
87
35
|
If many tests fail in the same setup helper, dependency install step, auth/token path, or external service call, diagnose the shared mechanism first. Do not create per-test fixes for a shared failure.
|
|
88
36
|
|
|
89
|
-
|
|
37
|
+
## Classify the E2E Failure Surface
|
|
90
38
|
|
|
91
39
|
Use the earliest observed failure surface to decide where to investigate first:
|
|
92
40
|
|
|
@@ -102,7 +50,7 @@ Use the earliest observed failure surface to decide where to investigate first:
|
|
|
102
50
|
|
|
103
51
|
This classification can change as evidence improves. State the final surface in the plan.
|
|
104
52
|
|
|
105
|
-
##
|
|
53
|
+
## Classify the Flake Pattern (E2E)
|
|
106
54
|
|
|
107
55
|
For the full report schema, field reference, caps, and example reports:
|
|
108
56
|
|
|
@@ -221,94 +169,4 @@ Do not propose a fix without concrete artifacts. At minimum, include:
|
|
|
221
169
|
- When available: **screenshot** from `failureArtifacts.screenshotBase64` showing page state at failure
|
|
222
170
|
- When available: **Datadog trace** via `attempts[].network.instances[].traceId` showing backend behavior for the failing request
|
|
223
171
|
- When relevant: **logs/RUM/CI evidence** that confirms whether the issue is app, backend, infra, auth/test-data, or CI tooling
|
|
224
|
-
- A **confidence score**
|
|
225
|
-
|
|
226
|
-
If confidence is less than 5/5, identify the missing evidence and propose concrete frontend and/or backend observability changes that would make the next occurrence diagnosable at 5/5 confidence. These changes may span multiple repositories.
|
|
227
|
-
|
|
228
|
-
If confidence is 2 or below, do not propose a code fix. Instead, recommend specific instrumentation or reproduction steps to raise confidence.
|
|
229
|
-
|
|
230
|
-
If >2, continue to [Decide Fix Approach](#decide-fix-approach).
|
|
231
|
-
|
|
232
|
-
### Confidence Score
|
|
233
|
-
|
|
234
|
-
Rate your confidence in the root cause on a 1-5 scale. Report this score alongside your evidence.
|
|
235
|
-
|
|
236
|
-
| Score | Meaning | Criteria |
|
|
237
|
-
| ----- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
238
|
-
| **5** | Certain | Root cause is directly visible in artifacts (e.g., assertion diff shows stale data, network response confirms 5xx, screenshot shows error banner) |
|
|
239
|
-
| **4** | High confidence | Evidence strongly supports the diagnosis but one link in the chain is inferred rather than observed (e.g., timeline shows the right sequence but no Datadog trace to confirm backend behavior) |
|
|
240
|
-
| **3** | Moderate confidence | Evidence is consistent with the diagnosis but alternative explanations remain plausible. Flag the alternatives explicitly |
|
|
241
|
-
| **2** | Low confidence | Limited evidence, mostly reasoning from code patterns rather than observed artifacts. Recommend gathering more data before committing to a fix |
|
|
242
|
-
| **1** | Speculative | No direct evidence for the root cause. The fix is a best guess. Recommend reproducing the failure locally or adding instrumentation before proceeding |
|
|
243
|
-
|
|
244
|
-
## Decide Fix Approach
|
|
245
|
-
|
|
246
|
-
Applies to all test types.
|
|
247
|
-
|
|
248
|
-
Choose the fix locus from the evidence, not from where the assertion failed. A flaky E2E test can be exposing a CI dependency issue, auth/test-data service issue, backend bug, deployment problem, product state bug, or test harness bug.
|
|
249
|
-
|
|
250
|
-
Use this decision order:
|
|
251
|
-
|
|
252
|
-
1. **Shared setup or CI fix** when many tests fail before user-flow assertions or all failures share a tool, cache, install, auth, seed-data, or fixture path.
|
|
253
|
-
2. **Backend/service/data fix** when the expected request is emitted and backend telemetry or response bodies show errors, throttling, stale data, inconsistent state, or unexpected latency.
|
|
254
|
-
3. **Product fix** when real users can hit the same unsafe intermediate state, render error, permission/session race, stale cache, or missing error handling.
|
|
255
|
-
4. **Test data or harness fix** when the scenario is not user-realistic, the test setup is semantically wrong, or the test needs a deterministic app-ready signal.
|
|
256
|
-
5. **Assertion/locator fix** only when the app state is correct and the selector/assertion is the only broken part.
|
|
257
|
-
|
|
258
|
-
Before proposing any retry, timeout, or wait change, pass the idempotency check:
|
|
259
|
-
|
|
260
|
-
- Is the retried operation safe to repeat?
|
|
261
|
-
- Does retrying preserve the same test scenario?
|
|
262
|
-
- Could retrying amplify the root cause, such as rate limits, one-time credentials, duplicate writes, or destructive mutations?
|
|
263
|
-
- Is there a deterministic signal to wait on instead of a longer timeout?
|
|
264
|
-
|
|
265
|
-
If the answer is no or unclear, do not add a retry/wait as the fix. Propose a root-cause fix or instrumentation instead.
|
|
266
|
-
|
|
267
|
-
Common valid fix types:
|
|
268
|
-
|
|
269
|
-
- **Shared setup / CI**
|
|
270
|
-
- Pin or lock runtime tools and dependencies
|
|
271
|
-
- Fail fast on incompatible tool contracts
|
|
272
|
-
- Remove mutable global state from CI setup
|
|
273
|
-
- Add setup-level diagnostics before sharding
|
|
274
|
-
|
|
275
|
-
- **Test harness / data** (when the failure is non-product):
|
|
276
|
-
- Reset cookies, storage, and session between retries
|
|
277
|
-
- Isolate test data; generate stronger unique identities
|
|
278
|
-
- Make retry blocks idempotent
|
|
279
|
-
- Wait on deterministic app signals, not arbitrary sleeps
|
|
280
|
-
- (Service tests) Close connections and app properly in `afterAll`
|
|
281
|
-
- (Component tests) Flush pending state updates and timers before asserting
|
|
282
|
-
- (Unit tests) Reset shared mutable state in `beforeEach`
|
|
283
|
-
|
|
284
|
-
- **Product** (when real users would hit the same issue):
|
|
285
|
-
- Handle stale or intermediate states safely
|
|
286
|
-
- Make routing/render logic robust to eventual consistency
|
|
287
|
-
- Add telemetry for ambiguous transitions
|
|
288
|
-
|
|
289
|
-
- **Backend/service**
|
|
290
|
-
- Remove avoidable shared mutable writes from hot paths
|
|
291
|
-
- Make setup operations idempotent or explicitly rate limited
|
|
292
|
-
- Fix stale reads, cache invalidation, and eventual-consistency assumptions
|
|
293
|
-
- Add trace/log correlation for ambiguous failures
|
|
294
|
-
|
|
295
|
-
Choose **both** if user impact exists _and_ tests are fragile.
|
|
296
|
-
|
|
297
|
-
## Plan Output Format
|
|
298
|
-
|
|
299
|
-
Produce the plan with these fields:
|
|
300
|
-
|
|
301
|
-
- **Test ID:** if provided in prompt
|
|
302
|
-
- **Agent session ID:** your running session ID to resume if needed
|
|
303
|
-
- **Confidence:** score (1-5) with brief justification
|
|
304
|
-
- **Failure surface:** CI/job setup, test setup/auth/data, app bootstrap, user action no-op, backend request, post-success render, assertion/locator, or mixed
|
|
305
|
-
- **Current main status:** whether the failing commit's code path still exists on current `main`, has already been fixed, or has changed enough that the plan must be adjusted
|
|
306
|
-
- **Symptom:** what failed and where
|
|
307
|
-
- **Root cause:** concise technical explanation
|
|
308
|
-
- **Evidence:** artifacts supporting the diagnosis (traces, network, error messages, screenshots as applicable)
|
|
309
|
-
- **Proposed fix:** test harness, product, or both — with the specific file(s) and the change you would make
|
|
310
|
-
- **Observability to reach 5/5:** required when confidence is less than 5/5. List the frontend and/or backend telemetry, logging, tracing, reporter, or metric changes that would make this flake diagnosable with 5/5 confidence next time, including any repositories that should change. Use "N/A -- confidence is 5/5" only for a 5/5 plan.
|
|
311
|
-
- **Sibling candidates:** files that appear to share the same anti-pattern, for the reviewer (or fix.md) to confirm. Or "N/A -- fix is test-specific" if the issue is one-off (see [`fix.md`](./fix.md) for what counts as a structural anti-pattern worth searching for).
|
|
312
|
-
- **Validation plan:** lint/typecheck commands and test commands to run after applying the fix
|
|
313
|
-
- **Open questions:** anything that needs human input before fixing
|
|
314
|
-
- **Residual risk:** what could still be flaky after the fix
|
|
172
|
+
- A **confidence score** -- see [Confidence Score](./plan.md#confidence-score) in `plan.md` for the 1-5 scale and what to do with it.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Plan a Flaky Test Fix -- Fast Path (Service, Component, Unit)
|
|
2
|
+
|
|
3
|
+
Diagnosis and planning phase of the flaky-debug skill for service, React component, and unit tests. Produces a structured plan that the user reviews. Ends at [`plan.md`](./plan.md) for the fix decision and plan output format.
|
|
4
|
+
|
|
5
|
+
For service, component, and unit tests, the failure information plus the test source code is usually sufficient to diagnose the flake. Do not over-investigate -- read the evidence, read the code, plan the fix.
|
|
6
|
+
|
|
7
|
+
## Gather Failure Context
|
|
8
|
+
|
|
9
|
+
Capture from the user's input (ask if missing):
|
|
10
|
+
|
|
11
|
+
- **Test file and name** -- exact file path and test title
|
|
12
|
+
- **Error message and stack trace** -- the raw failure output
|
|
13
|
+
- **Framework** -- Jest, Vitest, etc.
|
|
14
|
+
- **Failure metadata** -- branch, pipeline URL, duration, shard, timestamp (when available)
|
|
15
|
+
|
|
16
|
+
## Read the Test and Code Under Test
|
|
17
|
+
|
|
18
|
+
1. Read the failing test file. Focus on the specific failing test and its surrounding `describe`/`beforeEach`/`afterEach`/`afterAll` blocks.
|
|
19
|
+
2. Read the production code that the test exercises -- follow imports from the test file.
|
|
20
|
+
3. For service tests: also read the test module setup (the `Test.createTestingModule(...)` or app bootstrap code), and check for `afterAll` cleanup that closes the app/database connections.
|
|
21
|
+
|
|
22
|
+
## Classify the Flake Pattern
|
|
23
|
+
|
|
24
|
+
| Category | Test Types | Signal |
|
|
25
|
+
| ------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
26
|
+
| **Connection lifecycle** | Service | "connection closed", "topology destroyed", socket errors in stack -- app/DB not fully ready or torn down too early |
|
|
27
|
+
| **Port conflict** | Service | EADDRINUSE -- multiple test files bootstrapping on the same port |
|
|
28
|
+
| **Async teardown race** | Service | Errors appear after test passes -- `afterAll` closes the app while background work is still running |
|
|
29
|
+
| **Database state leakage** | Service | Test depends on DB state that a parallel/prior test modified |
|
|
30
|
+
| **Unresolved async work** | Component | "not wrapped in act()" warnings, state updates after unmount |
|
|
31
|
+
| **Timer/animation not flushed** | Component | Test asserts before `setTimeout`/`requestAnimationFrame` fires, or `useFakeTimers` not advanced |
|
|
32
|
+
| **Mock not restored** | Component, Unit | `jest.spyOn` or `jest.mock` bleeds into the next test -- missing `mockRestore`/`restoreAllMocks` |
|
|
33
|
+
| **Shared mutable state** | Unit | Module-level variable or singleton mutated by one test, observed by another |
|
|
34
|
+
| **Date/time sensitivity** | Unit | Test assumes a specific date, time zone, or `Date.now()` value that shifts across runs |
|
|
35
|
+
| **Test ordering dependency** | All | Passes in isolation, fails when run with other tests (or vice versa) |
|
|
36
|
+
|
|
37
|
+
## Diagnose with Evidence
|
|
38
|
+
|
|
39
|
+
Before proposing a fix, gather:
|
|
40
|
+
|
|
41
|
+
- The **error message and stack trace** from the failure
|
|
42
|
+
- The **specific code path** in the test or production code that caused the flake
|
|
43
|
+
- A brief **explanation** of why the flake is intermittent (what timing or state condition triggers it)
|
|
44
|
+
- A **confidence score** -- see [Confidence Score](./plan.md#confidence-score) in `plan.md` for the 1-5 scale and what to do with it.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Decide the Fix and Format the Plan
|
|
2
|
+
|
|
3
|
+
Shared tail of the flaky-debug planning phase, used by both [`plan-e2e.md`](./plan-e2e.md) and [`plan-fast-path.md`](./plan-fast-path.md). Produces a structured plan that the user reviews. In fix mode, the plan is consumed by [`fix.md`](./fix.md).
|
|
4
|
+
|
|
5
|
+
## Confidence Score
|
|
6
|
+
|
|
7
|
+
Rate your confidence in the root cause on a 1-5 scale. Report this score alongside your evidence.
|
|
8
|
+
|
|
9
|
+
| Score | Meaning | Criteria |
|
|
10
|
+
| ----- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| **5** | Certain | Root cause is directly visible in artifacts (e.g., assertion diff shows stale data, network response confirms 5xx, screenshot shows error banner) |
|
|
12
|
+
| **4** | High confidence | Evidence strongly supports the diagnosis but one link in the chain is inferred rather than observed (e.g., timeline shows the right sequence but no Datadog trace to confirm backend behavior) |
|
|
13
|
+
| **3** | Moderate confidence | Evidence is consistent with the diagnosis but alternative explanations remain plausible. Flag the alternatives explicitly |
|
|
14
|
+
| **2** | Low confidence | Limited evidence, mostly reasoning from code patterns rather than observed artifacts. Recommend gathering more data before committing to a fix |
|
|
15
|
+
| **1** | Speculative | No direct evidence for the root cause. The fix is a best guess. Recommend reproducing the failure locally or adding instrumentation before proceeding |
|
|
16
|
+
|
|
17
|
+
Apply the score:
|
|
18
|
+
|
|
19
|
+
- **If >2:** continue to [Decide Fix Approach](#decide-fix-approach).
|
|
20
|
+
- **If less than 5/5:** the plan must include the frontend and/or backend observability changes that would make the next occurrence diagnosable at 5/5 confidence. Scope recommendations to repositories and services implicated by the evidence; include multiple repositories only when the artifacts link them to the failure.
|
|
21
|
+
- **If confidence is 2 or below:** do not propose a code fix. Instead, recommend specific instrumentation or reproduction steps to raise confidence.
|
|
22
|
+
|
|
23
|
+
## Decide Fix Approach
|
|
24
|
+
|
|
25
|
+
Applies to all test types.
|
|
26
|
+
|
|
27
|
+
Choose the fix locus from the evidence, not from where the assertion failed. A flaky E2E test can be exposing a CI dependency issue, auth/test-data service issue, backend bug, deployment problem, product state bug, or test harness bug.
|
|
28
|
+
|
|
29
|
+
Use this decision order:
|
|
30
|
+
|
|
31
|
+
1. **Shared setup or CI fix** when many tests fail before user-flow assertions or all failures share a tool, cache, install, auth, seed-data, or fixture path.
|
|
32
|
+
2. **Backend/service/data fix** when the expected request is emitted and backend telemetry or response bodies show errors, throttling, stale data, inconsistent state, or unexpected latency.
|
|
33
|
+
3. **Product fix** when real users can hit the same unsafe intermediate state, render error, permission/session race, stale cache, or missing error handling.
|
|
34
|
+
4. **Test data or harness fix** when the scenario is not user-realistic, the test setup is semantically wrong, or the test needs a deterministic app-ready signal.
|
|
35
|
+
5. **Assertion/locator fix** only when the app state is correct and the selector/assertion is the only broken part.
|
|
36
|
+
|
|
37
|
+
Before proposing any retry, timeout, or wait change, pass the idempotency check:
|
|
38
|
+
|
|
39
|
+
- Is the retried operation safe to repeat?
|
|
40
|
+
- Does retrying preserve the same test scenario?
|
|
41
|
+
- Could retrying amplify the root cause, such as rate limits, one-time credentials, duplicate writes, or destructive mutations?
|
|
42
|
+
- Is there a deterministic signal to wait on instead of a longer timeout?
|
|
43
|
+
|
|
44
|
+
If the answer is no or unclear, do not add a retry/wait as the fix. Propose a root-cause fix or instrumentation instead.
|
|
45
|
+
|
|
46
|
+
Common valid fix types:
|
|
47
|
+
|
|
48
|
+
- **Shared setup / CI**
|
|
49
|
+
- Pin or lock runtime tools and dependencies
|
|
50
|
+
- Fail fast on incompatible tool contracts
|
|
51
|
+
- Remove mutable global state from CI setup
|
|
52
|
+
- Add setup-level diagnostics before sharding
|
|
53
|
+
|
|
54
|
+
- **Test harness / data** (when the failure is non-product):
|
|
55
|
+
- Reset cookies, storage, and session between retries
|
|
56
|
+
- Isolate test data; generate stronger unique identities
|
|
57
|
+
- Make retry blocks idempotent
|
|
58
|
+
- Wait on deterministic app signals, not arbitrary sleeps
|
|
59
|
+
- (Service tests) Close connections and app properly in `afterAll`
|
|
60
|
+
- (Component tests) Flush pending state updates and timers before asserting
|
|
61
|
+
- (Unit tests) Reset shared mutable state in `beforeEach`
|
|
62
|
+
|
|
63
|
+
- **Product** (when real users would hit the same issue):
|
|
64
|
+
- Handle stale or intermediate states safely
|
|
65
|
+
- Make routing/render logic robust to eventual consistency
|
|
66
|
+
- Add telemetry for ambiguous transitions
|
|
67
|
+
|
|
68
|
+
- **Backend/service**
|
|
69
|
+
- Remove avoidable shared mutable writes from hot paths
|
|
70
|
+
- Make setup operations idempotent or explicitly rate limited
|
|
71
|
+
- Fix stale reads, cache invalidation, and eventual-consistency assumptions
|
|
72
|
+
- Add trace/log correlation for ambiguous failures
|
|
73
|
+
|
|
74
|
+
Choose **both** if user impact exists _and_ tests are fragile.
|
|
75
|
+
|
|
76
|
+
## Plan Output Format
|
|
77
|
+
|
|
78
|
+
Produce the plan with these fields:
|
|
79
|
+
|
|
80
|
+
- **Test ID:** if provided in prompt
|
|
81
|
+
- **Agent session ID:** your running session ID to resume if needed
|
|
82
|
+
- **Confidence:** score (1-5) with brief justification
|
|
83
|
+
- **Failure surface:** CI/job setup, test setup/auth/data, app bootstrap, user action no-op, backend request, post-success render, assertion/locator, or mixed
|
|
84
|
+
- **Current main status:** whether the failing commit's code path still exists on current `main`, has already been fixed, or has changed enough that the plan must be adjusted
|
|
85
|
+
- **Symptom:** what failed and where
|
|
86
|
+
- **Root cause:** concise technical explanation
|
|
87
|
+
- **Evidence:** artifacts supporting the diagnosis (traces, network, error messages, screenshots as applicable)
|
|
88
|
+
- **Proposed fix:** test harness, product, or both — with the specific file(s) and the change you would make
|
|
89
|
+
- **Observability to reach 5/5:** required when confidence is less than 5/5. List the frontend and/or backend telemetry, logging, tracing, reporter, or metric changes that would make this flake diagnosable with 5/5 confidence next time. Include another repository only when the evidence implicates it. Use "N/A -- confidence is 5/5" only for a 5/5 plan.
|
|
90
|
+
- **Sibling candidates:** files that appear to share the same anti-pattern, for the reviewer (or fix.md) to confirm. Or "N/A -- fix is test-specific" if the issue is one-off (see [`fix.md`](./fix.md) for what counts as a structural anti-pattern worth searching for).
|
|
91
|
+
- **Validation plan:** lint/typecheck commands and test commands to run after applying the fix
|
|
92
|
+
- **Open questions:** anything that needs human input before fixing
|
|
93
|
+
- **Residual risk:** what could still be flaky after the fix
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flaky-triage
|
|
3
|
+
description: Scheduled triage stage between flake-intake and agent dispatch. Clusters flaky-investigation tickets by shared root cause, closes duplicates and infra blips, and releases one canonical ticket per cluster for dispatch. Use when running the recurring flaky-triage task, when asked to triage the flaky queue, or to backtest clustering against historical tickets.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The pipeline stage between flake-intake (deterministic, string-level collapse: bursts and storms) and per-ticket dispatch. Intake creates investigation tickets in the **Triage** state, where groundcrew ignores them. This skill clusters them semantically — same root cause, even when error text differs — then performs ticket surgery and releases exactly one dispatchable ticket per root cause.
|
|
7
|
+
|
|
8
|
+
This skill routes; it never diagnoses. Do not propose fixes, read test source files, or run flaky-debug. Diagnosis happens later, on the released ticket, through the normal dispatch flow.
|
|
9
|
+
|
|
10
|
+
## Rules
|
|
11
|
+
|
|
12
|
+
- One canonical ticket per root cause, never one per sighting (rubric B5).
|
|
13
|
+
- Never hold a ticket hostage: anything you cannot confidently cluster is released as a singleton. The worst case must equal the no-triage baseline.
|
|
14
|
+
- Load `../flaky-critic/references/rubric.md` before citing close-out rules. Cite rubric rule IDs (B5, D1, D2, D3) in every close-out comment.
|
|
15
|
+
- Decide the full cluster picture before writing anything to Linear.
|
|
16
|
+
- Keep bulky data in local scratch files; keep only the manifest and decisions in context.
|
|
17
|
+
- All Linear writes are idempotent: skip any action whose marker comment already exists.
|
|
18
|
+
|
|
19
|
+
**Rubric IDs** (cite the matching ID in every close-out comment):
|
|
20
|
+
|
|
21
|
+
- **B5** — one canonical ticket per root cause, never one per sighting.
|
|
22
|
+
- **D1** — infra/environment incident: cancel with incident window + correlation evidence + why no code fix applies + re-arm note.
|
|
23
|
+
- **D2** — duplicate of canonical: matching evidence + no new implementation ticket needed beyond the canonical.
|
|
24
|
+
- **D3** — already-fixed: matches an investigation/implementation ticket closed in the last 14 days.
|
|
25
|
+
|
|
26
|
+
## Phase 1: Queue
|
|
27
|
+
|
|
28
|
+
Fetch candidate tickets from Linear: project `Groundcrew`, label `flaky-investigation`, state `Triage`. (During migration, also include state `Todo` with no assignee.) Skip tickets that already carry a `<!-- flaky-triage:` marker comment. If the queue is empty, skip to the digest.
|
|
29
|
+
|
|
30
|
+
Use `list_issues` only to enumerate the queue; fetch each candidate with `get_issue` — list results truncate descriptions and will silently drop the Flake details JSON. Fetch candidate details in parallel when the available tooling supports it.
|
|
31
|
+
|
|
32
|
+
Build one manifest row per ticket from its Flake details JSON: `issueId`, `repo`, `framework`, `testFile`, `testName`, `suite` (top-level describe / file basename family), `firstErrorLine`, `firstProjectStackFrame`, `pipelineUrl`, `commit`, `timestamps`, `priorTickets` (from the Prior Related Tickets section). Storm (`[storm:`) and burst (`[burst:`) tickets are pre-clustered by intake: treat each as a single-member cluster and release it; never merge them into other clusters.
|
|
33
|
+
|
|
34
|
+
Phase 1 is done when every non-skipped candidate has a manifest row — don't carry a partial manifest into Phase 2.
|
|
35
|
+
|
|
36
|
+
## Phase 2: In-flight context
|
|
37
|
+
|
|
38
|
+
Fetch what is already being worked, to catch duplicates before they spawn plans. Scope searches to the repos, files, normalized errors, helper names, and prior tickets from the Phase 1 manifest first; widen only when the scoped search leaves a plausible duplicate unresolved.
|
|
39
|
+
|
|
40
|
+
- Open Linear tickets labeled `flaky-implementation` (any state but terminal).
|
|
41
|
+
- PRs: search `flaky-test-fix` in both `open` and `closed` states; treat closed-unmerged siblings as duplicate signals, not already-fixed proof. Also try title keywords `flaky`/`deflake`.
|
|
42
|
+
- Open `[storm:` / `[burst:` tickets and their contained fingerprints.
|
|
43
|
+
- Investigation/implementation tickets closed in the last 14 days, for already-fixed matches only after confirming the merged fix is on main and the sighting predates it (D3).
|
|
44
|
+
|
|
45
|
+
Check all four sources before Phase 3 — a cluster decided against partial in-flight context can't be trusted.
|
|
46
|
+
|
|
47
|
+
## Phase 3: Cluster
|
|
48
|
+
|
|
49
|
+
Normalize first-error lines before comparing: replace UUIDs, emails, names, phone numbers, IDs, ObjectIds, hashes, ports, and timestamps with placeholders; collapse generated asset names; keep HTTP status codes, helper names, endpoint paths, and lifecycle stages intact.
|
|
50
|
+
|
|
51
|
+
Cluster by strongest shared evidence first:
|
|
52
|
+
|
|
53
|
+
1. Same CI run / commit / tight timestamp window plus same setup or helper stack.
|
|
54
|
+
2. Same failure surface: CI/job setup, test setup/auth/data, app bootstrap, backend request, post-success render, assertion/locator.
|
|
55
|
+
3. Same first project stack frame or shared setup helper.
|
|
56
|
+
4. Same endpoint / static asset / status-code pattern.
|
|
57
|
+
5. **Same module mechanism:** sibling tests in one file family or suite exercising the same logic class — e.g., several boundary/threshold tests of one module failing on timing, or several tests of one dialog failing on the same interaction — even when assertion messages differ. Name the shared mechanism explicitly; "same file" alone is insufficient.
|
|
58
|
+
6. Shared prior related tickets.
|
|
59
|
+
7. **Same environment incident:** multiple otherwise-distinct clusters whose failures all reduce to backend 5xx in seed/setup/readiness helpers within the same few minutes, across ≥2 repos or ≥3 pipelines. Different helpers and error text do not separate them — one staging outage surfaces through every helper that touches it. Merge them into one incident cluster (backtest lesson: 2026-06-09's 13 tickets were four helper-level clusters but one incident).
|
|
60
|
+
|
|
61
|
+
Do not merge clusters merely because failures share a run. Same-run failures can have different root causes.
|
|
62
|
+
|
|
63
|
+
## Phase 4: Act (per cluster, in this order)
|
|
64
|
+
|
|
65
|
+
1. **Matches in-flight work** — error family or mechanism matches an open implementation ticket or open PR: close every member as Duplicate linked to that canonical, comment citing B5/D2 with the match evidence. Release nothing.
|
|
66
|
+
2. **Matches an open storm/burst ticket** — normalized error matches its signature or contained fingerprints: close members as Duplicate of the storm/burst ticket so late stragglers join the existing event.
|
|
67
|
+
3. **Infra blip / environment incident** — an incident cluster (evidence tier 7): use the Phase 3 threshold above. In production runs, corroborate via Phase 2 (Datadog monitor history / error spike through `pup` when available; passed-on-retry signals). Default action: close all members as Canceled with a D1 comment. If the incident exposes a hardening gap (e.g., seed path lacks diagnostics), release ONE canonical for that hardening and dup the rest to it — never one per helper.
|
|
68
|
+
4. **Multi-ticket cluster** — pick the canonical (richest evidence: most failures, clearest artifacts). Comment the cluster manifest on it: member IDs, shared mechanism, evidence tier from Phase 3, and the marker `<!-- flaky-triage: cluster=<short-slug> -->`. Close the other members as Duplicate of the canonical (D2 format). Release the canonical.
|
|
69
|
+
5. **Singleton or uncertain** — release as-is with a brief `<!-- flaky-triage: singleton -->` comment.
|
|
70
|
+
|
|
71
|
+
**Release** = set state to `Todo` and assign to the Linear API user (the viewer). Before release, ensure the ticket satisfies the Groundcrew eligibility contract from `../create-groundcrew-ticket/SKILL.md`: repository text in the description, exactly one `agent-*` label, leaf issue, and no non-terminal blockers unless intentionally blocked. Assignment + Todo is what makes groundcrew dispatch it; it also serves as the lease — released tickets never re-enter the queue.
|
|
72
|
+
|
|
73
|
+
## Phase 5: Digest
|
|
74
|
+
|
|
75
|
+
End with a compact report: queue size, cluster count with members and evidence tiers, released / duplicated / canceled counts, in-flight matches found, and risks (possible false merges, missing evidence). When run as a recurring task, follow any re-arm instructions in the task description after the digest.
|
|
76
|
+
|
|
77
|
+
## Dry-run and backtest
|
|
78
|
+
|
|
79
|
+
When invoked with `--dry-run`, when the task description says dry run, or when backtesting: perform Phases 1–4 fully but **write nothing to Linear** — print each proposed action (`close STAFF-X as Duplicate of STAFF-Y, evidence: …`) instead. For a backtest, run blind against the historical tickets you are given (do not look up how they were actually resolved until after stating your clusters), then output only your proposed clusters and actions.
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: humanize-prose
|
|
3
|
-
description: Strip AI writing tells from prose you draft or clean: PR descriptions, Slack messages, docs, emails, commit messages.
|
|
3
|
+
description: Strip AI writing tells from prose you draft or clean: PR descriptions, Slack messages, docs, emails, commit messages. Use whenever the user asks to "humanize" or "deslop" text, or runs /humanize-prose. Also applies implicitly: any prose you draft for the user must already satisfy these rules.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Strip AI writing tells out of prose, whether cleaning existing text or generating it. Edit in place, change as little as possible, preserve meaning. When a change would alter meaning, leave it and flag it.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Applies to PR descriptions, Slack messages, docs, and emails.
|
|
11
|
-
|
|
12
|
-
Cut:
|
|
8
|
+
Cut, across the whole text, not just the first instance of each:
|
|
13
9
|
|
|
14
10
|
- Throat-clearing openers: "In this PR, I've...", "This change introduces...", "I wanted to...".
|
|
15
11
|
- Hedging filler: "it's worth noting", "it's important to", "generally speaking", "as you may know".
|
|
16
12
|
- Marketing adjectives and trendy intensifiers: robust, seamless, comprehensive, powerful, leverage, streamline, delve, load-bearing.
|
|
17
13
|
- Rule-of-three padding and restating the obvious.
|
|
18
|
-
- Connective tissue that links sentences without adding content: "That said", "With that in mind", "To that end", "As such", "Moreover", "Furthermore", "Additionally", "It follows that". Drop the phrase or replace it with a full stop.
|
|
14
|
+
- Connective tissue that links sentences without adding content: "That said", "With that in mind", "To that end", "As such", "Moreover", "Furthermore", "Additionally", "It follows that", "What this means is...". Drop the phrase or replace it with a full stop.
|
|
19
15
|
- Duplicated information: a point already made earlier in different words, a closing line that repeats the opening, a sentence that restates its own heading. Keep it once.
|
|
20
16
|
- Contradictory information: two statements in the same text that conflict (a number, a claim, or a recommendation stated one way then another). Keep the version that is correct and flag the contradiction; do not silently pick one if you cannot tell which is right.
|
|
21
17
|
- Bullet bloat where two sentences of prose are tighter; bold-everything formatting.
|
|
22
18
|
- Summary-of-the-summary closers: "In conclusion...", "Overall, this...".
|
|
23
19
|
- Em-dashes and double hyphens (use a comma, colon, or full stop instead).
|
|
20
|
+
- False agency: passive constructions or abstract/inanimate subjects performing human actions ("the complaint becomes a fix", "mistakes were made", "the decision emerges"). Name the actor.
|
|
21
|
+
- Binary-contrast crutch: manufactured "not X, it's Y" framing standing in for a direct claim.
|
|
22
|
+
- Vague declaratives and hollow absolutes: unsupported generalizations ("the implications are significant") and lazy extremes ("always", "never", "every") doing the work a specific claim should.
|
|
24
23
|
|
|
25
24
|
Keep it concrete: what changed, why, what to check. Match the channel (a PR body is not a Slack one-liner).
|
|
26
25
|
|
|
File without changes
|
|
File without changes
|