Implementation Plan: Implement resumes after in_review to in_progress rejection
Branch: ccr-806fafb9-5qycab | Date: 2026-09-29 | Spec: spec.md Input: Mission specification from kitty-specs/implement-rework-resume-01M3QA1X/spec.md
Summary
start_implementation_status (the shared implementation-start authority) refuses the implementer's resume on an in_progress WP because its ownership check compares the requester with the slot occupant, which after an in_review → in_progress rework verdict is the reviewer. The fix admits the implementer of record, resolved by the existing status.review_roles.latest_implementer_actor projection, through one pure predicate that move-task's ownership role allowance also uses, so the two ownership checks share one rule. The resume stays an idempotent no-op on the lane (no event emitted).
Technical Context
Language/Version: Python 3.11+ Primary Dependencies: typer, rich (CLI); no new dependencies Storage: append-only status.events.jsonl (read only by this change) Testing: pytest — real-CLI harness tests/specify_cli/cli/commands/agent/_rework_loop_harness.py; unit tests on the lifecycle arm and the predicate Target Platform: Linux / macOS / Windows CLI Project Type: single project (src/specify_cli/) Performance Goals: no extra event-log read on the unchanged paths (NFR-001) Constraints: no --force in the loop (C-002); reuse the canonical projection (C-001); complexity ≤ 15 Scale/Scope: 2 source modules, ~40 changed source lines
Supply-chain check (DIRECTIVE_051): no dependency decision in this mission — not applicable.
Charter Check
- Single canonical authority — PASS: one predicate (
is_latest_implementer) instatus/review_roles.pyowns the "requester is the implementer of record" rule for both the lifecycle arm andmove-task's_implementer_arm;_ownership_role_allowancekeeps its requester-free None/generic guard because_reviewer_armneeds it too; no fourth implementer projection (C-001, #5340 stays the unification follow-up). - Architectural alignment — PASS: the lifecycle imports
review_rolesfunction-locally (as it already does forcoordination.status_transition), becausereview_rolesimports_actor_key/GENERIC_IMPLEMENTATION_ACTORSfrom the lifecycle module at import time. - ATDD / red-first — PASS: the real-CLI regression through
agent action implementis RED on the planning base (exit 1,WorkPackageClaimConflict) and committed before the fix. - Tiered rigour — status ownership is core domain: unit tests on every new branch (admit, third tool, generic, empty log, read failure) plus the real-CLI loop.
- Terminology — Mission / work package; no
featurealiases introduced.
Project Structure
Documentation (this mission)
kitty-specs/implement-rework-resume-01M3QA1X/
├── spec.md
├── plan.md
├── research.md
├── tasks.md
├── tasks/WP01-implementer-resume.md
├── issue-matrix.json
└── traces/ (tooling-friction.md, approach.md, design-decisions.md)
Source Code (repository root)
src/specify_cli/status/
├── review_roles.py # + is_latest_implementer(latest, actor) predicate
└── work_package_lifecycle.py # IN_PROGRESS arm admits the implementer of record
src/specify_cli/cli/commands/agent/
└── tasks_transition_core.py # _implementer_arm reuses the predicate (the None/generic guard in _ownership_role_allowance stays: it also gates _reviewer_arm)
tests/specify_cli/cli/commands/agent/
├── test_rework_unforced_loop.py # real-CLI resume + fail-closed
└── test_rework_guard_ratchets.py # third tool refused via implement
tests/status/test_work_package_lifecycle.py # lifecycle arm unit tests
tests/unit/status/test_review_roles.py # predicate unit tests
Structure Decision: single project; changes stay inside status/ plus the one move-task core module that already consumes the projection.
Complexity Tracking
No charter violations.
Implementation Concern Map
IC-01 — Implementer-of-record admission at the implementation-start authority
- Purpose: let the implementer of record resume an
in_progressWP after a rework verdict, fail closed on read failure, keep third tools refused. - Relevant requirements: FR-001, FR-002, FR-003, FR-004, NFR-001, NFR-002, C-001, C-002, C-003
- Affected surfaces:
src/specify_cli/status/work_package_lifecycle.py(IN_PROGRESS arm + extracted helper),src/specify_cli/status/review_roles.py(shared predicate),src/specify_cli/cli/commands/agent/tasks_transition_core.py(_implementer_armreuses the predicate, behaviour-preserving) - Sequencing/depends-on: none
- Risks: import cycle (mitigated by a function-local import); append-order vs Lamport disagreement between the projection and the reducer slot under merged-log reordering (accepted residual, #4941).