savepoint 1.0.3 → 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.
- package/.github/workflows/ci.yml +20 -0
- package/.savepoint/Design.md +4 -3
- package/.savepoint/releases/v1.1/epics/E15-hardening/E15-Audit.md +272 -0
- package/.savepoint/releases/v1.1/epics/E15-hardening/E15-Detail.md +25 -8
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T001-benchmarks.md +11 -11
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T002-fuzz-targets.md +15 -9
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T003-debug-flag.md +11 -11
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T004-dist-checksums.md +9 -9
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T005-windows-targets.md +11 -11
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T006-abbreviation-splitting.md +9 -9
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T007-root-test-allowlist.md +15 -10
- package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T008-ci-and-release-automation.md +46 -0
- package/.savepoint/router.md +4 -4
- package/AGENTS.md +2 -2
- package/Makefile +3 -1
- package/agent_skills_test.go +1 -1
- package/internal/board/board.go +4 -0
- package/internal/board/card_test.go +33 -0
- package/internal/board/column.go +43 -14
- package/internal/board/column_test.go +71 -0
- package/internal/board/debug.go +26 -0
- package/internal/board/debug_test.go +108 -0
- package/internal/board/detail.go +33 -0
- package/internal/board/detail_test.go +48 -0
- package/internal/board/epic_panel.go +2 -0
- package/internal/board/update.go +19 -0
- package/internal/board/update_test.go +27 -0
- package/internal/board/view_test.go +62 -0
- package/internal/board/watch.go +6 -0
- package/internal/buildtool/main.go +44 -6
- package/internal/buildtool/main_test.go +178 -0
- package/internal/data/fuzz_test.go +75 -0
- package/internal/data/parser.go +3 -2
- package/internal/data/testdata/fuzz/FuzzSplitFrontmatterBody/68eb66b0fe91e7e3 +2 -0
- package/internal/data/write.go +9 -6
- package/main.go +24 -5
- package/package.json +1 -1
- package/savepoint +0 -0
- /package/project-audit/{audit_report_opus_4.6 → audit_report_opus_4.6.md} +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
ci:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-go@v5
|
|
16
|
+
with:
|
|
17
|
+
go-version: '1.26'
|
|
18
|
+
check-latest: true
|
|
19
|
+
|
|
20
|
+
- run: make ci
|
package/.savepoint/Design.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: project-design
|
|
3
3
|
status: active
|
|
4
|
-
last_audited: v1.1/
|
|
4
|
+
last_audited: v1.1/E15-hardening
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Savepoint — System Architecture
|
|
@@ -27,6 +27,7 @@ last_audited: v1.1/E14-structural-improvements
|
|
|
27
27
|
- **Doctor command** (`savepoint doctor`, `savepoint doctor --epic E##`) runs read-only integrity diagnostics for config, router state, release/epic/task structure, frontmatter validity, acceptance criteria presence, dependencies, duplicate task IDs, stale audit files, orphaned task IDs, and configured quality gates. It prints a human-readable report with repair suggestions and exits 0 when clean, 1 when problems are diagnosed, and 2 for internal or invocation failures.
|
|
28
28
|
- **Audit remediation baseline** (v1.1 E13) centralizes frontmatter/body splitting and line-ending normalization in `internal/data`, uses typed sentinel errors for doctor repair suggestions, applies a configurable `quality_gates.gate_timeout`, removes tracked build artifacts from source control, adds `.golangci.yml`, and moves board filesystem reads/writes behind Bubble Tea command messages while preserving direct file I/O inside command helpers.
|
|
29
29
|
- **Structural improvement baseline** (v1.1 E14) groups board `Model` fields into focused embedded state structs, defines consumer-side board/doctor data-access interfaces, routes doctor orphan discovery through `Discover.ListRootDirs`, renders audit-tab hidden sections via exact heading matches, improves quality-gate shell tokenization for quoted and escaped arguments, removes the separate `TaskStatus` enum in favor of `ColumnType`, and adds `internal/testutil` for shared Go test fixtures.
|
|
30
|
+
- **Hardening baseline** (v1.1 E15) adds board render/layout benchmarks, data frontmatter fuzz targets, debug logging via CLI `--debug` or `SAVEPOINT_DEBUG`, abbreviation-aware task checklist sentence splitting, root test package isolation, documented audit-tab hidden-section allowlisting, repo-local CI, `make ci`, distribution SHA256 checksums, and Windows amd64/arm64 build outputs.
|
|
30
31
|
- **Agent audit workflow** is skill-driven, not a CLI pipeline. At `audit-pending`, a fresh audit agent writes one epic-local `E##-Audit.md`; the user reviews its Audit tab, then asks an agent to apply the admin proposal blocks, update the visible audit findings to reflect the applied outcome, and close the epic.
|
|
31
32
|
|
|
32
33
|
## 2. Directory layout
|
|
@@ -178,8 +179,8 @@ All failure modes are diagnosed by `savepoint doctor`. Doctor diagnoses and prop
|
|
|
178
179
|
- **License:** MIT.
|
|
179
180
|
- **Runtime:** Go CLI binary. Source builds with `go build`; tests run with `go test ./...`.
|
|
180
181
|
- **Local build:** `make build` delegates to `internal/buildtool`, builds `savepoint` or `savepoint.exe`, and injects `main.version` from `VERSION` or the latest git tag.
|
|
181
|
-
- **Cross-platform builds:** `make build-all` cross-compiles linux-amd64, linux-arm64, darwin-amd64, and
|
|
182
|
-
- **Artifacts:** `make dist` creates versioned `.tar.gz` archives in `dist/` for
|
|
182
|
+
- **Cross-platform builds:** `make build-all` cross-compiles linux-amd64, linux-arm64, darwin-amd64, darwin-arm64, windows-amd64, and windows-arm64 raw binaries into `dist/{platform}-{arch}/savepoint` or `savepoint.exe` for Windows. `make ci` runs the repo-local verification sequence used by CI.
|
|
183
|
+
- **Artifacts:** `make dist` creates versioned `.tar.gz` archives in `dist/` for Linux, Darwin, and Windows targets using Go archive APIs, not shell `tar`, and writes SHA256 hashes to `dist/checksums.txt`.
|
|
183
184
|
- **Smoke validation:** `make smoke-test` builds the local binary and runs `--version` as a headless exit-0 check.
|
|
184
185
|
- **No telemetry.** Ever.
|
|
185
186
|
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: audit-findings
|
|
3
|
+
audited: 2026-05-06
|
|
4
|
+
---
|
|
5
|
+
# Audit Findings: E15 Phase 3 - Hardening
|
|
6
|
+
|
|
7
|
+
## Main Findings
|
|
8
|
+
|
|
9
|
+
Applied the E15 audit proposals and closed the epic as audited.
|
|
10
|
+
|
|
11
|
+
- Fixed the Windows archive packaging issue: Windows tarballs now preserve `savepoint.exe` as the archive member name instead of extracting as `savepoint`.
|
|
12
|
+
- Added a regression test covering the Windows archive member name.
|
|
13
|
+
- Reconciled E15 documentation drift in `Design.md`, `AGENTS.md`, and `E15-Detail.md`.
|
|
14
|
+
- Marked `E15-Detail.md` as `status: audited`.
|
|
15
|
+
- Updated `Design.md` `last_audited` to `v1.1/E15-hardening`.
|
|
16
|
+
- Advanced router state to `epic-design` with no active epic because there are no later unarchived epics in v1.1.
|
|
17
|
+
|
|
18
|
+
Verification after applying proposals:
|
|
19
|
+
|
|
20
|
+
- `go test ./internal/buildtool`
|
|
21
|
+
- `make build`
|
|
22
|
+
- `make test`
|
|
23
|
+
- `make ci`
|
|
24
|
+
|
|
25
|
+
No remaining audit blockers are known. The `## Proposed Changes` section remains below as the apply trace.
|
|
26
|
+
|
|
27
|
+
## Code Style Review
|
|
28
|
+
|
|
29
|
+
- [x] One job per file - E15 changes stayed within board rendering/debug, data parsing/fuzzing, buildtool packaging, CI, and task metadata.
|
|
30
|
+
- [x] One job per function - new helpers such as `executableName`, `writeChecksums`, `stripDebugFlag`, `debugf`, and abbreviation checks are narrowly scoped.
|
|
31
|
+
- [x] Test branches - Windows build output and Windows archive member naming are now covered.
|
|
32
|
+
- [x] Types document intent - existing Go types and small helper APIs remain explicit enough for this scope.
|
|
33
|
+
- [x] Build only what is needed - no speculative runtime features were added beyond E15 scope.
|
|
34
|
+
- [x] Handle errors at boundaries - buildtool, filesystem, checksum, fuzz, and parser errors are propagated with context.
|
|
35
|
+
- [x] One source of truth - target lists and executable naming are centralized in buildtool; the proposed archive fix reuses that source.
|
|
36
|
+
- [x] Comments explain why - new comments document abbreviation suppression and audit-tab hidden sections rather than restating obvious code.
|
|
37
|
+
- [x] Content lives in data - workflow and architecture copy remain in markdown; no new product copy was embedded in logic.
|
|
38
|
+
- [x] Small diffs - most changes are localized, test-backed additions.
|
|
39
|
+
|
|
40
|
+
## Proposed Changes
|
|
41
|
+
|
|
42
|
+
### Target File
|
|
43
|
+
internal/buildtool/main.go
|
|
44
|
+
|
|
45
|
+
### Replace
|
|
46
|
+
```go
|
|
47
|
+
if err := writeTarGz(archive, source, "savepoint"); err != nil {
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### With
|
|
51
|
+
```go
|
|
52
|
+
if err := writeTarGz(archive, source, executableName(target.os)); err != nil {
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Target File
|
|
56
|
+
internal/buildtool/main_test.go
|
|
57
|
+
|
|
58
|
+
### Replace
|
|
59
|
+
```go
|
|
60
|
+
import (
|
|
61
|
+
"crypto/sha256"
|
|
62
|
+
"encoding/hex"
|
|
63
|
+
"os"
|
|
64
|
+
"path/filepath"
|
|
65
|
+
"runtime"
|
|
66
|
+
"strings"
|
|
67
|
+
"testing"
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### With
|
|
72
|
+
```go
|
|
73
|
+
import (
|
|
74
|
+
"archive/tar"
|
|
75
|
+
"compress/gzip"
|
|
76
|
+
"crypto/sha256"
|
|
77
|
+
"encoding/hex"
|
|
78
|
+
"io"
|
|
79
|
+
"os"
|
|
80
|
+
"path/filepath"
|
|
81
|
+
"runtime"
|
|
82
|
+
"strings"
|
|
83
|
+
"testing"
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Target File
|
|
88
|
+
internal/buildtool/main_test.go
|
|
89
|
+
|
|
90
|
+
### Replace
|
|
91
|
+
```go
|
|
92
|
+
func TestExecutableName(t *testing.T) {
|
|
93
|
+
if got := executableName("windows"); got != "savepoint.exe" {
|
|
94
|
+
t.Errorf("executableName(windows) = %q, want savepoint.exe", got)
|
|
95
|
+
}
|
|
96
|
+
if got := executableName("linux"); got != "savepoint" {
|
|
97
|
+
t.Errorf("executableName(linux) = %q, want savepoint", got)
|
|
98
|
+
}
|
|
99
|
+
if got := executableName("darwin"); got != "savepoint" {
|
|
100
|
+
t.Errorf("executableName(darwin) = %q, want savepoint", got)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### With
|
|
106
|
+
```go
|
|
107
|
+
func TestExecutableName(t *testing.T) {
|
|
108
|
+
if got := executableName("windows"); got != "savepoint.exe" {
|
|
109
|
+
t.Errorf("executableName(windows) = %q, want savepoint.exe", got)
|
|
110
|
+
}
|
|
111
|
+
if got := executableName("linux"); got != "savepoint" {
|
|
112
|
+
t.Errorf("executableName(linux) = %q, want savepoint", got)
|
|
113
|
+
}
|
|
114
|
+
if got := executableName("darwin"); got != "savepoint" {
|
|
115
|
+
t.Errorf("executableName(darwin) = %q, want savepoint", got)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func TestWriteTarGzPreservesWindowsExecutableName(t *testing.T) {
|
|
120
|
+
dir := t.TempDir()
|
|
121
|
+
source := filepath.Join(dir, "savepoint.exe")
|
|
122
|
+
if err := os.WriteFile(source, []byte("binary"), 0o755); err != nil {
|
|
123
|
+
t.Fatal(err)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
archive := filepath.Join(dir, "savepoint-windows-amd64.tar.gz")
|
|
127
|
+
if err := writeTarGz(archive, source, executableName("windows")); err != nil {
|
|
128
|
+
t.Fatalf("writeTarGz: %v", err)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
f, err := os.Open(archive)
|
|
132
|
+
if err != nil {
|
|
133
|
+
t.Fatal(err)
|
|
134
|
+
}
|
|
135
|
+
defer f.Close()
|
|
136
|
+
|
|
137
|
+
gz, err := gzip.NewReader(f)
|
|
138
|
+
if err != nil {
|
|
139
|
+
t.Fatal(err)
|
|
140
|
+
}
|
|
141
|
+
defer gz.Close()
|
|
142
|
+
|
|
143
|
+
tr := tar.NewReader(gz)
|
|
144
|
+
header, err := tr.Next()
|
|
145
|
+
if err != nil {
|
|
146
|
+
t.Fatal(err)
|
|
147
|
+
}
|
|
148
|
+
if header.Name != "savepoint.exe" {
|
|
149
|
+
t.Fatalf("archive member = %q, want savepoint.exe", header.Name)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
content, err := io.ReadAll(tr)
|
|
153
|
+
if err != nil {
|
|
154
|
+
t.Fatal(err)
|
|
155
|
+
}
|
|
156
|
+
if string(content) != "binary" {
|
|
157
|
+
t.Fatalf("archive content = %q, want binary", content)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Target File
|
|
163
|
+
.savepoint/Design.md
|
|
164
|
+
|
|
165
|
+
### Replace
|
|
166
|
+
```md
|
|
167
|
+
- **Structural improvement baseline** (v1.1 E14) groups board `Model` fields into focused embedded state structs, defines consumer-side board/doctor data-access interfaces, routes doctor orphan discovery through `Discover.ListRootDirs`, renders audit-tab hidden sections via exact heading matches, improves quality-gate shell tokenization for quoted and escaped arguments, removes the separate `TaskStatus` enum in favor of `ColumnType`, and adds `internal/testutil` for shared Go test fixtures.
|
|
168
|
+
- **Agent audit workflow** is skill-driven, not a CLI pipeline. At `audit-pending`, a fresh audit agent writes one epic-local `E##-Audit.md`; the user reviews its Audit tab, then asks an agent to apply the admin proposal blocks, update the visible audit findings to reflect the applied outcome, and close the epic.
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### With
|
|
172
|
+
```md
|
|
173
|
+
- **Structural improvement baseline** (v1.1 E14) groups board `Model` fields into focused embedded state structs, defines consumer-side board/doctor data-access interfaces, routes doctor orphan discovery through `Discover.ListRootDirs`, renders audit-tab hidden sections via exact heading matches, improves quality-gate shell tokenization for quoted and escaped arguments, removes the separate `TaskStatus` enum in favor of `ColumnType`, and adds `internal/testutil` for shared Go test fixtures.
|
|
174
|
+
- **Hardening baseline** (v1.1 E15) adds board render/layout benchmarks, data frontmatter fuzz targets, debug logging via CLI `--debug` or `SAVEPOINT_DEBUG`, abbreviation-aware task checklist sentence splitting, root test package isolation, documented audit-tab hidden-section allowlisting, repo-local CI, `make ci`, distribution SHA256 checksums, and Windows amd64/arm64 build outputs.
|
|
175
|
+
- **Agent audit workflow** is skill-driven, not a CLI pipeline. At `audit-pending`, a fresh audit agent writes one epic-local `E##-Audit.md`; the user reviews its Audit tab, then asks an agent to apply the admin proposal blocks, update the visible audit findings to reflect the applied outcome, and close the epic.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Target File
|
|
179
|
+
.savepoint/Design.md
|
|
180
|
+
|
|
181
|
+
### Replace
|
|
182
|
+
```md
|
|
183
|
+
- **Cross-platform builds:** `make build-all` cross-compiles linux-amd64, linux-arm64, darwin-amd64, and darwin-arm64 raw binaries into `dist/{platform}-{arch}/savepoint`.
|
|
184
|
+
- **Artifacts:** `make dist` creates versioned `.tar.gz` archives in `dist/` for the Linux and Darwin targets using Go archive APIs, not shell `tar`.
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### With
|
|
188
|
+
```md
|
|
189
|
+
- **Cross-platform builds:** `make build-all` cross-compiles linux-amd64, linux-arm64, darwin-amd64, darwin-arm64, windows-amd64, and windows-arm64 raw binaries into `dist/{platform}-{arch}/savepoint` or `savepoint.exe` for Windows. `make ci` runs the repo-local verification sequence used by CI.
|
|
190
|
+
- **Artifacts:** `make dist` creates versioned `.tar.gz` archives in `dist/` for Linux, Darwin, and Windows targets using Go archive APIs, not shell `tar`, and writes SHA256 hashes to `dist/checksums.txt`.
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Target File
|
|
194
|
+
AGENTS.md
|
|
195
|
+
|
|
196
|
+
### Replace
|
|
197
|
+
```md
|
|
198
|
+
| `internal/board/` | TUI board, overlays, epic sidebar, Next Activity line, router priority key, detail checklist rendering, status glyphs, forced color profile, async update I/O commands, shared board utilities |
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### With
|
|
202
|
+
```md
|
|
203
|
+
| `internal/board/` | TUI board, overlays, epic sidebar, Next Activity line, router priority key, detail checklist rendering, status glyphs, forced color profile, debug logging hooks, async update I/O commands, shared board utilities |
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Target File
|
|
207
|
+
AGENTS.md
|
|
208
|
+
|
|
209
|
+
### Replace
|
|
210
|
+
```md
|
|
211
|
+
| `internal/buildtool/` | Makefile helper, cross-compile, archives |
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### With
|
|
215
|
+
```md
|
|
216
|
+
| `internal/buildtool/` | Makefile helper, cross-compile including Windows targets, archives, distribution checksums |
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Target File
|
|
220
|
+
.savepoint/releases/v1.1/epics/E15-hardening/E15-Detail.md
|
|
221
|
+
|
|
222
|
+
### Replace
|
|
223
|
+
```md
|
|
224
|
+
## Components
|
|
225
|
+
|
|
226
|
+
| Module | Purpose |
|
|
227
|
+
|--------|---------|
|
|
228
|
+
| `internal/board/view_test.go` | Add render benchmarks |
|
|
229
|
+
| `internal/data/parser_test.go` | Add fuzz targets |
|
|
230
|
+
| `cmd/main.go` | Add --debug / SAVEPOINT_DEBUG |
|
|
231
|
+
| `internal/buildtool/main.go` | Add checksums, Windows targets |
|
|
232
|
+
| `internal/board/detail.go` | Fix abbreviation handling |
|
|
233
|
+
| `internal/board/epic_panel.go` | Extract allowlist constant |
|
|
234
|
+
| `agent_skills_test.go` | Move to cmd_test package |
|
|
235
|
+
| `Makefile` | Add `ci` target for local verification |
|
|
236
|
+
| `.github/workflows/ci.yml` | Add repo CI workflow |
|
|
237
|
+
|
|
238
|
+
## Boundaries
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### With
|
|
242
|
+
```md
|
|
243
|
+
## Components
|
|
244
|
+
|
|
245
|
+
| Module | Purpose |
|
|
246
|
+
|--------|---------|
|
|
247
|
+
| `internal/board/view_test.go` | Add render and layout benchmarks |
|
|
248
|
+
| `internal/board/card_test.go` | Add card render benchmarks |
|
|
249
|
+
| `internal/board/column_test.go` | Add column render benchmarks |
|
|
250
|
+
| `internal/data/fuzz_test.go` | Add frontmatter and split-body fuzz targets |
|
|
251
|
+
| `main.go` | Add global --debug parsing and SAVEPOINT_DEBUG activation |
|
|
252
|
+
| `internal/board/debug.go` | Add board debug logging helper |
|
|
253
|
+
| `internal/board/board.go` | Log board initialization under debug mode |
|
|
254
|
+
| `internal/board/watch.go` | Log watcher and reload activity under debug mode |
|
|
255
|
+
| `internal/board/update.go` | Log update dispatch and preserve focused-card visibility |
|
|
256
|
+
| `internal/buildtool/main.go` | Add checksums and Windows targets |
|
|
257
|
+
| `internal/board/detail.go` | Fix abbreviation handling |
|
|
258
|
+
| `internal/board/epic_panel.go` | Document audit hidden-section allowlist |
|
|
259
|
+
| `agent_skills_test.go` | Move to external root test package |
|
|
260
|
+
| `Makefile` | Add `ci` target for local verification |
|
|
261
|
+
| `.github/workflows/ci.yml` | Add repo CI workflow |
|
|
262
|
+
|
|
263
|
+
## Implemented As
|
|
264
|
+
|
|
265
|
+
- Debug activation is in root `main.go` because global flags are parsed before dispatching into `cmd/`.
|
|
266
|
+
- Fuzz targets live in `internal/data/fuzz_test.go` rather than `internal/data/parser_test.go`.
|
|
267
|
+
- Fuzzing found and fixed `SplitFrontmatterBody` delimiter-offset handling and CR line-ending normalization.
|
|
268
|
+
- Root `agent_skills_test.go` remains at the repository root but now uses external package `main_test`, which removes the root package coupling without moving fixture-relative paths.
|
|
269
|
+
- CI was included as repo-local guardrail scope for E15 via `T008-ci-and-release-automation`.
|
|
270
|
+
|
|
271
|
+
## Boundaries
|
|
272
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: epic-design
|
|
3
|
-
status:
|
|
3
|
+
status: audited
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# E15: Phase 3 — Hardening
|
|
@@ -18,18 +18,35 @@ Address the remaining Phase 3 findings from the consolidated codebase audit (Opu
|
|
|
18
18
|
- Windows build targets in buildtool
|
|
19
19
|
- Abbreviation-aware checklist sentence splitting
|
|
20
20
|
- Root-level test relocation and audit allowlist consolidation
|
|
21
|
+
- Repo-local CI workflow and `ci` Makefile target for build/test verification
|
|
21
22
|
|
|
22
23
|
## Components
|
|
23
24
|
|
|
24
25
|
| Module | Purpose |
|
|
25
26
|
|--------|---------|
|
|
26
|
-
| `internal/board/view_test.go` | Add render benchmarks |
|
|
27
|
-
| `internal/
|
|
28
|
-
| `
|
|
29
|
-
| `internal/
|
|
27
|
+
| `internal/board/view_test.go` | Add render and layout benchmarks |
|
|
28
|
+
| `internal/board/card_test.go` | Add card render benchmarks |
|
|
29
|
+
| `internal/board/column_test.go` | Add column render benchmarks |
|
|
30
|
+
| `internal/data/fuzz_test.go` | Add frontmatter and split-body fuzz targets |
|
|
31
|
+
| `main.go` | Add global --debug parsing and SAVEPOINT_DEBUG activation |
|
|
32
|
+
| `internal/board/debug.go` | Add board debug logging helper |
|
|
33
|
+
| `internal/board/board.go` | Log board initialization under debug mode |
|
|
34
|
+
| `internal/board/watch.go` | Log watcher and reload activity under debug mode |
|
|
35
|
+
| `internal/board/update.go` | Log update dispatch and preserve focused-card visibility |
|
|
36
|
+
| `internal/buildtool/main.go` | Add checksums and Windows targets |
|
|
30
37
|
| `internal/board/detail.go` | Fix abbreviation handling |
|
|
31
|
-
| `internal/board/epic_panel.go` |
|
|
32
|
-
| `agent_skills_test.go` | Move to
|
|
38
|
+
| `internal/board/epic_panel.go` | Document audit hidden-section allowlist |
|
|
39
|
+
| `agent_skills_test.go` | Move to external root test package |
|
|
40
|
+
| `Makefile` | Add `ci` target for local verification |
|
|
41
|
+
| `.github/workflows/ci.yml` | Add repo CI workflow |
|
|
42
|
+
|
|
43
|
+
## Implemented As
|
|
44
|
+
|
|
45
|
+
- Debug activation is in root `main.go` because global flags are parsed before dispatching into `cmd/`.
|
|
46
|
+
- Fuzz targets live in `internal/data/fuzz_test.go` rather than `internal/data/parser_test.go`.
|
|
47
|
+
- Fuzzing found and fixed `SplitFrontmatterBody` delimiter-offset handling and CR line-ending normalization.
|
|
48
|
+
- Root `agent_skills_test.go` remains at the repository root but now uses external package `main_test`, which removes the root package coupling without moving fixture-relative paths.
|
|
49
|
+
- CI was included as repo-local guardrail scope for E15 via `T008-ci-and-release-automation`.
|
|
33
50
|
|
|
34
51
|
## Boundaries
|
|
35
52
|
|
|
@@ -38,6 +55,6 @@ Address the remaining Phase 3 findings from the consolidated codebase audit (Opu
|
|
|
38
55
|
- Medium/Low hardening items (M10, L7, L10, L11, L12)
|
|
39
56
|
|
|
40
57
|
**Out of scope:**
|
|
41
|
-
-
|
|
58
|
+
- External deployment hosting beyond repo-local CI/release automation
|
|
42
59
|
- New UI features or commands
|
|
43
60
|
- Structural improvements (separate epic E14)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: E15-hardening/T001-benchmarks
|
|
3
|
-
status:
|
|
3
|
+
status: done
|
|
4
4
|
objective: Add benchmark tests for board render functions
|
|
5
5
|
depends_on: []
|
|
6
6
|
---
|
|
@@ -16,16 +16,16 @@ depends_on: []
|
|
|
16
16
|
|
|
17
17
|
## Acceptance Criteria
|
|
18
18
|
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
19
|
+
- [x] Benchmark added for RenderCard with varied content widths
|
|
20
|
+
- [x] Benchmark added for renderColumn with multiple tasks
|
|
21
|
+
- [x] Benchmark added for layout calculations at different widths
|
|
22
|
+
- [x] Benchmarks are repeatable with consistent results
|
|
23
|
+
- [x] Benchmarks don't modify package state
|
|
24
|
+
- [x] `go test -bench=. ./internal/board/` runs without errors
|
|
25
25
|
|
|
26
26
|
## Implementation Plan
|
|
27
27
|
|
|
28
|
-
- [
|
|
29
|
-
- [
|
|
30
|
-
- [
|
|
31
|
-
- [
|
|
28
|
+
- [x] Add benchmark functions in view_test.go, card_test.go, column_test.go
|
|
29
|
+
- [x] Create test data with representative task mixtures
|
|
30
|
+
- [x] Run benchmarks and document baseline
|
|
31
|
+
- [x] Run `make build && make test`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: E15-hardening/T002-fuzz-targets
|
|
3
|
-
status:
|
|
3
|
+
status: done
|
|
4
4
|
objective: Add fuzz targets for YAML frontmatter parsing round-trip
|
|
5
5
|
depends_on: []
|
|
6
6
|
---
|
|
@@ -15,14 +15,20 @@ depends_on: []
|
|
|
15
15
|
|
|
16
16
|
## Acceptance Criteria
|
|
17
17
|
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
18
|
+
- [x] Fuzz target added for extractFrontmatter round-trip
|
|
19
|
+
- [x] Fuzz target added for WriteTaskStatus round-trip (write then re-parse)
|
|
20
|
+
- [x] Fuzz targets exercise edge cases (empty content, malformed YAML, unicode)
|
|
21
|
+
- [x] `go test -fuzz=. ./internal/data/` runs without errors
|
|
22
22
|
|
|
23
23
|
## Implementation Plan
|
|
24
24
|
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
- [
|
|
25
|
+
- [x] Create fuzz_test.go in internal/data with fuzz targets
|
|
26
|
+
- [x] Define corpus seed inputs from known edge cases
|
|
27
|
+
- [x] Run fuzz targets for short duration to verify stability
|
|
28
|
+
- [x] Run `make build && make test`
|
|
29
|
+
|
|
30
|
+
## Drift Notes
|
|
31
|
+
|
|
32
|
+
- Fuzzer found bug in `SplitFrontmatterBody`: used `len(TrimSpace(raw))` for bodyStart, causing off-by-N when frontmatter has leading/trailing whitespace. Fixed to compute bodyStart from actual `\n---` offset.
|
|
33
|
+
- Fuzzer found `normalizeLineEndings` not idempotent with `\r\r\n` sequences. Fixed to also replace lone `\r` with `\n` (handles legacy Mac CR line endings).
|
|
34
|
+
- No new files/modules beyond `internal/data/fuzz_test.go` (in-scope per E15-Detail.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: E15-hardening/T003-debug-flag
|
|
3
|
-
status:
|
|
3
|
+
status: done
|
|
4
4
|
objective: Add --debug flag and SAVEPOINT_DEBUG env var for structured debug logging
|
|
5
5
|
depends_on: []
|
|
6
6
|
---
|
|
@@ -15,16 +15,16 @@ depends_on: []
|
|
|
15
15
|
|
|
16
16
|
## Acceptance Criteria
|
|
17
17
|
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
18
|
+
- [x] --debug flag accepted at CLI level
|
|
19
|
+
- [x] SAVEPOINT_DEBUG env var recognized
|
|
20
|
+
- [x] Debug output includes board init, file watcher events, and command dispatch
|
|
21
|
+
- [x] Debug output is off by default (no performance impact)
|
|
22
|
+
- [x] `go test ./...` passes with no regressions
|
|
23
23
|
|
|
24
24
|
## Implementation Plan
|
|
25
25
|
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
- [
|
|
29
|
-
- [
|
|
30
|
-
- [
|
|
26
|
+
- [x] Define debug logging helper in a shared location
|
|
27
|
+
- [x] Add --debug flag parsing in main.go
|
|
28
|
+
- [x] Instrument key points in board init, file watcher, and update dispatch
|
|
29
|
+
- [x] Add tests for debug flag behavior
|
|
30
|
+
- [x] Run `make build && make test`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: E15-hardening/T004-dist-checksums
|
|
3
|
-
status:
|
|
3
|
+
status: done
|
|
4
4
|
objective: Generate checksums.txt during make dist using Go crypto APIs
|
|
5
5
|
depends_on: []
|
|
6
6
|
---
|
|
@@ -14,14 +14,14 @@ depends_on: []
|
|
|
14
14
|
|
|
15
15
|
## Acceptance Criteria
|
|
16
16
|
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
17
|
+
- [x] dist() generates checksums.txt file with SHA256 hashes
|
|
18
|
+
- [x] checksums.txt is included in the dist directory
|
|
19
|
+
- [x] Existing archive creation behavior preserved
|
|
20
|
+
- [x] `go test ./...` passes
|
|
21
21
|
|
|
22
22
|
## Implementation Plan
|
|
23
23
|
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
24
|
+
- [x] Add SHA256 checksum computation in dist() using crypto/sha256
|
|
25
|
+
- [x] Write checksums.txt to dist directory
|
|
26
|
+
- [x] Add tests for checksum generation
|
|
27
|
+
- [x] Run `make build && make test`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: E15-hardening/T005-windows-targets
|
|
3
|
-
status:
|
|
3
|
+
status: done
|
|
4
4
|
objective: Add Windows amd64 and arm64 build targets to buildtool
|
|
5
5
|
depends_on: []
|
|
6
6
|
---
|
|
@@ -13,16 +13,16 @@ depends_on: []
|
|
|
13
13
|
|
|
14
14
|
## Acceptance Criteria
|
|
15
15
|
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
16
|
+
- [x] Windows amd64 target added
|
|
17
|
+
- [x] Windows arm64 target added
|
|
18
|
+
- [x] .exe suffix handled for Windows binaries
|
|
19
|
+
- [x] Existing Linux and Darwin targets preserved
|
|
20
|
+
- [x] `go test ./...` passes
|
|
21
21
|
|
|
22
22
|
## Implementation Plan
|
|
23
23
|
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
- [
|
|
24
|
+
- [x] Add windows-amd64 and windows-arm64 to targets list
|
|
25
|
+
- [x] Handle .exe suffix in build output path via `executableName(goos)`
|
|
26
|
+
- [x] Update localExecutable to detect Windows (already done in prior task)
|
|
27
|
+
- [x] Update tests for new targets
|
|
28
|
+
- [x] Run `make build && make test`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: E15-hardening/T006-abbreviation-splitting
|
|
3
|
-
status:
|
|
3
|
+
status: done
|
|
4
4
|
objective: Fix splitChecklistSentences to skip periods preceded by known abbreviations
|
|
5
5
|
depends_on: []
|
|
6
6
|
---
|
|
@@ -13,14 +13,14 @@ depends_on: []
|
|
|
13
13
|
|
|
14
14
|
## Acceptance Criteria
|
|
15
15
|
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
16
|
+
- [x] Known abbreviations (e.g., "e.g.", "i.e.") do not trigger sentence breaks
|
|
17
|
+
- [x] Existing sentence splitting behavior preserved for non-abbreviation periods
|
|
18
|
+
- [x] Abbreviation list is configurable/extensible
|
|
19
|
+
- [x] `go test ./...` passes with no regressions
|
|
20
20
|
|
|
21
21
|
## Implementation Plan
|
|
22
22
|
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
23
|
+
- [x] Define known abbreviation set
|
|
24
|
+
- [x] Add abbreviation check before period-based sentence split
|
|
25
|
+
- [x] Add test cases for abbreviations in sentences
|
|
26
|
+
- [x] Run `make build && make test`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: E15-hardening/T007-root-test-allowlist
|
|
3
|
-
status:
|
|
3
|
+
status: done
|
|
4
4
|
objective: Move agent_skills_test.go to a test package and extract audit allowlist to a named constant
|
|
5
5
|
depends_on: []
|
|
6
6
|
---
|
|
@@ -14,15 +14,20 @@ depends_on: []
|
|
|
14
14
|
|
|
15
15
|
## Acceptance Criteria
|
|
16
16
|
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
17
|
+
- [x] agent_skills_test.go moved to cmd_test package (or appropriate location)
|
|
18
|
+
- [x] allowedSections extracted to a named constant with documentation
|
|
19
|
+
- [x] All existing tests still pass after refactoring
|
|
20
|
+
- [x] `go test ./...` passes with no regressions
|
|
21
21
|
|
|
22
22
|
## Implementation Plan
|
|
23
23
|
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
- [
|
|
24
|
+
- [x] Move agent_skills_test.go to an appropriate internal test package
|
|
25
|
+
- [x] Update imports and paths in moved test
|
|
26
|
+
- [x] Extract allowedSections map to a named constant
|
|
27
|
+
- [x] Update any references in epic_panel.go
|
|
28
|
+
- [x] Run `make build && make test`
|
|
29
|
+
|
|
30
|
+
## Notes
|
|
31
|
+
|
|
32
|
+
- `agent_skills_test.go` changed from `package main` → `package main_test` (external test package at root). Paths remain valid since Go test working dir is the package dir.
|
|
33
|
+
- `epicAuditHiddenSectionHeadings` already extracted as package-level var; added doc comment explaining suppression rationale.
|