Canonical Status Model Cleanup

Overview

Make the 3.0 canonical status model true everywhere in the spec-kitty repo. Work package status lives only in status.events.jsonl and reducer-derived outputs (status.json), never in WP frontmatter or WP-local lane logs. This is a hard cutover for active runtime code, templates, docs, and tests. Historical checked-in artifacts under kitty-specs/ are preserved but fenced off so they stop teaching or influencing current behavior.

Problem Statement

The 3.0 status model (status.events.jsonl + reducer) was introduced but never fully propagated. The codebase has dual authority:

  • Active WP frontmatter still carries lane, review_status, reviewed_by, review_feedback, and progress fields that compete with canonical events
  • Runtime commands fall back to frontmatter lane when canonical state is missing, silently masking bootstrap failures
  • Templates and generation surfaces still emit lane: "planned" in WP frontmatter and lane-bearing history entries
  • Active docs, README, and command help still describe frontmatter-lane semantics as current behavior
  • Tests construct modern WPs with lane: in frontmatter, validating the abandoned model
  • Historical kitty-specs examples are cited as active guidance, mixing 2.x and 3.0 semantics

This dual authority causes silent correctness bugs, confusing error paths, and stale teaching surfaces.

Actors

ActorDescription
CLI UserDeveloper running spec-kitty commands for feature planning and implementation
AI AgentAutomated agent (Claude, Codex, etc.) consuming templates and prompts to implement work packages
Runtimespec-kitty Python CLI runtime executing workflow, task, merge, and dashboard commands

User Scenarios & Acceptance

Scenario 1: Task Finalization Seeds Canonical State

Given a feature with newly generated WP files after /spec-kitty.tasks When the user runs either spec-kitty agent feature finalize-tasks or spec-kitty agent tasks finalize-tasks Then every WP that lacks canonical state gets an initial planned status event emitted to status.events.jsonl, status.json is materialized, and the WP files contain no lane field in their frontmatter. Both entrypoints produce identical results.

Scenario 2: Runtime Hard-Fails When Event Log Is Absent

Given a feature whose WP files exist but status.events.jsonl does not exist at all When the user runs any runtime command (workflow implement, tasks move-task, next, status, merge) Then the command fails immediately with a clear error: "Canonical status not found for feature <slug>. Run spec-kitty agent feature finalize-tasks --feature <slug> to bootstrap status." No frontmatter fallback occurs.

Scenario 2b: Partial Canonical State Shows Unknown WPs

Given a feature whose status.events.jsonl exists but contains events for only some WPs (e.g., WP01 and WP02 have events but WP03 does not) When the user runs spec-kitty agent tasks status or the dashboard Then WPs with canonical events are shown in their correct lanes. WPs without any canonical event are shown as "uninitialized" in the board output. The command does not fail — it renders what it has and flags the gap.

Scenario 3: Generated WPs Are Lane-Free

Given a user running /spec-kitty.tasks to generate work packages When the WP prompt files are written Then no WP file contains lane: in its YAML frontmatter. History entries contain only timestamp, actor, and action text — no lane field.

Scenario 4: Agent Reads Status from Canonical Source

Given an AI agent implementing a WP in a worktree When the agent needs to check WP status or move a WP between lanes Then all status reads come from the canonical reducer (status.json or status.events.jsonl), and all status writes go through emit_status_transition(). The agent never reads or writes lane in WP frontmatter.

Scenario 5: Dashboard Reads Canonical State Only

Given a user running spec-kitty agent tasks status or the dashboard scanner When the board is rendered Then WP lane positions come from the materialized status.json, not from frontmatter. If the event log exists but a WP has no events, that WP is shown as "uninitialized" (per Scenario 2b). If the event log is entirely absent, the command hard-fails (per Scenario 2). Frontmatter lane is never used as a fallback source.

Scenario 6: Historical Artifacts Don't Pollute Active Behavior

Given old feature records in kitty-specs/ with frontmatter lane: fields When any active runtime command scans for WP state Then the old frontmatter lanes are ignored. Only canonical event state is used. Active docs do not cite these old records as examples of current behavior.

Scenario 7: Validate-Only Checks Bootstrap Readiness

Given a feature with WP files but no canonical state yet When the user runs spec-kitty agent feature finalize-tasks --validate-only (or spec-kitty agent tasks finalize-tasks --validate-only) Then the output reports which WPs lack canonical state and what finalization would do, without mutating any files.

Scenario 8: Migration Tools Still Work

Given a legacy feature with frontmatter-lane state but no event log When the user runs explicit migration tooling Then the migration reads frontmatter lanes and bootstraps canonical events from them. This is the only code path that reads frontmatter lane as authoritative.

Functional Requirements

IDRequirementStatus
FR-001Both spec-kitty agent feature finalize-tasks and spec-kitty agent tasks finalize-tasks emit an initial planned status event for every WP that lacks canonical state in status.events.jsonl. Both entrypoints produce identical bootstrap results.Proposed
FR-002Both finalize-tasks entrypoints materialize status.json after seeding initial events.Proposed
FR-003Both finalize-tasks entrypoints support --validate-only, which reports which WPs lack canonical state and whether bootstrap would succeed, without mutating files.Proposed
FR-004Active WP frontmatter schema no longer includes lane, review_status, reviewed_by, review_feedback, or progress as top-level fields.Proposed
FR-005Frontmatter validation for active WPs requires only static definition fields (work_package_id, title, dependencies, subtasks, owned_files, authoritative_surface, execution_mode, planning_base_branch, merge_target_branch, branch_strategy) and never requires lane.Proposed
FR-006Active WP history entries contain only timestamp (at), actor/agent, optional shell PID, and action text. No lane field in history entries.Proposed
FR-007Active body-section activity log text does not include lane= entries or lane-transition records.Proposed
FR-008All runtime commands that read WP status (workflow implement/review, tasks move-task/status/list, next, dashboard, acceptance, merge/preflight) read from canonical reducer state only — never from frontmatter lane.Proposed
FR-009When the event log (status.events.jsonl) is entirely absent for a feature, runtime commands hard-fail with a clear error directing the user to run finalize-tasks or migration tooling. No silent frontmatter fallback.Proposed
FR-009aWhen the event log exists but a specific WP has no events, read-only commands (status, dashboard) show that WP as "uninitialized" in their output. Mutating commands (move-task, workflow implement) hard-fail for that specific WP with guidance to run finalize-tasks.Proposed
FR-010Active planning prompts and templates (task-generation guidance, tasks README bootstrap, generic WP templates, mission-specific templates) do not emit lane: "planned" or lane-bearing history examples.Proposed
FR-011Active docs (README, command help, generated README text) describe status.events.jsonl as sole status authority, status.json as derived snapshot, and WP frontmatter as static definition only.Proposed
FR-012Old "frontmatter-only lane" explanations in docs are relabeled as historical/versioned context, not current guidance.Proposed
FR-013Active tests do not construct modern WPs with lane: in frontmatter except in explicit legacy/migration test coverage.Proposed
FR-014Migration-only code paths that read frontmatter lane remain functional for explicit migration commands.Proposed
FR-015Any parser or helper that reconstructs status from WP-local history is either deleted or demoted to migration-only.Proposed
FR-016Historical kitty-specs/* records are preserved unchanged. Active guidance does not cite them as examples of current behavior.Proposed
FR-017Operational metadata fields (agent, assignee, shell_pid, requirement_refs) remain in WP frontmatter unchanged. This cleanup does not remove non-status operational metadata.Proposed

Non-Functional Requirements

IDRequirementThreshold
NFR-001Runtime error messages for missing canonical state are actionable.Every hard-fail message names the missing file, the affected feature, and the exact command to run to fix it.
NFR-002Test coverage on new/modified code.90%+ line coverage on modified finalization, runtime reader, and template generation code.
NFR-003Type checking passes on all new and modified code.mypy --strict produces zero errors on changed files.
NFR-004No regression in existing features with canonical state.All features that already have status.events.jsonl continue to work identically after this change.

Constraints

IDConstraint
C-001Historical kitty-specs/* records are preserved unchanged. Do not mass-rewrite old feature records.
C-002Only the spec-kitty repo is in scope. spec-kitty-orchestrator override cleanup is a follow-up.
C-003Non-status operational metadata (agent, assignee, shell_pid, requirement_refs) remains unchanged in WP frontmatter.
C-004Explicit migration tools must still be able to ingest legacy frontmatter-lane artifacts. Migration-only code is preserved.
C-005No fallback logic. If canonical state is missing, fail — do not silently reconstruct from frontmatter.
C-006WP-local history remains allowed as human-readable non-authoritative notes, but must not encode lane state.

Success Criteria

IDCriterion
SC-001After finalize-tasks, every WP in a feature has canonical state in status.events.jsonl and a materialized status.json.
SC-002No active runtime command reads lane from WP frontmatter for status determination.
SC-003No active template or generation surface emits lane: in WP frontmatter or lane-bearing history entries.
SC-004Runtime commands hard-fail with actionable guidance when canonical state is missing.
SC-005Active docs and README consistently describe the 3.0 status model without referencing frontmatter-lane as current behavior.
SC-006All active tests construct WPs without lane: in frontmatter, except explicit migration/legacy test fixtures.
SC-007Features with existing canonical state (e.g., 059-saas-mediated-cli-tracker-reflow) work identically after this change.

Key Entities

EntityDescription
status.events.jsonlAppend-only event log per feature. Sole authority for WP lane state. Each line is a StatusEvent JSON object.
status.jsonDerived materialized snapshot produced by the reducer from status.events.jsonl. Read-only view used by dashboard and runtime queries.
WP FrontmatterYAML frontmatter in WP prompt files. After this cleanup: static definition fields + operational metadata only. No mutable status fields.
WP HistoryYAML history array and body activity notes in WP files. After this cleanup: lane-free records (timestamp, actor, action text). Non-authoritative.
finalize-tasksCLI command that validates WPs, parses dependencies, and (after this cleanup) seeds initial canonical status for newly generated WPs.
StatusEventPydantic model in specify_cli/status/models.py. Immutable event representing a lane transition.
Reducerspecify_cli/status/reducer.py. Deterministic function: events → snapshot. Same events always produce same state.

Dependencies

DependencyStatusImpact
Feature 034 (Status State Model Remediation)CompleteIntroduced the canonical status model this feature enforces everywhere.
Feature 059 (SaaS Tracker Reflow)CompleteMost recent feature sprint — validates that existing canonical state continues working.
Existing specify_cli/status/ packageAvailableemit.py, reducer.py, store.py, models.py, transitions.py — all reused, not rewritten.

Assumptions

#Assumption
A-001The specify_cli/status/ package (emit, reducer, store, models, transitions) is correct and stable. This feature uses it, does not redesign it.
A-002All active features created after Feature 034 already have status.events.jsonl. This cleanup primarily affects generation surfaces, templates, and runtime fallback paths.
A-003Historical kitty-specs/* records will never be migrated in bulk. They are inert artifacts preserved for git history.
A-004spec-kitty-orchestrator/.kittify/overrides cleanup is deferred to a follow-up.

Risks

RiskLikelihoodImpactMitigation
Breaking features that rely on frontmatter-lane fallbackLowMediumFeatures created after 034 already have canonical state. Hard-fail error directs users to finalize-tasks.
Template changes reintroducing lane fields laterMediumLowAdd grep-based regression test that scans active templates for lane: in frontmatter positions.
Tests that construct WPs with lane: are missedMediumMediumSystematic search for lane: in test fixtures; update all non-migration tests.

Out of Scope

  • Redesigning the canonical status model itself (Feature 034 scope)
  • Removing non-status operational metadata (agent, assignee, shell_pid) from frontmatter
  • Mass-rewriting historical kitty-specs records
  • spec-kitty-orchestrator override cleanup (follow-up)
  • Adding new status model features (new lanes, new event types)