RFC-0015: Effective Tool Argument Authorization
Generated from the repository source of truth. Source file:
/docs/RFC-0015-effective-tool-argument-authorization.md. Status:Accepted.
- Status: Accepted
- Date: 2026-07-15
- Accepted: 2026-07-15
- Owners: aioc maintainers
- Depends on: RFC-0001, RFC-0002, RFC-0004, RFC-0005
- Amends: RFC-0002, RFC-0005
- Amended by: RFC-0016
Context
Section titled “Context”RFC-0002 requires policy evaluation before tool execution, and RFC-0005 binds approval evidence to a canonical tool proposal. The original implementation decoded provider arguments as JSON, evaluated policy and computed the proposal hash, then applied the tool’s Zod schema immediately before execution.
Zod schemas may add defaults, coerce values, strip properties, or transform
payloads. The value evaluated by policy could therefore differ from the value
passed to the tool. Invalid schema input could also produce an allow decision
before execution failed.
Decision
Section titled “Decision”AIOC prepares tool arguments before policy evaluation:
raw provider arguments-> strict JSON decoding-> requested arguments-> one tool-schema parse-> parsed arguments-> canonical proposal fingerprint-> policy evaluation-> tool execution with the same parsed argumentsThe following invariants are normative:
- JSON decoding and tool-schema validation happen before tool policy.
- Invalid arguments do not reach policy or tool execution.
- Tool-schema parsing runs exactly once per execution attempt.
parsedArguments,argsCanonicalJson, andproposalHashdescribe the schema output that the tool will receive.- An allowed tool receives the same
parsedArgumentsobject evaluated by policy. - A policy that mutates the canonical argument value is converted to the
deterministic deny reason
policy_mutated_arguments.
Argument Views
Section titled “Argument Views”ToolPolicyInput exposes three distinct views:
export interface ToolPolicyInput<TContext = unknown> { agentName: string; toolName: string; rawArguments: string; requestedArguments?: unknown; parsedArguments: unknown; proposalHash: string; argsCanonicalJson: string; runContext: RunContext<TContext>; turn: number;}rawArgumentsis the exact provider string.requestedArgumentsis the JSON-decoded model request before the tool schema. It is additive and optional for compatibility with externally constructed policy inputs.parsedArgumentsis the tool-schema output after validation and normalization. It is the authorization and execution payload.
Policies may inspect requestedArguments to detect coercion or removed input,
but authorization must be based on the operational meaning of
parsedArguments.
Validation Failures
Section titled “Validation Failures”Malformed JSON and schema rejection produce ToolArgumentsValidationError
with stage json or schema respectively.
Validation failure is not a policy decision:
- tool policy is not invoked;
- no allow, deny, or approval-required decision is emitted;
- the tool is not executed.
Synthetic handoff calls share strict JSON decoding because they use the same provider function-call envelope, but this RFC does not add a handoff schema or normalization contract.
This RFC preserves the existing terminal error delivery behavior. Returning validation failures as model-visible tool results is deferred.
Proposal Hash And Approval
Section titled “Proposal Hash And Approval”For tool proposals, argsCanonicalJson and proposalHash are derived from
parsedArguments.
SuspendedToolProposal adds the optional requestedArguments field and keeps
parsedArguments as the effective, schema-normalized proposal:
export interface SuspendedToolProposal extends SuspendedProposalBase { kind: "tool"; toolName: string; rawArguments: string; requestedArguments?: unknown; parsedArguments: unknown; argsCanonicalJson: string;}Approval reviewers should treat parsedArguments as the action being approved
and requestedArguments as diagnostic evidence about the model request.
Mutation Detection
Section titled “Mutation Detection”The runtime canonicalizes parsedArguments before invoking policy and repeats
canonicalization when policy returns. A change produces
policy_mutated_arguments and prevents execution.
This check protects the proposal/effect invariant from accidental in-process policy mutation. It does not make application-owned policy code an isolated or tamper-resistant security boundary.
Compatibility And Migration
Section titled “Compatibility And Migration”The TypeScript change is additive: requestedArguments is optional and the
existing parsedArguments field remains present.
The runtime semantics intentionally change:
- existing policies now observe defaults, coercions, stripping, and transforms
through
parsedArguments; - policies that need the pre-schema request should use
requestedArguments; - proposal hashes may change for schemas that normalize input;
- outstanding approval grants created from pre-schema hashes must be reissued.
Accepting both old and new proposal hashes is not supported because it would reintroduce ambiguity about the action being approved.
Non-Goals
Section titled “Non-Goals”- No schema digest in proposal fingerprints.
- No general immutable JSON contract for Zod transform output.
- No model-visible validation recovery protocol.
- No typed handoff payloads.
- No exact suspended-proposal executor.
Minimal Test Matrix
Section titled “Minimal Test Matrix”- Zod defaults are visible to policy and tool execution.
- Coercions and transforms produce the same policy and execution value.
- Stripped input remains visible only in
requestedArguments. - Semantically equivalent normalized inputs produce the same proposal hash.
- Malformed JSON and schema-invalid input do not invoke policy or tool code.
- Policy mutation produces
policy_mutated_argumentsand no execution. - Suspended tool proposals retain requested and parsed argument views and use the effective proposal hash.
Status
Section titled “Status”Accepted. Implemented in src/run.ts, src/policy.ts, src/errors.ts,
src/suspended-proposals.ts, and src/run-record.ts, with focused regression
coverage in src/tests/unit/tool-arguments.unit.ts.