# Single-item financial correction and review-action release audit

Use this read-only review pattern when a financial inbox adds duplicate decisions, card-settlement handling, or post-confirmation category corrections.

## Bind and separate the contracts

1. Freeze the exact SHA, branch, tracked changes, untracked files, schema version, backend/frontend collected counts, and known responsive finding.
2. Separate predecessor evidence from the new contract. Existing batch-confirm, duplicate detection, cursor, or audit tests are regression evidence only; they do not prove a new item-specific action.
3. Trace each user-visible action through frontend type/client, route model, service, fingerprint/baseline, write transaction, durable relation, canonical financial-effects reader, audit, refreshed counts/version, and responsive UI.
4. If the authoritative acceptance request only exists in session history, retrieve the complete original message rather than relying on truncated search snippets; clearly label any provisional decomposition.

## High-value architecture probes

### Item capability versus group mutation

- Seed two open candidates with the same classification.
- Preview and confirm one immutable item token.
- Prove only that candidate, its exact durable relation/transaction, and one bounded audit event change.
- The sibling must remain byte-equivalent and open.
- Legacy classification-group endpoints must reject item-specific duplicate, ignore, settlement, and correction actions or be unreachable from the UI.
- Never offer a row-menu action that merely opens an informational message. Every offered action must resolve to an executable server-derived capability.

Bind Preview to the item token, internal candidate identity, candidate revision, action, selected original/account/category, review data version, complete baseline, and contract version. Confirm must acquire the write lock, reconstruct the capability, revalidate all fields, and return `409` with zero writes on any mismatch. Identical replay returns the original decision/audit identity; altered replay conflicts.

A display token derived as an unkeyed truncated hash of a candidate ID may identify the row, but is not sufficient authorization by itself. Use the repository's private capability-token pattern where the decision must survive a re-preview.

### Duplicate workflow

Test two distinct capabilities:

- **Keep as independent:** exactly one economic event remains, a compatible category is selected, review closes, and audit records the explicit non-duplicate decision.
- **Exclude as duplicate:** requires one concrete eligible original; the preview displays sanitized date/amount/source and reason classes for both; Confirm establishes a unique `duplicate_of` relation, retains source rows, and gives the duplicate zero incremental financial effect.

Counterprobe self-links, absent or terminal originals, merely similar merchant/history evidence, amount/date/source mismatches, competing originals, and reuse of one duplicate in multiple relations. Reopen must auditably revoke the effective duplicate decision/link, restore exactly one review item, change cursor/data version, create no transaction, and be idempotent.

### Credit-card settlement

A merchant label alone is not a settlement. Bind deterministic evidence from amount, currency, known bank/card accounts, bounded date/billing window, and a unique counterpost where available. Preview shows debit account, card source, payment amount, counterpart status, attributable purchase total, before/after expense impact, and explicit additional expense impact zero.

- Complete purchase coverage: settlement is neutral; purchases remain the expense events exactly once.
- Missing or ambiguous counterpost/purchase coverage: fail closed to `partial`, require explicit confirmation, and show the missing import as the next step.

Trace the durable settlement relation through every canonical financial-effects, overview, budget, category, forecast, export, and detail reader. Relabeling a candidate without reader coverage is not acceptance.

### Own-account transfer correction

A user-selected transfer is a bounded item correction, not permission to neutralize arbitrary spending. The server advertises it only when the observed row has a known active source account, canonical currency, ordinary signed income/expense semantics, and at least one distinct eligible own account. The browser receives opaque account tokens plus masked labels, never database IDs.

Preview binds the source item, row/data versions, signed direction, and selected counterpart. Confirm revalidates eligibility under the lock and atomically creates one negative leg, one positive leg, one durable transfer relation, one candidate update, and one audit event. The imported candidate links to exactly the observed leg; the opposite leg is a schema-permitted system record. Prove unchanged income/expense/net, one logical neutral volume, exact replay identity, and zero-write rejection for same-account, inactive, stale-token, foreign-currency, and reversed-direction probes.

### Confirmed-category correction

Do not expose a legacy direct update helper. Add a fingerprint-bound Preview → Confirm boundary that:

- shows old/new category and both category deltas;
- preserves amount, currency, source lineage, and total financial effect;
- requires an active category compatible with immutable income/expense semantics;
- redirects transfers, settlements, duplicates, linked refunds, and receipt detail to dedicated workflows;
- applies linked-refund category changes to the eligible origin when that is the canonical contract;
- invalidates/reloads month, year, category, budget, forecast, review, and cursor/data-version surfaces;
- writes old/new category, actor, time, expected/actual writes, and contract version in the same transaction.

Inject a failure after the domain update but before audit and prove complete rollback, both standalone and inside a caller-owned transaction/savepoint.

## Regression matrix minimum

Cover at least:

1. one token among two same-classification rows;
2. legacy group mutation impossible;
3. preview full-digest read-only;
4. stale token/revision/data-version/baseline/target/action all return 409/no-write;
5. identical and altered replay;
6. keep-independent counts exactly once;
7. duplicate requires and binds an original, zero effect, source retention;
8. duplicate reopen;
9. complete and incomplete card settlement;
10. special cases cannot use ordinary confirm/recategory;
11. category type validation and immutable monetary/source fields;
12. canonical aggregate reconciliation before/after correction;
13. stale review and transaction cursor rejection after mutation;
14. bounded/redacted audit and API responses;
15. browser-backed 1440/820/390 geometry, 44 px targets, keyboard/focus/Escape, zero overflow/errors.

## Migration and release-gate checks

If durable correction/settlement structures are added, require an explicit N→N+1 migration from a real previous-schema copy—not only a fresh schema or a much older aggregate upgrade. Verify pre-existing business digest, `integrity_check`, empty `foreign_key_check`, exact FKs/indexes/triggers, independent backup/restore equality, and second-run no-op. Audit whether the recorded checksum covers executable migration logic rather than only a label.

Inventory CI independently:

- compare collected backend/frontend counts with labels and numeric floors;
- ensure the frontend has deletion protection, not only process exit;
- ensure aggregate local gates include the custom migration script and Ruff;
- widen fixed Ruff path lists to cover every new module/test/workflow;
- add a real browser gate because jsdom cannot prove viewport geometry;
- distinguish restart helpers from exact-SHA deployment/backup/migration/rollback automation.

## Evidence discipline

Run only synthetic/disposable writes during review. Production UAT for candidate decisions remains Preview-only and must be bracketed by complete database/table digests plus strict side-effect sentinels. Record corrected invocation paths as environment notes, not durable tool-failure rules. Recheck and clean the worktree after collection/build tools because read-only audits can still generate untracked lock or cache files.
