Testbed — Interactive Engine Feature Exerciser¶
API reference reflects testbed contract v1
The testbed feature is under active development. The REST endpoints and UI capabilities documented here reflect the testbed contract v1 authored alongside the v0.7.0 release. Implementation status may be ahead of or behind this document at any given commit.
Purpose¶
The testbed provides a browser-based UI for exercising real engine features through the pyjaguar Python bindings. Where the benchmark dashboard measures throughput, the testbed lets you interact with the engine in real time: start and pause scenarios, step frame by frame, inject faults, and observe entity state, events, and domain-specific behaviour.
The testbed tab in benchdash is hidden automatically when pyjaguar is unavailable, so there is no breakage for users who build without Python bindings.
Prerequisites¶
Build the engine with Python bindings enabled:
This produces pyjaguar.so (Linux / macOS) or pyjaguar.pyd (Windows) in the build output directory. The bindings must be on PYTHONPATH or in the same directory as run_bench.py.
Launch¶
Navigate to http://127.0.0.1:8765/index.html and select the Testbed tab. If pyjaguar is not importable, the tab displays an installation notice instead.
Scenario Presets¶
Four scenario presets are available from the UI dropdown:
| Preset | Description |
|---|---|
| Multi-domain | Air, land, and sea entities in a combined-arms exercise |
| Air patrol | Flight of four aircraft flying a racetrack orbit |
| Orbit demo | LEO satellite propagated with corrected SGP4 |
| Custom | User-configurable entity count, domain mix, and integrator |
Playback Controls¶
| Control | Behaviour |
|---|---|
| Play | Start the simulation clock |
| Pause | Freeze the clock; state is preserved |
| Step | Advance exactly one simulation tick |
| Time scale | Multiplier applied to wall-clock dt (1×, 2×, 4×, 8×, 32×) |
Live Entity Table¶
A sortable table shows every active entity updated each tick:
| Column | Description |
|---|---|
| ID | Entity identifier |
| Name | Entity name |
| Domain | Air / Land / Sea / Space |
| Position (LLA) | Latitude, longitude, altitude |
| Speed (m/s) | Scalar velocity magnitude |
| Integrator | Currently assigned integrator name |
| NaN flag | Lit when NaN containment triggered |
Clicking a row opens a detail panel with the full EntityState struct.
Charts¶
- Trajectory — 2-D ground track (latitude vs longitude)
- Altitude — altitude (m) vs simulation time
- Speed — speed (m/s) vs simulation time
Charts update in real time and retain a configurable history window (default: 300 ticks).
Live Event Log¶
The event log streams all events dispatched by the engine during the current run. Each row shows:
| Field | Description |
|---|---|
| Tick | Simulation tick number |
| Sim time | Simulation clock value (s) |
| Type | Event type (e.g., CollisionEnter, Stall, OrbitInsertion) |
| Source | Entity ID that generated the event |
| Category | Event category bitmask |
The log is filterable by event type and entity ID. A maximum of 1000 entries are retained in the browser.
Feature Test Panels¶
Six feature-specific test panels are available from sub-tabs within the Testbed tab:
Atmosphere Profile¶
Plots the US Standard Atmosphere 1976 density, pressure, and temperature curves from 0 to 86 km. Verifies that the StandardAtmosphere model returns physically correct values at layer boundaries.
Integrator Comparison¶
Runs the same initial condition through two integrators (selectable: Euler, RK4, ABM4, DormandPrince, Symplectic) and plots position divergence over time. Useful for verifying that per-entity state isolation is working correctly — the two integrators must not share history.
DIS Encode / Decode Roundtrip¶
Encodes an EntityStatePDU with configurable position and velocity, decodes the bytes back, and displays:
- Hex dump of the raw bytes
- Field-by-field comparison of original vs decoded values
- Pass / fail assertion for each field
NaN Containment Injection¶
Forces a NaN into a selected entity's velocity component on the next tick. The panel confirms that:
- The NaN is detected by
PhysicsSystem. - The entity is rolled back to its last valid state.
- A warn-once log message is emitted.
- The simulation continues without crashing.
REST API¶
All endpoints are served on the same port as the main dashboard (--port, default 8765).
GET endpoints¶
| Endpoint | Response | Description |
|---|---|---|
GET /api/testbed/capabilities |
JSON object | Whether pyjaguar is available; supported feature flags |
GET /api/testbed/state |
JSON object | Current tick, sim time, all entity states |
GET /api/testbed/history |
JSON array | Position/speed history for all entities (last N ticks) |
GET /api/testbed/events |
JSON array | Event log since last poll |
GET /api/testbed/atmosphere |
JSON array | Atmosphere profile 0–86 km (200 sample points) |
POST endpoints¶
| Endpoint | Body | Description |
|---|---|---|
POST /api/testbed/scenario |
{"preset": "air_patrol"} |
Load a scenario preset |
POST /api/testbed/control |
{"action": "play"|"pause"|"step", "time_scale": 1.0} |
Playback control |
POST /api/testbed/integrator_compare |
{"integrators": ["rk4", "euler"], "scenario": "orbit"\|"projectile", "steps": 500, "dt": 0.05} |
Run integrator comparison |
POST /api/testbed/dis_roundtrip |
{"entity_id": 1} |
DIS encode/decode roundtrip |
POST /api/testbed/nan_inject |
{"entity_id": 1, "steps": 5} |
Inject NaN into entity state |
All POST endpoints return {"ok": true} on success or {"ok": false, "error": "..."} on failure.
Architecture Note¶
The testbed server runs in the same Python process as the benchdash pipeline. pyjaguar is imported lazily — if import fails, the /api/testbed/* endpoints return {"ok": false, "error": "pyjaguar not available"} and the front-end hides the tab.
The engine runs in a background thread managed by the testbed server; HTTP handlers and the engine tick loop communicate through a thread-safe queue. Engine state snapshots are copied under a lock before being serialised to JSON.