fix(billing): stop writing empty Autumn records on read failure

Draft
PO
1mo ago
+258-46

Problem

  • A user's Autumn billing record was written with no email, name, or account type — degrading a real billing record.
  • getAutumnCustomerFields opens a Hyperdrive Postgres connection to read five identity columns. A transient Postgres internal error was swallowed and the function returned bare defaults.
  • Callers then passed those defaults to getOrCreateAutumnCustomer, which both reads balances and writes identity, so the record was created or touched with only source: thinkex.
  • The drizzle wrapper inlines the bound parameters (including the user id) into the error message, so error tracking groups fragment into one issue per user.

Changes

  • Retry then skip, never write empty identity — getAutumnCustomerFields retries the read once, then returns null instead of defaults when it still fails.
    • Billing panel (getWorkspaceBillingStateFn): returns no state for that load rather than overwriting the record.
    • Usage tracking (trackAutumnUsage): skips the identity write but still records the meter, which carries no identity.
  • Stable error grouping — recordOperationalFailure normalizes a drizzle query error before capture: keep the SQL statement, drop the parameter list, surface the underlying driver cause. This runs on the shared capture path, so any drizzle failure benefits.
  • Reuse the shared DB helper — the read now goes through withDb instead of a hand-rolled connect/dispose.
Read outcomeBeforeAfter
SuccessFull identity fieldsFull identity fields
No user rowDefaultsDefaults
Transient failureDefaults → empty identity writeRetry once → null → write skipped

Why

One user hit a transient Postgres failure while their billing panel loaded, and the graceful-degradation path silently corrupted their Autumn billing record. The cost is small in volume but persistent: every occurrence degrades a real record, and the per-user error titles splinter one fault into many issues as traffic grows.

Testing notes

  • node_modules/.bin/vp check — format, lint, and types pass.
  • New unit tests: src/integrations/autumn/client.server.test.ts (retry recovery, null on repeated failure, skip-write path) and a normalizeCapturedError case in operational-error.test.ts.
  • Full vp test --run: all pass except a pre-existing, unrelated failure in src/integrations/posthog/build.test.ts (needs PostHog build env vars; fails identically with these changes stashed).

Created with PostHog Desktop from this inbox report.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.