PATROL-LAB · Q&A
Technical questions & answers
How the simulation, mission DSL, determinism and LLM plugins actually work — searchable and filterable by tag. For product-level questions, see the FAQ.
Why is the gait kinematic instead of a dynamics simulation?
The perf budget is 60 fps on an integrated-GPU laptop, and the whole simulation runs client-side. A browser MuJoCo dynamics loop on top of the three.js render loop is outside that budget, so locomotion is a kinematic trot with heading control. The trade-off is stated in the UI (SIM KINEMATIC) instead of hidden — honesty over hype.
How does the interpreter keep runs reproducible?
The MissionRunner interprets the DSL on a fixed 120 Hz timestep with a seeded RNG for sensor findings. Nothing reads wall-clock time or request timing, so a mission with the same seed produces the same statements, readings, alerts and DONE event — in dev, in e2e, and on the deployed site.
What can the mission DSL express today?
MISSION/END, GOTO (with optional SPEED), INSPECT with a sensor atom (THERMAL, VISUAL, ACOUSTIC) and optional ALERT IF thresholds (TEMP, GAS, VIBRATION), plus WAIT and a global SPEED. Before each INSPECT the robot implicitly repositions to the POI. Parse errors carry line and column, surfaced in the editor's lint gutter.
Where exactly is the LLM's boundary?
Two stateless API routes: /api/llm/compile (natural language → mission DSL) and /api/llm/report (grounded report from the mission log). The compiler's output must pass the DSL parser; a bounded retry feeds parser errors back to the model. If it still fails, you see the errors — the LLM never gets an execution path around the interpreter.
What happens without an OPENAI_API_KEY?
The app is fully functional. MOCK_MODE supplies rule-based artifacts: the compiler emits a template mission and the report writer summarizes the real mission log. Both are labeled in the UI (MOCK, RULE-BASED) so a mock output is never mistaken for a model output.
How does the inspection report avoid made-up numbers?
The report prompt is grounded: it receives the actual mission event log and must return strict JSON summarizing it. The UI renders the summary and recommendations from that contract, and the event IDs cited in the report map back to the live event log — so every claim in a report is checkable against the run.
How does the MuJoCo model become a three.js robot?
scripts/bake_rig.py (uv + mujoco) bakes the MJCF into rig.json, including per-mesh center-of-mass offsets — all 24 meshes are non-zero, so raw XML placement would drift. At runtime the rig builds 13 bodies, 12 hinge joints and 50 visual geoms under a three-space holder group that corrects the MJCF frame (a regression spec guards that quaternion).
How do ~16 MB of robot assets stay off the critical path?
Textures are downscaled to 512 px (12 MB → 1.3 MB) after a cold-start frame-rate flake, the scene loads behind a visible progress bar (asset counter + percentage), and the UI never blocks on the download. The heavy meshes stream async while the console shell is already interactive.
Why is there no A* path planner?
The site graph currently has no obstacles, so straight legs between POIs are already optimal — an A* would add code without changing behavior. The deferral is recorded in the roadmap: it gets revisited when the site gains no-go zones, not before.
How do the follow and orbit cameras differ?
Follow is the default: exponential smoothing with delta-tracking and an ideal-framing drift, plus park-beside-POI approach offsets during inspections. Orbit hands control to OrbitControls and is gated while the robot moves. The toggle in the viewport badge switches modes at any time.
What do the Playwright suites actually assert?
Four specs: smoke (robot loads, 12 joints, >5k tris, no page errors), mission (golden mission completes DONE 10/10 statements with 4 findings, parse errors are refused, step mode advances one line at a time), orientation (a quaternion probe guarding the holder frame), and llm (mock compile → accept → run → report end to end).
How does determinism help the tests?
Because same seed ⇒ same run, e2e can assert exact outcomes: the golden mission finishes DONE with exactly 10/10 statements and 4 findings, every time. A flake in those specs means a real regression, not simulator noise — which is the point of deterministic simulation.
How do I verify a dashboard number is real?
Every KPI reads from interpreter state exposed through the zustand store: mission clock and odometer from the runner, POI coverage from the POI registry, findings and alerts from the event log, seed from the run config. The debug hook window.__patrol exposes frames/tris/joints/mode for exactly this kind of checking.
What does the status vocabulary mean?
IDLE (no mission loaded), EXECUTING/INSPECTING (interpreter mid-statement / mid-scan), PAUSED (held at a line), DONE (all statements executed), FAULT (runtime error). The same words appear in the pill, the event log and the report, so status language is consistent across the console.
Looking for the basics? Read the FAQ — or go back to mission control.