EIP.tools

EIP.tools

⚠️ DraftStandards Track: ERC

ERC-8468: Agent Safety Framework (ASF)

Registry of versioned safety specifications and of the scoped, attributable adoption relations that bind subjects to them

Authors
Created2026-10-25
Discussion Linkhttps://ethereum-magicians.org/t/erc-8468-agent-safety-framework-asf/30073
Requires

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/re...
Pull Request#2113PR open

EIP-GPT summary

Contents
AbstractMotivationSpecification1. Terminology2. Conformance3. Identifiers and canonicalization3.1 Content hashes3.2 Subject and scope keys3.3 Specification and binding identifiers3.4 Profile, family and requirement identifiers4. Safety Specification4.1 Document4.2 Constraints4.3 Enforcement channels4.4 Versions5. Specification Registry interface6. Safety Binding6.1 Meaning6.2 Binding parameters document6.3 Pinning6.4 Enforcement locations6.5 Interveners6.6 Validity7. Binding Registry interface8. Lifecycle8.1 States8.2 Response requirements8.3 What a transition does and does not do8.4 Moving between versions8.5 Standing stops9. Derived bindings and attenuation9.1 Registry rules9.2 Parameter attenuation10. Requirement sets and the check10.1 Clause evaluation10.2 Clauses10.3 Combinators10.4 Malformed requirements10.5 Requirement identifier and document10.6 Native results of other mechanisms11. Consumer rules11.1 Authority verification11.2 Which bindings are required11.3 Check at the time of effect11.4 Unknown and dependency failure11.5 Separate states11.6 Multi-party acceptance11.7 Incident reports, claims and labels11.8 Identity, representation and use12. Profiles12.1 Families12.2 Profile descriptors12.3 Required and optional profiles13. Extensibility13.1 Namespaces13.2 Extension members13.3 Unsupported extensions and profiles13.4 Revisions14. Interface identifiersRationaleBackwards CompatibilityTest CasesKeysIdentifiersCanonicalizationRequirement identifierRegistry behaviourConsumer scenariosReference ImplementationSecurity ConsiderationsCopyright

Abstract

This ERC defines the Agent Safety Framework (ASF): two registry objects and one check through which the safety arrangements that govern autonomous systems become protocol objects with a source, a version, a scope, an attributable adoption relation and a lifecycle.

Two objects are standardized. A Safety Specification is a reusable, versioned, content-addressed document that states which protected interests a set of requirements serves, which constraints apply, who may adopt and enforce them, which evidence is expected, through which channels and at which locations the constraints are enforced, how unknown conditions and failures are handled, and which remedies are pre-accepted. A Safety Binding is the attributable statement, made on chain by the adopting account itself, that it adopts one pinned version of a specification for one subject within one scope, under a named external authority basis and declared enforcement locations, for a validity window, with named interveners and an explicit lifecycle. Bindings can be derived from other bindings without ever widening them.

A registry-level check lets any consumer ask, before it acts, whether a set of bindings currently satisfies a requirement it has published, and receive a verdict of satisfied, not satisfied or unknown together with the reason. Which bindings a resource requires is decided by the resource's own authority rules; a subject can never substitute a looser arrangement for the one required.

The framework standardizes none of the underlying mechanisms. Identity, authorization, policy evaluation, execution gating, evidence and dispute resolution remain with the proposals and systems that provide them, and their native results are preserved when consumers read them. What the framework records is who adopted which arrangement, for which subject and scope, in which version, enforced where, and whether that adoption is in force now.

Motivation

Agents now hold credentials, operate accounts and move funds on behalf of people and organizations. The mechanisms that bound what they may do are maturing in several places at once: permission grants and delegations in accounts, policy verdicts bound to actions, identity and reputation registries, decision mechanisms and task escrows. What none of them records is the relation between them: in this task, on these resources, in this execution environment, which participants have accepted which safety requirements, in which version, relying on which evidence, enforced by which mechanism, and whether that acceptance can still be relied upon now.

Without that relation, four failures recur. A counterparty cannot tell before interacting which arrangement, if any, governs an agent, so it either trusts a label or asks for nothing. A safety requirement written into a document cannot be told apart from one that is actually enforced at an execution boundary, so promises and controls are mixed. A requirement that was accepted in one version is silently reinterpreted when its publisher releases a new one, so nobody knows which conditions were agreed. And when an arrangement is paused, revoked or breached, there is no shared way to say what stops, what continues, who was entitled to intervene and on what basis.

The framework answers each of these with a registry object rather than with a new control: the Safety Specification fixes what was agreed, the Safety Binding fixes who agreed to it for what, the lifecycle fixes how the agreement changes, and the check lets every consumer verify the relation at the moment it matters. Because the adopting account is always the sending account, the registry cannot be used to attribute an arrangement to someone who did not accept it; because every specification version is content-addressed and pinned, publishing a new version changes nothing for existing adopters; and because enforcement locations are declared, a consumer can distinguish an arrangement the subject merely promises to follow from one enforced by its account, its runtime, a custodian, a contract or a collective decision.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in all capitals, as shown here.

1. Terminology

  • Safety arrangement: a set of requirements and of the means by which they are enforced and evidenced, in the broad sense that covers security (resistance to unauthorized access, manipulation and theft), safety (avoidance of unacceptable harm with or without an attacker), alignment (behaviour consistent with the accepted task, rules and interests), control (the ability of parties outside the system to limit its effects when it errs, is manipulated or drifts) and assurance (the evidence under which, within what scope and for how long, the system may be relied upon). These are distinct questions; none of them is a label that a binding settles.
  • Subject: the system or account whose behaviour a safety arrangement governs: an agent account, a registered agent identity, a swarm, an economic unit or any other referenceable system. A subject is referenced by a string and identified in the registry by its subjectKey.
  • Principal: the party on whose behalf the subject acts. The principal is often, but not necessarily, the adopter.
  • Safety Specification (specification): a versioned, content-addressed document of safety requirements and of the means by which they are enforced and evidenced (Section 4).
  • Publisher: the account entitled to publish new versions of a specification and to transfer or renounce that entitlement.
  • Safety Binding (binding): the on-chain record that an adopter adopts one version of a specification for one subject within one scope (Section 6).
  • Adopter: the account that created a binding. The adopter is always the account that sent the creating transaction. That the adopter is who it is (identity) is established by the registry; that it may act for the subject (representation) and that an action serves a permitted purpose (legitimate use) are separate facts established elsewhere.
  • Scope: the part of the world a binding applies to: a task, a resource, an execution environment, an account, or a general scope. A scope is a JSON object identified by its scopeKey.
  • Authority basis: the external permission record (a wallet permission, a delegation, a membership record, a charter, tender terms, an operator agreement) that entitles the adopter to adopt for the subject and scope. The registry records a reference to it and never evaluates it.
  • Enforcement location: where an arrangement is actually enforced: by the subject itself, by its account, by its runtime, by a resource custodian, by a contract or by a collective decision mechanism (Section 6.4).
  • Intervener: an account other than the adopter that holds some lifecycle rights over a binding (Section 6.5).
  • Response requirement: one of five combinable requirements a suspension imposes on the subject (Section 8.2), described operationally by a response document.
  • Derived binding: a binding that names a parent binding and is bounded by it (Section 9).
  • Requirement set: a consumer's statement of which bindings must hold, combined by all-of, any-of or k-of (Section 10).
  • Consumer: a contract, wallet, runtime, task or service that decides whether to admit or execute something on the strength of bindings.
  • Profile: a versioned, content-addressed vocabulary for one kind of constraint, identified by a profile identifier (Section 12). Profiles defined by this ERC use the asf: namespace; extension profiles use the x: namespace.
  • Family: one of eight groupings of profiles by the kind of safety problem they address (Section 12.1).

2. Conformance

A conforming deployment consists of one Specification Registry (Section 5) and one Binding Registry (Section 7). Both MUST implement ERC-165 and MUST report the interface identifiers of Section 14. A Binding Registry MAY accept specifications held by any Specification Registry on the same chain that implements the interface of Section 5.

A conforming Safety Specification, binding parameters document, requirement set document or profile descriptor is a JSON document that satisfies the corresponding data model of Sections 4, 6, 10 and 12 and whose canonical hash (Section 3.1) equals the hash recorded on chain or cited by the record that refers to it.

A conforming consumer MUST implement the rules of Section 11.

Implementations MAY support only a subset of profiles. A consumer that encounters a profile or extension it does not understand, and that a specification marks as required, MUST treat the specification as not understood and MUST NOT act as if the requirement were satisfied (Section 13.3).

3. Identifiers and canonicalization

3.1 Content hashes

The content hash of any document of this ERC is the Keccak-256 digest of the UTF-8 encoding of the document after canonicalization with the JSON Canonicalization Scheme (RFC 8785). This rule defines contentHash of a specification version, paramsHash of a binding, the descriptor hash of a profile and the document hash of a requirement set. Numbers that carry economic quantities MUST be encoded as decimal strings so that canonicalization never alters them.

3.2 Subject and scope keys

subjectKey is the Keccak-256 digest of the UTF-8 encoding of the subject reference string. Account subjects use the reference eip155:<chainId>:<address> with the address in lowercase hexadecimal; other subjects use the reference form of the system that defines them (a CAIP-19 asset reference, a did: identifier, or a framework-specific URN). The registry treats the key as opaque.

scopeKey is the content hash (Section 3.1) of the scope object. The one-member object {"ref": "<reference>"} is the form that a contract can canonicalize without a JSON library; scope objects with more members are canonicalized off chain and passed as keys.

3.3 Specification and binding identifiers

specId    = keccak256(abi.encode(chainId, specificationRegistry, publisher, salt))
bindingId = keccak256(abi.encode(chainId, bindingRegistry, adopter, subjectKey, scopeKey,
                                 specificationRegistry, specId, version, salt))

Both identifiers bind the chain and the registry so that a record cannot be replayed elsewhere, and both bind the account that created the record so that nobody can occupy another account's identifier space.

3.4 Profile, family and requirement identifiers

profileId and familyId are the Keccak-256 digests of the UTF-8 encoding of the identifier string (for example asf:profile:authority/bounded-spend@1 and asf:family:identity-authority). requirementId is the Keccak-256 digest of the ABI encoding of the RequirementSet struct of Section 10 (Section 10.5).

4. Safety Specification

4.1 Document

A Safety Specification is a JSON object with the following members. Members marked (R) are REQUIRED.

MemberTypeMeaning
asf (R)stringData model version. This document defines "1.0".
kind (R)stringMUST be "safety-specification".
name (R)stringHuman-readable name.
summarystringDescriptive only.
publisherobjectref and name of the publisher. Informative; the on-chain publisher is authoritative.
version (R)integerMUST equal the registry version under which the document is published.
protects (R)arrayProtected interests: objects with domain (one of assets-economic, information-privacy, control-rules, credit-eligibility, human-public), roles (whose interest: principal, operator, counterparty, bystander, public) and description. human-public covers the rights and welfare of persons, society and the public, the principal included.
applicability (R)objectsubjects, tasks, resources, environments, permittedUses, prohibitedUses (arrays of strings) and notes: what the specification is meant for and which uses it excludes even where the subject holds the technical authority to perform them.
constraints (R)arrayConstraint objects (Section 4.2).
authority (R)objectwhoMayAdopt, whoMayEnforce, authorityBasis: who is expected to adopt and enforce, and which kinds of external permission records a binding is expected to cite.
evidence (R)arrayEvidence objects: id, kind (attestation, proof, audit, runtime-log, test-result, declaration, decision), source, binds (which of subject, instance, version, action, rule-version, purpose, state and validity the evidence is bound to) and validity.
enforcement (R)objectchannels: the enforcement channels (Section 4.3).
failureHandling (R)objectunknown, denied, dependencyFailure, each one of refuse, wait, handoff, degrade, and notes.
remedies (R)objectsuspensionModes (the response requirements of Section 8.2 the publisher expects to be used, alone or combined), reversibility (reversible, partially-reversible, irreversible, mixed: how much of a harm can be undone afterwards), interventionWindow (how quickly an intervention must act to avoid or limit harm; recorded separately from reversibility), serviceContinuity (services and duties that stay available during a suspension), incidentReporting (channels, evidenceRequirements), recovery, dispute, compensation.
profiles (R)objectrequired: profile identifiers a consumer MUST understand to rely on the specification; optional: profiles that MAY be ignored.
limitationsarrayAssumptions and gaps the publisher states.
extensionsobjectExtension members (Section 13).
metadataobjectFree-form, non-normative.

4.2 Constraints

A constraint object has the members id (R), profile (R, a profile identifier), family (R, Section 12.1), statement (R), parameters, scope (R) and enforcedBy (R). scope states what the constraint is evaluated over: action (one action), state (the current state), trajectory (the history of the subject within a window), group (the combined behaviour of several subjects) or relation (a relation between trajectories, for example that a secret did not influence what the outside world could observe). enforcedBy lists the identifiers of the channels (Section 4.3) that check the constraint; every identifier MUST name a channel of the same document.

A constraint's parameters are defaults or fixed values; a binding instantiates the remaining parameters under the constraint's profile (Section 6.2).

4.3 Enforcement channels

A channel object has the members id (R), description (R), mechanism (kind, ref, version, notes), location (R, one of self, account, runtime, custodian, contract, collective), coverage (R, full or partial) and knownBypasses (array of strings). A specification whose every channel has location self describes a promise, not a control; consumers decide what that is worth.

4.4 Versions

A specification version is immutable once published. A correction, a tightening or a loosening is a new version. Publishing a new version MUST NOT change any binding of an earlier version; adopters move by creating new bindings (Section 8.4). A publisher MAY mark a version deprecated; the mark is informative and MUST NOT change the state or the evaluation of any binding.

5. Specification Registry interface

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

struct SpecificationVersion {
    bytes32 contentHash;        // keccak256(UTF-8(JCS(document)))
    string locator;             // where the document can be fetched; mutable, the hash is not
    uint64 publishedAt;
    bool deprecated;            // publisher's informative signal; never changes a binding
    bytes32[] requiredProfiles; // profile identifiers a consumer MUST understand
}

interface IASFSpecificationRegistry /* is IERC165 */ {
    event SpecificationRegistered(bytes32 indexed specId, address indexed publisher, bytes32 salt);
    event SpecificationVersionPublished(bytes32 indexed specId, uint32 indexed version, bytes32 contentHash,
        string locator, bytes32[] requiredProfiles);
    event LocatorUpdated(bytes32 indexed specId, uint32 indexed version, string locator);
    event VersionDeprecated(bytes32 indexed specId, uint32 indexed version, bytes32 reasonRef);
    event PublisherChanged(bytes32 indexed specId, address indexed previousPublisher, address indexed newPublisher);

    /// @notice Registers a specification under msg.sender and publishes its version 1.
    function registerSpecification(bytes32 salt, bytes32 contentHash, string calldata locator,
        bytes32[] calldata requiredProfiles) external returns (bytes32 specId);
    /// @notice Publishes the next version. Only the publisher. Reverts for frozen specifications.
    function publishVersion(bytes32 specId, bytes32 contentHash, string calldata locator,
        bytes32[] calldata requiredProfiles) external returns (uint32 version);
    /// @notice Replaces the locator of a version; the content hash is untouched. Only the publisher.
    function setLocator(bytes32 specId, uint32 version, string calldata locator) external;
    /// @notice Marks a version deprecated. Informative: bindings are unaffected. Only the publisher.
    function deprecateVersion(bytes32 specId, uint32 version, bytes32 reasonRef) external;
    /// @notice Transfers or renounces publishing control. address(0) freezes the specification.
    function setPublisher(bytes32 specId, address newPublisher) external;

    function computeSpecId(address publisher, bytes32 salt) external view returns (bytes32);
    function specificationExists(bytes32 specId) external view returns (bool);
    function publisherOf(bytes32 specId) external view returns (address);
    function latestVersion(bytes32 specId) external view returns (uint32);
    function versionOf(bytes32 specId, uint32 version) external view returns (SpecificationVersion memory);
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Registry rules:

  1. specId MUST be computed as in Section 3.3 with msg.sender as the publisher. Registering an existing specId MUST revert.
  2. Versions MUST be numbered sequentially from 1 and MUST be immutable once published. registerSpecification and publishVersion MUST revert when contentHash is zero.
  3. publishVersion, setLocator, deprecateVersion and setPublisher MUST revert unless msg.sender is the current publisher, and MUST revert for a frozen specification (publisher address(0)). A frozen specification remains readable and adoptable.
  4. versionOf MUST revert for an unknown specification or version, so that a binding registry can rely on a successful return.

The registry does not validate that the document at locator hashes to contentHash or that the document satisfies Section 4; consumers verify both before relying on a version.

6. Safety Binding

6.1 Meaning

A binding states: the adopter adopts version version of specification specId held by specRegistry, with content contentHash, for the subject subjectKey within the scope scopeKey, instantiated by the parameters document paramsHash, on the authority basis authorityRef, enforced at the locations in enforcement, from validFrom until validUntil, with the interveners listed, and (optionally) as a derivation of parentBindingId.

Four things a binding does not state, and that consumers MUST establish separately, are the following:

  1. That the adopter was entitled to adopt for the subject and the scope. The registry records the adopter faithfully and records the reference to the authority basis; whether that basis exists, covers the subject, the scope and the period, and names the adopter, is verified by the consumer against the permission source it already trusts (Section 11.1).
  2. That any particular action of the subject is permitted. Permission is decided by the permission and policy mechanisms the specification names.
  3. That the arrangement is actually enforced. The binding declares where enforcement is claimed to happen; the consumer decides which locations it accepts.
  4. That the subject is safe. A satisfied binding means that an attributable party accepted a stated arrangement whose enforcement is declared, and that this acceptance is currently in force.

6.2 Binding parameters document

The off-chain parameters document is a JSON object with the members asf (R, "1.0"), kind (R, "safety-binding"), adopter (R: ref, role), subject (R: ref, key, kind), scope (R: object, key), specification (R: registry, specId, version, contentHash, locator, name), parameters (R: an object keyed by profile identifier whose values instantiate the constraints of the specification), authorityBasis (R: an array of kind, ref, description), mechanisms (R: an array of channel, mechanism, location, coverage), evidence, derived (parentBindingId, narrowing), validity (from, until), interveners (array of ref, rights, role), extensions and metadata. The binding's paramsHash is the content hash of this document. authorityRef SHOULD be the content hash of the authorityBasis array; a binding MAY instead carry an opaque reference defined by the authority basis itself. The on-chain enforcement bit set SHOULD be the union of the locations listed under mechanisms.

Every profile listed as required by the adopted specification version MUST have an entry under parameters.

6.3 Pinning

A binding pins one specification version by (specRegistry, specId, version, contentHash). The registry MUST verify at creation that specRegistry implements the interface of Section 5 and that the content hash it reports for the version equals the pinned one. After creation the pin never changes: a later version, a deprecation, a changed locator or a frozen publisher leaves the binding exactly as adopted.

6.4 Enforcement locations

The enforcement member of a binding is a bit set over the following locations, ordered from the least to the most independent of the subject:

BitLocationMeaning
1selfthe subject promises to comply
2accountthe subject's account or wallet enforces (permissions, session keys, modules)
4runtimethe execution environment enforces (sandbox, loader, monitors outside the subject's authority)
8custodiana custodian of the resource or an API enforces
16contractan on-chain contract or guard enforces
32collectivea collective decision mechanism enforces

A requirement MAY demand that given locations are declared (Section 10.2). A declaration is a commitment of the adopter, attributable to it; it is not a proof that the mechanism works.

6.5 Interveners

A binding MAY name up to sixteen interveners, each with a rights bit set over RIGHT_SUSPEND (1), RIGHT_RESUME (2) and RIGHT_TERMINATE (4). The adopter holds all three rights over its own transitions, with one exception stated in Section 8.1: a suspension recorded by an intervener is not the adopter's to lift. The set of interveners is fixed at creation; changing it means terminating the binding and creating a new one, so that an intervener's rights cannot be quietly removed while the binding appears unchanged. Interveners give the responsibility layer of a safety arrangement a hook: a guardian, a decision mechanism's executor or a task's publisher can pause an arrangement with a basis recorded in the binding itself, and nobody else can. A requirement MAY demand that a binding names given interveners with given rights and, by doing so, closes the resume right to the accounts it names (Section 10.2), so that a resource can insist that someone other than the subject is able to stop it and that the subject cannot lift that stop through an intervener of its own choosing. A suspension recorded by an intervener is also a standing stop against the adopter for the subject and the specification (Section 8.5): it is not escaped by holding another binding or by terminating the stopped one and adopting afresh, and it is the intervener's to lift, not the resume holders' of any binding.

6.6 Validity

validFrom and validUntil are unix timestamps; validUntil is exclusive and zero means open-ended. A binding exists only from its createdAt; the registry records a validFrom earlier than createdAt as declared but a binding is never satisfied for a time before createdAt. A later registration cannot prove an earlier acceptance.

7. Binding Registry interface

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

enum BindingState { None, Active, Suspended, Terminated }
// response requirements of a suspension (bit set, Section 8.2):
//   RESTRICT_NO_NEW_RISK 1, RESTRICT_SHRINK 2, RESTRICT_ESSENTIAL_ONLY 4, RESTRICT_DERISK_ONLY 8, RESTRICT_FULL_STOP 16
enum Verdict { Unknown, Satisfied, NotSatisfied }
enum Reason { None, NoBinding, Terminated, Suspended, NotYetValid, Expired, SpecMismatch, VersionMismatch,
    AdopterMismatch, SubjectMismatch, ScopeMismatch, EnforcementMismatch, ParentNotSatisfied,
    SpecRegistryUnavailable, IntervenerMismatch, StoppedByIntervener }
enum Combinator { All, Any, KOf }

struct Intervener { address account; uint8 rights; }

struct BindingInput {
    bytes32 subjectKey; bytes32 scopeKey;
    address specRegistry; bytes32 specId; uint32 version; bytes32 contentHash;
    bytes32 paramsHash; string paramsLocator;
    bytes32 authorityRef; uint16 enforcement;
    uint64 validFrom; uint64 validUntil;
    bytes32 parentBindingId; bytes32 salt;
    Intervener[] interveners;
}

struct Binding {
    address adopter; bytes32 subjectKey; bytes32 scopeKey;
    address specRegistry; bytes32 specId; uint32 version; bytes32 contentHash;
    bytes32 paramsHash; string paramsLocator; bytes32 authorityRef; uint16 enforcement;
    uint64 validFrom; uint64 validUntil; bytes32 parentBindingId; uint8 depth;
    uint64 createdAt; uint64 stateChangedAt; BindingState state;
    uint8 restrictions; bytes32 responseRef; address suspendedBy; // of the current or last suspension; cleared by resume, kept through termination
}

struct Stop { bytes32 bindingId; uint8 restrictions; bytes32 responseRef; uint64 since; } // a standing stop (Section 8.5): the binding of the latest suspension recorded into it (zero = none), the union of the recorded sets, the latest response document supplied, the first recording time

struct Clause {
    address specRegistry; bytes32 specId; uint32[] versions;
    address adopter; bytes32 subjectKey; bytes32 scopeKey; uint16 enforcement;
    Intervener[] interveners; // required interveners (named accounts); when non-empty, also the only accounts that may hold RIGHT_RESUME
}

struct RequirementSet { Combinator combinator; uint16 k; Clause[] clauses; }

interface IASFBindingRegistry /* is IERC165 */ {
    event BindingCreated(bytes32 indexed bindingId, address indexed adopter, bytes32 indexed subjectKey,
        bytes32 scopeKey, address specRegistry, bytes32 specId, uint32 version, bytes32 contentHash,
        bytes32 parentBindingId);
    event BindingStateChanged(bytes32 indexed bindingId, BindingState previous, BindingState current,
        uint8 restrictions, bytes32 responseRef, address actor, bytes32 reasonRef);
    event BindingParamsLocatorUpdated(bytes32 indexed bindingId, string locator);
    event StopRecorded(address indexed adopter, bytes32 indexed subjectKey, address specRegistry, bytes32 specId,
        address indexed intervener, bytes32 bindingId, uint8 restrictions, bytes32 responseRef);
    event StopLifted(address indexed adopter, bytes32 indexed subjectKey, address specRegistry, bytes32 specId,
        address indexed intervener, address actor, bytes32 reasonRef);
    event StopLifterSet(address indexed intervener, address lifter);

    function adopt(BindingInput calldata input) external returns (bytes32 bindingId);
    function suspend(bytes32 bindingId, uint8 restrictions, bytes32 responseRef, bytes32 reasonRef) external;
    function resume(bytes32 bindingId, bytes32 reasonRef) external;
    function terminate(bytes32 bindingId, bytes32 reasonRef) external;
    function liftStop(address adopter, bytes32 subjectKey, address specRegistry, bytes32 specId, address intervener,
        bytes32 reasonRef) external;
    function setStopLifter(address lifter) external;
    function setParamsLocator(bytes32 bindingId, string calldata locator) external;

    function computeBindingId(address adopter, BindingInput calldata input) external view returns (bytes32);
    function bindingOf(bytes32 bindingId) external view returns (Binding memory);
    function intervenersOf(bytes32 bindingId) external view returns (Intervener[] memory);
    function rightsOf(bytes32 bindingId, address account) external view returns (uint8);
    function stopOf(address adopter, bytes32 subjectKey, address specRegistry, bytes32 specId, address intervener)
        external view returns (Stop memory);
    function stopLifterOf(address intervener) external view returns (address);

    function countBySubject(bytes32 subjectKey, address adopter) external view returns (uint256);
    function bindingsBySubject(bytes32 subjectKey, address adopter, uint256 offset, uint256 limit)
        external view returns (bytes32[] memory);
    function countByScope(bytes32 scopeKey, address adopter) external view returns (uint256);
    function bindingsByScope(bytes32 scopeKey, address adopter, uint256 offset, uint256 limit)
        external view returns (bytes32[] memory);

    function checkBinding(bytes32 bindingId, Clause calldata clause)
        external view returns (Verdict verdict, Reason reason, uint8 restrictions);
    function check(RequirementSet calldata requirement, bytes32[] calldata bindingIds)
        external view returns (Verdict verdict, Reason[] memory reasons, uint8[] memory restrictions);
    function requirementId(RequirementSet calldata requirement) external pure returns (bytes32);
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Registry rules:

  1. The adopter of a binding MUST be msg.sender of adopt. bindingId MUST be computed as in Section 3.3. adopt MUST revert when a record with that identifier exists in any state, including Terminated: a binding identifier is never recreated.
  2. adopt MUST revert when specRegistry has no code or does not report the interface identifier of Section 14 for the Specification Registry, when versionOf(specId, version) reverts, or when the reported content hash is zero or differs from input.contentHash.
  3. adopt MUST revert when validUntil is non-zero and not later than the current block time, or not later than a non-zero validFrom.
  4. adopt MUST apply the derived-binding rules of Section 9.1 when parentBindingId is non-zero.
  5. adopt MUST revert for an intervener with a zero account, for an intervener equal to the adopter, for duplicate interveners, for a rights value of zero or above 7, and for more than sixteen interveners.
  6. A new binding MUST be Active with an empty response set, MUST record createdAt, and MUST be appended to the index of (subjectKey, adopter) and to the index of (scopeKey, adopter). The adopter is part of every index key.
  7. Lifecycle transitions MUST follow Section 8, including the standing stops of Section 8.5. setParamsLocator MUST revert unless msg.sender is the adopter and the binding is not Terminated; it never changes paramsHash.
  8. checkBinding, check and requirementId MUST follow Section 10.

8. Lifecycle

8.1 States

A binding is Active, Suspended or Terminated; None means the record does not exist. Active -> Suspended requires RIGHT_SUSPEND and a non-empty, in-range set of response requirements, and records the caller's responseRef and the caller itself as suspendedBy; Suspended -> Active requires RIGHT_RESUME and clears all three; Active -> Terminated and Suspended -> Terminated require RIGHT_TERMINATE and leave the three fields as they were, so that a terminated record shows the stop it carried. Terminated is terminal: the record never becomes Active again and accepts no transition; a standing stop recorded through it is lifted through liftStop (Section 8.5), not through the record. Every other transition MUST revert. Every transition MUST emit BindingStateChanged with the acting account and the caller's reasonRef, an opaque reference to the evidence or decision behind the transition.

A suspension recorded by an intervener is not the adopter's to lift: when suspendedBy is not the adopter, resume MUST revert for the adopter and MUST succeed only for an intervener holding RIGHT_RESUME (the one who suspended, if it holds the right, or another). The adopter's own suspensions MAY be lifted by the adopter or by any intervener holding the right. The adopter keeps RIGHT_TERMINATE in every state: it can end an arrangement it no longer accepts, in an attributable way and for good, but it cannot make a stop imposed by someone else disappear while the binding appears to continue. Because the adopter chooses the interveners, this rule alone does not establish independence: a requirement that needs it names the interveners and thereby decides who may hold the resume right (Section 10.2). And because the adopter can hold several bindings for the same subject and can replace a binding it terminated, a rule that attached only to one record would not establish a stop either: an intervener's suspension is therefore also a standing stop against the adopter (Section 8.5).

8.2 Response requirements

A suspension carries a bit set of response requirements and a responseRef, the content hash of a response document. The five requirements are different dimensions of one response and MAY be combined; a single suspension can forbid new exposure, shrink authority, keep a duty running and leave the unwinding path open at once.

BitRequirementWhat it expresses
1RESTRICT_NO_NEW_RISKa prohibition: no action that adds exposure, obligations or new counterparties
2RESTRICT_SHRINKa capability change: only actions that reduce the current scope, exposure or authority
4RESTRICT_ESSENTIAL_ONLYa duty: the actions a profile lists as necessary to keep a service alive continue
8RESTRICT_DERISK_ONLYa permitted path: unwinding, repayment, cancellation and recovery stay open
16RESTRICT_FULL_STOPa stop target: nothing under the binding proceeds on the paths it covers

RESTRICT_FULL_STOP dominates every other bit for the paths the response covers. The registry MUST reject an empty set and any value above 31; it does not interpret the set.

The response document (members asf, kind = "intervention-response", binding, initiator with ref, role and basis, restrictions, scope with resources and paths, prohibited, allowed, mustContinue, inFlight, duration, resume with who and condition, evidence, metadata) states who started the response and under which right, what it covers, what it prohibits, allows and keeps running, how actions already authorized or sent are handled, how long it lasts and who may end it. Its canonical hash is the responseRef. A zero responseRef means that no response document has been published for the suspension (an urgent stop MAY be recorded before the document exists); consumers then read the suspension by its bit set and the specification's profiles alone, and the initiator SHOULD publish the document and reference it in the reasonRef of the next transition. A specification's remedies.suspensionModes lists the requirements its adopters and interveners are expected to use; the registry does not enforce that list, and consumers MAY treat a suspension whose set they cannot interpret as a full stop.

8.3 What a transition does and does not do

Suspending or terminating a binding changes the verdict of every check that depends on it. It does not by itself revoke a wallet permission, stop a running process, reverse a completed transfer, retract disclosed information or cancel an external commitment; those effects follow from the mechanisms the specification names, under their own authority. Resuming a binding does not restore a permission that was revoked in the meantime. Terminating a binding does not erase incidents, debts, completed effects or existing obligations, and the record remains readable.

8.4 Moving between versions

An adopter that wants a newer specification version creates a new binding pinned to it, presents the new binding to its consumers and terminates the old one when the consumers have switched. Two bindings of one adopter for the same subject and scope MAY be Active at once; a requirement decides which versions it admits.

8.5 Standing stops

A suspension recorded by an intervener (an account other than the adopter) MUST also be recorded into the intervener's standing stop against the adopter, keyed by the adopter, the binding's subjectKey, its specRegistry and specId, and the intervener. When no stop stands for that key, the suspension creates it, with the binding identifier, the response set, the responseRef and the time; when one stands, the suspension widens it: the stop's response set becomes the union of the two sets, its binding identifier becomes that of the new suspension, its responseRef is replaced only when the new suspension supplies a non-zero one, and its time is unchanged. A later suspension therefore never narrows or replaces a standing stop. Every recording MUST emit StopRecorded with the stop's set and document after it. The adopter's own suspensions record no stop.

The stop is the intervener's. It is lifted, and only lifted, by the intervener that recorded it or by the one account the intervener named as its lifter (setStopLifter, which the intervener MAY call at any time and which applies to all of its stops; stopLifterOf reports it), either through liftStop or by a resume, by one of those two accounts, of a binding whose suspension that intervener recorded. liftStop MUST revert for any other caller and MUST revert as an invalid transition when no stop stands; lifting MUST emit StopLifted with the acting account. A resume by any other holder of RIGHT_RESUME reopens the record and leaves the stop standing; no right of the adopter lifts a stop. Terminating the binding does not lift the stop, and a Terminated record accepts no resume. stopOf returns the standing stop for a key, or a zero record.

A standing stop has effect only through clauses that name the intervener (Section 10.1, step 9): a clause that does not name the account that recorded the stop is not concerned by it, and a clause that names it is not satisfied by any binding of that adopter for that subject and specification while the stop stands, whatever the binding's own state. The stop therefore applies to the adopter, the subject and the specification, not to one binding identifier, across scopes and versions; a sibling binding held in advance and a fresh binding adopted after the stop are refused alike. Its reach and its authority come from the same place: a clause that names an intervener relies on that intervener's stops, and those stops are lifted by that intervener (or the lifter it named), never by the holders of the resume right of whichever binding a stop happened to be recorded through, whom the adopter chose and whom the clause may never have named. A requirement that names a suspender therefore relies on the suspender's own judgment, or on the lifter the suspender names, to end its stops; an intervener that wants a stop to be reviewable by another party names that party as its lifter.

9. Derived bindings and attenuation

9.1 Registry rules

A binding whose parentBindingId is non-zero is derived. At creation the registry MUST verify that the parent exists and is Active, that the parent pins the same specRegistry, specId and version, that the child's validUntil is non-zero and not later than the parent's whenever the parent's validUntil is non-zero, and that the parent's depth is below eight. The child's depth is the parent's plus one. The child's adopter, subject and scope MAY differ from the parent's: a member of a group derives its own binding from the group's, an operator derives one for a sub-agent from the principal's.

At evaluation (Section 10.1) a derived binding is satisfied only if every ancestor is Active and inside its validity window. A suspended or terminated ancestor makes every descendant not satisfied with reason ParentNotSatisfied, while the descendants' own records stay untouched; the response set in force for a descendant is the union over the chain, so a suspension of the parent reaches the children with its requirements intact, and a termination of the parent reaches them as a closed chain.

9.2 Parameter attenuation

A derived binding MUST NOT be wider than its parent. For every profile whose descriptor declares a partial order (Section 12.2), the child's parameters MUST be not wider than the parent's under that order; for every profile without a declared order, the child's parameters MUST equal the parent's. The child's parameters document records the relation per profile under derived.narrowing with its basis. The registry cannot evaluate parameters; consumers that rely on a derived binding verify the narrowing against the two parameters documents, and MUST treat a child whose narrowing cannot be established as not satisfied, never as satisfied by default.

10. Requirement sets and the check

10.1 Clause evaluation

checkBinding(bindingId, clause) evaluates one binding against one clause at the current block time, in the following order, and returns the first failing reason:

  1. NoBinding: bindingId is zero or no record exists.
  2. Terminated, Suspended: the record's state. For Suspended the response set in force (below) is returned.
  3. NotYetValid: the current time is before the later of validFrom and createdAt. Expired: validUntil is non-zero and not later than the current time.
  4. SpecMismatch: the clause's specRegistry or specId differs from the binding's.
  5. VersionMismatch: the clause's versions list is non-empty and does not contain the binding's version.
  6. AdopterMismatch, SubjectMismatch, ScopeMismatch: the clause's adopter, subjectKey or scopeKey is non-zero and differs from the binding's.
  7. EnforcementMismatch: a bit set in the clause's enforcement is not set in the binding's.
  8. IntervenerMismatch: a required intervener of the clause is not an intervener of the binding with at least the required rights, or the clause names interveners and an account it does not name holds RIGHT_RESUME on the binding (Section 10.2).
  9. StoppedByIntervener: an account the clause names holds a standing stop against the binding's adopter for the binding's subject and specification (Section 8.5), through this binding or another; the stop's response set is returned.
  10. ParentNotSatisfied: an ancestor is not Active or is outside its validity window; the response set in force is returned.
  11. SpecRegistryUnavailable: the pinned specification registry no longer reports its interface identifier. This is the only outcome with verdict Unknown; every other failure is NotSatisfied.

A binding that passes every step is Satisfied with reason None.

The response set in force for a binding is the union of the response sets of every Suspended record among the binding and its ancestors, so that a parent's requirements are never hidden behind a child's narrower set and a full stop anywhere in the chain is visible to every descendant. It is empty when any record in that chain is Terminated or outside its validity window: a chain that is not in force keeps no path open. checkBinding returns it with Suspended and with ParentNotSatisfied, and returns the standing stop's set with StoppedByIntervener; check returns it per clause. A consumer MUST take the set from the check and MUST NOT read it from the clause binding's own record, which carries no set while an ancestor is suspended or while a stop stands against its adopter through another binding.

Verdict and Reason describe this registry's facts about the adoption relation and nothing else. They are not a normalization of the results of permission, policy or validation mechanisms, whose native results consumers read through Section 10.6.

10.2 Clauses

A clause names the specification registry and identifier (both REQUIRED and non-zero), an explicit list of admitted versions (empty admits every version; ranges are deliberately not expressible), an adopter, a subject key and a scope key (zero is a wildcard for each), an enforcement bit set (every set bit MUST be declared by the binding), and a list of required interveners. Each required intervener is a non-zero account with a rights bit set: the binding MUST name that account as an intervener holding at least those rights. A clause that names interveners also closes the resume right: the binding MUST NOT grant RIGHT_RESUME to any account the clause does not name, since otherwise the adopter, who chooses the interveners, could add an account of its own and lift any intervener's suspension through it. Additional interveners holding only RIGHT_SUSPEND or RIGHT_TERMINATE are allowed, because they can only stop. There is no wildcard: "some intervener other than the adopter" cannot establish independence from an adopter who chooses them all. A requirement that wants a subject's own commitment sets adopter to the subject's account; a requirement that accepts a principal's adoption for its agent sets adopter to the principal and subjectKey to the agent; a requirement that wants the subject's own commitment and still wants to be able to stop it names itself, or the party it trusts, as a required intervener with RIGHT_SUSPEND, and names with RIGHT_RESUME the party that may reopen the record, which may be the suspender itself. A stop recorded by a named intervener stands against the adopter for the subject and the specification until that intervener, or the lifter it named, lifts it (Section 8.5), so a clause that names interveners is met by no binding of a stopped adopter, held in advance or adopted afresh, and no holder of the resume right on any binding can end the stop in the intervener's place. Without a required intervener, a self-adopted binding is under the sole control of the subject it constrains, and its suspensions are the subject's to lift.

10.3 Combinators

check(requirement, bindingIds) evaluates bindingIds[i] against clauses[i] (the two arrays MUST have equal length; bytes32(0) means that no candidate is supplied) and combines the clause verdicts:

  • All: Satisfied when every clause is satisfied; Unknown when no clause is not satisfied and at least one is unknown; otherwise NotSatisfied.
  • Any: Satisfied when at least one clause is satisfied; Unknown when none is satisfied and at least one is unknown; otherwise NotSatisfied.
  • KOf: with k between 1 and the number of clauses, Satisfied when at least k clauses are satisfied; NotSatisfied when the satisfied and unknown clauses together are fewer than k; otherwise Unknown.

Unknown MUST NOT be treated as satisfied by any consumer. Clause verdicts are never combined into a score. check returns, next to the reason of every clause, the response set in force for that clause's binding (Section 10.1).

The combinators have a fixed meaning. All expresses distinct necessary conditions; a failing clause is never offset by the others. Any and KOf express alternatives that the resource publishing the requirement has accepted in advance as substitutes for one another; they are not a vote. Methods inside a profile MAY use statistics, weights or economic estimates with their own stated semantics; what no consumer may do is let a score offset a non-waivable condition or create a permission.

10.4 Malformed requirements

check and requirementId MUST revert for an empty clause list, for a clause with a zero specRegistry or specId, for a required intervener with a zero account or a rights value of zero or above 7, for KOf with k of zero or above the clause count, and for All or Any with a non-zero k.

10.5 Requirement identifier and document

requirementId is the Keccak-256 digest of the ABI encoding of the RequirementSet struct, with enumerations encoded as uint8. A resource that publishes what it requires SHOULD publish the requirement set document (members asf, kind = "requirement-set", name, combinator (all, any, k-of), k, clauses with role, specification, versions, adopter, subject, scope, enforcement, interveners (each with ref, rights and role), and metadata). Role-relative values ("self") in the document are resolved by the consumer when it builds the struct for a concrete participant.

10.6 Native results of other mechanisms

A consumer that reads the result of a permission, policy, validation or decision mechanism named by a specification MUST preserve that mechanism's native result: the standard and version, the native result value and reason, the verification status of any proof, the action and context the result refers to, its validity, and the rule by which the consumer maps it into its own decision. A summary the consumer forms for display or for its own logic never replaces the authoritative values, a conclusion of "no rule authorizes this action" is not the same as "could not evaluate", and a failed proof verification is not the same as an explicit denial. A "conflict" between results exists only where the consumer's published combination rule says so; it is never attributed to one of the mechanisms as its own result.

11. Consumer rules

11.1 Authority verification

Before relying on a binding, a consumer MUST verify, against the permission source it already trusts, that the adopter was entitled to adopt for the subject and the scope at the time of the action, and that the authority basis covers the current task and period. The binding's authorityRef tells the consumer where to look; it proves nothing by itself. A resolver provided by the author of the binding that always answers favourably is not a permission source.

11.2 Which bindings are required

Which bindings a resource requires, in which versions, from which adopters, with which enforcement locations and with which interveners, is determined by the resource's own authority rules (its terms, charter, permission policy or the requirement set it published). A subject MUST NOT be allowed to substitute a different binding for a required one, and a consumer MUST NOT accept a binding of a looser specification, an unlisted version, another adopter, weaker enforcement or fewer intervener rights than required. A resource that admits self-adopted bindings and needs to be able to stop the subject itself SHOULD require an intervener it controls or trusts, whose stops are its own to lift (Section 8.5); otherwise the subject's suspensions are the subject's own to lift. A stop recorded by a required intervener applies to the adopter for the subject and the specification through every binding the resource may scan (Section 8.5), so the resource need not pin binding identifiers to make its stop hold.

11.3 Check at the time of effect

A consumer MUST evaluate the requirement at the time an effect is produced, not only when a session or a batch is validated: a binding suspended between validation and execution MUST stop the execution. When a required binding is not satisfied, the normal execution path MUST NOT fall back to an unchecked path. Under Suspended, StoppedByIntervener or ParentNotSatisfied the consumer MAY continue the actions that the response set in force, the response document and the specification's profiles allow (for example repayment and cancellation while RESTRICT_DERISK_ONLY is set and RESTRICT_FULL_STOP is not) and MUST stop everything else. The set a consumer applies is the one check returns for the clause; it MUST NOT be read from the clause binding's own record, and an empty set keeps nothing open.

11.4 Unknown and dependency failure

A verdict of Unknown, a specification document that cannot be fetched or does not hash to its pin, a required profile the consumer does not understand, or an authority basis that cannot be verified are all handled according to the specification's failureHandling, and never as a pass. Refusing, waiting, handing the decision to an authorized party and degrading to a pre-accepted restricted mode are the admissible responses.

11.5 Separate states

Consumers MUST keep four facts separate in their own records: that a binding is registered, that the requirement is satisfied, that an action was authorized and sent, and that its outcome is known. An action whose outcome is unknown MUST be reconciled before any retry; a failed outcome MUST NOT be recorded over a successful one.

11.6 Multi-party acceptance

Where several parties must accept an arrangement (a principal, an operator, a task publisher, a data controller, the members of a group), each party adopts separately or expresses acceptance through the precise confirmation mechanism of the protocol that governs its participation. One party's binding never implies another party's acceptance.

11.7 Incident reports, claims and labels

An incident report is a statement by its source; a claim is a request for a remedy under some procedure; a risk label is an opinion of whoever attached it. None of them is a finding, and the existence of a report, a claim or a label confers no power to reduce credit, freeze assets, revoke a delegation, suspend a binding, remove a member or retire an identity. Every external effect needs an independent authority basis (an intervener right in the binding, a resource's own rule, a decision of a mechanism with jurisdiction over the matter) and the consumer's own consumption rule.

Consumers that index or present reports MUST keep four facts separate: that a statement was made, that a procedure accepted it, that the procedure reached a finding, and that an entitled party acted on it. They MUST index responses, corrections and withdrawals together with the statements they concern, MUST NOT present counts of statements as findings, MUST treat the contents of a report (prompts, code, links, documents) as untrusted input, and SHOULD keep sensitive evidence out of public records, publishing commitments and disclosing to entitled reviewers. A party with its own, pre-existing authority over a resource MAY take a limited, time-bounded protective measure on the strength of a report under the evidence threshold its own rules set; urgency creates no new authority.

11.8 Identity, representation and use

Three facts about an adopter or a subject are established separately and MUST NOT be inferred from one another: that an account is the account it claims to be (identity, established by the registry for the adopter and by the identity system named in the subject reference for the subject); that it may act for a principal, a resource or an organization (representation, established against the authority basis); and that a given action serves a permitted use (legitimate use, established against the specification's permittedUses, prohibitedUses and the rules that protect the human-public domain). An action can be authentic and authorized and still outside the permitted uses; an arrangement that only checks the first two has not covered the third.

12. Profiles

12.1 Families

Profiles are grouped into eight families, used as the family member of constraints and descriptors. The grouping is practical; a profile belongs to one family, and the families are not claimed to be disjoint as safety problems.

FamilyAddresses
identity-authoritywho acts, for whom, with which delegated and re-delegated authority, for how long
information-privacywhich inputs are trusted, what may be read, disclosed, retained or used for another purpose
execution-supply-chainwhether models, programs, tools, contracts and environments run as specified; pinned dependencies; isolation
behavior-goalstask goals, prohibited behaviours, required review, capability limits, protection of monitoring
assets-economicper-action and cumulative limits, exposure, settlement uncertainty
multi-agent-systemshared budgets, recursive delegation, conflicts, common-cause failures, cascades
human-publicprotected persons and third parties, purpose limits, value rules, appeal and review
governance-accountabilitysources of jurisdiction, incident evidence, pre-accepted consequences, intervention, recovery and compensation

12.2 Profile descriptors

A profile is described by a content-addressed descriptor with the members asf (R), kind (R, "profile-descriptor"), identifier (R), family (R), summary (R), evaluatesOver (subset of action, state, trajectory, group, relation), parameterSchema (R, the JSON Schema of the parameters a binding supplies), partialOrder (R: defined and rule, whether and how "not wider than" between two parameter sets is decided), verification (R: an array of method, location, inputs, resultMeaning, trustAssumptions), limitations and metadata. A descriptor with partialOrder.defined false makes derived bindings under that profile keep their parameters equal to the parent's (Section 9.2).

Profile identifiers have the form asf:profile:<family-short-name>/<name>@<version> for profiles defined by this ERC and x:<namespace>:<name>@<version> for extensions. The descriptors of six initial profiles accompany this proposal as informative examples: bounded spending authority, untrusted input, pinned dependencies, shared budget, monitoring integrity and intervention. A descriptor MAY carry requirements: conditions an implementation that claims the profile MUST satisfy and be able to show beyond the parameter schema.

A profile that claims a constraint over a group of subjects (a shared budget, a shared exposure, a common resource) MUST state the metering scope that the subjects share and its unit; the invariant that holds on every path that can consume the resource, with no exposure counted twice and every pending exposure owned; that a reservation or allocation requires authority and preserves no right to execute once the underlying authorization is gone; that a commitment in the group's ledger, a submitted transaction and a completed external effect are three distinct facts; that an unknown outcome releases nothing until the mechanism rules out late effects or an authoritative result allows it; and that a logical operation is distinct from its submission attempts. Declaring a coordination model does not by itself support a claim that the group constraint is enforced; the registry records the claim and the consumer verifies the mechanism.

Some information-flow properties (that a secret did not influence what an observer could see, that two executions are indistinguishable) are relations between possible executions rather than conditions on one trajectory, and a single observed execution without a leak establishes none of them. A profile that claims such a property MUST fix what secret it protects and which disclosures are permitted, which inputs or executions are compared and which public conditions are held fixed, what the observer sees (content, length, timing, calls, logs, on-chain relations), the models, tools, environments and versions it applies to, the property with its error bounds and composition rule, what the proof or test supports and which channels it leaves uncovered, and when the evaluation must be redone. Exploratory tests and partial evaluations MAY be referenced as evidence of limited scope; they MUST NOT be presented as a general guarantee.

12.3 Required and optional profiles

A specification's profiles.required lists the profiles a consumer MUST understand to rely on it; the same identifiers are recorded on chain as requiredProfiles of the version. A binding MUST supply parameters for every required profile. A binding MAY add or tighten conditions only under profiles the adopted specification lists; adding a new mandatory interpretation needs a new specification version and a new adoption.

13. Extensibility

13.1 Namespaces

Identifiers in the asf: namespace are defined by this ERC and its revisions. Extension identifiers use the x: namespace followed by a namespace of the defining party. Unregistered asf: identifiers MUST NOT be used.

13.2 Extension members

Every document of this ERC MAY carry an extensions object keyed by identifier. An extension member with required true is part of the document's meaning; one without is informative.

13.3 Unsupported extensions and profiles

A consumer that does not understand a required extension member or a required profile MUST treat the document as not understood and MUST NOT act as if the corresponding requirement were satisfied. Optional members MAY be ignored and MUST NOT change permissions, constraints or failure handling.

13.4 Revisions

Later revisions of this ERC MAY add response requirements, reasons, enforcement locations, families and document members. Added enumeration values and bits MUST be appended; added members MUST be optional; the identifier derivations of Section 3 MUST NOT change. While this proposal is a draft, the Clause struct and therefore requirementId values and the interface identifiers MAY change between revisions; each revision states its identifiers in Section 14.

14. Interface identifiers

The interface identifiers are computed as the XOR of the selectors of all functions declared in Sections 5 and 7 (excluding supportsInterface), following ERC-165:

IASFSpecificationRegistry  0x9bddde77
IASFBindingRegistry        0xcff7f826

Rationale

The adoption relation is the object. Permission grants, delegations, policy verdicts, identity registries, decision mechanisms and task escrows each answer one question: who the subject is, what it was granted, whether a proof holds, whether an action passes a policy, how an executor behaves. The unanswered question is relational: in this scope, which participants accepted which arrangement, in which version, enforced where, and is that acceptance in force now. Making the relation a registry object with a source, a version, a scope and a lifecycle is a smaller addition than any new control, and it is the one addition that lets the existing controls be composed and relied upon by third parties. A registry of safety documents alone, or a registry of policies alone, or one more allow/deny interface, would not have been a contribution; several proposals already provide each of those.

The adopter is the sender. An open registry invites records that say "a well-known agent adopts my arrangement". Such a record can prove only that some account published the statement. Deriving the adopter from msg.sender, putting the adopter into every identifier and every index key, and leaving the entitlement to adopt to the consumer's own permission source are the three rules that make the registry unforgeable in the only sense a registry can be: it never attributes a statement to an account that did not make it.

Pinned versions, no automatic upgrade. A publisher's belief that version 2 is safer than version 1 is not consent by the parties who accepted version 1. Bindings pin a content hash and move only by new adoption. Deprecation exists so that a publisher can speak without being able to change anything.

Registry-level check only. The registry evaluates existence, state, validity, pin, adopter, subject, scope, declared enforcement and the ancestor chain. It never evaluates a policy, because policy evaluation already has standards and because a registry that evaluated policies would become a policy engine with a privileged position. What the check adds is a single cheap call that a guard, an account module or a task contract can make at the moment of effect, with a reason that wallets can show to people, and a verdict that distinguishes refusal from ignorance.

Unknown is a verdict. A dependency that cannot be queried, a document that cannot be fetched and a profile that is not understood are not refusals, and they are not passes. Collapsing them into either produces wrong retries, wrong refunds and silent bypasses. The check therefore returns Unknown where the registry itself cannot decide, the combinators propagate it without ever counting it as satisfied, and the consumer rules route it to the specification's own failure handling.

Derived bindings and the attenuation rule. Re-delegation that silently widens authority is a known problem, and proposals for inheritable agent mandates already state that a child mandate is bounded by its parent on every clause. The framework does not define another mandate system and claims no priority on that rule. What it adds is the obligation that a binding claiming to derive from another references the original (the parent and its authority basis), states under which profiles its parameters are comparable and which cumulative constraints it shares, and names the mechanism that actually enforces the derived arrangement. The decidable part is enforced on chain (same pinned version, validity inside the parent's, bounded depth, ancestors must hold); the profile-dependent part follows a precise rule off chain: not wider under the profile's declared order, equal where no order is declared, and never satisfied by default when the relation cannot be established.

Combinable response requirements rather than one pause. Stopping everything is sometimes the most harmful response: a trading agent that cannot repay or cancel while suspended, a service that cannot keep an essential function alive. The five requirements are different dimensions of a response (a prohibition, a capability change, a duty, a permitted path, a stop target), so they combine rather than exclude one another, and the response document carries what a bit set cannot: scope, parameters, in-flight handling, duration and who may end it. Completability is designed in advance rather than improvised during an incident. Because responses attach to bindings and bindings derive from one another, the set that governs a derived binding is the union over its chain: a parent's response reaches every descendant with its requirements intact, and a full stop anywhere in the chain is visible to every consumer below it.

Interveners with explicit rights. Who may pause an arrangement is itself a safety question; a danger label must not create power. Interveners and their rights are fixed in the binding at creation, and every transition records the actor and a reference to its basis. A guardian, a decision mechanism or a task publisher can therefore act on an arrangement precisely to the extent the adopter granted.

An intervener's stop is not the adopter's to lift. Where the adopter is the party being constrained, a self-adopted binding whose suspensions the adopter can lift is advisory: a guardian suspends, the adopter resumes in the next block, and a consumer that checks at judgment time sees an active binding. Two rules close this. A suspension recorded by an intervener can be lifted only by an intervener holding the resume right, never by the adopter; and a requirement can name the interveners a binding must carry, which also decides who may hold the resume right at all. The second half matters because the adopter chooses the interveners: a rule that let "any intervener with the resume right" lift a stop would be met by an account the adopter controls, so the clause, not the adopter, names the accounts that may lift a stop, and the escalation shape (one party may only suspend, an executor may resume) is expressed by naming both. Additional suspenders are harmless and allowed; additional resume holders are not. A wildcard ("some intervener other than the adopter") was considered and rejected for the same reason. The adopter keeps the right to terminate, because it must stay possible to end an arrangement one no longer accepts; what it cannot do is make a stop imposed by someone else disappear while the binding appears to continue.

A stop applies to the adopter, not to a record. Rules that attach to one binding identifier are escaped without touching that binding: adopt takes a salt, so an adopter can hold a second binding for the same subject and specification that meets the clause as well as the first, and a consumer that scans the adopter's bindings for a satisfying one finds it; or the adopter terminates the suspended record and adopts a fresh one that names the intervener again, and a permissionless judgment runs before the intervener reacts. Both paths lead through the registry's own index, so the registry closes them: an intervener's suspension is recorded into a standing stop keyed by the adopter, the subject, the specification and the intervener, it outlives the termination of the binding it was recorded through, and a clause that names the intervener is met by no binding of that adopter for that subject and specification while it stands. The key is what a clause can pin (adopter, subject, specification), so the stop reaches exactly the bindings the clause would otherwise accept; keeping it per intervener means that a stop concerns only the clauses that name its author. Terminated records keep their suspension fields for the same reason: the stored state, not only the event log, must show who stopped what.

A stop is the intervener's to lift. An earlier revision lifted a stop through the resume right of the binding it was recorded through. That put the reach and the authority of a stop in different places: the stop counted against every clause naming the intervener, while its lifting belonged to accounts the adopter had chosen for one binding. Two requirements for the same specification show the gap: the first names a publisher as suspender and an executor as resume holder, the second names only the publisher; a stop the publisher recorded through the first binding could then be lifted by that executor, whom the second requirement never named. The same revision kept one record per key and replaced it on each suspension, so a milder second suspension displaced a stricter first one and moved the lifting to the newer binding's resume holders. The stop is now the intervener's: it is lifted by the intervener or by the one lifter the intervener names, through liftStop or through the intervener's own resume, and a later suspension widens it by union instead of replacing it. A resume holder on a binding reopens that record and nothing more. The escalation shape (one party may only suspend, another reviews and lifts) is still available at both levels: the clause names the executor with the resume right for the record, and the suspender names the executor as its lifter for the stop.

Enforcement locations are declared. "The agent will respect the limit" and "the account enforces the limit" are different arrangements. Recording the location bit set lets a requirement demand enforcement at a given independence from the subject and lets consumers see at once when a specification is a promise. The declaration is attributable, not verified; verification belongs to evidence and to the mechanisms themselves.

Eight families, several labels. The families group profiles the way practitioners group safety problems. They overlap as problems, an incident usually carries several labels and a causal path through them, and nothing on chain depends on a unique class: records have their own identifiers, requirements are identified by profile and requirement identifiers, and a classification label never decides a permission, a responsibility or a response. The analysis behind the framework distinguishes three axes (where in the chain of a delegated action a relation breaks, which protected domain is affected, and what the source of the risk is) as an indexing structure; the families are its practical projection and the protected domains of Section 4.1 its second axis. Two incidents with the same labels can require different handling (an expired delegation and an expired price proof, for example), which is why the registry keeps fine-grained reasons and why classification is never the input of a decision.

Why a registry and not a token. An adoption is a relation with a lifecycle, not a transferable whole. Nothing is gained by making it transferable, and a transferable adoption would be a forgery primitive.

Native results are preserved. Permission grants return their own reasons, policy verdicts distinguish an explicit denial from the absence of an authorizing rule and from an evaluation that could not complete, and account-abstraction validation returns validation data rather than a verdict at all. Folding these into one vocabulary would lose exactly the distinctions consumers act on, so the framework asks consumers to keep the native values and to publish the rule by which they map them, and it keeps its own Verdict and Reason confined to facts about the adoption relation.

No power from labels. Reports, claims and risk labels are how a system learns about harm, and also how a system can be attacked: by flooding, by impersonating a victim or an adjudicator, by turning a report's content into instructions, by presenting counts as findings. The consumer rules therefore separate statement, acceptance, finding and action, require responses and withdrawals to travel with the statements, and deny every label any effect of its own.

Why "safety" in the name. The framework governs arrangements that cover unauthorized access and theft, non-malicious capability failures, harmful uses within granted authority, the rights of persons and service continuity, and the abuse of control and accountability mechanisms themselves. The word is used in the broad sense that the Terminology section gives it: a safety arrangement states what is protected and how, whether the threat is an attacker, a capability failure or a misuse within granted authority, and the five underlying questions (security, safety in the narrow sense, alignment, control, assurance) are kept apart rather than collapsed into a label.

Backwards Compatibility

No backward compatibility issues were found. The framework introduces two new registries and four document kinds and changes no existing interface. Bindings reference existing accounts, identities, permissions, policies, tasks and groups by their own identifiers and never modify them.

Test Cases

The following cases are self-contained. Hashes use Keccak-256 over UTF-8 bytes; documents are canonicalized with JCS before hashing.

Keys

account        0x000000000000000000000000000000000000a6e7 on chain 11155111
accountRef     "eip155:11155111:0x000000000000000000000000000000000000a6e7"
subjectKey     keccak256(accountRef)
             = 0x6b2705e9928112a88838b860ee655bb520ce8daaddfc13a7c86b3dce9d1f0aa5

scope object   {"ref":"eip155:11155111:0x00000000000000000000000000000000000a11ce"}
scopeKey       keccak256(JCS(scope object))
             = 0xec1e6882a693a6002b29959105b68efe6dcb7e8e25b8568874054c0f0294b01b

scope object   {"task":"x:task-tender:eip155:11155111:0x0000000000000000000000000000000000007a5c:17","phase":"execution"}
JCS            {"phase":"execution","task":"x:task-tender:eip155:11155111:0x0000000000000000000000000000000000007a5c:17"}
scopeKey     = 0x045b0f249b8616b9027a0d0589d5b84c2b6d16127853a2db940d1e6c1c264e18

Identifiers

specId    = keccak256(abi.encode(11155111, 0x00000000000000000000000000000000000a5f01,
                                 0x00000000000000000000000000000000000009b1,
                                 0x0000000000000000000000000000000000000000000000000000000000000001))
          = 0x899c35f7a9a397ee81c993eb699bcbd33ab5fe08969a150b35a7623cea743285

bindingId = keccak256(abi.encode(11155111, 0x00000000000000000000000000000000000a5f02,
                                 0x00000000000000000000000000000000000a11ce,
                                 0x6b2705e9928112a88838b860ee655bb520ce8daaddfc13a7c86b3dce9d1f0aa5,
                                 0xec1e6882a693a6002b29959105b68efe6dcb7e8e25b8568874054c0f0294b01b,
                                 0x00000000000000000000000000000000000a5f01,
                                 0x899c35f7a9a397ee81c993eb699bcbd33ab5fe08969a150b35a7623cea743285,
                                 uint32(1),
                                 0x0000000000000000000000000000000000000000000000000000000000000011))
          = 0x45a157df553265719ffba4e798dc30e7ac391690e19bc8679e0b7ffd83b21003

Canonicalization

The vectors file canonicalization.json carries a minimal specification document, its JCS string and its content hash; a conforming implementation reproduces the hash from the JCS string.

Requirement identifier

The vectors file requirement.json carries a three-clause KOf requirement (k = 2), its ABI encoding under the type tuple(uint8,uint16,tuple(address,bytes32,uint32[],address,bytes32,bytes32,uint16,tuple(address,uint8)[])[]) (the third clause requires two interveners, a suspender and a resume holder) and its requirementId; requirementId(requirement) of a conforming registry returns that value.

Registry behaviour

  1. registerSpecification with a zero content hash reverts; registering the same salt twice reverts; publishVersion, setLocator, deprecateVersion and setPublisher by an account other than the publisher revert; every write to a frozen specification reverts while its versions stay readable.
  2. Publishing version 2 leaves version 1's content hash unchanged; a binding pinned to version 1 keeps version 1 and fails a clause that admits only version 2 with VersionMismatch, while a clause admitting versions 1 and 2 is satisfied.
  3. adopt through a specRegistry that does not report the interface, or for an unknown version, or with a content hash that differs from the registry's, reverts.
  4. adopt with the same input twice reverts; after suspension and after termination it still reverts; a new salt yields a new binding.
  5. adopt with validUntil equal to the current time, or earlier than validFrom, reverts; a validFrom thirty days in the past is recorded while createdAt is the block time.
  6. Interveners: a zero account, the adopter itself, duplicate accounts, rights 0 or 8, and seventeen entries each revert. A guardian granted only RIGHT_SUSPEND can suspend and can neither resume nor terminate; a stranger can do nothing; the adopter can suspend, terminate and lift its own suspensions. A suspension recorded by the guardian cannot be lifted by the adopter (NotAuthorized), is lifted by an intervener holding RIGHT_RESUME, and the adopter can still terminate; suspendedBy, the response set and responseRef are recorded on suspension, cleared on resumption and kept through termination. Standing stops: the guardian's suspension records a stop keyed by the adopter, the subject, the specification and the guardian (StopRecorded), the adopter's own suspension records none; the stop survives the adopter's termination of the binding; the terminated record accepts no resume from anyone; the adopter and a stranger cannot lift the stop (NotAuthorized), the guardian can with liftStop (StopLifted, the record stays Terminated), a second lift is an invalid transition; the guardian's own resumption of a binding it suspended lifts its stop, a resumption by another holder of the resume right reopens the record and leaves the stop standing; once the guardian names that holder as its lifter, the holder lifts by liftStop or by resuming, and a zero account revokes the naming. Widening: a second suspension by the guardian through another binding makes the stop's set the union of both, keeps its first time and the response document when the later suspension supplies none, replaces the document when it supplies one, and points at the latest binding; the records keep their own sets; the guardian's resumption of either binding lifts the one stop while the other record stays Suspended; a suspension after a lift starts a new stop.
  7. suspend with an empty response set or a value above 31 reverts, and several requirements combine in one suspension with their response reference recorded; resume of an Active binding reverts; every transition of a Terminated binding reverts; setParamsLocator of a Terminated binding reverts and otherwise changes the locator but not the hash.
  8. Derived bindings: a parent that is Suspended, unknown, pins another version, or has a shorter validity than the child, and a chain deeper than eight, each make adopt revert; a chain of depth eight is accepted. Suspending the root makes a grandchild NotSatisfied with ParentNotSatisfied and the root's response set; resuming restores it; terminating the root fails the child while the child's own record stays Active. The response set in force is the union over the chain: a suspended child under a suspended root reports both sets, a full stop anywhere in the chain is in the set of every descendant, and a terminated or expired record in the chain empties the set.
  9. checkBinding returns NoBinding for a zero or unknown identifier, Suspended with the response set, Terminated, NotYetValid before the window, Satisfied at validFrom, Expired at validUntil, and the mismatches of Section 10.1 in that order; an enforcement requirement that is a subset of the declared set is satisfied. Required interveners: a clause naming an account the binding does not list, or lists with fewer rights, fails with IntervenerMismatch after the enforcement check and before the ancestor walk; naming the adopter fails, since the adopter is never an intervener; several required interveners must all be present; a zero account or a rights value of 0 or 8 makes checkBinding and requirementId revert. Closed resume right: a binding that names the required suspender and an unnamed account holding RIGHT_RESUME fails with IntervenerMismatch; unnamed accounts holding only suspend or terminate rights are allowed; a named account may hold more rights than required; a clause that names a suspender and an executor with the resume right is met by a binding granting exactly those, the executor reopens the record the suspender suspended and the adopter cannot, the suspender's stop stands until the suspender lifts it or names the executor as its lifter, after which the executor's resumption lifts both; a clause without required interveners does not constrain the resume right. Standing stops: after the guardian suspends one of two bindings of the same adopter for the same subject and specification, the other, still Active, fails a clause naming the guardian with StoppedByIntervener and the stop's response set, and passes a clause naming nobody; check returns the set per clause; a fresh binding adopted after the adopter terminated the stopped one fails the same way while the terminated record reports Terminated; a clause naming a different suspender, and a binding of the same adopter for another subject, are not concerned; the stop is checked after the required interveners (a binding not naming the guardian fails with IntervenerMismatch first) and before the ancestors (a derived binding under a suspended root reports the stop and its set, not the parent's); the adopter cannot lift the stop, the guardian's liftStop satisfies every sibling again. Authority of the stop: with two requirements for the same specification, one naming the guardian (suspend) and an executor (resume) and the other naming only the guardian (suspend and resume), the guardian's stop recorded through the first binding, once that binding is resumed by the executor, still fails the second requirement and the first with StoppedByIntervener, the executor cannot lift it and the guardian can; a de-risk-only suspension after a full stop leaves the union, full stop included, in force for a third binding, a resumption by the executor changes nothing, and the guardian's own resumption lifts the stop.
  10. A specification registry that stops reporting its interface turns Satisfied into Unknown with SpecRegistryUnavailable; All and Any over that clause return Unknown; KOf with k = 2 over one satisfied and one unknown clause returns Unknown, with k = 1 returns Satisfied.
  11. requirementId and check revert for an empty clause list, a non-zero k under All, k of 0 or above the clause count under KOf, a zero specId, and for candidate and clause arrays of different lengths. All fails on one suspended clause; Any passes on one satisfied clause; KOf 2-of-3 passes with two satisfied and fails with one.

Consumer scenarios

  1. Wallet path: an account whose operator may act only while the principal's binding is satisfied executes while Active; after a guardian suspends with RESTRICT_NO_NEW_RISK and RESTRICT_DERISK_ONLY set, calls that add exposure revert and the listed de-risking calls still go through; once RESTRICT_FULL_STOP is in the set even those revert; the principal cannot lift the guardian's suspension, the guardian can, and execution then resumes; after termination nothing goes through; a binding that expires closes the path without any transaction; a third party's binding for the same agent fails with AdopterMismatch; a binding declaring only self enforcement fails a requirement for account enforcement with EnforcementMismatch; the account exposes no path that skips the check. Derived bindings on the wallet path: when the account requires the agent's own binding derived from the principal's root, a de-risk-only suspension of the root blocks new exposure through the derived binding while repayment and cancellation still go through, although the derived record itself carries no set; a full stop on the root closes the de-risking path; termination of the root reports ParentNotSatisfied with an empty set and closes everything; the sets of a suspended child and a suspended root combine, and a full stop on either side dominates. Standing stop on the wallet path: when the account's requirement names the guardian, the principal who terminates the guardian-suspended binding and presents a fresh one finds new exposure still blocked with StoppedByIntervener and the stop's set, de-risking still open under it, cannot lift the stop, and the guardian's liftStop reopens the wallet.
  2. Task path: a tender whose acceptance authority requires the fulfiller's own binding accepts and pays a fulfiller that holds one through the kernel's real acceptance call, rejects a fulfiller without one and releases the reservation, rejects a fulfiller whose binding was suspended between submission and judgment, rejects a binding adopted by someone else for the fulfiller, and when the verdict is Unknown neither accepts nor rejects, leaving the kernel's own judgment clock in force. With a clause that requires the task publisher as an intervener with RIGHT_SUSPEND, a fulfiller whose self-adopted binding does not name the publisher is rejected with IntervenerMismatch and one whose binding names it is accepted; after the publisher suspends that binding the fulfiller cannot resume it and is rejected at judgment; a fulfiller that terminates the suspended binding and adopts a fresh one that names the publisher again is still rejected, with StoppedByIntervener reported for the fresh binding, the terminated record keeps suspendedBy, the fulfiller cannot lift the stop and the suspend-only publisher lifts it without holding any resume right; a fulfiller holding two bindings that both name the publisher is rejected after the publisher suspends either one, whoever calls judge, and a third binding adopted after the stop is refused too; with the publisher named with both the suspend and the resume right, the fulfiller's terminate-and-readopt is rejected with the stop's set, the terminated record accepts no resumption and the fulfiller cannot lift the stop, the publisher lifts it, the fresh binding is then admitted and paid, a new suspension of the fresh binding re-points the stop at it and the publisher's own resumption lifts it again. A fulfiller that names the publisher and adds an account of its own holding RIGHT_RESUME is rejected before any suspension; with a clause that names the publisher (suspend) and an executor (resume), the executor's resumption reopens the record and leaves the publisher's stop standing until the publisher names the executor as its lifter, after which the executor's resumption lifts the stop and the fulfiller is accepted. Two tenders for the same specification, the first naming the publisher (suspend) and an executor (resume), the second only the publisher (suspend and resume): after the publisher stops the fulfiller through the first tender's binding and that tender's executor resumes it, the second tender still rejects the fulfiller with StoppedByIntervener, the executor cannot lift the stop, the publisher can, and with the executor named as the publisher's lifter its resumption frees the fulfiller for both.

Reference Implementation

The reference implementation, schemas, vectors and worked examples are provided with the assets of this proposal:

  • ASFSpecificationRegistry.sol and ASFBindingRegistry.sol, with the interfaces under contracts/interfaces, the shared types in ASFTypes.sol, the key derivations in ASFKeys.sol, the requirement storage helpers in ASFRequirementLib.sol the registry's evaluation (Section 10) in ASFEvaluation.sol and its writes (adopt and the lifecycle of Section 8) in ASFLifecycle.sol, two libraries linked externally and called with the registry's storage so that the registry's deployed code stays within the per-transaction gas limit of networks that price code deposit heavily; the split changes neither the interfaces nor any identifier.
  • Two consumers that close the loop at an execution boundary: ASFGuardedAccount.sol, an account whose operator acts only while the required bindings are satisfied and whose de-risking calls stay open while the response set in force (of the presented binding or of its suspended ancestors) includes RESTRICT_DERISK_ONLY and not RESTRICT_FULL_STOP, and ASFTaskTenderAdapter.sol, an acceptance authority for token-bound task tenders that admits only fulfillers holding the required bindings, with the task publisher as a required intervener, and leaves the tender's own clock in force on Unknown.
  • JSON Schemas for specifications, binding parameters, requirement sets, intervention responses and profile descriptors under schemas.
  • Vectors for interface identifiers, identifiers, keys, canonicalization, specification and binding identifiers and the requirement identifier under vectors.
  • Worked examples under examples: a personal-assistant specification with the principal's binding for an assistant on one account, a swarm specification with the organizer's binding for the swarm and a member's derived binding, two requirement sets, two intervention responses (a guardian's de-risk-only response and a principal's full stop), and six profile descriptors.

Security Considerations

Forged adoption claims. Anyone can create a binding that names any subject and any scope. The record proves only that its adopter made the statement. Consumers that present or rely on bindings must key everything by adopter, as the registry's indexes do, and must verify the adopter's entitlement against a permission source of their own choosing. A user interface that shows "agent X adopted arrangement Y" without showing who adopted it on X's behalf misleads its users.

Promises presented as controls. A binding declaring enforcement only at the self location is a promise. Requirements that matter should demand account, runtime, custodian, contract or collective enforcement, and consumers should read coverage and knownBypasses of the specification's channels. Declared locations are attributable commitments, not verified facts; evidence and the mechanisms themselves carry the verification.

Suspension is not revocation. Suspending a binding stops consumers that check it; it does not touch the permissions, keys, processes or commitments behind the arrangement. Operators should pair a suspension with the revocations the specification names, and consumers should not assume that a suspended binding has made the subject inert.

Validation-time staleness. A requirement checked when a session or batch is validated can be stale when the effect lands. Consumers must check at the time of effect; the reference consumers do so on every call.

Ancestor takeover and griefing. Anyone may create a binding derived from a public parent; this restricts the child, never the parent, and the child's adopter is attributable, so no harm reaches the parent. A parent's adopter or intervener can, by suspending the parent, stop every descendant; parties deriving from a parent accept that dependency knowingly, and a requirement that must not depend on a parent should require root bindings.

Index spam. Indexes are keyed by adopter, so a spammer fills only its own index. Consumers that scan another account's index bound the scan, as the reference adapter does.

Document availability and integrity. Content lives off chain behind locators. A document that cannot be fetched or does not hash to its pin makes the binding unverifiable, not satisfied; publishers should use durable content-addressed storage and adopters should keep copies of what they adopted.

Specification registry as a dependency. A binding pins a specification registry. If that registry stops answering, checks turn Unknown, which consumers route to the specification's failure handling. Deploying the two registries together and treating the specification registry as immutable infrastructure keeps this dependency inert.

Reports and labels as weapons. An open reporting channel can be flooded, impersonated or used to smuggle instructions to the agents that review it. The consumer rules of Section 11.7 deny reports, claims and labels any effect of their own, keep statement, acceptance, finding and action apart, index corrections with accusations, and treat report contents as untrusted input. Deposits and fees can limit spam but buy no findings; a dismissed claim is not evidence of bad faith by the reporter.

Response documents. A suspension's operational meaning lives in the response document behind responseRef. A consumer that cannot fetch it knows the bit set and the initiator but not the scope or the in-flight rule, and should fall back to the most restrictive reading its profiles allow.

Intervener key compromise. An intervener's key can suspend or, if granted, terminate a binding, and a suspension it records cannot be lifted by the adopter. Rights should be granted narrowly, interveners should be collectively governed accounts where the stakes warrant it, at least one intervener with the resume right should be independent of any single key, and the response requirements limit what a hostile suspension can achieve to stopping, never to widening. The adopter can always terminate and adopt afresh; a hostile intervener can stop an arrangement, not hold it hostage, except for the clauses that name it: a stop by a compromised or unresponsive intervener stands, for the clauses naming it, until that intervener or the lifter it named lifts it. An intervener should therefore name a lifter it trusts, such as a collectively governed account or an executor, before one is needed; a compromised intervener key can also rename the lifter, so the lifter is a review path, not a recovery path; and a consumer whose intervener key is lost changes its requirement.

Interveners chosen by the adopter. Every intervener of a binding was named by the adopter, so no registry rule about interveners establishes independence by itself: an adopter can name accounts it controls. Independence comes from the requirement, which names the accounts that must hold rights and closes the resume right to the accounts it names; consumers whose requirements name no interveners should know that the subject controls its own lifecycle. Naming a resource's own account as the required suspender gives that resource a stop over the subject; tenders and charters that want a neutral stop name an independent executor or a decision mechanism.

Termination, fresh adoption and sibling bindings. The adopter of a suspended binding can terminate it and create a new one, or can hold a second binding for the same subject and specification from the start. The registry does not prevent either; it makes both ineffective against a stop: a suspension recorded by an intervener stands against the adopter for the subject and the specification until the intervener, or the lifter it named, lifts it (Section 8.5), the terminated record keeps its suspendedBy, response set and responseRef, the new binding has a new identifier and a new createdAt, and a clause that names the intervener is met by none of the adopter's bindings while the stop stands. A consumer that scans an adopter's bindings for a satisfying one, as the reference adapter does, therefore cannot be led to a sibling. Replacement bindings remain visible and attributable where no stop stands; a consumer that must refuse them for other reasons pins the identifier it admitted or requires a binding created before a given time through its own rules.

Privacy of arrangements. Specifications and binding parameters can disclose business relationships and operational details. Publishers and adopters may keep sensitive members as commitments and disclose them to selected parties while keeping the canonical hash on chain; a consumer that cannot read a document treats it as unverified.

Time. Validity windows and suspensions depend on block time. Consumers should allow for the latency between a decision to suspend and its inclusion, and specifications should set failure handling for the interval.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth