Skip to content

[M5] Persistent state + streaks - #15

Merged
rwrife merged 1 commit into
mainfrom
issue-5-persistent-state
Jul 4, 2026
Merged

rwrife merged 1 commit into
mainfrom
issue-5-persistent-state

Conversation

@rwrife

@rwrife rwrife commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Closes #5

Gives the plant memory between runs by fleshing out internal/store and wiring it into the default render flow.

What changed

  • internal/store (was a stub) — full load/save of a versioned JSON state file.
    • XDG-aware path: $XDG_CONFIG_HOME/commit-sprout/state.json, falling back to ~/.config/commit-sprout/state.json (a non-absolute XDG_CONFIG_HOME is ignored).
    • Persists: highest stage ever reached (stored by stable name, e.g. "leafy"), best streak, and last-seen commit hash/time.
    • Atomic writes: temp file in the same dir → SyncRename, so a crash or full disk never leaves a corrupt/half-written file. No stray temp files on success.
    • Sane defaults + versioned schema: version field for future migrations; missing files and corrupt/garbled JSON recover to defaults (no error), and the next save heals the file. Legacy version: 0, unknown stage names, and negative streaks are normalized on load.
    • plant interop: State.Plant() projects onto the pure plant.State; State.FromPlant(...) folds a computed result back, ratcheting highest-stage/best-streak upward only (never regresses) and recording the latest commit.
  • cmd/root.go — real load → compute → render → save pipeline (replaces the old zero plant.State{}). Persistence is best-effort: load errors fall back to a fresh plant, save errors warn on stderr but never fail the command. New --no-save flag for read-only runs.
  • README — marks persistence as implemented (M5) and documents the state file + --no-save.

Checklist (from #5)

  • internal/store loads/saves JSON at ~/.config/commit-sprout/state.json (XDG-aware)
  • Persist highest stage, current streak, last-seen commit hash/time
  • Atomic writes (temp file + rename)
  • Sane defaults + migration-friendly versioned schema field
  • Wire store into the main flow (load → compute → render → save)
  • Tests for round-trip load/save and missing/corrupt file recovery

Testing

  • gofmt -l . clean, go vet ./... clean, go build ./... and go test ./... all green.
  • 15 new store tests (round-trip, missing/corrupt recovery, normalization, atomicity/no-temp-leak, nested dir creation, XDG + home-fallback paths, Plant/FromPlant ratchet & no-regress).
  • End-to-end smoke test: fresh repo with a 4-day streak writes highest_stage: leafy / best_streak: 3; a later stale run with a remembered blooming state correctly renders tall (wilting) (memory floor holds — one stage below peak, not a collapse to seed) and leaves highest-stage/best-streak intact; --no-save leaves the file byte-for-byte untouched.

Not merging — Phase 1 next cycle handles the merge after CI.

Notes / scope

  • The schema carries a last_commit_hash field for forward-compat, but gitstat.Activity doesn't currently expose a hash publicly, so it's persisted best-effort (empty for now) and last_commit_time is the field actually populated today. Plumbing a public hash through gitstat would be its own change beyond M5's store scope.

@rwrife rwrife mentioned this pull request Jul 3, 2026
6 tasks
@rwrife
rwrife merged commit ca57920 into main Jul 4, 2026
1 check passed
@rwrife
rwrife deleted the issue-5-persistent-state branch July 4, 2026 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[M5] Persistent state + streaks

1 participant