Tasks: Upgrade reports one outcome

Mission: upgrade-outcome-single-rendering-01M444Q6 | Branch: issue-4925-upgrade-outcome-single-rendering | Plan: plan.md | Spec: spec.md

Three sequential work packages. They share src/specify_cli/cli/commands/upgrade.py, so there is no parallelism between them.

Subtask Index

IDDescriptionWPParallel
T001Pin with a test that the legacy surface-repair branch is unreachableWP01
T002Delete the legacy branch and its helpersWP01
T003Repoint the six tests that patched the dead helperWP01
T004Red-first regression repro through the CLI entry pointWP02
T005Outcome model: kind, reasons, errors, warnings, status, closing lineWP02
T006Unit matrix for the outcomeWP02[P]
T007Finalizer and surface-repair step return a reportWP02
T008Presentation reads the outcome (one text tail, both JSON builders)WP02
T009CLI matrix: kind × mode × path, dry-run rowsWP02
T010Strengthen the tests that only pinned the exit codeWP02[P]
T011Help text and its generated mirrorsWP02[P]
T012Architectural gate with self-mutation and floorWP03
T013Decision recordWP03[P]
T014Changelog entry; remove the known-limitation noteWP03[P]
T015Docs index and freshness guardsWP03

Phase 1 – Tidy first

WP01 – Remove the unreachable legacy surface-repair branch

  • Prompt: tasks/WP01-remove-unreachable-surface-repair-branch.md
  • Goal: one surface-repair path before the functional change. Behaviour-preserving.
  • Priority: P1 (enabler)
  • Independent test: the unreachability test, plus the existing upgrade tests pass unmodified in output and exit code.
  • Dependencies: none
  • Requirements: FR-016
  • Estimated prompt size: ~150 lines

T001 Pin with a test that the legacy surface-repair branch is unreachable (WP01) T002 Delete the legacy branch and its helpers (WP01) T003 Repoint the six tests that patched the dead helper (WP01)

Risks: _repair_stale_command_manifest loses its only caller; verify the prepared path covers it before deleting.

Phase 2 – Functional change

WP02 – Upgrade outcome owns kind, reasons and rendering

  • Prompt: tasks/WP02-outcome-owns-kind-reasons-and-rendering.md
  • Goal: the closing line, JSON status and exit code derive from one outcome on both paths and in both modes.
  • Priority: P1
  • Independent test: the regression repro is red on its own commit and green at the end; the CLI matrix passes.
  • Dependencies: Depends on WP01
  • Requirements: FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-013, FR-014, FR-017, FR-018; NFR-001, NFR-002, NFR-003, NFR-004; SC-001, SC-002, SC-003, SC-004
  • Estimated prompt size: ~230 lines

T004 Red-first regression repro through the CLI entry point (WP02) T005 Outcome model: kind, reasons, errors, warnings, status, closing line (WP02) T006 Unit matrix for the outcome (WP02) T007 Finalizer and surface-repair step return a report (WP02) T008 Presentation reads the outcome (WP02) T009 CLI matrix: kind × mode × path, dry-run rows (WP02) T010 Strengthen the tests that only pinned the exit code (WP02) T011 Help text and its generated mirrors (WP02)

Risks: hidden consumers of the removed boolean; double printing of the dry-run notice; generated docs.

Phase 3 – Close the class

WP03 – Rendering gate, decision record and changelog

  • Prompt: tasks/WP03-gate-decision-record-and-changelog.md
  • Goal: an empty-allowlist gate keeps presentation from bypassing the outcome; the contract is recorded.
  • Priority: P2
  • Independent test: the gate passes on the tree and fails on each synthetic violation.
  • Dependencies: Depends on WP02
  • Requirements: FR-012, FR-015; NFR-005; SC-005
  • Estimated prompt size: ~130 lines

T012 Architectural gate with self-mutation and floor (WP03) T013 Decision record (WP03) T014 Changelog entry; remove the known-limitation note (WP03) T015 Docs index and freshness guards (WP03)

Risks: the gate may surface a residual in WP02's output.