Watch one row move: Pending → Matched*
*Matched means invoice identified on the Recon+ page only. It does not mean the saved Pending result or Xero bank feed changed. This is a proposed display transition, not a live transaction.
CURRENT SAVED RESULT
Month window missed the invoice
Saved state: PendingEXPECTED PAGE DISPLAY*
Reference + contact + exact cents verified
Page label: Matched*Unchanged underneath: saved row Pending · action null · Xero Payment not posted · Xero bank-feed OK not clicked.
The actual decision tree
- Bank receipt arrives → saved source identity + reference
- A / CANONICAL RUNGet Xero sales invoices by selected invoice date
- Older invoice outside period → absent from
sales_report - SQL reads
_sales→ Sales Not Found → saved bank row Pending - Support-only trace → bank receipt not enqueued
- Older invoice outside period → absent from
- B / SEPARATE LOCAL PAGE READExtract unique NPP reference from saved bank source
- Bounded Xero candidate search beyond month → verify number + tenant + contact + currency + exact cents + uniqueness
- Pass → read-only invoice identity on page; fail or unavailable → no identity claim
- A / CANONICAL RUNGet Xero sales invoices by selected invoice date
Outside both branches: Xero bank-feed OK, new Payment, or confirmed bank reconciliation. Neither branch performs those actions.
First divergence: the invoice’s date is outside the selected sales window. The SQL matcher only sees invoices supplied to its current run; it cannot search the older invoice by itself.
01 / INPUT SOURCE
Start with the bank line, not a guessed invoice.
The bank statement supplies the original row ID, date, amount, narration and NPP reference. Xero sales and optional uploaded invoice files form a separate pool. Cin7 is order evidence, not an automatic allocation.
The selected run omitted it. An uploaded row in another saved run is not this run’s authoritative Xero invoice.
02 / DATE GATE · FIRST DIVERGENCE
The date filter limits what SQL can see.
The run route calls getXeroSalesInvoices with invoice Date bounds. AUTHORISED or PAID invoices outside the selected sales window are not returned. The current-run sales_report therefore lacks this older invoice.
The invoice date precedes the selected period. A separate exact Xero query can return it, but that query is not the canonical run fetch.
03 / CANONICAL SQL
A matcher cannot select an absent sales row.
query_modular.sql constructs _sales from the current run’s sales_report. Its direct, payee and subset rules need qualifying invoice rows and amount checks; they cannot invent an older invoice.
The saved bank row remains Pending without a linked sales ID. This is missing input, not proof that the Xero invoice API failed.
04 / LATER TRACE
The support-only checkpoint does not include this bank row.
The existing invoice-link trace enqueues support receipts. The standalone receiving-bank NPP credit was absent from its item list, so retrying that trace does not search the bank line.
Cin7 checks on support references are not a bank-line fallback and do not automatically feed SQL.
05 / LOCAL READ-ONLY PATH
An exact reference can discover the older invoice.
Separate local worktree source loads the saved bank line on a GET. Only one unambiguous Pending source in the selected client, tenant and bank account may yield an NPP reference. A bounded Xero SearchTerm lookup then searches invoice candidates beyond the run month.
This is not a canonical SQL rerun. It is a read-only page projection in local source, not proof of a deployed feature.
06 / CANDIDATE CHECKS
An API result is a candidate, not a match.
Require a matching full invoice-number prefix, unique InvoiceID and contact ID, ACCREC status, same currency, compatible bank-name prefix, exact cents and no competing bank or invoice owner. Reject ambiguous results; provider errors mean unavailable.
If any check fails, leave the saved row unchanged. Contact likeness or equal amount alone never selects an invoice.
07 / PRESENTATION BOUNDARY
Invoice identified is not bank feed reconciled.
If all gates pass, local page code can show the invoice number, contact and Xero PAID status in a read-only chip and drawer. The saved row retains Pending, action=null and no new Xero Payment; bank-feed reconciliation is independent.
The user may see an invoice identified on Recon+ without claiming that Xero’s bank feed is reconciled or posting another Payment.