Coaching page showed missing/partial sessions, wrong balances, no vouchers/invoices for migrated students — page still read the pre-T-079 top-level Sessions location
Symptom¶
Owner, 2026-07-01 (verbatim): "look into the Coaching page and the information that page fetch and write on Firestore, and see why some information are not being shown (I have previously migrated and restructured coaching related firestore docs, and apparently, some of the things didn't get re-write or re-routed afterwards)."
On the coaching dashboard, students whose sessions had been migrated showed missing or partial data — empty/short session lists, wrong (often zero) Balance Due, no voucher counts, and no invoice indicators. Other students looked fine, so it read as "some information not being shown."
Root cause¶
The T-079 "sessions under students" migration moved coaching sessions from the top-level
Sessions/ collection to Students/{abbr}/Sessions/{id} (new shape: inline
origStartTimestamp/origEndTimestamp, invoice as a map field), and converted the
accounting/records consumers to collectionGroup('Sessions'). The coaching page readers were
never re-pointed — CoachingSessionsApp, SessionsTab, lib/billing/compute.ts,
lib/coaching/useBillingInfo.ts, RetainersTab, lib/sessions.ts all kept querying the old
top-level Sessions where sessionName == account, and SessionDetail/RateModal wrote
vouchers/rates to the old top-level path.
Live-data audit (tebs-mel, 2026-07-01): 67 sessions had moved to Students/{abbr}/Sessions,
while 46 legacy sessions remained orphaned in top-level Sessions/ (the T-079 migration script
skips docs with no abbr/studentAbbr). Zero id-overlap. So the page (reading only top-level) saw
only the orphan scraps per student — e.g. Nancy Kwai showed 2 of 21, Kiri T 22 of 50,
Lok Chow 1 of 12, Jake Ngai 0 of 1; students never migrated (Asa/Ceh/ET/ML/OJ) looked fine.
Fix¶
Escalated to T-146 (structural): all coaching-page session reads/writes routed through a new
shared source lib/coaching/sessionsSource.ts (canonical nested location + legacy fallback);
new-shape awareness (inline timestamps, invoice map field); the 46 orphans re-homed into
Students/{abbr}/Sessions (scripts/rehome-orphan-coaching-sessions.ts); stale root-doc session
summaries backfilled; Firestore rule added for the nested session sub-subcollections. See T-146 for
the full decision record, verification, and blast radius.