Recon+ / decision hierarchy

Watch one row become Matched*.

One bank receipt. Two different questions: does the run match it? and can the page identify an older invoice? The existing run stops at the first. A separate local read-only lookup addresses the second.

CURRENT SAVED RUN · invoice absent → PendingSEPARATE LOCAL READ PATH · reference + identity checks → page display onlyOUTSIDE BOTH PATHS · Xero bank-feed OK is a human action

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.

Complete · proposed page match; press Play to see the row move

Unchanged underneath: saved row Pending · action null · Xero Payment not posted · Xero bank-feed OK not clicked.

The actual decision tree

  1. Bank receipt arrives → saved source identity + reference
    1. A / CANONICAL RUNGet Xero sales invoices by selected invoice date
      1. Older invoice outside period → absent from sales_report
      2. SQL reads _sales → Sales Not Found → saved bank row Pending
      3. Support-only trace → bank receipt not enqueued
    2. B / SEPARATE LOCAL PAGE READExtract unique NPP reference from saved bank source
      1. Bounded Xero candidate search beyond month → verify number + tenant + contact + currency + exact cents + uniqueness
      2. Pass → read-only invoice identity on page; fail or unavailable → no identity claim

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.

All 7 layers are visible

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.

Does this run contain the full older invoice?NO · SAVED RESULT

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.

Invoice in the current run’s Xero or uploaded sales pool?NO · DATE WINDOW

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.

Qualifying invoice available to canonical SQL?NO · SALES NOT FOUND

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.

Does the later trace inspect this bank receipt?NO · OUT OF SCOPE

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.

Is the bank reference unique and eligible for bounded lookup?ONLY IF SOURCE-BACKED

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.

Do all identity and uniqueness checks pass?YES → IDENTIFIED ONLY

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.

Does the display prove the later bank credit paid this invoice?NO · OWNERSHIP UNKNOWN

The user may see an invoice identified on Recon+ without claiming that Xero’s bank feed is reconciled or posting another Payment.