Send subscription.updated when the meter period advances
Summary
Related Issue: none
cycle_meters moves current_meter_period_start / current_meter_period_end forward without emitting subscription.updated. As a result, webhook consumers keep a stale meter period.
What
cycle_metersnow calls_after_subscription_updatedonce the meter clock has advanced. It does this on both paths:- Active: after settlement, the meter reset and the credit re-grant.
- Frozen (inactive, e.g.
past_due): after the clock advances, with nothing settled or reset.
- Tests in
TestCycleMetersnow assert thatsubscription.updatedis sent once on both paths. The active-path test also asserts thatcustomer.state_changedis enqueued.
Why
The billing cycle already sends subscription.updated through SubscriptionUpdateContext, so the meter period was only stale when it advanced on its own (meter interval shorter than the billing interval).
How
The status doesn't change at a meter boundary. So _after_subscription_updated (called with the current status as the previous status) only sends the subscription.updated webhook and enqueues customer.state_changed. The second one is useful too, since meters were just reset.
Behaviour change: merchants whose meter interval is shorter than their billing interval now receive one extra subscription.updated per meter period.
Checklist
- This PR addresses a single concern (one bug fix, one feature, one refactor)
- The diff is reasonably sized and easy to review
- New functionality is covered by tests (the new assertions fail without the fix)
- Linting and type checking pass (ruff and mypy on the changed files;
tests/subscriptionpasses, 495 tests) - No unrelated changes or drive-by fixes are included
๐ค Generated with Claude Code
https://claude.ai/code/session_018HHcDPUBuyzYF2BrPiqMzM
Generated by Claude Code