Releases: srcfl/ftw
Release list
v0.130.4
🛰️ Marvin
Don't Panic.
Patch Changes
-
ed59d81: Answer health probes during slow boots.
The API port is now bound before the state DB opens, serving
/api/healthwith 200{"status":"starting"}(and 503 elsewhere) until
the real mux takes over on the same listener. Previously a boot that ran
a one-time VACUUM or a full integrity check on a multi-GB database left
the port unbound for up to tens of minutes, so the Docker healthcheck
failed and the self-update sidecar judged the deploy failed and rolled
back in the middle of the compaction.
v0.130.3
🛰️ Marvin
Don't Panic.
Patch Changes
-
00a9da5: Yield between maintenance chunks so live writers are never starved.
v0.130.2 bounded every maintenance transaction, but back-to-back chunks
still starved the control loop during a large backlog migration: SQLite's
busy handler retries without fairness, so the maintenance loop re-acquired
the write lock before any waiting writer won its retry. Prune chunks,
rolloff deletes, and diagnostics batch-deletes now pause (250/100 ms)
between transactions, guaranteeing every waiting writer a window.
v0.130.2
🛰️ Marvin
Don't Panic.
Patch Changes
-
1b62749: Critical fix: bounded maintenance transactions (upgrade-lock incident).
The first history prune after upgrading a long-running install (v0.129.0's
Prune wiring) could hold SQLite's write lock for hours: the hot→warm
aggregation used a correlated subquery that re-scanned the hot table once
per 15-minute bucket, and the whole backlog ran as one transaction. Every
control-loop write failed with SQLITE_BUSY until it finished.- Prune is now linear (single-pass bucket aggregation) and chunked: each
transaction ages at most ~24 h of rows, so writers interleave. A 93-day
backlog that previously locked the DB for 4+ hours now completes in
seconds. Chunk and cutoff boundaries are bucket-aligned, which also fixes
a pre-existing partial-bucket overwrite at the retention edge. - Prune logs its result (rows aged, chunks, duration) — maintenance is no
longer silent. - Parquet rolloff deletes each day's rows right after that day's file is
durable, in hour-sized transactions, instead of one giant end-of-run
DELETE that could lose the race against live writers. - Planner-diagnostics retention in SQLite reduced 30 → 7 days (measured
485 MB at 30 days on a real site; Parquet keeps everything), deletes are
batched, and the table is excluded from state snapshots (snapshots shrink
from ~470 MB to ~20 MB).
- Prune is now linear (single-pass bucket aggregation) and chunked: each
v0.130.1
🛰️ Marvin
Don't Panic.
Patch Changes
- d08c4cc: Automatically add and validate the independently updatable optimizer sidecar when upgrading safe existing Linux or macOS Compose installations, with rollback cleanup and fail-closed handling for operator-owned overrides.
v0.130.0
🛰️ Marvin
Don't Panic.
Minor Changes
- eba5722: Add independently updatable optimizer and Lua-driver modules with protocol negotiation, signed monorepo driver releases, content-addressed activation, selective restart, health verification, and rollback while retaining bundled and Go-DP safety fallbacks. Add explicit opt-in anonymous fleet statistics for active installations and public driver/component health.
Patch Changes
- a4f0b33: Repair the setup wizard and pair-session component after the FTW rename, and add CI guards for browser JavaScript, release metadata, and stale Changeset package names.
v0.129.0
🛰️ Improbability Drive
Don't Panic.
Minor Changes
-
8d61001: Add Sungrow PV curtail support, reset stale inverter control state when the driver loads, and surface hardware fault states such as thermal shutdowns in diagnostics.
-
af005b9: Database hardening and richer history access.
Durability & SD-card resilience
- Parquet rolloff now fsyncs day files (and their directory) before the atomic rename — a power cut can no longer lose a day of rolled-off samples whose SQLite rows were already deleted.
- The rolloff streams one UTC day at a time instead of buffering the whole backlog in memory (a multi-week backlog could OOM a Pi and then never complete).
- Planner-diagnostics day files are merged instead of overwritten — the hourly rolloff previously discarded every earlier hour of the same day from cold storage.
- One-time
VACUUMat boot when a large share of state.db is freelist (reclaims the high-water mark left by big prunes), guarded by a free-disk check. - Truncating WAL checkpoint after every hourly rolloff; each control-loop tick (history + metrics) is now persisted in a single transaction, halving the WAL commit rate.
Faster history queries
- Downsampled
/api/historyand/api/seriesqueries aggregate per bucket in SQL instead of fetching every raw row into Go (a month view used to materialize >1M rows per request), and buckets carry a min/max envelope so short power spikes stay visible zoomed out.
Richer history over REST
/api/serieswindows older than 14 days transparently include the cold Parquet tier./api/seriessupports comma-separated multi-metric queries, absolutesince/untilbounds, andformat=csvexport./api/series/catalogreports each metric's display unit; units fromhost.emit_metricare now persisted across restarts.
Growth control
- New
state.cold_retention_daysconfig bounds the cold Parquet tier (default 0 = keep everything). - Low-disk warning (log + event feed) when free space drops below 500 MB.
Patch Changes
-
af005b9: Run the wide-history retention tiers during the hourly storage rolloff so old full-resolution dashboard rows are aggregated instead of growing
state.dbindefinitely. -
a4c695a: Decouple the Raspberry Pi installer image from application releases and reduce redundant CI work while retaining required validation.
-
3e1b98a: Fail closed for direct state-changing
p2pFetchAPI calls on public relay origins so owner ceremony and control request bodies are never raw-fetched to the relay.Enable short TCP keepalive on Modbus TCP driver sockets to make stale inverter sessions recover faster after network/controller interruptions.
Use MyUplink's known-working OAuth scope set by default and expose an override for installations that can use narrower read-only auth.
Let
BatteryCoversEVtake effect in passive-arbitrage PV-surplus charge slots by allowing the planned-grid cap to back off charging and cover EV import while preserving deliberate grid-charge slots.Resolve failed remote-home P2P attempts to the actionable sign-in/setup gate instead of leaving the page on "Reaching your home..." forever.
v0.128.1
🛰️ Mostly Harmless
Don't Panic.
Patch Changes
- dcffc61: Add a one-command, rollback-safe migration from legacy Docker Compose and
local-development images to the official Sourceful images. Include license
and notice files in Docker build contexts so canonical main and updater images
publish successfully. - 43e2d1b: Repair self-updates from legacy or developer Compose layouts by applying a
temporary canonical image override without rewriting the host deployment, and
preserve automatic image and state rollback on that path. Add a bilingual
legacy-upgrade runbook and refresh migration/operator documentation,
fresh-clone simulator defaults, driver catalog coverage, release-image
selection, and license payloads after the Sourceful transfer.
FTW drivers (stable)
Moving stable channel for independently released FTW Lua drivers. Trust manifest.json only after Ed25519 verification.
FTW Raspberry Pi installer
Latest FTW Raspberry Pi installer image. Built from eba5722 on 2026-07-16. Fresh installations pull the current stable FTW containers from GHCR on first boot.
FTW drivers (edge)
Moving edge channel for independently released FTW Lua drivers. Trust manifest.json only after Ed25519 verification.