# `Accrue.Entitlements.Resolver.LocalMap`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v1.5.1/lib/accrue/entitlements/resolver/local_map.ex#L1)

Default entitlement resolver — derives a billable's entitlements from
**local subscription state only**, with zero processor calls.

Resolution path:

  1. Read-only `accrue_customers` lookup by `(owner_type, owner_id)` —
     a clone of the private `Accrue.Billing.fetch_customer/2`, NEVER the
     effectful get-or-create customer path (which would hit the processor
     on a miss). A `nil`/wrong-shape billable resolves to no customer.
  2. Entitling-subscription read via `Accrue.Billing.Query.entitling/1`
     (active/trialing, not paused, not ended; the database twin of
     `Accrue.Billing.Subscription.entitling?/1`; never raw `.status`)
     joined to its items, selecting `{price_id, quantity}`. Using the
     entitlement-grade fragment closes the paused fail-open gap: a
     `status: :active` row with a non-nil `pause_collection` no longer
     grants entitlement.
  3. Fold each active item through the `price_id -> plan` reverse index
     built from `Accrue.Config.entitlements/0`, accumulating:
       * `active_plans` — the SET of ALL active plan atoms (membership
         source of truth for `has_active_plan?/2`),
       * `features` — the UNION of every active plan's features,
       * `quantities` — merged `quota_key => min(cap, quantity)`,
       * `grace_plans` — the SUBSET of `active_plans` admitted via the
         past-due grace window (empty unless `past_due_grace` is enabled).

Past-due grace overlay (ENT-09): when `Accrue.Config.past_due_grace/0` is
`:none` (default) the base fetch stays `Query.entitling/1` with the lean
`{price_id, quantity}` select — zero query/compute change. When grace is
enabled the fetch widens to `Query.entitling_with_grace_candidates/1` (adds
`:past_due` only, never `:unpaid`), and each `:past_due` candidate (per
`Subscription.dunning_sweepable?/1`) is kept only if
`PastDueGrace.within_grace?/2` is true for its `past_due_since`; kept rows
are tagged into `grace_plans`. A grace grant is an affirmative, resolved,
configured decision — never a fail-open.

An active item whose `price_id` is unmapped is dropped under the default
`:deny` (and its plan is NOT added to `active_plans`); under `:raise` the
resolver raises so the context's `try/rescue` collapses it to fail-closed.

`:plan` carries a single representative active plan (the last folded one,
or `nil`) for display only — membership decisions use `active_plans`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
