Docs/Timebase Components/How Atlas Aligns and Times Values
AtlasConcept

How Atlas Aligns and Times Values

When you subscribe to a live instance in Atlas, you get a stream of complete rows where every property either carries a current value or stays empty.

Updated 3 Nov 2026Timebase Docs

Overview#

When you subscribe to a live instance in Atlas, you get a stream of complete rows where every property either carries a current value or stays empty. Atlas does this by aligning values from multiple sources that update at different rates, holding back the row until enough inputs have arrived to emit safely, and letting you tune how long it is willing to wait.

This article explains the one configuration knob that controls that wait time, what happens to a row when a data source goes offline, why unsampled tags show zero, and how to read the quality field that some connectors emit alongside a value.

You would read this when you are building a domain that depends on multi-rate inputs, when a live dashboard is missing data after a connector dropped, or when a property that should be zero is showing a date like 0001-01-01.

The problem: sources update at different rates#

Many real-world processes involve data sources that publish updates at very different frequencies:

  • A flow sensor updates 10 times per second
  • A temperature sensor updates once per minute
  • A lab measurement arrives once per hour

When you compute a KPI that depends on all three sources, using "the current value" from each source at query time would mix readings from vastly different points in time. A flow reading from a moment ago and a lab reading from an hour ago cannot be meaningfully combined.

Point Normalization solves this. Atlas collects all the input values that have arrived so far, picks a past timestamp that every input has a reading for (or something close to it), and aligns every input's value to that shared moment. The result reflects a genuine snapshot of process state, not a random collision of different time windows.

How Atlas decides what to emit: the bounded-lateness gate#

When you subscribe to a full instance or a full entity type in Atlas, the subscription is gated. Atlas does not emit a new aligned row the instant one input updates. Instead, it waits until a certain amount of time has passed since the oldest unprocessed reading. The default wait time is 2000 milliseconds - two seconds.

This wait time is called bounded lateness, and you tune it with one setting in settings.config:

"LiveProjection": {
  "AllowedLatencyMs": 2000
}

Valid values range from 0 (emit immediately, minimum latency, accept misaligned rows) to 86400000 (wait up to 24 hours, maximum alignment). An out-of-range value aborts startup.

You can also override the default on a per-path basis when a connector acknowledges a subscription, but the instance-wide value is the maximum - Atlas uses the largest AllowedLatencyMs required by any gating series in that instance.

What happens depends on the value:

  • AllowedLatencyMs = 0 - Atlas emits a row the instant any input updates. Properties whose sources have not reported yet are filled with carry-forward from the last time they did report (or read as default zeros if they have never reported). Misalignment is unavoidable.
  • AllowedLatencyMs = 2000 (default) - Atlas waits until 2 seconds have passed since the oldest input's timestamp. If all inputs have now attested by then, the row emits. If an input has never attested and 2 seconds pass, the row still emits with that input's field carried forward or empty.
  • AllowedLatencyMs = large value - Atlas waits longer, accepting higher latency in exchange for tighter alignment. A slow input does not drag every row forward - the gate advances with wall-clock time and fires its next row automatically.
Note

A single-property subscription (not a full instance) skips the gate entirely and publishes immediately on each input update, unaligned.

Three cases: what happens when an input is offline#

The gate behavior differs depending on the life cycle of a source:

Case 1: Never attested. A source that has never sent a reading in this session - the tag is offline at startup, or the subscription failed to establish. After AllowedLatencyMs milliseconds, the gate fires and the property for that source contributes nothing (it reads as empty or is omitted from the row). If that source later comes online and sends its first reading, the property re-enters on the next emit. This costs zero latency - a new source does not hold back existing sources.

Case 2: Dead connector. A source that was reporting but its connector went offline. The gate stalls. Every aligned row for that instance freezes at the timestamp of the last value that source produced, with no floor based on wall-clock time. The row does not emit - period - because there is a gating series with no current watermark and no way to advance. Once the connector comes back online and re-handshakes, Atlas re-subscribes and the gate resumes. The stream is unbroken - you simply stop receiving updates during the outage.

Case 3: Live but behind. A source that is reporting but has fallen behind the current timestamp by more than AllowedLatencyMs. The gate floor advances with wall-clock time: readyUpTo = max(oldest_input_timestamp, now - AllowedLatencyMs). After AllowedLatencyMs milliseconds with no update from that input, the gate fires with the input's last known value, carry-forwarded. The row lags by roughly the source's update interval plus the allowed latency.

These three cases are unconditional behavior - there is no mode to choose. The AllowedLatencyMs setting is the only dial.

Ask Gage

Ask the graph-query agent: "Query an instance that pulls from multiple connector sources with different update rates. Show me the Timestamp and anchor values for one row, explaining which source each property came from and why they are aligned at that one moment in time."

It returns a row with its alignment metadata, showing you how the gate collected readings at different times into one coherent snapshot.

When a connector drops: what happens to the values#

When a connector goes offline (Case 2, above), the last values it sent are retained in place. They remain readable with no quality degradation - they still report as Good if the source reported them as Good.

The gate stalls, so you stop receiving new aligned rows. But you do receive something important: if the connector was only an input to a Calculated Property (not part of the gating series), the calculation stops updating because the gate it depends on is frozen. If the connector is part of the gate (e.g., you subscribe to an instance that has a property bound to it), then the full instance subscription stops emitting entirely.

This is different from "properties report Bad quality on source failure" - that older claim is not true. The quality does not change. The gate behavior is what governs responsiveness, and it is determined by whether the source was part of the gate (it froze the gate) or only an input to a calculation (the calculation's watermark froze).

After the connector reconnects, it sends a fresh handshake with a new AtlasSessionId. Atlas re-subscribes to its paths, and the gate resumes from that point forward. Values that occurred during the outage are not written into Atlas's current-value store - they are retrievable only through a range query against the source.

How values are aligned: the anchor grid#

When Atlas emits an aligned row, every property carries its own Timestamp field showing the actual time of the reading that was selected. But the row itself also carries an Anchors array - one timestamp per row - showing the moment in time the row was aligned to.

These anchor timestamps come from a declared isTimeAxis field on the property's data type. For the standard atlas-common:TVQ (Timestamp-Value-Quality) compound, the Timestamp field is marked as the time axis. When you define your own compound type, you choose which field serves as the reference clock for alignment.

Properties without a time axis (scalars, compounds without a declared axis) are treated as having infinite latency - they lock the aligned row at their last known value with no floor, and they do not participate in time-based alignment at all.

A change to such a property still produces a row. That row is anchored at the gate's current frontier - the latest moment every time-series input has been vouched for - and carries each time-series property's last reading at or before that moment, so the anchors you receive never move backwards. Only when no time-series property has reported yet does the row take the emit time as its anchor. If you asked for watermarks, value-less heartbeat rows arrive only while no reading is waiting on the gate; while data is held, the data rows that follow carry the watermark themselves.

The anchor and the property's own timestamp are separate concepts serving different purposes:

  • The anchor (from isTimeAxis) is what governs the row's alignment semantics - "at what point in time was this row composed"
  • The property's Timestamp leaf is what you read in queries to understand "when did this input's reading actually occur"

Both travel in the ValueRowSetDto on the wire, and both are available to consume.

Quality: what it is and where it comes from#

Not every connector emits quality, but those that do emit it as an integer column binding to atlas-common:Quality. The quality value is a raw OPC code, and the status is encoded in the top two bits:

Value Status
0 Bad
64 Uncertain
192 Good

Quality binds today. Seven connector plugins emit it: the Timebase Historian, OPC UA, i3X, Aveva Historian, Aveva PI System, CanaryLabs Historian, and InfoHub.

If you read a property via the REST API pull-read at GET /api/v1/branches/{branch}/domains/{domain}/instances/{instanceId}/values, the quality is not the connector's integer code. Instead, the response carries a Good or GoodNoData string. GoodNoData means the property holds no value: nothing has arrived from the source yet, the static value is blank, or a calculation returned none. The connection may still be healthy, and the response carries "value": null. There is no Bad or Uncertain in the pull-read response - Atlas does not degrade quality based on freshness, and the pull-read always returns the current value.

Important: Atlas never sets a property's quality to Bad or Uncertain on failure. Quality is data, supplied by the connector at the moment of the reading. Atlas does not act on it, and downstream consumers must branch on it if they need different behavior for degraded quality.

Atlas also never fabricates a quality value on writes - if a source never sends one, no quality field materializes on the property.

Values that have never been sampled#

A Bound property holds no value until something writes one. Until the first sample lands, the cell reads as null:

Property type Reads as before the first sample
Number (integer or float) null
Date and time null
Quality (when bound) null

This happens in three ordinary situations: the subscription has not yet received an update, the source tag is offline, or the connector is down.

Note

"never sampled" is distinct from a genuine reading of zero, because a written zero is a value. A compound property that has never received a sample is null as a whole, so WHERE n.Temperature IS NULL finds it. Once any field holds a value the property is a compound, so test the field, for example WHERE n.Temperature.Value IS NULL.

How calculated properties work#

A Calculated Property waits for all of its inputs to reach a common timestamp before firing. This is unconditional behavior - there is no mode to choose:

  1. Atlas tracks a watermark (the latest timestamp seen) for each input.
  2. The calculation gates on the minimum of all input watermarks. It does not fire until every input has an attestation.
  3. Once all inputs have attested at least once, the calculation publishes when the watermark floor advances.

Two traps to watch for:

  • A calculation waits for every input's first value. If one input has not reported by the time you subscribe, the calculation holds until it does. Confirm every input is live before you wait on the result. Verify that all input sources are actually online and subscribed before raising a ticket. This differs from instance alignment - instance subscriptions gracefully exclude sources that have never attested.
  • A calculation error is permanent. If the function fails at runtime (e.g., division by zero), the calculation logs the error and sets itself to faulted. It stops updating permanently and does not retry. The property never produces another value in that session. Restart Atlas to clear the fault and re-attempt.

Calculated properties do not participate in point normalization. Each input to the function is read at its latest known value, not resampled onto a shared grid. If you need temporal alignment on calculated inputs, use the Timestamp fields to implement that logic inside the function itself.

Ask Gage

Ask the graph-query agent: "Show me the current value and timestamp for a calculated property, then list its input properties' timestamps. Verify that the calculation is not blocked by a never-attested input."

It traces the calculation's watermarks and confirms whether all inputs have reported or if one is holding the calculation at MinValue, explaining production delays.

Troubleshooting#

Symptom Likely cause What to do
A live instance subscription stops emitting entirely A gating series' connector is offline, so the gate froze (Case 2, above) Verify the connector is online on the Home page. Once it reconnects, the gate resumes automatically and the subscription emits again
An unsampled tag reads null, or shows a dash No sample has arrived yet, or the source is offline. A property holds no value until something writes one Confirm the source tag is live and the connector is running. If the value stays null while other properties on the same connector are updating, treat it as a binding-path problem. See Property Sourcing Strategies
A live dashboard is showing values from N seconds ago The default AllowedLatencyMs of 2000 is in effect (Case 3, above). The gate waits 2 seconds for alignment, introducing latency Reduce AllowedLatencyMs in settings.config to accept tighter tolerance. Set it to 0 for immediate emit with minimal alignment
Values look aligned but lag by more than AllowedLatencyMs The slowest input is updating less frequently than expected. The lag is roughly the input's interval plus the allowed latency Check whether the slowest input source is alive. Monitor the Timestamp fields to confirm the age of each reading
A calculated property never produces a first value One or more inputs have not yet reported in this session. The calculation waits for every input to attest at least once Verify that all input sources are online and have sent at least one reading. Check the Historian or the relevant connector's datasource list
A calculated property stopped producing values after emitting normally The calculation faulted at runtime (e.g., division by zero). This is permanent until restart Check the Atlas log for a CalculatedPropertyWorker entry showing the fault. Fix the input data or the function and restart Atlas to clear the fault
Two subscriptions to the same instance emit at different rates Single-property subscriptions emit immediately on update (no gate); full-instance subscriptions go through alignment and the bounded-lateness gate This is expected behavior. Align your consumer to the full-instance subscription's cadence, or use single-property subscriptions if latency is more important than alignment
After a connector reconnects, old values are not backfilled Atlas does not backfill on reconnect. On reconnect, the connector re-handshakes and the subscription resumes from that point Historical data is available only through a range query against the source. Backfill is not automatic. There is no manual backfill trigger in the UI

Single-instance availability#

Atlas runs as one container and one process. All live-projection state is in-process and non-durable. A restart clears all watermarks, resets every gating series to "never attested", and re-enters bounded-lateness mode from scratch. The world itself is rebuilt automatically at startup (every recorded (branch, domain) pair is recompiled), but the runtime gate state is not restored.

There is no clustering, no redundancy, and no supported way to run two Atlas instances against one data volume. See Scaling and Deployment for full details.

esc
↑↓ navigate · ↵ open · ⌘K anywhere