The seed: the Dyn sources an install starts from, which the host ships
(Operator's default front: a welcome screen, a component library, the
front's settings). The host embeds them at build time
(Application.app_dir/2 can't resolve priv/ on the device) and hands them
to start/2.
start/2 installs it in the background after the launch's Dyn step
(Rho.Dyn.seed/3): compiling a big seed whole takes about half a minute
on a Moto G 2021. The seed becomes a generation like any other, so its
screens are the agent's to change, and reverting to that generation
restores the defaults.
A newer seed on a phone that has one (an app update that changed
the seed). The install records each seed file's sha256 as it shipped
(Rho.Dyn.Store.seed_files/1). When this build's seed differs, it is
installed again, merged three ways with what runs now (merge/3): a
seed file the user (or the agent) never changed is replaced by the new
one (or removed, when the new seed dropped it); a new seed file is added
unless the user already has a file at that path; a file the user
changed, deleted or wrote stays exactly as it is. So user edits are never
lost, at the price that an edited seed file doesn't get the update
(reverting to the seed's generation, or asking the agent, does). The
merged generation goes through the whole check, compile and selftest; if
it fails (an edited file relies on something the new seed changed),
nothing changes and that seed is recorded as rejected, so it isn't
retried every launch; the next app update with a different seed tries
again. An install that recorded nothing (an older app's) is taken to have
shipped the :legacy digests, if the host has them (Operator 1.0's);
the seed generation's own sources can't stand in for them, since that
install merged the user's files into it.
Summary
Functions
Each file's sha256 (hex), as needed/3 and the seed's record compare them.
The sources to install: seed over current (what runs now), given
shipped (path => sha256 of the seed files as the installed seed shipped
them; %{} for a first install). See the moduledoc for the rules.
What the Dyn store at dir needs for a seed whose files have digests:
:install (no seed yet), {:update, shipped} (an older seed is
installed; shipped its files' digests as they shipped, legacy when it
recorded none) or :none (this seed, or this seed was rejected there).
Is the seed being installed right now?
Installs (or updates) the seed sources in a process of its own
(registered under this module's name) unless it's current, or can't be
now (safe mode, a proposal pending: the next launch tries again). When it
ends, :notify runs (the host's front redraws). Options: :keeper
(Rho.Dyn.Keeper), :notify (a 0-arity function, default none),
:rationale, :legacy (see needed/3).
Functions
Each file's sha256 (hex), as needed/3 and the seed's record compare them.
@spec merge( %{required(String.t()) => String.t()}, %{required(String.t()) => String.t()}, %{ required(String.t()) => String.t() } ) :: %{required(String.t()) => String.t()}
The sources to install: seed over current (what runs now), given
shipped (path => sha256 of the seed files as the installed seed shipped
them; %{} for a first install). See the moduledoc for the rules.
@spec needed(Path.t(), %{required(String.t()) => String.t()}, %{ required(String.t()) => String.t() }) :: :install | {:update, %{required(String.t()) => String.t()}} | :none
What the Dyn store at dir needs for a seed whose files have digests:
:install (no seed yet), {:update, shipped} (an older seed is
installed; shipped its files' digests as they shipped, legacy when it
recorded none) or :none (this seed, or this seed was rejected there).
@spec running?() :: boolean()
Is the seed being installed right now?
Installs (or updates) the seed sources in a process of its own
(registered under this module's name) unless it's current, or can't be
now (safe mode, a proposal pending: the next launch tries again). When it
ends, :notify runs (the host's front redraws). Options: :keeper
(Rho.Dyn.Keeper), :notify (a 0-arity function, default none),
:rationale, :legacy (see needed/3).