feat(measurement-jobs): free-tier card gate (setup mode) + instant backfill drain (chat#1796)
Two in-scope refinements to the historical measurement-job path from chat#1796, both TDD.
1. Free-tier card-on-file link (was billing $99/mo)
The card gate was issuing createStripeSession — the paid subscription flow (mode: "subscription" on the $99/mo price, 30-day trial). New createCardOnFileSession uses Stripe Checkout mode: "setup": it collects a card for $0, no subscription, no price/product (so no Stripe dashboard/CLI work). The account saves a payment method and pays only for metered usage via the existing credits system (which auto-recharges off the saved card). Gate now points at it.
2. Instant drain (no 24h wait)
After a historical job enqueues, it now fires start(songstatsBackfillWorkflow) immediately — the same workflow the daily cron runs — so backfill begins right away. Safe by reuse, not new machinery:
- the workflow's
getBackfillBudgetStepcaps it to the rolling Songstats quota (limit − reserve − 30-day ledger) and stops when dry — the rate-limit lesson is already enforced; FOR UPDATE SKIP LOCKEDclaims prevent double-processing alongside the cron;- the daily cron stays as the backstop (multi-day draining when capped, retries, orphan reclaim);
- only kicks when something was actually enqueued (all-skipped → no-op); fire-and-forget so a scheduling hiccup can't fail the job.
Testing
26 new/updated unit tests (setup-mode session, gate → setup session, instant-drain trigger fires when enqueued / not when all-skipped). Full research+stripe+workflows suite 453 green; tsc/lint/format clean.
Verify on preview: a cardless key on historical → 402 + a mode:setup ($0) checkout link; and the enqueued tracks should start draining within minutes (budget permitting) rather than next day.
Summary by cubic
Add a free‑tier card-on-file gate for historical measurement jobs and start backfills immediately after enqueue. This removes the paid subscription requirement and reduces the wait from up to 24h to minutes.
- New Features
- Free-tier card gate: use
createCardOnFileSession(Stripe Checkoutmode: "setup") to save a card for $0. Replaces the subscription checkout; 402 now returns a setup link when no card is on file. - Instant backfill: call
start(songstatsBackfillWorkflow)right after enqueue. Only when items are enqueued; budget gate and SKIP LOCKED prevent double work; the daily cron remains the backstop.
- Free-tier card gate: use