savepoint 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/.claude/settings.local.json +12 -1
  2. package/.golangci.yml +11 -0
  3. package/.savepoint/Design.md +37 -36
  4. package/.savepoint/{audit/v1.1/E02-cross-platform-compatibility/proposals.md → releases/v1.1/epics/E02-cross-platform-compatibility/E02-Audit.md} +48 -38
  5. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Audit.md +195 -0
  6. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Detail.md +14 -1
  7. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T006-forced-256-color-profile.md +3 -3
  8. package/.savepoint/{audit/v1.1/E04-epic-navigation/proposals.md → releases/v1.1/epics/E04-epic-navigation/E04-Audit.md} +65 -54
  9. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Audit.md +237 -0
  10. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Detail.md +25 -16
  11. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T001-update-agents-md.md +17 -6
  12. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T002-update-router-md.md +15 -5
  13. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T003-update-design-md.md +19 -5
  14. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T004-implement-m-hotkey.md +11 -1
  15. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T005-update-help-overlay.md +9 -6
  16. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T006-tests-and-quality-gates.md +29 -13
  17. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Audit.md +56 -0
  18. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Detail.md +63 -0
  19. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T005-proposals.md +44 -0
  20. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T007-apply-close.md +35 -0
  21. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T009-integration.md +40 -0
  22. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T010-audit-file-migration.md +45 -0
  23. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T011-model-tab-state.md +26 -0
  24. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T012-epic-audit-render.md +33 -0
  25. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T013-handle-tab-keys.md +34 -0
  26. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T014-tab-indicator.md +33 -0
  27. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Audit.md +336 -0
  28. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Detail.md +61 -0
  29. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T001-cli-entrypoint.md +37 -0
  30. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T002-target-validation.md +28 -0
  31. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T003-scaffold-writer.md +46 -0
  32. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T004-atomic-writes.md +27 -0
  33. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T005-magic-prompt.md +25 -0
  34. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T006-clipboard.md +26 -0
  35. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T007-integration-test.md +26 -0
  36. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Audit.md +333 -0
  37. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Detail.md +68 -0
  38. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T001-cli-entrypoint.md +26 -0
  39. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T002-non-tty-fallback.md +27 -0
  40. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T003-tui-app-shell.md +28 -0
  41. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T004-board-model.md +29 -0
  42. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T005-detail-pane.md +27 -0
  43. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T006-status-transitions.md +29 -0
  44. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T007-theme-fallbacks.md +29 -0
  45. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T008-integration-test.md +27 -0
  46. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Audit.md +207 -0
  47. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Detail.md +65 -0
  48. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T001-cli-entrypoint.md +24 -0
  49. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T002-config-router-validation.md +28 -0
  50. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T003-structure-checks.md +29 -0
  51. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T004-dependency-checks.md +27 -0
  52. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T005-audit-orphan-checks.md +28 -0
  53. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T006-quality-gates-report.md +31 -0
  54. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/E11-Detail.md +36 -0
  55. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T001-debug-logging.md +25 -0
  56. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T002-increase-debounce.md +21 -0
  57. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T003-error-handling.md +22 -0
  58. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T004-test-verify.md +29 -0
  59. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Audit.md +444 -0
  60. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Detail.md +45 -0
  61. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T001-default-phase.md +35 -0
  62. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T002-default-status.md +19 -0
  63. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T003-better-errors.md +29 -0
  64. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T004-validate-on-write.md +25 -0
  65. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T005-tests.md +37 -0
  66. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Audit.md +118 -0
  67. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Detail.md +73 -0
  68. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T001-safe-cleanup.md +66 -0
  69. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T002-bug-fixes.md +35 -0
  70. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T003-centralize-duplication.md +60 -0
  71. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T004-infrastructure.md +33 -0
  72. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T005-decompose-update.md +37 -0
  73. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T006-async-io.md +40 -0
  74. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T007-test-coverage.md +37 -0
  75. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Audit.md +267 -0
  76. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Detail.md +54 -0
  77. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T001-group-model.md +39 -0
  78. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T002-data-interfaces.md +42 -0
  79. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T003-discover-orphans.md +33 -0
  80. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T004-epic-panel-headings.md +35 -0
  81. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T005-shell-tokenization.md +27 -0
  82. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T006-unify-enums.md +29 -0
  83. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T007-testutil-package.md +28 -0
  84. package/.savepoint/releases/v1.1/epics/E15-hardening/E15-Detail.md +43 -0
  85. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T001-benchmarks.md +31 -0
  86. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T002-fuzz-targets.md +28 -0
  87. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T003-debug-flag.md +30 -0
  88. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T004-dist-checksums.md +27 -0
  89. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T005-windows-targets.md +28 -0
  90. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T006-abbreviation-splitting.md +26 -0
  91. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T007-root-test-allowlist.md +28 -0
  92. package/.savepoint/releases/v1.1/epics/_archived/T001-cli-entrypoint.md +25 -0
  93. package/.savepoint/releases/v1.1/epics/_archived/T002-quality-gates.md +27 -0
  94. package/.savepoint/releases/v1.1/epics/_archived/T003-snapshot.md +27 -0
  95. package/.savepoint/releases/v1.1/epics/_archived/T004-ai-reconcile.md +29 -0
  96. package/.savepoint/releases/v1.1/epics/_archived/T006-tui-review.md +31 -0
  97. package/.savepoint/releases/v1.1/epics/_archived/T008-skip-handling.md +34 -0
  98. package/.savepoint/releases/v1.1/v1.1-PRD.md +67 -7
  99. package/.savepoint/router.md +9 -16
  100. package/AGENTS.md +38 -23
  101. package/README.md +0 -1
  102. package/agent-skills/savepoint-audit/SKILL.md +86 -34
  103. package/agent-skills/savepoint-build-task/SKILL.md +7 -2
  104. package/agent-skills/savepoint-create-plan/SKILL.md +7 -2
  105. package/agent-skills/savepoint-create-task/SKILL.md +44 -31
  106. package/agent-skills/savepoint-draft-prd/SKILL.md +7 -2
  107. package/agent-skills/savepoint-system-design/SKILL.md +7 -2
  108. package/agent_skills_test.go +91 -0
  109. package/cmd/board.go +59 -0
  110. package/cmd/board_test.go +137 -0
  111. package/cmd/doctor.go +53 -0
  112. package/cmd/doctor_test.go +146 -0
  113. package/cmd/init.go +63 -0
  114. package/cmd/init_test.go +104 -0
  115. package/internal/board/board.go +40 -36
  116. package/internal/board/board_test.go +27 -82
  117. package/internal/board/card.go +43 -23
  118. package/internal/board/card_test.go +41 -5
  119. package/internal/board/column.go +44 -13
  120. package/internal/board/column_test.go +5 -2
  121. package/internal/board/detail.go +0 -47
  122. package/internal/board/epic_panel.go +118 -22
  123. package/internal/board/epic_panel_test.go +302 -17
  124. package/internal/board/help.go +1 -0
  125. package/internal/board/help_test.go +1 -0
  126. package/internal/board/integration_test.go +266 -0
  127. package/internal/board/interfaces.go +65 -0
  128. package/internal/board/interfaces_test.go +114 -0
  129. package/internal/board/io.go +93 -0
  130. package/internal/board/model.go +79 -118
  131. package/internal/board/plain.go +88 -0
  132. package/internal/board/plain_test.go +117 -0
  133. package/internal/board/release.go +1 -9
  134. package/internal/board/release_test.go +6 -6
  135. package/internal/board/status.go +4 -4
  136. package/internal/board/theme.go +24 -0
  137. package/internal/board/theme_test.go +31 -0
  138. package/internal/board/transitions.go +113 -88
  139. package/internal/board/transitions_test.go +164 -141
  140. package/internal/board/tui.go +32 -0
  141. package/internal/board/update.go +325 -215
  142. package/internal/board/update_test.go +299 -18
  143. package/internal/board/util.go +76 -0
  144. package/internal/board/view.go +31 -28
  145. package/internal/board/view_test.go +12 -2
  146. package/internal/board/watch.go +35 -5
  147. package/internal/buildtool/main.go +2 -10
  148. package/internal/buildtool/main_test.go +46 -0
  149. package/internal/data/config.go +17 -3
  150. package/internal/data/config_test.go +49 -0
  151. package/internal/data/discover.go +26 -0
  152. package/internal/data/discover_test.go +34 -10
  153. package/internal/data/errors.go +4 -0
  154. package/internal/data/lifecycle.go +13 -6
  155. package/internal/data/lifecycle_test.go +14 -11
  156. package/internal/data/parser.go +21 -6
  157. package/internal/data/parser_test.go +31 -7
  158. package/internal/data/task.go +0 -9
  159. package/internal/data/write.go +85 -11
  160. package/internal/data/write_test.go +167 -0
  161. package/internal/doctor/checks.go +567 -0
  162. package/internal/doctor/checks_test.go +716 -0
  163. package/internal/doctor/gates.go +193 -0
  164. package/internal/doctor/gates_test.go +166 -0
  165. package/internal/doctor/interfaces.go +64 -0
  166. package/internal/doctor/interfaces_test.go +104 -0
  167. package/internal/doctor/repairs.go +80 -0
  168. package/internal/doctor/repairs_test.go +81 -0
  169. package/internal/doctor/report.go +157 -0
  170. package/internal/doctor/report_test.go +89 -0
  171. package/internal/init/clipboard.go +146 -0
  172. package/internal/init/clipboard_test.go +74 -0
  173. package/internal/init/install.go +16 -0
  174. package/internal/init/integration_test.go +197 -0
  175. package/internal/init/prompt.go +14 -0
  176. package/internal/init/prompt_test.go +77 -0
  177. package/internal/init/scaffold.go +59 -0
  178. package/internal/init/scaffold_test.go +179 -0
  179. package/internal/init/template_freshness_test.go +56 -0
  180. package/internal/init/validate.go +85 -0
  181. package/internal/init/validate_test.go +141 -0
  182. package/internal/init/write.go +73 -0
  183. package/internal/init/write_test.go +91 -0
  184. package/internal/styles/styles_test.go +133 -0
  185. package/internal/testutil/fixture.go +113 -0
  186. package/internal/testutil/fs.go +26 -0
  187. package/main.go +101 -4
  188. package/package.json +2 -2
  189. package/project-audit/audit_report_glm_5.1.md +411 -0
  190. package/project-audit/audit_report_opus_4.6 +406 -0
  191. package/project-audit/consolidated-audit-report.md +456 -0
  192. package/savepoint +0 -0
  193. package/templates/project/.savepoint/Design.md +2 -2
  194. package/templates/project/.savepoint/router.md +10 -10
  195. package/templates/project/AGENTS.md +33 -21
  196. package/templates/project/agent-skills/savepoint-audit/SKILL.md +87 -0
  197. package/templates/project/agent-skills/savepoint-build-task/SKILL.md +44 -0
  198. package/templates/project/agent-skills/savepoint-create-plan/SKILL.md +33 -0
  199. package/templates/project/agent-skills/savepoint-create-task/SKILL.md +44 -0
  200. package/templates/project/agent-skills/savepoint-draft-prd/SKILL.md +37 -0
  201. package/templates/project/agent-skills/savepoint-system-design/SKILL.md +38 -0
  202. package/templates/prompts/audit-reconciliation.prompt.md +33 -28
  203. package/templates/prompts/design.prompt.md +3 -1
  204. package/.savepoint/audit/v1/E01/proposals.md +0 -168
  205. package/.savepoint/audit/v1/E01/snapshot.md +0 -78
  206. package/.savepoint/audit/v1/E01-go-setup/proposals.md +0 -166
  207. package/.savepoint/audit/v1/E01-go-setup/snapshot.md +0 -71
  208. package/.savepoint/audit/v1/E01-scaffolding/proposals/AGENTS.md +0 -66
  209. package/.savepoint/audit/v1/E01-scaffolding/proposals/Design.md +0 -210
  210. package/.savepoint/audit/v1/E01-scaffolding/proposals/epic-Design.md +0 -117
  211. package/.savepoint/audit/v1/E01-scaffolding/proposals/quality-review.md +0 -101
  212. package/.savepoint/audit/v1/E01-scaffolding/snapshot.md +0 -54
  213. package/.savepoint/audit/v1/E02-data-model/snapshot.md +0 -128
  214. package/.savepoint/audit/v1/E02-data-readers/proposals.md +0 -123
  215. package/.savepoint/audit/v1/E02-data-readers/snapshot.md +0 -54
  216. package/.savepoint/audit/v1/E03-board-tui-core/proposals.md +0 -146
  217. package/.savepoint/audit/v1/E03-board-tui-core/snapshot.md +0 -57
  218. package/.savepoint/audit/v1/E03-cli-foundation/snapshot.md +0 -106
  219. package/.savepoint/audit/v1/E04-board-components/proposals.md +0 -118
  220. package/.savepoint/audit/v1/E04-board-components/snapshot.md +0 -77
  221. package/.savepoint/audit/v1/E04-templates-and-prompts/snapshot.md +0 -115
  222. package/.savepoint/audit/v1/E05-init-command/snapshot.md +0 -125
  223. package/.savepoint/audit/v1/E05-phase-transitions/proposals.md +0 -83
  224. package/.savepoint/audit/v1/E05-phase-transitions/snapshot.md +0 -36
  225. package/.savepoint/audit/v1/E06-atari-noir-layout/proposals.md +0 -130
  226. package/.savepoint/audit/v1/E06-atari-noir-layout/snapshot.md +0 -84
  227. package/.savepoint/audit/v1/E06-tui-board/snapshot.md +0 -64
  228. package/.savepoint/audit/v1/E07-audit-pipeline/snapshot.md +0 -165
  229. package/.savepoint/audit/v1/E08-board-workflow-cleanup/snapshot.md +0 -65
  230. package/.savepoint/audit/v1.1/E02-cross-platform-compatibility/snapshot.md +0 -41
  231. package/.savepoint/audit/v1.1/E04-epic-navigation/snapshot.md +0 -48
  232. package/ink-cli-ui-design.zip +0 -0
  233. package/savepoint.exe +0 -0
@@ -0,0 +1,444 @@
1
+ ---
2
+ type: audit-findings
3
+ audited: 2026-05-03
4
+ ---
5
+ # Audit Findings: E12 Task File Validation & Auto-Fix
6
+
7
+ ## Main Findings
8
+
9
+ E12 is closed. Parser-side defaults are in place: missing task status parses as `planned`, missing phase/stage on parsed `in_progress` tasks becomes `build`, and invalid status/phase messages include actionable hints.
10
+
11
+ The write-time lifecycle gap found during audit was fixed. `ValidateTaskLifecycle` now receives a task pointer, so defaulting an `in_progress` task to `StageBuild` persists for callers such as `WriteTaskStatus`. Regression coverage now verifies both lifecycle defaulting and persisted `phase: build` writes.
12
+
13
+ The E12 task files now include the required `## Context Files` sections. Architecture and agent documentation were reconciled to describe `internal/data` lifecycle validation/defaulting.
14
+
15
+ Verification after applying proposals: `go build ./...` passed and `go test ./...` passed.
16
+
17
+ ## Code Style Review
18
+
19
+ - [x] One job per file
20
+ - [x] One-sentence functions
21
+ - [x] Test branches
22
+ - [x] Types are documentation
23
+ - [x] Build, don't speculate
24
+ - [x] Errors at boundaries
25
+ - [x] One source of truth
26
+ - [x] Comments explain WHY
27
+ - [x] Content in data files
28
+ - [x] Small diffs
29
+
30
+ ## Proposed Changes
31
+
32
+ ### Target File
33
+ internal/data/lifecycle.go
34
+
35
+ ### Replace
36
+ ```go
37
+ func ValidateTaskLifecycle(task Task) error {
38
+ if !IsCanonicalColumn(task.Column) {
39
+ return fmt.Errorf("invalid status %q: use planned, in_progress, or done. Add 'status: planned' or 'status: in_progress' to task frontmatter", task.Column)
40
+ }
41
+
42
+ if task.Column == ColumnInProgress {
43
+ if task.Stage == "" {
44
+ task.Stage = StageBuild
45
+ return nil
46
+ }
47
+ if !IsCanonicalStage(task.Stage) {
48
+ return fmt.Errorf("invalid phase %q: use build, test, or audit. Add 'phase: build' to task frontmatter", task.Stage)
49
+ }
50
+ return nil
51
+ }
52
+
53
+ if task.Stage != "" {
54
+ return fmt.Errorf("phase field %q is only valid when status is in_progress. Remove 'phase' or change status to in_progress", task.Stage)
55
+ }
56
+
57
+ return nil
58
+ }
59
+ ```
60
+
61
+ ### With
62
+ ```go
63
+ func ValidateTaskLifecycle(task *Task) error {
64
+ if !IsCanonicalColumn(task.Column) {
65
+ return fmt.Errorf("invalid status %q: use planned, in_progress, or done. Add 'status: planned' or 'status: in_progress' to task frontmatter", task.Column)
66
+ }
67
+
68
+ if task.Column == ColumnInProgress {
69
+ if task.Stage == "" {
70
+ task.Stage = StageBuild
71
+ return nil
72
+ }
73
+ if !IsCanonicalStage(task.Stage) {
74
+ return fmt.Errorf("invalid phase %q: use build, test, or audit. Add 'phase: build' to task frontmatter", task.Stage)
75
+ }
76
+ return nil
77
+ }
78
+
79
+ if task.Stage != "" {
80
+ return fmt.Errorf("phase field %q is only valid when status is in_progress. Remove 'phase' or change status to in_progress", task.Stage)
81
+ }
82
+
83
+ return nil
84
+ }
85
+ ```
86
+
87
+ ### Target File
88
+ internal/data/write.go
89
+
90
+ ### Replace
91
+ ```go
92
+ if err := ValidateTaskLifecycle(*task); err != nil {
93
+ return err
94
+ }
95
+ ```
96
+
97
+ ### With
98
+ ```go
99
+ if err := ValidateTaskLifecycle(task); err != nil {
100
+ return err
101
+ }
102
+ ```
103
+
104
+ ### Target File
105
+ internal/data/lifecycle_test.go
106
+
107
+ ### Replace
108
+ ```go
109
+ func TestValidateTaskLifecycle_allowsPlannedWithoutPhase(t *testing.T) {
110
+ task := Task{Column: ColumnPlanned}
111
+ if err := ValidateTaskLifecycle(task); err != nil {
112
+ t.Fatalf("ValidateTaskLifecycle() error = %v", err)
113
+ }
114
+ }
115
+
116
+ func TestValidateTaskLifecycle_allowsInProgressWithPhase(t *testing.T) {
117
+ task := Task{Column: ColumnInProgress, Stage: StageAudit}
118
+ if err := ValidateTaskLifecycle(task); err != nil {
119
+ t.Fatalf("ValidateTaskLifecycle() error = %v", err)
120
+ }
121
+ }
122
+
123
+ func TestValidateTaskLifecycle_rejectsUnknownStatus(t *testing.T) {
124
+ task := Task{Column: "review"}
125
+ if err := ValidateTaskLifecycle(task); err == nil {
126
+ t.Fatal("ValidateTaskLifecycle() expected unknown status error")
127
+ }
128
+ }
129
+
130
+ func TestValidateTaskLifecycle_rejectsPhaseOutsideInProgress(t *testing.T) {
131
+ task := Task{Column: ColumnPlanned, Stage: StageBuild}
132
+ if err := ValidateTaskLifecycle(task); err == nil {
133
+ t.Fatal("ValidateTaskLifecycle() expected phase/status error")
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### With
139
+ ```go
140
+ func TestValidateTaskLifecycle_allowsPlannedWithoutPhase(t *testing.T) {
141
+ task := Task{Column: ColumnPlanned}
142
+ if err := ValidateTaskLifecycle(&task); err != nil {
143
+ t.Fatalf("ValidateTaskLifecycle() error = %v", err)
144
+ }
145
+ }
146
+
147
+ func TestValidateTaskLifecycle_defaultsInProgressWithoutPhase(t *testing.T) {
148
+ task := Task{Column: ColumnInProgress}
149
+ if err := ValidateTaskLifecycle(&task); err != nil {
150
+ t.Fatalf("ValidateTaskLifecycle() error = %v", err)
151
+ }
152
+ if task.Stage != StageBuild {
153
+ t.Fatalf("Task.Stage = %q, want %q", task.Stage, StageBuild)
154
+ }
155
+ }
156
+
157
+ func TestValidateTaskLifecycle_allowsInProgressWithPhase(t *testing.T) {
158
+ task := Task{Column: ColumnInProgress, Stage: StageAudit}
159
+ if err := ValidateTaskLifecycle(&task); err != nil {
160
+ t.Fatalf("ValidateTaskLifecycle() error = %v", err)
161
+ }
162
+ }
163
+
164
+ func TestValidateTaskLifecycle_rejectsUnknownStatus(t *testing.T) {
165
+ task := Task{Column: "review"}
166
+ if err := ValidateTaskLifecycle(&task); err == nil {
167
+ t.Fatal("ValidateTaskLifecycle() expected unknown status error")
168
+ }
169
+ }
170
+
171
+ func TestValidateTaskLifecycle_rejectsPhaseOutsideInProgress(t *testing.T) {
172
+ task := Task{Column: ColumnPlanned, Stage: StageBuild}
173
+ if err := ValidateTaskLifecycle(&task); err == nil {
174
+ t.Fatal("ValidateTaskLifecycle() expected phase/status error")
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### Target File
180
+ internal/data/write_test.go
181
+
182
+ ### Replace
183
+ ```go
184
+ func TestWriteTaskStatus_addsPhaseWhenStagePresent(t *testing.T) {
185
+ dir := t.TempDir()
186
+ path := filepath.Join(dir, "task.md")
187
+ content := `---
188
+ id: E01/T005
189
+ status: in_progress
190
+ objective: "No phase yet"
191
+ ---`
192
+
193
+ if err := os.WriteFile(path, []byte(content), 0644); err != nil {
194
+ t.Fatal(err)
195
+ }
196
+
197
+ fi, _ := os.Stat(path)
198
+
199
+ task := &Task{
200
+ ID: "E01/T005",
201
+ Column: ColumnInProgress,
202
+ Stage: StageAudit,
203
+ }
204
+
205
+ if err := WriteTaskStatus(path, task, fi.ModTime()); err != nil {
206
+ t.Fatalf("WriteTaskStatus() error = %v", err)
207
+ }
208
+
209
+ result, _ := os.ReadFile(path)
210
+
211
+ if !strings.Contains(string(result), "phase: audit") {
212
+ t.Error("phase field should be added when stage is set")
213
+ }
214
+ }
215
+ ```
216
+
217
+ ### With
218
+ ```go
219
+ func TestWriteTaskStatus_addsPhaseWhenStagePresent(t *testing.T) {
220
+ dir := t.TempDir()
221
+ path := filepath.Join(dir, "task.md")
222
+ content := `---
223
+ id: E01/T005
224
+ status: in_progress
225
+ objective: "No phase yet"
226
+ ---`
227
+
228
+ if err := os.WriteFile(path, []byte(content), 0644); err != nil {
229
+ t.Fatal(err)
230
+ }
231
+
232
+ fi, _ := os.Stat(path)
233
+
234
+ task := &Task{
235
+ ID: "E01/T005",
236
+ Column: ColumnInProgress,
237
+ Stage: StageAudit,
238
+ }
239
+
240
+ if err := WriteTaskStatus(path, task, fi.ModTime()); err != nil {
241
+ t.Fatalf("WriteTaskStatus() error = %v", err)
242
+ }
243
+
244
+ result, _ := os.ReadFile(path)
245
+
246
+ if !strings.Contains(string(result), "phase: audit") {
247
+ t.Error("phase field should be added when stage is set")
248
+ }
249
+ }
250
+
251
+ func TestWriteTaskStatus_defaultsInProgressPhaseWhenStageMissing(t *testing.T) {
252
+ dir := t.TempDir()
253
+ path := filepath.Join(dir, "task.md")
254
+ content := `---
255
+ id: E01/T010
256
+ status: planned
257
+ objective: "No phase yet"
258
+ ---`
259
+
260
+ if err := os.WriteFile(path, []byte(content), 0644); err != nil {
261
+ t.Fatal(err)
262
+ }
263
+
264
+ fi, _ := os.Stat(path)
265
+
266
+ task := &Task{
267
+ ID: "E01/T010",
268
+ Column: ColumnInProgress,
269
+ }
270
+
271
+ if err := WriteTaskStatus(path, task, fi.ModTime()); err != nil {
272
+ t.Fatalf("WriteTaskStatus() error = %v", err)
273
+ }
274
+
275
+ result, _ := os.ReadFile(path)
276
+
277
+ if !strings.Contains(string(result), "phase: build") {
278
+ t.Error("phase field should default to build for in_progress writes")
279
+ }
280
+ }
281
+ ```
282
+
283
+ ### Target File
284
+ .savepoint/Design.md
285
+
286
+ ### Replace
287
+ ```md
288
+ - **Go data-reader boundary:** established in epic `E02-data-readers` (2026-05-01). `internal/data` owns Savepoint file parsing and discovery for the Go implementation: task frontmatter models, markdown YAML extraction, router state parsing, config theme defaults, release/epic/task directory listing, and boundary error sentinels.
289
+ ```
290
+
291
+ ### With
292
+ ```md
293
+ - **Go data-reader boundary:** established in epic `E02-data-readers` (2026-05-01). `internal/data` owns Savepoint file parsing and discovery for the Go implementation: task frontmatter models, markdown YAML extraction, router state parsing, config theme defaults, release/epic/task directory listing, task lifecycle validation/defaulting, write-time status validation, and boundary error sentinels.
294
+ ```
295
+
296
+ ### Target File
297
+ AGENTS.md
298
+
299
+ ### Replace
300
+ ```md
301
+ | `internal/data/` | Task/router models, frontmatter parsing, discovery |
302
+ ```
303
+
304
+ ### With
305
+ ```md
306
+ | `internal/data/` | Task/router models, frontmatter parsing, lifecycle validation/defaulting, discovery |
307
+ ```
308
+
309
+ ### Target File
310
+ .savepoint/releases/v1.1/epics/E12-validation-fix/E12-Detail.md
311
+
312
+ ### Replace
313
+ ```md
314
+ **Out of scope:**
315
+ - New UI features
316
+ - New commands
317
+ ```
318
+
319
+ ### With
320
+ ```md
321
+ **Out of scope:**
322
+ - New UI features
323
+ - New commands
324
+
325
+ ## Implemented as
326
+
327
+ - Parser-side defaults live in `internal/data/parser.go`: empty status/column normalizes to `planned`, and parsed `in_progress` tasks without phase/stage default to `build`.
328
+ - Lifecycle validation and user-facing hints live in `internal/data/lifecycle.go`.
329
+ - Status writes validate lifecycle rules through `internal/data/write.go`; audit follow-up must persist the default `phase: build` when callers write `in_progress` with no stage.
330
+ - Regression coverage lives in `internal/data/parser_test.go`, `internal/data/lifecycle_test.go`, and `internal/data/write_test.go`.
331
+ ```
332
+
333
+ ### Target File
334
+ .savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T001-default-phase.md
335
+
336
+ ### Replace
337
+ ```md
338
+ # T001: Default Phase to Build
339
+
340
+ ## Acceptance Criteria
341
+ ```
342
+
343
+ ### With
344
+ ```md
345
+ # T001: Default Phase to Build
346
+
347
+ ## Context Files
348
+
349
+ - `internal/data/parser.go`
350
+ - `internal/data/lifecycle.go`
351
+ - `internal/data/parser_test.go`
352
+
353
+ ## Acceptance Criteria
354
+ ```
355
+
356
+ ### Target File
357
+ .savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T002-default-status.md
358
+
359
+ ### Replace
360
+ ```md
361
+ # T002: Default Status to Planned
362
+
363
+ ## Acceptance Criteria
364
+ ```
365
+
366
+ ### With
367
+ ```md
368
+ # T002: Default Status to Planned
369
+
370
+ ## Context Files
371
+
372
+ - `internal/data/parser.go`
373
+ - `internal/data/parser_test.go`
374
+
375
+ ## Acceptance Criteria
376
+ ```
377
+
378
+ ### Target File
379
+ .savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T003-better-errors.md
380
+
381
+ ### Replace
382
+ ```md
383
+ # T003: Better Error Messages
384
+
385
+ ## Acceptance Criteria
386
+ ```
387
+
388
+ ### With
389
+ ```md
390
+ # T003: Better Error Messages
391
+
392
+ ## Context Files
393
+
394
+ - `internal/data/lifecycle.go`
395
+ - `internal/data/lifecycle_test.go`
396
+
397
+ ## Acceptance Criteria
398
+ ```
399
+
400
+ ### Target File
401
+ .savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T004-validate-on-write.md
402
+
403
+ ### Replace
404
+ ```md
405
+ # T004: Validate On Write
406
+
407
+ ## Acceptance Criteria
408
+ ```
409
+
410
+ ### With
411
+ ```md
412
+ # T004: Validate On Write
413
+
414
+ ## Context Files
415
+
416
+ - `internal/data/write.go`
417
+ - `internal/data/write_test.go`
418
+ - `internal/data/lifecycle.go`
419
+
420
+ ## Acceptance Criteria
421
+ ```
422
+
423
+ ### Target File
424
+ .savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T005-tests.md
425
+
426
+ ### Replace
427
+ ```md
428
+ # T005: Tests
429
+
430
+ ## Acceptance Criteria
431
+ ```
432
+
433
+ ### With
434
+ ```md
435
+ # T005: Tests
436
+
437
+ ## Context Files
438
+
439
+ - `internal/data/parser_test.go`
440
+ - `internal/data/lifecycle_test.go`
441
+ - `internal/data/write_test.go`
442
+
443
+ ## Acceptance Criteria
444
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ type: epic-design
3
+ status: audited
4
+ ---
5
+
6
+ # E12: Task File Validation & Auto-Fix
7
+
8
+ ## Purpose
9
+
10
+ Fix task file parsing to provide helpful defaults and clear error messages when validation fails. Currently tasks fail with cryptic errors like `"invalid in_progress phase "": use build, test, or audit"`.
11
+
12
+ ## What this epic adds
13
+
14
+ - Default `phase: build` when status=in_progress but phase missing
15
+ - Default `status: planned` when both status/column missing
16
+ - Better error hints with suggested fixes
17
+ - Validate on write with helpful messages
18
+
19
+ ## Components
20
+
21
+ | Module | Purpose |
22
+ |--------|---------|
23
+ | `internal/data/parser.go` | Default phase to "build" in firstStage() |
24
+ | `internal/data/parser.go` | Default status to "planned" in normalizeColumn() |
25
+ | `internal/data/lifecycle.go` | Better error messages with hints |
26
+ | `internal/data/write.go` | Validate on write |
27
+
28
+ ## Boundaries
29
+
30
+ **In scope:**
31
+ - Default phase for in_progress tasks
32
+ - Default status for tasks
33
+ - Better error messages
34
+ - Write-time validation
35
+
36
+ **Out of scope:**
37
+ - New UI features
38
+ - New commands
39
+
40
+ ## Implemented as
41
+
42
+ - Parser-side defaults live in `internal/data/parser.go`: empty status/column normalizes to `planned`, and parsed `in_progress` tasks without phase/stage default to `build`.
43
+ - Lifecycle validation and user-facing hints live in `internal/data/lifecycle.go`.
44
+ - Status writes validate lifecycle rules through `internal/data/write.go` and persist the default `phase: build` when callers write `in_progress` with no stage.
45
+ - Regression coverage lives in `internal/data/parser_test.go`, `internal/data/lifecycle_test.go`, and `internal/data/write_test.go`.
@@ -0,0 +1,35 @@
1
+ ---
2
+ id: E12-validation-fix/T001-default-phase
3
+ status: done
4
+ objective: Default phase to build when status=in_progress but phase missing
5
+ depends_on: []
6
+ ---
7
+
8
+ # T001: Default Phase to Build
9
+
10
+ ## Context Files
11
+
12
+ - `internal/data/parser.go`
13
+ - `internal/data/lifecycle.go`
14
+ - `internal/data/parser_test.go`
15
+
16
+ ## Acceptance Criteria
17
+
18
+ - [x] firstStage() returns "build" when both stage and phase are empty
19
+ - [x] Tasks without phase field parse successfully
20
+ - [x] Make build passes
21
+ - [x] go test ./... passes
22
+
23
+ ## Implementation Plan
24
+
25
+ - [x] Set default at parse time after validation:
26
+ - In parser.go: ParseTaskFile() line 60-63
27
+ - After validation: `if task.Column == in_progress && task.Stage == "" { task.Stage = StageBuild }`
28
+ - [x] Run `make build` to verify change
29
+ - [x] Run `go test ./...` all pass
30
+
31
+ Notes:
32
+ - Default set at parsing time, not validation time
33
+ - Works with both planned and done tasks (phase ignored)
34
+ - Better error messages in lifecycle.go already implemented
35
+ - Tests added for new behavior
@@ -0,0 +1,19 @@
1
+ ---
2
+ id: E12-validation-fix/T002-default-status
3
+ status: done
4
+ objective: Default status to planned when both status and column missing
5
+ depends_on:
6
+ - E12-validation-fix/T001-default-phase
7
+ ---
8
+
9
+ # T002: Default Status to Planned
10
+
11
+ ## Context Files
12
+
13
+ - `internal/data/parser.go`
14
+ - `internal/data/parser_test.go`
15
+
16
+ ## Acceptance Criteria
17
+
18
+ - [x] Already implemented in normalizeColumn() - returns ColumnPlanned for empty
19
+ - [x] go test ./... passes
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: E12-validation-fix/T003-better-errors
3
+ status: done
4
+ objective: Improve error messages with hints for common issues
5
+ depends_on:
6
+ - E12-validation-fix/T001-default-phase
7
+ - E12-validation-fix/T002-default-status
8
+ ---
9
+
10
+ # T003: Better Error Messages
11
+
12
+ ## Context Files
13
+
14
+ - `internal/data/lifecycle.go`
15
+ - `internal/data/lifecycle_test.go`
16
+
17
+ ## Acceptance Criteria
18
+
19
+ - [x] Error messages include suggested fix
20
+ - [x] Show which field is problematic with context
21
+ - [x] go test ./... passes
22
+
23
+ ## Implementation Plan
24
+
25
+ - [x] Improved errors in lifecycle.go (lines 7, 16, 22)
26
+ - Examples of better messages:
27
+ - `invalid status %q: use planned, in_progress, or done. Add 'status: planned'...`
28
+ - `invalid phase %q: use build, test, or audit. Add 'phase: build'...`
29
+ - [x] Tests pass
@@ -0,0 +1,25 @@
1
+ ---
2
+ id: E12-validation-fix/T004-validate-on-write
3
+ status: done
4
+ objective: Add validation when writing task files
5
+ depends_on:
6
+ - E12-validation-fix/T003-better-errors
7
+ ---
8
+
9
+ # T004: Validate On Write
10
+
11
+ ## Context Files
12
+
13
+ - `internal/data/write.go`
14
+ - `internal/data/write_test.go`
15
+ - `internal/data/lifecycle.go`
16
+
17
+ ## Acceptance Criteria
18
+
19
+ - [x] Already validated in write path via WriteTaskStatus
20
+ - [x] go test ./... passes
21
+
22
+ ## Implementation Plan
23
+
24
+ - [x] Validation already runs via ParseTaskFile in write.go
25
+ - [x] Tests pass
@@ -0,0 +1,37 @@
1
+ ---
2
+ id: E12-validation-fix/T005-tests
3
+ status: done
4
+ objective: Verify all validation scenarios work correctly
5
+ depends_on:
6
+ - E12-validation-fix/T001-default-phase
7
+ - E12-validation-fix/T002-default-status
8
+ - E12-validation-fix/T003-better-errors
9
+ - E12-validation-fix/T004-validate-on-write
10
+ ---
11
+
12
+ # T005: Tests
13
+
14
+ ## Context Files
15
+
16
+ - `internal/data/parser_test.go`
17
+ - `internal/data/lifecycle_test.go`
18
+ - `internal/data/write_test.go`
19
+
20
+ ## Acceptance Criteria
21
+
22
+ - [x] All new defaults work in tests
23
+ - [x] Error messages tested
24
+ - [x] go test ./... passes
25
+
26
+ ## Implementation Plan
27
+
28
+ - [x] Run `go test ./...` - all pass
29
+ - [x] Updated lifecycle tests for new behavior:
30
+ - TestValidateTaskLifecycle_allowsPlannedWithoutPhase ✓
31
+ - TestValidateTaskLifecycle_allowsInProgressWithPhase ✓
32
+ - TestValidateTaskLifecycle_rejectsUnknownStatus ✓
33
+ - TestValidateTaskLifecycle_rejectsPhaseOutsideInProgress ✓
34
+ - [x] Updated parser tests:
35
+ - TestParseTaskFile_includesDefaultBuildForInProgress ✓
36
+ - TestParseTaskFile_allowsPhaseOutsideInProgress ✓
37
+ - [x] All other existing tests pass