arabelatso/regression-root-cause-analyzer
Locate root causes of failing regression tests by analyzing code changes, error messages, and test dependencies. Use when regression tests start failing after code changes, investigating test failures in CI/CD, debugging flaky tests, or understanding why previously passing tests now fail. Analyzes git diffs, stack traces, test output, and dependency changes to produce structured markdown reports ranking likely causes. Triggers when users ask to find why tests are failing, debug regression failures, investigate test breakage, or analyze failing test suites.
npx skills add https://github.com/ArabelaTso/Skills-4-SE --skill regression-root-cause-analyzer
Systematically investigate failing regression tests to identify root causes by analyzing code changes, error messages, test dependencies, and common failure patterns.
Collect essential details about the test failure:
Test failure details:
Quick commands to gather info:
# Run the failing test
pytest path/to/test_file.py::test_name -v
# Get recent commits
git log --oneline -10
# Check current branch and status
git status
git branch
# See what changed recently
git log --since="1 week ago" --oneline
# Check for uncommitted changes
git diff
Parse the error message and stack trace for clues. See failure-patterns.md for common patterns.
Error type indicators:
ImportError / ModuleNotFoundError:
ImportError: cannot import name 'UserService' from 'app.services'
app/services/AttributeError:
AttributeError: 'User' object has no attribute 'email_address'
User class definition changesTypeError (arguments):
TypeError: process_data() got an unexpected keyword argument 'format'
process_data definition and recent changesAssertionError:
AssertionError: assert 3 == 2
KeyError / IndexError:
KeyError: 'status'
Use git to find what changed since tests last passed.
# If you know the last good commit
git diff <last-good-commit> <current-commit>
# Check specific file changes
git log -p path/to/file.py
# See what changed in last N commits
git log -p -n 5
# Find commits that touched specific function
git log -S "function_name" -p
Priority order for investigation:
Commands to find changes:
# What files changed recently?
git diff --name-only HEAD~5..HEAD
# Changes to specific file
git diff HEAD~5..HEAD path/to/file.py
# Changes to test file
git diff HEAD~5..HEAD path/to/test_file.py
# Changes to requirements
git diff HEAD~5..HEAD requirements.txt package.json
Match the error to common patterns:
Symptoms:
TypeError: missing required argumentTypeError: got unexpected keyword argumentInvestigation steps:
grep -r "def function_name" .git log -p -S "def function_name"Symptoms:
AttributeError when accessing return valueTypeError: 'NoneType' object is not iterableInvestigation steps:
return [] to return NoneSymptoms:
pip install or npm installInvestigation steps:
git diff HEAD~5..HEAD requirements.txtSymptoms:
Investigation steps:
pytest test_file.py::test_oneProduce a structured markdown report:
test_user_registrationTypeError: process_user() got an unexpected keyword argument 'email_format'The process_user() function signature changed in commit abc123. The parameter email_format was renamed to email_type.
Evidence:
app/users.pydef process_user(data, email_format="html")def process_user(data, email_type="html")process_user(user_data, email_format="html")This is the direct cause of the TypeError.
Update test to use new parameter name:
# Before
result = process_user(user_data, email_format="html")
# After
result = process_user(user_data, email_type="html")
The function behavior is otherwise unchanged. Only the parameter name differs.
Likelihood: Low (10%)
The test fixture might have changed, but review shows fixtures are unchanged.
Likelihood: Very Low (5%)
Could be environment-related, but error is consistent locally and in CI.
pytest tests/test_users.py::test_user_registrationpytest tests/test_users.py::test_user_registrationBefore finalizing the analysis:
Test the hypothesis:
If fix doesn't work:
Commands to verify:
# Run the specific failing test
pytest path/to/test.py::test_name -v
# Run all related tests
pytest path/to/test.py -v
# Run with verbose output
pytest path/to/test.py::test_name -vv
# Run with print statements visible
pytest path/to/test.py::test_name -s
Find exact commit that broke tests:
# Start bisect
git bisect start
# Mark current (broken) commit
git bisect bad
# Mark last known good commit
git bisect good <commit-hash>
# Git will checkout middle commit
# Run tests, then mark good or bad
pytest tests/
# If tests pass
git bisect good
# If tests fail
git bisect bad
# Repeat until git finds the breaking commit
Diff approach:
# Compare file between commits
git diff <good-commit>:<path> <bad-commit>:<path>
# Show file at specific commit
git show <commit>:path/to/file.py
Checkout approach:
# Temporarily checkout old version
git checkout <good-commit> path/to/file.py
# Run tests
pytest tests/
# Restore current version
git checkout HEAD path/to/file.py
Minimal reproduction:
Example:
# Simplified test
def test_minimal_repro():
# Reproduce just the failing assertion
result = function_under_test(input)
assert result == expected # This fails
Fixture issues:
# Check what fixtures provide
def test_debug_fixture(sample_user):
print(f"Fixture data: {sample_user}")
assert False # Force test to show output
Mock issues:
# Verify mock is called
@patch('module.function')
def test_with_mock(mock_func):
mock_func.return_value = "test"
result = code_that_uses_function()
print(f"Mock called: {mock_func.called}")
print(f"Call args: {mock_func.call_args}")
Setup/teardown:
# Check state before/after
def test_check_state():
print(f"Before: {get_current_state()}")
run_test_code()
print(f"After: {get_current_state()}")
# Show commits that changed a file
git log --follow path/to/file.py
# Show commits with specific content
git log -S "function_name" --source --all
# Show commits by author
git log --author="AuthorName" --since="1 week ago"
# Show detailed commit
git show <commit-hash>
# Compare branches
git diff main feature-branch
# Run with maximum verbosity
pytest -vv
# Show print statements
pytest -s
# Stop at first failure
pytest -x
# Show local variables on failure
pytest -l
# Run last failed tests
pytest --lf
# Run tests that failed, then all
pytest --ff
# Collect tests without running
pytest --collect-only
# Show slowest tests
pytest --durations=10
# Add breakpoint
import pdb; pdb.set_trace()
# Or in Python 3.7+
breakpoint()
# Print stack trace
import traceback
traceback.print_stack()
# Inspect object
import pprint
pprint.pprint(vars(obj))
User request:
> "Tests started failing with TypeError about unexpected keyword argument"
Investigation:
TypeError: process() got unexpected keyword argument 'format'grep -r "def process" .git log -p -S "def process"Report:
## Root Cause: Parameter Renamed
Function `process()` parameter `format` renamed to `output_format` in commit abc123.
**Fix**: Update test call from `process(data, format="json")` to `process(data, output_format="json")`
**Likelihood**: High (99%)
User request:
> "Test passes sometimes but fails randomly"
Investigation:
for i in {1..10}; do pytest test.py; doneReport:
## Root Cause: Race Condition
Test has race condition in async code. The async operation sometimes completes before assertion, sometimes after.
**Evidence**: Test fails ~30% of the time when run repeatedly.
**Fix**: Add proper await or increase timeout.
**Likelihood**: High (85%)
User request:
> "All tests started failing after pip install"
Investigation:
git diff HEAD~1 requirements.txtrequests 2.28.0 → 2.31.0pip install requests==2.28.0Report:
## Root Cause: Breaking Change in requests 2.31.0
The `requests` library changed response encoding behavior in v2.31.0.
**Evidence**:
- Tests pass with requests==2.28.0
- Tests fail with requests==2.31.0
- Changelog mentions encoding changes
**Fix**: Update test expectations or pin requests version.
**Likelihood**: High (95%)
Start with the obvious:
Follow the stack trace:
Look for patterns:
Use version control:
git bisect for complex casesVerify assumptions:
Document findings:
For comprehensive failure patterns and their causes, see failure-patterns.md.
Take arabelatso/regression-root-cause-analyzer from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip, npm.
Without those the skill loads but fails at the first command.