Amended. The original notes described only the off-session change. This tag shipped 12 commits — main carried unreleased work that the tag swept up. The rest is documented below, late.
Off-session collection carries the vaulted instrument (breaking, behavioural)
PaymentIntent carried only an id, an amount and a reference, so a gateway asked to charge a renewal had nothing to charge against. Stripe answers an intent with no attached method requires_payment_method, which maps to "needs action" rather than "failed" — and hosts open dunning only on a failure. The result was a renewal that collected nothing and reported nothing.
PaymentIntentgainscustomerRef,paymentMethodRef(both nullable — the object still serves on-session collection) andisOffSession().PaymentGateway::charge()now specifies that an implementation MUST pull the named instrument, and MUST return a failed result when the intent names none. Failing is the recoverable outcome, because failing opens dunning.FakePaymentGatewayrefuses the same case. A fake easier to satisfy than production validates bugs rather than catching them.
Gateway adapters need the matching release: cboxdk/laravel-billing-stripe v0.5.x, cboxdk/laravel-billing-mollie v0.5.x.
⚠️ Metering: the usage-event window is now HALF-OPEN [from, to)
6ab8bd3 changed EventLog::sum()/aggregate(), both storage drivers, BillableUsageResolver and DefaultReconciler from inclusive-both-ends to half-open. An event landing exactly on a period boundary now belongs to the next period only, instead of being counted in both.
If you implement EventLog yourself, or read it with your own bounds, this changes your numbers. A caller passing now as the upper bound stops seeing events stamped at that instant. This was published silently; cboxdk/laravel-billing-clickhouse did not catch up until v0.2.0, and a consumer bridging the two in between would have double-counted boundary events.
Security
ebbb6c9—guzzlehttp/guzzleto 7.15.1, which carries three medium advisories below that version.
Also shipped, unannounced at the time
2f79e63fix(reconciliation): seed the checkpoint row before locking it8f34be2fix(subscription): honourtrialEndsAton trial conversion71ec47efix(quote): validate line quantity and single currency before totalling — this can now reject quotes that previously totalled7fe2847feat(money): weighted largest-remainder allocation6288bdcdocs(adr): ADR-0017 records the single-Laravel-major support window60dbdc2docs(security),9cf8362docs(wallet),b8f095aci
Note on verification
This tag was cut from a commit whose CI run had failed at an unsatisfiable lockfile-audit step, which skipped pint, phpstan, the test suite and the licence check. The gate has since been repaired and the full gate re-run against this code: pint clean, phpstan level max 0 errors, 413 tests, audit clean, 81/81 licences permissive.