Reads the use Boundary declarations out of Elixir source, so a test can assert on the shape of
the architecture's enforcement.
The boundary declarations fail in one direction only. A declaration that is too narrow fails
loudly — a forbidden reference, and the gate's compile step goes red. One that is too wide
compiles in silence, and nothing in the toolchain will ever report that more permission was
granted than the code uses. So the options that make the compiler check less are pinned by the
generated boundary declarations test against a list of sanctioned exceptions, and widening a
deps:/exports: grant is gated at authoring time by .claude/hooks/waiver-gate.sh.
One widening arrives the other way round — by deletion rather than addition — so it is read by
its own function rather than by the escape-hatch list: see strict?/1.
Only the declaration is read, never prose about one
A declaration runs from a line whose first token is use Boundary until its brackets balance on
a line that does not run on — one ending in neither , nor :, since mix format may leave a
bare use Boundary, or a bare key such as exports: on a line of its own. The body of every
""" heredoc is skipped first. That matters more than it sounds: a moduledoc explaining why a
module may never say exports: :all, a test module quoting every option it forbids, or an
installer whose template strings hold whole declarations must all score nothing. A scanner that
matched anywhere in the file would score each as a maximal grant.
Summary
Types
A use Boundary … declaration, flattened to one line.
A check-disabling option: the token to search for, and what it does.
Functions
Whether mix_exs_source actually runs the boundary compiler.
compiler_configured?/1 for a file on disk.
The use Boundary declarations in source, each flattened to a single line.
declarations/1 for a file on disk.
The check-disabling options used in source, as {token, effect} pairs.
disabled_checks/1 for a file on disk.
Every check-disabling option this module knows about, as {pattern, token, effect}.
Whether any declaration in source exports everything with a bare exports: :all.
exports_all?/1 for a file on disk.
Every file under root that carries at least one use Boundary declaration.
Whether any declaration in source sets type: :strict.
strict?/1 for a file on disk.
Types
Functions
Whether mix_exs_source actually runs the boundary compiler.
Comment lines are dropped first, because a mix.exs may also describe compilers: [:boundary]
in a note above the dependency — a bare substring search passes on that prose after the setting
itself is deleted, which is the single largest bypass in the scheme.
compiler_configured?/1 for a file on disk.
@spec declarations(String.t()) :: [declaration()]
The use Boundary declarations in source, each flattened to a single line.
A declaration starts at a line whose first non-space token is use Boundary and ends when the
brackets opened since then balance on a line ending in neither , nor :, so a multi-line
declaration is returned whole — including mix format's shape of a key alone on its line with
the value below — and a comment or moduledoc mentioning one is ignored.
@spec declarations_in(String.t()) :: [declaration()]
declarations/1 for a file on disk.
The check-disabling options used in source, as {token, effect} pairs.
Each is a place where the compiler was told to enforce less than it could.
disabled_checks/1 for a file on disk.
@spec escape_hatches() :: [hatch()]
Every check-disabling option this module knows about, as {pattern, token, effect}.
Whether any declaration in source exports everything with a bare exports: :all.
Legal for the umbrella, and a trap for a sub-boundary: it makes every module public the moment
it compiles, where an explicit list fails safe — a new module is private until a person admits
it. exports: {:all, except: […]} is a narrowing of the same thing and does not count.
exports_all?/1 for a file on disk.
Every file under root that carries at least one use Boundary declaration.
Whether any declaration in source sets type: :strict.
The mirror of disabled_checks/1, and the reason it needs its own function: every option that
function scans for is a token whose presence weakens the check, so its arrival shows up in a
diff. type: :strict weakens by going away. Boundary's default is :relaxed, which checks
calls into an external application only when the boundary already names some other module from
it — so deleting one word from a pure core's declaration drops the "nothing outside the standard
library" half of its guarantee, and the deletion compiles clean, passes the gate, and scores
nothing in .claude/hooks/waiver-gate.sh, which ranks deps:/exports: entries and does not
read type:.
strict?/1 for a file on disk.