savepoint 1.0.2 → 1.0.4

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 (242) hide show
  1. package/.claude/settings.local.json +12 -1
  2. package/.github/workflows/ci.yml +20 -0
  3. package/.golangci.yml +11 -0
  4. package/.savepoint/Design.md +40 -38
  5. package/.savepoint/{audit/v1.1/E02-cross-platform-compatibility/proposals.md → releases/v1.1/epics/E02-cross-platform-compatibility/E02-Audit.md} +48 -38
  6. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Audit.md +195 -0
  7. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Detail.md +14 -1
  8. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T006-forced-256-color-profile.md +3 -3
  9. package/.savepoint/{audit/v1.1/E04-epic-navigation/proposals.md → releases/v1.1/epics/E04-epic-navigation/E04-Audit.md} +65 -54
  10. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Audit.md +237 -0
  11. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Detail.md +25 -16
  12. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T001-update-agents-md.md +17 -6
  13. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T002-update-router-md.md +15 -5
  14. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T003-update-design-md.md +19 -5
  15. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T004-implement-m-hotkey.md +11 -1
  16. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T005-update-help-overlay.md +9 -6
  17. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T006-tests-and-quality-gates.md +29 -13
  18. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Audit.md +56 -0
  19. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Detail.md +63 -0
  20. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T005-proposals.md +44 -0
  21. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T007-apply-close.md +35 -0
  22. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T009-integration.md +40 -0
  23. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T010-audit-file-migration.md +45 -0
  24. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T011-model-tab-state.md +26 -0
  25. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T012-epic-audit-render.md +33 -0
  26. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T013-handle-tab-keys.md +34 -0
  27. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T014-tab-indicator.md +33 -0
  28. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Audit.md +336 -0
  29. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Detail.md +61 -0
  30. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T001-cli-entrypoint.md +37 -0
  31. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T002-target-validation.md +28 -0
  32. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T003-scaffold-writer.md +46 -0
  33. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T004-atomic-writes.md +27 -0
  34. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T005-magic-prompt.md +25 -0
  35. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T006-clipboard.md +26 -0
  36. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T007-integration-test.md +26 -0
  37. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Audit.md +333 -0
  38. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Detail.md +68 -0
  39. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T001-cli-entrypoint.md +26 -0
  40. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T002-non-tty-fallback.md +27 -0
  41. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T003-tui-app-shell.md +28 -0
  42. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T004-board-model.md +29 -0
  43. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T005-detail-pane.md +27 -0
  44. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T006-status-transitions.md +29 -0
  45. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T007-theme-fallbacks.md +29 -0
  46. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T008-integration-test.md +27 -0
  47. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Audit.md +207 -0
  48. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Detail.md +65 -0
  49. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T001-cli-entrypoint.md +24 -0
  50. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T002-config-router-validation.md +28 -0
  51. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T003-structure-checks.md +29 -0
  52. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T004-dependency-checks.md +27 -0
  53. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T005-audit-orphan-checks.md +28 -0
  54. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T006-quality-gates-report.md +31 -0
  55. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/E11-Detail.md +36 -0
  56. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T001-debug-logging.md +25 -0
  57. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T002-increase-debounce.md +21 -0
  58. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T003-error-handling.md +22 -0
  59. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T004-test-verify.md +29 -0
  60. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Audit.md +444 -0
  61. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Detail.md +45 -0
  62. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T001-default-phase.md +35 -0
  63. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T002-default-status.md +19 -0
  64. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T003-better-errors.md +29 -0
  65. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T004-validate-on-write.md +25 -0
  66. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T005-tests.md +37 -0
  67. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Audit.md +118 -0
  68. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Detail.md +73 -0
  69. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T001-safe-cleanup.md +66 -0
  70. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T002-bug-fixes.md +35 -0
  71. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T003-centralize-duplication.md +60 -0
  72. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T004-infrastructure.md +33 -0
  73. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T005-decompose-update.md +37 -0
  74. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T006-async-io.md +40 -0
  75. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T007-test-coverage.md +37 -0
  76. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Audit.md +267 -0
  77. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Detail.md +54 -0
  78. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T001-group-model.md +39 -0
  79. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T002-data-interfaces.md +42 -0
  80. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T003-discover-orphans.md +33 -0
  81. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T004-epic-panel-headings.md +35 -0
  82. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T005-shell-tokenization.md +27 -0
  83. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T006-unify-enums.md +29 -0
  84. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T007-testutil-package.md +28 -0
  85. package/.savepoint/releases/v1.1/epics/E15-hardening/E15-Audit.md +272 -0
  86. package/.savepoint/releases/v1.1/epics/E15-hardening/E15-Detail.md +60 -0
  87. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T001-benchmarks.md +31 -0
  88. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T002-fuzz-targets.md +34 -0
  89. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T003-debug-flag.md +30 -0
  90. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T004-dist-checksums.md +27 -0
  91. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T005-windows-targets.md +28 -0
  92. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T006-abbreviation-splitting.md +26 -0
  93. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T007-root-test-allowlist.md +33 -0
  94. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T008-ci-and-release-automation.md +46 -0
  95. package/.savepoint/releases/v1.1/epics/_archived/T001-cli-entrypoint.md +25 -0
  96. package/.savepoint/releases/v1.1/epics/_archived/T002-quality-gates.md +27 -0
  97. package/.savepoint/releases/v1.1/epics/_archived/T003-snapshot.md +27 -0
  98. package/.savepoint/releases/v1.1/epics/_archived/T004-ai-reconcile.md +29 -0
  99. package/.savepoint/releases/v1.1/epics/_archived/T006-tui-review.md +31 -0
  100. package/.savepoint/releases/v1.1/epics/_archived/T008-skip-handling.md +34 -0
  101. package/.savepoint/releases/v1.1/v1.1-PRD.md +67 -7
  102. package/.savepoint/router.md +10 -17
  103. package/AGENTS.md +39 -24
  104. package/Makefile +3 -1
  105. package/README.md +0 -1
  106. package/agent-skills/savepoint-audit/SKILL.md +86 -34
  107. package/agent-skills/savepoint-build-task/SKILL.md +7 -2
  108. package/agent-skills/savepoint-create-plan/SKILL.md +7 -2
  109. package/agent-skills/savepoint-create-task/SKILL.md +44 -31
  110. package/agent-skills/savepoint-draft-prd/SKILL.md +7 -2
  111. package/agent-skills/savepoint-system-design/SKILL.md +7 -2
  112. package/agent_skills_test.go +91 -0
  113. package/cmd/board.go +59 -0
  114. package/cmd/board_test.go +137 -0
  115. package/cmd/doctor.go +53 -0
  116. package/cmd/doctor_test.go +146 -0
  117. package/cmd/init.go +63 -0
  118. package/cmd/init_test.go +104 -0
  119. package/internal/board/board.go +44 -36
  120. package/internal/board/board_test.go +27 -82
  121. package/internal/board/card.go +43 -23
  122. package/internal/board/card_test.go +74 -5
  123. package/internal/board/column.go +75 -15
  124. package/internal/board/column_test.go +76 -2
  125. package/internal/board/debug.go +26 -0
  126. package/internal/board/debug_test.go +108 -0
  127. package/internal/board/detail.go +33 -47
  128. package/internal/board/detail_test.go +48 -0
  129. package/internal/board/epic_panel.go +120 -22
  130. package/internal/board/epic_panel_test.go +302 -17
  131. package/internal/board/help.go +1 -0
  132. package/internal/board/help_test.go +1 -0
  133. package/internal/board/integration_test.go +266 -0
  134. package/internal/board/interfaces.go +65 -0
  135. package/internal/board/interfaces_test.go +114 -0
  136. package/internal/board/io.go +93 -0
  137. package/internal/board/model.go +79 -118
  138. package/internal/board/plain.go +88 -0
  139. package/internal/board/plain_test.go +117 -0
  140. package/internal/board/release.go +1 -9
  141. package/internal/board/release_test.go +6 -6
  142. package/internal/board/status.go +4 -4
  143. package/internal/board/theme.go +24 -0
  144. package/internal/board/theme_test.go +31 -0
  145. package/internal/board/transitions.go +113 -88
  146. package/internal/board/transitions_test.go +164 -141
  147. package/internal/board/tui.go +32 -0
  148. package/internal/board/update.go +344 -215
  149. package/internal/board/update_test.go +326 -18
  150. package/internal/board/util.go +76 -0
  151. package/internal/board/view.go +31 -28
  152. package/internal/board/view_test.go +74 -2
  153. package/internal/board/watch.go +41 -5
  154. package/internal/buildtool/main.go +45 -15
  155. package/internal/buildtool/main_test.go +224 -0
  156. package/internal/data/config.go +17 -3
  157. package/internal/data/config_test.go +49 -0
  158. package/internal/data/discover.go +26 -0
  159. package/internal/data/discover_test.go +34 -10
  160. package/internal/data/errors.go +4 -0
  161. package/internal/data/fuzz_test.go +75 -0
  162. package/internal/data/lifecycle.go +13 -6
  163. package/internal/data/lifecycle_test.go +14 -11
  164. package/internal/data/parser.go +22 -6
  165. package/internal/data/parser_test.go +31 -7
  166. package/internal/data/task.go +0 -9
  167. package/internal/data/testdata/fuzz/FuzzSplitFrontmatterBody/68eb66b0fe91e7e3 +2 -0
  168. package/internal/data/write.go +88 -11
  169. package/internal/data/write_test.go +167 -0
  170. package/internal/doctor/checks.go +567 -0
  171. package/internal/doctor/checks_test.go +716 -0
  172. package/internal/doctor/gates.go +193 -0
  173. package/internal/doctor/gates_test.go +166 -0
  174. package/internal/doctor/interfaces.go +64 -0
  175. package/internal/doctor/interfaces_test.go +104 -0
  176. package/internal/doctor/repairs.go +80 -0
  177. package/internal/doctor/repairs_test.go +81 -0
  178. package/internal/doctor/report.go +157 -0
  179. package/internal/doctor/report_test.go +89 -0
  180. package/internal/init/clipboard.go +146 -0
  181. package/internal/init/clipboard_test.go +74 -0
  182. package/internal/init/install.go +16 -0
  183. package/internal/init/integration_test.go +197 -0
  184. package/internal/init/prompt.go +14 -0
  185. package/internal/init/prompt_test.go +77 -0
  186. package/internal/init/scaffold.go +59 -0
  187. package/internal/init/scaffold_test.go +179 -0
  188. package/internal/init/template_freshness_test.go +56 -0
  189. package/internal/init/validate.go +85 -0
  190. package/internal/init/validate_test.go +141 -0
  191. package/internal/init/write.go +73 -0
  192. package/internal/init/write_test.go +91 -0
  193. package/internal/styles/styles_test.go +133 -0
  194. package/internal/testutil/fixture.go +113 -0
  195. package/internal/testutil/fs.go +26 -0
  196. package/main.go +120 -4
  197. package/package.json +2 -2
  198. package/project-audit/audit_report_glm_5.1.md +411 -0
  199. package/project-audit/audit_report_opus_4.6.md +406 -0
  200. package/project-audit/consolidated-audit-report.md +456 -0
  201. package/templates/project/.savepoint/Design.md +2 -2
  202. package/templates/project/.savepoint/router.md +10 -10
  203. package/templates/project/AGENTS.md +33 -21
  204. package/templates/project/agent-skills/savepoint-audit/SKILL.md +87 -0
  205. package/templates/project/agent-skills/savepoint-build-task/SKILL.md +44 -0
  206. package/templates/project/agent-skills/savepoint-create-plan/SKILL.md +33 -0
  207. package/templates/project/agent-skills/savepoint-create-task/SKILL.md +44 -0
  208. package/templates/project/agent-skills/savepoint-draft-prd/SKILL.md +37 -0
  209. package/templates/project/agent-skills/savepoint-system-design/SKILL.md +38 -0
  210. package/templates/prompts/audit-reconciliation.prompt.md +33 -28
  211. package/templates/prompts/design.prompt.md +3 -1
  212. package/.savepoint/audit/v1/E01/proposals.md +0 -168
  213. package/.savepoint/audit/v1/E01/snapshot.md +0 -78
  214. package/.savepoint/audit/v1/E01-go-setup/proposals.md +0 -166
  215. package/.savepoint/audit/v1/E01-go-setup/snapshot.md +0 -71
  216. package/.savepoint/audit/v1/E01-scaffolding/proposals/AGENTS.md +0 -66
  217. package/.savepoint/audit/v1/E01-scaffolding/proposals/Design.md +0 -210
  218. package/.savepoint/audit/v1/E01-scaffolding/proposals/epic-Design.md +0 -117
  219. package/.savepoint/audit/v1/E01-scaffolding/proposals/quality-review.md +0 -101
  220. package/.savepoint/audit/v1/E01-scaffolding/snapshot.md +0 -54
  221. package/.savepoint/audit/v1/E02-data-model/snapshot.md +0 -128
  222. package/.savepoint/audit/v1/E02-data-readers/proposals.md +0 -123
  223. package/.savepoint/audit/v1/E02-data-readers/snapshot.md +0 -54
  224. package/.savepoint/audit/v1/E03-board-tui-core/proposals.md +0 -146
  225. package/.savepoint/audit/v1/E03-board-tui-core/snapshot.md +0 -57
  226. package/.savepoint/audit/v1/E03-cli-foundation/snapshot.md +0 -106
  227. package/.savepoint/audit/v1/E04-board-components/proposals.md +0 -118
  228. package/.savepoint/audit/v1/E04-board-components/snapshot.md +0 -77
  229. package/.savepoint/audit/v1/E04-templates-and-prompts/snapshot.md +0 -115
  230. package/.savepoint/audit/v1/E05-init-command/snapshot.md +0 -125
  231. package/.savepoint/audit/v1/E05-phase-transitions/proposals.md +0 -83
  232. package/.savepoint/audit/v1/E05-phase-transitions/snapshot.md +0 -36
  233. package/.savepoint/audit/v1/E06-atari-noir-layout/proposals.md +0 -130
  234. package/.savepoint/audit/v1/E06-atari-noir-layout/snapshot.md +0 -84
  235. package/.savepoint/audit/v1/E06-tui-board/snapshot.md +0 -64
  236. package/.savepoint/audit/v1/E07-audit-pipeline/snapshot.md +0 -165
  237. package/.savepoint/audit/v1/E08-board-workflow-cleanup/snapshot.md +0 -65
  238. package/.savepoint/audit/v1.1/E02-cross-platform-compatibility/snapshot.md +0 -41
  239. package/.savepoint/audit/v1.1/E04-epic-navigation/snapshot.md +0 -48
  240. package/ink-cli-ui-design.zip +0 -0
  241. package/savepoint +0 -0
  242. package/savepoint.exe +0 -0
@@ -0,0 +1,333 @@
1
+ ---
2
+ type: audit-findings
3
+ audited: 2026-05-03
4
+ ---
5
+ # Audit Findings: E08 Board Command
6
+
7
+ ## Main Findings
8
+
9
+ E08 is closed as audited. The board command surface, non-TTY fallback, Bubble Tea shell, model grouping, detail overlay, keyboard navigation, status writes, filters, theme profile detection, and integration coverage are in place.
10
+
11
+ The two audit blockers were applied: board task writes now surface mtime conflicts instead of overwriting externally modified task files, and dependency gating now blocks planned tasks from entering `in_progress` until dependencies are done.
12
+
13
+ Documentation reconciliation was applied to Design.md, AGENTS.md, and the E08 epic detail. Remaining process note: all eight E08 task files were missing the required `## Context Files` section; that was not backfilled because it is a task-authoring process gap rather than an implementation blocker.
14
+
15
+ ## Code Style Review
16
+
17
+ - [x] One job per file
18
+ - [x] One-sentence functions
19
+ - [x] Test branches
20
+ - [x] Types are documentation
21
+ - [x] Build, don't speculate
22
+ - [x] Errors at boundaries
23
+ - [x] One source of truth
24
+ - [x] Comments explain WHY
25
+ - [x] Content in data files
26
+ - [x] Small diffs
27
+
28
+ Notes: The applied changes remove the speculative mtime overwrite and add branch coverage for planned-task dependency gating. The broader reducer size remains a known shape of `internal/board/update.go`, but the E08 audit blockers are resolved.
29
+
30
+ ## Proposed Changes
31
+
32
+ ### Target File
33
+ internal/board/update.go
34
+
35
+ ### Replace
36
+ ```go
37
+ func writeTaskStatus(task *data.Task, expectedMtime time.Time) error {
38
+ if err := data.WriteTaskStatus(task.Path, task, expectedMtime); err != nil {
39
+ if err != data.ErrMtimeConflict {
40
+ return err
41
+ }
42
+ fi, statErr := os.Stat(task.Path)
43
+ if statErr != nil {
44
+ return statErr
45
+ }
46
+ if retryErr := data.WriteTaskStatus(task.Path, task, fi.ModTime()); retryErr != nil {
47
+ return retryErr
48
+ }
49
+ }
50
+ fi, err := os.Stat(task.Path)
51
+ if err != nil {
52
+ return err
53
+ }
54
+ task.Mtime = fi.ModTime()
55
+ return nil
56
+ }
57
+ ```
58
+
59
+ ### With
60
+ ```go
61
+ func writeTaskStatus(task *data.Task, expectedMtime time.Time) error {
62
+ if err := data.WriteTaskStatus(task.Path, task, expectedMtime); err != nil {
63
+ return err
64
+ }
65
+ fi, err := os.Stat(task.Path)
66
+ if err != nil {
67
+ return err
68
+ }
69
+ task.Mtime = fi.ModTime()
70
+ return nil
71
+ }
72
+ ```
73
+
74
+ ### Target File
75
+ internal/board/integration_test.go
76
+
77
+ ### Replace
78
+ ```go
79
+ // TestMtimeConflict_boardRetries verifies the board retries after an mtime conflict and persists the transition.
80
+ func TestMtimeConflict_boardRetries(t *testing.T) {
81
+ path := filepath.Join(t.TempDir(), "T001.md")
82
+ content := "---\nid: E01/T001\nstatus: in_progress\nphase: build\n---\n\n# Task\n"
83
+ if err := os.WriteFile(path, []byte(content), 0644); err != nil {
84
+ t.Fatal(err)
85
+ }
86
+ fi, err := os.Stat(path)
87
+ if err != nil {
88
+ t.Fatal(err)
89
+ }
90
+
91
+ task := data.Task{
92
+ ID: "E01/T001",
93
+ Column: data.ColumnInProgress,
94
+ Stage: data.StageBuild,
95
+ Path: path,
96
+ Mtime: fi.ModTime().Add(-time.Minute), // intentionally stale
97
+ }
98
+ m := NewModel([]data.Task{task}, "v1", "E01")
99
+ m.FocusedColumn = data.ColumnInProgress
100
+
101
+ got, _ := m.Update(tea.KeyMsg{Type: tea.KeySpace})
102
+ updated := requireModel(t, got)
103
+
104
+ if updated.AllTasks[0].Stage != data.StageTest {
105
+ t.Errorf("Stage = %q after retry, want test", updated.AllTasks[0].Stage)
106
+ }
107
+ if strings.Contains(updated.StatusMessage, "conflict") {
108
+ t.Errorf("conflict error surfaced to user unexpectedly: %q", updated.StatusMessage)
109
+ }
110
+ }
111
+ ```
112
+
113
+ ### With
114
+ ```go
115
+ // TestMtimeConflict_boardWarns verifies the board surfaces an mtime conflict instead of overwriting external edits.
116
+ func TestMtimeConflict_boardWarns(t *testing.T) {
117
+ path := filepath.Join(t.TempDir(), "T001.md")
118
+ content := "---\nid: E01/T001\nstatus: in_progress\nphase: build\n---\n\n# Task\n"
119
+ if err := os.WriteFile(path, []byte(content), 0644); err != nil {
120
+ t.Fatal(err)
121
+ }
122
+ fi, err := os.Stat(path)
123
+ if err != nil {
124
+ t.Fatal(err)
125
+ }
126
+
127
+ task := data.Task{
128
+ ID: "E01/T001",
129
+ Column: data.ColumnInProgress,
130
+ Stage: data.StageBuild,
131
+ Path: path,
132
+ Mtime: fi.ModTime().Add(-time.Minute), // intentionally stale
133
+ }
134
+ m := NewModel([]data.Task{task}, "v1", "E01")
135
+ m.FocusedColumn = data.ColumnInProgress
136
+
137
+ got, _ := m.Update(tea.KeyMsg{Type: tea.KeySpace})
138
+ updated := requireModel(t, got)
139
+
140
+ if !strings.Contains(updated.StatusMessage, "mtime conflict") {
141
+ t.Errorf("StatusMessage = %q, want mtime conflict warning", updated.StatusMessage)
142
+ }
143
+
144
+ raw, err := os.ReadFile(path)
145
+ if err != nil {
146
+ t.Fatal(err)
147
+ }
148
+ if !strings.Contains(string(raw), "phase: build") {
149
+ t.Errorf("task file was overwritten despite mtime conflict:\n%s", raw)
150
+ }
151
+ }
152
+ ```
153
+
154
+ ### Target File
155
+ internal/board/transitions.go
156
+
157
+ ### Replace
158
+ ```go
159
+ case data.ColumnPlanned:
160
+ return true, ""
161
+ case data.ColumnInProgress:
162
+ ```
163
+
164
+ ### With
165
+ ```go
166
+ case data.ColumnPlanned:
167
+ return dependenciesDone(t, allTasks)
168
+ case data.ColumnInProgress:
169
+ ```
170
+
171
+ ### Target File
172
+ internal/board/transitions.go
173
+
174
+ ### Replace
175
+ ```go
176
+ switch stage {
177
+ case data.StageBuild:
178
+ return true, ""
179
+ case data.StageTest:
180
+ return true, ""
181
+ case data.StageAudit:
182
+ for _, depID := range t.DependsOn {
183
+ dep := findTask(depID, allTasks)
184
+ if dep == nil {
185
+ return false, fmt.Sprintf("dependency %q not found", depID)
186
+ }
187
+ if dep.Column != data.ColumnDone {
188
+ return false, fmt.Sprintf("dependency %q is not done", depID)
189
+ }
190
+ }
191
+ return true, ""
192
+ default:
193
+ ```
194
+
195
+ ### With
196
+ ```go
197
+ switch stage {
198
+ case data.StageBuild:
199
+ return true, ""
200
+ case data.StageTest:
201
+ return true, ""
202
+ case data.StageAudit:
203
+ return dependenciesDone(t, allTasks)
204
+ default:
205
+ ```
206
+
207
+ ### Target File
208
+ internal/board/transitions.go
209
+
210
+ ### Replace
211
+ ```go
212
+ func findTask(id string, tasks []data.Task) *data.Task {
213
+ for i := range tasks {
214
+ if tasks[i].ID == id {
215
+ return &tasks[i]
216
+ }
217
+ }
218
+ return nil
219
+ }
220
+ ```
221
+
222
+ ### With
223
+ ```go
224
+ func dependenciesDone(t *data.Task, allTasks []data.Task) (bool, string) {
225
+ for _, depID := range t.DependsOn {
226
+ dep := findTask(depID, allTasks)
227
+ if dep == nil {
228
+ return false, fmt.Sprintf("dependency %q not found", depID)
229
+ }
230
+ if dep.Column != data.ColumnDone {
231
+ return false, fmt.Sprintf("dependency %q is not done", depID)
232
+ }
233
+ }
234
+ return true, ""
235
+ }
236
+
237
+ func findTask(id string, tasks []data.Task) *data.Task {
238
+ for i := range tasks {
239
+ if tasks[i].ID == id {
240
+ return &tasks[i]
241
+ }
242
+ }
243
+ return nil
244
+ }
245
+ ```
246
+
247
+ ### Target File
248
+ internal/board/transitions_test.go
249
+
250
+ ### Replace
251
+ ```go
252
+ func TestCanAdvance_plannedAlwaysAllowed(t *testing.T) {
253
+ task := data.Task{Column: data.ColumnPlanned}
254
+ ok, reason := CanAdvance(&task, nil)
255
+ if !ok {
256
+ t.Errorf("CanAdvance(planned) = false %q, want true", reason)
257
+ }
258
+ }
259
+ ```
260
+
261
+ ### With
262
+ ```go
263
+ func TestCanAdvance_plannedAllowedWhenDependenciesDone(t *testing.T) {
264
+ allTasks := []data.Task{
265
+ {ID: "T1", Column: data.ColumnPlanned, DependsOn: []string{"T2"}},
266
+ {ID: "T2", Column: data.ColumnDone},
267
+ }
268
+ ok, reason := CanAdvance(&allTasks[0], allTasks)
269
+ if !ok {
270
+ t.Errorf("CanAdvance(planned with done dep) = false %q, want true", reason)
271
+ }
272
+ }
273
+
274
+ func TestCanAdvance_plannedBlockedByDependency(t *testing.T) {
275
+ allTasks := []data.Task{
276
+ {ID: "T1", Column: data.ColumnPlanned, DependsOn: []string{"T2"}},
277
+ {ID: "T2", Column: data.ColumnInProgress},
278
+ }
279
+ ok, reason := CanAdvance(&allTasks[0], allTasks)
280
+ if ok {
281
+ t.Fatal("CanAdvance(planned with unfinished dep) = true, want false")
282
+ }
283
+ if reason != "dependency \"T2\" is not done" {
284
+ t.Errorf("reason = %q, want dependency warning", reason)
285
+ }
286
+ }
287
+ ```
288
+
289
+ ### Target File
290
+ AGENTS.md
291
+
292
+ ### Replace
293
+ ```md
294
+ | `cmd/` | Init command arg parsing, dispatch |
295
+ ```
296
+
297
+ ### With
298
+ ```md
299
+ | `cmd/` | CLI command arg parsing and dispatch for init and board |
300
+ ```
301
+
302
+ ### Target File
303
+ .savepoint/releases/v1.1/epics/E08-board-command/E08-Detail.md
304
+
305
+ ### Replace
306
+ ```md
307
+ ## Boundaries
308
+ ```
309
+
310
+ ### With
311
+ ```md
312
+ ## Implemented As
313
+
314
+ - `main.go` dispatches `board` and uses the no-arg command path as the board default.
315
+ - `cmd/board.go` owns board-specific flag parsing for `--release`, `--epic`, and `--help`.
316
+ - `internal/board/board.go`, `tui.go`, `model.go`, `plain.go`, `transitions.go`, and related render/update files own project discovery, non-TTY fallback, TUI startup, filtering, detail overlays, keyboard flow, and task status writes.
317
+ - Audit entry-point work is represented as the non-TTY audit proposal signal and the epic Detail/Audit tab flow added around E06.
318
+
319
+ ## Boundaries
320
+ ```
321
+
322
+ ### Target File
323
+ .savepoint/Design.md
324
+
325
+ ### Replace
326
+ ```md
327
+ - **Board command** (`savepoint board`) reads project state, renders the Atari-Noir TUI board, supports release/epic filtering, detail overlays, task status transitions with mtime-guarded writes, release/epic-scoped router priority markers, fsnotify-based task auto-refresh (epic E06), header Next Activity display, height-aware column/detail viewport scrolling, stable focused/unfocused column border geometry (v1.1 E01), dedicated phase-colored Next Activity line below the header, sentence-boundary checklist rendering in task details, shared status glyph mapping for task cards and the epic sidebar, a forced ANSI256 Lipgloss color profile for board startup (v1.1 E03), a focusable wide-screen epic sidebar with purple epic focus, epic detail overlays, and status glyphs loaded from epic detail frontmatter (v1.1 E04), and an epic Detail/Audit tab switch that renders user-facing audit findings from `{epic}/E##-Audit.md` (v1.1 E06).
328
+ ```
329
+
330
+ ### With
331
+ ```md
332
+ - **Board command** (`savepoint board`, and bare `savepoint`) reads project state, renders the Atari-Noir TUI board when stdout is a TTY, falls back to a deterministic plain table in non-TTY mode, supports `--release`/`--epic` filtering, detail overlays, task status transitions with mtime-guarded writes, release/epic-scoped router priority markers, fsnotify-based task auto-refresh (epic E06), header Next Activity display, height-aware column/detail viewport scrolling, stable focused/unfocused column border geometry (v1.1 E01), dedicated phase-colored Next Activity line below the header, sentence-boundary checklist rendering in task details, shared status glyph mapping for task cards and the epic sidebar, a forced ANSI256 Lipgloss color profile for board startup (v1.1 E03), a focusable wide-screen epic sidebar with purple epic focus, epic detail overlays, and status glyphs loaded from epic detail frontmatter (v1.1 E04), and an epic Detail/Audit tab switch that renders user-facing audit findings from `{epic}/E##-Audit.md` (v1.1 E06).
333
+ ```
@@ -0,0 +1,68 @@
1
+ ---
2
+ type: epic-design
3
+ status: audited
4
+ ---
5
+
6
+ # E08: Board Command
7
+
8
+ ## Purpose
9
+
10
+ Implement `savepoint board`, a Bubble Tea terminal UI for viewing and moving tasks through the Savepoint workflow, including audit-review mode entry points.
11
+
12
+ ## Interface
13
+
14
+ ```bash
15
+ savepoint board # launch TUI
16
+ savepoint # alias for board
17
+ savepoint board --release v1 # filter by release
18
+ savepoint board --epic E03 # filter by epic
19
+ ```
20
+
21
+ ## What this epic adds
22
+
23
+ - Ink/Bubble Tea app shell launched by `savepoint board`
24
+ - Three-column Kanban view for planned, in_progress, done
25
+ - Detail pane for selected task
26
+ - Keyboard navigation (arrows, vim-style j/k/h/l)
27
+ - Status transition actions with gate enforcement
28
+ - Manual refresh with `r` key
29
+ - Theme tokens loaded from config.yml
30
+ - Render fallbacks: 24-bit → 256-color → 16-color → NO_COLOR → non-TTY plain table
31
+ - Optimistic mtime conflict detection before writes
32
+ - Audit entry point: signal if proposals exist, exit toward audit
33
+
34
+ ## Components
35
+
36
+ | Module | Purpose |
37
+ |--------|---------|
38
+ | `cmd/board.go` | CLI registration, arg parsing |
39
+ | `internal/board/cmd.go` | Non-TTY fallback, dispatch |
40
+ | `internal/board/tui.go` | Bubble Tea program setup |
41
+ | `internal/board/model.go` | Board state, columns, cards |
42
+ | `internal/board/detail.go` | Task detail pane |
43
+ | `internal/board/transitions.go` | Status transition gate enforcement |
44
+ | `internal/board/theme.go` | Theme loading, color fallbacks |
45
+ | `internal/board/plain.go` | Non-TTY plain text table |
46
+
47
+ ## Implemented As
48
+
49
+ - `main.go` dispatches `board` and uses the no-arg command path as the board default.
50
+ - `cmd/board.go` owns board-specific flag parsing for `--release`, `--epic`, and `--help`.
51
+ - `internal/board/board.go`, `tui.go`, `model.go`, `plain.go`, `transitions.go`, and related render/update files own project discovery, non-TTY fallback, TUI startup, filtering, detail overlays, keyboard flow, and task status writes.
52
+ - Audit entry-point work is represented as the non-TTY audit proposal signal and the epic Detail/Audit tab flow added around E06.
53
+
54
+ ## Boundaries
55
+
56
+ **In scope:**
57
+ - Board navigation and status transitions
58
+ - Gate enforcement for dependencies and status rules
59
+ - Plain table fallback when not in a TTY
60
+ - Manual `r` refresh
61
+ - Initial audit-review mode entry point if proposals exist
62
+
63
+ **Out of scope:**
64
+ - File watching
65
+ - Search
66
+ - Mouse interaction
67
+ - Drag-and-drop
68
+ - Full audit proposal diff implementation
@@ -0,0 +1,26 @@
1
+ ---
2
+ id: E08-board-command/T001-cli-entrypoint
3
+ status: done
4
+ objective: "Create CLI entrypoint for savepoint board command"
5
+ depends_on: []
6
+ ---
7
+
8
+ # T001: CLI Entrypoint
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - `savepoint board --help` shows usage: `board [--release <release>] [--epic <epic>]`
13
+ - `savepoint` (no args) defaults to board
14
+ - `savepoint board` launches TUI
15
+ - `savepoint board --release v1` filters by release
16
+ - `savepoint board --epic E03` filters by epic
17
+
18
+ ## Implementation Plan
19
+
20
+ - [x] Update main.go dispatch to recognize subcommands
21
+ - [x] Add `cmd/board.go` with CLI arg parsing
22
+ - [x] Wire board command into main.go
23
+ - [x] Implement arg validation (--release, --epic)
24
+ - [x] Default to board when no subcommand given
25
+ - [x] Test `savepoint board --help` output
26
+ - [x] Run `make build && make test`
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: E08-board-command/T002-non-tty-fallback
3
+ status: done
4
+ objective: "Implement non-TTY plain text table output"
5
+ depends_on: ["E08-board-command/T001-cli-entrypoint"]
6
+ ---
7
+
8
+ # T002: Non-TTY Fallback
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - When not in a TTY, outputs deterministic plain text
13
+ - Shows three columns: planned, in_progress, done
14
+ - Lists task IDs and objectives in each column
15
+ - Includes warning about non-interactive mode
16
+ - Shows audit-entry signal if audit proposals exist
17
+
18
+ ## Implementation Plan
19
+
20
+ - [x] Add `internal/board/plain.go`
21
+ - [x] Implement `RenderPlainTable(model) string`
22
+ - [x] Check `termenv.IsTerminal()` for TTY detection
23
+ - [x] Format tasks in three columns with headers
24
+ - [x] Add non-interactive warning banner
25
+ - [x] Check for audit proposals, show entry signal
26
+ - [x] Test non-TTY output
27
+ - [x] Run `make build && make test`
@@ -0,0 +1,28 @@
1
+ ---
2
+ id: E08-board-command/T003-tui-app-shell
3
+ status: done
4
+ objective: "Implement Bubble Tea TUI program shell"
5
+ depends_on: ["E08-board-command/T001-cli-entrypoint"]
6
+ ---
7
+
8
+ # T003: TUI App Shell
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - Launches Bubble Tea program with alt screen
13
+ - Loads theme from config.yml
14
+ - Initializes model with release/epic filters
15
+ - Handles quit (q, ctrl+c) gracefully
16
+ - Handles window resize
17
+
18
+ ## Implementation Plan
19
+
20
+ - [x] Add `internal/board/tui.go`
21
+ - [x] Implement `RunTUI(release, epic) error`
22
+ - [x] Create tea.Program with board model
23
+ - [x] Enable alt screen mode
24
+ - [x] Load and apply theme from config
25
+ - [x] Handle quit key (q, ctrl+c)
26
+ - [x] Handle window resize events
27
+ - [x] Test TUI launch in terminal
28
+ - [x] Run `make build && make test`
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: E08-board-command/T004-board-model
3
+ status: done
4
+ objective: "Implement TUI board model with 3-column Kanban"
5
+ depends_on: ["E08-board-command/T003-tui-app-shell"]
6
+ ---
7
+
8
+ # T004: Board Model
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - Three columns: planned, in_progress, done
13
+ - Column headers with task count
14
+ - Task cards showing ID and objective
15
+ - Keyboard navigation: arrows, vim-style j/k/h/l
16
+ - Selection highlighting with accent color
17
+ - Filter by release and epic
18
+
19
+ ## Implementation Plan
20
+
21
+ - [x] Add `internal/board/model.go` (extend existing or create new)
22
+ - [x] Implement column structure (planned, in_progress, done)
23
+ - [x] Implement card rendering (ID + objective truncated)
24
+ - [x] Implement selection state (current column, current card)
25
+ - [x] Handle key events: Up/Down/Left/Right, j/k/h/l
26
+ - [x] Apply theme colors for focus/accent
27
+ - [x] Implement release/epic filtering from args
28
+ - [x] Test board rendering in TUI
29
+ - [x] Run `make build && make test`
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: E08-board-command/T005-detail-pane
3
+ status: done
4
+ objective: "Implement task detail pane overlay"
5
+ depends_on: ["E08-board-command/T004-board-model"]
6
+ ---
7
+
8
+ # T005: Detail Pane
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - Enter key shows selected task detail overlay
13
+ - Displays full task content: ID, objective, status, depends_on, AC
14
+ - Keyboard navigation works (escape/enter to close)
15
+ - Overlay renders with theme styling
16
+ - Closes on q or escape
17
+
18
+ ## Implementation Plan
19
+
20
+ - [x] Add `internal/board/detail.go` (extend existing or create new)
21
+ - [x] Implement detail overlay state
22
+ - [x] Render selected task full content
23
+ - [x] Add enter key handler to show detail
24
+ - [x] Add escape/q handlers to close detail
25
+ - [x] Apply theme styling to overlay
26
+ - [x] Test detail pane interaction
27
+ - [x] Run `make build && make test`
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: E08-board-command/T006-status-transitions
3
+ status: done
4
+ objective: "Implement status transitions with gate enforcement"
5
+ depends_on: ["E08-board-command/T005-detail-pane"]
6
+ ---
7
+
8
+ # T006: Status Transitions
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - Space advances: planned → in_progress → done
13
+ - Backspace retreats: done → in_progress → planned
14
+ - Phase gating: can only reach done after audit phase
15
+ - Dependency gating: cannot advance if depends_on not done
16
+ - mtime conflict detection: warn if task modified since load
17
+ - Write status back to task frontmatter
18
+
19
+ ## Implementation Plan
20
+
21
+ - [x] Add `internal/board/transitions.go` (extend existing or create new)
22
+ - [x] Implement phase advancement (space key)
23
+ - [x] Implement phase retreat (backspace key)
24
+ - [x] Check phase gating (must reach audit phase before done)
25
+ - [x] Check dependency gating (all depends_on status: done)
26
+ - [x] Implement mtime conflict detection before write
27
+ - [x] Write new status to task frontmatter via data.WriteTaskStatus
28
+ - [x] Test transition behavior in TUI
29
+ - [x] Run `make build && make test`
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: E08-board-command/T007-theme-fallbacks
3
+ status: done
4
+ objective: "Implement theme loading and color fallbacks"
5
+ depends_on: ["E08-board-command/T003-tui-app-shell"]
6
+ ---
7
+
8
+ # T007: Theme Fallbacks
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - Load theme tokens from config.yml
13
+ - Support truecolor (24-bit) terminals
14
+ - Fall back to 256-color mode if no truecolor
15
+ - Fall back to 16-color if no 256-color
16
+ - Support NO_COLOR=1 for monochrome
17
+ - Apply theme to all UI elements (columns, cards, detail, overlays)
18
+
19
+ ## Implementation Plan
20
+
21
+ - [x] Add `internal/board/theme.go` (extend existing or create new)
22
+ - [x] Implement theme loading from config.yml
23
+ - [x] Implement truecolor profile detection
24
+ - [x] Implement 256-color fallback mapping
25
+ - [x] Implement 16-color fallback mapping
26
+ - [x] Support NO_COLOR=1 monochrome mode
27
+ - [x] Apply theme to columns, cards, detail, overlays
28
+ - [x] Test on different terminal profiles
29
+ - [x] Run `make build && make test`
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: E08-board-command/T008-integration-test
3
+ status: done
4
+ objective: "End-to-end integration test of board flow"
5
+ depends_on: ["E06-audit-command/T007-apply-close", "E07-init-command/T007-integration-test"]
6
+ ---
7
+
8
+ # T008: Integration Test
9
+
10
+ ## Acceptance Criteria
11
+
12
+ - Full board pipeline runs end-to-end
13
+ - TUI navigation, transitions, detail pane work
14
+ - Non-TTY fallback outputs correct table
15
+ - Status writes preserve task content
16
+ - Tests pass on Windows, Linux, macOS
17
+
18
+ ## Implementation Plan
19
+
20
+ - [x] Add `internal/board/integration_test.go`
21
+ - [x] Test: board launches in TTY mode
22
+ - [x] Test: board falls back to plain table in non-TTY
23
+ - [x] Test: keyboard navigation (arrows, vim keys)
24
+ - [x] Test: status transitions preserve content
25
+ - [x] Test: mtime conflict detection works
26
+ - [x] Test: release/epic filters work
27
+ - [x] Run full test suite: `make build && make test`