Developers
One decision before execution
Integration is a single evaluated check, placed where an action becomes irreversible. It takes what is actually being proposed, evaluates it against the mandate governing the actor, and returns an outcome with a reason. The caller proceeds on one answer and refuses on every other.
01Integration model
A check placed where the action becomes irreversible
The check is called before an execution rather than reconciled after one. It is given the account being acted for, the target, the asset, the action and the amount. The shape does not change between environments; only its position does.
// Evaluated before the action is carried out.
(bool allowed, bytes32 reason) = pass.checkPolicy(
account,
target,
asset,
action,
amount
);
if (!allowed) {
revert PolicyRefused(reason);
}// Evaluated before the call is submitted.
const decision = await pass.checkPolicy({
account,
target,
asset,
action: 'BUY',
amount,
});
if (decision.outcome !== 'AUTHORIZED') {
return refuse(decision.reason);
}Both forms are the same interface expressed for two callers. Onchain the decision is returned in reduced form — allowed is true exactly when outcome is AUTHORIZED — and the refusal reverts the execution. Offchain, the refusal stops a call from being submitted at all.
Call inputs
- account
- The party being acted for. Policy is evaluated against the mandate binding this actor to this subject, not against the key that signed.
- target
- The contract the call would reach. It determines which adapter, if any, is able to describe what the call does.
- asset
- The instrument being moved. Asset permissions are an explicit allow set — AAPL and NVDA in the running mandate, nothing outside it.
- action
- What is being done with the asset. Trading it and bridging it are separate permissions; an actor can hold one without the other.
- amount
- The size of the movement, in the unit the adapter resolves value to. The per-transaction ceiling and the room left in the period are both evaluated against it.
What the decision means
A decision is a pair. outcome is AUTHORIZED only when every applicable rule was evaluated and satisfied, and BLOCKED otherwise. reason names the first rule that refused, or AUTHORIZED when none did. Because it is an identifier rather than a message, a caller can branch on it and record the value an auditor will later read.
AUTHORIZED is an assertion about policy only. It states that this actor was permitted to do this thing, for this party, under these constraints. It makes no claim about whether the trade is a good one, whether the counterparty settles, or whether the target protocol behaves as documented. Those are real questions, answered elsewhere.
A refusal is not an error to be retried. It is a completed evaluation with a negative result, and the reason tells the caller which of several very different situations it is in.
interface Decision {
/** AUTHORIZED only when every applicable rule was evaluated and satisfied. */
outcome: 'AUTHORIZED' | 'BLOCKED';
/** The first rule that refused, or AUTHORIZED. */
reason: ReasonCode;
}02Placement
How close the check sits to the point of no return
Three positions, one consistent trade. The closer the check sits to the point where state changes, the fewer paths there are around it, and the more of the surrounding system has to accommodate it.
Inside the executing contract
- Covers
- Every call that reaches this contract, from any caller.
- Proximity
- At the point of state change. No path to the action avoids it.
- What it costs
- The contract has to be written to hold the check. One already deployed without it cannot acquire it.
In a guard in front of an account
- Covers
- Every action the account takes, including protocols it has never touched before.
- Proximity
- One hop before settlement. The account cannot act except through the module holding the check.
- What it costs
- The account has to support a guard, and that guard becomes a dependency of everything the account does.
At the agent’s execution boundary
- Covers
- What this agent proposes. Anything else holding the same key is unaffected.
- Proximity
- Before submission — furthest from the point of no return, and the cheapest place to refuse.
- What it costs
- Nothing onchain enforces it. An agent that is bypassed or replaced takes the check with it.
The positions compose rather than compete. A guard is enforcement; an agent-side check is triage. An agent evaluating its own proposal refuses what it can determine cheaply, before anything is broadcast, and the guard refuses what the agent got wrong.
Because both call the same interface and receive the same reason codes, the two layers cannot disagree about why an execution did not proceed. What changes between them is coverage, not verdict.
03Policy evaluation
The order of the checks is part of the specification
Policy is not a set of conditions evaluated in whatever order is convenient. It is a defined sequence. Evaluation stops at the first rule that is not satisfied, and that rule is the reason returned.
The sequence runs from the most fundamental question to the most specific. A mandate that does not exist cannot have a limit; an asset outside the allow set does not need to be priced. Each check is meaningful only once the ones before it have passed.
That is what makes a reason code useful rather than merely descriptive. A caller receiving DAILY_LIMIT_EXCEEDED knows the actor is bound, the mandate is live, the required credential is held, and the asset, action and venue are all permitted. The trade sat within the $2,500 per-transaction ceiling; the $10,000 of daily exposure is what ran out. That situation has a specific remedy, and it is nothing like ACTION_NOT_ALLOWED.
A decision therefore names one reason and not a list. The same intent evaluated against the same state returns the same reason, which is the property an audit trail can be built on.
- 01Actor bindingIs this actor bound to a mandate for this subject?
- ACTOR_NOT_AUTHORIZED
- 02Mandate lifecycleIs that mandate live — inside its window, not suspended?
- MANDATE_EXPIRED
- MANDATE_SUSPENDED
- 03CredentialsDoes the subject hold every credential the mandate requires?
- MISSING_CREDENTIAL
- CREDENTIAL_EXPIRED
- CREDENTIAL_REVOKED
- 04ActionIs this kind of action permitted at all?
- ACTION_NOT_ALLOWED
- 05AssetIs this asset named in the allow set?
- ASSET_NOT_ALLOWED
- 06VenueWas the intent produced by a permitted adapter?
- ADAPTER_NOT_ALLOWED
- 07Transaction limitIs this single movement within its ceiling?
- TX_LIMIT_EXCEEDED
- 08Periodic limitIs there room left in the period for it?
- DAILY_LIMIT_EXCEEDED
- DecisionReturned to the caller, with its reason
- AUTHORIZEDwhen no rule refused
04Reason codes
Every decision names the rule that produced it
The reason is a stable identifier rather than a message, so callers, logs and audit trails agree on why an execution did or did not proceed. The set is closed; this is all of it, AUTHORIZED included, because the reason field always carries a value.
| Code | Category | Summary |
|---|---|---|
| AUTHORIZED | Outcome | Every applicable rule evaluated successfully. |
| MISSING_CREDENTIAL | Credential | A credential required by the mandate is not held by the subject. |
| CREDENTIAL_EXPIRED | Credential | A required credential exists but is past its validity window. |
| CREDENTIAL_REVOKED | Credential | A required credential was withdrawn by its issuer. |
| ASSET_NOT_ALLOWED | Permission | The asset in the execution intent is outside the permitted set. |
| ACTION_NOT_ALLOWED | Permission | The action type is not permitted under this mandate. |
| ADAPTER_NOT_ALLOWED | Permission | The execution venue is not among the permitted adapters. |
| TX_LIMIT_EXCEEDED | Limit | The single-transaction ceiling was exceeded. |
| DAILY_LIMIT_EXCEEDED | Limit | The cumulative exposure limit for the period was exceeded. |
| MANDATE_EXPIRED | Lifecycle | The governing mandate is past its validity window. |
| MANDATE_SUSPENDED | Lifecycle | The mandate is temporarily inactive. |
| ACTOR_NOT_AUTHORIZED | Lifecycle | The actor is not bound to a mandate for this subject. |
| INVALID_EXECUTION_CONTEXT | Context | The execution intent could not be validated into policy inputs. |
Handling a refusal
The families are not interchangeable. Each points at a different part of the system, and that is what determines the correct response.
- CredentialIssuance or renewal
- The mandate is intact and the permission unchanged; the subject’s passport does not carry a valid attestation of a required type. The resolution is a new or renewed credential from an issuer, not an edit to the mandate.
- PermissionAn amendment by the granting party
- The actor proposed something the mandate does not permit. This is a refusal working as specified, not a fault to route around. If the actor should be permitted, the granting party widens the allow set deliberately, and that widening is itself a record.
- LimitTime, or a deliberate change to the bound
- A periodic limit clears when its window rolls, so waiting is a legitimate response. A per-transaction ceiling does not clear, and splitting an amount to fit beneath it defeats the purpose of setting one — which is what the periodic limit catches.
- LifecycleA grant, a reinstatement or a renewal
- The mandate is not currently a source of authority: expired, suspended, or never bound to this actor. Each is an operator action rather than an integration change, and suspension preserves the definition, so reinstating it is not reconstructing it.
- ContextAdapter coverage for the target
- No adapter could derive a trustworthy asset, action, venue and value from the call. The call may be well formed; PASS refuses because it will not evaluate policy against a description it cannot verify itself.
05Adapters
An adapter answers for one protocol, or refuses
Policy needs an asset, an action, a venue and a value. Deriving those four things from a call at a specific target is the whole of an adapter’s job, and it is a job with only two acceptable outcomes.
- Raw callBytes proposed by an actor
- Protocol adapterDecodes against a known target
- Validated intentWhat is actually being proposed
- Asset
- Action
- Value
- Venue
- PASS policyEvaluated against the mandate
- ExecutionProceeds only on AUTHORIZED
interface IExecutionAdapter {
/// @notice Derives what a proposed call actually does.
/// @dev MUST revert rather than return an uncertain result.
function resolve(
address target,
bytes calldata data,
uint256 value
) external view returns (ExecutionIntent memory intent);
}
struct ExecutionIntent {
address asset;
bytes32 action;
uint256 value;
address venue;
}resolve is a view over a target the adapter is written for. It returns an execution intent — asset, action, value, venue — or it reverts. The revert is the important half: a check is only as meaningful as the intent it is given, and an adapter that reports an uncertain result quietly leaves policy evaluating a guess.
Coverage is therefore a real constraint, not a roadmap item. A protocol that nothing decodes is not reachable under a mandate that permits approved adapters only, and widening that reach means writing and approving an adapter rather than relaxing a rule.
06Credential queries
Ask whether a condition holds, not for the evidence behind it
A mandate can require that the subject holds a credential. Evaluating that requirement means asking the passport one question, and the answer is an assertion rather than a document.
interface IPassportRegistry {
/// @notice Whether a subject currently holds a valid credential of a type.
/// @dev Returns the assertion only, never the evidence behind it.
function holdsCredential(
address subject,
bytes32 credentialType
) external view returns (bool held);
/// @notice The issuer and validity window standing behind an assertion.
function credentialStatus(
address subject,
bytes32 credentialType
) external view returns (
address issuer,
uint64 issuedAt,
uint64 expiresAt,
bool revoked
);
}An issuer performs the underlying check and attests to the result. The passport records that attestation against the subject. An integrator reads whether the condition holds and, where it matters, the issuer and validity window behind it. What the issuer examined is not part of the answer and is not held by the layer evaluating policy.
Expiry and revocation are read through the same query. An expired credential is treated as absent rather than as a warning, so time alone can withdraw an authority. A revocation takes effect across every mandate that depends on the credential, without those mandates being rewritten.
- Subject
- 0x3A…F02
- Passport
- 0x7F…94A
- Credential type
- STOCK_TOKEN_ELIGIBLE
- Held
- True
- Validity
- Bounded window, revocable by issuer
Also carried by this passport
- Attestations
- IDENTITY_VERIFIED
- NON_US_PERSON
- EEA_ELIGIBLE
- AML_CHECKED
- Read by policy
- Only what the mandate requires
07Protocol lifecycle
From a grant to an accounted execution
An integration touches two steps of this path: the check, and what the caller does with the answer. The rest determine what that answer means.
- Mandate granted
The party with authority defines what an actor may do on its behalf: permitted assets and actions, permitted venues, a per-transaction ceiling, a periodic exposure limit, required credentials and a validity window. The grant is a record — it can be amended, suspended or left to expire.
- Actor proposes
The actor constructs a call. It holds a key, so it is able to sign. Nothing so far has established that it is permitted to.
- Adapter validates
The adapter registered for the target decodes the call into an execution intent: asset, action, value, venue. If no adapter covers the target, or none can decode it with confidence, the path ends here with INVALID_EXECUTION_CONTEXT.
- Policy evaluates
The intent is evaluated against the governing mandate in the defined order, stopping at the first rule that is not satisfied.
- Decision returned
An outcome and a reason go back to the caller. The reason is a stable identifier, so the caller, an operator’s log and an auditor reading it later describe the same event the same way.
- Execution proceeds or refuses
On AUTHORIZED the call continues to the target. On anything else the caller refuses and carries the reason with the refusal. A refusal is a completed evaluation, not a failed one.
- Accounting updated
Authorized value is recorded against the mandate’s period, so the next evaluation sees the exposure that remains rather than the limit originally set. Refusals record nothing: an execution that did not happen does not consume a limit.
The sequence runs identically whether the actor is a person, a script or a model. Authority is a property of the mandate rather than of the thing holding the key.
08Continue
The specification carries the definitions
- Integration model
Where the check sits in a full system, and how the positions compose.
- Specification
Interfaces, evaluation order and the decision structure, stated precisely.
- Security model
What the model relies on, what it does not claim, and where trust is placed.