Support policy
What Aurora Meter Pro promises about compatibility, and what it does not. It restates commitments the package already keeps; it adds no commercial term, it changes nothing in the licence, and it is not a service level agreement.
The surface it applies to is the API inventory. If an entry is not on that page, nothing here covers it. The free core carries a policy of its own for its own surface, on the same terms.
1. What SemVer covers
This package follows Semantic Versioning. Inside 1.x, these things do not break:
-
Every entry in the API inventory classed
stableoroptional-dep: its name, its arity, the shape of its arguments and the shape of what it returns. -
The documented settlement semantics: a payment grants credit exactly once,
keyed on the provider’s PaymentIntent id; a usage delta is billed at most once
per
(tenant, feature, period), through a reporting ledger that holds one row per window and sends it under an identifier the provider deduplicates on, so a retry after an answer that never arrived does not bill the window twice; and a refund or dispute reconciles to one net reversal capped at what the payment granted and at what earlier events already took. -
Which money is in which unit: minor units (
amount_cents) at every provider boundary, micro-dollar integers in the core ledger. - Configuration key names, their types, and their defaults.
- Telemetry event names, measurement keys and metadata keys.
- Migration entry points and the schema-version contract in section 3.
- The set of provider webhook events the package requires you to subscribe to. Requiring a new one is a compatibility change and gets release notes that say so.
Additive change is allowed in a minor release: a new function, a new optional argument with a default, a new key in a returned map, a new metadata key on an existing telemetry event, a new configuration key whose default preserves today’s behaviour. Match on the keys you need rather than on a whole map, and additive change stays invisible to you.
2. What SemVer does not cover
-
Anything classed
internalin the inventory, whether or not it is public in the compiled code. Section 11 of that page names every internal module. -
Any function carrying
@doc false, which includes everyOban.Worker,Plug,Phoenix.LiveViewand provider-behaviour callback. Call the named entry point (report_all/0, notperform/1). - The rendered HTML and the CSS class names of the dashboard components.
- The wording of log messages, and the exact text inside an exception message. The tuples are covered; the strings are not.
- The SQL Pro generates and the query plans Postgres chooses for it.
- The shape of a provider object. Stripe owns that, and section 5 says what this package does about it.
- The five direct core-table reads recorded in section 12.1 of the inventory. They are coupling, they are scheduled for removal, and they are written down so that removing them surprises nobody.
3. Schema
A host owns its own database and runs its own migrations. Pro provides the
migration bodies through AuroraMeter.Pro.Migration.up/1 and down/1, and the
core provides its own: both must run, and Pro’s schema version 11 pairs
with core schema version 10 in this release.
-
1.x migrations are additive only. A new version adds tables, columns and
indexes. A version that would destroy data is refused unless the caller
passes
confirm_data_loss: true, and no such version is planned for 1.x. A column that stops being written (theusage_reports.pending_*columns, for one) is deprecated in place and dropped no earlier than 2.0. - Every version is idempotent, so re-running one is safe.
-
Every supported 0.x history upgrades to 1.0. In practice the histories
that exist are installs at Pro schema version 1 (from 0.1.x and 0.2.x) and at
Pro schema version 9 (from 0.3.0); each has a path to the 1.0 schema through
AuroraMeter.Pro.Migration.up(from: n), and each is exercised by the migration matrix in this repository’s CI on every push. -
AuroraMeter.Pro.Migration.latest_version/0reports the version the installed package expects.
4. Deprecations
A deprecated API keeps working. It warns, at most once per node per distinct key. It is not removed before 2.0.
| Entry | Replacement | Removed in |
|---|---|---|
AuroraMeter.Pro.Credits.Expirer |
AuroraMeter.Oban.CreditExpiry, in the free core |
2.0 |
AuroraMeter.Pro.Credits.with_lock/2 under that name |
AuroraMeter.Pro.Lock.with_lock/2 |
2.0 |
AuroraMeter.Pro.Subscriptions.plan_id/1 |
plan_ref/1, returning {plan_id, version} |
2.0 |
AuroraMeter.Pro.Config.plan_for_price/1 |
plan_ref/1, returning {plan_id, version} |
2.0 |
A bare plan_id key in :stripe_prices |
{plan_id, version} |
2.0 |
usage_reports.pending_* columns |
the outbox item’s own state | 2.0 |
Each of those replacements arrives with 1.0. Until it does, the entry on the
left is simply the API, and this table is the advance notice.
AuroraMeter.Pro.Credits.Expirer is the first whose replacement has landed: it
is now a shim that delegates to the core worker, its run/0 carries
@deprecated, and the scheduler map is the one-line change.
5. Working against a provider
Aurora Meter Pro talks to Stripe, and Stripe’s contract is not ours to promise. Three consequences, stated plainly:
- A provider object’s shape is Stripe’s. Pro reads the fields it names and ignores the rest. A field Stripe removes is a Stripe change; Pro adapts to it in a patch release and says so in the changelog.
- Provider API versions are recorded, not reconciled. Webhook payloads arrive serialised at the account’s default API version, while the package’s own requests go out at the client library’s default. Those can differ, and where evidence exists it records both rather than reporting one number.
- Pro does not claim automatic resolution of every unknown provider outcome. An uncertain result is held, retried against the provider’s current state, and surfaced, and the recovery guide says what an operator does with it.
Cancelled refunds
Cancelled refunds. A refund that ends in canceled is handled identically
to one that ends in failed. This is true by construction: Aurora Meter Pro
never reads a refund’s status. It reconciles from the charge’s current
amount_refunded and the charge’s current disputes, both re-read from Stripe at
the moment the event is applied (Credits.retrieve_refund/4). The two statuses
therefore cannot take different paths, and
AuroraMeter.Pro.Credits.SyncRefundTest asserts the same outcome for both,
including for a refund whose status contradicts the provider state.
The failed lifecycle is verified against a real Stripe test-mode account: a
real refund reaching failed, the charge’s amount_refunded falling back to zero, and the
ledger restoring exactly the refunded amount once across four deliveries and a
redelivery. The canceled lifecycle is supported but unverified against a
real provider, because Stripe’s own documentation
(https://docs.stripe.com/refunds and https://docs.stripe.com/testing, read
2026-09-14) provides no way to cancel a card refund other than the Stripe
Dashboard, and this project does not prove behaviour with a mechanism Stripe has
not documented. That is a statement about the evidence, not a narrowing of the
commitment: canceled remains a supported refund outcome.
The full reconciliation guarantee, its prerequisites and its known limits are I13 in Correctness.
6. Runtime support
The supported pairs are the ones CI exercises on every push, at the exact patch versions listed in the README’s “Supported versions” table. Nothing is claimed for a pair that is not tested.
- Floor: Elixir 1.15.8 on Erlang/OTP 26.2.5.21. The floor is OTP 26 rather than the core’s OTP 25, because the resolved Stripe HTTP stack pulls in a dependency whose own build refuses OTP 25 before any Pro code compiles. Elixir 1.15 supports OTP 24 to 26 and no further, so 1.15.8 with OTP 26 is the only pair available at the floor.
-
The core requirement is
~> 0.4, stated inmix.exsand in section 12 of the inventory. -
Optional
phoenix_live_viewis~> 1.0, and~> 1.0only.
Phoenix LiveView 1.0, when LiveView is present at all
Aurora Meter Pro 1.0 requires phoenix_live_view ~> 1.0 when the optional
dependency is present. A host with no LiveView keeps everything except
AuroraMeter.Pro.Components and the Pro LiveDashboard page: the Stripe
provider, the outbox, reconciliation, recovery, credits, alerts and rollups are
all data and behaviour with no view in them.
0.3.0 declared ~> 0.20 or ~> 1.0, and the 0.20 half was never true. Every
template in this package is written in LiveView 1.0’s curly body interpolation,
and 0.20 renders a {...} in an element body as literal text rather than as an
interpolation, so a 0.20 host compiled cleanly and rendered {@title} at its own
operators. Narrowing the requirement replaces a claim that never worked.
The route is the same as core’s, and core’s docs/support-policy.md has the
detail: upgrade LiveView to 1.0, or drop the optional dependency. Both packages
made the change together, so there is no pairing in which one of them claims
0.20.
Dropping a supported pair is a compatibility decision and needs release notes that say so before the release that drops it. Raising the floor inside 1.x happens only for a pair that is no longer available or no longer builds.
The floor is a compatibility guarantee, not a recommendation. Elixir 1.15.8 is the last release of its line and Erlang/OTP 26 is past its upstream maintenance window, so neither will receive further security patches.
7. Security
Report a suspected vulnerability privately, never through a public channel and
never with a real key, customer identifier or provider object in the report.
SECURITY.md has the disclosure routes, the supported-version
window for security fixes, how key material is handled and what the host is
responsible for. It is not duplicated here, so that there is one description of
the process and not two.
This package handles payment data only by reference: it stores a Stripe customer id, a payment method id and amounts. It never stores a card number, and its telemetry and log lines carry neither request bodies nor payment identifiers.
8. Support
There is no response-time commitment. Support is best effort. Buying Aurora
Meter Pro buys the software and its updates on the terms in
LICENSE.commercial, which this page does not change and does not extend. There
is no service level agreement, and this policy does not create one.
The most useful report names the Pro and core package versions, the Elixir and
Erlang/OTP versions, the Pro and core schema versions
(AuroraMeter.Pro.Migration.latest_version/0 and
AuroraMeter.Migration.latest_version/0), and the smallest configuration that
reproduces the behaviour. Never include a live key or a customer identifier.
9. Releases and transition releases
Releases are published by the maintainer. There is no automatic publish from CI, and no agent publishes a package.
A change that moves a default, or that starts refusing something previously accepted, ships in two steps. First a transition release that keeps today’s behaviour, warns about what is going to change, and lets a host opt in early by setting the key explicitly. Then the release that moves the default, whose notes list every default that moved and the key that pins the old one.
Every release carries a CHANGELOG.md entry. An entry that changes behaviour
names what a caller has to do, or says plainly that there is nothing to do.
Test helpers
AuroraMeter.Pro.Stripe.Fake and AuroraMeter.Pro.Credits.StripeClient.Fake
ship in the package and are listed in the inventory as stable, because a host
test suite that uses them should not break on a minor upgrade. They are governed
here rather than by SemVer on every helper name: a fake may gain a control or a
clearer failure message in a minor release, and a fake that becomes wrong
(because the provider behaviour it simulates changed) is corrected rather than
kept bug-compatible. A fake whose answers stopped matching the provider is worse
than no fake at all.
Nothing in production should call them.