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

# Previews and fences

> Show the reviewer what will happen — then refuse the commit if the data moved.

Approving a statement is approving a guess about what it does. Two mechanisms turn that guess into a fact.

## The preview

Before a human is asked, Warden runs the change inside a transaction, captures the affected rows before and after, and rolls it back. The reviewer sees per-record differences:

```
ord_1   status: paid → refunded
```

Every preview carries a **fidelity** label, and nothing downstream may drop it:

| Fidelity | How it was produced |
| - | - |
| `exact` | The change was executed and rolled back. This is what will happen |
| `estimated` | The engine could predict it but not execute it |
| `static` | Derived from the statement's shape alone |
| `none` | No preview was possible, and the reason is attached |

A preview with no basis carries **no changes at all**, so no interface can render an empty diff that reads as "this changes nothing" when the truth is "nobody could tell".

> [!NOTE]
>
> **Previews are produced only when a human will look.** Executing and rolling back a change is worth its cost for a reviewer and is pure overhead for a write policy already allows.

Values the database generates — identity columns, `now()`, defaults — differ between the preview and the commit, and every preview says so rather than letting a reviewer believe the generated ID they saw is the one that will exist.

### Previews are masked

A preview reads the target table directly, so its rows hold raw values. They are masked and column-restricted exactly as an agent's results would be, before the preview is stored. A review queue is rendered in browsers, may be sent to Slack, and outlives the operation; it must never become a way to read what the agent itself cannot.

## The fence

A human takes time. Between the preview and the click, the data can move.

When the proposal is made, Warden records the state of the rows the change targets — for PostgreSQL, each row's `xmin`, the system column that changes whenever a row is updated. At approval, the commit transaction re-reads those rows **with them locked** (`FOR UPDATE`) and compares. If anything differs, the change is refused:

```json theme={null}
{ "status": "stale", "code": "fence_stale", "retryable": true,
  "message": "The underlying data changed after this operation was reviewed." }
```

Nothing is written. The agent re-reads and proposes again, and the new proposal carries a fresh preview.

Because the check happens inside the same transaction as the write, with the rows locked, there is no window between "verified" and "applied" for a third party to slip through.

### What a fence catches

* A row the reviewer saw was modified by someone else.
* A row in the affected set was deleted.
* A row that did not match the predicate now does.

### What carries no fence

Inserts. They create records rather than modifying ones a reviewer could have looked at, so there is nothing to fingerprint — and the preview says so rather than implying a protection that is not there.

> [!WARNING]
>
> A connector that claims it can capture a fence and then cannot **refuses the proposal**. Approving a change whose staleness cannot be checked is precisely the failure fences exist to prevent. A failed *preview* is different: the reviewer is told none was possible, and decides with that knowledge.


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