Behaviour + runtime-dispatch seam for entitlement resolution.
A resolver derives a billable's current entitlements from local
subscription state (the default Accrue.Entitlements.Resolver.LocalMap)
or — for a host that opts in — from an alternate source. The
Accrue.Entitlements context dispatches to the configured resolver via
__impl__/0; swap it with:
config :accrue, :entitlements, resolver: MyApp.Entitlements.ResolverThe active_plans SET is the membership source of truth
resolve/2 returns a map whose :active_plans is the SET of ALL active
plan atoms for the billable. Accrue.Entitlements.has_active_plan?/2
tests membership against this set, never against the representative
:plan field. A single representative would wrongly answer false for a
billable holding two active subscriptions on two different mapped plans —
carrying the full set keeps has_active_plan?/2 consistent with the
UNION semantics of entitled?/2 and features_for/1 (which already union
features across all active subscriptions).
:plan is a single representative (the last folded plan, or nil) kept
for display / back-compat only — it MUST NOT be used for membership.
Summary
Types
Resolved entitlement state.
Callbacks
Resolves the entitlement state for billable.
Types
@type resolved() :: %{ :plan => term(), :active_plans => MapSet.t(), :features => MapSet.t(), :quantities => map(), optional(:grace_plans) => MapSet.t(), optional(:grace_features) => MapSet.t(), optional(:expired_grace_plans) => MapSet.t() }
Resolved entitlement state.
:plan— representative active plan atom (ornil); display only, NOT the membership source.:active_plans—MapSetof ALL active plan atoms; the membership source of truth.:features—MapSetUNION of features across all active subs.:quantities— mergedquota_key => min(cap, quantity)map.:grace_plans—MapSetof plan atoms admitted via the past-due grace window (a SUBSET of:active_plans). Empty whenpast_due_graceis:none(the default).Accrue.Entitlementsreads it to select the:past_due_gracetelemetry reason without re-querying.:grace_features—MapSetof features contributed by:grace_plans; letsAccrue.Entitlementsdecide whether a feature grant was decided by grace (and so should report:past_due_grace).:expired_grace_plans—MapSetof plan atoms whose:past_duegrace window has lapsed; these do NOT grant, but letAccrue.Entitlementsreport the distinct:past_due_expiredreason on the resulting deny.
Resolvers that do not implement the past-due grace overlay MAY omit the
three grace fields; Accrue.Entitlements treats absent grace fields as
empty.
Callbacks
Resolves the entitlement state for billable.
Returns {:ok, resolved} (see resolved/0) — note :active_plans is
the SET of all active plan atoms and is the membership source of truth
(:plan is a representative only). May return {:error, term}; the
context collapses any error/exception to the fail-closed value.