Tasks: Read-Path / Error-Fidelity Adoption

Mission: read-path-error-fidelity-adoption-01KV8NPC Branch: feat/read-path-error-fidelity (PRs to main) Source: plan.md (IC-01..IC-07 + decisions D-1..D-7), spec.md (FR-001..FR-012), contracts/behavioral-contracts.md, research/ (incl. investigation-2/, investigation-3-readwrite/), docs/engineering_notes/context-factory-readwrite-symmetry/00-SYNTHESIS.md

9 work packages, 43 subtasks. C-001: adopt the existing resolver, do not build. Zero owned_files overlap. Function-over-form + verification-by-deletion; TDD-first for the five bugs that reproduce on HEAD (research/live-repro.md + investigation-2/debbie-reverify-missed.md); topology-true fixtures only (full 26-char ULID + real coord-worktree + real submodule — NO fabricated short ids). WP01 lays the single context-factory seam (D-6) so the deferred write-side (#1716/#1878) adopts against a frozen seam. Net-new surfaces M1/M2/M3 folded (D-7).

Dependency graph / sequencing

WP01 (single context FACTORY + freeze + invariant + write-projection boundary — precondition)
  ├─> WP02 (next typed-error + M1 context-resolve)  ┐
  ├─> WP03 (mission.py entry)                        ├─ parallel (disjoint files)
  ├─> WP04 (decision authority)                      │
  ├─> WP05 (implement + #1993)                       │
  └─> WP09 (orchestrator typed-error + M3 fail-closed)┘
WP06 (root resolver)  — no dep, start anytime
WP07 (charter no-op)  — no dep, start anytime
WP08 (#1827 regression test, test-only) — no dep, start anytime

Immediately startable: WP01, WP06, WP07, WP08. After WP01 approved: WP02, WP03, WP04, WP05, WP09.

Subtask Index

IDDescriptionWPParallel
T001TDD: build-time CONTEXT_INVARIANT_VIOLATION testWP01
T002TDD: ExecutionContext immutability testWP01
T003Freeze the ExecutionContext compositeWP01
T004Assert target_branch == branch_ref.target_branch at buildWP01
T005Assemble WP-bearing context in one shot (no post-freeze write)WP01
T006Full-suite sweep; fix any mutator the freeze surfacesWP01
T007TDD: next read-path-miss → typed code, not MISSION_NOT_FOUNDWP02
T008Preserve code+paths at runtime_bridge.py query_current_stateWP02
T009Preserve code+paths at runtime_bridge.py answer_decision_via_runtimeWP02
T010Preserve code at next_cmd.py _find_mission_slugWP02
T011Emitter surfaces typed code+paths (mirror QueryModeValidationError)WP02
T012Verification-by-deletion: collapse removed, suite greenWP02
T013TDD: setup-plan exact-one auto-select; >1 structured errorWP03
T014Add exact-one auto-select in setup_plan (not the shared helper)WP03
T015TDD: is_committed true on primary-target-branch commitWP03
T016Add primary-target-branch leg to is_committed + diagnosticsWP03
T017TDD: _commit_to_branch hash report + no-op-vs-wrong-surfaceWP03
T018Fix _commit_to_branch (hash; distinguish no-op classes)WP03
T019finalize-tasks: anchor read on primary root (#11 fail-closed)WP03
T020TDD: decision open accepts coord handle; traversal token rejectedWP04
T021Delete escape-walk for resolved paths; repo_root from canonical authorityWP04
T022Structure the typed error (no raw traceback) at decision.py:103WP04
T023Keep _SAFE_SLUG_RE on raw token; confirm cmd_verify unaffectedWP04
T024TDD: implement consumes claim's resolved context (no "no workspace")WP05
T025Route implement to single resolution path (workflow.py)WP05
T026Extract resolve_lanes_dir(feature_dir) pure seamWP05
T027Route ad-hoc lanes.json derivations through the seamWP05
T028Unit test the seam + verification-by-deletionWP05
T029TDD: resolve_canonical_root returns submodule root (real submodule)WP06[P]
T030Fix paths.py submodule boundary (mirror locate_project_root)WP06[P]
T031Equivalence test {primary, coord, submodule}: both resolvers agreeWP06[P]
T032TDD: charter status side-effect-free + JSON-safe hashWP07[P]
T033Make status collectors side-effect-freeWP07[P]
T034Emit one normalized JSON-serializable hashWP07[P]
T035#1827 full record→commit→assert + resume regression test (passes)WP08[P]
T036#1827 falsification guard (broken ordering would fail)WP08[P]
T037Name build_execution_context factory + write-projection boundary contractWP01
T038M1: context mission-resolve typed-error pass-throughWP02
T039TDD: orchestrator endpoint emits typed code, not MISSION_NOT_FOUND (M2)WP09[P]
T040M2: stop flattening StatusReadPathNotFound across the 8 endpointsWP09[P]
T041TDD: coord-topology fail-closed guard fires for orchestrator status read (M3)WP09[P]
T042M3: resolve identity via factory boundary; stop empty-mid8 seedWP09[P]
T043M5: structure the typed error on cmd_verify (verify's own :421/:425 seam)WP04
T044M4: decide on _find_first_for_review_wp parent-walk re-deriver (route or defer) — DECISION: CONSCIOUS DEFERRAL. Review-mode discovery helper (not operator-facing read-path fidelity), low blast radius; its worktree-local-first/walk/repo_root read intent is not preserved by the coord-aware resolver, so routing would change read-anchor semantics beyond #1832's fragment-adopt scope (D-1 minimal carry). Recorded in-code at workflow.py _find_first_for_review_wp.WP05

FR Coverage

WPSpec FRs
WP01FR-009
WP02FR-001, FR-002
WP03FR-004, FR-005, FR-006
WP04FR-003
WP05FR-008, FR-011
WP06FR-007
WP07FR-010
WP08FR-012
WP09FR-001, FR-011

WP01 — Single context factory + freeze + build-invariant + write-projection boundary (IC-01)

  • Goal: Name the single context factory (build_execution_context), freeze the composite, assert the build-invariant, and declare the write-projection boundary contract (D-6) — the trustworthy-context precondition + the read/write-symmetry seam.
  • Priority: P0 (precondition for WP02–WP05, WP09). Dependencies: none.
  • Independent test: building a context with target_branch != branch_ref.target_branch raises CONTEXT_INVARIANT_VIOLATION; mutating a built context raises; resolve_action_context delegates to the factory.
  • Prompt: tasks/WP01-context-factory-invariant.md
  • ✅ T001 TDD: build-time CONTEXT_INVARIANT_VIOLATION test (WP01)
  • ✅ T002 TDD: ExecutionContext immutability test (WP01)
  • ✅ T003 Freeze the ExecutionContext composite (WP01)
  • ✅ T004 Assert target_branch == branch_ref.target_branch at build (WP01)
  • ✅ T005 Assemble WP-bearing context in one shot via the factory (no post-freeze write) (WP01)
  • ✅ T006 Full-suite sweep; fix any mutator the freeze surfaces (WP01)
  • ✅ T037 Name build_execution_context factory (sole door; resolve_action_context delegates) + write-projection boundary contract docstring/__all__ (WP01)

WP02 — next typed-error pass-through + M1 context-resolve (IC-02)

  • Goal: Preserve ActionContextError.code+checked-paths across the three next-family catch-sites AND context mission-resolve (M1); closes #12/#14/#15 (+M1) with no resolver change.
  • Priority: P0. Dependencies: WP01.
  • Independent test: next and context mission-resolve on a read-path miss emit the resolver's real code + checked paths, never MISSION_NOT_FOUND/"check the slug".
  • Prompt: tasks/WP02-next-typed-error-passthrough.md
  • ✅ T007 TDD: next read-path-miss → typed code, not MISSION_NOT_FOUND (WP02)
  • ✅ T008 Preserve code+paths at runtime_bridge query_current_state (WP02)
  • ✅ T009 Preserve code+paths at runtime_bridge answer_decision_via_runtime (WP02)
  • ✅ T010 Preserve code at next_cmd _find_mission_slug (WP02)
  • ✅ T011 Emitter surfaces typed code+paths (WP02)
  • ✅ T012 Verification-by-deletion: collapse removed, suite green (WP02)
  • ✅ T038 M1: context mission-resolve preserves the typed code (resolver.py:164) (WP02)

WP03 — mission.py planning-entry adoption (IC-03)

  • Goal: setup-plan exact-one auto-select; is_committed primary-target-branch leg; _commit_to_branch hash + no-op-vs-wrong-surface; finalize-tasks primary-anchored read.
  • Priority: P0. Dependencies: WP01. Sole owner of agent/mission.py + _substantive.py.
  • Independent test: single-mission repo → setup-plan needs no --mission; spec committed on primary target branch → spec_committed: true.
  • Prompt: tasks/WP03-mission-planning-entry.md
  • ✅ T013 TDD: setup-plan exact-one auto-select; >1 structured error (WP03)
  • ✅ T014 Add exact-one auto-select in setup_plan (not the shared helper) (WP03)
  • ✅ T015 TDD: is_committed true on primary-target-branch commit (WP03)
  • ✅ T016 Add primary-target-branch leg to is_committed + diagnostics (WP03)
  • ✅ T017 TDD: _commit_to_branch hash + no-op-vs-wrong-surface (WP03)
  • ✅ T018 Fix _commit_to_branch (hash; distinguish no-op classes) (WP03)
  • ✅ T019 finalize-tasks: anchor read on primary root (#11) (WP03)

WP04 — decision single authority (IC-04)

  • Goal: Delete the primary-anchored escape-walk for resolved paths; structure the typed error.
  • Priority: P1. Dependencies: WP01.
  • Independent test: valid coord-aware handle → decision open succeeds; raw traversal token still rejected; no raw traceback.
  • Prompt: tasks/WP04-decision-single-authority.md
  • ✅ T020 TDD: decision open accepts coord handle; traversal rejected (WP04)
  • ✅ T021 Delete escape-walk for resolved paths; repo_root from canonical authority (WP04)
  • ✅ T022 Structure the typed error at decision.py:103 (WP04)
  • ✅ T023 Keep _SAFE_SLUG_RE on raw token; confirm cmd_verify unaffected (WP04)
  • ✅ T043 M5: structure the typed error on cmd_verify (its own :421/:425 seam) (WP04)

WP05 — implement single-resolution + #1993 lanes-dir seam (IC-05)

  • Goal: agent action implement consumes the claim's resolved context; extract+route resolve_lanes_dir.
  • Priority: P1. Dependencies: WP01.
  • Independent test: implement after a verified claim never fails "no workspace could be resolved"; the lanes dir has one derivation.
  • Prompt: tasks/WP05-implement-single-resolution-lanes-seam.md
  • ✅ T024 TDD: implement consumes claim's resolved context (WP05)
  • ✅ T025 Route implement to single resolution path (workflow.py) (WP05)
  • ✅ T026 Extract resolve_lanes_dir(feature_dir) pure seam (WP05)
  • ✅ T027 Route ad-hoc lanes.json derivations through the seam (WP05)
  • ✅ T028 Unit test the seam + verification-by-deletion (WP05)
  • ✅ T044 M4: decide on _find_first_for_review_wp parent-walk re-deriver (route or defer) (WP05)

WP06 — root-resolver submodule unification (IC-06)

  • Goal: resolve_canonical_root stops at the submodule boundary, agreeing with locate_project_root.
  • Priority: P0 (launch-blocker #6/#2011). Dependencies: none.
  • Independent test: from inside a real submodule, resolve_canonical_root returns the submodule root and assert_initialized does not raise.
  • Prompt: tasks/WP06-root-resolver-submodule.md
  • ✅ T029 TDD: resolve_canonical_root returns submodule root (real submodule) (WP06)
  • ✅ T030 Fix paths.py submodule boundary (mirror locate_project_root) (WP06)
  • ✅ T031 Equivalence test {primary, coord, submodule} (WP06)

WP07 — charter status side-effect-free + JSON-safe (IC-07)

  • Goal: charter status/sync status is side-effect-free; one normalized JSON-serializable hash.
  • Priority: P2. Dependencies: none.
  • Independent test: git status unchanged across a charter status run; the emitted hash serializes.
  • Prompt: tasks/WP07-charter-status-no-op.md
  • ✅ T032 TDD: charter status side-effect-free + JSON-safe hash (WP07)
  • ✅ T033 Make status collectors side-effect-free (WP07)
  • ✅ T034 Emit one normalized JSON-serializable hash (WP07)

WP08 — #1827 baseline regression test (FR-012, test-only)

  • Goal: Lock #1827 as verified-already-fixed with a full record→commit→assert + resume regression test (D-3 — NO code fix).
  • Priority: P2. Dependencies: none.
  • Independent test: the full sequence (incl. resume/re-run) passes; a falsification guard proves the broken ordering would fail.
  • Prompt: tasks/WP08-1827-baseline-regression.md
  • ✅ T035 #1827 full record→commit→assert + resume regression test (WP08)
  • ✅ T036 #1827 falsification guard (WP08)

WP09 — orchestrator-api typed-error + fail-closed identity (IC-02b: M2 + M3)

  • Goal: M2 — stop flattening StatusReadPathNotFoundMISSION_NOT_FOUND across the 8 orchestrator endpoints (commands.py:263-266); M3 — stop seeding resolve_mid8(slug, mission_id=None)→empty mid8 (:261) which suppresses the coord-aware fail-closed guard. Resolve identity via the factory boundary (D-6).
  • Priority: P1 (read-path SAFETY). Dependencies: WP01 (consumes the factory identity boundary).
  • Independent test: an orchestrator status read on a read-path miss emits the typed code; on a coord topology the fail-closed guard fires (no stale primary read). Legacy {slug}-{lane} mission_id=None grammar (:484/:787) is untouched.
  • Prompt: tasks/WP09-orchestrator-typed-error-fail-closed.md
  • ✅ T039 TDD: orchestrator endpoint emits typed code, not MISSION_NOT_FOUND (M2) (WP09)
  • ✅ T040 M2: stop flattening StatusReadPathNotFound across the 8 endpoints (WP09)
  • ✅ T041 TDD: coord-topology fail-closed guard fires for orchestrator status read (M3) (WP09)
  • ✅ T042 M3: resolve identity via factory boundary; stop empty-mid8 seed (WP09)