skills/debugging/regression-root-cause-analyzer/SKILL.md
Traces regressions to the specific commit, change, or code path that introduced the behavioral breakage. Use when a previously passing test or feature now fails, when the user asks what change caused a regression, or when bisecting a regression across commits.
npx skillsauth add santosomar/general-secure-coding-agent-skills regression-root-cause-analyzerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A regression has one advantage over a greenfield bug: somewhere in history there is a commit where it worked. The entire skill is exploiting that advantage. Do not read code first — read history first.
| What you know | Good bound | Bad bound |
| ----------------------------------------- | -------------------------- | ----------------------- |
| "Worked in v2.3, broken in v2.4" | v2.3 tag | v2.4 tag |
| "Broke sometime this week" | Monday's first commit | HEAD |
| "Test X just started failing in CI" | Last green CI SHA | First red CI SHA |
| "Broke after I pulled" | ORIG_HEAD or reflog | HEAD |
| "No idea when" | Oldest tag — or bail (§ edge cases) | HEAD |
Verify both bounds before bisecting. Check out good → run → confirm green. Check out bad → run → confirm red. If either bound is wrong, bisect will converge on garbage.
git bisect is log₂(N), so even 1000 commits is 10 runs. Automate if the oracle is scriptable:
git bisect start <bad> <good>
git bisect run ./oracle.sh
Where oracle.sh exits 0 when the regression is absent and non-zero when present. If the oracle is manual (visual check), you're doing it by hand — still only ~10 iterations.
| Oracle situation | Approach |
| ----------------------------------------- | --------------------------------------------------------------- |
| Single failing test | oracle.sh = pytest path/to/test.py::test_name |
| Build breaks mid-range | Exit 125 in oracle to skip — bisect knows how to route around |
| Oracle takes 10 minutes | Bisect by first-parent on merge commits first, then drill into the guilty merge |
| Behavior, not a test | Write a one-liner test now; it's your bisect oracle and your regression guard |
Bisect gives you a SHA. Now engage: git show <sha>. You're looking for which hunk caused it, not just which commit.
| Commit shape | Triage |
| --------------------------- | ----------------------------------------------------------------------- |
| Single small hunk | Done — this is the root cause |
| Multi-file refactor | Revert one file at a time against bad; re-run oracle |
| Merge commit | Bisect the merged branch separately: git bisect start <merge> <merge>^1 |
| Dependency bump | Diff the dep's changelog between old/new pins |
| Seemingly unrelated commit | Re-verify your bounds — 90% of "bisect lied" is actually bad bounds |
Input: test_admin_can_delete_user passes on v3.1.0, fails on main (400 commits later).
git bisect start main v3.1.0
git bisect run pytest tests/test_admin.py::test_admin_can_delete_user -x
9 iterations. Guilty: a3f91c2 — Refactor permission middleware.
git show a3f91c2 — 200-line diff across 4 files. Revert files one at a time:
git checkout a3f91c2 -- src/middleware/perms.py && pytest ... -x # still red
git checkout a3f91c2^ -- src/middleware/perms.py && pytest ... -x # green
Fault is in perms.py. Inspect its hunk: ADMIN in user.roles became user.role == ADMIN during the refactor — but users have a list of roles. One-character design shift, 200-line diff.
→ bug-to-patch-generator with fault location src/middleware/perms.py:L42.
git show -m <merge>.git bisect skip generously, or bisect the generated artifact (if CI retains old builds) rather than source.bug-localization.## Introducing commit
<sha> — <subject>
<author>, <date>
## Fault hunk
<file:line-range>
<the relevant diff lines, not the whole commit>
## Mechanism
<One paragraph: what the change did and why it breaks the observed behavior>
## Handoff
→ bug-to-patch-generator with <file>:<line>
development
Extracts human-readable pseudocode from a verified formal artifact (Dafny, Lean, TLA+) while preserving the verified properties as annotations, so the proof-carrying logic can be reimplemented in a production language. Use when porting verified code to an unverified target, when documenting what a formal spec actually does, or when handing a verified algorithm to an implementer.
development
Translates natural-language or pseudocode descriptions of concurrent and distributed systems into TLA+ specifications ready for the TLC model checker. Identifies state variables, actions, type invariants, safety properties, and liveness properties from the description. Use when formalizing a protocol, when the user describes a distributed algorithm to verify, when designing a consensus or locking scheme, or when starting formal verification of a concurrent system.
testing
Reduces a TLA+ model so TLC can actually check it — shrinks constants, adds state constraints, abstracts data, or applies symmetry — when the state space is too large to enumerate. Use when TLC runs out of memory, when checking takes hours, or when a spec works at N=2 and you need confidence at larger scale.
development
TLA+-specific instance of model-guided repair — reads a TLC error trace, identifies the enabling condition that should have been false, strengthens the corresponding action, and maps the fix to source code. Use when TLC reports an invariant violation or deadlock and you have the code-to-TLA+ mapping from extraction.