Skip to content

Verified: Historian

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

HST-002 verified

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

HST-004 verified

-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

HST-008 no test yet

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.

HST-009 no test yet

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

HST-013 no test yet

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

HST-022 verified

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