7.7 KiB
ADR 0015: Simulation Polygon as a qualification boundary
Status
Accepted for architecture; SIM S0 qualification returned GO on 2026-07-24.
Navigation behavior, safety behavior and real actuator authority are not
accepted.
Context
Mission Core has proven a K1 observation/archive/perception vertical, but the perception outputs do not yet have a closed-loop consumer. Adding Gazebo, PX4, ROS 2 and Nav2 directly to the web process or modeling every experiment as an observation session would blur product ownership, lifecycle, evidence and authority.
Replay, physics simulation, a digital twin, HIL and real shadow also have
different causal meaning. A recorded stream cannot react to a hypothetical
command, while a closed-loop world can. Calling both SimulationRun would make
reports easy to misuse.
Decision
- Polygon is a first-class Mission Core bounded context for autonomy qualification and assurance.
- Mission Core owns scenarios, qualification-run lifecycle, authority policy, canonical contracts, provenance, evidence admission, evaluation and reports.
- Gazebo, PX4 SITL, ROS 2, Nav2, Rerun and datasets are replaceable providers.
QualificationRunis the umbrella aggregate. Its kinds explicitly separatesimulation_closed_loop,replay_shadow,digital_twin_closed_loop,controller_in_loop,hilandphysical_shadow.- Simulation Orchestrator is the sole process-lifecycle owner. Gazebo and PX4 do not run inside the Mission Core web process, and the browser has no direct PX4 channel.
- Gazebo
/clockis authoritative in closed-loop simulation. ROS 2 uses simulated time and PX4 uXRCE-DDS time synchronization is disabled for this profile. - Mission Core uses ENU/FLU. PX4 uses NED/FRD. Exactly one adapter boundary converts frames and requires golden tests.
- The first command boundary permits only rover speed+steering and speed+yaw-rate profiles with sequence, TTL, heartbeat, watchdog and stop-on-loss behavior. Direct actuator setpoints are rejected.
- Source-of-record, derived artifacts and presentation state remain separate. Reset creates a new immutable run/episode.
- Ground truth is evaluator-only and is not visible to perception or planning.
- SIM S0 targets the reviewed Windows 11 worker through a dedicated
MissionCore-SimWSL2 Ubuntu 24.04 distribution physically underD:\NDC_MISSIONCORE. - SIM S0 does not depend on the existing Docker Desktop runtime. Its WSL backend is C-backed and currently serves unrelated co-tenants.
- S1 uses exact
px4_msgsdirectly. The experimentalpx4-ros2-interface-libis not a mandatory S1 dependency. - A top-level Polygon UI is gated on accepted contracts and a proven S1 backend lifecycle with persisted run history.
- Real actuator authority requires a new decision and physical safety gate.
- S0 processes run inside an ephemeral loopback-only Linux network namespace. Micro XRCE-DDS Agent's UDP wildcard bind is acceptable only inside that boundary; no S0 listener may be reachable from the worker LAN or Windows host network.
Consequences
- Perception can be measured by downstream decisions without granting it hidden behavior authority.
- Standard planners and future Mission Core planners can be compared on the same scenario and metric profiles.
- Replay cannot be presented as closed-loop safety evidence.
- Provider upgrades require explicit compatibility and evidence refresh.
- More up-front domain and artifact work is required before a visual demo.
- The AI worker must satisfy D-only, resource and coexistence constraints before installation is accepted.
- Simulation and HIL reduce risk but do not certify the real trike.
First implementation
The qualification doctor is deliberately read-only:
simulation/s0/qualification-profile.yamlis the accepted S0 stack, storage, clock, authority, port and process contract.k1link.simulation.s0strictly validates that contract and optional digest-bound worker evidence.missioncore-sim s0 doctorinspects the current host without installing, starting or modifying anything.- MISSIONCOR-40 tracks factual worker qualification.
The first target bootstrap also includes simulation/s0/worker-smoke.sh. It
creates the reviewed loopback-only namespace, starts only the pinned stock-rover
providers, observes ROS 2 vehicle status and Gazebo clock, requests PX4 shutdown,
checks for owned-process residue and writes D-only factual artifacts. It never
arms the vehicle or sends an actuator command.
simulation/s0/gazebo_time_control.py owns the S0 pause/single-step/1×/2× RTF
and resource acceptance probe. simulation/s0/build_evidence_manifest.py
admits only exact-profile, D-confined, passing 1×/2× runs into the digest-bound
evidence generation. These scripts are qualification tooling; the S1
Simulation Orchestrator remains the future product lifecycle owner.
The doctor reports INCOMPLETE until it is running on the reviewed target with
resolved/accepted pins and all required evidence. On the accepted profile
generation and nine-claim confined evidence set it returned GO; it cannot
infer that result from repository state alone.
S1A implementation
k1link.simulation.contracts now defines the first product-owned
QualificationRun, provider/authority/artifact provenance, canonical
Ackermann and Differential rover setpoints, and qualification events.
k1link.simulation.run_store persists them as an immutable manifest plus
one-file-per-sequence append-only journals. Exclusive creation and file/directory
fsync prevent partially acknowledged records; loading rejects gaps, identity
drift, non-regular records and illegal lifecycle history.
The aggregate derives its current state by replay. Terminal runs cannot accept
new events, commands or artifacts. A restart never silently resumes an active
run: reconciliation terminates it as failed with
orchestrator-recovery-interrupted. Reset requires a terminal parent and
creates a new linked run/episode. Commands are admitted only for a running
closed-loop virtual run with the current authority generation and bounded
simulation-time TTL. Replay/shadow commands, direct actuator authority and
ungated HIL/controller-in-loop admission fail closed.
This increment proves the local lifecycle/repository contract. It does not yet own provider processes, transmit a PX4 setpoint, execute heartbeat/watchdog failsafe behavior, or qualify navigation/safety behavior. The target orchestrator must place the caller-supplied repository root under the accepted D-only worker boundary.
S1B ownership foundation
k1link.simulation.orchestrator now owns the application lifecycle through a
transport-neutral worker port. Start and stop requests are persisted with
idempotency identity, one active run owns a worker at a time, and
pause/resume/step/reset cannot bypass run-state validation. Provider start
failure, S0 profile drift, stop residue and restart interruption all become
explicit run events and terminal failures.
k1link.simulation.process_supervisor provides the worker-local POSIX ownership
primitive: shell-free argv, dedicated provider PGIDs, run-scoped logs, atomic
process registry, partial-start rollback and ascending shutdown order matching
the accepted S0 dependency graph. k1link.simulation.worker binds that
primitive to the exact accepted S0 profile digest and canonical D-only S1 run
artifact and process-runtime layouts.
This is not target-worker acceptance. Provider specifications, loopback network namespace creation, live readiness probes, restart-safe PID/start-token reconciliation and Gazebo world-control/PX4 command adapters remain open. The worker port deliberately fixes ownership semantics without prematurely fixing the eventual transport.