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

One sensor module, one process.

The process holds the module's state and nothing else: every decision is a
callback on the pure module (`Monty.Frameworks.Models.AbstractMontyClasses.SensorModule`).
That split is what lets a sensor module be tested with a plain function call
and still be supervised, restarted and inspected at runtime.

The client API below is the only way in. It is deliberately separate from
the callbacks, so call sites read as `SensorModuleServer.step(server, ...)`
rather than as raw GenServer messages, and every entry point carries a
typespec. The server registers itself in `Monty.Runtime.Registry` under
`{:sensor_module, model_id, id}`: after a restart the name points at the new
process and no stored pid goes stale.

# `id`

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

# `server`

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

# `spec`

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

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear_buffers`

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

Drops the observations this sensor kept, keeping what it has learnt.

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

# `propose_goals`

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

# `propose_region`

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

# `reset`

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

# `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.

# `step`

```elixir
@spec step(server(), map(), map(), Monty.Context.t(), boolean()) ::
  Monty.Cmp.Message.t() | nil
```

Records the sensor's pose and turns one observation into a percept.

One round trip rather than two: `update_state` exists for the module's sake,
not for the caller's.

---

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