Work / Chitragupt / Wiki / Decisions
2026-06-10-zod-parse-firestore-boundary
Decisioncanonicalverified 2026-06-26
DECISION.2026-06-10.ZOD-PARSE-FIRESTORE-BOUNDARYPhase 7e: zod-parse boundary on high-impact Firestore reads
Decision
Convert eight high-impact Firestore snapshot reads to zod-parse-at-boundary via a new parseDocData / parseField helper. Leave the remaining ~25 trivial primitive casts in place — they are runtime-safe.
Why
Phase 7e exit criterion targeted "14 as casts on Firestore snapshot data replaced with zod-parse-at-boundary". Audit surfaced ~42 total casts; on inspection, the bulk are field-level as Timestamp | undefined / as string | undefined which Firestore JS SDK preserves natively — replacing them with zod adds noise without protection. Schema drift bites in nested object + array shapes, not primitives.
Impact
- New helper
apps/functions/src/_lib/parse-snap.tsexportsparseDocData(snap, schema, label)+parseField(snap, field, schema, label)— throwsHttpsErrorwith the exact failing path on drift. - Eight high-impact reads converted:
admin/kpis.ts(AdminKpi snapshot),ca/clients.ts(CaEngagement),family/overview.ts(TaxReview for member drill-in),marketplace/engagement.ts(CaPricingMatrix on consult request),expense/dispute.ts(AnomalyDisputeBankForm in grievance PDF),tax/exports.ts(TaxReview consumed by both alert gate + CA-handoff PDF render — replaces 5 casts with one parse),_lib/subscription-gate.ts(AyUnlock array — paywall-critical),_lib/storage-accounting.ts(SubscriptionPlan enum — tier gate). - Remaining ~25 trivial casts on Timestamp / string / number /
Record<string, unknown>deliberately left; documented as runtime-safe.
Status
Active.
Sources
- .context/wiki/decisions/* § "2026-06-10 — Phase 7e: zod-parse boundary on high-impact Firestore reads"
Every project of mine is written down like this.
Read the résumé