@openvtc/trust-tasks 0.17.10 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/dist/_shared/components.d.ts +18 -1
  3. package/dist/_shared/components.d.ts.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/rooms/_shared/0.1/room.d.ts +1 -1
  9. package/dist/rooms/_shared/0.1/room.d.ts.map +1 -1
  10. package/dist/rooms/epoch/chain/0.1/payload.d.ts +4 -4
  11. package/dist/rooms/epoch/chain/0.1/payload.js +2 -2
  12. package/dist/rooms/epoch/chain/0.1/payload.js.map +1 -1
  13. package/dist/rooms/epoch/mint/0.1/payload.d.ts +4 -4
  14. package/dist/rooms/epoch/mint/0.1/payload.js +2 -2
  15. package/dist/rooms/epoch/mint/0.1/payload.js.map +1 -1
  16. package/dist/rooms/keys/present/0.2/payload.d.ts +378 -0
  17. package/dist/rooms/keys/present/0.2/payload.d.ts.map +1 -0
  18. package/dist/rooms/keys/present/0.2/payload.js +212 -0
  19. package/dist/rooms/keys/present/0.2/payload.js.map +1 -0
  20. package/dist/rooms/owner/claim/0.1/payload.d.ts +4 -4
  21. package/dist/rooms/owner/claim/0.1/payload.js +2 -2
  22. package/dist/rooms/owner/claim/0.1/payload.js.map +1 -1
  23. package/dist/rooms/owner/issue-authority/0.2/payload.d.ts +315 -0
  24. package/dist/rooms/owner/issue-authority/0.2/payload.d.ts.map +1 -0
  25. package/dist/rooms/owner/issue-authority/0.2/payload.js +174 -0
  26. package/dist/rooms/owner/issue-authority/0.2/payload.js.map +1 -0
  27. package/dist/rooms/owner/transfer/0.1/payload.d.ts +4 -4
  28. package/dist/rooms/owner/transfer/0.1/payload.js +2 -2
  29. package/dist/rooms/owner/transfer/0.1/payload.js.map +1 -1
  30. package/dist/rooms/records/curate/0.1/payload.d.ts +4 -4
  31. package/dist/rooms/records/curate/0.1/payload.js +2 -2
  32. package/dist/rooms/records/curate/0.1/payload.js.map +1 -1
  33. package/dist/rooms/records/get/0.1/payload.d.ts +78 -6
  34. package/dist/rooms/records/get/0.1/payload.d.ts.map +1 -1
  35. package/dist/rooms/records/get/0.1/payload.js +40 -2
  36. package/dist/rooms/records/get/0.1/payload.js.map +1 -1
  37. package/dist/rooms/records/list/0.1/payload.d.ts +78 -6
  38. package/dist/rooms/records/list/0.1/payload.d.ts.map +1 -1
  39. package/dist/rooms/records/list/0.1/payload.js +40 -2
  40. package/dist/rooms/records/list/0.1/payload.js.map +1 -1
  41. package/dist/rooms/records/put/0.1/payload.d.ts +4 -4
  42. package/dist/rooms/records/put/0.1/payload.js +2 -2
  43. package/dist/rooms/records/put/0.1/payload.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/_shared/components.ts +18 -1
  46. package/src/index.ts +2 -0
  47. package/src/rooms/_shared/0.1/room.ts +1 -1
  48. package/src/rooms/epoch/chain/0.1/payload.ts +2 -2
  49. package/src/rooms/epoch/mint/0.1/payload.ts +2 -2
  50. package/src/rooms/keys/present/0.2/payload.ts +261 -0
  51. package/src/rooms/owner/claim/0.1/payload.ts +2 -2
  52. package/src/rooms/owner/issue-authority/0.2/payload.ts +234 -0
  53. package/src/rooms/owner/transfer/0.1/payload.ts +2 -2
  54. package/src/rooms/records/curate/0.1/payload.ts +2 -2
  55. package/src/rooms/records/get/0.1/payload.ts +46 -4
  56. package/src/rooms/records/list/0.1/payload.ts +46 -4
  57. package/src/rooms/records/put/0.1/payload.ts +2 -2
@@ -217,7 +217,7 @@ export const PAYLOAD_SCHEMA = {
217
217
  "membership",
218
218
  "authority"
219
219
  ],
220
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
220
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
221
221
  "properties": {
222
222
  "membership": {
223
223
  "type": "string",
@@ -303,7 +303,7 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
303
303
  "membership",
304
304
  "authority"
305
305
  ],
306
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
306
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
307
307
  "properties": {
308
308
  "membership": {
309
309
  "type": "string",
@@ -3,7 +3,7 @@
3
3
  * Source: specs/rooms/records/get/0.1/payload.schema.json
4
4
  */
5
5
 
6
- import type { AuthorityPresentation, Ext, SealedRecord } from "../../../../_shared/components.js";
6
+ import type { AuthorityPresentation, DataCommitment, DigestMultibase, Ext, SealedRecord } from "../../../../_shared/components.js";
7
7
 
8
8
 
9
9
  export interface RoomsRecordsGetPayload {
@@ -40,11 +40,15 @@ export interface RoomsRecordsGetResponsePayload {
40
40
  cleartext?: {
41
41
  [k: string]: unknown | undefined;
42
42
  };
43
+ /**
44
+ * The room's data commitment at the moment this record was read. Carried on a single-record read as well as a listing so a reader can tell whether the room moved between two reads — and, once traces are specified, so this record can be proved to sit inside this root.
45
+ */
46
+ dataCommitment?: DataCommitment;
43
47
  ext?: Ext;
44
48
  }
45
49
 
46
50
  /** Shared definitions this specification references, re-exported under the names it used to declare them with. */
47
- export type { AuthorityPresentation, Ext, SealedRecord };
51
+ export type { AuthorityPresentation, DataCommitment, DigestMultibase, Ext, SealedRecord };
48
52
 
49
53
  /** Trust Task type URI. */
50
54
  export const TYPE_URI = "https://trusttasks.org/spec/rooms/records/get/0.1" as const;
@@ -125,6 +129,10 @@ export const PAYLOAD_SCHEMA = {
125
129
  "description": "Present on an `open` room.",
126
130
  "additionalProperties": true
127
131
  },
132
+ "dataCommitment": {
133
+ "$ref": "#/$defs/DataCommitment",
134
+ "description": "The room's data commitment at the moment this record was read. Carried on a single-record read as well as a listing so a reader can tell whether the room moved between two reads — and, once traces are specified, so this record can be proved to sit inside this root."
135
+ },
128
136
  "ext": {
129
137
  "$ref": "#/$defs/Ext"
130
138
  }
@@ -140,6 +148,21 @@ export const PAYLOAD_SCHEMA = {
140
148
  "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
141
149
  }
142
150
  },
151
+ "DataCommitment": {
152
+ "title": "DataCommitment",
153
+ "$ref": "#/$defs/DigestMultibase",
154
+ "description": "The root of the room's record tree — a host's commitment to *which records the room holds*, as distinct from what any one of them says.\n\nA room's records are already signed and room-bound, so a host cannot forge, alter or relocate one. What it can do for free is stay silent: a listing that omits a record is indistinguishable from a room that never held it. This value is what makes that omission detectable, so it is only worth anything when the reader can compare it against a copy the host did not choose for them — one it gave another member, one it gave the same member earlier, or the witnessed anchor. A commitment read once, in isolation, proves nothing; a host that shows two members two different roots has been caught.\n\n**The construction is normative**, because two hosts that compute different roots over the same room make every comparison meaningless:\n 1. Take every record the room holds — including tombstones, which are records — and order them by `key` using unsigned byte order.\n 2. Leaf: `SHA-256(0x00 || JCS(record))`, where JCS is the RFC 8785 canonicalization of the record as this family's `RecordMetadata` plus its stored content, and `0x00` is RFC 6962's leaf-domain prefix.\n 3. Internal node: `SHA-256(0x01 || left || right)`.\n 4. A level with an odd number of nodes promotes the last one unchanged. It MUST NOT be duplicated: duplicating makes a tree of n leaves collide with one of n+1 whose last is repeated, so two different rooms commit to the same root.\n 5. A room holding no records commits to `SHA-256(\"\")`, a distinguished value rather than zeroes — a root of zeroes is what an uninitialised buffer looks like, and an empty room is a real state a host must be able to commit to honestly.\n\nThe leaf covers the whole record rather than its body, and that is deliberate: a host that could flip `status` from active to retracted, move `pinned`, or rewrite `author` on an `attributed` room would rewrite what the room means without touching a byte of ciphertext. The **plaintext is never involved** — on the sealed tiers the host holds ciphertext and commits to exactly what it stores.\n\nThe commitment is over the **whole room**, never over the page being returned. A page-scoped root is one a host satisfies by construction and could never fail."
155
+ },
156
+ "DigestMultibase": {
157
+ "title": "DigestMultibase",
158
+ "description": "A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\n\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\n\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\n\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \"interoperability is not guaranteed between implementations using such values\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.",
159
+ "type": "string",
160
+ "minLength": 16,
161
+ "pattern": "^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$",
162
+ "examples": [
163
+ "zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
164
+ ]
165
+ },
143
166
  "SealedRecord": {
144
167
  "title": "SealedRecord",
145
168
  "type": "object",
@@ -174,7 +197,7 @@ export const PAYLOAD_SCHEMA = {
174
197
  "membership",
175
198
  "authority"
176
199
  ],
177
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
200
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
178
201
  "properties": {
179
202
  "membership": {
180
203
  "type": "string",
@@ -230,6 +253,10 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
230
253
  "description": "Present on an `open` room.",
231
254
  "additionalProperties": true
232
255
  },
256
+ "dataCommitment": {
257
+ "$ref": "#/$defs/DataCommitment",
258
+ "description": "The room's data commitment at the moment this record was read. Carried on a single-record read as well as a listing so a reader can tell whether the room moved between two reads — and, once traces are specified, so this record can be proved to sit inside this root."
259
+ },
233
260
  "ext": {
234
261
  "$ref": "#/$defs/Ext"
235
262
  }
@@ -245,6 +272,21 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
245
272
  "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
246
273
  }
247
274
  },
275
+ "DataCommitment": {
276
+ "title": "DataCommitment",
277
+ "$ref": "#/$defs/DigestMultibase",
278
+ "description": "The root of the room's record tree — a host's commitment to *which records the room holds*, as distinct from what any one of them says.\n\nA room's records are already signed and room-bound, so a host cannot forge, alter or relocate one. What it can do for free is stay silent: a listing that omits a record is indistinguishable from a room that never held it. This value is what makes that omission detectable, so it is only worth anything when the reader can compare it against a copy the host did not choose for them — one it gave another member, one it gave the same member earlier, or the witnessed anchor. A commitment read once, in isolation, proves nothing; a host that shows two members two different roots has been caught.\n\n**The construction is normative**, because two hosts that compute different roots over the same room make every comparison meaningless:\n 1. Take every record the room holds — including tombstones, which are records — and order them by `key` using unsigned byte order.\n 2. Leaf: `SHA-256(0x00 || JCS(record))`, where JCS is the RFC 8785 canonicalization of the record as this family's `RecordMetadata` plus its stored content, and `0x00` is RFC 6962's leaf-domain prefix.\n 3. Internal node: `SHA-256(0x01 || left || right)`.\n 4. A level with an odd number of nodes promotes the last one unchanged. It MUST NOT be duplicated: duplicating makes a tree of n leaves collide with one of n+1 whose last is repeated, so two different rooms commit to the same root.\n 5. A room holding no records commits to `SHA-256(\"\")`, a distinguished value rather than zeroes — a root of zeroes is what an uninitialised buffer looks like, and an empty room is a real state a host must be able to commit to honestly.\n\nThe leaf covers the whole record rather than its body, and that is deliberate: a host that could flip `status` from active to retracted, move `pinned`, or rewrite `author` on an `attributed` room would rewrite what the room means without touching a byte of ciphertext. The **plaintext is never involved** — on the sealed tiers the host holds ciphertext and commits to exactly what it stores.\n\nThe commitment is over the **whole room**, never over the page being returned. A page-scoped root is one a host satisfies by construction and could never fail."
279
+ },
280
+ "DigestMultibase": {
281
+ "title": "DigestMultibase",
282
+ "description": "A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\n\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\n\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\n\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \"interoperability is not guaranteed between implementations using such values\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.",
283
+ "type": "string",
284
+ "minLength": 16,
285
+ "pattern": "^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$",
286
+ "examples": [
287
+ "zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
288
+ ]
289
+ },
248
290
  "SealedRecord": {
249
291
  "title": "SealedRecord",
250
292
  "type": "object",
@@ -279,7 +321,7 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
279
321
  "membership",
280
322
  "authority"
281
323
  ],
282
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
324
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
283
325
  "properties": {
284
326
  "membership": {
285
327
  "type": "string",
@@ -3,7 +3,7 @@
3
3
  * Source: specs/rooms/records/list/0.1/payload.schema.json
4
4
  */
5
5
 
6
- import type { AuthorityPresentation, Ext, RecordMetadata } from "../../../../_shared/components.js";
6
+ import type { AuthorityPresentation, DataCommitment, DigestMultibase, Ext, RecordMetadata } from "../../../../_shared/components.js";
7
7
 
8
8
 
9
9
  export interface RoomsRecordsListPayload {
@@ -45,11 +45,15 @@ export interface RoomsRecordsListResponsePayload {
45
45
  * Present when more records remain.
46
46
  */
47
47
  cursor?: string;
48
+ /**
49
+ * The room's data commitment at the moment this listing was taken. OPTIONAL because a host that does not maintain the tree cannot honestly assert one, and a fabricated root is worse than an absent one — its absence says 'this host offers no completeness guarantee', which is true and useful. Present, it is signed along with the rest of the response, which is what makes it evidence rather than a claim.
50
+ */
51
+ dataCommitment?: DataCommitment;
48
52
  ext?: Ext;
49
53
  }
50
54
 
51
55
  /** Shared definitions this specification references, re-exported under the names it used to declare them with. */
52
- export type { AuthorityPresentation, Ext, RecordMetadata };
56
+ export type { AuthorityPresentation, DataCommitment, DigestMultibase, Ext, RecordMetadata };
53
57
 
54
58
  /** Trust Task type URI. */
55
59
  export const TYPE_URI = "https://trusttasks.org/spec/rooms/records/list/0.1" as const;
@@ -139,6 +143,10 @@ export const PAYLOAD_SCHEMA = {
139
143
  "maxLength": 4096,
140
144
  "description": "Present when more records remain."
141
145
  },
146
+ "dataCommitment": {
147
+ "$ref": "#/$defs/DataCommitment",
148
+ "description": "The room's data commitment at the moment this listing was taken. OPTIONAL because a host that does not maintain the tree cannot honestly assert one, and a fabricated root is worse than an absent one — its absence says 'this host offers no completeness guarantee', which is true and useful. Present, it is signed along with the rest of the response, which is what makes it evidence rather than a claim."
149
+ },
142
150
  "ext": {
143
151
  "$ref": "#/$defs/Ext"
144
152
  }
@@ -154,6 +162,21 @@ export const PAYLOAD_SCHEMA = {
154
162
  "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
155
163
  }
156
164
  },
165
+ "DataCommitment": {
166
+ "title": "DataCommitment",
167
+ "$ref": "#/$defs/DigestMultibase",
168
+ "description": "The root of the room's record tree — a host's commitment to *which records the room holds*, as distinct from what any one of them says.\n\nA room's records are already signed and room-bound, so a host cannot forge, alter or relocate one. What it can do for free is stay silent: a listing that omits a record is indistinguishable from a room that never held it. This value is what makes that omission detectable, so it is only worth anything when the reader can compare it against a copy the host did not choose for them — one it gave another member, one it gave the same member earlier, or the witnessed anchor. A commitment read once, in isolation, proves nothing; a host that shows two members two different roots has been caught.\n\n**The construction is normative**, because two hosts that compute different roots over the same room make every comparison meaningless:\n 1. Take every record the room holds — including tombstones, which are records — and order them by `key` using unsigned byte order.\n 2. Leaf: `SHA-256(0x00 || JCS(record))`, where JCS is the RFC 8785 canonicalization of the record as this family's `RecordMetadata` plus its stored content, and `0x00` is RFC 6962's leaf-domain prefix.\n 3. Internal node: `SHA-256(0x01 || left || right)`.\n 4. A level with an odd number of nodes promotes the last one unchanged. It MUST NOT be duplicated: duplicating makes a tree of n leaves collide with one of n+1 whose last is repeated, so two different rooms commit to the same root.\n 5. A room holding no records commits to `SHA-256(\"\")`, a distinguished value rather than zeroes — a root of zeroes is what an uninitialised buffer looks like, and an empty room is a real state a host must be able to commit to honestly.\n\nThe leaf covers the whole record rather than its body, and that is deliberate: a host that could flip `status` from active to retracted, move `pinned`, or rewrite `author` on an `attributed` room would rewrite what the room means without touching a byte of ciphertext. The **plaintext is never involved** — on the sealed tiers the host holds ciphertext and commits to exactly what it stores.\n\nThe commitment is over the **whole room**, never over the page being returned. A page-scoped root is one a host satisfies by construction and could never fail."
169
+ },
170
+ "DigestMultibase": {
171
+ "title": "DigestMultibase",
172
+ "description": "A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\n\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\n\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\n\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \"interoperability is not guaranteed between implementations using such values\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.",
173
+ "type": "string",
174
+ "minLength": 16,
175
+ "pattern": "^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$",
176
+ "examples": [
177
+ "zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
178
+ ]
179
+ },
157
180
  "RecordMetadata": {
158
181
  "title": "RecordMetadata",
159
182
  "type": "object",
@@ -216,7 +239,7 @@ export const PAYLOAD_SCHEMA = {
216
239
  "membership",
217
240
  "authority"
218
241
  ],
219
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
242
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
220
243
  "properties": {
221
244
  "membership": {
222
245
  "type": "string",
@@ -266,6 +289,10 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
266
289
  "maxLength": 4096,
267
290
  "description": "Present when more records remain."
268
291
  },
292
+ "dataCommitment": {
293
+ "$ref": "#/$defs/DataCommitment",
294
+ "description": "The room's data commitment at the moment this listing was taken. OPTIONAL because a host that does not maintain the tree cannot honestly assert one, and a fabricated root is worse than an absent one — its absence says 'this host offers no completeness guarantee', which is true and useful. Present, it is signed along with the rest of the response, which is what makes it evidence rather than a claim."
295
+ },
269
296
  "ext": {
270
297
  "$ref": "#/$defs/Ext"
271
298
  }
@@ -281,6 +308,21 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
281
308
  "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
282
309
  }
283
310
  },
311
+ "DataCommitment": {
312
+ "title": "DataCommitment",
313
+ "$ref": "#/$defs/DigestMultibase",
314
+ "description": "The root of the room's record tree — a host's commitment to *which records the room holds*, as distinct from what any one of them says.\n\nA room's records are already signed and room-bound, so a host cannot forge, alter or relocate one. What it can do for free is stay silent: a listing that omits a record is indistinguishable from a room that never held it. This value is what makes that omission detectable, so it is only worth anything when the reader can compare it against a copy the host did not choose for them — one it gave another member, one it gave the same member earlier, or the witnessed anchor. A commitment read once, in isolation, proves nothing; a host that shows two members two different roots has been caught.\n\n**The construction is normative**, because two hosts that compute different roots over the same room make every comparison meaningless:\n 1. Take every record the room holds — including tombstones, which are records — and order them by `key` using unsigned byte order.\n 2. Leaf: `SHA-256(0x00 || JCS(record))`, where JCS is the RFC 8785 canonicalization of the record as this family's `RecordMetadata` plus its stored content, and `0x00` is RFC 6962's leaf-domain prefix.\n 3. Internal node: `SHA-256(0x01 || left || right)`.\n 4. A level with an odd number of nodes promotes the last one unchanged. It MUST NOT be duplicated: duplicating makes a tree of n leaves collide with one of n+1 whose last is repeated, so two different rooms commit to the same root.\n 5. A room holding no records commits to `SHA-256(\"\")`, a distinguished value rather than zeroes — a root of zeroes is what an uninitialised buffer looks like, and an empty room is a real state a host must be able to commit to honestly.\n\nThe leaf covers the whole record rather than its body, and that is deliberate: a host that could flip `status` from active to retracted, move `pinned`, or rewrite `author` on an `attributed` room would rewrite what the room means without touching a byte of ciphertext. The **plaintext is never involved** — on the sealed tiers the host holds ciphertext and commits to exactly what it stores.\n\nThe commitment is over the **whole room**, never over the page being returned. A page-scoped root is one a host satisfies by construction and could never fail."
315
+ },
316
+ "DigestMultibase": {
317
+ "title": "DigestMultibase",
318
+ "description": "A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\n\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\n\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\n\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \"interoperability is not guaranteed between implementations using such values\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.",
319
+ "type": "string",
320
+ "minLength": 16,
321
+ "pattern": "^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$",
322
+ "examples": [
323
+ "zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
324
+ ]
325
+ },
284
326
  "RecordMetadata": {
285
327
  "title": "RecordMetadata",
286
328
  "type": "object",
@@ -343,7 +385,7 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
343
385
  "membership",
344
386
  "authority"
345
387
  ],
346
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
388
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
347
389
  "properties": {
348
390
  "membership": {
349
391
  "type": "string",
@@ -231,7 +231,7 @@ export const PAYLOAD_SCHEMA = {
231
231
  "membership",
232
232
  "authority"
233
233
  ],
234
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
234
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
235
235
  "properties": {
236
236
  "membership": {
237
237
  "type": "string",
@@ -334,7 +334,7 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
334
334
  "membership",
335
335
  "authority"
336
336
  ],
337
- "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier.",
337
+ "description": "What a party presents to act on a room. Carries the whole authority chain: a host MUST NOT dereference an authority credential's `parent` to fetch a link it was not given. Resolving over the network would make verification depend on availability, turn every identifier into a request the host can be induced to make against an address the holder chooses, and signal credential use to whoever hosts the identifier. A host MUST bind the presenter to the chain's leaf. A chain that verifies is evidence that authority was conferred on somebody; it is not evidence that the party presenting it is that somebody. The leaf's subject MUST equal the party the host authenticated for this request — an identity the transport established or a document `proof` proved, never one named in a payload. A host that omits this check authorizes every captured presentation, and the omission is silent, because the chain still verifies.",
338
338
  "properties": {
339
339
  "membership": {
340
340
  "type": "string",