Skip to main content

Sim hierarchy

Every submission picks one of three run modes. Every device can also declare a per-device sim_override in the topology. The framework combines the two with a fixed resolver — a 12-row lookup — to decide how each action dispatches.

The rule in one sentence: the submission mode is the ceiling; per-device overrides can ratchet toward sim but never toward live.

The three modes

from orca.runtime.run_modes import WorkflowRunMode
ModeWhat dispatches
PURE_SIMEvery device runs against its sim driver. No wire calls. Fast, local.
DEVICE_SIMThe real driver runs; under it, the gateway-routed sim backend (PLR Chatterbox or similar) replaces the hardware backend. Wire is exercised, devices are not real.
LIVEReal drivers on real hardware.

Mode is required on every submission. There's no deployment-level default — runtime.submit(workflow, mode=...) is the only way to specify it. The CLI mirrors this: orca run <workflow> --run-mode <mode> rejects submissions that don't pass --run-mode.

Per-device sim_override

shaker = Shaker("shaker_01", sim_override=WorkflowRunMode.PURE_SIM)

A sim_override on a device pins that device's dispatch independently of what the submission picks. Common use cases:

  • A device is offline for maintenance — pin it to PURE_SIM so workflows can continue running against the rest of the lab.
  • A device is awaiting calibration — pin it to PURE_SIM until validated.
  • You're bringing a new device online — pin it to DEVICE_SIM to exercise driver code without touching hardware.

The override lives at topology construction time. It's read by SystemTopologyRegistry and surfaced on TopologyCard.topology_sim_override. The runtime threads it onto every dispatch through SimulationManager.

sim_override=None (the default) means "follow the submission mode."

The 12-row resolver

resolve_effective_mode_for_device(submission_mode, device_sim_override) is the entire resolver. It returns a ResolvedDeviceMode(resolved, warning).

Submission modeDevice sim_overrideEffective modeWarning?
PURE_SIM(any)PURE_SIMno
DEVICE_SIMNoneDEVICE_SIMno
DEVICE_SIMPURE_SIMPURE_SIM (ratchet down)no
DEVICE_SIMDEVICE_SIMDEVICE_SIMno
DEVICE_SIMLIVEDEVICE_SIM (override silently inert)no
LIVENoneLIVEno
LIVEPURE_SIMPURE_SIM (ratchet down)YES
LIVEDEVICE_SIMDEVICE_SIM (ratchet down)YES
LIVELIVELIVEno

Twelve rows when you fully enumerate device_sim_override ∈ {None, PURE_SIM, DEVICE_SIM, LIVE} against the three submission modes. The collapsed version above is the operative summary.

Two rules govern the table:

  1. Overrides only ratchet toward sim. A device pinned to LIVE under a PURE_SIM submission still dispatches PURE_SIM — the submission ceiling wins.
  2. A LIVE submission warns about sim-direction overrides. Any device pinned to PURE_SIM or DEVICE_SIM under a LIVE submission fires a warning so the operator doesn't accidentally LIVE-deploy with half the lab still in sim.

The LIVE confirmation gate

A LIVE submission against any device with a sim-direction sim_override is refused unless the submission carries acknowledge_warnings=True. The in-process call raises LiveSubmissionWithSimOverridesUnacknowledgedError, whose .devices attribute is the full list of offending devices as (device_name, sim_override, resolved_mode) tuples:

# error.devices
[
("shaker_01", WorkflowRunMode.PURE_SIM, WorkflowRunMode.PURE_SIM),
("sealer_01", WorkflowRunMode.DEVICE_SIM, WorkflowRunMode.DEVICE_SIM),
]

Operators see exactly which devices the LIVE submission would skip before deciding whether to proceed.

To proceed:

SurfaceHow to acknowledge
CLIorca run <workflow> --run-mode LIVE --confirm
Pythonruntime.submit(workflow, mode=WorkflowRunMode.LIVE, acknowledge_warnings=True)

Acknowledging applies to all sim-direction overrides on that submission — it's a single boolean, not a per-device list. If you want LIVE on one of the pinned devices, remove the sim_override on that device first (a topology edit, then a runtime rebuild).

The current_run_mode ContextVar

Internally the resolver result is propagated through current_run_mode: ContextVar[WorkflowRunMode]. It's seeded at each execution entrypoint and re-seeded per-thread at thread start. asyncio.Task inherits a snapshot of the parent context, so child tasks see the seed automatically.

You don't normally read this directly — SimulationManager.driver is the consumer at dispatch time. If you're writing custom dispatch glue (rare) or test code that wants to match the production fallback, the constant UNSEEDED_FALLBACK_MODE (= PURE_SIM) is what reads outside a seeded scope return.

Where it's enforced

LayerWhat it checks
Submission validation (SystemRuntime.submit_workflow / runtime.submit)Computes resolved modes for every device and fires LIVE_SUBMISSION_WITH_SIM_OVERRIDES_UNACKNOWLEDGED if any sim-direction override is present without acknowledge_warnings=True.
Dispatch (SimulationManager.driver)Per-action lookup of current_run_mode.get(); returns the sim driver or the wire driver based on the resolved mode.

Pitfalls

  • Mode is required on every submission. There is no deployment-level default. A bare runtime.submit(workflow) raises. The CLI orca run without --run-mode exits with EXIT_USAGE. This is deliberate — getting the mode wrong is a class of bug worth refusing rather than defaulting.
  • A device pinned to LIVE is NOT a no-op. It tells the resolver "this device will never go to sim regardless of submission mode" — but the submission mode is still the ceiling, so a PURE_SIM submission still dispatches PURE_SIM on that device. The override is functionally inert in the toward-live direction; the only thing it changes is the warning ("the warning fires only if you also try LIVE").
  • --confirm is per-submission. It doesn't change the topology. The next submission against the same workflow without --confirm will refuse again. To remove the friction permanently, edit the topology to drop the sim_override.
  • DEVICE_SIM still requires drivers. It's the real driver running with a sim backend — if the driver itself doesn't load (import error, missing config), DEVICE_SIM fails the same way LIVE would. PURE_SIM is the only mode that skips driver loading entirely.
  • The sim/live decision is per-action, not per-thread. A thread can pick up a plate from a LIVE-resolved device and drop it on a PURE_SIM-resolved device in the same method. The transporter is also resolved per-action and may itself be mixed.

Where to go next

  • CLI: run — operator surface for --run-mode and --confirm.
  • Submissions — the larger submission shape that carries mode.
  • Devices — how sim_override slots into device construction.