Implementation Plan: Next dependency wedge — dispatch the review
Branch: kitty/mission-next-dependency-review-dispatch-01M46TJ7 | Date: 2026-10-05 | Spec: ./spec.md Input: Mission specification from kitty-specs/next-dependency-review-dispatch-01M46TJ7/spec.md
Summary
Three defects, one promise: advancing next and querying next must agree on a finalized task board, and neither may wedge when the only actionable work is the review of a for_review WP that a planned WP depends on. Each defect is a small, surgical fix at a single authoritative seam, landed red-first (ADR 2026-07-17-1):
1. Defect 1 (#5669) — the routing authority _finalized_task_board_override_step (src/runtime/next/runtime_bridge.py) returns "implement" for a dependency-walled planned WP, so the for_review→"review" branch is never reached. Fix: gate the planned arm on real claimability (preview_claimable_wp), keep the claimed/in_progress resume arms, and fall through to for_review→review when the planned WP is walled. One seam fixes both the dispatch path (_resolve_wp_board_implement_action) and the query path (_build_finalized_override_query_decision). 2. #5310 (folded) — advancing next on first contact (no persisted run) boots a fresh discovery runtime (decide_next_via_runtime→_dn_bootstrap→get_or_start_run) instead of consulting the finalized board that query mode honours. Fix: make the advance first-contact path consult the finalized-board authority so advance and query agree; it inherits Defect 1's corrected verdict. 3. Defect 2 (#5669 part 2) — next appends kitty-specs/<slug>/mission-events.jsonl (its own observability log) and leaves it uncommitted, so the move-task dirty gate refuses move-task --to approved on lanes. Fix: classify that exact path as a review-handoff survivor in dirty_classifier.py::_is_review_handoff_survivor_path (scoped to the review/move-task gate; NOT the global churn owner).
Technical Context
Language/Version: Python 3.11+ Primary Dependencies: internal — src/runtime/next/ (control loop), src/specify_cli/review/ (dirty gate), src/specify_cli/status/ (lane reader), src/mission_runtime/ (placement seam). No new third-party deps. Storage: canonical status event log (status.events.jsonl); legacy mission-events.jsonl. No schema change. Testing: pytest, targeted surfaces only (NO full/heavy suite locally — CI owns architectural/e2e/perf). Red-first @pytest.mark.regression per defect, issue-pinned. Target Platform: CLI, cross-platform (Linux/macOS/Windows). Project Type: single project. Performance Goals: next stays within the CLI <2s budget; no added run-start/git cost on the hot path (NFR-003). Constraints: single canonical authority (C-001); mission-events.jsonl stays globally non-benign (C-002); ATDD red-first (C-003). Scale/Scope: three functions changed across two modules; ~3 focused WPs.
Charter Check
GATE: Must pass before implementation. Re-check after design.
- ATDD-first (C-011) — PASS by construction: each WP lands a failing-first regression (RED on the mission's
planning_base_branch, GREEN on the fix) before the implementation commit. → C-003. - Single canonical authority (DIRECTIVE_044) — PASS: Defect 1 reuses
preview_claimable_wpinside the one routing seam (no second claimability predicate); Defect 2 is a scoped per-gate survivor (the global churn owner is deliberately NOT widened — it has live readers + an explicit keep-local ruling). → C-001, C-002. - Tiered rigour / DDD — the
nextcontrol loop is core domain → highest rigour; the dirty gate is glue/IO → still gets a negative-control test. - NO_FULL_HEAVY_SUITES_IN_MISSION — PASS: targeted module tests + the specific named gate files only; CI runs the full matrix.
- Terminology canon — PASS: "Mission" vocabulary; no
--featureflags introduced. - Branch/version — no version number assigned in scope; PRs only, operator merges.
- Red-main discipline — these are the P1 reds; land the reproductions, fix, no green-washing.
Project Structure
Documentation (this mission)
kitty-specs/next-dependency-review-dispatch-01M46TJ7/
├── plan.md # This file
├── spec.md # Mission spec
├── research/ # Code-grounding findings (brownfield seams)
├── traces/ # tooling-friction / approach / design-decisions
└── tasks.md + tasks/ # /spec-kitty.tasks output
Source Code (repository root)
src/runtime/next/
├── runtime_bridge.py # Defect 1: _finalized_task_board_override_step (routing seam);
│ # #5310: decide_next_via_runtime / _dn_bootstrap (advance first-contact)
├── runtime_bridge_io.py # #5310: get_or_start_run (run bootstrap) — read for context
├── discovery.py # preview_claimable_wp (claimability authority — reused, not changed)
└── decision.py # _implement_state_action (live fallback — NOT changed, confirm preempted)
src/specify_cli/review/
└── dirty_classifier.py # Defect 2: _is_review_handoff_survivor_path (scoped survivor)
src/specify_cli/orchestrator_api/
└── decision_verbs.py # #5310: verify it shares the next/board seam (no parallel override)
tests/
├── next/test_finalized_task_routing.py # Defect 1 unit (routing verdict)
├── runtime/test_next_board_authority.py # Defect 1 dispatch end-to-end
├── integration/test_next_preview_primary_routing.py # query↔advance parity
├── review/test_dirty_classifier.py # Defect 2 survivor + negative control
└── (a #5310 regression home chosen at tasks time — advance first-contact vs query)
Structure Decision: Single project. Edits confined to src/runtime/next/runtime_bridge.py (Defects 1 and #5310) and src/specify_cli/review/dirty_classifier.py (Defect 2). No new modules, no new public symbols beyond what the fixes require.
Complexity Tracking
No charter violations. The one judgement call (Defect 2 declines the "single global owner" instinct in favour of a scoped per-gate survivor) is justified under C-002, not a violation: the global owner has live correctness readers and an explicit keep-local ruling, so widening it would be the regression.
Implementation Concern Map
> Concerns, not work packages. /spec-kitty.tasks translates these into WPs.
IC-01 — Dependency-aware finalized-board routing (the wedge)
- Purpose: The finalized-board router must report
review(notimplement) when the onlyplannedWPs are dependency-walled and afor_reviewWP exists, so both dispatch and query dispatch the pending review. - Relevant requirements: FR-001, FR-002, FR-003, FR-004; SC-001, SC-002; NFR-001, NFR-002, NFR-003.
- Affected surfaces:
src/runtime/next/runtime_bridge.py::_finalized_task_board_override_step(gate theplannedarm onpreview_claimable_wp); it is consumed by_resolve_wp_board_action(dispatch) and_query_dispatch_decision/_build_finalized_override_query_decision(query). Reusesdiscovery.py::preview_claimable_wp. - Sequencing/depends-on: none (foundational).
- Risks: must preserve the #4860 guard (a walled WP never dispatched for
implement); must keepclaimed/in_progress→implement(resume) and thein_review/done/accept/no_actionable_wpendings byte-identical; double idempotentpreview_claimable_wpread is acceptable (no new authority). Confirm the query call-site threads the coord-aware dirs.
IC-02 — Advance first-contact honours the finalized board (#5310)
- Purpose: Advancing
nextwith no persisted run must consult the finalized-board authority (agreeing with query mode) rather than booting a freshdiscoveryrun. - Relevant requirements: FR-005; SC-003; NFR-001.
- Affected surfaces:
src/runtime/next/runtime_bridge.pyadvance path (decide_next_via_runtime/_dn_bootstrap); context-readruntime_bridge_io.py::get_or_start_run. Verifysrc/specify_cli/orchestrator_api/decision_verbs.pyshares the seam (no parallel override). - Sequencing/depends-on: IC-01 (builds on the corrected override verdict).
- Risks: distinct root from IC-01 — must not pull the whole run-bootstrap machinery into the Defect-1 change; if the remediation is larger than a board-authority consult, it stays its own WP. Must not regress a genuinely not-started mission (no finalized board → discovery is correct).
IC-03 — Scoped dirty-gate survivor for mission-events.jsonl (lanes approval)
- Purpose:
next's uncommittedkitty-specs/<slug>/mission-events.jsonlmust not refuse amove-tasktransition; the exemption must be narrow. - Relevant requirements: FR-006, FR-007; SC-004; C-002.
- Affected surfaces:
src/specify_cli/review/dirty_classifier.py::_is_review_handoff_survivor_path(add the exact-anchored path), consumed via_is_benign←classify_dirty_paths←_validate_research_artifacts←_validate_ready_for_review(runs for FOR_REVIEW/APPROVED/DONE). - Sequencing/depends-on: none (independent of IC-01/IC-02).
- Risks: must NOT widen
coordination.coherence.is_self_bookkeeping_churn/is_toolchain_generated_churn(destructive consolidate/accept/merge consumers + research-gate readers); must anchor tokitty-specs/<slug>/mission-events.jsonlso a user file namedmission-events.jsonlelsewhere still blocks (negative control). Mirror the function-local-literal pattern the file already uses so the R-014 exemption-registry scan is satisfied.