Keys belong on Stripe creates only, not on mutations

FixBillingService
Shipped
August 26, 2026 at 2:40 AM UTC
Author
Kamo
Commit
d54a9fe

Round 1 review (Ruling 15) found the Critical: a stable idempotency key on an update/cancel/attach/detach is not a safeguard, it is a bug. Those calls already set an explicit target state, so they are idempotent in effect without any key; a stable key instead lets Stripe's 24h cached-response replay swallow a genuinely later change. Concretely: cancel() -> reactivate() -> cancel() presented the SAME key on both cancel() calls, so the second one got back the FIRST call's cached response and never touched the live subscription -- the DB and UI said "will not renew" while Stripe kept billing, with no exception anywhere. The same shape hit the default-payment-method toggle and syncStripeItems' proration-bearing update (5 seats -> 10 -> 5 would have dropped a real proration). Neither AccountSubscription nor Account carries a per-invocation field (no updated-at that moves, no version column) to fold into a key instead, which is why the fix is no key at all on these ten mutations, not a smarter one. Keeps the key on all ten genuine creates (SetupIntent, Customer, Session, four Price.create, Product, Meter, Subscription.create), which remain non-idempotent by nature and still need one. StripeIdempotency's class javadoc now states this plainly, including the specific cancel/reactivate/cancel failure mode, so the ten mutation call sites aren't "restored" later. The coverage test now asserts both directions: every create carries a key **************** a forward-looking regex net) and no mutation does **************** for the regex-visible ones, plus **************** pinning the true per-file count so a key added back to any of the local-variable- receiver mutations the regex cannot see -- most of AccountSubscriptionService's and AccountPaymentMethodService's -- still fails the build). Verified both new assertions actually catch a reintroduced key before reverting the probe.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing