Contracts
reaper-and-hygiene-contracts.md
Contracts — session-reaper-and-tmp-leak-hygiene-01KWWAE7 (#1842)
Contract 1 — Session reaper (WP01, tests/conftest.py)
pytest_sessionstart(session) — captures a narrow name-pattern baseline (controller only, session.config.workerinput is None):
- Input: REPO_ROOT.
- Output (stashed): existing
kitty-specs/{test-feature-, -123-test-feature, golden-path-demo}dir names,kitty/mission-test-feature-/kitty/golden-pathbranch names,.worktrees/dir names. - Invariant: shallow scan only (glob/iterdir/git) — NO deep
rglobmtime inventory (C-001).
pytest_sessionfinish(session, exitstatus) — reaps the delta (controller only):
reap_session_delta(repo_root, baseline): removes onlycurrent − baseline—rmtreedirs,git branch -Dbranches,git worktree prunethenrmtree.worktrees/*husks absent fromgit worktree list --porcelain.sweep_tmp_residue(repo_root, baseline, run_test_home_dirs): delta-sweepsprompt_tmp_dir(repo_root)residue; removes the current run'sspec-kitty-test-homes/<run_uid>/by name (fromrun_test_home_dirs).assert_no_leaked_test_residue(result): raises if the reaped REPO_ROOT delta was non-empty (reap-then-assert).- Invariants: NFR-001 (workers never reap); NFR-002 (pre-session artifacts never deleted); concurrent OTHER runs' test-homes preserved (only config-derived uids removed).
_current_run_test_home_dirs(config) — serial → serial-<pid>; xdist controller → serial-<pid> + workers' shared <testrunuid> (via _xdist_testrunuid).
Contract 2 — /tmp prompt namespace (WP02, src/runtime/next/_tmp_namespace.py)
prompt_tmp_dir(repo_root: Path) -> Path — single source of truth. Returns (creating if absent) <gettempdir()>/spec-kitty-prompts/<sha256(repo_root)[:16]>/. Consumed by prompt_builder.py (spec-kitty-next-), decision.py (both spec-kitty-composed- mkstemp sites), workflow.py (spec-kitty-implement|review-*), AND WP01's reaper (the swept root). Invariant: no writer hand-copies the prefix (drift-proof test asserts is_relative_to(prompt_tmp_dir(repo_root))).
Contract 3 — Workspace-context tombstone (WP03)
Cancel (coordination/status_transition.py emit_status_transition_transactional, both coord-topology + fallback branches): on to_lane == CANCELED, when all lane WPs terminal (all(wp.lane in {done, canceled})), call delete_context(repo_root, worktree_dir_name(slug, mission_id=None, lane_id)). Merge (merge/executor.py _phase_cleanup_worktrees_and_branches): per lane, targeted delete_context (order-independent — pure unlink). Invariant (C-004): only the CANCELED transition fires the cancel hook; no other transition behavior changes.