Backfill invoice detail.payment.tx[] reverse trail from existing bank-tx matches
Why (owner, 2026-06-23)¶
T-078 (PR #763) added detail.payment.tx[] on invoice docs β the reverse
audit pointer that lets an invoice show which bank tx paid it, even read in
isolation. It's the companion to the canonical gl['4000'] / gl['4001']
allocation on the bank-tx side. The runtime match/unmatch paths maintain it
going forward, but every match written BEFORE T-078 shipped never got the
reverse pointer β so those invoices had an empty detail.payment.tx.
Surfaced during the tx 9zVOyZ6AggDJaSpKqD25 diagnosis (its two invoices
ERL-2025-010-0423 / ERL-2025-019-0624 both read empty). Owner asked to
backfill the trail across all pre-T-078 matches.
What shipped¶
scripts/backfill-invoice-payment-tx-trail.tsβ walks every bank tx (tebs-erlaccounting/transactions/entries), decodes each via the canonical V1 adapter (readTransactionAsV1β no logic drift vs runtime), and for each matched invoice / coaching invoice stamps the txId into the invoice's trail viaFieldValue.arrayUnion: Β· Project invoices (tebs-erl):projects/{year}/projects/{projectId}/invoice/{invoiceNumber}βdetail.payment.txΒ· Coaching invoices (tebs-mel):Students/{abbr}/Sessions/{sessionId}βinvoice.detail.payment.txPaths/fields mirror the runtime helpers (syncProjectInvoiceTxTrail/syncCoachingInvoiceTxTrail). Backup-first, idempotent, halt-on-error,--dry-run,--skip-coaching.- Run on prod 2026-06-23: 46 trail additions β 31 project + 15 coaching,
0 invoices not found, 0 sessions not found. Re-run dry-run confirms
idempotency (0 remaining). Backups under
scripts/migration-backups/(gitignored).
Scope / safety¶
Additive audit data only β does NOT touch gl allocations, status, amounts,
or display. The bank-tx side stays canonical; this only restores the reverse
pointer. arrayUnion + pre-read dedup β safe to re-run.
Verification¶
- Dry-run before apply: 46 planned, all docs/sessions resolved.
- Apply: 46 written.
- Re-run dry-run: 0 needed (idempotent).
- tx
9zVOyZ6AggDJaSpKqD25now appears in bothERL-2025-010-0423andERL-2025-019-0624trails.
Log¶
- 2026-06-23 created + shipped. Script written to repo convention (getAdminFirestore via .env.local in prod); run here by mapping the session's GOOGLE_ creds β FIREBASE_ADMIN_. Backfill applied to prod. Source: Accounting (Diagnostics) Β· https://claude.ai/code/session_01G58Y71noihrYCDEDMexmea
Commit index (backfilled 2026-07-01, best-effort Β· Coaching (Diagnostic))¶
Candidate related commits, auto-backfilled from git on main: commits whose message references this task's UID or a PR number it cites. Not verified β this squash-merged history can't yield a precise per-task list, so rows tagged (mentions only) name the task in passing (may be tangential) and untagged work commits may be missing. Treat as a starting point: verify, prune tangential rows, and append any real ones per the AGENTS.md "record every related SHA" policy.
- (no git-discoverable commit references this UID or its PRs β append real SHAs here as identified.)