A card notification is sent for an authorisation; a released hold never
reaches a statement. Txn 7951 (a $1,040.41 Airbnb hold, booking cancelled
the next day) sat in the reconcile queue forever and counted as spend.
Neither reconcile (needs a statement twin) nor supersede (needs a survivor)
can express it.
- transactions.voided_at + void_reason; CHECKs: reason mandatory,
statementless only
- EXCLUDE_RECONCILED_SOURCE excludes voided rows; reconcile queue,
findAutoMatches, both adoption helpers, annual charges and the manual
reconcile POST filter it; merge refuses a voided row on either side
- POST/DELETE /api/transactions/<id>/void; refuses reconciled, superseded
and settled-split rows
- "Never posted" button on /reconcile
- wallet-ingestion deliberately still sees voided rows, so a late twin or a
prompt_version re-post cannot rebook the hold
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>