Give AI autonomy without giving it authority

Version 0.7 September 2026

Human Agency Protocol — Governance

HAP is governed by invariant constraints, not institutions.

There is no central authority, no steward council, no registry, and no mandatory approval process. Compliance is enforced locally and cryptographically by any participant using the open specification.

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


Core Laws

HAP is designed to satisfy three non-negotiable laws of globally scalable protocols:

  1. Anyone can implement it
  2. Anyone can verify it
  3. No one can stop it

Any governance mechanism that violates these laws is invalid.


Canonical HAP Invariants

A system may only claim to be HAP-compliant if all of the following invariants hold.

Invariant 1 — No Mandate, No Ticket. No Ticket, No Execution.

A consequential action is any operation that affects external state, human wellbeing, financial position, legal standing, or reputation.

No executor (human or machine) may perform a consequential action unless preceded by:

  1. A valid HAP mandate conforming to a trusted Profile, given by an identifiable Mandate Owner
  2. A valid mandate ticket issued by the AS for that specific action, under that mandate, before the action runs

This is the v0.4 strengthening of the v0.3 invariant. v0.3 required only the mandate. v0.4 requires both the mandate (proof of authorization) and the ticket (proof that the specific action was within bounds at the time of execution).

v0.7 gives the invariant its final form of words — the same words used in public: no mandate, no ticket; no ticket, no execution. The first half rules out acting without a mandate; the second rules out acting outside one. A permission system promises only the first, and only for access; the ticket puts an identifiable human behind each act (identifiable by DID; the name is disclosed only by opt-in — Invariant 2).

v0.6 added the sentence that follows the invariant: a mandate constrains execution; it does not transfer authority. HAP does not model an automated system as an authority holder — authority remains with the Mandate Owner, and the protocol authorizes executions against mandates, never agents (see protocol.mdAuthority, Mandate, Ticket, Capability, Execution).

Invariant 2 — Explicit Human Mandate Ownership

Every mandate must reference at least one identifiable human Mandate Owner. Collective, symbolic, or anonymous ownership is invalid.

v0.7 states the boundary sharply: a Mandate Owner is one identifiable natural person, resolved by the Authority Server’s authentication to exactly one human. Institutional authority is valid under HAP only when exercised through such a person, who answers for the act. A role, a committee, a policy, a shared account, or a system MUST NOT be enrolled as an owner identity. Whether the person’s name is disclosed is a separate, opt-in property (protocol.mdIdentity Assurance); the rule is about who stands behind the DID, not whether the DID is labelled. Designs in which “the human” means an institution’s policy — humans as a species rather than this person for this act — do not satisfy this invariant, however carefully the policy is enforced.

Invariant 3 — Required-Owner Coverage

Each Mandate Owner is identified by DID. In group mode, execution is invalid if the profile’s required approvers (as defined by the AS group configuration) are not all covered by the granting Mandate Owners. In personal mode, the user commits directly with no approver checks.

Invariant 4 — Privacy Preservation

No semantic content may leave local custody by protocol design. ASes and Executors receive only:

Scope content, intent text, and any other narrative remain local.

Invariant 5 — Profile Conformance

Mandates must reference a specific Profile. Validation rules are Profile-defined. Unknown or untrusted Profiles must be rejected.

Invariant 6 — Binding Commitment

Once execution occurs, the associated commitment, ownership record, and ticket must be append-only and non-reversible. History may be appended to, but not rewritten. Revocation does not rewrite history — it only prevents new tickets from being issued against a mandate.

Invariant 7 — Cryptographic Ticket Before Execution

New in v0.4.

Every authorized action must obtain an AS-signed ticket before it executes. The ticket is the cryptographic proof that this execution was authorized before it ran. A system that authorizes actions without tickets is not v0.4+ compliant.

Invariant 8 — Tool-Gating Manifest Integrity

New in v0.5.

A Gatekeeper that fronts MCP tool calls (or any other tool-shaped surface) MUST gate every tool — including read-only tools — through a tool-gating manifest. There is no permissive default and no implicit categorization. actionType MUST be resolved from the manifest, never inferred from string patterns on tool names.

A system that exposes ungated tool access, or that derives enforcement semantics from tool-name parsing, is not v0.5+ compliant.

v0.6 extends the same fail-closed reading to the read path: a tool classified as a read that declares no applicable read governance MUST be denied (or carry an explicit, recorded exemption), and a resource scope enforced on writes MUST bind reads of the same resource (protocol.mdRead Authorization).

Invariant 9 — Deterministic Signing

New in v0.5.

Mandate and ticket signatures MUST be produced over a deterministic JSON canonicalization (sorted keys, no insignificant whitespace, base64url signatures, RFC 8785 compatible). The specification publishes the signing test vectors (Reference Conformance); an implementation MUST reproduce them so independent verifiers can confirm canonicalization parity.

A system whose signatures depend on object insertion order or implementation-specific JSON serialization is not v0.5+ compliant.

Invariant 10 — Complete Mediation

New in v0.6.

A HAP deployment MUST ensure that every consequential capability within its scope is reachable only through a HAP-enforced boundary — either because no path to the effector exists that does not traverse the Gatekeeper (path exclusivity), or because the effector itself refuses to produce the consequential effect without a valid mandate ticket (ticket-demanding execution).

A ticket-demanding effector satisfies this invariant only where it establishes the authenticity, action class, scope binding, freshness, and replay protection appropriate to that action (see Deployment Security Profile). Verifying a signature alone is not mediation: it confirms the ticket is genuine, not that it authorizes this effect now.

Invariant 1 is conditional on this one. A deployment that leaves an unmediated path to a consequential capability does not satisfy “no execution without mandate and ticket” for that capability, no matter how correctly its Gatekeeper behaves — the Gatekeeper is simply not on the path.

HAP does not implement, and cannot verify, the isolation this invariant depends on. It states the requirement, defines the two ways to satisfy it, and specifies the operator obligations below.


Profile Governance

Profiles are the mechanism for authority-specific enforcement. Profile governance follows these principles:

Permissionless Creation

Anyone may create and publish a Profile. No approval is required.

Versioned Evolution

Profiles version independently of HAP Core. Breaking changes require version bumps. Once published, a profile version is immutable — changes require a new version.

Local Trust Decisions

Applications and ASes decide which Profiles to trust. There is no global Profile registry.

Trust on First Use

profile_id is a stable identifier, not a runtime fetch URL. ASes and Gatekeepers MUST resolve profile_id to bytes through a one-time provisioning step (bundled at install, or fetched once and persisted) and MUST NOT re-fetch on the mandate or ticket hot path. The protocol relies on the publisher’s immutability promise plus each operator’s local copy. Two different questions are answered by two different mechanisms. Did the publisher serve honest bytes at provisioning time? — the protocol provides no cryptographic check for that; operators concerned about publisher integrity SHOULD verify a content hash at provisioning time using out-of-band means. Was this mandate issued under the profile I hold, and did the AS and the Gatekeeper agree on it? — since v0.7 the signed mandate carries profile_hash (sha256 over the JCS serialization of the parsed profile — protocol.mdProfile hash), so the profile a mandate was issued under is content-addressed from the artifact itself, the issuance check (PROFILE_HASH_MISMATCH) catches a Gatekeeper and an AS holding different profiles for the same profile_id, and a later substitution by the AS is detectable. Provisioning remains one-time.

Once provisioned, the local copy is the operator’s source of truth for that profile_id. The protocol’s trust unit is “Public Key + Profile + Local Policy”; the profile is part of the local trust anchor, not a remote dependency.

Transparent Specification

Profiles must fully specify:

Ambiguous Profiles are unenforceable.

Profiles MUST NOT define:

Profile Versioning


Permissionless Implementation

Any individual, team, or system may:

No approval is required. No registration is necessary.


Cryptographic Self-Verification

Compliance is proven exclusively through:

If an implementation satisfies the invariants, it is compliant. If it does not, it is not.

No external certification is required.


Adversarial Interoperability

HAP assumes all remote parties are potentially hostile.

Local systems decide which entities to trust using:

There is no global root of trust. There is only local sovereignty plus cryptographic proof.


Forkability and Naming

Forking is a feature, not a failure.

Any community may fork:

However:

This preserves interoperability without requiring permission.


Reference Conformance

To support interoperability without institutional control, the HAP ecosystem maintains:

Deliverable (since v0.5; widened in v0.7). The vectors are the specification’s, not any implementation’s. Since v0.7 they live with the specificationcontent/<version>/vectors/*.json, one test case per top-level entry — so any third-party AS or Gatekeeper can self-verify parity; an implementation-neutral artifact meant to settle whose bytes are correct cannot live inside one implementation. An implementation SHOULD consume these files in its own test suite rather than carry copies, and its report says whether it does.

v0.7 defines the conformance vector set — implementation-neutral, checkable offline, with no server, no store, no identity system, and no URL (the specification defines no endpoints, so a suite that speaks HTTP to fixed paths cannot be pointed at a conformant implementation that shares none of them). Three sets:

  1. Canonical bounds and scope → hash. A bounds object and a scope object, the exact canonical string each must produce, and its sha256. A one-character disagreement here means nothing either party signs will ever verify against the other, and it is invisible until two implementations meet.
  2. Payload → signature. A mandate, a ticket, a mandate projection (plain and review_above_cap), a co-signed mandate, and an approval, each with a published test key and the exact base64url signature. Pins field ordering, escaping, number formatting, and encoding together.
  3. Request → required refusal. A table of (situation, request, error code): no actionTypeINVALID_ACTION_TYPE; over a cumulative bound → CUMULATIVE_LIMIT_EXCEEDED; review mode without an approved proposal → PROPOSAL_REQUIRED; a revoked mandate → MANDATE_REVOKED; an unregistered appliesTo member → PROFILE_INVALID; a retired identifier in a ticket request → MALFORMED_TICKET_REQUEST. This set matters most, because refusal is where the safety lives.
  4. Profile → profile_hash. A published profile and the value every party must compute for it.

An implementation that reproduces every vector is conformant on those points. What vectors cannot prove — sequence: that the ticket preceded execution, that cumulative state is counted correctly across many calls — remains a claim about a running system and needs a live suite. This is a normative deliverable of the specification, not a promoted direction (a MUST-ship artifact is neither additive nor optional, so rule 3 does not apply). The v0.7 files exist (content/0.7/vectors/, 2026-09-03); what review.md tracks is their consumption by the reference library.

Running these tests is voluntary. Publishing results is optional.

Implementation reports

Implementation status is not part of this specification. The specification says what MUST hold; whether a given implementation holds it is a claim that implementation makes, in its own report, where a reader can weigh it against what that implementation exposes. A report SHOULD state: the protocol version(s) claimed on the wire; which optional surfaces (companion specifications, owner-signature bindings, disclose_fields) it implements; which vectors it reproduces; and every normative requirement it does not yet meet, in the specification’s own terms. It SHOULD NOT describe internals the reader cannot inspect. The reference implementation’s report is published with the conformance suite (hap-e2e/CONFORMANCE.md); its Gatekeeper and core library are open, its Authority Server is not, and the report says which claims a reader can check.

No entity grants approval. No entity issues certification.


AS Governance

Authority Servers are trusted parties. Their governance must be explicit:

AS Operators

AS Accountability

Each obligation below is an honest-operator control (protocol.mdEnforcement classes): it binds an AS that means to comply and is no defence against one that does not. What holds against the operator is the artifact in someone else’s hands — the signed ticket and mandate the Gatekeeper keeps in custody.

AS Misbehavior


Deployment Security Profile

New in v0.6.

Complete Mediation (Invariant 10) is satisfied by the execution environment, not by the protocol. A conformant deployment MUST provide the following properties. They are stated as obligations so an operator, an auditor, or a security reviewer has a checklist rather than an inference.

Each item states a security property. Where a topology is named it is an example of how the property is commonly achieved, never a definition of it: a deployment that achieves the property by other means is conformant, and one that matches the topology without achieving the property is not.

Credential and effector custody. A deployment MUST ensure that possession of any credential available to the agent is insufficient to cause a consequential effect without HAP authorization. Under path exclusivity, credentials capable of causing the effect MUST remain behind the Gatekeeper boundary. Under ticket-demanding execution, the effector MAY be directly reachable by the agent, and the agent MAY hold a credential that reaches it, provided the effector independently validates a ticket before producing the effect. The credential then confers reachability, not consequential authority, and separating those two is the point of the strategy.

Executor access. An Executor MUST either accept consequential commands only through the Gatekeeper boundary, or independently enforce valid mandate tickets at its own execution boundary. Exposing a directly callable interface is a violation only in the first case.

Ticket-demanding effectors. Where an effector enforces tickets itself, it MUST establish:

  1. Authenticity — the ticket is genuine and was issued by an Authority Server the effector trusts. Where the effector cannot verify the signature itself, this reduces to trusting the issuer, and MUST NOT be described as independent verification.
  2. Action class — the ticket authorizes this kind of action (actionType, and a profileId the effector expects). A ticket for a cheaper action MUST NOT release a costlier one.
  3. Scope binding — the ticket binds this effect, checked by recomputing the content hash from what is about to be executed. This is the load-bearing check; without it the ticket authorizes some action rather than this one.
  4. Freshness — the ticket falls within a validity window the effector defines, and its timestamp is not implausibly in the future. This is what stops an old ticket returning old, possibly vulnerable, state to production.
  5. Replay protection, scaled to the action — where repeating the action is itself the harm (a payment, a message send, an irreversible provisioning step), the effector MUST consume the ticket atomically so a second presentation fails. Where the effect is idempotent, the validity window MAY suffice; a spent-ticket store SHOULD NOT be mandated there, since it buys little and adds state, atomicity requirements, and new failure modes.
  6. Honest scope statement — the effector MUST document which properties it does not check, so an operator does not infer coverage that is absent.

A verifier SHOULD NOT depend on the software it is verifying: an effector that recomputes the canonical form itself, rather than calling the library that produced it, keeps a defect in that library from becoming invisible to the check that exists to catch it.

Gatekeeper integrity. The agent MUST NOT be able to modify, replace, reconfigure, restart into a different configuration, impersonate, intercept, or extract protected secrets from the Gatekeeper. (Non-normative: this is commonly achieved by separating agent and Gatekeeper into distinct processes under distinct user accounts, containers, hosts, or hardware boundaries, scaled to the value of the effectors involved. Separation alone does not establish the property — two processes under one account may be able to attach to one another, and a privileged container or a VM with an exposed management interface provides less than its topology suggests.)

Signing-key custody. The Authority Server’s signing key MUST NOT reside on any host the agent can reach. Where a profile or verifier policy requires a mandate binding above raw, the owner’s signing key MUST be held in the custody that binding names and MUST NOT be exportable to software the agent can read.

Fail-closed everywhere. Every dependency whose absence would otherwise permit execution MUST refuse instead: an unreachable Authority Server blocks, an unreadable profile blocks, an undeterminable resource scope blocks, an unparseable argument blocks. “Degraded mode” is not a conformant configuration.

Declared posture. A deployment claiming HAP conformance SHOULD record, per consequential capability, which mediation strategy it relies on. This is a declaration, not a proof — HAP cannot verify it, in exactly the sense that signing_surface is a declaration (protocol.mdOwner Signatures). It carries information because there is no benefit in claiming a posture to a party who will weigh it, and none a verifier can check. It is recorded because a control that is assumed rather than stated is the failure mode this specification repeatedly forbids elsewhere.

Which strategy is available

The two strategies are not interchangeable, and the choice is often not free:

SituationApproach
Third-party effector you cannot modify (payments, mail, calendar)Path exclusivity only — ticket-demanding execution is unavailable
Effector you own, with a trigger that cannot be fully restricted (CI/CD, webhooks, internal APIs)Ticket-demanding, subject to the six conditions above
Effector you own, reachable only through a credential the Gatekeeper holdsPath exclusivity, or both
High-value effector where topology cannot be guaranteed indefinitelyBoth

Ticket-demanding execution requires an effector you control, or one whose operator has adopted the protocol. A third-party API cannot be made to demand tickets, and no amount of architecture on the deploying side changes that. Where it is unavailable, path exclusivity is the only option and its fragility must be carried knowingly — it depends on a topology holding for the life of the deployment, and nothing in the system reports when it stops holding.


Multi-AS Ecosystem

The protocol supports multiple ASes:

Interoperability

The protocol does not yet specify cross-AS ticket federation (unchanged since v0.5). A single mandate lives on a single AS. Multi-AS federation for tickets is deferred to a future version.


Approver Authority Governance

Since v0.5, required approvers are configured per group on the AS, not in profiles.

Within Groups

Audit Trail


Dispute Resolution

When mandate or ticket validity is disputed:

  1. Verify cryptographic validity (signatures, hashes)
  2. Verify required-approver coverage at time of mandate
  3. Verify AS was trusted at time of mandate
  4. For tickets: verify the ticket was issued during the mandate’s TTL window and before any revocation
  5. If all valid → mandate and ticket stand
  6. If authority was invalid → mandate is void, AS may be at fault
  7. If ticket was issued for an unauthorized action → AS misbehavior

TTL Enforcement

Retention Enforcement

Revocation


Error Transparency

See the canonical error-code tables in protocol.md.


What Governance Is Not

HAP governance explicitly rejects:

HAP governs behavior, not actors.


Trust Model

Trust in HAP is constructed as:

Public Key + Profile + Local Policy

Every Authority Server, Profile, Executor, or App identifies itself via a public key. Local systems choose which keys and Profiles to trust. Unknown or untrusted keys are ignored by default.

There is no global trust anchor.

The Authority Server Cannot Check Itself

Several controls in this specification have the same shape, and stating the shape once is worth more than restating the limitation each time it recurs:

An AS-side check is not a defence against the AS. An AS-signed artifact held by another party is evidence a compromised AS cannot retroactively alter.

Both halves are load-bearing, and the second stops the first from proving too much.

The first half retires a class of decorative control. If the only thing standing between a claim and its abuse is the Authority Server validating that claim, then against a compromised Authority Server nothing stands there at all. A requirement the AS records, a uniqueness check the AS performs, a key directory the AS serves — each holds against an honest operator and evaporates against a dishonest one. That is not a reason to remove such controls; it is a reason not to describe them as defences against the operator.

The second half is why tickets are worth anything. An AS-signed artifact does not prevent a malicious operator. But once it is signed and in someone else’s hands it cannot be rewritten — which is precisely why tickets outlive mandates: expiring or revoking an authorization does not erase the record of what happened under it. Evidence and prevention are different properties, and the AS can supply the first without being trusted for the second.

Owner signatures (protocol.mdOwner Signatures) are this invariant applied: it exists to move authorization out of the class the first half describes (an AS assertion) and into the class the second half describes (a distributed, independently verifiable artifact). Instances the invariant catches inside this specification: cumulative bound enforcement (an AS-side check — conceded below; the Gatekeeper’s own custody archive covers only its own executions and is deliberately not an enforcement input), nonce consumption (AS-side, so defence-in-depth against third parties only), mandate-request co-signature requirements (recorded by the AS, so assurance rather than enforcement), and any AS-served key directory, including an AS signature over its own key directory — that is the AS vouching for the AS.

Consequence. Adopting this invariant obliged an audit of everything this specification describes as “enforced,” separating what holds only against an honest AS from what holds against a later-compromised one. v0.7 performed it; the result is the enforcement-class table in protocol.mdEnforcement classes, which annotates each control as honest-operator or compromise-resistant and forbids describing the former as a defence against the operator. An invariant with no audit behind it would have been the same decorative control it was written to eliminate.

Scope of AS trust. Choosing to trust an Authority Server’s key means trusting it to sign honestly and to enforce cumulative bounds, revocation, and approval. The local Gatekeeper is the counterweight: it re-derives gate_content_hashes from locally-held content and enforces per-transaction bounds and scope constraints, so a misbehaving AS cannot cause an Executor to run an action the human never authored locally. A compromised AS can still over-authorize authorities the human did create — cumulative state and pre-flight ordering are claims about a sequence only the AS witnesses, and that residue is stated honestly in protocol.mdWhat this does and does not prove. What v0.6 removes from the compromised-AS attack surface is fabrication of authority: where owners co-sign their mandates and approvals, the AS can no longer forge authorization artifacts attributed to a Mandate Owner, fabricate or discard approvals, flip commitment mode, or extend a mandate’s life. Mandates without owner signatures retain the v0.5 posture. The remaining hardening directions (a witnessed transparency log, approver-public-key authenticity) are tracked in review.md → “Resilience to a Compromised Authority Server.”

Relationship to execution-boundary control models (non-normative)

Since early 2026 several independent designs have converged on the execution boundary as the control point for AI agents. They share a lineage — security and compliance: an institution writes policy, a system enforces it at the last moment, and the agent is a system to be governed. HAP shares the door and not the philosophy. It is a delegation model from the leadership lineage: a named person gives a mandate, and the system proves that what ran fell inside it. The differences are the ones this document already makes normative — a named human’s mandate rather than institutional authority (Invariant 2); a portable proof held by parties other than the operator rather than an internal control (The Authority Server Cannot Check Itself; Gatekeeper custody); an open specification rather than a proprietary layer (Core Laws); and a why — the committed intent — rather than only a permission. In one line: control governs the agent; a mandate governs the delegation. A control model can sit under HAP as part of the execution environment (protocol.mdWhat HAP does not secure); it cannot substitute for it, because a fence with no named human behind each act is exactly the unmandated condition the protocol exists to end — and it stays that condition however narrow the fence becomes.


Companion Specifications

Some capabilities sit outside HAP Core but interoperate through it. v0.5 introduced the notion of a companion specification — an optional, independently versioned document that defines an extension surface. Companion specs MAY be implemented without affecting HAP Core conformance. A companion spec MUST NOT relax any HAP Core invariant; it MAY add new invariants applicable only to participants implementing the companion.

output-provenance@0.1

Binds mandates to observable outputs (URLs, artifacts, configuration state) via an optional output_ref field in the profile’s scope schema. See review.md § “Output Provenance” for the design. Profile-bound by design: when a deployment-style profile adopts it, output_ref is promoted into that profile’s normative surface — not into HAP Core. The companion-spec registration exists so the design has a stable name; it does not make Output Provenance a Core surface.

(decision-streams@0.1 was registered here in v0.5. The direction retired in v0.6 — nothing had implemented it since v0.3 and no integrator asked. The registration is withdrawn; the design record remains in the v0.5 archive.)

intent-disclosure@0.1

Status: Normative companion specification. Optional — implementing it does not affect HAP Core conformance, but a participant that claims intent-disclosure@0.1 MUST satisfy every requirement below.

Enables multi-recipient encrypted intent for review and review_above_cap authorizations, where the intent text is needed by approvers (typically on different machines than the original mandate owner) but MUST NOT be readable by the AS.

The HAP privacy invariant says no semantic content leaves local custody. That works for automatic mode, where no one downstream of the mandate owner reads intent. For review modes, two non-conformant solutions tempt implementers:

  1. Send intent in plaintext to the AS for relay. Violates the privacy invariant.
  2. Keep intent on the mandate owner’s machine and require approvers to fetch it directly. Operationally fragile, breaks asynchronous review.

intent-disclosure@0.1 chooses a third path: encrypt the intent under each approver’s public key, store the ciphertext on the AS, and let approvers decrypt locally. The AS holds bytes it cannot read.

Disclosure object

The mandate owner computes the following object and sends it to the AS alongside the mandate. These fields are AS-side metadata — they are not part of the signed mandate payload; their integrity is guaranteed instead by intent_disclosure_hash (below), which is signed.

{
  "intent_ciphertext": "base64url(iv ‖ AES-256-GCM ciphertext)",
  "encrypted_keys": {
    "did:key:alice": { "ct": "base64url(wrapped CEK)", "enc": "base64url(HPKE enc)" },
    "did:key:bob":   { "ct": "base64url(wrapped CEK)", "enc": "base64url(HPKE enc)" }
  },
  "approvers_frozen": ["did:key:alice", "did:key:bob"]
}
FieldRequiredDescription
intent_ciphertextyesThe canonical intent text (per Intent canonicalization in protocol.md) encrypted under a freshly generated 256-bit content-encryption key (CEK) with AES-256-GCM; the 96-bit IV is prepended to the ciphertext before base64url encoding.
encrypted_keysyesOne entry per approver, keyed by the approver’s DID. Each entry wraps the CEK to that approver using HPKE (RFC 9180) with suite DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM: enc is the HPKE encapsulated key, ct is the HPKE-sealed CEK. Each recipient is sealed independently.
approvers_frozenyesSnapshot of the approver DID set at issuance time. The key set of encrypted_keys MUST equal this set.

Signed binding (intent_disclosure_hash)

When a mandate carries a disclosure object, its signed payload (the Ed25519-signed MandatePayload) MUST include the field intent_disclosure_hash, computed as:

intent_disclosure_hash = "sha256:" + hex(
  sha256( utf8( intent_ciphertext ‖ "\n" ‖ JCS(sort(approvers_frozen)) ) )
)

where intent_ciphertext is the exact base64url string above, sort(approvers_frozen) orders the DIDs by Unicode code point, and JCS is RFC 8785 JSON Canonicalization of the sorted array. The mandate owner computes this after encryption and signs it as part of the mandate.

This is the integrity anchor: intent_ciphertext, encrypted_keys, and approvers_frozen travel unsigned, but any change to the ciphertext or the approver set alters intent_disclosure_hash, which is covered by the AS signature over the mandate — and, where the owner co-signed, by the owner-signed projection as well, which is what makes approver-set substitution detectable against a compromised AS. (encrypted_keys is bound transitively: its key set MUST equal approvers_frozen, and a verifier MUST reject any mismatch.)

Verification chain

  1. AS, at issuance time — recompute intent_disclosure_hash from the received intent_ciphertext + approvers_frozen; it MUST equal the value in the signed payload, and keys(encrypted_keys) MUST equal approvers_frozen. On any mismatch the AS MUST reject the mandate (fail-closed) — it does not store it.
  2. AS, relaying to an approver — return intent_ciphertext, the caller’s own encrypted_keys[caller_did], and approvers_frozen only to a DID present in approvers_frozen.
  3. Approver, on receipt of the disclosure — verify the AS signature over the mandate (and the owner signature, where present); recompute intent_disclosure_hash and confirm it matches; HPKE-open the CEK; AES-256-GCM-decrypt the intent; recompute gate_content_hashes.intent over the decrypted, canonicalized text and confirm it equals the value in the signed mandate. Only then is the intent trustworthy. This chain ties ciphertext, approver set, and plaintext-intent commitment together under one signature.

Companion-spec invariants

As a companion spec, only review / review_above_cap deployments opt in; automatic-only deployments carry none of this. See protocol.md Intent canonicalization for the shared hashing rule the chain depends on; which implementations claim this companion spec is stated in their own conformance reports (Reference ConformanceImplementation reports).

Known limitation (read against The Authority Server Cannot Check Itself). The approver public keys used to wrap the CEK are served by the AS and are not bound into any signed payload — intent_disclosure_hash freezes the approver set, not their keys. Intent confidentiality therefore holds against a passive AS and any interceptor, but an actively malicious AS could substitute an attacker key at issuance. Binding the approver→key map into the signed payload would make later substitution detectable but cannot stop an AS already malicious at issuance; what would actually hold is a key the verifier never receives from the AS. That fix does not transfer for free from the owner-signing answer, because these are encryption (X25519) keys where did:key as used in this specification carries an Ed25519 signing key. Changing the hash definition is a breaking change, so it is deferred to intent-disclosure@0.2; the open design question is tracked in review.md.


Final Statement

HAP does not ask for permission. It does not seek legitimacy from institutions.

Its authority derives from invariants that cannot be bypassed without detection.

Systems that preserve those invariants interoperate. Systems that do not are ignored.

That is the entirety of governance.