Implementation Plan: Planning Pipeline Integrity and Runtime Reliability
Branch: main | Date: 2026-04-07 | Spec: spec.md Input: kitty-specs/069-planning-pipeline-integrity/spec.md
Summary
Fix four structural defects in spec-kitty's planning and runtime surfaces. All four are small, targeted changes to existing modules; the largest work item introduces a new wps.yaml manifest format and integrates it into finalize-tasks. No new dependencies required. All existing libraries (pydantic, jsonschema, ruamel.yaml) already present.
Technical Context
Language/Version: Python 3.11+ Primary Dependencies: typer, rich, ruamel.yaml (YAML parsing), pydantic ≥2.0 (data models), jsonschema (Draft 2020-12 validation) — all present in pyproject.toml Storage: Filesystem only (YAML, JSONL, Markdown, JSON) Testing: pytest, mypy --strict, 90%+ coverage on new code (charter requirement) Target Platform: Cross-platform (Linux, macOS, Windows 10+) Project Type: Single Python package (src/specify_cli/) Performance Goals: CLI operations <2s; materialize() skip-write must not add perceptible latency Constraints: No new required network calls; no changes to spec-kitty-runtime package (external); backwards compatibility for missions without wps.yaml
Charter Check
Charter file: .kittify/charter/charter.md (version 1.1.0)
| Gate | Status | Notes |
|---|---|---|
| Python 3.11+ | ✅ PASS | All new code targets 3.11+ |
| mypy --strict | ✅ PASS | All new functions will have full type annotations |
| 90%+ test coverage | ✅ PASS | Unit + integration tests planned for every changed function |
| CLI operations <2s | ✅ PASS | All changes are local I/O; no network calls added |
| pytest passing | ✅ PASS | No tests deleted; new tests added |
| ruamel.yaml for YAML parsing | ✅ PASS | wps_manifest.py will use ruamel.yaml |
| No new required network calls | ✅ PASS | Constraint C-004 satisfied |
No charter violations.
Project Structure
Planning artifacts (this feature)
kitty-specs/069-planning-pipeline-integrity/
├── spec.md # Feature specification
├── plan.md # This file
├── research.md # Phase 0: code review findings and design decisions
├── data-model.md # Phase 1: module contracts and data shapes
├── checklists/requirements.md # Spec quality checklist
└── tasks/ # WP prompt files (created in /spec-kitty.tasks)
Source code changes
src/specify_cli/
├── status/
│ ├── reducer.py # MODIFY: deterministic materialized_at + skip-write guard
│ └── views.py # MODIFY: materialize_if_stale() returns reduce() not materialize()
├── core/
│ ├── wps_manifest.py # NEW: WpsManifest Pydantic model, loader, tasks.md generator
│ ├── dependency_parser.py # NO CHANGE (legacy fallback, retained as-is)
│ └── mission_creation.py # MODIFY: KEBAB_CASE_PATTERN + error message
├── cli/commands/agent/
│ └── mission.py # MODIFY: finalize-tasks integrates wps.yaml tier 0
├── next/
│ ├── decision.py # MODIFY: add DecisionKind.query, Decision.is_query field
│ ├── runtime_bridge.py # MODIFY: add query_current_state() function
│ └── next_cmd.py (cli) # MODIFY: result default None, query mode branch; _print_human() query branch
├── schemas/
│ └── wps.schema.json # NEW: published JSON Schema for wps.yaml
├── upgrade/migrations/
│ └── m_3_2_0_update_planning_templates.py # NEW: push template changes to existing installations
└── missions/software-dev/command-templates/
├── tasks-outline.md # MODIFY: produce wps.yaml only (not tasks.md)
└── tasks-packages.md # MODIFY: read/update wps.yaml, generate WP files
tests/specify_cli/
├── status/
│ └── test_reducer.py # ADD: deterministic materialized_at, skip-write tests
├── core/
│ └── test_wps_manifest.py # NEW: full coverage of wps_manifest module
├── cli/commands/agent/
│ └── test_mission_finalize_tasks.py # ADD: wps.yaml integration tests
├── next/
│ └── test_next_cmd.py # ADD: query mode tests
└── core/
└── test_mission_creation.py # ADD: digit-prefix slug tests
Work Packages
WP01 — Fix status.json dirty-git (#524)
Scope: Make materialize() idempotent; fix reduce() non-determinism; fix materialize_if_stale(). Files: status/reducer.py, status/views.py, tests/specify_cli/status/test_reducer.py Dependencies: none Key changes: See data-model.md §Modified Module reducer.py and views.py
WP02 — Add wps_manifest module (#525 core)
Scope: New wps_manifest.py module with Pydantic model, YAML loader, tasks.md generator, and JSON Schema file. Files: core/wps_manifest.py (new), schemas/wps.schema.json (new), tests/specify_cli/core/test_wps_manifest.py (new) Dependencies: none Key changes: See data-model.md §New Module wps_manifest.py and §New File wps.schema.json
WP03 — Integrate wps.yaml into finalize-tasks (#525 integration)
Scope: Update finalize-tasks to use wps.yaml as tier 0; regenerate tasks.md from manifest when present. Files: cli/commands/agent/mission.py, integration tests Dependencies: WP02 (needs wps_manifest module) Key changes: See data-model.md §finalize-tasks integration
WP04 — Update tasks-outline and tasks-packages templates + migration (#525 prompts)
Scope: Rewrite both command templates; write a new migration to push the update to existing installations. Files: missions/software-dev/command-templates/tasks-outline.md, missions/software-dev/command-templates/tasks-packages.md, upgrade/migrations/m_3_2_0_update_planning_templates.py (new) Dependencies: WP02 (schema must exist before templates reference it) Key changes: tasks-outline → output wps.yaml only; tasks-packages → update wps.yaml, still generate WP prompt files. Migration required: m_2_1_3_restore_prompt_commands only activates for thin shims — existing full prompts are skipped. A new migration must detect content-stale prompt files (check for old "Create tasks.md" text) and overwrite them from the source templates using get_agent_dirs_for_project().
WP05 — Implement query mode for next (#526)
Scope: Change result default to None; add query_current_state(); add DecisionKind.query. Files: next/decision.py, next/runtime_bridge.py, cli/commands/next_cmd.py, tests Dependencies: none Key changes: See data-model.md §Modified decision.py, §Modified runtime_bridge.py, §Modified next_cmd.py
WP06 — Fix slug validator (#527)
Scope: One regex change + error message update in mission_creation.py. Files: core/mission_creation.py, tests/specify_cli/core/test_mission_creation.py Dependencies: none Key changes: See data-model.md §Modified mission_creation.py
Dependency Graph
WP01 ─────────────────────────────────────────────────── (no deps)
WP02 ─────────────────────────────────────────────────── (no deps)
WP03 depends on WP02 (different files: mission.py)
WP04 depends on WP02 (different files: templates + migration)
WP05 ─────────────────────────────────────────────────── (no deps)
WP06 ─────────────────────────────────────────────────── (no deps)
WP03 and WP04 are independent of each other — they share only the WP02 dependency and touch entirely different files. They must be in separate lanes:
- Lane A: WP01, WP05, WP06 (no inter-dependencies)
- Lane B: WP02 → WP03
- Lane C: WP02 → WP04
Testing Strategy
Unit tests (per WP)
WP01:
test_reduce_deterministic_materialized_at: same events → samematerialized_attest_materialize_skips_write_when_unchanged: two calls → only one writetest_materialize_writes_when_events_change: new event → write occurstest_reduce_empty_events_stable: empty events →materialized_at=""consistentlytest_materialize_if_stale_does_not_write: call tomaterialize_if_stale()on clean repo → zero modified files in git tree
WP02:
test_load_wps_manifest_valid: parses a valid wps.yaml → correct WpsManifesttest_load_wps_manifest_absent: missing file → returns Nonetest_load_wps_manifest_invalid_schema: malformed YAML → raises ValidationError with field nametest_load_wps_manifest_empty_deps_present:dependencies: []in YAML → field_set includes "dependencies"test_load_wps_manifest_deps_absent: nodependencieskey → field_set does NOT include "dependencies"test_generate_tasks_md_preserves_wps: generated tasks.md includes all WP titles, dep lines, subtask counts
WP03:
test_finalize_tasks_uses_wps_yaml_when_present: wps.yaml takes precedence over tasks.md prosetest_finalize_tasks_deps_not_overwritten_when_present:WP05: dependencies: []in wps.yaml → WP05 assigned no depstest_finalize_tasks_regenerates_tasks_md: after finalize, tasks.md content matches manifesttest_finalize_tasks_legacy_fallback: no wps.yaml → prose parser used, behavior unchanged
WP04 (additional):
test_migration_detects_stale_tasks_outline: file with"Create \tasks.md\"→detect()returns Truetest_migration_skips_fresh_tasks_outline: file with new wps.yaml instructions →detect()returns Falsetest_migration_apply_overwrites_stale: apply() on stale file → new template content writtentest_migration_respects_agent_config: unconfigured agent dirs skipped
WP05:
test_query_mode_does_not_advance: state counter identical before/after bare calltest_query_mode_output_begins_with_label: stdout first line is[QUERY — no result provided, state not advanced]test_query_mode_output_shows_step: stdout includes current step identifiertest_result_success_still_advances:--result successretains advancing behaviortest_query_mode_json_output: JSON output includes"is_query": true
WP06:
test_slug_accepts_digit_prefix:068-feature,001-foo→ no errortest_slug_rejects_uppercase:User-Auth→ raises MissionCreationErrortest_slug_rejects_underscore:user_auth→ raises MissionCreationErrortest_slug_rejects_empty:""→ raises MissionCreationError
Integration tests
- SC-001 integration:
spec-kitty agent tasks statuson clean repo →git status --porcelainempty - SC-002 integration:
finalize-taskswith prose cross-references in WP05 prompt → WP05 deps unchanged - SC-003 integration:
spec-kitty next --agent claudewithout--result→ step counter unchanged - SC-004 integration:
spec-kitty agent mission create "068-feature-name"→ no slug error
Backwards Compatibility
| Surface | Impact | Mitigation |
|---|---|---|
status.json schema | materialized_at now reflects last event timestamp, not current time | Schema unchanged; field semantics are "when snapshot was computed" — a past timestamp is valid |
spec-kitty next without --result | Previously advanced; now returns query response | Desired behavior change. Agents that relied on bare next advancing should add --result success |
Missions without wps.yaml | finalize-tasks behavior completely unchanged | Legacy fallback always active when wps.yaml absent |
Slug 123-fix | Previously rejected; now accepted | Accept-side change only; existing valid slugs unaffected |
Branch Contract (final)
- Planning/base branch:
main - Merge target:
main - branch_matches_target: true
Next command: /spec-kitty.tasks