Helpers for discovering which providers a council references.
Used by CouncilEx.AutoCouncil provider_check: true to filter out
catalog entries whose councils need providers that aren't configured.
Council form coverage
Static (
use CouncilEx) — every static council compiles a__providers__/0function via theCouncilEx.__before_compile__/1hook. That function calls back intofrom_spec/1with the council's compiled%Spec{}. Cheap, no provider config required.Dynamic (
%DynamicCouncil{}) —used/1callsDynamicCouncil.to_spec/1and walks the resulting%Spec{}. No I/O, just keyword merges + a profile lookup per member.
Sub-councils
A council member may itself be a sub-council shim
(CouncilEx.Members.SubCouncilAdapter). Those shims expose
__sub_council__/0 returning the target. from_spec/1 detects shims
and recurses into the target so the parent's provider set covers all
inner providers transitively.
Sentinels (:__sub_council__) and nil are filtered out.
Failure mode
used/1 returns {:error, term()} if introspection fails (e.g. a
profile module isn't loaded). The caller should treat {:error, _} as
"skip the eligibility check" rather than dropping the entry — load
order races shouldn't starve the router.
Summary
Functions
Return the MapSet of provider keys the app currently has configured
under :council_ex, :providers.
Returns true if every provider used by council is configured.
Walk a %Spec{} and collect referenced providers.
Return the set of providers a council references.
Functions
Return the MapSet of provider keys the app currently has configured
under :council_ex, :providers.
@spec eligible?(module() | CouncilEx.DynamicCouncil.t(), MapSet.t() | nil) :: boolean()
Returns true if every provider used by council is configured.
Treats introspection failures ({:error, _} from used/1) as
"eligible" — better to attempt the run and surface a clear error than
to silently drop a council due to a load-order race.
@spec from_spec(CouncilEx.Spec.t()) :: MapSet.t(atom())
Walk a %Spec{} and collect referenced providers.
Public so the __providers__/0 hoisted into static councils can call
into it without going through the polymorphic used/1 path.
@spec used(module() | CouncilEx.DynamicCouncil.t()) :: {:ok, MapSet.t()} | {:error, term()}
Return the set of providers a council references.
Polymorphic on council form. Returns {:ok, MapSet.t(atom())} or
{:error, term()}.