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 (T001T055) roll up into 11 work packages (WP01WP11). 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 MissionRepositoryMissionTemplateRepository in src/doctrine/missions/repository.py
  • ✅ T002 Add TemplateResult value object class to repository.py (dict-backed, __slots__, properties: content, origin, tier)
  • ✅ T003 Add ConfigResult value object class to repository.py (dict-backed, __slots__, properties: content, origin, parsed)
  • ✅ T004 Add default() classmethod that returns MissionTemplateRepository(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: export MissionTemplateRepository + TemplateResult + ConfigResult, add MissionRepository = MissionTemplateRepository alias

Implementation Notes

  • All existing method bodies stay the same -- just rename from get_ to __path for path-returning methods
  • get_template()_content_template_path() (naming alignment with spec)
  • get_expected_artifacts() currently returns Path | None -- rename to _expected_artifacts_path()
  • TemplateResult and ConfigResult follow the contract in contracts/mission-template-repository.md exactly
  • The _missions_root property should expose self._root for 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 ResolutionTier import. Mitigation: TemplateResult.tier can use Any type hint with runtime check, or the type is str | None to avoid importing from specify_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, constructs TemplateResult)
  • ✅ T007 [P] Add get_content_template(mission, name)TemplateResult | None (reads file from _content_template_path, constructs TemplateResult)
  • ✅ 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, return None if path is None, read file content with path.read_text(encoding="utf-8"), wrap in TemplateResult(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, sort
  • list_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 None return + 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 | None on MissionTemplateRepository (reads + parses YAML with ruamel.yaml)
  • ✅ T011 [P] Add get_action_guidelines(mission, action)TemplateResult | None on MissionTemplateRepository (reads markdown)
  • ✅ T012 [P] Add get_mission_config(mission)ConfigResult | None on MissionTemplateRepository (reads + parses mission.yaml)
  • ✅ T013 [P] Add get_expected_artifacts(mission)ConfigResult | None on MissionTemplateRepository (reads + parses expected-artifacts.yaml)
  • ✅ T014 Create src/constitution/template_resolver.py with ConstitutionTemplateResolver class. Method: resolve_command_template(mission, name, project_dir?)TemplateResult. Composes MissionTemplateRepository (tier 5) + specify_cli.runtime.resolver (tiers 1-4). Raises FileNotFoundError if not found at any tier.
  • ✅ T015 Add resolve_content_template(mission, name, project_dir?)TemplateResult on ConstitutionTemplateResolver (same pattern as T014)

Implementation Notes

  • Config methods (T010-T013) go on MissionTemplateRepository in src/doctrine/missions/repository.py — these are doctrine-level reads with zero external imports
  • Config methods use ruamel.yaml with YAML(typ="safe") -- matching action_index.py pattern
  • get_action_index should construct a ConfigResult with raw text + parsed dict, NOT return an ActionIndex dataclass (that's a separate concern)
  • ConstitutionTemplateResolver (T014-T015) lives in src/constitution/template_resolver.py — constitution depends only on doctrine + kernel (no specify_cli imports). The 5-tier resolver primitives must be relocated from specify_cli.runtime.resolver to 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 into TemplateResult(content, origin, tier).
  • If resolver raises FileNotFoundError, re-raise (per contract)
  • resolve_* with project_dir=None should still work by falling back to package-default tier only
  • Package boundary invariant: MissionTemplateRepository (doctrine) must have ZERO imports from specify_cli or constitution. Verify with grep after 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 doctrine and specify_cli.runtime.resolver~~ Eliminated: resolve methods now live in constitution, not doctrine. Constitution depends only on doctrine + kernel — no specify_cli imports. The 5-tier resolver primitives must be relocated to a constitution-reachable package before ConstitutionTemplateResolver can be created.
  • Risk: ruamel.yaml parse failure on malformed YAML. Mitigation: Try/except returning None with warning log per contract.
  • Risk: Resolver expects different calling convention. Mitigation: Read resolver source carefully; the resolve() function in resolver.py needs 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.py passes unchanged via alias (run before/after). Also verify list_missions() signature and return type match FR-008 (sorted list[str]).
  • ✅ T018 Create tests/doctrine/test_mission_template_repository.py with test categories:
  • Value object construction and properties (TemplateResult, ConfigResult)
  • Doctrine-level reads: all get_* methods against real doctrine assets
  • None returns: 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: MissionRepository alias resolves correctly, isinstance check
  • 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_path fixture for edge case tests (empty root, missing dirs)
  • For resolver tests, call without project_dir to test package-default tier only (avoids needing a mock project)
  • Use MissionTemplateRepository.default() for doctrine-level tests
  • Test from doctrine.missions import MissionRepository still resolves to MissionTemplateRepository

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 -- replace resolve_doctrine_root() / "missions" (line 225), load_action_index() call (line 229), guidelines_path construction (line 249) with MissionTemplateRepository.default() API calls
  • ✅ T020 Reroute src/constitution/catalog.py -- replace _load_template_sets_with_presence() (lines 256-267) manual missions_root + directory iteration with MissionTemplateRepository.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" with repo = MissionTemplateRepository.default(). Replace load_action_index(missions_root, mission, action) with repo.get_action_index(mission, action) and use .parsed property. Replace guidelines_path = missions_root / ... with result = repo.get_action_guidelines(mission, action) and use .content.
  • catalog.py (T020/T021): Replace directory iteration logic with repo.list_missions(). Replace mission_dir / "mission.yaml" with repo.get_mission_config(name). Keep the function signature the same.
  • show_origin.py (T022): Replace _discover_mission_names() body with MissionTemplateRepository.default().list_missions(). Replace _discover_command_names() with repo.list_command_templates(mission). Replace _discover_template_names() with repo.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.py callers expect ActionIndex dataclass from load_action_index(), but get_action_index() returns ConfigResult. Mitigation: context.py only uses the action index to get the artifact list keys -- check if it needs ActionIndex or just the parsed dict. May need to keep load_action_index() call but provide the path from repository.
  • Risk: catalog.py function 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-5 get_package_asset_root() (lines 174-175, 302-303) with MissionTemplateRepository.default()._command_template_path() / ._content_template_path() / ._mission_config_path()
  • ✅ T024 Reroute src/specify_cli/runtime/bootstrap.py -- replace get_package_asset_root() (line 74) with MissionTemplateRepository.default()._missions_root for missions source path
  • ✅ T025 Reroute src/specify_cli/runtime/migrate.py -- replace get_package_asset_root() (line 177) with MissionTemplateRepository.default()._missions_root
  • ✅ T026 [P] Reroute src/specify_cli/template/manager.py -- replace files("doctrine").joinpath("missions") (lines 242-243) with MissionTemplateRepository.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 on subdir (either command-templates or templates). Lines 302-303 similarly for mission config. Tiers 1-4 are untouched (C-003).
  • bootstrap.py (T024): populate_from_package() uses asset_root = get_package_asset_root() then shutil.copytree. Replace source with MissionTemplateRepository.default()._missions_root. Note: lines 84, 89 use asset_root.parent for sibling dirs -- these need _missions_root.parent which is the doctrine package root. Document this coupling.
  • migrate.py (T025): Replace package_root = get_package_asset_root() with MissionTemplateRepository.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 for src/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.py needs parent traversal (_missions_root.parent). Mitigation: This is acceptable -- document it and consider adding a _doctrine_root property 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) -- replace doctrine_root / "missions" / mission / "mission.yaml" with MissionTemplateRepository.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 with MissionTemplateRepository.default()._missions_root or appropriate API call.
  • ✅ T030 Run full test suite (pytest) and fix any regressions. Validate with grep: no direct missions_root / mission / "command-templates", missions_root / mission / "templates", missions_root / mission / "actions" patterns in production code outside repository.py, shipped migrations, and test_package_bundling.py.

Implementation Notes

  • compiler.py (T027/T028): Both files construct doctrine_root / "missions" / mission / "mission.yaml" to read mission config. Replace with repo.get_mission_config(mission) and use .parsed property. The compilers may also need .content for 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 old specify_cli/missions/ directory (which was migrated to doctrine/missions/). This is a bug regardless of this feature. Replace with MissionTemplateRepository.default()._missions_root or appropriate lookup.
  • Validation (T030): Run pytest with 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.py stale path may have tests that rely on it working. Mitigation: Run feature.py tests 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-feature subcommand to create-mission (add hidden create-feature alias 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.print output that say "feature" when they mean "mission"
  • ✅ T033 Mark the agent feature registration in __init__.py as hidden=True so 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 that agent feature remains as a hidden alias
  • ✅ T035 [P] Update docs/reference/slash-commands.md — replace spec-kitty agent feature invocations with spec-kitty agent mission
  • ✅ T036 [P] Update README.md CLI examples (lines ~866–902) — replace agent feature with agent mission
  • ✅ T037 [P] Update CLAUDE.md reference (line ~317) — replace spec-kitty agent feature finalize-tasks with spec-kitty agent mission finalize-tasks
  • ✅ T038 [P] Update doctrine command templates that emit spec-kitty agent feature (task-prompt-template.md files in src/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 --feature flag to --mission across CLI surface (pulled from 057 scope). --mission becomes primary, --feature remains 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, and SPECIFY_FEATURE env var references. Add SPECIFY_MISSION as primary env var with SPECIFY_FEATURE as deprecated fallback.

Implementation Notes

  • Do NOT rename the Python file feature.pymission.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__.py to keep backward compat without polluting --help.
  • create-featurecreate-mission: Add @app.command(name="create-mission") and keep a hidden alias via a thin wrapper or typer's deprecated flag.
  • --feature--mission flag rename: Add --mission as primary option, keep --feature as deprecated alias via typer's multiple-name feature. The agent 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: --feature flag rename affects many CLI entry points. Mitigation: --feature kept 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.py with ProjectMissionPaths class: 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 use ProjectMissionPaths
  • ✅ T041 [P] Reroute src/specify_cli/mission.py (9 patterns: lines ~276, 457, 467, 470, 493, 500, 522, 714, 722) to use ProjectMissionPaths
  • ✅ T042 [P] Reroute src/specify_cli/cli/commands/agent/config.py (2 patterns: lines ~145, 365) to use ProjectMissionPaths

Implementation Notes

  • Pure indirection: No behavior change. Each path construction is replaced with the equivalent ProjectMissionPaths call.
  • 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.py hardcoded 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.constitutionspecify_cli.manifest. Mitigation: mission_paths.py has zero imports from specify_cli — it only uses pathlib.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.0 dev dependency to pyproject.toml
  • ✅ T045 Create tests/architectural/conftest.py with session-scoped evaluable and landscape fixtures
  • ✅ T046 Create tests/architectural/test_layer_rules.py encoding 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_REVIEW lane to status model + transitions
  • ✅ T050 Add role and approved_by frontmatter fields to scanner
  • ✅ T051 Update workflow review command to use in_review lane
  • ✅ T052 Update move-task --to approved to populate approved_by
  • ✅ T053 Dashboard: render in_review lane column, role badge, approved_by in detail pane
  • ✅ T054 Verify scanner passes role and approved_by through 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 IDCovered 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 IDSummaryWork PackagePriorityParallel?
T001Rename class MissionRepository → MissionTemplateRepositoryWP01P0No
T002Add TemplateResult value objectWP01P0Yes
T003Add ConfigResult value objectWP01P0Yes
T004Add default() classmethodWP01P0No
T005Rename path methods to private _*_path()WP01P0No
T006Add get_command_template() public methodWP02P0Yes
T007Add get_content_template() public methodWP02P0Yes
T008Add list_command_templates() methodWP02P0Yes
T009Add list_content_templates() methodWP02P0Yes
T010Add get_action_index() config methodWP03P0Yes
T011Add get_action_guidelines() methodWP03P0Yes
T012Add get_mission_config() config methodWP03P0Yes
T013Add get_expected_artifacts() config methodWP03P0Yes
T014Create ConstitutionTemplateResolver in src/constitution/ with resolve_command_template()WP03P0No
T015Add resolve_content_template() on ConstitutionTemplateResolverWP03P0No
T016Update __init__.py exports + aliasWP01P0No
T017Verify existing tests pass via aliasWP04P0No
T018Create comprehensive test moduleWP04P0No
T019Reroute constitution/context.pyWP05P1Yes
T020Reroute constitution/catalog.pyWP05P1Yes
T021Reroute specify_cli/constitution/catalog.pyWP05P1Yes
T022Reroute specify_cli/runtime/show_origin.pyWP05P1Yes
T023Reroute specify_cli/runtime/resolver.py (tier-5)WP06P1Yes
T024Reroute specify_cli/runtime/bootstrap.pyWP06P1Yes
T025Reroute specify_cli/runtime/migrate.pyWP06P1Yes
T026Reroute specify_cli/template/manager.pyWP06P1Yes
T027Reroute constitution/compiler.pyWP07P2Yes
T028Reroute specify_cli/constitution/compiler.pyWP07P2Yes
T029Fix stale path in feature.pyWP07P2Yes
T030Full test suite + validation grepWP07P2No
T031Rename create-feature → create-mission subcommandWP08P2No
T032Update feature.py docstrings + help strings to MissionWP08P2No
T033Mark agent feature alias as hidden in __init__.pyWP08P2No
T034Update docs/reference/agent-subcommands.mdWP08P2Yes
T035Update docs/reference/slash-commands.mdWP08P2Yes
T036Update README.md CLI examplesWP08P2Yes
T037Update CLAUDE.md referenceWP08P2Yes
T038Update doctrine command templatesWP08P2Yes
T043Update glossary: "Feature Branch" accepted VCS term, "Mission Specification" replaces "Feature Specification"WP08P2Yes
T048Rename --feature flag to --mission across CLI surface (--feature kept as deprecated alias)WP08P2Yes
T039Create ProjectMissionPaths in constitution moduleWP09P2No
T040Reroute specify_cli/manifest.py to ProjectMissionPathsWP09P2Yes
T041Reroute specify_cli/mission.py to ProjectMissionPathsWP09P2Yes
T042Reroute specify_cli/cli/commands/agent/config.py to ProjectMissionPathsWP09P2Yes
T044Add pytestarch>=4.0.0 dev dependencyWP10P0No
T045Create tests/architectural/conftest.py fixtures (evaluable, landscape)WP10P0No
T046Create tests/architectural/test_layer_rules.py (3 invariants)WP10P0No
T047Validate architectural tests pass; smoke-test negative caseWP10P0No
T049Add IN_REVIEW lane to status model + transitionsWP11P0No
T050Add role and approved_by frontmatter fields to scannerWP11P0No
T051Update workflow review to use in_review laneWP11P0No
T052Update move-task --to approved to populate approved_byWP11P0No
T053Dashboard: render in_review lane, role badge, approved_byWP11P0Yes
T054Verify scanner passes role and approved_by to JSON APIWP11P0No
T055Rename "feature" to "mission" in detection error messages, status hints, SPECIFY_FEATURE env varWP08P2Yes

<!-- 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