savepoint 1.0.0 → 1.0.2

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 (136) hide show
  1. package/.claude/settings.local.json +8 -1
  2. package/.savepoint/Design.md +26 -17
  3. package/.savepoint/audit/v1/E01/proposals.md +168 -0
  4. package/.savepoint/audit/v1/E01/snapshot.md +78 -0
  5. package/.savepoint/audit/{E01-go-setup → v1/E01-go-setup}/proposals.md +7 -7
  6. package/.savepoint/audit/{E01-go-setup → v1/E01-go-setup}/snapshot.md +2 -2
  7. package/.savepoint/audit/{E01-scaffolding → v1/E01-scaffolding}/proposals/AGENTS.md +5 -5
  8. package/.savepoint/audit/{E02-data-readers → v1/E02-data-readers}/proposals.md +20 -20
  9. package/.savepoint/audit/{E02-data-readers → v1/E02-data-readers}/snapshot.md +1 -1
  10. package/.savepoint/audit/{E03-board-tui-core → v1/E03-board-tui-core}/proposals.md +11 -11
  11. package/.savepoint/audit/{E03-board-tui-core → v1/E03-board-tui-core}/snapshot.md +1 -1
  12. package/.savepoint/audit/{E04-board-components → v1/E04-board-components}/proposals.md +14 -14
  13. package/.savepoint/audit/{E04-board-components → v1/E04-board-components}/snapshot.md +1 -1
  14. package/.savepoint/audit/{E05-init-command → v1/E05-init-command}/snapshot.md +1 -1
  15. package/.savepoint/audit/{E05-phase-transitions → v1/E05-phase-transitions}/proposals.md +4 -4
  16. package/.savepoint/audit/{E05-phase-transitions → v1/E05-phase-transitions}/snapshot.md +1 -1
  17. package/.savepoint/audit/v1/E06-atari-noir-layout/proposals.md +130 -0
  18. package/.savepoint/audit/v1/E06-atari-noir-layout/snapshot.md +84 -0
  19. package/.savepoint/audit/{E07-audit-pipeline → v1/E07-audit-pipeline}/snapshot.md +6 -6
  20. package/.savepoint/audit/v1.1/E02-cross-platform-compatibility/proposals.md +114 -0
  21. package/.savepoint/audit/v1.1/E02-cross-platform-compatibility/snapshot.md +41 -0
  22. package/.savepoint/audit/v1.1/E04-epic-navigation/proposals.md +156 -0
  23. package/.savepoint/audit/v1.1/E04-epic-navigation/snapshot.md +48 -0
  24. package/.savepoint/config.yml +3 -3
  25. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T001-init-module.md +1 -1
  26. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T005-layout.md +1 -1
  27. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T002-card.md +1 -1
  28. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T006-help-overlay.md +1 -1
  29. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/E06-Detail.md +62 -0
  30. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T002-header-and-dividers.md +1 -1
  31. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T003-footer-status-bar.md +1 -1
  32. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T004-component-refinement.md +1 -1
  33. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T007-detail-card-fixes.md +7 -7
  34. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T008-checkbox-states.md +10 -8
  35. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T009-router-priority-marker.md +16 -9
  36. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T010-auto-refresh-watcher.md +27 -22
  37. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/E01-Detail.md +40 -0
  38. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T001-next-activity-header.md +56 -0
  39. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T002-rename-epic-design-files.md +38 -0
  40. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T003-rename-release-prd.md +28 -0
  41. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T004-update-instruction-files.md +51 -0
  42. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T005-update-cross-references.md +45 -0
  43. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T006-column-and-detail-scrolling.md +68 -0
  44. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T007-column-focus-border-stability.md +57 -0
  45. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/E02-Detail.md +49 -0
  46. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T001-fix-makefile.md +37 -0
  47. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T002-linux-build-target.md +38 -0
  48. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T003-macos-build-target.md +36 -0
  49. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T004-smoke-tests-and-artifacts.md +59 -0
  50. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Detail.md +32 -0
  51. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T001-border-resize-fix.md +40 -0
  52. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T002-next-activity-below-header.md +64 -0
  53. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T003-checkbox-rendering-fix.md +56 -0
  54. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T005-unify-status-glyphs.md +65 -0
  55. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T006-forced-256-color-profile.md +36 -0
  56. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Detail.md +51 -0
  57. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T001-sidebar-focusable-navigation.md +65 -0
  58. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T002-epic-detail-overlay.md +73 -0
  59. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T003-epic-status-glyphs.md +73 -0
  60. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Detail.md +45 -0
  61. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T001-update-agents-md.md +34 -0
  62. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T002-update-router-md.md +30 -0
  63. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T003-update-design-md.md +33 -0
  64. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T004-implement-m-hotkey.md +88 -0
  65. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T005-update-help-overlay.md +30 -0
  66. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T006-tests-and-quality-gates.md +46 -0
  67. package/.savepoint/releases/v1.1/v1.1-PRD.md +79 -0
  68. package/.savepoint/router.md +33 -105
  69. package/.savepoint/visual-identity.md +4 -3
  70. package/AGENTS.md +56 -113
  71. package/Makefile +19 -3
  72. package/README.md +7 -6
  73. package/agent-skills/savepoint-audit/SKILL.md +6 -6
  74. package/agent-skills/savepoint-build-task/SKILL.md +2 -2
  75. package/agent-skills/savepoint-create-plan/SKILL.md +3 -3
  76. package/agent-skills/savepoint-create-task/SKILL.md +2 -2
  77. package/agent-skills/savepoint-draft-prd/SKILL.md +1 -1
  78. package/agent-skills/savepoint-system-design/SKILL.md +1 -1
  79. package/go.mod +4 -1
  80. package/go.sum +2 -0
  81. package/internal/board/board.go +66 -14
  82. package/internal/board/board_test.go +124 -0
  83. package/internal/board/card.go +40 -3
  84. package/internal/board/card_test.go +121 -14
  85. package/internal/board/column.go +40 -5
  86. package/internal/board/column_test.go +65 -10
  87. package/internal/board/detail.go +115 -23
  88. package/internal/board/detail_test.go +132 -25
  89. package/internal/board/epic_panel.go +105 -8
  90. package/internal/board/epic_panel_test.go +343 -5
  91. package/internal/board/layout.go +12 -2
  92. package/internal/board/layout_test.go +17 -0
  93. package/internal/board/model.go +146 -23
  94. package/internal/board/render_policy_test.go +77 -0
  95. package/internal/board/status.go +23 -0
  96. package/internal/board/update.go +300 -9
  97. package/internal/board/update_test.go +166 -0
  98. package/internal/board/view.go +141 -17
  99. package/internal/board/view_test.go +161 -3
  100. package/internal/board/watch.go +100 -0
  101. package/internal/buildtool/main.go +219 -0
  102. package/internal/data/parser.go +39 -1
  103. package/internal/data/parser_test.go +43 -2
  104. package/internal/data/task.go +22 -2
  105. package/internal/styles/palette.go +9 -7
  106. package/internal/styles/styles.go +42 -25
  107. package/main.go +9 -0
  108. package/package.json +5 -4
  109. package/savepoint +0 -0
  110. package/savepoint.exe +0 -0
  111. package/templates/project/.savepoint/router.md +6 -5
  112. package/templates/project/AGENTS.md +47 -101
  113. package/templates/prompts/audit-reconciliation.prompt.md +6 -6
  114. package/templates/prompts/epic-design.prompt.md +3 -3
  115. package/templates/prompts/task-breakdown.prompt.md +1 -1
  116. package/templates/prompts/task-building.prompt.md +1 -1
  117. package/templates/prompts/task-planning.prompt.md +1 -1
  118. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/Design.md +0 -42
  119. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/Design.md +0 -26
  120. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T001-border-resize-fix.md +0 -35
  121. package/main.exe +0 -0
  122. /package/.savepoint/audit/{E01-scaffolding → v1/E01-scaffolding}/proposals/Design.md +0 -0
  123. /package/.savepoint/audit/{E01-scaffolding → v1/E01-scaffolding}/proposals/epic-Design.md +0 -0
  124. /package/.savepoint/audit/{E01-scaffolding → v1/E01-scaffolding}/proposals/quality-review.md +0 -0
  125. /package/.savepoint/audit/{E01-scaffolding → v1/E01-scaffolding}/snapshot.md +0 -0
  126. /package/.savepoint/audit/{E02-data-model → v1/E02-data-model}/snapshot.md +0 -0
  127. /package/.savepoint/audit/{E03-cli-foundation → v1/E03-cli-foundation}/snapshot.md +0 -0
  128. /package/.savepoint/audit/{E04-templates-and-prompts → v1/E04-templates-and-prompts}/snapshot.md +0 -0
  129. /package/.savepoint/audit/{E06-tui-board → v1/E06-tui-board}/snapshot.md +0 -0
  130. /package/.savepoint/audit/{E08-board-workflow-cleanup → v1/E08-board-workflow-cleanup}/snapshot.md +0 -0
  131. /package/.savepoint/releases/v1/epics/E01-go-setup/{Design.md → E01-Detail.md} +0 -0
  132. /package/.savepoint/releases/v1/epics/E02-data-readers/{Design.md → E02-Detail.md} +0 -0
  133. /package/.savepoint/releases/v1/epics/E03-board-tui-core/{Design.md → E03-Detail.md} +0 -0
  134. /package/.savepoint/releases/v1/epics/E04-board-components/{Design.md → E04-Detail.md} +0 -0
  135. /package/.savepoint/releases/v1/epics/E05-phase-transitions/{Design.md → E05-Detail.md} +0 -0
  136. /package/.savepoint/releases/v1/{PRD.md → v1-PRD.md} +0 -0
@@ -0,0 +1,156 @@
1
+ # Audit Proposals: v1.1 E04 Epic Navigation
2
+
3
+ ## Target File
4
+
5
+ `.savepoint/Design.md`
6
+
7
+ ## Replace
8
+
9
+ ```yaml
10
+ last_audited: E01-tui-optimisation (2026-05-02)
11
+ ```
12
+
13
+ ## With
14
+
15
+ ```yaml
16
+ last_audited: E04-epic-navigation (2026-05-02)
17
+ ```
18
+
19
+ ## Target File
20
+
21
+ `.savepoint/Design.md`
22
+
23
+ ## Replace
24
+
25
+ ```md
26
+ - **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, and stable focused/unfocused column border geometry (v1.1 E01).
27
+ ```
28
+
29
+ ## With
30
+
31
+ ```md
32
+ - **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), and a focusable wide-screen epic sidebar with purple epic focus, epic detail overlays, and status glyphs loaded from epic detail frontmatter (v1.1 E04).
33
+ ```
34
+
35
+ ## Target File
36
+
37
+ `.savepoint/Design.md`
38
+
39
+ ## Replace
40
+
41
+ ```md
42
+ **Layout:** single screen with a 3-column task board (`planned`, `in_progress`, `done`), optional epic sidebar on wide terminals, centered overlays for release/epic/help/task detail, static Atari-Noir header/footer, full-width dividers, uniform black TUI backgrounds, and navigation hints. The header can show a compact right-aligned Next Activity value from router state. Columns and detail overlays use height-aware viewport slicing with subtle above/more scroll indicators. Focused and unfocused columns preserve the same rounded-border geometry so focus changes do not shift content. Non-TTY output remains a plain table fallback.
43
+ ```
44
+
45
+ ## With
46
+
47
+ ```md
48
+ **Layout:** single screen with a 3-column task board (`planned`, `in_progress`, `done`), optional epic sidebar on wide terminals, centered overlays for release/epic/help/task/epic-detail views, static Atari-Noir header/footer, full-width dividers, uniform black TUI backgrounds, and navigation hints. The header can show a compact right-aligned Next Activity value from router state. Columns and detail overlays use height-aware viewport slicing with subtle above/more scroll indicators. Focused and unfocused columns preserve the same rounded-border geometry so focus changes do not shift content. On terminals at least 120 columns wide, the epic sidebar is focusable from the Planned column; it uses the purple epic accent for focused panel borders, focused epic labels, and epic detail overlays while task-column focus remains orange. Non-TTY output remains a plain table fallback.
49
+ ```
50
+
51
+ ## Target File
52
+
53
+ `.savepoint/Design.md`
54
+
55
+ ## Replace
56
+
57
+ ```md
58
+ **Board persistence and refresh:** task status transitions write canonical task frontmatter through `internal/data.WriteTaskStatus` with mtime conflict checks. The board treats `Model.Root` as the `.savepoint` directory, watches `.savepoint/releases/` recursively with fsnotify, adds watches for newly-created release/epic/task directories, and reloads task plus release/epic index data after debounced file changes. Router priority markers match release + epic + task, not only the short `T###` value; completed cards render with the orange build glyph even if they previously matched router priority.
59
+ ```
60
+
61
+ ## With
62
+
63
+ ```md
64
+ **Board persistence and refresh:** task status transitions write canonical task frontmatter through `internal/data.WriteTaskStatus` with mtime conflict checks. The board treats `Model.Root` as the `.savepoint` directory, watches `.savepoint/releases/` recursively with fsnotify, adds watches for newly-created release/epic/task directories, and reloads task plus release/epic index data plus epic status metadata after debounced file changes. Router priority markers match release + epic + task, not only the short `T###` value; completed cards render with the orange build glyph even if they previously matched router priority. Epic status glyphs are cached from each epic's `E##-Detail.md` frontmatter and shown in the wide epic sidebar only.
65
+ ```
66
+
67
+ ## Target File
68
+
69
+ `AGENTS.md`
70
+
71
+ ## Replace
72
+
73
+ ```md
74
+ | `internal/board/` | TUI board models, layout, rendering, overlays, task transitions, router priority markers, and fsnotify refresh |
75
+ | `internal/data/` | Task/router/config models, frontmatter parsing, checklist state parsing, mtime-guarded writes, discovery, and generic file readers |
76
+ | `internal/styles/` | Atari-Noir palette constants, terminal color fallbacks, shared TUI styles, stable column border styles, scroll indicators, semantic glyph/tag styles, and footer/header styling |
77
+ ```
78
+
79
+ ## With
80
+
81
+ ```md
82
+ | `internal/board/` | TUI board models, layout, rendering, overlays, focusable epic sidebar navigation, epic detail overlays, epic status glyph loading, task transitions, router priority markers, and fsnotify refresh |
83
+ | `internal/data/` | Task/router/config models, frontmatter parsing, checklist state parsing, mtime-guarded writes, discovery, and generic file readers |
84
+ | `internal/styles/` | Atari-Noir palette constants, terminal color fallbacks, shared TUI styles, stable column border styles, scroll indicators, purple epic navigation/detail styles, semantic glyph/tag styles, and footer/header styling |
85
+ ```
86
+
87
+ ## Target File
88
+
89
+ `.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Detail.md`
90
+
91
+ ## Replace
92
+
93
+ ```yaml
94
+ status: planned
95
+ ```
96
+
97
+ ## With
98
+
99
+ ```yaml
100
+ status: audited
101
+ ```
102
+
103
+ ## Target File
104
+
105
+ `.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Detail.md`
106
+
107
+ ## Replace
108
+
109
+ ```md
110
+ ## Architectural notes
111
+
112
+ - `EpicPanelFocus bool` is a lightweight flag replacing the need for a new column type
113
+ - The epic detail overlay content is read from `E##-Detail.md` on the filesystem when Enter is pressed (not pre-loaded)
114
+ - Detail file path is deterministic: `{root}/releases/{release}/epics/{epic-slug}/{shortID}-Detail.md`
115
+ - If the detail file is missing, the overlay shows a "(no detail available)" message
116
+ - Column selection, task selection, and existing overlay behavior are completely unchanged
117
+ ```
118
+
119
+ ## With
120
+
121
+ ```md
122
+ ## Architectural notes
123
+
124
+ - `EpicPanelFocus bool` is a lightweight flag replacing the need for a new column type
125
+ - The epic detail overlay content is read from `E##-Detail.md` on the filesystem when Enter is pressed (not pre-loaded)
126
+ - Detail file path is deterministic: `{root}/releases/{release}/epics/{epic-slug}/{shortID}-Detail.md`
127
+ - If the detail file is missing, the overlay shows a "(no detail available)" message
128
+ - Column selection, task selection, and existing overlay behavior are completely unchanged
129
+
130
+ ## Implemented as
131
+
132
+ - `internal/board/model.go` adds `EpicPanelFocus`, `EpicPanelCursor`, `EpicDetailOffset`, `EpicDetailContent`, and `EpicStatus` model state.
133
+ - `internal/board/update.go` handles global keys before epic-panel routing, focuses the panel from the Planned column on wide layouts, changes the selected epic during panel cursor movement, writes router release/epic state, and opens the epic detail overlay on Enter.
134
+ - `internal/board/epic_panel.go` renders the purple-accented epic sidebar focus state, purple epic detail overlay, markdown detail body, and side-panel-only status glyph prefixes.
135
+ - `internal/board/board.go` loads epic status frontmatter during board-data loading; `internal/board/watch.go` carries that status map through reloads.
136
+ - Epic navigation deliberately uses `VibePurple` (`#B1A1DF`) for focused epic panel borders, focused epic labels, epic detail overlays, and epic/audit accents, while task-column focus remains Atari Orange.
137
+ - Implementation deviation: T001 originally said Enter in epic-panel focus selected the focused epic. The final behavior from T002 is that up/down selects and filters immediately, while Enter opens the epic detail overlay.
138
+ ```
139
+
140
+ ## Quality Review
141
+
142
+ ## Must Fix Before Close
143
+
144
+ None.
145
+
146
+ ## Carry Forward
147
+
148
+ - Accepted design decision: `RenderEpicDetail` intentionally omits the components/files table from the overlay for readability. The epic detail overlay shows the narrative sections and keeps implementation file mapping in the source `E##-Detail.md`.
149
+ - `readEpicDetailFile` falls back to `E##-Design.md` and then any `E##-*.md`, which is more permissive than the epic design's deterministic path. The fallback is harmless and user-friendly, but it should be documented if kept as product behavior.
150
+ - `epicPanelPageSize()` was added for eventual PgUp/PgDown support but is not currently used. This is minor dead code carried from the task plan and can be removed or wired in during a future sidebar paging task.
151
+
152
+ ## Already Fixed
153
+
154
+ - Global `q`, `e`, `r`, and `?` keys are processed before epic-panel-specific key handling, so panel focus does not trap quit, release, epic dropdown, or help commands.
155
+ - Focused epic sidebar rendering uses purple focused border/title/item styles, making the colour-scheme shift from task orange to epic purple visible in the TUI.
156
+ - Focused board tests, `go build -o savepoint main.go`, and `go test ./...` pass.
@@ -0,0 +1,48 @@
1
+ ---
2
+ type: audit-snapshot
3
+ release: v1.1
4
+ epic: E04-epic-navigation
5
+ created: 2026-05-02
6
+ source: manual-router-snapshot
7
+ ---
8
+
9
+ # Audit Snapshot: v1.1 E04 Epic Navigation
10
+
11
+ The audit CLI snapshot was missing when the router entered `audit-pending`. Per router guidance, this manual snapshot is scoped to the known epic and task records only.
12
+
13
+ ## Epic Scope
14
+
15
+ - `.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Detail.md`
16
+ - `.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T001-sidebar-focusable-navigation.md`
17
+ - `.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T002-epic-detail-overlay.md`
18
+ - `.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T003-epic-status-glyphs.md`
19
+
20
+ ## Changed Files Recorded by Tasks
21
+
22
+ - `internal/board/model.go`
23
+ - `internal/board/update.go`
24
+ - `internal/board/view.go`
25
+ - `internal/board/epic_panel.go`
26
+ - `internal/board/board.go`
27
+ - `internal/board/watch.go`
28
+ - `internal/board/epic_panel_test.go`
29
+ - `internal/board/update_test.go`
30
+ - `internal/board/board_test.go`
31
+ - `internal/styles/styles.go`
32
+ - `internal/styles/palette.go`
33
+ - `.savepoint/config.yml`
34
+
35
+ ## Implemented Delta
36
+
37
+ - Wide-board epic sidebar is focusable from the Planned column and returns focus to the board with right arrow.
38
+ - Epic-panel up/down navigation selects the focused epic immediately, filters visible tasks, and writes release/epic router state.
39
+ - Enter from epic-panel focus opens an `EPIC DETAIL` overlay backed by the selected epic detail markdown file.
40
+ - Epic detail overlay supports esc/q close, line scrolling, and page scrolling.
41
+ - Epic status glyphs are loaded from each epic detail file's `status` frontmatter at board-data load time and propagated through reloads.
42
+ - Epic panel focus, epic item focus, epic detail overlay, and epic/audit accents now use `VibePurple` (`#B1A1DF`) rather than the orange task-column focus color.
43
+
44
+ ## Verification Evidence
45
+
46
+ - `go test ./internal/board` passed.
47
+ - `go build -o savepoint main.go` passed.
48
+ - `go test ./...` passed.
@@ -13,9 +13,9 @@ audit:
13
13
  divergence_threshold: 0.5 # warn if a proposal changes >50% of a live file
14
14
 
15
15
  theme:
16
- bg: "#121212"
17
- surface: "#0D0D0D"
18
- surface_2: "#0F0F0F"
16
+ bg: "#000000"
17
+ surface: "#000000"
18
+ surface_2: "#000000"
19
19
  border: "#1A1A1A"
20
20
  text: "#F0E6DA"
21
21
  accents:
@@ -27,7 +27,7 @@ depends_on: []
27
27
  Files read:
28
28
 
29
29
  - `.savepoint/router.md`
30
- - `.savepoint/releases/v1/epics/E01-go-setup/Design.md`
30
+ - `.savepoint/releases/v1/epics/E01-go-setup/E01-Detail.md`
31
31
  - `.savepoint/releases/v1/epics/E01-go-setup/tasks/T001-init-module.md`
32
32
  - `go.mod`
33
33
  - `go.sum`
@@ -25,7 +25,7 @@ depends_on: [E03-board-tui-core/T004-styles]
25
25
 
26
26
  ## Context Log
27
27
 
28
- Files read: internal/board/model.go, view.go, update.go, board.go, view_test.go, update_test.go, model_test.go, internal/styles/styles.go, go.mod, .savepoint/releases/v1/epics/E03-board-tui-core/Design.md
28
+ Files read: internal/board/model.go, view.go, update.go, board.go, view_test.go, update_test.go, model_test.go, internal/styles/styles.go, go.mod, .savepoint/releases/v1/epics/E03-board-tui-core/E03-Detail.md
29
29
 
30
30
  Estimated input tokens: ~6 000
31
31
 
@@ -26,7 +26,7 @@ depends_on: [E04-board-components/T001-column]
26
26
 
27
27
  ## Context Log
28
28
 
29
- Files read: `internal/board/column.go`, `internal/board/column_test.go`, `internal/styles/styles.go`, `internal/styles/palette.go`, `internal/data/task.go`, `.savepoint/releases/v1/epics/E04-board-components/Design.md`, `AGENTS.md`, `.savepoint/router.md`
29
+ Files read: `internal/board/column.go`, `internal/board/column_test.go`, `internal/styles/styles.go`, `internal/styles/palette.go`, `internal/data/task.go`, `.savepoint/releases/v1/epics/E04-board-components/E04-Detail.md`, `AGENTS.md`, `.savepoint/router.md`
30
30
 
31
31
  Estimated input tokens: ~4 000
32
32
 
@@ -24,7 +24,7 @@ depends_on: [E04-board-components/T005-release-dropdown]
24
24
 
25
25
  ## Context Log
26
26
 
27
- Files read: `.savepoint/router.md`, `.savepoint/releases/v1/epics/E04-board-components/Design.md`, this task file, `agent-skills/ink-tui-design/SKILL.md`, `.savepoint/visual-identity.md`, `internal/board/model.go`, `internal/board/update.go`, `internal/board/view.go`, `internal/board/detail.go`, `internal/board/epic_panel.go`, `internal/board/release.go`, `internal/board/update_test.go`, `internal/board/view_test.go`, `internal/board/detail_test.go`, `internal/board/release_test.go`, `internal/styles/styles.go`, `go.mod`, `Makefile`
27
+ Files read: `.savepoint/router.md`, `.savepoint/releases/v1/epics/E04-board-components/E04-Detail.md`, this task file, `agent-skills/ink-tui-design/SKILL.md`, `.savepoint/visual-identity.md`, `internal/board/model.go`, `internal/board/update.go`, `internal/board/view.go`, `internal/board/detail.go`, `internal/board/epic_panel.go`, `internal/board/release.go`, `internal/board/update_test.go`, `internal/board/view_test.go`, `internal/board/detail_test.go`, `internal/board/release_test.go`, `internal/styles/styles.go`, `go.mod`, `Makefile`
28
28
  Estimated input tokens: ~8500
29
29
  Notes: Added help overlay renderer, `?` key handling, centered overlay rendering over dimmed board, and focused render/update/view tests. Focused test `go test ./internal/board/...` initially failed in the sandbox because Go could not access the external build cache; rerun with approved cache access passed. Quality gates: `go build ./...` pass, `go vet ./...` pass, `go test ./...` pass.
30
30
 
@@ -0,0 +1,62 @@
1
+ ---
2
+ type: epic-design
3
+ status: audited
4
+ ---
5
+
6
+ # Epic E06: Atari-Noir Layout Uplift
7
+
8
+ ## Purpose
9
+
10
+ Update the existing TUI to align with the **Atari-Noir SavePoint design system**. This is a visual and layout uplift focused on restraint, clarity, and control, preserving existing functionality while eliminating visual noise and strictly adhering to the new color and layout rules.
11
+
12
+ ## What this epic adds
13
+
14
+ - Centralized Atari-Noir color system in `palette.go`.
15
+ - Restructured `styles.go` mapped to exact usage rules.
16
+ - Static header component: `▣ S A V E P O I N T`.
17
+ - Static footer component: `PLAN │ BUILD │ AUDIT`.
18
+ - Full-width subtle horizontal dividers.
19
+ - Refined component styling (columns, cards, epic panel) to remove unnecessary borders and improve spacing.
20
+
21
+ ## Definition of Done
22
+
23
+ - All colors match the Atari-Noir strict specification.
24
+ - Header renders correctly with no wrapping.
25
+ - Footer displays PLAN / BUILD / AUDIT cleanly without dynamic status text.
26
+ - Full-width dividers frame the content.
27
+ - Cards/panels feel like surfaces, not text blocks.
28
+ - Spacing is consistent and components breathe.
29
+ - Focus/selection is obvious through position and Atari Orange borders, not relying solely on color text changes.
30
+ - Existing functionality remains 100% intact.
31
+
32
+ ## Components and files
33
+
34
+ | Path | Purpose |
35
+ |------|---------|
36
+ | `internal/styles/palette.go` | Define strict hex values |
37
+ | `internal/styles/styles.go` | Map styles to new usage rules |
38
+ | `internal/board/view.go` | Implement header, footer, dividers |
39
+ | `internal/board/layout.go` | Adjust layout height calculations |
40
+ | `internal/board/column.go` | Refine column styling and spacing |
41
+ | `internal/board/card.go` | Refine card surface and focus state |
42
+ | `internal/board/epic_panel.go` | Refine epic panel layout |
43
+
44
+ ## Implemented As
45
+
46
+ - `internal/styles/palette.go` defines the Atari-Noir hex palette plus ANSI256/ANSI16 fallbacks.
47
+ - `internal/styles/styles.go` centralizes header, divider, footer, column, card, detail, glyph, and semantic tag styles.
48
+ - `internal/board/view.go` renders the static SavePoint header, explicit full-width top/bottom dividers, the static `PLAN │ BUILD │ AUDIT` footer, subdued navigation hints, and overlay composition.
49
+ - `internal/board/card.go` wraps long task titles instead of truncating them, uses a green `▣` marker only for the release/epic/task-scoped router-priority task, and keeps all done cards on the orange build glyph.
50
+ - `internal/board/detail.go` adds spacing below Acceptance Criteria and Implementation Plan headings, renders checklist state with `☑`/`□`, and labels only the release/epic/task-scoped router-priority task.
51
+ - `internal/data/task.go` and `internal/data/parser.go` represent Implementation Plan items as `CheckItem{Text, Done}` and parse `- [x]`, `- [ ]`, and legacy `- ` items.
52
+ - `internal/data/write.go` persists task status and phase changes with mtime conflict protection.
53
+ - `internal/board/watch.go` adds fsnotify-based recursive release directory watching from the `.savepoint/releases/` root, dynamically adds watches for newly-created subdirectories, applies a 100ms debounce, and sends reload messages used by `internal/board/update.go`.
54
+
55
+ ## Implementation Deltas
56
+
57
+ - The original visual-only scope expanded to include board usability fixes requested during E06: footer navigation hints, detail overlay spacing, card title word-wrap, checklist state rendering, router priority markers, and auto-refresh on task file changes.
58
+ - Audit closeout removed unnecessary borders from unfocused header, board, column, card, and epic-panel surfaces while preserving Atari Orange borders for focused cards/columns and detail overlays.
59
+ - User-approved visual guardrail: Background, Surface, and Surface 2 are intentionally the same black value in the terminal TUI. Do not reintroduce subtly different background fills for panels/cards.
60
+ - The main view now renders explicit full-width divider lines with `styles.Divider` rather than relying on component frames as separators.
61
+ - Auto-refresh reload now refreshes both task data and release/epic indexes so newly-added task files and newly-added epic directories can appear without restarting the board.
62
+ - Router-priority matching is intentionally scoped by release and epic before task number; a router task of `T001` must not mark every epic's `T001` as priority.
@@ -27,7 +27,7 @@ depends_on: ["E06-atari-noir-layout/T001-color-system"]
27
27
 
28
28
  Files read:
29
29
  - `.savepoint/router.md`
30
- - `.savepoint/releases/v1/epics/E06-atari-noir-layout/Design.md`
30
+ - `.savepoint/releases/v1/epics/E06-atari-noir-layout/E06-Detail.md`
31
31
  - `.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T002-header-and-dividers.md`
32
32
  - `.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T001-color-system.md`
33
33
  - `.savepoint/visual-identity.md`
@@ -30,7 +30,7 @@ depends_on: ["E06-atari-noir-layout/T002-header-and-dividers"]
30
30
 
31
31
  Files read:
32
32
  - `.savepoint/router.md`
33
- - `.savepoint/releases/v1/epics/E06-atari-noir-layout/Design.md`
33
+ - `.savepoint/releases/v1/epics/E06-atari-noir-layout/E06-Detail.md`
34
34
  - `.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T003-footer-status-bar.md`
35
35
  - `.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T002-header-and-dividers.md`
36
36
  - `.savepoint/visual-identity.md`
@@ -26,7 +26,7 @@ depends_on: ["E06-atari-noir-layout/T001-color-system"]
26
26
 
27
27
  Files read:
28
28
  - `.savepoint/router.md`
29
- - `.savepoint/releases/v1/epics/E06-atari-noir-layout/Design.md`
29
+ - `.savepoint/releases/v1/epics/E06-atari-noir-layout/E06-Detail.md`
30
30
  - `.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T004-component-refinement.md`
31
31
  - `internal/styles/palette.go`
32
32
  - `internal/styles/styles.go`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  id: E06-atari-noir-layout/T007-detail-card-fixes
3
- status: planned
3
+ status: done
4
4
  objective: "Add line breaks under Acceptance Criteria and Implementation Plan headings in task detail, and word-wrap card titles instead of truncating"
5
5
  depends_on: []
6
6
  ---
@@ -18,11 +18,11 @@ depends_on: []
18
18
 
19
19
  ## Implementation Plan
20
20
 
21
- - [ ] Edit `internal/board/detail.go` — add `""` entry after the `Acceptance Criteria:` heading line and after the `Implementation Plan:` heading line.
22
- - [ ] Edit `internal/board/detail.go` — make `wrapText` and `splitLongWord` exported (capitalize) so they can be reused from `card.go`.
23
- - [ ] Edit `internal/board/card.go` — replace `truncate(t.Title, inner)` with a multi-line approach that word-wraps the title across available width.
24
- - [ ] Edit `internal/board/card.go` — combine wrapped title lines with newlines in the card content (joining with `\n`).
25
- - [ ] Run `make build && make test` to verify no regressions.
21
+ - [x] Edit `internal/board/detail.go` — add `""` entry after the `Acceptance Criteria:` heading line and after the `Implementation Plan:` heading line.
22
+ - [x] Edit `internal/board/detail.go` — make `wrapText` and `splitLongWord` exported (capitalize) so they can be reused from `card.go`.
23
+ - [x] Edit `internal/board/card.go` — replace `truncate(t.Title, inner)` with a multi-line approach that word-wraps the title across available width.
24
+ - [x] Edit `internal/board/card.go` — combine wrapped title lines with newlines in the card content (joining with `\n`).
25
+ - [x] Run `make build && make test` to verify no regressions.
26
26
 
27
27
  ## Context Log
28
28
 
@@ -33,4 +33,4 @@ Files read:
33
33
 
34
34
  Estimated input tokens: 600
35
35
 
36
- Notes:
36
+ Notes: Exported WrapText/SplitLongWord from detail.go; updated card_test.go TestRenderCard_titleTruncated → TestRenderCard_titleWraps. Build and tests pass.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  id: E06-atari-noir-layout/T008-checkbox-states
3
- status: planned
3
+ status: done
4
4
  objective: "Parse and render checked/unchecked state for Implementation Plan checklist items"
5
5
  depends_on: []
6
6
  ---
@@ -19,11 +19,11 @@ depends_on: []
19
19
 
20
20
  ## Implementation Plan
21
21
 
22
- - [ ] Edit `internal/data/task.go` — add `CheckItem` struct with `Text string` and `Done bool` fields; change `Checklist []string` to `Checklist []CheckItem`.
23
- - [ ] Edit `internal/data/parser.go` — update `extractChecklistSection()` to detect `- [x] ` vs `- [ ] ` vs `- ` prefixes and set `Done` accordingly; strip prefix from `Text`.
24
- - [ ] Update all usages of `Checklist` across the codebase (likely only `board/detail.go` and tests).
25
- - [ ] Edit `internal/board/detail.go` — in the Implementation Plan section, render done items with `☑ ` + green `TagDone` styling and undone items with `□ ` + dim `CardMeta` styling.
26
- - [ ] Run `make build && make test` to verify no regressions.
22
+ - [x] Edit `internal/data/task.go` — add `CheckItem` struct with `Text string` and `Done bool` fields; change `Checklist []string` to `Checklist []CheckItem`.
23
+ - [x] Edit `internal/data/parser.go` — update `extractChecklistSection()` to detect `- [x] ` vs `- [ ] ` vs `- ` prefixes and set `Done` accordingly; strip prefix from `Text`.
24
+ - [x] Update all usages of `Checklist` across the codebase (likely only `board/detail.go` and tests).
25
+ - [x] Edit `internal/board/detail.go` — in the Implementation Plan section, render done items with `☑ ` + green `TagDone` styling and undone items with `□ ` + dim `CardMeta` styling.
26
+ - [x] Run `make build && make test` to verify no regressions.
27
27
 
28
28
  ## Context Log
29
29
 
@@ -32,7 +32,9 @@ Files read:
32
32
  - `internal/data/parser.go`
33
33
  - `internal/board/detail.go`
34
34
  - `internal/styles/styles.go`
35
+ - `internal/data/parser_test.go`
36
+ - `internal/board/detail_test.go`
35
37
 
36
- Estimated input tokens: 800
38
+ Estimated input tokens: 1200
37
39
 
38
- Notes:
40
+ Notes: Added `extractChecklistItems` alongside existing `extractChecklistSection` (kept for `[]string` Acceptance path). Build and all tests pass.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  id: E06-atari-noir-layout/T009-router-priority-marker
3
- status: planned
3
+ status: done
4
4
  objective: "Highlight the router priority task with a green marker on the card and optional text highlight"
5
5
  depends_on: []
6
6
  ---
@@ -12,18 +12,19 @@ depends_on: []
12
12
  - The model reads `RouterState.Task` (the `task:` field from `router.md`) and stores it as `Model.RouterTask`
13
13
  - In the board view, the task card whose ID matches `RouterTask` shows a green `▣` glyph (using `TagDone`/green style) instead of the normal phase-colored glyph
14
14
  - Non-priority tasks keep their existing phase-colored glyphs unchanged
15
+ - Board always default view to current state release and epic
15
16
  - The task detail overlay shows a `"(router priority)"` label or marker when the displayed task matches `RouterTask`
16
17
  - All existing keyboard interactions, column rendering, and card behavior remain intact
17
18
 
18
19
  ## Implementation Plan
19
20
 
20
- - [ ] Edit `internal/board/model.go` — add `RouterTask string` field to `Model`.
21
- - [ ] Edit `internal/board/board.go` — in `newProjectModel()`, read `routerState.Task` into `model.RouterTask`.
22
- - [ ] Edit `internal/board/card.go` — update `RenderCard` to accept a `routerTaskID string` parameter; when `t.ID == routerTaskID`, replace the phase glyph with a green `▣` using `TagDone` style.
23
- - [ ] Edit `internal/board/card.go` — update `RenderCard` signature and callsites (`column.go`, `view.go`).
24
- - [ ] Edit `internal/board/detail.go` — update `RenderDetail` to accept a `routerTaskID string`; when matching, append a `"(router priority)"` green label line.
25
- - [ ] Update all callsites of `RenderCard` and `RenderDetail` to pass `m.RouterTask`.
26
- - [ ] Run `make build && make test` to verify no regressions.
21
+ - [x] Edit `internal/board/model.go` — add `RouterTask string` field to `Model`.
22
+ - [x] Edit `internal/board/board.go` — in `newProjectModel()`, read `routerState.Task` into `model.RouterTask`.
23
+ - [x] Edit `internal/board/card.go` — update `RenderCard` to accept a `routerTaskID string` parameter; when `t.ID == routerTaskID`, replace the phase glyph with a green `▣` using `TagDone` style.
24
+ - [x] Edit `internal/board/card.go` — update `RenderCard` signature and callsites (`column.go`, `view.go`).
25
+ - [x] Edit `internal/board/detail.go` — update `RenderDetail` to accept a `routerTaskID string`; when matching, append a `"(router priority)"` green label line.
26
+ - [x] Update all callsites of `RenderCard` and `RenderDetail` to pass `m.RouterTask`.
27
+ - [x] Run `make build && make test` to verify no regressions.
27
28
 
28
29
  ## Context Log
29
30
 
@@ -35,7 +36,13 @@ Files read:
35
36
  - `internal/board/detail.go`
36
37
  - `internal/data/router.go`
37
38
  - `internal/board/view.go`
39
+ - `internal/board/card_test.go`
40
+ - `internal/board/detail_test.go`
41
+ - `internal/board/column_test.go`
38
42
 
39
- Estimated input tokens: 1000
43
+ Estimated input tokens: 1800
40
44
 
41
45
  Notes:
46
+ - `go build && go test ./...` — PASS (all board tests green)
47
+ - `RenderColumn` signature extended with `routerTaskID string`; all 7 test callsites updated
48
+ - New tests: `TestRenderCard_routerPriorityUsesGreenGlyph`, `TestRenderDetail_routerPriorityLabel`, `TestRenderDetail_noRouterPriorityLabelWhenNoMatch`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  id: E06-atari-noir-layout/T010-auto-refresh-watcher
3
- status: planned
3
+ status: done
4
4
  objective: "Auto-refresh the board when task files change on disk via fsnotify file watcher"
5
5
  depends_on: []
6
6
  ---
@@ -19,26 +19,26 @@ depends_on: []
19
19
 
20
20
  ## Implementation Plan
21
21
 
22
- - [ ] Add `github.com/fsnotify/fsnotify` to `go.mod`
23
- - [ ] Create `internal/board/watch.go`:
22
+ - [x] Add `github.com/fsnotify/fsnotify` to `go.mod`
23
+ - [x] Create `internal/board/watch.go`:
24
24
  - Define `fileChangeMsg struct{}` and `reloadMsg struct{ tasks []data.Task }`
25
25
  - `watchFiles(w *fsnotify.Watcher) tea.Cmd` — blocks on watcher.Events, drains channel for 100ms, emits single `fileChangeMsg`
26
26
  - `reloadTasks(root string) tea.Cmd` — calls `loadAllTasks(root)` and emits `reloadMsg{tasks}`
27
27
  - `loadAllTasks(root string) ([]data.Task, error)` — extracted from `board.go`, reuses `Discover` + `Parser`
28
- - [ ] Edit `internal/board/model.go`:
29
- - Add `watcher *fsnotify.Watcher` field to `Model`
30
- - `Init()` — create watcher, `watcher.AddRecursive(root)` on `.savepoint/releases/`, return `watchFiles(watcher)`
31
- - Close watcher in `Init()` if root is empty (test mode)
32
- - [ ] Edit `internal/board/board.go`:
28
+ - [x] Edit `internal/board/model.go`:
29
+ - Add `Watcher *fsnotify.Watcher` field to `Model`
30
+ - `Init()` — returns `watchFiles(m.Watcher)` if watcher non-nil, else nil
31
+ - [x] Edit `internal/board/board.go`:
33
32
  - Extract task-discovery loop from `newProjectModel` into `loadAllTasks(root string) ([]data.Task, error)`
34
- - `newProjectModel` calls `loadAllTasks` instead of inline logic
35
- - [ ] Edit `internal/board/update.go`:
33
+ - `newProjectModel` calls `loadAllTasks` + `newWatcher`, sets `model.Watcher`
34
+ - `loadEpicTasks` now sets `task.Path` and `task.Mtime` from stat
35
+ - [x] Edit `internal/board/update.go`:
36
36
  - Handle `fileChangeMsg` → return `reloadTasks(m.Root)` cmd
37
- - Handle `reloadMsg` → swap `m.AllTasks = msg.tasks`, call `m.refreshTasks()`, return `watchFiles(m.watcher)` to re-subscribe
38
- - On quit (`q`/`ctrl+c`), close `m.watcher` before `tea.Quit`
39
- - [ ] Edit `internal/board/transitions.go`:
40
- - In `Advance` / `Retreat`, call `data.WriteTaskStatus(taskPath, task, expectedMtime)` to persist to disk so the watcher picks it up
41
- - [ ] Run `go build ./...` and `go test ./...` to verify no regressions
37
+ - Handle `reloadMsg` → swap `m.AllTasks = msg.tasks`, call `m.refreshTasks()`, return `watchFiles(m.Watcher)` to re-subscribe
38
+ - On quit (`q`/`ctrl+c`), close `m.Watcher` before `tea.Quit`
39
+ - `space`/`backspace` now call `data.WriteTaskStatus` to persist to disk
40
+ - [x] `internal/data/task.go`: added `Path string` and `Mtime time.Time` (yaml:"-") to Task
41
+ - [x] Run `go build ./...` and `go test ./...` to verify no regressions
42
42
 
43
43
  ## Context Log
44
44
 
@@ -47,15 +47,20 @@ Files read:
47
47
  - `internal/board/board.go`
48
48
  - `internal/board/update.go`
49
49
  - `internal/board/transitions.go`
50
- - `internal/board/watch.go` (does not exist yet)
50
+ - `internal/board/watch.go` (created)
51
51
  - `internal/data/write.go`
52
+ - `internal/data/task.go`
53
+ - `internal/data/parser.go`
52
54
  - `.savepoint/AGENTS.md`
53
- - `.savepoint/releases/v1/epics/E06-atari-noir-layout/Design.md`
54
- - `.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T009-router-priority-marker.md`
55
55
 
56
- Estimated input tokens: 1800
56
+ Estimated input tokens: 2200
57
+
58
+ Quality gates: `go build ./...` PASS, `go test ./...` PASS (board: 0.317s, data: 0.343s)
57
59
 
58
60
  Notes:
59
- - The watcher watches `.savepoint/releases/` recursively. `fsnotify` v1.7+ supports `AddWith(path, fsnotify.Recursive)` on macOS/Windows; on Linux, fall back to walking and adding each subdirectory.
60
- - The 100ms debounce in `watchFiles` collapses rapid write sequences (e.g. editor save + lsp format) into a single reload.
61
- - `WriteTaskStatus` needs the task file path. Task struct may need a `Path` field populated at load time to make persistence possible.
61
+ - fsnotify v1.10.0 has no recursive AddWith option; used `filepath.WalkDir` + `w.Add` per subdir instead.
62
+ - `data.Task` gained `Path` and `Mtime` (yaml:"-") fields populated in `loadEpicTasks`.
63
+ - Advance/Retreat disk writes live in `update.go`, not `transitions.go` (keeps transitions pure).
64
+ - Watcher created in `newProjectModel`; Init() subscribes if non-nil; nil watcher = test-safe.
65
+ - Follow-up fix (2026-05-02): `newWatcher` receives `root` as the `.savepoint` directory, so it watches `root/releases` directly rather than `.savepoint/.savepoint/releases`. Watch startup errors now fail model creation instead of being silently ignored.
66
+ - Follow-up fix (2026-05-02): file-change reloads refresh task data plus release/epic indexes, and create events add watches for newly-created directories before the debounced reload.
@@ -0,0 +1,40 @@
1
+ ---
2
+ type: epic-design
3
+ status: audited
4
+ ---
5
+
6
+ # Epic E01: TUI Optimisation
7
+
8
+ ## Purpose
9
+
10
+ Performance, layout robustness, and structural improvements for the board TUI. Focused on fixing rendering edge-cases (resize clipping, wasted space) and improving the codebase's architectural hygiene around file watching and data refresh.
11
+
12
+ ## Definition of Done
13
+
14
+ - Right-border clipping is eliminated at all terminal widths ≥ 40
15
+ - Resize handling is robust — no corruption, no artifacts when growing/shrinking
16
+ - The board auto-refreshes when task files change on disk via fsnotify
17
+ - Board columns use virtual viewport scrolling — 4-5 cards visible with `↑/↓` indicators
18
+ - Detail overlay is height-capped (~70%) with scroll indicators for overflow content
19
+ - All scroll indicators use dim/subtle styling consistent with Atari Noir aesthetic
20
+
21
+ ## Implemented As
22
+
23
+ - Header Next Activity rendering is implemented in `internal/board/view.go` using `FormatNextActivity` and `styles.HeaderRight`.
24
+ - Column and detail scrolling are implemented through `ColumnOffsets`, `DetailOffset`, height-aware layout, viewport slicing, and subtle scroll indicators in `internal/board/model.go`, `internal/board/layout.go`, `internal/board/update.go`, `internal/board/column.go`, and `internal/board/detail.go`.
25
+ - Focus border stability is implemented by rendering unfocused columns with `styles.ColumnUnfocused`, matching focused column border dimensions while using the subtle border color.
26
+ - Naming conventions were reconciled across workflow docs: per-epic `Design.md` files became `E##-Detail.md`, and release `PRD.md` became `{release}-PRD.md`.
27
+ - The originally listed fsnotify watcher scope was already present from the prior TUI epic and was reviewed as existing behavior rather than newly introduced in this epic.
28
+
29
+ ## Components and files
30
+
31
+ | Path | Purpose |
32
+ |------|---------|
33
+ | `internal/board/layout.go` | Layout arithmetic and resize guards, height-aware ContentHeight |
34
+ | `internal/board/view.go` | Minimum width clamping, height passthrough to renderers |
35
+ | `internal/board/watch.go` | File watcher and reload commands |
36
+ | `internal/board/model.go` | Watcher lifecycle, ColumnOffsets, DetailOffset state |
37
+ | `internal/board/update.go` | Reload message handling, auto-scroll offsets, PageUp/PageDown |
38
+ | `internal/board/column.go` | Virtual viewport slicing, scroll indicator rendering |
39
+ | `internal/board/detail.go` | Height-capped overlay, detail scroll indicators |
40
+ | `internal/styles/styles.go` | ScrollIndicator style (dim/subtle) |