# Input-bound offline review

[Editable TSV sheets](review-sheet.md) now provide an export/edit/apply/replay path without hand-written decision JSON. They bind the originating bundle and verify all conflict evidence; structural choices require a fresh sheet for newly exposed cells.

A bare decision array names conflicts but has no revision information. `ReviewBundle` owns all three parsed CSV snapshots, the ordered key selection and cumulative decisions. It recomputes conflicts on import/replay; it never trusts a persisted preview or accepts unused decisions.

Review also owns optional [source row ordering](ordering.md) and [explicit retained-column lineage](lineage.md). `review` accepts `--row-order ORDER` and `--columns FILE`; `review-resolve` retains them and `replay` rejects overrides. Non-default ordering uses seven-field `review-2` (adds `row_order`); lineage uses eight-field `review-3` (adds `row_order` and `column_lineage`). Original CSV schemas remain in the bundle. Legacy `review-1` is still supported and exported for default plans without lineage.

[Retained-row lineage](row-lineage.md) adds `--rows FILE`. Its nine-field `review-4` includes row_order/column_lineage/row_lineage and original source identities. Decisions use output keys, while replay compares the original snapshots. Older bundle exports retain their format when row lineage and column evolution are absent.

[Column evolution](column-evolution.md) adds `--column-evolution FILE` for explicit rename/delete correspondence. Its ten-field `review-5` extends review-4 with `column_evolution`, retaining the original schemas and explicit branch absences. Resolve/revise/combine/sheets preserve this policy; replay rejects overrides. Retained `ColumnLineage` and legacy bundle versions keep their existing contracts.

```text
moon run cmd/main -- review BASE.csv OURS.csv THEIRS.csv --key id
moon run cmd/main -- review-resolve DRAFT.json DECISIONS.json
moon run cmd/main -- replay BASE.csv OURS.csv THEIRS.csv --key id --review REVIEWED.json
moon run scripts/review-demo.mbtx
```

Save each command's stdout as a **new UTF-8 file**, separately from its inputs. `review` and `review-resolve` exit 0 when a valid bundle was produced, even if incomplete. `replay` exits 1 for pending conflicts and 2 for input/decision errors. With `--report`, replay prints diagnostics/evidence rather than CSV. Structural review may expose cell conflicts: export the updated bundle and use `review-resolve` again.

Library API: `ReviewBundle::from_plan`, `to_json`, `from_json`, `plan`, `resolve`, `replay`. The guard compares **all cells, headers, row/header order and ordered key selection**, including data unrelated to conflicts. It accepts CSV quote style, LF/CRLF and BOM changes after parsing. Row/header reordering requires a new review, even though merge identity itself is order-independent.

`ReviewBundle::revise` and CLI `review-revise` now explicitly replace/revoke recorded decisions. They recompute applicability and preserve earlier bundles; inapplicable dependent choices require explicit revocation, rather than silent removal. Newly exposed cells remain a second review phase. [Revision guide](revision.md) covers the strict edit schema and runnable workflow. Bundles store current choices, not an authenticated history.

Format `mntablemerge/review-1` has exactly six fields: format/base/ours/theirs/key/decisions. Snapshots are canonical CSV strings. Unknown fields/versions, duplicate JSON keys, wrong types, invalid snapshots/identities, irrelevant/duplicate decisions and nesting beyond 64 are rejected. Import/export is limited to 16,000,000 UTF-16 code units including escaped envelope content; export refuses oversized bundles. Returned JSON may be edited; importing revalidates it.

The bundle **does not authenticate the reviewer or detect deliberate alteration of the bundle itself**. It binds replay to its supplied snapshots. Treat files as copies of their input data. Signatures, compact hashed bundles and encryption are not implemented.

The offline helper uses pinned OurAirports fixtures, completes a missing intersection, verifies expected CSV, rejects changed input and checks byte-for-byte input preservation. It requires no network/private infrastructure.
