Published in openvibe-contracts v0.107.0 (docs/adr/ADR-036-run-execution-authority.md), rendered as is.

ADR-036: Run is an execution authority, not a Host detail

Status: Proposed 2026-10-05 (plan track T14, "Run is not a Host detail"; plan §8 lists ADR-036 as one of the records "to write before their code", and Run's own code is owner-blocked). For the owner's review. Builds on ADR-034 §5 (control plane and data plane; cells), ADR-032 (containers: platform services stay systemd units; tenant code isolation belongs to Stage C) and ADR-046 (offers, requirements, placement, signed plans and trust classes).

Context and current evidence

Decision

1. Run is an execution authority; Host is a deployment authority

2. Runtime classes

3. Provider adapters are Fabric offers, not code paths in Run

The adapters the plan names (T14, lines 567–569) — OpenVibe official worker, OpenVibe Node worker, self-hosted Run worker, managed browser providers, external sandbox providers, external GPU providers — are offers, not branches inside Run. Each reports:

Run states platform.workload-requirements@1 and reads the platform.placement-result@1. Placement is always openvibe-sdk/placement plan(): hard constraints first, then the objective and hysteresis, with an explanation. Run writes no placer of its own (ADR-046: "A service states requirements and reads results; it does not rank offers."). The plan's §2.1.11 cross-reference is the Fabric section as written in ADR-046/T1, not a separate scheme.

Node descriptor → offers. When Run turns an OpenVibe.Node into Fabric offers it applies the mapping the Node protocol already fixes (OpenVibe.Node docs/protocol.md:310–321):

| Node descriptor field | Fabric offer | Example | | --- | --- | --- | | capabilities.worker.runtime_classes | resource-offer.capabilities item worker:<class> | worker:function, worker:code | | capabilities.worker.max_jobs | runtime-offer.limits.concurrency | 1 | | capabilities.worker.max_ttl_ms | runtime-offer.limits.duration_seconds | 600 | | device node_id / cell | resource-offer.node_id / resource-offer.cell | node_01H… / wnam-1 | | worker trust (local policy) | resource-offer.trust | user-owned for a user's own Node |

4. The cost ladder

The scheduler always uses the cheapest capability that works: API/MCP → HTTP/structured → Playwright/CDP browser → AI browser → visual desktop → full machine (plan T14, line 570). This ladder is what keeps a caller such as Actor cheap. Each rung is a candidate offer class the placer can choose; the objective (cheapest, balanced, lowest-latency, private) decides among offers that pass the hard constraints.

5. Run guarantees

Every job, on every adapter, is held to the same guarantees (plan T14, lines 572–574):

Consequences

Open questions for the owner

  1. Isolation mechanism. The plan requires more than a container for hostile arbitrary code but names no mechanism. Micro-VM (Firecracker/Kata), a userspace kernel (gVisor) and namespace/seccomp sandboxes are all open; the Node worker's current function isolation is namespaces plus a seccomp allowlist.
  2. Snapshot/resume backend. Whether a resumed environment's state lives in Media, a Node-local disk, or a provider's own snapshot is open.
  3. Idle-suspend policy. Who decides to suspend — Run, the node's local policy, or a placement objective — is open.
  4. Self-hosted Run workers. Whether one may run other projects' jobs, or only its owner's, mirrors ADR-046's user-owned question and is open.
  5. Browser/desktop semantics. Headed versus headless, and what a session's lifetime is, is deferred to the code for those classes.

What this ADR does not claim