# `Rho.Dyn.Generation`
[🔗](https://github.com/GenericJam/rho/blob/v0.1.0/lib/rho/dyn/generation.ex#L1)

One generation of the Dyn layer: what `gens/<n>/manifest.json` holds
(see `Rho.Dyn.Store`).

Status lifecycle:

  * `:building` while a proposal compiles and selftests (a crash leaves it so);
  * `:rejected` (check, compile or selftest failed: `reason` says why) or
    `:candidate` (passed; waiting for approval);
  * `:superseded` when a newer proposal replaced a candidate, `:discarded`
    when the human (or agent) dropped it;
  * `:probation` once activated, until it is proven: 60 s without a Dyn
    crash (`quiet`) **and** a later app start reached stable (`restarted`);
  * `:proven`, or `:reverted` (automatically or by hand; `reason`).

Generation 0 is the empty Dyn layer: no sources, always proven, the root
every revert chain ends at.

`modules` has one entry per compiled module: the `module` the agent wrote
(`"Dyn.Notes"`), the `versioned` one it was compiled into
(`"Dyn.G3.Notes"`), its `kind` (`:tool`, `:screen` or `:module`),
the logical `name` the registry files it under (a tool's `c:Rho.Tool.name/0`, the
module name below `Dyn.` otherwise) and the `sha256` of its BEAM.
`selftests` has one `%{module, kind, ok, detail, ms}` per module.

# `kind`

```elixir
@type kind() :: :tool | :screen | :module
```

# `module_entry`

```elixir
@type module_entry() :: %{
  module: String.t(),
  versioned: String.t(),
  kind: kind(),
  name: String.t(),
  sha256: String.t()
}
```

# `selftest`

```elixir
@type selftest() :: %{
  module: String.t(),
  kind: kind(),
  ok: boolean(),
  detail: String.t(),
  ms: non_neg_integer()
}
```

# `status`

```elixir
@type status() ::
  :building
  | :candidate
  | :rejected
  | :superseded
  | :discarded
  | :probation
  | :proven
  | :reverted
```

# `t`

```elixir
@type t() :: %Rho.Dyn.Generation{
  activated_at: String.t() | nil,
  compile_ms: non_neg_integer() | nil,
  created_at: String.t() | nil,
  files: [String.t()],
  modules: [module_entry()],
  n: non_neg_integer(),
  parent: non_neg_integer() | nil,
  proven_at: String.t() | nil,
  quiet: boolean(),
  rationale: String.t(),
  reason: String.t() | nil,
  restarted: boolean(),
  reverted_at: String.t() | nil,
  runtime: String.t() | nil,
  selftests: [selftest()],
  status: status(),
  warnings: [String.t()]
}
```

# `empty`

```elixir
@spec empty() :: t()
```

Generation 0: the empty Dyn layer.

# `ever_active?`

```elixir
@spec ever_active?(t()) :: boolean()
```

Was it ever the active generation (so reverting to it makes sense)?

# `from_json`

```elixir
@spec from_json(map()) :: t()
```

Reads a manifest's JSON back; unknown statuses and kinds fall back to defaults.

# `to_json`

```elixir
@spec to_json(t()) :: map()
```

The manifest's JSON form (string statuses and kinds).

---

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