Record GL trial-balance integrity check (audit #2)

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 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 17:48:48 -04:00
parent f804906481
commit f9039fc735
+32
View File
@@ -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 O1O9 + 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 #13/#5/#6/#8 remains unrecoverable (see top). Nothing merged to `master` yet.