Skip to main content

diagnosing-bugs

A discipline for hard bugs, flaky tests, CI hangs, and performance regressions in this SDK. Use when the user says "diagnose" or "debug this", reports something broken/throwing/failing/hanging/slow, or a test is flaky. Builds a tight, red-capable feedback loop before hypothesizing.

소스 정보

저장소
getsentry/sentry-dart
최근 소스 활동
2026년 7월 1일 11:47
감지된 SKILL.md 언어
영어
스타
873
포크
304

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
diagnosing-bugs
description
A discipline for hard bugs, flaky tests, CI hangs, and performance regressions in this SDK. Use when the user says "diagnose" or "debug this", reports something broken/throwing/failing/hanging/slow, or a test is flaky. Builds a tight, red-capable feedback loop before hypothesizing.
A discipline for hard bugs. Skip a phase only when you can say why. **The whole skill is Phase 1: get a loop that goes red on this bug.** Everything after is mechanical once you have it. If you catch yourself reading code to form a theory before that loop exists, stop — jumping to a hypothesis without a red-capable loop is the exact failure this prevents. For trivial bugs with an obvious fix and an obvious test, skip this and just write the failing test — this skill is for the bugs that resist. ## Phase 1 — Build a feedback loop A **tight** loop is fast, deterministic, and goes **red** on *this* bug. Build one and the bug is 90% solved; bisection, hypothesis-testing, and instrumentation all just consume it. Be aggressive and creative here — spend disproportionate effort. ### Ways to construct one — try roughly in this order 1. **Failing test at the seam** — `dart test path/to/test.dart` or `flutter test`, unit or widget, at whatever seam reaches the bug. Tightest loop there is. 2. **`fakeAsync` harness** — for timer, microtask, and timing-dependent bugs (most flakes). Pin the clock via `options.clock`, elapse time deterministically. 3. **`testWidgets` harness** — for Flutter UI bugs: pump the widget tree, drive the gesture, assert on the tree (e.g. a hit-test or navigation regression). 4. **Integration test** — `flutter test integration_test/...` when the bug crosses the native (JNI/FFI) boundary, which cannot be faked (see `packages/flutter/AGENTS.md`). 5. **Replay a captured payload** — save a real envelope / event / span / network payload to disk and replay it through the code path in isolation. 6. **Throwaway harness** — a minimal `void main()` that exercises the bug path with one call and mocked deps. 7. **Stress/repetition loop** — for non-deterministic bugs: run the trigger 100×, parallelise, narrow timing windows, inject delays. The goal is a higher reproduction rate, not a clean repro. 8. **Differential loop** — run the same input through two versions or two configs (e.g. before/after a dependency bump) and diff the output. For regressions that "appeared after X". 9. **Bisection harness** — if it appeared between two commits, script the red/green check and `git bisect run` it. ### Tighten the loop Once you have *a* loop, treat it as a product and tighten it: - **Faster** — narrow the test scope, skip unrelated init. - **Sharper** — assert the exact symptom the user described, not "didn't crash". - **More deterministic** — pin the clock (`options.clock`), use `fakeAsync`, seed any randomness, avoid real network/filesystem (per test-guidelines). A 2-second deterministic loop beats a 30-second flaky one. For **non-deterministic** bugs the goal is a *high enough* reproduction rate to debug against — a 50% flake is debuggable, 1% is not. Keep raising the rate. ### Completion criterion Phase 1 is done when you can name **one command** — a test invocation or script path — that you have **already run at least once** (paste the invocation and its output), and that is: - [ ] **Red-capable** — drives the actual bug path and asserts the user's exact symptom, so it goes red now and green once fixed - [ ] **Deterministic** — same verdict every run (flaky bugs: a pinned, high reproduction rate) - [ ] **Fast** — seconds, not minutes No red-capable command, no Phase 2. ### When you genuinely cannot build a loop Say so explicitly, list what you tried, and ask the user for: access to an environment that reproduces it, a captured artifact (envelope dump, log, CI run, screen recording with timestamps), or permission for temporary instrumentation. Do **not** hypothesise without a loop. ## Phase 2 — Reproduce and minimise Run the loop, watch it go red. Confirm it produces the failure mode the **user** described — not a nearby one (wrong bug = wrong fix). Then shrink the repro to the smallest scenario that still goes red: cut inputs, callers, config, and steps **one at a time**, re-running after each cut. Done when every remaining element is load-bearing — removing any one turns it green. The minimal repro shrinks the hypothesis space and becomes the regression test. ## Phase 3 — Hypothesise Generate **3–5 ranked, falsifiable hypotheses** before testing any — a single hypothesis anchors you on the first plausible idea. Each must state its prediction: "If X is the cause, then changing Y makes the bug vanish." If you can't state the prediction, it's a vibe — sharpen or discard it. Show the ranked list to the user before testing; they often re-rank it instantly ("we just changed #3"). Don't block on it if they're away. ## Phase 4 — Instrument Each probe maps to one prediction from Phase 3. **Change one variable at a time.** - Prefer a debugger / breakpoint over logs where the env supports it. One breakpoint beats ten logs. - Otherwise add targeted logs at the boundaries that distinguish hypotheses — never "log everything and grep". - **Tag every debug log** with a unique prefix like `[DEBUG-a4f2]` so cleanup is one grep. - **Performance regressions**: logs are the wrong tool. Establish a baseline measurement (`Stopwatch`, a timing harness, DevTools, the observatory), then bisect. Measure first, fix second. ## Phase 5 — Fix and regression test Write the regression test **before** the fix — but only at a **correct seam**, one that exercises the real bug pattern as it occurs at the call site (per test-guidelines). A too-shallow seam (a unit test that can't replicate the chain that triggered it) gives false confidence. If no correct seam exists, **that is itself the finding** — note it; the architecture is preventing the bug from being locked down. With a correct seam: turn the minimised repro into a failing test, watch it fail, apply the fix, watch it pass, then re-run the Phase 1 loop against the original un-minimised scenario. ## Phase 6 — Cleanup and post-mortem Before declaring done: - [ ] Original repro no longer reproduces (re-run the Phase 1 loop) - [ ] Regression test passes (or the absence of a seam is documented) - [ ] All `[DEBUG-…]` instrumentation removed (grep the prefix) - [ ] Throwaway harnesses deleted - [ ] The correct hypothesis is stated in the commit / PR message, so the next debugger learns Then ask: **what would have prevented this bug?** If the answer is architectural — no good test seam, tangled callers, a shallow module hiding the real bug behind it — hand off to the **design-first** skill with the specifics. Make that call *after* the fix is in, when you know the most.
GitHub에서 보기