Skip to content

Hosted: billing core, closed by default - #1405

Merged
nedtwigg merged 3 commits into
mainfrom
hosted-billing-core
Oct 29, 2026
Merged

nedtwigg merged 3 commits into
mainfrom
hosted-billing-core

Conversation

@nedtwigg

Copy link
Copy Markdown
Member

Billing PR 1 of 4, on top of #1403 (pgstencil 0.4.1). Billing stays closed: with no STRIPE_* bindings set, nothing here opens it.

  • Packages: adds @pgstencil/stripe@^0.4.1 and stripe, composes the billing migrations (001–006), and regenerates the dependency disclosure. verifyPackages and the release workflow's attestation check now cover all three pgstencil packages.
  • hosted/server/billing.ts:
    • billingSetup keeps billing closed unless all five STRIPE_* bindings are set. It throws on a wrong founding-ladder length, a malformed Price id, or a repeated Price, and sets live mode from the key prefix.
    • withBilling builds Billing with no trial, managedPayments: false and automaticTax: true (Stripe Tax).
    • openCohort fix: a cohort closes on gross purchases, and seats left come from the net count. A refund right after a cohort closes no longer reopens the cheaper step.
    • resyncBilling runs on the account Worker's cron every 10 minutes.
    • StripeDev (billing-dev.ts) backs the tests.
  • Entitlement: an account is entitled when it has exactly one current subscription that grants access by the database clock (active with period_end > now(), or trialing with trial_end > now()), or holds the ADMIN_EMAIL comp. past_due grants nothing, as the Terms say.
    • Live as soon as this deploys: it replaces the old ADMIN_EMAIL-only check, but while the bindings stay unset no account can have a subscription.
  • Isolation: only the production account Worker's bindings carry STRIPE_*, and the relay and voice Workers never import billing.
  • Grants: runtime-roles.sql grants the relay and voice roles the subscription columns they read, without price_id, which neither reads; a test pins that it is refused. It also grants dormouse_app the pgstencil_billing schema, only if that role exists and never revoking. Without it, the account Worker's entitlement queries would fail with permission errors on deploy. Please look closely at this grant: it changes what an existing production role can read.
  • Specs:
    • hosted.md has a rewritten "Entitlement" section and a new "Billing" section.
    • pricing.md moves the built half of "Checkout and entitlement" and the cohort rules above the fold.
    • security-hosted.md gets FAIL IF S281 (Stripe bindings; relay and voice never import billing) and S282 (entitlement), and widens S110, S118 and S119.

Next: routes and webhook (PR 2), the account app (PR 3), then the website switch and legal gates (PR 4).

🤖 Generated with Claude Code

nedtwigg and others added 2 commits October 28, 2026 04:23
Adds @pgstencil/stripe 0.4.1 and its stripe peer, composes the billing
migrations into Hosted's, and builds the Billing construction: no trial,
Stripe Billing with Stripe Tax (automaticTax), never Managed Payments,
founding offered at the open cohort's Price. A cohort now closes on its
gross purchases and counts seats left from the net, so a refund right
after a cohort closes no longer reopens the cheaper step.

The five STRIPE_* bindings reach only the production account Worker's
mapper; without all of them billing is closed and the new ten-minute
resync cron does nothing. A malformed, repeated, or wrong-length Price
list throws, and live mode comes from the key prefix.

The entitlement is now the account's subscription, as status() reads
it (exactly one current subscription, active or trialing before its
end, by the database clock), ORed with the ADMIN_EMAIL comp. The relay
and voice roles get the subscription columns it reads; db:migrate
grants the account's dormouse_app the billing schema. verifyPackages
and the npm attestation step cover all three pgstencil packages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hosted.md states the subscription entitlement with the ADMIN_EMAIL
comp, and a Billing section for the closed-by-default bindings, the
Price checks, no trial or Managed Payments with Stripe Tax, the
founding cohort's gross/net rule, the resync cron, and the account
role's billing grant. pricing.md promotes the built half of "Checkout
and entitlement" and the cohort rules above the fold; checkout itself
stays under Future. security-hosted.md adds S281 (Stripe bindings only
on the production account; relay and voice never import billing) and
S282 (the entitlement rule), widens S110 to the subscription columns,
and S118/S119 to all three pgstencil packages. Ratchets hosted.md and
security-hosted.md for the new rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2be11e1
Status: ✅  Deploy successful!
Preview URL: https://ed89ba8a.mouseterm.pages.dev
Branch Preview URL: https://hosted-billing-core.mouseterm.pages.dev

View logs

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nightly hosted audit still scopes its package check to two packages. .github/audit/hosted.md says "Check the installed pgstencil and @pgstencil/auth packages against "Deployment boundary"", but this PR widens S118 and S119 to "any installed pgstencil package (core, auth, stripe)". An auditor following its prompt never reads @pgstencil/stripe's dist/provenance.json, so those two rules go unchecked for the new package. That line is outside the diff, so it can't take a suggestion. Adding @pgstencil/stripe to it is enough, and I can push that commit if you'd like.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nedtwigg

Copy link
Copy Markdown
Member Author

Added @pgstencil/stripe to .github/audit/hosted.md's package check in 2be11e1. No other audit prompt or security spec names only the two packages.

@nedtwigg
nedtwigg added this pull request to stack #1416 October 28, 2026 19:57
@nedtwigg
nedtwigg merged commit 464b191 into main Oct 29, 2026
13 checks passed
@nedtwigg
nedtwigg deleted the hosted-billing-core branch October 29, 2026 00:06
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.

2 participants