By Ether DataRequest data sample
All sections

Temporal Provenance

A timestamp is not one moment but a lifecycle of moments produced by a clock of a stated source, accuracy, and model — the time analog of geometry provenance.

stable3 min read
Source time
timestamp, clock_metadata
Destination time
temporal_provenance

The geo KB treats provenance as a first-class object: a geometry carries its source, CRS, and boundary vintage, and a conversion that loses them is broken. Time deserves the same treatment, and this is where temporal interoperability stops being calendaring and becomes a distributed-systems and AI-pipeline problem.

A value like 2026-07-12T14:31:02Z looks complete. It is not. It hides which clock produced it, how accurate that clock was, what timescale it is on, and which stage of a pipeline the instant refers to.

A timestamp is a lifecycle, not a moment

The same datum passes through many times, and any of them can be mistaken for the canonical event time:

requestedTime
What a caller asked for.
observedTime
When the phenomenon happened — the sensor's world.
capturedTime
When the device recorded it.
receivedTime
When the ingestion endpoint got it.
ingestedTime
When it entered the pipeline.
processedTime
When it was transformed.
storedTime
When it was persisted.
reportedTime
When it was surfaced in a report.

Two systems can pick different stages as canonical from the same record and land in different hour-of-week slots. So the choice of canonical stage must travel with the value, and the gap between observedTime and storedTime is the pipeline latency — a real quantity, not a rounding error.

The clock is part of the value

source
gps ≈ 20 ns · ptp ≈ 1 µs · ntp ≈ 1–10 ms · cellular ≈ 100 ms · manual ≈ minutes · monotonic · inferred · synthetic
accuracyMs
1-sigma accuracy. It sets how wide the slot assignment's error bar is (see time uncertainty).
model
utc · tai · gps · smeared · monotonic. A smeared clock (Google/AWS leap-second smear) disagrees with UTC by up to ~0.5 s.
synchronized
NTP/PTP sync state. An unsynchronized clock can be minutes off while emitting valid-looking timestamps.
A monotonic clock has no UTC

performance.now() and CLOCK_MONOTONIC measure elapsed time from an arbitrary origin. They have no fixed epoch, so they cannot be converted to UTC or a slot at all. Mixing a monotonic reading into a wall-clock column silently corrupts every latency and ordering computation downstream.

The model, made checkable

The KB ships this as an executable type, not just prose. A TemporalProvenance record is validated: monotonic values are rejected as unmappable, a backwards lifecycle step is flagged (a VM snapshot restore, an offline replay, an NTP jump, or a corrected timestamp), the canonical stage must be present, and sub-second digits from a coarse clock are flagged as false precision.

import {
  provenanceIssues,
  canonicalInstant,
  pipelineLatencyMs,
  type TemporalProvenance,
} from "@/lib/time";

const p: TemporalProvenance = {
  observedTime: "2026-07-12T14:31:02.000Z",
  capturedTime: "2026-07-12T14:31:02.200Z",
  ingestedTime: "2026-07-12T14:35:00.000Z",
  storedTime: "2026-07-12T14:35:01.000Z",
  canonicalStage: "observedTime",
  clock: { source: "gps", accuracyMs: 0.00002, model: "utc", synchronized: true },
  conversion: { tzdbVersion: "2026a", disambiguation: "none", lossless: true },
};

canonicalInstant(p); // epoch ms of observedTime, or null if monotonic/unmappable
pipelineLatencyMs(p); // storedTime − observedTime = 239_000 ms
provenanceIssues(p); // [] — clean; else out-of-order / monotonic / false-precision

The Python parity uses the same lifecycle fields on a dataclass plus zoneinfo for the conversion metadata; the tested reference implementation is the TypeScript in lib/time/temporal-provenance.ts.

Why it matters now

AI pipelines make this urgent. An AI-inferred timestamp is a model output, not an observation; a synthetic event time must never masquerade as measured; and when multiple clock authorities disagree during an outage, the record must say which one won. None of that fits in a single ISO-8601 string.

Carrying temporal provenance is what turns this knowledge base from a time-conversion reference into a temporal-interoperability standard for event streams, distributed systems, and AI agents.

Edge cases affecting this page

Timestamp provenance (which time became canonical)Sensor time, API time, database time, and client time are different instants. Which one became the canonical event time (and therefore the slot) is a modeling decision that must travel with the value, exactly like geometry provenance in the geo KB.Monotonic vs wall clockA monotonic clock (performance.now(), CLOCK_MONOTONIC) measures elapsed time from an arbitrary origin and has no fixed epoch, so it cannot be converted to UTC or a slot. Mixing monotonic and wall-clock timestamps silently corrupts latency analysis.NTP synchronization stateA device whose clock is unsynchronized can be minutes off while still emitting well-formed timestamps. The format is valid; the value is not.Multiple clock authorities disagreeGPS, PTP, and NTP can disagree during outages or holdover. Which authority wins determines the timestamp, and the choice is often undocumented.AI-inferred timestampA timestamp reconstructed by an LLM or by interpolation is a model output, not an observation. Treating an inferred time as measured injects unquantified error into every slot it lands in.VM snapshot rollbackRestoring a virtual machine from a snapshot moves its clock backwards, so a later event can carry an earlier timestamp than an earlier one.Offline capture, delayed replayIoT and mobile devices capture events offline and upload them later, so yesterday's events arrive today. Arrival order is not occurrence order, and late data reopens already-reported slots.
Requested vs. Executed TimeConceptual modelTime UncertaintyProvenance & uncertaintyCausal Time vs Physical TimeProvenance & uncertaintyMeasurement SemanticsMeasurement semantics