Skills-4-SE bisect-aware-instrumentation
Instrument code to support efficient git bisect by producing deterministic pass/fail signals and concise runtime summaries for each tested commit. Use when debugging regressions with git bisect, automating bisect workflows, creating bisect test scripts, handling flaky tests during bisection, or needing clear exit codes and logging for automated bisect runs. Helps identify the exact commit that introduced a bug through automated testing.
git clone https://github.com/ArabelaTso/Skills-4-SE
T=$(mktemp -d) && git clone --depth=1 https://github.com/ArabelaTso/Skills-4-SE "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/bisect-aware-instrumentation" ~/.claude/skills/arabelatso-skills-4-se-bisect-aware-instrumentation && rm -rf "$T"
skills/bisect-aware-instrumentation/SKILL.mdBisect-Aware Instrumentation
Overview
Instrument code to support efficient git bisect operations by producing deterministic pass/fail signals and concise runtime summaries. This skill helps create robust test scripts that work reliably with
git bisect run, handling edge cases like flaky tests, build failures, and non-deterministic behavior.
Core Workflow
1. Understand the Regression
Before instrumenting, clarify:
- What behavior changed? (bug introduced, performance regression, test failure)
- What is the "good" commit? (known working state)
- What is the "bad" commit? (known broken state)
- How to reproduce the issue? (test command, manual steps)
2. Create Bisect Test Script
Generate a test script that returns proper exit codes for git bisect:
Exit Code Convention:
: Good commit (test passes)0
: Bad commit (test fails)1-124, 126-127
: Skip commit (cannot test - build failure, missing dependencies)125
Template:
#!/bin/bash # bisect_test.sh - Test script for git bisect run set -e # Exit on error # Build/setup phase if ! make build 2>/dev/null; then echo "SKIP: Build failed" exit 125 fi # Run test with timeout timeout 30s ./run_test || TEST_RESULT=$? # Interpret results if [ $TEST_RESULT -eq 0 ]; then echo "GOOD: Test passed" exit 0 elif [ $TEST_RESULT -eq 124 ]; then echo "SKIP: Test timeout" exit 125 else echo "BAD: Test failed with code $TEST_RESULT" exit 1 fi
3. Add Determinism Safeguards
Handle non-deterministic behavior:
Retry Logic for Flaky Tests:
# Run test multiple times to confirm PASS_COUNT=0 for i in {1..3}; do if ./run_test; then ((PASS_COUNT++)) fi done if [ $PASS_COUNT -eq 3 ]; then echo "GOOD: All 3 runs passed" exit 0 elif [ $PASS_COUNT -eq 0 ]; then echo "BAD: All 3 runs failed" exit 1 else echo "SKIP: Flaky test ($PASS_COUNT/3 passed)" exit 125 fi
Environment Isolation:
# Clean state before each test rm -rf /tmp/test_cache export RANDOM_SEED=42 export TZ=UTC
4. Add Logging and Summaries
Generate concise output for each commit:
#!/bin/bash COMMIT=$(git rev-parse --short HEAD) LOG_FILE="bisect_log_${COMMIT}.txt" echo "Testing commit: $COMMIT" | tee $LOG_FILE echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)" | tee -a $LOG_FILE # Run test and capture output if ./run_test > test_output.txt 2>&1; then echo "RESULT: GOOD" | tee -a $LOG_FILE exit 0 else echo "RESULT: BAD" | tee -a $LOG_FILE echo "Error output:" | tee -a $LOG_FILE tail -20 test_output.txt | tee -a $LOG_FILE exit 1 fi
5. Run Git Bisect
Execute the bisect workflow:
# Start bisect git bisect start # Mark known good and bad commits git bisect bad HEAD git bisect good v1.2.0 # Run automated bisect chmod +x bisect_test.sh git bisect run ./bisect_test.sh # Review results git bisect log
Instrumentation Patterns
Pattern 1: Performance Regression Detection
#!/bin/bash # Detect when performance drops below threshold THRESHOLD=1000 # milliseconds # Run benchmark DURATION=$(./benchmark | grep "Duration:" | awk '{print $2}') if [ -z "$DURATION" ]; then echo "SKIP: Benchmark failed to run" exit 125 fi if [ $DURATION -lt $THRESHOLD ]; then echo "GOOD: Performance $DURATION ms (< $THRESHOLD ms)" exit 0 else echo "BAD: Performance $DURATION ms (>= $THRESHOLD ms)" exit 1 fi
Pattern 2: Test Suite Bisection
#!/bin/bash # Find commit that broke specific test TEST_NAME="test_user_authentication" # Run specific test if pytest tests/${TEST_NAME}.py -v; then echo "GOOD: $TEST_NAME passed" exit 0 else echo "BAD: $TEST_NAME failed" exit 1 fi
Pattern 3: Build Failure Detection
#!/bin/bash # Find commit that broke the build if make clean && make all; then echo "GOOD: Build succeeded" exit 0 else echo "BAD: Build failed" exit 1 fi
Pattern 4: Output Validation
#!/bin/bash # Find commit that changed program output EXPECTED_OUTPUT="Success: 42" ACTUAL_OUTPUT=$(./program 2>&1) if [ "$ACTUAL_OUTPUT" = "$EXPECTED_OUTPUT" ]; then echo "GOOD: Output matches expected" exit 0 else echo "BAD: Output mismatch" echo " Expected: $EXPECTED_OUTPUT" echo " Actual: $ACTUAL_OUTPUT" exit 1 fi
Advanced Techniques
Handling Complex Build Systems
#!/bin/bash # Handle projects with complex dependencies # Check if dependencies are available if ! command -v node &> /dev/null; then echo "SKIP: Node.js not available in this commit" exit 125 fi # Install dependencies (with caching) if [ -f package.json ]; then npm ci --silent || { echo "SKIP: Dependency installation failed" exit 125 } fi # Run test npm test
Parallel Test Execution
#!/bin/bash # Run multiple tests in parallel for faster bisection # Run tests in parallel parallel --halt soon,fail=1 ::: \ "pytest tests/unit/" \ "pytest tests/integration/" \ "npm run lint" if [ $? -eq 0 ]; then echo "GOOD: All tests passed" exit 0 else echo "BAD: At least one test failed" exit 1 fi
State Preservation
#!/bin/bash # Preserve state between bisect steps STATE_DIR=".bisect_state" mkdir -p $STATE_DIR # Save current commit info git rev-parse HEAD > $STATE_DIR/current_commit # Run test ./run_test RESULT=$? # Log result echo "$(git rev-parse --short HEAD): $RESULT" >> $STATE_DIR/results.log exit $RESULT
Troubleshooting
Issue: Bisect Marks Wrong Commit
Cause: Test script has incorrect exit codes or flaky behavior
Solution: Add verbose logging and retry logic
set -x # Enable debug output # Add retry logic as shown in section 3
Issue: Too Many Commits Skipped
Cause: Build failures or missing dependencies across history
Solution: Use broader skip conditions
# Skip commits with known issues if git log -1 --format=%s | grep -q "WIP\|broken"; then echo "SKIP: Known broken commit" exit 125 fi
Issue: Bisect Takes Too Long
Cause: Slow test execution
Solution: Optimize test or use binary search hints
# Use timeout to fail fast timeout 10s ./run_test || exit 125 # Or provide bisect hints git bisect skip $(git rev-list --grep="refactor" HEAD~50..HEAD)
Best Practices
- Make tests deterministic: Fix random seeds, timestamps, and external dependencies
- Use timeouts: Prevent hanging tests from blocking bisect
- Log everything: Save detailed logs for each tested commit
- Handle build failures gracefully: Use exit code 125 to skip untestable commits
- Test the test script: Verify it works on known good and bad commits before bisecting
- Keep it fast: Optimize tests to run quickly (bisect tests O(log n) commits)
Quick Reference
Start bisect:
git bisect start git bisect bad <bad-commit> git bisect good <good-commit>
Run automated bisect:
git bisect run ./bisect_test.sh
Manual bisect:
git bisect good # Current commit is good git bisect bad # Current commit is bad git bisect skip # Cannot test current commit
End bisect:
git bisect reset
Resources
- references/git_bisect_guide.md: Comprehensive git bisect documentation
- references/exit_codes.md: Exit code conventions and best practices
- scripts/bisect_template.sh: Template bisect test script
- scripts/bisect_wrapper.py: Python wrapper for complex bisect logic