Step 8: Polish — lint, clock abstraction, e2e test.

- golangci-lint config with errcheck, govet, staticcheck, errorlint
- Fix all lint issues (unchecked error returns in cleanup paths, De Morgan)
- Inject jonboulle/clockwork into Garden for deterministic timestamps
- Add manifest.NewWithTime() for clock-aware initialization
- E2e lifecycle test: init → add → checkpoint → modify → status → restore → verify
- Update CLAUDE.md, PROJECT_PLAN.md, PROGRESS.md

Phase 1 (local) is now complete. All 9 CLI commands implemented and tested.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 22:03:53 -07:00
parent 08e24b44e0
commit d1a6e533a4
11 changed files with 200 additions and 37 deletions

View File

@@ -30,7 +30,11 @@ type Manifest struct {
// New creates a new empty manifest with Version 1 and timestamps set to now.
func New() *Manifest {
now := time.Now().UTC()
return NewWithTime(time.Now().UTC())
}
// NewWithTime creates a new empty manifest with the given timestamp.
func NewWithTime(now time.Time) *Manifest {
return &Manifest{
Version: 1,
Created: now,
@@ -72,18 +76,18 @@ func (m *Manifest) Save(path string) error {
tmpName := tmp.Name()
if _, err := tmp.Write(data); err != nil {
tmp.Close()
os.Remove(tmpName)
_ = tmp.Close()
_ = os.Remove(tmpName)
return fmt.Errorf("writing temp file: %w", err)
}
if err := tmp.Close(); err != nil {
os.Remove(tmpName)
_ = os.Remove(tmpName)
return fmt.Errorf("closing temp file: %w", err)
}
if err := os.Rename(tmpName, path); err != nil {
os.Remove(tmpName)
_ = os.Remove(tmpName)
return fmt.Errorf("renaming temp file: %w", err)
}