The Subscription Clock
Time-based billing that survives upgrades, downgrades, time zones, and February.
The incident
A customer upgraded from Basic to Pro on day 14 of a 31-day month. The proration math was off by one day — in the customer's favor on upgrades and against them on downgrades. Nobody noticed for a quarter. Then a finance audit did, and every invoice in the window had to be recomputed and explained.
Why the obvious approach fails
Billing time looks like arithmetic and behaves like a minefield: months have four different lengths, days have DST boundaries, 'a month later' from January 31st has three defensible answers, and plan changes mid-cycle create credit-and-charge pairs that must sum exactly right. Ad-hoc date math scattered through the codebase guarantees drift — each call site resolves the ambiguities slightly differently. Billing time needs to be one engine with one set of rules, tested against the calendar's pathologies.
The standard
- All billing-time computation lives in one temporal engine; no raw date arithmetic in business logic.
- Proration computes to the second: credit for unused time and charge for new time are exact and sum-verified per change event.
- Dunning is an explicit state machine — retry schedule, notification points, grace period, downgrade — declared as configuration.
- Plan definitions are versioned: grandfathered customers keep their terms without code branches.
- Every invoice line traces to the events (subscribe, upgrade, usage) that produced it.
How Cortex validates it
At plan time
Subscription blueprints declare the billing model, proration policy, and dunning states before build.
At validation
assert: invoice_lines.trace_to(events)assert: proration(upgrade) + proration(credit) == plan_delta exactlyassert: billing_math.calls outside temporal_engine == 0Assertion syntax is illustrative.
At review
The approver sees the calendar-pathology test suite results: month-length edges, DST boundaries, and mid-cycle changes, all green with computed values shown.