Summary
This issue proposes two related additions to RWP:
- An optional
service block in the Record DID Document (§4.3), following the service property defined in [DID-CORE], allowing a Record's resolver to declare additional, optional access channels beyond the mandatory recordEndpoint.
- A mechanism, defined at the SchemaRecord level (§3.3, §schema-record), for declaring which functions/operations a Record Type — and therefore its resolver — supports (e.g. retrieve, compare, validate, publish). This declaration is what populates the
service block above.
Both points belong together: the service block is the mechanism in the DID Document; the SchemaRecord-level declaration is the source of truth for what capabilities a given Record Type actually offers.
Motivation
RWP currently requires every Record DID Document to expose exactly one mandatory access channel: recordEndpoint, which MUST return the full Record. There is currently no normative way for a resolver to advertise additional ways of interacting with a Record — for example:
- a restricted/public view of the Record for callers without full access rights,
- a machine-readable listing of operations a Record (or its Record Type) supports, so that automated systems (including AI agents, e.g. via MCP) can discover what they are allowed to do with a Record before attempting to do it,
- alternative retrieval or processing channels scoped by access level.
This aligns with the broader idea — discussed on public-credentials@w3.org (Michael Herman, Vikas Malhotra, Sept 2026, "What if: Data had DIDs (and a DID Document)?") — that instead of always pulling/pushing data to a processor, processing actions could be described in the DID Document itself and sent to the data. RWP is already structurally close to this: every Record has a DID, and every Record Type is governed by a SchemaRecord. Declaring supported functions per Record Type, and exposing that through the DID Document, is a natural extension of the existing model, not a new architectural concept.
Proposal
1. Optional service block (§4.3, DID Document)
Add service as an OPTIONAL field to the DID Document schema:
{
"@context": "https://www.w3.org/ns/did/v1",
"id": "did:rwp:bern.ch:f47ac10b-58cc-4372-a567-0e02b2c3d479",
"recordEndpoint": "https://records.bern.ch/api/v1/records/f47ac10b",
"created": "2026-05-31T14:00:00Z",
"updated": "2026-05-31T14:00:00Z",
"currentVersion": "sha256:e3b0c44298fc1c149afb...",
"controller": "did:rwp:bern.ch:controller-001",
"verificationMethod": [ ... ],
"service": [
{
"id": "did:rwp:bern.ch:f47ac10b-58cc-4372-a567-0e02b2c3d479#public",
"type": "RWP-PublicRecordAccess",
"serviceEndpoint": "https://records.bern.ch/api/v1/records/f47ac10b/public"
},
{
"id": "did:rwp:bern.ch:f47ac10b-58cc-4372-a567-0e02b2c3d479#functions",
"type": "RWP-FunctionRegistry",
"serviceEndpoint": "https://records.bern.ch/api/v1/records/f47ac10b/functions"
}
]
}
Notes:
recordEndpoint remains the only MUST field for retrieving the full Record. service is MAY: an implementation is not required to offer any additional channel.
- §4.3 currently states: "The DID document MUST be updated when the physical storage location changes (recordEndpoint, updated, currentVersion). All other fields MUST NOT be changed." This rule needs to be extended to clarify whether/how changes to
service entries are permitted (e.g. MAY be added, updated, or removed without constituting a new Record version, since they do not affect Record identity or content).
- Each
service entry follows the DID-CORE structure (id, type, serviceEndpoint). The type values are RWP-specific and would need to be defined/registered by this specification (see open question below).
2. Capability declaration at SchemaRecord level (§3.3 / schema-record.bs)
A SchemaRecord already defines a concrete Record Type and its schema/validation requirements. This proposal extends that responsibility: a SchemaRecord SHOULD be able to declare which functions/operations are applicable to Records of that type — for example retrieve, compare, validate, publish, spellcheck, wordcount, or Record-Type-specific operations.
This declaration is what a resolver uses to populate the RWP-FunctionRegistry service endpoint for any Record of that type. It keeps the source of truth at the type level (governed, versioned, auditable via SchemaRecord) rather than requiring every individual Record instance to redundantly declare the same capabilities.
Open questions to resolve during discussion:
- Exact structure of the capability list within SchemaRecord (flat list of operation identifiers vs. richer objects with input/output description).
- Whether capabilities are purely descriptive (informational, "this Record Type supports X") or normative (a conformant resolver MUST implement declared capabilities).
Open question: namespace for service.type values
Three options have been considered:
- Reuse existing conventions where applicable (e.g.
DIDCommMessaging for a DIDComm-based channel). This has the advantage of interoperating with existing DID tooling, but DIDComm's type only advertises a messaging transport — it does not itself declare which operations/features are supported. That discovery happens later, at runtime, via DIDComm's Discover Features protocol, after a connection is established. This is not well suited to RWP's goal of exposing capabilities directly via resolver lookup, without a prior handshake.
- RWP-defined
type values (e.g. RWP-FunctionRegistry, RWP-PublicRecordAccess, RWP-MCP), registered and defined normatively by this specification. This keeps capability discovery resolvable in a single lookup, consistent with RWP's existing resolver model.
- A new SystemRecord subtype, e.g.
ServiceRecord, following the same pattern as SchemaRecord, MergeRecord, DeletionRecord, etc. This would be justified only if the capability declaration itself needs to be a fully versioned, hash-verifiable, independently addressable Record (with its own DID, integrity evidence, and lifecycle) — rather than a field carried inside SchemaRecord or the DID Document's service block.
Recommendation for discussion: start with option 2 (RWP-defined type values, populated from SchemaRecord), since it requires no new Record type and fits directly into the existing service mechanism of [DID-CORE]. Option 3 should be revisited only if capability declarations need independent versioning/integrity guarantees beyond what SchemaRecord already provides.
Relationship to Access Control
RWP already delegates authorization decisions to implementing systems (see chapters/access-control.bs) rather than mandating a specific access-control model. This proposal should explicitly cross-reference that chapter: a service entry (e.g. a restricted/public view, or a function registry) is a declaration of availability, not a grant of access. Actual authorization for invoking any declared service or function remains governed by the access-control rules already defined elsewhere in the specification. The two chapters should reference each other so implementers understand that exposing a service entry does not bypass access control.
Non-goals
- This issue does not propose removing or changing the mandatory
recordEndpoint field or its semantics.
- This issue does not propose a specific transport protocol (DIDComm, MCP, plain REST, etc.) as mandatory. Any concrete protocol choice should remain implementation-specific, expressed via the
type/serviceEndpoint pair.
References
- [DID-CORE] Decentralized Identifiers (DIDs) v1.0/v1.1, W3C —
service property.
- RWP §4.3 DID Document, §3.3 Record taxonomy, chapters/schema-record.bs, chapters/access-control.bs.
- Related public discussion: public-credentials@w3.org thread "What if: Data had DIDs (and a DID Document)?" (Sept 2026).
Summary
This issue proposes two related additions to RWP:
serviceblock in the Record DID Document (§4.3), following theserviceproperty defined in [DID-CORE], allowing a Record's resolver to declare additional, optional access channels beyond the mandatoryrecordEndpoint.serviceblock above.Both points belong together: the
serviceblock is the mechanism in the DID Document; the SchemaRecord-level declaration is the source of truth for what capabilities a given Record Type actually offers.Motivation
RWP currently requires every Record DID Document to expose exactly one mandatory access channel:
recordEndpoint, which MUST return the full Record. There is currently no normative way for a resolver to advertise additional ways of interacting with a Record — for example:This aligns with the broader idea — discussed on public-credentials@w3.org (Michael Herman, Vikas Malhotra, Sept 2026, "What if: Data had DIDs (and a DID Document)?") — that instead of always pulling/pushing data to a processor, processing actions could be described in the DID Document itself and sent to the data. RWP is already structurally close to this: every Record has a DID, and every Record Type is governed by a SchemaRecord. Declaring supported functions per Record Type, and exposing that through the DID Document, is a natural extension of the existing model, not a new architectural concept.
Proposal
1. Optional
serviceblock (§4.3, DID Document)Add
serviceas an OPTIONAL field to the DID Document schema:{ "@context": "https://www.w3.org/ns/did/v1", "id": "did:rwp:bern.ch:f47ac10b-58cc-4372-a567-0e02b2c3d479", "recordEndpoint": "https://records.bern.ch/api/v1/records/f47ac10b", "created": "2026-05-31T14:00:00Z", "updated": "2026-05-31T14:00:00Z", "currentVersion": "sha256:e3b0c44298fc1c149afb...", "controller": "did:rwp:bern.ch:controller-001", "verificationMethod": [ ... ], "service": [ { "id": "did:rwp:bern.ch:f47ac10b-58cc-4372-a567-0e02b2c3d479#public", "type": "RWP-PublicRecordAccess", "serviceEndpoint": "https://records.bern.ch/api/v1/records/f47ac10b/public" }, { "id": "did:rwp:bern.ch:f47ac10b-58cc-4372-a567-0e02b2c3d479#functions", "type": "RWP-FunctionRegistry", "serviceEndpoint": "https://records.bern.ch/api/v1/records/f47ac10b/functions" } ] }Notes:
recordEndpointremains the only MUST field for retrieving the full Record.serviceis MAY: an implementation is not required to offer any additional channel.serviceentries are permitted (e.g. MAY be added, updated, or removed without constituting a new Record version, since they do not affect Record identity or content).serviceentry follows the DID-CORE structure (id,type,serviceEndpoint). Thetypevalues are RWP-specific and would need to be defined/registered by this specification (see open question below).2. Capability declaration at SchemaRecord level (§3.3 / schema-record.bs)
A SchemaRecord already defines a concrete Record Type and its schema/validation requirements. This proposal extends that responsibility: a SchemaRecord SHOULD be able to declare which functions/operations are applicable to Records of that type — for example
retrieve,compare,validate,publish,spellcheck,wordcount, or Record-Type-specific operations.This declaration is what a resolver uses to populate the
RWP-FunctionRegistryservice endpoint for any Record of that type. It keeps the source of truth at the type level (governed, versioned, auditable via SchemaRecord) rather than requiring every individual Record instance to redundantly declare the same capabilities.Open questions to resolve during discussion:
Open question: namespace for
service.typevaluesThree options have been considered:
DIDCommMessagingfor a DIDComm-based channel). This has the advantage of interoperating with existing DID tooling, but DIDComm'stypeonly advertises a messaging transport — it does not itself declare which operations/features are supported. That discovery happens later, at runtime, via DIDComm's Discover Features protocol, after a connection is established. This is not well suited to RWP's goal of exposing capabilities directly via resolver lookup, without a prior handshake.typevalues (e.g.RWP-FunctionRegistry,RWP-PublicRecordAccess,RWP-MCP), registered and defined normatively by this specification. This keeps capability discovery resolvable in a single lookup, consistent with RWP's existing resolver model.ServiceRecord, following the same pattern asSchemaRecord,MergeRecord,DeletionRecord, etc. This would be justified only if the capability declaration itself needs to be a fully versioned, hash-verifiable, independently addressable Record (with its own DID, integrity evidence, and lifecycle) — rather than a field carried inside SchemaRecord or the DID Document'sserviceblock.Recommendation for discussion: start with option 2 (RWP-defined
typevalues, populated from SchemaRecord), since it requires no new Record type and fits directly into the existingservicemechanism of [DID-CORE]. Option 3 should be revisited only if capability declarations need independent versioning/integrity guarantees beyond what SchemaRecord already provides.Relationship to Access Control
RWP already delegates authorization decisions to implementing systems (see chapters/access-control.bs) rather than mandating a specific access-control model. This proposal should explicitly cross-reference that chapter: a
serviceentry (e.g. a restricted/public view, or a function registry) is a declaration of availability, not a grant of access. Actual authorization for invoking any declared service or function remains governed by the access-control rules already defined elsewhere in the specification. The two chapters should reference each other so implementers understand that exposing aserviceentry does not bypass access control.Non-goals
recordEndpointfield or its semantics.type/serviceEndpointpair.References
serviceproperty.