> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exact reads

> Wait until a dataset covers a mutation, retain exact versions for readers and read a fixed snapshot while publication continues

A dataset keeps publishing while you read it. When a reader needs a specific
state rather than the newest one, use one of three tools:

| Need | Use |
| - | - |
| A version that includes the writes of one mutation | A [receipt](#wait-for-a-mutations-changes) |
| Exact versions held for an application read | A [read context](#hold-versions-for-a-read) |
| A named snapshot an external job reads by Iceberg tag | A [checkpoint](#read-an-exact-snapshot) |

The examples use the `orders` dataset from the [overview](/datasets/overview)
and a `datasets` client, `new Datasets(components.datasets)`.

## Wait for a mutation's changes

A receipt records the source position a mutation committed. Take it in the
mutation whose writes must be visible:

```ts bijection/corrections.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { Datasets, datasetReceipt } from "@bijection/datasets";
import { v } from "bijection/values";
import { components } from "./_generated/api";
import { mutation, query } from "./_generated/server";
import { orders } from "./datasets";

const datasets = new Datasets(components.datasets);

export const correctOrder = mutation({
  args: { id: v.id("orders"), amountMinor: v.int64() },
  handler: async (ctx, { id, amountMinor }) => {
    await ctx.db.patch(id, { amountMinor });
    return datasets.receipt(ctx, orders);
  },
});

export const correctedVersion = query({
  args: { receipt: datasetReceipt },
  handler: (ctx, { receipt }) => datasets.covering(ctx, receipt),
});
```

`datasets.covering` returns a published version that includes the receipt's
writes, or `null` until one is published. Subscribed with `useQuery`,
it updates as soon as that version exists. A covering version may also include
writes committed after the receipt; it never excludes the receipt's own. A
receipt needs an established export: `datasets.receipt` refuses before the
table's first version is published.

From a terminal, wait for the same coverage with the receipt's `id`:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
bijection dataset status orders --after RECEIPT_ID --wait 30s
```

`--wait` bounds only the observation, up to `10m`; publication continues after
the command exits. `--binding-revision <revision>` waits instead until an
accepted binding revision has published.

A pipeline input declared with `basis: "admission"` is stricter: it captures
exactly the receipt's commit. The export ends a publication at every receipt's
commit, and the run reads that version, which excludes every later write. If
the export has passed the commit without such a version, the run's input is
blocked with `input_unavailable` rather than moved to a later version.

## Hold versions for a read

A read context fixes an exact publication, or an exact set of versions, for a
bounded lease. Open it in a mutation after your own authorization check:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const context = await datasets.openReadContext(ctx, {
  owner: "reports",
  key: `monthly:${month}`,
  target: { publication: publicationId },
  leaseMs: 10 * 60_000,
});
```

`datasets.readContext` inspects it, `datasets.readContextSnapshots` returns its
snapshots, and `datasets.closeReadContext` releases it. The lease defaults to
five minutes, so a reader that stops does not hold versions forever.

## Read an exact snapshot

A checkpoint retains exact versions as a named Iceberg tag on every selected
table, so a job reads a fixed snapshot even while publication continues:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
bijection dataset checkpoint retain nightly --datasets orders --lease 2h --wait 2m --output manifest.json
```

The manifest names each table's snapshot and frozen metadata file; it carries no
storage credentials. Your job reads with its own catalog identity:

```sql theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
SELECT * FROM app.orders VERSION AS OF 'nightly'
```

Check a checkpoint, and release it when every reader has finished:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
bijection dataset checkpoint status nightly
bijection dataset checkpoint release nightly --wait 2m
```

With `--lease`, the checkpoint releases itself when the lease ends unless you
retain it again, so a job that dies does not hold its snapshots forever. A job
holding a [producer grant](/datasets/customer-compute#give-your-scheduler-a-producer-grant)
retains and releases its own leased checkpoints with that grant instead of
these commands.

`--datasets` names datasets that share one source feed; an event archive is one
dataset. Add `--after <receipt>` to wait durably for a complete cut that covers
a receipt. Names are 1 to 128 letters, digits, `.`, `_` or `-`, and a different
selection needs a new name. Bijection never moves or deletes a tag it did not
create.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.