Home / Projects / Orchestrata Ultimate / Decisions / ADR index / ADR-0018
ADR-0018: Three-uid execution model (agent / sandboxed executor / trusted gate)
| field | value |
|---|---|
| Status | Accepted |
| Date | 2026-07-24 |
| Register | factory (docs/adr, 4-digit ids) |
| Source | docs/adr/0018-three-uid-execution-model.md — permalink at bdafa201a (unchanged on master since that commit) |
| Wiki register entry | ADR-0018 (wiki status: Accepted) |
The record
- Status: Accepted
- Date: 2026-07-24
- Spec: SPEC-033 §3, §7
Context
The OS trust boundary (gate assets read-only to the agent, promotion trusted-side) says who may write
gate assets. It never says who executes the tests — and the gate must run agent-authored code
(conftest.py, fixtures, the code under test itself).
Both naive placements fail:
- Tests run as the trusted user → the agent authors code that the trusted user executes. The agent owns the trusted user, and the boundary is decorative.
- Tests run as the agent user → the gate consumes a pass/fail number produced entirely inside the untrusted domain, and can be handed any number the agent likes.
This is the actual privilege-escalation path, and it is not addressed by protecting files.
Decision
Three distinct uids, none of which may impersonate another:
- Agent uid — authors code in the worktree. No access to gate assets, no promotion rights.
- Sandboxed executor uid — runs tests and agent-authored code, in an environment the trusted side controls (no network beyond an explicit proxy, no write access to gate assets or the fact store).
- Trusted gate uid — orchestrates, evaluates rules, and performs fact promotion. Never executes agent-authored code. It consumes only structured results from the sandbox.
The red-team charter (B1e) extends accordingly: from "attempt writes to protected assets" to "cause the trusted runner to execute agent-controlled code."
Alternatives rejected
- Two uids (agent / trusted) — forces the trusted side either to execute agent code or to trust the agent's numbers; both collapse the boundary.
- Container-per-agent without uid separation — bounds blast radius but does not prevent the gate from consuming untrusted results.
Consequences
- Requires real OS-level isolation (users, mount namespaces). In a constrained or containerised environment this may not be grantable, and the separation would be cosmetic — so B1d must carry a verified acceptance test: "can a process running as the agent uid read or write the gate rulebase?" Verified, never assumed.
- Structured result passing (not log scraping) becomes a hard interface requirement.
Provenance
Round-3 Opus (#7), the finding that the OS boundary is silent on test execution. Round-3 Sonnet independently flagged that the spec treats OS separation as free and needs a verified acceptance test.
Related ADRs
No other ADR is named in this record.
Rulings cited
None.