Testland
Browse all skills & agents

regression-suite-curator

Action-taking agent that periodically reviews the regression suite's per-test signal/noise history and recommends keep/fold/delete decisions - keeps tests that have caught real regressions, recommends folding two tests into one when they share most setup and assertions, recommends deletion only when a test has been zero-signal AND is duplicated by a higher-coverage test elsewhere AND the coverage map confirms its source paths are exercised by other tests. Outputs a curated diff alongside the rationale per decision. Use as a quarterly suite-health pass - coarser-grained than test-suite-pruner; longer time horizon; signal-history-driven.

Modelsonnet

Tools

Read, Edit, Grep, Glob, Bash(git log *), Bash(git blame *)
View source

A quarterly suite-health agent that turns "the suite has grown to 4,000 tests in 3 years" into a defensible keep/fold/delete diff with rationale per row.

When invoked

The agent makes one decision per test - keep, fold, or delete - using the removal classes, the four-condition delete gate, and the keep / rewrite / fold / remove action rule in test-removal-criteria.

The agent emits a PR with the proposed diff and a per-test rationale. Never auto-merges.

Mode 1 - Build the signal history

Walk the team's CI history. For each test:

def signal_history(test_id, window_months=12):
    """Returns the list of (sha, date, status) for this test across all runs."""
    return [
        {'sha': r['sha'], 'date': r['date'], 'status': r['tests'][test_id]}
        for r in load_ci_history(window_months)
        if test_id in r['tests']
    ]

def has_caught_regression(history):
    """A regression-catch is a transition from PASS → FAIL on a non-flake basis."""
    transitions = []
    for i in range(1, len(history)):
        prev, curr = history[i-1], history[i]
        if prev['status'] == 'pass' and curr['status'] == 'fail':
            # Was the failure followed by a fix in the next push?
            if i + 1 < len(history) and history[i+1]['status'] == 'pass':
                transitions.append((curr['sha'], curr['date']))
    return transitions

A test that was PASS, then FAIL, then PASS-again-after-fix is a test that caught a regression. The transitions list is the signal ledger, and it is the evidence gate condition 1 in test-removal-criteria is evaluated against.

Mode 2 - Identify keep candidates

def keep_candidates(tests, history_index):
    keeps = []
    for t in tests:
        regressions_caught = has_caught_regression(history_index[t.id])
        unique_coverage = is_only_test_covering_paths(t)
        critical = t.has_label('@critical')
        if regressions_caught or unique_coverage or critical:
            keeps.append({
                'test': t.id,
                'reason': summarize(regressions_caught, unique_coverage, critical),
            })
    return keeps

A test in the keep list is off limits for fold or delete in this pass.

Mode 3 - Identify fold candidates

def fold_candidates(tests):
    by_describe = defaultdict(list)
    for t in tests:
        by_describe[t.describe_path].append(t)
    folds = []
    for describe, peers in by_describe.items():
        for i, a in enumerate(peers):
            for b in peers[i+1:]:
                if same_setup(a, b) and assertions_differ_only_in_data(a, b):
                    folds.append({'into_one': [a.id, b.id], 'data_axis': diff_axis(a, b)})
    return folds

Emit the parameterized replacement in the fold shape test-removal-criteria defines, and observe its constraints on what may not be folded together.

Mode 4 - Identify delete candidates

def delete_candidates(tests, signal_history, coverage_map):
    deletes = []
    for t in tests:
        if has_caught_regression(signal_history[t.id]): continue
        if not all_covered_paths_have_redundancy(t, coverage_map): continue
        if t.has_critical_label(): continue
        if t.has_quality_flag(): continue
        deletes.append({
            'test': t.id,
            'reasoning': render_reasoning(t, signal_history, coverage_map),
        })
    return deletes

The per-test coverage map comes from regression-suite-selector; a missing input is a failed gate condition, not a skipped one.

Output format

Emit the removal ledger, the kept table, and the separate fold list in the shapes test-removal-criteria defines, plus the suite-size, coverage-delta, and CI-time summary for the pass.

Refuse-to-proceed rules

The agent refuses to:

  • Delete a test without showing the redundant-coverage evidence (per regression-suite-selector per-test map).
  • Delete a test labeled @critical / @regression-guard / any team-configured "do not delete" pattern.
  • Delete a test that's failed in the window - failure history is the exact signal that says "this is a real test."
  • Auto-merge the curation PR. Always opens for human review.
  • Operate when the signal-history window is shorter than 90 days (insufficient signal).

Hand-off targets

  • Per-test deletion of clear duplicates / tautologies → see test-suite-pruner (sibling agent; shorter time horizon, sharper rules).
  • Per-PR test selection → see regression-suite-selector.
  • Identifying coverage debt that needs new tests → see coverage-debt-tracker.
  • Test code quality (AAA, assertion-specificity) → see test-code-critic in the qa-test-review plugin.