Skip to content
Back to skills

2532 Detection Strategies A741df25

ASecurity

This document outlines strategies for detecting behavioral regressions between code versions.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
code-qualitypythongobashtestingrefactoringgitapidatabasesecurityperformance

Works with

  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2532-detection_strategies_a741df25 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2532 Detection Strategies A741df25?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2532 Detection Strategies A741df25
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2532-detection-strategies-a741df25/badge)](https://www.skillsdirectory.com/skills/tools-only-2532-detection-strategies-a741df25)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Regression Detection Strategies

This document outlines strategies for detecting behavioral regressions between code versions.

## Types of Regressions

### 1. Output Regressions

**Description**: Function returns different values for same inputs.

**Examples**:
- Calculation changes: `sum([1,2,3])` returns `6` → `7`
- Format changes: Returns `"2024-01-01"` → `"01/01/2024"`
- Type changes: Returns `42` → `"42"`
- Precision changes: Returns `3.14` → `3.14159`

**Detection**:
- Capture function outputs on old version
- Run same inputs on new version
- Compare outputs with appropriate tolerance

### 2. Exception Regressions

**Description**: Different exceptions raised or exception behavior changes.

**Examples**:
- New exception: Code that succeeded now raises exception
- Missing exception: Code that raised exception now succeeds
- Different exception type: `ValueError` → `TypeError`
- Different exception message: `"Invalid input"` → `"Bad value"`

**Detection**:
- Record which tests raise exceptions on old version
- Check if same tests raise same exceptions on new version
- Compare exception types and messages

### 3. State Regressions

**Description**: Observable state changes differ between versions.

**Examples**:
- Database state: Different records created/updated
- File system: Different files written
- External API calls: Different requests made
- Side effects: Different logs, metrics, events

**Detection**:
- Capture state snapshots before/after operations
- Compare state changes between versions
- Check side effects (logs, DB queries, API calls)

### 4. Performance Regressions

**Description**: Significant performance degradation.

**Examples**:
- Execution time: 100ms → 5000ms
- Memory usage: 10MB → 500MB
- Database queries: 1 query → N+1 queries
- API calls: 1 call → 10 calls

**Detection**:
- Measure execution time on both versions
- Track resource usage (memory, CPU, I/O)
- Count external calls (DB, API, file system)
- Flag significant increases (>50% slower)

### 5. Behavioral Regressions

**Description**: Subtle behavior changes not caught by assertions.

**Examples**:
- Order changes: List returned in different order
- Timing changes: Async operations complete in different order
- Randomness: Different random values (if not seeded)
- Caching: Different cache hit/miss patterns

**Detection**:
- Normalize outputs (sort lists, fix random seeds)
- Check invariants beyond exact equality
- Verify logical properties hold

## Detection Approaches

### Approach 1: Test Output Comparison

**Method**: Run tests on both versions, compare outputs.

**Steps**:
1. Run test suite on old version, capture outputs
2. Run test suite on new version, capture outputs
3. Compare outputs test by test
4. Flag differences as potential regressions

**Pros**:
- Simple to implement
- Works with existing tests
- No code modification needed

**Cons**:
- Only detects what tests observe
- May have false positives (intentional changes)
- Requires deterministic tests

**Implementation**:
```python
# Run on old version
old_results = run_tests(old_version)

# Run on new version
new_results = run_tests(new_version)

# Compare
for test_name in old_results:
    if old_results[test_name] != new_results[test_name]:
        report_regression(test_name, old_results[test_name], new_results[test_name])
```

### Approach 2: Differential Testing

**Method**: Run same inputs through both versions simultaneously.

**Steps**:
1. Extract test inputs from test suite
2. Run inputs through old version, record outputs
3. Run inputs through new version, record outputs
4. Compare outputs for each input

**Pros**:
- Precise comparison
- Can test at function level
- Isolates specific changes

**Cons**:
- Requires extracting test inputs
- May need to handle side effects
- More complex setup

**Implementation**:
```python
# Extract inputs from tests
inputs = extract_test_inputs(test_suite)

# Run through both versions
for test_input in inputs:
    old_output = run_on_old_version(test_input)
    new_output = run_on_new_version(test_input)

    if not outputs_match(old_output, new_output):
        report_regression(test_input, old_output, new_output)
```

### Approach 3: Snapshot Testing

**Method**: Capture snapshots of outputs/state, compare against new version.

**Steps**:
1. Run tests on old version, save snapshots
2. Run tests on new version
3. Compare new outputs against saved snapshots
4. Flag mismatches

**Pros**:
- Comprehensive state capture
- Good for complex outputs
- Easy to review changes

**Cons**:
- Large snapshot files
- Brittle to formatting changes
- Requires snapshot management

**Implementation**:
```python
# Generate snapshots from old version
snapshots = {}
for test in test_suite:
    output = run_test(test, old_version)
    snapshots[test.name] = serialize(output)
save_snapshots(snapshots)

# Compare against new version
for test in test_suite:
    output = run_test(test, new_version)
    expected = load_snapshot(test.name)
    if serialize(output) != expected:
        report_regression(test.name, expected, output)
```

### Approach 4: Property-Based Comparison

**Method**: Check that properties/invariants hold across versions.

**Steps**:
1. Define properties that should be preserved
2. Verify properties on old version
3. Verify same properties on new version
4. Flag property violations

**Pros**:
- Catches semantic changes
- Less brittle than exact comparison
- Focuses on important properties

**Cons**:
- Requires defining properties
- May miss some regressions
- More complex to implement

**Implementation**:
```python
# Define properties
properties = [
    lambda result: len(result) > 0,  # Non-empty result
    lambda result: all(x > 0 for x in result),  # All positive
    lambda result: result == sorted(result),  # Sorted
]

# Check properties on both versions
for test in test_suite:
    old_output = run_test(test, old_version)
    new_output = run_test(test, new_version)

    for prop in properties:
        old_holds = prop(old_output)
        new_holds = prop(new_output)

        if old_holds != new_holds:
            report_property_violation(test, prop, old_holds, new_holds)
```

## Comparison Strategies

### Exact Comparison

**When to use**: Deterministic outputs, no floating point.

```python
def exact_match(old, new):
    return old == new
```

### Approximate Comparison

**When to use**: Floating point numbers, timing-dependent values.

```python
def approx_match(old, new, tolerance=1e-6):
    if isinstance(old, float) and isinstance(new, float):
        return abs(old - new) < tolerance
    return old == new
```

### Structural Comparison

**When to use**: Complex objects, ignore certain fields.

```python
def structural_match(old, new, ignore_fields=None):
    if ignore_fields is None:
        ignore_fields = ['timestamp', 'id']

    old_filtered = {k: v for k, v in old.items() if k not in ignore_fields}
    new_filtered = {k: v for k, v in new.items() if k not in ignore_fields}

    return old_filtered == new_filtered
```

### Semantic Comparison

**When to use**: Order-independent collections, equivalent representations.

```python
def semantic_match(old, new):
    # Lists: compare as sets (ignore order)
    if isinstance(old, list) and isinstance(new, list):
        return set(old) == set(new)

    # Dicts: compare keys and values
    if isinstance(old, dict) and isinstance(new, dict):
        return old.keys() == new.keys() and all(
            semantic_match(old[k], new[k]) for k in old.keys()
        )

    return old == new
```

## Handling Non-Determinism

### Random Values

**Problem**: Tests use random values, outputs differ each run.

**Solution**: Fix random seed.

```python
# Old version
import random
random.seed(42)
run_tests()

# New version
import random
random.seed(42)
run_tests()
```

### Timestamps

**Problem**: Outputs include current time.

**Solution**: Mock time or ignore timestamp fields.

```python
# Mock time
from unittest.mock import patch
with patch('datetime.datetime') as mock_datetime:
    mock_datetime.now.return_value = datetime(2024, 1, 1)
    run_tests()

# Or ignore timestamps in comparison
def compare_ignoring_timestamps(old, new):
    return structural_match(old, new, ignore_fields=['timestamp', 'created_at'])
```

### Async Operations

**Problem**: Async operations complete in different order.

**Solution**: Sort results or use deterministic execution.

```python
# Sort results before comparison
old_results = sorted(run_async_test(old_version), key=lambda x: x.id)
new_results = sorted(run_async_test(new_version), key=lambda x: x.id)
compare(old_results, new_results)
```

### External Dependencies

**Problem**: External APIs, databases return different data.

**Solution**: Mock external dependencies.

```python
# Mock external API
with patch('requests.get') as mock_get:
    mock_get.return_value.json.return_value = {'data': 'fixed'}
    run_tests()
```

## Regression Severity Classification

### Critical Regressions

**Indicators**:
- Test that passed now fails
- Exception raised where none before
- Data corruption or loss
- Security vulnerability introduced

**Action**: Block release, fix immediately.

### High Severity Regressions

**Indicators**:
- Incorrect output for valid input
- Wrong exception type raised
- Significant performance degradation (>2x slower)
- Breaking API changes

**Action**: Fix before release.

### Medium Severity Regressions

**Indicators**:
- Minor output format changes
- Performance degradation (50-100% slower)
- Changed error messages
- Deprecated API usage

**Action**: Review and fix if time permits.

### Low Severity Regressions

**Indicators**:
- Cosmetic changes (whitespace, formatting)
- Minor performance changes (<50%)
- Log message changes
- Internal refactoring

**Action**: Document, fix in future release.

### False Positives

**Indicators**:
- Intentional behavior changes
- Bug fixes that change output
- Improved error handling
- Performance improvements

**Action**: Mark as expected, update baseline.

## Best Practices

### 1. Establish Baseline

Run tests on old version multiple times to ensure stability:
```bash
# Run 3 times to check for flaky tests
for i in {1..3}; do
  run_tests old_version > baseline_$i.txt
done

# Compare baselines
diff baseline_1.txt baseline_2.txt
```

### 2. Isolate Changes

Test one change at a time when possible:
- Single commit
- Single feature
- Single bug fix

### 3. Use Version Control

Tag versions for comparison:
```bash
git tag old-version v1.0.0
git tag new-version v1.1.0
```

### 4. Automate Comparison

Create automated regression check:
```bash
#!/bin/bash
# Run tests on both versions
git checkout old-version
pytest --json-report > old_results.json

git checkout new-version
pytest --json-report > new_results.json

# Compare results
python compare_results.py old_results.json new_results.json
```

### 5. Document Expected Changes

Maintain changelog of intentional behavior changes:
```markdown
# v1.1.0 Changes

## Intentional Behavior Changes
- Function `foo()` now returns list instead of tuple
- Error messages now include more context
- Performance optimization: 2x faster

## Bug Fixes
- Fixed off-by-one error in `bar()`
```

### 6. Review All Differences

Don't automatically assume all differences are bugs:
- Some may be intentional improvements
- Some may be bug fixes
- Some may be acceptable trade-offs

### 7. Maintain Test Stability

Ensure tests are deterministic:
- Fix random seeds
- Mock external dependencies
- Use fixed timestamps
- Sort non-deterministic outputs

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.