Cloud plan entitlements: production readiness tests and promote gates

Merged
TE
8d ago
+198-4

What

Readiness work for turning paid NEXT Cloud entitlements on in production. This PR does not turn anything on.

  • backend/apps/api/test/cloud-plan-production.test.ts (new) loads the production Worker block of wrangler.jsonc and turns CLOUD_PLAN_ENTITLEMENTS on in memory. It checks:
    • every paid plan id (go, pro, max, founders, team) gets its PAID_PLAN_LIMITS;
    • an unpaid team gets no plan, even when it is on CLOUD_ALLOWED_TEAMS (production never applies the stub plan);
    • an unknown plan id gets no plan;
    • with the flag off, a paid team also gets no plan;
    • plan ids match across the three places that define them: PAID_PLAN_LIMITS, the protocol's INFERENCE_*_PLAN_IDS, and web billing's PAID_PLAN_IDS (web/services/billing/pro.ts). A new web plan id (for example a Team Max) fails this test until it gets Cloud limits;
    • production may turn the flag on only when its config can actually create a machine (createConfigProblem is clear). Today production has no CLOUD_FREESTYLE_SNAPSHOT (no cmuxnp-prod-vmimg- image) and no vm-api transport. The flip PR stays red on this test until a production image exists, so no paying team gets "not configured" instead of a machine.
  • cloud-plan-entitlements.test.ts adds Durable Object-level cases:
    • Founders gets Pro's limits;
    • a lapsed plan (TeamDO answers "no plan") is dropped at the next read, while an outage keeps the plan (the outage case was already covered);
    • a downgrade from Pro to Go with 2 machines keeps both machines, and the next create answers cloud.quota.exceeded naming pro;
    • a shared team uses the team's Team plan, never a member's personal Max.
  • prod-promote.ts, the production promote gates:
    • G7: CLOUD_PLAN_ENTITLEMENTS joins the guarded money vars, so a production value needs an entry in production-approvals.json;
    • G5: when the flag is on, the provider key secret of the configured transport must exist (CLOUD_FREESTYLE_API_KEY for direct, CLOUD_VM_API_SERVICE_KEY for vm-api). This uses the same pattern as HOME_INVITES_SEND needing HOME_INVITE_FROM.
  • paid-product-DESIGN.md section 9.2 names these gates.

Why

Leo, 2026-10-28: "whatever's convenient for cloud, like that can be productionized, operationalized, we ought to just put out there"
Leo, 2026-10-28: "'pay money to us'"

The entitlement code was built and tested only in the test environment, where the allowlist stub also applies. Nothing proved how it behaves under production's config. Nothing stopped the flag from reaching production without a provider. And no test covered lapse, downgrade, Founders, or shared-team plans.

Risk

Low. The change is tests plus two promote-gate rules. Both rules act only when production's CLOUD_PLAN_ENTITLEMENTS changes or is on, and today it is unset. Runtime code is unchanged.

Tested

On a Linux CI box (cmux-ci test):

  • release rails: bun test test/prod-promote.test.ts passed 31/31, and tsc passed;
  • backend: typecheck and lint:size passed;
  • vitest: cloud-plan-production.test.ts and cloud-plan-entitlements.test.ts passed 16/16.

Agent session: agent session

šŸ¤– Generated with Claude Code


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


Summary by cubic

Adds production readiness tests and promote gates so paid Cloud entitlements can be turned on safely, without turning them on.

  • The new cloud-plan-production.test.ts runs the production Worker config with CLOUD_PLAN_ENTITLEMENTS on and verifies paid plans get their limits, unpaid and unknown plans get none, and the flag stays off until production can actually create a machine.
  • It tests the provider rule on both transports: direct needs CLOUD_FREESTYLE_API_KEY, vm-api needs CLOUD_VM_API_SERVICE_KEY.
  • cloud-plan-entitlements.test.ts adds coverage for Founders, lapsed plans, downgrades over the machine cap, and shared teams using the team plan.
  • A plan-id test fails if web billing and the protocol define a plan that has no Cloud limits.
  • prod-promote.ts now treats the flag as a guarded money var (G7) and, when the flag is on, requires the provider key secret of the configured transport (G5).
  • Runtime code is unchanged; the new gates only act when the flag changes or is on, and today production has it unset.