# SIM S1C live-worker runbook

## Scope

This runbook starts the first browser-visible stock Ackermann rover through the
Mission Core control plane. It accepts only a virtual PX4/Gazebo run. It does
not admit a physical vehicle, direct actuator setpoints, navigation or safety.

Runtime placement:

```text
React Control Station
  -> same-origin Mission Core Polygon API
  -> mode-0600 Unix socket
  -> unprivileged Simulation Worker agent
  -> loopback-only network namespace
  -> Micro XRCE-DDS Agent + PX4 SITL + Gazebo Harmonic
```

The Unix socket is ephemeral runtime coordination. Source, run journals,
provider logs and qualification artifacts remain under
`/mnt/d/NDC_MISSIONCORE/simulation`.

## Preconditions

- use the dedicated `MissionCore-Sim` WSL distribution;
- stage an immutable Git archive below the reviewed D root;
- verify its SHA-256 against the source artifact;
- use an exact 40-character Mission Core commit;
- confirm no PX4, Gazebo or Micro XRCE-DDS provider residue exists;
- keep `actuator_authority=false`;
- do not add a routed NIC to the worker namespace.

## Start worker agent

From the exact staged source generation:

```bash
sudo simulation/s1/worker-agent.sh <exact-40-character-commit>
```

The wrapper creates `/run/missioncore-sim` as a private runtime directory,
enters a fresh network namespace, raises only loopback and drops to the
`missioncore` user before importing product code.

Expected status through the backend gateway:

```json
{
  "schema_version": "missioncore.simulation-worker-status/v1",
  "worker_id": "mission-gpu-s1",
  "transport": "unix",
  "mode": "simulation",
  "available": true,
  "control_available": true,
  "active_run_id": null,
  "run_state": null
}
```

## Start Mission Core

```bash
export MISSIONCORE_POLYGON_RUNS_ROOT=/mnt/d/NDC_MISSIONCORE/simulation/artifacts/s1/runs
export MISSIONCORE_POLYGON_WORKER_SOCKET=/run/missioncore-sim/worker.sock
export MISSIONCORE_POLYGON_WORKER_CONTROL=internal-virtual-only
export MISSIONCORE_COMMIT=<exact-40-character-commit>
uv run uvicorn k1link.web.app:app --host 127.0.0.1 --port 8765
```

Open the Control Station:

```text
http://127.0.0.1:8765/
```

After Mission Core confirms the worker, `Полигон` must appear in the header and
open the live workspace directly. The
`?workspace=polygon-run[&run=<qualification-run-id>]` URL remains a compatible
deep-link. The live panel must show `Worker готов`. Start/stop calls require an
`Idempotency-Key`; the React client generates one per operator intent. Removing
the `internal-virtual-only` environment gate must leave status visible while
disabling lifecycle actions.

## Live-state contract

The first S1C live sample comes from:

```text
/world/rover/dynamic_pose/info
```

It is published to the browser as `missioncore.vehicle-state/v1` with:

- `frame_id=map_enu`;
- `child_frame_id=base_link_flu`;
- integer Gazebo simulation time;
- bounded position and quaternion;
- `signal=ground-truth`;
- `quality=diagnostic`;
- `scope=virtual-only`;
- no navigation or safety acceptance.

This signal proves live presentation and frame naming only. It is not the
accepted PX4/ROS 2 telemetry path.

## Acceptance checklist

- [ ] exact source commit and source/build SHA-256 recorded;
- [ ] focused target tests pass from the same staged generation;
- [ ] worker status reports loopback-only, unprivileged and D-only boundaries;
- [ ] browser start creates one new immutable qualification run;
- [ ] status traverses `starting -> running`;
- [ ] both provider IDs appear only after readiness;
- [ ] live samples advance in Gazebo time;
- [ ] React shows run ID, sim time, ENU pose and provider list;
- [ ] archive remains path-free and command content is not exposed;
- [ ] browser stop reaches terminal `completed`;
- [ ] stop records `operator-stop-clean`;
- [ ] PX4, Gazebo and Micro XRCE-DDS leave no process residue;
- [ ] command count remains zero until the command-delivery checker is accepted.

## Failure handling

- A missing socket returns unavailable status; it does not fall back to PX4.
- Start/stop is `403` without the explicit backend control gate.
- Commit drift is rejected before provider start.
- A malformed or oversized worker message fails the gateway contract.
- Provider readiness failure seals the run as failed and triggers supervised
  cleanup.
- Agent termination aborts an active run and stops owned provider groups.
- Agent restart reconciles an interrupted journal as failed; restart-safe
  cross-process PID ownership remains a separate open checker.
