Skip to content

feat(billing): add operator pause switch for trial enforcement - #2782

Merged
tyler-dane merged 1 commit into
mainfrom
claude/trial-enforcement-config-0748a3
Aug 14, 2026
Merged

feat(billing): add operator pause switch for trial enforcement#2782
tyler-dane merged 1 commit into
mainfrom
claude/trial-enforcement-config-0748a3

Conversation

@tyler-dane

Copy link
Copy Markdown
Contributor

Summary

  • Adds billing.enforcement (default false/paused) as a global operator kill switch so the trial/billing product can stay free for every user while Checkout, webhooks, and Stripe keys keep working behind the scenes in an environment
  • Fails open on a pending or errored /api/config fetch, so a slow network never flashes a gate at a visitor before the real value loads
  • Never stamps the anonymous 7-day trial clock while paused, so flipping the switch on later doesn't retroactively expire visitors who browsed during the pause
  • assertBillingAllowsWrites no-ops when paused even with valid Stripe keys present
  • billing.enforcement accepts a yaml boolean or a "true"/"false" string (mirrors sync.enforceLeastPrivilege's BooleanFromInput pattern), since the deploy workflow injects it from a GitHub Environment var — a strict boolean-only schema would crash the entire backend on any casing typo
  • Deploy plumbing: BILLING_ENFORCEMENT GitHub Environment var → compass.yaml/api/config

Not in scope (flagged in docs/features/billing.md for enable day)

Existing hosted accounts are not grandfathered — flipping enforcement: true while Stripe is configured will show any existing account without a Stripe subscription id the BillingGateModal. bun run cli backfill-billing is the existing lever if that's not the intended effect.

Test plan

  • bun run type-check — clean
  • bun test:core, targeted bun test:backend (billing + config suites), full relevant bun test:web sweep (billing, RootShell, Sidebar, AuthModal, auth) — all passing
  • Reviewed via /code-review high (2 findings, both fixed) and /simplify (3 findings fixed, 1 knowingly skipped as out-of-scope)
  • Verified in browser: dev:web standalone with no backend confirms the fail-open default posture (no trial gate, calendar fully usable)
  • Manual: flip billing.enforcement: true in a local compass.yaml and confirm the trial chip/gate return

🤖 Generated with Claude Code

Adds `billing.enforcement` (default false/paused) so the trial/billing
product can stay fully free for every user while Checkout, webhooks, and
Stripe keys keep working behind the scenes. Fails open on a pending or
errored /api/config fetch so a slow network never flashes a gate, and
never stamps the anonymous trial clock while paused so flipping the
switch on later doesn't retroactively burn days.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@tyler-dane
tyler-dane merged commit 7d83b10 into main Aug 14, 2026
20 checks passed
@tyler-dane
tyler-dane deleted the claude/trial-enforcement-config-0748a3 branch August 14, 2026 05:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant