// Package story defines the Epic and Story data types that sit above // internal/task's flat task tree in the planning hierarchy. This phase // (7a) is pure data model + CRUD: no orchestration reads or writes these // types yet. A later phase builds fan-out/orchestration logic (creating // Builder/Evaluator/Arbitration tasks, gating deploys, etc.) on top of what // is stored here. package story import ( "encoding/json" "time" ) // Epic is a large, loosely-scoped initiative that decomposes into one or // more Stories. Epics are not execution units — they carry no root_task_id // and are never dispatched. type Epic struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description,omitempty"` // Status is "OPEN" or "CLOSED". This phase does not validate transitions // — storage writes whatever status string it is given, the same trust // level as task.Project/UpdateProject. Status string `json:"status"` // DiscoverySource is "human" or "agent" — how the epic came to exist. DiscoverySource string `json:"discovery_source,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // Story is a shippable slice of work realized by a tree of internal/task // Tasks rooted at RootTaskID. EpicID and ProjectID are loose references // (plain strings, no FK enforcement) to epics.id / projects.id, matching // the codebase's existing tolerance for unmatched reference strings (e.g. // tasks.project). // // Status is one of DISCOVERY|FRAMING|BACKLOG|PRIORITIZED|IN_PROGRESS| // SHIPPABLE|DEPLOYED|VALIDATING|REVIEW_READY|NEEDS_FIX|DONE|CANCELLED, but // this phase enforces no state machine on it (unlike task.ValidTransition) // — a later phase adds that once there is an orchestrator to make // transitions meaningful. UpdateStory writes whatever status string it is // given. type Story struct { ID string `json:"id"` EpicID string `json:"epic_id,omitempty"` ProjectID string `json:"project_id,omitempty"` Name string `json:"name"` BranchName string `json:"branch_name,omitempty"` Status string `json:"status"` DiscoverySource string `json:"discovery_source,omitempty"` // Spec is the Planner's framing-pass output: product + arch context. // Freeform text, not JSON. Spec string `json:"spec,omitempty"` // AcceptanceCriteria is stored as acceptance_criteria_json; defaults to // an empty list, never null in API responses. AcceptanceCriteria []string `json:"acceptance_criteria"` // Validation is the freeform {type, steps, success_criteria} blob a // later phase's validation agent will consume (curl|tests|playwright| // gradle). Stored verbatim as validation_json; nil/omitted if unset. Validation json.RawMessage `json:"validation,omitempty"` // DeployConfig is optional, freeform JSON — only populated if a story // should deploy-gate. Stored verbatim as deploy_config; nil/omitted if // unset. DeployConfig json.RawMessage `json:"deploy_config,omitempty"` Priority string `json:"priority,omitempty"` // RootTaskID is the top-level task realizing this story (usually a // Planner-role task). Empty/unset means the story has no execution tree // yet — GET .../task-tree returns an empty tree, not an error, in that // case. RootTaskID string `json:"root_task_id,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` }