Skip to content

Conversation

@jimsynz
Copy link
Contributor

@jimsynz jimsynz commented Jan 3, 2026

Summary

  • Convert commands from Task-based to GenServer-based execution for interruptibility and message handling
  • Commands become short-lived GenServers that can react to safety state changes and other messages during execution
  • Add support for parameterised command options with ParamRef resolution
  • Extract shared parameter resolution logic to BB.Server.ParamResolution

Changes

New modules

  • BB.Command.Server - GenServer wrapper for command callback modules
  • BB.Command.ResultCache - ETS-based cache for command results (handles race between process death and await)
  • BB.Error.State.CommandCrashed - Structured error for crashed commands
  • BB.Server.ParamResolution - Shared param resolution logic extracted from all server modules

Updated modules

  • BB.Command - Full behaviour with __using__ macro, new callbacks (handle_command/3, result/1, handle_safety_state_change/2, handle_options/2)
  • BB.Robot.Runtime - Start GenServer instead of Task, handle completion via cast
  • BB.Supervisor - Add DynamicSupervisor for commands
  • BB.Dsl - Accept {module, opts} tuple format for command handlers
  • Built-in commands (Arm, Disarm, MoveTo) updated to new pattern
  • Actuator.Server, Sensor.Server, Controller.Server - Use shared ParamResolution

Documentation

  • Updated 05-commands.md tutorial for GenServer-based commands
  • Added structured errors guidance to AGENTS.md

Breaking Changes

  • Command handlers must now implement BB.Command behaviour with new callbacks
  • handle_command/3 replaces the old execute/2 callback
  • Commands must implement result/1 to extract the result from state

Test plan

  • All existing tests pass (763 tests)
  • New tests for command options (static, parameterised, option updates)
  • Dialyzer passes
  • Credo passes

…cution

Commands are now short-lived GenServers that can react to safety state
changes and other messages during execution. Key changes:

- `BB.Command` behaviour with `handle_command/3`, `result/1`, and
  `handle_safety_state_change/2` callbacks
- `BB.Command.Server` GenServer wrapper managing lifecycle, param
  subscription, and result extraction
- `BB.Command.ResultCache` ETS-based cache enabling `await/2` to retrieve
  results even after command process terminates
- `BB.Command.await/2` and `yield/2` use `GenServer.call` with cache fallback
- Commands can control state transitions via `next_state` option in result
- Updated Arm, Disarm, and MoveTo commands to new pattern

BREAKING CHANGE: Command handlers must now implement `BB.Command` behaviour
with `handle_command/3` and `result/1` callbacks instead of the previous
`handle/2` pattern.
- Update DSL handler type to accept `{module, keyword_list}` tuple
- Add `imports: [BB.Dsl.ParamRef]` to command entity for `param()` function
- Fix bug in Command.Server passing robot_module instead of robot_state
- Add comprehensive tests for static and parameterised command options
The param resolution pattern was duplicated across Actuator.Server,
Sensor.Server, Controller.Server, and Command.Server. This extracts
the common logic into a shared module providing:

- `resolve_and_subscribe/2` - resolve ParamRefs and subscribe to changes
- `resolve/2` - resolve ParamRefs without subscribing
- `subscribe/2` - subscribe to parameter change topics
- `handle_change/4` - handle parameter change messages

All four server modules now use this shared implementation, removing
approximately 70 lines of duplicated code.
@jimsynz jimsynz merged commit e31a615 into main Jan 3, 2026
14 checks passed
@jimsynz jimsynz deleted the feature/genserver-commands branch January 3, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants