# Item-specific corrections and additive SQLite migration gates

Use this note when a transactional review inbox adds row-level corrections, duplicate decisions, neutral settlement handling, or category changes around an existing ledger.

## Item-specific correction contract

- Bind Preview to an opaque immutable item/transaction token, the current dataset version, the row version, a row baseline, the exact action, and every selected target such as category or retained original.
- Confirm recomputes the Preview under the write lock and accepts only the unchanged fingerprint. A stale dataset, row, category, original, or relation returns conflict before writes.
- Idempotent replay is keyed by the accepted fingerprint and returns the original audit/result without another mutation.
- A duplicate exclusion must validate a concrete retained canonical row. Amount/date/currency compatibility alone is insufficient: require deterministic merchant/source identity evidence and expose both rows plus reasons in Preview.
- “Not a duplicate” materializes exactly one financial transaction and changes the candidate to an ordinary post-decision classification so later safe category correction remains possible.
- A neutral card settlement uses a dedicated immutable relation, no category, zero income/expense/budget effect, and deterministic account/counterpost matching. Missing or incomplete card data yields `partial` and explicit acknowledgement; unique counterpost alone does not prove complete purchase coverage.
- An own-account transfer is not a relabelled expense. Preview binds the candidate side plus an opaque eligible-counterpart account token and displays sanitized from/to accounts. Confirm writes one balanced negative/positive transaction pair and one durable transfer relation atomically, links the source candidate to exactly one leg, classifies the synthetic counterpart as a permitted system row, leaves income/expense/net unchanged, and returns the same transfer/audit identities on replay. Revalidate active accounts, distinct identities, currency compatibility, and signed direction under the write lock.
- The review read model exposes only executable capabilities and the exact eligible targets needed by those capabilities. The UI renders each action independently from `available_actions`; it must not infer support from broad classification labels or display sibling buttons when only one action is authorized.
- Category correction is a separate Preview→Confirm contract. Revalidate category type, preserve amount/currency/source, redirect linked refunds to the origin, and fail closed to dedicated workflows for transfers, settlements, duplicates, and receipt details.
- Remove legacy direct-update calls from every reachable UI. Listing a new safe drawer is insufficient if another page or store still exposes a one-click category write.
- Read-only deployments may allowlist only Preview POST paths. Confirm paths remain blocked.

## Additive SQLite migration rehearsal

1. Create an owner-only online backup and an independent restore copy.
2. Record the pre-migration table set and exact pre-migration columns before applying the migration.
3. Digest existing business data using only those frozen old columns. An additive column with a default must not make unchanged old data look mutated.
4. Exclude migration bookkeeping and known compatibility scratch tables from business-data equality; verify them separately. Never decide exclusions after seeing a mismatch.
5. Apply the migration twice to prove idempotency.
6. Digest the same frozen columns afterward; require no changed existing business table.
7. Verify new-column defaults for every old row, new relation tables empty, target schema version, `integrity_check=ok`, and zero foreign-key violations.
8. Run production-shaped Preview calls against the restored copy and require both connection-level zero changes and unchanged database-file digest.

## Regression probes

- Two same-classification review rows: confirming one cannot mutate the other.
- Forged token/target with a valid fingerprint conflicts.
- Same amount/date but unrelated merchant cannot become a duplicate original.
- Keep-not-duplicate writes once, replays idempotently, and remains safely recategorizable.
- Duplicate exclusion writes no second ledger row, has zero financial effect, and can be audited/reopened.
- Complete and partial card-settlement fixtures reconcile purchase coverage and stay neutral.
- Own-account transfer Preview binds one eligible counterpart; Confirm creates exactly two opposite-signed legs and one relation, preserves income/expense/net, increments logical neutral volume once, and replays without extra rows. Counterprobe same account, inactive account, stale account token, currency mismatch, reversed incoming direction, and a synthetic counterpart source type rejected by the ledger CHECK constraint.
- Capability/read-model parity: for each listed item, invoke every advertised action and prove no hidden action is rendered; when only keep or only exclude is eligible, the sibling button is absent.
- Category change preserves global totals, changes only the intended category, redirects refunds, and blocks every special semantic type.
- Every visible transaction entry point passes an opaque transaction token to the shared drawer; no reachable component invokes the legacy direct update endpoint.
