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

One learning module, one process — a cortical column with a mailbox.

The process is deliberately thin: `matching_step`, `send_out_vote`,
`receive_votes` and the rest are callbacks on a pure module
(`Monty.Frameworks.Models.AbstractMontyClasses.LearningModule`), and the
order in which they are called belongs to `Monty.Runtime.Step`, not here.

Keeping the algorithm out of the GenServer is what makes the column
testable twice over: directly as a function, and through the process for the
things only a process has — isolation, restart, mailbox ordering.

The client API below is the only way in, so call sites read as
`LearningModuleServer.matching_step(server, percepts, ctx)` and every entry
point carries a typespec.

# `id`

```elixir
@type id() :: atom() | String.t()
```

# `percepts`

```elixir
@type percepts() :: [Monty.Cmp.Message.t()]
```

# `server`

```elixir
@type server() :: GenServer.server()
```

# `spec`

```elixir
@type spec() :: %{id: id(), model_id: id(), module: module(), state: term()}
```

# `vote`

```elixir
@type vote() :: term()
```

# `add_lm_processing_to_buffer_stats`

```elixir
@spec add_lm_processing_to_buffer_stats(server(), boolean()) :: :ok
```

Records whether this step's observation reached the module.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear_buffers`

```elixir
@spec clear_buffers(server()) :: :ok
```

Drops what the module accumulated, keeping what it learned.

What a run without episode boundaries asks of its modules when the object
under the sensor changes: Monty's `_reset_modules_buffers`.

# `clear_conclusion`

```elixir
@spec clear_conclusion(server()) :: :ok
```

Forgets what the module concluded, keeping what it believes.

# `clear_hypotheses`

```elixir
@spec clear_hypotheses(server()) :: :ok
```

Drops the hypotheses of a module the experiment does not supervise.

# `exploratory_step`

```elixir
@spec exploratory_step(server(), percepts(), Monty.Context.t()) :: :ok
```

# `fixme_update_ground_truth`

```elixir
@spec fixme_update_ground_truth(server()) :: :ok
```

Records which objects the graph a training episode built came from.

# `get_output`

```elixir
@spec get_output(server()) :: Monty.Cmp.Message.t() | nil
```

The module's top-down output, or `nil`.

Read at the start of a step; the coordinator decides whether it is
delivered (the receiver must also have seen a sensor percept).

# `graph_memory`

```elixir
@spec graph_memory(server()) ::
  Monty.Frameworks.Models.GraphMatching.GraphMemory.t() | :none
```

The long-term memory this module holds, or `:none`.

A training episode's memory is handed to the next one, and the module is what
holds it — asked here rather than read off the state, because only the module
knows where in its state the memory is.

# `matching_step`

```elixir
@spec matching_step(server(), percepts(), Monty.Context.t()) :: :ok
```

# `observation_processed?`

```elixir
@spec observation_processed?(server()) :: boolean()
```

Whether the last buffered observation was one this module processed.

# `propose_goals`

```elixir
@spec propose_goals(server()) :: [Monty.Cmp.Goal.t()]
```

# `propose_region`

```elixir
@spec propose_region(server()) :: Monty.Cmp.AttentionRegion.t()
```

# `query`

```elixir
@spec query(server(), (term() -&gt; answer)) :: answer when answer: var
```

Asks the module a question about its state, and answers only the answer.

`projection` runs inside the process that owns the state, so a caller that
wants four numbers out of a module holding ten object models asks for those
four numbers instead of copying the models across to read them. Copying is
not free: the graph memory of a pretrained ten-object module is tens of
megabytes, and a page that refreshes every step was paying for it per step.

The projection must not change the state — this is a read, and the module is
left exactly as it was.

# `receive_votes`

```elixir
@spec receive_votes(server(), [vote()]) :: :ok
```

# `reset_stm`

```elixir
@spec reset_stm(server()) :: :ok
```

# `send_out_vote`

```elixir
@spec send_out_vote(server()) :: vote()
```

Sends what this module believes, for the vote round to combine.

# `set_experiment_mode`

```elixir
@spec set_experiment_mode(server(), term()) :: :ok
```

Tells the module whether this episode trains or evaluates.

# `set_primary_target`

```elixir
@spec set_primary_target(server(), map() | nil) :: :ok
```

Names this episode's object without emptying the module's history.

# `set_stepwise_target`

```elixir
@spec set_stepwise_target(server(), String.t()) :: :ok
```

Records which object the module's sensor is on this step.

# `set_target`

```elixir
@spec set_target(server(), map() | nil) :: :ok
```

Names the object this episode is about, as the experiment knows it.

# `set_terminal_state`

```elixir
@spec set_terminal_state(server(), term()) :: :ok
```

Times the module out without asking it to reconsider.

# `start_link`

```elixir
@spec start_link(spec()) :: GenServer.on_start()
```

# `state`

```elixir
@spec state(server()) :: term()
```

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

# `supervise`

```elixir
@spec supervise(server(), map(), [number()]) :: :ok
```

Monty's `_pass_target_info_to_model`: the conclusion an experiment states.

A pretraining experiment does not match; it knows what it showed the agent.
`location_on_model` is where the object stood the first time this experiment
showed it, so a graph stays where it was learned.

# `update_ltm_from_stm`

```elixir
@spec update_ltm_from_stm(server()) :: :ok
```

Folds the episode into long-term memory, if it was a training episode.

# `update_stats_after_vote`

```elixir
@spec update_stats_after_vote(server()) :: :ok
```

Settles what the vote round left this module believing.

Monty's `update_stats_after_vote`, asked of every module after a round — the
module that heard nothing is exactly the one that can have nothing possible.

# `update_terminal_condition`

```elixir
@spec update_terminal_condition(server()) :: term()
```

Checks the module's terminal condition and replies with what it concluded.

---

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