Guarded commands, idempotency, and audit
All mutation surfaces—Studio, browser editor, HTTP API, CLI, and private MCP—must call the same guarded command path. A command declares its required permission and whether the effect requires an explicit confirmation.
executeCommand() verifies that the authenticated identity has the request tenant scope, authorizes the site permission, requires confirmation when configured, and uses a tenant/site/user/command-scoped idempotency key. It obtains an exclusive ledger claim before execution. A concurrent retry receives COMMAND_IN_PROGRESS; a repeated successful request returns the original result instead of repeating its side effect. Failed handlers abort their claim so a safe retry can proceed.
TenantWorkspaceCommandLedger persists claims and bounded JSON results in the tenant Durable Object. The claim token prevents an unrelated caller from completing or aborting another execution, and the adapter rejects keys outside its tenant prefix. Consequential handlers should still use optimistic versions or downstream idempotency: no generic ledger can prove whether an external side effect completed if a Worker terminates between that effect and ledger completion.
Every succeeded, denied, and replayed command creates an audit event with tenant, site, actor, command, outcome, and timestamp. TenantWorkspaceAuditStore persists these events in the tenant Durable Object. Audit writes are part of the command path; no public route or public MCP tool can read them.
Command handlers remain responsible for schema validation, optimistic resource versions, and any additional effect-specific safeguards. The hosting boundary authorizes the actor before invoking Durable Object RPC methods.