Skip to content

Collection runtime

Collection runtime

The collection runtime is the server half of every read and write. It compiles queries to SQL, evaluates policies, runs the collection transform, gates approvals, and records audit — all inside one decision path.

Query compilation

Client reads and writes arrive as structured operations, not raw SQL. The runtime compiles them against the compiled schema — joins, filters, and projections included — so tenant code never builds SQL strings.

Policy evaluation

Every operation is evaluated against the policies of the acting principal: row conditions narrow the SQL, field masks strip attributes from reads, an `authorize` predicate decides whether a write proceeds, and the root grant’s approval flow decides direct commit or a hold. A write outside the mutation predicate or naming a masked field is refused, never partially applied.

The mutation path

  client.collection.<collection>.update(id, input)
        │  the declared columns + explicit relation actions
        ▼
  ┌─────────────────────────────────────────────┐
  │  one write pipeline                         │
  │  1. refuse anything outside the selection;  │
  │     judge the caller; run the transform     │
  │  2. approval route → committed / held       │
  │     provisionally under approval_id         │
  │  3. root + nested actions commit atomically;│
  │     bolt_collection_history and             │
  │     SyncChange facts ride the txn           │
  │  4. sync publish + task enqueue (settle)    │
  └────────────────────┬────────────────────────┘
                       │  changed collections
                       ▼
            host subscription registry
                       │  affected live queries
                       ▼
                 SSE apply frames
  1. the client sends the declared input — selected columns plus explicit relation actions — through client.collection.<collection>.create(input), createMany(inputs), .update(id, input), updateMany(inputs), .delete(id), or deleteMany(ids)
  2. anything outside the collection’s input selection is refused, the caller is judged on the shape it submitted, and the transform turns inputs into payloads — a refusal writes nothing
  3. policy evaluation decides whether the write proceeds, and the grant’s approval flow may hold it for review
  4. the root and every included relationship reconcile atomically — history and SyncChange facts in the same transaction
  5. after the commit the host publishes the change, and its changed collections let it target every affected registered live query

The read path

Every live prefix (findMany / findFirst with a contiguous limit) is registered and evaluated on the server under the acting principal’s policy. The initial answer travels through sync.connect and remains only in browser memory. When a commit changes a dependency, the host advances affected prefixes and the stream carries a version-fenced keyed delta — or a reset that forces the browser to re-register. count, findGrouped, a cursored after page, semantic search, and a declared similarity (nearest) search are one-shot and are never filed live.

One transaction

Relation actions are explicit: `create`, `update`, `upsert`, `link`, `unlink`, and `delete` under the relation name. An omitted relation or an empty array does nothing, and nothing is ever deleted by omission. The root and every nested action commit in one transaction, so either the whole graph commits or none of it does; authorization, approvals, the transform, history, sync change capture, and events remain in the same write pipeline.

The authoring surface is Collections ; writes travel on the command channel, and the sync engine carries committed changes outward.