Skip to content

[M3] Plant state machine: activity -> stage + health + mood - #13

Merged
rwrife merged 1 commit into
mainfrom
issue-3-plant-state-machine
Jul 2, 2026
Merged

rwrife merged 1 commit into
mainfrom
issue-3-plant-state-machine

Conversation

@rwrife

@rwrife rwrife commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Closes #3

Implements M3 — Plant state machine: internal/plant turns a gitstat.Activity plus remembered State into a fully-resolved PlantState. Pure, deterministic, no I/O.

What changed

  • Compute(act, state, now) — the brain. Same inputs → same PlantState, every time. Takes an explicit now clock (matching gitstat's pure-function style) so wilt math is testable without wall-clock flake.
  • Stages (seed → sprout → leafy → tall → blooming) — streak-driven: >=1/3/7/14 consecutive days climb the ladder. A busy-day shortcut (>= 3 commits in the window) sprouts a bare seed on your first productive day even before a streak exists.
  • Health (healthy → thirsty → wilting) — by whole calendar days since the last commit: healthy through yesterday, thirsty on days 2–3, wilting from day 4+. No commits at all = a calm, healthy Seed (nothing to wilt yet).
  • Memory floorState.HighestStage keeps a mature plant from collapsing to a sprout on one slow day. While healthy/thirsty it holds its remembered peak; once wilting it slips exactly one stage below peak so neglect becomes visible — but never below Sprout once anything has grown. Live growth always beats stale memory, and UpdatedHighestStage is returned for M5 to persist.
  • Mood — short flavor line with personality; health problems (thirsty/wilting) take priority over stage celebration so the message nudges you to commit.
  • All thresholds in one Tuning thresholds block — per the issue's "easy to tune in one place".
  • Stable String() for Stage/Health (they can surface in CLI/prompt output).
  • Clock-skew guard — a commit timestamped slightly in the future counts as today, not a negative age.

Design note

State lives in the plant package (not store) on purpose: it keeps Compute free of any I/O dependency and fully unit-testable in isolation. The store package (M5) maps its persisted JSON onto this shape.

Tests

17 table-driven cases in plant_test.go: stage-by-streak across every boundary, busy-day shortcut (and just under it), health across all recency bands, no-commits seed, memory floor holding while healthy, memory floor slipping one stage when wilting, floor never dropping below sprout, live growth beating stale memory, mood prioritization (wilt vs bloom), determinism (25 repeats identical), clock skew, and stable stage/health strings.

Verification (Go 1.23.4, matching CI)

  • gofmt -l . clean
  • go vet ./... clean
  • go build ./... ok
  • go test ./... -count=1 ok

Done when (from the issue)

plant.Compute(activity, state) yields the right stage/health across a table of test cases. ✅

Also refreshed README step 2 with an "Implemented — M3" note mirroring the M2 annotation. No behavior change to the binary — M4 render will consume PlantState next.

@rwrife rwrife mentioned this pull request Jul 1, 2026
6 tasks
@rwrife
rwrife merged commit 823d27b into main Jul 2, 2026
1 check passed
@rwrife
rwrife deleted the issue-3-plant-state-machine branch July 2, 2026 22:20
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.

[M3] Plant state machine

1 participant