The sandbox registry resource, as a template the host owns (012 T025, FR-009).
defmodule MyApp.SandboxRegistry do
use AshSandbox.RegistryTemplate,
data_layer: AshPostgres.DataLayer,
domain: MyApp.Sandboxes,
repo: MyApp.Repo,
table: "sandboxes"
endThe host declares data layer, repo, table, and domain; this library owns the attributes, actions, and semantics.
Why a template and not a resource module
⚠️ Research R5's spike falsified the obvious alternative — the library declaring the resource and the host attaching a data layer afterward.
Ash.Resource.Info.data_layer/1 delegates to
Extension.get_persisted(resource, :data_layer). The data layer is written
into the resource module's beam when the library compiles. With no
declaration it is Ash.DataLayer.Simple — the no-persistence default — and
it stays that way permanently. The host can add the resource to its own
domain, and the whole thing compiles cleanly and exits 0, and nothing can ever
be stored.
That is the same failure shape as a boundary violation: compiles, exits 0, fails later. The alternative is recorded here because it looks right and nothing in the build will tell a future contributor otherwise.
__using__/1's options are public interface
Because the host writes this call site, its options are public API under
FR-014, and changing them is a breaking change under FR-015.
Required options
:data_layer— the host's data layer:domain— the host's Ash domain:repo— required byAshPostgres.DataLayer; ignored by data layers that do not use one:table— the host's table name
What this library does not declare
No data layer, no repo, no domain, no table, and no multitenancy strategy.
The last is deliberate: FR-003 forbids requiring any particular
multi-tenancy model, and a library that declared strategy: :context would
force one on every host.
Summary
Functions
The states in which a sandbox is live — it exists as far as its mechanism is concerned, whether or not it is serving traffic yet.
The states in which a sandbox is settled — nothing is running under the rules it was launched with.
Functions
@spec live_states() :: [atom()]
The states in which a sandbox is live — it exists as far as its mechanism is concerned, whether or not it is serving traffic yet.
⚠️ Enumerated, never expressed as "not stopped" (029 T018 ruling). state
below is a closed set precisely so that a state added later has to be
classified deliberately: a negation would silently sort a new state into
settled, and the one caller of this list refuses a write while a sandbox is
live. Axonn.Sandbox.EnvironmentAllowlistUpdateTest's partition test fails if
the two lists here stop covering the constraint exactly. (It lives in the host
because AshSandbox.EnvironmentTemplate cannot be exercised on this library's
own ETS fixtures — see that module.)
:stopping is live. A sandbox being torn down still has whatever its
mechanism installed at launch, and it can still reach the network until the
teardown completes.
@spec settled_states() :: [atom()]
The states in which a sandbox is settled — nothing is running under the rules it was launched with.
The complement of live_states/0 over state's closed set, written out
rather than derived, so that both halves have to be edited when the set grows.