# Open Personal Context 1.0-draft-1

Wire version 1.0. Apache-2.0. Source revision d5e2754e5349c118306e0cf4ff10c5f142eba18a.

# Open Personal Context specification

Document version: `1.0-draft-1`. Wire version: `1.0`.

This is the draft specification of Open Personal Context: how a person's context is typed, deliberately disclosed and verifiably accounted for across assistants and services. Autonym is its reference implementation. The draft defines person-controlled records, consent, disclosure, temporary context, contributions and portability. See [conformance status](conformance/README.md) for implementation and test coverage.

## Structure

| Part                  | Location                                                                                                                                                                 | Status                                                                                                                                                                                                                                                                                    |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Core                  | [`core/`](core/a01-scope-and-layering.md)                                                                                                                                | Normative: A1 to A11 and A14 to A17, with [terminology](core/terminology.md), [design principles](core/principles.md) and the implementation notes for [identifiers](core/identifiers.md) and [scopes](core/scopes.md)                                                                    |
| Reserved chapters     | [`core/reserved/`](core/reserved/a12-recipient-registry.md)                                                                                                              | Informative placeholders, with no requirements, for capabilities reserved for 2.0: A12 recipient registry, A13 emergency information and continuous connectors. Their version 1 rules now live in A2.1, A6.8 and A17.6                                                                    |
| Bindings              | [`bindings/`](bindings/README.md)                                                                                                                                        | B1 PDPP, B3 MCP and B4 REST normative; B2 Linked Web Storage informative                                                                                                                                                                                                                  |
| Adoption records      | [`adoption/`](adoption/README.md)                                                                                                                                        | Normative where cited: one record per external standard, the generated register and the PDPP pin in [`pdpp.lock.json`](adoption/pdpp.lock.json)                                                                                                                                           |
| Vocabulary            | [`vocabulary/`](vocabulary/README.md)                                                                                                                                    | Normative registry, generated as [`core.json`](vocabulary/core.json)                                                                                                                                                                                                                      |
| Conformance           | [`conformance/`](conformance/README.md)                                                                                                                                  | Normative manifest of stable check IDs in [`profiles.json`](conformance/profiles.json), and the [statement audit](conformance/statements.json) that maps every extracted normative statement to its checks; informative [test vectors](conformance/vectors/README.md) with synthetic keys |
| Contracts             | [`schemas/`](schemas/entry.json), [`openapi/`](openapi/autonym-v1.yaml), [`mcp/`](mcp/tools.json), [`errors.json`](errors.json), [`scopes.json`](scopes.json)            | Generated from `packages/schema`                                                                                                                                                                                                                                                          |
| Operational artefacts | [`schemas/health.json`](schemas/health.json), [`schemas/readiness.json`](schemas/readiness.json), [`examples/operational-errors.json`](examples/operational-errors.json) | Informative here: generated contracts of the reference server's operational surface, which the reference implementation documents outside the specification. `errors.json` covers these operational codes as well as the recipient codes B4.3 governs                                     |
| Examples              | [`examples/`](examples/protocol.json)                                                                                                                                    | Informative synthetic examples                                                                                                                                                                                                                                                            |
| History               | [`history/`](history/CHANGES-from-proposal.md)                                                                                                                           | Informative: changes from the recovered proposal and interpretation notes                                                                                                                                                                                                                 |

## Core chapters

- [A1 scope, status and layering](core/a01-scope-and-layering.md)
- [A2 actors and trust model](core/a02-actors-and-trust.md)
- [A3 identifiers, handles and resolution](core/a03-identifiers-and-resolution.md)
- [A4 data model](core/a04-data-model.md)
- [A5 disclosure and the compiler](core/a05-disclosure.md)
- [A6 authorisation](core/a06-authorisation.md)
- [A7 agent surface](core/a07-agent-surface.md)
- [A8 recipient API](core/a08-recipient-api.md)
- [A9 read receipts and the log](core/a09-receipts-and-log.md)
- [A10 revocation and purge](core/a10-revocation-and-purge.md)
- [A11 portability](core/a11-portability.md)
- [A14 contributions](core/a14-contributions.md)
- [A15 security requirements](core/a15-security.md)
- [A16 privacy and legal mapping](core/a16-privacy-mapping.md)
- [A17 conformance and change process](core/a17-conformance-and-change.md)

The consent, temporary-context and reciprocity requirements first published as A18 are now A4.6, A6.7, A14.5 and A17.5. [`section-map.json`](section-map.json) maps every section of document 0.2-draft to its new location.

## Edition and bundle

Edition `1.0-draft-1` is the specification text above with the generated contracts stamped with that version. [`manifest.json`](manifest.json) lists every file in the edition with its SHA-256, so an implementation can identify the exact edition it uses. `pnpm check:spec` fails if the manifest, the section map, a local link or a generated scaffold is out of date, or if the text names a person, cites the project's decision log or refers to a build phase or work package; `pnpm check:generated` fails if a generated contract differs from `packages/schema`; `pnpm check:statements` fails if a normative statement has no current entry in the statement audit. Neither certifies service behaviour.

The core text is maintained by hand from this edition on. The recovered proposal it was first imported from stays hash-locked, unchanged, in the reference repository's source inventory, outside the specification.

A17 defines versioning: the document version and the wire version are separate, the `Autonym-Version` header echoes the wire version, and breaking wire changes change the URL prefix and require an approved ADR. While the protocol is a draft, changes go through a reviewed pull request with a change-register entry, schema and generated artefact updates and corresponding conformance checks. A public registry or governance process is not established yet.

Licence: Apache-2.0. See the root `LICENSING.md` for boundaries.


---

# Terminology

**Status:** normative. Document version `1.0-draft-1`.

- **Person**: the individual who controls a record.
- **Record**: the person's stored context, partitioned where needed and protected by the provider.
- **Partition**: a selected portion of the record; the historical wire field is `profile_id`.
- **Handle**: the opaque, normally pairwise address a recipient uses after consent.
- **Entry**: a typed fact, preference or state with provenance, versions and temporal validity.
- **Overlay**: an explicitly enabled, bounded preference targeting a standing baseline.
- **Domain/key**: a vocabulary category and its exact admitted value definition.
- **Level**: the permitted disclosure detail, L0 to L3; every level requires a grant.
- **Recipient/client**: the authenticated assistant or service requesting a defined capability.
- **Grant**: the provider's stored authority for one recipient and purpose, approved by the person.
- **Read receipt**: the owner-visible evidence committed with a disclosure.
- **Purge instruction**: a signed request to delete copies obtained under an ended grant.
- **Provider**: a service implementing declared Autonym capabilities; conformance requires evidence.


---

# A1. Scope, status and layering

**Status:** normative. Document version `1.0-draft-1`.

Autonym specifies a person-controlled context record, explicit recipient grants, progressive disclosure, accountable reads and portable records. It is provider-independent: a compatible recipient implements this protocol rather than an integration unique to one host.

This is document **1.0-draft-1**, specifying proposed wire version **1.0**. It is a complete publication of the current draft scope, open to interoperability review. It is not a ratified standard, a released server, a certification or a promise that an integration exists. The [implementation and conformance status](../conformance/README.md) distinguishes executable contract checks from missing service behaviour.

RFC 2119 and RFC 8174 capitalised MUST, MUST NOT, SHOULD and MAY identify requirements. Requirements apply to the capabilities an implementation claims, with the shared security requirements applying to every capability. Every normative section maps to the stable checks in [the conformance manifest](../conformance/profiles.json). Pending runtime checks mean unverified implementation, not permission to ignore a requirement.

## A1.1 Normative material

The normative publication consists of the core chapters A1 to A11 and A14 to A17 in `core/`, the normative bindings in `bindings/`, the core vocabulary, JSON Schemas, OpenAPI, MCP tool definitions and conformance requirements. A12, A13 and continuous connectors are informative placeholders in `core/reserved/` for capabilities reserved for 2.0; they carry no requirements, and the version 1 rules A12 and A13 used to state now live in A2.1, A6.8 and A17.6. The consent, temporary-context and reciprocity requirements first published as A18 are folded into A4, A6, A14 and A17. Prose defines cross-object and stateful invariants which JSON Schema cannot express. An implementation MUST satisfy both. Synthetic examples are informative; their illustrative signature bytes are not cryptographic test vectors.

Unknown fields at a defined wire boundary MUST be rejected. Keys absent from the released core vocabulary MUST be rejected unless a separately versioned future extension is negotiated; there is no permissive arbitrary-JSON entry lane.

## A1.2 Layers and release boundary

- The record model and vocabulary describe what is stored and the approved renderings.
- The compiler intersects the current stored grant, request, vocabulary and temporal selection.
- OAuth, DPoP and discovery establish recipient authority and protected-resource audiences.
- REST and MCP carry the same objects and use the same counted read transaction.
- Receipts, revocation, purge and portability describe the lifecycle after disclosure.

Vocabulary 1.1 contains 30 keys across all 17 proposed domains, retaining the original 27 keys from vocabulary 1.0. This intentionally bounds the first interoperable release. Keys outside this vocabulary require a later specification. Version 1 defines Core, Write, Portable and Delegated provider capabilities and Read, Contribute and Reciprocal recipient capabilities.

Credential presentations, recipient registries, guardian/duress operation and emergency cards are reserved extensions outside v1 conformance. Their chapters state the boundary and safety requirements for future work. Implementations MUST NOT advertise those reserved capabilities as conforming v1 features. Person-facing management UI and private management API routing are implementation choices; portable entries and owner-visible rights remain normative. The public recipient API is fully described in A8 and B4.

## A1.3 Existing standards

Autonym uses OAuth metadata and token formats, PKCE, DPoP, JSON Schema, JSON Web Signatures, JSON Canonicalization Scheme, Problem Details and MCP. It does not invent replacement cryptography or claim clinical, legal or identity certification from use of those standards. Links to primary specifications appear with the relevant contracts.

The grant model is defined here and in A6, independently of any one authorisation protocol. Open Personal Context Core stays meaningful without PDPP: [B1](../bindings/B1-pdpp.md) is the normative 1.0 grant binding, not a dependency of the model. A provider that does not offer B1 still implements every core requirement, and a change to PDPP changes B1, not the core.

Checks: all applicable [conformance requirements](../conformance/profiles.json), particularly CLAIM-01 and WIRE-01.


---

# A2. Actors and trust model

**Status:** normative. Document version `1.0-draft-1`.

The provider is an OAuth protected resource and normally its own authorisation server; an implementation may split these while preserving issuer and audience boundaries. The person chooses the provider and controls consent from an authenticated first-party session.

Clients are registered as `assistant`, `assistant_unverified`, `service`, `connector` or `self`. Registration evidence, not the client's own assertion, determines the class. A client is `assistant` when the operator's assistant allowlist names the host of its Client ID Metadata Document or, for a client registered without one, names exactly every redirect URI it registers. A client that registers or publishes a loopback redirect URI is never `assistant`, by either path and whatever the allowlist names, because any program on the person's device can receive a redirect there, so the client's identity cannot be assured (RFC 8252 section 8.6). A redirect URI is a loopback URI when its host, as a URL parser reads it, is `localhost`, a name ending in `.localhost` or a loopback address, whatever its scheme. Any other public client, one that does not authenticate to the token endpoint, is `assistant_unverified`; a confidential client that authenticates with a key it registered (A6.1) is `service`. Only the operator assigns `connector`, and only the provider's own first-party clients are `self`. No class uses Bearer tokens: every access token is bound to the client's DPoP key (A6.3). Version 1 has no certified registry tiers.

A client's class limits the grants it may hold (A6.2), and a request beyond them fails OAuth `invalid_scope`:

| Class                  | Grant kinds           | Capability scopes                    | Longest grant     |
| ---------------------- | --------------------- | ------------------------------------ | ----------------- |
| `assistant`            | Read and contribution | `autonym:propose`, `autonym:confirm` | No limit by class |
| `assistant_unverified` | Read and contribution | `autonym:propose`                    | 30 days           |
| `service`              | Read and contribution | `autonym:propose`, `autonym:confirm` | 72 hours          |
| `connector`            | Contribution only     | `autonym:propose`                    | No limit by class |
| `self`                 | None                  | None                                 | None              |

An `assistant_unverified`, `connector` or `self` client never holds `autonym:persist` or `autonym:delegate`; whether an `assistant` or `service` client may hold either is the provider's policy for that client. A `self` client holds no grant: the person's first-party capabilities (A6.2) are not issued through the grant flow. The `assistant` class the allowlist gives and the operator's own classification are the only trust signals a class carries. Every client that is not `assistant` and that the operator has not classified appears at consent with a warning that it is unverified, whatever its class.

The provider is trusted to store/encrypt correctly, enforce grants and preserve audit evidence. The protocol does not cryptographically prevent a malicious provider from reading information it processes. Operators must have no routine decrypt-arbitrary-records interface. Device compromise, recipient copies and off-platform misuse remain outside what a grant can prevent.

The principal threats are token theft, widened/stale authority, overspent counters, unsafe inference, hidden identifier leakage, contributor replay, expired temporary context, malicious record text, compromised URL fetches and misleading portability claims. Controls are specified in A3 to A17 and the bindings. Pairwise handles reduce direct linkage; L0 is not a promise of anonymity. Purge evidence is not proof of deletion. Duress and guardian controls require future designs and cannot be claimed as v1 protection.

## A2.1 Recipient registries and trust evidence

A registry can provide evidence about a recipient, but cannot grant access to a person's record. The provider's stored grant remains authoritative. Names, logos, registration metadata and client assertions are not certification. Registry unavailability cannot silently increase permission. If a future grant depends on active trust evidence, unverifiable, expired or suspended evidence fails closed. No recipient registry may expose another recipient relationship or the person's destination provider.

Checks: CORE-01, PAIR-01, CLAIM-01, OAUTH-01, CONSENT-01 and the cross-cutting controls in A15.


---

# A3. Identifiers, handles and resolution

**Status:** normative. Document version `1.0-draft-1`.

## A3.1 Owner and recipient identifiers

Internal record, partition and entry identifiers use the prefix and ULID grammar in [identifiers](identifiers.md). They are owner-management and export identifiers. The legacy wire term `profile_id` means a partition of the person's record; it is not a commercial dossier.

Recipients MUST NOT receive a record DID, canonical entry ID, owner identifier, another client's handle or another client's grant identifier through ordinary reads. Version 1 portability uses the signed export and preserves canonical entry IDs. Person-held record keys and public DID host bindings are reserved for a separately specified extension, not a dependency of Core or Portable.

## A3.2 Pairwise handles and entry aliases

Syntax: `autonym:<local>@<authority>`. Newly issued pairwise locals are exactly 32 lower-case RFC 4648 base32 characters, without padding. The authority is the configured lower-case ASCII DNS hostname, with no port, user information, path or trailing dot. An IP address is never an authority, and neither is a name whose last label is all digits or `0x` followed by hexadecimal digits, since URL parsers read such a name as an IPv4 address. The handle pattern in the published schemas checks only the syntax of the authority's labels, so it also accepts such names. A valid shape example is `autonym:abcdefghijklmnopqrstuvwxyz234567@autonym.example`.

Each record partition has a dedicated random 256-bit handle key. Generate the local part as the first 32 characters of lower-case, unpadded RFC 4648 base32 of HMAC-SHA256 over UTF-8 RFC 8785 canonical JSON:

```json
{
  "purpose": "autonym.handle.v1",
  "client_id": "https://recipient.example/client",
  "rotation": "00000000-0000-4000-8000-000000000001"
}
```

`client_id` is the exact registered identifier, not a normalised URL or display name. `rotation` is a newly generated lowercase UUIDv4 per recipient rotation. Check uniqueness before committing issuance. A collision requires a fresh rotation and retry. HMAC keys are never shared with recipients or exported to a new provider.

Recipient entry references use `rent_` followed by all 52 base32 characters of HMAC-SHA256 under the same dedicated key, over JCS of `{purpose:"autonym.entry.v1", client_id, rotation, entry_id}`. The different `purpose` separates the two uses. Rotation atomically changes handles and aliases, invalidates old grants/tokens and starts required purge processing. Never expose canonical IDs through provenance, dependencies, errors, ETags or diagnostic counts.

The older 12-to-32-character parser grammar remains accepted for reading historical owner material. New wire objects use the exact 32-character contract. Public handles are optional: 3 to 30 ASCII characters, lower-case letters and digits with single internal hyphens. No leading, trailing or consecutive hyphens. Claiming one requires re-authentication, rate limits, a reserved-name list, one public name per partition, a 30-day change cooldown and a 12-month release quarantine. A public name provides a provider address for consent; it MUST NOT yield record contents, a DID or evidence that the person exists to unauthenticated enumeration. Token subjects remain pairwise.

Pairwise identifiers prevent identifier-based cross-recipient joins; they do not make context anonymous or prevent correlation using facts already disclosed.

## A3.3 Discovery

`GET /.well-known/autonym` returns [the discovery schema](../schemas/discovery.json): protocol version, configured issuer and authorisation server, the trusted JWKS URI of the provider's A5.4 key set, enabled REST/MCP endpoints and an honest role-specific capability declaration. Disabled surfaces are `null`. No person's identifier or record information appears in discovery. The schema example in [protocol examples](../examples/protocol.json) illustrates capability claims, not a deployed service.

OAuth protected-resource metadata is separate and follows A6. Clients resolve the host from a user-supplied handle or configured provider, validate HTTPS and metadata origin, and never trust request forwarding headers as the provider's identity. Every fetch of an untrusted client/provider URL must use SSRF-safe retrieval with DNS/address checks, size/time limits and revalidation at each allowed redirect.

## A3.4 Migration

Migration transfers an owner-approved export into a new provider. Canonical owner IDs can be preserved, but the new provider creates fresh pairwise keys, handles, aliases and authority. Imported grants are history only. The person reauthorises each recipient against the new audience.

The old provider MUST NOT redirect authenticated API or token requests to a different origin, forward credentials, or reveal the destination to contributors. Destination notifications are separately approved per recipient. An optional public-handle web redirect requires separate explicit approval and carries no credential or personal data. Purge instructions and acknowledgements continue at the old provider until settled; the new provider cannot acknowledge deletion of the old provider's disclosures.

Checks: PAIR-01, CORE-01, PORT-01, HANDLE-01, MIGRATE-01, FETCH-01. Fixed synthetic [framing vectors](../examples/identity-framing.json) give canonical bytes, HMAC digest, base32 and final identifiers. Independent cryptographic interoperability remains a runtime release gate.


---

# A4. Data model

**Status:** normative. Document version `1.0-draft-1`.

## A4.1 Entries and vocabulary

The exact stored/exported entry is defined by [entry.json](../schemas/entry.json), with complete synthetic examples in [protocol.json](../examples/protocol.json). Fields include an internal ID and immutable version, partition, domain/key, typed value, semantic kind, provenance, temporal interval, optional overlay, approved rendering, status and origin. Safety and sensitivity come from the trusted vocabulary, never contributor-supplied flags.

`context_kind` is `fact`, `preference` or `state`, independent of provenance. Facts describe a declared or evidenced condition. Preferences express choices. States describe bounded current circumstances. `value_type` must match the key definition, and `value` must pass that key's closed schema. The larger type-name enum reserves future types; it does not admit unregistered keys. [The vocabulary](../vocabulary/core.json) specifies types, cardinality, levels, renderers, flags, labels, explanations and per-level examples for every v1 key.

A change creates a new immutable version. Older versions remain history under owner retention policy. `active`, `superseded` and `archived` are stored value statuses; expiry is computed from time, not a status that depends on a worker. Deletion creates a separate non-content [tombstone](../schemas/tombstone.json) with ID/version/partition/domain/key and deletion time; it carries no value or evidence. A tombstone's version is one more than the last version of the entry it deletes, so no ID and version name both a version and a tombstone, and an earlier version keeps the status it was written with. Record erasure additionally follows owner retention and applicable obligations; retaining a tombstone does not permit retaining the deleted value indefinitely. A partition holds at most 10,000 entries that have not been deleted, which bounds what one read compiles; a write that would add another fails with `entry_limit_reached` and changes nothing. No agent operation adds an entry: a contribution is acknowledged as a proposal whatever the partition holds (A14), so only the person's own operations, such as accepting a proposal in the first-party app or an import, meet the limit.

## A4.2 Provenance

`declared` means the person entered or explicitly confirmed the exact statement; it requires `confirmed_at`. `observed` covers sourced observations/inferences, requires source identity, occurrence and ingestion times, confidence, and a finite validity end no later than 90 days after ingestion. `derived` names every input ID, version and actual field/level used. `attested` is reserved for future credential verification and MUST be withheld from v1 recipient disclosure unless the person separately confirms a declared entry.

Source identity is evidence of origin, not truth. Review of a contribution does not automatically relabel it as declared. Preserve source event identity and evidence after confirmation; never disclose that evidence merely because the confirmed preference is shareable.

Special-category and safety-critical keys MUST NOT be observed or inferred. `inferable:false` is absolute; a domain toggle cannot override it. Imported sensitive suggestions remain protected proposals until exact confirmation in the first-party app. Confidence is not consent.

## A4.3 Temporal intervals

Wire instants are UTC RFC 3339 instants with `Z`. Instants compare by the time they denote, at full fractional precision, not by their bytes: `2026-09-21T00:00:19.9999Z` and `2026-09-21T00:00:19.999900000Z` are the same instant. Date-only entry is a UI convenience: the UI resolves the selected timezone and daylight-saving ambiguity before storing an instant. A month means the selected local calendar interval, not an assumed number of seconds. Version 1 has no recurrence rule.

Use one provider `Clock` instant for the entire read transaction. Eligibility is `valid_from <= now < valid_until`. Null start means no lower bound; null end means no upper bound. Reject equal or reversed finite bounds. A `state` and every overlay require a finite end. Future entries do not appear early. Manual archive/disablement takes effect on the next read. Entry validity and grant validity are checked independently.

Staleness is informational: `confirmed_at` older than 365 days, or 90 days for safety-critical keys, sets `stale:true`. Never infer that a stale allergy has ceased. An expired temporary fact is omitted; any independently eligible standing safety fact remains.

## A4.4 Baselines and temporary overlays

An overlay is a separate preference entry with `overlay:{target_entry_id,enabled,selected}`. The target must be an active baseline in the same partition/domain/key. Version 1 allows overlays only for single-cardinality, non-sensitive, non-safety preferences. The person explicitly enables it; enabling it is separate from making it permanent. Overlay creation or expiry MUST NOT supersede or alter the baseline.

Overlays apply only to the baseline that is eligible and selected for its key at that instant; the overlays of any other baseline are neither disclosed nor considered. Selection counts only the eligible enabled overlays for that baseline: a selection on an overlay that is not eligible under A4.3, or not enabled, neither wins nor counts against another overlay. Among the eligible enabled overlays, one explicitly selected overlay wins. If none of them is selected and exactly one is eligible, that one applies. If several are eligible without one selection, or several of them are marked selected, apply none and use the eligible baseline until the person resolves the conflict. A choice atomically clears competing selections for that target. Do not resolve these conflicts using insertion order or confidence. The overlay is chosen from the record before the grant and request are applied, so a winning overlay that the grant or request withholds is omitted, and the baseline it replaces is never disclosed in its place.

Fasting and holiday context are additive, time-bounded states. Reduced walking after injury is a temporary safety-related fact, not permission to replace a standing requirement. A month without alcohol can temporarily replace a standing drink preference. These choices do not automatically reveal why, where or with whom.

For ordinary baseline conflicts, the person's declared value takes priority over observed/derived candidates. Multiple incompatible declarations require the person's choice before replacing the current selected baseline. Imports do not silently choose one. Many-cardinality keys retain individually eligible entries. All safety-critical keys are many-cardinality so several allergies, alerts or needs coexist; replacing one cannot remove another.

## A4.5 Derivations

At disclosure, recursively validate every dependency's current version, validity, purpose, grant rights and actual fields/level used. Domain permission alone is insufficient: permission for an L1 summary does not authorise deriving from hidden L3 identifiers. Reject cycles, depth above 16, more than 256 dependency references, absent inputs and stale versions. The limit counts every reference traversed from the disclosed entry, along every path and without de-duplication: an input reached by several paths, or named more than once, counts each time it is reached, and so do its own references. Recompute or withhold on any change or expiry. Never disclose dependency identifiers or raw source history through a preference read. In v1, dependency field references are `value` for the whole stored value or `value.<member>` for one named own member of a structured value. Nested paths, array indexes, wildcards, metadata and unknown members are unsupported and MUST be withheld. The required level must support the actual referenced field: a category or approved text override does not authorise its raw source value; a first-name rendering authorises `value.first`, not `value.full` or the whole name. Dependencies are checked under the same grant purpose and the request's level, declaration and confidence restrictions. The request's output domains and keys need not name an input, but the stored grant must permit it.

A separately confirmed declared preference can be shared independently of raw history. That is an explicit confirmation decision; accepting a stream or trusting a contributor does not perform it.

## A4.6 Temporary context

The precise representation is A4's semantic kind, UTC interval and optional baseline-targeting overlay. A temporary overlay requires a finite end and explicit activation. A fasting period or holiday is a bounded additive state; a month without alcohol is a drink-preference overlay. Grant expiry and entry expiry are independent.

The provider captures one trusted instant per transaction. Start is inclusive and end exclusive. Future context is withheld until its start; expired or disabled context stops on the next read without waiting for a cleanup job. The person's timezone is resolved when turning dates into instants. Version 1 deliberately omits recurrence; the person confirms each new interval.

An overlay never rewrites the standing preference. When it ends, the eligible baseline returns. It cannot weaken a safety fact. A single eligible enabled overlay applies without a selection. Conflicting overlays require the person's choice; while several eligible overlays compete without exactly one of them selected, use the baseline (A4.4). Turning a temporary preference into a lasting one is a separate explicit action.

Dependencies, derived values and caches cannot preserve an expired temporary state. Disclosure validity includes the next relevant time boundary; a bodyless conditional response cannot renew it. Permanent history, deletion and a recipient's previously received copy are separate lifecycle questions.

Checks: DISC-01, TEMP-01 to TEMP-03, CONTRIB-01 to CONTRIB-03, INFER-01, WIRE-01, PORT-01.


---

# A5. Disclosure and the compiler

**Status:** normative. Document version `1.0-draft-1`.

## A5.1 Levels

| Level | Maximum permitted detail                                                          |
| ----- | --------------------------------------------------------------------------------- |
| L0    | The key's closed `l0_category` code only; no value                                |
| L1    | Identifier-free values, including non-identifying structure and broad age bands   |
| L2    | L1 plus first names and only the additional structure the key explicitly supports |
| L3    | The full permitted value                                                          |

Names, exact dates of birth, detailed addresses, phone/email, account/loyalty numbers, employer and institution names MUST NOT appear at L1. Free text at L1 or L2 requires the person's identifier-safe approved rendering; omit it if absent. Automatic redaction is not approval. Structure by itself does not imply a higher level: safe roles and age bands may be structured at L1. L0 is reduced detail, not anonymity or ambient permission.

## A5.2 One compiler and transaction

The [context request](../schemas/context-request.json) has one optional `max_level`, default L3, applied independently to each requested domain. Omitted `declared_only` is false, `min_confidence` is zero. The request cannot widen the stored grant. Explicitly ungranted domains fail with `domain_not_granted`, without revealing whether they contain entries. Keys are the intersection of request, grant and vocabulary; unknown or ungranted keys do not reveal existence.

For each requested domain, select the highest vocabulary-supported level at or below both ceilings. If none exists, omit the entry. Effective `declared_only` is grant OR request; minimum confidence is the maximum of both. A declared-only read includes only exactly confirmed declared entries in v1. Restrict provenance evidence separately. For this filter, an exactly confirmed declaration has effective confidence 1; other eligible provenance uses its recorded confidence, with null treated as zero. This is a filtering convention, not proof that a statement is true.

Within one transaction: authenticate the client, validate token audience/sender proof, lock and recheck the grant and counters, capture trusted time, select eligible baselines/overlays, enforce dependencies, render, create and sign the envelope, append its receipt, increment the counter, commit, then return. A revoked, expired or exhausted grant fails `grant_revoked`, `grant_expired` or `grant_exhausted`. Signing failure, receipt failure or commit failure returns `internal_error` and no disclosure. Concurrent reads cannot overspend a limit. All surfaces call this same transaction.

Safety-critical entries sort first, then declared, observed and derived; ties sort by domain, key and recipient alias. No recipient envelope carries hidden-entry counts, omission reasons, internal IDs or full evidence. A domain list exposes only granted keys that could currently be disclosed, and has no counts.

`since` is a UTC change filter, not permission to reuse indefinitely. It includes entries whose selected value or temporal eligibility changed since the instant, including baseline restoration. Always include currently eligible safety-critical entries even when older. Implementations MAY conservatively include otherwise eligible entries when their selection group or dependency group changed; they MUST NOT omit restored eligibility because the baseline's stored value was unchanged. Deletion and explicit selection changes that are no longer represented in current entries require trusted change evidence from storage. A client must obtain a full fresh read after a previous envelope expires; a partial response does not renew missing entries.

## A5.3 Signed disclosure

[disclosure.json](../schemas/disclosure.json) is the exact response. Entries are a flat array with domain/key and client-bound `rent_` identifiers. The signature binds provider (the issuer URL discovery publishes, A3.3), protected-resource audience, client, handle, grant ID/revision, purpose, read ID, issue time and absolute `valid_until`. Example bytes in [protocol.json](../examples/protocol.json) are synthetic and intentionally not a verifiable signature.

`valid_until` is the earliest of grant expiry, any disclosed entry/dependency expiry, the next eligible overlay/selection time boundary affecting the result, and five minutes after issue. `ttl_seconds` is the nonnegative whole-second interval to that deadline, rounded down. Even an empty response expires at the next relevant selection boundary. Use `Cache-Control:no-store`; recipients may retain transient context only until this deadline unless a separate persistence right exists.

Persistence authorises retention, not continued use of an expired temporary fact as current context. A recipient must stop treating an entry as current at the signed deadline and refresh through a new authorised read. `persist_until` is null without explicit permission and never exceeds grant expiry. No onward-sharing right exists in v1.

## A5.4 Signature representation

Sign UTF-8 [RFC 8785 canonical JSON](https://www.rfc-editor.org/rfc/rfc8785) of the complete object without `proof`. Use ordinary base64url payload mode with [RFC 7515 Appendix F detached compact JWS](https://www.rfc-editor.org/rfc/rfc7515#appendix-F): `protected..signature`, each part in unpadded base64url and in no other spelling of the same bytes. The protected header has exactly three members: `alg:ES256`, `kid` and `typ`, which is `autonym-disclosure+jws` for a disclosure and the value the signing section names for any other object. Unencoded-payload mode is not used. Receipts (A9), purge acknowledgements (A10) and exports (A11) are signed the same way. Each signed object has one signed time: `issued_at` for a disclosure, `at` for a receipt or purge acknowledgement, `exported_at` for an export, and `iat` for the purge instruction token (A10). A signature is not an identifier: ECDSA admits more than one valid signature over the same bytes, so signed objects are compared without `proof`.

**Key IDs.** A `kid` is the [RFC 7638](https://www.rfc-editor.org/rfc/rfc7638) JWK thumbprint of the public key: SHA-256 over its required members `crv`, `kty`, `x` and `y`, in canonical unpadded base64url: 43 characters, the last of which carries two unused bits that are zero. A key ID therefore names exactly one key and cannot be reused for a different key.

**Key sets.** A provider publishes its verification keys at the discovery `jwks_uri` as an [RFC 7517](https://www.rfc-editor.org/rfc/rfc7517) JWK set following [key-set.json](../schemas/key-set.json). Each key has `kty:EC`, `crv:P-256`, `x` and `y` (each 32 bytes in canonical unpadded base64url, so one key has one key ID), `kid`, `alg:ES256` and `use:sig`, and no private member. A provider's signing key belongs to that provider alone and MUST NOT appear in another provider's key set, so that a valid signature identifies one provider whatever the signed object names (KEY-01). A retired key also has `exp`, the JWK parameter registered by [OpenID Federation 1.0 section 8.7.2](https://openid.net/specs/openid-federation-1_0.html#section-8.7.2): a whole number of seconds since 1970-01-01T00:00:00Z, the first instant at which the key signs nothing. It stays in the set, with the same `exp`, so that what it signed earlier still verifies (A9). No other key lifetime member is used: a key that carries `nbf`, `iat` or `revoked` is not used to verify anything. The keys a recipient registers to sign purge acknowledgements follow the same rules.

**Canonical instants.** Every instant a provider writes into an object it signs or hashes has one spelling: UTC with `Z`, seconds always present, and fractional seconds only when they are not zero, without trailing zeros, for example `2026-10-02T19:00:00Z` or `2026-10-02T19:00:00.25Z`. Precision is never reduced. Equal instants therefore give equal bytes, and a deadline's spelling reveals nothing beyond the instant itself. Instants compare by the time they denote; a verifier does not reject an instant for its spelling.

**Verification.** Parse the received text strictly before canonicalisation: reject duplicate members, with names compared after escapes are decoded, and anything that is not [I-JSON](https://www.rfc-editor.org/rfc/rfc7493), including a lone surrogate or noncharacter and a number written with more magnitude or precision than an IEEE 754 binary64 value provides: one whose decimal value differs from that of the shortest decimal identifying the binary64 value it parses to, such as `1E400` or `3.141592653589793238462643383279`, while `0.1` and `1e23` are accepted. A verifier bounds the size and nesting of what it parses (A15.3), and may refuse a member named `__proto__`, which no object here defines and which common JSON libraries handle inconsistently. Verify the signature over the canonical form of the parsed object without `proof`. Accept only ES256 and a key from the trusted, configured key set of the issuer: the configured provider for a disclosure, receipt, export or purge instruction, and the recipient's registered keys for an acknowledgement. Once an export verifies against the configured key set of the provider it came from, its `public_keys` are the trusted key set, and its `origin_host` the trusted issuer, for the receipts it carries (A11), which is how a receipt signed before a key rotation verifies from the export alone (A9). A carried receipt that names another provider is verified only against that provider's own configured key set, or reported as unverified history. A trusted issuer is never taken from the object being verified. Select the one key whose `kid` equals the protected header's, never a key or key URL that the object or its header supplies, and recompute its thumbprint. Reject:

- any protected header member other than `alg`, `kid` and `typ`, including `crit`, `jwk`, `jku`, `x5u` and `b64`, and any duplicate header member;
- `alg:none` and every algorithm other than ES256;
- a `typ` that differs from the expected value, compared exactly;
- proof metadata whose `alg` or `kid` disagrees with the protected header;
- a key ID that is not in the trusted set, appears in it more than once, or is not the thumbprint of its key;
- a matching key that does not follow [key-set.json](../schemas/key-set.json), such as one with a private member, `key_ops` or a lifetime member other than `exp`;
- a signed object whose signed time is at or after the instant the matching key's `exp` denotes (A9, KEY-01);
- a disclosure or receipt whose `provider`, or an export whose `origin_host`, is not the trusted issuer, compared as exact strings;
- a receipt whose `hash` is not the A9 hash of its own content;
- a disclosure whose `valid_until` is not after `issued_at`, is more than five minutes after it, or disagrees with `ttl_seconds`; one whose `issued_at` is more than 60 seconds after the verifier's trusted current time, the most the two clocks may differ; and one whose `valid_until` is not after the verifier's trusted current time.

Check every other signed binding as well, such as the client, audience, handle and grant of a disclosure. A valid signature alone does not establish current grant authority.

SD-JWT credential presentations are reserved for a later version and cannot be claimed by Core implementations.

Checks: DISC-01, SIGN-01, KEY-01, CORE-01, LOG-01, LOG-02, TEMP-02, TEMP-03, CONTRIB-03.


---

# A6. Authorisation

**Status:** normative. Document version `1.0-draft-1`.

This chapter states the authorisation requirements against the abstract grant model, independently of any one authorisation protocol. Open Personal Context Core stays meaningful without PDPP: [B1](../bindings/B1-pdpp.md) is the normative 1.0 grant binding, not a dependency of the model. B1 maps these requirements onto PDPP Core; where B1 and this chapter differ, this chapter wins.

## A6.1 Discovery and registration

Providers MUST serve a path-specific [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728) metadata document for each protected resource they serve, at the location RFC 9728 section 3 derives from its resource identifier, such as `/.well-known/oauth-protected-resource/mcp` and `/.well-known/oauth-protected-resource/v1`, and authorisation-server metadata under RFC 8414. There is no document at `/.well-known/oauth-protected-resource` itself: its `resource` would be the origin, which is not an audience. Each document names the issuer in `authorization_servers`, sets `dpop_bound_access_tokens_required` to true and lists `ES256` in `dpop_signing_alg_values_supported`. Metadata names the configured issuer, never an untrusted Host or forwarding header. Authorisation responses include the RFC 9207 `iss` parameter.

`<origin>/mcp`, `<origin>/v1` and the resource of each binding a provider offers, such as the PDPP resource of B1.2, are distinct audiences. An unauthenticated response includes a `WWW-Authenticate` challenge pointing to the requested resource's metadata. Client ID Metadata Documents are the primary registration mechanism for unknown clients; static registration supports first-party clients and RFC 7591 dynamic registration remains available to any client for compatibility. Metadata fetching requires exact client-ID matching, redirect checks and SSRF-safe retrieval. A client cannot self-assign a trusted class or certification.

Registration metadata, sent to the registration endpoint or published as a Client ID Metadata Document, has the members of [client-metadata.json](../schemas/client-metadata.json) or [client-metadata-document.json](../schemas/client-metadata-document.json): RFC 7591 members and `autonym_purge_uri`, the HTTPS URL to which purge instructions are delivered (A10). A client's keys are given inline in `jwks` under the A5.4 key-set rules: ES256 public keys whose key IDs are their RFC 7638 thumbprints, used for `private_key_jwt` client authentication and purge acknowledgements. The token endpoint authentication method is `none` for a public client or `private_key_jwt` for a confidential one; no client secret is issued or accepted. `private_key_jwt` needs `jwks`; `client_credentials` is only for a client that authenticates with `private_key_jwt`; `refresh_token` comes only with `authorization_code`, which goes with the `code` response type and at least one redirect URI; and redirect URIs, grant types and key IDs are each unique. A client that uses the A6.4 token exchange lists `urn:ietf:params:oauth:grant-type:token-exchange` in `grant_types`, and one that redeems a grant offer lists `urn:autonym:params:oauth:grant-type:grant-offer`; a grant type the provider does not offer is refused. A client that lists the grant offer grant type authenticates with `private_key_jwt`, as one that lists `client_credentials` does, because only its registered key shows that it is the client a grant offer names (A6.4); a public client may still use the token exchange as a delegate. A redirect URI is an HTTPS URL, or an `http` URL at `127.0.0.1`, `[::1]` or `localhost`, without a fragment, and a port in any URL is between 1 and 65535. A Client Identifier URL has no `.` or `..` path segment, written plainly or percent-encoded, and its host is a name whose last label is neither all digits nor `0x` followed by hexadecimal digits, which URL parsers read as an IPv4 address. `client_name`, `contacts`, `software_id` and `software_version` carry only characters of the Basic Multilingual Plane, and no control character, bidirectional formatting character, line or paragraph separator, interlinear annotation character or default-ignorable character, one that renders as nothing, such as a zero-width space, a soft hyphen, a Hangul filler or a variation selector. Characters outside the Basic Multilingual Plane are refused because they include the tag characters, which can carry hidden text, and a regular expression that reads text in 16-bit code units, as JavaScript's does, cannot tell those from the rest. `jwks_uri`, `sector_identifier_uri`, `application_type`, a software statement, a registry attestation and any member the schema does not list are refused, so a registration is never accepted with members silently dropped; whether a client may use the loopback-port exception is decided from its redirect URIs (A6.3). The registration endpoint answers RFC 7591 `invalid_redirect_uri` or `invalid_client_metadata` for metadata it refuses, and answers 429 `rate_limited` in the RFC 7591 error form to a source that registers too often.

## A6.2 Scopes and separate grants

[scopes.json](../scopes.json) and [scope grammar](scopes.md) define the existing `autonym:` syntax, ten purpose categories and exactly one purpose. A purpose alone gives no read, contribution, persistence or delegation right. Any accepted `:declared` modifier makes the entire stored grant declared-only, including wildcard combinations; use separate grants for different declaration restrictions. Explicit domain ceilings take precedence over wildcard L0. Scope parsing is syntactic; the issuance policy additionally rejects a mixed read/contribution grant.

Each capability scope has one meaning at issuance ([scope grammar](scopes.md)): `autonym:propose` requests a contribution grant, and `autonym:confirm` sets its `allow_confirmation`; `autonym:persist` permits a read grant's `persist_until`, and `autonym:delegate` sets its `allow_delegation`. `autonym:confirm:safety`, `autonym:write:declared`, `autonym:log:read` and `autonym:manage` belong to the person's own first-party clients and are never issued to a recipient. `openid` and `offline_access` are not Open Personal Context scopes, so a request naming either is refused like any other unknown scope. A request that mixes read and contribution, asks for a capability of the other grant kind or asks for one its client's class cannot hold (A2) fails OAuth `invalid_scope`; a contribution detail that does not follow its schema, or repeats a domain or a key, fails RFC 9396 `invalid_authorization_details`.

A contribution grant is requested with `autonym:propose`, exactly one purpose scope and one RFC 9396 `authorization_details` entry of type `urn:autonym:authorization-details:contribute` ([contribution-detail.json](../schemas/contribution-detail.json)), which names the domain and key allowlist, `max_events` and `allow_confirmation`. `allow_confirmation` is true exactly when `autonym:confirm` is requested; a detail that says otherwise fails RFC 9396 `invalid_authorization_details`, so the class limits on `autonym:confirm` (A2) also bound the detail. The provider generates its `stream_id` at issuance. A contribution grant is never a PDPP grant (B1.1).

The [grant schema](../schemas/grant.json) is a discriminated `read` or `contribute` object. A read grant names domain ceilings and explicit keys, declared-only/confidence restrictions, maximum reads, retention and delegation choice. A contribution grant names an explicit domain/key allowlist, event count and confirmation permission. They have distinct IDs, approval, tokens and revocation. Neither implies the other. An operation that the authenticated grant's kind or permissions do not allow fails `capability_not_granted`. Contributor tokens can inspect only their current grant and their own submission status.

The stored grant is authoritative for restrictions, status, expiry, counters and revision. Token scope and copied claims are advisory. Every read, including L0 and a conditional request, rechecks it. A revision changes whenever authority changes. `expires_at` must be after issuance; read/event counts cannot exceed their maximum. Persistence cannot exceed grant expiry. A wildcard is allowed only as a read domain at L0, never for contribution or advertising; wildcard permission is expanded against the current core vocabulary and remains subject to grant review. Every grant has exactly one audience, the resource it was requested for, and its tokens are valid only there. A grant is continuous when it can serve more than one action: a read grant whose `max_reads` is above 1, or a contribution grant whose `max_events` is above 1.

## A6.3 Consent and tokens

Use authorisation code with PKCE S256 only; reject plain/downgrade. Require exact registered redirect-URI matching, with only the RFC 8252 loopback-port exception, which applies only to a client whose registered redirect URIs are all `http` loopback URIs: a redirect to one of them may name any port. A client that registers any other redirect URI gets exact matching for every one. Codes are single-use and bound to client, redirect, resource, session and verifier. Use session-bound state, unframeable consent pages and rotating refresh tokens with replay detection. Refresh tokens are issued only for a continuous grant (A6.2), rotate on every use and never outlive the grant. A second use of an authorisation code or of a spent refresh token revokes the grant it belongs to, and that request fails OAuth `invalid_grant`. Consent shows the named recipient, purpose category and plain-language explanation, read or contribution permission, selected keys/levels, expiry, limits, retention and trust evidence. Each choice is independently revocable. Purpose changes require new consent. Refusing advertising cannot revoke an unrelated non-advertising grant. Recipient-side consent flags cannot substitute for the provider's decision.

Access tokens follow RFC 9068, with the claims of [access-token-claims.json](../schemas/access-token-claims.json): a JWT of `typ` `at+jwt`, signed with ES256 under the authorisation server's token keys, which are never A5.4 signing keys. Example claim fragment:

```json
{
  "iss": "https://autonym.example",
  "aud": "https://autonym.example/v1",
  "iat": 1789948800,
  "exp": 1789952400
}
```

These timestamps represent 21 September 2026 00:00 to 01:00 UTC. Full tokens also carry `sub`, the pairwise handle (A3.2); `client_id`; `jti`; `cnf.jkt`, the thumbprint of the client's DPoP key; `autonym_grant_id`; and `autonym_purpose`, the grant's purpose category. A token for a grant requested with scopes carries their canonical `scope`, and one for a grant requested with an authorisation detail carries `authorization_details`. `aud` names exactly one resource, the grant's. Access tokens last at most one hour and never beyond grant expiry. Refresh tokens cannot extend a grant. Check issuer, audience, signature, expiry and server-side grant on every authorised action.

Every access token, for every client class and every resource, is bound to the client's DPoP key under [RFC 9449](https://www.rfc-editor.org/rfc/rfc9449): no Bearer token is issued or accepted. A token request without a valid proof, or a pushed authorisation request with an invalid one, fails RFC 9449 `invalid_dpop_proof`, and one whose proof carries a stale nonce fails `use_dpop_nonce`, with a fresh nonce. A proof is accepted only once, and only within 60 seconds of its `iat`. At a resource, a bound token is sent as `Authorization: DPoP` with a proof that binds the method, the URL and the access token, signed by the key whose RFC 7638 thumbprint is the token's `cnf.jkt`; a proof signed by any other key fails `dpop_invalid`. Never accept a bound token as Bearer. A request to a resource without a proof fails `dpop_required`; an invalid, stale or replayed proof fails `dpop_invalid`. An `assistant_unverified` grant lasts at most 30 days and cannot persist, delegate or confirm. No third party receives `autonym:confirm:safety` or arbitrary declared-write authority.

OAuth endpoints answer in their own error form. The authorisation endpoint and the pushed authorisation request endpoint (RFC 9126) return `invalid_request`, `invalid_client`, `unauthorized_client`, `access_denied`, `unsupported_response_type`, `invalid_scope`, `invalid_target`, `invalid_request_uri`, `invalid_authorization_details` or `server_error`. A request with `prompt=none` that needs the person returns `login_required`, `consent_required` or `interaction_required`. The token endpoint returns `invalid_request`, `invalid_client`, `invalid_grant`, `unauthorized_client`, `unsupported_grant_type`, `invalid_scope`, `invalid_target` or `server_error`. At a resource, a token whose signature, issuer, audience, type, lifetime or claims fail verification fails RFC 6750 `invalid_token` with status 401 and the A6.1 challenge. A verified token whose grant has ended, or whose client is suspended, fails that registered code instead (A5.2, A6.8).

## A6.4 Standing rules and delegation

Delegated is an optional provider capability. A standing rule is a person-approved exact match on client IDs or registry-independent approved classes, allowed purpose categories, domain/key/level limits, maximum duration, read count, declared-only/confidence and persistence. Unknown matching fields fail closed. The provider records the rule version, creates a real child grant and notifies the person. Version 1 standing rules cannot issue advertising or contribution grants automatically.

A read grant may delegate only if its stored `allow_delegation` is true. The child can only narrow purpose, domains, keys, ceilings, confidence, expiry, retention and read limits. The child consumes a reserved portion of its parent's remaining read budget; no child can multiply authority. Revoke/expire the parent and all descendants become unusable. Depth is at most one; children cannot delegate again.

At the token endpoint, [RFC 8693 token exchange](https://www.rfc-editor.org/rfc/rfc8693) requires `grant_type=urn:ietf:params:oauth:grant-type:token-exchange`, `subject_token`, `subject_token_type=urn:ietf:params:oauth:token-type:access_token`, `requested_token_type=urn:autonym:params:oauth:token-type:grant-offer`, `scope`, `resource`, `autonym_recipient`, `autonym_purpose_text`, `autonym_expires_in` and `autonym_max_reads`. Authenticate the delegate and recheck its current grant. The request's DPoP proof is signed by the key whose thumbprint is the `subject_token`'s `cnf.jkt`, or the request fails OAuth `invalid_grant`. `autonym_recipient` names a client registered with the grant offer grant type, which therefore authenticates with `private_key_jwt` (A6.1); naming any other client fails, as a missing parameter does. Missing or widening parameters fail; no default broadening is permitted.

The response is `{access_token:<opaque-offer>,issued_token_type:"urn:autonym:params:oauth:token-type:grant-offer",token_type:"N_A",expires_in:300}`. The opaque offer contains at least 256 random bits, is stored hashed, expires after five minutes or parent expiry, and is not a resource token. The recipient redeems it through the RFC 6749 extension grant `grant_type=urn:autonym:params:oauth:grant-type:grant-offer`, `grant_code` and exact `resource`, authenticated as the target client with `private_key_jwt` and presenting its own DPoP key. Holding the offer is never enough to redeem it. Bind offer to target, audience and proposed child restrictions. Check parent, budget and one-use state again atomically at redemption. Invalid, used or expired offers return OAuth `invalid_grant`. The resulting access token has `act.client_id` naming the delegate. This exchange contract is an Autonym choice, not a claim that RFC 8693 defines grant offers.

## A6.5 Revocation

`POST /oauth/revoke` follows RFC 7009 for refresh tokens, and revoking a refresh token revokes the grant it belongs to. A public client's refresh token is bound to its DPoP key (RFC 9449 section 5), so revoking one needs proof of possession, as using one does: a public client's revocation request carries a DPoP proof of that request, checked as at the token endpoint (A6.3), and without a valid one it fails RFC 9449 `invalid_dpop_proof`, or fails `use_dpop_nonce` with a fresh nonce when its nonce is stale, and revokes nothing. A refresh token bound to a key other than the proof's is not revoked, and the request is answered as RFC 7009 answers an invalid token, so the answer does not tell the holder of a stolen refresh token whether it is live. A confidential client's revocation request is authenticated with `private_key_jwt` (A6.1). An access token is not revoked on its own: the endpoint answers RFC 7009 `unsupported_token_type` for one, and it ends with its grant, because every authorised action checks the stored grant (A6.3). The owner's grant-revocation action atomically invalidates all associated authority and descendants, records the event and enqueues required purge instructions. Revocation takes effect on the next attempted action, including retries and cached/conditional reads. No background token-expiry job is the enforcement boundary.

Checks: CORE-01, CONSENT-01, OAUTH-01, FETCH-01, SCOPE-01 to SCOPE-09, DISC-01, ADS-01, DELEGATE-01, TRANSPORT-01, PURGE-01.

## A6.6 Client lifecycle credentials

Purge polling/acknowledgement continues after record grants end. A registered confidential recipient uses OAuth client credentials with private-key authentication and DPoP to request only `scope=autonym:lifecycle:purge` and resource `<origin>/v1`. This is a client lifecycle token, not a record grant: its JWT ([lifecycle-token-claims.json](../schemas/lifecycle-token-claims.json)) has `autonym_token_kind:lifecycle`, `sub` and `client_id`, both the client's ID as RFC 9068 asks of a client credentials token, `scope` `autonym:lifecycle:purge`, issuer/audience, `cnf.jkt`, `iat`, `exp` and `jti`, but no handle or grant ID. Maximum lifetime is five minutes. It is valid only on the two purge routes and can access only that client's instructions. It cannot satisfy a record-grant check, discover records or create grants. The lifecycle scope is deliberately outside the record-grant scope parser and never appears in a consent grant. Public clients without a registered private key cannot use polling credentials; the provider uses registered callback delivery or the owner's visible manual follow-up, recording unavailable acknowledgement assurance.

## A6.7 Consent and advertising

The deployment requirements in [A16](a16-privacy-mapping.md) also apply. Advertising requires the local-law and opt-out controls in PRIVACY-05 as well as ADS-01 and ADS-02.

Read and contribution permissions require separate grants, approval and revocation. One named recipient, one purpose category and a plain-language purpose explanation are required. A recipient's consent manager may initiate a flow, but only the provider's stored active grant authorises access. Recommendation/personalisation permission MUST NOT be repurposed for advertising. Declining advertising MUST leave independent non-advertising permissions intact.

Advertising is optional and off by default. Version 1 permits only explicitly person-confirmed `viewing.genre_affinity`, `reading.genres` and `music.genres`, validated against their closed core enums. All other keys are ineligible. No inferred preferences, free text, activity history, extensions, wildcard domains, sensitive or safety information, identifiers, location, financial, employment or proxy categories enter this lane. A declared value derived from sensitive source material is not made eligible by relabelling it. Providers MUST require the person to choose the offered ordinary preference directly and prohibit sensitive targeting/inference by recipient policy.

An advertising read grant requires independent first-party consent, a self-directed adult-owned record, an active eligible named recipient, explicit key selection, declared-only mode, maximum L1, exactly one permitted read, expiry within 24 hours, no persistence, delegation or onward-sharing right. If adult/self-directed eligibility cannot be established, deny the feature; do not collect extra identity documents simply to enable advertising. An advertising read for which the recipient's eligibility cannot be established fails `advertising_ineligible`; the code never reveals that the person's or the record's eligibility has changed. Child/guardian-managed records are excluded. Recipient suspension stops reads immediately. Retain context only for the current interaction and never past the signed five-minute maximum; a new interaction needs fresh permission.

The consent view shows selected context, recipient, advertising purpose, expiry and no-retention terms. Refusal is an ordinary choice. No resale, advertising identifier, cross-recipient correlation, provider monetisation of contents or undisclosed ad-exchange disclosure is implied. Contextual ads that read no record need no Autonym read grant. Off-platform misuse cannot be prevented once data is disclosed; recipient terms and independent assurance remain necessary. These rules are not a legal-compliance certificate.

Every advertising read has the same signed envelope and receipt as other reads. Withdrawal and purge state are visible to the person. Purge acknowledgement is an assertion, not proof that every copy has gone.

Checks: CONSENT-01, ADS-01, ADS-02, SCOPE-10, PRIVACY-05.

## A6.8 Client standing and safety purposes

A suspended client takes no recipient action, even with an otherwise active grant, except at the A6.6 purge routes: it is not authorised, obtains and refreshes no token, and its request to a resource fails `client_suspended`. The child grants of a suspended client's delegations (A6.4) are unusable while it is suspended. A suspension revokes nothing, so a resumed client's unexpired grants work again; a deregistered client's grants are revoked. The person sees the recipient's registered identity and available evidence during consent.

A normal v1 `safety` or `medical` purpose still requires a current recipient grant, the same compiler and a receipt. There is no anonymous emergency override, special URL that bypasses consent, or promise of emergency-service availability.

Checks: CORE-01, ADS-01, CLAIM-01.


---

# A7. Agent surface

**Status:** normative. Document version `1.0-draft-1`.

This chapter states the operations and confirmation rules an agent-facing binding provides. The [MCP binding](../bindings/B3-mcp.md) (B3) carries them over the Model Context Protocol; the REST binding carries the same objects (A8, B4).

## A7.1 Operations

Each operation below is exposed under the same name by the agent binding.

| Operation           | Authority                                                                                                  | Accounting                                      |
| ------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `get_grant`         | The authenticated current grant only                                                                       | No read                                         |
| `list_domains`      | Read grant                                                                                                 | No read; eligible granted keys only             |
| `get_context`       | Read grant                                                                                                 | One atomic counted read                         |
| `propose_entry`     | Separate contribution grant                                                                                | One accepted unique event                       |
| `confirm_entry`     | Contribution grant with ordinary confirmation permission; sensitive acceptance only in the first-party app | Exact-statement review                          |
| `withdraw_proposal` | The contributor's own proposal                                                                             | No read; cannot undo an independent declaration |

The `get_context` operation returns the A5 signed disclosure. It must not produce an unsigned alternative value. The provider rechecks the stored grant for every operation call.

## A7.2 Confirmation

Version 1 `confirm_entry` always returns `review_required` with an HTTPS first-party review URL. It never accepts a contributor assertion as confirmation. The URL locates the authenticated person's review screen; it is not a bearer credential and reveals no proposal value before login. The server creates a one-use review session of at most five minutes bound to the owner session, proposal ID/version, source client and exact JCS statement `{domain,key,value_type,value,context_kind,temporal}` hash. The app displays that exact statement and rechecks the binding before committing confirmation. Any proposal change invalidates the session. Third-party callers receive only their own proposal status afterward. Sensitive acceptance is always first-party.

Multi Round-Trip Requests and assistant-attested confirmation are reserved for a separately specified future extension. A contributor's confirmation permission in v1 only permits requesting the first-party review link; it never permits writing a declaration directly.

## A7.3 Briefing

The briefing (the `autonym_briefing` prompt in B3) requests `agent` and `communication` at L1 through one compiler transaction. Both domains must be granted; no fallback ambient read exists. It counts once, returns a text message containing the signed disclosure JSON, and labels any human-readable summary as derived from that object. A summary cannot extend validity or add entries. The recipient must apply normal instruction/safety boundaries to contributed text; context is data, not authority to override system or tool policy.

Checks: TRANSPORT-01, CORE-01, SIGN-01, LOG-01, CONTRIB-01.


---

# A8. Recipient API

**Status:** normative. Document version `1.0-draft-1`.

This chapter states the recipient API requirements that do not depend on the binding. The [REST binding](../bindings/B4-rest.md) (B4) gives the HTTP routes, request validation, idempotency, conditional reads, errors and rate limits; the [MCP binding](../bindings/B3-mcp.md) (B3) carries the same operations to agents.

Public discovery is unauthenticated; every recipient action is authenticated and authorised.

Unknown or foreign proposal IDs return the same `proposal_not_found`. Contribution retries are identified by authenticated event ID as specified in A14. Always recheck authority before replaying a stored response; a retry after revocation cannot retrieve protected results.

Body-size, rate and authentication failures do not consume read counts. Only committed fresh disclosures consume reads.

Owner management must support reviewing entries/proposals/grants/history, temporal activation, correction, revocation, export/import and deletion with re-authentication for sensitive changes. The earlier `/v1/me/*` list was illustrative. Private UI routes are outside this recipient interoperability contract; it does not grant recipients management authority.

Checks: TRANSPORT-01, CORE-01, LOG-01, CONTRIB-02.


---

# A9. Read receipts and the log

**Status:** normative. Document version `1.0-draft-1`.

Every fresh disclosure commits a [receipt](../schemas/receipt.json) before returning. Its read ID matches the signed envelope. It records the provider, grant, client, purpose, trusted time, surface, canonical request, internal entry/version/level references and response hash. `provider` is the provider's HTTPS issuer URL as discovery publishes it (A3.3), the same value as the signed disclosure's `provider`; it is part of the signed bytes, and a verifier binds the receipt to that provider's key set through it (A5.4). Internal references are owner-only; recipient-facing evidence uses the signed disclosure and its pairwise references.

The canonical request, the receipt's `request`, is the validated [context request](../schemas/context-request.json) with its A5.2 defaults written out. `max_level` (L3 when omitted), `declared_only` (false when omitted) and `min_confidence` (0 when omitted) are always present. `domains`, and `keys` when the request has them, are in ascending order without repeats. `keys` and `since` are present only when the request has them, and `since` uses the canonical instant spelling (A5.4). Requests that differ only in list order, repeated names or omitted defaults therefore have the same canonical request, and its JCS form is what the receipt's `hash` and signature cover. Writing the canonical form is the provider's duty; a verifier checks the signature over the request the receipt carries and does not reject it for its order or spelling.

`response_hash` is `sha256:` plus lower-case hexadecimal SHA-256 of the exact JCS UTF-8 envelope without `proof`, the same bytes signed in A5. The receipt's `hash` covers its JCS form excluding `hash` and `proof`, including `prev_hash`. The first event uses null previous hash. Sign the complete receipt excluding `proof` using the A5.4 method and protected `typ:autonym-receipt+jws`; its signed time is `at`.

The owner log is append-only and hash-chained per record partition. Non-read events use `{event_id,at,kind,actor_client_id,subject_id,details,prev_hash,hash}`. `kind` is one of `grant_created`, `grant_revoked`, `grant_expired`, `rule_applied`, `delegation_redeemed`, `proposal_decided`, `overlay_enabled`, `overlay_disabled`, `overlay_selected`, `read_not_modified`, `purge_issued`, `purge_acknowledged`, `operator_action` or `migration_imported`. `details` contains only decision codes and relevant opaque IDs, never entry values, utterances or tokens: `details.decision` is one of the codes of [log-event.json](../schemas/log-event.json) or null, `details.ids` lists opaque IDs and `details.response_hash` is an A9 hash or null. These events use the same hash rule and are included with receipts in export.

The kinds that grant issuance, revocation, expiry, conditional reads and operators write have this content:

- `grant_created`: `subject_id` is the new grant's ID, `actor_client_id` the client it is issued to and `details.decision` `approved`. `details.ids` names the grant and, where the provider keeps a record of the person's consent review, that review.
- `grant_revoked`: `subject_id` and `details.ids` name the grant. When the person revokes it, `actor_client_id` is null and the decision is `completed`. When its client revokes it through the revocation endpoint, with the proof of possession A6.5 asks of a public client, the actor is that client and the decision is `completed`. When the provider revokes it because its client used an authorisation code or a spent refresh token a second time (A6.3), the actor is that client and the decision is `failed`. When the operator deregisters the client (A6.8), the actor is null, the decision is `disabled` and an `operator_action` is appended in the same transaction.
- `grant_expired`: `subject_id` and `details.ids` name the grant, and the actor and the decision are null. The event records an expiry; every action checks expiry itself (A6.5).
- `read_not_modified`: `subject_id` names the grant, `actor_client_id` the reading client and the decision is `unchanged`. `details.ids` names the earlier read, and `details.response_hash` is that read's response hash.
- `operator_action`: `subject_id` is the record partition's ID, the actor is null, and `details.ids` says what the action concerned. A verification of the partition's log names the event IDs it reports, with the decision `completed` when the log verified, `failed` when it found a divergence and null when verification could not run. An action on a client names the client's grants in the partition that were active when the action began, with the decision `disabled` for a suspension or a deregistration, `enabled` for a resumption and `completed` for a change of class; the `grant_revoked` events a deregistration appends in the same transaction tell it apart from a suspension. One event names at most 32 IDs ([log-event.json](../schemas/log-event.json)), so an action on a client with more grants in the partition appends further `operator_action` events with the same decision, in the same transaction, until every grant is named.

Each other kind's content is defined with the operation that writes it, within the rule above.

Grant/counter updates and log append occur in the disclosure transaction. Failure cannot leave a successful unlogged read. A `304` appends an event referencing its previous read ID and response hash, without a fresh disclosure or counter increment.

Owners can inspect reads, consent changes, temporal activation, withdrawals and purge state. Operational logs and telemetry have a separate allowlist and never contain context values, approved renderings, source evidence, uploaded content, credentials or tokens. A cryptographic chain reveals tampering relative to a trusted checkpoint; a host controlling all keys and checkpoints is not magically unable to rewrite history. Owners should be able to export signed checkpoints.

ISO/IEC 27560 is a useful consent-record reference, but this draft does not claim certified mapping to its unavailable full text. The explicit fields here are the wire contract.

Receipts MUST stay verifiable after the signing key changes. A key ID is the RFC 7638 thumbprint of its public key (A5.4), so one key ID cannot name two keys, and a provider MUST NOT reuse a key ID. A retired signing key MUST NOT sign anything at or after its retirement. Its public key MUST stay in the provider's key set, with `exp` giving the time of its retirement (A5.4), for as long as any receipt or log event it signed is retained, and a published `exp` MUST NOT be removed or changed. A verifier rejects an object whose signed time is at or after its key's retirement (A5.4, KEY-01). Retirement is not a response to key compromise: whoever holds a retired private key can still produce an object dated before its retirement. Log retention and compaction MUST keep everything an old receipt needs to verify independently: the receipt, the hash-chain events it links to, any checkpoint it is anchored to and the public key that signed it. A receipt signed before a key rotation therefore verifies afterwards from the provider's published keys and the owner's export alone (LOG-02).

Checks: LOG-01, LOG-02, KEY-01, ADS-02, SIGN-01, PORT-01.


---

# A10. Revocation and purge

**Status:** normative. Document version `1.0-draft-1`.

Ending a grant stops future reads immediately. It does not remotely erase a recipient's existing copy. A provider issues a signed purge instruction for every ended grant with persistence rights; notices for transient grants may also be sent. The person can see delivery and acknowledgement state.

The payload follows [purge-instruction.json](../schemas/purge-instruction.json), signed as compact JWT with ES256, protected `typ:autonym-purge+jwt` and, as `kid`, the A5.4 key ID of a key in the provider's trusted key set. Its signed time is `iat`, so a recipient rejects a token whose `iat` is at or after that key's `exp` (A5.4). It binds provider issuer, pairwise subject, recipient audience, instruction ID, issue/expiry timestamps, grant ID and deadline. The reason is identical for revocation and expiry:

```json
{ "reason": "grant_ended" }
```

`scope:all` means copies obtained under that grant, including derived recipient copies. No explanation of why it ended is disclosed. Default acknowledgement deadline is seven days after issue; JWT validity is 30 days. Fetching an outstanding expired notice issues a fresh signed delivery with the same instruction ID/deadline, not a new erasure obligation.

Delivery uses registered HTTPS `autonym_purge_uri` through the SSRF-safe client. Retry after 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours and then daily until acknowledgement or 30 days. Each attempt revalidates destination ownership and DNS/address safety. A recipient may poll outstanding notices using authenticated client credentials bound to its registration; this lifecycle channel does not require a still-active read grant and confers no record-read authority. Do not drop a notice merely because the triggering grant expired.

[purge-ack.json](../schemas/purge-ack.json) binds instruction ID, time and `purged`, `not_held` or `legal_hold`, plus a bounded explanation. Where the recipient has a registered key, it signs the acknowledgement by the A5.4 method: a detached JWS over the UTF-8 RFC 8785 canonical JSON of the complete acknowledgement without `proof`, with protected `alg:ES256`, `typ:autonym-purge-ack+jws` and the registered key's A5.4 key ID as `kid`, carried in `proof`. Its signed time is `at`. The provider verifies it as A5.4 describes, against that recipient's registered keys only. Without a registered key, `proof` is null and the provider records the authenticated but unsigned assurance explicitly. Validate client/instruction binding. An acknowledgement is the recipient's attestation, signed where it holds a registered key, of the outcome it reports: `purged`, `not_held` or `legal_hold`. It proves only that the recipient made that attestation; even `purged` does not prove that every copy has gone. A provider MUST NOT present an acknowledgement, to the person or anywhere else, as proof of erasure or as evidence that no copy remains (PURGE-01). `legal_hold` records an exception claim, not completed purge.

Missing acknowledgement past the deadline remains visible to the person. The default status-retention period is 12 months, subject to a shorter period required by applicable law or necessity, or the owner's shorter lawful retention choice. Any longer retention needs the specific lawful justification and safeguards in A16.5. Do not expose it to other recipients. No registry standing or certification is inferred in v1.

Checks: PURGE-01, ADS-02, SIGN-01, KEY-01, CORE-01.


---

# A11. Portability

**Status:** normative. Document version `1.0-draft-1`.

## A11.1 Export and import

[export.json](../schemas/export.json) defines `autonym-export/1.0`: export time, origin, entries and included versions, non-content deletion tombstones, proposal events/acknowledgements, historical grants, read receipts, non-read log events, public verification keys, inactive policy history, unsupported-category report and proof. The owner chooses current versions or complete retained history. The export manifest says which was chosen. Owner-only wrappers bind every historical grant, receipt, log event, proposal and policy to its partition ID; validate those IDs against the partition list. Preserve canonical IDs, temporal intervals, overlay targets, semantic kinds, provenance, evidence references and original origin. Evidence references may be unavailable at the new host; report that explicitly, never treat missing evidence as verified.

Sign the JCS export excluding `proof` by the A5.4 method with the originating provider's ES256 key and protected `typ:autonym-export+jws`; its signed time is `exported_at`. Exported public keys preserve verifiability of historical artefacts, keeping any `exp` (A5.4); they do not become trusted active signing keys at the destination. Once the export verifies, its `public_keys` and `origin_host` are the trusted key set and issuer for the receipts it carries, and a carried receipt naming another provider is verified against that provider's own key set or reported as unverified history (A5.4). The owner's authenticated export operation establishes the source, with explicit source trust on import. Do not follow arbitrary key URLs from the file. Never export private keys, access/refresh tokens, passkeys, client secrets or executable credentials.

The importer validates size, schema, signatures, vocabulary, IDs, versions, temporal constraints, dependency cycles, relationships and each partition's A4.1 entry limit before changing the destination. Maximum decoded v1 import is 64 MiB and 100,000 entries/events of each supported kind. Reject duplicate IDs/versions with differing content. Identical retransmission is idempotent. Imports use a staged preview listing unsupported categories and conflicts. The person chooses whether to omit unsupported material or cancel; no silent data loss is permitted. Committing entries, selection and provenance is atomic for the accepted import.

Imported grants, rules, delegations and consent events are immutable history, never executable authority. The destination creates fresh keys, handles and client-bound grants after new consent. An old token MUST fail at the new provider. Unverified credentials remain archived and non-disclosable. A legacy value with no core key mapping is reported as unsupported, not coerced into a broad text field.

## A11.2 Optional encrypted export

The unencrypted signed JSON contract is required for Portable; passphrase encryption is an optional, fully specified format. Use compact [JWE](https://www.rfc-editor.org/rfc/rfc7516) with `alg:dir`, `enc:A256GCM`, `typ:autonym-export+jwe` and `cty:application/autonym-export+json`. Plaintext is UTF-8 of the signed export. Use a new random 96-bit GCM IV and 128-bit authentication tag as required by JWE.

Derive a 32-byte key with [Argon2id RFC 9106](https://www.rfc-editor.org/rfc/rfc9106#section-4), version 19, memory 65,536 KiB, three iterations, four lanes and a fresh random 16-byte salt. The UTF-8 passphrase is used exactly as entered, without normalisation or truncation. The protected header contains `crit:["autonym_kdf"]` and `autonym_kdf:{name:"argon2id",v:19,m:65536,t:3,p:4,salt:<base64url-unpadded>}`. This authenticated critical extension is the sole v1 KDF parameter set. Argon2id is not a JOSE `alg`.

Reject unsupported/missing KDF fields, salt size, algorithms, duplicate JSON members and excess encrypted size before allocating Argon2 memory. Limit concurrent derivations. Verify GCM before parsing or exposing plaintext, then verify export signatures and semantics. Authentication failure returns a generic invalid-export result, without distinguishing wrong passphrase from tampering. Use maintained Argon2/JWE libraries; do not implement these primitives in application code.

## A11.3 Honest portability

A provider claiming Portable supports both export and import for its stated categories and demonstrates round-trip preservation, conflict reporting and no authority transfer. A recipient claiming Reciprocal supports receiving and returning the person's stated data categories; it need not transfer proprietary model weights or ranking algorithms. Raw history and confirmed preferences are separate selections. Named media services are examples, not integration claims.

Checks: PORT-01, ENCRYPT-01, SIGN-01, KEY-01, LOG-02, CLAIM-01, TEMP-01 to TEMP-03.


---

# A14. Contributions

**Status:** normative. Document version `1.0-draft-1`.

## A14.1 Authority and transport

Version 1 uses authenticated HTTPS push: one event per `POST /v1/proposals`, or the identical `propose_entry` MCP tool. Maximum event body is 64 KiB. Batches, background polling, streaming subscriptions and vendor-specific export formats are outside v1. A connector repeatedly pushes within its bounded, separately revocable contribution grant; continuity does not imply perpetual permission.

Grant constraints are an exact domain/key allowlist, purpose, expiry, maximum accepted unique events and optional ordinary confirmation permission. A read grant cannot contribute; a contribution grant cannot read context, enumerate records, list other recipients or discover migration destinations. The current-grant endpoint is restricted to the authenticated grant and exposes no linked grants.

## A14.2 Events and deduplication

[contribution-event.json](../schemas/contribution-event.json) defines a discriminated `create`, `correct` or `withdraw` event. An event whose `value_type` or `value` does not match the key definition (A4.1) fails `value_rejected`. `event_id` is a contributor-scoped opaque ASCII identifier of 1 to 128 letters, digits, underscores or hyphens. Record the authenticated client as source; reject a body-supplied source client or ingestion time. The provider sets ingestion time from its trusted Clock. Occurrence time can describe past activity but must not exceed ingestion by more than five minutes; it does not backdate authority.

Uniqueness is `(record partition, authenticated client, event_id)`, independent of a refreshed grant. Hash the canonical submitted payload with SHA-256 for comparison. An identical authorised retry returns the original acknowledgement; a differing payload under the same ID returns `idempotency_conflict`. A new correction uses a new event ID and names its predecessor. Accept and acknowledge transactionally, after rechecking current grant activity and limits. Identical retries do not consume another event allowance, but still require active authority and rate limits.

Retain deduplication identities and payload digests for the stream lifetime plus 30 days. Revocation ends that stream; reopening requires a fresh stream namespace communicated in the new contribution grant. A stream namespace is a UUIDv4 and is included in every event. The provider never accepts the old namespace under a new stream grant. Retired namespaces retain a non-content tombstone so old events cannot reappear after deduplication expiry. Digests and metadata remain protected, not public diagnostics.

## A14.3 Corrections, withdrawal and provenance

Corrections/withdrawals may target only a previous event from the same client, stream and record. The full predecessor chain is bounded to 100 and cannot branch silently: a correction must reference the current head or fail `proposal_decided`. Source withdrawal stops disclosure of the contributed observation and invalidates dependent derivations. It cannot delete the person's independently confirmed declaration; instead flag the changed evidence for the person's review.

Event category distinguishes `user_supplied`, `activity`, `observation` and `inference`. Preserve it even after acceptance. Approval of a batch, client or general stream is not confirmation of a statement. Becoming `declared` requires explicit confirmation of the exact value and protected statement hash. The first-party app handles all sensitive or safety-critical proposals; all v1 confirmation occurs in the first-party app; third parties can request review only. `inferable:false`, safety and special-category prohibitions cannot be overridden by enabling a domain. For a special-category or safety-critical key, only a `user_supplied` event is accepted, and it remains a protected proposal until the person confirms it in the first-party app (A4.2); any other event for such a key fails `safety_write_forbidden` if the key is safety-critical and `inference_forbidden` otherwise. An `inference` event for any other key with `inferable:false` fails `inference_forbidden`.

Rejected suggestions must not repeatedly resurface: suppress identical `(client,domain,key,canonical value digest)` proposals for 90 days unless the person explicitly reopens the suggestion or supplies a new declaration. Evidence references are opaque pointers, not permission for the server to fetch arbitrary URLs. External evidence retrieval needs separate safe-fetch and owner consent rules.

## A14.4 Separation of history and preference

Contributing viewing activity does not imply permission to read a person's other preferences. Another service may request reviewed preferences, raw history or both, with separate key selection. Derivations obey A4's recursive input-rights rule. An independently confirmed preference can be shared without history, while original source evidence remains protected.

Continuous connectors are reserved for 2.0; see [the connectors reservation](reserved/a14-connectors.md).

## A14.5 Contribution and reciprocal portability

A contribution grant is bounded permission to submit proposals, not to read or overwrite the record. Version 1 HTTPS push has a strict event schema, authenticated source identity, stream namespace, idempotent event IDs, finite limits, correction/withdrawal rules and replay tombstones. A14 defines the full contract. No continuous subscription survives revocation.

Distinguish user-supplied preferences, activity, observations and inference. Review does not automatically create a declaration: the person confirms the exact statement, while provenance and protected evidence remain intact. A contributor cannot alter an independent declaration or learn who later reads its contribution.

A person can share reviewed preferences, raw history or both. Preferences do not automatically expose history. Derivations require permission for every actual input field and level; a separately confirmed declaration may be shared independently.

Portability requires bidirectional transfer for the categories claimed, preservation of meaning and temporal/provenance data, validation, unsupported-data reporting and tests. Exports do not transfer executable tokens, grants or private keys. Provider migration requires fresh provider/audience-valid consent. The old contributor does not learn the destination by default.

Checks: CONTRIB-01 to CONTRIB-03, INFER-01, CONSENT-01, TEMP-03, CORE-01.


---

# A15. Security requirements

**Status:** normative. Document version `1.0-draft-1`.

The protocol minimises disclosure; it does not make a trusted host harmless or guarantee deletion by a recipient. Treat record contents and contributor text as untrusted data. They cannot override recipient system instructions, tool permissions or safety boundaries.

## A15.1 Authority and isolation

Every recipient action requires current server-side authority. Enforce issuer, exact audience, client binding, expiry, the DPoP proof, grant revision, domain/key/level constraints, purpose, temporal validity and limits. Recheck inside the transaction. Deny missing, unknown or incompatible state. The privacy boundary covers errors, discovery, provenance, identifiers, metrics and conditional requests as well as entry values.

Use client-bound handles and entry aliases. A contributor cannot enumerate other recipients or learn where the person migrated. L0 categories are closed and reveal no direct value; combinations may still identify a person or imply sensitive information. Providers SHOULD refuse a wildcard L0 grant to a client already holding L2 or higher in any domain, and explain its actual grant selection to the person.

## A15.2 Signed objects

Required signatures cover successful disclosure envelopes, owner-verifiable read receipts, export envelopes, purge instructions and purge acknowledgements where the recipient has a registered key. Reserved future host-binding formats must define their own signed object before use. TLS is still mandatory.

HTTP `204`/`304`, operational health/readiness, errors, lists and discovery are not signed disclosure envelopes. MCP wraps the same signed object rather than an unsigned equivalent. This boundary replaces the earlier ambiguous phrase “every response signed”. Signature verification includes configured trust, protected type/algorithm, complete signed bindings, strict canonicalisation and deadline checks; see A5.

## A15.3 Implementation controls

- Use maintained cryptographic libraries and secure platform primitives. Private keys and encrypted record contents must be isolated from operational support access. Administrative actions are logged to affected owner history without exposing values.
- Rate-limit by client, grant and unauthenticated origin. Bound nested JSON, body size, dependency depth, exports, cryptographic work and retries. Unavailable key storage or grant state fails closed with `not_ready`.
- Fetch client-supplied URLs only through SSRF-safe retrieval, checking resolved addresses and redirects and blocking private/link-local destinations unless an explicitly isolated local mode is configured. No credential forwarding across origins.
- Keep values, renderings, utterances, evidence, uploads, credentials and tokens out of operational logs, traces, metrics, emails and job payloads. Owner history is separately protected.
- Protect first-party changes with authenticated sessions, CSRF controls, fresh re-authentication for sensitive actions and visible audit history. A first-party request without a current session fails `session_required`, one whose CSRF proof does not verify fails `csrf_invalid`, and a sensitive action without recent re-authentication fails `reauthentication_required`. A sign-in that does not succeed fails `sign_in_failed` whatever the reason, and a sign-up while the provider admits no new accounts fails `signup_unavailable`; neither depends on whether an address has an account. Never expose a route that decrypts arbitrary records for operators.

Version 1 excludes guardian-managed advertising and reserves general guardian/duress functionality. These need independent abuse, safeguarding and control-transfer designs before release. A plausible-looking “duress record” is not a security guarantee and must not be claimed from this draft.

Checks: all security-relevant checks in the [manifest](../conformance/profiles.json), including FETCH-01 and WILDCARD-01. Cryptographic interoperability, concurrency, storage and live authorisation remain runtime release gates.


---

# A16. Privacy and legal mapping

**Status:** normative. Document version `1.0-draft-1`.

## A16.1 What the protocol supports

This subsection is informative. Protocol mechanisms can support privacy obligations; they do not establish lawful processing, legal compliance or certification. Roles, purposes, jurisdiction, safeguards and actual operation matter. A16.2 to A16.8 define deployment requirements for providers and recipients claiming conformance. They add no wire fields and do not turn conformance into legal approval.

| Mechanism                                | What it can support                                       | What it does not establish                                                                            |
| ---------------------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Consent screen and grant                 | Recording a specific decision and facilitating withdrawal | Valid freely given, informed consent or the correct lawful basis in every situation                   |
| Revocation                               | Stopping future provider-mediated access                  | Erasure of existing recipient copies or withdrawal of every other legal basis                         |
| Read log                                 | Evidence useful for an access response                    | All information required by an access right                                                           |
| Correction and versioning                | Rectifying active data and retaining necessary history    | Rectification merely because an old and new version both exist                                        |
| Purge notice and acknowledgement         | Requesting deletion and recording a recipient's assertion | Completed erasure, removal of backups, or absence of an applicable exception                          |
| Export/import                            | Transfer of the specified user-data categories            | That every item falls within a statutory portability right or may be disclosed despite others' rights |
| Sensitive-key and inference restrictions | Data minimisation and additional technical controls       | A lawful condition for processing special-category data                                               |
| Pairwise identifiers and short validity  | Privacy by design and reduced linkability                 | Anonymity, impossibility of inference or prevention of off-platform misuse                            |

The EU GDPR provisions most directly relevant include Articles 7, 9, 15, 16, 17, 20 and 25. Read their conditions and exceptions in the [official regulation](https://eur-lex.europa.eu/eli/reg/2016/679/oj/eng). UK applicability must be evaluated separately using current legislation and [ICO consent guidance](https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/lawful-basis/consent/); it is not assumed identical to EU rules.

The [EU Data Governance Act](https://eur-lex.europa.eu/eli/reg/2022/868/oj/eng) has its own scope, notification requirements and conditions, including Articles 11 and 12. A technical registry badge cannot confer data-intermediation status. Advertising eligibility rules in A6.7 are protocol restrictions, not a declaration that an advertising use is lawful.

The [international privacy guide](https://autonym.dev/international-privacy) gives dated, informative jurisdiction notes and primary sources. It is not a substitute for the deployment assessment below and is not incorporated as normative law.

## A16.2 Applicability, roles and lawful processing

Before collecting, storing, accepting a contribution, deriving or disclosing personal data, each deploying provider and recipient MUST document the applicable jurisdictions, its actual legal roles, purposes, data categories and lawful conditions for those operations. The assessment MUST consider the people served, establishment, targeting, sector and actual processing, rather than relying solely on nationality, IP address or hosting location. Where a required condition is absent or unresolved, the affected operation MUST remain disabled. Independently lawful operations need not be disabled.

Protocol actors do not determine legal roles. The assessment MUST distinguish independent, joint and processor relationships where applicable, including account administration, security logs, hosting and recipient use. Encryption and a person's household use do not automatically exempt a commercial provider. Required notices, agreements and evidence of the selected lawful conditions MUST be in place before the relevant processing.

A grant is a technical permission, not itself a lawful basis. Where consent is relied on, the implementation MUST retain proportionate evidence of the actual notice and version, language, purposes, parties, categories, affirmative action, time and withdrawal route. It MUST satisfy any applicable explicit, separate, written or representative-consent formality and permit refusal and withdrawal without prohibited detriment. Withdrawal MUST be as easy as giving consent where the law requires it. Grant acceptance MUST NOT waive statutory rights or authorise a purpose that the protocol prohibits.

Required indirect-collection notices MUST be handled at the legally required time. Data in a pending or rejected contribution has already been collected; a confirmation queue is not an exemption. Compliance records MUST remain protected and MUST NOT expand discovery or disclose additional personal data to recipients.

Check: PRIVACY-01.

## A16.3 Sensitive data, necessity and further use

The provider and recipient MUST assess legal sensitivity for the actual data, source, inference and combination in each applicable jurisdiction. Vocabulary flags and disclosure levels are technical controls, not an exhaustive legal classification. A low-resolution rendering can remain personal or sensitive data. Implementations MUST NOT relabel data, lower its disclosure level or describe it as a preference to evade a legal restriction.

Collection, storage and disclosure MUST be limited to the purpose and necessity permitted by applicable law. Operations governed by a grant MUST also remain within that grant’s purpose and authority. Where processing requires a special condition, that condition MUST be established before the affected data is accepted or used. Consent MUST NOT be treated as overriding a statutory prohibition or strict necessity requirement. Unsupported categories and uses MUST remain disabled for the affected deployment.

Model training, advertising, enrichment and other further uses MUST NOT be inferred from permission to read, contribute or host a record. Any further use MUST satisfy its own applicable legal conditions and the protocol's purpose and authority limits; fresh consent cannot override a protocol prohibition.

Check: PRIVACY-02.

## A16.4 International flows

Before an international flow begins, the deploying parties MUST document its source, destination, parties, purposes and data categories, including hosting, backups, remote access, subprocessors and onward disclosure. They MUST establish any required transfer mechanism, assessment, contract, notice, separate permission, filing, representation or localisation arrangement for that flow. A grant, encrypted transport, chosen hosting region or an agreement designed for another jurisdiction is not sufficient evidence by itself.

The assessment MUST record which flows an instrument covers, applicable conditions and a review point. A material change of destination, recipient, access arrangement or legal protection MUST trigger reassessment before the changed flow proceeds. A flow whose required safeguards are no longer satisfied MUST be suspended without silently selecting a different destination.

Check: PRIVACY-03.

## A16.5 Rights, retention and erasure

Each deploying party MUST provide an accessible route for applicable access, correction, deletion, restriction, objection and portability requests, authorised representatives, complaints and appeals. Identity verification MUST be proportionate. It MUST NOT require a new account where applicable law prohibits doing so. The party MUST track the applicable deadline, any permitted extension, outcome, reasons and challenge route. A protocol export or read log alone MUST NOT be represented as a complete statutory response.

Correction MUST stop superseded information from being presented as current and communicate corrections or restrictions to recipients where required. Keeping both versions is not sufficient. Disputed or restricted data MUST be prevented from entering uses that the restriction prohibits.

Retention rules MUST cover entries, history, contributions, receipts, logs, caches, exports and backups. Grant expiry and revocation MUST NOT be treated as deletion. Append-only audit design MUST NOT imply indefinite personal-data retention. Implementations MUST use bounded history and proportionate evidence, with a tested deletion or effective cryptographic-erasure process where appropriate. Restoring a backup MUST reapply deletions and restrictions before restored data becomes available for processing.

Revocation, consent withdrawal, restriction and erasure MUST be handled as distinct actions with their actual effects explained. A10's default seven-day acknowledgement period is a protocol target, not a universal legal deadline. A recipient's purge acknowledgement MUST be described as its assertion, not proof that every copy has disappeared. Missing acknowledgements and incomplete deletion MUST have a tracked follow-up process.

Any retained data under a legal exception or hold MUST have a specific documented ground, restricted access and use, a review or end condition, and any legally required explanation and challenge route. Such retention MUST NOT be reported as erasure or become an implicit new grant.

Check: PRIVACY-04.

## A16.6 Advertising choices and children

A6.7's advertising restrictions are an upper bound, not legal authorisation. Before enabling that optional capability, the deploying parties MUST assess whether the arrangement constitutes regulated sale, sharing, targeted advertising or another restricted use, including non-monetary consideration. The capability MUST remain disabled wherever a required condition cannot be met.

Implementations MUST honour applicable objections, opt-outs and recognised preference signals, including signals received after a grant was issued, before the next affected disclosure or use. A grant MUST NOT silently override a valid opt-out. The absence of a signal is not consent. Any legally permitted later opt-in MUST be handled through the required informed process. Version 1 defines no universal transport for these signals; an implementation without a reliable way to receive and enforce applicable choices MUST keep the affected advertising use disabled. Device access, cookies and direct marketing require their own assessment.

Version 1's reserved guardian mechanisms do not establish a child-consent or capacity framework. A deployment directed to children, or otherwise within applicable child-protection duties, MUST establish the required age, capacity, representative authority and child-specific safeguards through a separately specified and verified process before enabling affected processing. Until that process exists, the deployment MUST restrict its supported audience and affected functions accordingly, using proportionate measures. It MUST NOT claim that a generic checkbox establishes parental authority. Child and guardian advertising remains excluded by A6.7.

Check: PRIVACY-05.

## A16.7 Accountability and regulated services

Each deploying party MUST establish the impact assessments, security measures, contracts, records, registrations, permits, licences, prior authorisations, officers and representatives required for its actual activity. Where an approval is required before processing or a transfer, the party MUST establish that it has been granted and covers the intended activity, rather than treating an application or personal consent as approval. It MUST track conditions, expiry and renewal, and stop the affected operation when required permission is absent or expires. It MUST maintain and exercise an incident process with jurisdiction-specific triggers, reporting routes and deadlines. Unauthorised disclosures, including misuse by an authorised recipient, MUST be assessed; incident handling MUST NOT assume that every law uses the same threshold or a 72-hour deadline.

A recipient using data for a decision subject to explanation, objection, review or human-intervention rights MUST provide the applicable process and information. A read receipt explains an access event, not the reasoning or consequences of a subsequent decision.

Parties MUST assess any activity-specific regime, including data intermediation, registered consent-management services and sector health or financial rules, before claiming that status. A technical provider, consent screen or registry entry MUST NOT be described as a legally registered or certified service without the required legal conditions, registration and any structural safeguards.

Check: PRIVACY-06.

## A16.8 Evidence and claims

A deployment claiming conformance MUST hold evidence for PRIVACY-01 to PRIVACY-06 identifying the tested build, jurisdictions, supported uses and categories, assessment date, responsible reviewer, restrictions, operational procedures and observed results. Evidence MUST include representative exercises of the relevant consent, rights, transfer, retention, opt-out and incident processes. Legal applicability decisions require accountable review; automated schema checks cannot make them.

The deployment MUST reassess material changes in law, purpose, audience, data or flows. Public claims MUST state their scope and limitations without publishing personal data, privileged advice or confidential security details. A checklist, pending test or published contract MUST NOT be presented as an operating safeguard. No conformance statement under A17 may be labelled a legal compliance certificate.

Checks: PRIVACY-01 to PRIVACY-06 and CLAIM-01.


---

# A17. Conformance and change process

**Status:** normative. Document version `1.0-draft-1`.

## A17.1 Provider and recipient roles

[The conformance manifest](../conformance/profiles.json) defines exact required check groups and dependencies. Shared security, data-minimisation and A16 deployment requirements apply to every claimed capability. PRIVACY-01 to PRIVACY-06 require operational evidence for the deployment's stated jurisdictions and uses; passing them is not a legal compliance certificate.

| Role      | Capability | Required behaviour                                                                                                       |
| --------- | ---------- | ------------------------------------------------------------------------------------------------------------------------ |
| Provider  | Core       | Pairwise identity, typed record, temporal compiler, consent, one or both public surfaces, receipts, revocation and purge |
| Provider  | Write      | Core plus separate contributions, protected confirmation and correction/replay handling                                  |
| Provider  | Portable   | Core plus export and import, preservation/unsupported reporting and migration without authority transfer                 |
| Provider  | Delegated  | Core plus bounded standing rules and one-use target-bound grant offers                                                   |
| Recipient | Read       | Correct grant use, signature/binding/expiry verification, permitted retention and purge                                  |
| Recipient | Contribute | Separate contribution authority, provenance, retries and own-event correction/withdrawal                                 |
| Recipient | Reciprocal | Read and Contribute plus inbound/outbound transfer for the same stated categories                                        |

Advertising is optional and additionally requires ADS-01 and ADS-02. In the same way, a provider that offers public handles additionally requires HANDLE-01, one that offers the A11.2 encrypted export requires ENCRYPT-01, and one that offers the B1 binding requires BINDING-01. WILDCARD-01 checks the A15.1 recommendation; no capability requires it. Verified credential presentations, Trust registries and emergency cards are reserved, unclaimable v1 extensions. “Read” does not mean Portable. An export-only implementation cannot claim Portable or Reciprocal.

## A17.2 Claims and evidence

Use [capability-claim.json](../schemas/capability-claim.json): role, wire/document version, capabilities, exact domain/key categories, directions, limitations, evidence URLs/timestamps and `assurance:self-declared`. Provider capability names and recipient capability names cannot be interchanged. Directions must match actual behaviour and the declared capabilities. A Read-only claim cannot advertise contribution or transfer. Every claimed direction has at least one supported category; categories may differ for reading and contribution. Portable/Reciprocal covers both export and import for every category named in that claim. Evidence identifies a reproducible test suite version, tested build and result for every required check.

The draft establishes no certification authority and issues no badges. Independent certification requires a separately published governance and assessment process. A self-declared implementation can accurately publish its evidence and limitations, but cannot say “certified” because its JSON parsed or because a provider supports a similar capability.

Contract checks in the reference repository validate schemas, vocabulary examples, scope syntax and selected pure policy invariants, and run example and property tests of the pure compiler. A library verifier in the same repository checks A5.4 detached signatures on disclosures, receipts, purge acknowledgements and exports. The published [test vectors](../conformance/vectors/README.md) for disclosures, receipts and purge are checked by the repository's tests, which use that verifier for every detached signature among them, and independently by a second verifier written from the specification text alone with other libraries. A [statement audit](../conformance/statements.json) maps every normative sentence it extracts from the core, the bindings and the vocabulary page to the checks that test it, or to the reason no suite can. These checks do not exercise a running recipient service. Where a check's manifest entry records `integration` evidence, the reference implementation's integration tests, which run its provider against real storage, cover every duty the check's requirement places on a provider that one provider's own tests can show; a verifier's part of the requirement keeps the evidence of its own tests and vectors, and that shows the reference provider meets those duties, not that another implementation does. Full runtime checks in the manifest remain pending and must pass before a conforming implementation is claimed. Failure reports must identify check ID, expected behaviour and observed behaviour without exposing personal values.

## A17.3 Changes

Document version `1.0-draft-1` is distinct from proposed wire version `1.0`. After wire release, breaking changes require a new version/URL prefix, an ADR, migration guidance and explicit approval. Additive core keys require full value/rendering definitions, sensitivity review, examples and conformance coverage. Unknown keys stay rejected until the new vocabulary version is negotiated.

A17.4 describes review, compatibility and published editions.

## A17.4 Versioning and editions

The current document version is `1.0-draft-1`; the proposed wire version is `1.0`. Document versions identify editions of the specification. Wire versions identify the protocol used by compatible implementations.

### Draft status

The draft is open to review and interoperability testing. Published requirements and implementation status are separate: the [implementation and conformance status](../conformance/README.md) records which contracts have executable checks and which service capabilities remain in development.

### Reviewing changes

Changes are reviewed with their effects on privacy, consent, security and compatibility. A protocol change includes the corresponding normative text, schemas, examples and conformance requirements. Implementations follow the requirements for the version they claim.

New vocabulary keys need a complete value definition, supported disclosure levels, rendering rules, sensitivity review, examples and conformance coverage. Keys remain unavailable until their vocabulary version is supported and negotiated.

### Compatibility

After the wire protocol is released, breaking changes require a new wire version and URL prefix, an approved architecture decision record and migration guidance. Additive changes retain existing consent and disclosure limits. Reserved extensions need their own complete contracts and evidence before implementations can claim support.

### Published editions

Each edition includes the specification text, machine-readable contracts, examples and conformance requirements. Downloadable bundles include a source revision and checksums so implementations can identify the exact edition they use.

## A17.5 Capability claims and acceptance

A17 defines provider Core/Write/Portable/Delegated separately from recipient Read/Contribute/Reciprocal. Discovery identifies role, version, exact categories, directions, evidence and limitations. Version 1 assurance is self-declared; there is no issued certification or badge. No export means no full portability claim.

Checks for A17.5 and the requirements first published as A18: CONSENT-01, ADS-01/02, TEMP-01/02/03, CONTRIB-01/02/03, PORT-01 and CLAIM-01 in the [conformance manifest](../conformance/profiles.json). SCOPE-10 and structural/pure policy tests execute now; service authorisation, temporal selection, cryptography, transactions and integrations remain implementation gates.

## A17.6 Self-declaration and reserved capabilities

For v1, capability discovery uses [capability-claim.json](../schemas/capability-claim.json) and explicitly states `assurance:self-declared`, role, protocol/document version, data categories, directions, limitations and test evidence. A provider must not turn self-declaration into a verified/certified badge or trusted client class. No v1 tier can be purchased or inferred from passing a structural schema check. Registry tiers, signed registry attestations, registry-mediated governance and emergency cards are reserved for a later version; see the placeholders for [A12](reserved/a12-recipient-registry.md) and [A13](reserved/a13-emergency-information.md).

An implementation offering a separate experimental emergency card must clearly distinguish it from v1 conformance. Offline scans cannot reliably be logged or remotely revoked, and the person must be told before creating one. Never label an offline disclosure as a logged Autonym read or make an emergency-care reliability claim from this protocol.

Checks: CLAIM-01 and all checks required by the declared capabilities.


---

# Design principles

**Status:** informative. Document version `1.0-draft-1`.

- Every disclosure level needs a grant, including L0. There is no ambient read or default permission.
- L1 may contain safe structure, roles and age bands. Identifiers still require their permitted higher level.
- The stored grant wins over token scope and request filters. A request can only narrow it.
- Read and contribution authority are separate, independently approved and revoked.
- Temporary context is a bounded overlay or additive state; expiry restores the baseline without a destructive edit.
- Advertising is optional, off by default, one read within 24 hours, limited to three confirmed entertainment-preference keys, with no retention, delegation or onward right.
- Each recipient gets its own handle and entry references. Canonical IDs and raw derivation evidence remain private.
- Portability transfers data and history, not executable credentials or consent authority.
- Provider and recipient claims are distinct. No implementation or certification follows from publishing a schema.
- The 30-key vocabulary 1.1 is closed and retains the original 27 keys from vocabulary 1.0. Broader candidates, credential presentations, emergency cards, registries and guardian/duress operation require later specifications.

The [interpretation notes](../history/source-ambiguities.md) link these principles to their requirements. See [versioning and changes](a17-conformance-and-change.md#a174-versioning-and-editions) for the review and compatibility process.


---

# Typed record identifiers

**Status:** implementation note for A4.1. It records how the reference library implements the section; its requirements bind that library and add none for other implementations. Document version `1.0-draft-1`.

This implements the prefixed ULIDs in [A4.1](a04-data-model.md) and the additional entity types in the service design. It does not implement public or pairwise handles, access tokens, account recovery or any authentication mechanism. Identifiers are not secrets or proof of authority; they encode a creation timestamp.

The single source of truth is `packages/schema/src/identifiers.ts`. The [generated schema](../schemas/identifier.json) accepts any supported type; callers MUST use `idSchemaFor(prefix)` at a boundary that expects one particular type. [Synthetic examples](../examples/identifiers.json) are generated from the same prefix enum.

| Prefix | Entity            |
| ------ | ----------------- |
| acc_   | Account           |
| rec_   | Record            |
| prf_   | Record partition  |
| ent_   | Entry             |
| gr_    | Grant             |
| rd_    | Read              |
| prp_   | Proposal          |
| cl_    | Client            |
| evt_   | Chain event       |
| pi_    | Purge instruction |
| rule_  | Standing rule     |
| dp_    | Delegation policy |
| imp_   | Import job        |
| exp_   | Export job        |

The wire representation MUST use the exact lower-case prefix and underscore followed by 26 upper-case Crockford Base32 characters. The first ULID character MUST be 0-7; the remaining alphabet excludes I, L, O and U. Whitespace, abbreviated ids, alternative case, look-alike substitutions and trailing bytes are rejected rather than normalised. The canonical upper-case representation removes aliases at storage and authorisation boundaries. This is an explicit Autonym wire constraint; generic ULID tools may also accept lower-case text.

`createId(prefix, timestampMilliseconds)` uses the maintained `ulid` library's default platform CSPRNG and requires an explicit integral Unix timestamp from 1 through 281474976710655 inclusive. A service supplies its Clock reading as whole milliseconds, with any finer digits dropped rather than rounded (`epochMilliseconds(clock.now())`); the helper MUST NOT use ambient time, Math.random or a custom PRNG. Zero is valid in the wire format, but generation deliberately rejects zero: the pinned library treats it as a request for ambient time. Invalid prefixes/timestamps or missing secure randomness fail with a fixed `IdentifierError`, containing no input or underlying library error. These are local helper failures, not new transport error codes.

Generation is random within a millisecond, not monotonic. Database uniqueness constraints and conflict handling remain required in the persistence package; sample generation is not proof that collisions are impossible. No timestamp or id is suitable as a bearer credential. Pairwise recipient identifiers remain a separate privacy contract.

ID-01 checks every prefix and canonical boundaries, including ULID overflow. ID-02 checks explicit time with ambient time and Math.random made unavailable. ID-03 checks invalid generation input. ID-04 checks 10,000 generated ids against the type and timestamp. ID-05 bundles the public schema package for a real Chromium browser, exercises scope parsing and generation, and proves generation fails without WebCrypto. The browser harness is built separately and is absent from the application image.

The entry model and its value shapes are specified in [A4.1](a04-data-model.md) and the [entry schema](../schemas/entry.json); this note covers identifiers only. The reference provider's record store refuses any stored identifier with a prefix from the table above that is not in canonical form.


---

# Scope grammar implementation

**Status:** implementation note for A6.2. It records how the reference library implements the section; its requirements bind that library and add none for other implementations. Document version `1.0-draft-1`.

This implements the grammar in [A6.2](a06-authorisation.md), not an authorisation server. An authorisation server parses the `scope` of an authorisation or token request with it; no recipient route accepts scopes. Scopes from a token MUST NOT replace the stored grant as authority (A6.2; read-path verification remains pending).

The source of truth is `packages/schema/src/scope/index.ts`. [scopes.json](../scopes.json) publishes the closed purpose/capability sets and limits, with the purpose codes and capability meanings below; its `scope` marker, `grammar-and-meanings`, says that it holds the grammar and the meanings issuance applies (A6.2), not an endpoint; [scope-token.json](../schemas/scope-token.json) validates one token; [examples](../examples/scopes.json) are generated and round-trip through the parser. A token schema does not validate a complete grant. Complete sets MUST pass the semantic checks below.

## Parsing and canonical form

`parseScopes(string)` returns a canonical token array; `serialiseScopes(array)` revalidates and joins it. Both MUST reject unknown tokens, trailing content, invalid case and malformed boundaries with `invalid_scope`. No input is trimmed, decoded or case-folded. The separator is exactly one ASCII space. Input is limited to 16,384 ASCII bytes, 128 tokens before deduplication and 128 characters per domain. Non-ASCII input, leading/trailing spaces and all other whitespace are rejected. The domain character alphabet is the published scope grammar, including extension names and exact case. A syntactically valid domain is not automatically a registered vocabulary domain.

Exactly one purpose token MUST occur before deduplication. A valid token set without one fails with `purpose_missing`; two occurrences, even identical ones, fail with `invalid_scope`. An empty string also fails with `purpose_missing`. Malformed input is rejected before the purpose count. All ten purposes and eight capability strings are generated from schemas.

`*` MUST appear only on L0 read scopes. No missing domain implies an L0 floor. `ceilingFor(set, domain)` returns the explicit domain ceiling, or L0 for a wildcard, or null. It revalidates the whole set and rejects a wildcard or invalid queried domain. It is a ceiling lookup only: expiry, status, read counters, confidence, purpose, declared-only and every other stored grant restriction are still required before a read.

Read duplicates for the same exact domain and the same declared-only mode MUST collapse to their highest level at the first occurrence's position. Duplicate capabilities collapse to their first occurrence. Explicit domains and `*` remain distinct. Mixed unrestricted and `:declared` reads for the same domain MUST be rejected in this implementation. At grant issuance, any accepted `:declared` modifier makes the entire stored grant `declared_only:true`, including wildcard/explicit-domain combinations. Consent shows this restriction. A person wanting different declaration restrictions uses separate grants. Explicit domain ceilings take precedence over the wildcard L0 ceiling; no declaration restriction is removed. No present code treats a ceiling as permission to disclose an entry.

Validation errors contain a fixed name, registered code and title, never the input or the underlying Zod issues. `invalid_scope` and `purpose_missing` are registered as status 400 Problem Details variants for routes outside OAuth. At the authorisation and token endpoints, a record-grant scope the parser refuses fails OAuth `invalid_scope` (RFC 6749 sections 4.1.2.1 and 5.2) in the OAuth error form, and so does a scope without a purpose. The A6.6 lifecycle scope is not a record-grant scope: the token endpoint checks it on its own, outside the parser. The parser itself throws `ScopeValidationError`.

## Purpose codes

Where a purpose has to be an absolute URI, such as PDPP's `purpose_code` (B1.4), the purpose `autonym:purpose:<category>` is written `urn:autonym:purpose:<category>`: `urn:autonym:purpose:booking`, for example. [scopes.json](../scopes.json) lists the ten codes as `purpose_codes`. No other code names an Open Personal Context purpose.

## Capability meanings

Each capability scope has one meaning at issuance (A6.2), published in [scopes.json](../scopes.json) as `capability_meanings`. A client receives a third-party capability only when its class may hold it (A2).

| Scope                    | Who may hold it | Meaning                                                                       |
| ------------------------ | --------------- | ----------------------------------------------------------------------------- |
| `autonym:propose`        | Third party     | Requests a contribution grant, separate from any read grant                   |
| `autonym:confirm`        | Third party     | Sets `allow_confirmation` on that contribution grant                          |
| `autonym:persist`        | Third party     | Permits `persist_until` on a read grant                                       |
| `autonym:delegate`       | Third party     | Sets `allow_delegation` on a read grant                                       |
| `autonym:confirm:safety` | First party     | Reserved to the person's own first-party clients; never issued to a recipient |
| `autonym:write:declared` | First party     | Reserved to the person's own first-party clients; never issued to a recipient |
| `autonym:log:read`       | First party     | Reserved to the person's own first-party clients; never issued to a recipient |
| `autonym:manage`         | First party     | Reserved to the person's own first-party clients; never issued to a recipient |

A capability of one grant kind cannot be combined with a request for the other kind, so `autonym:propose` with a read scope, `autonym:persist` or `autonym:delegate` is a mixed request. The second of the published [examples](../examples/scopes.json), which reads two domains and asks for `autonym:propose`, is valid grammar but such a mixed request, so issuance refuses it with `invalid_scope`. `openid` and `offline_access` are not Open Personal Context scopes: the parser refuses them like any other unknown token.

## Advertising purpose

`autonym:purpose:advertising` is separate from `personalisation` and `recommendation`. The parser MUST preserve that distinction and MUST NOT add read, proposal or persistence capabilities from a purpose alone. A combined advertising and personalisation set MUST be rejected by the one-purpose rule; separate consent requires separate grants. SCOPE-10 checks this grammar boundary. [A6.7](a06-authorisation.md#a67-consent-and-advertising) defines the draft consent requirements. Parsing a scope does not establish consent, an eligible domain or permission to disclose.

## Executable checks

`packages/schema/test/scopes.test.ts` supplies SCOPE-01 (source fixture), SCOPE-02 (closed purposes/capabilities), SCOPE-03 (one purpose), SCOPE-04 (wildcard and absence), SCOPE-05 (duplicates and declaration ambiguity), SCOPE-06 (exact parsing), SCOPE-07 (limits and caller boundary validation), SCOPE-08 (10,000 arbitrary inputs) and SCOPE-09 (10,000 valid sets, round trips and ceiling bounds). SCOPE-10 checks the advertising boundary. These are grammar checks, not certification of the A17 recipient capabilities.

Recipient OpenAPI/MCP contracts are now generated, while endpoints and SDK implementations remain pending. Parsing is not an endpoint or a conformance claim. The separate client-lifecycle scope in A6 is not a record-grant scope.


---

# A12. Recipient registry and trust

**Status:** informative placeholder for a capability reserved for 2.0. It carries no requirements. Document version `1.0-draft-1`.

The Trust capability, registry tiers, signed registry attestations and registry-mediated governance are reserved for a later version. A future registry extension would need to specify issuer trust, verification, expiry, suspension, appeal, purge evidence and independent assessment before certification claims could become valid. Trust certification is outside v1, with no issued certificates.

The version 1 rules this chapter stated in edition 0.2-draft now live in [A2.1](../a02-actors-and-trust.md#a21-recipient-registries-and-trust-evidence) (registries and trust evidence), [A6.8](../a06-authorisation.md#a68-client-standing-and-safety-purposes) (client standing) and [A17.6](../a17-conformance-and-change.md#a176-self-declaration-and-reserved-capabilities) (self-declaration), with their check ids unchanged.


---

# A13. Emergency information

**Status:** informative placeholder for a capability reserved for 2.0. It carries no requirements. Document version `1.0-draft-1`.

Emergency cards are outside the v1 interoperable capability set. The future design direction is an explicitly person-selected clinical subset carried using a separately verified health-link standard. That work would need to establish clinical mappings, offline disclosure, key distribution, expiry, revocation limitations, consent and device access before release. This draft does not invent a SMART Health Link or IPS wire format or claim compliance with those standards. Clinical interoperability and offline-card acceptance are outside v1 scope.

The version 1 rules this chapter stated in edition 0.2-draft now live in [A6.8](../a06-authorisation.md#a68-client-standing-and-safety-purposes) (safety and medical purposes) and [A17.6](../a17-conformance-and-change.md#a176-self-declaration-and-reserved-capabilities) (experimental emergency cards), with their check id unchanged.


---

# Continuous connectors (reserved from A14)

**Status:** informative placeholder for a capability reserved for 2.0. It carries no requirements. Document version `1.0-draft-1`.

Version 1 contributions use the authenticated HTTPS push of [A14](../a14-contributions.md): one event per request within a bounded, separately revocable contribution grant. Batches, background polling, streaming subscriptions and vendor-specific export formats are outside version 1 (A14.1).

A continuous connector framework is reserved for 2.0. This page adds no requirement: continuous connectors are outside version 1 conformance under A14.1, and A1.2 and A17.1 govern what an implementation may claim.


---

# Bindings

**Status:** index. Document version `1.0-draft-1`.

A binding carries the core requirements over an existing standard. Each binding says what it takes from that standard, what it adds and which core sections it implements. The [adoption records](../adoption/README.md) describe the standards themselves. PDPP citations here refer to PDPP Core v0.1.0 at commit `8f79a48`.

| Binding                                           | Status at `1.0-draft-1`              | Binds                                                                 |
| ------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------------- |
| [B1 PDPP](B1-pdpp.md)                             | Normative draft; checks pending      | The A6 grant model to PDPP Core grants, introspection and token kinds |
| [B2 Linked Web Storage](B2-linked-web-storage.md) | Informative in 1.0, normative in 2.0 | Storage of a record in a Linked Web Storage or Solid pod              |
| [B3 MCP](B3-mcp.md)                               | Normative                            | The A7 agent surface to the Model Context Protocol                    |
| [B4 REST](B4-rest.md)                             | Normative                            | The A8 recipient API to HTTP and OpenAPI                              |


---

# B1. PDPP binding

**Status:** normative draft. Binds PDPP Core v0.1.0 at commit `8f79a48` of PDP-Connect/pdpp, recorded with its file hashes in [`pdpp.lock.json`](../adoption/pdpp.lock.json) and described in the [PDPP adoption record](../adoption/pdpp.md). Document version `1.0-draft-1`.

This binding states how an Open Personal Context read grant is issued, introspected and exercised as a PDPP Core grant, and what Open Personal Context adds that PDPP Core cannot carry. [A6](../core/a06-authorisation.md) remains the authorisation contract: where this binding and A6 differ, A6 wins and the difference is a defect in this binding. Open Personal Context Core stays meaningful without PDPP: this binding is the normative 1.0 grant binding, not a dependency of the model.

Section numbers below refer to PDPP Core v0.1.0, `spec-core.md`, at commit `8f79a48`. Conformance items are cited by role and item number from its section 9.

## B1.1 Scope

This binding covers read grants (`kind: "read"`) only. A contribution grant (`kind: "contribute"`) has no PDPP Core equivalent: PDPP Core section 12 leaves ingest to the informative Collection Profile. Contribution grants are issued and exercised through [B3](B3-mcp.md) and [B4](B4-rest.md) only, never as a PDPP grant.

The mapping in this binding is independent of how the authorisation server is built. It applies however a provider builds its authorisation server. The Autonym reference server implements PDPP Core natively.

Every wire value this binding introduces (the B1.5 detail, the purpose codes, the stream names and record shape, the identifier derivations, the `autonym_lifecycle` token kind, the `Autonym-Read-Id` header and a `pdpp` receipt surface) is draft text until it is defined in the schema package and its artefacts are generated.

## B1.2 The source and its declaration

A provider that offers this binding acts as one `provider_native` source (section 6, Source kinds). The PDPP endpoints form their own protected resource with their own identifier, distinct from the B4 resource; `source.id` MUST equal that identifier (section 5, Declaration acceptance).

The provider publishes one SourceDeclaration (section 5) generated from the [core vocabulary](../vocabulary/README.md), never written by hand:

- `protocol_version` is `0.1.0`.
- `declaration_version` names the vocabulary version and the edition of this binding, so a grant records exactly which vocabulary its streams were resolved against. It is opaque to PDPP.
- `streams[]` holds the streams of B1.3. Their `display.label` and `display.detail` describe the data and never the requester's purpose. The vocabulary has key labels but no domain labels, so this display text is new product copy and needs review before it is published.
- No stream declares `consent_time_field`, so `time_range` is rejected for every stream (section 6, Note on `time_range`). Temporal selection stays an Open Personal Context read parameter (A4.3, A5.2).
- No stream supports `resources` selection, and no stream declares views, relationships, `expand`, `search` or `aggregations`.
- No stream declares a `blob_ref` field.

## B1.3 Levels as statically declared derived streams

PDPP Core has no disclosure level. This binding expresses each level as a separate, statically declared derived stream, as the non-normative "Derived subset streams" paragraph of section 12 allows. The mapping is Open Personal Context's, not PDPP's.

For every domain `<domain>` in the core vocabulary and every level `L<n>` at which at least one of the domain's keys has a vocabulary rendering, the declaration contains:

- `<domain>.l<n>`: the domain rendered at or below `L<n>` by the A5 compiler;
- `<domain>.l<n>.declared`: the same, restricted to exactly confirmed declared entries (A5.2).

Domain names may contain dots, so a stream name is read from the right: an optional `.declared` suffix, then the level, then the domain.

Each stream has `semantics: "mutable_state"` and exactly one record for each grant that includes it. The record is always returned, even when no key is currently disclosable, so its presence reveals nothing. Its fields are:

- `id`, the primary key and the only schema-required field: a record identifier derived as in B1.4 (Identifiers);
- one top-level field per vocabulary key of the domain, whose value is an array of the compiled entries for that key, in A5.2 order. Each element has the members of a [disclosure.json](../schemas/disclosure.json) entry except `domain` and `key`: `id` (the client-bound `rent_` alias), `version`, `level`, `value_type`, `value`, `context_kind`, `safety_critical`, `provenance` (`kind`, `confirmed`) and `stale`. A key with several eligible entries, such as several allergies, has one element for each.

A key with no eligible entry, or no rendering at or below the stream's level, is absent from the record. Absence never reveals why.

Stream names MUST NOT be generated per request (section 12). A new vocabulary key or level appears only in a new declaration revision, and never widens an issued grant (section 5, Versioning and snapshots).

## B1.4 Grant mapping

An Open Personal Context read grant issued through this binding is one PDPP grant (section 7) for the provider's source, plus the Open Personal Context detail of B1.5. Every property of [grant.json](../schemas/grant.json) is mapped below. A property marked "B1.5" travels only in the Open Personal Context detail.

| Open Personal Context property | PDPP Core v0.1.0 representation                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                           | `grant_id`, and introspection `grant_id`.                                                                                                                                                                                                                                                                                                                                                                    |
| `revision`                     | B1.5. A PDPP grant is immutable and PDPP Core v0.1.0 has no narrowing (section 7, Grant narrowing). A change of authority is made by revoking the grant and issuing a new one with a new `id` (Revoke and reissue, below).                                                                                                                                                                                   |
| `handle`                       | `subject.id`, and introspection `subject_id`. The pairwise handle (A3.2) is an opaque string unique within the issuer's namespace, which is all section 7 requires.                                                                                                                                                                                                                                          |
| `client_id`                    | `client.client_id`, and introspection `client_id`. `client.client_display` holds the requester metadata the authorisation server resolved (section 6, Client display metadata).                                                                                                                                                                                                                              |
| `purpose`                      | `purpose_code` and `purpose_description`, below.                                                                                                                                                                                                                                                                                                                                                             |
| `purpose.category`             | `purpose_code`, the absolute URI `urn:autonym:purpose:<category>`. The authorisation server accepts only the ten Open Personal Context purposes and rejects any other code by local policy, which Authorization Server item 6 permits.                                                                                                                                                                       |
| `purpose.text`                 | `purpose_description`. A request without it is rejected, because A6.3 requires a plain-language purpose; it is always displayed.                                                                                                                                                                                                                                                                             |
| `issued_at`                    | `issued_at`.                                                                                                                                                                                                                                                                                                                                                                                                 |
| `expires_at`                   | `expires_at`, always present under this binding although PDPP makes it optional.                                                                                                                                                                                                                                                                                                                             |
| `status`                       | Grant lifecycle tracked by the authorisation server (section 7), reported as introspection `active` and as the `grant_revoked` and `grant_expired` errors (section 8, Errors). Never a field of the PDPP grant.                                                                                                                                                                                              |
| `kind`                         | `read` is issued as a PDPP grant. `contribute` is never issued as a PDPP grant (B1.1).                                                                                                                                                                                                                                                                                                                       |
| `read`                         | `streams`, one StreamGrant per entry, resolved as below.                                                                                                                                                                                                                                                                                                                                                     |
| `read[].domain`                | The domain part of the StreamGrant `name`. The wildcard `*`, allowed only at L0 (A6.2), is expanded at issuance to one L0 StreamGrant for each core vocabulary domain that has no explicit entry in the grant, because explicit domain ceilings take precedence over the wildcard (A6.2, Authorization Server item 4). PDPP's own `*` stream wildcard is not used, because it would also select every level. |
| `read[].keys`                  | StreamGrant `fields`: the listed keys plus `id`. `null` (all keys) is expanded at issuance to every key of the domain with a rendering at or below the granted level, and frozen (Authorization Server items 4 and 13).                                                                                                                                                                                      |
| `read[].max_level`             | The level part of the StreamGrant `name`: the highest declared level of the domain at or below `max_level`. If the domain has no declared level at or below it, the entry is refused at issuance. The compiler renders each key at the highest vocabulary-supported level at or below the ceiling (A5.2).                                                                                                    |
| `declared_only`                | The `.declared` stream variant of B1.3 when true, so the restriction is visible on the PDPP consent surface and enforced by stream membership. Also in B1.5.                                                                                                                                                                                                                                                 |
| `min_confidence`               | B1.5.                                                                                                                                                                                                                                                                                                                                                                                                        |
| `max_reads`                    | B1.5. `access_mode` is `single_use` when `max_reads` is 1 and `continuous` otherwise; a request whose `access_mode` disagrees with its `max_reads` is rejected.                                                                                                                                                                                                                                              |
| `reads_used`                   | Not carried. A counter in the provider's stored grant (A6.2), never part of a PDPP grant or introspection response.                                                                                                                                                                                                                                                                                          |
| `persist_until`                | `retention` with `on_expiry: "delete"`. `max_duration` is the ISO 8601 duration from `issued_at` to `persist_until`, or `PT5M` when `persist_until` is null, the longest validity an A5 envelope can carry. The exact instant is in B1.5 and governs (B1.11, B1-D7).                                                                                                                                         |
| `allow_delegation`             | B1.5. A delegated child grant (A6.4) is a separate PDPP grant with its own `grant_id` and its own identifiers.                                                                                                                                                                                                                                                                                               |
| `onward_share`                 | B1.5. Always false in version 1; the consent surface renders it as server-generated text.                                                                                                                                                                                                                                                                                                                    |
| `contribute`                   | Not carried (B1.1).                                                                                                                                                                                                                                                                                                                                                                                          |
| `contribute[].domain`          | Not carried (B1.1).                                                                                                                                                                                                                                                                                                                                                                                          |
| `contribute[].keys`            | Not carried (B1.1).                                                                                                                                                                                                                                                                                                                                                                                          |
| `max_events`                   | Not carried (B1.1).                                                                                                                                                                                                                                                                                                                                                                                          |
| `events_used`                  | Not carried (B1.1).                                                                                                                                                                                                                                                                                                                                                                                          |
| `allow_confirmation`           | Not carried (B1.1).                                                                                                                                                                                                                                                                                                                                                                                          |
| `stream_id`                    | Not carried (B1.1). It names an Open Personal Context contribution event stream and is unrelated to PDPP streams.                                                                                                                                                                                                                                                                                            |

PDPP grant fields with no Open Personal Context counterpart take fixed values: `version` is `0.1.0`; `source` is `{ kind: "provider_native", id }` from B1.2; `source_declaration.version` is the declaration revision the grant was resolved against; `selection_preset` is absent; `time_constraint` and `resources` are absent; each StreamGrant's `instance_ids` holds exactly one instance handle, resolved without asking the person because there is only one eligible instance (Authorization Server item 15).

**Identifiers.** The record `id` and the instance handle are derived like an A3.2 handle local part: HMAC-SHA256 under the record partition's handle key, over RFC 8785 canonical JSON of the client ID, the handle rotation, the grant `id` and the stream name, with the purpose values `autonym.pdpp.record.v1` and `autonym.pdpp.instance.v1` respectively. Every grant, including every delegated child, therefore has its own values, and two recipients never share one. A record partition identifier or any other internal identifier is never used.

**Revoke and reissue.** When a grant issued through this binding is narrowed, the new grant inherits the old grant's `reads_used`, the read budget reserved by its delegated children and its expiry, so a reissue never restores spent authority. Each child is reissued under the new grant within its limits, or revoked. The change is logged as one authority change, and A10 applies to it on the same terms as a revision change through B3 or B4.

## B1.5 The Open Personal Context detail

Beside the `https://pdpp.dev/data-access` detail, the authorisation request and the issued authorisation carry one RFC 9396 `authorization_details` entry of type `urn:autonym:authorization-details:read`. It holds what PDPP Core cannot express: `min_confidence`, `max_reads`, `persist_until`, `allow_delegation` and `onward_share` in the request, and additionally the grant `id` and `revision` once issued. Its JSON Schema will be generated from the schema package with the grant implementation; until then this list is the contract.

A request that carries the PDPP detail without this entry is completed with `max_reads` 1, `persist_until` null, `allow_delegation` false and `onward_share` false, the most restrictive values, and `min_confidence` 0, the A5.2 default, which filters nothing. The person sees these values before approval. A request that cannot be expressed under A6 fails with RFC 9396 `invalid_authorization_details`; this includes a purpose code that is not an Open Personal Context purpose and two entries that disagree.

These restrictions can refuse a read that the PDPP grant alone would allow (B1.11, B1-D1). An exhausted read budget gives 403 with code `grant_exhausted`. Entries below `min_confidence` are omitted as A5.2 omits them, never refused.

## B1.6 Tokens and introspection

- Client access tokens are A6.3 tokens with the PDPP resource as audience. Under PDPP they are client tokens: introspection, or the co-located local equivalent, returns `active`, `pdpp_token_kind: "client"`, `subject_id` (the pairwise handle), `grant_id`, `client_id`, `exp` and `authorization_details` holding both entries of B1.5 (section 8, Token introspection).
- A token issued for another audience, including every contribution-grant token and every read token issued outside this binding, is inactive at the PDPP resource.
- This binding issues no PDPP owner tokens. The person reads, exports and deletes their own record through the app session and A11, never through a bearer credential that could be handed to a recipient (B1.11, B1-D8).
- The A6.6 client lifecycle token introspects as `pdpp_token_kind: "autonym_lifecycle"`, a companion-profile kind that section 8 permits. A PDPP resource server, including this provider's, treats it as unauthorised for every PDPP operation. `pdpp_token_kinds_supported` lists `client` only.
- The authorisation server, resource server and introspection run in one deployment, so the resource server uses the local equivalent and caches nothing: A6.5 requires revocation to take effect on the next attempted action, which is stricter than the 60-second bound of section 10. If an RFC 7662 endpoint is offered for a separated resource server, only that resource server's credential may call it.
- PKCE S256, exact redirect matching, single-use codes and rotating refresh families follow A6.3, which meets Authorization Server items 19 and 20. Refresh tokens are not issued for a `single_use` grant.
- DPoP is required where A6.3 requires it. A DPoP-bound token is never accepted as a Bearer token.

## B1.7 Reads through the compiler

A client-token request to list records or to get the record of a granted stream is an Open Personal Context read of one domain at one level. It runs the A5.2 transaction in full: lock and recheck the stored grant and the B1.5 restrictions, compile, create and sign the A5 envelope, append the A9 receipt with surface `pdpp` and increment the read counter, then commit. The PDPP record is a projection of that signed envelope's entries and contains every entry of the envelope and nothing else. Nothing else renders entry data for this binding.

- Each successful client-token read carries `Autonym-Read-Id` with the receipt's `rd_` read ID. Whether the signed envelope is also returned is not yet settled.
- `changes_since` (Resource Server items 7 and 8) returns the record only when its compiled projection at the current horizon differs from its compiled projection at the cursor's horizon. A change to an entry that is hidden, ungranted, below the stream's level or outside the projection never makes the record eligible (section 8, List records).
- Getting a record by an identifier that is not this grant's record gives the same 404 `not_found` as an unknown identifier, without a read.
- Listing streams for a client token names the granted streams only. It carries no record count, update time or freshness that depends on the record; where the response shape requires such a member, it holds a value that does not depend on the record.
- Stream metadata for a client token is the closed projection Resource Server item 15 requires: the granted stream and its granted fields only.
- Client-token `filter[...]`, `view`, `expand[]` and `expand_limit[...]` are rejected with 400 `invalid_request` (Resource Server items 5, 9 and 10).
- The blob endpoint answers 404 `blob_not_found` to every request, because no stream declares a blob.

## B1.8 Revocation, receipts and purge

PDPP Core says revocation is not deletion and defines no erasure signal (section 10, Revocation), and leaves audit events to a companion profile (section 11). This binding adds both without changing PDPP semantics:

- every read is receipted under A9, and grant issuance and revocation are logged events;
- ending a grant issues A10 purge instructions on the same terms as for any other grant, delivered and acknowledged outside PDPP.

## B1.9 Transport, errors and versions

- The PDPP section 8 endpoints are served under a base path published as `pdpp_core_query_base` in the RFC 9728 metadata for the PDPP resource (Resource Server item 16). The base path and resource identifier are not yet fixed.
- On a 401 the response carries a `WWW-Authenticate: Bearer` challenge with the RFC 9728 `resource_metadata` parameter, as Resource Server item 16 requires, and also a `DPoP` challenge where the provider accepts DPoP-bound tokens.
- Until the error mapping is settled, errors on the PDPP endpoints use the section 8 error object, with PDPP's codes where PDPP defines one and the registered Open Personal Context code otherwise, so a PDPP client falls back on the status as section 8 requires. B4 routes keep Problem Details (B4.3), and OAuth endpoints keep their OAuth error responses.
- `PDPP-Version` is negotiated on the PDPP endpoints (Resource Server item 11, Authorization Server item 17). `Autonym-Version` keeps its B4 meaning; the two are independent.
- The authorisation request is pushed (RFC 9126) because the two `authorization_details` entries exceed comfortable URL lengths (section 10, Grant integrity).

## B1.10 PDPP Core conformance

A provider claiming this binding meets the section 9 requirements as the tables below state: Authorization Server items 1 to 21; Resource Server items 2 to 11, 15 and 16; Resource Server item 1 except for the owner operations of B1-D8; and Resource Server items 12 and 14 trivially, because this binding issues no owner tokens. Resource Server item 13, a SHOULD, is not supported. Each row summarises the requirement; section 9 is authoritative.

**Authorization Server**

| Item | Section 9 requirement                                                                                                                         | How this binding meets it                                                                                                                                                                                                                    |
| ---- | --------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1    | Accept selection requests in the RFC 9396 `https://pdpp.dev/data-access` detail                                                               | Accepted alongside the B1.5 detail                                                                                                                                                                                                           |
| 2    | Validate a request against one retained SourceDeclaration snapshot, refusing unknown streams, unsupported parameters and unrecognised presets | Validated against the retained generated declaration (B1.2). Unknown streams, `time_range` (no stream declares `consent_time_field`) and every selection preset are refused, since no grant under this binding carries one (B1.4)            |
| 3    | Issue grants that follow the section 7 field tables, every field derived from the request, client registration or policy                      | Grants follow the B1.4 mapping and its fixed values                                                                                                                                                                                          |
| 4    | Expand wildcards and presets into explicit streams, fields, instances and constraints before issuance                                         | The domain wildcard and `null` key lists are expanded and frozen at issuance (B1.4)                                                                                                                                                          |
| 5    | Refuse a request with both or neither of `streams` and `selection_preset`                                                                     | Refused like any request that cannot be expressed under A6, in the RFC 9396 form of B1.5                                                                                                                                                     |
| 6    | Never refuse a purpose code only because the PDPP registry lacks it; local policy may refuse                                                  | Only the ten Open Personal Context purposes are accepted, a local policy the item permits (B1.4)                                                                                                                                             |
| 7    | Keep requester metadata, declaration text, structured policy and client claims distinct at consent                                            | The consent surface shows them as separate categories, attributes client claims to the client and never presents them as enforced terms                                                                                                      |
| 8    | Track grant lifecycle and reflect revocation in introspection at once                                                                         | Revocation takes effect on the next attempted action (A6.5) and introspection reports it at once (B1.6)                                                                                                                                      |
| 9    | Bind access tokens to one grant, with the PDPP introspection members                                                                          | A6.3 tokens bound to one grant, introspected with the members of B1.6                                                                                                                                                                        |
| 10   | Consume a `single_use` grant atomically with its first client token                                                                           | A grant with `max_reads` 1 is `single_use` (B1.4) and is consumed atomically with its first client token                                                                                                                                     |
| 11   | Validate stream, field, view and resource-id shape at issuance                                                                                | Stream and field shape are validated at issuance; views and resource IDs are never accepted (B1.2)                                                                                                                                           |
| 12   | Define no view with fields outside the declaration                                                                                            | Met trivially: no stream declares a view (B1.2)                                                                                                                                                                                              |
| 13   | Resolve views at issuance; client-token reads refuse a query-time view                                                                        | No views are declared, and a client-token `view` is refused (B1.7)                                                                                                                                                                           |
| 14   | Obtain explicit affirmative consent before issuing an `ai_training` grant                                                                     | Met by refusing the `ai_training` purpose code, which is not an Open Personal Context purpose                                                                                                                                                |
| 15   | Resolve instances before final approval and bind approval to an immutable review revision                                                     | The one eligible instance is resolved before review (B1.4); approval is bound to an immutable review revision and refused if eligibility or the revision changes before approval                                                             |
| 16   | Retain one exact declaration snapshot from validation to consent evidence                                                                     | The declaration snapshot used for consent is retained with the grant, which names its revision (B1.4)                                                                                                                                        |
| 17   | Refuse an unsupported `PDPP-Version` with status 400 and the section 8 code for it                                                            | `PDPP-Version` is negotiated as B1.9 states, and an unsupported version is refused with status 400 and that code                                                                                                                             |
| 18   | For a separated resource server, authenticate it at RFC 7662 introspection                                                                    | The servers are co-located and use the local equivalent; an RFC 7662 endpoint offered to a separated resource server accepts only that server's credential and answers with the complete enforcement context of B1.6 in one response         |
| 19   | Consume each authorisation code on its first redemption                                                                                       | Codes are single-use (A6.3, B1.6)                                                                                                                                                                                                            |
| 20   | Issue refresh tokens only for `continuous` grants, rotate them by family and revoke the family on reuse                                       | Refresh tokens rotate by family with replay detection (A6.3). Reuse of a superseded token revokes the grant, with every token issued for it, and fresh authorisation is required. No refresh token is issued for a `single_use` grant (B1.6) |
| 21   | Refuse unsupported persisted authorisation state                                                                                              | Unsupported persisted state is refused and never rebuilt from current configuration; fresh consent is required                                                                                                                               |

**Resource Server**

| Item | Section 9 requirement                                                                                                    | How this binding meets it                                                                                                                                          |
| ---- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 1    | Implement the section 8 endpoints, including the blob endpoint and owner-authenticated delete                            | Partly. Every section 8 endpoint exists. The blob endpoint never finds a blob, because no stream declares one (B1.7), and owner delete refuses every token (B1-D8) |
| 2    | Enforce stream membership, instances, time constraint, fields and resources on every client request                      | Stream membership, the instance handle and `fields` are enforced on every read (B1.7); no time constraint or resource filter is ever granted (B1.2, B1.4)          |
| 3    | Resolve tokens through introspection or a co-located equivalent, caching for at most 60 seconds                          | Co-located local equivalent with no caching (B1.6, B1-D6)                                                                                                          |
| 4    | Distinguish owner tokens from client tokens                                                                              | Token kinds are distinguished; no owner token is issued, and an `autonym_lifecycle` token is unauthorised for every PDPP operation and not advertised (B1.6)       |
| 5    | Refuse request-time predicate filters on client tokens                                                                   | Refused (B1.7)                                                                                                                                                     |
| 6    | Use the section 8 structured errors                                                                                      | The section 8 error object on the PDPP endpoints (B1.9, B1-D5)                                                                                                     |
| 7    | Support `changes_since` incremental sync, with tombstones, unchanged projections omitted and status 410 on cursor expiry | The compiled projection at the cursor's horizon is compared with the current one (B1.7), with the section 8 tombstone and cursor-expiry behaviour                  |
| 8    | Include `next_changes_since` on the terminal page of every `changes_since` response                                      | Included as section 8 requires                                                                                                                                     |
| 9    | Refuse client-token `filter[...]` with status 400 before consulting the declaration                                      | Refused with status 400 before the declaration is consulted (B1.7)                                                                                                 |
| 10   | Refuse unknown query parameters and unsupported query shapes with status 400                                             | Refused, never silently ignored                                                                                                                                    |
| 11   | Implement `PDPP-Version` negotiation                                                                                     | Negotiated (B1.9)                                                                                                                                                  |
| 12   | Scope owner tokens to one subject's data                                                                                 | Met trivially: no owner tokens are issued (B1-D8)                                                                                                                  |
| 13   | SHOULD support owner-token self-export through the record endpoints                                                      | Not supported: the person exports through the first-party app and A11 (B1-D8)                                                                                      |
| 14   | Return full current stream metadata to owner tokens                                                                      | Met trivially: no owner tokens are issued (B1-D8)                                                                                                                  |
| 15   | Return client tokens only a projection of stream metadata derived from the grant                                         | The closed projection: the granted stream and its granted fields only (B1.7)                                                                                       |
| 16   | Publish RFC 9728 metadata with the `pdpp_` members, and a `Bearer` challenge with `resource_metadata` on status 401      | Published for the PDPP resource (B1.2, B1.9), with the `Bearer` challenge on status 401 and a `DPoP` challenge where DPoP-bound tokens are accepted (B1.9)         |

Client items 1 to 8 bind a recipient that uses this binding, not the provider.

Until PDP-Connect publishes its conformance suite, conformance is shown by Autonym's own executable checks, each traced to one section 9 role and item number and never given an invented identifier; PDP-Connect's suite replaces them when it is published.

The Open Personal Context side of this binding is checked by CONSENT-01, CORE-01 and DELEGATE-01 in the [conformance manifest](../conformance/profiles.json), whose runtime evidence is pending the phases the manifest names. BINDING-01, the check of the manifest's optional `pdpp-binding` feature, covers the requirements specific to this binding: the generated source declaration of B1.2, the static streams of B1.3 and the owner endpoints of B1-D8. Its runtime evidence is pending too, and none of these checks is executable yet.

## B1.11 Deviations from PDPP Core

Read strictly against PDPP Core v0.1.0, this binding does the following, which PDPP Core does not anticipate. None widens what a PDPP grant authorises.

- **B1-D1. Extra refusals.** Section 12 (Extensions) says a grant authorises exactly what sections 7 and 8 define. The B1.5 restrictions can refuse a read that the PDPP grant alone would allow.
- **B1-D2. `single_use` retries.** Section 7 lets a client retry with the same token until it expires. With `max_reads` 1, a second successful read is refused.
- **B1-D3. Levels rest on non-normative text.** Derived streams appear only in the non-normative part of section 12.
- **B1-D4. No Bearer tokens.** PDPP Core carries client tokens as RFC 6750 Bearer tokens. Every token here is DPoP-bound (A6.3), so a client that cannot use DPoP obtains no grant.
- **B1-D5. Error format.** Open Personal Context codes appear inside the section 8 error object where PDPP defines none, until the error mapping is settled.
- **B1-D6. No introspection caching.** Stricter than section 10 and conformant with it.
- **B1-D7. Retention measured from issue.** PDPP clients may measure `retention.max_duration` from collection rather than from `issued_at`; `persist_until` in B1.5 governs, and how it reaches a PDPP-only client is not yet settled.
- **B1-D8. No owner tokens.** The owner record endpoints, including owner-authenticated delete (Resource Server item 1) and self-export (item 13, a SHOULD), refuse every token; the person uses the app and A11 instead.

Checks: BINDING-01, CONSENT-01, CORE-01, DELEGATE-01.


---

# B2. Linked Web Storage binding

**Status:** informative in 1.0, normative in 2.0. Binds Linked Web Storage Protocol 1.0, W3C Working Draft of 21 September 2026 (see the [adoption record](../adoption/linked-web-storage.md)). Document version `1.0-draft-1`.

This binding will describe how a person's record can be kept in a Linked Web Storage or Solid pod instead of the provider's native store: the resource layout for a record, how access grants map to Open Personal Context grants, and what cannot be represented.

The draft is to be written after 1.0. Until then a provider-native store is the only described storage, and this file adds no requirement.


---

# B3. MCP binding

**Status:** normative. Binds MCP revision `2026-07-28`. Document version `1.0-draft-1`.

This binding carries the A7 agent surface, and the A5 signed disclosure, over the Model Context Protocol. It binds MCP revision 2026-07-28; the [MCP adoption record](../adoption/mcp.md) says what is taken from it, what is extended and what is not used.

## B3.1 Transport

The normative target is MCP revision [2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/changelog), Streamable HTTP, server name `autonym`. This specifies an implementation requirement; the reference repository does not yet expose this surface.

The server is stateless, with no initialise/initialized handshake or `Mcp-Session-Id`, and MUST implement [server/discover](https://modelcontextprotocol.io/specification/2026-07-28/server/discover). Requests carry protocol version/capabilities in `_meta`. Require `Mcp-Method` on every request and `Mcp-Name` on `tools/call`, `resources/read` and `prompts/get`. Decode and validate headers against the body under the [transport rules](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http); mismatches fail. Roots, Sampling and Logging are not adopted. Legacy revisions are unsupported unless separately declared and tested; no legacy compatibility is claimed by this draft.

## B3.2 Tools

The complete input and output definitions are generated in [tools.json](../mcp/tools.json). Each A7.1 operation is an MCP tool of the same name.

Tool lists are fixed and public. Grant-dependent resource lists are private. Use the revision's list-cache fields. Resource reads use `ttlMs:0` and `cacheScope:"private"`; these transport hints never extend signed context validity.

`get_context` returns the A5 signed disclosure in structured content and the same JSON as text content. Errors follow B3.4.

## B3.3 Resources and prompts

`autonym://context/{domain}` maps to a single-domain context request under the same grant and compiler, counts as one read, and returns the signed JSON object. No grant means no read.

The `autonym_briefing` prompt carries the A7.3 briefing. It returns a text message containing the signed disclosure JSON.

## B3.4 Errors

Every code in the [registry](../errors.json) has exactly one row below: a form in which it reaches an agent, carrying the same Problem Details object as B4.3, or the last row, of codes no agent operation raises. A request that is not a valid JSON-RPC message, fails the MCP request schema or names an unknown tool, resource or prompt gets the JSON-RPC protocol error MCP defines, not a registered code. Every JSON-RPC error `message` is the registered title or, for a protocol error, fixed text; neither carries a submitted value or validation detail. A token that fails verification at the MCP endpoint fails RFC 6750 `invalid_token` as A6.3 says, before any JSON-RPC processing: status `401` with the A6.1 challenge carrying that code. It is not a registered code, so it has no row below.

| Form                                                                                                                                                                                                                                                                                                                                                                                                   | Codes                                                                                                                                                                                                                                                                                                                                                      |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTP response on the MCP endpoint, before any JSON-RPC processing, with the registered status and the Problem Details body. A `401` also carries the A6.1 challenge and a `429` carries `Retry-After`                                                                                                                                                                                                  | `dpop_required`, `dpop_invalid`, `payload_too_large`, `rate_limited`, `not_ready`                                                                                                                                                                                                                                                                          |
| JSON-RPC error `-32603` (Internal error) with the Problem Details object as `data`                                                                                                                                                                                                                                                                                                                     | `internal_error`                                                                                                                                                                                                                                                                                                                                           |
| From `tools/call`, a tool result with `isError:true` whose only content is the Problem Details JSON as text, without structured content, because each tool's output schema describes its successful result. From any other method, such as `resources/read`, `prompts/get` or a grant-dependent `resources/list`, a JSON-RPC error `-32602` (Invalid params) with the Problem Details object as `data` | `invalid_scope`, `purpose_missing`, `invalid_request`, `not_found`, `idempotency_conflict`, `domain_not_granted`, `grant_revoked`, `grant_expired`, `grant_exhausted`, `safety_write_forbidden`, `inference_forbidden`, `proposal_not_found`, `proposal_decided`, `value_rejected`, `capability_not_granted`, `advertising_ineligible`, `client_suspended` |
| None: no agent operation adds an entry in this version (A4.1, A7.1, A14), and the session, CSRF, re-authentication, sign-in and sign-up refusals answer only the person's own first-party requests (A15.3), so these refusals reach only the person's own operations, never an agent                                                                                                                   | `entry_limit_reached`, `session_required`, `csrf_invalid`, `reauthentication_required`, `sign_in_failed`, `signup_unavailable`                                                                                                                                                                                                                             |

These forms follow the MCP error handling for [tools](https://modelcontextprotocol.io/specification/2026-07-28/server/tools#error-handling), [resources](https://modelcontextprotocol.io/specification/2026-07-28/server/resources#error-handling) and [prompts](https://modelcontextprotocol.io/specification/2026-07-28/server/prompts#error-handling): a tool reports an input or business failure in its result so that the model can recover, a resource or prompt reports it as a JSON-RPC error, and a tool's structured content always matches its output schema.

Checks: TRANSPORT-01, CORE-01, SIGN-01, LOG-01.


---

# B4. REST binding

**Status:** normative. Binds the A8 recipient API to HTTP. Document version `1.0-draft-1`.

## B4.1 Contract and routes

The complete recipient contract is [OpenAPI 3.1](../openapi/autonym-v1.yaml), generated from the same schema definitions as MCP. The file uses JSON syntax, which is valid YAML. This is a draft contract, not a deployed endpoint. Public discovery is unauthenticated; every recipient action is authenticated and authorised.

Use HTTPS, exact `<origin>/v1` audience, and `Autonym-Version:1.0` on protocol responses. Every access token is DPoP-bound (A6.3): a request carries `Authorization:DPoP` plus the DPoP header, and a token presented as Bearer is refused. Reject repeated scalar query parameters, malformed values, unknown fields and unknown protocol versions with `invalid_request`. Comma-separated domain/key lists have no empty items or duplicates. Maximum body size is 64 KiB, including nested values; a larger body fails `payload_too_large`. A context response has at most 1,000 entries; reject an over-limit request without a partial unmarked disclosure.

| Method | Path                               | Result                                                      |
| ------ | ---------------------------------- | ----------------------------------------------------------- |
| GET    | `/.well-known/autonym`             | Provider discovery                                          |
| GET    | `/v1/grant`                        | Current authenticated grant                                 |
| GET    | `/v1/domains`                      | Eligible granted domains/keys, without counts               |
| GET    | `/v1/context`                      | Signed disclosure, one counted read                         |
| GET    | `/v1/context/{domain}`             | Same, with conditional-request support                      |
| POST   | `/v1/proposals`                    | Contribution event acknowledgement                          |
| GET    | `/v1/proposals/{id}`               | Own proposal status only                                    |
| POST   | `/v1/proposals/{id}/confirm`       | Exact-statement confirmation/review                         |
| DELETE | `/v1/proposals/{id}`               | Withdraw own proposal                                       |
| GET    | `/v1/purge-instructions`           | At most 100 outstanding signed instructions for this client |
| POST   | `/v1/purge-instructions/{jti}/ack` | Purge acknowledgement                                       |

The path ID and body ID must match wherever both occur. Mutating requests other than contribution events require a client-scoped UUIDv4 `Idempotency-Key`, canonical-payload equality, and 30-day deduplication. A reused key with a different payload fails `idempotency_conflict`.

## B4.2 Conditional reads

An ETag is a quoted opaque HMAC under a dedicated provider key of JCS containing the client, grant ID/revision, the A9 canonical request, sorted selected alias/version/level triples, temporal selection epoch and the previous envelope deadline. Store its association with that exact signed envelope and response hash. Never use a content-only ETag.

A matching `If-None-Match` may return `304` only while the prior envelope is still valid, its entire selection and authority still match, and the grant has not exhausted its read limit. This writes a `read_not_modified` event and counts towards rate limits but does not increment `reads_used`. It cannot extend a signed deadline. At or after any time boundary return a new counted signed response if permitted, or the relevant error. Revocation, counter checks and dependency checks cannot be bypassed through `304`. Responses use `Cache-Control:no-store`; this conditional facility is only for a recipient's explicitly held, still-valid transient object.

## B4.3 Errors and limits

[errors.json](../errors.json) is the closed registry, and [problem.json](../schemas/problem.json) is the exact RFC 9457 representation. Each registered code has one `urn:autonym:error:<code>` type, one status and one title, and names the sections whose text raises it; a response carries exactly that status. No rejected value, record content, credential or existence hint appears in an error. Authentication/token-endpoint errors retain their OAuth-defined representation, and a `401` also carries the A6.1 `WWW-Authenticate` challenge. The registry separately lists the OAuth codes this specification cites and the codes the B1 grant binding takes from its base specification (B1.9); they keep the representation their own specifications define and are not registered codes. `handle_moved` is deliberately removed; API migration does not redirect credentials or disclose a destination.

An unknown path answers `not_found`. An unexpected failure answers `internal_error`, and a provider that cannot reach its key storage or grant state answers `not_ready` (A15.3); neither says why.

The provider enforces at least per-client and per-grant rate limits and answers 429 `rate_limited` with `Retry-After`. Default ceiling is 60 authorised requests per minute per grant and 600 per minute per client; a provider may lower these published operational limits, but cannot silently increase consent limits.

Checks: TRANSPORT-01, WIRE-01, TEMP-03, CORE-01, LOG-01, PURGE-01, MIGRATE-01.


---

# Vocabulary registry

**Status:** normative. Document version `1.0-draft-1`.

[core.json](core.json) is generated from the schema package. It contains every admitted v1 key, its closed value schema, supported disclosure levels, renderer operations/examples and policy flags. This page explains the 30-key vocabulary 1.1 release boundary and its compatibility with the original 27 keys. Unknown and future candidate keys are rejected; there is no implicit free-text fallback.

The `viewing`, `reading` and `music` domains form the named group `media` (`groups.media` in [core.json](core.json)). The group is a label for documentation and the worked example; it adds no key, level or permission.

The normative [core vocabulary](core.json) version `1.1` contains 30 keys across 17 domains. Each key has a closed value schema, semantic kind, cardinality, supported levels, closed L0 category, safety/sensitivity/inference flags, advertising eligibility, label, explanation and example renderer output at every supported level.

| Domain        | Version 1 keys                                                       |
| ------------- | -------------------------------------------------------------------- |
| identity      | `display_name`, `age_band`, `pronouns`                               |
| contact       | `email`                                                              |
| household     | `pets`                                                               |
| dining        | `diet`, `allergy`, `drink_preference`, `fasting`, `cuisine_affinity` |
| health        | `medical_alert`                                                      |
| accessibility | `mobility_need`                                                      |
| travel        | `seat_preference`, `trip_context`                                    |
| viewing       | `genre_affinity`, `watched_history`                                  |
| reading       | `genres`                                                             |
| music         | `genres`                                                             |
| shopping      | `delivery_preference`                                                |
| home          | `temperature_preference`                                             |
| work          | `communication_style`                                                |
| finance       | `currency`                                                           |
| education     | `learning_style`                                                     |
| communication | `tone`, `preferred_language`, `spelling`                             |
| agent         | `verbosity`, `never_do`, `always_do`, `explanation_depth`            |

Renderer operations are closed: `category` emits only the L0 code; `identity` emits the already-validated value; `pick_first` emits only `first`; `approved_override_or_omit` emits the person's approved identifier-safe L1 rendering or omits the entry. L2 free text uses the same safe rendering. No generic redactor or language model supplies a substitute. Stored type describes the source; a rendered entry's type describes the actual rendering (for example `text` for L0 or an approved override).

Safety and special-category values cannot be inferred. Advertising is limited to person-confirmed `viewing.genre_affinity`, `reading.genres` and `music.genres`, with the additional A6.7 controls. The vocabulary's closed lists deliberately exclude broad free text from that lane.

All other keys from earlier proposals, including clinical coding, account/loyalty details and arbitrary extensions, remain candidates outside this release. Import must report unsupported values before committing. This is an explicit first-release boundary, not a permissive catch-all schema. No semantic compatibility with IPS, SNOMED, ISO 24751 or other domain standards is claimed without a separately reviewed mapping.

Checks: DISC-01, ADS-01, CONTRIB-01, PORT-01.

## Vocabulary 1.1 additions

`introduced_in` records the first vocabulary version containing each key. The original 27 keys remain version 1.0 keys with unchanged value and disclosure semantics. Vocabulary versions are independent of wire version 1.0 and document version 1.0-draft-1.

- `agent.always_do` is a single preference containing 1-1024 characters of explicitly confirmed instruction text. It is not inferable. L0 is `agent_context`; L1/L2 require the person's approved identifier-safe rendering; L3 is the saved text. It grants no permission and cannot override safety rules or consent. Conflicting positive and negative instructions require the person's resolution; positive wording is not higher authority.
- `agent.explanation_depth` has values `overview` (main point), `reasons` (main point and why) and `walkthrough` (explain the steps). It controls explanation depth/structure, while `agent.verbosity` controls length. It neither requests nor promises private model reasoning. L0 is `agent_context`; L1-L3 return the exact enum value.
- `communication.spelling` has values `en-GB` and `en-US` and applies only to English replies. It explicitly overrides an English language tag's spelling convention; it does not choose the reply language. Without it, the language tag and recipient's ordinary conventions apply. It does not rewrite quotations, proper names or code. L0 is `communication_context`; L1-L3 return the exact enum value.

All three are single-cardinality ordinary preferences, support L0-L3 and ordinary temporal overlays, and are not safety-critical, special-category or advertising-eligible. The two enums are inferable under the existing provenance rules; `always_do` is not. Free text can nevertheless contain sensitive details or identifiers. Absence creates no default stored preference. Freshness follows A4.3's 365-day confirmation rule.

A provider MUST NOT widen an existing grant merely because its vocabulary catalogue gains keys. It MUST retain the vocabulary version approved for that grant and the version supported by the recipient, and expose only their supported, authorised intersection. Missing version evidence means the original 1.0 key set. This restriction applies at every level, including L0, and to dependencies and temporal deadlines. Grant approval and recipient support for 1.1 must both be established before returning a new key. The reference library accepts these as trusted internal snapshot inputs; no new discovery or token field is implied. Runtime negotiation, consent persistence and cross-surface verification remain release gates.

Checks: VOCAB-1.1-01 to VOCAB-1.1-09, DISC-01, TEMP-01 to TEMP-03. Synthetic entries are included under `pilot_vocabulary` in [protocol examples](../examples/protocol.json).


---

# Implementation and conformance status

Document 1.0-draft-1 publishes complete contracts for its declared v1 scope. No recipient service or conformance certification is claimed.

| Layer                                                                                                                             | Status                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Operational health/readiness, scope parsing, prefixed IDs and app shell                                                           | Implemented and tested in the reference repository                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| Entry/grant/disclosure/contribution/receipt/purge/export/discovery schemas                                                        | Specified, generated and structurally tested                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| 30-key vocabulary 1.1 and closed rendering definitions                                                                            | Specified and generated; examples and selected pure policy checks tested                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| Temporal interval helper, supported-level selection and advertising grant structure                                               | Executable pure checks; not an authorised runtime compiler                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| Pure compiler: grant/request intersections, vocabulary renderers, overlay selection, dependency checks and temporal deadlines     | Implemented with pure example and property tests and browser evidence, using one injected Clock instant per read; transaction and endpoint integration pending                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| Full stored-grant authorisation and OAuth/DPoP server                                                                             | The authorisation contract is specified and generated: client registration metadata and metadata documents, access-token and lifecycle-token claims and the contribution authorisation detail, with `-SCHEMA` tests of the access-token and lifecycle-token lifetime bounds (OAUTH-01). The authorisation server, stored-grant authorisation and runtime evidence are pending                                                                                                                                                                                                                                                                                                                                                                                                                |
| Transactional reads, signed receipts and concurrency                                                                              | The reference provider signs receipts, chains them with log events per record partition and verifies a partition's chain over its stored rows and its exported form; `-CHAIN` tests against a real database cover appending under concurrency, tampering and signing-key rotation. Transactional reads, the owner's export and runtime evidence pending                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| Record storage: per-record encryption, immutable entry versions, deletion and crypto-shredding                                    | The reference provider stores each record's entries encrypted under the record's own data key, one immutable version per change, with tombstones that remove a deleted entry's value, overrides, evidence and client-supplied provenance (source, times, confidence, derivations), keeping its provenance kind and recording time until the record is erased, a per-partition entry limit, and crypto-shredding that destroys the record's wrapped key; its integration tests run against a real database, with real concurrency. No recipient or management route reads or writes it yet                                                                                                                                                                                                    |
| Pairwise handles and entry aliases                                                                                                | The reference provider derives each recipient's pairwise handle and entry aliases as A3.2 specifies, under a dedicated key per partition; `-STORE` tests against a real database reproduce the published framing vectors through its handle store and show distinct handles for 10,000 recipients of one partition, one handle per recipient until a rotation, a rotation that changes the handle and every alias at once, and collisions retried with a fresh rotation. No route or command issues, rotates or resolves a handle yet, and a provider whose configured authority is an IP address issues none. A recipient read showing that no canonical identifier escapes is pending, so PAIR-01 stays pending; invalidating grants and starting purge on rotation (A3.2) are pending too |
| Public REST/MCP, contribution/replay processing and purge outbox                                                                  | Pending implementation and runtime evidence                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| Detached-signature verification: strict JSON, ES256, thumbprint key IDs, issuer binding, key retirement and disclosure deadlines  | Implemented as a library verifier with SIGN-01 tests in Node and a browser; published [test vectors](vectors/README.md) verified by the reference verifier and independently by Python `jwcrypto` and `rfc8785`; purge instruction token rejection and runtime signing pending                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| Signing, encrypted export/import and delegation                                                                                   | Contract specified. Signing: `-SIGNER` tests check signed output against the reference verifier and the published test vectors; `-STORE` tests of the reference key store against a real database cover a provider's KEY-01 duties (integration evidence); signing in a running recipient surface pending. Encrypted export/import and delegation: cryptographic/interoperability tests and runtime pending                                                                                                                                                                                                                                                                                                                                                                                  |
| Role-specific conformance runner and certification                                                                                | Requirements published; no running endpoint suite or certificates                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| Jurisdiction assessment, rights/retention operations, transfer safeguards, opt-out and governance checks PRIVACY-01 to PRIVACY-06 | Requirements specified; deployment evidence and runtime enforcement pending                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| Registry, credentials, emergency cards, guardian/duress                                                                           | Reserved outside v1 conformance                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

The [conformance manifest](profiles.json) has stable IDs, expected behaviours, capability dependencies and explicit pending runtime evidence. Each check records `runtime_evidence` (`library` where executable library tests cover the requirement as stated; `integration` where the reference implementation's integration tests, which run its provider against real storage, cover every duty the requirement places on a provider that one provider's own tests can show, while any part that falls to a verifier keeps its library tests or published test vectors and any part one provider cannot show is named below; otherwise `pending`) and `pending_phase`, the build phase that supplies its runtime evidence, or, for a check with `integration` evidence, the phase whose integration tests supplied it. Integration evidence shows that the reference provider meets those duties; it is not a suite another implementation can run against its own service. Library and integration evidence both come from the reference repository's own tests: neither is evidence gathered from a running service, which no check has yet (below). A check that the published [test vectors](vectors/README.md) evidence also lists their files in `vectors`. The SCOPE, ID and VOCAB-1.1 families are listed in the manifest with their library evidence; they belong to no capability profile. WILDCARD-01 checks a recommendation (A15.1) and belongs to no capability profile either. The optional features `public-handles` (HANDLE-01), `encrypted-export` (ENCRYPT-01) and `pdpp-binding` (BINDING-01) apply only to a provider that offers them, as `advertising` does (A17.1). Test names in the reference repository follow the convention below. SCOPE-01 to SCOPE-10 and ID-01 to ID-05 remain syntax/identifier checks, not grant or recipient certification.

The reference repository names each library or integration test by the check it evidences, and a suffix on the check ID says what kind of evidence the test gives:

- `-SCHEMA`: a test of a schema or a pure helper that covers only part of the check's requirement.
- `-COMPILER`: an example test of the pure compiler at the library boundary.
- `-PROPERTY`: a property checked across many inputs, either by fast-check with a fixed seed and run count, so that a failure replays exactly, or by an exhaustive pass over every published vocabulary key.
- `-VERIFIER`: a test of the verifier's side of a check whose remaining duties belong to a running provider, as for KEY-01.
- `-SIGNER`: a test of the signing side of a check at the library boundary: what the reference signer writes verifies with the reference verifier and has the published test vectors' exact header and payload bytes for the same key and type. It is not runtime evidence: key custody, rotation and signing inside a provider's transactions are shown by `-STORE` tests or a running provider.
- `-STORE`: an integration test of one of the reference provider's stores, such as its signing key store or its pairwise handle store, run against a real database, with real concurrency where the requirement concerns it. When such tests cover every duty a check's requirement places on a provider that one provider's tests can show, the check records `integration` evidence.
- `-CHAIN`: a test of the reference provider's owner log, either without a database or against a real database: appending each event's exact bytes in order, and verifying a partition's chain over its stored rows and over its exported form. A further word names what the test shows, such as `-CHAIN-TAMPER` (edits to the stored chain are reported at the first divergence), `-CHAIN-CONCURRENCY`, `-CHAIN-VECTORS` (the published receipt chain is reproduced) or `-CHAIN-SCALE`, a timing guard on verification that, like `-BENCHMARK`, is not conformance evidence. It is not runtime evidence: LOG-01 and LOG-02 also require the disclosure transaction and the owner's export.
- `-BENCHMARK`: a timing guard on the compiler against a median budget. It is not conformance evidence.

A test with no suffix, such as those named SIGN-01 or SCOPE-01, is named by its check alone; the tests of the published test vectors, for example, carry the bare check ID. A test may name more than one check. A suffix describes a test, not a check: whether library or integration tests cover a check's requirement is recorded only by the check's `runtime_evidence`. Some repository tests carry IDs that are not in the manifest: those that check the shape of the generated contracts, examples and entry validation, and those for the reference server's operational surface, its application shell, the contracts of its internal ports and those of its record store that no check names, whose names can look like a check ID with a suffix, listed above or not. They are implementation tests, not conformance checks, and evidence no check. A record store test named by a check ID with the `-STORE` suffix is a `-STORE` test of that check.

Every sentence of the normative pages (`core/`, `bindings/` and the vocabulary page) that carries MUST, MUST NOT, SHOULD or SHOULD NOT, every requirement they state in the imperative, and every sentence that uses a lower-case must or should, has an entry in [statements.json](statements.json): the checks that test it, or the reason no suite can, such as an organisational obligation or a sentence that only restates another. The items of a list introduced by an imperative ending in a colon, such as the A5.4 rejection list, count as imperatives. Some requirements stated without a modal, such as the A5.4 key, key-set and instant rules, the A9 canonical request and the A10 acknowledgement bytes, also have hand-chosen entries of kind `declarative`. No such sentence needs one, so the audit does not show that every requirement without a modal is covered; but a declarative entry must still quote its sentence, and a sentence the audit extracts takes the extracted kind. `pnpm check:statements` fails when a sentence has no entry, an entry no longer matches the text, or an entry names a check that is not in the manifest or not cited by its page. Runtime checks are pending because no recipient endpoint exists; this is not an exception permitting weaker behaviour. A release must supply real authentication, storage, concurrency, cryptographic and cross-surface evidence, with failures reported as expected versus observed. No logo or badge substitutes for that evidence.

The [test vectors](vectors/README.md) are fixed bytes an implementation can check offline: synthetic keys, canonical JSON, a signed disclosure, a receipt chain across a key rotation, a purge instruction and acknowledgement, and the signed objects a verifier must reject. They evidence a verifier's side of SIGN-01, KEY-01, LOG-01, LOG-02 and PURGE-01: rejecting the failures A5.4 lists for the objects they cover, verifying a receipt signed before a rotation from the published key set alone, recomputing the receipt hash chain and checking an acknowledgement's signed bytes. They are not runtime evidence. KEY-01's verifier rejections have published vectors, but never reusing a key ID, never sharing a key with another provider, signing nothing at or after a key's `exp`, and keeping a retired key published with an unchanged `exp` are a provider's duties, shown by a running key store: the reference implementation shows them with `-STORE` tests of its key store against a real database, its `integration` evidence, which also covers a provider whose issuer changes: its earlier issuer's retired keys stay in the key set it publishes, with their `exp`. That evidence does not cover the rest of KEY-01's statements: a verifier's rejections, evidenced by the `-VERIFIER` tests and the vectors; a key set served at a discovery `jwks_uri`, and keys a recipient registers, which need a running service; and the keys of any other provider. One provider's tests cannot show that no other provider holds the same key. They show that its keys are generated by the provider itself from a cryptographically secure random source, are never imported, and differ between independent installations; the rest depends on every provider keeping its private keys to itself and on verifiers trusting only the key set configured for each issuer (A5.4).

VOCAB-1.1-01 to VOCAB-1.1-09 exercise the approved pilot additions, version metadata, explicit grant/recipient vocabulary intersection, text/enum validation, renderings, inference restrictions, grant isolation, temporal overlays and unavailable-key deadline isolation. Library checks do not establish runtime negotiation or stored consent evidence. The original 27 keys remain available under vocabulary 1.0; all 30 are tested under 1.1.


---

# Test vectors

**Status:** informative. Document version `1.0-draft-1`. Every file in this folder except this page is generated by the reference implementation, and its build fails if any differs from what the code produces. Do not edit them by hand.

These vectors let an implementation check, offline and without an Autonym account, that it canonicalises, signs and verifies the A5.4 signed objects exactly as the specification requires: disclosures (A5.3), receipts (A9), purge instructions and acknowledgements (A10).

**The keys are synthetic and published with their private parts.** They were generated for these vectors and the [media worked example](../../examples/media/README.md) only, belong to no provider or recipient, and must never be trusted anywhere else. Anyone can sign anything with them, so a signature they verify proves nothing outside these tests.

## Files

| File                                 | What it proves                                                                                                                                                                                                                                                                                                                        | Checks                                    |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| [`keys.json`](keys.json)             | Two provider keys, one retired with `exp`, and one recipient key, each with its private part. `key_sets` gives their public parts as the provider's and the recipient's key sets, the form [key-set.json](../../schemas/key-set.json) defines; the retired key stays in the set with its `exp`. Each `kid` is the RFC 7638 thumbprint | KEY-01                                    |
| [`jcs.json`](jcs.json)               | RFC 8785 canonical JSON: member names sorted by their 16-bit code units, characters outside ASCII, escapes, integers and the number form, each with the exact canonical text, its UTF-8 in hexadecimal and its SHA-256; and inputs strict parsing refuses, including numbers beyond what binary64 holds                               | SIGN-01                                   |
| [`disclosure.json`](disclosure.json) | Signed disclosures: one signed by the active provider key, one signed by the later-retired key before its `exp`, and the edge of the 60-second clock allowance                                                                                                                                                                        | SIGN-01, KEY-01                           |
| [`receipt.json`](receipt.json)       | A receipt hash chain across a key rotation, each receipt with its `provider`, the canonical request derived from the request as received, the hash of the disclosure it records and its hash input. Both verify a year later from the provider's published key set alone                                                              | SIGN-01, LOG-01, LOG-02, KEY-01           |
| [`purge.json`](purge.json)           | The purge instruction token, a compact JWT signed by the provider, and the recipient's signed acknowledgement over its canonical JSON                                                                                                                                                                                                 | SIGN-01, PURGE-01                         |
| [`negative.json`](negative.json)     | Signed objects a verifier must reject, each breaking one A5.4 rule: tampering, duplicate members, numbers and strings that are not I-JSON, `alg:none` and HS256, unknown and ambiguous key IDs, `crit` and other header members, wrong `typ`, unusable keys, retired keys, expiry, time bounds, issuer binding and receipt hashes     | SIGN-01, KEY-01, LOG-01, LOG-02, PURGE-01 |

## Using a vector

A detached-signature vector gives `typ`, the exact received `text` (the object with its `proof`), and `verify`: the key set (a name from `key_sets` in `keys.json`, or an inline key set when the vector needs one that [key-set.json](../../schemas/key-set.json) refuses), the trusted issuer and the verifier's clock reading `now`. Verify `text` as A5.4 describes and compare the outcome with `expected`: either `valid: true` with the `kid` and the signed time, or `valid: false` with a `reason`.

A positive vector also shows each step: the object without `proof` (`unsigned`), its canonical text (`jcs`) and that text's SHA-256, the `protected_header` and the detached `jws`. A receipt vector adds its hash input and chain link, its request as received with its canonical form, and the disclosure whose hash it records.

The purge instruction token is stored as its three parts in the RFC 7515 flattened JSON form; a recipient receives `protected.payload.signature`. Verify it at its `iat` with the provider's key set: the header has exactly `alg`, `kid` and `typ:autonym-purge+jwt`, and the payload is `claims`.

The reasons in `negative.json` and `jcs.json` are labels for the rule each vector breaks. An implementation need not use them; it must reject every negative vector.

| Reason                                             | A5.4 rule                                                                                                                                            |
| -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `duplicate_member`, `not_i_json`, `malformed_json` | Parse strictly before canonicalisation: repeated member names, in the object or its protected header; text that is not I-JSON; text that is not JSON |
| `malformed_proof`                                  | The `proof` member and the detached JWS: unpadded base64url in its one canonical spelling                                                            |
| `critical_header`, `header`                        | No protected header member other than `alg`, `kid` and `typ`; `crit` named separately                                                                |
| `algorithm`                                        | Only ES256                                                                                                                                           |
| `type`                                             | `typ` compared exactly                                                                                                                               |
| `header_mismatch`                                  | Proof metadata agrees with the protected header                                                                                                      |
| `unknown_key`, `key_id`                            | Exactly one trusted key has the header's `kid`, and the `kid` is its key's thumbprint                                                                |
| `key`                                              | The matching key follows key-set.json: no private member, no `key_ops`, no lifetime member other than `exp`, canonical spellings                     |
| `signature`                                        | The ES256 signature over the canonical bytes; RFC 7518 section 3.4 makes it exactly 64 bytes                                                         |
| `retired`                                          | The signed time is before the key's `exp`                                                                                                            |
| `issuer`                                           | The object's `provider` is the trusted issuer                                                                                                        |
| `hash`                                             | A receipt's `hash` is the A9 hash of its content                                                                                                     |
| `time_bounds`, `not_yet_valid`, `expired`          | A disclosure's deadline, issue time and expiry                                                                                                       |

A verifier may also refuse a member named `__proto__`; no vector depends on whether it does.

## What is not covered

The vectors cover canonical JSON and the signed objects listed above. They do not cover the signed export (A11.1), whose receipts are represented here only by the carried receipt in `negative.json`, the optional encrypted export (A11.2), purge-token rejections, or anything a provider must do at run time, such as checking current grant authority.

## Stability

The files change only deliberately. Regenerating them reproduces the same bytes: the keys are kept, and because ES256 signatures are randomised, each signature is kept while it still verifies over its object, so only a change to a signed object signs it afresh. The reference implementation's tests pin each file's SHA-256, so a vector changes only by a deliberate edit. An implementation identifies the bytes it tested against by their digests in the edition [manifest](../../manifest.json), and any change to a vector is recorded in the change history.

The reference implementation verifies every vector with its own verifier and, independently, with Python's `jwcrypto` and `rfc8785` packages, reading only these files.


---

# Standards adoption register

**Status:** normative where cited. Document version `1.0-draft-1`. Generated from the records in this folder by `pnpm spec:adoption`; do not edit by hand.

Every external standard the specification uses has one adoption record here, with the same headings: version pinned, what is taken, why, what is extended, what is replaced or not used, deviations, and the conformance checks that prove the integration. The specification cites the record wherever it uses the standard. An adopted standard is pinned; a later version is taken only through a change entry with a migration note.

| Standard | Version pinned | Status | What Open Personal Context takes | Why | What it extends or replaces | Specification home |
| --- | --- | --- | --- | --- | --- | --- |
| [W3C AI Agent Memory Interoperability CG and draft-saihm](agent-memory-interop.md) | Community Group charter 1.0 (adopted 19 June 2026); draft-saihm-memory-protocol-01 (27 May 2026) | Track and align shapes | Nothing normative; receipt and erasure message shapes are compared for alignment | Avoids gratuitous divergence from emerging agent-memory work | Open Personal Context receipts are per read, not per memory write | A9, A10 notes |
| [W3C Data Privacy Vocabulary (DPV)](dpv.md) | DPV 2.3 (25 February 2026) | Adopt terms | Purpose and provenance classes | Interoperable purpose names rather than invented ones | Maps Open Personal Context purposes to DPV terms; adds the advertising constraints | A4.2, A6.2 |
| [Human Context Protocol](hcp.md) | Position paper SSRN 5403981 (project page dated 18 December 2025); no protocol version or file format published | Map, do not adopt | Nothing yet; a mapping from user-held preferences into the declared lane is planned | Lets people who keep preferences in an HCP server bring them into a record as declared entries | Replaces language-model-mediated disclosure with deterministic, person-approved renderings | A11 import mapping (planned) |
| [IAB Tech Lab Data Deletion Request Framework](iab-data-subject-rights.md) | Version 2.0 (August 2026) | Adopt the request and acknowledgement shape | Signed deletion request and acknowledgement concepts | A published shape for purge semantics that recipients may already handle | Binds the request and acknowledgement to the grant and receipt identifiers | A10 |
| [ISO/IEC 24751 (AccessForAll)](iso-24751.md) | ISO/IEC 24751-2:2008 (with parts 1 and 3:2008 and part 4:2023) | Adopt the vocabulary for the accessibility domain (catalogue entry only) | Accessibility preference terms, pending a licensed text | Avoids inventing accessibility keys | Maps to vocabulary keys | Vocabulary registry |
| [ISO/IEC TS 27560 consent record information structure](iso-27560.md) | ISO/IEC TS 27560:2023, edition 1 (8 August 2023) | Adopt the record structure (catalogue entry only) | Consent receipt fields, pending a licensed text | Lets a grant be exported as a recognised consent record | Adds disclosure level and rendering version | A6.3, A9, A11 |
| [JWS (RFC 7515), JCS (RFC 8785), JWK (RFC 7517), JWK thumbprints (RFC 7638), JWA (RFC 7518), I-JSON (RFC 7493), JWK exp (OpenID Federation 1.0)](jose.md) | RFC 7515, RFC 7517 and RFC 7518 (May 2015); RFC 7493 (March 2015); RFC 7638 (September 2015); RFC 8785 (June 2020); RFC 9864 (October 2025); OpenID Federation 1.0, Final (17 February 2026), JWK exp only | Adopt | Signing receipts, disclosures, purge instructions, purge acknowledgements and exports over canonical JSON, with ES256 and published keys named by their thumbprints and retired with exp | Standard signatures with maintained libraries; no bespoke cryptography | Defines the receipt, disclosure, purge and export object shapes and their protected typ values, the provider key set and one spelling for instants | A5.3, A5.4, A9, A10, A11, A15.2 |
| [JSON Schema 2020-12, OpenAPI 3.1, RFC 9457 Problem Details](json-schema-openapi-problem-details.md) | JSON Schema 2020-12 (16 June 2022); OpenAPI 3.1.0 (15 February 2021); RFC 9457 (July 2023) | Adopt | Wire shapes, API description and the error format | The generated artefacts and their drift checks depend on them | Adds the closed registry of urn:autonym:error:* types | A8, B4, generated contracts |
| [JWE (RFC 7516) and Argon2id (RFC 9106)](jwe-argon2id.md) | RFC 7516 (May 2015); RFC 9106 (September 2021) | Adopt | Passphrase-encrypted export | Standard envelope encryption for the portable export, with a maintained memory-hard key derivation | None | A11.2 |
| [W3C Linked Web Storage / Solid](linked-web-storage.md) | Linked Web Storage Protocol 1.0, Working Draft of 21 September 2026; Solid Protocol 0.11.0 (12 May 2024) | Optional storage binding, 2.0 stream | Resource addressing and access grants as an alternative store | Lets a person keep the record in a pod they already have | Binding only; the native store remains the default | Binding B2 (post 1.0) |
| [Model Context Protocol](mcp.md) | Specification revision 2026-07-28 (current revision on 4 October 2026) | Adopt as the agent binding | Tools, resources, prompts, server discovery, the stateless Streamable HTTP transport and the MCP authorisation flow | The surface assistants actually use | Defines the Open Personal Context tool set, confirmation semantics and briefing resources; no generic record access | A7, B3 |
| [OAuth 2.1, PKCE, RFC 9396 rich authorisation requests, DPoP (RFC 9449)](oauth.md) | draft-ietf-oauth-v2-1-16 (3 September 2026) with RFC 6749, 6750, 7009, 7523, 7591, 7636, 7662, 8252, 8414, 8693, 8707, 9068, 9101, 9126, 9207, 9396, 9449, 9700 and 9728, OpenID Connect Core 1.0 section 9 and draft-ietf-oauth-client-id-metadata-document-02 | Adopt as the authorisation primitives of A6, B1, B3 and B4 | Client registration and lifecycle, PKCE flows, pushed authorisation requests, resource indicators, sender-constrained tokens, structured authorisation details, protected-resource and server metadata, issuer identification, revocation, token exchange and JWT access tokens | Mature, library-supported primitives that recipients already speak | Profiles the authorization_details type for domain and level, the contribution request and the grant-offer exchange; makes PKCE S256 and DPoP mandatory for every client and every access token; nothing replaced | A6, B1 |
| [PDPP Core (PDP-Connect, LF Decentralized Trust)](pdpp.md) | PDPP Core v0.1.0 at commit 8f79a48 (2026-09-23) | Adopt as the normative 1.0 grant binding (B1); implement in the Autonym server | Grants with purpose, selection, expiry and revocation; sources and records; the query surface; introspection; the Core section 9 conformance requirements, tested by Autonym's own checks until PDPP publishes its suite | A neutral, foundation-hosted grant protocol with a planned conformance programme; building on it is cheaper than defending a bespoke one and opens the Verified Operator route | Adds disclosure levels and renderings as statically declared derived streams; adds per-read receipts, purge acknowledgement and typed context, which Core leaves out; makes DPoP and PKCE mandatory where Core leaves them out or advisory | B1 |
| [SD-JWT VC, OpenID4VC, SMART Health Links, International Patient Summary](reserved-credentials.md) | RFC 9901; draft-ietf-oauth-sd-jwt-vc-19; OpenID4VP 1.0; OpenID4VCI 1.0; SMART Health Cards and Links IG 1.0.0; IPS IG 2.0.1 | Reserved | Nothing in 1.0; credential presentations and an emergency card in 2.0 | Needed only by capabilities reserved for 2.0 | Nothing in 1.0 | Reserved chapters (A12, A13) |
| [SCITT architecture and COSE Receipts](scitt.md) | RFC 9943 and RFC 9942 (June 2026) | Evaluate; adopt if the receipt format can be expressed as a SCITT receipt | Under evaluation - transparency receipts and the append-only log shape | Aligns the accountability log with a published transparency standard | Possible replacement of the bespoke chain format; not yet decided | A9, this record decides |


---

---
name: agent-memory-interop
title: W3C AI Agent Memory Interoperability CG and draft-saihm
status: Track and align shapes
version: Community Group charter 1.0 (adopted 19 June 2026); draft-saihm-memory-protocol-01 (27 May 2026)
source: https://www.w3.org/community/ai-agent-memory-interop/
takes: Nothing normative; receipt and erasure message shapes are compared for alignment
why: Avoids gratuitous divergence from emerging agent-memory work
extends: Open Personal Context receipts are per read, not per memory write
spec_home: A9, A10 notes
---

# AI agent memory interoperability

## Version pinned

- The W3C [AI Agent Memory Interoperability Community Group](https://www.w3.org/community/ai-agent-memory-interop/) (`ai-agent-memory-interop`), launched 3 June 2026, charter 1.0 adopted 19 June 2026. It has published no report or draft. A Community Group is not on the W3C standards track.
- [draft-saihm-memory-protocol-01](https://datatracker.ietf.org/doc/draft-saihm-memory-protocol/), "The Sovereign AI Horizontal Memory (SAIHM) Protocol", 27 May 2026, an individual Internet-Draft intended as Informational, with no IETF standing. The group's charter treats it as a normative reference.

## What is taken

Nothing normative. When receipt (A9) and erasure (A10) shapes are next revised, they are compared with these to avoid needless divergence.

## Why

Open Personal Context tracks this work as prior art for receipts and erasure.

## What is extended

Open Personal Context receipts record each disclosure to a recipient, not each memory write. Purge acknowledgements are recorded assertions, never proof of erasure (A10).

## What is replaced or not used

The draft's post-quantum identity binding, public-chain audit anchoring and encrypted memory cells are not used.

## Deviations

The group's post of 29 July 2026 and the IETF datatracker disagree on the draft's status (concluded independent-submission consideration, as against "In ISE Review"). This record cites the datatracker.

## Conformance checks

None. LOG-01 and PURGE-01 cover the Open Personal Context receipt and purge shapes.


---

---
name: dpv
title: W3C Data Privacy Vocabulary (DPV)
status: Adopt terms
version: DPV 2.3 (25 February 2026)
source: https://w3id.org/dpv/
takes: Purpose and provenance classes
why: Interoperable purpose names rather than invented ones
extends: Maps Open Personal Context purposes to DPV terms; adds the advertising constraints
spec_home: A4.2, A6.2
---

# Data Privacy Vocabulary

## Version pinned

[Data Privacy Vocabulary (DPV) version 2.3](https://w3id.org/dpv/), 25 February 2026, a Final Community Group Report of the W3C Data Privacy Vocabularies and Controls Community Group, read through w3id.org on 4 October 2026. A Community Group report is not a W3C Recommendation.

## What is taken

- Purpose terms: `dpv:Purpose`, `dpv:hasPurpose` and categories such as `ServiceProvision`, `Personalisation` and `TargetedAdvertising`.
- Provenance terms: `DataSource`, `hasDataSource`, and `Provided`, `Collected`, `Observed`, `Derived` and `Inferred`.

The mapping from the ten Open Personal Context purpose categories (A6.2) and the provenance kinds (A4.2) to these terms is written when grants carry purposes on the wire.

## Why

Purpose and provenance names that other privacy tooling already understands make grants and receipts easier to audit and to export as consent records.

## What is extended

Advertising is a separate, explicitly consented purpose with the A6.7 restrictions, which DPV's `TargetedAdvertising` does not itself impose.

## What is replaced or not used

PDPP's example purpose URIs under `pdpp.dev` are not used as the purpose vocabulary (see the [PDPP record](pdpp.md), at commit `8f79a48`).

## Deviations

DPV's dated "This version" link returned 404 on 4 October 2026; this record pins the w3id.org address with the version number.

## Conformance checks

CONSENT-01 and SCOPE-02 in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending.


---

---
name: hcp
title: Human Context Protocol
status: Map, do not adopt
version: Position paper SSRN 5403981 (project page dated 18 December 2025); no protocol version or file format published
source: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5403981
takes: Nothing yet; a mapping from user-held preferences into the declared lane is planned
why: Lets people who keep preferences in an HCP server bring them into a record as declared entries
extends: Replaces language-model-mediated disclosure with deterministic, person-approved renderings
spec_home: A11 import mapping (planned)
---

# Human Context Protocol

## Version pinned

"Robust AI Personalization Controls: The Human Context Protocol", [SSRN 5403981](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=5403981), from the Loyal Agents project of the Stanford Digital Economy Lab with the Consumer Reports Innovation Lab; the [project page](https://digitaleconomy.stanford.edu/project/loyal-agents/hcp-human-context-protocol/) is dated 18 December 2025. It is a research proposal with a prototype (`github.com/tobinsouth/hcp-demo`, no release). There is no versioned specification to pin, so this record pins the paper.

## What is taken

Nothing in version 1. An importer is planned that maps a person's HCP preferences into proposals for declared entries, each confirmed by the person (A4.2), with the mapping table published here.

## Why

HCP describes a user-owned preference layer exposed to agents through three server tools (schema definition, preference search and preference update). People who already keep preferences there should be able to bring them into a record without retyping them.

## What is extended

Open Personal Context discloses through deterministic compiled renderings at a granted level (A5), rather than letting a model decide what to reveal from natural-language preferences.

## What is replaced or not used

HCP's language-model-mediated disclosure is not used.

## Deviations

HCP publishes no file format: the paper stores preferences "primarily in natural language", and the project site mentions JSON, Markdown, vector databases or personal data pods. The planned importer therefore needs a concrete export to map before it can be specified. The work is joint between the Stanford Digital Economy Lab and the Consumer Reports Innovation Lab.

## Conformance checks

None in version 1. PORT-01 will cover the importer once it is specified.


---

---
name: iab-data-subject-rights
title: IAB Tech Lab Data Deletion Request Framework
status: Adopt the request and acknowledgement shape
version: Version 2.0 (August 2026)
source: https://github.com/InteractiveAdvertisingBureau/Data-Subject-Rights/blob/main/Data%20Deletion%20Request%20Framework.md
takes: Signed deletion request and acknowledgement concepts
why: A published shape for purge semantics that recipients may already handle
extends: Binds the request and acknowledgement to the grant and receipt identifiers
spec_home: A10
---

# IAB Tech Lab Data Deletion Request Framework

## Version pinned

IAB Tech Lab [Data Deletion Request Framework](https://github.com/InteractiveAdvertisingBureau/Data-Subject-Rights/blob/main/Data%20Deletion%20Request%20Framework.md) version 2.0, August 2026 (version 1.0 was May 2024), read from the file in the `Data-Subject-Rights` repository on 4 October 2026. The repository's commit could not be recorded, because GitHub API access was denied in this session; the version and date come from the file's own history. The framework's name is the Data Deletion Request Framework; "Data Subject Rights" is the repository name.

## What is taken

The concepts, not the wire format: a deletion request signed by the party that holds the authority, forwarded to each recipient, and an acknowledgement signed by the recipient carrying a result. The framework uses signed JSON Web Tokens for the request and the acknowledgement and publishes verification keys at well-known locations.

## Why

Purge reuses established deletion-request concepts rather than defining its own. Recipients in advertising may already implement this framework.

## What is extended

A10 binds each purge instruction to the grant that ended and the pairwise subject, uses the reason `grant_ended` for both revocation and expiry, and records the acknowledgement as `purged`, `not_held` or `legal_hold`. An acknowledgement is the recipient's assertion, never proof of erasure.

## What is replaced or not used

The framework's hop-by-hop forwarding and its `/.well-known/iabtl/` key locations are not used; Open Personal Context delivers instructions directly to each recipient and verifies keys against the recipient's registration (A10).

## Deviations

The framework is sometimes described as a "Data Subject Rights framework"; this record uses its own name.

## Conformance checks

PURGE-01 and ADS-02 in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending.


---

---
name: iso-24751
title: ISO/IEC 24751 (AccessForAll)
status: Adopt the vocabulary for the accessibility domain (catalogue entry only)
version: ISO/IEC 24751-2:2008 (with parts 1 and 3:2008 and part 4:2023)
source: https://www.iso.org/standard/43603.html
takes: Accessibility preference terms, pending a licensed text
why: Avoids inventing accessibility keys
extends: Maps to vocabulary keys
spec_home: Vocabulary registry
---

# ISO/IEC 24751

## Version pinned

The ISO/IEC 24751 series, Individualized adaptability and accessibility in e-learning, education and training, from JTC 1/SC 36, read from ISO's open data feed on 4 October 2026 (the catalogue pages refused automated reads):

- ISO/IEC 24751-1:2008, Framework and reference model, [catalogue 41521](https://www.iso.org/standard/41521.html).
- **ISO/IEC 24751-2:2008, "Access for all" personal needs and preferences for digital delivery**, [catalogue 43603](https://www.iso.org/standard/43603.html), the part relevant to accessibility preferences.
- ISO/IEC 24751-3:2008, "Access for all" digital resource description, [catalogue 43604](https://www.iso.org/standard/43604.html).
- ISO/IEC 24751-4:2023, "Access for all" framework for individualized accessibility and registry server API, [catalogue 82901](https://www.iso.org/standard/82901.html).

## What is taken

No licensed copy of the standard was available to the editors; the field-level mapping from the accessibility vocabulary keys to part 2's preference terms is pending a licensed text, and this record cites the catalogue entry only.

## Why

Accessibility preferences are among the most sensitive and useful context a person can share; reusing an established information model avoids inventing terms.

## What is extended

When the mapping is written, each mapped term becomes a vocabulary key with its disclosure levels and renderings (see the [vocabulary registry](../vocabulary/README.md)).

## What is replaced or not used

Parts 1, 3 and 4 are recorded for context; only part 2's preference terms are candidates for mapping.

## Deviations

The vocabulary registry already states that no semantic compatibility with ISO 24751 is claimed without a separately reviewed mapping. The mapping is pending a licensed text.

## Conformance checks

None until the mapping exists; the VOCAB checks will cover any key it adds.


---

---
name: iso-27560
title: ISO/IEC TS 27560 consent record information structure
status: Adopt the record structure (catalogue entry only)
version: ISO/IEC TS 27560:2023, edition 1 (8 August 2023)
source: https://www.iso.org/standard/80392.html
takes: Consent receipt fields, pending a licensed text
why: Lets a grant be exported as a recognised consent record
extends: Adds disclosure level and rendering version
spec_home: A6.3, A9, A11
---

# ISO/IEC TS 27560

## Version pinned

ISO/IEC TS 27560:2023, Privacy technologies - Consent record information structure, edition 1, 8 August 2023, from JTC 1/SC 27, [catalogue entry 80392](https://www.iso.org/standard/80392.html). It is a Technical Specification, not an International Standard. The catalogue marks it "to be revised"; a replacement draft, ISO/IEC CD 27560.2, "Structure of Personally Identifiable Information (PII) Processing Records", is in progress. Catalogue data were read from ISO's open data feed on 4 October 2026, because the catalogue page refused automated reads.

## What is taken

No licensed copy of the standard was available to the editors; the field-level mapping from grants and receipts to the consent record structure is pending a licensed text, and this record cites the catalogue entry only. A9 already says the draft claims no certified mapping to this standard.

## Why

Exporting a grant as a recognised consent record lets a person or an auditor read it with other consent tooling, through the portable export (A11).

## What is extended

When the mapping is written, the disclosure level and the rendering version are expected to be extensions, since they are Open Personal Context concepts.

## What is replaced or not used

Nothing yet.

## Deviations

The field-level mapping is pending a licensed text. The W3C DPV group's guide "Consent Records and Receipts as per ISO/IEC TS 27560:2023 using DPV" (15 February 2026) is a possible public route to the field list, but it is not the standard's text.

## Conformance checks

PORT-01 in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending until the mapping exists.


---

---
name: jose
title: JWS (RFC 7515), JCS (RFC 8785), JWK (RFC 7517), JWK thumbprints (RFC 7638), JWA (RFC 7518), I-JSON (RFC 7493), JWK exp (OpenID Federation 1.0)
status: Adopt
version: RFC 7515, RFC 7517 and RFC 7518 (May 2015); RFC 7493 (March 2015); RFC 7638 (September 2015); RFC 8785 (June 2020); RFC 9864 (October 2025); OpenID Federation 1.0, Final (17 February 2026), JWK exp only
source: https://www.rfc-editor.org/rfc/rfc7515
takes: Signing receipts, disclosures, purge instructions, purge acknowledgements and exports over canonical JSON, with ES256 and published keys named by their thumbprints and retired with exp
why: Standard signatures with maintained libraries; no bespoke cryptography
extends: Defines the receipt, disclosure, purge and export object shapes and their protected typ values, the provider key set and one spelling for instants
spec_home: A5.3, A5.4, A9, A10, A11, A15.2
---

# JOSE signatures and canonical JSON

## Version pinned

- [RFC 7515](https://www.rfc-editor.org/rfc/rfc7515), JSON Web Signature, May 2015, Proposed Standard.
- [RFC 7517](https://www.rfc-editor.org/rfc/rfc7517), JSON Web Key, May 2015, Proposed Standard.
- [RFC 7518](https://www.rfc-editor.org/rfc/rfc7518), JSON Web Algorithms, May 2015, Proposed Standard, updated by [RFC 9864](https://www.rfc-editor.org/rfc/rfc9864) (October 2025, Proposed Standard).
- [RFC 7638](https://www.rfc-editor.org/rfc/rfc7638), JSON Web Key (JWK) Thumbprint, September 2015, Proposed Standard.
- [RFC 7493](https://www.rfc-editor.org/rfc/rfc7493), The I-JSON Message Format, March 2015, Proposed Standard.
- [RFC 8785](https://www.rfc-editor.org/rfc/rfc8785), JSON Canonicalization Scheme, June 2020, Informational.
- [OpenID Federation 1.0](https://openid.net/specs/openid-federation-1_0.html), 17 February 2026, Final: only the JWK parameter `exp` that its section 8.7.2 registers in the IANA JSON Web Key Parameters registry.

## What is taken

- Detached compact JWS (RFC 7515 Appendix F) over UTF-8 RFC 8785 canonical JSON of the object without `proof`, with ES256 and a `kid` resolved only against the issuer's trusted key set (A5.4).
- JWK sets for publishing verification keys (A3.3, A5.4, A11.1).
- RFC 7638 SHA-256 thumbprints as key IDs, so a key ID names one key (A5.4, A9), as OpenID Federation 1.0 also recommends for its keys.
- The registered JWK parameter `exp`, in whole seconds since the epoch, as a published key's retirement time: what the key signed before it still verifies, and anything dated at or after it is rejected (A5.4, A9).
- I-JSON: signed text with a lone surrogate, a noncharacter, a number with more magnitude or precision than binary64 provides, or a repeated member name is rejected before canonicalisation (A5.4).
- RFC 8785 canonicalisation for handle and alias derivation input (A3.2), response hashes (A9) and statement hashes (A7.2).

## Why

Signed, canonical objects let a recipient or the person verify what was disclosed offline with standard libraries. AGENTS.md rule 9 forbids hand-rolled cryptography or canonicalisation.

## What is extended

The signed object shapes and their protected `typ` values are Open Personal Context's: `autonym-disclosure+jws`, `autonym-receipt+jws`, `autonym-purge+jwt`, `autonym-purge-ack+jws` and `autonym-export+jws`. One spelling is fixed for instants in signed objects (A5.4).

## What is replaced or not used

Unencoded-payload mode, `alg:none`, critical headers, any protected header member other than `alg`, `kid` and `typ`, and key URLs or keys supplied by the object or its header are rejected (A5.4). Only ES256 is accepted. Of the key lifetime parameters OpenID Federation 1.0 registers, only `exp` is used; a key carrying `nbf`, `iat` or `revoked` is not used to verify, and OpenID Federation's historical keys endpoint and signed JWK set are not used: retired keys stay in the ordinary key set.

## Deviations

RFC 8785 is Informational, not standards track; it is adopted because it is the maintained canonicalisation scheme JOSE libraries implement. RFC 9864 updates RFC 7518 with fully specified algorithm identifiers and changes nothing for ES256: it names the JOSE `ES256` as already fully specified (P-256 with SHA-256), defines new fully specified identifiers only for COSE ECDSA and for EdDSA, and deprecates only the polymorphic JOSE `EdDSA`. Its recommendation that a JWK carry `alg`, so that a key is used with one algorithm, is why each published key carries `alg:ES256`.

## Conformance checks

SIGN-01, LOG-01, LOG-02, KEY-01 and, for the signed purge instruction and acknowledgement, PURGE-01 in the [conformance manifest](../conformance/profiles.json). SIGN-01 has library evidence from the reference verifier's tests. The published [test vectors](../conformance/vectors/README.md) give the RFC 8785 canonical bytes, the detached JWS of each signed object with its keys, and the failures A5.4 rejects; the reference implementation checks them with its own verifier and independently with Python `jwcrypto` and `rfc8785`. KEY-01 has integration evidence from the reference implementation's key store, tested against a real database. Runtime evidence for the others is pending.


---

---
name: json-schema-openapi-problem-details
title: JSON Schema 2020-12, OpenAPI 3.1, RFC 9457 Problem Details
status: Adopt
version: JSON Schema 2020-12 (16 June 2022); OpenAPI 3.1.0 (15 February 2021); RFC 9457 (July 2023)
source: https://json-schema.org/draft/2020-12/json-schema-core
takes: Wire shapes, API description and the error format
why: The generated artefacts and their drift checks depend on them
extends: Adds the closed registry of urn:autonym:error:* types
spec_home: A8, B4, generated contracts
---

# JSON Schema, OpenAPI and Problem Details

## Version pinned

- **JSON Schema draft 2020-12:** [Core](https://json-schema.org/draft/2020-12/json-schema-core) (draft-bhutton-json-schema-01) and [Validation](https://json-schema.org/draft/2020-12/json-schema-validation) (draft-bhutton-json-schema-validation-01), published by json-schema.org on 16 June 2022 in Internet-Draft format, with the meta-schema `https://json-schema.org/draft/2020-12/schema`. It is a final json-schema.org release; it was never adopted by the IETF.
- **OpenAPI 3.1.0:** [OpenAPI Specification v3.1.0](https://spec.openapis.org/oas/v3.1.0.html), 15 February 2021, which the generated `openapi/autonym-v1.yaml` declares.
- **Problem Details:** [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457), July 2023, Proposed Standard.

## What is taken

- Every schema in `spec/schemas/` and every embedded schema in the OpenAPI document and MCP tool definitions is JSON Schema 2020-12, generated from `packages/schema` with Zod.
- The recipient REST contract is an OpenAPI 3.1.0 document in JSON syntax, which is valid YAML (B4.1).
- Errors are RFC 9457 `application/problem+json` objects ([`problem.json`](../schemas/problem.json)), with OAuth errors keeping their OAuth representation (B4.3).

## Why

Generated artefacts and the drift check (`pnpm check:generated`) make the schemas the single source of truth; widely supported formats let implementers generate clients and validators instead of reading prose.

## What is extended

- A closed error registry, [`errors.json`](../errors.json), of `urn:autonym:error:<code>` types, each naming the sections that raise it. No unregistered code may be returned. The registry also lists the OAuth codes the text cites and the codes the B1 grant binding takes from its base specification, which keep their own representation (B4.3).
- Problem objects carry no rejected value, record content, credential or existence hint (B4.3).

## What is replaced or not used

Nothing is replaced. OpenAPI 3.2 is not used.

## Deviations

OpenAPI 3.1.2 (19 September 2025) is the latest 3.1 patch release. Patch releases clarify the text but do not change the 3.1 feature set; the generated document stays at `3.1.0` until a change entry moves it.

## Conformance checks

TRANSPORT-01 in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending; structural conformance is proven today by `pnpm check:generated`.


---

---
name: jwe-argon2id
title: JWE (RFC 7516) and Argon2id (RFC 9106)
status: Adopt
version: RFC 7516 (May 2015); RFC 9106 (September 2021)
source: https://www.rfc-editor.org/rfc/rfc7516
takes: Passphrase-encrypted export
why: Standard envelope encryption for the portable export, with a maintained memory-hard key derivation
extends: None
spec_home: A11.2
---

# JWE and Argon2id

## Version pinned

- [RFC 7516](https://www.rfc-editor.org/rfc/rfc7516), JSON Web Encryption, May 2015, Proposed Standard.
- [RFC 9106](https://www.rfc-editor.org/rfc/rfc9106), Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications, September 2021, Informational (IRTF CFRG).

## What is taken

The optional encrypted export (A11.2): compact JWE with `alg:dir` and `enc:A256GCM`, and a 32-byte key derived with Argon2id version 19, memory 65,536 KiB, three iterations, four lanes and a fresh 16-byte salt, carried in the authenticated critical header `autonym_kdf`.

## Why

A person moving a record needs it encrypted at rest with a passphrase, using primitives with maintained implementations.

## What is extended

Nothing beyond the `autonym_kdf` critical header, which carries the single permitted parameter set. Argon2id is not a JOSE `alg`.

## What is replaced or not used

No other key-management algorithm or KDF is accepted.

## Deviations

None.

## Conformance checks

PORT-01, and ENCRYPT-01 for the optional `encrypted-export` feature, in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending.


---

---
name: linked-web-storage
title: W3C Linked Web Storage / Solid
status: Optional storage binding, 2.0 stream
version: Linked Web Storage Protocol 1.0, Working Draft of 21 September 2026; Solid Protocol 0.11.0 (12 May 2024)
source: https://www.w3.org/TR/2026/WD-lws10-core-20260921/
takes: Resource addressing and access grants as an alternative store
why: Lets a person keep the record in a pod they already have
extends: Binding only; the native store remains the default
spec_home: Binding B2 (post 1.0)
---

# Linked Web Storage and Solid

## Version pinned

- [Linked Web Storage Protocol 1.0](https://www.w3.org/TR/2026/WD-lws10-core-20260921/) (`lws10-core`), W3C Working Draft of 21 September 2026, on the Recommendation track. The draft also describes itself as "an unofficial proposal".
- [Solid Protocol version 0.11.0](https://solidproject.org/TR/2024/protocol-20240512), 12 May 2024, a draft Community Group report of the Solid Community Group, not on the W3C standards track.

## What is taken

Nothing in 1.0. B2 is informative in 1.0 and is to be drafted after it. The protocol defines authentication, authorisation with access grants ("a data object created by a storage controller, expressing an ability for an agent to perform specific actions on Storage Resources within certain defined constraints"), a storage description resource, containers and resource operations.

## Why

Linked Web Storage and Solid are an optional storage binding: a person who already keeps data in a pod should be able to keep the record there.

## What is extended

B2 will map Open Personal Context grants, which carry disclosure levels, renderings and receipts, onto access grants, and say what cannot be represented.

## What is replaced or not used

The native provider store is the default; nothing in 1.0 depends on a pod.

## Deviations

None.

## Conformance checks

None in 1.0.


---

---
name: mcp
title: Model Context Protocol
status: Adopt as the agent binding
version: Specification revision 2026-07-28 (current revision on 4 October 2026)
source: https://modelcontextprotocol.io/specification/2026-07-28
takes: Tools, resources, prompts, server discovery, the stateless Streamable HTTP transport and the MCP authorisation flow
why: The surface assistants actually use
extends: Defines the Open Personal Context tool set, confirmation semantics and briefing resources; no generic record access
spec_home: A7, B3
---

# Model Context Protocol

## Version pinned

[MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28), read on 4 October 2026. Its versioning page names it the current protocol version. A current revision can still receive backwards-compatible changes; a later revision is taken only through a change entry.

## What is taken

- The stateless model of this revision: no initialise handshake and no `Mcp-Session-Id`; protocol version and capabilities in `_meta`; `server/discover` (B3.1).
- Streamable HTTP with the `Mcp-Method` and `Mcp-Name` headers validated against the body (B3.1).
- Tools with input and output schemas, resources and prompts, and the revision's list-cache fields (B3.2, B3.3).
- Tool execution errors and JSON-RPC error responses as the revision defines them, carrying the registered Problem Details object (B3.4).
- The MCP authorisation flow over OAuth: protected-resource metadata and Client ID Metadata Documents for unknown clients (A6.1; see the [OAuth record](oauth.md)).

## Why

Assistants reach external context through MCP. Binding the A7 agent surface to it lets an assistant connect to a record without bespoke integration.

## What is extended

A fixed, public tool set (`get_grant`, `list_domains`, `get_context`, `propose_entry`, `confirm_entry`, `withdraw_proposal`), the `autonym://context/{domain}` resource and the `autonym_briefing` prompt, all returning the A5 signed disclosure; exact-statement confirmation through the first-party app (A7.2). There is no generic record access.

## What is replaced or not used

Roots, Sampling and Logging are not adopted. Legacy protocol revisions are not supported unless separately declared and tested (B3.1).

## Deviations

- Revision 2026-07-28 deprecates Dynamic Client Registration in favour of Client ID Metadata Documents. A6.1 keeps Client ID Metadata Documents as the primary mechanism and RFC 7591 registration available to any client, MCP clients included, for compatibility.
- The revision's authorisation section cites OAuth 2.1 draft revision 13 and Client ID Metadata Document draft revision 00; the [OAuth record](oauth.md) pins revisions 16 and 02. Both pairs were compared. From revision 13 to 16, OAuth 2.1 removes PKCE `plain`, has the authorisation server send `iss` in every authorisation response, mentions pushed authorisation requests in its authorisation endpoint section, adds guidance on JWT client authentication and on consent phishing, gathers its value sizes into one section and clarifies its error responses and repeated parameters; A6.3 already requires S256 only and `iss`, so a client that follows revision 13 and meets A6 is unaffected. From revision 00 to 02, the Client ID Metadata Document draft lists the client identifier URL's rules (https, a path, no user information, fragment or dot segments), compares it as a simple string without port normalisation, forbids shared-secret authentication and private key material in the document, recommends client authentication more strongly, limits the loopback exception to its SSRF rules to development and testing, and adds privacy considerations. A6.1 takes revision 02; a revision 00 document that follows those rules is accepted.
- Revision 2026-07-28 has an MCP client send its access token as `Authorization: Bearer` and does not list RFC 9449. Open Personal Context binds every access token to a DPoP key and accepts none as Bearer (A6.3), so an MCP client that cannot send a DPoP proof cannot obtain or use a token. The protected-resource metadata of `<origin>/mcp` says so with `dpop_bound_access_tokens_required` (A6.1).

## Conformance checks

TRANSPORT-01, CORE-01, SIGN-01 and LOG-01 in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending.


---

---
name: oauth
title: OAuth 2.1, PKCE, RFC 9396 rich authorisation requests, DPoP (RFC 9449)
status: Adopt as the authorisation primitives of A6, B1, B3 and B4
version: draft-ietf-oauth-v2-1-16 (3 September 2026) with RFC 6749, 6750, 7009, 7523, 7591, 7636, 7662, 8252, 8414, 8693, 8707, 9068, 9101, 9126, 9207, 9396, 9449, 9700 and 9728, OpenID Connect Core 1.0 section 9 and draft-ietf-oauth-client-id-metadata-document-02
source: https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/16/
takes: Client registration and lifecycle, PKCE flows, pushed authorisation requests, resource indicators, sender-constrained tokens, structured authorisation details, protected-resource and server metadata, issuer identification, revocation, token exchange and JWT access tokens
why: Mature, library-supported primitives that recipients already speak
extends: Profiles the authorization_details type for domain and level, the contribution request and the grant-offer exchange; makes PKCE S256 and DPoP mandatory for every client and every access token; nothing replaced
spec_home: A6, B1
---

# OAuth 2.1 and its profiles

## Version pinned

| Standard                                 | Version                                                                                                                                           | Status                                                |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| OAuth 2.1                                | [draft-ietf-oauth-v2-1-16](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/16/), 3 September 2026                                          | Internet-Draft, IETF OAuth working group; not an RFC  |
| OAuth 2.0                                | [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749), October 2012                                                                                  | Proposed Standard, updated by RFC 8252, 8996 and 9700 |
| Bearer token usage                       | [RFC 6750](https://www.rfc-editor.org/rfc/rfc6750), October 2012                                                                                  | Proposed Standard                                     |
| PKCE                                     | [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636), September 2015                                                                                | Proposed Standard                                     |
| Rich Authorization Requests              | [RFC 9396](https://www.rfc-editor.org/rfc/rfc9396), May 2023                                                                                      | Proposed Standard                                     |
| DPoP                                     | [RFC 9449](https://www.rfc-editor.org/rfc/rfc9449), September 2023                                                                                | Proposed Standard                                     |
| Protected Resource Metadata              | [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728), April 2025                                                                                    | Proposed Standard                                     |
| Authorization Server Metadata            | [RFC 8414](https://www.rfc-editor.org/rfc/rfc8414), June 2018                                                                                     | Proposed Standard                                     |
| Dynamic Client Registration              | [RFC 7591](https://www.rfc-editor.org/rfc/rfc7591), July 2015                                                                                     | Proposed Standard                                     |
| JWT client authentication                | [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523), May 2015                                                                                      | Proposed Standard                                     |
| `private_key_jwt`                        | [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) incorporating errata set 2, 15 December 2023, section 9          | OpenID Foundation Final Specification                 |
| Issuer identification                    | [RFC 9207](https://www.rfc-editor.org/rfc/rfc9207), March 2022                                                                                    | Proposed Standard                                     |
| Resource indicators                      | [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707), February 2020                                                                                 | Proposed Standard                                     |
| Pushed authorisation requests            | [RFC 9126](https://www.rfc-editor.org/rfc/rfc9126), September 2021                                                                                | Proposed Standard                                     |
| JWT-secured authorisation requests       | [RFC 9101](https://www.rfc-editor.org/rfc/rfc9101), August 2021                                                                                   | Proposed Standard                                     |
| Token revocation                         | [RFC 7009](https://www.rfc-editor.org/rfc/rfc7009), August 2013                                                                                   | Proposed Standard                                     |
| Token introspection                      | [RFC 7662](https://www.rfc-editor.org/rfc/rfc7662), October 2015                                                                                  | Proposed Standard                                     |
| Token exchange                           | [RFC 8693](https://www.rfc-editor.org/rfc/rfc8693), January 2020                                                                                  | Proposed Standard                                     |
| JWT access tokens                        | [RFC 9068](https://www.rfc-editor.org/rfc/rfc9068), October 2021                                                                                  | Proposed Standard                                     |
| Native apps                              | [RFC 8252](https://www.rfc-editor.org/rfc/rfc8252), October 2017                                                                                  | Best Current Practice                                 |
| OAuth 2.0 security best current practice | [RFC 9700](https://www.rfc-editor.org/rfc/rfc9700), January 2025                                                                                  | Best Current Practice (BCP 240)                       |
| Client ID Metadata Document              | [draft-ietf-oauth-client-id-metadata-document-02](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/02/), 6 July 2026 | Internet-Draft, IETF OAuth working group; not an RFC  |

Versions and statuses were read from the RFC Editor's metadata and the IETF datatracker on 4 October 2026; the texts of RFC 7523, RFC 9700, OpenID Connect Core 1.0 and both Internet-Drafts, with the earlier revisions the [MCP record](mcp.md) compares, were read from those sources on 8 October 2026. The two Internet-Drafts are moving targets; a later revision is taken only through a change entry.

## What is taken

- Authorisation code with PKCE S256 only, exact redirect matching with the RFC 8252 loopback exception, single-use codes and rotating refresh tokens, with a reused code or refresh token ending the grant, as RFC 9700 sections 4.2.4 and 4.14 recommend (A6.3).
- RFC 9728 protected-resource metadata, one path-specific document for each protected resource, RFC 8414 server metadata with RFC 9728's `protected_resources`, and the RFC 9207 `iss` parameter (A6.1).
- Client ID Metadata Documents as the primary registration for unknown clients, static registration for first-party clients and RFC 7591 for any client, with client metadata limited to the members A6.1 lists (A6.1).
- `private_key_jwt` client authentication, which OpenID Connect Core 1.0 section 9 defines on RFC 7523 section 2.2, with the client's inline ES256 keys (A6.1).
- RFC 8707 `resource` to name the one audience of a grant, and RFC 9126 pushed authorisation requests, with RFC 9101's `invalid_request_uri` for a pushed request that cannot be used (A6.2, A6.3, B1.9).
- RFC 9396 `authorization_details` as the envelope for structured requests, which is also PDPP Core v0.1.0's envelope (see the [PDPP record](pdpp.md), pinned at commit `8f79a48`), and for the contribution request (A6.2).
- RFC 9449 DPoP for every access token, RFC 9068 for access token claims, RFC 7009 for refresh-token revocation and RFC 8693 token exchange for delegated grant offers (A6.3 to A6.5).
- RFC 6750's `invalid_token` error code for a refused token, not its Bearer scheme (A6.3).
- RFC 7662's response shape for the introspection result a provider projects for the PDPP binding (B1.6); no public introspection endpoint is required.
- The error codes these documents define, kept in their own error form on OAuth endpoints and listed in the [error registry](../errors.json).

## Why

These are the primitives recipients and assistants already implement, with maintained libraries, so Open Personal Context profiles them rather than defining its own authorisation protocol.

## What is extended

- The `authorization_details` content is profiled for domains and disclosure levels through the PDPP binding ([B1](../bindings/B1-pdpp.md)), and for contribution grants by the type `urn:autonym:authorization-details:contribute` (A6.2).
- RFC 7591 client metadata gains `autonym_purge_uri`, where purge instructions are delivered (A6.1).
- The access token gains `autonym_grant_id` and `autonym_purpose` (A6.3).
- The grant-offer exchange in A6.4 uses RFC 8693 with an Open Personal Context token type, `urn:autonym:params:oauth:token-type:grant-offer`. A6.4 states that this is an Open Personal Context choice, not something RFC 8693 defines.
- The client lifecycle token in A6.6 is an Open Personal Context profile of the client credentials grant.
- A grant offer's recipient is a confidential client that authenticates with `private_key_jwt`, so holding an offer is never enough to redeem it (A6.1, A6.4).
- RFC 7009 asks a public client for no credential at the revocation endpoint. A public client's refresh token is bound to its DPoP key (RFC 9449 section 5), so its revocation also carries a DPoP proof by that key, and a refresh token bound to another key is not revoked (A6.5).

## What is replaced or not used

- The implicit grant and the resource owner password grant are not used; OAuth 2.1 removes them.
- PKCE `plain` is rejected (A6.3).
- Bearer tokens are neither issued nor accepted for any client: every access token is DPoP-bound (A6.3).
- Client secrets, `client_secret_basic`, `client_secret_post` and `client_secret_jwt` are not used; a confidential client authenticates with `private_key_jwt` (A6.1).
- `jwks_uri`, `sector_identifier_uri` and software statements are not accepted in client metadata (A6.1).
- OpenID Connect's `application_type` client metadata member is not accepted: whether the RFC 8252 loopback-port exception applies is decided from the client's redirect URIs, and only a client whose redirect URIs are all `http` loopback URIs uses it (A6.1, A6.3).
- A public RFC 7662 introspection endpoint is not required: a provider's resource servers introspect locally (B1.6).
- OpenID Connect sign-in is not used: no ID token, `openid` scope or userinfo endpoint. A provider's authorisation-server metadata may still carry OpenID Connect's `subject_types_supported`; it describes the provider's own internal subject identifier, never the pairwise handle every access token carries as `sub` (A3.2, A6.3).

## Deviations

- OAuth 2.1 is still an Internet-Draft. Open Personal Context cites revision 16 and the RFCs it consolidates, and does not claim conformance to an unpublished RFC.
- RFC 9068 section 2.1 requires an authorisation server to support RS256 for access tokens. Open Personal Context signs and accepts access tokens with ES256 only (A6.3), as the [JOSE record](jose.md) does for signed objects; no client has to verify one.
- RFC 7591 section 2 has an authorisation server ignore client metadata it does not understand. Open Personal Context refuses a registration or a metadata document with any member A6.1 does not list, so a client is never registered with part of what it asked for silently dropped. It also refuses a software statement, which RFC 7591 lets a server ignore, because a provider trusts no statement issuer.
- RFC 7591 section 2 defaults `token_endpoint_auth_method` to `client_secret_basic`. Open Personal Context accepts no client secret, so registration metadata always states the method.
- Mandatory DPoP departs from the Bearer usage MCP specifies for its clients; see the [MCP record](mcp.md).

## Conformance checks

CORE-01, CONSENT-01, OAUTH-01, FETCH-01, DELEGATE-01, TRANSPORT-01 and the SCOPE family in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending.


---

---
name: pdpp
title: PDPP Core (PDP-Connect, LF Decentralized Trust)
status: Adopt as the normative 1.0 grant binding (B1); implement in the Autonym server
version: PDPP Core v0.1.0 at commit 8f79a48 (2026-09-23)
source: https://github.com/PDP-Connect/pdpp/blob/8f79a48d7fe94a6b2aab15aac78d409b9ea13712/spec-core.md
takes: Grants with purpose, selection, expiry and revocation; sources and records; the query surface; introspection; the Core section 9 conformance requirements, tested by Autonym's own checks until PDPP publishes its suite
why: A neutral, foundation-hosted grant protocol with a planned conformance programme; building on it is cheaper than defending a bespoke one and opens the Verified Operator route
extends: Adds disclosure levels and renderings as statically declared derived streams; adds per-read receipts, purge acknowledgement and typed context, which Core leaves out; makes DPoP and PKCE mandatory where Core leaves them out or advisory
spec_home: B1
---

# PDPP Core

**Status:** normative where cited. Document version `1.0-draft-1`.

## Version pinned

PDPP Core v0.1.0, `spec-core.md` in [PDP-Connect/pdpp](https://github.com/PDP-Connect/pdpp/tree/8f79a48d7fe94a6b2aab15aac78d409b9ea13712) at commit `8f79a48d7fe94a6b2aab15aac78d409b9ea13712` (committed 23 September 2026; main on 4 October 2026). The document's header reads "Personal Data Portability Protocol (PDPP) v0.1.0", status "Normative draft", dated 3 September 2026. Its SHA-256 and size, and those of the other PDPP files cited here, are recorded in [`pdpp.lock.json`](pdpp.lock.json).

Also read at the same commit, and cited only for the facts stated below: `spec-collection-profile.md` (status "Informative. Builder guidance for connector collection. Not a conformance requirement."), `GOVERNANCE.md` (status "Consultation draft") and `README.md`. The reference implementation is no longer in this repository: the README at commit `8f79a48` says it lives in [PDP-Connect/data-connect](https://github.com/PDP-Connect/data-connect) under `reference-implementation/`, read at data-connect commit `832c7985b2338b3cd0a10da9546e517eac439d75`.

Licences, from the repository at commit `8f79a48`: code Apache-2.0 (`LICENSE`), specification text Community Specification License 1.0 (`LICENSE-specs`; the `REUSE.toml` override uses `LicenseRef-CSL-1.0`), documentation CC BY 4.0 (`LICENSE-docs`).

`pnpm check:pdpp-pin` fails if a file in `spec/adoption/` or `spec/bindings/` cites PDPP without this commit, links another PDPP commit or states another PDPP Core version. A weekly workflow runs `pnpm check:pdpp-pin --upstream`, which fails if the pinned text no longer matches the lock and flags any cited file whose text on upstream main has changed.

## What is taken

- **Grants** (PDPP Core v0.1.0 section 7): the immutable grant artefact and its fields `version`, `grant_id`, `issued_at`, `subject`, `client`, `source`, `source_declaration`, `purpose_code`, `purpose_description`, `access_mode`, `streams` (StreamGrant: `name`, `instance_ids`, `fields`, `time_constraint`, `resources`), `selection_preset`, `retention` and `expires_at`. Lifecycle (active, expired, revoked) is tracked by the authorisation server, not stored in the grant.
- **Selection requests** (section 6), carried in an RFC 9396 `authorization_details` envelope of type `https://pdpp.dev/data-access`, with purposes as absolute URIs.
- **Sources, records and the query surface** (sections 4, 5 and 8), including source declarations and their streams.
- **Introspection** (section 8): `active`, `pdpp_token_kind`, `subject_id`, `grant_id`, `client_id`, `exp` and `authorization_details`, with the rule that the response contains everything needed to enforce the request.
- **Errors** (section 8): the error object on the PDPP endpoints, with PDPP's codes where PDPP defines one, such as `not_found`, `invalid_request`, `grant_revoked`, `grant_expired` and `blob_not_found` (B1.9). The [error registry](../errors.json) lists these codes without registering them.
- **Token kinds** (section 10): owner and client tokens, distinguished by `pdpp_token_kind`; section 8 lets companion profiles add kinds and requires unknown kinds to be treated as unauthorised.
- **Conformance requirements** (section 9): the numbered requirements for the Authorization Server and Resource Server roles. Section 9 says a formal conformance test suite "is planned but is not defined in v0.1", and `GOVERNANCE.md` section 5.7 says it is published by 1 January 2027 and that Verified Operator opens on its publication. Until then Autonym builds its own checks from the section 9 requirements.

## Why

PDPP is a neutral grant model hosted under LF Decentralized Trust, with a published governance process and a planned conformance programme. Building the grant layer to its contract is cheaper than defending a bespoke grant protocol, lets recipients that already speak PDPP read Open Personal Context records, and opens the Verified Operator route when it exists. PDPP is the first authorisation binding, and the Autonym reference server implements it natively.

## What is extended

PDPP Core section 11 leaves interoperable audit and transparency events to "a separate companion profile", and section 10 says revocation is not deletion. Open Personal Context adds, through [B1](../bindings/B1-pdpp.md):

- disclosure levels and approved renderings, expressed as statically declared derived streams. PDPP Core mentions derived streams only in non-normative text (section 12), so this mapping is Open Personal Context's, not PDPP's;
- per-read signed receipts and the owner's log (A9);
- purge instructions and acknowledgement (A10);
- typed context with provenance, validity and temporal selection (A4);
- pairwise subject handles (A3), which PDPP does not define: its `subject.id` is an opaque string;
- mandatory PKCE and DPoP (A6.3). PDPP is "a profile of OAuth 2.0", mentions PKCE only in passing and describes DPoP as non-normative advice and a candidate hardening profile for a later version.

## What is replaced or not used

- The Collection Profile and connector runtime are not used: they are informative in PDPP, and continuous connectors are reserved for Open Personal Context 2.0.
- PDPP's six example purpose URIs under `pdpp.dev` are not adopted as the purpose vocabulary. B1 uses `urn:autonym:purpose:<category>` for the ten Open Personal Context purposes, annotated with W3C Data Privacy Vocabulary terms (see the [DPV record](dpv.md)).
- PDPP owner tokens are not issued, so owner-authenticated delete and self-export are not offered through PDPP ([B1](../bindings/B1-pdpp.md), B1-D8).
- Bearer client tokens are not accepted for any client: every token is DPoP-bound (A6.3, B1-D4).

## Deviations

At commit `8f79a48` there is no conformance suite yet, DPoP is non-normative advice rather than an optional feature, and the reference implementation lives in PDP-Connect/data-connect rather than in the PDPP repository. This record states those verified facts.

The places where the binding departs from a strict reading of PDPP Core v0.1.0 are listed as B1-D1 to B1-D8 in [B1.11](../bindings/B1-pdpp.md#b111-deviations-from-pdpp-core). None widens what a PDPP grant authorises.

## Conformance checks

CONSENT-01, CORE-01, DELEGATE-01 and BINDING-01 in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending as the manifest records. BINDING-01, the check of the optional `pdpp-binding` feature, tests the binding's own choices: the generated source declaration, static streams and the owner endpoints of B1-D8. Autonym's PDPP Core checks will cite PDPP Core v0.1.0 section 9 by role and item number, never by invented identifiers, and are replaced by PDPP's suite when it is published.


---

---
name: reserved-credentials
title: SD-JWT VC, OpenID4VC, SMART Health Links, International Patient Summary
status: Reserved
version: RFC 9901; draft-ietf-oauth-sd-jwt-vc-19; OpenID4VP 1.0; OpenID4VCI 1.0; SMART Health Cards and Links IG 1.0.0; IPS IG 2.0.1
source: https://www.rfc-editor.org/rfc/rfc9901
takes: Nothing in 1.0; credential presentations and an emergency card in 2.0
why: Needed only by capabilities reserved for 2.0
extends: Nothing in 1.0
spec_home: Reserved chapters (A12, A13)
---

# Reserved credential and health standards

## Version pinned

These are recorded for the 2.0 capabilities they would serve. No version 1 requirement depends on them.

| Standard                                  | Version                                                                                                              | Status                                   |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| SD-JWT                                    | [RFC 9901](https://www.rfc-editor.org/rfc/rfc9901), November 2025                                                    | Proposed Standard                        |
| SD-JWT VC                                 | [draft-ietf-oauth-sd-jwt-vc-19](https://datatracker.ietf.org/doc/draft-ietf-oauth-sd-jwt-vc/), 31 August 2026        | Internet-Draft with the IESG; not an RFC |
| OpenID for Verifiable Presentations       | [1.0](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html), 9 July 2025                              | Final                                    |
| OpenID for Verifiable Credential Issuance | [1.0](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html), 16 September 2025                  | Final                                    |
| SMART Health Links                        | HL7 [SMART Health Cards and Links IG 1.0.0](https://hl7.org/fhir/uv/smart-health-cards-and-links/STU1), 22 July 2025 | Standard for trial use                   |
| International Patient Summary             | HL7 FHIR [IPS IG 2.0.1](https://hl7.org/fhir/uv/ips/2.0.1), 19 June 2026                                             | Standard for trial use                   |
| ISO 27269                                 | Not verified: the ISO catalogue could not be read on 4 October 2026                                                  | Not verified                             |

## What is taken

Nothing in 1.0.

## Why

Verifiable credential presentations and an emergency card are reserved for 2.0. Recording the current versions now keeps the reserved placeholders honest about what they would build on.

## What is extended

Nothing in 1.0.

## What is replaced or not used

A5.4 reserves SD-JWT presentations; A13's placeholder states that the draft invents no SMART Health Link or IPS wire format and claims no compliance with them.

## Deviations

The ISO 27269 edition is unverified; it is to be read from the ISO catalogue before any 2.0 work cites it.

## Conformance checks

None in 1.0. CLAIM-01 prevents an implementation from claiming these capabilities in version 1.


---

---
name: scitt
title: SCITT architecture and COSE Receipts
status: Evaluate; adopt if the receipt format can be expressed as a SCITT receipt
version: RFC 9943 and RFC 9942 (June 2026)
source: https://www.rfc-editor.org/rfc/rfc9943
takes: Under evaluation - transparency receipts and the append-only log shape
why: Aligns the accountability log with a published transparency standard
extends: Possible replacement of the bespoke chain format; not yet decided
spec_home: A9, this record decides
---

# SCITT

## Version pinned

- [RFC 9943](https://www.rfc-editor.org/rfc/rfc9943), An Architecture for Trustworthy and Transparent Digital Supply Chains, June 2026, Proposed Standard (from draft-ietf-scitt-architecture-22).
- [RFC 9942](https://www.rfc-editor.org/rfc/rfc9942), CBOR Object Signing and Encryption (COSE) Receipts, June 2026, Proposed Standard (from draft-ietf-cose-merkle-tree-proofs-18).

## What is taken

Nothing yet. RFC 9943 registers single-issuer signed statements with a Transparency Service that keeps an append-only verifiable data structure and returns a receipt proving registration. RFC 9942 defines those receipts as signed CBOR inclusion and consistency proofs. An evaluation will decide whether the A9 per-read receipt and the owner's hash-chained log can be expressed this way.

## Why

SCITT-compatible receipt or transparency mechanisms are evaluated before a proprietary format is fixed, so the accountability log can align with a published transparency standard. The decision is due before a provider issues receipts from its read path. The reference implementation's stored chain keeps each event's exact signed bytes and refers to an event by its partition, position and hash, so either outcome can be added without rewriting them.

## What is extended

Not yet decided.

## What is replaced or not used

Until that decision, A9 keeps its JWS-signed, hash-chained receipts (see the [JOSE record](jose.md)).

## Deviations

Both SCITT documents were published as RFCs in June 2026, and this record cites the RFCs rather than the earlier Internet-Drafts.

## Conformance checks

LOG-01 in the [conformance manifest](../conformance/profiles.json), with runtime evidence pending.


---

# Media worked example

**Status:** informative. Document version `1.0-draft-1`. Every file in this folder except this page is generated by `packages/schema/src/examples/media.ts` through `pnpm --filter @autonym/schema generate`, and `pnpm check:generated` fails if any differs. Do not edit them by hand.

All data here is synthetic. The person, the recipient and the identifiers are invented for this example, and the keys are the synthetic keys published with the [test vectors](../../conformance/vectors/README.md).

## The story

A person keeps a few media preferences in their record: viewing genres, two programmes they watched, reading genres and music genres. They also keep how they like an assistant to talk to them: brief answers, an informal tone, British English ([`person.json`](person.json)).

A recommendation service, `https://recommender.example/client`, asks for permission to suggest something to watch, read or listen to this evening. The person is shown three versions of the same request and approves each, so the example can compare them. They differ only in the disclosure level (A5.1):

| Grant                              | Level | What the service receives                                                                                                                               |
| ---------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`grants/l0.json`](grants/l0.json) | L0    | Only the category of each key, for example `viewing_context`. It learns which kinds of preference exist, nothing more ([rendering](renderings/l0.json)) |
| [`grants/l1.json`](grants/l1.json) | L1    | The genres, tone, language and verbosity themselves, which carry no identifier. Viewing history stays at its category ([rendering](renderings/l1.json)) |
| [`grants/l2.json`](grants/l2.json) | L2    | The same as L1 for these keys, and the right to keep what it reads until the grant ends ([rendering](renderings/l2.json))                               |

Two things the example shows:

- **The vocabulary decides what a level means for each key.** The genre lists are identifier-free, so the vocabulary renders them in full from L1 upwards. Viewing history supports only L0 and L3 in the vocabulary, so even the L2 grant receives `viewing_context` for both programmes. The compiler picks the highest level the key supports at or below the grant's ceiling (A5.2).
- **The compiler is the only renderer.** Each rendering is the output of the A5 compiler over `person.json` and the grant, signed as A5.4 describes. The test recompiles it and compares byte for byte.

All three grants are for the `recommendation` purpose (A6.2). None of them is for advertising, so the advertising rules of A6.7 are not exercised.

## Receipts

Each read appends a receipt to the person's log ([L0](receipts/l0.json), [L1](receipts/l1.json), [L2](receipts/l2.json)) before the response is returned (A9). A receipt names the provider, the grant, the client, the purpose and the read ID, and lists the internal entry references and levels returned. Those references are visible to the person only; the recipient sees the client-bound `rent_` aliases in the rendering. `request` is the A9 canonical request: the domains sorted, with `declared_only` and `min_confidence` written out although the request omitted them. `response_hash` is the SHA-256 of the canonical rendering without its proof. The three receipts form one hash chain: each later one points at the previous receipt's `hash`. They are an excerpt of the person's log. A real log also holds the non-read events of A9 in the same chain, such as `grant_created` before the first read and `grant_revoked`, `purge_issued` and `purge_acknowledged` after it, so its first receipt would not have a null `prev_hash`.

## Purge

Only the L2 grant may keep what it reads. The grant files show each grant as issued, before the reads and before this revocation. When the person ends the L2 grant, the provider issues a signed purge instruction (A10): [`purge/instruction.json`](purge/instruction.json) holds the claims, and [`purge/instruction-token.json`](purge/instruction-token.json) holds the signed token. A recipient receives it as a compact JWT, `protected.payload.signature`; the file stores the same three parts in the RFC 7515 flattened JSON form, because the repository's secret scanner rejects any committed compact JWT and allowlisting is not this example's decision. The recipient deletes its copy and returns a signed acknowledgement before the deadline ([`purge/ack.json`](purge/ack.json)). The acknowledgement proves only that the recipient signed an attestation that it purged; it does not prove that every copy has gone (A10). As A10 requires, the acknowledgement signature covers the canonical JSON of the acknowledgement without `proof`, by the A5.4 detached method.

## Keys and signatures

The example is signed with the synthetic keys published with the test vectors in [`keys.json`](../../conformance/vectors/keys.json), private parts included, so anyone can check or reproduce the signatures. The active provider key signs the renderings, the receipts and the purge instruction; the recipient key signs the acknowledgement. The provider's key set in that file also holds a key that retired before these reads, so it signs nothing here. Each key's `kid` is the RFC 7638 thumbprint of its public key, as A5.4 requires. The keys belong to no real provider or recipient and must never be trusted outside the vectors and this example.

ES256 signatures are randomised. The generator therefore keeps an existing signature while it still verifies over the regenerated content, and signs afresh only when the content changes.

## Identifiers

The pairwise handle, the `rent_` aliases and the other identifiers have the right shape but are not derived. The A3.2 derivation is shown by the vectors in [`identity-framing.json`](../identity-framing.json).

## Checks

`packages/schema/test/media-example.test.ts` checks that:

- every file validates against its schema;
- recompiling gives the same renderings, and their signatures verify;
- every rendering, receipt and the acknowledgement verifies from its published text with the reference verifier, as A5.4 describes, against the provider's and the recipient's key sets in `keys.json`;
- the example is signed with the published test-vector keys and holds no key of its own;
- L0 discloses no identifier for any programme title or genre list (a property test);
- receipts name the provider and reference the grants and the returned entries, and the hash chain and signatures verify;
- the purge acknowledgement matches its instruction.


---

# Changes from the recovered proposal

The first draft imported A1-A17, terminology and both appendices from the recovered proposal. Recovered originals remain unchanged in the source inventory. The import was reproducible, rejected an unexpected source hash and applied only the corrections listed here, plus Markdown formatting and explicit implementation-status notes.

- The reference implementation introduced an explicitly bounded operational HTTP surface in `operations.md`, operational errors in `errors.json` and generated health, readiness and problem schemas. These are not a replacement for the proposal's A8 recipient error registry.
- The reference implementation's server takes its key from a local key file of exactly 32 bytes, readable only by its own user, or, in tests only, from a key held in one process's memory. It reports ready only when that key provider and its database both work and its signing keys exist, and it refuses to start in production; accepting a local key file in production will require an explicit acknowledgement of local key custody. This is stricter than an always-ready development placeholder; it avoids suggesting that a process can protect real records before its keys are under deliberate custody.
- `migrate` applies the reference implementation's database migrations as a dedicated role and creates its job queues, and `serve` and `work` refuse a database role with any attribute beyond login, a membership of any role, the right to create in the database or any schema or to make temporary tables, ownership of any object, a grant outside the service's own schemas, a parameter privilege or settings of its own; the grants inside the service's own schemas are the ones its migrations make, and are not read at start. `work` runs the job runner, whose job payloads carry identifiers only; no job is defined yet. `ctl` offers help, the creation of a new key file, the listing and rotation of the provider's signing keys, and the verification of a partition's owner log, which reads its events and the signing keys, decrypts no record, and records an `operator_action` in each log it read. None of these gives an operator any access to records.
- Where the reference implementation is hosted does not change the recipient wire protocol.

## Scope grammar implementation clarifications

The scope grammar implementation covers [A6.3 parsing](../core/scopes.md) independently of the remaining entry schemas. Duplicate reads with the same declaration mode collapse to their highest level as required by the backlog. Mixed declaration modes for one domain are rejected until their semantics are resolved. Bounds, exact space separators, case handling, duplicate-purpose rejection and safe validation errors are documented and checked as SCOPE-01 to SCOPE-09. The generated token schema is explicitly insufficient for whole-grant validation. No recipient endpoint, OAuth mapping or complete SDK is added.

## Normative import corrections

The [identifier subset](../core/identifiers.md) adds the prefixes required by the service design and explicitly requires canonical upper-case ULID bodies with valid 128-bit bounds. It does not change public/pairwise handles or invent the remaining entry shapes. Generation requires a positive explicit timestamp because the pinned library treats zero as ambient time. These clarifications have ID-01 to ID-05 checks, including a separately bundled browser run.

| Correction                   | Sections   | Applied change                                                                                                                                                                               |
| ---------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| D1                           | All        | Autonym names for scheme, scopes, headers, metadata, claims, media type, URNs, resources, examples and conformance names                                                                     |
| D2                           | A7         | MCP revision 2026-07-28, stateless discovery/current metadata and routing headers, cache fields, legacy compatibility, Multi Round-Trip confirmation; no new adoption of deprecated features |
| D3                           | A1, A6.2   | Client ID Metadata Documents first, static first-party clients and retained DCR compatibility                                                                                                |
| D4                           | A6.1       | RFC 9207 issuer parameter on authorisation responses                                                                                                                                         |
| D5                           | A6.1, A6.5 | Separate MCP/REST audiences and metadata; REST token example uses the REST audience                                                                                                          |
| D11                          | A8         | Grant-scoped HMAC ETags; 304 reads logged and rate-limited without increasing the read counter                                                                                               |
| D12                          | A6.4       | Stored grant is authoritative; copied token claims cannot widen or freeze it; no L0 read without a grant                                                                                     |
| D17                          | A10        | Purge reason is grant_ended for both revocation and expiry                                                                                                                                   |
| D19                          | A2         | assistant_unverified class and its restricted defaults for public clients off the assistant allowlist, without self-promotion; since 14 October 2026 without Bearer tokens (A6.3)            |
| Design 12.1                  | A3.2       | Public handle grammar and claim protections; recipient tokens/envelopes remain pairwise. The pairwise alphabet is lower-case RFC 4648 base32 without padding                                 |
| Design 4.1                   | A6.7       | Token revocation path is /oauth/revoke under the configured authorisation-server prefix                                                                                                      |
| Design 10 and logging rule   | A7         | Sensitive proposals return to the person's app; assistant attestation is ordinary-key-only and utterances are protected evidence rather than operational logs                                |
| Design 3.1 and honest status | A17        | Distinguish 0.1-draft document from 1.0 wire version; conformance suite is pending, not shipped                                                                                              |

The current MCP transport standard requires `Mcp-Name` for `tools/call`, `resources/read` and `prompts/get`; it is not a blanket requirement on every method. This clarifies the shorthand in the service design. Exact source links and verification are in the dependency record. Existing illustrative JSON examples remain draft illustrations; their full generated equivalents arrive with the corresponding implementation.

All imported requirements are pending the executable checks described in [conformance status](../conformance/README.md). Unresolved source ambiguities are listed separately; this import does not decide them silently. No internal hostname appears in these public contracts.

## 21 September 2026: consent, temporary context and reciprocity

A scope review added an addendum on consent, temporary context and reciprocity. Its text is now in [A6.7](../core/a06-authorisation.md#a67-consent-and-advertising) and the other sections listed under the edition 1.0-draft-1 restructure below. Grants and temporal attributes already existed; the additions clarify purpose separation, temporary override precedence and reciprocal contribution. The historical source files remain unchanged. The reproducible import adds `advertising` to A6.3 and links the overriding addendum from A4, A6, A11 and A17.

The scope schema, manifest, token schema and examples now include the explicit advertising purpose; SCOPE-10 checks that it grants no implicit read, proposal or persistence capability and cannot combine purposes. No authorisation server, recipient integration, temporal compiler or portability endpoint is introduced. Read/Contribute are capability descriptions mapped to existing Core/Write requirements, not renamed protocol identifiers or issued certifications. No breaking URL or wire-version change is made.

## Full draft publication, 21 September 2026

Document 0.2-draft resolves S1 to S4 and every item in the source ambiguity register. Historical corrections above describe earlier stages; the current numbered chapters supersede conflicting original examples. The original source hash remains checked; versioned editorial Markdown sources generate the revised chapters reproducibly.

The draft now includes typed contracts, a 27-key closed vocabulary, recipient OpenAPI/MCP definitions, examples and stable conformance requirements. Recipient IDs, temporary-context state, grants and export shapes change within an unreleased wire draft under ADR 0002. No existing recipient runtime is migrated. Unknown candidate keys and reserved extensions are explicitly excluded rather than published as incomplete wire formats.

## Public documentation cleanup

The public standard presents protocol requirements, design principles, interpretation notes and versioning guidance. No wire format, consent rule, vocabulary key or conformance requirement changes.

## International privacy deployment requirements

A16.1 retains the informative legal mapping. A16.2 to A16.8 require deployment-specific evidence for legal applicability, sensitive-data limits, international flows, rights and retention, opt-outs and child safeguards, and accountable operation, including granted regulatory permits and their continuing validity. PRIVACY-01 to PRIVACY-06 apply to every claimed provider or recipient capability. Unsupported operations remain disabled; passing protocol checks is not legal certification. A10 permits shorter lawful or necessary purge-status retention independently of an owner request, and A18 explicitly applies the local advertising checks. No wire format or vocabulary changes. Operational implementation and evidence remain pending.

## Pure compiler clarifications, 24 September 2026

The first compiler makes A4.5's field-right checks reproducible with a bounded `value` / `value.<member>` dependency notation; unsupported paths are withheld. A5.2 defines confidence filtering for exact declarations and null confidence, and permits conservative inclusion after selection-group changes while requiring baseline/dependency restoration. Request output filters do not grant input rights. These clarify the unreleased draft without changing wire object shapes, vocabulary keys or capability claims. The compiler's internal snapshot and owner-only receipt references are not new recipient contracts. Fractional UTC boundaries are compared without truncating to milliseconds.

## Approved pilot vocabulary 1.1, 24 September 2026

Adds `agent.always_do`, `agent.explanation_depth` and `communication.spelling` with the reviewed definitions in Appendix A. Every key records its introduction version. The 27 original keys retain their semantics; the catalogue now has 30 keys in 17 domains. Compiler disclosure of new keys requires both stored grant approval and recipient support for vocabulary 1.1, defaulting missing evidence to 1.0. No wire envelope shape or protocol version changes. VOCAB-1.1-01 to VOCAB-1.1-09 and the full compiler properties cover the addition; runtime negotiation and consent persistence remain pending.

## Edition 1.0-draft-1 restructure, 4 October 2026

Edition `1.0-draft-1` restructures the 0.2-draft text without changing a requirement. The core chapters move to `core/`, A12, A13 and continuous connectors to `core/reserved/`, the MCP and REST transport detail of A7 and A8 to the bindings B3 and B4, and the vocabulary to `vocabulary/`. A18 is folded section by section: A18.1 becomes A6.7, A18.2 becomes A4.6, A18.3 becomes A14.5 and A18.4 becomes A17.5; the unnumbered change-process page becomes A17.4. Every section's new location is in [`section-map.json`](../section-map.json). The operational HTTP surface and the app shell describe the reference implementation rather than the standard and move to its design documentation. The core text is now maintained by hand; the recovered proposal stays hash-locked and the editorial import pipeline is retired. The document version, held once in `packages/schema`, becomes `1.0-draft-1` in the schema identifiers embedded in the OpenAPI document and the MCP tool definitions, the OpenAPI version, the conformance manifest, and the capability-claim and discovery schemas; the wire version stays `1.0`. Capability claims and discovery documents stating `0.2-draft` no longer validate; no implementation had published one. The operational health and readiness schemas and the operational error examples stay generated into `spec/` as informative artefacts of the reference server, governed by its design documentation. The conformance manifest gains a `pending_phase` for every check and lists the SCOPE, ID and VOCAB-1.1 families it previously cited only in text. The vocabulary document gains the documentation group `media` (`viewing`, `reading`, `music`), which adds no key or permission.

## Reserved chapters as placeholders, 4 October 2026

The version 1 rules A12 and A13 stated move into the normative core, with their check ids unchanged: registries and trust evidence to A2.1, client standing and safety or medical purposes to A6.8, and self-declaration and experimental emergency cards to A17.6. `core/reserved/` now holds informative placeholders for A12, A13 and continuous connectors, which carry no requirements. No requirement changes. `handle_moved` stays removed (B4.3).

## PDPP binding body, 4 October 2026

The body of [B1](../bindings/B1-pdpp.md) binds read grants to PDPP Core v0.1.0 at commit `8f79a48`. Disclosure levels become statically declared derived streams, one per domain and level, with a `.declared` variant; restrictions PDPP cannot express travel in a second RFC 9396 detail; contribution grants and PDPP owner tokens are outside the binding; and the deviations from a strict reading of PDPP Core are listed as B1-D1 to B1-D8. No requirement of the core changes and no generated contract changes. The binding's new wire values (the detail type, purpose codes, stream names and record shape, identifier derivations, the `autonym_lifecycle` token kind, `Autonym-Read-Id` and a `pdpp` receipt surface) are draft text until they are generated from the schema package. The reasons for adopting PDPP Core, and what is taken from it, are in [its adoption record](../adoption/pdpp.md).

## Review amendments, 5 October 2026

The grant model belongs to the core: A1.3 and A6 now say that Open Personal Context Core stays meaningful without PDPP, and that B1 is the normative 1.0 grant binding, not a dependency of the model; the PDPP and OAuth adoption records say the same. A9 adds the key lifecycle that keeps receipts verifiable after a key rotation: key IDs are never reused, retired keys sign nothing new and stay published with their retirement date, and retention and compaction keep everything an old receipt needs. A5.4 verifiers reject a signature made after the key's retirement. Two checks join the Core provider profile, KEY-01 and LOG-02, both pending runtime evidence; the retirement-date member is defined when the key-publication contract is generated. A10 states that an acknowledgement proves only the recipient's signed attestation of the outcome it reports, never that every copy has gone. No wire format changes.

## Error registry for 1.0, 5 October 2026

The [error registry](../errors.json) now covers the whole 1.0 specification and replaces the proposal's A8 error list. Each registered code carries its `urn:autonym:error:<code>` type, status, title and the sections whose text raises it, and each of those sections names the code: A5.2 the grant, domain and disclosure-failure codes; A6 the capability, sender-proof, advertising and client-standing codes; A8 and A14 the proposal, value, idempotency and contribution codes; and A15.3 and B4 the operational codes. `client_suspended` (403) is added for the A6.8 rule that a suspended or disabled client cannot read. A14.3 now states the refusal that the A4.2 prohibitions on observing and inferring sensitive keys require: for a special-category or safety-critical key only a `user_supplied` event is accepted, as a protected proposal, and any other event fails `safety_write_forbidden` or `inference_forbidden`. `level_exceeded` is removed because no section raises it: A5.2 caps a requested level at the grant's ceiling instead of refusing the request. A later version that refuses such a request registers a code with the text that raises it. The registry also lists, without registering them, the OAuth codes and the PDPP Core section 8 codes that the text cites, including `blob_not_found` on the PDPP endpoints (B1.7, B1.9). B3.4 maps every registered code to one MCP error form. The status and title of every remaining code are unchanged.

## PDPP conformance table, 5 October 2026

B1.10 now states, item by item, how the binding meets each Authorization Server and Resource Server requirement of PDPP Core section 9 at commit `8f79a48`, so the published binding stands on its own. It previously relied on a table in a design document, and B1 no longer links to that document. No requirement changes.

## Signed-object contract, 6 October 2026

A5.4 now settles the bytes every detached signature covers and how they are verified. Receipts, purge acknowledgements and exports use the same method as disclosures, and each signed object names its signed time. A key ID is the RFC 7638 SHA-256 thumbprint of its public key, so one key ID cannot name two keys. The provider's key set at the discovery `jwks_uri` follows the new [key-set.json](../schemas/key-set.json): ES256 P-256 signing keys only, no private members. A retired key carries the JWK parameter `exp` that OpenID Federation 1.0 registers, in whole seconds, and a verifier rejects any object signed at or after it; a key carrying another lifetime member is not used. This makes the A9 key lifecycle, previously pending a published retirement member, a complete contract. Verification parses the received text strictly before canonicalisation, refusing repeated member names and non-I-JSON (lone surrogates, noncharacters and numbers with more magnitude or precision than a binary64 value provides), and refuses any protected header member other than `alg`, `kid` and `typ`. Every instant a provider writes into a signed or hashed object has one canonical spelling, without trailing fractional zeros and without losing precision.

A receipt now names its `provider`, the issuer URL discovery publishes, inside the signed bytes, and a verifier rejects one whose `provider` is not the trusted issuer. A9 defines the receipt's canonical request: the validated context request with `max_level`, `declared_only` and `min_confidence` always written out, its lists sorted without repeats and `since` in the canonical spelling; the receipt's `request` member now requires those defaults. A10 says the acknowledgement signature covers the RFC 8785 canonical JSON of the acknowledgement without `proof`, by the A5.4 method, and that the purge token's `kid` and `iat` follow A5.4. A verifier also recomputes a receipt's `hash`, refuses a disclosure issued more than 60 seconds ahead of its own clock, and accepts key coordinates and key IDs only in canonical base64url; a provider's signing key appears in no other provider's key set, and a published `exp` never changes. A receipt carried in an export is checked against the export's verified `origin_host`, and a verifier refuses an object that its schema would rewrite rather than return a value that was not signed. These are wire changes before the 1.0 wire release: receipts gain a required `provider`, and `proof.kid`, exported public keys and receipt requests are stricter, and the media example is re-signed under thumbprint key IDs.

## Normative statement audit, 6 October 2026

Every sentence of the normative pages that carries MUST, MUST NOT, SHOULD or SHOULD NOT, every requirement they state in the imperative, and every sentence that uses a lower-case must or should, now has an entry in [`statements.json`](../conformance/statements.json) naming the checks that test it or the reason no suite can. RFC 8174 gives the lower-case forms no normative force, but the text often uses them for requirements, so they are audited too; their wording is unchanged. The items of the A5.4 rejection list count as imperatives, and some requirements stated without a modal, such as the key, key-set and instant rules of A5.4, the canonical request of A9 and the acknowledgement bytes of A10, also have hand-chosen declarative entries; nothing requires one for every such sentence. Nine checks join the conformance manifest for requirements no check covered, all pending runtime evidence: WIRE-01 (A1.1 and A4.1, unknown members, keys and values outside a key's closed schema), HANDLE-01 (A3.2, public handles), MIGRATE-01 (A3.4 and B4.3, migration), INFER-01 (A4.2 and A14.3, keys that cannot be observed or inferred), OAUTH-01 (A6.1 and A6.3, metadata, registration and the code flow), FETCH-01 (A15.3, A3.3 and A6.1, retrieval of supplied URLs), ENCRYPT-01 (A11.2, the optional encrypted export), BINDING-01 (the requirements of B1 itself) and WILDCARD-01 (the A15.1 recommendation). The Core provider profile gains WIRE-01, OAUTH-01, FETCH-01 and INFER-01, and Portable gains MIGRATE-01. The Read and Contribute recipient profiles gain WIRE-01 and FETCH-01, because both are shared security requirements. HANDLE-01, ENCRYPT-01 and BINDING-01 are the checks of three new optional features, `public-handles`, `encrypted-export` and `pdpp-binding`, which A17.1 now names beside advertising; WILDCARD-01, a recommendation, belongs to no profile. A5 now also cites TEMP-02 and LOG-02, A6 the SCOPE checks of its scope grammar and DISC-01, A4 and B4 WIRE-01, A10 KEY-01, and A11 KEY-01 and LOG-02. The PDPP, OAuth and JWE adoption records name the new checks that apply to them.

The audit tightened four passages of A4 without changing behaviour:

- A4.3 says that instants compare by the time they denote, at full fractional precision, not by their bytes.
- A4.4 says that overlays apply only to the baseline that is eligible and selected for its key, and that selection counts only that baseline's eligible enabled overlays, so a selection on an ineligible or disabled overlay neither wins nor counts against another. It also says that the overlay is chosen from the record before the grant and request apply, so a winning overlay that they withhold is omitted and the baseline it replaces is never disclosed in its place.
- A4.5 says how its limit of 256 dependency references is counted: every reference traversed from the disclosed entry, along every path and without de-duplication, so an input reached by several paths, or named more than once, counts each time it is reached, together with its own references. The text previously said "more than 256 total dependencies" and did not say how a shared input counts. This is the stricter reading: an implementation that counted distinct inputs would accept graphs this rule withholds, never the reverse.
- A4.6 no longer reads as contradicting A4.4 when a single eligible enabled overlay has no selection: that overlay applies. Among several eligible enabled overlays, the baseline is used until exactly one of them is selected.

The reference compiler already behaves this way, and its TEMP-01 to TEMP-03 tests pin each reading. No wire format, vocabulary key or error code changes.

## Published test vectors, 6 October 2026

[`conformance/vectors/`](../conformance/vectors/README.md) publishes informative test vectors for the A5.4 signed objects: synthetic provider and recipient keys with their private parts, one provider key retired with `exp`; RFC 8785 canonical JSON with its UTF-8 bytes and SHA-256; signed disclosures; a receipt chain across a key rotation with its canonical requests; a purge instruction token and acknowledgement; and the signed objects a verifier must reject. The provider key set in `keys.json` is also the example of [key-set.json](../schemas/key-set.json). The media worked example is re-signed with the vector keys and no longer carries keys of its own. The conformance manifest gains an optional `vectors` member listing the vector files that evidence a check. No requirement changes.

## Contract checks in A17.2, 6 October 2026

A17.2's description of the reference repository's contract checks now also names the compiler's example and property tests, the library verifier for A5.4 detached signatures, the published test vectors, checked by the repository's tests with that verifier and independently by a second verifier written from the specification text alone, and the statement audit. The sentence that follows says "These checks" instead of "They". No requirement changes: the A17.2 sentences that use a modal or the imperative are unchanged, and runtime checks remain pending.

## Integration evidence in the conformance manifest, 7 October 2026

A check's `runtime_evidence` may now be `integration` as well as `library` or `pending`: the reference implementation's integration tests, which run its provider against real storage, cover every duty the check's requirement places on a provider that one provider's own tests can show, while a verifier's part keeps the evidence of its own tests and vectors. A17.2 and the [conformance README](../conformance/README.md) say what it shows and what it does not: that the reference provider meets those duties, not that another implementation does. The README also says that neither library nor integration evidence is gathered from a running service, what `pending_phase` names for a check with integration evidence (the phase whose tests supplied it), and which parts of KEY-01 its integration evidence leaves to a verifier's tests, to a running service or to other providers; it covers a provider whose issuer changes, whose earlier retired keys stay published. KEY-01 records it, from the tests of the reference key store against a real database, and the README defines the `-STORE` test-name suffix for such tests. The README also says what one provider's tests cannot show of a key never being shared between providers. PAIR-01 stays pending: its last requirement, that no canonical identifier escapes, needs a running read path, so tests of a store alone cannot cover it. No requirement, schema or wire format changes.

## Medical alert example, 6 October 2026

In [the vocabulary](../vocabulary/core.json), the L1 and L2 example renderings of `health.medical_alert` repeated the `agent.never_do` example text. Each free-text key's L1 and L2 example is now its own example, so the medical alert shows its synthetic example at L1, L2 and L3. No key, value schema, supported level, renderer operation, flag, label or explanation changes, and a compiler never uses an example.

## Entry limit per partition, 7 October 2026

A4.1 now bounds a partition at 10,000 entries that have not been deleted, which bounds what one read compiles: the reference compiler takes at most 10,000 entries in one read, and without a bound a partition past it could no longer be read at all. A write that would add another entry fails with the new registered code `entry_limit_reached` (409, "Entry limit reached") and changes nothing; a new version of an existing entry, and a deletion, are not refused by it. The proposal set no such limit. No other code's status or title changes, and no schema changes beyond the registry, the Problem Details union and their generated examples.

No agent operation adds an entry in this version: a contribution is acknowledged as a proposal whatever the partition holds, and only the person's own operations, such as accepting a proposal in the first-party app or an import, meet the limit. B3.4 therefore lists `entry_limit_reached` in a row of its own, of codes no agent operation raises, rather than with the refusals of an agent's request, so a contributor never learns how many entries a partition holds. A11.1 adds each partition's entry limit to what an importer validates before changing the destination, and PORT-01's requirement now includes it.

## Tombstone versions, 8 October 2026

A4.1 now fixes a tombstone's version: one more than the last version of the entry it deletes, so no ID and version name both an entry version and a tombstone, and two exports either side of a deletion never give one `(id, version)` two meanings, which A11.1's rejection of differing duplicates relies on. An earlier version keeps the status it was written with: a new version never changes an earlier one. The proposal left a tombstone's version unstated.

## Handle authority, 8 October 2026

A3.2 now says that an IP address is never a handle's authority, and neither is a name whose last label is all digits or `0x` followed by hexadecimal digits, since URL parsers read such a name as an IPv4 address. The proposal allowed the DNS name of the host, which names such as `example.1` and `foo.0xab` can be. A3.2 also says that the handle pattern in the published schemas checks only the syntax of the authority's labels, so it accepts such names. No schema or example changes: tightening the published pattern would change a wire format, and is not made here.

## Authorisation contract, 14 October 2026

Every access token is now bound to its client's DPoP key, for every client class and every resource. The proposal and D19 let an assistant, an unverified one included, use Bearer tokens, and A6.3 required DPoP only for service and connector clients; A2, A6.3, A15.1 and B4.1 now say that no class uses Bearer tokens, and the [OpenAPI document](../openapi/autonym-v1.yaml) no longer has its `EligibleAssistantBearer` security scheme. A token request without a valid proof fails RFC 9449 `invalid_dpop_proof`, a proof is accepted only once and within 60 seconds of its `iat`, and a resource keeps `dpop_required` and `dpop_invalid`. The [MCP record](../adoption/mcp.md) says how this departs from the Bearer usage MCP specifies.

A2 assigns every class from registration evidence: a client on the operator's assistant allowlist is `assistant`, any other public client `assistant_unverified` and a confidential client that authenticates with a registered key `service`. Previously only a public MCP client was `assistant_unverified`, and every other unknown client was `service`. A6.1 replaces the root protected-resource metadata document with one path-specific document for each resource, because the root document's `resource` would be the origin, which is not an audience, and says which registration metadata a provider accepts ([client-metadata.json](../schemas/client-metadata.json), [client-metadata-document.json](../schemas/client-metadata-document.json)): inline ES256 keys, and no `jwks_uri`, `sector_identifier_uri`, software statement, client secret or member the schema does not list. A6.2 gives each capability scope its meaning, gives every grant one audience, defines a continuous grant and defines the contribution request, an RFC 9396 detail of type `urn:autonym:authorization-details:contribute` ([contribution-detail.json](../schemas/contribution-detail.json)). A6.3 names the access token's claims ([access-token-claims.json](../schemas/access-token-claims.json)), signed with ES256 only, ends a grant whose authorisation code or refresh token is used a second time, and lists the OAuth error codes its endpoints answer; the A6.6 lifecycle token's claims are in [lifecycle-token-claims.json](../schemas/lifecycle-token-claims.json). A6.5 says that an access token ends with its grant and is not revoked on its own. A6.8 widens suspension from reads to every recipient action except the purge routes, and to the delegations of a suspended client; a deregistration revokes the client's grants. A9 defines the content of `grant_created`, `grant_revoked`, `grant_expired`, `read_not_modified` and `operator_action`, including how an `operator_action` says what it concerned, which A9 previously left to supplementary contracts that did not exist. The [scope grammar](../core/scopes.md) publishes the purpose codes `urn:autonym:purpose:<category>` and the capability meanings, which [scopes.json](../scopes.json) now carries too.

The [error registry](../errors.json) registers five codes for the person's own first-party requests (A15.3): `session_required` (401, "Sign-in is required"), `csrf_invalid` (403, "Request could not be verified"), `reauthentication_required` (403, "Recent sign-in is required"), `signup_unavailable` (403, "Sign-up is not available") and `sign_in_failed` (400, "Sign-in failed"); B3.4 lists them with the codes no agent operation raises. The registry also lists the OAuth codes A6 now cites, and `rate_limited` names A6.1, whose registration endpoint answers it in RFC 7591's error form. A2 gives each class's grant kinds, capability scopes and longest grant in a table, and leaves `autonym:persist` and `autonym:delegate` for an `assistant` or `service` client to the provider's policy. A client is `assistant` by its redirect URIs only when the allowlist names every one of them, and a client that registers or publishes a loopback redirect URI is never `assistant`, by either path; every client that is not `assistant` and not classified by the operator is shown as unverified at consent, whatever its class. A6.1 states the rules between registration members, accepts the A6.4 token exchange and grant offer in `grant_types`, the grant offer only from a client that authenticates with `private_key_jwt`, and refuses `application_type`, a Client Identifier URL with a percent-encoded dot segment or a host that URL parsers read as an IPv4 address, a port outside 1 to 65535, and in display text control, bidirectional, default-ignorable and interlinear annotation characters and any character outside the Basic Multilingual Plane. A6.2 makes a contribution detail's `allow_confirmation` true exactly when `autonym:confirm` is requested. A6.3 applies the loopback-port exception only to a client whose redirect URIs are all loopback URIs, requires a resource's DPoP proof to be signed by the token's `cnf.jkt` key, and answers `invalid_token` only for a token that fails verification. A6.4 binds the token exchange's proof to the subject token's key and names only a confidential recipient, which redeems the offer with `private_key_jwt`. A6.5 ends the grant whose refresh token its client revokes, with a DPoP proof by the token's key from a public client, and A9 records that revocation with the client as actor. A6.6's lifecycle token carries `sub`, the client's ID, as RFC 9068 section 2.2 requires of every JWT access token, and its `scope`. A9 splits an action on a client with more than 32 grants in one partition over several `operator_action` events. The `scope` marker of scopes.json becomes `grammar-and-meanings`, because the file now carries the meanings issuance applies. The requirements of OAUTH-01, LOG-01, CONSENT-01 and DELEGATE-01 in the [conformance manifest](../conformance/profiles.json) now name the A2, A6.4, A6.5, A6.6, A6.8 and A9 rules their statements cite, and no check is loosened. B1-D4 and the [PDPP record](../adoption/pdpp.md) say that no client uses Bearer tokens, and a reused refresh token in B1.10 revokes the grant; the rest of B1's DPoP wording follows with the PDPP binding's own change, and where it differs, A6 wins. The example client key is no longer the published recipient test key, whose private part anyone can read.

These are wire changes before the 1.0 wire release, inside the unreleased wire draft that ADR 0002 allows to change: the OpenAPI security schemes, the error registry, the Problem Details union and scopes.json change, and five schemas are added, with examples in [authorisation.json](../examples/authorisation.json). The test vectors do not change.


---

# Interpretation notes

This guide links cross-cutting protocol rules to their normative sections. It is informative; the linked requirements define implementation behaviour.

| Topic                                       | Requirement                                                                                              |
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Handle encoding and derivation              | A3 exact alphabet, JCS domain-separated framing, 32-character new handle, recipient entry aliases        |
| Request disclosure ceiling                  | A5 single scalar request intersected independently with each grant-domain ceiling                        |
| Declared-only and confidence combination    | A5 logical OR and maximum threshold                                                                      |
| Token validity                              | A6 one-hour valid UTC example; complete token rules explicit                                             |
| Sensitivity and inference                   | A4/A14 prohibit inference for non-inferable, sensitive and safety keys                                   |
| Vocabulary and rendering                    | Appendix A and generated core.json define all 30 vocabulary 1.1 keys; candidates rejected                |
| L1 versus L2 structure                      | A5 identifier-free structure allowed at L1; names only when the key explicitly allows them at L2         |
| Sparse-level and free-text fallback         | A5 highest supported permitted level; approved text or omission                                          |
| Signature boundaries                        | A5/A15 exact signed object boundary and representations                                                  |
| Briefing authority and read count           | A7 shared authorised transaction, both domains required, one read                                        |
| Advertising policy                          | A6.7 explicit three-key, adult-only, one-read policy                                                     |
| Temporal representation                     | A4 explicit kind, interval, overlay target/activation/selection                                          |
| Contributor identity, correction and replay | A14 strict event schema, authenticated source, stream namespaces and replay rules                        |
| Role claims and certification               | A17 role/version/category evidence; self-declaration only                                                |
| Global IDs and migration privacy            | A3 recipient-specific aliases, owner-only canonical IDs, no credential redirects                         |
| Purge polling after grant expiry            | A10 authenticated client lifecycle channel with no record-read authority                                 |
| Export encryption and delegated offers      | A11 exact JWE/KDF; A6 exact OAuth exchange/redemption                                                    |
| Legal equivalence claims                    | A16.1 informative support mapping; A16.2 to A16.8 normative deployment evidence, not legal certification |

See [conformance status](../conformance/README.md) for implementation and test coverage.
