§ Trust Tasks
Version: 1.0
Document Status: Working Draft 0.7.0
Last Updated: 2026-09-24
GitHub: https://github.com/trustoverip/dtgwg-trust-tasks-spec
Editors:
- Glenn Gore, Affinidi
Contributors:
- The participants of the Trust Tasks Task Force of the Decentralized Trust Graph Working Group (DTGWG)
Abstract
This document defines the Trust Tasks framework: a specification for the verifiable work that occurs between two or more parties, expressed as bilateral documents that the framework links when an exchange involves more than two. A Trust Task is a self-contained, transport-agnostic, JSON-based description of an outcome that two parties agree to achieve. This framework specification defines the document structure, version scheme, namespace, and conformance requirements that every individual Trust Task specification — published under the registry at https://trusttasks.org/ — is expected to satisfy. Individual Trust Task specifications (for example, the acl/change-role specification at https://trusttasks.org/spec/acl/change-role/0.1) are conforming refinements of this framework.
Intellectual Property Rights
This specification is provided under the Joint Development Foundation (JDF) charter for Trust Over IP (ToIP) and is subject to the intellectual property rights policy of the Decentralized Trust Graph Working Group (DTGWG):
Copyright: Creative Commons Attribution 4.0 International (CC BY 4.0)
Patent: W3C Mode (based on the W3C Patent Policy)
Source Code: Apache License, Version 2.0
THESE MATERIALS ARE PROVIDED “AS IS.” The parties expressly disclaim any warranties (express, implied, or otherwise), including implied warranties of merchantability, non-infringement, fitness for a particular purpose, or title, related to the materials. The entire risk as to implementing or otherwise using the materials is assumed by the implementer and user. IN NO EVENT WILL THE PARTIES BE LIABLE TO ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF ACTION OF ANY KIND WITH RESPECT TO THIS DELIVERABLE OR ITS GOVERNING AGREEMENT, WHETHER BASED ON BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR NOT THE OTHER MEMBER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
§ Introduction
This section is informative.
Two parties interoperate when they agree on the shape of the work they cooperate on. Today that agreement is reached ad hoc: every onboarding flow, every consent receipt, every credential exchange is described in a vendor-specific schema, carried over a vendor-specific protocol, and validated by vendor-specific code. The result is a combinatorial explosion of pairwise integrations.
A Trust Task is a single, finite description of an outcome between two parties — a KYC handoff, a consent grant, a payment commitment — that is portable across implementations because the task definition is decoupled from the transport that delivers it.
Three properties make a Trust Task portable:
- Self-contained — the document carries everything needed to act on it: parties, criteria, schema, identifiers. No hidden context.
- Transport-agnostic — the document makes no assumption about the protocol that delivers it. DIDComm, HTTPS, message queue, paper — the task is the task.
- JSON-based — the canonical serialization is a single JSON object validated against a published JSON Schema.
The body of this framework specification defines the document structure, version scheme, and namespace shared by every individual Trust Task specification published under the registry.
This is a Working Draft prepared by the Trust Tasks Task Force of the Decentralized Trust Graph Working Group (DTGWG) of the Trust Over IP Foundation. Publication as a Working Draft does not imply endorsement by the ToIP membership. Comments are welcome via the issue tracker. The editors expect the substantive sections — in particular Minimum Requirements, Error Responses, Transport Bindings, and Security Considerations — to evolve as individual Trust Task specifications progress through the Maturity Levels and surface gaps in this framework.
The individual Trust Task specifications that conform to this framework, together with the transport bindings and the generated client libraries, are maintained in the Trust Tasks registry repository and published at https://trusttasks.org/.
§ Design Goals
This section is informative.
The framework aims to solve four related problems that arise wherever two or more parties cooperate over a network.
-
A common task vocabulary across any transport. In a decentralized ecosystem there is no single message bus or RPC framework: parties speak DIDComm, HTTPS, message queues, paper, and anything else. Trust Tasks let two parties agree on what they are doing without first agreeing on how the bits move between them. The same task specification works regardless of the transport carrying it.
-
Security, privacy, and identity that scale to the transport. A Trust Task document can rely on the integrity, authentication, and party-identity guarantees already provided by the transport in use — for example, mutually-authenticated TLS or a signed DIDComm envelope — and where those guarantees are absent, the document’s own
proof,issuer, andrecipientmembers (Proof, TheissuerandrecipientMembers) supply them in-band. Implementers can match cryptographic work to the threat model in front of them rather than always paying the worst-case cost. -
Payload freedom, declared at the boundaries. The framework defines the outer document shape and deliberately leaves the
payloadunconstrained. Each Trust Task specification chooses its own payload structure, JSON Schema, and — where useful — JSON-LD context. The framework only requires that each choice be declared explicitly (Specification Requirements) and be machine-validatable. -
A standard family of response types. Many tasks need a structured way for a recipient party to report what happened. The framework reserves a small set of response-type Trust Task specifications addressing the common cases — failure (Error Responses), success (the
#responsevariant of the task’s own Type URI, which since framework version 0.5.0 also carries the courtesy acknowledgement of a fire-and-forget task and supersedestrust-task-ok), and a recipient-suggested continuation (trust-task-next-step) — each itself a Trust Task so that one validation, signing, and transport pipeline serves both the task and its response. All three are specified as of this revision (see Error Responses and Reserved Response-Type Slugs).
§ Requirements Language
This section is normative.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in BCP 14 RFC 2119 RFC 8174 when, and only when, they appear in all capitals, as shown here.
§ Terminology
This section is normative.
The key terms used throughout this specification are defined below. Where one of these terms is italicized on subsequent use, the definition given here applies.
Any hyperlinked term not included in this section is referenced from one of the following glossaries:
- ceremony definitions (ceremony definition)
-
The published, versioned description of a Trust Ceremony, identified by a URI in the
/ceremony/subtree (Ceremony Namespace). It is not a Trust Task specification and no document’styperesolves to one. Its content is out of scope for this version. - consequential Trust Tasks (consequential Trust Task)
-
A Trust Task whose successful execution has an effect the consumer cannot silently undo: it alters recipient party state, releases confidential material, or exercises the subject’s own authority. Precisely, a Trust Task is consequential where any of the following holds —
sideEffects.levelismutatingordestructive,exposure.disclosesissecret, orexposure.actsAsSubjectistrue(see Specification Requirements items 13 and 14). Where a consumer determines the authoritative values from the handler it is about to invoke rather than from the values the Trust Task specification declares, the authoritative values govern. An absent, unrecognized, or unresolvable declaration is consequential, consistent with the fail-safe defaults of Specification Requirements items 13 and 14. The term names a class of task for which several rules in this specification are stricter than the general case; it carries no authorization meaning of its own (see Consumer Requirements item 10). - consumers (recipient party, consumer)
-
A party that receives and processes a Trust Task document. Synonym: recipient party when emphasizing the consumer’s acceptance role (for example, in error-response prose). The two terms refer to the same entity and are used interchangeably throughout this specification.
- Data Integrity Proof (proof)
-
An optional integrity-providing object attached to a Trust Task document, in the form of a W3C Data Integrity Proof (see Proof).
- Document identifier (document identifiers, document identifier)
-
The string carried in the
idmember of a Trust Task document that uniquely identifies that instance. - enactments (enactment)
-
One run of a Trust Ceremony, identified by a globally unique, non-reusable string carried in
ceremony.enactment. An enactment is to a ceremony definition what a Trust Task document is to a Trust Task specification. - error responses (error response)
-
A Trust Task document whose
typeresolves to the framework’s reservedtrust-task-errorspecification and that reports a failure with respect to a previously received Trust Task document. See Error Responses. - Outcome evidence (outcome evidence)
-
The initiating document of a cited exchange together with the terminal success document showing that the exchange completed, paired under Evidence That a Cited Exchange Completed. A citation names and binds an exchange; outcome evidence is what shows the cited task reached
responded. - Parent thread identifier (parent thread identifier)
-
An optional string carried in the
parentThreadIdmember that names the exchange containing this one, where a Trust Task is conducted inside a broader exchange. See TheparentThreadIdMember. - parties (party)
-
An entity that participates in a Trust Task. Each party is identified by a Verifiable Identifier.
- payloads (payload)
-
The task-specific portion of a Trust Task document, carried in the
payloadmember. Its internal structure is defined by the Trust Task specification identified by the document’stype. - producers (producer)
-
A party that emits a Trust Task document. Synonym: issuer when referring to the value carried in the document’s
issuermember. - Thread identifier (thread identifiers, thread identifier)
-
An optional string carried in the
threadIdmember that correlates a Trust Task document with other documents belonging to the same logical exchange. See ThethreadIdMember. - transport bindings (transport binding)
-
A specification that defines how Trust Task documents are exchanged over a specific transport protocol, including how transport-derived identity, integrity, and freshness are mapped into framework members. See Transport Bindings.
- Trust Ceremonies (trust ceremony, Trust Ceremony)
-
A flow composed of several Trust Tasks, optionally described by a published ceremony definition. Named here because a Trust Task document may record its membership of one; see The
ceremonyMember. - Trust Task documents (trust task document, Trust Task document)
-
A single JSON object that is an instance of a Trust Task. It carries its own type, identifier, and integrity metadata alongside a task-specific payload. The structure is defined normatively in Trust Task Documents.
- Trust Task specifications (trust task specification, Trust Task specification)
-
A document, conforming to this framework, that defines a single Trust Task — its slug, version, target framework version, parties, normative payload schema, proof requirement, and any task-specific error extensions. See Specification Requirements for the full set of declarations a specification MUST publish.
- Trust Tasks (trust task, trust tasks, Trust Task)
-
A unit of verifiable work between two parties, formally defined by a Trust Task specification and exchanged as Trust Task documents. Each instance of work — a KYC handoff, a consent grant, a payment commitment — is a Trust Task. The document model defined by this framework is bilateral: each Trust Task document names at most one issuer and one recipient. Exchanges involving more than two parties are modeled as multiple bilateral Trust Tasks linked by the framework’s
threadIdmember (see ThethreadIdMember). - Type URIs (Type URI)
-
An absolute URI that identifies a Trust Task specification at a specific version. It is compared as a name; where its scheme is
httpsit is also the resolvable namespace for that version. The public-registry form, and the forms a private specification may use, are defined in Type URI. - Verifiable Identifier (Verifiable Identifiers, VIDs, VID)
-
A string identifier whose controller is verifiable under a trust framework. Decentralized Identifiers (DIDs) DID Core are one realization of VIDs; others include X.509 subjects, OIDC subject identifiers, and key thumbprints. The framework does not constrain the VID scheme; the consumer’s trust framework determines which schemes are accepted and how each is resolved to verification material.
§ Trust Task Documents
This section is normative.
A Trust Task document is a single JSON object. The framework deliberately does not define a separate envelope: type, version, identifier, and integrity metadata are members of the document itself. This simplifies validation — one object, one schema composition — and removes the ambiguity of “is this field on the wrapper or the body?”
§ Encoding
A Trust Task document MUST be a JSON object as defined in RFC 8259. The document MUST be encoded as UTF-8 without a byte-order mark.
§ Top-Level Members
A Trust Task document has the following top-level members.
| Member | Required | Type | Description |
|---|---|---|---|
id |
MUST | string | The Document identifier — a globally unique string for this instance of the task. UUIDv4 is RECOMMENDED; any uniquely-assignable string is permitted. See The id Member. |
threadId |
MAY | string | The Thread identifier — correlates this document with others in the same logical exchange (e.g. a response back to its originating request). See The threadId Member. |
parentThreadId |
MAY | string | The Parent thread identifier — the threadId of the exchange that contains this one, where this exchange is conducted inside another. See The parentThreadId Member. |
ceremony |
MAY | object | Records that this document is a step of a Trust Ceremony — a flow composed of several Trust Tasks. See The ceremony Member. |
type |
MUST | string (URI) | The Type URI identifying the Trust Task specification and version this document conforms to. See The type Member. |
issuer |
MAY | string (VID) | A Verifiable Identifier identifying the party responsible for the document’s content. See The issuer and recipient Members. |
recipient |
MAY | string (VID) | A Verifiable Identifier identifying the party the issuer expects to act upon the document. See The issuer and recipient Members. |
issuedAt |
SHOULD | string (date-time) | An RFC 3339 timestamp recording when the document was produced. It is the value by which a consumer places the document in its acceptance window; see Consumer Requirements item 13 for the freshness bounds applied to it, and Specification Requirements item 17 for when a Trust Task specification MUST require it. |
expiresAt |
MAY | string (date-time) | An RFC 3339 timestamp after which the document is no longer valid to accept. Where expiresAt is specified, the recipient party MUST honor the expiry: a consumer MUST NOT act upon a document for which now ≥ expiresAt (inclusive bound; the instant expiresAt is itself treated as expired). A consumer MAY apply a small clock-skew tolerance, typically ≤ 60 seconds, when evaluating this comparison. expiresAt bounds acceptance, not execution: it does not abort work already under way (see Consumer Requirements item 12). See Consumer Requirements. |
payload |
MUST | object | The task-specific body. Its internal structure is governed by the Trust Task specification identified by type. See The payload Member. |
@context |
MAY | string | array | object | If present, enables JSON-LD processing of the document. See JSON-LD Compatibility. |
proof |
MAY | object | An optional integrity proof. See Proof. |
A Trust Task document MAY contain additional top-level members beyond those listed above. Member names beginning with x- are RESERVED for experimental extensions and MUST NOT be used in a published Trust Task specification.
Example 1 — A complete Trust Task document (non-normative)
{ "id": "4f3c9e2a-1b81-4d3e-9b51-7a3c89e3d1f2", "type": "https://trusttasks.org/spec/acl/change-role/0.1", "issuer": "did:web:org.example", "recipient": "did:web:maintainer.example", "issuedAt": "2026-06-10T14:00:00Z", "expiresAt": "2026-06-11T14:00:00Z", "payload": { "subject": "did:web:bob.example", "fromRole": "member", "toRole": "moderator" }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "eddsa-jcs-2022", "verificationMethod": "did:web:org.example#key-1", "created": "2026-06-10T14:00:00Z", "proofPurpose": "authentication", "proofValue": "z5xy..." } }The
payloadmember is the only part whose internal shape is defined by the per-task specification; everything else is framework-defined. This example carries aproofmember because the Trust Task specification it names declaresproofREQUIRED — a role change is retained as the evidentiary record of how privilege was acquired, and is relied upon after delivery. The framework itself leavesproofOPTIONAL: a document of a specification that does not require one is conforming without it, provided it is delivered over a transport that supplies end-to-end integrity and authentication between producer and consumer (see When to Include a Proof).
§ The id Member
The id member’s value MUST be a string that is globally unique to this instance of the task. The framework places no further constraint on its form: UUIDv4 RFC 9562 is RECOMMENDED as a low-coordination default that requires no namespace ownership, but any string an implementation can guarantee unique is permitted — for example, a DID URL, a UUIDv7, a URN, or an opaque content-addressed identifier. Producers MUST NOT reuse an id value across documents.
The id is opaque to the framework. Resolvability of the id (the ability to dereference it back to the document) is not required. Where resolvability is needed for a particular use case, an individual Trust Task specification or transport binding MAY require a more specific form (for example, a DID URL).
§ The type Member
The type member’s value MUST be a Type URI in the form defined in Type URI. The version of the Trust Task specification a document conforms to is conveyed by the trailing <MAJOR.MINOR> segment of this URI; no separate version member is carried in the document.
A type URI MAY carry a fragment identifier. The framework reserves the fragments #request and #response to disambiguate the two directions of a request/response exchange that share a single Trust Task specification; see Request and Response Variants.
§ Request and Response Variants
A single Trust Task specification often describes both a request document (the document a producer sends to initiate the task) and a response document (the document the consumer returns when the task completes successfully). The framework distinguishes the two via the fragment of the type URI:
type form |
Meaning |
|---|---|
https://trusttasks.org/spec/<slug>/<MAJOR.MINOR> |
Request document. Implicitly equivalent to the explicit form below. |
https://trusttasks.org/spec/<slug>/<MAJOR.MINOR>#request |
Request document, explicit form. |
https://trusttasks.org/spec/<slug>/<MAJOR.MINOR>#response |
Success-response document for the same specification. |
A reply to a Trust Task document takes one of exactly three dispositions, distinguished by the reply’s own type and by nothing else:
| Disposition | type of the reply |
Closes the exchange? | Defined in |
|---|---|---|---|
| Success | the originating Type URI with the fragment #response |
Yes | This section |
| Failure | https://trusttasks.org/spec/trust-task-error/<MAJOR.MINOR> |
Yes | Error Responses |
| Continuation | https://trusttasks.org/spec/trust-task-next-step/<MAJOR.MINOR> |
No — the originating document remains accepted and blocked (Document Lifecycle) |
Reserved Response-Type Slugs |
The three are exhaustive and are not interchangeable: a consumer MUST NOT report a failure as a #response, a success as a trust-task-error, or a blocked task as either. A party receiving a reply MUST determine its disposition from the reply’s type alone — the fragment for the first, the slug for the other two — and MUST NOT infer it from the presence or absence of any payload member.
The table is stated here because “is this document a response?” is otherwise answerable in three places — the fragment rule below, the distinct-Type URI rule of Error Responses, and the third-disposition rule of Reserved Response-Type Slugs — and an implementation that finds one of them hard-codes a list of the slugs it happens to know, which the next reserved slug silently invalidates.
The rules:
- A Trust Task document whose
typeURI carries no fragment or the fragment#requestis a request. The two forms are semantically equivalent; producers MAY emit either, consumers MUST accept both. - A Trust Task document whose
typeURI carries the fragment#responseis the success response of a request whosetypeis the same URI with the fragment stripped. The request and response are correlated bythreadIdper ThethreadIdMember. - The fragments
#requestand#responseare RESERVED for this purpose. An individual Trust Task specification MUST NOT assign other fragment meanings to itstypeURI. - A failure response is not a
#response-variant document of the request’s Type URI. Failures are reported via the framework’s distincttrust-task-errorType URI per Error Responses. - Consumers MUST preserve the fragment when comparing
typeURIs, when routing documents internally, and when keying hash maps ontype. A consumer that strips the fragment before keying will conflate request and response documents. - The payload JSON Schema for a request/response pair is published as a single schema document whose
$idis the bare Type URI (no fragment). Within that schema, the request payload shape is the top-level schema (or the schema reachable via$anchor: "request"); the response payload shape is reachable via$anchor: "response". See Specification Requirements for the publishing requirements.
§ Acknowledging a Fire-and-Forget Task
A specification that defines a fire-and-forget task — one with no expected success response document — declares no response sub-schema (Specification Requirements item 7.6). Its consumer MAY nonetheless return a document whose type is the originating Type URI with the fragment #response and whose payload is the empty object {}, as a courtesy acknowledgement that the document was received and performed.
The rules for that acknowledgement:
- The
payloadMUST be exactly{}. The specification declares no response shape, so there is no shape for a member to validate against; a consumer MUST NOT place any member in it, and a party receiving one MUST NOT attribute meaning to anything it nonetheless contains. - A consumer receiving such an acknowledgement validates it against the framework schema alone and MUST NOT attempt to resolve a
responseanchor, which item 7.6 forbids the specification to declare. - A producer MUST NOT rely on receiving one. Its absence carries no information — the consumer may not implement acknowledgement, may implement it and stay silent, or the document may be lost — and a producer that reads absence as failure and reissues a consequential Trust Task causes exactly the duplicate effect Consumer Requirements item 11 exists to prevent. This is the general rule of Document Lifecycle, not an exception to it.
- A consumer MUST NOT send one for a specification that does define a success response. Two success dispositions for one task leave a producer unable to tell which is authoritative.
This form supersedes the reserved trust-task-ok slug, which exists for precisely this purpose and cannot serve it. trust-task-ok is a different Trust Task specification from the task it acknowledges, so a producer awaiting a reply must recognize a type unrelated to the one it sent; and it is defined so that it cannot carry meaning — a consumer MUST NOT require any member of it and a producer MUST NOT rely on receiving one — which leaves a registry entry, a schema, and a generated type in every language whose entire content is “something arrived”. The same fact now travels on the reply a producer was already prepared to receive. trust-task-ok is deprecated accordingly; see Reserved Response-Type Slugs.
An acknowledgement that genuinely matters remains outside both forms. A task whose acknowledgement will be relied upon, audited, or disputed declares its own success response with its own payload and its own proof requirement, or a dedicated receipt task — the empty {} attests nothing beyond arrival, and is signed, where it is signed at all, only to that effect.
§ The payload Member
The payload member’s value MUST be a JSON object whose internal structure is defined by the Trust Task specification identified by the document’s type. This framework places no constraint on the contents of payload beyond requiring that it be an object.
The framework separates document-level metadata (id, threadId, parentThreadId, ceremony, type, issuer, recipient, issuedAt, expiresAt, proof) from task-specific data (payload) so that a single framework-level schema validates the outer structure, with per-task schemas applied only to payload. Schema scope is defined in Schema Scope.
§ The ext Extension Member
A Trust Task specification MAY allow an ext member at the top level of payload, at any nested object whose contents the specification controls, or both. The ext member is the framework’s sanctioned extension point for ecosystem-defined data that the base specification does not enumerate.
The framework reserves the following normative rules for any ext member, in any specification:
extMUST be a JSON object when present.- Each immediate key of
extMUST match the reverse-DNS grammar^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$— lowercase, at least one dot. Examples:vnd.affinidi.webvh,org.example.acl. Bare keys without a namespace are non-conforming. - The structure under each namespace is opaque to the framework. Producers MAY place any JSON value the namespace’s controller chooses to define.
- A producer MUST NOT rely on any framework-level meaning for the contents of any
ext.*namespace. - A consumer MUST ignore namespaces it does not recognize, consistent with the unrecognized-member rule of Consumer Requirements, except where the namespace is named critical under Marking a Namespace Critical. A consumer MAY require its own namespace as a matter of local policy and reject documents lacking that namespace with
malformedRequest. - The framework reserves no
ext.*namespace today. Trust Task specifications MUST NOT define cross-specification semantics for anyextkey; ecosystem semantics belong to the namespace controller.
A Trust Task specification opts into ext at a given object level by including a property named ext (typically a $ref to the framework’s published Ext $def) and adjusting that level’s additionalProperties declaration accordingly. Specifications that do not include ext at a given level reject the member at that level under their existing additionalProperties: false.
A proof covers ext in the same way it covers any other member of payload, so ext inherits the integrity guarantees of Proof when a proof is present.
ext is distinct from the task-specific details member of a trust-task-error response (Extension by Individual Trust Task Specifications). details carries structured data tied to a specific error code defined by the spec author; ext carries vendor-namespaced extension data defined by the ecosystem. Both members MAY appear on the same document and are not interchangeable.
§ Marking a Namespace Critical
Rule 5 makes an ext namespace safe to ignore, which is what allows a specification to grow without a version increment. It also makes a producer unable to tell an ignored namespace from an understood one: a consumer that silently drops a namespace the document’s meaning depends on reaches a verdict the producer did not ask for, and reaches it invisibly. Criticality is how a producer forecloses that.
A Trust Task specification that allows ext at a given object level MAY also allow an extCritical member at that same level. The following rules apply wherever it is allowed:
extCriticalMUST be an array of one or more unique strings when present, and MUST NOT be present at an object level whereextis absent.- Each entry MUST match the reverse-DNS grammar of rule 2 of The
extExtension Member and MUST name a namespace present as an immediate key of the siblingextmember. An entry naming an absent namespace is non-conforming; a consumer MUST reject such a document withmalformedRequest. - A namespace named in
extCriticalis critical: the producer asserts that the document’s meaning depends on it, and that processing the document as though the namespace were absent would reach a different outcome than the one requested. - A consumer that does not recognize a critical namespace MUST NOT process the document, and MUST reject it with
unsupportedExtension(Standard Error Codes). Rule 5 of TheextExtension Member does not apply to it. A consumer that recognizes the namespace processes the document under its own policy exactly as it would have without the marking — criticality obliges a consumer to understand a namespace or refuse, and never to act on one. - A producer MUST NOT mark a namespace critical where the document remains correct without it. Marking is a statement about meaning, not about importance: a namespace carrying an optimization, a hint, or an audit annotation is not critical, and marking it turns every consumer that has not implemented it into a failure where it would otherwise have interoperated.
- A producer SHOULD establish that a consumer understands a namespace before marking it critical — through discovery (Discovery and Capability Negotiation), through the governance framework the parties operate under, or out of band. Criticality reports a downgrade rather than preventing one, so a producer that marks without establishing support has chosen a failed exchange over a silent one; that is the right trade only where the silent outcome would have been worse.
extCritical is covered by proof exactly as ext is, so a critical marking cannot be stripped from a signed document without invalidating it. On an unsigned document it is removable in transit, and a producer that needs the marking to survive the trip MUST sign the document.
A specification opts in by including an extCritical property at the same object level as its ext property, typically as a $ref to the framework’s published ExtCritical $def. A specification that allows ext and not extCritical at a given level rejects the member at that level under its existing additionalProperties: false, and every namespace at that level remains ignorable under rule 5 of The ext Extension Member.
§ JSON-LD Compatibility
A Trust Task document MAY include an @context member. If present, the document MUST be processable as JSON-LD; the framework places no further constraint on the contents of @context beyond requiring it to be a string, an array of strings or objects, or an object, in line with the JSON-LD specification. A Trust Task specification that wishes to declare a canonical JSON-LD context MUST publish it at its Type URI under content negotiation for application/ld+json where the Type URI’s scheme is https (see Content Negotiation), and otherwise distribute it out of band (Private and Unpublished Trust Task Specifications item 4).
A consumer that does not implement JSON-LD processing MUST ignore the @context member and process the document as plain JSON. JSON-LD support is therefore strictly additive — no consumer is required to implement it, and no document is required to include it.
Example 2 — A Trust Task document with a JSON-LD context (non-normative)
{ "@context": [ "https://www.w3.org/ns/credentials/v2", "https://trusttasks.org/spec/acl/change-role/0.1" ], "id": "urn:uuid:7d8b1e3a-9a72-4f86-9d04-2a4b6c2c5e10", "type": "https://trusttasks.org/spec/acl/change-role/0.1", "issuer": "did:web:org.example", "recipient": "did:web:maintainer.example", "issuedAt": "2026-06-10T14:00:00Z", "payload": { "subject": "did:web:bob.example", "fromRole": "member", "toRole": "moderator" } }A consumer that implements JSON-LD processes the document accordingly; a consumer that does not implement JSON-LD ignores
@contextand processes the same document as plain JSON. The two interpretations validate against the same payload schema. The second@contextentry shows where a specification’s own context appears; the registeredacl/change-role0.1 does not publish one, and a Trust Task specification that wishes to declare a canonical context publishes it at its Type URI under content negotiation forapplication/ld+jsonas this section requires. Theproofthe specification requires is omitted throughout this example, which turns on@contextalone.
§ Proof
A Trust Task document MAY include a proof member whose value is a W3C Data Integrity Proof object as defined in VC Data Integrity. When present, the proof binds the document’s content to its issuer.
The choice of cryptographic suite is open beyond the baseline defined in Cryptosuites: any Data Integrity cryptosuite MAY be used where the consumer verifies it. The verificationMethod of the proof MUST resolve to verification material controlled by the party identified by the document’s issuer member (see The issuer and recipient Members). It MUST also be one that party has authorized for the proof’s proofPurpose (Proof Purpose and Verification Relationship).
When proof is present, it covers the document with proof itself excluded from the signed content, per the canonicalization rules of the chosen Data Integrity suite.
§ Cryptosuites
The baseline. A conforming consumer MUST be able to verify a proof whose cryptosuite is eddsa-jcs-2022 (Data Integrity EdDSA Cryptosuites): Ed25519 over the RFC 8785 canonicalization of the document. The baseline is a floor on verification, not a constraint on signing. It is the one suite a producer can rely on any conforming consumer to verify, and so it is what makes two independent implementations interoperable without prior agreement. JCS is chosen over RDF canonicalization because a Trust Task document is JSON whether or not it carries @context (JSON-LD Compatibility), and verifying it must not require a JSON-LD processor.
Choosing a suite. A producer selects the suite from the key it signs with, and a consumer selects the verifier from the proof’s cryptosuite and the key type of its verificationMethod; no further negotiation member is defined. A producer signing for a consumer whose capabilities it does not know SHOULD sign with the baseline. It MAY sign with another suite where it has reason to believe the consumer verifies it:
- the governing Trust Task specification requires or permits that suite (Specification Requirements item 8);
- the parties’ trust framework or a prior agreement between them names it; or
- the recipient’s VID resolves to verification material of the key type that suite uses — a party that publishes an ML-DSA key is taken to verify ML-DSA proofs.
Beyond the baseline. A consumer SHOULD also be able to verify ecdsa-jcs-2019 (Data Integrity ECDSA Cryptosuites) with a P-256 key: hardware-backed signers, including platform secure enclaves, WebAuthn authenticators and many HSMs, sign only with P-256. Every other suite is agreed as above.
An unsupported suite is a failure, not an absence. A consumer that does not implement the cryptosuite a proof names MUST reject the document with proofInvalid (Consumer Requirements item 7). It MUST NOT process the document as though it carried no proof: a document that is required to carry a proof would otherwise be accepted on the strength of a signature nobody checked.
A specification may require a suite. A Trust Task specification MAY require a particular suite, or a class of suites, for its documents — for example a quantum-resistant suite for evidence intended to be retained for many years, or a suite that meets a regulatory requirement. It states the requirement alongside its proof requirement (Specification Requirements item 8). Such a requirement narrows what the producer signs with; it does not relieve any consumer of the baseline.
Quantum-resistant suites (draft). The quantum-resistant Data Integrity suites are, at this framework version, an experimental W3C draft (Quantum-Resistant Cryptosuites v1.0) and are not part of the baseline. They are used under the rules above, as agreed suites. So that implementations that adopt them now interoperate, this framework pins the identifiers and key encodings it uses to that draft:
cryptosuite |
Algorithm | Multikey public-key header | Multibase |
|---|---|---|---|
mldsa44-jcs-2024 |
ML-DSA-44 (FIPS 204) | mldsa-44-pub, multicodec 0x1210 |
base64url, u |
slhdsa128-jcs-2024 |
SLH-DSA-SHA2-128s (FIPS 205) | slhdsa-sha2-128s-pub, multicodec 0x1220 |
base64url, u |
The JCS variants are pinned for the reason the baseline is. The draft’s other suites (its RDF-canonicalized variants, FALCON-512 and SQIsign) are not pinned and are agreed like any other suite. Where the draft changes an identifier or an encoding before it is finalized, this framework adopts the new identifier as a new entry and does not reinterpret an existing one: a proof already produced under a pinned identifier keeps verifying under it. The framework expects to name a quantum-resistant suite in the baseline once a W3C Recommendation defines one.
The suites in this section, summarized (non-normative):
cryptosuite |
Key | Status in this framework |
|---|---|---|
eddsa-jcs-2022 |
Ed25519 | Baseline — every consumer MUST verify |
ecdsa-jcs-2019 |
P-256 | Every consumer SHOULD verify |
mldsa44-jcs-2024 |
ML-DSA-44 | Draft; pinned; agreed |
slhdsa128-jcs-2024 |
SLH-DSA-SHA2-128s | Draft; pinned; agreed |
| any other Data Integrity suite | — | Agreed |
§ When to Include a Proof
The default rules governing the presence of proof in a Trust Task document are:
- If the document is delivered over a transport that already provides end-to-end integrity and authentication between producer and consumer — for example, mutually-authenticated TLS or a signed DIDComm envelope —
proofMAY be omitted. - If the document is delivered over a transport that does not provide such guarantees, or where tampering or substitution by intermediaries is possible,
proofSHOULD be included. - If a strong, transport-independent guarantee of non-tampering and of producer identity is required — typically because the document is intended to be retained, replayed, or relied on by parties beyond the original consumer —
proofMUST be included.
Whenever proof is included, the Audience Binding rule also applies: the producer commits to an in-band recipient so that the proof binds not only the content but also the intended audience.
An individual Trust Task specification MAY strengthen these defaults (for example, mandate proof regardless of transport) but MUST NOT weaken them. The declaration each Trust Task specification makes about its own proof requirement is governed by Specification Requirements.
§ Proof Purpose and Verification Relationship
A key controlled by the issuer is not thereby authorized to sign for every purpose. A DID document, or any other controller document an issuer resolves to, states what each of its keys is for through its verification relationships, and a key published only for key agreement, or authorized only to authenticate, has not been authorized to make assertions. A consumer that accepted any key listed anywhere in the document would let whichever key is least protected sign for the most consequential purpose.
This section restates, for Trust Task documents, the rule VC Data Integrity already applies through the Retrieve Verification Method algorithm of Controlled Identifiers. It is a clarification of conformance to those specifications, not an additional requirement on top of them. When verifying a proof, a consumer MUST:
- Treat the value of
proofPurposeas the name of the verification relationship to check. The purposes a signature can carry areassertionMethod,authentication,capabilityInvocationandcapabilityDelegation. AproofwhoseproofPurposeiskeyAgreement, is absent, or names no verification relationship the consumer recognizes MUST be rejected: a key-agreement key never authorizes a signature. - Resolve the
verificationMethodagainst the controller document of theissuer, and reject theproofunless the identifier of that document is theissuer, exactly as compared under TheissuerandrecipientMembers, and the verification method’scontrolleris that same identifier. A verification method belonging to any other identifier is refused even when theissuer’s document lists it. - Reject the
proofunless the verification method appears in the verification relationship named byproofPurpose, either by reference or embedded by value. A reference is resolved before comparison: a relative reference such as#key-1is resolved against the controller document’s identifier, and the method it names is taken from the document’sverificationMethodset. A reference MUST NOT be resolved to a verification method embedded under a different relationship, since that method is defined for that relationship alone. A verification method that appears only under another relationship, or only underverificationMethod, is not authorized for the purpose.
Where a DID method defines the relationships of a key implicitly rather than listing them, the relationships the method’s resolution defines are the ones checked. For example, the single signing key of a did:key is authorized for authentication, assertionMethod, capabilityInvocation and capabilityDelegation, and the key-agreement key derived from it is authorized for keyAgreement only.
A failure under this section is a failed verification, and the consumer rejects the document with proofInvalid (Consumer Requirements item 7).
Which purpose a producer signs with. A producer MUST set proofPurpose to a relationship under which its own controller document lists the signing key. A producer SHOULD sign a Trust Task document with proofPurpose authentication. The proof of a Trust Task document shows that the party controlling the issuer identifier produced the document, whether it is a request, a response, or an instruction, and that is what the authentication relationship authorizes a key to show. assertionMethod authorizes a key to make attestations that a third party may rely on in its own right. A producer SHOULD NOT sign a Trust Task document with assertionMethod unless the governing Trust Task specification defines the document’s proof as such an attestation (Specification Requirements item 8). A key an issuer keeps for its day-to-day operation is then never required to hold attestation authority.
The rules above do not depend on which purpose a producer chose: a consumer checks the relationship the proof names. A Trust Task specification MAY require a particular proofPurpose for its documents, stating it with its proof requirement, and a consumer MAY apply such a requirement as local policy. During a migration an issuer can therefore list a key under both relationships, so that proofs made before and after the change both verify.
§ The issuer and recipient Members
A Trust Task document MAY identify the parties involved by including the issuer and recipient members at the top level of the document.
issuer— a Verifiable Identifier (see Terminology) identifying the party responsible for the document’s content. Whenproofis present, theissuerMUST identify the entity to which the proof’sverificationMethodresolves.recipient— a Verifiable Identifier identifying the party the issuer expects to act upon the document.
The framework does not constrain the VID scheme used: a DID, an X.509 subject, an OIDC subject identifier, a key thumbprint, or any other identifier whose controller is verifiable under the consumer’s trust framework is acceptable.
A group as a party (non-normative). A party need not be a single agent. A group that holds an authority jointly — for example under a t-of-n threshold key, where no member can exercise it alone — is a party when it has a VID of its own, such as a DID whose verification method is the group’s key. It then fills
issuerorrecipientlike any other party, and every identity rule of this framework applies to it unchanged. Which members may act for the group, and how a member proves it belongs, is an authorization question (Consumer Requirements item 10), answered by the governing Trust Task specification or the consumer’s trust framework rather than by the document envelope. The same holds for an audience that is bounded but not enumerable when the document is created: the group’s VID is therecipient, and a Trust Task specification defines how a presenter proves membership.
A VID is compared by exact string equality wherever this framework requires a VID-to-VID comparison (notably the in-band-vs-transport cross-check in Precedence of In-Band over Transport-Derived Identity, the recipient-enforcement rule in Consumer Requirements item 5, and the proof-binding rule in Proof). Producers SHOULD emit VIDs in their canonical form for the scheme in use — no leading or trailing whitespace, no normalization of case-sensitive segments, and (for schemes that admit equivalent forms) the form that the scheme’s authority designates as canonical. A consumer MAY reject a Trust Task document whose issuer, recipient, or any VID-typed payload member is not in canonical form with malformedRequest; a consumer that accepts non-canonical input MUST NOT silently normalize before applying any framework rule that compares the value — normalization changes the string, and the framework’s comparisons are over the unchanged bytes.
Both members are OPTIONAL. Their purpose is to let the parties be identified in-band where the transport in use does not already convey strong, authenticated party identity — for example, an unauthenticated HTTP POST, a public message queue, or paper hand-off.
Where a secure transport already conveys authenticated party identity (such as mutually-authenticated TLS or a signed DIDComm envelope), these in-band members MAY be omitted.
§ Precedence of In-Band over Transport-Derived Identity
The framework treats the in-band issuer and recipient members as authoritative for party identity. Specifically, for each party:
- If the in-band member is present, its value is the party identity that the consumer MUST apply for every subsequent framework rule that references that party — including, but not limited to,
proofverification (where applicable, see Proof), recipient enforcement (see Consumer Requirements, item 5), and Trust Task specification requirements that reference the party. The transport-derived identity is, in this case, only a cross-check: where both an in-band identity and a transport-derived identity are present for the same party, they MUST be consistent, and a consumer MUST treat a mismatch as a validation failure (see Consumer Requirements, item 6). - If the in-band member is absent, a consumer MAY derive the party identity from the transport — typically via the transport binding in use (see Transport Bindings) — and MAY treat the derived value as if it had been carried in-band for the purposes of subsequent rules. A consumer with no in-band value and no transport-derived value for a party that the Trust Task specification declares as REQUIRED MUST reject the document.
In short: the document is the source of truth for who the parties are. The transport, when it provides authenticated identity, is used either to fill in what the document omits, or to verify what the document asserts — never to override it.
An individual Trust Task specification MAY require either or both members to be present — for example, to support audit, third-party replay, or forwarding — but MUST NOT prohibit a consumer from comparing them with transport-derived identity.
Example 3 — A Trust Task document using non-DID Verifiable Identifiers (non-normative)
{ "id": "urn:uuid:0e9d4c2b-5f81-4d3e-9b51-7a3c89e3d1f2", "type": "https://trusttasks.org/spec/acl/change-role/0.1", "issuer": "x509:CN=Operations,O=Example Org,C=NL", "recipient": "x509:CN=Directory,O=Example Org,C=NL", "issuedAt": "2026-06-10T14:00:00Z", "payload": { "subject": "oidc:https://issuer.example/sub#user-94217", "fromRole": "member", "toRole": "moderator" } }Here
issuerandrecipientare X.509 subject distinguished names andpayload.subjectis an OIDC subject identifier. The framework treats any string identifier whose controller is verifiable under the consumer’s trust framework as a valid VID; DIDs are one realization among several. Theproofthe named specification requires is omitted for brevity; it plays no part in the point this example makes.
§ Audience Binding
When a Trust Task document carries a proof member, the document MUST also carry an in-band recipient member, unless the Trust Task specification identified by the document’s type declares itself a bearer specification (see Bearer Specifications).
This rule exists because a Data Integrity Proof covers the signed bytes — the issuer, payload, and other framework members — but does not cover any transport-derived identity. A document signed without an in-band recipient therefore provides no cryptographic binding between the producer’s assertion and the intended audience: an attacker who obtains the document — from a consumer’s storage, an intermediate cache, or an exfiltration — can replay the bytes to a different consumer without any signal that the original producer did not intend that audience to act upon them. A consumer receiving such a replayed document would otherwise verify the proof successfully, observe that no recipient constrains the assertion, and apply the producer’s claim to its own context.
A consumer receiving a proof-carrying document with no in-band recipient, where the originating Trust Task specification is not a bearer specification, MUST reject the document with a malformedRequest error response (see Error Responses).
Specifications that declare proof as REQUIRED (see Specification Requirements item 8) implicitly require recipient in-band for all non-bearer cases; the audience-binding rule and the proof requirement combine to ensure the document is self-contained for both producer identity and intended audience.
§ Bearer Specifications
A Trust Task specification whose payload carries an assertion meaningful to any consumer that can verify the producer’s identity — for example, a public attestation, a heartbeat, or a schema-publication announcement — MAY opt out of the Audience Binding rule by declaring itself a bearer specification. The opt-out is published in the specification’s front matter (see Specification Requirements item 12).
A bearer specification makes an explicit, normative claim that documents conforming to it are intended for unspecified consumption: any party that can verify the document’s proof (where present) is a legitimate recipient.
A bearer specification MUST:
- Declare
bearer: truein its front matter. - Declare its
recipientparty requirement as OPTIONAL (the audience-binding rule no longer applies). - State in its prose what assertion the document conveys and why audience binding is inappropriate for it.
A bearer specification SHOULD NOT carry any field in payload whose interpretation depends on the receiving party’s identity (for example, “balance owed to you”); such fields belong in audience-bound specifications.
The default for any Trust Task specification is non-bearer. Specifications MUST NOT declare themselves bearer unless the audience-free property is intrinsic to the assertion they publish.
§ The threadId Member
Every Trust Task document carries its own unique id (The id Member); a response document MUST NOT reuse the id of the document it is responding to. Correlating documents back to one another — for example, linking a response to its originating request — is the purpose of the threadId member, not the id member.
A Trust Task document MAY include a threadId member that correlates it with other Trust Task documents belonging to the same logical exchange — for example, a request and its response, or a request, an intermediate trust-task-next-step response, and the final result.
A producer that emits a Trust Task document in response to another Trust Task document SHOULD set threadId to the value of the originating document’s threadId. If the originating document carried no threadId, the producer SHOULD set threadId to the value of the originating document’s id. The effect of this convention is that every document in a logical exchange carries the same threadId, and that value can always be traced back to the id of the document that started the thread.
The framework places no constraint on the form of a threadId beyond requiring it to be a string. Producers initiating a new exchange MAY omit threadId entirely (single-shot tasks need no thread), MAY mint a fresh value (e.g. a UUID), or MAY reuse the document’s own id.
threadId carries no normative validation semantics. Consumers MUST NOT reject a document on the basis of threadId alone, but MAY use it for routing, correlation, aggregation, or audit.
Example 4 — Request and response correlated by
threadId(non-normative)A producer issues an initiating Trust Task document:
{ "id": "4f3c9e2a-1b81-4d3e-9b51-7a3c89e3d1f2", "type": "https://trusttasks.org/spec/acl/change-role/0.1", "issuer": "did:web:org.example", "recipient": "did:web:maintainer.example", "issuedAt": "2026-06-10T14:00:00Z", "payload": { "subject": "did:web:bob.example", "fromRole": "member", "toRole": "moderator" } }It carries no
proof, and the specification it names declares one REQUIRED, so the consumer refuses it. The original document carried nothreadId, so the responding party setsthreadIdto the originating document’sid:{ "id": "8a91c7b3-2e62-4a91-a3a4-9d61b75e2f01", "type": "https://trusttasks.org/spec/trust-task-error/0.2", "threadId": "4f3c9e2a-1b81-4d3e-9b51-7a3c89e3d1f2", "issuer": "did:web:maintainer.example", "recipient": "did:web:org.example", "issuedAt": "2026-06-10T14:00:02Z", "payload": { "code": "proofRequired", "retryable": false } }Both documents now share
threadId = 4f3c9e2a-1b81-4d3e-9b51-7a3c89e3d1f2; any subsequent document in this exchange — for example, a retry with a freshidand a validproof— would carry the samethreadId.
§ Naming an Exchange from Outside the Framework
A threadId names one exchange and expresses no relationship to any other. Exchanges nest in practice — a Trust Task conducted to complete a step of some broader interaction is still its own exchange, with its own threadId. The optional parentThreadId member (The parentThreadId Member) records that containment, but it is a navigation aid: it does not change which exchange attests an event, and the rule below holds whether or not it is present.
This matters whenever something outside the framework refers to an exchange as evidence that an event occurred: a credential that cites the exchange which established what it attests, an audit record, a governance decision that turns on some task having been performed. Nesting makes the reference ambiguous, because more than one thread was open when the event happened, and only one of them attests it.
The rule is that such a reference MUST name the innermost exchange whose documents attest the event being cited, and MUST name it by the id of the document that initiated that exchange — the value every document in the thread traces back to under the convention above (The id Member makes that id globally unique and non-reusable, which a threadId is not required to be).
Naming an enclosing exchange instead collects evidence of the wrong event. Where a witnessing ceremony is conducted inside a broader relationship exchange, for example, only the ceremony’s own response attests that the witnessing took place; the enclosing exchange’s response attests the relationship interaction and says nothing about the witnessing. A consumer verifying the outer reference would conclude something the documents do not support.
Naming the right exchange is necessary but not sufficient: an id identifies a document without binding the citation to it, so a citation relied upon outside the exchange also carries a digest over the document it names. See Binding a Citation to the Document It Names.
§ The parentThreadId Member
A Trust Task document MAY include a parentThreadId member whose value is the threadId of the exchange that contains this one. Its purpose is navigation: it lets a party holding a document from the inner exchange find the exchange it was conducted within, which a flat threadId cannot express.
The member takes the same posture as threadId (The threadId Member):
- A producer that emits a Trust Task document within an enclosing exchange SHOULD set
parentThreadIdto that exchange’sthreadId, and SHOULD carry the same value onto every document of the inner exchange — including its response and any error response — since the whole exchange shares one parent. - A producer MUST NOT set
parentThreadIdequal to the document’s ownthreadId. An exchange cannot contain itself. parentThreadIdcarries no normative validation semantics. Consumers MUST NOT reject a document on the basis ofparentThreadIdalone, but MAY use it for routing, correlation, aggregation, or audit.
The member records one level of containment. Reconstructing a deeper ancestry requires the intervening documents, and the framework defines no representation for a full chain; a specification needing one is better served by an explicit payload structure than by inferring it from thread metadata.
Where the transport carries its own parent-thread concept, the two MUST agree when both are present, and the in-band member remains authoritative for framework-level processing; see What a Transport Binding Specifies. A transport binding that maps the two states the rule for its own protocol.
Example 4a — A ceremony nested inside a broader exchange (non-normative)
A relationship exchange is under way on thread
9b1d…. Completing it requires a witnessing ceremony, which is its own Trust Task exchange with its own thread:{ "id": "urn:uuid:2c7f5e10-6a4b-4f8e-9d31-0b6a2f4c8e15", "type": "https://trusttasks.org/spec/webvh/witness/publish/0.1", "threadId": "urn:uuid:4a0e2b77-88c1-4d55-9f2a-6c3d1e5b7a92", "parentThreadId": "9b1d3f60-52a8-4c17-8e44-1d9c7b05f3ae", "issuer": "did:web:witness.example", "recipient": "did:web:host.example", "issuedAt": "2026-08-08T10:15:00Z", "payload": { "…": "…" } }A credential citing the witnessing as evidence anchors to this inner exchange, per Naming an Exchange from Outside the Framework — the enclosing exchange attests the relationship interaction, not the witnessing. The
parentThreadIdis what lets a holder of this document find that enclosing exchange; it is not what the citation names.
§ Binding a Citation to the Document It Names
Naming an Exchange from Outside the Framework requires an external citation to name an exchange by the id of the document that initiated it. An id is a name. The id Member obliges a conforming producer to mint it globally unique and never to reuse it, but that obligation constrains conforming producers and nobody else: anyone may write a different document — different parties, different payload — and give it the same id. A consumer that pairs a citation with a document by comparing ids alone accepts that substitute, and then reports an event the documents do not attest.
A citation that will be relied upon by parties outside the exchange SHOULD therefore carry, alongside the id, a task digest over the document it names. Where a citation carries one, it MUST be computed as:
taskDigest = multibase( multihash( H( JCS( document ∖ proof ) ) ) )
where:
document ∖ proofis the Trust Task document with its top-levelproofmember removed where present, and no other member removed or added. Aproofappearing withinpayload— in an embedded presentation, credential, or other artifact — is part of that payload’s content and MUST NOT be removed. Where the document carries no top-levelproof, the input is the document unchanged; no placeholder is substituted.JCSis the RFC 8785 canonicalization, serialized as UTF-8, as used elsewhere in this framework.His any hash function expressible in multihash; the multihash prefix declares which, so the algorithm is not fixed by this specification and survives an algorithm change without a format revision. SHA-256 is RECOMMENDED.- The result is encoded as a multibase-encoded multihash, per the
DigestMultibasedefinition of the framework’s shared schema component (Shared Schema Components).
The top-level proof is excluded because Proof already defines it as excluded from the content a proof covers. The digest and the document’s own signature therefore commit to the same content, and a document has exactly one task digest whether or not anyone ever signed it. A digest whose input included proof would be undefined for the documents When to Include a Proof permits to carry none, and would change value the moment a document was signed — so a citing party and a verifying party computing it at different points in the document’s life would disagree.
A consumer verifying a citation MUST recompute the digest from the document it holds — removing the top-level proof first, where present — and MUST compare the decoded multihash bytes, not the encoded strings. DigestMultibase admits more than one base encoding, and two conforming encodings of the same digest are different strings; a string comparison rejects a valid pairing. A consumer that does not implement the hash algorithm named by the multihash prefix MUST treat the citation as unverified: it MUST NOT recompute under a different algorithm, and MUST NOT fall back to id comparison alone.
This is not the document identity of Consumer Requirements item 11. The two answer different questions and are deliberately computed differently. Item 11 and Retry Semantics ask which serialization arrived, so a re-signed proof over identical content makes a different document — that is the idConflict case, and the distinction is the whole point of the rule. A citation asks what the document says, so the same statement signed, unsigned, or re-signed is one document with one task digest. A specification requiring the bytes-as-received sense — trust-ceremony-receipt’s step digest, for one — states so and computes over the document including its proof; it is not applying this section loosely.
The framework names the two, because both have until now been called digestMultibase in the places they appear and the difference between them is load-bearing:
taskDigest |
stepDigest |
|
|---|---|---|
| Asks | What does the document say? | Which serialization arrived? |
| Input | The document with its top-level proof removed |
The document including its top-level proof, plus any salt the defining specification requires |
| The same statement, signed and unsigned | One value | Two values |
| The same content, re-signed | One value | Two values |
| Defined by | This section | The specification that requires the bytes-as-received sense |
| Used for | Binding a citation made outside the framework to the document it names | Chain of custody: the step chain of an enactment (ceremony.prev, trust-ceremony-receipt), and the document identity Consumer Requirements item 11 keys idConflict on |
Both are computed with JCS, a multihash-tagged hash, and a multibase encoding over a Trust Task document, and both are carried in a member of the DigestMultibase shape (Shared Schema Components). The only structural difference is the treatment of the top-level proof, and it is the whole of the difference in meaning: excluding it makes the digest a property of the statement, so that a document has one task digest whether or not anyone ever signed it; including it makes the digest a property of the artifact, so that a re-signed document is a different document — which is exactly what a custody chain and an idConflict check need it to be.
These are names for prose and for implementations. Neither is a document member: the members that carry these values keep the names their own specifications give them. The naming exists because an implementation with a single function called digestMultibase has, in practice, picked one of these two answers and is applying it to both questions — and whichever it picked, it is wrong for one of them.
What a task digest establishes, and what it does not (this note is non-normative)
Recomputation is unconditional: content that differs cannot produce the value, and there is no string for a substitute document to copy. That is why a digest is preferred here to the cited document’s own
proofvalue. AproofValueis a string, and a string can be pasted verbatim onto a counterfeit; it binds only behind full signature verification — canonicalize, hash, resolve the signer’s verification method, verify — which costs more than the digest recompute and is unavailable entirely for the documents When to Include a Proof permits to carry noproofat all.The digest attests content, not authenticity. It is load-bearing because the citing artifact carries it under the citer’s own signature: a party cannot obtain a signature over a digest of a document the signer never saw, so a counterfeit that borrowed the
idfails the pairing no matter who wrote it. It says nothing about whether the cited document itself was signed, and aproof-stripped copy of a genuine document reproduces the same value by design. Authenticity of the exchange comes from the documents’ own proofs under When to Include a Proof — a specification whose citations must also establish that the cited document was attributable MUST require aproofon it, and MUST NOT rely on the task digest for that.
§ Evidence That a Cited Exchange Completed
Binding a Citation to the Document It Names fixes which exchange a citation names. It says nothing about whether that exchange completed. A credential can cite an exchange that was cancelled, that failed, or that is still open, and its citation still binds — the initiating document exists in every one of those cases. A party relying on a citation as evidence that the cited event occurred therefore needs a second artifact: a terminal document showing that the task reached responded (Document Lifecycle). This section defines that pairing once, so that a Trust Task specification whose exchanges are cited states only what is particular to it.
Outcome evidence for a cited exchange is the exchange’s initiating document together with a terminal document satisfying the rules below. A consumer relying on a citation as evidence that the cited exchange completed MUST confirm all four, and MUST NOT treat the citation as evidence of completion otherwise:
- The citation binds the initiating document. The initiating document’s
idequals the citation, and the citation’s task digest reproduces over that document under Binding a Citation to the Document It Names. - The terminal document belongs to that exchange. Its
threadIdequals the initiating document’sthreadIdwhere the initiating document carries one, and the initiating document’sidwhere it does not. Pairing runs through the initiating document because ThethreadIdMember permits an initiator to mint athreadIdunrelated to itsid; a rule that compares the terminal’sthreadIdwith the citation directly rejects every conforming exchange whose initiator did so. A matchingthreadIdis necessary but not sufficient: athreadIdis not required to be unique (Naming an Exchange from Outside the Framework), and the obligation not to carry one across exchanges (Identifier Correlation and Linkability item 2) binds conforming producers and nobody else. The terminal document MUST therefore also satisfy the binding to the initiating document that the governing Trust Task specification declares under Specification Requirements item 20.5, which its ownproofcovers. - The terminal document is the declared outcome evidence. Its
typeis a success response that the Trust Task specification governing the initiating document declares as that exchange’s outcome evidence under Specification Requirements item 20. A document of any other type in the same thread attests something else: an error response reportserrored, orcancelledwhere the consumer stopped of its own accord; the response to atrust-task-controldocument reports that the task was stopped at the producer’s request (Task Control), and is itself a#response;trust-task-next-stepreports it blocked (Reserved Response-Type Slugs). The declaration is needed because an exchange need not close with the response to its own initiating document: a session opened under one specification may close with the response to a task conducted on its thread under another. - The terminal document was produced by the party the exchange was addressed to. Its
proofverifies, and the party it verifies under is the initiating document’srecipient, which item 20 requires the initiating document to carry; where it is absent, this check fails. A proof that verifies under the document’s ownissuershows only that someone signed it — a party holding the initiating document can sign a well-formed response itself. The responder is not in general the issuer of the citing artifact: where a vetter opens a session with an applicant and later issues the credential citing it, the terminal response is the applicant’s.
A consumer that does not hold outcome evidence satisfying these rules MUST treat the citation as not evidencing completion, whether or not such evidence exists elsewhere. That does not by itself invalidate the citing artifact, whose own validity is a matter for the specification that defines it. Discovering or retrieving outcome evidence a consumer does not already hold is out of scope for this version of this framework: a party relying on a citation as evidence of completion SHOULD carry both documents of the outcome evidence with the citing artifact, and the governing specification’s retention class (Specification Requirements item 18) states that they are expected to be kept for that purpose.
Why four checks, and not fewer (this note is non-normative)
Each check closes a case that a rule without it decides wrongly. Without check 2’s route through the initiating document, an honest exchange whose initiator minted its
threadIdfails; without its declared binding, a genuine success response from an earlier exchange whose initiator reused thethreadIdwith the same counterparty reads as completion of a later one. The binding is to the initiating document’sidand task digest wherever it can be: a fresh value such as a challenge is also minted by the initiator. So it closes that case only where the initiator is the party whose word the citing artifact already rests on, and item 20.5 permits it only there. Without check 3, a cancelled task’s control response — a#responsein the same thread, under a valid proof — reads as completion. Without check 4, a response signed by the holder of the initiating document reads as the counterparty’s. And naming the terminal type as the initiating document’s type with the#responsefragment, rather than as a declaration, rejects the witnessing ceremony: it opens withwitness/sessionand closes withwitness/session/submit#response.
witness/session/submit/0.1andvetting/session/0.1each state their own pairing today, and each is consistent with this section for its own exchange: both require the initiator to setthreadIdequal toid, and both name their evidence. What neither can do is generalize — the first identifies the responder as the credential’s issuer, which is true of witnessing and not of vetting — which is why the rule is stated here, once. Neither yet makes the declaration item 20 asks for —witness/session/0.1because that declaration belongs to the specification governing the initiating document rather than towitness/session/submit/0.1,vetting/session/0.1because it names no binding — though each already carries the binding it would name: the submit response’svwccarriestaskContextandtaskDigestMultibase, and the vetting response’scardis presented against the session’s freshly generatedchallenge.
§ Naming Conventions
JSON member names and enumerated string values in Trust Task documents follow the casing rules below, so that documents are consistent across specifications both for human readers and for code generators.
-
Framework-defined members. Every member defined by this framework —
id,threadId,parentThreadId,type,issuer,recipient,issuedAt,expiresAt,payload,proof,ceremonyand its members,extCritical, and the members of the error payload in Error Payload — MUST be named in lowerCamelCase. The sole exception is@context, which is named as required by JSON-LD. -
Framework-defined values. Enumerated string values defined by this framework — notably the standard error
codeidentifiers of Standard Error Codes — MUST be expressed in lowerCamelCase. -
Payload member names. A Trust Task specification SHOULD name the members of its
payloadin lowerCamelCase. A specification MAY deviate only where it embeds a member whose name is fixed by an external vocabulary (for example, a field copied verbatim from a WebAuthn or JOSE structure), and it SHOULD confine such foreign naming to the embedded sub-object. -
Specification-defined values. String values drawn from a closed set that a Trust Task specification itself defines — statuses, kinds, decisions, event types, extended error
codeidentifiers — SHOULD be expressed in lowerCamelCase (for example,cacheAndKeys,stepUp,proofInvalid). -
Externally-owned values. A value whose canonical form is fixed by an external specification MUST be carried verbatim and MUST NOT be re-cased, because the framework compares such values by exact string equality (see The
issuerandrecipientMembers). Examples include WebAuthn enumerations (public-key,cross-platform), JOSE algorithm identifiers (EdDSA,ES256), cookieSameSitevalues (Lax,Strict), and W3C Data Integrity type and purpose values (DataIntegrityProof,assertionMethod). -
Out of scope. This section does not govern slugs (lowercase, hyphen-separated; Type URI) or
extnamespace keys (reverse-DNS; TheextExtension Member); each retains its own grammar.
A change to the casing of an existing member name or specification-defined value is a breaking change and follows the rules of Versioning; the re-casing introduced in framework version 0.2 is recorded in Appendix B.
§ The ceremony Member
Some outcomes take more than one Trust Task. A governance decision may need several endorsements; an onboarding may span a witness and a registry. The framework’s model for these is settled in Terminology — they are multiple bilateral Trust Tasks — but the collection itself had, until framework version 0.4.0, no name, no identifier, and no way to be evidenced.
A Trust Ceremony is such a collection: a flow of Trust Tasks, optionally described by a published ceremony definition (Ceremony Namespace), of which one run is an enactment. A Trust Task document MAY carry a ceremony member recording that it is one step of an enactment.
The member’s value is an object with the following members. Its full schema is published with the framework envelope schema for this version.
| Member | Required | Type | Description |
|---|---|---|---|
enactment |
MUST | string | Identifies one run of a ceremony. Globally unique and never reused, on the same terms as id (The id Member). |
step |
MUST | string | Names this step within the ceremony. |
definition |
MAY | string (URI) | The ceremony definition this step is enacted under, rooted at Ceremony Namespace. |
definitionDigest |
MUST where definition is present |
string | A multibase-encoded multihash over the RFC 8785 canonicalization of that definition. |
parentEnactment |
MAY | string | The enactment containing this one, where a ceremony is conducted as a step of another. |
round |
MAY | integer | Distinguishes repetitions of the same step by the same party. Absent means 1. |
terminal |
MAY | boolean | Marks a step that ends the enactment. |
prev |
MAY | array | The steps this one follows, each an object of id and digestMultibase. |
§ Ceremony Membership Is Optional
The ceremony member is optional in every sense that matters, and this is a normative property rather than a convenience:
- A Trust Task specification needs no awareness of ceremonies. The member is carried on the document, not in
payload, so any existing specification may be used as a ceremony step with no change to its schema and no new version. A specification MAY refer to ceremonies in its prose — for example, to name a ceremony definition in which the task is commonly a step — but MUST NOT make a document’s conformance depend on whether it is a ceremony step, and MUST NOT define or constrain theceremonymember. - A Trust Task document without the member is fully conforming.
- A consumer that does not implement ceremonies MUST process such a document exactly as it processes any other, under the unrecognized-member rule of Consumer Requirements.
§ The Identifiers Are Orthogonal
enactment does not replace threadId and is not a form of parentThreadId. Within a ceremony, threadId scopes one step’s request/response exchange exactly as it does elsewhere, and enactment scopes the flow across all of its steps; a producer sets both. The steps of an enactment are typically siblings — several top-level exchanges, none conducted inside another — which is containment’s opposite and not what parentThreadId records.
The distinction that matters for evidence is that enactment MUST be globally unique and non-reusable where threadId need not be (The threadId Member). A reference naming a flow as evidence therefore names the enactment, under the rule of Naming an Exchange from Outside the Framework.
§ Ceremony Integrity
Where a proof is present it covers the ceremony member as it covers any other (Proof). This is the member’s placement rationale, not an incidental consequence: a signed enactment cannot be lifted into a different flow, and a signed definitionDigest cannot be reinterpreted under a definition that gives the step’s name another meaning. Carried as transport metadata or as an unsigned sidecar, the member would provide neither guarantee.
A producer MUST NOT set parentEnactment equal to the document’s own enactment; an enactment cannot contain itself. A producer SHOULD carry the same ceremony.enactment onto every document of the step it names, including any error response.
§ Membership Is a Claim, Not a Permission
A ceremony member is an assertion by the document’s issuer that this document belongs to the named enactment. A consumer can check what it holds — that a step matches the definition, that a prev digest resolves — but cannot verify from one document that the enactment exists as described.
Accordingly:
A consumer MUST NOT grant any authority on the basis of ceremony membership alone.
Every authorization decision continues to be reached under Consumer Requirements item 10, exactly as for a document carrying no ceremony member — and note that verifying issuer and proof is not by itself such a decision. Without this rule the member would be a confused-deputy vector: “you are in the onboarding ceremony, so perform this step” is an unauthenticated assertion by whoever composed the document. The rule is also what makes Ceremony Membership Is Optional item 3 safe — because membership authorizes nothing, a consumer that ignores the member entirely omits nothing it was entitled to do.
ceremony otherwise carries no normative validation semantics: a consumer MUST NOT reject a document on the basis of the member alone, and MAY use it for routing, correlation, aggregation, or audit.
§ Document Lifecycle
Every rule in this framework that governs what a consumer may do next presupposes a state the document is in. Consumer Requirements item 4 governs acceptance; item 11 governs a document already accepted; item 12 governs execution under way; Task Control suspends and cancels accepted work; Error Responses reports a refusal. Each of those sections describes the state it needs and none of them names the whole set, so implementations have inferred five overlapping lifecycles from one document.
The states below are that set, stated once. They are normative: the state names are the vocabulary the rest of this specification’s cross-references are to be read against, and a transport binding maps them onto its own protocol under the rule at the end of this section.
| State | Reached when | Permitted next states | Reserved reply that carries the transition | What silence in this state means |
|---|---|---|---|---|
received |
The consumer holds the document’s bytes and has not yet validated them. | validated, errored, expired |
— | Nothing. A producer cannot distinguish a document in received from one that never arrived. |
validated |
Every applicable check of Consumer Requirements items 1–10 and 13 has passed. | accepted, errored, expired |
— | Nothing. Validation is internal to the consumer and is never signaled on the wire. |
accepted |
The consumer has committed to execute and has written the duplicate-execution record of Consumer Requirements item 11. | executing, suspended, cancelled, errored |
trust-task-next-step — reported understood but blocked; the document remains accepted and the exchange stays open (Reserved Response-Type Slugs). |
Nothing. Acceptance is not acknowledged unless the specification defines a reply that acknowledges it. |
executing |
Work has begun. Expiry no longer bounds it (Consumer Requirements item 12). | responded, errored, cancelled, suspended |
— | Nothing. In particular, silence here is indistinguishable from accepted and from responded. |
suspended |
A valid, authorized suspend has been received and recorded (Suspension and Resumption). | executing (on resume), cancelled, expired |
The response to the trust-task-control document that suspended it. |
Nothing. A producer MUST NOT infer suspension, lapse, or resumption from the absence of a notification (Notifications, and the Meaning of Silence). |
responded |
The outcome has been delivered. Terminal. | — | <type>#response, whose payload is {} where the specification defines no success response and the consumer acknowledges as a courtesy (Request and Response Variants). |
Nothing. Where no acknowledgement is sent, silence is consistent with this state and with every state above it, and MUST NOT be read as success. |
errored |
The consumer has refused, failed, or abandoned the work. Terminal. | — | trust-task-error (Error Responses). |
Nothing. A consumer returns an error response where the transport permits one; where it cannot, the failure is unobservable to the producer. |
cancelled |
A valid, authorized cancel has taken effect, or the consumer stopped on its own initiative. Terminal (When a Control Operation Takes Effect). | — | The response to the trust-task-control document, for a producer-requested cancellation; trust-task-error carrying cancelled where the consumer stopped of its own accord (Standard Error Codes). |
Nothing. The two directions are distinguished by which reply arrives, never by which one does not. |
expired |
now ≥ expiresAt was reached before the document was accepted, or before a suspended document was resumed. Terminal. |
— | trust-task-error carrying expired, where one can be returned. |
Nothing. Expiry is evaluated by the consumer’s clock and is not announced. |
The re-arrival of a document already in accepted or any later state is not a state transition: Consumer Requirements item 11 requires the consumer to absorb it, and the disposition of a duplicate rule of that section governs what, if anything, it returns. A re-arrival whose content differs is a different document and is refused with idConflict.
Silence signifies no state. Four sections of this framework have had occasion to say what an absent reply means, and they have not said the same thing: a fire-and-forget task treats it as success, trust-task-ok says its absence “carries no information”, Consumer Requirements item 11 uses it to mean a duplicate absorbed, and Notifications, and the Meaning of Silence says a lost control notification means nothing at all. Only one of those readings is safe, and this table settles on it: the absence of a reply distinguishes no two states in the table above, and a producer MUST NOT infer any state from it. The framework already warns that the silence of item 11 “must not be reused to signify work half-done” (Consumer Requirements); the general rule is that it may not be reused to signify anything.
The consequence for a fire-and-forget specification is that its consumer now has a way to say “received and done” positively rather than by not speaking — the empty #response of Request and Response Variants — and its producer still MUST NOT rely on hearing it.
A transport binding MUST map this table. A transport binding (Transport Bindings) MUST state, for its own protocol, which protocol event or status corresponds to each state above, or state explicitly that its protocol expresses no counterpart for a given state. A binding that leaves the mapping implicit invites the substitution this section exists to prevent — an HTTP 202 read as accepted, an acknowledged queue delivery read as executing, a closed connection read as cancelled (Transport-Level Cancellation Is Not Semantic Cancellation) — each of which reports a document state from a transport fact that does not establish it.
§ Versioning
This section is normative.
§ Version Scheme
Every Trust Task specification MUST carry a version of the form MAJOR.MINOR, where MAJOR and MINOR are non-negative decimal integers without leading zeros (except for the value 0 itself). Patch-level versions are not used for Trust Task specifications; this framework specification is itself versioned as MAJOR.MINOR.PATCH, per Versioning of This Framework Specification. The grammar, in RFC 5234, is:
version = major "." minor
major = "0" / nonzero *DIGIT
minor = "0" / nonzero *DIGIT
nonzero = %x31-39 ; "1".."9"
§ Versioning of This Framework Specification
This framework specification’s _Version:_ header field states the version that a wider ratifying body confirms when this framework reaches Working Group Approved Deliverable or ToIP Approved Deliverable status; it is currently 1.0 and not yet ratified. The MAJOR.MINOR.PATCH number described in the remainder of this section — the one embedded in this framework’s Type URI, in every target framework version declaration, and in the changelog of Appendix B — is carried instead in the header’s _Document Status:_ field, as Working Draft MAJOR.MINOR.PATCH, and is what a specification or consumer actually targets and resolves against.
This framework specification is itself versioned under Semantic Versioning 2.0.0, as MAJOR.MINOR.PATCH. A MAJOR increment marks a change that is breaking for consumers implementing this framework or for the specification-authoring contract of Specification Requirements; a MINOR increment marks a backwards-compatible addition, such as a new optional document member or a new reserved slug; a PATCH increment marks a correction — errata, clarified prose, a repaired example — that changes neither the wire format nor what a conforming Trust Task specification must declare. The grammar extends the production above:
framework-version = major "." minor "." patch
patch = "0" / nonzero *DIGIT
The three-part form applies to this document alone. Every individual Trust Task specification carries the two-part MAJOR.MINOR version defined above, and that includes the framework-defined specifications published under the reserved trust-task- and trust-ceremony- prefixes of Type URI — trust-task-error/0.4 is a Trust Task specification and versions like one. Only the exact reserved slug trust-task, which addresses this document, carries a PATCH component.
This framework is published in the registry at its full three-part version. Its own Type URI is https://trusttasks.org/spec/trust-task/<MAJOR.MINOR.PATCH> (Schema Scope), and the target framework version a specification declares (Specification Requirements item 3) is that same three-part value. A PATCH release therefore mints a new framework Type URI rather than editing the representation served at an existing one — which is what Stability already requires of every other artifact in the registry, and what errata applied in place to a published framework version would otherwise violate.
Publishing a PATCH obliges no specification to move. A specification targeting 0.4.0 remains conformant when 0.4.1 is published; re-targeting is an ordinary version bump of the specification itself, sequenced as in Migrating Between Versions. A consumer MUST validate the outer document against the framework version its specification targets and MUST NOT substitute a different PATCH, for the reason given for shared schema components in Shared Schema Components item 2: a pin that resolves to “whatever is latest” lets a later change alter an already-published wire contract silently.
Framework releases published before this rule — 0.1 through 0.4 — denote the releases now written 0.1.0 through 0.4.0; 0.4 and 0.4.0 are the same release, and the entries in Appendix B are unchanged by the renumbering. Specifications already published against a two-part target framework version remain conformant: a consumer MUST resolve a two-part value M.N as M.N.0, and the registry MUST continue to serve the two-part framework URIs https://trusttasks.org/spec/trust-task/0.1 through /0.4 as aliases of the corresponding .0 release, so that no already-published specification stops resolving. A specification published or re-issued from this version onward MUST declare the three-part form.
§ Ratification and the Stable Release Line
This subsection governs the transition between this framework specification’s own _Version:_ and _Document Status:_ header fields as the document moves from Working Draft to a ratified deliverable, and back again for its next major revision. It applies to the framework document itself; the draft/candidate/standard/retired lifecycle of Maturity Levels governs individual Trust Task specifications and shared schema components and is unaffected by it.
Before this framework specification’s first ratification, Document Status MAY remain at MAJOR 0 even across a breaking change — mirroring the allowance Compatibility Rules gives an individual draft-status artifact — since SemVer 2.0.0 §4 already treats 0.y.z as carrying no compatibility guarantee. _Version:_ does not move during this phase; it states the release a wider ratifying body is being asked to confirm, not the draft’s own churn.
At the moment a wider body ratifies this framework specification as a Working Group Approved Deliverable or ToIP Approved Deliverable, Document Status’s MAJOR component crosses from 0 to 1 — not as an arbitrary convention, but because that crossing is what SemVer 2.0.0 §4 defines 1.0.0 to mean: “defines the public API.” The header’s status label changes from Working Draft to the ratified label, and _Version:_ is confirmed at the matching MAJOR.MINOR.
From that point on, _Version:_ and Document Status’s MAJOR.MINOR MUST carry the same value; they differ only in the status label that prefixes Document Status. A MINOR increment approved by the ratifying body — a backwards-compatible addition ratified after the initial release — updates both fields together. A PATCH increment — errata with no effect on conformance — updates Document Status alone; it MUST NOT require _Version:_ to change, since _Version:_ states what a consumer targets and a PATCH by definition changes nothing a consumer must resolve against.
Work toward the next breaking revision resumes the two-field split: the first breaking change made against a ratified MAJOR.MINOR line MUST increment Document Status to the next MAJOR.0.0 immediately, with the status label reverting to Working Draft, by the ordinary rule of Compatibility Rules — this is unconditional once ratified, unlike the pre-first-ratification allowance above. _Version:_, however, MUST NOT advance to that new MAJOR until the new line is itself ratified; it continues to state the last-ratified release throughout the new line’s drafting, for the same reason it does not move with each Working Draft revision before a first ratification.
§ Compatibility Rules
A change to a Trust Task specification MUST be classified as either backwards-compatible or breaking:
- A backwards-compatible change — for example, adding an optional member, relaxing a constraint, adding a permitted enumeration value to a non-discriminating field, or clarifying prose — MUST result in a
MINORincrement. - A breaking change — for example, adding or removing a required member, removing a permitted enumeration value, narrowing a constraint, or changing the semantics of an existing member — MUST result in a
MAJORincrement, withMINORreset to0.
Implementations of a given Trust Task specification at version M.N MUST accept documents conforming to any version M.K where K ≤ N.
Forward minor-version compatibility is also intended: because a MINOR increment is by definition backwards-compatible, an implementation at M.N SHOULD accept a document at M.K where K > N, provided it can ignore any payload members it does not recognize and the document otherwise validates against the framework schema and the M.N payload schema known to the implementation. A consumer that elects not to support forward minor-version processing MUST reject such documents with an unsupportedVersion error response (see Standard Error Codes).
A MAJOR mismatch is never forward-compatible: a consumer at M.N MUST reject any document whose Type URI carries a MAJOR segment it does not implement, returning unsupportedVersion where the transport permits a response.
This paragraph is non-normative. Consumers that implement forward-minor compatibility typically route documents by matching the Type URI’s slug and MAJOR segment and selecting the highest MINOR they implement. A consumer that routes by exact-URI equality (slug + MAJOR.MINOR) is conformant — strict matching is permitted by Compatibility Rules — but precludes the forward-minor SHOULD; downstream implementations choosing strict matching should document the trade-off.
While a Trust Task specification — or a shared schema component (Shared Schema Components) — is at draft status (Maturity Levels), its schema and prose MAY change without notice. Accordingly, a breaking change to a draft artifact MAY be released as a MINOR increment rather than a MAJOR one. Once an artifact reaches candidate, standard, or retired, the classification above applies strictly: every breaking change MUST increment MAJOR.
A narrower rule applies within draft: an editorial or normalization change to a draft artifact — re-casing an enumerated value or member name into conformance with Naming Conventions, re-pinning a $ref to a newer framework or shared schema component version where the re-pin does not change the payload’s effective wire shape, or rewording descriptions and other prose — MUST be made in place, errata-style, within the existing version, and MUST NOT mint a new version. Such a change carries no semantic difference on the wire; publishing it as a new version inflates the registry, grows the generated libraries, and forces implementations to straddle wire-identical versions for no behavioral gain. At draft status this in-place rule takes precedence over the version-coupling rule of Shared Schema Components; from candidate onward the classification above applies strictly — a re-cased value, in particular, is a breaking change (Naming Conventions). A version that was nonetheless minted for a purely editorial change MAY declare the optional wireCompatibleWith front-matter field, naming the wire-identical predecessor version, so that consumers can dual-accept documents of the predecessor by mechanical normalization rather than a hand-written adapter.
§ Maturity Levels
A Trust Task specification progresses through a defined lifecycle, captured by its status value. The lifecycle is normative: implementations and the registry use status to decide whether a specification can change underfoot, whether new documents SHOULD be issued against it, and how the bare-URL redirect in Type URI resolves. The maturity level is independent of the MAJOR.MINOR version number.
| Status | Meaning | Schema stability (Stability) |
|---|---|---|
draft |
Working draft. The schema and prose MAY change without notice. | Not stable. |
candidate |
Schema is frozen except for editorial clarifications. The specification MUST demonstrate two independent, interoperable implementations to enter this status. | Stable. |
standard |
Stable in the long term. A candidate specification MUST complete a continuous 90-day stability window with no breaking changes before promotion to standard. |
Stable. |
retired |
Specification is no longer recommended for new use; preserved for historical reference and to keep already-issued documents verifiable. The schema and prose are frozen at the moment of retirement. | Stable. |
§ Permitted Transitions
A status value MUST change only along one of the transitions below:
draft→candidate— once the entry criteria forcandidateare met.candidate→standard— once the 90-day stability window has elapsed without breaking changes.draft→retired— abandoning a working draft.candidate→retired— deprecating a candidate before standardization.standard→retired— sunsetting a standard after a successor has been published.
retired is terminal: a retired specification MUST NOT transition back to any earlier status. To revive functionality, the editor publishes a new MAJOR.MINOR of the slug starting at draft (see Version Scheme).
§ Behaviour at Each Status
- Producers MAY emit documents whose
typeresolves to adraft,candidate, orstandardspecification. Producers SHOULD NOT emit documents against aretiredspecification. - Consumers MUST treat
draft,candidate,standard, andretiredspecifications identically for the purpose of schema validation (the framework rules in Consumer Requirements apply uniformly). Consumers SHOULD surface a deprecation signal — in logs, audit records, or downstream interfaces — when a received document’styperesolves to aretiredspecification, so operators can plan migration. - A
retiredspecification SHOULD declare its successor via the optionalsupersededByfront-matter field (see Specification Requirements).
A specification’s current status is recorded in its front matter and reflected in the registry at https://trusttasks.org/. The same lifecycle applies to this framework specification itself.
The process by which a slug is assigned, by which a specification enters the registry, and by which its status is updated is governed by the registry policy maintained alongside the registry at https://trusttasks.org/. That policy is out of scope for this framework specification.
§ Migrating Between Versions
This section is informative.
When a Trust Task specification makes a breaking change — including adopting a new version of a shared schema component (Shared Schema Components) — implementers are encouraged to migrate using an expand-then-contract sequence that keeps both versions interoperable throughout, so that no single deployment step requires producers and consumers to change in lockstep:
-
Author the new version. Publish the new specification version —
M.(N+1)for a backwards-compatible change, or(M+1).0for a breaking change at non-draftstatus (a breaking change atdraftmay use aMINORincrement per Compatibility Rules). If the change is driven by a shared schema, publish the new shared schema component version first and re-pin the specification’s$refto it (see the coupling rule below). The previous specification version remains published and unchanged. -
Update receivers first. Deploy consumer support for the new version alongside the old, so a consumer accepts documents of both the old and the new version. Because no producer is emitting the new version yet, this step is safe to roll out on its own. For a
MINORincrement, a forward-minor-compatible consumer (Compatibility Rules) may already accept the new version with no code change; for aMAJORincrement the consumer must add explicit support before any producer emits it. -
Update senders. Once receivers across the deployment accept the new version, deploy producer support so producers begin emitting the new version. Traffic shifts to the new version while consumers continue to accept any stragglers still on the old one.
-
Retire the old version. After traffic has fully migrated and any applicable stability window has elapsed, transition the old version to
retired(Maturity Levels) and declaresupersededBypointing at the new version. Producers stop emitting the old version; consumers may drop support for it on their own schedule.
Coupling of schema and specification versions. A Trust Task specification and its payload JSON Schema are a single versioned artifact — the schema’s $id is the specification’s Type URI (Schema Scope) — so any change to the payload schema is, by definition, a new specification version. A shared schema component (Shared Schema Components) versions independently, but a specification cannot adopt a new shared schema component version without issuing a new version of itself: re-pinning a $ref changes the specification’s effective wire contract. A specification MAY instead remain pinned to the older component version and not bump.
§ Namespace
This section is normative.
The framework defines a single namespace per versioned Trust Task specification. In the public registry, one canonical URL serves human-readable prose, machine-readable schemas, and (where defined) JSON-LD contexts, differentiated by HTTP content negotiation.
§ Type URI
Every versioned Trust Task specification MUST be addressable by a Type URI — an absolute URI in the sense of RFC 3986. The canonical, public-registry form is:
https://trusttasks.org/spec/<slug>/<MAJOR.MINOR>
A Trust Task specification published through the public registry MUST use this form. Trust Task specifications intended only for private or internal use — and not published through the public registry — MAY use any other absolute URI — an https URL, a DID URL, a URN, or a URI of another scheme — in one of the two shapes below. The requirements that apply to those are given in Private and Unpublished Trust Task Specifications.
<prefix>/spec/<slug>/<MAJOR.MINOR> path form
urn:<NID>:<prefix>:spec:<slug-segments>:<MAJOR.MINOR> URN form
A Type URI whose scheme is urn MUST use the URN form; every other Type URI MUST use the path form. In the URN form, the /-delimited segments of <slug> are written :-delimited, so that the slug acl/grant appears as acl:grant. Examples:
https://trusttasks.org/spec/acl/grant/0.1 public registry
https://example.com/trust-tasks/spec/acl/grant/0.1 private, https
did:example:123456789abcdefghi/spec/acl/grant/0.1 private, DID URL
urn:example:tasks:spec:acl:grant:0.1 private, URN
A Type URI is a name. A consumer identifies the Trust Task specification a document conforms to by comparing its type with the Type URIs it supports by exact string equality, preserving any fragment (Request and Response Variants). Nothing in this framework requires a consumer to dereference a Type URI in order to process a document. Dereferencing under Content Negotiation is one way to obtain a specification’s representations, and applies only to a Type URI whose scheme is https; for any other scheme the representations are distributed out of band (Private and Unpublished Trust Task Specifications item 4).
For every form, the components below carry identical meaning:
- The URI scheme MUST NOT be
http. Every representation served at anhttpURI lacks transport-layer authentication and integrity, and permitting it would normalize a transport-downgrade path for any consumer that dereferences the URI. A Type URI whose scheme ishttpis non-conformant in every form. <slug>is a lowercase, hyphen-separated short name assigned to the specification, optionally organized into one or more path segments (e.g.trust-task-discovery, oracl/grant). The slug MUST match the regular expression^[a-z][a-z0-9]*(-[a-z0-9]+)*(/[a-z][a-z0-9]*(-[a-z0-9]+)*)*$. Each/-delimited segment MUST individually satisfy the single-segment grammar (^[a-z][a-z0-9]*(-[a-z0-9]+)*$); consecutive hyphens are not permitted within a segment, and consecutive slashes are not permitted between segments. Segments group related specifications under a shared namespace and are reflected verbatim in the path of a path-form Type URI, or with each/written as:in the URN form —https://trusttasks.org/spec/acl/grant/0.1is the Type URI of a specification whose slug isacl/grant. A slug is unique only within its authority: a private specification (Private and Unpublished Trust Task Specifications) may use a slug the registry also uses, and the two are different specifications. A Type URI identifies a specification by its whole string, never by its slug alone.<MAJOR.MINOR>is the specification version as defined in Version Scheme. The sole exception is the reserved slugtrust-task, which addresses this framework specification and carries a three-part<MAJOR.MINOR.PATCH>segment instead (Versioning of This Framework Specification); every other slug, the framework-defined ones included, carries the two-part form. When resolving a Type URI, a consumer identifies the version as the final segment — the final path segment in the path form, the final:-delimited segment in the URN form — which always matches one of the two version grammars, and the slug as the segments between the first/spec/(path form) or the first:spec:(URN form) and the version. In the URN form the slug’s segments are rejoined with/, sourn:example:tasks:spec:acl:grant:0.1andhttps://trusttasks.org/spec/acl/grant/0.1name specifications with the same slug and version. They are still distinct Type URIs, and distinct specifications (see Private and Unpublished Trust Task Specifications item 5).
A Type URI used as the value of a Trust Task document's type member MAY additionally carry the fragment #request or #response, with the meanings defined in Request and Response Variants. The fragments #request and #response are RESERVED; no other fragment values are defined by this framework, and individual Trust Task specifications MUST NOT define their own.
The following slugs are RESERVED for framework-defined specifications and MUST NOT be used by any individual Trust Task specification:
-
The exact slug
trust-task, reserved for this framework specification itself. It is the one slug whose version segment is three-part. -
Any slug whose first segment is
trust-taskortrust-ceremony, or begins with the prefixtrust-task-ortrust-ceremony-, reserved for framework-defined specifications. Equivalently, the slug MUST NOT match the pattern^trust-(task|ceremony)($|-|/). Thetrust-ceremonyhalf of the reservation is unused at this version and exists so that the ceremony layer of TheceremonyMember has a namespace to publish into that no other party can claim first. The slugs currently published by the framework under this reservation are:Slug Purpose trust-task-errorError-response payload — see The trust-task-error Specification. trust-task-okCourtesy acknowledgement of a task that defines no success response — deprecated at 0.5.0, see Reserved Response-Type Slugs. The slug remains reserved permanently. trust-task-next-stepRecipient-suggested continuation — see Reserved Response-Type Slugs. trust-task-discoveryDiscovery and capability negotiation — see Discovery and Capability Negotiation. trust-task-controlCancellation, suspension, and resumption of an accepted task — see Task Control. trust-ceremony-receiptEvidence that one enactment of a Trust Ceremony completed — see The ceremonyMember.
The Type URI is the single canonical reference to a versioned Trust Task specification. Where its scheme is https it is also resolvable, serving both humans (rendered prose) and machines (validation schema, optional JSON-LD context) under content negotiation as defined in Content Negotiation.
The framework also reserves a parallel /binding/ subtree under the same authority for transport binding identifiers and binding-internal resources (envelope type values, binding schema URIs, status mappings). The /binding/ subtree is structurally disjoint from /spec/: no URI under /binding/ is a Type URI, and a Trust Task document whose type is rooted at /binding/... is malformed. The grammar and rules for the /binding/ subtree are defined in Binding Namespace.
A third subtree, /ceremony/, is reserved for ceremony definitions on the same terms. It is likewise structurally disjoint from both: no URI under /ceremony/ is a Type URI, and a Trust Task document whose type is rooted at /ceremony/... is malformed. The grammar and rules for the /ceremony/ subtree are defined in Ceremony Namespace.
A Type URI with the version segment omitted (i.e. https://trusttasks.org/spec/<slug>) SHOULD redirect to the latest standard version of the specification, or — if no standard version exists — to the latest candidate, or — failing that — to the latest draft. retired versions MUST NOT be selected by the bare-URL redirect, since retired signals “no longer recommended for new use”; if every version of a slug is retired, the bare URL SHOULD return 410 Gone with a body that links to the latest retired version and its declared supersededBy successor, if any.
§ Content Negotiation
A server hosting a Type URI MUST support HTTP content negotiation RFC 9110 and MUST be capable of returning the representations listed below. The server MUST return the representation matching the highest-priority acceptable media type in the request’s Accept header. If the Accept header is absent or names no representation listed below, the server MUST return the text/html representation.
| Media type | Representation |
|---|---|
text/html |
The rendered specification document for human readers. |
application/schema+json |
The normative JSON Schema JSON Schema 2020-12 for this specification (see Schema Scope for what the schema covers). |
application/ld+json |
The JSON-LD context for this specification, when one is defined. If no context is published for this Type URI, the server MUST respond with HTTP 406 Not Acceptable. |
Every representation returned MUST describe the same version of the specification as is encoded in the requested Type URI.
§ Schema Scope
The JSON Schema served at the Type URI of an individual Trust Task specification describes only the contents of that specification’s payload member.
The outer document structure (id, threadId, parentThreadId, ceremony, type, issuer, recipient, issuedAt, expiresAt, payload, @context, proof) is described by the JSON Schema served at the framework’s own Type URI — https://trusttasks.org/spec/trust-task/<MAJOR.MINOR.PATCH>, three-part per Versioning of This Framework Specification — under content negotiation for application/schema+json. A complete document validation therefore composes the framework schema (outer structure) with the task-specific payload schema.
The JSON Schema served at any Type URI MUST declare:
$idequal to that Type URI.$schemaset tohttps://json-schema.org/draft/2020-12/schema.
It MUST specify additionalProperties either explicitly as false or with an accompanying prose statement of how unrecognized members are to be treated.
§ Stability
For any value of <slug> and any value of the version segment, the representations served at the corresponding Type URI MUST NOT change in a way that alters their normative content once the specification has reached the candidate, standard, or retired status. This applies to the framework’s own Type URI on the same terms, which is why a framework PATCH release is published at a new URI rather than applied in place. Once a specification is retired, the schema and prose are frozen at the moment of retirement; the only permitted change is correcting the status value itself (which is itself terminal — see Maturity Levels) or adding the supersededBy declaration.
This commitment is made by the public registry for Trust Task specifications it hosts; private specifications published under their own authority (see Private and Unpublished Trust Task Specifications) SHOULD offer their consumers an equivalent commitment, scoped to their own trust boundary.
§ Private and Unpublished Trust Task Specifications
Not every Trust Task specification is intended for the public registry. A producer and consumer operating within a single organization, deployment, or trust boundary MAY define their own Trust Task specifications solely for internal use — never publishing them under https://trusttasks.org/ — and still conform fully to this framework.
The following rules apply to Trust Task specifications that are not published through the public registry:
-
Authority. A private specification’s Type URI MUST NOT be served from, or claim to identify a resource at, the
https://trusttasks.org/domain. That domain is reserved for Trust Task specifications published through the public registry process, and this is what keeps a private Type URI from ever equaling a registry one, even where the two share a slug. A private specification’s Type URI MUST be an absolute URI in one of the two shapes defined in Type URI, and SHOULD sit in a namespace the publisher controls, so the URI uniquely identifies the specification: an HTTPS authority (typically a project or organization domain), a DID the publisher controls, or a URN namespace the publisher is entitled to assign names in. Examples:https://example.com/trust-tasks/spec/<slug>/<MAJOR.MINOR> https://internal.example/spec/<slug>/<MAJOR.MINOR> did:example:123456789abcdefghi/spec/<slug>/<MAJOR.MINOR> urn:example:tasks:spec:<slug-segments>:<MAJOR.MINOR>The slug grammar, version grammar, fragment conventions, and component meanings defined in Type URI apply unchanged, whatever the scheme.
-
Reservation rule. The slug reservation rule in Type URI — that the slug MUST NOT match
^trust-(task|ceremony)($|-|/)— applies regardless of authority. A private specification MUST NOT use those reserved slugs even on its own domain, so that documents flowing between trust boundaries cannot be confused with framework-defined response types. -
Framework conformance is unchanged. All other framework requirements — the document structure (Trust Task Documents), versioning rules (Versioning), conformance behavior (Minimum Requirements), and error response shape (Error Responses) — apply identically to private Trust Task specifications. Implementations consuming both private and registry-published specifications SHOULD use the same validation and signing pipeline for both.
-
Resolvability. A private Type URI whose scheme is
httpsSHOULD resolve to the specification’s representations under content negotiation (Content Negotiation) for parties within the publisher’s trust boundary, but MAY be unresolvable from the public internet. A private Type URI of any other scheme is not dereferenced under this framework. A consumer that does not dereference a private Type URI relies on out-of-band distribution of the specification document and schema, and authenticates their source as Schema-Validation DoS requires of any schema not embedded at build time. -
Promotion to the registry (informative). A private Trust Task specification MAY later be submitted for inclusion in the public registry. The submission process is governed by the registry policy referenced in Maturity Levels; a re-host typically involves a slug check, transfer of the JSON Schema document, and publication under
https://trusttasks.org/spec/<slug>/<MAJOR.MINOR>. The original private Type URI and the new public Type URI identify distinct specifications unless and until the registry policy explicitly aliases them.
Private Trust Task specifications are full Trust Task specifications for the purposes of conformance: a producer or consumer that satisfies Minimum Requirements against a private spec is a conforming producer or conforming consumer of that spec, exactly as it would be for a registry-published one.
§ Shared Schema Components
A Trust Task specification’s payload JSON Schema MAY reference reusable schema fragments — shared schema components — that several specifications have in common (for example, an access-control entry, a device binding, a sealed-envelope shape, or a synchronization event). Shared schema components are an authoring convenience and a consistency mechanism. They are not independently published Type URIs: a Trust Task document’s type MUST NOT resolve to a shared schema component, and a shared schema component is never the unit a document conforms to — only a specification is.
A shared schema component is nonetheless a versioned artifact in its own right, governed by the following rules.
-
Versioning. A shared schema component carries a
MAJOR.MINORversion and follows the same compatibility rules as a specification (Compatibility Rules), including thedraftcaveat. A breaking change to a shared schema component — re-casing an enumerated value, removing or renaming a$def, narrowing a constraint — MUST be published as a new version of that component. The prior version remains in place for the specifications still pinned to it. -
Pinning. A consuming specification MUST reference a shared schema component at a specific version. Resolving a reference to “the latest” version of a component is non-conformant, because a later change to the component would otherwise alter an already-published specification’s wire contract silently.
-
Coupling to specification versions. Because a consuming specification pins a specific component version, adopting a new component version requires the consuming specification to publish a new version of itself (see Migrating Between Versions). A component version bump therefore never changes an already-published specification underfoot; the new component values become observable only through a new specification version that re-pins to them.
-
Lifecycle and discovery. A shared schema component SHOULD declare its own
status(Maturity Levels) and MAY declaresupersededBywhen retired. The registry SHOULD surface shared schema components and their versions alongside specifications, so that implementers can see which specification versions depend on which component versions.
§ Ceremony Namespace
A ceremony definition — the published description of a flow composed of several Trust Tasks, referenced by the ceremony.definition member of The ceremony Member — is identified by a URI in the /ceremony/ subtree of the framework’s authority:
https://trusttasks.org/ceremony/<slug>/<MAJOR.MINOR>
<slug> follows the same lowercase, hyphenated grammar as a Trust Task slug (Type URI) and is subject to the same ^trust-(task|ceremony)($|-|/) reservation; <MAJOR.MINOR> follows the version grammar of Version Scheme.
The /ceremony/ subtree is structurally disjoint from /spec/ and /binding/. A ceremony definition is not a Trust Task specification: no document’s type resolves to one, and a consumer that receives a Trust Task document whose type is rooted at /ceremony/... MUST reject it with malformedRequest (Standard Error Codes). The Type URI grammar of Type URI already excludes the path; the rule is stated explicitly so the namespace boundary is visible at a glance and so such documents have a defined disposition rather than relying on grammar mismatch.
A ceremony definition is referenced by content as well as by name: a step carrying ceremony.definition MUST also carry ceremony.definitionDigest (The ceremony Member). A URI alone would leave the flow’s rules mutable by whoever controls the URI, retroactively and for every enactment already performed.
This version of the framework defines the namespace, the reservation, and the reference mechanism. The content of a ceremony definition — its role, step, ordering and completion vocabulary — is out of scope for this revision and is expected to be specified in a future one. A consumer encountering a ceremony.definition it cannot resolve or does not understand MAY process the document as though the member were absent; by Membership Is a Claim, Not a Permission it forgoes no authority in doing so.
The authority rule of Private and Unpublished Trust Task Specifications item 1 applies equivalently: a private ceremony definition MUST use an authority its publisher controls and MUST NOT claim to identify a resource at https://trusttasks.org/ceremony/....
§ Minimum Requirements
This section is normative.
§ Producer Requirements
A conforming producer MUST:
- Emit a Trust Task document whose top-level structure satisfies Top-Level Members.
- Set the
typemember to the Type URI of the Trust Task specification being implemented, including its<MAJOR.MINOR>segment. - Place all task-specific data in
payload, and emit apayloadvalue that validates against the specification’s JSON Schema — obtained by content-negotiating the Type URI forapplication/schema+json(see Content Negotiation), or distributed out of band where the Type URI is not dereferenced (Private and Unpublished Trust Task Specifications item 4). - Populate
idwith a value satisfying TheidMember.
A conforming producer SHOULD populate issuedAt to support freshness checks downstream, SHOULD populate issuer and recipient when the transport in use does not provide authenticated party identity end-to-end between producer and consumer, SHOULD set threadId when emitting a Trust Task document in response to another (see The threadId Member), SHOULD set parentThreadId when the exchange is conducted inside another and carry it onto every document of the inner exchange (see The parentThreadId Member), SHOULD set ceremony when the document is a step of a Trust Ceremony and carry the same enactment onto every document of that step including any error response (see The ceremony Member), and SHOULD preserve any unrecognized members received from upstream parties when forwarding a Trust Task document.
A conforming producer that emits an ext member (see The ext Extension Member) MUST namespace every immediate child key of ext under a reverse-DNS prefix the producer controls; bare or un-namespaced child keys are non-conforming.
A conforming producer that emits an extCritical member (see Marking a Namespace Critical) MUST name in it only namespaces present in the sibling ext member, MUST NOT name a namespace the document remains correct without, and MUST sign the document where the marking must survive transit. It SHOULD establish that the consumer understands a namespace before marking it critical.
§ Consumer Requirements
A conforming consumer MUST:
-
Validate the outer document structure against the framework JSON Schema. The applicable framework version is the target framework version declared by the Trust Task specification identified by the document’s
typemember (see Specification Requirements). The framework schema for that version is obtained by content-negotiatinghttps://trusttasks.org/spec/trust-task/<MAJOR.MINOR.PATCH>forapplication/schema+json, where<MAJOR.MINOR.PATCH>is the declared target framework version — not the<MAJOR.MINOR>of the document’stypemember, which identifies the task specification version, is two-part, and may differ. -
Validate the document’s
payloadmember against the JSON Schema obtained by content-negotiating the document’stypemember forapplication/schema+json, or distributed out of band where the Type URI is not dereferenced (Private and Unpublished Trust Task Specifications item 4). -
Reject any document whose
typeit does not recognize, unless the consumer’s policy explicitly permits forward-compatible processing under Compatibility Rules. -
Honor the document’s expiry where present: if
expiresAtis set andnow ≥ expiresAtrelative to the consumer’s clock (with the optional skew tolerance permitted in Top-Level Members), treat the document as expired and not act upon it. This is an acceptance bound: it governs whether the consumer may begin, and does not by itself require it to abandon execution already under way (see item 12). -
Reject any document whose
recipientmember is set and does not identify the consumer’s own party. Where the Trust Task specification declaresrecipientas REQUIRED (see Specification Requirements item 5), reject any document lacking an in-bandrecipientwithmalformedRequest. -
Reject any document for which an in-band
issuerorrecipientmember is inconsistent with an authenticated identity derived from the transport for the same party. -
If the document carries a
proofmember, verify it per Proof against the in-bandissuerand reject the document withproofInvalidon verification failure. Independently, if the Trust Task specification identified bytypedeclaresproofas REQUIRED (see Specification Requirements item 8) and noproofis present, reject the document withproofRequired. -
If the document carries a
proofmember and no in-bandrecipient, and the Trust Task specification identified bytypeis not a bearer specification (Bearer Specifications), reject the document withmalformedRequest. This enforces the Audience Binding rule. -
Not grant any authority on the basis of a
ceremonymember. Membership of an enactment is an assertion by the document’s issuer, not a verified fact, and every authorization decision MUST be reached under item 10 below exactly as for a document carrying no such member. See Membership Is a Claim, Not a Permission. A consumer that does not implement ceremonies applies the unrecognized-member rule below and forgoes nothing by doing so. -
Not treat identity or document-proof validation as authorization. Successful validation of a VID,
issuer,recipient, transport-derived identity, orproofestablishes who made the assertion and that the document reached the consumer unaltered. It MUST NOT, by itself, be treated as establishing that the producer is authorized to request the outcome the Trust Task describes, or that the consumer is authorized to perform it. Before executing a Trust Task, a consumer MUST evaluate whatever authorization requirements apply under the Trust Task specification identified by the document’stype, the consumer’s own policy, and the trust or governance framework it operates under. -
Not execute a consequential Trust Task (Terminology) twice on account of the same Trust Task document. Once a consumer has accepted a document with a given
idfor execution, receipt of that same document again MUST NOT cause the consequential effect to occur a second time, unless the Trust Task specification identified by the document’stypeexplicitly declares repeated execution safe and intended. A consumer receiving a document whoseidmatches one it has already accepted but whose content differs MUST reject the later document withidConflict(Standard Error Codes) and MUST NOT treat it as a retry of the original. Transport request identifiers, transport message identifiers, and execution handles MUST NOT substitute for the Trust Task document’sidas the key for this rule. -
Re-evaluate, immediately before each irreversible or externally visible effect of a consequential Trust Task (Terminology), every condition that the Trust Task specification and the consumer’s own policy require for that effect. Successful validation establishes that a document was eligible for processing when it was validated; it does not establish that the work remains executable indefinitely, and for execution that is delayed, long-running, or resumed the two instants can be far apart. Where a required condition — an authorization, delegation, mandate, capability, membership, standing, credential or key status, subject relationship, or a deadline the Trust Task specification defines for itself — is no longer satisfied at that point, the consumer MUST NOT perform the subsequent effect. A valid, authorized control operation the consumer has received under Task Control is such a condition.
-
Reject a document whose timestamps place it outside the window in which the consumer is willing to act. Specifically, a consumer MUST reject with
malformedRequest(Standard Error Codes):- a document whose
issuedAtis later than the consumer’s own clock by more than the clock-skew tolerance it applies under Top-Level Members; and - a document whose
expiresAtis at or before itsissuedAt.
Both are refused as malformed rather than as
expired:expirednames a document that was once acceptable and no longer is, and neither of these ever was. A future-dated document asserts a production instant the consumer has not reached, and a document whose validity ends at or before it began is unacceptable at every instant, including the one it was minted in — a consumer that returnedexpiredfor it would be telling the producer to wait, when what the producer must do is reissue. - a document whose
For each of the rules in this section that references the issuer or recipient party, the in-band member value is authoritative when present and the transport-derived identity is a cross-check; when the in-band member is absent the consumer MAY derive the value from the transport. This precedence is defined normatively in Precedence of In-Band over Transport-Derived Identity.
The evaluation required by item 10 MAY consider delegation, mandate, capability, membership, standing, credential status, subject relationship, purpose limitation, or any other evidence the consumer requires; this framework does not prescribe an authorization model and does not constrain which of these a consumer consults. A verified assertion MAY itself constitute authorization evidence, but only where the Trust Task specification explicitly defines that role for it (Specification Requirements item 15) and the consumer’s policy accepts it for that purpose — a signed decision whose proof is the authorization is a design a specification may adopt deliberately, not a default a consumer may infer. Where authorization fails after the document has otherwise validated, the consumer SHOULD return an error response of permissionDenied (Standard Error Codes) where one can be returned safely, subject to the message-content rule of Error-Response Identity Leakage.
Keying and comparison for item 11. The duplicate-execution key is the Trust Task document’s id alone, which producers are required to mint globally unique and never to reuse (The id Member). Two documents bearing the same id are the same document for the purposes of item 11 when their serializations are identical under RFC 8785 canonicalization — the same identity Retry Semantics defines for a retry. Any other difference, including a changed payload, a changed recipient, or a re-signed proof over identical content, makes them different documents sharing an id, which is the idConflict case. A consumer implementing item 11 therefore retains a digest of what it accepted, not merely the id: an id alone cannot distinguish the retry it must absorb from the conflict it must reject.
Bounding the record. A consumer cannot apply item 11 to a document it can no longer recognize, so it MUST retain the record for at least as long as it remains willing to execute that document. The two bounds are the same bound. Where expiresAt is present it fixes both: after it, the document is refused under item 4 and the record may be dropped. Where expiresAt is absent, the consumer’s own acceptance window — typically a freshness bound over issuedAt — fixes both, and a consumer MUST NOT accept for execution a document older than the window over which it retains records. Retention beyond that point is not required: a document the consumer would now refuse as stale cannot be replayed into a second execution. A consumer that can establish neither an expiresAt nor an age for a document has no window in which to place it, and MUST NOT execute a consequential Trust Task on it.
Why item 13 exists. Item 11 is only implementable inside a bounded window, and the two timestamp members are what bound it. Without a freshness bound the consumer must retain its record of every accepted document forever — because a document it can no longer recognize is a document it will execute a second time, and a document with no expiresAt and no usable issuedAt never leaves the set it must recognize. Item 13 removes the two ways a document could otherwise sit outside any window while still appearing acceptable: an issuedAt in the consumer’s future, which places the document in a window that has not opened and would keep re-entering it as the clock advances; and an expiresAt at or before the issuedAt, which describes a validity interval that never contained an instant and so answers item 4 differently depending only on which member the consumer happened to consult. Neither refusal is a judgement about the producer’s intent — a skewed clock produces the first case routinely — and both are cheap: they are decided from the document alone, before any resolution, verification, or execution work.
The obligation on the producer side is Specification Requirements item 17: a Trust Task specification defining a consequential Trust Task MUST require issuedAt, so that a consumer of the tasks for which item 11 matters most always has a value to place the document by.
What item 12 does and does not re-check. The rule is about authority, not about the clock. expiresAt is deliberately absent from its list: that member bounds acceptance (Top-Level Members), and re-checking it mid-execution would convert a statement about a request’s staleness into an execution timeout the producer never set and could not have calculated — it does not know how long the consumer’s work takes. A consumer MUST NOT abandon execution solely because expiresAt has passed since it began.
A Trust Task that genuinely has a completion deadline — an offer that lapses, a quote that cannot be honored after a stated instant — expresses it in its own payload, where the Trust Task specification can define what lapsing means for that task. Such a deadline is then one of the conditions item 12 re-evaluates, on the same footing as a revoked delegation, with no framework member required. task-consent/request/0.1 is the worked example: its payload.expiresAt states that the pending request lapses and no decision is accepted for it — a meaning the envelope member could not carry, because the envelope does not know what a decision is.
Stopping is not always safer than finishing. Item 12 is placed before each irreversible effect for a reason: once such an effect has occurred it cannot be undone by declining the next one, and for many consequential Trust Tasks abandoning a partially applied change leaves the recipient party in a state neither party asked for. A consumer MUST NOT treat abandonment as inherently the safe option; where a Trust Task specification defines a sequence whose partial application is unsafe, the specification says so and the consumer follows it.
Where execution has already produced partial or irreversible effects and the consumer stops, it SHOULD return a response or status that distinguishes partial execution from a task that was never begun. The two are different facts about the world, and a producer that cannot tell them apart cannot decide whether to reissue. Where the Trust Task specification defines no success-response document, this disposition is reported as an error response (Error Responses) rather than left silent. Silence would report nothing at all (Document Lifecycle) and would in particular be indistinguishable from the duplicate absorbed under item 11 — two facts about the world that oblige a producer to do opposite things.
Disposition of a duplicate. Where the original execution is still in progress, the consumer SHOULD return or expose the existing execution state rather than begin another. Where execution has completed and the Trust Task specification defines a success-response document (Specification Requirements item 7.6), the consumer SHOULD return the previously determined result, or an equivalent receipt where that specification permits one. Where the specification defines no success-response document — the fire-and-forget case of that same item — there is nothing to return beyond the courtesy acknowledgement of Acknowledging a Fire-and-Forget Task, which a consumer MAY return on a duplicate exactly as on the original: the consumer declines to execute again, and neither the acknowledgement nor its absence is an error. In no case is a duplicate reported as taskFailed; the task did not fail, it already happened.
Relationship to idempotency. Idempotency as a property of the underlying operation remains task-specific and outside this framework. Item 11 requires only that transport retry or replay not invoke a consequential operation a second time. A Trust Task specification whose operation is naturally idempotent — where executing twice is indistinguishable from executing once, in every effect the recipient party exposes — MAY declare repeated execution safe and intended, which disapplies item 11 for that specification. Such a declaration is about the operation, not about the consumer’s convenience, and a specification MUST NOT make it merely to avoid implementing the rule.
This paragraph is non-normative. Item 10 generalizes a principle the framework already applies in two narrower places: Membership Is a Claim, Not a Permission and item 9, where ceremony membership authorizes nothing, and Specification Requirements items 13 and 14, where the side-effect and exposure classes describe a task without authorizing it. Those are instances of the general rule rather than exceptions to it. The inference the rule forecloses — valid proof + recognized issuer + correct recipient = authorized instruction — is the confused-deputy vector of Membership Is a Claim, Not a Permission reached by a different route, and it is most dangerous where the producer is an autonomous agent: such a producer can typically prove its own identity perfectly while holding no authority to act for a subject, exercise a delegated capability, disclose information, or cause a consequential effect (Terminology).
A conforming consumer SHOULD preserve, but MUST NOT act upon, members it does not recognize. A consumer that does not implement JSON-LD processing MUST ignore the @context member.
For documents that carry an ext member (see The ext Extension Member), a conforming consumer MUST ignore every ext immediate-key namespace it does not recognize — the unrecognized-namespace rule is the same “preserve but MUST NOT act upon” rule as for unrecognized top-level members, applied at the ext level — except where the document names that namespace in a sibling extCritical member, which a conforming consumer MUST reject with unsupportedExtension rather than ignore (Marking a Namespace Critical). A consumer MAY require one or more specific namespaces under ext as a matter of local policy and MUST reject a document missing a required namespace with malformedRequest; consumers applying such a policy SHOULD publish the requirement via discovery (Discovery and Capability Negotiation) so producers can satisfy it before the wire trip.
When a consumer rejects a Trust Task document under any rule in this section, and the transport in use supports a response from consumer to producer, the consumer SHOULD return an error response conforming to Error Responses.
§ Specification Requirements
A conforming Trust Task specification MUST declare each of the following. Together these declarations make the specification self-describing to both human readers and machine consumers, and constitute the minimum needed to author or interpret a Trust Task document.
-
Slug — the lowercase slug used in the specification’s Type URI, satisfying the grammar and reservation rules of Type URI.
-
Version — the
MAJOR.MINORversion of this specification, satisfying Version Scheme. -
Target framework version — the
MAJOR.MINOR.PATCHversion of this framework specification that the Trust Task specification targets, three-part per Versioning of This Framework Specification. A value declared before that rule took effect is two-part and resolves asM.N.0. A consumer uses this declared value to select the framework schema under which the outer document is validated (see Consumer Requirements, item 1). -
Maturity level — one of
draft,candidate,standard, orretired, satisfying Maturity Levels. A specification whose status isretiredSHOULD also declare asupersededByvalue (item 11) pointing at the successor. -
Parties — the role of each party expected in a document conforming to this specification, the VID schemes accepted for each, and whether each of the
issuerandrecipientmembers is REQUIRED, RECOMMENDED, or OPTIONAL in a document. The defaults from TheissuerandrecipientMembers apply if the specification is silent, but explicit declaration is RECOMMENDED. A REQUIRED declaration is enforceable: a consumer MUST reject documents lacking an in-band member declared REQUIRED withmalformedRequest(see Consumer Requirements item 5). RECOMMENDED and OPTIONAL declarations are advisory and impose no rejection obligation. A specification identifies which party fills each framework member by tagging that partyissuerorrecipient; a party named only in the payload — neither the document’sissuernor itsrecipient— carries no such tag. The requirement of the party taggedrecipientgoverns therecipientmember of a request document; because a response document swaps the parties (Request and Response Variants), the requirement of the party taggedissuergoverns therecipientmember of a response.Each party declaration SHOULD additionally carry an
identifierScope— one ofpairwise,public, orany— stating which kind of VID the specification expects for that party under Identifier Correlation and Linkability.pairwisestates that the identifier is expected to be scoped to the relationship in which the document is exchanged;publicstates that a cross-relationship identifier is intrinsic to what the task asserts, and apublicdeclaration MUST be accompanied by the prose justification that subsection requires;anystates that the specification takes no position and the choice belongs to the parties.What the declaration is, and what it is not.
identifierScopeis a machine-readable restatement of item 1 of Identifier Correlation and Linkability, which is a binary rule: a party identifier is either scoped to the relationship in which the document is exchanged, or it is reused across relationships and therefore requires the justification that item accompanies it with. The three values mirror that rule and its abstention. The member is not a taxonomy of how widely an identifier may be correlated, and its name should not be read as claiming to be one.Two consequences follow, and both matter where a party identifier is also described by some other specification’s vocabulary:
- It is declared by a Trust Task specification, about a party role. It says what this specification expects of whichever identifier fills that role, in every document of the task, before any particular identifier exists. It is not a statement by a holder about an identifier it controls, and it does not become one when a document is produced. Where a holder declares something about its own identifier under another specification, that declaration and this one are different assertions about different subjects; neither overrides the other, and a divergence between them is not by itself a conformance failure. Which identifiers a consumer accepts remains governed by its own trust framework, as the following paragraph requires.
- An identifier recognizable within a bounded set is, for item 1’s purposes, a cross-relationship identifier. A VID that several counterparties can recognize — those of one community, or any other bounded group — is reused across relationships, and the joins item 1 forecloses are available to any two of them who compare what they hold. Such a party is therefore declared
public, and the justification obligation applies to it in full. The framework deliberately does not grade the width of a cross-relationship identifier: the bound may be unknown to the parties, may grow, and does not change what item 1 is about. A specification whose prose needs to record that the recognizable set is bounded, and to what, states that in the justification.
The declaration is descriptive, not prescriptive, on exactly the terms of items 13 and 14. It states what the specification expects and MUST NOT be read as obliging a consumer to accept a party identifier merely because it matches the declared scope, nor as licensing the rejection of one that does not; which VID schemes and scopes a consumer accepts remains a matter for its own trust framework (The
issuerandrecipientMembers). A consumer that renders or reasons about the value MUST treat an absent or unresolvable declaration as no less correlatable thanpublic, since an identifier that may be joined across relationships is the more exposed reading. Its purpose is to make Identifier Correlation and Linkability item 1 machine-readable: a reviewer, a registry, or a producer choosing an identifier to present can see which specifications expect a public one without reading every specification for the justification. -
Outcome — a non-normative prose statement of what successful execution of the task achieves between the parties. This is the human-readable counterpart to the payload schema.
-
Payload JSON Schema — a normative JSON Schema for the
payloadmember that:- Is a valid JSON Schema document under JSON Schema 2020-12.
- Sets
$idto the specification’s Type URI (without fragment). - Sets
$schematohttps://json-schema.org/draft/2020-12/schema. - States how unrecognized payload members are treated — by specifying
additionalPropertiesexplicitly asfalse, by specifyingunevaluatedPropertiesasfalse, or with an accompanying prose statement. A schema assembled byallOfover a shared schema component (Shared Schema Components) MUST useunevaluatedProperties:additionalPropertiesis evaluated by each subschema against the whole instance and cannot see members a sibling subschema matched, so it rejects the composing schema’s own members. For the same reason a shared component intended for composition SHOULD leave itself open and let the consuming schema close the result. - Is served at its Type URI under content negotiation for
application/schema+json, where the Type URI’s scheme ishttps; otherwise it is distributed out of band (Private and Unpublished Trust Task Specifications item 4). - Where the specification defines a success-response document (per Request and Response Variants), the schema MUST contain a sub-schema reachable via
$anchor: "response"describing the response document’spayload; the top-level schema (or the sub-schema reachable via$anchor: "request") describes the request document’spayload. A consumer receiving a document whosetypecarries#responseresolves the response sub-schema from the schema of the bare Type URI (however obtained) and follows theresponseanchor. Where the specification defines no success-response document, the schema MUST NOT declare aresponseanchor; such tasks are fire-and-forget at the application layer (failures are still reported viatrust-task-errorper Error Responses).
-
Proof requirement — an explicit statement of whether the
proofmember is OPTIONAL, RECOMMENDED, or REQUIRED, together with a brief rationale referencing the threat model addressed (for example, tampering by intermediaries, replay, repudiation by the producer, or reliance by third parties beyond the original consumer). The declared requirement MUST NOT be weaker than the default applicable under When to Include a Proof. The specification MAY also require a particular cryptosuite, or a class of cryptosuites, for its proofs (Cryptosuites).The statement takes one of two forms. A specification MAY declare a single requirement applying to every document variant, or it MAY declare per-variant requirements for the request and the response separately. The per-variant form exists because the two are relied upon differently: a response retained as evidence by a party outside the original exchange can require a proof where the request that triggered it does not, and the reverse is equally common — a request that destroys state needs to be attributable while the acknowledgement it returns protects nothing. A single value forces the stricter of the two onto both, overstating the requirement on whichever variant needs it less. Where a specification declares no requirement for the response, the request’s applies to it, so an omission can never weaken a variant.
A consumer applies the requirement declared for the variant it is processing, identified by the document’s
typefragment (Request and Response Variants); the rejection rule is unchanged (Consumer Requirements item 7).The error variant is deliberately not declarable here. An error response’s
typeresolves to the framework’strust-task-errorspecification (The trust-task-error Specification), which is a different Trust Task specification from the one being declared, and Consumer Requirements item 7 resolves the proof requirement from the specification the document’stypenames. A declaration made here could not reach it. -
Task-specific error codes (where used) — for each extended
codedefined under Extension by Individual Trust Task Specifications, the code identifier, its meaning, its defaultretryablevalue, and the JSON Schema fragment describing anydetailsobject it carries. Where no extensions are defined, the specification SHOULD state so explicitly. -
JSON-LD context (where used) — if the specification publishes a canonical JSON-LD context, the context MUST be served at the specification’s Type URI under content negotiation for
application/ld+jsonwhere the Type URI’s scheme ishttps, and is otherwise distributed out of band (see JSON-LD Compatibility and Content Negotiation). Where no context is published, the specification SHOULD state so explicitly. -
Successor (
supersededBy, retired specifications only) — aretiredspecification SHOULD declare its successor as a string of the form<slug>or<slug>/<MAJOR.MINOR>. The bare-slug form points to “the latest non-retired version of that slug”; the explicit form pins to a specific version. The value is used by the registry’s bare-URL redirect (see Type URI) and by consumer-side deprecation tooling to direct implementers at the recommended replacement. Specifications whose status is notretiredMUST NOT declaresupersededBy. -
Bearer flag (where applicable) — a Trust Task specification that opts out of the Audience Binding rule MUST declare
bearer: truein its front matter. The default is non-bearer; specifications omit the field or setbearer: falsewhen audience binding applies. A bearer specification MUST also declarerecipientas OPTIONAL under item 5 and MUST include the audience-free rationale required by Bearer Specifications. -
Side-effect class — an explicit classification of the effect that successful execution has on the recipient party, declared in front matter as a
sideEffectsobject carrying alevel— one ofnone,mutating, ordestructive— and a briefrationale.nonedenotes a read-only or idempotent task that persists no state change (a query, an enumeration, a discovery probe);mutatingdenotes creation or alteration of recoverable state;destructivedenotes an irreversible or authority-shifting effect (deactivation, rotation of a sole controlling key, deletion, transfer of ownership). For adestructiveclassification the rationale MUST name the irreversible or authority-shifting effect. This classification is the structured, machine-actionable counterpart to the prose Outcome of item 6.The classification is descriptive: it states what the task does, not whether approval is required to do it. A consumer that gates execution on human approval — for example an agent executing a task delegated to it by a producer — MAY derive its approval policy from this class, but that policy is the consumer’s alone. Accordingly: a Trust Task specification MUST NOT declare, in any form, that a task does or does not require consent, human approval, or an authentication step-up; such policy MUST NOT be delegable to a specification or to the registry that serves it. A consumer that enforces an approval policy MUST determine the authoritative side-effect class from the handler it is about to invoke rather than from the declared value alone, and MUST treat an absent, unrecognized, or unresolvable declaration as no weaker than
mutating. The declared class exists to inform and to render, not to authorize. -
Exposure class — a declaration, orthogonal to the side-effect class of item 13, of what successful execution causes to leave the recipient or to be exercised on the subject’s behalf, independent of any change to recipient state. Declared in front matter as an
exposureobject carrying adisclosesvalue — one ofnone,metadata, orsecret— and anactsAsSubjectboolean.disclosesstates the sensitivity of data the task returns to the caller:none(an acknowledgement or a determination only),metadata(non-secret descriptive data about a subject or resource, such as an enumeration or a status read), orsecret(confidential material the caller retains, such as released credential material or a usable session blob).actsAsSubjectistruewhen execution exercises the subject’s own authority to produce an attributable effect in the subject’s name — a login performed on their behalf, a signature bearing their identity, a credential issued under their authority — even when no data is disclosed and no recipient state changes. Wheredisclosesis notnoneoractsAsSubjectistrue, arationalenaming the disclosed material or the exercised authority is REQUIRED.The side-effect class (item 13) and the exposure class are orthogonal: the former measures the integrity effect on recipient state, the latter the confidentiality and agency effect of data egress and delegated action. A read-only task (
sideEffects.level: none) may still disclose a secret; a signing task may change no recipient state yet act with the subject’s full authority. Both are governed by the same discipline as item 13: the exposure class is descriptive, not prescriptive — a specification MUST NOT derive from it a consent requirement — and a consumer that gates on it MUST determine the authoritative values from the handler it is about to invoke, and MUST treat an absent or unresolvable declaration as no less exposed thandiscloses: secretwithactsAsSubject: true.The
exposureobject SHOULD additionally carry aningestsvalue — one ofnone,metadata,personal, orsecret— grading the sensitivity of the data the task requires the producer to send.disclosesis response-only by construction: it grades what execution returns to the caller. A task whose requestpayloadcarries a full verifiable presentation, a document image, or a free-text field a person typed therefore declaresdiscloses: noneentirely correctly today, while saying nothing about the most sensitive data in the exchange — and a consumer reading only the exposure class would conclude the task moves nothing of consequence in either direction.nonedenotes a request carrying no data about any subject (a discovery probe, an acknowledgement, a control operation);metadatadenotes non-secret descriptive data (an identifier to be resolved, a status to be read);personaldenotes data relating to an identified or identifiable person, free text a person authored included;secretdenotes confidential material the recipient party will thereafter hold (credential material, a key, a session blob, an authenticator response). Whereingestsispersonalorsecret, arationalenaming the ingested material is REQUIRED.The enumeration deliberately differs from
discloses, which has nopersonalvalue. A disclosure is graded by what the caller could do with what it receives; an ingest is graded by what the recipient now holds about a person who is frequently not a party to the exchange at all, and for whom the relevant question is not confidentiality but whether the data should have moved. What becomes of it once it has moved is the other half of the question, and item 18 carries that half.The discipline of this item governs
ingestsunchanged: the value is descriptive, not prescriptive, a specification MUST NOT derive a consent requirement from it, a consumer that gates on it MUST determine the authoritative value from the handler it is about to invoke, and a consumer MUST treat an absent or unresolvable declaration as no less sensitive thanpersonal. The floor ispersonalrather thansecretbecause a request that ingests genuine secret material is rare enough that assuming it of every undeclared specification would make the class carry no information, whereas personal data in a request is the ordinary case — andpersonalis already the level at which the minimization guidance of Privacy Considerations item 1 attaches. -
Authorization evidence (consequential tasks) — a Trust Task specification defining a consequential Trust Task (Terminology) MUST describe any class of authorization evidence a consumer needs in order to interpret the task correctly — for example the delegation, mandate, capability, membership, standing, or subject relationship the task presupposes. Where the task presupposes nothing beyond the consumer’s own policy, the specification SHOULD state so explicitly.
This declaration is descriptive on exactly the terms of items 13 and 14. It states what authority the task assumes, and MUST NOT be read as obliging a consumer to authorize execution merely because the described evidence is present; the authorization decision remains the consumer’s alone under Consumer Requirements item 10. The bar in item 13 applies here unchanged: a specification MUST NOT declare, in any form, that a task does or does not require consent, human approval, or an authentication step-up.
A specification MAY additionally declare that a verified assertion carried by the task is authorization evidence for a stated purpose — the design Consumer Requirements item 10 contemplates, in which a proof is relied upon as authorization rather than merely as integrity. Such a declaration MUST name the purpose and MUST NOT extend beyond it, and remains subject to the consumer’s policy accepting the assertion for that purpose.
Unlike items 5, 8, 12, 13, and 14, this declaration is satisfied in the specification’s prose and has no front-matter field; it is not machine-validated.
-
Execution checkpoints (multi-stage consequential tasks) — a specification describing multi-stage consequential execution SHOULD identify any additional points at which validity or authority is expected to be re-evaluated, beyond the one Consumer Requirements item 12 requires before each irreversible effect. A specification whose stages must not be partially applied SHOULD say so explicitly, so that a consumer deciding whether to stop knows which of stopping and continuing its author considered the safer failure.
Where the specification defines its own completion deadline — an instant after which the task’s outcome is no longer meaningful — it declares that in its
payloadand states what lapsing means for the task. The framework’sexpiresAtbounds acceptance only (Top-Level Members) and MUST NOT be relied upon to terminate execution. -
Freshness (consequential tasks) — a Trust Task specification defining a consequential Trust Task (Terminology) MUST require the
issuedAtmember, raising the framework’s SHOULD (Top-Level Members) to a MUST for documents conforming to it. Such a specification SHOULD also state the acceptance window it expects its consumers to apply, and MAY requireexpiresAtwhere the task’s outcome is meaningless after a fixed interval.The reason is the one given under Consumer Requirements: the duplicate-execution protection of item 11 is exactly the rule that matters for a consequential task, and it is implementable only over a bounded window. A document carrying neither
expiresAtnorissuedAtgives its consumer no window to place it in, so item 11 obliges that consumer either to retain its record of the document forever or to refuse to execute it at all — and a framework whose most dangerous tasks are the ones a consumer may have to refuse for want of a timestamp has the requirement in the wrong place. RequiringissuedAtof the specification puts it on the party that can satisfy it for nothing. -
Retention class — a declaration of what the recipient party is expected to keep of a document conforming to this specification, and for how long. Declared in front matter as a
retentionobject carrying aclass— one oftransient,exchange, ordurable— and arationale.transientdenotes a task whose data the recipient needs only in order to produce its reply and is expected to discard when the exchange closes;exchangedenotes data the recipient holds for the life of the exchange and for the windows this framework already obliges it to hold — the duplicate-execution record of Consumer Requirements item 11, an acceptance window, a suspension it may be asked to resume — and no longer;durabledenotes data the recipient is expected to keep beyond the exchange because placing it there is what the task is for: a compliance record, an issued credential, a registry entry, an audit trail. Adurableclassification MUST name in its rationale what is retained and what obliges its retention.The framework has carried no retention vocabulary at all, and the gap is not neutral. Every rule in this document and in the published specifications that uses the word retain mandates more retention, for good reasons: a proof is required so a document can be relied upon after delivery (When to Include a Proof), a digest is retained so a duplicate can be absorbed (Consumer Requirements item 11), an error is identified so it can serve as evidence (Error Payload). Each of those is right on its own and their sum is a framework that tells a recipient party what it must keep and never once what it may let go — so the safe reading of every task has been to keep everything.
retentionis the missing half: a per-specification statement of which of those obligations actually reaches this task, so that a consumer can tell the data it is obliged to hold from the data it merely still has. It pairs withexposure.ingests(item 14): that value says what arrived, this one says what becomes of it.The classification is descriptive, not prescriptive, on exactly the terms of items 13 and 14. It states what the task’s design assumes and MUST NOT be read as obliging a recipient party to retain anything, as authorizing it to retain anything, or as discharging any retention or deletion obligation the consumer is under by law, contract, or governance framework — those bind the consumer and are no more delegable to a specification than a consent requirement is (item 13, Governance Considerations). A consumer that gates on the value MUST determine the authoritative class from the handler it is about to invoke rather than from the declared value alone, and MUST treat an absent or unresolvable declaration as no weaker than
durable.A
transientdeclaration does not disapply Consumer Requirements item 11. That record is a digest of what was accepted rather than a copy of the document’s contents, and a consumer retains it for the acceptance window of item 13 whatever this class says — the two are not in tension, and a specification whose data must genuinely not outlive the exchange is served by the digest precisely because a digest is not the data. -
Free-text members — for every member of its
payloadwhose value is free text, meaning a string whose content no enumeration, pattern, or external vocabulary constrains, a Trust Task specification MUST:- Declare a
maxLengthin the payload JSON Schema. - State who reads the value — an operator, an approver, a log, a downstream system, nobody — and whether the recipient party is expected to retain it (item 18).
- State whether the value is trusted. Where it is authored by any party other than the one whose signature covers the document’s assertions, the specification MUST say so explicitly and MUST require that any surface rendering it attribute it to its author.
Such a member SHOULD be OPTIONAL, and a specification SHOULD prefer a closed enumeration the specification itself defines — which Naming Conventions item 4 already governs — accompanied where genuinely needed by one bounded, optional note, over a free-text member carrying the meaning that the enumeration should have carried.
task-consent/request/0.1’snoteis the pattern to copy: 500 characters, optional, attributed on every rendering surface to therequesterwho wrote it, declared explicitly untrusted as the one member of that payload whose prose the executor did not author, and forbidden from substituting for, reordering, or obscuring the executor-authored effects it appears beside. Every one of those constraints is in the specification, where the party who knows what the field is for could state it.Two things drive the rule. The first is disclosure: a free-text member is the one place in a Trust Task document where the schema constrains the shape and nothing constrains the content, so it is where personal data arrives in a task that declares it ingests none (Specification Requirements item 14), where a secret arrives pasted by a person who was asked for a reason, and where instructions addressed to a downstream reader arrive in a field the specification believed was a comment. A bound and a stated audience do not prevent that, but they are the minimum that lets a consumer reason about it, and an unbounded field cannot be reasoned about at all. The second is wire cost: an unbounded string is an unbounded document. Parser Hardening has a consumer bound the body at the transport layer, which is the right defence and the wrong place to decide the number — a transport-layer limit is one figure for every task the consumer implements, where only the specification knows whether this field is a reason code or a paragraph. Declaring the bound in the schema also makes it validatable, so an oversized value is refused as
malformedRequestby the pipeline every consumer already runs rather than by a limit each one picks for itself.A member whose content is constrained — an enumerated status, a VID, a Type URI, a timestamp, a value carried verbatim from an external vocabulary (Naming Conventions item 5) — is not free text and this item does not reach it.
- Declare a
-
Outcome evidence (cited exchanges) — a Trust Task specification whose exchanges a party outside the exchange may cite as evidence that an event occurred — a DTG credential’s
taskContext, an audit record, a governance decision (Naming an Exchange from Outside the Framework) — MUST declare which success response constitutes that exchange’s outcome evidence under Evidence That a Cited Exchange Completed, naming it by Type URI with its#responsefragment. For that response the specification:-
MUST define its
payloadschema (item 7.6), so that successful termination is observable from the exchange’s own documents; -
MUST declare
proofREQUIRED, as a single requirement or for the response variant (item 8), since the response is relied upon by parties beyond the original consumer; -
MUST require the
issuedAtmember (item 17), whether or not the task is otherwise consequential, so that a relying party can place the evidence in time; -
SHOULD declare retention class
durable(item 18), naming the citation as what obliges retention; and -
MUST declare how that response is bound to the initiating document, as payload members a consumer can compare, each named by a JSON Pointer (RFC 6901) evaluated against the root of the Trust Task document that carries it (for example
/payload/vwc/taskContext). The binding is one of:- members carrying the initiating document’s
idand its task digest (Binding a Citation to the Document It Names); or - a member reproducing an unguessable value that the initiating document freshly supplied, such as a presentation challenge, together with the initiating-document member that supplied it. That value’s freshness is guaranteed only by the initiating document’s producer, which can reuse it together with a
threadIdand so present one exchange’s response as the outcome evidence of another. A specification MAY declare this form only where it requires the initiating document’s producer to be the issuer of the citing artifact, so that a relying party already depends on that producer’s honesty for what the artifact states. Otherwise it MUST declare the first form.
Sharing a
threadIddoes not satisfy this sub-item. - members carrying the initiating document’s
Where a cited exchange is conducted under more than one specification — a session opened under one and completed by a task conducted on its thread under another — the specification governing the initiating document makes the declaration, since that document’s
typeis what a relying party holds when it looks for one. That specification MUST also require the initiating document to carryrecipient(check 4 of Evidence That a Cited Exchange Completed identifies the responder by it), so an exchange whose initiating document is governed by a bearer specification (Bearer Specifications) and names no recipient cannot be cited as evidence of completion. A specification that defines no success response of its own, and whose only positive terminal signal is the empty#responseof Acknowledging a Fire-and-Forget Task, MUST NOT be cited as evidence of completion unless it declares a success response under this item — which, under sub-items 1 and 5, gives that response a defined payload carrying its binding, and so replaces the empty acknowledgement. -
-
Document size bound (where declared) — a Trust Task specification MAY declare, for its request document, its success-response document, or both, the largest serialized Trust Task document a consumer serving the task is expected to accept, in bytes of the document’s UTF-8 JSON text as received —
proofincluded, and any transport envelope around the document excluded. A specification whosepayloadcan legitimately carry bulk content — an embedded schema, a log, a range of a file — SHOULD declare it; one whosepayloadis small and fixed in shape need not.The declaration is a two-sided interoperability bound. A consumer serving the task MUST NOT refuse a document within the bound declared for its variant on grounds of size alone, and SHOULD refuse a larger one with
malformedRequest— Standard Error Codes defines no dedicated code, and a document exceeding its specification’s bound does not conform to it — before parsing it where the transport lets the consumer learn thetypefirst. The two variants are independent: a bound declared for one does not apply to the other. Where a specification declares no bound, the consumer’s own limit under Parser Hardening applies, exactly as before.The reason is the one item 19 gives for free-text members, applied to the whole document: a transport-layer limit is one figure for every task a consumer implements, where only the specification knows whether its
payloadis an identifier or a schema. A consumer that serves many tasks otherwise has two choices, both wrong — a limit sized for the small tasks, which refuses the large ones, or a limit sized for the largest, which opens every other task to bodies it has no use for.A bound is not a licence for arbitrarily large documents. Content larger than a single document can carry through the transports the task is expected to use is moved by a chunked transfer, whose chunk task declares a bound of its own; a specification SHOULD choose its bound with the smallest message limit among those transports in mind.
A worked example of a Trust Task specification satisfying these requirements appears in Appendix A.
§ Error Responses
This section is normative.
A recipient party that cannot or will not act upon a received Trust Task document MAY return an error response describing why. Error responses are themselves Trust Task documents of a framework-defined type, so that one validation, signing, and transport pipeline serves both successful tasks and their refusals.
The framework distinguishes the two reply forms cleanly:
- A success response uses the request’s Type URI with the fragment
#response(see Request and Response Variants). Its payload shape is defined by the originating Trust Task specification. - An error response uses the framework’s distinct
trust-task-errorType URI (defined below). Its payload shape is defined by this framework, independent of the originating specification.
A recipient party MUST NOT report failure by emitting a #response-variant document of the originating spec, nor success by emitting a trust-task-error document. The two reply types are not interchangeable.
§ The trust-task-error Specification
The framework reserves the slug trust-task-error for the error-response Trust Task specification at:
https://trusttasks.org/spec/trust-task-error/<MAJOR.MINOR>
An error response is a Trust Task document whose type is the URI above. Its payload carries the standard error structure defined in Error Payload. The id member of an error response identifies the error instance and MUST NOT be reused; correlation back to the original task being responded to is carried by the framework’s threadId member (The threadId Member).
The error response’s issuer is the consumer that emitted it (the reporting consumer in the conformance language of the trust-task-error specification’s registry entry). Its recipient is the party the consumer wishes to inform of the failure. For most rejections — expired, unsupportedType, unsupportedVersion, proofRequired, proofInvalid, taskFailed, and the rest of Standard Error Codes — that party is the original producer as carried in the rejected document’s in-band issuer member.
The exception is identityMismatch (and any rejection raised in the same evaluation step that surfaced the mismatch): under such a rejection the rejected document’s in-band issuer is by definition the contested identity, and MUST NOT be used as the error response’s recipient. A consumer that emits an error response under identityMismatch MUST address the response to the transport-authenticated sender of the rejected document, and MUST NOT address it to the in-band issuer. Where no transport-authenticated sender is available, the consumer SHOULD NOT emit an error response at all — sending one to the contested in-band identity would constitute an oracle, and (in any transport that signs error responses) would compel the consumer to emit a signed document about a party that did not in fact participate in the exchange.
The consumer MUST likewise sanitize the payload.message member of an identityMismatch error response: a free-text message that reveals the consumer’s expected transport-authenticated identity, or the contested in-band value, leaks identity information to a possibly hostile sender. The standard wire form for this code is the code identifier alone, optionally accompanied by a non-identifying message (e.g. "identityMismatch: in-band identity does not match transport-derived identity"). The general form of this rule — which binds every code, not only this one — is What a message May Not Say.
§ Error Payload
The payload of an error response has the following members. The correlation back to the Trust Task document this error reports on is carried at the framework level by the threadId member (The threadId Member), which a producer of an error response MUST set.
threadId correlates the exchange for a party that saw the originating request. It identifies nothing to anyone else: it is opaque, and the payload otherwise names neither the Trust Task specification the failure occurred under nor the document instance that triggered it. A party handed a retained error — a verifier evaluating it as evidence, an auditor reconstructing a sequence — sees a code and a retryable flag and cannot tell what failed. For an extended code the slug namespace (Extension by Individual Trust Task Specifications) hints at the family; for the standard codes of Standard Error Codes there is no signal at all.
The inResponseTo member closes that. A consumer emitting an error response SHOULD populate it, and MUST populate it where the error is intended to be retained, replayed, or relied upon by parties beyond the original producer — the same condition under which When to Include a Proof makes a proof mandatory, and for the same reason: an error that cannot be attributed and cannot be identified is not evidence of anything. Its typeUri carries the reported-on document’s type including any #request or #response fragment, which is what tells a consumer whose semantics apply to an extended code; its id carries that document’s document identifier, which The id Member makes globally unique and never reused, so it names one instance where threadId names an exchange.
Under identityMismatch a consumer SHOULD omit inResponseTo.id: per The trust-task-error Specification the response is addressed to the transport-authenticated sender rather than the in-band issuer, and that party did not necessarily compose the document whose identifier would be echoed.
| Member | Required | Type | Description |
|---|---|---|---|
code |
MUST | string | A short identifier for the failure category. MUST be one of the codes in Standard Error Codes or an extended code as defined in Extension by Individual Trust Task Specifications. |
inResponseTo |
SHOULD | object | Identifies the Trust Task document this error reports on: typeUri (its type, including any fragment) and id (its document identifier). See above. |
message |
SHOULD | string | A human-readable description of the error, subject to the disclosure rule of What a message May Not Say. Non-normative as to the cause of the failure; intended for logs and operator UI. |
retryable |
MUST | boolean | true if the producer of the original document MAY retry the task; false if retrying with the same document or credentials is not expected to succeed. |
retryAfter |
MAY | string (date-time) | An RFC 3339 timestamp before which the producer SHOULD NOT retry. Meaningful only when retryable is true. |
details |
MAY | object | Task-specific extension data; see Extension by Individual Trust Task Specifications. Bounded per Bounding details. The framework itself defines the shape carried under the cancelled code; see Effects Reported with cancelled. |
Example 5 — An error response (non-normative)
{ "id": "9e2a1c44-7b81-4d3e-9b51-7a3c89e3d1f2", "type": "https://trusttasks.org/spec/trust-task-error/0.2", "threadId": "2d7f0b6e-5c3a-4e8b-8f1d-6a9e4c2b7d15", "issuer": "did:web:maintainer.example", "recipient": "did:web:org.example", "issuedAt": "2026-06-11T14:05:00Z", "payload": { "code": "expired", "message": "Task expired at 2026-06-11T14:00:00Z.", "retryable": false }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "eddsa-jcs-2022", "verificationMethod": "did:web:maintainer.example#key-1", "created": "2026-06-11T14:05:00Z", "proofPurpose": "authentication", "proofValue": "z58D..." } }
§ What a message May Not Say
The message member is a wire-exposed value, and it is exposed under the least favorable conditions the framework has: an error response is emitted to a party the consumer has, by construction, just failed to validate; it is frequently emitted before any authorization decision has been reached (Consumer Requirements item 10); and it is retainable by whoever receives it.
A consumer emitting an error response MUST NOT place in message:
- Consumer-internal state — an internal identifier, a queue or worker name, a policy or rule name, a host name, a file or database path, a stack frame, or a software version.
- The contested value of a mismatched party — the in-band value the consumer rejected, or the transport-authenticated identity it expected instead. This is the rule already stated for
identityMismatchin The trust-task-error Specification; it is restated here because it is not peculiar to that code. - Resolver, verifier, or key-status internals — the URL the consumer dereferenced, a resolver’s own error text, the verification method it tried, the status list it consulted, or the reason a signature failed beyond the fact that it did.
A message MUST instead be derived from the code identifier and from the Trust Task specification’s public vocabulary — the same material the receiving party could have read for itself.
This applies to every code in Standard Error Codes and to every extended code, not only to identityMismatch. The rule was written for that code first because the leak is most obvious there, not because that is where it applies. Every other rejection is emitted on the same path, to the same possibly-unauthenticated party, and any consumer-internal fact placed in the message makes the error response an oracle: a sender that can vary one member of a document and read the message back can enumerate which identities the consumer recognizes, which identifiers it can resolve, and which of its dependencies are currently reachable — an identity- and reachability-probing instrument the consumer pays for and operates on the sender’s behalf. The consumer's own logs are the correct place for everything this rule excludes; nothing here bars recording it locally, only sending it.
§ Bounding details
details is the one member of the error payload whose size the framework does not otherwise constrain, and it travels in the direction no bound reaches: a producer that bounded its request bounded nothing about the reply. It is also emitted on a failure path — the path least exercised in testing and most readily reached by an unauthenticated party.
Accordingly, a Trust Task specification that defines a details shape for a code MUST declare a bound for it: a maximum serialized size, a maximum number of members, or both, alongside the JSON Schema fragment required by Extension by Individual Trust Task Specifications. Where no bound is declared for the code being emitted, a consumer MUST NOT emit a details object exceeding 4096 bytes of RFC 8785-canonicalized UTF-8 or 16 immediate members.
A party receiving a details object that exceeds either bound MUST NOT reject the error response on that account — the response is already a failure report, and discarding it loses the code the party needs — but MUST ignore the contents of details and MUST still honor code, retryable, and retryAfter, on the same terms as the fallback for an unrecognized extended code. Any free-text member inside details is subject to Specification Requirements item 19 and to the disclosure rule of What a message May Not Say; details is not a route around either.
§ Standard Error Codes
The framework defines the error codes listed below. A conforming consumer MUST recognize each of these codes and MUST apply the corresponding semantics.
| Code | Meaning | Default retryable |
|---|---|---|
malformedRequest |
The document did not validate against the framework schema or the task-specific payload schema. | false |
unsupportedType |
The consumer does not recognize the type URI. |
false |
unsupportedVersion |
The type URI was recognized but its MAJOR.MINOR version is not supported. |
false |
unsupportedExtension |
The document named a namespace critical under Marking a Namespace Critical that the consumer does not recognize. The consumer understood the type and its version, and refused rather than process the document without the namespace. |
false |
expired |
The document’s expiresAt was in the past at the time of evaluation. |
false |
proofRequired |
A proof was required (by the Trust Task specification or consumer policy) and was missing. |
false |
proofInvalid |
A proof was present but failed verification. |
false |
permissionDenied |
The requesting party is not authorized to invoke this task. | false |
wrongRecipient |
The document’s recipient does not identify the receiving consumer. |
false |
identityMismatch |
An in-band issuer or recipient value is inconsistent with the corresponding transport-authenticated identity. |
false |
idConflict |
The document’s id matches one the consumer has already accepted, but its content differs — see Consumer Requirements item 11. |
false |
cancelled |
The consumer stopped the task on its own initiative — operator action, policy, capacity, or a compliance hold. Distinct from a producer-requested cancellation, which is answered by a response to the control document (Task Control). | false |
taskFailed |
The recipient party attempted the task and could not complete it; further detail SHOULD appear in details. |
varies |
unavailable |
The recipient party is temporarily unable to process the task. | true |
internalError |
The recipient party encountered an unexpected internal failure. | true |
The “Default retryable” column gives the value an emitter of an error response SHOULD use unless task-specific knowledge dictates otherwise. The actual retryable value carried in a given error response is authoritative.
§ Effects Reported with cancelled
A consumer emitting cancelled has stopped work it had accepted, and Consumer Requirements item 12 already obliges it to distinguish partial execution from a task that was never begun — because a producer that cannot tell the two apart cannot decide whether to reissue, and because Control Does Not Roll Back makes clear that nothing is undone by stopping. What that obligation lacked was a shape: the same fact, reported to the same producer, is machine-readable when the producer asked for the stop and prose when the consumer decided on it.
The framework therefore defines the details shape for the cancelled code as a single member, effects, whose value is an array of effect objects:
| Member | Required | Type | Description |
|---|---|---|---|
description |
MUST | string | Human-readable statement of the effect that occurred. |
ref |
MAY | string | An identifier for the effect where one exists — a credential identifier, a record identifier, a transaction reference — so that a compensating task can name it. |
reversible |
MAY | boolean | Whether the consumer believes this effect can be compensated by a further Trust Task. Advisory. Absent means unknown, which a producer SHOULD treat as no weaker than false. |
This is deliberately the same array-of-effects shape the trust-task-control specification defines for the response to a producer-requested cancellation. The two report the identical fact — what had already landed when the stop took hold — and differ only in which party decided, which is a distinction the framework keeps precisely so that neither party has to infer it (Task Control). A producer deciding whether to invoke a compensating task should not have to parse that decision out of prose in one direction and read it from an array in the other.
The rules:
- A consumer emitting
cancelledafter one or more irreversible or externally visible effects have occurred MUST populateeffectswith one entry per effect. - An
effectsvalue of[]means nothing landed. An absenteffectsmember means the consumer did not report, and a producer MUST NOT read its absence as “nothing landed” — the general rule of Document Lifecycle applies to an omitted member as it does to an absent reply. descriptionis free text and is bound by Specification Requirements item 19 and by What amessageMay Not Say. It names the effect on the recipient party’s own state, which is what the producer needs; it MUST NOT name the internal mechanism that produced it.effectscounts toward the bound of Boundingdetails. A consumer whose effect list would exceed it reports the effects that are consequential for the producer and says so in the lastdescription, rather than truncating silently.
§ Retry Semantics
In this specification, “retrying” means re-sending a Trust Task document bit-for-bit identical to the one that elicited the error response — same id, same payload, same proof. Issuing a new document, even one addressing the same underlying intent, is not a retry; see below.
A party that receives an error response MUST NOT retry the original Trust Task document if retryable is false. When retryable is true, the party SHOULD wait at least until any retryAfter value before retrying, and SHOULD apply backoff appropriate to the transport in use.
Retrying is safe for a consequential Trust Task precisely because Consumer Requirements item 11 requires the consumer to absorb the duplicate rather than execute it again. The two rules are one mechanism seen from each end: this section tells a producer that the only safe resend is the bit-for-bit identical document, and item 11 tells a consumer that a bit-for-bit identical document it has already accepted MUST NOT produce a second consequential effect. A producer that “retries” by re-signing, re-stamping issuedAt, or otherwise altering the bytes has not retried — it has issued a different document under a reused id, which item 11 requires the consumer to reject with idConflict (Standard Error Codes). Where a producer genuinely needs a fresh attempt, it issues a new document with a fresh id, as the paragraph below describes.
A false value of retryable represents a hard failure for that specific document. It does not prohibit the producer from issuing a new Trust Task document — that is, a document with a fresh id (which SHOULD carry the same threadId to preserve correlation) — addressing the cause of the failure. For example, after receiving an error response of code = proofInvalid with retryable = false, the producer MUST NOT re-send the failed document, but MAY issue a new document carrying a valid proof.
§ Extension by Individual Trust Task Specifications
An individual Trust Task specification MAY define additional error codes specific to its task. Extended codes MUST be namespaced, separated from the local code by a colon, e.g. acl/change-role:stateMismatch. The namespace MUST be one of exactly two things:
- The emitting specification’s own
<slug>— that is, the slug of the request the error response refers to. This is the default and covers any code the specification defines for itself. - A family namespace — a proper path prefix of that slug, formed of one or more of its leading
/-separated segments (fordid-management/did/delete, the permitted prefixes aredid-management/didanddid-management). A family namespace MUST be used only for a code whose meaning is defined once for the whole family — in a shared convention that the family’s specifications reference — and never to give a specification-specific code a broader name than it has earned.
The namespace MUST NOT be the slug of a related or referenced specification, and this remains true under rule 2: a proper prefix of a specification’s own slug names that specification’s own family and can never name a sibling. A consumer of acl/change-role that needs to surface a rejection borrowed conceptually from acl/revoke therefore emits acl/change-role:<local> or acl:<local>, never acl/revoke:<local>. Extended codes MUST NOT shadow any code listed in Standard Error Codes.
This paragraph is non-normative. Rule 2 exists because families do share failure modes. Every specification under did-management can reject a request naming a domain the consumer does not host, and that rejection means the same thing in each of them; stating it once as did-management:unknownDomain lets a consumer handle the family uniformly, where per-slug codes would oblige it to enumerate every member to recognize one condition. The narrowness of rule 2 is what keeps this safe: because a family namespace is always a prefix of the emitting slug, a consumer can verify the namespacing of a received code against the document’s type alone, with no registry lookup.
A consumer (not only the spec author) MAY mint additional namespaced codes for invariants the specification did not enumerate, provided the namespacing rule above is honored. The framework’s fallback-to-taskFailed rule for unrecognized extended codes (see the second paragraph below) keeps these consumer-minted codes interoperable with clients that only implement the canonical set.
An individual Trust Task specification MAY also define the structure of details for its own error responses. Where it does so, the specification MUST state which code values may carry a details object and MUST provide a JSON Schema fragment describing the details shape for each.
A consumer that does not recognize an extended code SHOULD treat the error as if its code were taskFailed and MUST still honor the retryable and retryAfter members.
The details member defined here is distinct from the ext extension member defined in The ext Extension Member. details carries task-specific structured data tied to a specific error code, defined by the spec author; its shape is constrained by the JSON Schema fragment the specification publishes for each carrying code. ext carries vendor-namespaced extension data at payload or nested-object level, defined by the ecosystem; its namespace structure is opaque to the framework. Both members MAY appear on the same error response and serve different purposes — implementations MUST NOT treat them as interchangeable.
Example 6 — An error response with an extended code and
details(non-normative){ "id": "c4d2f713-9a8e-4d04-b29c-2f1b0b4cbe71", "type": "https://trusttasks.org/spec/trust-task-error/0.2", "threadId": "7b1e4d09-3c62-4a17-9f2d-51c8ab3e7d40", "issuer": "did:web:maintainer.example", "recipient": "did:web:org.example", "issuedAt": "2026-06-12T11:04:00Z", "payload": { "code": "acl/change-role:roleNotRecognized", "message": "Role 'principal' is not part of this ACL's role vocabulary.", "retryable": false, "details": { "offendingRole": "principal", "knownRoles": ["member", "moderator", "admin"] } } }A consumer implementing the
acl/change-roleTrust Task specification interprets the extendedcodeper that specification’s declarations (see Specification Requirements, item 9). A consumer that does not implementacl/change-roletreats the error as ifcode = taskFailed, retainsretryable = false, and ignores the contents ofdetails.
§ Reserved Response-Type Slugs
The framework reserves the following additional response-type Trust Task specification slugs. These slugs MUST NOT be used for any individual Trust Task specification registered under Type URI.
| Slug | Purpose |
|---|---|
trust-task-ok |
Deprecated at framework version 0.5.0. A courtesy acknowledgement — confirming that a task defining no success response of its own was received and performed, and optionally surfacing opaque references the consumer chose to share. Never relied upon. Superseded by the empty #response of Acknowledging a Fire-and-Forget Task. |
trust-task-next-step |
A recipient-suggested continuation — indicating that the original task was understood but cannot complete in isolation, together with the next Trust Task the recipient party expects in order to proceed. |
trust-task-next-step is published; its registry entry at https://trusttasks.org/spec/trust-task-next-step/0.1 defines the normative payload shape and conformance requirements, in the same relationship to this section that the trust-task-discovery entry has to Discovery and Capability Negotiation. A next step is a third disposition alongside the success response and the error response of this section: it reports that the originating task was understood and is blocked, leaving the exchange open where the other two close it. A consumer MUST NOT report a blocked task as an error response, nor a refusal as a next step; the three replies are not interchangeable. A next step confers no authorization — the Type URI it names is a suggestion the receiving party evaluates under its own policy, on the same advisory footing as a discovery response (Status of the Discovery Response).
trust-task-ok is published at https://trusttasks.org/spec/trust-task-ok/0.1, and is deprecated as of framework version 0.5.0 in favor of the empty #response acknowledgement defined in Acknowledging a Fire-and-Forget Task. It remains a courtesy acknowledgement with the meaning it has always had: a consumer MAY return one to confirm that it received and performed a Trust Task whose specification defines no success-response document of its own, and MUST NOT send one in place of a response a specification does define — two success dispositions for one task leave a producer unable to tell which is authoritative.
Its weakness is deliberate, and is also why it is deprecated. A producer MUST NOT rely on receiving an acknowledgement, and the absence of one carries no information: a consumer may not implement the specification, may implement it and not send one, or the document may be lost. A producer that reads absence as failure and reissues a consequential Trust Task causes exactly the duplicate effect Consumer Requirements item 11 exists to prevent. A whole Trust Task specification — a registry entry, a schema, a generated type in each supported language, a type a producer must learn to recognize that bears no relation to the one it sent — to carry a fact that may not be relied upon is more machinery than the fact is worth, and the reply the producer already awaits can carry it instead. An acknowledgement that genuinely matters is not either form: such a task declares its own success response, or a dedicated receipt task with its own proof requirement.
The consequences of deprecation are deliberately small, because the slug’s own weakness makes them small:
- A consumer SHOULD NOT emit a
trust-task-okdocument from framework version 0.5.0 onward, and SHOULD emit the empty#responseinstead. - A producer MUST continue to accept a
trust-task-okdocument, on the terms above, for as long as the specification is served. It never conveyed anything a producer was entitled to act on, so accepting it costs nothing. - The slug and its Type URI remain RESERVED under Type URI permanently, whatever becomes of the specification published under it. Retirement of the registry entry itself follows Maturity Levels and is a matter for the registry, not for this document.
Implementations encountering a Trust Task document of a reserved type whose specification is not yet published MAY ignore the document or MAY return an unsupportedType error response.
§ Transport Bindings
This section is normative.
The framework deliberately leaves transport unconstrained (Design Goals Goal 1): a Trust Task document can be conveyed over any channel that preserves its content. To make that composability work in practice, each transport protocol used to carry Trust Task documents SHOULD be accompanied by a transport binding specification.
A transport binding defines how Trust Task documents are exchanged over a specific transport — for example, DIDComm, the IETF Trust Spanning Protocol (TSP), HTTPS with mutual-TLS, AMQP, or paper. It is the integration layer between the framework’s transport-agnostic semantics and the realities of a particular transport.
§ What a Transport Binding Specifies
A transport binding SHOULD specify each of the following:
- Document carriage. How a Trust Task document is placed onto and retrieved from the transport (request body, message payload, envelope field, attachment, etc.).
- Field population from transport context. Which framework members the binding derives from transport-derived information — typically
issuer(from a transport-authenticated sender),recipient(from a transport-authenticated addressee), and any signature metadata that lets a consumer verify the frameworkproofagainst transport-bound keys or, per When to Include a Proof, accept the document without an in-bandproof. Per Precedence of In-Band over Transport-Derived Identity, the binding fills these members from the transport only when the corresponding in-band member is absent; when the in-band member is present, the transport-derived value is used as a cross-check, not as a substitute. - Consistency enforcement. The behavior when an in-band framework member and its transport-derived equivalent disagree. The framework requires they MUST be consistent (see The
issuerandrecipientMembers, Precedence of In-Band over Transport-Derived Identity, and Consumer Requirements); the binding states how the comparison is performed for the transport in question (for example, how a DID carried in-band is matched against a transport-authenticated DID). - Thread correlation (where the transport has its own). Several transports carry their own correlation and parent-correlation identifiers — DIDComm’s
thidandpthid, for example. Where a binding maps these onto the framework’sthreadId(ThethreadIdMember) andparentThreadId(TheparentThreadIdMember), it MUST state that mapping, and the mapping MUST require the two to agree only when both are explicitly present. The two layers identify different things and typically default into their own identifier spaces — a transport’s correlation identifier commonly falls back to that transport’s own message identifier, which is not the Trust Task document’sid— so requiring agreement unconditionally would fail exchanges that are otherwise conforming. As everywhere else in Precedence of In-Band over Transport-Derived Identity, the in-band member is authoritative and the transport value is a cross-check; a producer SHOULD populate the transport’s identifiers from the framework members rather than the reverse. A disagreement is a structural inconsistency and is reported asmalformedRequest, notidentityMismatch— no party’s identity is in dispute. - Transport security profile. The integrity, authentication, confidentiality, and freshness guarantees the transport provides, so that consumers can correctly evaluate the
proofrequirement under When to Include a Proof. A transport binding from which any framework security or identity requirement is derived — any binding that populatesissuerorrecipientfrom transport context, or that addresses the omission ofproof— MUST specify this profile; for such a binding the item is not optional. See Permittingproofto Be Omitted. - Error and response delivery. How an error response (Error Responses) is returned to the producer of the original document, including the behavior when the transport is fire-and-forget.
- Lifecycle mapping. Which protocol event or status corresponds to each state of Document Lifecycle, or an explicit statement that the protocol expresses no counterpart for a given state. This item is required (MUST) of every binding, per the rule stated in that section: a transport status left silently equated to a document state — a
202toaccepted, an acknowledged delivery toexecuting, a dropped connection tocancelled— reports a document state from a transport fact that does not establish it.
§ Permitting proof to Be Omitted
When to Include a Proof permits a Trust Task document to omit proof where the transport already provides end-to-end integrity and authentication between producer and consumer. Whether a given transport does so is not a property a consumer can read off the transport’s name: it depends on where the security boundary actually terminates, and on what intermediaries can do to a document in flight.
A transport binding that permits a Trust Task document to omit proof under When to Include a Proof MUST specify the security properties on which that allowance depends. That specification MUST address each of the following, and MUST state explicitly where an item does not apply to the transport rather than leaving it unaddressed:
- The authenticated producer. Which credential or transport principal is authenticated, and by which mechanism.
- The mapping to a VID. How that principal is deterministically mapped to the VID used for the framework’s identity comparisons (Precedence of In-Band over Transport-Derived Identity).
- Audience binding. How the intended consumer is identified or bound, and whether that binding is authenticated or merely asserted.
- Integrity across intermediaries. What protects the document’s bytes across every party that handles them.
- Re-origination. Whether any intermediary can modify or re-originate the document without detection by the final consumer.
- Freshness and replay. What protection, if any, the transport provides against a document being delivered more than once or out of time.
- Key and credential status. Any revocation, expiry, or key-status assumption the allowance depends on.
- Where the guarantee stops. Any condition — a routing mode, a mediator, a proxy, a store-and-forward queue — under which the transport ceases to provide producer-to-consumer end-to-end protection.
A transport binding MUST NOT state that proof may be omitted solely because an individual transport hop is authenticated, where an intermediary can modify or re-originate the Trust Task document without detection by the final consumer. Hop authentication tells the consumer who handed it the bytes, which is not the same fact as who composed them.
Where a binding’s guarantees differ by mode — direct versus routed, nested versus not, mediated versus point-to-point — the allowance MUST be stated per mode. A single allowance covering a transport that has both an end-to-end mode and a relayed one overstates the weaker case.
Silence is not permission. A transport binding that does not address the omission of proof MUST NOT be read as permitting it, and a consumer operating over such a binding evaluates the proof requirement from When to Include a Proof and the Trust Task specification alone, as it would over a transport with no binding at all. A binding whose transport does not provide producer-to-consumer end-to-end integrity and authentication SHOULD say so plainly; that statement is as useful to an implementer as an allowance, and it is what stops a familiar transport name from being read as a guarantee it does not give.
§ The Transport Handler
An implementation that exchanges Trust Task documents over a given transport SHOULD expose its transport-binding logic as a discrete transport handler component:
- On the producer side, the handler composes an outbound Trust Task document, MAY omit
issuerandrecipientwhere the transport will provide authenticated identity for those roles end-to-end (see Precedence of In-Band over Transport-Derived Identity), and applies the transport’s signing or sealing where the binding integrates it withproof. - On the consumer side, the handler extracts an inbound Trust Task document from the transport, applies the Precedence of In-Band over Transport-Derived Identity precedence — using in-band
issuerandrecipientvalues where present (cross-checking them against transport-derived identity) and deriving them from the transport only where the in-band member is absent — and surfaces any inconsistencies as validation failures per Consumer Requirements.
The handler boundary lets the framework’s validation logic remain transport-agnostic while different transports plug in their own population rules. A DIDComm handler can populate issuer from the verified sender DID of the surrounding DIDComm envelope; a TSP handler can do the same from the TSP message authentication; a mutual-TLS HTTPS handler can populate issuer from the peer certificate’s subject; an unauthenticated transport handler populates nothing, and the framework falls back to the in-band proof per When to Include a Proof.
A transport binding specification SHOULD identify itself by a stable URI and SHOULD declare which version of this framework it targets. The framework does not maintain a closed registry of transport bindings; new bindings MAY be published independently.
§ Binding Namespace
A transport binding published through the framework’s registry is identified by a URI in the /binding/ subtree of the framework’s authority:
https://trusttasks.org/binding/<slug>/<MAJOR.MINOR>
<slug> follows the same lowercase, hyphenated grammar as a Trust Task slug (Type URI); <MAJOR.MINOR> follows the version grammar of Version Scheme. Additional path segments under a binding URI — for example https://trusttasks.org/binding/didcomm/0.1/envelope — identify resources internal to the binding’s own vocabulary (envelope type values, schema URIs, status mappings, and similar). Those segments are defined by the transport binding specification, not by this framework.
The /binding/ subtree and the /spec/ subtree of Type URI are structurally disjoint. A Type URI — the value carried in a Trust Task document’s type member (The type Member) — always carries /spec/<slug>/<MAJOR.MINOR> (or, in the URN form, :spec:<slug-segments>:<MAJOR.MINOR>) and MUST NOT be rooted at /binding/.... A consumer that receives a Trust Task document whose type is a URI under https://trusttasks.org/binding/ MUST reject it with malformedRequest per Standard Error Codes. The Type URI grammar of Type URI already excludes the /binding/ path; this rule is stated explicitly so implementers and reviewers can see the namespace boundary at a glance and so that documents which somehow construct a /binding/... type value have a defined disposition rather than relying on grammar mismatch alone.
A transport binding specification published through the registry SHOULD live at bindings/<slug>/<MAJOR.MINOR>/spec.md in the framework’s source tree, paralleling the specs/<slug>/<MAJOR.MINOR>/ layout for Trust Task specifications. The grammar and content requirements for transport binding specifications are defined in What a Transport Binding Specifies.
A private transport binding — one not published through the registry — is named on the terms Private and Unpublished Trust Task Specifications items 1 and 4 set for a private Type URI:
- Its URI MUST NOT be served from, or claim to identify a resource at, the
https://trusttasks.org/domain, so a private binding URI can never equal a registry one, even where the two share a slug. - Its URI MUST be an absolute URI in one of two shapes: a path form ending
/binding/<slug>/<MAJOR.MINOR>, or a URN form ending:binding:<slug-segments>:<MAJOR.MINOR>, with the slug’s/written as:. The scheme MUST NOT behttp. The slug and version grammars above apply to both shapes. - Its URI SHOULD sit in a namespace the publisher controls — an HTTPS authority, a DID the publisher controls, or a URN namespace the publisher is entitled to assign names in — so that it uniquely identifies the binding. A publisher can then name a private specification and the binding it travels over under one authority:
https://example.com/trust-tasks/binding/<slug>/<MAJOR.MINOR> did:example:123456789abcdefghi/binding/<slug>/<MAJOR.MINOR> urn:example:tasks:binding:<slug-segments>:<MAJOR.MINOR> - A binding URI is a name, compared by exact string equality. Only an
httpsbinding URI is dereferenced; a binding named in any other scheme is distributed out of band.
§ Discovery and Capability Negotiation
This section is normative.
Two parties about to enter a Trust Task exchange often need to negotiate a shared task vocabulary first: a producer asks “which Trust Tasks are you prepared to act upon?” before committing to send any particular document. The framework supports this with a reserved Trust Task specification of its own: trust-task-discovery.
The slug trust-task-discovery is reserved by Type URI under the framework’s trust-task- namespace. Its current published version lives at:
https://trusttasks.org/spec/trust-task-discovery/0.2
Its registry entry defines the full request/response payload schema and conformance requirements. This section gives the framework-level overview; for the normative definitions of payload.patterns semantics, response shape, and conformance, see that registry entry.
trust-task-discovery/0.1 remains published. It differs only in carrying the responder’s frameworkVersion as MAJOR.MINOR, which cannot name a framework release in the three-part form of Versioning of This Framework Specification; a responder answers each version it supports in the version it was asked.
§ Discovery Request
A discovery request is a Trust Task document whose type is https://trusttasks.org/spec/trust-task-discovery/0.2. Its payload carries an optional list of slug-glob patterns:
{
"patterns": ["acl/*", "consent/request"]
}
When patterns is absent or empty, the responder treats the query as ["*"] — return every supported Trust Task.
A discovery request’s patterns list SHOULD be bounded: the specification SHOULD declare a maximum number of patterns and a maximum length for each, and a responder MAY reject a request exceeding either with malformedRequest. A pattern list is evaluated against every slug the responder supports, so an unbounded list is an unbounded amount of matching work bought for one document — and unlike the free-text bound of Specification Requirements item 19, this one is paid by the party that did not choose it. A discoverer that wants everything sends ["*"], which costs one comparison.
§ Pattern Grammar
Patterns are deliberately coarse. The grammar is:
"*"— matches every slug."<prefix>/*"— matches every slug whose value starts with the literal<prefix>/(e.g."acl/*"matchesacl/grant,acl/revoke, andacl/grant/sub)."<slug>"— exact match.
Wildcards in positions other than as the trailing /* of a <prefix>/* pattern are not interpreted; they match literally. Multiple patterns combine with OR semantics: a slug matches the query if it matches at least one pattern.
A pattern matches slugs under every authority the responder supports, so one query can return a registry Type URI and a private Type URI that share a slug. They name different specifications (Type URI), and a discoverer chooses among the entries of supportedTypes by the whole Type URI, never by the slug.
The grammar omits version filters, recursive globs (**), and regex on purpose. Versions are part of the Type URI the responder returns; a discoverer that needs to filter on version applies the constraint client-side.
§ Discovery Response
A discovery response is a Trust Task document whose type is https://trusttasks.org/spec/trust-task-discovery/0.2#response. Its payload carries the matching subset of Type URIs the responder supports:
{
"supportedTypes": [
"https://trusttasks.org/spec/acl/grant/0.1",
"https://trusttasks.org/spec/acl/revoke/0.1",
"https://trusttasks.org/spec/consent/request/1.0"
]
}
Each entry is a bare Type URI — no #request or #response fragment. A Type URI’s presence in supportedTypes means the responder handles both directions of that specification’s exchange.
A response with "supportedTypes": [] is conformant and means “I support nothing matching your query.”
§ Status of the Discovery Response
A discovery response is advisory. A Type URI’s presence is a hint that the responder will accept a Trust Task document of that type, not a binding commitment: the responder may have revoked support, may apply per-document permissions, or may reject a subsequent request with proofInvalid or permissionDenied. Every subsequent exchange runs the full Consumer Requirements pipeline; discovery only narrows what the discoverer chooses to send.
§ Authenticity of a Discovery Response
A discovery response is advisory as to content, but a discoverer acts on it: it narrows what the discoverer chooses to send, and — through the capability annotations described below — can shape what a producer puts in the documents it sends next. An advisory document that is acted upon still has to be attributable.
The trust-task-discovery specification originally declared its proof requirement OPTIONAL, on the rationale that a discovery exchange takes place between parties that “have already authenticated through the transport”. That premise does not hold generally, and the framework has since said why it cannot be assumed from a transport’s name: Permitting proof to Be Omitted requires a transport binding to establish the point explicitly, and at least one published binding — the HTTPS binding — states in its own security profile that it provides no producer-to-consumer end-to-end guarantee. A discovery exchange over such a binding is one between parties that have authenticated nothing.
Accordingly, from framework version 0.5.0:
-
The
proofrequirement applicable to thetrust-task-discoveryspecification is RECOMMENDED, not OPTIONAL. This is a framework default under When to Include a Proof, so Specification Requirements item 8 forbids the specification’s own declaration being weaker; both published versions of the registry entry now declare it. -
A discoverer MUST NOT act upon a discovery response whose origin it can authenticate neither in-band — from a
proofresolving to anissuerit recognizes — nor from the transport. This mirrors the rule thetrust-task-next-stepspecification already imposes on a continuation, and for the same reason: an unauthenticated redirection is indistinguishable from an injected one. “Act upon” here means narrowing the task set the discoverer will send, satisfying an advertised requirement, or recording the response as evidence of what a party supports; a discoverer that cannot authenticate the response MAY still discard it, log it, or retry. -
A responder’s advertised requirements are untrusted input. The expanded form of a
supportedTypesentry may carry capability annotations — therequiredExtnamespace list, by which a responder publishes theextpolicy described in Consumer Requirements, being the one the specification defines. Such an annotation is a statement by the responder about the responder’s own policy. It MUST NOT cause a producer to attach to a subsequent Trust Task document any data it would not otherwise have sent: a producer satisfies an advertised requirement only where it independently holds the data, is willing to disclose it to that party, and would have been willing to do so had the requirement never been advertised. A producer that treats an advertised requirement as an instruction has handed the choice of what leaves it to whoever answered the query — which, absent rule 2, is whoever answered it first.A producer unwilling or unable to satisfy an advertised requirement simply does not send the task. The alternative reading turns a discovery response into a data-collection instrument that costs an attacker one unauthenticated reply.
§ Privacy of Discovery Responses
A discovery response leaks information about which specifications the responder implements. Responders that consider their supported task set sensitive SHOULD authenticate the discoverer before responding, and MAY return a filtered subset of their true capabilities (or no response at all) when the discoverer is unknown or unauthenticated. See the discovery spec’s “Privacy considerations” section for additional discussion.
§ Task Control
This section is normative.
Acceptance of a Trust Task document, or commencement of execution upon it, MUST NOT by itself make the requested work semantically irrevocable. This section defines transport-independent semantics by which a producer can withdraw or pause work a consumer has already accepted.
The mechanism is a Trust Task document like any other, of the framework-reserved specification trust-task-control (Type URI). It is a request, not a response: it flows from producer to consumer, and is therefore not one of the reserved response-type slugs of Reserved Response-Type Slugs. Its payload, its response variant, and its conformance requirements are defined by its registry entry.
The framework defines three operations: cancel, suspend, and resume. The corresponding operation for a consumer that stops work on its own initiative is not a control operation at all — it is an error response carrying cancelled (Standard Error Codes), because a consumer refusing or abandoning work is already the case Error Responses covers. The two directions are deliberately not symmetric: only a producer sends a control document, and only a consumer emits cancelled, so that no party and no auditor need infer from a document alone which of them decided.
§ Control Authorization
The party identified by the target document’s issuer is authorized to cancel, suspend, or resume that task by default; a consumer MUST NOT require further authorization evidence from that party. Where the target document carried no in-band issuer, the authorized party is the identity authenticated for it under Precedence of In-Band over Transport-Derived Identity.
Whether a consumer honors a control document from any other party is that consumer’s own decision under Consumer Requirements item 10, evaluated exactly as for any other Trust Task. This is a floor, not a ceiling: a consumer executing work on behalf of a mandate holder, a supervising principal, or an organization whose agent initiated the task MAY recognize that party’s authority to stop it, under its own policy and applicable governance framework. The framework does not foreclose that, and a consumer that recognizes only the initiator is equally conformant.
A control document MUST carry a proof, and the Audience Binding rule applies to it. A control operation that cannot be attributed is worthless as evidence of withdrawal, and an unattributable one is a denial-of-service vector against another party’s work. Membership of a Trust Ceremony confers no authority here, exactly as Membership Is a Claim, Not a Permission provides generally.
§ Identifying the Target
A control document MUST identify the specific Trust Task document to which it applies, by that document’s id. It SHOULD also carry the target’s type, so that a consumer can detect a control document aimed at an id it holds under a different Trust Task specification, and SHOULD carry the same threadId as the target so the two correlate within one exchange.
threadId, parentThreadId, and ceremony membership MUST NOT, by themselves, identify the controlled task. More than one Trust Task document can occur within a single exchange or enactment, and an operation naming only the exchange is ambiguous exactly when it matters most — in a flow busy enough to have several tasks in flight.
§ When a Control Operation Takes Effect
A valid, authorized control operation that a consumer has received is one of the conditions that Consumer Requirements item 12 requires it to re-evaluate before each irreversible or externally visible effect. This is the normative connection between the two mechanisms, and it is stated here explicitly rather than left to be inferred from item 12’s general wording.
A consumer therefore does not need a separate race protocol. Having received and authorized a cancellation or suspension, it records it; at the next item 12 checkpoint the condition fails, and item 12 already requires that the subsequent effect MUST NOT be performed and that partial execution be reported distinguishably from a task that was never begun.
Where an irreversible or externally visible effect has already occurred, a consumer MUST NOT report the task as cleanly cancelled. It reports what occurred, so that the producer can determine whether a compensating action is required (see Control Does Not Roll Back).
Cancellation is terminal. A cancelled task MUST NOT be resumed, retried, or cancelled again; a producer that still wants the work issues a new Trust Task document with a fresh id. This is the same line Retry Semantics draws for error responses, and for the same reason: a document with two contradictory lifecycle states cannot be reasoned about by any party that retains it.
A control document MAY arrive before the Trust Task document it names — ordinary on asynchronous and store-and-forward transports. A consumer SHOULD record it against the target id and refuse the later-arriving document rather than execute it. The record required by Consumer Requirements item 11 serves this purpose and is bounded by the same acceptance window; a control document naming an id whose window has lapsed has nothing to match, and is reported as such. The item 11 record MUST survive cancellation for the remainder of that window, so that a re-delivery of the original document after cancellation is absorbed rather than executed.
§ Control Does Not Roll Back
Cancellation prevents future effects. It MUST NOT be understood to undo effects that have already occurred, and this framework does not require a consumer to retain state for the purpose of reversing them.
Many effects are irreversible by construction — Specification Requirements item 13 defines destructive in those terms — and for many others the state needed to reverse the effect is precisely the material the task existed to destroy or to disclose. Where an effect can be undone at all, the undoing is a distinct act with its own authority, its own audit trail, and frequently its own Trust Task specification; a Trust Task specification MAY name such a compensating task in its prose, and a consumer MUST NOT be presumed to perform one automatically.
What the framework requires instead is information: the response to a control operation reports which effects were created before the operation took hold, so that the producer can decide whether to invoke a compensating task itself.
§ Suspension and Resumption
A suspension halts further effects while preserving the consumer’s current execution state. It does not return the task to a pre-execution state, and it does not undo work already performed — that would be the rollback Control Does Not Roll Back declines to require. Resumption continues from the state the consumer holds.
A consumer MUST NOT resume a suspended task after the target document’s expiresAt. Resumption is a fresh decision to proceed — the acceptance question of Consumer Requirements item 4, asked a second time — whereas execution already in progress is protected by item 12’s deliberate exclusion of expiry from the conditions it re-evaluates. A suspension preserves state; it does not preserve an indefinite right to restart. A producer that still wants the work issues a new document.
A control document MUST NOT carry an instruction that a suspension resume automatically after an interval of the producer’s choosing. Such an interval is a deadline the producer cannot calculate — it does not know how long the consumer’s work takes — and it lets a producer pin consumer state for a period of its own election. How long a consumer retains a suspended task is that consumer’s own policy, bounded by expiresAt where present.
§ Notifications, and the Meaning of Silence
A party SHOULD notify its counterparty when a task is cancelled or when a suspended task lapses, so that the other side can release whatever state it holds. Such notifications are fire-and-forget: no response is expected, and a consumer that does not implement task control emits none.
Accordingly: no party may infer the state of a task from the absence of a notification. A notification may be lost, discarded by an intermediary, or never sent. A producer that reads silence as “still running” waits indefinitely; one that reads it as “safely abandoned” and reissues can cause exactly the second consequential effect that Consumer Requirements item 11 exists to prevent.
The response to a control document is not such a notification. It is a reply to a request, its content is relied upon under Control Does Not Roll Back, and it is subject to the ordinary rules of Request and Response Variants.
§ Transport-Level Cancellation Is Not Semantic Cancellation
Cancelling a transport operation — abandoning an HTTP request, cancelling a queue delivery, closing a session, discarding an execution handle — terminates that delivery. It MUST NOT be interpreted as semantic cancellation of the underlying Trust Task, unless the applicable transport binding carries a framework-defined control operation with equivalent semantics (Transport Bindings).
A Trust Task document that has been accepted, queued, forwarded, or handed to a worker survives the connection that delivered it, and may be held by a consumer the withdrawing party is no longer in contact with. A consumer that treats a dropped connection as a withdrawal will stop work the producer still wants; a producer that treats one as a withdrawal will believe it has stopped work that is still running.
§ Support Is Optional
A consumer that does not implement task control rejects a control document with unsupportedType (Standard Error Codes), as it would any other unrecognized type. Task control is therefore best-effort, and a producer MUST NOT rely on a cancellation having been honored in the absence of a response confirming it. A consumer that does implement it SHOULD advertise trust-task-control through discovery (Discovery and Capability Negotiation), so that a producer can establish before the wire trip whether the work it is about to request can later be stopped.
§ Security Considerations
This section is informative. Future revisions are expected to make portions of it normative as individual Trust Task specifications surface concrete requirements.
A Trust Task document carries no inherent transport security. The framework’s default rules for when an integrity proof is required of a document are given in When to Include a Proof, and each Trust Task specification declares its own requirement under Specification Requirements. When proof is included, it MUST conform to the W3C Data Integrity format defined in VC Data Integrity (see Proof); every consumer verifies the baseline suite, and any other suite is selected as Cryptosuites describes, based on the trust requirements agreed by the parties.
§ Cross-Recipient Replay
A Trust Task document signed without an in-band recipient provides no cryptographic binding between the producer's assertion and the intended audience. An attacker who obtains such a document — from a consumer's storage, an intermediate cache, or an exfiltration — can replay the bytes to a different consumer; the proof verifies against the original producer’s VID, and a recipient who does not know the producer’s out-of-band intent has no signal that the assertion was not made to them. The Audience Binding rule is the primary defence: when proof is present, recipient is also required in-band, and consumers reject any document that violates this rule with malformedRequest. Bearer specifications (Bearer Specifications) are the only specifications for which a proof-carrying document without an in-band recipient is conformant; bearer status is an intentional, normative property of the specification, not a consumer-side flag.
Replay of the same document by the original recipient back into the same consumer (within transport bounds) is also possible. For a consequential Trust Task this is not merely a threat to be mitigated by local caching: Consumer Requirements item 11 makes duplicate-execution protection a normative consumer requirement, keyed on the document id and bounded by the consumer’s acceptance window. The rule deliberately does not distinguish a hostile replay from a legitimate transport retry, because at the document layer the two are indistinguishable — the same bytes arriving twice. What matters for interoperability is that the second arrival does not repeat the effect, whichever it was.
Consumers handling assertions whose effect persists between exchanges but whose task is not consequential are outside item 11 and SHOULD still maintain such a cache for the lifetime of the assertion’s relevance.
§ Cryptosuite Downgrade
A proof’s cryptosuite is chosen by the producer and is not negotiated (Cryptosuites), so no party in transit can talk a producer into a weaker suite. The downgrade risks lie elsewhere:
- Substituting the proof. A Data Integrity proof signs its own options,
cryptosuiteincluded, together with the document, so an intermediary that rewritescryptosuiteinvalidates the proof rather than weakening it. Replacing theproofwith one in a suite the consumer does not implement gains nothing either: the consumer rejects the document withproofInvalidand does not treat it as unsigned. Removing theproofis stopped only where a proof is required (When to Include a Proof, Consumer Requirements item 7); where a specification declaresproofOPTIONAL, removal leaves a conforming unsigned document. - A weaker key the issuer also controls. An issuer whose VID resolves to keys of several types can be impersonated through the weakest of them once that key or its algorithm is broken — the case a specification’s requirement of a quantum-resistant suite exists for (Specification Requirements item 8). Such a requirement protects a document only where the consumer checks the proof’s suite against it; a consumer that accepts any suite the issuer’s keys support accepts the forgery. Retiring a broken key type from the VID is the issuer’s remedy, and checking the suite is the consumer’s.
- The consumer’s own floor. The baseline obliges a consumer to be able to verify
eddsa-jcs-2022, not to accept every suite it can verify. A consumer may refuse, withproofInvalid, a suite its own policy no longer considers sound.
§ Stripping a Criticality Marking
Criticality reports a downgrade rather than preventing one (Marking a Namespace Critical). On a signed document extCritical is covered by proof, so removing an entry, or the whole member, invalidates the document. On an unsigned document an intermediary can remove the marking, and the consumer then ignores the namespace under rule 5 of The ext Extension Member — reaching the verdict the marking existed to prevent, with neither party able to see that it happened. That is why a producer that needs the marking to survive transit is required to sign the document. An intermediary can equally add a marking to an unsigned document, naming a namespace present in ext that the consumer does not implement; the result is a refusal with unsupportedExtension, a denial of service no worse than tampering with any other member of an unsigned document.
§ Parser Hardening
A consumer deserializing untrusted JSON into a Trust Task document is exposed to the standard hazards of unbounded JSON parsing: deeply nested structures can cause stack overflow, large strings or arrays can exhaust memory, and integer overflows can occur on size fields. A consumer SHOULD bound the body size at the transport layer and SHOULD configure a maximum parse depth on the JSON deserializer. The framework does not mandate specific limits because they vary by deployment, but a depth limit of 128 levels and a body-size limit appropriate to the Trust Task specification’s payload (typically a few hundred kilobytes) are reasonable defaults. Where a Trust Task specification declares a document size bound (Specification Requirements item 21), that bound is the limit appropriate to it, and a consumer enforcing one limit per task rather than one for every task is what the declaration exists to allow.
§ Schema-Validation DoS
A consumer that validates payload values against a JSON Schema obtained dynamically (for example, via Content Negotiation over the network) MUST treat the schema as trusted only after authenticating its source. A maliciously-crafted schema can carry pattern regular expressions that exhibit catastrophic backtracking on otherwise-innocuous strings, causing the validator to consume unbounded CPU and effectively become a DoS oracle for any producer able to choose payload values. Consumers that compile schemas from arbitrary authorities SHOULD apply per-validation timeouts.
This consideration does not apply when the schema is embedded with the consumer at build time (for example, fetched from the registry once at release time, verified against Stability immutability, and shipped as part of the consumer’s binary). It does apply to dynamic-registry scenarios and to consumers that accept private specifications (Private and Unpublished Trust Task Specifications) over a runtime channel.
§ Error-Response Identity Leakage
A consumer emitting an error response under Error Responses treats the error response’s payload.message as a wire-exposed value. Free-text messages that reveal the consumer’s expected transport-authenticated identity, the contested in-band value of a mismatched party, or other consumer-internal state convert each error response into an identity- and reachability-probing oracle for an unauthenticated producer. This was guidance in earlier revisions and is now normative for every code, extended codes included: the enumerated prohibitions and the reasoning are in What a message May Not Say, and the corresponding bound on details is in Bounding details. The code-specific rule for identityMismatch — which also governs who the response is addressed to — remains in The trust-task-error Specification.
§ Privacy Considerations
This section is informative except where a subsection states otherwise. Future revisions are expected to make further portions of it normative as individual Trust Task specifications surface concrete requirements.
- Personal data is visible to every handler. Personal data carried in a Trust Task document is visible to every party that handles the document. Individual Trust Task specifications SHOULD minimize personal data in their schemas to that strictly necessary to achieve the task’s outcome, and SHOULD prefer references (e.g. DID URLs) to direct attribute values where the relying party is able to dereference them.
- Self-contained documents are durable evidence. Because Trust Task documents are self-contained, a captured document remains evidence of its content after it has been delivered. Producers SHOULD consider whether the document’s contents are appropriate for indefinite retention by the consumer.
- Discovery reveals an implementer’s task set. A discovery response tells the discoverer which Trust Task specifications the responder implements. Responders that consider that set sensitive SHOULD authenticate the discoverer before responding; see Privacy of Discovery Responses.
- Error responses can be identity oracles. Free-text
payload.messagevalues that echo consumer-internal authentication context leak identity information to an unauthenticated producer; see Error-Response Identity Leakage. - The document’s own identifiers correlate the parties. A Trust Task document names both parties in the clear and carries handles whose purpose is to join documents to one another. The normative rules that follow bound what those handles may be derived from and how widely the party identifiers may be reused; see Identifier Correlation and Linkability.
- Outcome evidence carries the exchange’s correlators. Presenting outcome evidence (Evidence That a Cited Exchange Completed) discloses the initiating and terminal documents whole —
id,threadId,parentThreadId,issuerandrecipientincluded — to every party that evaluates it, and those handles join the presentation to the exchange and to every other presentation of the same evidence. Whether a composed presentation is unlinkable is therefore not a property of the citing artifact’s own proof mechanism; it has to be assessed across the composition, which the Verifiable Trust Infrastructure specification addresses. A party SHOULD present outcome evidence only where the relying decision depends on the exchange having completed.
§ Identifier Correlation and Linkability
This subsection is normative.
A Trust Task document is, by construction, a record that names both parties in the clear and survives delivery. Top-Level Members carries issuer and recipient on the document rather than in payload; nearly every published Trust Task specification declares both REQUIRED; and a majority declare proof REQUIRED under Specification Requirements item 8. The median document on the wire is therefore a signed, retainable statement that a named party asked a named party to do a named thing at a named instant. Item 2 above observes that such a document is durable evidence of its content. This subsection addresses what it is evidence of about the parties, which before framework version 0.5.0 no rule in this framework constrained at all.
-
Party identifiers SHOULD be relationship-scoped. The
issuerandrecipientof a Trust Task document SHOULD be VIDs scoped to the relationship in which the document is exchanged — pairwise identifiers — rather than a single identifier the party presents to every counterparty it deals with. A Trust Task specification MAY declare a public, cross-relationship identifier for a party where that public identifier is intrinsic to what the task asserts — a registry that must be nameable to be resolved, an attesting authority whose statements are worthless unless they can be attributed publicly, a bearer specification whose purpose is unspecified consumption (Bearer Specifications) — and where it does, it MUST state in its prose why. Convenience is not intrinsic. A party that presents one identifier to every counterparty makes every document it has ever issued joinable by any two of those counterparties who compare what they hold, and the framework’s own rules make that holding likely: Audience Binding puts the counterparty’s identifier inside the signature, and When to Include a Proof makes the document worth retaining. -
The correlators MUST be freshly minted and unguessable.
id(TheidMember),threadId(ThethreadIdMember) andceremony.enactment(TheceremonyMember) exist so that documents can be joined to one another — and anything that joins documents for the parties joins them equally for an observer in the middle, for an intermediary, and for any party that retains one of them later. Each of the three MUST be a freshly minted value carrying sufficient entropy to be unguessable, and MUST NOT be derived — by hashing, encoding, truncation, or any other transformation — from subject data, an account number, a session identifier, a transaction reference, a counter, or any other value that carries meaning outside the document. A producer MUST NOT carry athreadIdacross exchanges that are not one exchange;idis already non-reusable under TheidMember andenactmentunder The Identifiers Are Orthogonal.A random UUIDv4 satisfies both requirements. A UUIDv5 over a subject identifier satisfies neither — it is stable across every document about that subject, so it is the subject identifier under an encoding. A sequential counter satisfies neither and additionally discloses the producer’s volume to every counterparty. Deriving a correlator from meaningful data is the specific failure this rule forecloses, because it looks like an implementation convenience and produces an identifier that is joinable outside the exchange forever.
-
issuedAtMAY be coarsened. Where the Trust Task specification does not need sub-minute freshness, a producer MAY roundissuedAtdown to a coarser granularity — the minute, or the hour — provided the value remains a conforming RFC 3339 timestamp and remains inside the acceptance window a consumer applies under Consumer Requirements item 13. A full-precision timestamp is a fingerprint: two documents bearing unrelated identifiers and the same millisecond were produced by the same process, which is exactly the join the identifier rules above are written to prevent. Coarsening and freshness trade against each other — the coarser the value, the wider the skew tolerance a consumer needs in order to accept it — so a specification that expects its producers to coarsen SHOULD state by how much. -
A ceremony enactment links every counterparty in the flow.
ceremony.enactmentis shared, by design, across every document of an enactment, and the steps of an enactment are typically bilateral exchanges with different counterparties (The Identifiers Are Orthogonal). Carrying the member therefore hands each of those counterparties a handle that joins it to all the others, whether or not they were ever intended to learn of one another. That is the right default for a flow whose participants are already mutually visible and the wrong one for a flow whose participants are not. A ceremony definition whose participation must not be linkable across steps declaresenactmentPrivacy: blinded— the mechanism thetrust-ceremony-receiptregistry entry defines against exactly this exposure — and a flow that cannot accept the enumeration MUST NOT instead rely on a receipt simply not being handed out: Bearer Specifications governs audience, not distribution.
§ Governance Considerations
This section is informative.
This specification defines a document format and a namespace; it deliberately leaves the policy questions that surround them to the governance frameworks under which the parties operate, consistent with the ToIP Governance Metamodel.
- The process by which a slug is assigned, by which a Trust Task specification enters the registry, and by which its
statusis updated is governed by the registry policy maintained alongside the registry at https://trusttasks.org/. That policy is out of scope for this specification; see Maturity Levels. - The stability commitment of Stability is made by the public registry for the specifications it hosts. Publishers of private specifications make an equivalent commitment scoped to their own trust boundary; see Private and Unpublished Trust Task Specifications.
- This framework prescribes no authorization model. Whether a producer may request an outcome, and whether a consumer may perform it, is determined by the consumer’s own policy and by the trust or governance framework it operates under; see Consumer Requirements item 10.
- A Trust Task specification MUST NOT declare that a task does or does not require consent, human approval, or an authentication step-up. Such policy is not delegable to a specification or to the registry that serves it; see Specification Requirements items 13 and 14.
- Transport bindings are not subject to a closed registry: new bindings MAY be published independently of this framework, under the namespace rules of Binding Namespace.
§ Internationalization Considerations
This section is informative.
This specification defines a JSON document format. Two internationalization properties follow from it and are normative elsewhere in this document: a Trust Task document MUST be encoded as UTF-8 without a byte-order mark (Encoding), and every framework-defined member name and enumerated value is an ASCII lowerCamelCase identifier that is never translated (Naming Conventions).
Human-readable values — the message member of an error response, and any natural-language field an individual Trust Task specification defines in its payload — may appear in any language. This framework defines no language-tagging mechanism for them. Guidance on language negotiation and tagging for such values will be completed before this specification advances beyond Working Draft status.
§ Accessibility Considerations
This section is informative.
This specification defines a data format exchanged between software components rather than a user interface, and places no direct accessibility requirements on implementers. Accessibility guidance for implementations that render Trust Task documents — in particular consent prompts, approval dialogs, and the operator-facing surfaces implied by Specification Requirements items 13 and 14 — will be completed before this specification advances beyond Working Draft status.
§ Conformance
This section is normative.
As well as sections marked as informative, all authoring guidelines, diagrams, examples, and notes in this specification are informative. Everything else in this specification is normative.
This specification defines normative requirements, using the keywords defined in Requirements Language, for the conformance targets below.
§ Conformance Targets
- Conforming Trust Task specification — a document that satisfies Trust Task Documents, Versioning, Namespace, and Specification Requirements.
- Conforming producer — an implementation that emits Trust Task documents satisfying Producer Requirements.
- Conforming consumer — an implementation that processes Trust Task documents satisfying Consumer Requirements.
A producer or consumer that satisfies these requirements against a private, unpublished Trust Task specification is a conforming producer or conforming consumer of that specification, exactly as it would be for a registry-published one; see Private and Unpublished Trust Task Specifications.
§ Conformance Tests
A conformance test suite for this framework has not yet been published. The registry repository at https://github.com/trustoverip/dtgwg-trust-tasks-tf carries executable conformance material that is expected to form its basis: the framework envelope JSON Schema for each framework version, the payload schema of every registered Trust Task specification, and the generated Rust and TypeScript client libraries whose validation pipelines implement Consumer Requirements. A normative test suite will be defined before this specification advances beyond Working Draft status.
§ References
This section is informative.
§ Normative References
- IETF RFC 2119: Key words for use in RFCs to Indicate Requirement Levels
- IETF RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words
- IETF RFC 3339: Date and Time on the Internet: Timestamps
- IETF RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
- IETF RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format
- IETF RFC 9110: HTTP Semantics
- IETF RFC 8785: JSON Canonicalization Scheme (JCS)
- IETF RFC 9562: Universally Unique IDentifiers (UUIDs)
- IETF RFC 5234: Augmented BNF for Syntax Specifications (ABNF)
- IETF RFC 6901: JavaScript Object Notation (JSON) Pointer
- W3C Verifiable Credential Data Integrity 1.0
- W3C Data Integrity EdDSA Cryptosuites v1.0
- W3C Data Integrity ECDSA Cryptosuites v1.0
- JSON Schema: A Media Type for Describing JSON Documents, Draft 2020-12
- W3C Decentralized Identifiers (DIDs) v1.0
- Semantic Versioning 2.0.0
§ Informative References
- W3C Quantum-Resistant Cryptosuites v1.0 (experimental draft)
- NIST FIPS 204: Module-Lattice-Based Digital Signature Standard (ML-DSA)
- NIST FIPS 205: Stateless Hash-Based Digital Signature Standard (SLH-DSA)
- W3C Verifiable Credentials Data Model v2.0
- W3C Manual of Style
- ToIP Governance Metamodel Specification V1.0
- Trust Tasks registry — the published Trust Task specifications, transport bindings, and ceremony definitions that conform to this framework
- Trust Tasks registry repository — the source of the registry, the transport bindings, and the generated client libraries
- Decentralized Trust Graph Credentials — Core Specification — the companion DTGWG credential specification whose
taskContextbinding cites Trust Task exchanges - Verifiable Trust Infrastructure (VTI) Specification — the companion DTGWG system specification whose composition requirements govern what a relying party may conclude from a credential together with the outcome evidence of the exchange it cites
§ Appendices
§ Appendix A: Example Trust Task Specification
This appendix is informative.
This appendix shows the elements an individual Trust Task specification declares in order to satisfy Specification Requirements. The declarations below are those of the registered acl/change-role 0.1 specification, brought up to this framework version: the registry entry predates several of the declarations shown and is being updated to match (Appendix B). That registry entry, not this appendix, is normative for the task itself.
§ Front Matter
| Declaration | Value |
|---|---|
| Slug | acl/change-role |
| Version | 0.1 |
| Type URI | https://trusttasks.org/spec/acl/change-role/0.1 |
| Target framework version | 0.7.0 |
| Maturity level | draft |
issuer party |
The changing authority. REQUIRED. No VID scheme restriction is declared. identifierScope: pairwise. |
recipient party |
The ACL maintainer. REQUIRED. No VID scheme restriction is declared. identifierScope: pairwise. |
| Outcome | The issuer records to the recipient the transition of a subject’s role within an access-control list, subject to an optimistic concurrency check against the subject’s prior role. |
| Proof requirement | REQUIRED. Rationale: role changes are the highest-impact ACL operation — a promotion extends privilege, a demotion withdraws it — so a non-repudiable, transport-independent record is necessary for audit, dispute resolution, and downstream parties that retained the prior grant (see When to Include a Proof). No cryptosuite is required beyond the baseline of Cryptosuites. |
issuedAt requirement |
REQUIRED. Rationale: a role change overwrites the entry rather than incrementing it, so a stale copy applied out of order silently reinstates a role an operator has already moved the subject off; the issue time is what lets the maintainer order two changes to the same entry and refuse the older one. The task is consequential, so this is also required by Specification Requirements item 17. The specification does not narrow the consumer’s acceptance window. |
| Side effects | mutating — reassigns a subject’s role in the ACL; recoverable by changing it back. |
| Exposure | discloses: none, actsAsSubject: false, ingests: personal. Rationale: the request names the subject by VID and may carry a free-text reason about them. |
| Retention | durable. Rationale: the maintainer keeps the change, and the signed request that made it, as the audit record of who changed the subject’s role; that audit is what the proof requirement exists for. |
| Subject path | /subject |
JSON-LD @context |
Not published at this version. |
Two further declarations are made in the specification’s prose rather than in front matter:
- Authorization evidence (Specification Requirements item 15). The task presupposes that the issuer holds authority to change roles in the maintainer’s access-control list — typically an administrative role in that same list. Whether it does is decided by the maintainer’s own policy (Consumer Requirements item 10); a verified
proofestablishes who asked, not that they may. - Free-text members (Specification Requirements item 19).
reasonis the one free-text member, bounded bymaxLength1024. It is read by the maintainer’s operators and appears in its audit log, so it is retained with the change. It is authored by the issuer, whoseproofcovers it, and is rendered as the issuer’s statement, never as the maintainer’s.
§ Payload JSON Schema
Served at the Type URI under content negotiation for application/schema+json. The $defs.Response sub-schema is the payload of the #response variant defined in Request and Response Variants; $ref values are relative to the schema’s own position in the registry.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://trusttasks.org/spec/acl/change-role/0.1",
"title": "ACL Change Role — payload",
"type": "object",
"additionalProperties": false,
"required": ["subject", "fromRole", "toRole"],
"properties": {
"subject": {
"type": "string",
"description": "VID of the party whose role is changing."
},
"fromRole": {
"type": "string",
"minLength": 1,
"description": "The subject's prior role. Used by the maintainer for the optimistic concurrency check."
},
"toRole": {
"type": "string",
"minLength": 1,
"description": "The role to transition the subject to."
},
"reason": {
"type": "string",
"maxLength": 1024,
"description": "Optional human-readable rationale."
},
"ext": {
"$ref": "../../../_framework/0.7/framework.schema.json#/$defs/Ext",
"description": "Ecosystem-defined extension members per the framework's ext rules."
}
},
"$defs": {
"Response": {
"$anchor": "response",
"title": "ACL Change Role — response payload",
"description": "The success response to an acl/change-role request. Carried in a Trust Task document whose type is https://trusttasks.org/spec/acl/change-role/0.1#response.",
"type": "object",
"additionalProperties": false,
"required": ["entry"],
"properties": {
"entry": {
"description": "The AclEntry the maintainer now holds for the subject. entry.role MUST equal the request's payload.toRole.",
"$ref": "../../_shared/0.1/acl-entry.schema.json#/$defs/AclEntry"
},
"ext": {
"$ref": "../../../_framework/0.7/framework.schema.json#/$defs/Ext",
"description": "Ecosystem-defined extension members per the framework's ext rules."
}
}
}
}
}
§ Task-Specific Error Codes
| Code | Meaning | Default retryable |
details shape |
|---|---|---|---|
acl/change-role:roleNotRecognized |
The fromRole or toRole string is not part of the ACL maintainer’s role vocabulary. |
false |
{ "offendingRole": <string>, "knownRoles": <array of string> } |
acl/change-role:stateMismatch |
The subject’s current role does not match payload.fromRole; the change was based on stale state. |
true |
{ "currentRole": <string> } |
Both codes are namespaced under the emitting specification’s own slug, per rule 1 of Extension by Individual Trust Task Specifications. The details JSON Schema fragment for acl/change-role:roleNotRecognized is:
{
"type": "object",
"additionalProperties": false,
"properties": {
"offendingRole": { "type": "string" },
"knownRoles": {
"type": "array",
"items": { "type": "string" }
}
}
}
§ An Example Conforming Document
{
"id": "1b3c5e2a-1b81-4d3e-9b51-7a3c89e3d1f2",
"type": "https://trusttasks.org/spec/acl/change-role/0.1",
"issuer": "did:web:org.example",
"recipient": "did:web:maintainer.example",
"issuedAt": "2026-06-10T14:00:00Z",
"payload": {
"subject": "did:web:bob.example",
"fromRole": "member",
"toRole": "moderator",
"reason": "Promoted after six months of community contributions."
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"verificationMethod": "did:web:org.example#key-1",
"created": "2026-06-10T14:00:00Z",
"proofPurpose": "authentication",
"proofValue": "z5xy..."
}
}
This document carries a proof member because the specification declares proof as REQUIRED in Front Matter. A consumer:
- Matches the document’s
typeagainst the Type URIs it supports, dereferencing it where needed, to learn the target framework version (0.7.0), and fetches the framework schema athttps://trusttasks.org/spec/trust-task/0.7.0. The outer document structure is validated against it. - Fetches the payload schema at the same
typeURI under content negotiation forapplication/schema+json. Thepayloadis validated against it. - Verifies the
proofper Proof against the VID inissuer. - Confirms
recipientmatches the consumer’s own VID, and thatissuedAtdoes not lie in the consumer’s own future beyond its skew tolerance. This document declares noexpiresAt; where one is present it is checked here too. - Applies the checks the specification adds on top of the framework’s — for
acl/change-role, that the subject’s current role equalspayload.fromRole, failing which the consumer answersacl/change-role:stateMismatch. The framework knows nothing of this check; it is the part Specification Requirements obliges each specification to state for itself. - Decides under its own policy whether the issuer may change roles in this list (Consumer Requirements item 10), and records the document’s
idso that a second arrival does not change the role again (item 11).
If any step fails, the consumer returns an error response per Error Responses.
§ Appendix B: Changelog
This appendix is informative.
§ Framework version 0.7.0
This revision is additive. Every document conforming to 0.6.0 still conforms. A Trust Task specification may opt into one new optional member inside payload, extCritical, and the standard error codes gain unsupportedExtension. It widens what a private specification may use as its Type URI, names a baseline cryptosuite that every consumer verifies, and lets a producer mark an ext namespace critical. Three changes can require work from an existing consumer: one that parses Type URIs by assuming https must be updated before it can accept documents of a private specification that uses another scheme, one that cannot verify eddsa-jcs-2022 must add it, and every consumer must recognize the new standard code (Standard Error Codes).
-
A private Type URI may be any absolute URI (Type URI, Private and Unpublished Trust Task Specifications). The scheme had to be
https, which tied every specification’s name to DNS and a certificate authority even where no consumer ever dereferences it. Specifications in the public registry keep thehttps://trusttasks.org/spec/<slug>/<MAJOR.MINOR>form unchanged. A private specification may now also be named by a DID URL, a URN, or any other absolute URI whose scheme is nothttp. Every form except URNs uses the existing path shape, ending/spec/<slug>/<MAJOR.MINOR>; a URN ends:spec:<slug-segments>:<MAJOR.MINOR>, with the slug’s/written as:. The slug and version grammars, the reserved slugs and the reserved fragments apply to every form, andhttpis excluded from every form. -
A Type URI is a name (Type URI). The framework now states what it already assumed: a consumer matches
typeby exact string equality and need not dereference it. Content negotiation applies only tohttpsType URIs. A specification whose Type URI is not dereferenced distributes its document and schema out of band, and a consumer authenticates their source as it would any schema not embedded at build time. The producer requirement and the payload-schema requirement that assumed content negotiation now allow for this. -
Corrected private-URI example. The first private example in Private and Unpublished Trust Task Specifications omitted the
/spec/segment that the slug-extraction rule in Type URI depends on. -
A baseline cryptosuite (Cryptosuites). The framework left the suite open and named no floor, so two conforming implementations were not guaranteed to verify each other’s proofs. Every conforming consumer MUST now verify
eddsa-jcs-2022. This is a floor on verification, not a constraint on signing: a producer chooses the suite from its key, signs with the baseline when it does not know what the consumer verifies, and may sign with another suite where the specification, a trust framework, or the recipient’s published keys indicate the consumer verifies it. Consumers SHOULD also verifyecdsa-jcs-2019with P-256, for hardware-backed signers. Aproofin a suite the consumer does not implement is rejected withproofInvalid, never treated as absent. A Trust Task specification may require a particular suite. -
Quantum-resistant suites pinned to the W3C draft.
mldsa44-jcs-2024(ML-DSA-44) andslhdsa128-jcs-2024(SLH-DSA-SHA2-128s) are not part of the baseline, but their identifiers and Multikey encodings are pinned to the W3C Quantum-Resistant Cryptosuites draft so that early adopters interoperate. A later change in the draft is adopted as a new entry, not a reinterpretation. -
A producer may mark an
extnamespace critical (Marking a Namespace Critical). Rule 5 of TheextExtension Member makes every namespace safe to ignore, so a producer could not tell an ignored namespace from an understood one, and a consumer that dropped a namespace the document’s meaning depends on reached a verdict the producer never asked for. A Trust Task specification that allowsextat an object level MAY now also allow a siblingextCriticalarray naming namespaces that are critical. A consumer that does not recognize a critical namespace MUST reject the document with the new standard error codeunsupportedExtension(Standard Error Codes). A producer MUST NOT mark a namespace that is merely useful, and SHOULD establish support before marking. Opting in is per specification and per object level, so no existing document changes meaning. -
Examples sign with the baseline suite. Example 1 in Top-Level Members, the error-response example and the example in Appendix A carried
eddsa-rdfc-2022, which a consumer is not required to verify. They now sign witheddsa-jcs-2022, the baseline named in Cryptosuites. -
The Abstract states the bilateral model. The Abstract spoke of work “between two or more parties” while Terminology defines each document as bilateral. The Abstract now says that exchanges between more than two parties are made of bilateral documents the framework links.
-
A group as a party (The
issuerandrecipientMembers). A new non-normative note: a group that holds an authority jointly, such as under a threshold key, is a party when it has its own VID, and whether a given member may act for it is an authorization question, not a matter for the envelope. -
A private transport binding is named like a private Type URI (Binding Namespace). A private binding URI had to use “an authority the publisher controls”, with no shape stated. It now takes the same forms as a private Type URI: a path ending
/binding/<slug>/<MAJOR.MINOR>under an HTTPS authority or a DID, or a URN ending:binding:<slug-segments>:<MAJOR.MINOR>. It still MUST NOT usehttps://trusttasks.org/,httpis excluded, and the publisher-controlled namespace is a SHOULD, as it is for a private Type URI. Only anhttpsbinding URI is dereferenced. -
Security considerations for suites and criticality (Cryptosuite Downgrade, Stripping a Criticality Marking). Two new subsections set out what the baseline cryptosuite and
extCriticaldo and do not protect against: a substituted or removed proof, an issuer key of a weaker type, and a marking removed from or added to an unsigned document. -
Producer obligations for
extCritical(Producer Requirements). The producer rules of Marking a Namespace Critical are restated where the other producer obligations are listed. -
Slugs are scoped to their authority (Type URI, Pattern Grammar). A private specification may share a slug with a registry specification. Because a private specification can never be named under
https://trusttasks.org/, the two Type URIs never collide: a Type URI identifies a specification by its whole string, and a discoverer chooses among discovery results by that string, not by slug. -
A specification may mention ceremonies (The
ceremonyMember). The rule that a specification MUST NOT declare anything about ceremonies is relaxed: it MAY refer to them in prose, and still MUST NOT make conformance depend on being a ceremony step or constrain theceremonymember. -
unsupportedTypefor an unpublished reserved type (Reserved Response-Type Slugs). A consumer that answers a document of a reserved type whose specification is not yet published now returnsunsupportedType; it returnedunsupportedVersion, which implies the type was recognized. -
validatedmay lead toexpired(Document Lifecycle). A document can expire between validation and acceptance, and the table now permits the transition. Its validation checks also include the timestamp window of Consumer Requirements item 13. -
Appendix A brought up to date. The example now targets 0.7.0 and makes the declarations current Specification Requirements expect:
identifierScope,exposure.ingests,retention, authorization evidence and the free-textreasonmember. The consumer walkthrough adds the authorization and duplicate-execution steps. -
Editorial fixes. Text that still assumed every Type URI is dereferenced — the payload-schema, JSON-LD context and schema-validation rules — now allows for out-of-band distribution. Stale statements about the discovery specification’s
proofrequirement, and phrases dated “this version” that meant 0.5.0 or 0.4.0, are corrected. Member lists now nameparentThreadId,ceremonyandextCriticalwhere they were missing. The restated slug-reservation rule matches Type URI, and cross-references in Marking a Namespace Critical name theextrules they mean. RFC 6901 is added to the references. Example 4 now precedes Example 4a, and Example 5 no longer reuses Example 4’s thread. Spelling is US throughout, grammar fixes are made, and BCP 14 keywords are bolded where they had been left plain. -
Companion changes in the registry. What remains is to publish a 0.7 framework envelope schema, which adds the
ExtCritical$defthat Marking a Namespace Critical refers specifications to; to publishtrust-task-error/0.6, whose closed list of standard codes gainsunsupportedExtension; and to bring theacl/change-role/0.1entry into line with Appendix A.
§ Framework version 0.6.0
This revision is additive. The document wire format gains no member and loses none, and every document conforming to 0.5.0 still conforms. It adds one new obligation on consumers, and one on Trust Task specifications. Each applies only where an exchange is cited from outside the framework as evidence that it completed.
-
Evidence that a cited exchange completed (Evidence That a Cited Exchange Completed). Binding a Citation to the Document It Names fixed which exchange a citation names, and said nothing about whether that exchange completed. A credential citing a cancelled, failed or still-open exchange binds as well as one citing a completed exchange. The completion rule lived instead in individual Trust Task specifications (
witness/session/submit/0.1,vetting/session/0.1) and in the companion credential specification, and none of those versions generalized. Outcome evidence is now defined once. It is the initiating document together with a terminal success document, which a consumer relying on a citation as evidence of completion MUST pair by four checks:- the citation binds the initiating document;
- the terminal document belongs to that exchange, by
threadIdrouted through the initiating document and by the binding its governing specification declares; - its
typeis the declared outcome-evidence response; - its
proofverifies under the initiating document’srecipient.
Each check closes a case a weaker rule decides wrongly: a minted
threadId, a cancelled task’s control#response, a response signed by the holder, and athreadIdreused across exchanges. All four were exercised against real Trust Task documents before release. -
Declaring outcome evidence (Specification Requirements item 20). A Trust Task specification whose exchanges may be cited as evidence of completion declares which success response is its outcome evidence. For that response it defines a payload schema, requires
proofandissuedAt, and SHOULD declaredurableretention. It declares the payload members that bind the response to the initiating document: the initiating document’sidand task digest, or, only where the initiator must also issue the citing artifact, a fresh value such as a challenge. It requires the initiating document to carryrecipient. The declaration is made by the specification governing the initiating document, because an exchange may close with the response to a task conducted on its thread under another specification. A specification that declares nothing is not thereby non-conforming, but its exchanges cannot be cited as evidence of completion. -
Outcome evidence carries the exchange’s correlators (Privacy Considerations item 6). Presenting outcome evidence discloses whole Trust Task documents, including their
id,threadIdand both parties’ identifiers, whatever the citing artifact’s own proof mechanism. Whether a composed presentation is unlinkable is therefore assessed across the composition. The Verifiable Trust Infrastructure specification is added as an informative reference for that. -
Companion changes in the registry. The registry already carries the declarations for its two cited exchanges,
witness/session/0.1andvetting/session/0.1, through anoutcomeEvidencefront-matter key that the registry build checks against item 20. What remains is to publish a 0.6 framework envelope schema, identical in shape to 0.5’s, so that a specification can declare 0.6.0 as its target framework version.
§ Framework version 0.5.0
This revision is additive, with one deprecation. The document wire format gains no member and loses none; every document conforming to 0.4.0 still conforms. Three new front-matter declarations are SHOULD, each with a fail-safe reading of an absent value, so no already-published Trust Task specification becomes non-conforming for want of them.
-
Identifier correlation and linkability (Identifier Correlation and Linkability). The framework had, until this version, said nothing about what its own identifiers disclose about the parties. A census of the registry settles that this is not a hypothetical: 346 of 349 published specifications declare both
issuerandrecipientREQUIRED, and 210 declareproofREQUIRED, so the median Trust Task document is a signed, retainable record naming both parties in clear. Privacy Considerations item 2 already observed that such a document is durable evidence of its content; nothing addressed what it is evidence of about the parties.Four rules, now normative.
issuerandrecipientSHOULD be relationship-scoped (pairwise) VIDs unless the specification states why a public identifier is intrinsic to what the task asserts. The three correlation handles —id,threadId,ceremony.enactment— MUST be freshly minted, unguessable, and MUST NOT be derived from subject data, an account number, a session identifier, or a counter; a UUIDv5 over a subject identifier is the subject identifier under an encoding, and a sequential counter additionally discloses volume.issuedAtMAY be coarsened where the specification does not need sub-minute freshness, because a full-precision timestamp is a fingerprint. And aceremony.enactmentlinks every counterparty in a flow by default — a ceremony definition whose participation must not be linkable declaresenactmentPrivacy: blindedrather than relying on a receipt not being handed out. -
One document lifecycle (Document Lifecycle). The lifecycle a consumer follows was implied in five places — the acceptance bound of Consumer Requirements item 4, the duplicate record of item 11, the re-evaluation of item 12, Task Control, and Error Responses — and no section named the whole set, so implementations inferred five overlapping lifecycles from one document. A normative state table now names them once (
received,validated,accepted,executing,suspended,responded,errored,cancelled,expired), together with the reserved reply that carries each transition.Silence had acquired four meanings — success for a fire-and-forget task, nothing for
trust-task-ok, “duplicate absorbed” under item 11, and nothing again for control notifications — and the document’s own text already warned that the silence of item 11 “must not be reused to signify work half-done”. The table settles on the only safe reading: the absence of a reply distinguishes no two states, and a producer MUST NOT infer any state from it. A transport binding MUST map the table onto its own protocol, so that a202is not silently equated with acceptance, an acknowledged delivery with execution, or a dropped connection with cancellation. -
Freshness (Consumer Requirements item 13, Specification Requirements item 17). The duplicate-execution record of item 11 is implementable only inside a bounded window, and nothing obliged a document to carry a timestamp that could place it in one — so a document with no
expiresAtand no usableissuedAtnever leaves the set a consumer must recognize, and its record has to be kept forever. A consumer MUST now reject a document whoseissuedAtis in its own future beyond its skew tolerance, and one whoseexpiresAtis at or before itsissuedAt. Both aremalformedRequestrather thanexpired, becauseexpirednames a document that was once acceptable and neither of these ever was. A Trust Task specification defining a consequential Trust Task MUST requireissuedAt, which puts the obligation on the party that can satisfy it for nothing. -
Retention, ingested data, and identifier scope (Specification Requirements items 5, 14, and 18). Three new front-matter declarations, each descriptive, not prescriptive on the exact terms of items 13 and 14: none may be read as obliging a consumer to do anything, none may carry a consent requirement, and each has a fail-safe reading of an absent or unresolvable value.
retention(classoftransient,exchange, ordurable, plus arationale) gives the framework a retention vocabulary it has never had. The gap was not neutral: every rule in this document and in the published corpus that uses the word retain mandates more retention — a proof so a document can be relied on later, a digest so a duplicate can be absorbed, aninResponseToso an error can be evidence — and none bounds it, so the safe reading of every task has been to keep everything. Absent or unresolvable reads asdurable.exposure.ingests(none,metadata,personal,secret) closes a blind spot in the exposure class:disclosesis response-only, so a task whose request carries a full verifiable presentation, a document image, or free-text a person typed declaresdiscloses: noneentirely correctly and says nothing about the most sensitive data in the exchange. Absent or unresolvable reads as no less sensitive thanpersonal.parties[].identifierScope(pairwise,public,any) makes the first rule of Identifier Correlation and Linkability machine-readable, so a reviewer or a registry can see which specifications expect a public identifier without reading each one for the justification. Absent or unresolvable reads as no less correlatable thanpublic.These three need front-matter meta-schema support in the registry repository before they can be declared; see the note at the end of this entry.
-
Free-text members are bounded (Specification Requirements item 19). A free-text member is the one place in a Trust Task document where the schema constrains the shape and nothing constrains the content — so it is where personal data arrives in a task declaring it ingests none, where a secret arrives pasted by someone asked for a reason, and where instructions addressed to a downstream reader arrive in a field the specification took for a comment. It is also unbounded wire cost: Parser Hardening puts the limit at the transport layer, which is the right defence and the wrong place to pick the number, since one figure there covers every task the consumer implements.
Any free-text member MUST declare a
maxLength, SHOULD be OPTIONAL, and the specification MUST state who reads the value, whether it is retained, and whether it is trusted. A closed enumeration plus one bounded, optional note is preferred to free text carrying the meaning the enumeration should have carried.task-consent/request/0.1’snoteis the pattern: 500 characters, optional, attributed to its author on every surface, declared explicitly untrusted, and forbidden from displacing the effects it appears beside. -
A fire-and-forget task can be acknowledged, and
trust-task-okis deprecated (Acknowledging a Fire-and-Forget Task, Reserved Response-Type Slugs). Forbidding a fire-and-forget specification from emitting a#responseis the sole reasontrust-task-okexists — and that slug is defined so that it cannot carry meaning: a consumer MUST NOT require any member of it, a producer MUST NOT rely on receiving one. A registry entry, a schema, and a generated type in every supported language, on atypebearing no relation to the one the producer sent, to convey “something arrived”.A fire-and-forget specification’s consumer MAY now return
<type>#responsewithpayloadexactly{}, and a producer still MUST NOT rely on it.trust-task-okis deprecated in its favor: a consumer SHOULD NOT emit one from this version, a producer MUST continue to accept one for as long as the specification is served, and the slug stays RESERVED permanently. Retirement of the registry entry is a separate change in the registry repository and is not effected by this revision.Request and Response Variants also gains a table of the three response dispositions — success
#response, failuretrust-task-error, continuationtrust-task-next-step— beside the fragment rule. “Is this document a response?” was answerable in three separate places, so an implementation that found one of them hard-coded a list of the slugs it knew, which the next reserved slug silently invalidates. -
Discovery hardening (Authenticity of a Discovery Response, Discovery Request). The discovery specification justifies its OPTIONAL
proofrequirement on the ground that the parties “have already authenticated through the transport”. That is false over the HTTPS binding, whose own security profile states plainly that it provides no producer-to-consumer end-to-end guarantee — and Permittingproofto Be Omitted already refuses to let a guarantee be read off a transport’s name.The applicable
proofrequirement rises to RECOMMENDED, and a discoverer MUST NOT act on a discovery response whose origin it can authenticate neither in-band nor from the transport — the ruletrust-task-next-stepalready imposes on a continuation, for the identical reason: an unauthenticated redirection is indistinguishable from an injected one. A responder’s advertised requirements, such as arequiredExtnamespace, are untrusted input and MUST NOT cause a producer to attach data it would not otherwise have sent; the contrary reading turns a discovery response into a data-collection instrument that costs an attacker one unauthenticated reply. A request’spatternslist SHOULD be bounded, since the matching work is paid by the party that did not choose it. -
The error model states what may not be said, and bounds what may (What a
messageMay Not Say, Boundingdetails, Effects Reported withcancelled). The message-sanitization rule was normative foridentityMismatchalone and a SHOULD in an informative section for everything else — yet every rejection is emitted on the same path, to the same possibly-unauthenticated party, generally before any authorization decision has been reached. It is now normative for every code: amessageMUST NOT reveal consumer-internal state, the contested value of a mismatched party, or resolver, verifier, or key-status internals. Otherwise each error response is an identity- and reachability-probing oracle that the consumer pays for and operates on the sender’s behalf.detailswas the one error-payload member with no size bound, traveling in the direction no producer-side bound reaches. A specification defining adetailsshape MUST now declare a bound; where none is declared, 4096 bytes of JCS or 16 immediate members apply. An oversizeddetailsis ignored — never grounds to discard thecode, which is what the receiving party actually needs.The
cancelledcode gains a framework-defineddetailsshape: aneffectsarray, deliberately the same array-of-effects thattrust-task-controlalready defines for the response to a producer-requested stop. The two report the identical fact — what had already landed when the stop took hold — and differed only in that one was machine-readable and the other prose, according to which party decided.effects: []means nothing landed; an absenteffectsmeans the consumer did not report, and MUST NOT be read as “nothing landed”. -
Two digests, named (Binding a Citation to the Document It Names).
taskDigestexcludes the top-levelproofand asks what the document says;stepDigestincludes it and asks which serialization arrived. Both have been carried in members calleddigestMultibase, so an implementation with a single function of that name has in practice picked one answer and applies it to both questions — and whichever it picked is wrong for one of them. A short table now states the difference beside the citation rule that turns on it. Clarification only: neither is a document member, no computation changes, and every existing citation and step chain remains conforming. -
Companion changes required in the registry. Two items in this revision are not complete until the registry repository moves. The three new front-matter declarations —
retention,exposure.ingests, andparties[].identifierScope— need support inspecs/spec.meta.schema.jsonbefore a specification can declare them; until then they are declarable in prose only. And the deprecation oftrust-task-okis a statement of this framework’s position: retiring the registry entry itself follows Maturity Levels and belongs to the registry’s own change process.
§ Framework version 0.4.0
-
The
ceremonymember (TheceremonyMember). A Trust Task document MAY now record that it is one step of a Trust Ceremony — a flow composed of several Trust Tasks. The framework has always modeled multi-party work as multiple bilateral tasks (Terminology); what it lacked was a way for the collection to be named, identified, and evidenced, so every implementation held that knowledge in application code and no two could interoperate above the level of a single task. The member carries the enactment (globally unique and non-reusable, unlikethreadId, because evidence about a flow needs a stable anchor), the step’s name, an optional content-pinned reference to a published ceremony definition, and an optional set of predecessor digests.Three properties are deliberate. It is carried on the document rather than in
payload, so no Trust Task specification changes and any existing task may be composed into a flow its author never anticipated. It is covered byproof, so a step cannot be lifted into a different enactment or reinterpreted under a different definition. And it confers no authority (Membership Is a Claim, Not a Permission, Consumer Requirements item 9) — membership is an assertion by the issuer, not a verified fact, which is what makes it safe for a consumer to ignore the member entirely.Additive: the document wire format gains an optional member, and every document conforming to 0.3 still conforms.
-
The
/ceremony/subtree and thetrust-ceremonyreservation (Ceremony Namespace, Type URI). Ceremony definitions are identified in a third subtree under the framework’s authority, structurally disjoint from/spec/and/binding/on the same terms — no URI under it is a Type URI, and a document whosetypeis rooted there is malformed. The slug reservation of Type URI widens from^trust-task($|-|/)to^trust-(task|ceremony)($|-|/); the new half is unused at this version and exists so the namespace cannot be claimed by another party before the layer that needs it is specified.The content of a ceremony definition is out of scope for this revision. This version defines where definitions live, how a step references one, and that the reference is by content as well as by name — a URI alone would leave a flow’s rules mutable by whoever controls the URI, retroactively and for every enactment already performed.
-
Authorization is distinct from identity and proof (Consumer Requirements item 10, Specification Requirements item 15). A consumer MUST NOT treat successful validation of a VID,
issuer,recipient, transport-derived identity, orproofas establishing that anyone is authorized to request or perform the task, and MUST evaluate authorization separately before executing. The framework already said this twice in narrow forms — ceremony membership grants nothing (Membership Is a Claim, Not a Permission, Consumer Requirements item 9), and the side-effect and exposure classes describe without authorizing (Specification Requirements items 13 and 14) — but never for an ordinary task, leaving an implementer free to read valid proof + recognized issuer + correct recipient as an authorized instruction. That inference is the same confused-deputy vector Membership Is a Claim, Not a Permission forecloses, and it is most dangerous where the producer is an agent that can prove its identity but holds no authority to act.The rule is deliberately model-neutral: it requires that an authorization decision be made, not how. A verified assertion may still be the authorization where a specification defines that role and the consumer’s policy accepts it — the
task-consentdesign — but that is now an explicit declaration under item 15 rather than an available default.Additive: the wire format is unchanged and every document conforming to 0.3 still conforms. A consumer that already separated authorization from validation needs no change.
-
trust-task-okpublished (Reserved Response-Type Slugs). The success acknowledgement reserved since 0.1 now has a registry entry, and the four revisions it spent unspecified are the reason it is narrower than its original description implied. A consumer MAY return one to confirm that it received and performed a task whose specification defines no success response of its own; it MUST NOT be sent in place of a response a specification does define, because two success dispositions for one task leave a producer unable to tell which is authoritative.Its weakness is the design. A producer MUST NOT rely on receiving one, and the absence of one carries no information — a consumer may not implement it, may implement it and stay silent, or the document may be lost. That rule is what keeps the specification safe to add at all: a producer that read absence as failure and reissued a consequential Trust Task would cause exactly the duplicate effect Consumer Requirements item 11 exists to prevent, and it also leaves item 11’s own use of silence — an absorbed duplicate of a fire-and-forget task — unambiguous.
Accordingly an acknowledgement that genuinely matters is not this document. A task whose acknowledgement will be relied on, audited, or disputed declares its own success response, or a dedicated receipt task with its own proof requirement — the choice
chat/message/0.1already made deliberately, so that its acknowledgement is a signed link in a chain rather than a transport-level ack.Additive: the wire format is unchanged, and a consumer that ignores acknowledgements loses nothing it was entitled to.
-
Task control (Task Control, Type URI, Standard Error Codes). A producer can now withdraw or pause work a consumer has already accepted. The framework could express what should happen next —
parentThreadId, ceremonies,trust-task-next-step— but nothing let a request be taken back, which for long-running and agentic execution is a corrigibility gap: an agent could be told to start and had no defined way to be told to stop. Transport-level cancellation is not a substitute, because a document that has been accepted, queued, or forwarded survives the connection that delivered it.The mechanism is deliberately small, because three rules added earlier in this revision already do most of the work. Consumer Requirements item 12 is where a control operation takes effect — a received, authorized operation is one of the conditions it re-evaluates before each irreversible effect, and When a Control Operation Takes Effect says so explicitly rather than leaving it to be inferred. Item 12 already requires that the subsequent effect not be performed and that partial execution be reported distinguishably, so no separate race protocol was needed. Item 11’s per-
idrecord serves as the tombstone for a control document that arrives before the task it names, bounded by the same acceptance window. Item 10 settles who may ask.Authorization is a floor, not a ceiling. The target’s
issueris authorized by default; whether a consumer honors any other party is its own decision under item 10. An absolute rule would have foreclosed the mandate holder and supervising principal — the delegated execution this framework exists to support — at framework level, where every other authorization decision is the consumer’s.Cancellation prevents future effects and never undoes past ones (Control Does Not Roll Back). Many effects are irreversible by construction, and the state needed to reverse one is frequently the material the task existed to destroy: retaining a superseded private key so a rotation could be rolled back would defeat the rotation. What the framework requires instead is information — the response reports what occurred, so the producer can invoke a compensating task itself.
Suspension halts further effects while preserving execution state (Suspension and Resumption); it does not rewind the task, which would be the rollback Control Does Not Roll Back declines to require. A consumer MUST NOT resume after
expiresAt, because resumption is the acceptance question of item 4 asked a second time — while execution already under way stays protected by item 12’s exclusion of expiry.Silence carries no information (Notifications, and the Meaning of Silence). Notifications are fire-and-forget and a consumer need not implement control at all, so a producer that reads silence as “safely abandoned” and reissues can cause the second consequential effect item 11 exists to prevent.
Additive: the wire format is unchanged for every existing task, and a consumer that does not implement control rejects the new type as it would any other it does not recognize.
-
cancelled(Standard Error Codes). A new standard error code for a consumer that stops a task on its own initiative — operator action, policy, capacity, a compliance hold. Named for what happened rather than who caused it, since an operator is one reason among several. It is distinct from a producer-requested cancellation, which is answered by a response to the control document: without the distinction, no party and no auditor reading the retained documents could tell a withdrawal from a refusal, and the two imply opposite things about whether to try again. Carried bytrust-task-error/0.5. -
Validity during execution (Consumer Requirements item 12, Specification Requirements item 16, Top-Level Members). Validating a document established that it was eligible for processing at the instant it was validated. For execution that is delayed, long-running, resumed, or agentic, that instant and the instant a consequential effect actually lands can be far apart — and the authority in between can evaporate. A consumer MUST now re-evaluate, immediately before each irreversible or externally visible effect, every condition its policy and the Trust Task specification require: delegation, mandate, capability, membership, standing, credential or key status, subject relationship.
task-consent/decision/0.1already required this locally, re-checking policy and approver enrolment so a device revoked during the approval window cannot carry a task through; item 12 makes the general case normative.The rule is about authority, not the clock.
expiresAtis deliberately excluded, and Top-Level Members now says plainly that it bounds acceptance and does not abort work under way. Re-checking it mid-execution would turn a statement about a request’s staleness into an execution timeout the producer never set and could not compute, since it does not know how long the consumer’s work takes. A task with a genuine completion deadline declares it in its ownpayload, where the specification can define what lapsing means — astask-consent/request/0.1already does — and item 12 then re-evaluates it like any other condition. No new framework member was needed.Stopping is not automatically safe. Once an irreversible effect has occurred, declining the next one does not undo it, and abandoning a partly applied change can leave the recipient party in a state neither party asked for. Item 12 sits before each effect for that reason, Specification Requirements item 16 asks multi-stage specifications to say when partial application is unsafe, and a consumer that does stop SHOULD report partial execution distinguishably from never having begun — a producer that cannot tell the two apart cannot decide whether to reissue.
-
A transport binding must justify any allowance to omit
proof(What a Transport Binding Specifies, Permittingproofto Be Omitted). When to Include a Proof has always let a document omitproofwhere the transport provides end-to-end integrity and authentication between producer and consumer, but What a Transport Binding Specifies only SHOULDed the security profile that would establish whether it does. A binding could therefore rest a proof allowance on “the transport is authenticated” without saying which party is authenticated, how that principal becomes a VID, what an intermediary can do to the bytes, or where the guarantee stops — leaving consumers to infer a security boundary from a transport’s name.The profile is now MUST for any binding from which a framework security or identity requirement is derived, and a binding permitting omission must address eight specific properties, saying explicitly where one does not apply. Two rules carry most of the weight: hop authentication is not producer authentication where an intermediary can re-originate undetected, and an allowance MUST be stated per mode where a transport has both an end-to-end mode and a relayed one.
Silence is not permission. A binding that does not address omission is not to be read as permitting it. A binding whose transport genuinely cannot offer the guarantee SHOULD say so plainly — that statement is as useful as an allowance, and it is what stops a familiar transport name from being taken for a guarantee it does not give.
-
Duplicate-execution protection (Consumer Requirements item 11, Standard Error Codes, Retry Semantics). A consumer MUST NOT let the same Trust Task document cause a consequential effect twice. The pieces were all present — unique
ids (TheidMember), audience binding (Audience Binding), bit-for-bit retry (Retry Semantics), and an idempotency cache recommended in Cross-Recipient Replay — but the last of those was a SHOULD in a non-normative section, so two conforming consumers could both validate a repeated document correctly and one of them execute the transfer, the deletion, or the key rotation a second time. The framework had strong document-identifier uniqueness and no execution uniqueness to match it.The rule keys on the document
idand is deliberately blind to intent: at the document layer a hostile replay and a legitimate transport retry are the same bytes arriving twice, and what matters is that the second arrival does not repeat the effect. Three questions the requirement has to answer, and does: a consumer retains a digest, not just anid, because anidalone cannot tell the retry it must absorb from the conflict it must reject; retention is bounded by the same window over which the consumer will still execute the document, so the rule never demands unbounded memory; and where a specification defines no success response, the duplicate is simply not executed and the silence is correct rather than an error.Retry Semantics gains the other half of the story — retry is safe because item 11 absorbs the duplicate — and records that a producer that re-signs or re-stamps has not retried but has issued a different document under a reused
id. -
idConflict(Standard Error Codes). A new standard error code for a document whoseidmatches one already accepted but whose content differs. Distinguishing this from a retry is the point: a retry is absorbed silently, a conflict is refused. Consumers at earlier framework versions will not recognize the code;trust-task-error/0.4carries it. -
The term consequential Trust Task (Terminology). The predicate
sideEffects.level ∈ {mutating, destructive} ∨ exposure.discloses = secret ∨ exposure.actsAsSubject = trueis now named once rather than re-spelled at each use, with the fail-safe reading of an absent or unresolvable declaration folded into the definition. No new obligation attaches to the term itself. -
Binding a citation to the document it names (Binding a Citation to the Document It Names). Naming an Exchange from Outside the Framework has required an external citation to name an exchange by the initiating document’s
idsince 0.3, and anidturns out to be only half of an anchor. TheidMember’s uniqueness obligation binds conforming producers; it stops nobody from writing a different document — different parties, differentpayload— and giving it the sameid. A verifier pairing a credential with a document byidequality alone accepts that counterfeit and then reports an event the documents do not attest. The gap was found from the DTG Core Credentials side, on a Verifiable Witness Credential whosetaskContextis exactly such a citation.A citation relied upon outside the exchange now SHOULD carry a task digest over the document it names, and the computation is fixed where one is carried: JCS over the document with its top-level
proofremoved, hashed, multihash-tagged, multibase-encoded. Excludingproofis what makes the value well-defined — Proof already excludesprooffrom the content a proof covers, so the digest and the signature commit to the same content, and a document has one task digest whether or not it was ever signed. A digest that includedproofwould be undefined for every document When to Include a Proof permits to carry none, and would change value at the moment of signing.Two rules exist because the obvious implementations get them wrong. Comparison is over the decoded multihash bytes, never the encoded string:
DigestMultibaseadmits both base58btc and base64url, so two conforming encodings of one digest are different strings and a string compare rejects a valid pairing. And an unimplemented hash algorithm makes a citation unverified — never recomputed under a substitute algorithm, and never silently downgraded toidcomparison.The section states plainly what the mechanism does not do. The digest attests content, not authenticity; it is load-bearing because the citing artifact signs it, and a
proof-stripped copy of a genuine document reproduces the same value by design. It is also not the document identity of Consumer Requirements item 11, which asks which serialization arrived and counts a re-signedproofas a different document — that distinction isidConflictand remains untouched. Additive and non-breaking: no document member is added, and no existing citation becomes non-conforming. -
trust-task-next-steppublished (Reserved Response-Type Slugs). The continuation response reserved since 0.1 now has a registry entry defining its payload. A next step is a third disposition alongside the success response and the error response: the two of those close the originating task, and a next step leaves it open. A consumer MUST NOT report a blocked task as an error, nor a refusal as a next step. -
This framework specification is now versioned under Semantic Versioning (Versioning of This Framework Specification). Framework releases are numbered
MAJOR.MINOR.PATCHand published at the full three-part version: this document’s Type URI becomeshttps://trusttasks.org/spec/trust-task/0.4.0, and thetargetFrameworkVersiona specification declares is that same three-part value. The point of thePATCHcomponent is that errata to a published framework version get a number and a URI of their own. Previously they had nowhere to go: correcting0.4in place is exactly what Stability forbids for every other artifact in the registry, and minting0.5for a typo overstates what changed.It applies to this document alone. Individual Trust Task specifications keep the two-part
MAJOR.MINORof Version Scheme — including the framework-defined ones, sotrust-task-error/0.4is unchanged — and no Type URI outside the reservedtrust-taskslug moves.Nothing already published stops resolving.
0.1through0.4denote0.1.0through0.4.0;0.4and0.4.0are the same release, and the entries below stand as published. A two-parttargetFrameworkVersionresolves asM.N.0, and the registry continues to serve the two-part framework URIs as aliases. Specifications published or re-issued from this version onward declare the three-part form. The document wire format is unchanged.
§ Framework version 0.3
- Error responses can identify what failed (Error Payload). The error payload gains an optional
inResponseTomember carrying the reported-on document’stypeandid. Previously an error response was correlated only bythreadId, which means something to a party that saw the originating request and nothing to anyone else — so an error retained as evidence named neither the task it terminated nor the instance, and for the standard codes of Standard Error Codes carried no signal of origin at all. SHOULD in general, MUST where the error will be relied upon beyond the original producer. Published astrust-task-error/0.3; optional in this version so a 0.2 consumer’s output remains valid, with a future major version expected to require it and 0.1/0.2 retired once consumers have moved. - Per-variant proof requirements (Specification Requirements item 8). A Trust Task specification may now declare the
proofrequirement for its request and response variants separately, rather than one value covering both. The two are relied upon differently — a response retained as evidence outside the original exchange can need a proof where the request that triggered it does not, and a request that destroys state needs attribution where its acknowledgement protects nothing — and a single value forces the stricter onto both. The single form remains valid and unchanged; where the per-variant form omits the response, the request’s value applies, so an omission cannot weaken a variant. The error variant stays undeclarable: an error response’stypenamestrust-task-error, a different specification, so a declaration here could not reach it. Additive — every existing declaration keeps its meaning. - The
parentThreadIdmember (TheparentThreadIdMember). A Trust Task document MAY now carry thethreadIdof the exchange that contains it, so a party holding a document from a nested exchange can find the exchange it was conducted within — something a flatthreadIdcannot express, and which specifications were otherwise forced to invent per-family payload conventions for. It takesthreadId’s posture: optional, no normative validation semantics, consumers MUST NOT reject on it alone. It records one level of containment deliberately, rather than half-defining an ancestry chain. Where a transport carries its own parent-thread concept the two MUST agree when both are present, with the in-band member authoritative. Additive: the document wire format gains an optional member, and every document conforming to 0.2 still conforms. - Naming an exchange from outside the framework (Naming an Exchange from Outside the Framework). Added the rule that anything referring to an exchange as evidence of an event — a credential citing the exchange that established what it attests, an audit record, a governance decision — MUST name the innermost exchange whose documents attest that event, by the
idof the document that initiated it. AthreadIdnames one exchange and expresses no containment, so where exchanges nest, more than one thread is open when an event occurs and only one attests it; naming an enclosing exchange collects evidence of the wrong event. Clarification only — no member is added and no existing behavior changes. - Family namespaces for extended error codes (Extension by Individual Trust Task Specifications). The namespace of an extended
codemay now be either the emitting specification’s own slug (as before) or a family namespace — a proper path prefix of that slug — for a condition whose meaning is defined once across a family in a shared convention, such asdid-management:unknownDomainon everydid-management/*specification. Previously the namespace MUST have equaled the slug exactly, which gave a family-wide failure mode no way to be named once; specifications expressed it anyway, so the rule was already being broken to say something true. The relaxation is deliberately narrow: because a family namespace is always a prefix of the emitting slug, a consumer can still verify a received code’s namespacing against the document’stypealone, and a sibling’s slug remains forbidden. Additive — every previously conforming code remains conforming. The prefix relationship is now enforced by the registry build, which never checked the original rule either. - Draft editorial changes stay in place (Compatibility Rules). An editorial or normalization change to a
draftartifact — casing normalization per Naming Conventions, a framework or shared-schema-component$refre-pin with no wire effect, prose rewording — is now made in place and MUST NOT mint a new version. A wire-identical version minted before this rule MAY declare the new optionalwireCompatibleWithfront-matter field naming its predecessor, so consumers can dual-accept by mechanical normalization. - Side-effect and exposure classes (Specification Requirements items 13–14). Every conforming specification now MUST declare two orthogonal, descriptive classifications of what executing the task does: a side-effect class (
none/mutating/destructive— the integrity effect on recipient state) and an exposure class (disclosesofnone/metadata/secret, plus anactsAsSubjectflag — the confidentiality and agency effect). Both are descriptive only — a specification MUST NOT derive a consent requirement from them — and exist so a delegated-execution consumer can decide whether to seek human approval without per-task code. This is a breaking change to the specification-authoring contract, carried by the internalspec-meta/2.0front-matter meta-schema; the document wire format is unchanged from 0.2, sotargetFrameworkVersionand document validation are unaffected and specifications keep their existing framework-version targets.
§ Framework version 0.2
- Naming conventions (Naming Conventions). Added a normative section defining casing: framework-defined members and values use lowerCamelCase; payload member names and specification-defined enumerated values SHOULD use lowerCamelCase; externally-owned values (WebAuthn, JOSE,
SameSite, W3C Data Integrity, …) are carried verbatim. - Standard error codes re-cased (Standard Error Codes). The standard error
codeidentifiers are now lowerCamelCase:malformedRequest,unsupportedType,unsupportedVersion,proofRequired,proofInvalid,permissionDenied,wrongRecipient,identityMismatch,taskFailed,internalError(the single-word codesexpired,unavailableare unchanged). This is a breaking change carried bytrust-task-error/0.2; the snake_case0.1codes remain valid for documents whosetyperesolves to a0.1specification. - Shared schema components (Shared Schema Components). Added a section giving shared schema fragments first-class, independently-versioned status, with a mandatory version-pinning rule and the schema/specification version-coupling rule.
- Migration guidance (Migrating Between Versions). Added the non-normative receiver-before-sender (expand/contract) migration sequence and the coupling of schema and specification versions.
- Draft version caveat (Compatibility Rules). Clarified that a breaking change to a
draftartifact MAY be released as aMINORincrement. - Affected
0.1specifications were re-published as0.2with lowerCamelCase enumerated values;0.1remains served unchanged for backwards compatibility and will beretiredonce consumers have migrated.
§ Framework version 0.1
- Initial working draft of the Trust Tasks framework.
§ Appendix C: Acknowledgements
The editors thank the members of the Trust Over IP Foundation Decentralized Trust Graph Working Group for their ongoing review and contributions to this specification. The editors also thank the participants of the DTG Credentials Task Force, whose review of Trust Task citation from the credential side produced the task-digest requirement of Binding a Citation to the Document It Names.
Copyright © 2026 Trust Over IP (ToIP) Contributors
This work is licensed under a Creative Commons Attribution 4.0 International License.