USL

Query Plane

Today's storage API and the draft SessionQL 1.0 contract

USL has two deliberately separate query surfaces:

  1. the implemented L1 storage API, a small Rust API for deterministic record reads;
  2. the draft portable query plane in RFC 0001, which specifies SessionQL 1.0, Query IR 1.0, search, lineage, insights, subscriptions, and a read-only SQL attachment.

The RFC is an implementation contract, not a claim that every capability below ships in usl-core today.

Implemented: L1 storage API

The current Rust surface is session-scoped and schema-agnostic:

Store::create(path, opts) / Store::open(path, opts) -> Store
store.append(&Record) -> seq            // assigned monotonically
store.flush()                           // full fsync
store.scan(&SessionId, from_seq) -> Vec<StoredRecord>
store.get(&SessionId, seq) -> Option<StoredRecord>
store.next_seq() -> u64
Store::verify(path) -> Verification     // read-only integrity report

Reading

  • scan returns a session's records with seq >= from_seq, in ascending order — the basis for replay and live tail.
  • get is a point read by session + seq.
  • verify opens read-only and reports data_end, next_seq, frame_count, and the truncation offset (if any), without mutating the file.

The index

The store keeps an in-memory Index (session_id → frame offsets), rebuilt by replaying the log on open. Reads open a fresh file handle and re-verify CRC on every frame — defense in depth against silent corruption. This index is part of the current L1 engine; it is not the structured/full-text/vector sidecar system proposed by RFC 0001.

Draft: portable query contract

The RFC adds a stable boundary shared by CLIs, SDKs, UIs, natural-language translators, and interchangeable execution engines:

operationpurpose
query.executeExecute SessionQL text or a typed QueryPlanV1
query.explainReturn the normalized plan, indexes, row counts, scores, and freshness decision
query.subscribeReplay then tail a deterministic, bounded audit query
resume.describeLocate a result in its original runtime without overstating resume capabilities

Every result is fixed to an asOfSeq. Cursors bind the query, access policy, snapshot, index generations, and full sort key, so pagination cannot silently drift after concurrent appends.

interface QueryResultV1<Row> {
  apiVersion: "query.usl.dev/v1";
  queryHash: string;
  asOfSeq: number;
  watermarks: IndexWatermarkV1[];
  rows: Row[];
  nextCursor?: string;
  warnings: QueryWarningV1[];
  explain?: QueryExplainV1;
}

System boundary

  • ASP defines canonical events, identity, causality, and provenance.
  • USL persists the append-only source of truth and defines query semantics.
  • SESDB may execute the plan, but does not define the specification.
  • SQL is an optional read-only analytics attachment, not a SessionQL equivalent.

Continue with SessionQL, Search & indexing, or Insights & subscriptions.

Source of truth: usl-core/src/store.rs.

On this page