<!-- Source: https://docs.biosimulant.com/references/bioworld-api -->

# BioWorld API

`BioWorld` is the communication-step orchestrator. It drains finite before/after
modules, advances each-window modules, commits outputs atomically, and routes
signals through validated connections.

## Creating a world

```python

world = biosim.BioWorld(communication_step=0.1)
```

`communication_step` is required. It defines the synchronization cadence for inter-module exchange.

## Execution model

- Ready `ONCE_BEFORE_RUN` modules drain in deterministic dependency layers at the
  run start boundary.
- Every run advances in windows `[t, t + communication_step]`.
- Inputs for a window are collected from the committed signal store at the start boundary.
- The world invokes every `EACH_WINDOW` module across the same positive window.
- The world normalizes and commits all outputs atomically at the end boundary.
- Ready `ONCE_AFTER_RUN` modules drain after the final window commit.
- The kernel has no execution-order scheduling contract. Tied-time ordering is intentionally not part of the public semantics.

Outputs produced during one window are visible to downstream modules on a later
communication turn. This keeps tied-time behavior order-independent.

## Running a simulation

```python
world.run(duration=10.0)
```

`duration` is the simulation-time horizon. The world does not accept the legacy external tick parameter.

If the world has not been set up yet, `run()` calls `setup()` automatically before the first window.

## Final propagation

```python
world.run(duration=10.0)
world.settle(steps=1)
```

`settle()` performs zero-time communication turns after the requested duration.
It schedules only modules downstream of outputs published at the last boundary,
delivers their committed inputs, calls `advance_window(current_time, current_time)`,
and commits any outputs they publish as the next propagation frontier.

Use settling for legacy temporal report, export, or visualization modules that
should consume final producer outputs. Canonical modules are excluded from
zero-time settling; use `ONCE_AFTER_RUN` for finite final analysis. Once-policy
dependency chains drain automatically.

## Runtime events

```python
from biosimulant import WorldEvent

def listener(event, payload):
    print(event.value, payload)

world.on(listener)
world.run(duration=1.0)
world.off(listener)
```

| Event | When |
|-------|------|
| `STARTED` | Before the first communication window |
| `STEP` | After each committed communication window |
| `FINISHED` | After the run exits, including stopped runs |
| `PAUSED` | When a paused run reaches a pause boundary |
| `RESUMED` | When a paused run resumes |
| `STOPPED` | When a cooperative stop request is honored |
| `ERROR` | When an exception escapes the run loop |

`STEP` payloads include progress fields such as `t`, `window_start`, `window_end`, `start`, `end`, `duration`, `progress`, `progress_pct`, and `remaining`.

## Control flow

```python
world.request_pause()
world.request_resume()
world.request_stop()
```

These controls are cooperative. They take effect at communication boundaries, not mid-window.

## Snapshots and branching

```python
baseline = world.snapshot()

world.run(duration=5.0)
world.restore(baseline)

branch = world.branch()
branch.run(duration=5.0)
```

Snapshots capture:

- current simulation time
- committed signal store
- per-connection event and stale-read delivery state
- per-module snapshot payloads
- once-policy completion state
- setup config

`BioWorld` does not expose a kernel-level `reset()` method. For repeatable reruns, restore a snapshot or build a fresh world.

## Signal semantics

- Source timestamps are preserved as `emitted_at`.
- State signals are held until that source module publishes a non-empty replacement mapping.
- Event signals persist in the store but are delivered once per connection per source timestamp.
- Staleness is checked against the consuming port's `SignalSpec.max_age` and `stale_policy`.

## Visuals

```python
visuals = world.collect_visuals()
for entry in visuals:
    print(entry["module"], len(entry["visuals"]))
```

Modules that implement `visualize()` can publish transport-safe visualization specs for Labs Serve UI and platform consumers.

If a separate downstream module builds the visualization, give it
`ExecutionPolicy.ONCE_AFTER_RUN`. It then runs after the final window with the
final committed inputs. Settle turns do not invoke `execute()` modules.

## See Also

- [BioModule API](/references/biomodule-api)
- [WiringBuilder API](/references/wiring-api)
- [BioSignal & SignalSpec](/references/signals)
- [How to Use a BioWorld](/how-to/use-bioworld)
