# Valid-time key slices The valid-time index can answer exact point and range predicates without reading candidate objects. Its sorted key sequence constructs exact-match JSON objects only when a consumer requests them; exceptional candidates retain demand-time verification. `size()` counts exact keys and verifies exceptional candidates; repeated iteration and early close do not close the borrowed revision transaction. ## Admission and exact fallbacks | Source | Indexed predicate | Fallback | | --- | --- | --- | | `jn:valid-at`, two-argument `jn:scan-valid-time-index` | Closed point containment | Original exact temporal predicate for rounded, clamped, open, duplicate, or lexically ambiguous bounds; exact linear scan when no interval index applies | | `jn:open-bitemporal(C,R,T,P)` | Half-open validity: `validFrom <= P < validTo` | Exact temporal verification for exceptional bounds; half-open linear scan when no interval index applies | | `for $x in jn:open-bitemporal(C,R,T,P) where P lt xs:dateTime($x.vt) return ...` | Half-open source intersected with the residual; inclusive `le`, reversed `gt/ge`, general comparisons, and the analogous start comparisons are supported | Original cast/comparison for exceptional records; original temporal scan plus comparison for a different configured field or absent index | | `for $x in jn:doc/open(...)[] where xs:dateTime($x.vf) op P and P op xs:dateTime($x.vt) return ...` | All four combinations of inclusive/strict endpoints, either operand/conjunct order | Original full array scan and comparisons unless every member has two exact bounds and its array order agrees with key order | | `for $x in jn:doc/open(...)[] where xs:dateTime($x.vf) op U and L op xs:dateTime($x.vt) return ...` | Range intersection for `L <= U`, with independent strict/closed start and end ties | Original comparisons for reversed windows, rounded/clamped instants, missing/unsafe bounds, or unsafe array order | Each point or range bound must be an invariant variable or `xs:dateTime` literal. Only `xs:dateTime` field casts are consumed. A plain source matches exactly two temporal comparisons, in one conjunction or two consecutive selections. A bitemporal source can fold that pair while retaining its original point constraint; otherwise its residual rule consumes the first eligible conjunct, preserving later conjuncts and their evaluation order. Positional/allowing-empty bindings, other casts and other source shapes retain their ordinary evaluation. The SH1 point-source queries call `jn:open-bitemporal` directly; they need no `local:slice` wrapper or additional strict-end comparison. The optimizer-only `open-bitemporal-slice` target is translated directly and is absent from the public function registry, so query text cannot call it. Brackit optimizes user-function bodies, so dynamic collection/resource/time parameters work inside functions such as `local:slice`. An identity `for $x in return $x` pipeline over the public function or a folded scan is removed, allowing `count()` calls to use the key count. Typed, positional, and nonidentity loop bindings retain their original evaluation. Transaction time is resolved at each evaluation. No revision is captured during compilation. Timezone offsets in `xs:dateTime` arguments are preserved when converting to `Instant`. Folded bitemporal comparisons retain their original operand type, comparison kind, and direction independently of the source function's dateTime argument conversion. Their fallbacks filter the original half-open interval or linear source in its existing order. Inclusive end residuals and start residuals cannot include records excluded by the source's strict end. Temporal fallbacks do not narrow with dateTime CAS indexes: their Brackit casts can omit bounds accepted by the temporal predicate’s `Instant.parse`, so they provide no candidate coverage proof. Timezone-less comparison points retain Brackit's ordinary comparisons, as do non-singleton plain FLWOR points. Computed field dereferences are not folded. Non-object array members evaluate the original comparisons with empty field dereferences. Plain-FLWOR points are evaluated only on row demand and at their original operand position; empty documents, non-array roots, and empty arrays supply no unboxed rows and never evaluate their point expression. Direct temporal functions retain their original object-root and missing-resource semantics. Reordered arrays retain the key-only bitemporal route, whose sorted keys preserve the temporal source's order, while plain FLWOR retains its document-order admission check. ## Row masks for projection scans Projection consumers of these key sequences follow the mechanism, admission rules and fallbacks in [Index-routed row source](INDEX_ROUTED_ROW_SOURCE.md). ## Index representation The lower and upper RI-tree stores retain their `(fork, endpoint)` keys. `stabHalfOpen` excludes an upper endpoint equal to the point, including at the equal fork. `startingAt` removes strict-start ties. `forEachRef` enumerates every registration in one ordered-store scan, for index-wide consistency assertions. These probes have counted scan bounds, not timing assertions. A companion HOT tree stores revisioned postings for: - object membership by immediate parent, removing candidate parent probes; - intervals requiring exact verification; - parents whose child node keys have been observed out of order. The physical roots and key encoding are specified in [HOT index specification §2.3.4](HOT_INDEX_SPECIFICATION.md#234-validtime-idxintervalvalidtimekeyserializerjava). The order guard is conservative: creating a fresh index can reestablish orderedness after subsequent edits restore it. `IndexDef.hasUnsupportedValidTimeFormat()` identifies incompatible catalog definitions. Readers omit these indexes from discovery and use the ordinary exact query fallback, including historical reads, optimizer discovery and VIEW-authorized REST reads. Reads do not change catalog bytes or add revisions. Writer creation, listener binding and index creation reject incompatible definitions; there is no migration API or automatic upgrade path. Create a fresh current-format database for this representation. Writer rebinding resolves the represented revision's catalogue before listener creation; reverting to an incompatible catalogue is rejected. Every record carrying postings is registered in the interval tree, so one chunk-wise stab is the only candidate source. Every duplicate-bound record is registered over the whole domain and marked inexact, so the original field lookup and cast determine its answer wherever a query could match it. At an exact query instant, a strict-end traversal delivers endpoint-equal chunks flagged for verification-only intersection. A rounded endpoint such as `.000500Z` shares the point's millisecond; verification postings rescue it without a second closed stab. Strict-start tie removal likewise preserves flagged records, including clamped starts at the domain origin. Non-exact query instants use one closed traversal, whose candidates are verified against their original fields. Closed and strict stabs outside every interval read no candidate object at all. Membership filters nested objects entirely from index postings. Retained built-in temporal residuals run for every candidate after the original temporal predicate and only as each candidate is demanded. Iteration and positional access can stop before a later malformed cast; counting evaluates all candidates that need verification. Exact candidates require no field reads when no residual remains. A retained temporal residual always filters exact candidates as well, and disables key-only known cardinality. Folded bitemporal comparisons use the key-only sequence when the comparison matches the indexed bounds and all selected candidates are exact; otherwise they retain the built-in comparison and reuse the selected keys and evidence. Caller-supplied arbitrary predicates are not supported. Among source-valid records, a strict integer tie must not suppress an original cast error. Point candidates intersect compressed HOT chunks with immutable membership masks word-wise before expansion; verification-only chunks additionally intersect the verification mask. Matching keys are accumulated as runs by chunk base, unioned in occupied words and emitted once in ascending order, without a hash set or final key sort. Sparse chunks retain runs; dense chunks use bitmaps. The threshold and work bounds are owned by the [work-budget counter reference](../bundles/sirix-core/src/test/java/io/sirix/budget/README.md#the-counters). Only matching candidate keys are retained; unrelated companion posting references are never enumerated or copied into query collections. Exact range slices retain their sorted-key membership checks against compressed chunks. Direct and folded point sequences read companion evidence only for chunks returned by the single traversal. An empty stab emits no interval or posting references and performs no posting lookups. Plain-FLWOR coverage uses posting cardinalities and compressed bitmap intersection without expanding references. Document-order admission stops at the first live guard chunk; exceptional-bound admission stops at the first intersection with the array's membership. Exceptional intervals in other cohorts do not prevent key-only counts over exact array members. The read index controller retains up to 256 cohort admission results, scoped to database, resource, immutable revision, definition identity, array key and length. Half-open primitive-key requests at an exactly representable point reuse a successful cached proof to issue the half-open chunk stab without reading end-equal chunks or verification masks. Membership postings still exclude matching records from other arrays. Without a cached proof, requests retain ordinary candidate verification; a nonempty matching result can establish the cohort proof for later requests, while an empty result does not initiate cohort admission reads. Controller eviction or collection of the owning session releases these proofs; entries retain no readers or transactions. Every key-only factory declines writers and intent-log-backed serving cursors before discovering indexes, including read-only wrappers over mutable readers. Historical immutable readers remain eligible while their resource has an active writer. Mutable calls use the exact current-document fallback, which refreshes held whole-array/object and object-field views. Mutable positional slices refresh their members and cursor anchors while retaining their original window. Direct scans and primitive-key requests also decline positional and object-field array views: whole-storage-array postings cannot prove those views' membership. Key requests collect and sort exact fallback matches, retaining the strict end mode. Repeated immutable queries reuse successful or declined admission without decoding whole membership and verification postings; point conversion and endpoint selection remain per evaluation. Companion masks are cached per resource session for immutable reads, keyed by revision, index, store, fork, endpoint, chunk base and HOT lookup-cache generation. The bounded cache retains no transaction or candidate set and is cleared on session close; writers and sessions with the HOT lookup cache disabled bypass it. Trie cursors remain bound to each transaction; the rationale is in [`ValidTimeReadCache`](../bundles/sirix-core/src/main/java/io/sirix/index/interval/ValidTimeReadCache.java). Index-root metadata reuse follows the [revision-scoped page-cache contract](formal-verification.md#revision-scoped-index-metadata). ## Verification plan All Gradle and Maven commands use a fresh, worktree-private Maven-local directory and a private `TMPDIR`. Do not use or modify `~/.m2` for this change: it may contain a stale Brackit snapshot. The example paths below must be empty at the start of a verification campaign. Before running the commands, define the shared-host `heavy()` limiter captured in [`measure.sh`](performance/cheap-first/measure.sh); its shell usage is described in the [campaign reproduction instructions](performance/cheap-first/README.md#reproduction). ```bash export TMPDIR="$PWD/build/validtime-verification/tmp" mkdir -p "$TMPDIR" "$PWD/build/m2-private" heavy ./gradlew --no-daemon -Dorg.gradle.jvmargs=-Xmx2g \ -Dmaven.repo.local="$PWD/build/m2-private" --max-workers=2 \ -PtestHeapMin=512m -PtestHeapMax=2g \ :sirix-core:test --tests 'io.sirix.index.interval.*' \ :sirix-query:test --tests 'io.sirix.query.function.jn.temporal.*' \ --tests io.sirix.query.function.DateTimeToInstantTest \ --tests io.sirix.query.budget.ValidTimeSliceWorkBudgetTest ``` Run the complete `:sirix-core:test :sirix-query:test` suites and the work-budget commands in [VERIFICATION.md](VERIFICATION.md), with the same private Maven repository. On the shared laptop, every Gradle or Maven invocation runs under the captured memory-gated two-slot `heavy()` limiter. All runs, including the full suites, use two Gradle workers, a 512 MB initial/2 GiB maximum test heap and a 2 GiB maximum Gradle heap. The complete query suite also requires a worktree-local Gradle init script setting its test task's `forkEvery = 1` and `maxParallelForks = 1`, supplied with `-I` so every test class runs in a fresh worker within the same heap cap. The new budget decorates a real transaction. Before demand and during exact-key counting it permits zero candidate moves, timestamp reads, and object-constructor child-pointer reads. The first `next()` permits one object read. Direct function, direct FLWOR slice and plain `jn:doc(...)[]` FLWOR counts exercise the query interface through the decorated cursor. A second case holds only sub-millisecond bounds, so every record carries a verification posting. Closed, strict-start, strict-end, and combined strict stabs before and after all intervals must return zero with zero candidate moves, timestamp reads, constructor reads, interval references and posting references. `sirix.validTime.scanDiag` gates the emitted-reference counters behind a static-final flag; both module test tasks provide it, and captures require the gate to be on. Direct key and sequence consumers and folded bitemporal count/first-item queries use the decorated cursor. Positive probes inside the intervals and at a rounded end tie must still verify the records on demand in every mode. Posting lookups and compressed chunks are counted separately from emitted references: candidate checks emit zero posting references. An explicit scan is the positive control for reference enumeration. Repeated demand reuses candidates and posting evidence without further posting reads. Selective positive-stab budgets place an exact match first and last among 31 or 127 expired inexact rows, exercising packed and bitmap postings, plus nested candidates outside the root cohort. Count performs zero object/timestamp reads; exists and first demand construct one object, with work bounded by the three candidates. Opt-in 100,000-row versions exercise both placements in the dedicated Test phase. Multi-chunk plain FLWOR budgets put expired inexact nested records beside exact outer records with one match, first and last. Their first admission proves nonzero validation work; repeated count/exists/first queries visit only the two candidate evidence chunks, using cached masks when available. Packed and bitmap fixtures retain explicit reference enumeration and cardinality controls. Separate executable checks cover warmed proofs across resource and cohort boundaries, changed points, writer mutations, reordered arrays, dropped/rebuilt definitions, reverts and reopened historical revisions. The two 100,000-row cohort variants are also opt-in. `ValidTimeMutableSliceTest` reproduces both pending-edit wrong-result directions through real writers, read-only cursor wrappers and intent-log reader facades. It checks direct count, exists, positional demand, iteration and sorted keys, every strict/inclusive endpoint mode, structural edits, held views, warmed slice members/anchors, immutable windows, object-field views, deferred empty points, cast errors and historical readers with an active writer. Edited test transactions roll back before closing. User-function demand and return-type coverage is described under [Brackit dependency](#brackit-dependency). A deliberate eager-materialization mutation must fail the count budget; ordinary result assertions alone cannot detect it. The small empty-stab inexact fixture remains at 64 records. The dedicated Test phase must execute all five 100,000-record variants: empty stabs, selective positive stabs with the match first/last, and plain-FLWOR cohorts with the match first/last. For empty stabs, record the printed `moveTo`, `getFirstChildKey`, `getValue`, `intervalRefs` and `postingRefs` counts, all zero for each empty answer before and after the intervals in every mode and query route. Printed modes use bit 1 for strict start and bit 2 for strict end. It is opt-in so ordinary CI retains fixture-scale coverage: ```bash SIRIX_VALID_TIME_LARGE_BUDGET=true heavy ./gradlew --no-daemon -Dorg.gradle.jvmargs=-Xmx2g \ -Dmaven.repo.local="$PWD/build/m2-private" --max-workers=2 \ -PtestHeapMin=512m -PtestHeapMax=2g :sirix-query:test \ --tests '*ValidTimeSliceWorkBudgetTest.oneHundredThousand*' --info ``` The Test phase must retain the captured heap limits and limiter for these opt-in scenarios; their presence alone is not evidence of a 100k result. Correctness coverage includes exhaustive small RI-tree domains, hand-computed strict/inclusive answers, reversed operators, dynamic resources and correlated points, nested objects, missing and malformed fields, sub-millisecond endpoints, start bounds clamped below the domain origin, duplicate bounds registered over the whole domain, changed precision with unchanged rounded keys, moved array elements, and historical revisions. Existing incremental-maintenance fixtures also check the parent postings after each update/delete/move and after reopening historical revisions, and that every verification posting belongs to a registered interval. ## Brackit dependency The consumed `1.0-alpha10-SNAPSHOT` supports lazy UDF returns through `Sequence.isRepeatable()` and `Sequence.knownSize()`. Sirix opts immutable valid-time key sequences into that protocol, including folded user-function bodies in the laziness tests. SH1 Q6/Q11 use direct public calls. For exact candidates, the known cardinality comes from index keys without constructing objects or reading timestamps. Inexact candidates and sequences retaining a built-in temporal residual report an unknown cardinality. Mutable views still use the existing fallback. Optimizer-generated comparison scans retain the selected immutable producer's repeatability and known cardinality for valid literal points and already captured `DateTime` tuple bindings. Capability inspection never invokes the deferred point expression; other points and fallback scans retain their existing evaluation and error timing. Comparison modes are internal to the optimizer, and the public `jn:scan-valid-time-index` remains a two-argument function. Brackit preserves return-type validation and normalizes empty/singleton UDF results to their existing scalar representation. That normalization may construct a singleton object, and unknown cardinalities require bounded lookahead. Exact multi-item `item()*` returns need no lookahead: count constructs zero objects, and the first requested item constructs one. `ValidTimeSliceWorkBudgetTest.userFunctionCountDoesNotMaterializeTheSlice` is enabled and guards two- and 64-row counts, first-item demand, independent readers after early close, and constrained return-type errors through both bitemporal and plain comparison rewrites. The plain comparison UDFs cover all strict/inclusive, value/general, operand-direction, and conjunct-order combinations. Direct-call and direct-FLWOR zero-read bounds remain unchanged. The standalone [UdfMaterializationRepro.java](bench/validtime-slice/io/sirix/query/bench/validtime/UdfMaterializationRepro.java) needs only Brackit and implements the same producer protocol: both the direct count and the trivial UDF wrapper construct zero items. Unmarked producers retain Brackit's conservative eager behavior. ## Timing reproduction [LatencyProbe.java](bench/validtime-slice/io/sirix/query/bench/validtime/LatencyProbe.java) separates compilation, complete result iteration, serialization, and TSV canonicalization. It aborts on any oracle mismatch before reporting a timing. Build the normal query runtime classpath with `:sirix-query:printClickBenchRuntimeClasspath` and compile the probes against it with `javac -d `. Their package is `io.sirix.query.bench.validtime`; add `` to the runtime classpath when launching them. Preserve class directories and the core jar per measured variant so another build cannot change code under a running measurement. Use the unmodified SH1 loader and its natural publication batching, with read-only inputs/oracles under `/var/tmp/sirix-bitemporal/t25k` and `t100k`. Stores and output belong under the task-specific campaign directory. Use the kit JVM flags: `--enable-preview --add-modules=jdk.incubator.vector -Xms512m -Xmx2g -XX:MaxDirectMemorySize=1g` (and native-access permission for the storage backend). ```text io.sirix.query.bench.validtime.LatencyProbe ``` Warm: one JVM, ten repetitions, discard the first; Q6 and Q11 use three repetitions, discard the first. Cold: three fresh JVMs per query, one repetition each. Report medians of compile + execute + serialize, with canonicalization separately. Store/resource opening is outside the measured interval. These are cold-process measurements, not a forced OS-page-cache eviction. Also run the kit's twelve direct-call queries and byte-compare all twelve TSVs at both tiers. Timing results are recorded only after these checks pass. ## Retained verification (2026-10-05) This evidence predates the subsequent optimizer-generated UDF capability fix and removal of the five-argument public scan. It does not validate the final source; source-bound revalidation belongs to the Test phase. Source `46da5ab1f7d56a3bafe7aee6a3749528b99c6114` passed the complete core suite (**13,111 tests**, zero failures/errors, 77 skips) and the complete query suite (**2,247 tests**, zero failures/errors, 12 skips). The query confirmation ran every class in a fresh 2 GiB worker after the initial shared worker exhausted its 2 GiB heap; no test was excluded and the heap cap was retained. Both module Spotless checks passed. All active work-budget cases in those suites passed. The five opt-in **100,000-row** cases then passed separately with zero skips and live counter diagnostics. Captures show zero object and timestamp reads for exact counts, one object on first demand, and zero interval/posting references for empty probes. The isolated UDF count/demand guard is enabled and passed. Both new regressions failed before the half-open change: end-equal records were included and the internal target could be called directly. The internal-rewrite regression also executes the rewrite before confirming it remains absent from query-text function resolution. [Verification provenance](bench/validtime-slice/halfopen-verification.json) records the source and runtime fingerprints, suite/budget counts, actual heap policy and oracle checks. [100k work-counter captures](bench/validtime-slice/halfopen-work-counters.txt) retain the printed measurements. Subsequent source fixes or rebases require refreshed source-bound validation. ## Retained timing observations (2026-10-05) The measured implementation is `46da5ab1f7d56a3bafe7aee6a3749528b99c6114`, including public half-open `jn:open-bitemporal`, direct SH1 calls and the preceding correctness fixes. These timings predate the later comparison-UDF and public-scan changes and are not measurements of the final source. Fresh stores used the unchanged loader's natural publication batching. All twelve TSVs matched the read-only oracles byte-for-byte at both t25k and t100k; each timing repetition checked its oracle too. The complete repetitions are retained in [halfopen-results.csv](bench/validtime-slice/halfopen-results.csv) and [halfopen-direct-results.csv](bench/validtime-slice/halfopen-direct-results.csv). The before runtime is frozen source `79c7ab99e769300dffd1ab51d8f65ec8b9501818`, using its original strict-end wrapper and a separately rebuilt compatible store. The measured runtime uses direct public calls. Both ran on the shared laptop with the kit's 512 MB initial/2 GiB maximum heap, 1 GiB direct-memory limit and FILE_CHANNEL storage. Warm medians discard the first of ten repetitions (three for Q6/Q11); cold medians use three fresh JVMs. Opening and canonicalization are outside total query latency, which is compile + full iteration + serialization. The measured Brackit SHA-256 is `d72e8ea6fb8cb8730961049ca71f82da0e5d580e2189f5ec7b7e1560a1856a88`; the frozen before runtime uses `8164d45e0a3aab8926d92f59c9996daafbfa0dc9c550d0ddbd2a4ee6fc877ca7`. Base and dependency changes are included in these observations. In particular, the measured revision's hash membership implementation contributes most of Q12's improvement. These are measurements of two software states on a shared machine, rather than an isolated attribution of every gain to this slice change or a latency guarantee. The direct half-open slice count returned the Q7 oracle's independently summed **97,212** records on every repetition. Its warm total median fell from **458.4 ms to 72.1 ms**, and its fresh-process query median from **3,407.2 ms to 467.7 ms**. It removes candidate-object and timestamp-field work but does not meet the study's 15 ms estimate. Grouping and repeated slices remain substantial costs. Median total query latency (milliseconds): | Query | Before warm | Measured warm | Before cold | Measured cold | | --- | ---: | ---: | ---: | ---: | | Q4 | 1,161.2 | 387.0 | 6,280.6 | 4,122.7 | | Q6 | 13,449.6 | 4,418.4 | 30,737.2 | 22,330.0 | | Q7 | 575.3 | 230.2 | 4,511.1 | 2,878.0 | | Q8 | 643.1 | 307.4 | 4,686.1 | 3,086.3 | | Q9 | 699.4 | 275.5 | 4,889.3 | 3,085.9 | | Q11 | 36,207.2 | 14,061.3 | 39,743.4 | 15,260.4 | | Q12 | 288,564.5 | 149.7 | 260,748.2 | 4,468.1 | ## Historical validation results (2026-10-03) These historical figures measured implementation revision `a17efd081a1a9f2928058785d7b4c7b0a6a7fb07` (`ship`) against `79c7ab99e769300dffd1ab51d8f65ec8b9501818` (`baseline`). Both CSVs record that revision for every row. They predate the subsequent correctness and posting-layout fixes and are not evidence for current code. The dedicated Test phase must rebuild stores and rerun affected SH1 oracle checks and measurements on the actual corrected revision before reporting current results. The complete core suite passed: 11,957 tests, zero failures/errors, 76 existing skips. The complete query suite passed: 1,818 tests, zero failures/errors, six skips (five existing skips and the explicitly pending Brackit UDF budget). The focused interval/temporal and all work-budget commands also passed, as did both module formatter checks. The deliberate eager-materialization mutation failed the active budget at its zero-candidate-moves assertion before being restored. Both historical implementation SH1 stores used the kit's natural 25-publication batching. Every TSV from the unmodified twelve-query kit matched its oracle byte-for-byte at t25k and t100k. Each reported timing repetition also checked its oracle. The historical t100k implementation store used 366,795,207 logical bytes versus 358,405,103 for the baseline (about 2.34% more for the additional revisioned postings). The baseline is `79c7ab99e769300dffd1ab51d8f65ec8b9501818`. Measurements used frozen compiled outputs per variant on an Intel Core i7-12700H, Oracle GraalVM 25.0.3+9.1, and the kit's 512 MB initial/2 GB maximum JVM heap. Brackit was `1.0-alpha10-SNAPSHOT`, SHA-256 `8164d45e0a3aab8926d92f59c9996daafbfa0dc9c550d0ddbd2a4ee6fc877ca7`. This was a shared laptop; other work, including part of this lane's full-suite validation, overlapped the timing campaign. Treat the medians as observed workload measurements, not latency guarantees. [DirectSliceProbe.java](bench/validtime-slice/io/sirix/query/bench/validtime/DirectSliceProbe.java) counts a direct half-open slice at the kit's latest publication and valid-time point. Its independent expected count is the sum of the Q7 oracle's group counts: 97,212. With the same repetition/discard method, its total warm median fell from **403.1 ms to 93.0 ms** and its fresh-process query median from **3,938.7 ms to 596.9 ms**. This removes candidate-object and timestamp-field work, but does not meet the study's 15 ms estimate. [All direct-slice repetitions](bench/validtime-slice/direct-slice-results.csv) are retained. The end-to-end SH1 medians and every repetition are recorded in [results.csv](bench/validtime-slice/results.csv). Q12 is measured on the baseline's original anti-join; the separate membership change is not included, so its several-minute join dominates the saved slice work. At the measured revision, the Q6/Q11 path through `local:slice` lacked demand-only materialization despite timestamp-predicate folding inside that body. The current dependency contract is described under [Brackit dependency](#brackit-dependency). Median total query latency (milliseconds): | Query | Before warm | After warm | Before cold | After cold | | --- | ---: | ---: | ---: | ---: | | Q4 | 1,272.9 | 574.8 | 6,923.7 | 4,711.0 | | Q6 | 13,383.1 | 4,933.2 | 36,851.6 | 19,118.8 | | Q7 | 780.6 | 247.8 | 4,300.0 | 3,033.1 | | Q8 | 722.2 | 415.8 | 4,834.1 | 2,844.3 | | Q9 | 769.4 | 377.3 | 4,616.3 | 3,177.2 | | Q11 | 43,265.2 | 13,326.2 | 42,481.8 | 16,400.4 | | Q12 | 314,039.0 | 249,531.7 | 307,634.4 | 216,514.9 | ## Range intersections and joined overlap residuals The RI-tree streams forks inside `[L,U]` through one contiguous ordered-store range. Forks outside that range can match only on the two boundary paths, with one endpoint check per probe. Each registration is emitted once, in at most `2 * height + 1` store probes. `startingAt(U)` and `endingAt(L)` remove strict endpoint ties after exact revision coverage has been proved. Candidate keys still intersect persisted array membership, excluding nested and sibling arrays. Joined grouping and ordered row joins admit paired numeric comparisons and explicit `xs:dateTime(field)` comparisons over canonical UTC timestamp columns, gated by the persisted [UTC provenance contract](DISK_FORMAT.md#projection-indexes-segment--slot-layout). Projection epochs are seconds; joined timestamp buffers convert them exactly to milliseconds once per selected row. Comparisons then use primitive longs per joined pair. Mixed-side `+`, `-`, `*` aggregate programs and `count(distinct-values(field))` use the same matched pairs, with primitive sets per distinct aggregate and group. Missing values contribute no operand or distinct member. Range predicates over an existing bitemporal point source intersect its sorted key set with the range key set; they cannot replace the original point constraint. Stable transaction-time expressions resolve both views at the same runtime revision. UTC timestamp grouping keys retain canonical Z text, while distinct counts can use the epoch lane without constructing strings. Only served join annotations consume post-join range predicates: the generic join and its casts remain the fallback when a runtime revision, range, covering projection or provenance check declines. Immutable dense numeric masks can reuse columns already requested for the same column-store identity, field roster and exact sorted key set. The cache has weak identity keys and a weighted heap bound (at most 64 MiB or 1/64 of heap, with a 1 MiB floor); it retains no query-local string interner. Each reader owns its mutable masks. Sparse and string sources keep their existing column-loading path, and reuse never fills a pruned leaf. Compact storage-key domains collect range matches in a bitmap capped at 2 MiB, clear strict ties directly, and enumerate sorted unique keys. Large or sparse domains use output-sized primitive lists and a bounded radix sort that skips constant bytes; its scratch space is capped at 32 MiB or 1/128 of heap. Small, signed, or larger inputs retain comparison sorting. The persisted membership check still excludes nested and sibling arrays. Exact range keys can reuse one immutable snapshot per resource session, keyed by the revision index controller's identity, revision number, array key, index id, bounds and strictness. Controller invalidation prevents reuse after truncation and recommit with the same revision number (`ValidTimeRangeCacheTest.reusedRevisionDoesNotServeRangeKeysCachedBeforeTruncation`). Publication clones the keys, and callers receive copies. Session keys are weak; total retained weight is bounded by the smaller of 16 MiB and 1/64 of heap, with a 1 MiB floor. Joined kernels prove complete presence from the selected masks before choosing direct numeric leaf feeds. Compact integer join domains use bounded head arrays (at most 1 Mi entries and four per build row); other domains keep primitive hash heads. AND-only paired residuals use direct comparisons; mixed AND/OR predicates retain the postfix evaluator. Numeric distinct fields can use exact bitmaps when both value and group domains bound total bitmap storage to 2 MiB per query. Wide domains, strings, timestamps and computed operands retain exact primitive sets.