Skip to main content

Modular Simulation Kernel

Why this shape

The product must support deterministic fixed-step runs, placed and scheduled stimuli, saved experiments, a future Python step/action interface, and later headless execution. Putting those rules inside UI scenes would make replay, testing, and external control fragile. The kernel is independent of the renderer and coordinates small feature modules.

This is a pragmatic modular kernel, not a promise of arbitrary runtime code installation. Sprint 1 plugins are reviewed source modules registered by the composition root.

Boundary

Godot UI / future Python API
|
commands + state
|
SimulationKernel
- fixed-step clock
- seeded RNG
- lifecycle
- ordered plugins
- event stream
|
+-------+---------+------------+----------+
| | | |
ArenaPlugin StimulusPlugin AgentPlugin RecorderPlugin

The kernel is the only owner of simulated time and seeded randomness. Plugins must never create their own unseeded random generator or advance time.

UI panels never retain a kernel reference. They emit intent signals to the app shell; the shell calls the stable kernel API and routes stepped and run_state_changed updates back to interested panels. This lets different team members work in src/app/panels/ without repeatedly editing main.gd.

Simulation speed changes how many fixed steps are executed per display tick. It never changes fixed_delta, the experiment seed, or simulation rules. Max speed uses a small per-frame time budget so the UI remains responsive.

Plugin lifecycle

Every module implements SimulationPlugin:

  1. plugin_id() returns a stable unique identifier.
  2. priority() controls deterministic execution order.
  3. initialize(context, experiment) receives shared state and configuration.
  4. before_step(context) handles inputs and scheduled changes.
  5. step(context) advances the feature by exactly one fixed step.
  6. after_step(context) observes the completed step.
  7. shutdown(context) releases run-specific state.

The current ordering is arena, stimuli, controller, recorder. IDs and priorities are part of the compatibility contract.

Experiment model

An experiment is one versioned JSON document:

metadata + simulation + arena + stimuli + protocol + treatment + controller
  • Geometry defines boundaries and physical regions.
  • A region can have a semantic zone and a surface material.
  • Stimulus sources have a type, position, radius, and properties.
  • Protocol entries switch sources at integer steps.
  • Treatment identifies no-treatment, medicine, or placebo conditions and an administration step.
  • The controller is replaceable: statistical now, Python/external later.

Materials and stimuli are separate. A bridge can use wire mesh while also being brightly illuminated; wood-chip bedding can affect movement while an odour source independently affects sensing.

Determinism rules

  • Advance only in integer steps with a fixed delta.
  • Initialize the one shared RNG from the experiment seed.
  • Keep plugin order stable.
  • Record interventions at their effective step.
  • Do not use wall-clock time in simulation decisions.
  • Do not mutate a saved experiment during a run.
  • A future replay check must compare a state hash at every step.

Near-term decisions still required

  • Backend language/framework and database.
  • HTTP/WebSocket boundary between Godot and backend.
  • Authentication provider/library.
  • External API integration required by the general project brief.
  • Documentation-site generator and hosting.