From f9039fc7356fe6b3c581fb6a6b4d3d13377c6642 Mon Sep 17 00:00:00 2001 From: Scott Pouliot Date: Sat, 20 Jun 2026 17:48:48 -0400 Subject: [PATCH] Record GL trial-balance integrity check (audit #2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Empirical per-company trial-balance net on stored CurrentBalance. Both tenants imbalanced, but from pre-existing data, not this session: - Demo: $89.5k opening-balance-without-equity (demo artifact) + $3,153.63 postings. - SCP: $3,079.52, all postings. Forensics: AR reconciles (invoices−payments), but Revenue has $0 GL movement (24 header-only invoices, 0 line items → no per-item revenue credit) and payment-side bank debit never posted. One-sided postings from imported/header-only docs + null offset accounts skipped by AccountBalanceService — same class as O2/O6/O7/O8. Conclusion: this session's changes did not introduce the imbalance and in fact prevent the bug class going forward. Remediation options documented (not auto-applied — SCP is live data). Co-Authored-By: Claude Opus 4.8 --- docs/ACCOUNTING_AUDIT.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/ACCOUNTING_AUDIT.md b/docs/ACCOUNTING_AUDIT.md index be83e51..2b66766 100644 --- a/docs/ACCOUNTING_AUDIT.md +++ b/docs/ACCOUNTING_AUDIT.md @@ -246,8 +246,40 @@ deposit account. **No ledger-drift bugs found.** Notes: always consistent with the displayed type. A read-only sweep of the dev DB (109 accounts) found **0** existing mismatches, so no repair tool was needed. +### 2026-06-20 — GL trial-balance integrity check (audit "#2") +Ran an empirical per-company trial-balance net on stored `Account.CurrentBalance` +(`SUM(debit-normal) − SUM(credit-normal)`, which must net to 0 for balanced books). **Both tenants are +imbalanced**, but the cause is pre-existing data, **not** this session's changes. + +- **Demo Company:** net Dr **$92,653.63** = **$89,500 opening-balance** entry without an offsetting equity + line (normal demo-data artifact) + **$3,153.63** from postings. +- **SCP Powder Coating** (opening balance $0, clean start): net Dr **$3,079.52**, entirely from postings. + +**Root cause (forensics on SCP):** AR reconciles correctly (~invoices $21,496 − payments $18,314 ≈ stored +$3,079), so AR posted on both sides. But **Revenue has $0 GL movement** (the 24 invoices are header-only — +**0 line items** — so the per-`InvoiceItem` revenue credit never fires) and the **payment-side bank debit +never posted** ($0 bank delta from 22 payments). This is the classic one-sided posting from +(a) imported/header-only invoices and (b) postings to unconfigured (null) offset accounts, which +`AccountBalanceService` silently skips. Same architectural class as O2/O6/O7/O8. + +**Conclusion:** this session's work (default GL accounts, deposit guard, money-account guards, tenant sweep) +**did not introduce the imbalance** — those changes are read-path + validation + defaults and actually +*prevent* this bug class going forward (new invoices now fall back to a default revenue account; deposits/ +payments are guarded against null money accounts). The existing imbalance is legacy/imported data. + +**Remediation options (owner's call — not auto-applied; SCP is live company data):** +- `Recalculate Balances` re-derives from source docs but will **not** conjure revenue for header-only + invoices (no line items to credit), so it won't fully fix SCP on its own. +- Durable fix: the **JournalEntry single-source** refactor (`docs/ACCOUNTING_LEDGER_REFACTOR.md`) forces every + event to post balanced lines. +- Historical cleanup: correcting journal entries (or backfilling revenue/bank accounts on the imported docs + then recomputing) — a deliberate data-remediation task. +- Worth considering: surfacing this trial-balance net as a built-in "GL Health" indicator so drift is visible. + ## Status **All findings O1–O9 + the read-path sweep are resolved** on `dev` (O9 by policy decision — expense at purchase — needing no code change). The optional structural follow-up is the JournalEntry single-source refactor (`docs/ACCOUNTING_LEDGER_REFACTOR.md`), which would prevent the O2/O6/O7/O8 bug class from recurring. +The 2026-06-20 trial-balance check confirmed a pre-existing GL imbalance from legacy/imported one-sided +postings (not from recent changes) — see above for remediation options. Original audit numbering #1–3/#5/#6/#8 remains unrecoverable (see top). Nothing merged to `master` yet.