# Revert a journaled table operation by its `migration_id`. Refused (nothing written) when any

`POST /datanotes/operations/undo_migration/` (operation `undo_migration`)

Revert a journaled table operation by its `migration_id`. Refused (nothing written) when any
touched note changed since; the conflicts are listed. Also refused when the revert would leave rows
breaking a CHECK that follows links or a `ref_where` / `ref_by` (rows it writes, or rows that link to
them), listed like the refusals of other writes with the way out (fix the row, or drop the rule).
The rules are those of the schema the revert puts back: undoing a rename_value / rename_column
puts the old names back with the rows, and a rule the revert puts back must hold on every row.
A `batch` is checked as a whole first (nothing written when refused), then reverted operation by
operation, from the last; when one finds a note changed since, those after it stay reverted
and a retry skips them. An undo is journaled like any operation: undoing it (the
`migration_id` of its answer; `undoes` names the operation undone) is a redo, whatever the operation (a batch included). The
revert is a new version (`UNDO`) in the transaction log; undoing a table's rename or move takes
its whole log back to the old name, the versions made under the new one included.

The schema changes only through operations like this one: never edit metastore.yaml by hand (no validation, no undo).

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `X-Datanotes-Actor` | header | `string` | no | JSON: on whose behalf the write is made, recorded in the journal (`harness`, `model`, `session`). |

## Request body

`application/json`, required

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `migration_id` | `string` | yes |  |  |

## Responses

| Status | Description | Body |
| --- | --- | --- |
| 200 | Done. | `object` (application/json) |
| 400 | Bad input: the body is not a JSON object, or an argument is unknown, missing or of the wrong type. | `Error` (application/json) |
| 401 | Missing or wrong bearer token. | `Error` (application/json) |
| 403 | A named token beyond its permissions (the engine's administration, tables outside its `write` patterns, schema changes without `ddl`). | `Error` (application/json) |
| 404 | Unknown table, view, migration, note or folder. | `Error` (application/json) |
| 409 | Undo refused (later changes depend on it, or it was undone already): nothing written (a batch is checked as a whole first; when one of its operations then finds a note changed since, the operations after it stay reverted: `touched`, and a retry skips them). Same body as 200, with `ok: false`. | `object \| AmbiguousName` (application/json) |
| 500 | Unexpected error (`{error}`), or a write that failed partway and could not be rolled back: `rolled_back: false`, `failed` lists the files left (undo_migration on `migration_id` retries the rollback). | `object \| Error` (application/json) |

The schemas named here are in [openapi.json](https://datanotes.dev/openapi.json) (`components.schemas`).
