Files
iot-dc3/docs
pnoker 284c8187bf feat(tsdb): land s16 tiered retention and rollup — transparent tier reads on the shared caggs
The timescale adapter now owns the S16 lifecycle: raw 30 days (seed 05,
was 180) -> 1-minute tier 1 year (configurable via
dc3.tsdb.timescale.rollup.minute-keep-days) -> 1-hour tier forever.
bucketedAggregate and bucketedCount serve bucket widths at or above a
tier's granularity from that tier with exactly composable expressions
(AVG recombines as SUM(num_sum)/SUM(num_count), COUNT as
SUM(sample_count)); PERCENTILE and FIRST/LAST stay on the raw path — the
shared caggs carry textual first/last only, and tiered numeric first/last
would version-skew deployments created before such columns existed.
Single-window aggregate() stays raw by design: alarm windows must never
read through materialization lag.

The tiers are the observability pipeline's existing real-time continuous
aggregates (cagg_point_value_1m/1h, queried by Grafana) — one structure
serves both consumers; the adapter bootstraps the same names with an
identical shape via IF NOT EXISTS, so embedded seed boots, standalone
adapter boots and already-running deployments all converge on it without
rebuilding anything. Real-time mode (materialized_only=FALSE, no longer
the TS 2.13+ default) keeps tier reads correct immediately after an
append; the refresh policies only move aggregation work off the read
path. deleteRange refreshes both tiers afterwards.

Also fixed along the way: TDengine's bucketedAggregate PERCENTILE hit the
same "single table query" limit as aggregate() and now routes per-series
subtables.

Gates: timescale TCK 24/24 including the new rollup case (tiered
COUNT/AVG/LAST/bucketedCount and bucketed P50 all verified against raw
scans before any refresh materialized); TDengine TCK 24/24 with the same
case passing via honest raw degradation (2 declared-capability skips).
2026-08-21 13:01:45 +08:00
..