Skip to content

perf(state): retain bounded telemetry aggregates for EMS #1287

Description

@frahlg

FTW should retain the history needed for local energy management, charging, forecasts and support without storing every driver poll indefinitely. Live telemetry and safety must keep their current freshness and cadence.

Current code buffers every scalar emission in telemetry.Store and persists it through persistTelemetryTick. RecentRetention keeps those rows for 14 days; RolloffToParquet copies the same resolution to daily files. Dashboard JSON also keeps 30 days of hot snapshots. This amplifies live database growth, archive work and backup IO. See #1246, #1280 and #1259.

Proposed fixed defaults for scalar/chart history:

Age Stored resolution Storage
First day 10 seconds SQLite
1–30 days 1 minute Parquet
30 days–2 years 5 minutes Parquet
Longer Energy totals and selected events Existing ledger/event retention

Do not reduce the control or driver polling rate. Aggregate before writing scalar/chart history. Keep energy accounting separate: meter deltas, power integration, import/export direction, gaps and resets must use the original measurements before compaction. Forecast training uses its existing quarter-hour observations. Preserve settings, stable identities, session goals, command outcomes and fault transitions.

Gauge buckets need count, sum, min/max, last value/time, interval width and coverage; gap intervals stay gaps. Never average a cumulative meter into energy or a status code into a new state. Merge summaries by counts/coverage, not by averaging averages. Only retain fields that have a concrete product consumer; raw export to a user-owned store stays optional and must not become a dependency of Core.

Implement in stages:

  1. Verify each consumer and define the aggregate/coverage contract, including counters and status signals.
  2. Write 10-second summaries at ingestion with bounded memory, shutdown flush, retry receipts and no duplicate contribution after an uncertain commit. Keep the live store and ledger path independent.
  3. Publish verified 1-minute and then 5-minute Parquet summaries with bounded maintenance. Readers must support old and new files and report the actual resolution.
  4. Convert old history outside the control path, restartably. Verify weighted totals, extrema, coverage and time bounds before pruning. Preserve the existing backup until restore has passed; do not run blocking VACUUM on a live box.
  5. Measure storage growth, archive load, backup size, durable-goal latency and live collection on Pi. A smaller file alone is not a passing control/IO test.

Acceptance tests: irregular polling, one-second power spike, sign changes, cumulative counter reset, outage/reconnect, late correction, duplicate retry, restart mid-bucket, partial archive failure, mixed old/new archive reads and backup/restore across the transition. Energy and EV delivered totals must match the original-measurement reference. Diagnostics must retain the spike and transitions while empty periods remain missing.

This issue records the owner's direction and a proposed retention policy. The new aggregation policy has not shipped. Existing storage reliability fixes remain necessary during the transition.

Activity

  1. frahlg commented on Sep 17, 2026

    @frahlg
    MemberAuthor

    The implementation has merged:

    Full local make verify, focused race tests and required CI passed. Isolated ARM64 tests on the Pi passed for the archive, energy accounting, vehicle goals and control writes. Existing backups and sources remain intact.

    Keep this issue open for acceptance step 5 and the installed transition. The final synthetic backup test still failed #1246 at 2.228 s against the unchanged 2 s durable-goal limit. No new beta or production install has taken place. A new candidate must still demonstrate growth, archive/backup load, the installed history transition and control behavior under that load. Code completion is not this target acceptance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions