description: "Work package task list for canonical state authority & single metadata writer"
Work Packages: Canonical State Authority & Single Metadata Writer
Inputs: Design documents from /kitty-specs/051-canonical-state-authority-single-metadata-writer/ Prerequisites: plan.md (required), spec.md (user stories), research.md, data-model.md, quickstart.md
Tests: Included — this sprint requires focused tests for canonical-state behavior and metadata-writer behavior per the spec requirements.
Organization: Fine-grained subtasks (Txxx) roll up into work packages (WPxx). Each work package must be independently deliverable and testable.
Prompt Files: Each work package references a matching prompt file in /tasks/ generated by /spec-kitty.tasks.
Work Package WP01: Create feature_metadata.py Module (Priority: P0)
Goal: Create the single metadata writer API at src/specify_cli/feature_metadata.py — TypedDict definitions, atomic writes, schema validation, and all mutation helpers. This is the foundation that all other WPs depend on. Independent Test: Import feature_metadata and exercise every public function against a temp directory. All tests pass, formatting is consistent, atomic write handles interruption. Prompt: /tasks/WP01-create-feature-metadata-module.md Requirement Refs: FR-002, FR-003, FR-004, FR-005, FR-007, FR-008, FR-010, NFR-001, NFR-002, NFR-003
Included Subtasks
- ✅ T001 Create
src/specify_cli/feature_metadata.pywith TypedDict definitions - ✅ T002 Implement
load_meta()— relocate fromupgrade/feature_meta.py, add error handling - ✅ T003 Implement
validate_meta()— check required fields, return error list - ✅ T004 Implement
_atomic_write()— temp file +os.replace(), cleanup on failure - ✅ T005 Implement
write_meta()— validate, serialize with standard format, atomic write - ✅ T006 Implement mutation helpers —
record_acceptance(),record_merge(),finalize_merge(),set_vcs_lock(),set_documentation_state(),set_target_branch()with bounded history - ✅ T007 Unit tests in
tests/specify_cli/test_feature_metadata.py
Implementation Notes
- Standard format:
json.dumps(meta, indent=2, ensure_ascii=False, sort_keys=True) + "\n" - Extends existing
write_feature_meta()convention — addssort_keys=True - Bounded history: cap
acceptance_historyandmerge_historyat 20 entries (retain most recent) - Unknown fields preserved during read-modify-write (forward compatibility)
- Each mutation helper: load → mutate → validate → write
Parallel Opportunities
- None — this is the foundational WP.
Dependencies
- None (starting package).
Risks & Mitigations
- Risk:
sort_keys=Trueaddition changes diff output for existing meta.json files → Mitigation: Only reformats on actual mutations, not bulk reformatting. - Risk:
os.replace()behavior on Windows → Mitigation: Usetempfile.mkstemp()in same directory to stay on same filesystem.
Work Package WP02: Canonical Acceptance Refactor (Priority: P1) 🎯 MVP
Goal: Replace Activity Log body-text parsing in acceptance with materialize() from canonical status model. Migrate acceptance and orchestrator meta.json writes to feature_metadata.py. This is the highest-impact change — acceptance correctness no longer depends on markdown body content. Independent Test: Run acceptance on a feature where Activity Log sections have been deleted from all WP files. Acceptance succeeds because it reads canonical status.events.jsonl instead. Prompt: /tasks/WP02-canonical-acceptance-refactor.md Requirement Refs: FR-001, FR-009, FR-011, NFR-002, C-001, C-004
Included Subtasks
- ✅ T008 Replace Activity Log parsing in
acceptance.py(~lines 355-392) withmaterialize()call - ✅ T009 Replace Activity Log parsing in
acceptance_support.py(~lines 457-492) with same logic - ✅ T010 Migrate
acceptance.py:538meta.json write torecord_acceptance() - ✅ T011 Migrate
acceptance_support.py:620meta.json write torecord_acceptance() - ✅ T012 Migrate
orchestrator_api/commands.py:787meta.json write torecord_acceptance()(fixes missing newline) - ✅ T013 Integration tests proving canonical state authority and orchestrator parity
Implementation Notes
- The acceptance validation currently checks 3 rules against Activity Log entries. Replace with one check: is
snapshot[wp_id].lane == "done"for all WPs. - Handle missing event log explicitly: raise error, do not fall back to Activity Log.
- Orchestrator acceptance currently writes only
accepted_atandaccepted_by. After migration,record_acceptance()normalizes both paths to write the same fields. - Both
acceptance.pyandscripts/tasks/acceptance_support.pyhave mirrored implementations — apply same change to both.
Parallel Opportunities
- T008 and T009 are identical logic applied to different files — can be done simultaneously.
- T010-T012 are mechanical write-site migrations — can parallel with T008-T009.
Dependencies
- Depends on WP01 (
record_acceptance()andfeature_metadata.pymust exist).
Risks & Mitigations
- Risk: Legacy features without
status.events.jsonl→ Mitigation: Explicit error message ("no canonical state found for {feature}"), not silent fallback to Activity Log. - Risk: Acceptance validation changes behavior subtly → Mitigation: Integration tests with both deleted and corrupted Activity Log.
Work Package WP03: Migrate VCS, Merge, and Feature Creation Writes (Priority: P1)
Goal: Migrate the remaining non-acceptance meta.json write sites to feature_metadata.py. Fixes 2 missing-trailing-newline bugs in feature.py. Independent Test: Run spec-kitty implement (VCS lock), merge flow, and feature creation — verify all produce consistently formatted meta.json through the single writer. Prompt: /tasks/WP03-migrate-vcs-merge-feature-writes.md Requirement Refs: FR-002, FR-004, FR-009, NFR-004
Included Subtasks
- ✅ T014 [P] Migrate
implement.py:591,601VCS lock writes toset_vcs_lock() - ✅ T015 [P] Migrate
tasks_cli.py:573merge metadata write torecord_merge() - ✅ T016 [P] Migrate
tasks_cli.py:592finalize merge write tofinalize_merge() - ✅ T017 [P] Migrate
feature.py:632,658feature creation writes towrite_meta()(fixes missing newline bugs) - ✅ T018 Tests for each migrated write site
Implementation Notes
- Each migration is a mechanical replacement: replace
json.dumps()+write_text()with the appropriatefeature_metadata.pyfunction call. feature.py:632creates the initial meta.json — usewrite_meta()directly (not a mutation helper, since there's no existing file to load).feature.py:658addsdocumentation_state— useset_documentation_state().- All 4 subtasks touch different files and can proceed in parallel.
Parallel Opportunities
- T014, T015, T016, T017 are fully independent (different files).
Dependencies
- Depends on WP01 (mutation helpers must exist).
- Can run in parallel with WP02.
Risks & Mitigations
- Risk: Feature creation path writes initial meta.json (not read-modify-write) → Mitigation:
write_meta()handles both fresh and existing files.
Work Package WP04: Migrate doc_state.py Write Sites (Priority: P2)
Goal: Refactor doc_state.py's 8 write functions to delegate file I/O to feature_metadata.py while keeping validation logic in doc_state.py. Independent Test: Call each doc_state setter, verify meta.json has consistent formatting (sorted keys, ensure_ascii=False, trailing newline) matching the standard. Prompt: /tasks/WP04-migrate-doc-state-writes.md Requirement Refs: FR-002, FR-009, NFR-004
Included Subtasks
- ✅ T019 Refactor doc_state.py read/write pattern to use
load_meta()andwrite_meta()fromfeature_metadata.py - ✅ T020 [P] Update individual field setters:
set_iteration_mode(),set_divio_types_selected(),set_generators_configured(),set_audit_metadata() - ✅ T021 [P] Update composite writers:
write_documentation_state(),initialize_documentation_state(),update_documentation_state(),ensure_documentation_state() - ✅ T022 Tests verifying consistent formatting across all doc_state write paths
Implementation Notes
doc_state.pycurrently usesjson.dump(meta, f, indent=2)via file handle — replace withload_meta()for reads andwrite_meta()for writes.- Keep all validation logic (checking iteration_mode values, divio types, generator fields, coverage_percentage range) in
doc_state.py. - Only delegate the file I/O layer.
- The
meta_fileparameter in doc_state functions takes a Path to meta.json — convert tofeature_dir(parent directory) when callingload_meta()/write_meta().
Parallel Opportunities
- T020 and T021 are independent groups of functions.
Dependencies
- Depends on WP01 (
load_meta()andwrite_meta()must exist). - Can run in parallel with WP02 and WP03.
Risks & Mitigations
- Risk: doc_state.py validation logic tightly coupled with I/O → Mitigation: Keep validation functions intact, only replace the
json.load()/json.dump()calls.
Work Package WP05: Compatibility Wrapper & Codebase Sweep (Priority: P2)
Goal: Add compatibility re-exports in upgrade/feature_meta.py, verify zero direct meta.json writes remain outside feature_metadata.py, and add integration tests proving the full canonical-state + single-writer system works end-to-end. Independent Test: Grep entire src/specify_cli/ for direct meta.json writes — zero results outside feature_metadata.py. Integration tests pass with corrupted compatibility views. Prompt: /tasks/WP05-compatibility-wrapper-codebase-sweep.md Requirement Refs: FR-002, FR-006, FR-009, NFR-002, C-001
Included Subtasks
- ✅ T023 Update
upgrade/feature_meta.py— thin re-exports forload_feature_meta()andwrite_feature_meta() - ✅ T024 Verify migration callers (
m_2_0_6_consistency_sweep.py) work through wrapper - ✅ T025 Codebase sweep — test that greps for direct meta.json writes outside
feature_metadata.pyand fails on violations - ✅ T026 Integration test: end-to-end acceptance flow reads canonical state, writes through single API
- ✅ T027 Integration test: corrupt compatibility views (Activity Log + frontmatter lane), verify correctness preserved
Implementation Notes
upgrade/feature_meta.pykeeps its inference functions (infer_target_branch,infer_mission,infer_created_at,build_baseline_feature_meta) — these are upgrade-specific, not metadata writer concerns.- Only
load_feature_meta()andwrite_feature_meta()become thin wrappers. - The codebase sweep test (T025) should be a pytest test that uses
subprocessorpathlibto scan source files — catches regressions if someone adds a direct write later. - Integration tests create a complete feature directory with
status.events.jsonl, WP files, andmeta.json, then exercise the full acceptance flow.
Parallel Opportunities
- T023-T024 (wrapper) and T025 (sweep) are independent.
- T026-T027 (integration tests) depend on all prior WPs being complete.
Dependencies
- Depends on WP02, WP03, and WP04 (all write sites must be migrated before sweep can pass).
Risks & Mitigations
- Risk: Migration callers in frozen code break → Mitigation: T024 specifically tests migration compatibility.
- Risk: Future developers bypass the API → Mitigation: T025 sweep test catches direct writes in CI.
Dependency & Execution Summary
WP01 (foundation) ─────────────────────────────────────┐
├─→ WP02 (canonical acceptance) ─────────────────────┤
├─→ WP03 (VCS/merge/creation migration) ────────────┤──→ WP05 (sweep + integration)
└─→ WP04 (doc_state migration) ─────────────────────┘
- Sequence: WP01 first, then WP02/WP03/WP04 in parallel, then WP05.
- Parallelization: WP02, WP03, and WP04 are fully independent after WP01 completes. Run 3 agents simultaneously.
- MVP Scope: WP01 + WP02 delivers the core value — canonical state authority for acceptance + single metadata writer for acceptance paths.
Requirements Coverage Summary
| Requirement ID | Covered By Work Package(s) |
|---|---|
| FR-001 | WP02 |
| FR-002 | WP01, WP02, WP03, WP04, WP05 |
| FR-003 | WP01 |
| FR-004 | WP01, WP03 |
| FR-005 | WP01 |
| FR-006 | WP05 |
| FR-007 | WP01 |
| FR-008 | WP01 |
| FR-009 | WP02, WP03, WP04, WP05 |
| FR-010 | WP01 |
| FR-011 | WP02 |
| NFR-001 | WP01 |
| NFR-002 | WP01, WP02, WP05 |
| NFR-003 | WP01 |
| NFR-004 | WP03, WP04 |
| C-001 | WP02, WP05 |
| C-002 | All (scoped to Phase 3+4 only) |
| C-003 | WP01 |
| C-004 | WP02 |
| C-005 | All |
Subtask Index (Reference)
| Subtask ID | Summary | Work Package | Priority | Parallel? |
|---|---|---|---|---|
| T001 | TypedDict definitions in feature_metadata.py | WP01 | P0 | No |
| T002 | Implement load_meta() | WP01 | P0 | No |
| T003 | Implement validate_meta() | WP01 | P0 | No |
| T004 | Implement _atomic_write() | WP01 | P0 | No |
| T005 | Implement write_meta() | WP01 | P0 | No |
| T006 | Implement mutation helpers with bounded history | WP01 | P0 | No |
| T007 | Unit tests for feature_metadata.py | WP01 | P0 | No |
| T008 | Replace Activity Log parsing in acceptance.py | WP02 | P1 | No |
| T009 | Replace Activity Log parsing in acceptance_support.py | WP02 | P1 | Yes |
| T010 | Migrate acceptance.py meta.json write | WP02 | P1 | Yes |
| T011 | Migrate acceptance_support.py meta.json write | WP02 | P1 | Yes |
| T012 | Migrate orchestrator_api meta.json write | WP02 | P1 | Yes |
| T013 | Integration tests for canonical acceptance | WP02 | P1 | No |
| T014 | Migrate implement.py VCS lock writes | WP03 | P1 | Yes |
| T015 | Migrate tasks_cli.py merge metadata write | WP03 | P1 | Yes |
| T016 | Migrate tasks_cli.py finalize merge write | WP03 | P1 | Yes |
| T017 | Migrate feature.py creation writes | WP03 | P1 | Yes |
| T018 | Tests for migrated VCS/merge/creation writes | WP03 | P1 | No |
| T019 | Refactor doc_state.py I/O to use feature_metadata.py | WP04 | P2 | No |
| T020 | Update individual field setters in doc_state.py | WP04 | P2 | Yes |
| T021 | Update composite writers in doc_state.py | WP04 | P2 | Yes |
| T022 | Tests for doc_state formatting consistency | WP04 | P2 | No |
| T023 | Compatibility re-exports in upgrade/feature_meta.py | WP05 | P2 | No |
| T024 | Verify migration callers work through wrapper | WP05 | P2 | No |
| T025 | Codebase sweep test for direct meta.json writes | WP05 | P2 | Yes |
| T026 | End-to-end acceptance integration test | WP05 | P2 | No |
| T027 | Corrupted compatibility views integration test | WP05 | P2 | No |
<!-- status-model:start -->
Canonical Status (Generated)
<!-- status-model:end -->
- WP01: done
- WP02: done
- WP03: done
- WP04: done
- WP05: done