Skip to content

Forensic audit

Every scrape path (browser + api-direct) emits a per-account audit line during .post. The line is the primary debug surface for "did the scrape actually pull transactions for this account?".

Source src/Scrapers/Pipeline/Mediator/Scrape/ForensicAuditAction.ts

What it looks like in pipeline.log

--- Account ***6789 | 42 txns ---
--- Account ***5432 | 0 txns ---
--- Account ***9981 | 18 txns ---
Element Source
***NNNN maskTail4(accountNumber) — last-4 of the discovered iter id
N txns scrape.accounts[i].txns.length

The line is emitted regardless of underlying transport — browser banks call it from SCRAPE.post, api-direct banks call it from API-DIRECT-SCRAPE.post. Both paths produce the same line shape so triage scripts work cross-bank.

Why it's load-bearing

When a scrape result comes back "empty", the first question is always: did we get 0 transactions per account, or 0 accounts entirely? The forensic audit answers it directly:

What you see What it means Where to look next
No --- Account --- lines 0 accounts discovered ACCOUNT-RESOLVE — discovery returned empty
--- Account *** | 0 txns --- for one account That account is genuinely empty for the date range OR scrape miss Compare with scrape.post.empty-gate.<verdict> event
--- Account *** | 0 txns --- for every account Real scrape miss OR legitimate "no transactions this month" Consult network.countSuccessfulResponses() via empty-gate heuristic
--- Account *** | N txns --- with N > 0 Scrape worked for that account OK

Cross-reference with BALANCE-RESOLVE

The forensic audit reports txn count, BALANCE-RESOLVE separately reports resolved balance. Together they tell the full per-account story:

--- Account ***6789 | 42 txns ---
balance.miss account=***6789 message=balance unresolved — fallback to 0

→ 42 transactions captured fine, but the balance fetch for that bank account failed (quarantined). The account still ships with balance: 0 and the txn list. Open a bug if the bank's balance endpoint truly should have returned data.

Pre-v6 behavior

Before the v6 BALANCE-RESOLVE rewrite, this audit line was only emitted from SCRAPE — api-direct banks had no equivalent. v8.4 adds the same call to ApiDirectScrapePhase.post so both paths produce the line. See Architecture → BALANCE-RESOLVE (v6).