Simulation
A scenario says where it runs and owns both sides. Start one and the pipeline sees simulated observations through the same door a sensor uses; stop it and the run is on the record.
Scenarios
Every route here wants a credential and X-Workspace-Id. Without the workspace header a
route answers 400 and names it.
curl https://<your-backend-host>/api/scenarios \
-H "Authorization: Bearer $TOKEN" -H "X-Workspace-Id: $WORKSPACE"
curl -X POST https://<your-backend-host>/api/scenarios \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" -H "X-Workspace-Id: $WORKSPACE" \
-d '{ "name": "Harbour, two waves", "spec": { "…": "…" } }'
A scenario row is a name and a spec: the seed, the region, the environment, the
forces, the time and the video. Each force has an id, a side (defender or
adversary), a controller (c2 for a force DomeCommand flies, scenario for one the
simulator flies), an optional objective, its drones as a swarm or a specific list,
and its assets: sensors and effectors, each with an id and roles. A worked document is
on Scenario model, and the whole run in curl on
Running a simulation.
The spec is stored in its canonical form. A document written in the shorthand, with a
friendlies fleet and an attack fleet, comes back as forces, the defending force carries
the default sensor layout, and keys nothing reads are dropped. Read the answer rather than
assuming it matches what you sent. A spec that does not deserialise is refused with 400
and the field that broke it.
PUT /api/scenarios/{id} replaces the spec, canonicalised the same way. DELETE removes it.
The simulation lifecycle
curl https://<your-backend-host>/api/sim/simulators # what this build can run
curl https://<your-backend-host>/api/sim/state # what is running now
curl -X POST https://<your-backend-host>/api/sim/start \
-H "Content-Type: application/json" -d '{ "scenario_id": "<uuid>" }'
curl -X POST https://<your-backend-host>/api/sim/pause \
-H "Content-Type: application/json" -d '{ "paused": true }'
curl -X POST https://<your-backend-host>/api/sim/stop
PUT /api/sim/state selects the workspace's simulation mode and simulator; it
answers 409 while a run is live and the change would swap the environment out
from under it. Progress during a run rides the stream:
simulated tracks arrive as track_update events flagged simulated, and the
picture's sim block carries the run's clock.
A build without the simulator feature has no embedded simulator to drive, and
POST /api/sim/start answers 501 on one.
Recorded runs
Every run is recorded: which scenario, when, and every event the pipeline produced while it ran.
curl "https://<your-backend-host>/api/sim/runs?limit=20"
curl https://<your-backend-host>/api/sim/runs/<run-id>
curl "https://<your-backend-host>/api/sim/runs/<run-id>/events?kind=track&limit=1000"
curl -X DELETE https://<your-backend-host>/api/sim/runs/<run-id>
The events route takes the same kind, since, until and limit filters as
the event log, scoped to one run. Replaying a run is reading
its events back in order; reproducing one is starting its scenario again from the
same seed.