be-ledger Health Audit
be-ledger Health Audit
Queries 8–13 October 2026prod 75725bemaster b4bd523
Audit · queries 8–13 October 2026

be-ledger health audit

Does the ledger database match the money we moved, and is be-ledger the ledger it should be? Read-only checks against prod-ledger-use2-sqlDb and its read replica, the dw-prod-gwiiag warehouse and Elastic, and a review of be-ledger's code at prod 75725be and master b4bd523 and of the services that post to it.

Verdict

Mostly yes: the ledger matches the money it moved. Since 1 March 2026 every balance follows from the journal: 0 breaks in 104.8M journal rows, and each of the 676,914 balances that names its last journal row matches it. Against Lithic's settlement report, 18.81M debit card transactions from April to 5 October 2026 match to the cent, −$653.37M net, and no settled transaction lacks a ledger flow. The 58,157 Galileo-era GA= flows that also carry Lithic transactions charge exactly Galileo's own settlement plus Lithic's final amount, −$1.69M, and hold nothing. On the credit-card program 741,801 of 784,953 Lithic transactions match, and 43,109 more moved no money on either side. Apart from Galileo-era rows, whose keys do not map to be-transactions, every journal row that moved money from April to September 2026 has a be-transactions record.

Where it does not match. 43 credit-card transactions were charged $1,642.59 less than Lithic settled, all last written between January and April 2026: settlement-report rows overwrote each cleared amount, a posting be-lithic stopped on 25 April 2026, and no such row has reached a card flow since (W46). On 5 Visa stand-in transactions the ledger equals Lithic's transaction record, $0.00, while Lithic's settlement report settles $287.73 of credits to 4 customers and a $1.99 purchase; only Lithic can say which is right (CL-27). Before March 2026, 23 balance breaks on 17 accounts net −$701.98, and on one of those accounts available has been $973.00 below its flows since 7 January 2026 (DATA-1). Nothing reconciles the ledger with Lithic automatically, so none of these was caught before this audit.

Accounts older than the journal. The oldest journal row is from 20 March 2025, and nothing records what an account held before its first row, so no account opened before then can be proven from the ledger's own records. 348,378 accounts opened before April 2025 differ from their flows by +$47.03M net: +$40.59M is the balance they held before their first journal row, and +$6.43M, on 66,927 accounts, is more than that. Replayed version by version on 231 accounts, the excess equals, to the cent, 1,060 breaks, journal rows at which the balance moved by a different amount than the row's flow. 1,055 are the first journal row of a flow written 20–31 March 2025, which is what a movement taken from the balance before the journal began looks like; of the 5 later ones, 3 come from balance writes of June and July 2025 with no journal row of their own (P27). Accounts opened in April 2025 show that the gap hides real errors: be-ledger took their first balance from the caller (DB-20), so on 1,100 accounts opened 1–8 April 2025 a deposit, fee or credit was counted twice, +$54,793.43 net. Postings consistent with be-transactions' reconcile handler took each back out of the balance by 4 July 2025 (CL-30), so the balances are right and the flows of those accounts are off by the doubled amount (Opening balances).

Holds and reserves. 1,078 flows on 864 customer accounts hold a reserve last written between March 2025 and March 2026 (P23). 54 of them keep −$1,226.57 of 47 customers' money unavailable; 48 of those are be-transactions reservations of 11–12 December 2025 that never left PreAuth (W47). 727, on 702 accounts, were released in the balance but not on the flow, so a later event or expiry on one would release its money a second time; 647 of them, written from May to July 2025, have the exact shape of the rows be-transactions' reconcile handler writes, which sets an account's reserve to zero by writing its negative onto a new flow (CL-30). On 110 accounts, 182 GA= holds are offset to the cent by credit reserves of the same shape from May and September 2025, and available is unaffected. On the other 38 accounts whose reserve differs from their flows, each difference is traced to the journal rows, balance writes with no journal row or direct flow updates that caused it (P4b, P26, P28). Another 845 flows sit on the empty account id with +$20,739.61: 30 carry a PMA= credit whose journal row names a customer account, and 815 have no journal row (Holds, Flows with no account).

It is not yet an excellent ledger. Prod publishes a transfer's debit event before the transfer commits, so a rolled-back transfer still reaches statements, audit and the warehouse: 1,595 phantom events since February, −$1.72M of debits that never happened (EV-1, fixed on master). The database enforces no uniqueness, no references and no double entry, corrections are written straight into the money tables with no record of them (DB-11), and three callers can skip a debit on retry.

0
breaks between balances and the journal
104,773,210 journal rows since 1 March 2026
18,811,746
debit card transactions match Lithic's settlement report to the cent
April to 5 October 2026, −$653.37M net; none missing; 5 stand-in transactions differ, where Lithic's own records disagree (CL-27)
58,157
Galileo-era GA= flows charge exactly Galileo's settlement plus Lithic's
−$1,689,088.96 to the cent; none holds money
+$47.03M
net difference between 348,378 older balances and their flows
+$40.59M was held before the oldest journal row, with no opening entry; +$6.43M on 66,927 accounts goes beyond it
43
credit-card transactions charged less than Lithic settled
$1,642.59 on 39 accounts, all from January to April 2026
54
stale holds keep customers' money unavailable
−$1,226.57 on 47 accounts; 48 are be-transactions reservations of December 2025 left in PreAuth
1,595
phantom ledger events since February
−$1.72M of debits that never happened (EV-1)

Does it match the money?

Data consistency 8 open

What is wrong in the data today, kept apart from the code that caused it. Since March 2026 the ledger's balances agree with its journal; these items are where the ledger, or a copy built from it, does not match the money, or where a measured difference has not been traced to its cause.

ItemScopeMoneyStatus
Event copies that differ from the journal1,595 phantom events, one published twice; 13 lost and 2 doubled; 2 rows missing in the warehouse−$1,722,060.87 of debits that never happened, in statements, audit and the warehouseOpen: deploy, then clean up
Stale flow reserves and account reserves1,078 flow reserves on 864 accounts, March 2025 to March 2026; reserves differ from flows on 740 accounts−$1,226.57 unavailable to 47 customers; −$20,610.06 released in the balance but open on the flowOpen
Balances with no opening entry348,378 accounts opened before April 2025; 1,111 opened in April 2025+$40,585,634.28 recorded only in balances; +$6,434,523.47 on 66,927 accounts beyond their opening; +$55,186.63 on the April 2025 accountsOpen: partly traced
Credit-card transactions charged differently from Lithic43 transactions on 39 accounts, January to April 2026$1,642.59 charged less than Lithic settled: $1,571.47 on 40 settled, $71.12 credited on 3 voidedOpen: needs a decision
Flows on the empty account id845 flows, the newest from November 2025: 30 with a credit row naming a customer, 815 with no journal row+$20,739.61 on no customer's balance; the 30 credits, +$4,749.55, name their accountsOpen: 815 owners not traced
Visa stand-in transactions where Lithic's two records disagree5 transactions on 5 accounts, 25 July and 31 August 2026Ledger at 0, as Lithic's transaction record; its settlement report settles $287.73 of credits and a $1.99 purchaseOpen: ask Lithic
Balance breaks before March 202623 rows on 17 accounts, November 2025 to February 2026Net −$701.98; one account $973.00 below its flowsOpen: cause unknown
Accounts with no balance row66 accounts, auto-created 3 February 2026No money; an authorisation on one is approved for any amount (CL-1)Open

All data items, including the ones checked and found correct

Code issues 52

Defects in be-ledger and the services that post to it, by severity.

Where to start

Data corrections

  1. Clean the phantom events out of statements, audit and the warehouse, after the deploy
    1,595 phantom debit events, −$1.72M, sit in copies that customers and finance read. A cleanup before the deploy would be overtaken by new ones.
  2. Clear the stale flow reserves without moving money twice
    54 holds keep −$1,226.57 of 47 customers' money unavailable; 48 are be-transactions reservations of December 2025 left in PreAuth, and 2 are transfers be-transactions reversed. 727 holds on 702 accounts are already released in the balance, so releasing them the normal way would credit $20,610.06 a second time; they need a correction on the flow only. 182 GA= holds and their 110 offsetting credits net to zero per account and close together.
  3. Decide on the 43 credit-card transactions with be-credit
    $1,571.47 under-charged on 40 transactions and $71.12 credited on 3. A ledger correction alone would leave LoanPro wrong.

Code fixes

  1. Deploy master to prod
    Stops new phantom events (EV-1) and lost events (EV-2); every capped transfer in prod adds a phantom today. The fix is already on master and stage.
  2. Reconcile the ledger against Lithic every day
    Nothing compares the ledger with Lithic today. The 43 credit-card transactions, and the 5 stand-in transactions on which Lithic's own records disagree, were found only by this audit.
  3. Measure and fix the retry paths that skip a debit
    Unmeasured. If they fire, Majority funds the payout, plan period or top-up.

The full fix plan, both tracks in order

Not measured or not traced

Not measured: CL-2, CL-3 and CL-8, which need the be-pspfunding, be-phoneplan, be-mtu and prod-wallet databases. Measured but not traced to a cause: whether the March 2025 first rows behind the difference beyond the opening, 1,055 of them on the 231 accounts replayed, were taken from the balance before the journal began, which the ledger alone cannot show; and whose money the 815 flows on the empty account id with no journal row hold (Flows with no account).