# Working with proposals How the [proposal mechanism](/reference/proposals) looks from the agent side of the wire. The rule underneath everything: an Ajan token's mutation is **recorded, never executed** — nothing you do is visible in the store until the owner applies it. ## 202 means recorded A mutation through any surface — `POST /v1/commands`, a `propose`-policy route, an MCP tool — answers HTTP 202 with the normal outcome shape plus `proposed: true` and `auditId: null`: ``` { "ok": true, "proposed": true, "proposalId": "prp_…", "itemId": "pri_…", "position": 3, "preview": { "wouldChange": [...], "warnings": [] } } ``` `auditId: null` is the tell — "no audit row ⇔ nothing applied" is a platform invariant, so you can distinguish proposed from applied without guessing. Over MCP, results of recorded calls start with `PROPOSED (not applied)`. The recorded `preview` is the same dry-run the owner will see; read its `wouldChange` and `warnings` to know what you actually proposed. You have **one open proposal per token**; the first recorded mutation creates it, later ones append items in order (max [`proposalMaxItems`](/reference/limits) items). Items keep their order at apply — sequence your calls the way they must run (create the product before pricing it). ## Notes Every recorded call accepts a `note` (≤500 chars) — the rationale the owner sees next to that item in Öneriler. Use it: "Fiyat listesindeki yeni KDV oranına göre güncelleme" reviews faster than a bare diff. ## Submitting When the change set is complete, [`proposal.submit`](/reference/commands/proposal.submit) with a `title` and a `summary`. The proposal moves to `submitted`, the owner is mailed a review link, and it expires unreviewed after [`proposalSubmittedDays`](/reference/limits) days. An empty proposal cannot be submitted. From the CLI: [`propose`](/reference/cli). While a proposal is `open` you can keep appending; after submit, a further mutation opens a fresh proposal. ## Drift: stale items At apply time each item is re-previewed against the current world and its recorded preview hash must match. If the store moved underneath you — the owner edited the same price, an order shipped, the live design advanced — that item goes `stale`, the proposal pauses, and the owner decides: skip the item, or accept the new preview and continue. You do not resolve drift; the owner does. What you can do is keep proposals small and submit promptly — drift is a function of time. Failures behave the same way: apply stops at the first failing item and never rolls back applied ones (each applied item is an ordinary audited command). ## Watching status - [`proposals.list`](/reference/routes/proposals.list) / [`proposals.get`](/reference/routes/proposals.get) — your proposals (agent tokens see only their own), with per-item status: `pending`, `applied`, `stale`, `failed`, `skipped`. - The MCP resource `mzk://proposal/current` serves the same view. - CLI: `mozaik proposal list|status` ([`proposal`](/reference/cli)). ## Withdrawing and expiry [`proposal.withdraw`](/reference/commands/proposal.withdraw) drops your own proposal in `open`, `submitted` or `paused` — use it when you discover a mistake rather than submitting a correction on top. Open proposals idle out after [`proposalOpenIdleDays`](/reference/limits) days; submitted ones expire after [`proposalSubmittedDays`](/reference/limits) days; a revoked token's open proposal is withdrawn automatically. Expired or withdrawn proposals apply nothing.