Debug
Find root cause before touching code. Fix without understood cause = guess wearing fix's clothes.
Step 1 — Reproduce
- Deterministic repro first: failing test,
--demo --dumpdiff, exact key sequence in TUI. Can't trigger = can't prove fixed. - Read actual error verbatim — full message, full backtrace (
RUST_BACKTRACE=1). Answer often in the line the eye skips. - Capture repro as failing
#[test]now when feasible — becomes regression test in Step 5 for free. - Flaky: loop it (
while cargo test bad_test; do :; doneor-- --test-threads=1to expose ordering) — establish failure rate before changing anything.
Step 2 — Shrink search space
Cheapest checks first:
- Recent changes:
git log --oneline -15,git diff HEAD~5on touched area. Most bugs days old, not years.git bisectwhen known-good commit exists and repro is scriptable. - Boundaries: bad value born here or delivered here? Probe at boundary (sysfs read in, nusb descriptor in, tree flatten out) to decide which side owns bug.
- Binary search: instrument midpoint, pick wrong half, repeat. No shotgunning ten prints — each probe answers one question.
- One assumption per probe: "this sysfs path exists", "this branch runs", "usb.ids actually loaded". Verify, don't assume.
Step 3 — Root cause
- Ask "why" past first plausible answer. Symptom: panic on unwrap. Cause: field
None. Root cause: scan skips devices without that descriptor. Fix the scan. - Fixing shared fn? Grep callers first. Bug can bite them too → fix belongs in shared path, not the one caller from the report.
- State root cause in one sentence. Can't = haven't found it — back to Step 2.
Step 4 — Fix
- Smallest change removing root cause. No drive-by refactors (see
refactorskill). - Real fix large + something bleeding? Guard + TODO acceptable — say it's mitigation, name real fix, don't call bug closed.
Step 5 — Prove it
- Step 1 repro now passes.
cargo testgreen.cargo clippy -- -D warningsclean. - Remove every temp probe/
eprintln!. - Report: root cause (one sentence), fix, verification. Tests still fail → say so.
Rust probes
RUST_BACKTRACE=1(or=full) on any panic.cargo test bad_test -- --nocapture— isolate one test, see prints.dbg!(expr)overprintln!— shows file:line + expression, greppable to remove.- TUI eats stdout: probe with
eprintln!+2>/tmp/probe.log, or drop to--dumppath where prints are visible. - No hardware / weird topology: reproduce in
--demo, or fake sysfs dir if bug is linux-path parsing.