# changes (/product/modules/changes)



`changes` is how records arrive other than by a person filling in a form: an agent turn, a spreadsheet import, a feed run, a storefront sync, a purge. Each one is a **change batch**.

## The batch

A batch is a row in `change_batches`, with its channel, its status, its counts and its origin — what it read from. Every table a feed or an import can land carries a pointer back to the batch, so a batch opens its records as an ordinary grid filter composed with the tenant's own filters and pagination. The rows a batch refused are its rejects, each with a reason and the payload as it arrived.

## Approval

Generated data does not land at all until someone applies it. An AI or imported write is staged as a proposal — a row in `change_proposals` carrying what it would write, revisable while it waits — so an unreviewed product has no row rather than a hidden one. Applying it writes the real tables and the [audit](/product/modules/audit) history records what happened; rejecting it leaves the proposal as the record that someone declined. Who applied or rejected it is a step on the proposal, and a tenant can require that person to be someone other than the one who staged it.

Guardrails — a price ceiling, protected fields — are settings data the write path reads, checked when a change is staged and again when it is applied.

## Routes

| Route           | Content                                                   |
| --------------- | --------------------------------------------------------- |
| `/changes`      | One row per batch, what it proposes, and apply or reject. |
| `/changes/<id>` | The rows that batch refused, and why.                     |

## Settings scope

`changes`.

## Permissions

`changes.read` to see batches and proposals; `changes.manage` to change a batch. Applying and rejecting are admin-only.

## Switched off

Never. It is core: every tenant has the assistant, and every assistant write stages here.
