Research: Regression-slice test cleanup

R-01 Where do the verdicts come from?

  • Decision: the per-file ledgers in issues #5618, #5619, #5620, #5621 and the report in #5622 are the input; they were produced by packs/internal/procedures/test-suite-quality-assessment.procedure.yaml on 2026-10-04.
  • Rationale: the operator brief names them as authoritative; re-deriving would duplicate the review.
  • Alternatives considered: re-running the static scan (make test-quality-scan) — rejected; the ledgers already carry verdicts, and #5621 notes the text-search scan over-selected prose-only files.

R-02 Does removing regression change what CI runs?

  • Decision: no de-routing risk. Module shards select not performance and not stress, so a regression test already runs per-PR; unmarking only moves fast/unit tests into make test-fast.
  • Rationale: verified in scripts/ci/shard_select.py and Makefile (FAST_TIER_MARKERS).
  • Alternatives considered: none needed. The gates that still bind marker edits are test_marker_job_completeness.py, test_ci_collection_completeness.py and test_fast_tier_marker_completeness.py; run them after the marker edits.

R-03 How are planted breaks applied safely in lane worktrees?

  • Decision: edit src/ inside the lane worktree, run only the named test files, git checkout -- src/ to revert, confirm git status --short src/ is empty before any commit.
  • Rationale: pytest.ini sets pythonpath = src, so the worktree's own src/ shadows the editable install for in-process tests. Tests that shell out to spec-kitty import from the venv's editable path (the repository root checkout), so they need PYTHONPATH=<worktree>/src for the break to reach them.
  • Alternatives considered: mutation tooling (mutmut) — rejected as heavier than needed and not scoped to one behaviour.

R-04 Root independence (#5622)

  • Decision: skip under os.geteuid() == 0 with an explicit reason unless the test's I/O seam can be patched cheaply to raise PermissionError; prefer the seam injection where the code under test reads through one call.
  • Rationale: root bypasses mode bits; CI is non-root, so the skip loses no CI coverage, while seam injection keeps the coverage everywhere.