Tasks: Internal --feature & status_service sanitization
Mission: codebase-sanitization-1060-1622-01KV5F0B Branch: mission/codebase-sanitization-1060-1622 (planning base = merge target; PR to upstream/main) Spec: spec.md · Plan: plan.md · Bulk-edit map: occurrence_map.yaml
Overview
5 work packages. Workstream 1 (#1060-A): WP01 + WP02 remove the hidden --feature alias from the 10 in-scope commands; WP03 locks the terminology gate and proves out-of-scope commands are unchanged. Workstream 2 (#1622): WP04 is verify-only — locks the already-resolved state with a regression test + closes the ticket. Boyscout (adversarial-squad fold-in F1): WP05 retires the dead hidden_feature_option helper (FR-009).
Bounded conflict surface (NFR-001): no edits under src/specify_cli/status/, src/specify_cli/task_utils/, or legacy_detector.py. resolve_selector and _legacy_aliases.py are RETAINED (FR-008). Each removal WP follows ATDD at the behavioral level (de-alias rejection test red → green within the WP); WP03 lands the global gate as the regression lock once all removals are merged.
Dependencies
WP01 (agent cmds) ─┬─→ WP03 (gate lock + out-of-scope proof)
WP02 (other cmds) ─┴─→ WP05 (retire dead _legacy_aliases helper) [WP05 deps WP02]
WP04 (#1622 verify) ── independent (parallel with all)
removals land).
charter/lint.py-keeps---feature assertion is invalidated once WP02 lands).
- WP01 ∥ WP02 ∥ WP04 (different files — fully parallel).
- WP03 depends on WP01 + WP02 (the global gate only goes green after both
- WP05 depends on WP02 (it owns
test_legacy_feature_alias.py, whose
Subtask Index
| ID | Description | WP | Parallel |
|---|---|---|---|
| T001 | Remove --feature from agent/tasks.py (12 hits) + retarget resolve_selector | WP01 | |
| T002 | Remove --feature from agent/status.py (9 hits) | WP01 | [P] |
| T003 | Remove --feature from agent/workflow.py (4 hits; keep unrelated status_service import) | WP01 | [P] |
| T004 | Remove --feature from agent/context.py + agent/mission.py | WP01 | [P] |
| T005 | Update agent-namespace tests: de-alias rejection + --mission still works | WP01 | |
| T006 | ruff/mypy clean + run targeted agent-command tests | WP01 | |
| T007 | Remove --feature from charter/lint.py | WP02 | [P] |
| T008 | Remove --feature from materialize.py | WP02 | [P] |
| T009 | Remove --feature from validate_encoding.py + validate_tasks.py | WP02 | [P] |
| T010 | Remove --feature from verify.py | WP02 | [P] |
| T011 | Update these commands' tests: de-alias rejection + --mission still works | WP02 | |
| T012 | ruff/mypy clean + run targeted tests | WP02 | |
| T013 | Extend terminology guard: in-scope cluster must have NO --feature option (hidden or visible) | WP03 | |
| T014 | Out-of-scope preservation regression test (e.g. merge --feature still resolves) | WP03 | |
| T015 | Verify FR-003: no first-party src/doctrine/ source passes --feature to an in-scope command | WP03 | |
| T016 | Run full contract + architectural suites; confirm green | WP03 | |
| T017 | Grep-proof #1622 evidence: 2 funcs absent; 3 enums/error de-exported live internals | WP04 | |
| T018 | Confirm dead-symbol gate green (test_no_dead_symbols, baselines unchanged) | WP04 | |
| T019 | Close #1622 with re-classification (2/5 deletions; 3 retained-because-live) | WP04 | |
| T020 | Remove dead hidden_feature_option + LEGACY_FEATURE_HELP from _legacy_aliases.py | WP05 | |
| T021 | Reconcile test_legacy_feature_alias.py (retire helper tests + lint-keeps-feature assertion) | WP05 | |
| T022 | Remove dead-symbol/dead-module allowlist entries; confirm gates green | WP05 |
Phase 1 — Alias removal (parallel)
WP01 — Remove --feature from agent-namespace commands
plumbing from agent status/tasks/workflow/context/mission, retargeting resolve_selector calls to the mission-only path. --mission behavior unchanged.
unknown option; --mission X works identically to before.
- Goal: Delete the hidden
--featureoption +feature/explicit_feature - Priority: P1 (largest surface;
agent/tasks.pyhas 12 hits) - Requirements: FR-001, FR-002, FR-008
- Independent test:
spec-kitty agent tasks status --feature Xerrors as an - Subtasks: T001–T006 · Est.: ~380 lines · Deps: none
- Prompt: tasks/WP01-remove-feature-agent-commands.md
- ✅ T001 Remove
--featurefromagent/tasks.py(12 hits) + retarget resolve_selector (WP01) - ✅ T002 Remove
--featurefromagent/status.py(9 hits) (WP01) - ✅ T003 Remove
--featurefromagent/workflow.py; keep unrelated status_service import (WP01) - ✅ T004 Remove
--featurefromagent/context.py+agent/mission.py(WP01) - ✅ T005 Update agent-namespace tests: de-alias rejection +
--missionworks (WP01) - ✅ T006 ruff/mypy clean + run targeted agent-command tests (WP01)
WP02 — Remove --feature from non-agent in-scope commands
validate_tasks, verify.
--mission X works.
- Goal: Same removal for
charter lint,materialize,validate_encoding, - Priority: P1
- Requirements: FR-001, FR-002, FR-008
- Independent test:
spec-kitty verify --feature Xerrors as unknown option; - Subtasks: T007–T012 · Est.: ~320 lines · Deps: none
- Prompt: tasks/WP02-remove-feature-other-commands.md
- ✅ T007 Remove
--featurefromcharter/lint.py(WP02) - ✅ T008 Remove
--featurefrommaterialize.py(WP02) - ✅ T009 Remove
--featurefromvalidate_encoding.py+validate_tasks.py(WP02) - ✅ T010 Remove
--featurefromverify.py(WP02) - ✅ T011 Update these commands' tests: de-alias rejection +
--missionworks (WP02) - ✅ T012 ruff/mypy clean + run targeted tests (WP02)
Phase 2 — Regression lock
WP03 — Terminology gate lock + out-of-scope preservation proof
visible) on an in-scope command fails CI; prove out-of-scope commands still accept the alias; confirm no first-party caller regressions.
the gate fail; merge --feature X still resolves.
- Goal: Tighten the contract gate so any
--featureTyper option (hidden or - Priority: P1
- Requirements: FR-003, FR-004, FR-005
- Independent test: re-adding a
--featureoption to any in-scope file makes - Subtasks: T013–T016 · Est.: ~280 lines · Deps: WP01, WP02
- Prompt: tasks/WP03-terminology-gate-and-scope-proof.md
- □ T013 Extend terminology guard: in-scope cluster must have NO
--featureoption (WP03) - □ T014 Out-of-scope preservation regression test (
merge --featurestill resolves) (WP03) - □ T015 Verify FR-003: no
src/doctrine/source passes--featureto an in-scope command (WP03) - □ T016 Run full contract + architectural suites; confirm green (WP03)
WP05 — Retire dead hidden_feature_option helper (boyscout / FR-009)
from _legacy_aliases.py (0 src/ callers), retire their tests, and drop the dead-symbol/dead-module allowlist entries. resolve_selector untouched.
+ dead-module gates green.
- Goal: Remove the dead
hidden_feature_option()+LEGACY_FEATURE_HELP - Priority: P2
- Requirements: FR-009
- Independent test:
git grep hidden_feature_option→ 0 repo-wide; dead-symbol - Subtasks: T020–T022 · Est.: ~170 lines · Deps: WP02
- Prompt: tasks/WP05-retire-dead-legacy-aliases-helper.md
- □ T020 Remove dead
hidden_feature_option+LEGACY_FEATURE_HELPfrom_legacy_aliases.py(WP05) - □ T021 Reconcile
test_legacy_feature_alias.py(retire helper tests + lint-keeps-feature assertion) (WP05) - □ T022 Remove dead-symbol/dead-module allowlist entries; confirm gates green (WP05)
Phase 3 — Verify-and-close (#1622)
WP04 — #1622 verify-and-close (regression lock + ticket close)
regression test (no status_service.py edit) and close #1622 with the re-classification.
#1622 closed with the re-classification comment.
- Goal: Lock the already-resolved
status_servicestate with a new - Priority: P2
- Requirements: FR-006, FR-007
- Independent test: the new regression test passes; dead-symbol gate green;
- Subtasks: T017–T019 · Est.: ~190 lines · Deps: none
- Prompt: tasks/WP04-1622-verify-and-close.md
- ✅ T017 Add regression test: 2 funcs absent; 3 enums/error de-exported but live internals (WP04)
- ✅ T018 Confirm dead-symbol gate green (
test_no_dead_symbols, baselines unchanged) (WP04) - ✅ T019 Close #1622 with re-classification (WP04)
MVP
WP01 (the largest alias-removal surface) is the MVP demonstrating the de-aliasing pattern; WP02 mirrors it; WP03 locks it; WP04 closes the bookkeeping.