A gateway must mediate every governed external effect and independently validate what the model proposes. Its useful output is an action admitted under current authority and controls, with a traceable refusal when those controls cannot be established.
Correction, October 16, 2026: the earlier tutorial used local ToolCall/ToolResult shapes as if they were canonical, reduced risk to an ordinal mode ladder, accepted an evidence-only approval and implied that exceptions could not be audited. This version uses the published envelopes and executable authorization reference. Original publication date and URL are retained. The reference is not a production gateway, sandbox or cryptographic verifier.
Separate capability, authority and active controls
A registered capability describes a possible operation. The surfaced tool manifest narrows what a planner may select. Current authenticated mandate, exact scope, policy, required approval, permitted data movement, active execution boundary and aggregate budget independently constrain dispatch. A favorable business verdict cannot override a failed mandatory condition.
Native ActionRisk separates effect, authority, reversibility, interaction and data scope. ApprovalMode remains a v1 compatibility projection. A lower projection does not erase the underlying risk vector or authorize a broader scope. A destructive projection does not universally imply the same human-click workflow: policy selects the approver and exact obligation. Standing workload/owner grants may permit bounded actions without a per-action approval; a required human authority cannot be replaced with a machine recommendation.
The compiler’s existing cumulative prohibition filter is one conservative tool-surfacing check. It is separate from the normalized runtime composition of absolute guardrails and priority-ordered business outcomes described in Governance.
Use canonical envelopes
Import ToolCallEnvelope and ToolResultEnvelope from @/lib/contextos/types. The authoritative shapes are in Runtime API Schemas and API Contracts. The former tutorial’s local aliases map as follows:
| Earlier illustrative field | Canonical representation |
|---|---|
call_id | tool_call_id, shared by the call and its result |
approval_mode | Requested, effective and highest v1 projection fields; native risk is separate |
adapter_id | Registry-routing context; the envelope names the exact capability_id |
data | ToolResultEnvelope.output |
duration_ms | latency_ms |
Embedded approval_gate or reversal_token | Correlated controlled profile/store records; these are not new required base-envelope fields |
For example, this complete v1 call remains compatible:
{
"envelope_version": "contextos.tool_call.v1",
"tool_call_id": "tool_refund_attempt_1",
"run_id": "run_contract",
"trace_id": "trace_contract",
"capability_id": "adp_payments.issue_refund",
"args": { "order_id": "ord_881", "amount_inr": 4200 },
"principal_chain": [{ "kind": "agent", "id": "agt_support", "tenant_id": "tenant_acme_prod" }],
"approval_mode_requested": "destructive",
"approval_mode_effective": "destructive",
"approval_mode_highest": "destructive",
"evidence_refs": ["evidence_snapshot:order_881@1"],
"idempotency_key": "refund-ord_881-operation-1"
}An attempt’s tool_call_id may change on retry. The stable operation ID and provider idempotency key must continue to identify the same intended effect; appending an attempt counter to the provider key defeats deduplication. Supplying a key alone does not prove that the provider enforces it.
Run the conjunctive reference decision
evaluateAuthorization consumes authenticated broker observations, normalized policy outcomes, trusted stored approval records and required independent-control observations. Trusted admission derives the required-control list from the admitted workflow and profiles. Model-supplied control lists or verified flags cannot authenticate themselves.
This complete function uses the synthetic authorizationFixture() supplied by the companion test. The test extracts this marked fence and calls the actual imported helper with fixed data; run npx vitest run tests/approval-tutorial.test.ts from the repository.
import { evaluateAuthorization } from "@/lib/contextos/authorization";
import type { AuthorizationInput } from "@/lib/contextos/authorization";
function runGatewayExample(
input: AuthorizationInput,
scenario: "valid" | "missing-boundary" | "revoked" | "wrong-proposal",
) {
const candidate = structuredClone(input);
candidate.policy_outcomes[0].verdict = "allow";
candidate.policy_outcomes[0].priority = 999;
if (scenario === "missing-boundary") candidate.constraint_observations = [];
if (scenario === "revoked") candidate.authority.observations[0].revocation_status = "revoked";
if (scenario === "wrong-proposal" && candidate.approval) {
candidate.approval.proposal.proposal_id = "proposal_other";
}
const result = evaluateAuthorization(candidate);
return {
verdict: result.verdict,
action_digest: result.decision.action_digest,
reason_codes: result.decision.reason_codes,
};
}The valid fixture allows its bounded action. Missing containment evidence, revoked authority and a substituted approval proposal each block despite the high-priority business allow. The reference consumes evidence of an active control; it does not start or inspect an OS sandbox, issue credentials or verify a remote broker signature.
Keep dispatch and recovery explicit
Production integration pseudocode:
resolve capability and validate arguments against its pinned schema
load trusted admitted contract, exact proposal and current authority observations
obtain active containment, data-flow, approval and budget observations
run the conjunctive authorization check for the complete action digest
atomically coordinate redemption, operation ownership, fencing and budget reservation
recheck required external preconditions and invoke through the mediated adapter
persist the receipt, verified postcondition or unknown effect outcome
emit canonical envelopes and correlated decision/profile receiptsNo unmediated path may bypass this boundary. That is a deployment invariant to test, not something a pure validator can establish. Browser/computer actions, redirects, subprocesses and delegated agents need the same mediation, tenant and credential restrictions as API adapters.
A timeout after sending a request is not proof of failure. Preserve an unknown effect outcome and reconcile it with the provider before retrying. Cancellation stops further eligible work but does not undo an in-flight external commit. A compensation request needs its own authority, budget and receipt; a compensatable action does not guarantee rollback succeeds.
Audit failures as well as permissions
An applicable compiler predicate failure throws a sanitized ContextCompileError before returning compiled output. The gateway boundary must catch and record that failure or visibly propagate it; it cannot fabricate a successful context. Structured denials, verification outages, uncertain effects and worker-fence conflicts also belong in the trace and correlated decision records.
An immutable evidence digest proves which bytes were reviewed. Separately verified current facts establish freshness-sensitive preconditions. Rehashing a pinned snapshot cannot detect a later shipment or ownership change. See Approval Gates in Code for the exact proposal, stored-expiry and redemption checks.
