@openvtc/trust-tasks 0.19.17 → 0.19.19

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 (127) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/_runtime/consume.d.ts +1 -1
  3. package/dist/_runtime/consume.js +2 -2
  4. package/dist/_shared/components.d.ts +46 -0
  5. package/dist/_shared/components.d.ts.map +1 -1
  6. package/dist/index.d.ts +8 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +8 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/persona/_shared/0.1/persona-record.d.ts +1 -1
  11. package/dist/persona/_shared/0.1/persona-record.d.ts.map +1 -1
  12. package/dist/persona/attribute/list/1.0/payload.d.ts +124 -4
  13. package/dist/persona/attribute/list/1.0/payload.d.ts.map +1 -1
  14. package/dist/persona/attribute/list/1.0/payload.js +72 -2
  15. package/dist/persona/attribute/list/1.0/payload.js.map +1 -1
  16. package/dist/persona/attribute/promote/1.0/payload.d.ts +506 -0
  17. package/dist/persona/attribute/promote/1.0/payload.d.ts.map +1 -0
  18. package/dist/persona/attribute/promote/1.0/payload.js +263 -0
  19. package/dist/persona/attribute/promote/1.0/payload.js.map +1 -0
  20. package/dist/persona/attribute/put/1.0/payload.d.ts +110 -4
  21. package/dist/persona/attribute/put/1.0/payload.d.ts.map +1 -1
  22. package/dist/persona/attribute/put/1.0/payload.js +62 -2
  23. package/dist/persona/attribute/put/1.0/payload.js.map +1 -1
  24. package/dist/persona/binding/get/1.0/payload.d.ts +24 -0
  25. package/dist/persona/binding/get/1.0/payload.d.ts.map +1 -1
  26. package/dist/persona/binding/get/1.0/payload.js +10 -0
  27. package/dist/persona/binding/get/1.0/payload.js.map +1 -1
  28. package/dist/persona/binding/list/1.0/payload.d.ts +24 -0
  29. package/dist/persona/binding/list/1.0/payload.d.ts.map +1 -1
  30. package/dist/persona/binding/list/1.0/payload.js +10 -0
  31. package/dist/persona/binding/list/1.0/payload.js.map +1 -1
  32. package/dist/persona/binding/set/1.0/payload.d.ts +38 -0
  33. package/dist/persona/binding/set/1.0/payload.d.ts.map +1 -1
  34. package/dist/persona/binding/set/1.0/payload.js +15 -0
  35. package/dist/persona/binding/set/1.0/payload.js.map +1 -1
  36. package/dist/persona/contact/get/1.0/payload.d.ts +84 -4
  37. package/dist/persona/contact/get/1.0/payload.d.ts.map +1 -1
  38. package/dist/persona/contact/get/1.0/payload.js +52 -2
  39. package/dist/persona/contact/get/1.0/payload.js.map +1 -1
  40. package/dist/persona/contact/put/1.0/payload.d.ts +84 -4
  41. package/dist/persona/contact/put/1.0/payload.d.ts.map +1 -1
  42. package/dist/persona/contact/put/1.0/payload.js +52 -2
  43. package/dist/persona/contact/put/1.0/payload.js.map +1 -1
  44. package/dist/persona/disclosure/preview/1.0/payload.d.ts +5 -5
  45. package/dist/persona/disclosure/preview/1.0/payload.d.ts.map +1 -1
  46. package/dist/persona/disclosure/preview/1.0/payload.js +4 -2
  47. package/dist/persona/disclosure/preview/1.0/payload.js.map +1 -1
  48. package/dist/persona/local/binding/set/1.0/payload.d.ts +14 -0
  49. package/dist/persona/local/binding/set/1.0/payload.d.ts.map +1 -1
  50. package/dist/persona/local/binding/set/1.0/payload.js +5 -0
  51. package/dist/persona/local/binding/set/1.0/payload.js.map +1 -1
  52. package/dist/persona/profile/compose/1.0/payload.d.ts +965 -0
  53. package/dist/persona/profile/compose/1.0/payload.d.ts.map +1 -0
  54. package/dist/persona/profile/compose/1.0/payload.js +531 -0
  55. package/dist/persona/profile/compose/1.0/payload.js.map +1 -0
  56. package/dist/persona/profile/delete/1.0/payload.d.ts +71 -0
  57. package/dist/persona/profile/delete/1.0/payload.d.ts.map +1 -1
  58. package/dist/persona/profile/delete/1.0/payload.js +38 -0
  59. package/dist/persona/profile/delete/1.0/payload.js.map +1 -1
  60. package/dist/persona/profile/get/1.0/payload.d.ts +345 -6
  61. package/dist/persona/profile/get/1.0/payload.d.ts.map +1 -1
  62. package/dist/persona/profile/get/1.0/payload.js +206 -2
  63. package/dist/persona/profile/get/1.0/payload.js.map +1 -1
  64. package/dist/persona/profile/list/1.0/payload.d.ts +288 -6
  65. package/dist/persona/profile/list/1.0/payload.d.ts.map +1 -1
  66. package/dist/persona/profile/list/1.0/payload.js +173 -2
  67. package/dist/persona/profile/list/1.0/payload.js.map +1 -1
  68. package/dist/persona/profile/put/1.0/payload.d.ts +230 -6
  69. package/dist/persona/profile/put/1.0/payload.d.ts.map +1 -1
  70. package/dist/persona/profile/put/1.0/payload.js +138 -2
  71. package/dist/persona/profile/put/1.0/payload.js.map +1 -1
  72. package/dist/persona/profile/reinstate/1.0/payload.d.ts +325 -0
  73. package/dist/persona/profile/reinstate/1.0/payload.d.ts.map +1 -0
  74. package/dist/persona/profile/reinstate/1.0/payload.js +181 -0
  75. package/dist/persona/profile/reinstate/1.0/payload.js.map +1 -0
  76. package/dist/persona/profile/retire/1.0/payload.d.ts +436 -0
  77. package/dist/persona/profile/retire/1.0/payload.d.ts.map +1 -0
  78. package/dist/persona/profile/retire/1.0/payload.js +238 -0
  79. package/dist/persona/profile/retire/1.0/payload.js.map +1 -0
  80. package/dist/persona/profile/timeline/1.0/payload.d.ts +588 -0
  81. package/dist/persona/profile/timeline/1.0/payload.d.ts.map +1 -0
  82. package/dist/persona/profile/timeline/1.0/payload.js +322 -0
  83. package/dist/persona/profile/timeline/1.0/payload.js.map +1 -0
  84. package/dist/persona/profile/usage/1.0/payload.d.ts +533 -0
  85. package/dist/persona/profile/usage/1.0/payload.d.ts.map +1 -0
  86. package/dist/persona/profile/usage/1.0/payload.js +302 -0
  87. package/dist/persona/profile/usage/1.0/payload.js.map +1 -0
  88. package/dist/trust-task-control/0.1/payload.d.ts +19 -19
  89. package/dist/trust-task-control/0.1/payload.js +7 -7
  90. package/dist/trust-task-discovery/0.1/payload.d.ts +3 -3
  91. package/dist/trust-task-discovery/0.1/payload.js +1 -1
  92. package/dist/trust-task-discovery/0.2/payload.d.ts +368 -0
  93. package/dist/trust-task-discovery/0.2/payload.d.ts.map +1 -0
  94. package/dist/trust-task-discovery/0.2/payload.js +186 -0
  95. package/dist/trust-task-discovery/0.2/payload.js.map +1 -0
  96. package/dist/vtc/invitations/deliver/0.1/payload.d.ts +318 -0
  97. package/dist/vtc/invitations/deliver/0.1/payload.d.ts.map +1 -0
  98. package/dist/vtc/invitations/deliver/0.1/payload.js +183 -0
  99. package/dist/vtc/invitations/deliver/0.1/payload.js.map +1 -0
  100. package/package.json +1 -1
  101. package/src/_runtime/consume.ts +2 -2
  102. package/src/_shared/components.ts +49 -0
  103. package/src/index.ts +8 -0
  104. package/src/persona/_shared/0.1/persona-record.ts +1 -1
  105. package/src/persona/attribute/list/1.0/payload.ts +72 -2
  106. package/src/persona/attribute/promote/1.0/payload.ts +344 -0
  107. package/src/persona/attribute/put/1.0/payload.ts +68 -2
  108. package/src/persona/binding/get/1.0/payload.ts +14 -0
  109. package/src/persona/binding/list/1.0/payload.ts +14 -0
  110. package/src/persona/binding/set/1.0/payload.ts +23 -0
  111. package/src/persona/contact/get/1.0/payload.ts +52 -2
  112. package/src/persona/contact/put/1.0/payload.ts +52 -2
  113. package/src/persona/disclosure/preview/1.0/payload.ts +5 -3
  114. package/src/persona/local/binding/set/1.0/payload.ts +9 -0
  115. package/src/persona/profile/compose/1.0/payload.ts +650 -0
  116. package/src/persona/profile/delete/1.0/payload.ts +45 -0
  117. package/src/persona/profile/get/1.0/payload.ts +215 -4
  118. package/src/persona/profile/list/1.0/payload.ts +179 -4
  119. package/src/persona/profile/put/1.0/payload.ts +144 -4
  120. package/src/persona/profile/reinstate/1.0/payload.ts +219 -0
  121. package/src/persona/profile/retire/1.0/payload.ts +289 -0
  122. package/src/persona/profile/timeline/1.0/payload.ts +402 -0
  123. package/src/persona/profile/usage/1.0/payload.ts +354 -0
  124. package/src/trust-task-control/0.1/payload.ts +12 -12
  125. package/src/trust-task-discovery/0.1/payload.ts +2 -2
  126. package/src/trust-task-discovery/0.2/payload.ts +286 -0
  127. package/src/vtc/invitations/deliver/0.1/payload.ts +234 -0
@@ -27,6 +27,13 @@ export interface PersonaProfileDeleteResponsePayload {
27
27
  * False when no live profile was present. A repeat delete returns false and deliberately takes no new version, so watchers never observe a change that did not happen.
28
28
  */
29
29
  existed: boolean;
30
+ /**
31
+ * How many distinct parties this face has disclosed to, across how many contexts, from the holder's disclosure history. Counts, not identifiers; persona/disclosure/history names them. Returned on the delete because the delete does not un-tell anyone: the history, and what those parties hold, remain.
32
+ */
33
+ disclosedTo?: {
34
+ partyCount: number;
35
+ contextCount: number;
36
+ };
30
37
  /**
31
38
  * Persona DIDs whose bindings were cleared. Present only when `unbind` was true and something was cleared — a holder is owed the list of which personas their one action left presenting nothing.
32
39
  *
@@ -105,6 +112,25 @@ export const PAYLOAD_SCHEMA = {
105
112
  "type": "boolean",
106
113
  "description": "False when no live profile was present. A repeat delete returns false and deliberately takes no new version, so watchers never observe a change that did not happen."
107
114
  },
115
+ "disclosedTo": {
116
+ "type": "object",
117
+ "additionalProperties": false,
118
+ "required": [
119
+ "partyCount",
120
+ "contextCount"
121
+ ],
122
+ "description": "How many distinct parties this face has disclosed to, across how many contexts, from the holder's disclosure history. Counts, not identifiers; persona/disclosure/history names them. Returned on the delete because the delete does not un-tell anyone: the history, and what those parties hold, remain.",
123
+ "properties": {
124
+ "partyCount": {
125
+ "type": "integer",
126
+ "minimum": 0
127
+ },
128
+ "contextCount": {
129
+ "type": "integer",
130
+ "minimum": 0
131
+ }
132
+ }
133
+ },
108
134
  "unboundPersonas": {
109
135
  "type": "array",
110
136
  "maxItems": 256,
@@ -167,6 +193,25 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
167
193
  "type": "boolean",
168
194
  "description": "False when no live profile was present. A repeat delete returns false and deliberately takes no new version, so watchers never observe a change that did not happen."
169
195
  },
196
+ "disclosedTo": {
197
+ "type": "object",
198
+ "additionalProperties": false,
199
+ "required": [
200
+ "partyCount",
201
+ "contextCount"
202
+ ],
203
+ "description": "How many distinct parties this face has disclosed to, across how many contexts, from the holder's disclosure history. Counts, not identifiers; persona/disclosure/history names them. Returned on the delete because the delete does not un-tell anyone: the history, and what those parties hold, remain.",
204
+ "properties": {
205
+ "partyCount": {
206
+ "type": "integer",
207
+ "minimum": 0
208
+ },
209
+ "contextCount": {
210
+ "type": "integer",
211
+ "minimum": 0
212
+ }
213
+ }
214
+ },
170
215
  "unboundPersonas": {
171
216
  "type": "array",
172
217
  "maxItems": 256,
@@ -3,7 +3,7 @@
3
3
  * Source: specs/persona/profile/get/1.0/payload.schema.json
4
4
  */
5
5
 
6
- import type { ClaimType, Ext, Profile, ProfileEntry, ProofRung, Provenance, ResolvedClaim, Slot, Ulid, ValueType, Version_PersonaV0_1 as Version } from "../../../../_shared/components.js";
6
+ import type { ClaimType, Ext, FaceReach, Profile, ProfileEntry, ProofRung, Provenance, ResolvedClaim, Slot, Ulid, ValueType, Version_PersonaV0_1 as Version } from "../../../../_shared/components.js";
7
7
 
8
8
 
9
9
  /**
@@ -22,6 +22,13 @@ export interface PersonaProfileGetPayload {
22
22
  */
23
23
  export interface PersonaProfileGetResponsePayload {
24
24
  profile: Profile;
25
+ /**
26
+ * How many distinct parties this face has disclosed to, across how many contexts, from the holder's disclosure history. Counts, not identifiers; persona/disclosure/history names them. A producer shows this before a delete: deleting a face does not un-tell anyone what it told them.
27
+ */
28
+ disclosedTo?: {
29
+ partyCount: number;
30
+ contextCount: number;
31
+ };
25
32
  /**
26
33
  * Present only when `resolve` was true: the claims this profile would present, in entry order, with overrides applied and pinned versions honoured. A credential-backed claim whose backing could not be re-derived appears carrying `stale`, because a holder inspecting a profile needs to see that it has stopped being fully presentable.
27
34
  *
@@ -34,7 +41,7 @@ export interface PersonaProfileGetResponsePayload {
34
41
  }
35
42
 
36
43
  /** Shared definitions this specification references, re-exported under the names it used to declare them with. */
37
- export type { ClaimType, Ext, Profile, ProfileEntry, ProofRung, Provenance, ResolvedClaim, Slot, Ulid, ValueType, Version };
44
+ export type { ClaimType, Ext, FaceReach, Profile, ProfileEntry, ProofRung, Provenance, ResolvedClaim, Slot, Ulid, ValueType, Version };
38
45
 
39
46
  /** Trust Task type URI. */
40
47
  export const TYPE_URI = "https://trusttasks.org/spec/persona/profile/get/1.0" as const;
@@ -94,6 +101,25 @@ export const PAYLOAD_SCHEMA = {
94
101
  "profile": {
95
102
  "$ref": "#/$defs/Profile"
96
103
  },
104
+ "disclosedTo": {
105
+ "type": "object",
106
+ "additionalProperties": false,
107
+ "required": [
108
+ "partyCount",
109
+ "contextCount"
110
+ ],
111
+ "description": "How many distinct parties this face has disclosed to, across how many contexts, from the holder's disclosure history. Counts, not identifiers; persona/disclosure/history names them. A producer shows this before a delete: deleting a face does not un-tell anyone what it told them.",
112
+ "properties": {
113
+ "partyCount": {
114
+ "type": "integer",
115
+ "minimum": 0
116
+ },
117
+ "contextCount": {
118
+ "type": "integer",
119
+ "minimum": 0
120
+ }
121
+ }
122
+ },
97
123
  "resolved": {
98
124
  "type": "array",
99
125
  "maxItems": 256,
@@ -187,7 +213,7 @@ export const PAYLOAD_SCHEMA = {
187
213
  },
188
214
  "Provenance": {
189
215
  "title": "Provenance",
190
- "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.",
216
+ "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.\n\n`derived` — the value was taken from a source the holder connected or supplied — a code-hosting profile, an uploaded CV — rather than typed by them or attested by an issuer. Nobody signed it: it is the holder's claim that the source said so, and a consumer MUST NOT present it as attested. It exists as its own kind because a derived value is neither of the others — the holder did not author it, and no one vouches for it — and a holder deciding whether to disclose deserves to know which of their values they typed.\n\nFor how strongly a disclosed value identifies the holder, the kinds rank `credentialBacked` above `derived` above `selfAsserted`; `generated` values are per-verifier and do not correlate.",
191
217
  "type": "object",
192
218
  "required": [
193
219
  "kind"
@@ -258,6 +284,31 @@ export const PAYLOAD_SCHEMA = {
258
284
  "description": "When true (the default and the only useful setting), a distinct value is minted for each verifier."
259
285
  }
260
286
  }
287
+ },
288
+ {
289
+ "additionalProperties": false,
290
+ "required": [
291
+ "kind",
292
+ "source",
293
+ "derivedAt"
294
+ ],
295
+ "properties": {
296
+ "kind": {
297
+ "const": "derived"
298
+ },
299
+ "source": {
300
+ "type": "string",
301
+ "minLength": 1,
302
+ "maxLength": 64,
303
+ "pattern": "^[a-z][A-Za-z0-9.-]*$",
304
+ "description": "The KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share."
305
+ },
306
+ "derivedAt": {
307
+ "type": "string",
308
+ "format": "date-time",
309
+ "description": "When the value was taken from the source. A derived value is a snapshot: the source may have changed since, and nothing re-derives it."
310
+ }
311
+ }
261
312
  }
262
313
  ]
263
314
  },
@@ -333,6 +384,23 @@ export const PAYLOAD_SCHEMA = {
333
384
  "$ref": "#/$defs/ProfileEntry"
334
385
  }
335
386
  },
387
+ "reach": {
388
+ "$ref": "#/$defs/FaceReach"
389
+ },
390
+ "status": {
391
+ "type": "string",
392
+ "enum": [
393
+ "active",
394
+ "retired"
395
+ ],
396
+ "default": "active",
397
+ "description": "`retired`: the face is worn nowhere, is left out of pickers and default listings, and cannot be worn until reinstated (persona/profile/retire, persona/profile/reinstate). Its disclosure history and every value it carries are kept — retiring is 'stop being this', not 'forget this'. Absent reads as `active`."
398
+ },
399
+ "retiredAt": {
400
+ "type": "string",
401
+ "format": "date-time",
402
+ "description": "When the face was retired. Present exactly when `status` is `retired`."
403
+ },
336
404
  "credentialRefs": {
337
405
  "type": "array",
338
406
  "maxItems": 256,
@@ -355,6 +423,47 @@ export const PAYLOAD_SCHEMA = {
355
423
  }
356
424
  }
357
425
  },
426
+ "FaceReach": {
427
+ "title": "FaceReach",
428
+ "description": "Where a pool face may be worn. `anywhere` is the default and what an absent member means. `only` names the contexts it may be worn in, and a maintainer MUST refuse to wear it in any other (persona/binding/set `outsideReach`).\n\nA tagged object rather than a bare list of contexts, deliberately: an empty list has been read as both 'unrestricted' and 'nowhere' in this family's neighbours, and a shape where the two cannot be confused is worth more than one where they must be remembered. So `only` requires at least one context, and 'nowhere' is not a reach — it is a retired face.\n\nA context-local face has no reach: it lives in its context and is worn there by construction.",
429
+ "oneOf": [
430
+ {
431
+ "type": "object",
432
+ "additionalProperties": false,
433
+ "required": [
434
+ "kind"
435
+ ],
436
+ "properties": {
437
+ "kind": {
438
+ "const": "anywhere"
439
+ }
440
+ }
441
+ },
442
+ {
443
+ "type": "object",
444
+ "additionalProperties": false,
445
+ "required": [
446
+ "kind",
447
+ "contextIds"
448
+ ],
449
+ "properties": {
450
+ "kind": {
451
+ "const": "only"
452
+ },
453
+ "contextIds": {
454
+ "type": "array",
455
+ "minItems": 1,
456
+ "maxItems": 256,
457
+ "uniqueItems": true,
458
+ "items": {
459
+ "type": "string",
460
+ "minLength": 1
461
+ }
462
+ }
463
+ }
464
+ }
465
+ ]
466
+ },
358
467
  "ProfileEntry": {
359
468
  "title": "ProfileEntry",
360
469
  "description": "One line of a profile, in exactly one of four forms. Together they are the whole of a profile's flexibility, and each exists for a case the others handle badly.\n\n`{ref}` — use the pool attribute, live. Editing the pool updates every profile that references it, which is the point.\n\n`{ref, pinVersion}` — use the value as it was at that version. For a profile that must keep presenting the value a counterparty already verified.\n\n`{ref, override}` — the same fact, a different value here. (\"In the gaming profile my display name is different.\")\n\n`{inline}` — a value that never enters the pool, and so never leaks into another profile.\n\nOmission is exclusion; there is no removal marker.\n\nAny form MAY carry a `slot` naming the role the entry plays in the profile — see `Slot`. A maintainer MUST refuse a profile in which two entries carry the same slot: a slot exists to answer one question with one entry.",
@@ -482,6 +591,25 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
482
591
  "profile": {
483
592
  "$ref": "#/$defs/Profile"
484
593
  },
594
+ "disclosedTo": {
595
+ "type": "object",
596
+ "additionalProperties": false,
597
+ "required": [
598
+ "partyCount",
599
+ "contextCount"
600
+ ],
601
+ "description": "How many distinct parties this face has disclosed to, across how many contexts, from the holder's disclosure history. Counts, not identifiers; persona/disclosure/history names them. A producer shows this before a delete: deleting a face does not un-tell anyone what it told them.",
602
+ "properties": {
603
+ "partyCount": {
604
+ "type": "integer",
605
+ "minimum": 0
606
+ },
607
+ "contextCount": {
608
+ "type": "integer",
609
+ "minimum": 0
610
+ }
611
+ }
612
+ },
485
613
  "resolved": {
486
614
  "type": "array",
487
615
  "maxItems": 256,
@@ -575,7 +703,7 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
575
703
  },
576
704
  "Provenance": {
577
705
  "title": "Provenance",
578
- "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.",
706
+ "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.\n\n`derived` — the value was taken from a source the holder connected or supplied — a code-hosting profile, an uploaded CV — rather than typed by them or attested by an issuer. Nobody signed it: it is the holder's claim that the source said so, and a consumer MUST NOT present it as attested. It exists as its own kind because a derived value is neither of the others — the holder did not author it, and no one vouches for it — and a holder deciding whether to disclose deserves to know which of their values they typed.\n\nFor how strongly a disclosed value identifies the holder, the kinds rank `credentialBacked` above `derived` above `selfAsserted`; `generated` values are per-verifier and do not correlate.",
579
707
  "type": "object",
580
708
  "required": [
581
709
  "kind"
@@ -646,6 +774,31 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
646
774
  "description": "When true (the default and the only useful setting), a distinct value is minted for each verifier."
647
775
  }
648
776
  }
777
+ },
778
+ {
779
+ "additionalProperties": false,
780
+ "required": [
781
+ "kind",
782
+ "source",
783
+ "derivedAt"
784
+ ],
785
+ "properties": {
786
+ "kind": {
787
+ "const": "derived"
788
+ },
789
+ "source": {
790
+ "type": "string",
791
+ "minLength": 1,
792
+ "maxLength": 64,
793
+ "pattern": "^[a-z][A-Za-z0-9.-]*$",
794
+ "description": "The KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share."
795
+ },
796
+ "derivedAt": {
797
+ "type": "string",
798
+ "format": "date-time",
799
+ "description": "When the value was taken from the source. A derived value is a snapshot: the source may have changed since, and nothing re-derives it."
800
+ }
801
+ }
649
802
  }
650
803
  ]
651
804
  },
@@ -721,6 +874,23 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
721
874
  "$ref": "#/$defs/ProfileEntry"
722
875
  }
723
876
  },
877
+ "reach": {
878
+ "$ref": "#/$defs/FaceReach"
879
+ },
880
+ "status": {
881
+ "type": "string",
882
+ "enum": [
883
+ "active",
884
+ "retired"
885
+ ],
886
+ "default": "active",
887
+ "description": "`retired`: the face is worn nowhere, is left out of pickers and default listings, and cannot be worn until reinstated (persona/profile/retire, persona/profile/reinstate). Its disclosure history and every value it carries are kept — retiring is 'stop being this', not 'forget this'. Absent reads as `active`."
888
+ },
889
+ "retiredAt": {
890
+ "type": "string",
891
+ "format": "date-time",
892
+ "description": "When the face was retired. Present exactly when `status` is `retired`."
893
+ },
724
894
  "credentialRefs": {
725
895
  "type": "array",
726
896
  "maxItems": 256,
@@ -743,6 +913,47 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
743
913
  }
744
914
  }
745
915
  },
916
+ "FaceReach": {
917
+ "title": "FaceReach",
918
+ "description": "Where a pool face may be worn. `anywhere` is the default and what an absent member means. `only` names the contexts it may be worn in, and a maintainer MUST refuse to wear it in any other (persona/binding/set `outsideReach`).\n\nA tagged object rather than a bare list of contexts, deliberately: an empty list has been read as both 'unrestricted' and 'nowhere' in this family's neighbours, and a shape where the two cannot be confused is worth more than one where they must be remembered. So `only` requires at least one context, and 'nowhere' is not a reach — it is a retired face.\n\nA context-local face has no reach: it lives in its context and is worn there by construction.",
919
+ "oneOf": [
920
+ {
921
+ "type": "object",
922
+ "additionalProperties": false,
923
+ "required": [
924
+ "kind"
925
+ ],
926
+ "properties": {
927
+ "kind": {
928
+ "const": "anywhere"
929
+ }
930
+ }
931
+ },
932
+ {
933
+ "type": "object",
934
+ "additionalProperties": false,
935
+ "required": [
936
+ "kind",
937
+ "contextIds"
938
+ ],
939
+ "properties": {
940
+ "kind": {
941
+ "const": "only"
942
+ },
943
+ "contextIds": {
944
+ "type": "array",
945
+ "minItems": 1,
946
+ "maxItems": 256,
947
+ "uniqueItems": true,
948
+ "items": {
949
+ "type": "string",
950
+ "minLength": 1
951
+ }
952
+ }
953
+ }
954
+ }
955
+ ]
956
+ },
746
957
  "ProfileEntry": {
747
958
  "title": "ProfileEntry",
748
959
  "description": "One line of a profile, in exactly one of four forms. Together they are the whole of a profile's flexibility, and each exists for a case the others handle badly.\n\n`{ref}` — use the pool attribute, live. Editing the pool updates every profile that references it, which is the point.\n\n`{ref, pinVersion}` — use the value as it was at that version. For a profile that must keep presenting the value a counterparty already verified.\n\n`{ref, override}` — the same fact, a different value here. (\"In the gaming profile my display name is different.\")\n\n`{inline}` — a value that never enters the pool, and so never leaks into another profile.\n\nOmission is exclusion; there is no removal marker.\n\nAny form MAY carry a `slot` naming the role the entry plays in the profile — see `Slot`. A maintainer MUST refuse a profile in which two entries carry the same slot: a slot exists to answer one question with one entry.",
@@ -3,7 +3,7 @@
3
3
  * Source: specs/persona/profile/list/1.0/payload.schema.json
4
4
  */
5
5
 
6
- import type { ClaimType, Ext, Profile, ProfileEntry, ProofRung, Provenance, Slot, Ulid, ValueType, Version_PersonaV0_1 as Version } from "../../../../_shared/components.js";
6
+ import type { ClaimType, Ext, FaceReach, Profile, ProfileEntry, ProofRung, Provenance, Slot, Ulid, ValueType, Version_PersonaV0_1 as Version } from "../../../../_shared/components.js";
7
7
 
8
8
 
9
9
  /**
@@ -15,6 +15,10 @@ export interface PersonaProfileListPayload {
15
15
  */
16
16
  cursor?: string;
17
17
  limit?: number;
18
+ /**
19
+ * Include retired faces. Off by default: a retired face is one the holder has stopped being, and a picker that offered it back would undo the decision by accident.
20
+ */
21
+ includeRetired?: boolean;
18
22
  ext?: Ext;
19
23
  }
20
24
  /**
@@ -33,7 +37,7 @@ export interface PersonaProfileListResponsePayload {
33
37
  }
34
38
 
35
39
  /** Shared definitions this specification references, re-exported under the names it used to declare them with. */
36
- export type { ClaimType, Ext, Profile, ProfileEntry, ProofRung, Provenance, Slot, Ulid, ValueType, Version };
40
+ export type { ClaimType, Ext, FaceReach, Profile, ProfileEntry, ProofRung, Provenance, Slot, Ulid, ValueType, Version };
37
41
 
38
42
  /** Trust Task type URI. */
39
43
  export const TYPE_URI = "https://trusttasks.org/spec/persona/profile/list/1.0" as const;
@@ -75,6 +79,11 @@ export const PAYLOAD_SCHEMA = {
75
79
  "maximum": 500,
76
80
  "default": 100
77
81
  },
82
+ "includeRetired": {
83
+ "type": "boolean",
84
+ "default": false,
85
+ "description": "Include retired faces. Off by default: a retired face is one the holder has stopped being, and a picker that offered it back would undo the decision by accident."
86
+ },
78
87
  "ext": {
79
88
  "$ref": "#/$defs/Ext"
80
89
  }
@@ -146,6 +155,23 @@ export const PAYLOAD_SCHEMA = {
146
155
  "$ref": "#/$defs/ProfileEntry"
147
156
  }
148
157
  },
158
+ "reach": {
159
+ "$ref": "#/$defs/FaceReach"
160
+ },
161
+ "status": {
162
+ "type": "string",
163
+ "enum": [
164
+ "active",
165
+ "retired"
166
+ ],
167
+ "default": "active",
168
+ "description": "`retired`: the face is worn nowhere, is left out of pickers and default listings, and cannot be worn until reinstated (persona/profile/retire, persona/profile/reinstate). Its disclosure history and every value it carries are kept — retiring is 'stop being this', not 'forget this'. Absent reads as `active`."
169
+ },
170
+ "retiredAt": {
171
+ "type": "string",
172
+ "format": "date-time",
173
+ "description": "When the face was retired. Present exactly when `status` is `retired`."
174
+ },
149
175
  "credentialRefs": {
150
176
  "type": "array",
151
177
  "maxItems": 256,
@@ -174,6 +200,47 @@ export const PAYLOAD_SCHEMA = {
174
200
  "type": "integer",
175
201
  "minimum": 1
176
202
  },
203
+ "FaceReach": {
204
+ "title": "FaceReach",
205
+ "description": "Where a pool face may be worn. `anywhere` is the default and what an absent member means. `only` names the contexts it may be worn in, and a maintainer MUST refuse to wear it in any other (persona/binding/set `outsideReach`).\n\nA tagged object rather than a bare list of contexts, deliberately: an empty list has been read as both 'unrestricted' and 'nowhere' in this family's neighbours, and a shape where the two cannot be confused is worth more than one where they must be remembered. So `only` requires at least one context, and 'nowhere' is not a reach — it is a retired face.\n\nA context-local face has no reach: it lives in its context and is worn there by construction.",
206
+ "oneOf": [
207
+ {
208
+ "type": "object",
209
+ "additionalProperties": false,
210
+ "required": [
211
+ "kind"
212
+ ],
213
+ "properties": {
214
+ "kind": {
215
+ "const": "anywhere"
216
+ }
217
+ }
218
+ },
219
+ {
220
+ "type": "object",
221
+ "additionalProperties": false,
222
+ "required": [
223
+ "kind",
224
+ "contextIds"
225
+ ],
226
+ "properties": {
227
+ "kind": {
228
+ "const": "only"
229
+ },
230
+ "contextIds": {
231
+ "type": "array",
232
+ "minItems": 1,
233
+ "maxItems": 256,
234
+ "uniqueItems": true,
235
+ "items": {
236
+ "type": "string",
237
+ "minLength": 1
238
+ }
239
+ }
240
+ }
241
+ }
242
+ ]
243
+ },
177
244
  "ProfileEntry": {
178
245
  "title": "ProfileEntry",
179
246
  "description": "One line of a profile, in exactly one of four forms. Together they are the whole of a profile's flexibility, and each exists for a case the others handle badly.\n\n`{ref}` — use the pool attribute, live. Editing the pool updates every profile that references it, which is the point.\n\n`{ref, pinVersion}` — use the value as it was at that version. For a profile that must keep presenting the value a counterparty already verified.\n\n`{ref, override}` — the same fact, a different value here. (\"In the gaming profile my display name is different.\")\n\n`{inline}` — a value that never enters the pool, and so never leaks into another profile.\n\nOmission is exclusion; there is no removal marker.\n\nAny form MAY carry a `slot` naming the role the entry plays in the profile — see `Slot`. A maintainer MUST refuse a profile in which two entries carry the same slot: a slot exists to answer one question with one entry.",
@@ -288,7 +355,7 @@ export const PAYLOAD_SCHEMA = {
288
355
  },
289
356
  "Provenance": {
290
357
  "title": "Provenance",
291
- "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.",
358
+ "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.\n\n`derived` — the value was taken from a source the holder connected or supplied — a code-hosting profile, an uploaded CV — rather than typed by them or attested by an issuer. Nobody signed it: it is the holder's claim that the source said so, and a consumer MUST NOT present it as attested. It exists as its own kind because a derived value is neither of the others — the holder did not author it, and no one vouches for it — and a holder deciding whether to disclose deserves to know which of their values they typed.\n\nFor how strongly a disclosed value identifies the holder, the kinds rank `credentialBacked` above `derived` above `selfAsserted`; `generated` values are per-verifier and do not correlate.",
292
359
  "type": "object",
293
360
  "required": [
294
361
  "kind"
@@ -359,6 +426,31 @@ export const PAYLOAD_SCHEMA = {
359
426
  "description": "When true (the default and the only useful setting), a distinct value is minted for each verifier."
360
427
  }
361
428
  }
429
+ },
430
+ {
431
+ "additionalProperties": false,
432
+ "required": [
433
+ "kind",
434
+ "source",
435
+ "derivedAt"
436
+ ],
437
+ "properties": {
438
+ "kind": {
439
+ "const": "derived"
440
+ },
441
+ "source": {
442
+ "type": "string",
443
+ "minLength": 1,
444
+ "maxLength": 64,
445
+ "pattern": "^[a-z][A-Za-z0-9.-]*$",
446
+ "description": "The KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share."
447
+ },
448
+ "derivedAt": {
449
+ "type": "string",
450
+ "format": "date-time",
451
+ "description": "When the value was taken from the source. A derived value is a snapshot: the source may have changed since, and nothing re-derives it."
452
+ }
453
+ }
362
454
  }
363
455
  ]
364
456
  },
@@ -473,6 +565,23 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
473
565
  "$ref": "#/$defs/ProfileEntry"
474
566
  }
475
567
  },
568
+ "reach": {
569
+ "$ref": "#/$defs/FaceReach"
570
+ },
571
+ "status": {
572
+ "type": "string",
573
+ "enum": [
574
+ "active",
575
+ "retired"
576
+ ],
577
+ "default": "active",
578
+ "description": "`retired`: the face is worn nowhere, is left out of pickers and default listings, and cannot be worn until reinstated (persona/profile/retire, persona/profile/reinstate). Its disclosure history and every value it carries are kept — retiring is 'stop being this', not 'forget this'. Absent reads as `active`."
579
+ },
580
+ "retiredAt": {
581
+ "type": "string",
582
+ "format": "date-time",
583
+ "description": "When the face was retired. Present exactly when `status` is `retired`."
584
+ },
476
585
  "credentialRefs": {
477
586
  "type": "array",
478
587
  "maxItems": 256,
@@ -501,6 +610,47 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
501
610
  "type": "integer",
502
611
  "minimum": 1
503
612
  },
613
+ "FaceReach": {
614
+ "title": "FaceReach",
615
+ "description": "Where a pool face may be worn. `anywhere` is the default and what an absent member means. `only` names the contexts it may be worn in, and a maintainer MUST refuse to wear it in any other (persona/binding/set `outsideReach`).\n\nA tagged object rather than a bare list of contexts, deliberately: an empty list has been read as both 'unrestricted' and 'nowhere' in this family's neighbours, and a shape where the two cannot be confused is worth more than one where they must be remembered. So `only` requires at least one context, and 'nowhere' is not a reach — it is a retired face.\n\nA context-local face has no reach: it lives in its context and is worn there by construction.",
616
+ "oneOf": [
617
+ {
618
+ "type": "object",
619
+ "additionalProperties": false,
620
+ "required": [
621
+ "kind"
622
+ ],
623
+ "properties": {
624
+ "kind": {
625
+ "const": "anywhere"
626
+ }
627
+ }
628
+ },
629
+ {
630
+ "type": "object",
631
+ "additionalProperties": false,
632
+ "required": [
633
+ "kind",
634
+ "contextIds"
635
+ ],
636
+ "properties": {
637
+ "kind": {
638
+ "const": "only"
639
+ },
640
+ "contextIds": {
641
+ "type": "array",
642
+ "minItems": 1,
643
+ "maxItems": 256,
644
+ "uniqueItems": true,
645
+ "items": {
646
+ "type": "string",
647
+ "minLength": 1
648
+ }
649
+ }
650
+ }
651
+ }
652
+ ]
653
+ },
504
654
  "ProfileEntry": {
505
655
  "title": "ProfileEntry",
506
656
  "description": "One line of a profile, in exactly one of four forms. Together they are the whole of a profile's flexibility, and each exists for a case the others handle badly.\n\n`{ref}` — use the pool attribute, live. Editing the pool updates every profile that references it, which is the point.\n\n`{ref, pinVersion}` — use the value as it was at that version. For a profile that must keep presenting the value a counterparty already verified.\n\n`{ref, override}` — the same fact, a different value here. (\"In the gaming profile my display name is different.\")\n\n`{inline}` — a value that never enters the pool, and so never leaks into another profile.\n\nOmission is exclusion; there is no removal marker.\n\nAny form MAY carry a `slot` naming the role the entry plays in the profile — see `Slot`. A maintainer MUST refuse a profile in which two entries carry the same slot: a slot exists to answer one question with one entry.",
@@ -615,7 +765,7 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
615
765
  },
616
766
  "Provenance": {
617
767
  "title": "Provenance",
618
- "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.",
768
+ "description": "Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\n\n`selfAsserted` — the holder supplied it.\n\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\n\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.\n\n`derived` — the value was taken from a source the holder connected or supplied — a code-hosting profile, an uploaded CV — rather than typed by them or attested by an issuer. Nobody signed it: it is the holder's claim that the source said so, and a consumer MUST NOT present it as attested. It exists as its own kind because a derived value is neither of the others — the holder did not author it, and no one vouches for it — and a holder deciding whether to disclose deserves to know which of their values they typed.\n\nFor how strongly a disclosed value identifies the holder, the kinds rank `credentialBacked` above `derived` above `selfAsserted`; `generated` values are per-verifier and do not correlate.",
619
769
  "type": "object",
620
770
  "required": [
621
771
  "kind"
@@ -686,6 +836,31 @@ export const RESPONSE_PAYLOAD_SCHEMA = {
686
836
  "description": "When true (the default and the only useful setting), a distinct value is minted for each verifier."
687
837
  }
688
838
  }
839
+ },
840
+ {
841
+ "additionalProperties": false,
842
+ "required": [
843
+ "kind",
844
+ "source",
845
+ "derivedAt"
846
+ ],
847
+ "properties": {
848
+ "kind": {
849
+ "const": "derived"
850
+ },
851
+ "source": {
852
+ "type": "string",
853
+ "minLength": 1,
854
+ "maxLength": 64,
855
+ "pattern": "^[a-z][A-Za-z0-9.-]*$",
856
+ "description": "The KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share."
857
+ },
858
+ "derivedAt": {
859
+ "type": "string",
860
+ "format": "date-time",
861
+ "description": "When the value was taken from the source. A derived value is a snapshot: the source may have changed since, and nothing re-derives it."
862
+ }
863
+ }
689
864
  }
690
865
  ]
691
866
  },