Releases: OrangePeachPink/sprout
Release list
v0.8.1 — Architecture hardening, and the Predict delta
Architecture hardening, and the Predict delta
v0.8.0 was called "Predict" and its forecast never reached a surface. A blind review across
eight independent tracks found it after the fact — the headline model existed, was tested, and
was reachable by nothing a person could see. That gap became
PRD-0009,
and eight of its nine ratified requirements ship here.
The rest of the release went after the seams underneath — and kept finding the same defect, five
separate times: a layer correct about the question it asks, and silent about the one nobody wired.
Your plants now say one thing, in one place
Every surface used to reach its own conclusion about a plant. Now there is one composed state —
and the card, the queue, and the chart all read from it rather than re-deriving it.
- The attention model decides once what a plant needs. The harm level fires on plants trending
badly, not only on broken instruments; the calm signal is affirmative and time-bound; a plant that
was just watered is held rather than re-nagged. - An untrustworthy reading predicts nothing. A sensor we don't believe stops producing forecasts
instead of producing confident ones. - The queue is ordered by forecast, not by wetness — and it is the same ordering the card
shows, asserted in code so the two cannot drift apart. - The forecast appears on the history chart, with an unmistakable boundary between what was
measured and what is predicted, and a confidence vocabulary where the interval is the how-sure.
Adding a board no longer requires knowing how Sprout works
The whole path, in the app: describe your hardware → map probes to plants → flash → it reports.
No JSON, no config files, no command line. You declare the board before flashing it, and Sprout
keeps what you set up when the board first speaks. A board that answers but isn't registered is
offered for adoption rather than ignored.
Things that were quietly wrong, and aren't
- The health strip stopped crying wolf. Every sensor was drifting toward "inspect" — not because
the hardware was failing, but because three signals counted any single event, ever over unbounded
history. Older boards scored worse purely for being older. Now they are rates, dropout cadence is
measured locally instead of pooled across logging regimes, and an instrument with no readings gets
no verdict rather than a clean bill of health. - The zero state names the real state instead of waiting forever; the serial lock says who holds
the port and what to do about it; Ctrl-C exits clean;just doctorturned a wall of output into a
checklist. - Charts say when they're frozen rather than going silently stale, and the wide-window build is
twice as fast.
Under the hood
- The package flip:
toolsis importable by name and 227 lines ofsys.pathsurgery are gone,
with byte-identical output. - Release integrity, walked rather than assumed. A dry-run of the entire signing chain — draft,
sign, verify, publish, resolve, delete — on a throwaway tag found a cut-blocking defect on its
first run: the signer could not resolve a draft, and would have produced a second asset-less
release with an error blaming the operator for a draft that already existed. - Signed-pull OTA reached hardware, dark by construction. The feed fails closed.
The record, corrected
v0.8.0's entry was missing from the changelog entirely for four days while the file still
announced it as the next cycle. It is now written, honestly: that release shipped its foundations
and not its name, and it published with zero assets because the signer ran after publish and
GitHub refused the upload to an immutable release.
Releases now carry a theme-conformance gate — a themed release is not closed until someone
asks whether the name became true on the operator's surface.
Known scope, carried rather than hidden
- The health analysis still reads pre-production bench rows; lab sessions are unmarked on the
timeline (#1634,
#1635). - The version guard doesn't inspect
uv.lock, and doesn't check dates at all — both found during
this cut (#1633,
#1637).
Per-component detail is in
CHANGELOG.md.
Full generated commit list
What's Changed
✨ Features
- feat(board): just-wrappers for the five board fields (#1443) by @OrangePeachPink in #1444
- feat(flash): the alpha channel from the CLI — just flash-alpha (#1334) by @OrangePeachPink in #1482
🐛 Bug fixes
- fix(release): sign into the draft, publish seals it (#1438) by @OrangePeachPink in #1459
- dx(lint): epic-hygiene discovers epics structurally, not by the retiring label (#1446) by @OrangePeachPink in #1473
- fix(board): read renders empty fields as — and never crashes (#1447) by @OrangePeachPink in #1469
- fix(ci): experimental-board job is non-blocking on EVERY step, not just compile (#1439) by @OrangePeachPink in #1476
📖 Documentation
- docs(adr-0003): the v0.8.0 process standardization — the ratified retro package by @OrangePeachPink in #1441
- docs(team): the D pass — OPERATIONS + CONTRIBUTING sync to tonight's ratified process by @OrangePeachPink in #1450
🔧 Other changes
- docs(team): the design lane is named Design — one name, board and relays alike by @OrangePeachPink in #1440
- docs(adr-0027): §6 calibration portability RESOLVED — portable on a per-board transfer (#621) by @OrangePeachPink in #1448
- data(identity): #1454 — the shared resolved-identity join, the S1-seam closure by @OrangePeachPink in #1461
- fix(logger): #1428 — a fleet-logger refusal is not a crash, and its words survive by @OrangePeachPink in #1465
- docs(adr-0003): the new-ADR justification gate + harvested antipatterns (#1462) by @OrangePeachPink in #1464
- feat(telemetry): #1434 AC0 — emit the signed classifier step so rate_spike is auditable from the wire by @OrangePeachPink in #1463
- fix(tier): #1466 — the launcher fills the store, not only compacts it by @OrangePeachPink in #1471
- docs(adr-0000): 0012/0013 are satellites of 0006, not a merge (#1462) by @OrangePeachPink in #1472
- docs(adr-0035): fold ten amendments into one band model + a changelog (#1462) by @OrangePeachPink in #1467
- feat(registry): #1188 — a location edit reads as the move it is by @OrangePeachPink in #1470
- fix(home): #1432 — one physical channel is one card across the v5 flash by @OrangePeachPink in #1475
- feat(ota): S3 pull transport orchestrator — fetch → parse → decide → gated apply (#1284) by @OrangePeachPink in #1474
- fix(trial): #1435 — the trial says WHY it is empty, never a false 'no readings' by @OrangePeachPink in #1477
- docs(bench): safety-gate run sheet — on-device proof for #93 watchdog + fail-safe (#93) by @OrangePeachPink in #1480
- perf(classic): #1457 — halve the wide-window build (classify once, not twice) by @OrangePeachPink in #1484
- fix(cal): land the C5's measured board-level rails so open_adc can fire (#1433) by @OrangePeachPink in #1490
- perf(classic): #1456 — RSS-per-request instrument + a session-stability guard by @OrangePeachPink in #1487
- fix(provenance): #1430 — label the host CSV schema for what it is by @OrangePeachPink in #1489
- fix(classic): #1455 — the charts say when they're frozen, never silently old by @OrangePeachPink in #1486
- feat(registry): #1027 §5.1 — the calm discovery set (answering-but-unregistered boards) by @OrangePeachPink in #1491
- feat(registry): #1188 AC2 — structured placement on the temporal move (ADR-0029) by @OrangePeachPink in #1492
- feat(ota): S3 pull hardware bindings — real fetch_feed/esp_ota, dark by construction (#1284 AC4) by @OrangePeachPink in #1488
- docs(security): correct the ArduinoOTA claim in SECURITY.md — public builds arm no OTA receiver (Refs #1478) by @OrangePeachPink in #1483
- docs(release): the sign-the-draft-before-publish guard — v0.8.0 asset-less, in th...
v0.8.0 — Predict: Sprout Sees It Coming
What's Changed
✨ Features
- feat(just):
just check-host— the no-compiler local gate + exact per-OS compiler commands (#1189) by @OrangePeachPink in #1253 - feat(just): DuckDB/Parquet tier ergonomics — store-rebuild/verify/query + docs (#1249) by @OrangePeachPink in #1288
- feat(operator): launcher-managed daily-compaction hook (#1292) by @OrangePeachPink in #1302
- feat(dx): guard against raw NUL bytes in tracked text files (#1327) by @OrangePeachPink in #1355
- feat(dx): make the firmware-free contributor path the default gate (#1337) by @OrangePeachPink in #1373
- feat(flasher): release channels — stable by default, alpha behind a checkbox (#1334) by @OrangePeachPink in #1398
- feat(launch): pack the new tile app-icon into the desktop shortcut (#1359) by @OrangePeachPink in #1400
- feat(dx): the product version agrees everywhere it is declared (#1407) by @OrangePeachPink in #1409
- feat(dx): the import-layer lint — imports go strictly downward (#1336) by @OrangePeachPink in #1412
🐛 Bug fixes
- fix(home): the watering pass holds — retained state + frozen order (#1229) by @OrangePeachPink in #1250
- fix(just): ota host_ip path reads platformio_local.ini's password (#1268) by @OrangePeachPink in #1271
- design(flash): brand-align the web-flasher to the Sprout tokens (#271) by @OrangePeachPink in #1298
- ci(release): build the exact ref, fail closed, write once (#1346) by @OrangePeachPink in #1351
- ci(release): prove the ref, receipt the bytes, SHA-pin the rest of the fleet (#1346) by @OrangePeachPink in #1363
- ci: pin PlatformIO to 6.1.19 across the whole workflow fleet (#1346) by @OrangePeachPink in #1368
- ci(guard): finish the action pins + guard that they resolve (#1346) by @OrangePeachPink in #1377
- fix(dx): tracked paths stay Windows-clonable — rename + guard (#1337) by @OrangePeachPink in #1381
- fix(dx): the onboarding validator runs the literal
just start(#1337) by @OrangePeachPink in #1391 - ci(release): don't draft a release for a collapsed milestone (#1346) by @OrangePeachPink in #1417
📖 Documentation
- docs(team): the deliberately-not-at-our-scale ledger with reopen triggers by @OrangePeachPink in #1341
- docs: truth-in-docs sweep — every public statement matches the shipped system (#1332) by @OrangePeachPink in #1345
- docs: conduct reports don't route through the security channel (#1337) by @OrangePeachPink in #1383
- docs(process): record outside-PR approvals as formal GitHub reviews (#1337) by @OrangePeachPink in #1393
- docs(brand): canonical repository topics, in the repo (#1403) by @OrangePeachPink in #1404
- docs(brand): topics to the full 20 + the remaining blind-spot surfaces (#1403) by @OrangePeachPink in #1410
🔧 Other changes
- feat(watering): pair a glug with its detected re-water, not compete (#1137) by @OrangePeachPink in #1230
- feat(tier): D0 TRACER — one CSV device-day → Parquet → DuckDB, fidelity-asserted (#1238) by @OrangePeachPink in #1251
- design(concepts): v0.9.0 sketches — pumps, tank, refill, minimum rig (#597) by @OrangePeachPink in #1254
- docs(ota): PLATFORMIO_UPLOAD_FLAGS replace-not-merge + newline-split trap by @OrangePeachPink in #1255
- docs(adr): ADR-0026 — Phase-1 staged amendment; anti-rollback declined (#877) by @OrangePeachPink in #1256
- feat(classifier): C0 TRACER — segments + the valid-for-trend mask, glug-validated (#1244) by @OrangePeachPink in #1257
- fix(workbench): drop the stale INTERIOR-BANDS-PROPOSED badge — the ladder is ratified (#1233) by @OrangePeachPink in #1259
- feat(cards): pulse envelope spans the anchors — all 7 moods draw (#1235) by @OrangePeachPink in #1261
- refactor(classifier): rename the C0 kind suspect → flagged (#1245 containment ruling) by @OrangePeachPink in #1266
- feat(cal): #1236 ratified wet-end re-derivation → shipped defaults by @OrangePeachPink in #1262
- feat(bands): host sibling of the RATIFIED #1236 wet-end ladder — ⚠ PAIR-MERGE with Firmware by @OrangePeachPink in #1264
- docs(release): ADR-0009 Decision 7 + RELEASE_CUT §7 — release-feed curation (#1258) by @OrangePeachPink in #1265
- feat(ota): local-config override for the OTA password — no secret in git by @OrangePeachPink in #1260
- feat(workbench): one vocabulary — the mood word IS the band word (#1234 render half) by @OrangePeachPink in #1267
- docs(adr): ADR-0035 Status — note the #1236 wet-end re-derivation by @OrangePeachPink in #1270
- feat(control): surface the health latch as
withheld— the invisible-latch fix (#2) by @OrangePeachPink in #1269 - docs(cal): annotate the two #898 factor/anchor pairs — interval-dependent, both valid (#1215) by @OrangePeachPink in #1275
- migrate(classic): #1142 — retire the watering-status board (the Home grid is its replacement) by @OrangePeachPink in #1279
- feat(tier): D1 — the written store contract + the two ratification folds (#1239) by @OrangePeachPink in #1272
- feat(tier): D2 — backfill loader: all history → the store, idempotent + checked (#1240) [stacked on #1272] by @OrangePeachPink in #1274
- docs(adr): ADR-0036 — sensor-identity layers, ending the s# overload (#1042) by @OrangePeachPink in #1273
- feat(home): #1136 — the band-journey on the hero (start ring + travel arrow + one counted sentence) by @OrangePeachPink in #1276
- feat(telemetry): #1152 emit — open_adc + rate_spike at the source by @OrangePeachPink in #1277
- migrate(classic): #1149 — retire the proposed-interior-bands caveat (the ladder is ratified) by @OrangePeachPink in #1285
- design(concepts): #1148 — the voiced multi-plant history, three DRAFT concepts by @OrangePeachPink in #1286
- migrate(classic): #1143 — retire the band-movement bars (hero ladder + the #1136 journey are the destination) by @OrangePeachPink in #1280
- feat(cal): #963 Layer 1 — the runtime-writable owner-cal slot by @OrangePeachPink in #1290
- feat(tier): D4 — the ADR-0031 rollup tiers + the sparse event table (#1242) by @OrangePeachPink in #1291
- feat(classifier): C1 — the written taxonomy contract + rate-based rebound + the PASS (#1245) by @OrangePeachPink in #1278
- feat(classifier): C2 — full-history classification + per-plant validity (#1246) [stacked on #1278] by @OrangePeachPink in #1287
- feat(registry): #675 — the ADR-0029 profile dimension (loader + hardened template + seed back-fill) by @OrangePeachPink in #1281
- migrate(classic): #1147 + #1145 — the single-plant view's forecast fold + segment-truth label by @OrangePeachPink in #1294
- feat(classifier): C3 — surfaces honor the mask, the Design-ruled hatch (#1247) by @OrangePeachPink in #1295
- feat(classifier): C4 — the predicted-vs-actual backtest harness (#1248) by @OrangePeachPink in #1297
- feat(registry): #1027 data half — the honesty classes under the adopt trigger by @OrangePeachPink in #1299
- docs(spec): #1152 — finalize the instrument-exceptions spec against what shipped by @OrangePeachPink in #1300
- data(voice): #1141 next-touch pass — dashboard.py's three truth-framings to canon by @OrangePeachPink in https://github.com/OrangePeach...
v0.7.3 — Monitor: Sprout Gets a Voice
Monitor: Sprout Gets a Voice. The surface we designed first is now the product: open Sprout and meet your plants — a card grid in Sprout's own voice, most-thirsty first, each plant wearing its mood, with the instrument workbench one click behind it. Underneath the voice, the measurements grew up too: the seven-band ladder was re-derived from a six-day in-situ dry-down on the real windowsill fleet, ratified band by band, and shipped to both firmware and host as doctrine (ADR-0035, Accepted). And the door is open — this release ships with our first three community contributors named in CONTRIBUTORS.md.
Per-component reality (ADR-0009 §3)
- Host — the production Home + hero (two-surface architecture, ADR-0033 Accepted): the voice pool with event-free variants, the pulse histogram + segment-bound sparkline, one-tap "Glug glug" watering log, the 14d window, the full creative palette + chart focus-tap, in-app pot/location editing, shell route coverage.
- Firmware — the ratified band ladder (the one flash-affecting change: all seven levels in-soil, boundaries measured + ratified); the native suites grew (band-partition invariants, the dose-control sim — sim-only, not linked into the shipped build); the coincident water-anchor relax.
- Docs & process — ADR-0033 + ADR-0035 Accepted with measured numbers · the color-roles charter + BRAND.md canon · the audience-scoped instruction-file split (#1125) with the credit-protection CI · the contributors roster · Trust Your Sensor live on Pages · the voice-guard, per-hook job summary, and board-hygiene tooling.
Release evidence
- Register sweep (
just voice-guard --all): user-facing surfaces clean; remaining hits are internal code-comment names of shipped concepts (the kept class). - Board hygiene (
just board-hygiene): zero drift; one advisory (v0.8.0 sizing, routed to planning). - Weekly full battery (firmware included): green, fresh at cut. 58 accelerated merges, zero reverts (#1048's final tally).
What's Changed
✨ Features
- feat(dashboard): inline field-edit — rename plants, sensors, boards (#1038) by @OrangePeachPink in #1050
- feat(dashboard): per-channel view filtering — Show-all + double-click solo (#993) by @OrangePeachPink in #1053
- design(brand): Sprout asleep (night) — sleeping/sign-off scene + social card (Workflow variant) by @OrangePeachPink in #1086
- test(cal): parameterized band re-partition invariant suite (#1153) by @OrangePeachPink in #1164
- feat(home): the production Home + hero — the Sprout Voice UI lands (#875) by @OrangePeachPink in #1160
- feat(hero): the sparkline — the pulse mandate's second element (#1171) by @OrangePeachPink in #1184
- feat(watering): the manual watering log — slice 1 of "glug glug" (#1137) by @OrangePeachPink in #1185
- feat(app): edit pot size + location in-app — close the last JSON-surgery gaps (#833) by @OrangePeachPink in #1179
- feat(ci): fork-PR credit-protection nudge — warm, non-blocking (#1126) by @OrangePeachPink in #1167
- feat(control): bounded re-wetting + absorbed/ran-through sim (#414) by @OrangePeachPink in #1183
🐛 Bug fixes
- fix(copy): monitor give-up banner names the tethered board, not a Python None (#1032) by @OrangePeachPink in #1045
- fix(registry): migrate_static honors retired → paused, not active (#1036) by @OrangePeachPink in #1047
- fix(logger): evict archived segments from logs/ — B8's bounded-growth half (#1035) by @OrangePeachPink in #1051
- perf(fleet): circuit breaker for unanswering devices — the durable half of #953 (#1020) by @OrangePeachPink in #1054
- perf(capture): serve the page shell fast + instrument the boot (#1018) by @OrangePeachPink in #1061
- fix(#1018): renderShellState fills #cards, never wipes #overview (rescue of Data's stranded fix) by @OrangePeachPink in #1064
- fix(pages): apply the #1138 register ruling to the front-door head meta (#1181) by @OrangePeachPink in #1212
📖 Documentation
- docs(process): Velocity modes v2.1 — V2 standing policy, internal default, ~80% target by @OrangePeachPink in #1043
- docs(voice): move the internal pipeline + lane-self-sync from CONTRIBUTING to AGENTS (#920 slice 3) by @OrangePeachPink in #1052
- docs(bench): ESP32-C5 + S3 flash/recovery troubleshooting guide (#1046) by @OrangePeachPink in #1060
- docs(adr): ADR-0033 (Proposed) — two-surface architecture, Home + Workbench (#1044) by @OrangePeachPink in #1049
- docs(prd): add PRD-0008 public front door + launch-surface epic by @OrangePeachPink in #1068
- docs(adr): ADR-0034 — the Pages root is Sprout's public front door (FD-0, #1070) by @OrangePeachPink in #1079
- docs: link the maintainer credit to Veronica Hogue / vkhogue.com by @OrangePeachPink in #1078
- docs: add the good-first shelf replenish step to the release ritual by @OrangePeachPink in #1098
- docs: contributor-onboarding polish — claim protocol + self-credit invite by @OrangePeachPink in #1106
- docs: invite contributors to grab the contributor card (CONTRIBUTORS_WELCOME) by @OrangePeachPink in #1108
- docs(hardware): ADC1 sensor-ceiling-per-board table — the 4→6 scale headroom (#1039) by @OrangePeachPink in #1116
- dx(community): the contributor "what to expect" doc (#1105) by @OrangePeachPink in #1112
- docs: de-internal-ize contributor-facing surfaces + delete stale #740 CI note by @OrangePeachPink in #1131
- process(agents): stage A — docs/team/OPERATIONS.md canonical + the contributor fence (#1125) by @OrangePeachPink in #1130
- process(agents): stage B — AGENTS.md contributor-true; doctrine lives in OPERATIONS.md (#1125) by @OrangePeachPink in #1132
- docs(gtm): fold the plant/data-overlap audience doctrine into the GTM docs (#1039 item 5) by @OrangePeachPink in #1154
- docs(contributing): "Using a coding agent?" section + retire intro honesty lexicon (#1127) by @OrangePeachPink in #1140
- docs(adr): ADR-0033 grill amendment — Home card grid + Classic Sprout (Proposed → Accepted, #1044) by @OrangePeachPink in #1110
- docs(firmware): instrument-exceptions source-side spec (#1152) by @OrangePeachPink in #1159
- docs(refs): post-split AGENTS.md reference audit — classify + close the class (#1158) by @OrangePeachPink in #1163
- docs(experiments): extended in-situ dry-down (peak-summer) for #995 (#1174) by @OrangePeachPink in #1192
- docs(llms): apply #1138 — definitional intro, not personified (FD-3 delta) by @OrangePeachPink in #1187
- docs(contributors): list external contributors by handle before the 0.7.3 cut (#1196) by @OrangePeachPink in #1201
- docs(front-door): Trust Your Sensor live on Pages — FD-5 (#1075) by @OrangePeachPink in #1206
- docs: fix stale ADR range + broken cd in onboarding (#1092, #1093) by @OrangePeachPink in #1214
🔧 Other changes
- fix(fleet): loud identity mismatch — a ghost board can never need a screenshot again (#1026) by @OrangePeachPink in #1058
- feat(#966): rig-location setup UI — enable shading + weather from Diagnostics by @OrangePeachPink in #1062
- feat(#1027): adopt an answering board + migrate the sensorless roster (Data structure) by @OrangePeachPink in #1063
- feat(#995): the per-sensor health page — QA signals on the running rig by @OrangePeachPink in #1065
- docs(design): FD-1 front-door design brief + render-1:1 copy deck by @OrangePeachPink in #1067
- design(brand): FD-1 hero mark — self-contained animated Sprout by @OrangePeachPink in #1081
- fix(brand): hero-mark aria-label three-leaf (matches geometry) by @OrangePeachPink in #1084
- feat(pages): the Sprout front-door hub + FD-2 head block (FD-1) by @OrangePea...
v0.7.2 — the monitor you can trust
Sprout 0.7.2 is the release where the logger became unkillable and the plants got a real registry.
The headline promise, kept: just be a damn logger and never stop. The collection worker now supervises itself, restarts on any death, refuses loudly instead of silently, and every failure it can still hit writes itself into a log in plain words. The dashboard's one button never lies about recording state.
The other half: Plants & Sensors — your real fleet in a tab. Add plants and sensors, map any sensor to any plant with a plant-first picker (no channel soup), pause what's resting, and permanently delete what's gone — with a receipt showing exactly what left the disk. Classic review-then-save; nothing changes until you say so.
Also aboard: per-channel calibration tiers live on the wire and honest on every chip (a fully-calibrated channel wears no badge at all), an opt-in environment overlay (context, not cause), era-aware provenance that never cries VIOLATION at your own history, a web flasher that offers only what's bench-proven, ed25519 release signing (this release is its first live fire), and the dashboard's old 15-second slowness diagnosed down to ~3.
Grown on a kitchen windowsill. Raw counts + band are the truth. tend well. 🌱
What's Changed
✨ Features
- feat(analytics): cross-board comparability guard (honesty-guard slice, #832) by @OrangePeachPink in #943
- feat(dashboard): three-tier cal honesty — the C5 stops wearing "provisional" (#951) by @OrangePeachPink in #957
- feat(firmware): wifi==serial config-command parity — /cmd endpoint (#826) by @OrangePeachPink in #954
- feat(firmware/build): board-aware factory_bin + verified-marker (#271) by @OrangePeachPink in #956
- feat(firmware/cal): per-board-type calibration resolution chain (#952) by @OrangePeachPink in #964
- feat(dashboard): surface config_id on Diagnostics — closes the last ADR-0030 gap (#831) by @OrangePeachPink in #984
- feat(serve): verify-then-assert auto-start collection at launch — the honest promise of Monitor (#872) by @OrangePeachPink in #991
- feat(registry): temporal registry model — #921 slice 1 (Data foundation) by @OrangePeachPink in #996
- feat(cal): parse the cal_tier wire token — #951 tier chip true on the live WiFi fleet (#952/#957) by @OrangePeachPink in #997
- feat(registry): /registry GET seam for the Plants & Sensors tab + board taxonomy (#921 slice 2) by @OrangePeachPink in #1000
- feat(dashboard): Plants & Sensors tab — read-only registry + first-run landing (#921 slice 2) by @OrangePeachPink in #1003
- feat(telemetry): cal_tier/cal_src on the WiFi soil rows — the live tier chip (#4) by @OrangePeachPink in #1002
- feat(pages): Actions-deployed Pages — web-flasher bins + design library (#271) by @OrangePeachPink in #1006
- ci(release): ed25519 firmware signing + key-ceremony run-sheet (#302, PR-in-waiting) by @OrangePeachPink in #989
- feat(registry): POST /registry/apply — classic-save the mapping batch (#921 slice 3) by @OrangePeachPink in #1021
- feat(registry): device purge — the delete backend (#921 slice 4, small → v0.7.2) by @OrangePeachPink in #1022
- feat(dashboard): Plants & Sensors editing — add + classic save (#921 slice 3a) by @OrangePeachPink in #1023
- feat(registry): per-channel view on /registry — cal tier/provenance + free-port occupancy (#921 slice 5) by @OrangePeachPink in #1025
- feat(dashboard): opt-in environmental overlay on the plant trajectory + the value-verdict (#922) by @OrangePeachPink in #1030
- feat(dashboard): the mapping picker — plant-first, no dropdown soup (#921 slice 3b) by @OrangePeachPink in #1033
- feat(dashboard): Plants & Sensors lifecycle — Pause/Resume + loud Delete (#921 slice 3c) by @OrangePeachPink in #1024
🐛 Bug fixes
- fix(docs): pin Design Library contributor links to /blob/main; absolute PRD link by @OrangePeachPink in #914
- fix(design): commit Trust-Your-Sensor board photos (EXIF-stripped) + link the page (#912) by @OrangePeachPink in #937
- refactor(ui): plantLabel() everywhere + identity-leak tripwire — #803-805 class extinct (#925) by @OrangePeachPink in #939
- perf(serve): phase-timing decomposition for slow dashboard builds (#953) by @OrangePeachPink in #959
- fix(docs): repoint retired-BACKLOG ref + site-absolute the served /docs links (#911) by @OrangePeachPink in #960
- fix(ux): control-surface collapse — one collection action, serial baseline → Diagnostics (#923) by @OrangePeachPink in #955
- perf(fleet): parallelize served-device fetches — the ~14s was timeouts, not re-parse (#953 slice 2) by @OrangePeachPink in #967
- fix(dashboard): fleet-poll sources get their own labeled line, not file cosplay (#965) by @OrangePeachPink in #970
- fix(serve): client abort mid-response no longer cascades into a double traceback (#969) by @OrangePeachPink in #992
- fix(launcher): say when self-update is skipped + print the running sha by @OrangePeachPink in #982
- fix(serve): Stop preempts the request pile — reject-new + grace + hard-exit (#972) by @OrangePeachPink in #987
- fix(ux): served status line speaks honest sensor counts, not transport-split (#974) by @OrangePeachPink in #986
- feat(dashboard): dual-state logging button + am-I-recording banner (#980 + #979) by @OrangePeachPink in #999
- fix(dx): identifier-guard catches denylisted hostnames via committed SHA-256 hashes by @OrangePeachPink in #961
- fix(fleet): supervise the logger — restart on crash, loud give-up, idempotent start (#1004 · #968 · #1007) by @OrangePeachPink in #1010
- fix: close the P0 release gate — one-button start guards + mDNS IP-persist (#1004, #953) by @OrangePeachPink in #1014
- fix(dashboard): request-generation guard — a stale /data.json response can't paint (#976) by @OrangePeachPink in #1016
- fix(launcher): stub/body split so self-update can't overwrite the running script by @OrangePeachPink in #1015
- fix(ux): era-aware provenance contract — no red VIOLATION at legacy dirt data (#977) by @OrangePeachPink in #1017
- fix(logger): archival failures surface loudly, never silently swallowed (#900, slice) by @OrangePeachPink in #1019
- fix(pages): pull esp32c5 from the web flasher — EWT 10.0.0 can't flash it (#271) by @OrangePeachPink in #1028
- fix(registry): _REPO off-by-one — read/write the real config, not tools/config/ (#1029) by @OrangePeachPink in #1031
📖 Documentation
- docs(audit): ADR-0030 display-contract conformance — config_id is the one gap (#831) by @OrangePeachPink in #945
- docs(onboarding): Windows USB-serial driver prep + first-run pio penv retry by @OrangePeachPink in #948
- docs(adr): ADR-0026 body — Phase-0 acknowledgment + maker-first scaling by @OrangePeachPink in #944
- fix(docs): release-notes template points Discussions at its absolute URL (#911 finding 4) by @OrangePeachPink in #958
- docs(voice): welcome AI-assisted contributions, without gatekeeping (#920 slice 1) by @OrangePeachPink in #962
- docs(ux): sweep the settled collection vocabulary to the remaining surfaces (#873) by @OrangePeachPink in #971
- docs(on-ramp): reference cal_class_defaults.h as the real-anchor source (#550) by @OrangePeachPink in #983
- docs(voice): plain-language the contributor path — de-jargonize merge + review (#920 slice 2) by @OrangePeachPink in #988
- docs(doctrine): codify the honesty-law pair — wear only the caveats you've earned (#977) by @OrangePeachPink in #990
- docs(experiments): 2026-07-11 watering dose-response — first per-pot-cal fleet run (v0.7.2) by @OrangePeachPink in https://github.com/OrangePeachPink/s...
v0.7.1 — Wave 1: Monitor
What's Changed
✨ Features
- feat(process): release machinery — auto-draft on milestone close, notes-hygiene warn, turnkey cut checklist by @OrangePeachPink in #745
- feat(design): header orientation copy in Sprout's voice (#722) by @OrangePeachPink in #749
- feat(design): link Docs Front Door + Design Library from Diagnostics & Logs (#758) by @OrangePeachPink in #772
- feat(design): interim fleet palette — distinguish devices by line style (#686) by @OrangePeachPink in #774
- feat(design): within-band urgency on the cards — order by need + a position cue (#715) by @OrangePeachPink in #781
- feat(design): render the header orientation line from the voice pool (#722) by @OrangePeachPink in #787
🐛 Bug fixes
- fix(design): metrically-aware font fallback stacks in the tokens (#116) by @OrangePeachPink in #746
- feat(design): plant-first cards — lead with the plant, no machine IDs (#713 #714 #688) by @OrangePeachPink in #761
- fix(design): standard light/dark toggle — retire 'soil mode' (#723) by @OrangePeachPink in #763
- fix(design): scope Monitor view controls to the tabs where they act (#708) by @OrangePeachPink in #773
- feat(design): split calibration ladder — Watering status (Monitor) + Calibration reference (Diagnostics) (#716) by @OrangePeachPink in #775
- fix(design): render the four-tab nav on /lab pages — Lab stays first-class (#684) by @OrangePeachPink in #777
- fix(design): short-channel device cards keep normal columns, not full-width (#709) by @OrangePeachPink in #779
- fix(design): consolidate the cal-provisional banner to one fleet note (#687) by @OrangePeachPink in #780
- fix(dashboard): Watering-status ladder chips plant-first, retired excluded (#803) by @OrangePeachPink in #815
- fix(dashboard): single-plant navigator jump-list plant-first, retired excluded (#804) by @OrangePeachPink in #817
- fix(dashboard): channel toggle per live plant, plant-first, not channel index (#805) by @OrangePeachPink in #819
- fix(design): card shows friendly short board name + left/right side (#806) by @OrangePeachPink in #820
- fix(dashboard): floor the single-plant detail chart y-axis at 0 (#797) by @OrangePeachPink in #847
- fix(design): SVG geometry moustaches parse-error on public pages — bind via sc-camel- (#886) by @OrangePeachPink in #895
📖 Documentation
- docs(design): design doctrine — four-question test + two-jobs split rule (#726) by @OrangePeachPink in #742
- docs(process): one verification signal — the Status column (#729 ruling) by @OrangePeachPink in #755
- docs(adr): ADR-0029 — plant/pot/site profile registry, the inference dimension (#675) by @OrangePeachPink in #762
- docs(adr): register hygiene — ADR-0027 row reflects its accepted, shipped state by @OrangePeachPink in #784
- docs(adr): ADR-0020 §2 — mDNS hostname = the stable device_id nonce (reconcile #760) by @OrangePeachPink in #786
- docs(adr): register row — ADR-0025 Proposed → Accepted (maintainer-ruled, mechanism live in v4) by @OrangePeachPink in #799
- docs(design): out-of-box fence — golden path never requires soldering/mods (#801) by @OrangePeachPink in #846
- docs(adr): ADR-0030 (Proposed) — version identity, build provenance & display contract (#831) by @OrangePeachPink in #851
- docs(adr): ADR-0029 v2 (Proposed) — harden the profile schema for the three hard cases (#675) by @OrangePeachPink in #854
- docs(adr): ADR-0031 (Proposed) — read-path rollup tiers over immutable raw (#828) by @OrangePeachPink in #858
- docs(readme): stop the opening overclaiming watering — honest in the prose, too (Refs #59) by @OrangePeachPink in #874
- design(concepts): v0.9.0 watering/tank/optionality sketches — Library entry (#597) by @OrangePeachPink in #879
- docs(firmware): correct the stale ESP32-C5 platformio.ini flash comment by @OrangePeachPink in #891
- docs(evidence): clean-machine onboarding log (2026-07-09) + gap map by @OrangePeachPink in #893
🔧 Other changes
- chore(process): epic sub-issue hygiene lint (ADR-0003 §2 self-enforcing) by @OrangePeachPink in #682
- docs(release): version-milestone roadmap + first release criteria (ADR-0009) by @OrangePeachPink in #696
- docs(process): release/milestone mechanics + GitHub-native-by-default principle by @OrangePeachPink in #705
- docs(process): agent-lane roster — retire Sage/Ingest, expand DX, DesignQA leads design by @OrangePeachPink in #706
- docs(release): codify the release-notes quality bar (ADR-0009 §6) by @OrangePeachPink in #733
- docs(process): standardize Priority (P0–P3) + Size (XS–XL) meanings by @OrangePeachPink in #737
- chore(process): commits credit the maintainer — drop AI co-author trailers by @OrangePeachPink in #738
- ci: velocity-first sprint posture — fast per-PR lane + weekly full battery (#740) by @OrangePeachPink in #741
- docs(evidence): fix merged install-record ref #20 -> #679 (sensorless dashboard) by @OrangePeachPink in #681
- docs: post-v0.7.0 docs-pass — README + BOARDS reflect the shipped Wi-Fi fleet by @OrangePeachPink in #744
- feat(data): plant-first identity data-shape — probe/board-name/side/plant-meta (#713 Data half) by @OrangePeachPink in #743
- fix(quality): flag sub-wet-rail soil readings as sensor fault, not a moisture band (#670) by @OrangePeachPink in #672
- feat(data): watering-status data-shape — within-band position + sortable dryness (#715 Data half) by @OrangePeachPink in #747
- docs: re-validate onboarding vs shipped v0.7.0 (#690) — fleet-start step + CI-posture drift fix by @OrangePeachPink in #748
- fix(data): run ContextFiller on the fleet logger — interior temp/RH fills untethered soil rows (#701) by @OrangePeachPink in #750
- feat(firmware): emit schema v4 — config_id + rssi/uptime/heap + SENSOR_FAULT (#739) by @OrangePeachPink in #754
- fix(dx): pre-commit npx→language:node — kill the focus-stealing cmd.exe windows (#664) by @OrangePeachPink in #751
- docs(dx): PlatformIO first-run behavior + clean-reset runbook (#692) by @OrangePeachPink in #752
- docs(dx): add sprint-CI-posture revert to the go-public checklist (#740) by @OrangePeachPink in #753
- docs(dx): §2 runbook hardening — confirmed dual-Python fix + pioarduino-IDE unwanted guard (#692) by @OrangePeachPink in #756
- feat(data): parse_v1 schema-v4 extension — config_id / rssi·uptime·heap / SENSOR_FAULT (#739 Data half) by @OrangePeachPink in #759
- feat(firmware): advertise sprout-<device_id>.local via mDNS (#676) by @OrangePeachPink in #760
- feat(dx): headless collection lifecycle — just collection start|stop|status + reclaim (#689) by @OrangePeachPink in #764
- fix(dashboard): settled summary stats — no warmup / fault-zero pollution (#697) by @OrangePeachPink in #765
- docs(dx): the Docs Front Door + doc-IA map, cross-linked with the Design Library (#757) by @OrangePeachPink in #766
- feat(data): host cal-state reader — calibrated boards stop rendering provisional (#404) by @OrangePeachPink in #768
- test(data): host session-tolerance — a reset-driven session change is not churn (#712) by @OrangePeachPink in #769
- feat(dx): local time on the dashboard face — render the bare-UTC displa...
v0.7.0 — Wave 1: Monitor
🌱 Wave 1 — Monitor. The plants are online.
Sprout's first release. Eleven windowsill plants, monitored by WiFi-only ESP32s — one power cord each, zero data cables, zero bench time — all visible live in one dashboard, readings logged durably around the clock. This is the baseline every future release builds on.
✨ Highlights
- The untethered fleet — two proven ESP32 boards (classic + official C5) run on brick power and serve their own telemetry over WiFi; one Start governs collection. No serial tether at go-live.
- One honest dashboard — four-destination IA (Monitor / Capture / Lab / Diagnostics & Logs), raw ADC + band words as truth (percent only ever a labelled index), canonical moods bound to the band map, device-scoped calibration ladder, live-by-default.
- Identity model (ADR-0027) — minted stable device IDs, a channel≠probe split, and a registry as the authoritative name home, so a plant's name survives reflashes and DHCP.
- Optional-peripherals doctrine (ADR-0028) — the minimum Sprout (1 MCU + 1 soil sensor) is complete; every peripheral is optional and absence is first-class. Wave 1 ran 8 instrumented plants + 3 sensorless-by-design, honestly.
- First closed prediction loop — a blind drydown forecast scored 7/8 against install-night actuals; the one miss now seeds the Wave-2 predictor.
📖 Notable decisions this release
ADR-0027 (identity) · ADR-0028 (optional peripherals) · ADR-0009 (versioning & release policy — this release is its first exercise) · the four-tab information architecture.
⚠️ Honest scope (carried, not hidden)
- C5 bands are provisional until per-board ADC calibration (Wave 2, #443).
- The
!wedgesafety check was not re-run at this install (boards went straight to untethered) — tracked in #599. - The yellow C5 (
yyvvpd) is minted and shelved as a hot spare; recovery is non-urgent headroom.
Notes
Sprout's first tracked release — earlier development lives in the git history, not in prior release notes; the changelog discipline starts here (nothing before this is reconstructed — that would invent history). This is a private, pre-public release — the deliberate road to 1.0.0 is the Wave-4 public launch (ADR-0009: 1.0 is a chosen milestone, never reached by counting). v0.7.0 is the baseline tag; from here, release notes generate automatically tag-to-tag.
Full Wave-1 record: #584.