Each claim the Historian page makes, with the tests that
prove it in the last green CI run: 3 of 21 verified, 3 with no test yet.
The claims live in docs/claims/historian.yaml.
Last green CI run 16 Oct 2026, 14:48 UTC on c7618d3 · all runtime claims
HST-001 partly verified
The collector records every numeric or boolean leaf of GET /api/state matching -tags (booleans as 0/1) once per interval, and skips strings.
where the docs say so · The once-per-interval polling cadence itself is not asserted; collectOnce is tested per poll. ("Null values" dropped from the claim: not on the page.)
- pass
TestSampleOfRecordsNumbers in cmd/naut - pass
TestSampleOfRecordsBoolsAsZeroOne in cmd/naut - pass
TestSampleOfSkipsStringsAndNil in cmd/naut - pass
TestCollectOnceAgainstRealisticFrame in cmd/naut
Struct tag members are recorded as dotted paths (FIT_001.VALUE), nested structs walk further (FIT_001.RAW.COUNTS) and array members index with brackets (FIT_001.LOG[0]); strings are skipped at every depth.
where the docs say so
- pass
TestSampleOfFlattensStructTag in cmd/naut
HST-003 partly verified
-tags and -exclude globs match the full dotted leaf name, so * also matches dots; a dotless pattern matches only a top-level scalar and never a struct member, and *.VALUE matches that member of every struct.
where the docs say so · Asserted: * matching across dots (*_FIT_*) and *.VALUE. Not asserted: that a dotless pattern naming a struct tag never matches its members (no test uses a struct tag's bare name as a pattern), and the default of * when -tags is omitted.
- pass
TestSampleOfGlobFiltering in cmd/naut - pass
TestSampleOfMultiplePatterns in cmd/naut - pass
TestSampleOfDottedPatternMatchesNestedMember in cmd/naut
-exclude trims leaves a broader -tags pattern would otherwise record.
where the docs say so
- pass
TestSampleOfExcludeTrimsMatchedNoise in cmd/naut
HST-006 partly verified
With -min-interval at its default 0, every matched tag is recorded on every poll (change filtering is off).
where the docs say so · The behaviour at 0 is asserted on the filter directly; that the -min-interval flag defaults to 0 is not.
- pass
TestChangeFilterDisabledByDefault in cmd/naut
HST-007 partly verified
With -min-interval set, a tag is recorded when new, when it has moved by more than -deadband since last recorded, or when min-interval has elapsed since last recorded (heartbeat); otherwise it is dropped, and each tag is tracked independently.
where the docs say so · New, past-deadband, heartbeat, dropped and per-tag cases are asserted. That the deadband and heartbeat are measured from the last recorded sample, not the last poll, is not: a filter that updated its reference on every poll passes both tests. "More than" (strict) is not asserted.
- pass
TestChangeFilterRecordsOnChangeOrHeartbeat in cmd/naut - pass
TestChangeFilterPerTagIndependent in cmd/naut
Retention is a rolling window (-retention, default 7 days) pruned hourly.
where the docs say so · Prune and the hourly pruneLoop have no test; the Postgres store tests skip in CI.
Pointing -source at the Service in front of the replicas keeps samples flowing across a failover, because a standby proxies the poll to the leader.
where the docs say so · Standby proxying of /api/state is tested in the server package, but no test runs the historian collector across a failover.
HST-010 partly verified
GET /history returns downsampled [unixMs, value] pairs per tag as bucket averages, with maxPoints bounding the points.
where the docs say so · The [ts, value] wire shape is asserted in CI. Bucket averaging runs only in TestStorePostgres, which skips in CI (no Postgres) and checks only that a series comes back, not averages or the point bound. The TestBucketSize* tests exercise a test-local mirror of the formula, not the production code, so they are not cited. The 1-second bucket floor and the default of 600 dropped from the claim (not stated by the page).
- pass
TestSeriesIsChartWireFormat in hist - pass
TestStorePostgres in hist
HST-011 partly verified
GET /history/span returns the first and last sample and the count, and GET /healthz answers.
where the docs say so · The route test checks only that /history/span answers 200 against a fake store; /healthz is untested and the real span query needs Postgres.
- pass
TestExistingRoutesUnaffectedByStoreInterface in cmd/naut - pass
TestStorePostgres in hist
HST-012 partly verified
The tags query parameter is a CSV of exact archived leaf names with no globbing at query time, and a dot in a name is not special.
where the docs say so · TestStorePostgres (skipped in CI) queries exact names, including one with a comma and brace, at the store level. The /history CSV parsing, dotted names, and the absence of globbing are not asserted.
- pass
TestStorePostgres in hist
With server.historian (or NAUTILUS_HISTORIAN_URL) set, the controller proxies GET /api/history* to the historian, and does so on any replica, leader or standby.
where the docs say so · No test covers the /api/history proxy in the server package.
HST-014 partly verified
GET /history/agg takes tags, from, to, bucket and fn and returns [{tag, ts, value}], one row per tag per bucket, ts being the bucket's start in milliseconds since the epoch.
where the docs say so · In CI: the parameters reach the store and a row comes back as {tag, ts, value} with ts in ms. One row per tag per bucket is asserted only in the Postgres test (skipped in CI). The 400s for missing tags or fn or a bad bucket, and the 500 on a store error, are not page claims; their tests were removed.
- pass
TestHandleAggParsesQueryIntoAggQuery in cmd/naut - pass
TestAggregateAndSnapshotPostgres in hist
HST-015 partly verified
Omitting bucket aggregates the whole [from,to) range as a single row per tag.
where the docs say so · In CI only the Go-side path (first, last, delta, ontime) is tested; the SQL path (min, max, avg, sum, count) gives a single row only in the Postgres test, which skips in CI. The half-open upper bound is not asserted. "An empty series yields no buckets" dropped (not on the page), with TestBucketizeEmptySeriesYieldsNoBuckets.
- pass
TestBucketizeNoBucketingIsWholeRangeAtFrom in hist - pass
TestAggregateAndSnapshotPostgres in hist
HST-016 partly verified
Buckets align to the Unix epoch, not to from, so a 24h bucket lands on UTC midnight.
where the docs say so · Go-side bucketing is tested (with 1h buckets); the SQL aggregate's alignment runs only against Postgres (skipped in CI). "A sample exactly on a boundary starts the new bucket" dropped (not on the page).
- pass
TestBucketizeAlignsToEpochFloor in hist
HST-017 partly verified
min, max, avg, sum and count aggregate over a bucket's samples.
where the docs say so · The CI test only checks the fn-to-SQL-expression table. Results are asserted only in the Postgres test (skipped in CI), and there only for min, max and avg, not sum or count. The unknown-fn rejection is not a page claim; TestAggregateUnknownFnErrorsWithoutTouchingDB was removed.
- pass
TestSQLAggFnsCoversDocumentedFunctions in hist - pass
TestAggregateAndSnapshotPostgres in hist
HST-018 partly verified
first and last return a bucket's earliest and latest value, and delta is last minus first.
where the docs say so · The reducers are tested directly in CI. That fn=first/last/delta reaches the right reducer is asserted only for delta, in the Postgres test (skipped in CI).
- pass
TestFirstLastDeltaReducers in hist (4 of 4 passed) - pass
TestAggregateAndSnapshotPostgres in hist
HST-019 partly verified
ontime sums the seconds a tag was non-zero, counting each interval up to the next sample when the earlier sample was non-zero; the last sample in a bucket contributes no trailing interval.
where the docs say so · The reducer is tested directly; the straddling-boundary drop is not asserted, and fn=ontime reaching it is asserted only in the Postgres test (skipped in CI).
- pass
TestOntimeSeconds in hist (7 of 7 passed)
HST-020 partly verified
GET /history/at returns each tag's last value at-or-before at, and omits a tag with no such sample.
where the docs say so · The at-or-before and absent-tag semantics are asserted only in the Postgres test (skipped in CI); the CI test checks parameter passing and the JSON shape against a fake store. "Requires tags" (400) and the store-error 500 are not page claims; their tests were removed.
- pass
TestHandleAtParsesQueryAndReturnsSnapshot in cmd/naut - pass
TestAggregateAndSnapshotPostgres in hist
hist.Sink is a one-method seam (Insert) that a different store can implement.
where the docs say so · The load-bearing part is the compile-time `var _ Sink = (*fakeSink)(nil)` beside the test; the test body only checks the fake itself.
- pass
TestFakeSinkRecordsInserts in hist
HST-023 partly verified
The samples table and its (tag, ts DESC) index are created, and a round trip of Insert then Query returns the data.
where the docs say so · Skips unless NAUTILUS_TEST_DATABASE_URL is set; not run in CI. The index is never checked.
- pass
TestStorePostgres in hist