Implementation Plan: Move-task executor seam and test-friction cleanup
Branch: claude/move-task-degod-slice-2 | Date: 2026-10-04 | Spec: spec.md
Summary
This is slice 2 of #5629. The remaining decision, emission and recovery logic moves out of tasks_move_task.py into two sibling seam modules: tasks_move_task_hops.py for the pure hop builders and tasks_move_task_executor.py for planning, emission and recovery. The runtime-annotation emitter choice (owned checkout, then auto_commit, then plain) moves behind one coordination-shell helper that both move-task and mark-status call. Before any code moves, the move-task test surface is de-frictioned (DIRECTIVE_041 and the development-assist test-cleanup procedure), so that later moves need no hand edits to symbol lists:
- derive the compat keysets instead of listing them;
- generalise the no-shadow guard;
- retire the commit-hash provenance pin and the spent capture harness.
Technical Context
Language/Version: Python 3.11+ Primary Dependencies: typer, the specify_cli.status transition pipeline, specify_cli.coordination.status_transition Testing: pytest (+xdist --dist loadfile), the architectural gate battery Target Platform: CLI Project Type: single project Constraints: verbatim moves (C-003); one authoritative validation (C-002); no gate-ledger widening (C-004)
Charter Check
- Single canonical authority. The event log stays the sole authority. The shell helper removes the parallel emitter-choice authority in mark-status. PASS
- Architectural alignment. The new modules sit in the
specify_cliadapter layer. The shell helper keeps the status→coordination import direction by importing lazily. PASS - ATDD / red-first (ADR 2026-07-17-1). This is behaviour-preserving relocation with no defect to reproduce. New seams get focused tests in the same commit. N/A for red-first, PASS for tests.
- Campsite / test remediation (DIRECTIVE_041, procedure development-assist-test-cleanup). IC-01 and IC-05 apply them. PASS
- Terminology. "Mission" only, never "feature"; "status commit" is used where relevant. PASS
Project Structure
Documentation (this mission)
kitty-specs/move-task-executor-seam-lanes-01M43FAG/
├── spec.md plan.md tasks.md tasks/WP0*.md
└── traces/ (tooling-friction.md, approach.md, design-decisions.md)
Source Code (repository root)
src/specify_cli/cli/commands/agent/
├── tasks_move_task.py # CLI: parse, sequence, present (shrinks)
├── tasks_move_task_gates.py # slice 1
├── tasks_move_task_hops.py # NEW: pure hop builders
└── tasks_move_task_executor.py # NEW: plan finalize, emit, persist, rollback, lock
src/specify_cli/coordination/status_transition.py # NEW helper emit_runtime_annotation
src/specify_cli/cli/commands/agent/tasks_mark_status.py # adopts the helper
tests/specify_cli/cli/commands/agent/test_tasks_compat_surface.py # derived keysets
tests/specify_cli/cli/commands/agent/test_tasks_move_task_seams.py # generalised seam guard
tests/review/test_transition_gate_parity.py, tests/review/fixtures/parity/_capture.py
Complexity Tracking
None. Every function keeps its current complexity, because the bodies move verbatim.
Implementation Concern Map
IC-01 — Test-friction pre-work
- Purpose: Make the compat guard and the seam guard derive their keysets from module definitions, so that moves need no hand-maintained lists.
- Relevant requirements: FR-005, FR-006
- Affected surfaces:
test_tasks_compat_surface.py,test_tasks_move_task_gates_seam.py(generalised intotest_tasks_move_task_seams.py) - Sequencing/depends-on: none
- Risks: Losing the invariant that each
tasks.<name>is the seam's object, not a copy. Keep the identity check and add a negative control.
IC-02 — Hop-builder seam
- Purpose: Move the pure hop builders into
tasks_move_task_hops.py. - Relevant requirements: FR-001, FR-003
- Affected surfaces:
tasks_move_task.py, the new hops module, tests patching_mt_hop_review_result - Sequencing/depends-on: IC-01
- Risks:
_mt_hop_review_resultis patched ontasks, so the call site in_mt_emit_transitionsmust keep calling it through_tasks..
IC-03 — Executor seam
- Purpose: Move plan finalisation, emission, persistence, rollback and lock release into
tasks_move_task_executor.py. - Relevant requirements: FR-002, FR-003, FR-008
- Affected surfaces:
tasks_move_task.py, the new executor module, the status-events writes gate allow-list,untrusted_path_audit/inventory.md, tests patching_mt_finalize_plan/_mt_execute - Sequencing/depends-on: IC-02
- Risks: Patch interception (
_tasks.bridge), gate allow-lists, import cycles.
IC-04 — Shell-owned runtime-annotation emit
- Purpose: One helper,
emit_runtime_annotation(owned, auto_commit, ...), incoordination/status_transition.py, adopted by move-task and mark-status. - Relevant requirements: FR-004
- Affected surfaces:
coordination/status_transition.py,tasks_move_task_executor.py,tasks_mark_status.py - Sequencing/depends-on: IC-03
- Risks: The #3460 plain path must not build a transaction.
owned=threading must be kept (#3866). Mark-status tests patch emitters ontasks_mark_status.
IC-05 — Parity-oracle provenance retirement and patch-site gate
- Purpose: Retire the base-commit provenance test and
_capture.py, and add a grep gate that keeps re-homed patches pointing at live names. - Relevant requirements: FR-007, FR-008
- Affected surfaces:
tests/review/test_transition_gate_parity.py,tests/review/fixtures/parity/_capture.py - Sequencing/depends-on: none, but it lands last so the gate sees the final module layout
- Risks: Deleting real decision coverage. Only provenance and capture go; the fixtures and replay tests stay.