contract store · 10-store.md · 11-snapshot.md · 12-time.md · 13-replica.md · 14-drain.md · 15-endpoint.md · 16-collect.md · 17-merge.md · 18-pull.md · guide · card
Time bounds
The engine stamps transaction time at commit; a table declaration names its valid-time and availability-time columns. Each bound resolves before access controls select rows.
bound-time
Transaction-time and valid-time columns, their read parameters and the snapshots or rows each parameter selects.
two-clockstestTransaction time is_ingested_at; valid time is a declared pair of table columns, which the engine never infers, and it stamps no second transaction timestamp.valid-time-declarationtest[pipeline.tables.valid_time]declaresfromand an optionalto; a table declaringfromalone treats each row as valid from that instant onward.valid-time-typetestA declared valid-time column whose type is not a timestamp raisesStoreValidTimeNotTimestampat declaration.Why
P1instant-comparisontestEvery bound compares instants as timestamps, not strings; a date-only literal resolves to the start of the next day, exclusive.as-oftestInside each table’s FROM-source,as_ofselects the newest reachable snapshot created at or before the bound plus the committed runs at or before it that the snapshot omits.Why
because filtering current files by ingest stamp returns different rows before and after a foldrow-age-cutofftestA read of a table withretain-rowsexcludes rows older than its wall-clock cutoff,as_ofreads of retained snapshots included, and the result cache reuses no such statement.Why
because a historical snapshot does not restore a row after its declared age passesas-of-unretainedtesttesttestAnas_ofbefore the oldest snapshot retention kept, or selecting a snapshotcollected-snapshotcounts or whose successors fold a run absent here, raisesStoreAsOfUnretained, naming the oldest answerable instant.Why
P4valid-as-oftestvalid_as_offilters the same inner source withfrom <= valid_as_of AND (to IS NULL OR to > valid_as_of)over the declared pair.valid-time-undeclaredtestAvalid_as_ofread against a table declaring no pair raisesStoreValidTimeUndeclared, naming the table.Why
P1pin-boundtestA read carryingas_ofand a build pin resolves each table named by both byearlier-bound-wins.unbounded-latesttestA read carrying neither bound resolves each table to its current snapshot plus the committed runs it omits.beneath-enforcementtestBoth bounds apply before the row predicate, column mask and tenant filter, so they only narrow the rows access controls admit.Why
P5covering-versionstestFor an unkeyed table, a valid-time bound returns every version whose interval contains the requested instant.interval-rowstestA keyed table declaringvalid_timestores one row per key and valid-time interval, deduplicating on its primary key andfrom, so a fold keeps every interval.echotestA bounded read returnscontextful.boundsas{as_of?, valid_as_of?, inclusive}, each instant RFC 3339 UTC with nine fractional digits and aZ; an unbounded read omits it.
unsettled: Does an as_of read selecting a held snapshot older than a collected one read that snapshot, rather than refuse under as-of-unretained? owner: store affects: store.bound-time
available-time
The source availability timestamp, its value at landing and row selection under available_as_of.
declarationtesttest[pipeline.tables.available_time]declaresAvailableTime, omitted from canonical serialization when unset.columnholds the source availability instant astimestamptz, which landing keeps and availability bounds compare alone;zonedefaults to UTC.lag-filltesttestAt landing,available_time.lagfills a null availability column with valid-timeto, elsefrom, plus the durationlag.classesmaps the row’slag.class_columnvalue to, and injects_available_imputedtrue; a class without an entry leaves the instant null.Why
because a source can publish different record classes after different declared delayslive-sincetesttestA date-typed availability value resolves at landing to the start of the next day in the declaredzone; rows available beforeavailable_time.live_since, when the source began publishing live, get injected_available_reconstructedtrue.Why
because a date gives no publication time within its dayavailable-as-oftesttestavailable_as_offilters the inner source with<column> <= available_as_ofunderbeneath-enforcement, combining withas-ofandvalid-as-ofwhen the read supplies them.bound-echotestA read carryingavailable_as_ofadds it, in the same instant form, to the objectechoreturns.undeclaredtesttestAnavailable_as_ofread of a table declaring noavailable_timeraisesStoreAvailableTimeUndeclared, naming the table; a landing row resolving to a null instant raisesStoreAvailableTimeNull, naming the table and run.Why
because a missing availability instant either hides a backfill or leaks it to every boundvintage-rowstesttesttestA keyed table declaringavailable_timeis a vintage table, keeping every vintage per primary key, valid-timefromand availability instant; a read returns the latest at or before anyavailable_as_of, or undervintage = "first"the earliest.vintage-hashtestA landing row whosecontent_hash_columnvalue equals that of its key’s latest vintage lands no new vintage.Why
because a re-pulled unchanged window otherwise lands a false restatementvintage-validationtesttestA vintage table declaring nocontent_hash_columnraisesStoreVintageHashUndeclared, and one declaringretain-rowsraisesStoreVintageRetainRows, at validation, naming the table.Why
because a re-pull without a hash reads as a restatement, and a row-age cutoff shrinks a past answervintage-dedup-keytesttesttesttestA vintage table reads throughdedup-view, orinterval-rowsundervalid_time, and folds underdedup-vieworvalid-time-line, each adding the availability column to the key and keeping every vintage; an unclusteredvalid_timefold sorts byfrom, then primary key.vintage-scopetestA vintage landing compares only its own keys’ stored vintages, skipping row groups that text or signed-integer key bloom filters, or footer bounds on text, integer or temporal keys or temporal valid time, exclude.adjustment-factorstesttestavailable_time.adjustmentkeeps stored values raw; anavailable_as_ofread multiplies eachadjust_columnscolumn by the product offactor_columnvintages available by the bound, over factor rows sharing its factor-tableprimary_keyvalues with a later valid-timefrom.Why
because applying a correction published later exposes information unavailable at an earlier read bound
Scenarios
store.available-time.available-as-of: WHEN a 2026 backfill lands a first-quarter measurement with availability date2014-04-30, THENavailable_as_of2014-05-01returns the row andavailable_as_of2014-04-29returns none.store.available-time.vintage-rows: WHEN a first-quarter measurement lands at 17149.6 available2014-04-30, 17101.3 available2014-05-29and 17016.0 available2014-06-25, THENavailable_as_of2014-06-01returns 17101.3, an unbounded read returns 17016.0 before and after a fold, andvintage = "first"returns 17149.6.store.available-time.vintage-hash: WHEN a re-pull lands the measurement at 17016.0 with an unchanged content hash, THEN the table still holds three measurement vintages.store.available-time.vintage-scope: WHEN day 101 of 100 entities lands over 100 stored daily runs, THEN its comparison decodes no stored row; WHEN a revision of day 50 lands, THEN the comparison decodes only day 50’s 100 rows.
unsettled: Does vintage = "first" count a same-day correction as a revision of the initial release? owner: store affects: store.available-time