From 3d0d75519a9d94d0ba50a638f3d655e0093bd7a2 Mon Sep 17 00:00:00 2001 From: siddharthd Date: Sat, 22 Aug 2026 16:33:56 +1000 Subject: [PATCH] wallet: the deterministic parse must beat the model's location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found by reading the backfilled rows rather than by a test. The precedence was subtitle -> MODEL -> descriptor, so the model's answer won wherever it had one, which is always. That defeats the entire point of parsing the descriptor positionally: the ledger got "SAN FRANCISOUS" for the only foreign merchant in the capture window, plus the padded "MELBOURNE AU", and the bare "Sydney"/"Perth" with their country codes dropped. Correct order is subtitle -> deterministic descriptor -> model. After the fix those rows read SAN FRANCISO US, MELBOURNE AU, Sydney AU, Perth AU, and a subtitle-derived place still wins where one exists. The test that should have caught this passed because its fixture omitted `location`, so the fallback chain was never exercised — every real interpretation carries one. Fixture now includes the model's actual mangled answer for that row, so the test fails if the order regresses. Re-ran the backfill on the corrected code: 21 transactions, $6,284.37 unchanged, 13 with a location. The 21 previously-written rows were deleted first rather than superseded, which is normally forbidden on transactions — checked before doing it that they carried zero splits, tags and overrides, being machine-written minutes earlier by this same lane with nothing yet attached. --- src/__tests__/integration/wallet-ingest.test.ts | 5 +++++ src/lib/wallet-ingestion.ts | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/__tests__/integration/wallet-ingest.test.ts b/src/__tests__/integration/wallet-ingest.test.ts index 42e5dac..d2c984e 100644 --- a/src/__tests__/integration/wallet-ingest.test.ts +++ b/src/__tests__/integration/wallet-ingest.test.ts @@ -223,6 +223,11 @@ describe("location", () => { await ingest(req({ ...breadworldBank, event_id: 75, amount: 42.44, merchant: "SP PEAKDESIGN", + // The model's own answer for this row, included because every real + // interpretation carries one -- omitting it is what let a wrong + // precedence order pass this test the first time, and ship + // "SAN FRANCISOUS" into the ledger. + location: "SAN FRANCISOUS", notif_body: "$42.44 paid from Mastercard ending...8032. SP PEAKDESIGN SAN FRANCISOUS", })); const [t] = await txns(); diff --git a/src/lib/wallet-ingestion.ts b/src/lib/wallet-ingestion.ts index 5d29f6e..aefeb36 100644 --- a/src/lib/wallet-ingestion.ts +++ b/src/lib/wallet-ingestion.ts @@ -139,9 +139,15 @@ export async function processWalletIngestion(ev: WalletEvent): Promise