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,411 @@
1
+ # Codebase Audit Report
2
+
3
+ ## 1. Executive Summary
4
+
5
+ **Savepoint** is a Go CLI/TUI tool (~5,600 lines of production code, ~5,600 lines of tests, 264 tests) that provides a kanban-style project workflow manager with a terminal UI. It uses the Bubble Tea framework and a custom "Atari-Noir" visual theme.
6
+
7
+ **What is working well:**
8
+ - Clean module separation: `cmd/` (CLI), `internal/data/` (persistence), `internal/board/` (TUI), `internal/doctor/` (diagnostics), `internal/init/` (scaffolding), `internal/styles/` (palette)
9
+ - Dependency injection in `cmd/` via function types (`InitRunner`, `BoardRunner`, `DoctorRunner`) makes commands trivially testable
10
+ - Good test coverage for the core modules (data, board, doctor, init, cmd) with 264 tests
11
+ - Atomic file writes in `data/write.go` and `init/write.go` prevent corruption
12
+ - Well-designed responsive TUI layout with breakpoint-based column rendering
13
+ - Policy tests (`render_policy_test.go`) enforce visual constraints cross-cutting
14
+
15
+ **Biggest risks:**
16
+ - Synchronous filesystem I/O inside the Bubble Tea `Update()` loop will freeze the TUI on slow disks or large files
17
+ - `update.go` (521 lines) is a monolithic switch that handles 5+ overlay types, keyboard input, and file writes in one function
18
+ - `doctor/checks.go` (585 lines) reimplements `strings.Contains`/`strings.Index` and the cycle detection has an accuracy issue
19
+ - No Windows build target in `buildtool`; no checksums in distribution archives
20
+ - `buildtool` and `styles` packages have zero tests
21
+
22
+ **Extensibility:** The architecture suits the current project size well. Adding new overlays, columns, or commands would be straightforward. The main risk to extensibility is the `update.go` monolith — every new keybind or overlay type adds more branches to an already complex function.
23
+
24
+ **Architecture fit:** Good for a small-to-medium project. The Bubble Tea pattern (Model-Update-View) is well-applied, and the rendering helpers are pure functions. The data layer correctly separates parsing, discovery, and writing. The main architectural debt is the I/O-in-update pattern and the size of `update.go`.
25
+
26
+ ---
27
+
28
+ ## 2. Severity-Ranked Recommendations
29
+
30
+ ### Critical
31
+
32
+ #### C1. Synchronous file I/O in the TUI update loop
33
+
34
+ - **Finding:** `update.go` performs filesystem reads and writes directly inside `Update()`: `writeTaskStatus()`, `writeRouterTask()`, `writeRouterReleaseEpic()`, `readEpicDetailFile()`, `selectEpicPanelEpic()`. These block the TUI event loop.
35
+ - **Why it matters:** Any disk latency (network drives, slow SSDs, virus scanners) freezes the entire TUI. Bubble Tea's design intent is for `Update()` to be pure — I/O should happen in `tea.Cmd` functions that return messages.
36
+ - **Evidence:** `internal/board/update.go:285-330` (writeRouterTask, writeRouterReleaseEpic), `internal/board/update.go:217-250` (readEpicDetailFile), `internal/board/model.go:235-280` (writeRouterReleaseEpic, writeRouterTask)
37
+ - **Recommended fix:** Extract I/O operations into `tea.Cmd` functions. E.g., `writeTaskStatusCmd(task, path, mtime) tea.Cmd` returns a `tea.Msg` on completion. `Update()` dispatches the command and handles the result message. This is the standard Bubble Tea pattern.
38
+ - **Estimated effort:** Medium (requires refactoring `update.go` to emit commands for each I/O operation, add result message types, and handle them in separate `Update()` branches)
39
+
40
+ #### C2. Cycle detection produces inaccurate paths
41
+
42
+ - **Finding:** `detectCycles` in `checks.go` uses a `parent` map that gets overwritten when a node is visited from multiple paths. When a cycle is found, the path reconstructed via `parent` may not represent the actual cycle.
43
+ - **Why it matters:** Users could be shown a cycle path that doesn't actually exist, causing confusion or incorrect doctor reports.
44
+ - **Evidence:** `internal/doctor/checks.go` — the DFS `parent` map is a simple `map[string]string` that gets overwritten per-visit
45
+ - **Recommended fix:** Either use a stack-based cycle reconstruction (track the current DFS path as a slice) or validate the reconstructed path actually forms a cycle before reporting it.
46
+ - **Estimated effort:** Small
47
+
48
+ ### High
49
+
50
+ #### H1. `update.go` is a monolithic 521-line file handling all input, overlays, and I/O
51
+
52
+ - **Finding:** The `Update()` method alone is ~190 lines with deeply nested switches. Overlay handling mixes 5 overlay types in one `updateOverlay()` function.
53
+ - **Why it matters:** Every new feature (new keybind, new overlay) increases the branching complexity. It's hard to reason about which keys do what in which state.
54
+ - **Evidence:** `internal/board/update.go` — single file handling quit, navigation, task transitions, overlays for help/epic/release/detail/epic-detail, file watching, phase management
55
+ - **Recommended fix:** Extract `updateOverlay()` into per-type handlers (`updateHelpOverlay`, `updateEpicOverlay`, etc.). Extract board key handling into `handleBoardKey()`. Consider a key-to-handler dispatch map rather than a switch chain.
56
+ - **Estimated effort:** Medium
57
+
58
+ #### H2. Stdlib reimplementation in `repairs.go` and `buildtool/main.go`
59
+
60
+ - **Finding:** `contains()` and `indexOf()` in `repairs.go` reimplement `strings.Contains` and `strings.Index`. `trimSpace()` in `buildtool/main.go` reimplements `bytes.TrimSpace`.
61
+ - **Why it matters:** Makes code harder to read for Go developers expecting standard library calls. The custom implementations may have subtle differences from the stdlib versions (e.g., Unicode whitespace handling).
62
+ - **Evidence:** `internal/doctor/repairs.go:67-79`, `internal/buildtool/main.go:211-219`
63
+ - **Recommended fix:** Replace with `strings.Contains`, `strings.Index`, and `bytes.TrimSpace` respectively. Import the relevant packages.
64
+ - **Estimated effort:** Small
65
+
66
+ #### H3. Fragile repair suggestion matching via substring search on error messages
67
+
68
+ - **Finding:** `SuggestRepair()` pattern-matches against error message substrings to suggest fixes. If error messages change format, repairs silently break.
69
+ - **Evidence:** `internal/doctor/repairs.go:8-66` — hard-coded substring matching against messages like `"not found"`, `"invalid"`, `"missing"`
70
+ - **Recommended fix:** Define typed error codes or sentinel errors in `data/` and `doctor/`, and match on error type rather than substring. E.g., `func SuggestRepair(err error) string` switches on `errors.Is(err, ErrNoFrontmatter)` instead of `contains(err.Error(), "no frontmatter")`.
71
+ - **Estimated effort:** Medium
72
+
73
+ #### H4. Quality gate command execution has no timeout
74
+
75
+ - **Finding:** `RunQualityGates` executes commands from `config.yml` with no timeout. A hung command blocks the doctor indefinitely.
76
+ - **Evidence:** `internal/doctor/gates.go:32-55` — `exec.Command` with `Run()` and no `Context` timeout
77
+ - **Recommended fix:** Use `exec.CommandContext(ctx, ...)` with a configurable timeout (default: 60s). Add a `gate_timeout` config option.
78
+ - **Estimated effort:** Small
79
+
80
+ #### H5. `\r\n` normalization is scattered across files instead of centralized
81
+
82
+ - **Finding:** `strings.ReplaceAll(content, "\r\n", "\n")` appears in `parser.go`, `write.go` (3 times), `epic_panel.go`, and likely elsewhere. This is a cross-cutting concern that should be handled once.
83
+ - **Why it matters:** If the normalization logic changes (e.g., also handling `\r` alone), every call site must be found and updated. Missing a call site causes subtle cross-platform bugs.
84
+ - **Evidence:** `internal/data/parser.go:92`, `internal/data/write.go:22,46,104`, `internal/board/epic_panel.go`
85
+ - **Recommended fix:** Create a `normalizeLineEndings(s string) string` function in `internal/data/` and use it everywhere. Or read files with a `bufio.Scanner` which handles line endings, or use `strings.ReplaceAll` once at the point of file reading.
86
+ - **Estimated effort:** Small
87
+
88
+ ### Medium
89
+
90
+ #### M1. Dead code in `column.go` and `report.go`
91
+
92
+ - **Finding:** `taskLabel()` in `column.go` is defined but never called. `CheckResult` in `report.go` is defined but never used. `GateSuggestion` has an unused `exitCode` parameter.
93
+ - **Evidence:** `internal/board/column.go`, `internal/doctor/report.go`
94
+ - **Recommended fix:** Remove `taskLabel`. Remove `CheckResult` type. Remove or use the `exitCode` parameter in `GateSuggestion`.
95
+ - **Estimated effort:** Small
96
+
97
+ #### M2. Hardcoded state constants in `checks.go` duplicate `data/` definitions
98
+
99
+ - **Finding:** `validStates` map in `checks.go` duplicates the canonical state names defined in `data/lifecycle.go`. If a state is added to `lifecycle.go`, `checks.go` must be manually updated.
100
+ - **Evidence:** `internal/doctor/checks.go` — `validStates` map vs `data.IsCanonicalColumn()` / `data.IsCanonicalStage()`
101
+ - **Recommended fix:** Remove `validStates` and use `data.IsCanonicalColumn()` / `data.IsCanonicalStage()` for validation.
102
+ - **Estimated effort:** Small
103
+
104
+ #### M3. Inconsistent directory abstraction: `CheckOrphans` bypasses `data.Discover`
105
+
106
+ - **Finding:** Most of `checks.go` uses `data.Discover` for filesystem traversal, but `CheckOrphans` uses `os.ReadDir` directly.
107
+ - **Evidence:** `internal/doctor/checks.go` — `CheckOrphans` function
108
+ - **Recommended fix:** Add a `ListRootDirs()` or similar method to `data.Discover` and use it in `CheckOrphans`.
109
+ - **Estimated effort:** Small
110
+
111
+ #### M4. `shortID()` and `WrapText()`/`SplitLongWord()` should be in a shared utilities file
112
+
113
+ - **Finding:** `shortID()` is defined in `card.go` but used in `board.go`, `view.go`, `update.go`, and `detail.go`. `WrapText()` and `SplitLongWord()` in `detail.go` are general-purpose text utilities.
114
+ - **Why it matters:** Scattered utility functions make it hard to find shared logic and risk duplication.
115
+ - **Recommended fix:** Create `internal/board/util.go` (or `internal/text/util.go`) for `shortID`, `WrapText`, `SplitLongWord`, and `truncate`. Move `epicIndex`/`releaseIndex` to a generic `indexOrZero` helper.
116
+ - **Estimated effort:** Small
117
+
118
+ #### M5. Layout constants split between `layout.go` and `column.go`
119
+
120
+ - **Finding:** `colOverhead` is defined in `column.go` (value 4) and used in both `column.go` and `layout.go`. `minColWidth` is in `layout.go`. These layout-related constants should be co-located.
121
+ - **Evidence:** `internal/board/column.go:17` (`const colOverhead = 4`), `internal/board/layout.go:8-15`
122
+ - **Recommended fix:** Move all layout constants to `layout.go`.
123
+ - **Estimated effort:** Small
124
+
125
+ #### M6. `AtomicWrite` cross-device rename fallback doesn't actually solve cross-device moves
126
+
127
+ - **Finding:** `replaceFile()` in `init/write.go` tries `os.Rename` first, then falls back to creating a backup and renaming, but `os.Rename` will still fail on cross-device moves. The fallback should use `os.Link` + `os.Remove` or a plain copy.
128
+ - **Evidence:** `internal/init/write.go:52-63`
129
+ - **Recommended fix:** In the fallback path, use `os.Open` + `io.Copy` + `os.Remove` instead of `os.Rename` for cross-filesystem cases.
130
+ - **Estimated effort:** Small
131
+
132
+ #### M7. Ad-hoc Markdown parsing in `epic_panel.go` is fragile
133
+
134
+ - **Finding:** `epicDetailBody()` and `epicAuditBody()` contain hand-rolled markdown section extraction that skips headings containing "component" or "files" via substring matching. Any heading with those substrings will be silently hidden.
135
+ - **Evidence:** `internal/board/epic_panel.go` — text manipulation functions
136
+ - **Recommended fix:** Either use a proper markdown parser (e.g., `goldmark`) for section extraction, or use exact heading matches with a configurable allowlist/blocklist rather than substring matching.
137
+ - **Estimated effort:** Medium (if switching to a markdown parser) / Small (if switching substring to exact match)
138
+
139
+ #### M8. `Config.Theme` defaults not filling individual accent colors
140
+
141
+ - **Finding:** `fillThemeDefaults()` fills base theme colors when empty, but for accents, it's all-or-nothing: if the user specifies any accent, they must specify all accents, since the function only uses defaults when `len(theme.Accents) == 0`.
142
+ - **Evidence:** `internal/data/config.go:91-94`
143
+ - **Recommended fix:** Fill missing accent keys individually from `defaultTheme.Accents` instead of replacing the entire map.
144
+ - **Estimated effort:** Small
145
+
146
+ #### M9. No Windows build target in `buildtool`
147
+
148
+ - **Finding:** The `targets` list only includes linux/amd64, linux/arm64, darwin/amd64, darwin/arm64. No Windows target despite the project running on Windows (there's a `localExecutable()` Windows branch).
149
+ - **Evidence:** `internal/buildtool/main.go:21-26`
150
+ - **Recommended fix:** Add `{os: "windows", arch: "amd64"}` and `{os: "windows", arch: "arm64"}` to the targets list. Add `.exe` suffix handling in `writeTarGz`.
151
+ - **Estimated effort:** Small
152
+
153
+ ### Low
154
+
155
+ #### L1. Audit section allowlist in `epic_panel.go` should be configurable or data-driven
156
+
157
+ - **Finding:** `allowedSections` is a hard-coded map that determines which audit sections render in the TUI.
158
+ - **Recommended fix:** Either extract to a constant with a comment explaining why these sections are allowed, or make it configurable via config.
159
+ - **Estimated effort:** Small
160
+
161
+ #### L2. No distribution checksums
162
+
163
+ - **Finding:** `dist()` creates tar.gz archives but no SHA256 checksums file.
164
+ - **Recommended fix:** Generate a `checksums.txt` file during `dist` with SHA256 hashes of each archive.
165
+ - **Estimated effort:** Small
166
+
167
+ #### L3. `GateSuggestion` has unused `exitCode` parameter
168
+
169
+ - **Finding:** The second parameter is never referenced in the function body.
170
+ - **Evidence:** `internal/doctor/repairs.go:67`
171
+ - **Recommended fix:** Remove the parameter or use it to provide exit-code-specific suggestions.
172
+ - **Estimated effort:** Small
173
+
174
+ #### L4. `agent_skills_test.go` hardcodes expected skill count of 6
175
+
176
+ - **Finding:** The test asserts exactly 6 skills exist. Adding or removing a skill requires updating this test.
177
+ - **Recommended fix:** Remove the count assertion and just verify each skill has valid frontmatter, or derive the expected count from the directory listing.
178
+ - **Estimated effort:** Small
179
+
180
+ #### L5. Test helper duplication across packages
181
+
182
+ - **Finding:** File-writing helpers (`writeFile`, `writeTaskFixture`, etc.) are reimplemented in `board_test.go`, `checks_test.go`, and `write_test.go`.
183
+ - **Recommended fix:** Create an `internal/testutil` package with shared fixtures.
184
+ - **Estimated effort:** Medium
185
+
186
+ #### L6. `splitChecklistSentences` doesn't handle abbreviations
187
+
188
+ - **Finding:** Text splitting on `.`, `!`, `?` doesn't account for abbreviations like "e.g." or "i.e.", which could cause incorrect sentence breaks.
189
+ - **Recommended fix:** Use a more careful sentence boundary detector, or at minimum skip periods preceded by known abbreviations.
190
+ - **Estimated effort:** Small
191
+
192
+ #### L7. `Package main` test file at root level
193
+
194
+ - **Finding:** `agent_skills_test.go` is in `package main` but tests structural properties of the `agent-skills/` directory, not main package functionality. This makes it invisible to per-package test runs.
195
+ - **Recommended fix:** Move it to an appropriate subdirectory or create a `build/` or `meta/` test package.
196
+ - **Estimated effort:** Small
197
+
198
+ ---
199
+
200
+ ## 3. Complexity & Modularity Review
201
+
202
+ ### Overly large files
203
+
204
+ | File | Lines | Concern |
205
+ |------|-------|---------|
206
+ | `internal/board/update.go` | 521 | Monolithic switch handling all input, overlays, and I/O dispatch |
207
+ | `internal/doctor/checks.go` | 585 | "Check everything" monolith; each check function is OK but they share no common validation abstractions |
208
+ | `internal/data/write.go` | 216 | Two write paths (`WriteTaskStatus` and `WriteRouterState`) share YAML manipulation boilerplate |
209
+ | `internal/board/epic_panel.go` | 256 | Sidebar, detail, audit, and dropdown rendering mixed |
210
+
211
+ ### Tight coupling
212
+
213
+ - `internal/board/model.go` is a god struct (25+ fields) that every file in the board package mutates. This is idiomatic for Bubble Tea but creates a wide coupling surface.
214
+ - `update.go` directly calls I/O functions that modify the filesystem. The TUI update loop should not know about filesystem paths.
215
+
216
+ ### Mixed responsibilities
217
+
218
+ - `internal/board/board.go`'s `newProjectModel()` does discovery, file loading, watcher creation, and router reading. It's an initialization bottleneck mixing concerns.
219
+ - `model.go` contains both UI state and filesystem mutation functions (`writeRouterReleaseEpic`, `writeRouterTask`). Disk writes should be `tea.Cmd`s.
220
+
221
+ ### Repeated logic
222
+
223
+ - `\r\n` normalization appears in 4+ call sites across 2 packages
224
+ - `shortID()` is defined in `card.go` but consumed by 6+ files
225
+ - `epicIndex` and `releaseIndex` are structurally identical
226
+ - YAML frontmatter extraction + reconstruction appears in `write.go` twice with significant duplication between `updateFrontmatterField()` and `WriteTaskStatus()`
227
+
228
+ ### Unclear data flow
229
+
230
+ - `syncTaskStatus` in `transitions.go` sets `Status = string(Column)`, creating a dual-field synchronization issue. The `Task` struct has both `Status` and `Column`, and it's unclear which is authoritative.
231
+ - The `watch.go` reload silently swallows errors (returns `nil` on error).
232
+
233
+ ### Excessive abstraction (minor)
234
+
235
+ - `data.NewParser()`, `data.NewDiscover()`, `data.NewConfigReader()`, `data.NewRouterReader()` all return pointer-to-empty-struct. These could be package-level functions instead of methods on empty structs, removing unnecessary allocation and indirection.
236
+
237
+ ---
238
+
239
+ ## 4. Architecture Review
240
+
241
+ ### Folder organisation
242
+
243
+ ```
244
+ .
245
+ ├── main.go # CLI entrypoint, --version, command dispatch
246
+ ├── cmd/ # CLI arg parsing (3 commands: init, board, doctor)
247
+ ├── internal/
248
+ │ ├── board/ # TUI (17 source files, ~2300 lines)
249
+ │ ├── data/ # Models, parsing, discovery, writing (8 files)
250
+ │ ├── doctor/ # Diagnostics, checks, gates, repairs (4 files)
251
+ │ ├── init/ # Scaffolding, validation, clipboard (7 files)
252
+ │ ├── buildtool/ # Build helper (1 file, 219 lines)
253
+ │ └── styles/ # Palette + lipgloss styles (2 files)
254
+ ├── templates/ # Embedded project templates
255
+ └── agent-skills/ # Skill guides for AI agents
256
+ ```
257
+
258
+ This is well-organised. The `cmd/` → `internal/` boundary is clean: `cmd/` handles arg parsing and delegates to `internal/` via dependency-injected function types. The `internal/` packages have clear responsibilities.
259
+
260
+ ### Domain boundaries
261
+
262
+ - **Data layer** (`internal/data/`): Task lifecycle, parsing, discovery, config, writing. This is the right boundary.
263
+ - **Board/TUI** (`internal/board/`): Rendering, interaction, file watching. This package is the largest and could benefit from sub-packages, but Go's convention is to keep it flat.
264
+ - **Doctor** (`internal/doctor/`): Checks, gates, repairs, report. Each file has one job. Clean.
265
+ - **Init** (`internal/init/`): Scaffold, validate, write, clipboard, prompt. Clean.
266
+
267
+ ### State management
268
+
269
+ State management follows Bubble Tea's Elm Architecture: `Model` holds state, `Update()` processes messages and returns commands, `View()` renders. This is solid. The issue is I/O leaking into `Update()` rather than being emitted as `tea.Cmd`.
270
+
271
+ ### API/data layer structure
272
+
273
+ The data layer has no interfaces — all types are concrete structs. For this project size, this is appropriate. The `NewParser()` / `NewDiscover()` pattern returns `*Parser` / `*Discover` which are empty structs — these could just be package-level functions.
274
+
275
+ ### Configuration approach
276
+
277
+ Config is read from `.savepoint/config.yml` with sensible defaults. The `QualityGates` struct allows project-specific lint/test/typecheck commands. Theme customization supports three color tiers (truecolor, ANSI256, ANSI16). This is well-designed.
278
+
279
+ ### Error handling strategy
280
+
281
+ - **Data layer:** Uses sentinel errors (`ErrNoFrontmatter`, `ErrSavepointDirectoryMissing`, `ErrMtimeConflict`, `ErrProposalNotFound`) — good.
282
+ - **Board:** Errors from I/O inside `Update()` are displayed as status messages to the user — acceptable for a TUI.
283
+ - **Doctor:** Errors are collected into a structured `DiagnosticReport` with repair suggestions — well-designed.
284
+ - **Init:** Errors propagate up to `main.go` which prints to stderr and exits — simple and correct.
285
+
286
+ One gap: `watch.go`'s `reloadTasks` silently returns `nil` on filesystem errors, meaning a watcher failure silently blanks the board.
287
+
288
+ ---
289
+
290
+ ## 5. Best-Practice Review
291
+
292
+ ### Framework conventions
293
+
294
+ - Bubble Tea conventions are generally followed: `Init()`, `Update()`, `View()` pattern. However, I/O in `Update()` violates the framework's core principle that `Update()` should be pure. This is the biggest convention deviation.
295
+
296
+ ### Type safety
297
+
298
+ - `ColumnType`, `ProgressStage`, and `TaskStatus` are all `string` types. `TaskStatus` is defined but `Task.Column` uses `ColumnType` while `Task.Status` is a plain `string`. The `Status` field is redundant with `Column` and creates a dual-source-of-truth risk.
299
+ - `RouterState` uses `string` fields for `State`, `Release`, `Epic`, `Task` — these could benefit from typed constants similar to `ColumnType`.
300
+
301
+ ### Linting/formatting
302
+
303
+ - No linter configuration found (no `.golangci.yml`, no `golint` config). Assuming `go fmt` and `go vet` are used via `make test`.
304
+ - **Recommended:** Add `golangci-lint` with at least `errcheck`, `gosimple`, `staticcheck`, `unused`, and `ineffassign` linters.
305
+
306
+ ### Testing approach
307
+
308
+ - 264 tests across 39 test files — good coverage for core logic.
309
+ - Missing: `internal/buildtool/` (0 tests), `internal/styles/` (0 tests).
310
+ - Test helpers are duplicated across packages (write fixtures, temp directories).
311
+ - No benchmarks, no fuzz tests for the YAML parser.
312
+ - No `testdata/` directory — all fixtures are constructed inline.
313
+
314
+ ### Dependency management
315
+
316
+ - Dependencies are minimal and appropriate: `bubbletea`, `lipgloss`, `fsnotify`, `yaml.v3`, `clipboard`.
317
+ - No dependency is used for a single call that could be replaced by stdlib (except clipboard, which is inherently platform-specific).
318
+ - `gopkg.in/yaml.v3` is the only YAML parser — used consistently.
319
+
320
+ ### Build/deployment setup
321
+
322
+ - `Makefile` + `buildtool/main.go` provides `build`, `test`, `clean`, `dist`, `smoke-test`.
323
+ - The `go:embed` directive properly bundles templates.
324
+ - Missing: Windows cross-compilation, checksum generation, version injection via git tags (present but falls back to `v0.0.0`).
325
+
326
+ ### Environment variable handling
327
+
328
+ - `buildtool/version()` checks `VERSION` env var — appropriate.
329
+ - Clipboard detection uses `runtime.GOOS` — correct.
330
+
331
+ ### Logging/debugging practices
332
+
333
+ - No structured logging. Errors are printed to stderr in `main.go`.
334
+ - The TUI shows error messages as status bars. This is acceptable for a TUI app.
335
+ - **Gap:** No verbose/debug flag for TUI troubleshooting. Adding `--debug` or `SAVEPOINT_DEBUG` env var would help.
336
+
337
+ ---
338
+
339
+ ## 6. Refactor Roadmap
340
+
341
+ ### Phase 1 — Safe cleanup
342
+
343
+ **Objective:** Remove dead code, fix easy bugs, reduce cognitive load without behavior changes.
344
+
345
+ | Task | Risk |
346
+ |------|------|
347
+ | Remove `taskLabel()` from `column.go` (dead code) | Very Low |
348
+ | Remove `CheckResult` type from `report.go` (dead code) | Very Low |
349
+ | Remove unused `exitCode` parameter from `GateSuggestion` | Very Low |
350
+ | Replace `contains()`/`indexOf()` with `strings.Contains`/`strings.Index` in `repairs.go` | Very Low |
351
+ | Replace `trimSpace()` with `bytes.TrimSpace` in `buildtool/main.go` | Very Low |
352
+ | Replace `validStates` map with `data.IsCanonicalColumn()`/`data.IsCanonicalStage()` | Low |
353
+ | Co-locate layout constants (`colOverhead`) into `layout.go` | Low |
354
+ | Add `\r\n` normalization helper to `data/` package | Low |
355
+ | Centralize duplicated test helpers into `internal/testutil/` | Low |
356
+ | Fix cycle detection path reconstruction in `checks.go` | Low |
357
+
358
+ **Expected benefit:** Cleaner codebase, fewer surprises, eliminates one actual bug (cycle detection).
359
+
360
+ ### Phase 2 — Structural improvements
361
+
362
+ **Objective:** Decompose the update monolith, improve data flow, extract shared utilities.
363
+
364
+ | Task | Risk |
365
+ |------|------|
366
+ | Extract overlay handlers from `update.go` into per-overlay functions | Medium |
367
+ | Extract `handleBoardKey()` from `update.go` | Medium |
368
+ | Move `shortID`, `WrapText`, `SplitLongWord`, `truncate` to a utility file | Medium |
369
+ | Generalize `epicIndex`/`releaseIndex` into `indexOrZero` | Low |
370
+ | Make `data.NewParser/Discover/ConfigReader/RouterReader` package-level functions | Low |
371
+ | Fix `AtomicWrite` cross-device fallback to use `io.Copy` | Medium |
372
+ | Make `Config.Theme.Accents` fill missing keys individually | Low |
373
+ | Add Windows build targets to `buildtool` | Low |
374
+ | Add checksum generation to `dist` | Low |
375
+
376
+ **Expected benefit:** Reduced file complexity, better separation of concerns, cross-platform correctness.
377
+
378
+ ### Phase 3 — Hardening
379
+
380
+ **Objective:** Fix the I/O-in-update anti-pattern, add missing tests, improve security.
381
+
382
+ | Task | Risk |
383
+ |------|------|
384
+ | Refactor all filesystem I/O in `update.go` to `tea.Cmd` functions | Medium-High |
385
+ | Add `tea.Cmd`-based router writing for priority key and epic selection | Medium |
386
+ | Add timeout to quality gate execution (`exec.CommandContext`) | Low |
387
+ | Convert `SuggestRepair` to typed error matching | Medium |
388
+ | Add tests for `buildtool/` | Low |
389
+ | Add tests for `styles/` | Low |
390
+ | Add benchmark tests for render functions (`RenderColumn`, `RenderCard`, `RenderDetail`) | Low |
391
+ | Add fuzz targets for YAML frontmatter parsing | Low |
392
+ | Fix `watch.go` error handling (don't silently swallow errors) | Medium |
393
+ | Add `--debug`/`SAVEPOINT_DEBUG` flag for TUI troubleshooting | Low |
394
+ | Improve `splitChecklistSentences` for abbreviation handling | Low |
395
+
396
+ **Expected benefit:** TUI responsiveness, correct error propagation, test coverage completeness, security.
397
+
398
+ ---
399
+
400
+ ## 7. Top 10 Action List
401
+
402
+ - [ ] **Extract I/O from `update.go` into `tea.Cmd` functions** — Critical — `internal/board/update.go`, `internal/board/model.go` — Prevents TUI freezes on slow disk; follows Bubble Tea conventions; highest architectural impact
403
+ - [ ] **Fix cycle detection path reconstruction in `checks.go`** — High (bug) — `internal/doctor/checks.go` — Produces inaccurate error messages today
404
+ - [ ] **Decompose `update.go` overlay handling into per-type handlers** — High — `internal/board/update.go` — Reduces 521-line file complexity; makes adding new overlays safe
405
+ - [ ] **Replace stdlib reimplmentations (`contains`, `indexOf`, `trimSpace`)** — High — `internal/doctor/repairs.go`, `internal/buildtool/main.go` — Eliminates confusing custom code
406
+ - [ ] **Add timeout to quality gate execution** — High — `internal/doctor/gates.go` — Prevents indefinite blocking
407
+ - [ ] **Centralize `\r\n` normalization into a shared function** — Medium — `internal/data/parser.go`, `internal/data/write.go`, `internal/board/epic_panel.go` — Single source of truth for cross-platform line endings
408
+ - [ ] **Consolidate layout constants and shared utilities** — Medium — `internal/board/column.go`, `internal/board/layout.go`, `internal/board/card.go`, `internal/board/detail.go` — Reduces scatter and makes layout logic findable
409
+ - [ ] **Fix `AtomicWrite` cross-device rename fallback** — Medium — `internal/init/write.go` — Prevents silent data loss on cross-filesystem moves
410
+ - [ ] **Remove dead code (`taskLabel`, `CheckResult`, unused params)** — Low — `internal/board/column.go`, `internal/doctor/report.go`, `internal/doctor/repairs.go` — Reduces clutter
411
+ - [ ] **Add tests for `buildtool/` and `styles/`** — Medium — `internal/buildtool/`, `internal/styles/` — Achieves baseline coverage for untested packages