# `Monty.Runtime.Model`
[🔗](https://github.com/d-led/ex.tbp.monty/blob/v0.1.0/packages/ex_tbp_monty_core/lib/monty/runtime/model.ex#L1)

One running Monty model: its modules as supervised processes, and the step
coordinator.

The supervision tree is the wiring. Sensor and learning modules are children
with `restart: :permanent`, the coordinator is last, and the strategy is
`:one_for_one` — a module that dies is replaced while the coordinator keeps
its step count, because it addresses modules by registered name rather than
by pid. The episode's random stream (`Monty.Random.Stream`) is a child too:
it outlives a step and a module, and dies with the model.

`start_link/1` takes the model id plus the module specs:

    Monty.Runtime.Model.start_link(%{
      model_id: :demo,
      sensor_modules: [%{id: :patch, agent_id: "agent_id_0", module: SomeSM, state: SomeSM.new()}],
      learning_modules: [%{id: :lm_0, module: SomeLM, state: SomeLM.new()}],
      sm_to_lm: %{lm_0: [:patch]},
      motor: {SomeMotor, SomeMotor.new()}
    })

Steps are driven from outside (`step/4`) because the environment owns the
clock; a LiveView, an Oban job or a test decides when the next step happens.

# `options`

```elixir
@type options() :: map()
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `detailed`

```elixir
@spec detailed(atom() | String.t(), (term() -&gt; term())) ::
  Monty.Runtime.Step.detailed()
```

The modules' own states as they stand, for a logger writing an episode in full.

Monty's loggers read their modules straight off the model; here the modules are
processes, so this is the model being asked for all of them at once. See
`Monty.Runtime.Step.detailed/2` for why the caller brings a projection.

# `done?`

```elixir
@spec done?(atom() | String.t()) :: boolean()
```

Whether the model has concluded this episode.

# `fixme_set_ground_truth`

```elixir
@spec fixme_set_ground_truth(atom() | String.t(), map() | nil, keyword()) :: :ok
```

Tells every module which object this episode is about.

# `reset_episode`

```elixir
@spec reset_episode(atom() | String.t()) :: :ok
```

Clears short-term memory for a new episode, keeping long-term memory.

# `set_experiment_mode`

```elixir
@spec set_experiment_mode(
  atom() | String.t(),
  Monty.Frameworks.Models.AbstractMontyClasses.LearningModule.mode()
) :: :ok
```

Tells the model and its modules whether this episode trains or evaluates.

# `start_link`

```elixir
@spec start_link(options()) :: Supervisor.on_start()
```

# `state`

```elixir
@spec state(atom() | String.t()) :: Monty.Runtime.Step.State.t()
```

The coordinator's state, for tests and the run inspector.

# `status`

```elixir
@spec status(atom() | String.t()) :: Monty.Experiment.RecognitionStrategy.model()
```

The four things a recognition policy may read off the model.

# `step`

```elixir
@spec step(atom() | String.t(), map(), map(), Monty.Context.t()) ::
  {:ok, [map()], map()}
```

Runs one step of a model by id.

A coordinator that dies takes the step with it, and `GenServer.call` hands the
caller an exit whose reason is the exception the step was running. That exit is
unwrapped here, so the caller sees the exception the step died of — with the
step's own traceback, where the failing module's frame is — rather than "a
process exited", which is all a page could say about it otherwise
(`Monty.Studio.Failure`).

Anything else a call can be handed stays an exit: a model that is not running
is nobody's exception.

# `stop`

```elixir
@spec stop(atom() | String.t()) :: :ok | {:error, :not_found}
```

Stops a model started under the application's `ModelSupervisor`.

A model is stopped by terminating its supervisor; the children go with it, so
no module process outlives the run it belonged to.

# `supervise`

```elixir
@spec supervise(atom() | String.t(), map(), [number()], [String.t()]) :: :ok
```

Tells the modules the episode's answer, as a supervised experiment knows it.

Monty's `_pass_target_info_to_model`: the modules the experiment names are
given the object, its pose and where it stood; every other module's hypotheses
are dropped, because what it guessed is not something to learn from.

# `switch_to_exploratory_step`

```elixir
@spec switch_to_exploratory_step(atom() | String.t()) :: :ok
```

Switches the model into exploratory mode.

# `time_out`

```elixir
@spec time_out(atom() | String.t()) :: :ok
```

Ends the episode without a conclusion.

# `update_ltm`

```elixir
@spec update_ltm(atom() | String.t()) :: :ok
```

Hands what the episode saw to long-term memory.

# `via`

```elixir
@spec via(atom() | String.t()) :: {:via, module(), {atom(), term()}}
```

A `:via` name for a model's supervisor.

---

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