The deletion test

import subprocess
import sys
import tempfile
from pathlib import Path

from spotregen import make_sample_repo

tmp = tempfile.TemporaryDirectory()
root = make_sample_repo(Path(tmp.name) / "demo")


def spotregen(*args, drop=None):
    """Run `spotregen` in the sample repository; show the call and its output."""
    done = subprocess.run(
        [sys.executable, "-m", "spotregen", *args],
        cwd=root,
        capture_output=True,
        text=True,
        check=False,
    )
    print("$ spotregen", *args)
    lines = (done.stdout + done.stderr).splitlines()
    print("\n".join(x for x in lines if not (drop and drop in x)))
    print(f"[exit {done.returncode}]")

Definition 1 (The deletion test) Fowler’s deletion test asks what would be lost if a module were deleted. For one unit spotregen deletion-test lists the blast radius (every dependent, declared or not), the intent items with their evaluation and provenance coverage, and a verdict. The verdict is “regenerable” only if every intent item has an evaluation, every dependent is declared and the unit check reports no error.

Example 1 (A regenerable unit) A unit may be named by its dotted name or by any unique suffix.

spotregen("deletion-test", "core.calc")
$ spotregen deletion-test core.calc
# Deletion test: samplepkg.core.calc

File `src/samplepkg/core/calc.py`, pace fast, risk low.

## Blast radius

| dependent | kind | declared | note |
|---|---|---|---|
| `docs/guide.qmd` | doc | yes | teaches add |
| `src/samplepkg/app/main.py` | code | yes | sums values with add |
| `tests/test_regen_eval_calc.py` | test | yes | evaluation |

## Knowledge outside the implementation

| intent | kind | evaluations | decisions |
|---|---|---|---|
| C-1 | contract | 1 | why-add |

Verdict: regenerable. 1 intent items, all evaluated; 3 dependents, all declared.
[exit 0]

The exit code is 0 exactly when the report contains Verdict: regenerable.

Example 2 (An undeclared dependent)  

(root / "scripts").mkdir()
(root / "scripts" / "use_it.py").write_text("from samplepkg.core.calc import add\n")
spotregen("deletion-test", "core.calc")
$ spotregen deletion-test core.calc
# Deletion test: samplepkg.core.calc

File `src/samplepkg/core/calc.py`, pace fast, risk low.

## Blast radius

| dependent | kind | declared | note |
|---|---|---|---|
| `docs/guide.qmd` | doc | yes | teaches add |
| `scripts/use_it.py` | code | NO |  |
| `src/samplepkg/app/main.py` | code | yes | sums values with add |
| `tests/test_regen_eval_calc.py` | test | yes | evaluation |

## Knowledge outside the implementation

| intent | kind | evaluations | decisions |
|---|---|---|---|
| C-1 | contract | 1 | why-add |

## Gaps

- DEL01: scripts/use_it.py depends on the unit but is not a declared consumer

Verdict: NOT regenerable yet (1 gaps).
[exit 1]

The blast radius lists the script with declared = NO, the gaps name the finding that fails (DEL01) and the verdict is not regenerable. The exit code is 1.

TipUnknown units

A unit that matches nothing, or more than one unit, exits with code 2 and lists the known units.

spotregen("deletion-test", "nope")
$ spotregen deletion-test nope
spotregen: "unknown unit 'nope'; known: ['samplepkg.core.calc']"
[exit 2]

Next: the regeneration bundle.