Move separate meter cycling to GA
Moves separate meter cycling (a meter interval independent of the billing interval on recurring products) out of the meter_cycling_enabled organization feature flag and makes it generally available. Follows #14256, which removed the seat-based pricing flag.
What changed
- Product service.
product_service.createno longer rejectsmeter_intervalwhen the flag is off. Product update had no such gate, becausemeter_intervalcan only be set on create. - Organization schema.
meter_cycling_enabledis removed fromOrganizationFeatureSettingsstarting with API version 2027-01. It was never inOrganizationFeatureSettingsUpdate, so there was no allowlist entry to remove. - Web. The product form shows the meter cycle field on any recurring product that has a metered price or a meter-credit benefit, or that already has a saved cycle.
shouldShowMeterCycleloses itsisEnabledForOrganizationargument, and the two tests that only covered the flag are gone. - Tests. The flag-off rejection test is dropped. The happy-path tests in
TestCreateMeterCyclingno longer set the flag. - Generated files. The TS client (
clients/packages/client/src/v1.ts, frompnpm run generate, which targets 2027-01) anddocs/openapi/2027-01.openapi.jsonare updated. - Nothing in the backoffice toggled this flag.
API change
Removing meter_cycling_enabled from the feature-settings response schema is the same API change #14256 made for seat_based_pricing_enabled. One difference: that PR came before the frozen API contract (tests/test_openapi.py::test_current_openapi_frozen). To keep that test passing, the field is removed with Version(up_to=V2026_10), the way #15177 deprecated member_model_enabled. It disappears in 2027-01 and stays in the frozen 2026-04 and 2026-10 contracts, so server/tests/openapi.*.json is unchanged. Once the cleanup script has run, those older versions report the field's default, false.
Regeneration notes
docs/openapi/2027-01.openapi.json: runningjust openapi && just docs-openapihere rewrote all three docs specs with about 120k lines of unrelated drift, so I removed only themeter_cycling_enabledproperty by hand. That is the same change #15177 made to this file. The 2026-04 and 2026-10 docs specs are left alone, as in #15177.server/emails/src/types/openapi.ts: regenerated with no diff. The email schemas are not versioned and still include the field, just as they still includemember_model_enabled.- The generated SDKs under
sdk/are not touched, as in #14256.
Cleanup after deploy
server/scripts/drop_meter_cycling_flag.py is a copy of drop_seat_based_pricing_flag.py. It removes the meter_cycling_enabled key from organizations.feature_settings in batches, and assigns modified_at to itself so that organizations don't look freshly modified. Run it after this is deployed:
uv run python -m scripts.drop_meter_cycling_flag
# options: --batch-size 5000 --sleep-seconds 0.1
Verification
uv run task lint && uv run task lint_types: passpytest tests/product tests/organization tests/test_openapi.py: 975 passed- web:
turbo run lint typecheck --filter=web,oxlint --type-awareandoxfmt --checkon the changed files, andvitestonProductForm: pass
๐ค Generated with Claude Code