Work Packages: Mission Repository Encapsulation
Inputs: Design documents from /kitty-specs/058-mission-template-repository-refactor/ Prerequisites: plan.md (two-phase approach), spec.md (25 FRs, 9 user stories), research/consumer-analysis.md (14+ consumer files), contracts/mission-template-repository.md (API contract)
Tests: Included -- this is a refactor of core infrastructure where regressions must be caught.
Organization: Subtasks (T001–T055) roll up into 11 work packages (WP01–WP11). Phase 1 (WP01–WP04, WP10–WP11) creates the new API and enforces invariants; Phase 2 (WP05–WP07) reroutes consumers; WP08–WP09 are boyscouting/indirection.
Prompt Files: Each work package references a matching prompt file in /tasks/ generated by /spec-kitty.tasks.
Work Package WP01: Rename Class + Value Objects + Alias (Priority: P0)
Goal: Rename MissionRepository to MissionTemplateRepository, add TemplateResult and ConfigResult value objects, convert existing path methods to private _*_path() names, add default() classmethod, and establish backward-compatible MissionRepository alias. Independent Test: pytest tests/doctrine/missions/test_mission_repository.py -v passes unchanged via alias. from doctrine.missions import MissionRepository still works. Prompt: /tasks/WP01-rename-value-objects-alias.md Requirement Refs: FR-001, FR-013, FR-014, FR-015, FR-016, NFR-001, NFR-002, C-001 Estimated Size: ~350 lines
Included Subtasks
- ✅ T001 Rename class
MissionRepository→MissionTemplateRepositoryinsrc/doctrine/missions/repository.py - ✅ T002 Add
TemplateResultvalue object class torepository.py(dict-backed,__slots__, properties: content, origin, tier) - ✅ T003 Add
ConfigResultvalue object class torepository.py(dict-backed,__slots__, properties: content, origin, parsed) - ✅ T004 Add
default()classmethod that returnsMissionTemplateRepository(cls.default_missions_root()) - ✅ T005 Rename existing path-returning methods to private
_*_path()names (get_command_template→_command_template_path, etc.) - ✅ T016 Update
__init__.py: exportMissionTemplateRepository+TemplateResult+ConfigResult, addMissionRepository = MissionTemplateRepositoryalias
Implementation Notes
- All existing method bodies stay the same -- just rename from
get_to__pathfor path-returning methods get_template()→_content_template_path()(naming alignment with spec)get_expected_artifacts()currently returnsPath | None-- rename to_expected_artifacts_path()TemplateResultandConfigResultfollow the contract incontracts/mission-template-repository.mdexactly- The
_missions_rootproperty should exposeself._rootfor internal consumers
Parallel Opportunities
- T002 and T003 (value objects) can be written in parallel with each other
- T001 and T005 are tightly coupled (rename class and rename methods)
Dependencies
- None (starting package).
Risks & Mitigations
- Risk: Existing tests break from method renames. Mitigation: The alias means
MissionRepository(root).get_command_template()no longer exists (renamed to_command_template_path()). However, existing tests call the OLD method names. Run before/after to identify failures and update test imports/calls in WP04. - Risk: Import cycles from new
ResolutionTierimport. Mitigation:TemplateResult.tiercan useAnytype hint with runtime check, or the type isstr | Noneto avoid importing fromspecify_cli.
Work Package WP02: Template + Enumeration Public Methods (Priority: P0)
Goal: Add the content-returning public methods for templates and the enumeration methods. These are the most commonly needed methods. Independent Test: repo.get_command_template("software-dev", "implement") returns a TemplateResult with non-empty content. repo.list_command_templates("software-dev") returns sorted list including "implement". Prompt: /tasks/WP02-template-enumeration-methods.md Requirement Refs: FR-002, FR-003, FR-006, FR-007, FR-008 Estimated Size: ~300 lines
Included Subtasks
- ✅ T006 [P] Add
get_command_template(mission, name)→TemplateResult | None(reads file from_command_template_path, constructsTemplateResult) - ✅ T007 [P] Add
get_content_template(mission, name)→TemplateResult | None(reads file from_content_template_path, constructsTemplateResult) - ✅ T008 [P] Add
list_command_templates(mission)→list[str](dir listing, strip .md, sorted) - ✅ T009 [P] Add
list_content_templates(mission)→list[str](dir listing, sorted filenames)
Implementation Notes
- Each
get_method: call the private__path()method, returnNoneif path isNone, read file content withpath.read_text(encoding="utf-8"), wrap inTemplateResult(content, origin, tier=None) - Origin label format:
"doctrine/<mission>/command-templates/<name>.md"(see contract) list_command_templates: glob_root / mission / "command-templates" / "*.md", strip.md, sortlist_content_templates: glob_root / mission / "templates" / "*", exclude directories, sort
Parallel Opportunities
- All 4 subtasks are independent and can be implemented in parallel.
Dependencies
- Depends on WP01 (needs
TemplateResult, private_*_path()methods).
Risks & Mitigations
- Risk: Template files with non-UTF-8 encoding. Mitigation: All doctrine templates are UTF-8. Add try/except with
Nonereturn + warning log per contract.
Work Package WP03: Config Methods on Repository + ConstitutionTemplateResolver (Priority: P0)
Goal: Add the YAML-returning config methods to MissionTemplateRepository (doctrine-level). Create ConstitutionTemplateResolver in src/constitution/template_resolver.py for 5-tier project-aware resolution. This preserves doctrine's zero-dependency invariant while placing override resolution in the constitution module (where it belongs — constitution is the concretization of doctrine into local context-aware legislation). Constitution depends only on doctrine + kernel — no specify_cli imports. Independent Test: repo.get_action_index("software-dev", "implement") returns a ConfigResult with parsed dict. ConstitutionTemplateResolver(...).resolve_command_template("software-dev", "implement") returns a TemplateResult from the package default tier. Prompt: /tasks/WP03-config-resolver-methods.md Requirement Refs: FR-004, FR-005, FR-009, FR-010, FR-011, FR-012, FR-018, NFR-003, NFR-004 Estimated Size: ~450 lines
Included Subtasks
- ✅ T010 [P] Add
get_action_index(mission, action)→ConfigResult | NoneonMissionTemplateRepository(reads + parses YAML with ruamel.yaml) - ✅ T011 [P] Add
get_action_guidelines(mission, action)→TemplateResult | NoneonMissionTemplateRepository(reads markdown) - ✅ T012 [P] Add
get_mission_config(mission)→ConfigResult | NoneonMissionTemplateRepository(reads + parses mission.yaml) - ✅ T013 [P] Add
get_expected_artifacts(mission)→ConfigResult | NoneonMissionTemplateRepository(reads + parses expected-artifacts.yaml) - ✅ T014 Create
src/constitution/template_resolver.pywithConstitutionTemplateResolverclass. Method:resolve_command_template(mission, name, project_dir?)→TemplateResult. ComposesMissionTemplateRepository(tier 5) +specify_cli.runtime.resolver(tiers 1-4). RaisesFileNotFoundErrorif not found at any tier. - ✅ T015 Add
resolve_content_template(mission, name, project_dir?)→TemplateResultonConstitutionTemplateResolver(same pattern as T014)
Implementation Notes
- Config methods (T010-T013) go on
MissionTemplateRepositoryinsrc/doctrine/missions/repository.py— these are doctrine-level reads with zero external imports - Config methods use
ruamel.yamlwithYAML(typ="safe")-- matchingaction_index.pypattern get_action_indexshould construct aConfigResultwith raw text + parsed dict, NOT return anActionIndexdataclass (that's a separate concern)ConstitutionTemplateResolver(T014-T015) lives insrc/constitution/template_resolver.py— constitution depends only on doctrine + kernel (nospecify_cliimports). The 5-tier resolver primitives must be relocated fromspecify_cli.runtime.resolverto a constitution-reachable package before this class can be created.- The resolver composes
MissionTemplateRepository(tier 5) with the 5-tier resolution logic.ResolutionResult(path, tier, mission)is wrapped intoTemplateResult(content, origin, tier). - If resolver raises
FileNotFoundError, re-raise (per contract) resolve_*withproject_dir=Noneshould still work by falling back to package-default tier only- Package boundary invariant:
MissionTemplateRepository(doctrine) must have ZERO imports fromspecify_cliorconstitution. Verify withgrepafter implementation.
Parallel Opportunities
- T010-T013 (config methods) are all independent
- T014-T015 (resolver in constitution) depend on understanding the resolver but are independent of each other
Dependencies
- Depends on WP01 (needs value objects), WP02 (pattern established by template methods).
Risks & Mitigations
- Risk: ~~Circular import between
doctrineandspecify_cli.runtime.resolver~~ Eliminated: resolve methods now live inconstitution, notdoctrine. Constitution depends only on doctrine + kernel — nospecify_cliimports. The 5-tier resolver primitives must be relocated to a constitution-reachable package beforeConstitutionTemplateResolvercan be created. - Risk:
ruamel.yamlparse failure on malformed YAML. Mitigation: Try/except returningNonewith warning log per contract. - Risk: Resolver expects different calling convention. Mitigation: Read resolver source carefully; the
resolve()function inresolver.pyneeds to be understood before calling.
Work Package WP04: Comprehensive Tests (Priority: P0)
Goal: Create comprehensive test module covering all public API methods, value objects, backward compatibility, enumeration, error handling, and resolver integration. Independent Test: pytest tests/doctrine/test_mission_template_repository.py -v passes with 90%+ coverage of new code. Prompt: /tasks/WP04-comprehensive-tests.md Requirement Refs: NFR-002, all FRs (validation) Estimated Size: ~500 lines
Included Subtasks
- ✅ T017 Verify existing
test_mission_repository.pypasses unchanged via alias (run before/after). Also verifylist_missions()signature and return type match FR-008 (sortedlist[str]). - ✅ T018 Create
tests/doctrine/test_mission_template_repository.pywith test categories: - Value object construction and properties (
TemplateResult,ConfigResult) - Doctrine-level reads: all
get_*methods against real doctrine assets Nonereturns: nonexistent missions, templates, actions- Enumeration:
list_missions(),list_command_templates(),list_content_templates() - YAML parsing:
get_action_index(),get_mission_config(),get_expected_artifacts() - Backward compat:
MissionRepositoryalias resolves correctly,isinstancecheck - Resolver integration:
ConstitutionTemplateResolver.resolve_command_template()without project_dir (package default) - Edge cases: empty missions root, missing directories, malformed YAML
Implementation Notes
- Use real doctrine assets (not mocks) for doctrine-level tests -- the assets exist in the package
- Use
tmp_pathfixture for edge case tests (empty root, missing dirs) - For resolver tests, call without
project_dirto test package-default tier only (avoids needing a mock project) - Use
MissionTemplateRepository.default()for doctrine-level tests - Test
from doctrine.missions import MissionRepositorystill resolves toMissionTemplateRepository
Parallel Opportunities
- Test writing is inherently sequential but can be parallelized by test category
Dependencies
- Depends on WP01, WP02, WP03 (all API methods must exist).
Risks & Mitigations
- Risk: Tests couple to specific doctrine asset content that may change. Mitigation: Test for presence/type rather than exact content where possible (e.g., "content is non-empty string" not "content equals X").
Work Package WP05: HIGH Priority Consumer Reroutes (Priority: P1)
Goal: Reroute the 4 highest-priority consumer files that bypass MissionTemplateRepository with direct path construction: constitution/context.py, constitution/catalog.py (both copies), runtime/show_origin.py. Independent Test: Each rerouted file's tests pass. No direct mission path construction remains in these files. Prompt: /tasks/WP05-high-priority-reroutes.md Requirement Refs: FR-017 (partial), User Story 9 Estimated Size: ~450 lines
Included Subtasks
- ✅ T019 Reroute
src/constitution/context.py-- replaceresolve_doctrine_root() / "missions"(line 225),load_action_index()call (line 229),guidelines_pathconstruction (line 249) withMissionTemplateRepository.default()API calls - ✅ T020 Reroute
src/constitution/catalog.py-- replace_load_template_sets_with_presence()(lines 256-267) manual missions_root + directory iteration withMissionTemplateRepository.default().list_missions()+get_mission_config() - ✅ T021 Reroute
src/specify_cli/constitution/catalog.py-- replace_load_template_sets()(lines 107-116) same pattern as T020 - ✅ T022 Reroute
src/specify_cli/runtime/show_origin.py-- replace_discover_mission_names()(lines 68-69),_discover_command_names()(lines 85-86),_discover_template_names()(lines 103-104) with repository methods
Implementation Notes
- context.py (T019): Replace
missions_root = resolve_doctrine_root() / "missions"withrepo = MissionTemplateRepository.default(). Replaceload_action_index(missions_root, mission, action)withrepo.get_action_index(mission, action)and use.parsedproperty. Replaceguidelines_path = missions_root / ...withresult = repo.get_action_guidelines(mission, action)and use.content. - catalog.py (T020/T021): Replace directory iteration logic with
repo.list_missions(). Replacemission_dir / "mission.yaml"withrepo.get_mission_config(name). Keep the function signature the same. - show_origin.py (T022): Replace
_discover_mission_names()body withMissionTemplateRepository.default().list_missions(). Replace_discover_command_names()withrepo.list_command_templates(mission). Replace_discover_template_names()withrepo.list_content_templates(mission). - For each file, identify and run its existing tests BEFORE making changes, then re-run AFTER.
Parallel Opportunities
- T019-T022 touch different files and can be implemented in parallel.
Dependencies
- Depends on WP01-WP03 (needs full public API). WP04 tests should pass first as confidence gate.
Risks & Mitigations
- Risk:
context.pycallers expectActionIndexdataclass fromload_action_index(), butget_action_index()returnsConfigResult. Mitigation:context.pyonly uses the action index to get the artifact list keys -- check if it needsActionIndexor just the parsed dict. May need to keepload_action_index()call but provide the path from repository. - Risk:
catalog.pyfunction returns differ after reroute. Mitigation: Keep return types identical. The functions return template set data, not paths.
Work Package WP06: MEDIUM Priority Consumer Reroutes (Priority: P1)
Goal: Reroute the 4 medium-priority consumer files: runtime/resolver.py (tier-5 only), runtime/bootstrap.py, runtime/migrate.py, template/manager.py. Independent Test: Each rerouted file's tests pass. Tier-5 resolution uses repository. get_package_asset_root() usage reduced. Prompt: /tasks/WP06-medium-priority-reroutes.md Requirement Refs: FR-017 (partial), User Story 9 Estimated Size: ~400 lines
Included Subtasks
- ✅ T023 Reroute
src/specify_cli/runtime/resolver.py-- replace tier-5get_package_asset_root()(lines 174-175, 302-303) withMissionTemplateRepository.default()._command_template_path()/._content_template_path()/._mission_config_path() - ✅ T024 Reroute
src/specify_cli/runtime/bootstrap.py-- replaceget_package_asset_root()(line 74) withMissionTemplateRepository.default()._missions_rootfor missions source path - ✅ T025 Reroute
src/specify_cli/runtime/migrate.py-- replaceget_package_asset_root()(line 177) withMissionTemplateRepository.default()._missions_root - ✅ T026 [P] Reroute
src/specify_cli/template/manager.py-- replacefiles("doctrine").joinpath("missions")(lines 242-243) withMissionTemplateRepository.default()._missions_root
Implementation Notes
- resolver.py (T023): Only tier-5 lookups change. Lines 174-175 construct
pkg_missions / mission / subdir / name-- replace with appropriate_*_path()call based onsubdir(eithercommand-templatesortemplates). Lines 302-303 similarly for mission config. Tiers 1-4 are untouched (C-003). - bootstrap.py (T024):
populate_from_package()usesasset_root = get_package_asset_root()thenshutil.copytree. Replace source withMissionTemplateRepository.default()._missions_root. Note: lines 84, 89 useasset_root.parentfor sibling dirs -- these need_missions_root.parentwhich is the doctrine package root. Document this coupling. - migrate.py (T025): Replace
package_root = get_package_asset_root()withMissionTemplateRepository.default()._missions_root. The generic path construction at line 57 may stay as-is since it handles arbitrary sub-paths. - manager.py (T026): Replace
files("doctrine").joinpath("missions")with repository. Dev-mode probes (lines 77-106) may stay since they check forsrc/doctrine/layout, not mission assets.
Parallel Opportunities
- All 4 subtasks touch different files and can proceed in parallel.
Dependencies
- Depends on WP01 (private
_*_path()methods and_missions_root). Logically follows WP05.
Risks & Mitigations
- Risk: Resolver behavior change affects 5-tier resolution. Mitigation: Run resolver tests before/after. Only tier-5 changes. C-003 (resolver logic unchanged) must be honored.
- Risk:
bootstrap.pyneeds parent traversal (_missions_root.parent). Mitigation: This is acceptable -- document it and consider adding a_doctrine_rootproperty if pattern recurs.
Work Package WP07: Remaining Reroutes + Bug Fix + Validation (Priority: P2)
Goal: Reroute newly-discovered consumer files (compilers), fix the stale path bug in feature.py, run full test suite, and validate no direct path construction remains. Independent Test: Full pytest suite passes. grep for direct mission path construction patterns finds no matches outside repository, tests, and migrations. Prompt: /tasks/WP07-remaining-reroutes-validation.md Requirement Refs: FR-017 (completion), User Story 9, NFR-002 Estimated Size: ~400 lines
Included Subtasks
- ✅ T027 Reroute
src/constitution/compiler.py(line 601) -- replacedoctrine_root / "missions" / mission / "mission.yaml"withMissionTemplateRepository.default().get_mission_config(mission) - ✅ T028 Reroute
src/specify_cli/constitution/compiler.py(line 333) -- same pattern as T027 - ✅ T029 Fix stale path in
src/specify_cli/cli/commands/agent/feature.py(line 1716) --Path(__file__).parents[3] / "specify_cli" / "missions"references pre-migration directory. Replace withMissionTemplateRepository.default()._missions_rootor appropriate API call. - ✅ T030 Run full test suite (
pytest) and fix any regressions. Validate with grep: no directmissions_root / mission / "command-templates",missions_root / mission / "templates",missions_root / mission / "actions"patterns in production code outsiderepository.py, shipped migrations, andtest_package_bundling.py.
Implementation Notes
- compiler.py (T027/T028): Both files construct
doctrine_root / "missions" / mission / "mission.yaml"to read mission config. Replace withrepo.get_mission_config(mission)and use.parsedproperty. The compilers may also need.contentfor raw text injection. - feature.py (T029): Line 1716 uses
Path(__file__).parents[3] / "specify_cli" / "missions"-- this is a stale pre-migration path pointing at the oldspecify_cli/missions/directory (which was migrated todoctrine/missions/). This is a bug regardless of this feature. Replace withMissionTemplateRepository.default()._missions_rootor appropriate lookup. - Validation (T030): Run
pytestwith full suite. Then grep for patterns: missions_root / mission / "command-templates"(should only be in repository.py)missions_root / mission / "templates"(should only be in repository.py)missions_root / mission / "actions"(should only be in repository.py)get_package_asset_root()(should have reduced callers)importlib.resources.files("doctrine") / "missions"(should only be in kernel/paths.py and repository.py)- Note:
kernel/paths.py,specify_cli/manifest.py,specify_cli/mission.py, and migration files are explicitly excluded from rerouting (see research/consumer-analysis.md).
Parallel Opportunities
- T027 and T028 are the same pattern in different files -- parallel.
- T029 is independent.
- T030 must run after all other changes.
Dependencies
- Depends on WP05, WP06 (all major consumers rerouted first).
Risks & Mitigations
- Risk:
feature.pystale path may have tests that rely on it working. Mitigation: Runfeature.pytests before/after. The stale path probably fails silently today since the directory doesn't exist. - Risk: Missed consumers surface during T030 validation. Mitigation: This is by design -- T030 is the safety net. Any new finds get fixed in this WP.
Work Package WP08: Boyscouting – Terminology Consistency (Priority: P2)
Goal: Align the agent feature CLI surface with the constitution's Mission terminology canon. The agent mission alias already exists (canonical registration in __init__.py line 16), but user-facing strings, subcommand names, docstrings, documentation, and command templates still reference "feature." This WP cleans up the residual drift while already working in these files. Independent Test: spec-kitty agent mission --help shows clean "Mission" terminology. spec-kitty agent feature still works as hidden alias. Documentation references use agent mission. Prompt: /tasks/WP08-boyscouting-terminology-consistency.md Requirement Refs: Constitution terminology canon (lines 302–308) Estimated Size: ~300 lines
Included Subtasks
- ✅ T031 Rename
create-featuresubcommand tocreate-mission(add hiddencreate-featurealias for backward compat) - ✅ T032 Update module docstring in
feature.py(line 1:"""Feature lifecycle commands…"""→"""Mission lifecycle commands…""") and all user-facing help strings /rich.printoutput that say "feature" when they mean "mission" - ✅ T033 Mark the
agent featureregistration in__init__.pyashidden=Trueso it still works but doesn't appear in--help - ✅ T034 [P] Update
docs/reference/agent-subcommands.md— rewrite the "spec-kitty agent feature" section as "spec-kitty agent mission" with a note thatagent featureremains as a hidden alias - ✅ T035 [P] Update
docs/reference/slash-commands.md— replacespec-kitty agent featureinvocations withspec-kitty agent mission - ✅ T036 [P] Update
README.mdCLI examples (lines ~866–902) — replaceagent featurewithagent mission - ✅ T037 [P] Update
CLAUDE.mdreference (line ~317) — replacespec-kitty agent feature finalize-taskswithspec-kitty agent mission finalize-tasks - ✅ T038 [P] Update doctrine command templates that emit
spec-kitty agent feature(task-prompt-template.md files insrc/doctrine/missions/*/templates/) - ✅ T043 Update glossary: add "Feature Branch" as an accepted VCS term (short-lived branch based on target branch, intended for merge after validation) distinct from the prohibited "Feature" domain term. Clarify that "Mission Specification" replaces "Feature Specification" in spec-kitty artifacts.
- ✅ T048 [P] Rename
--featureflag to--missionacross CLI surface (pulled from 057 scope).--missionbecomes primary,--featureremains as deprecated alias. Most visible instance:spec-kitty agent workflow implement --mission <slug>. - ✅ T055 [P] Rename "feature" to "mission" in detection error messages (
feature_detection.py), status hints, andSPECIFY_FEATUREenv var references. AddSPECIFY_MISSIONas primary env var withSPECIFY_FEATUREas deprecated fallback.
Implementation Notes
- Do NOT rename the Python file
feature.py→mission.py. That's a large import-chain change with no user-facing benefit. The module name is internal. - Hidden alias pattern: Use
app.add_typer(feature.app, name="feature", hidden=True)in__init__.pyto keep backward compat without polluting--help. create-feature→create-mission: Add@app.command(name="create-mission")and keep a hidden alias via a thin wrapper or typer'sdeprecatedflag.--feature→--missionflag rename: Add--missionas primary option, keep--featureas deprecated alias via typer's multiple-name feature. Theagent workflow implement --feature <slug>pattern is the most visible user-facing instance.
Parallel Opportunities
- T034–T038 (doc/template updates) are all independent and can proceed in parallel.
- T031–T033 (code changes) should be sequential.
Dependencies
- Depends on WP07 (which already fixes the stale path in
feature.py; avoids merge conflicts in same file).
Risks & Mitigations
- Risk: Agents or CI scripts hard-code
spec-kitty agent feature. Mitigation: Hidden alias preserves the old name. No breaking change. - Risk:
--featureflag rename affects many CLI entry points. Mitigation:--featurekept as deprecated alias via typer multi-name; no breaking change. T048 covers the rename systematically.
Work Package WP09: Project-Local Mission Path Indirection (Priority: P2)
Goal: Centralize project-local mission path construction (manifest.py, mission.py, config.py) behind a constitution-module indirection to prepare for future constitution-aware resolution. This is an "add indirection" refactor — the behavior stays identical, but all .kittify/missions/ path construction flows through one place. Independent Test: All existing tests for manifest, mission, and config pass unchanged. The new ProjectMissionPaths helper is importable and produces identical paths. Prompt: /tasks/WP09-project-local-mission-path-indirection.md Requirement Refs: FR-019 Estimated Size: ~250 lines
Included Subtasks
- ✅ T039 Create
src/specify_cli/constitution/mission_paths.pywithProjectMissionPathsclass:mission_dir(project_dir, mission),mission_config(project_dir, mission),command_templates_dir(project_dir, mission),templates_dir(project_dir, mission),missions_root(project_dir) - ✅ T040 [P] Reroute
src/specify_cli/manifest.py(4 patterns: lines ~22, 43, 48, 72) to useProjectMissionPaths - ✅ T041 [P] Reroute
src/specify_cli/mission.py(9 patterns: lines ~276, 457, 467, 470, 493, 500, 522, 714, 722) to useProjectMissionPaths - ✅ T042 [P] Reroute
src/specify_cli/cli/commands/agent/config.py(2 patterns: lines ~145, 365) to useProjectMissionPaths
Implementation Notes
- Pure indirection: No behavior change. Each path construction is replaced with the equivalent
ProjectMissionPathscall. - Location:
src/specify_cli/constitution/mission_paths.py— sits in the constitution module because future work will make this resolution constitution-aware (e.g., constitution-defined mission overrides). - Static methods: All methods are
@staticmethod— no state needed yet. Future work may add project context. config.pyhardcoded mission: Lines 145 and 365 hardcode"software-dev". The reroute preserves this — fixing the hardcode is a separate concern.
Parallel Opportunities
- T040–T042 are independent and can proceed in parallel after T039.
Dependencies
- Depends on WP07 (avoid merge conflicts with consumer reroutes). Can run in parallel with WP08.
Risks & Mitigations
- Risk: Import cycle from
specify_cli.constitution→specify_cli.manifest. Mitigation:mission_paths.pyhas zero imports fromspecify_cli— it only usespathlib.Path. - Risk: Future constitution-aware resolution changes the interface. Mitigation: The static methods are the stable interface; internals can change freely.
Work Package WP10: Architectural Dependency Tests — PyTestArch (Priority: P0)
Goal: Encode the 2.x package boundary invariants as executable pytest tests using PyTestArch. Run in CI on every PR to prevent dependency direction violations. See ADR 2026-03-27-1. Independent Test: pytest tests/architectural/ -v passes. Introducing from specify_cli import X into any src/doctrine/ file causes test failure. Prompt: /tasks/WP10-architectural-dependency-tests.md Requirement Refs: FR-018, ADR 2026-03-27-1 Estimated Size: ~150 lines
Included Subtasks
- ✅ T044 Add
pytestarch>=4.0.0dev dependency topyproject.toml - ✅ T045 Create
tests/architectural/conftest.pywith session-scopedevaluableandlandscapefixtures - ✅ T046 Create
tests/architectural/test_layer_rules.pyencoding all 3 invariants (kernel isolation, doctrine isolation, constitution boundary) - ✅ T047 Validate tests pass on current codebase; smoke-test negative case
Dependencies
- Depends on WP03 (ConstitutionTemplateResolver must exist for tests to pass — validates resolve methods are in constitution, not doctrine).
Parallel Opportunities
- T044-T046 are sequential. T047 runs after all three.
- WP10 can run in parallel with WP04.
Work Package WP11: Review Workflow Metadata & Dashboard Visibility (Priority: P0)
Goal: Close 6 behavioural gaps in the review workflow: add in_review lane, record reviewer role and agent_profile, clarify agent = tool, add approved_by field, and make all fields visible in the dashboard. Independent Test: pytest tests/specify_cli/status/ tests/specify_cli/dashboard/ -v passes. Dashboard shows In Review column and new metadata badges. Prompt: /tasks/WP11-review-workflow-metadata.md Requirement Refs: FR-020, FR-021, FR-022, FR-023, FR-024, FR-025 Estimated Size: ~350 lines
Included Subtasks
- ✅ T049 Add
IN_REVIEWlane to status model + transitions - ✅ T050 Add
roleandapproved_byfrontmatter fields to scanner - ✅ T051 Update workflow review command to use
in_reviewlane - ✅ T052 Update
move-task --to approvedto populateapproved_by - ✅ T053 Dashboard: render
in_reviewlane column,rolebadge,approved_byin detail pane - ✅ T054 Verify scanner passes
roleandapproved_bythrough to JSON API
Dependencies
- Depends on WP03 (base branch).
- Must complete before WP04 and WP10 (per HiC instruction).
Parallel Opportunities
- T049 (status model) and T053 (dashboard UI) can be developed in parallel.
- T050-T052 (workflow commands) are sequential.
Dependency & Execution Summary
- Sequence: WP01 → WP02 → WP03 → WP11 → WP04/WP10 → WP05 → WP06 → WP07 → WP08/WP09
- Parallelization: WP02 → WP03 is sequential (WP03 depends on WP02 for established patterns). WP11 depends on WP03. WP04 and WP10 depend on WP11 and can run in parallel. WP05 and WP06 can run in parallel. WP08 and WP09 can run in parallel (both depend on WP07). Within each WP, most subtasks are parallel-safe.
- MVP Scope: WP01 + WP02 + WP03 + WP11 + WP04 + WP10 constitute the minimal viable release (class renamed, full API exists, review workflow metadata correct, tests pass, alias works, architectural invariants enforced). WP05-WP07 are the consumer rerouting which can be shipped incrementally. WP08 (boyscouting) and WP09 (project-local indirection) can be deferred.
Requirements Coverage Summary
| Requirement ID | Covered By Work Package(s) |
|---|---|
| FR-001 (rename class) | WP01 |
| FR-002 (get_command_template) | WP02 |
| FR-003 (get_content_template) | WP02 |
| FR-004 (resolve_command_template) | WP03 |
| FR-005 (resolve_content_template) | WP03 |
| FR-006 (list_command_templates) | WP02 |
| FR-007 (list_content_templates) | WP02 |
| FR-008 (list_missions) | WP01 (method pre-exists on MissionRepository; renamed class inherits it. Signature/return-type verified in WP04/T017) |
| FR-009 (get_action_index) | WP03 |
| FR-010 (get_action_guidelines) | WP03 |
| FR-011 (get_mission_config) | WP03 |
| FR-012 (get_expected_artifacts) | WP03 |
| FR-013 (private _command_template_path) | WP01 |
| FR-014 (private _content_template_path) | WP01 |
| FR-015 (private _missions_root) | WP01 |
| FR-016 (MissionRepository alias) | WP01 |
| FR-017 (reroute doctrine-asset consumers) | WP05, WP06, WP07 |
| FR-018 (package boundary invariants) | WP03, WP10 |
| FR-019 (project-local path indirection) | WP09 |
| FR-020 (IN_REVIEW lane) | WP11 |
| FR-021 (reviewer role field) | WP11 |
| FR-022 (approved_by field) | WP11 |
| FR-023 (agent = tool identifier) | WP11 |
| FR-024 (workflow review uses in_review) | WP11 |
| FR-025 (dashboard visibility) | WP11 |
| NFR-001 (no circular imports) | WP03, WP04 |
| NFR-002 (existing tests pass) | WP04 |
| NFR-003 (no caching) | WP02, WP03 |
| NFR-004 (safe YAML only) | WP03 |
| C-001 (shipped migrations untouched) | WP01 (alias) |
| C-002 (test_package_bundling exempted) | WP07 (validation) |
| C-003 (resolver logic unchanged) | WP06 |
| C-004 (CentralTemplateRepository out of scope) | All |
| C-005 (no constitution intermediary) | All |
Subtask Index (Reference)
| Subtask ID | Summary | Work Package | Priority | Parallel? |
|---|---|---|---|---|
| T001 | Rename class MissionRepository → MissionTemplateRepository | WP01 | P0 | No |
| T002 | Add TemplateResult value object | WP01 | P0 | Yes |
| T003 | Add ConfigResult value object | WP01 | P0 | Yes |
| T004 | Add default() classmethod | WP01 | P0 | No |
| T005 | Rename path methods to private _*_path() | WP01 | P0 | No |
| T006 | Add get_command_template() public method | WP02 | P0 | Yes |
| T007 | Add get_content_template() public method | WP02 | P0 | Yes |
| T008 | Add list_command_templates() method | WP02 | P0 | Yes |
| T009 | Add list_content_templates() method | WP02 | P0 | Yes |
| T010 | Add get_action_index() config method | WP03 | P0 | Yes |
| T011 | Add get_action_guidelines() method | WP03 | P0 | Yes |
| T012 | Add get_mission_config() config method | WP03 | P0 | Yes |
| T013 | Add get_expected_artifacts() config method | WP03 | P0 | Yes |
| T014 | Create ConstitutionTemplateResolver in src/constitution/ with resolve_command_template() | WP03 | P0 | No |
| T015 | Add resolve_content_template() on ConstitutionTemplateResolver | WP03 | P0 | No |
| T016 | Update __init__.py exports + alias | WP01 | P0 | No |
| T017 | Verify existing tests pass via alias | WP04 | P0 | No |
| T018 | Create comprehensive test module | WP04 | P0 | No |
| T019 | Reroute constitution/context.py | WP05 | P1 | Yes |
| T020 | Reroute constitution/catalog.py | WP05 | P1 | Yes |
| T021 | Reroute specify_cli/constitution/catalog.py | WP05 | P1 | Yes |
| T022 | Reroute specify_cli/runtime/show_origin.py | WP05 | P1 | Yes |
| T023 | Reroute specify_cli/runtime/resolver.py (tier-5) | WP06 | P1 | Yes |
| T024 | Reroute specify_cli/runtime/bootstrap.py | WP06 | P1 | Yes |
| T025 | Reroute specify_cli/runtime/migrate.py | WP06 | P1 | Yes |
| T026 | Reroute specify_cli/template/manager.py | WP06 | P1 | Yes |
| T027 | Reroute constitution/compiler.py | WP07 | P2 | Yes |
| T028 | Reroute specify_cli/constitution/compiler.py | WP07 | P2 | Yes |
| T029 | Fix stale path in feature.py | WP07 | P2 | Yes |
| T030 | Full test suite + validation grep | WP07 | P2 | No |
| T031 | Rename create-feature → create-mission subcommand | WP08 | P2 | No |
| T032 | Update feature.py docstrings + help strings to Mission | WP08 | P2 | No |
| T033 | Mark agent feature alias as hidden in __init__.py | WP08 | P2 | No |
| T034 | Update docs/reference/agent-subcommands.md | WP08 | P2 | Yes |
| T035 | Update docs/reference/slash-commands.md | WP08 | P2 | Yes |
| T036 | Update README.md CLI examples | WP08 | P2 | Yes |
| T037 | Update CLAUDE.md reference | WP08 | P2 | Yes |
| T038 | Update doctrine command templates | WP08 | P2 | Yes |
| T043 | Update glossary: "Feature Branch" accepted VCS term, "Mission Specification" replaces "Feature Specification" | WP08 | P2 | Yes |
| T048 | Rename --feature flag to --mission across CLI surface (--feature kept as deprecated alias) | WP08 | P2 | Yes |
| T039 | Create ProjectMissionPaths in constitution module | WP09 | P2 | No |
| T040 | Reroute specify_cli/manifest.py to ProjectMissionPaths | WP09 | P2 | Yes |
| T041 | Reroute specify_cli/mission.py to ProjectMissionPaths | WP09 | P2 | Yes |
| T042 | Reroute specify_cli/cli/commands/agent/config.py to ProjectMissionPaths | WP09 | P2 | Yes |
| T044 | Add pytestarch>=4.0.0 dev dependency | WP10 | P0 | No |
| T045 | Create tests/architectural/conftest.py fixtures (evaluable, landscape) | WP10 | P0 | No |
| T046 | Create tests/architectural/test_layer_rules.py (3 invariants) | WP10 | P0 | No |
| T047 | Validate architectural tests pass; smoke-test negative case | WP10 | P0 | No |
| T049 | Add IN_REVIEW lane to status model + transitions | WP11 | P0 | No |
| T050 | Add role and approved_by frontmatter fields to scanner | WP11 | P0 | No |
| T051 | Update workflow review to use in_review lane | WP11 | P0 | No |
| T052 | Update move-task --to approved to populate approved_by | WP11 | P0 | No |
| T053 | Dashboard: render in_review lane, role badge, approved_by | WP11 | P0 | Yes |
| T054 | Verify scanner passes role and approved_by to JSON API | WP11 | P0 | No |
| T055 | Rename "feature" to "mission" in detection error messages, status hints, SPECIFY_FEATURE env var | WP08 | P2 | Yes |
<!-- status-model:start -->
Canonical Status (Generated)
<!-- status-model:end -->
- WP01: done
- WP02: done
- WP03: done
- WP04: done
- WP05: done
- WP06: done
- WP07: done
- WP08: done
- WP09: done
- WP10: done
- WP11: done