@agenticprimitives/ontology 1.0.0-alpha.4 → 1.0.0-alpha.40

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 (183) hide show
  1. package/README.md +59 -21
  2. package/cbox/agent-facet-shapes.shacl.ttl +130 -0
  3. package/cbox/capability-catalog-shapes.shacl.ttl +284 -0
  4. package/cbox/card-projection-shapes.shacl.ttl +216 -0
  5. package/cbox/consultation-shapes.shacl.ttl +85 -0
  6. package/cbox/content-vocabulary.ttl +52 -0
  7. package/cbox/controlled-vocabularies.ttl +224 -4
  8. package/cbox/discovery-graph-shapes.shacl.ttl +284 -0
  9. package/cbox/familyoffice-shapes.shacl.ttl +92 -0
  10. package/cbox/familyoffice-vocabulary.ttl +48 -0
  11. package/cbox/geo-vocabulary.ttl +36 -0
  12. package/cbox/guidance-vocabulary.ttl +22 -0
  13. package/cbox/interaction-shapes.shacl.ttl +218 -0
  14. package/cbox/interaction-vocabulary.ttl +159 -0
  15. package/cbox/judgment-shapes.shacl.ttl +83 -0
  16. package/cbox/naming-registry-shapes.shacl.ttl +272 -0
  17. package/cbox/org-team-shapes.shacl.ttl +184 -0
  18. package/cbox/privacy-credential-shapes.shacl.ttl +187 -0
  19. package/cbox/profile-facet-vocabulary.ttl +50 -0
  20. package/cbox/registry-vocabulary.ttl +86 -0
  21. package/cbox/run-measures-shapes.shacl.ttl +59 -0
  22. package/cbox/run-provenance-shapes.shacl.ttl +264 -0
  23. package/cbox/scope-vocabulary.ttl +112 -0
  24. package/cbox/skill-grounding-vocabulary.ttl +18 -0
  25. package/cbox/skill-vocabulary.ttl +50 -0
  26. package/context.jsonld +37 -1
  27. package/dist/arg-types.d.ts +60 -0
  28. package/dist/arg-types.d.ts.map +1 -0
  29. package/dist/arg-types.js +143 -0
  30. package/dist/arg-types.js.map +1 -0
  31. package/dist/artifacts.d.ts +9 -2
  32. package/dist/artifacts.d.ts.map +1 -1
  33. package/dist/artifacts.js +153 -2
  34. package/dist/artifacts.js.map +1 -1
  35. package/dist/contact-fields.d.ts +28 -0
  36. package/dist/contact-fields.d.ts.map +1 -0
  37. package/dist/contact-fields.js +38 -0
  38. package/dist/contact-fields.js.map +1 -0
  39. package/dist/decisions.d.ts +69 -0
  40. package/dist/decisions.d.ts.map +1 -0
  41. package/dist/decisions.js +98 -0
  42. package/dist/decisions.js.map +1 -0
  43. package/dist/evaluation-context.d.ts +134 -0
  44. package/dist/evaluation-context.d.ts.map +1 -0
  45. package/dist/evaluation-context.js +136 -0
  46. package/dist/evaluation-context.js.map +1 -0
  47. package/dist/governance.d.ts +84 -0
  48. package/dist/governance.d.ts.map +1 -0
  49. package/dist/governance.js +88 -0
  50. package/dist/governance.js.map +1 -0
  51. package/dist/grounded-vocabulary.d.ts +29 -0
  52. package/dist/grounded-vocabulary.d.ts.map +1 -0
  53. package/dist/grounded-vocabulary.js +110 -0
  54. package/dist/grounded-vocabulary.js.map +1 -0
  55. package/dist/household.d.ts +19 -0
  56. package/dist/household.d.ts.map +1 -0
  57. package/dist/household.js +41 -0
  58. package/dist/household.js.map +1 -0
  59. package/dist/index.d.ts +1091 -3
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +1323 -5
  62. package/dist/index.js.map +1 -1
  63. package/dist/outcomes.d.ts +47 -0
  64. package/dist/outcomes.d.ts.map +1 -0
  65. package/dist/outcomes.js +40 -0
  66. package/dist/outcomes.js.map +1 -0
  67. package/dist/participant-vocabulary.d.ts +57 -0
  68. package/dist/participant-vocabulary.d.ts.map +1 -0
  69. package/dist/participant-vocabulary.js +66 -0
  70. package/dist/participant-vocabulary.js.map +1 -0
  71. package/dist/party-roles.d.ts +115 -0
  72. package/dist/party-roles.d.ts.map +1 -0
  73. package/dist/party-roles.js +343 -0
  74. package/dist/party-roles.js.map +1 -0
  75. package/dist/payload-classes.d.ts +22 -0
  76. package/dist/payload-classes.d.ts.map +1 -0
  77. package/dist/payload-classes.js +30 -0
  78. package/dist/payload-classes.js.map +1 -0
  79. package/dist/plan-shapes.d.ts +18 -0
  80. package/dist/plan-shapes.d.ts.map +1 -0
  81. package/dist/plan-shapes.js +38 -0
  82. package/dist/plan-shapes.js.map +1 -0
  83. package/dist/principles.generated.d.ts +11 -0
  84. package/dist/principles.generated.d.ts.map +1 -0
  85. package/dist/principles.generated.js +293 -0
  86. package/dist/principles.generated.js.map +1 -0
  87. package/dist/published-works.d.ts +13 -0
  88. package/dist/published-works.d.ts.map +1 -0
  89. package/dist/published-works.js +18 -0
  90. package/dist/published-works.js.map +1 -0
  91. package/dist/relations.d.ts +44 -0
  92. package/dist/relations.d.ts.map +1 -0
  93. package/dist/relations.js +104 -0
  94. package/dist/relations.js.map +1 -0
  95. package/dist/run-measures-context.d.ts +74 -0
  96. package/dist/run-measures-context.d.ts.map +1 -0
  97. package/dist/run-measures-context.js +77 -0
  98. package/dist/run-measures-context.js.map +1 -0
  99. package/dist/run-provenance-context.d.ts +315 -0
  100. package/dist/run-provenance-context.d.ts.map +1 -0
  101. package/dist/run-provenance-context.js +323 -0
  102. package/dist/run-provenance-context.js.map +1 -0
  103. package/dist/transitions.d.ts +42 -0
  104. package/dist/transitions.d.ts.map +1 -0
  105. package/dist/transitions.js +100 -0
  106. package/dist/transitions.js.map +1 -0
  107. package/dist/vault-records.d.ts +74 -0
  108. package/dist/vault-records.d.ts.map +1 -0
  109. package/dist/vault-records.js +777 -0
  110. package/dist/vault-records.js.map +1 -0
  111. package/dist/versions.generated.d.ts +262 -0
  112. package/dist/versions.generated.d.ts.map +1 -0
  113. package/dist/versions.generated.js +318 -0
  114. package/dist/versions.generated.js.map +1 -0
  115. package/evaluation.jsonld +133 -0
  116. package/mappings/actor-context-standards.ttl +89 -0
  117. package/mappings/agent-discovery-standards.ttl +127 -0
  118. package/mappings/collaboration-crosswalk-actors.ttl +30 -0
  119. package/mappings/collaboration-crosswalk-authority.ttl +31 -0
  120. package/mappings/collaboration-crosswalk-guidance.ttl +29 -0
  121. package/mappings/collaboration-crosswalk-intent.ttl +29 -0
  122. package/mappings/collaboration-crosswalk-messaging.ttl +37 -0
  123. package/mappings/collaboration-crosswalk-organization.ttl +66 -0
  124. package/mappings/collaboration-crosswalk-protocols.ttl +49 -0
  125. package/mappings/collaboration-crosswalk-skills.ttl +50 -0
  126. package/mappings/collaboration-profile.ttl +82 -0
  127. package/mappings/commerce-engagement-crosswalk.ttl +83 -0
  128. package/mappings/spine-standards.ttl +83 -0
  129. package/package.json +31 -9
  130. package/run-measures.jsonld +34 -0
  131. package/run-provenance.jsonld +314 -0
  132. package/tbox/actor-context.ttl +145 -0
  133. package/tbox/agent-resolution.ttl +308 -0
  134. package/tbox/agreement.ttl +77 -0
  135. package/tbox/attestation.ttl +156 -0
  136. package/tbox/card-projection.ttl +350 -0
  137. package/tbox/constraints.ttl +150 -0
  138. package/tbox/contact.ttl +61 -0
  139. package/tbox/content.ttl +76 -0
  140. package/tbox/context.ttl +508 -0
  141. package/tbox/coordination.ttl +263 -0
  142. package/tbox/core.ttl +325 -7
  143. package/tbox/dcat-imports.ttl +19 -0
  144. package/tbox/discovery.ttl +273 -0
  145. package/tbox/dqv-imports.ttl +29 -0
  146. package/tbox/earl-imports.ttl +32 -0
  147. package/tbox/engagement.ttl +349 -0
  148. package/tbox/entitlement.ttl +41 -0
  149. package/tbox/estate.ttl +78 -0
  150. package/tbox/evaluation.ttl +330 -0
  151. package/tbox/execution.ttl +720 -0
  152. package/tbox/familyoffice.ttl +87 -0
  153. package/tbox/fulfillment.ttl +140 -0
  154. package/tbox/geo.ttl +28 -0
  155. package/tbox/governance.ttl +67 -0
  156. package/tbox/guidance.ttl +40 -0
  157. package/tbox/household.ttl +142 -0
  158. package/tbox/identity.ttl +133 -6
  159. package/tbox/inference.ttl +177 -0
  160. package/tbox/intents.ttl +241 -0
  161. package/tbox/interaction.ttl +297 -0
  162. package/tbox/messaging.ttl +244 -0
  163. package/tbox/naming.ttl +114 -0
  164. package/tbox/org.ttl +410 -0
  165. package/tbox/payload.ttl +94 -0
  166. package/tbox/payment.ttl +124 -0
  167. package/tbox/plan.ttl +169 -0
  168. package/tbox/principles.ttl +212 -0
  169. package/tbox/privacy-credential.ttl +436 -0
  170. package/tbox/profile.ttl +107 -0
  171. package/tbox/prov-imports.ttl +73 -0
  172. package/tbox/registry.ttl +382 -0
  173. package/tbox/resolution.ttl +108 -0
  174. package/tbox/scope.ttl +59 -0
  175. package/tbox/security-exposure.ttl +102 -0
  176. package/tbox/situation.ttl +56 -0
  177. package/tbox/skills.ttl +316 -0
  178. package/tbox/skos-imports.ttl +54 -0
  179. package/tbox/transition.ttl +63 -0
  180. package/tbox/trust.ttl +210 -0
  181. package/tbox/values.ttl +81 -0
  182. package/tbox/verification-receipt.ttl +134 -0
  183. package/versions.adoption.json +173 -0
@@ -0,0 +1,272 @@
1
+ # C-box — SHACL shapes for typed names, contextual issuance, the workspace agent and registry agents,
2
+ # registration receipts and the lifecycle log (spec 346 §11; ADR-0061).
3
+ #
4
+ # STRUCTURE, NEVER PERMISSION. A typed name that conforms is still only a claim; a receipt that
5
+ # conforms is evidence, not authority (ADR-0020); a conformant lifecycle event proves the log's
6
+ # shape, not the truth of the event. What these refuse is a record that misleads on its face:
7
+ #
8
+ # a `.team` name on a Person — the suffix contradicts the on-chain record; the
9
+ # record wins, so the name must not resolve (§2.3)
10
+ # a workspace agent serving two workspaces — two contexts behind one agentive face
11
+ # a registry agent operating no registry — a '.registry' name that names nothing
12
+ # a receipt that omits a check — 'not verified' silently read as 'verified'
13
+ # a receipt listing a check twice — verified AND failed: which is it?
14
+ # an event with no chain link — an append-only log that can be rewritten
15
+ #
16
+ # SUBCLASS HANDLING. sh:class against ap:Agent / ap:OrganizationAgent relies on the rdfs:subClassOf*
17
+ # closure; shacl-engine 1.1.2 does not compute it. The house test materializes it from the T-box
18
+ # first. The SPARQL constraints need the cbox codelists (controlled-vocabularies.ttl,
19
+ # registry-vocabulary.ttl) IN THE DATA GRAPH — they join on skos:prefLabel / skos:inScheme.
20
+
21
+ @prefix apnam: <https://agenticprimitives.dev/ns/naming#> .
22
+ @prefix ap: <https://agenticprimitives.dev/ns/core#> .
23
+ @prefix aporg: <https://agenticprimitives.dev/ns/org#> .
24
+ @prefix apreg: <https://agenticprimitives.dev/ns/registry#> .
25
+ @prefix apdel: <https://agenticprimitives.dev/ns/delegation#> .
26
+ @prefix skos: <http://www.w3.org/2004/02/skos/core#> .
27
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
28
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
29
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
30
+
31
+ # ─── Typed names (§3.1, §2.3) ───────────────────────────────────────────────
32
+ # Targets names that CARRY a tld. Legacy roots (.agent / .impact) carry none and are exempt — they
33
+ # keep resolving as legacy throughout (spec 346 §3.5); a shape that failed them would be a migration.
34
+
35
+ apnam:TypedAgentNameShape a sh:NodeShape ;
36
+ rdfs:label "TypedAgentName shape" ;
37
+ sh:targetSubjectsOf apnam:tld ;
38
+
39
+ sh:property [
40
+ sh:path apnam:tld ;
41
+ sh:maxCount 1 ; sh:datatype xsd:string ;
42
+ sh:in ( "me" "org" "team" "svc" "workspace" "treasury" "registry" ) ;
43
+ sh:message "Exactly one canonical tld from apnam:tldScheme: me | org | team | svc | workspace | treasury | registry. 'ws' is an alias resolved before storage; .alliance and .agent are reserved/inactive." ;
44
+ ] ;
45
+ sh:property [
46
+ sh:path apnam:resolvesTo ;
47
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
48
+ sh:message "A typed name resolves to exactly one canonical Agent — every suffix names an agent; there are no non-agent subjects in the naming registry (ADR-0061 §4)." ;
49
+ ] ;
50
+ # The suffix is a CLAIM; the SA-keyed ap:agentType record is the authority. Disagreement resolves
51
+ # to null with reason type_mismatch (ADR-0013: empty is an answer) — so it must be a violation here.
52
+ sh:sparql [
53
+ sh:message "The name's tld MUST name the derived type recorded on its target (ap:agentType, via apnam:namesDerivedType). The suffix never overrides the record; the record never bends to the suffix (spec 346 §2.3)." ;
54
+ sh:select """
55
+ SELECT $this ?tld ?actual ?expected WHERE {
56
+ $this <https://agenticprimitives.dev/ns/naming#tld> ?tld ;
57
+ <https://agenticprimitives.dev/ns/naming#resolvesTo> ?agent .
58
+ ?agent <https://agenticprimitives.dev/ns/core#agentType> ?actual .
59
+ ?concept <http://www.w3.org/2004/02/skos/core#inScheme> <https://agenticprimitives.dev/ns/naming#tldScheme> ;
60
+ <http://www.w3.org/2004/02/skos/core#prefLabel> ?tld ;
61
+ <https://agenticprimitives.dev/ns/naming#namesDerivedType> ?expected .
62
+ FILTER (?actual != ?expected)
63
+ }
64
+ """ ;
65
+ ] .
66
+
67
+ # ─── Contextual issuance (§3.2, §9) ─────────────────────────────────────────
68
+
69
+ apnam:ContextualNameIssuanceShape a sh:NodeShape ;
70
+ rdfs:label "ContextualNameIssuance shape" ;
71
+ sh:targetClass apnam:ContextualNameIssuance ;
72
+
73
+ sh:property [
74
+ sh:path apnam:issuedBy ;
75
+ sh:minCount 1 ; sh:maxCount 1 ;
76
+ sh:or ( [ sh:class ap:OrganizationAgent ] [ sh:class ap:WorkspaceAgent ] ) ;
77
+ sh:message "Exactly one issuedBy, and it MUST be a context that owns a namespace: an OrganizationAgent (incl. a Team) or a WorkspaceAgent. A person issues no contextual names." ;
78
+ ] ;
79
+ sh:property [
80
+ sh:path apnam:issuedFor ;
81
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
82
+ sh:message "Exactly one issuedFor — the canonical subject the contextual name refers to." ;
83
+ ] ;
84
+ sh:property [
85
+ sh:path apnam:issuanceBasis ;
86
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class apdel:Delegation ;
87
+ sh:message "Exactly one issuanceBasis — the Delegation whose liveness makes the name CURRENT. No basis, no name: a contextual name is a reference over a live delegation, never an identity (ADR-0061 §6)." ;
88
+ ] ;
89
+ sh:property [
90
+ sh:path apnam:issuanceKind ;
91
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
92
+ sh:in ( "scoped" "reference" ) ;
93
+ sh:message "issuanceKind is exactly one of scoped | reference." ;
94
+ ] ;
95
+ sh:property [
96
+ sh:path apnam:issuedName ;
97
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
98
+ sh:message "The issued contextual form is recorded verbatim." ;
99
+ ] ;
100
+ sh:sparql [
101
+ sh:message "A 'reference' issuance names ANOTHER agent in the issuer's namespace: issuedFor MUST differ from issuedBy." ;
102
+ sh:select """
103
+ SELECT $this WHERE {
104
+ $this <https://agenticprimitives.dev/ns/naming#issuanceKind> "reference" ;
105
+ <https://agenticprimitives.dev/ns/naming#issuedBy> ?ctx ;
106
+ <https://agenticprimitives.dev/ns/naming#issuedFor> ?ctx .
107
+ }
108
+ """ ;
109
+ ] .
110
+
111
+ # ─── The two named service roles that are also derived types (§2.1) ─────────
112
+
113
+ ap:WorkspaceAgentShape a sh:NodeShape ;
114
+ rdfs:label "WorkspaceAgent shape" ;
115
+ sh:targetClass ap:WorkspaceAgent ;
116
+
117
+ sh:property [
118
+ sh:path aporg:coordinatesWorkspace ;
119
+ sh:maxCount 1 ; sh:class aporg:Workspace ;
120
+ sh:message "A WorkspaceAgent custodies and serves AT MOST ONE Workspace (spec 346 §2.2) — the '.workspace' name is one context's agentive face, not a multiplexer." ;
121
+ ] ;
122
+ sh:property [
123
+ sh:path ap:serviceRole ;
124
+ sh:minCount 1 ; sh:maxCount 1 ; sh:hasValue "workspace" ;
125
+ sh:message "serviceRole MUST be exactly 'workspace' — the §2.3 claim-time invariant, made structural." ;
126
+ ] .
127
+
128
+ ap:RegistryAgentShape a sh:NodeShape ;
129
+ rdfs:label "RegistryAgent shape" ;
130
+ sh:targetClass ap:RegistryAgent ;
131
+
132
+ sh:property [
133
+ sh:path apreg:operatesRegistry ;
134
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class apreg:Registry ;
135
+ sh:message "A RegistryAgent operates EXACTLY ONE apreg:Registry — a '.registry' name that operates nothing names nothing; one that operates two is two registries' face." ;
136
+ ] ;
137
+ sh:property [
138
+ sh:path ap:serviceRole ;
139
+ sh:minCount 1 ; sh:maxCount 1 ; sh:hasValue "registry" ;
140
+ sh:message "serviceRole MUST be exactly 'registry'." ;
141
+ ] .
142
+
143
+ # ─── Registration receipt (§7.2) ────────────────────────────────────────────
144
+
145
+ apreg:RegistrationReceiptShape a sh:NodeShape ;
146
+ rdfs:label "RegistrationReceipt shape" ;
147
+ sh:targetClass apreg:RegistrationReceipt ;
148
+
149
+ sh:property [
150
+ sh:path apreg:inRegistry ;
151
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class apreg:Registry ;
152
+ sh:message "A receipt belongs to exactly one Registry." ;
153
+ ] ;
154
+ sh:property [
155
+ sh:path apreg:subjectAgent ;
156
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
157
+ sh:message "A receipt is about exactly one canonical subject Agent." ;
158
+ ] ;
159
+ sh:property [
160
+ sh:path apreg:subjectType ;
161
+ sh:minCount 1 ; sh:maxCount 1 ;
162
+ sh:node [ sh:property [ sh:path skos:inScheme ; sh:hasValue ap:agentTypeScheme ] ] ;
163
+ sh:message "subjectType is exactly one ap:agentTypeScheme concept — the derived type the admission checked." ;
164
+ ] ;
165
+ sh:property [
166
+ sh:path apreg:receiptSigner ;
167
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:RegistryAgent ;
168
+ sh:message "A receipt is signed by exactly one RegistryAgent — the operator SA; an unsigned receipt is a claim by nobody." ;
169
+ ] ;
170
+ sh:property [
171
+ sh:path apreg:admittedAt ;
172
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:dateTime ;
173
+ sh:message "admittedAt is required — 'verified on <date>' is the whole consumer-facing claim." ;
174
+ ] ;
175
+ # Every listed check is a real AdmissionCheck …
176
+ sh:property [
177
+ sh:path [ sh:alternativePath ( apreg:verifiedCheck apreg:failedCheck apreg:notVerifiedCheck ) ] ;
178
+ sh:node [ sh:property [ sh:path skos:inScheme ; sh:hasValue apreg:admissionCheckScheme ] ] ;
179
+ sh:message "Every verified / failed / notVerified value MUST be an apreg:admissionCheckScheme concept." ;
180
+ ] ;
181
+ # … appears in AT MOST one list …
182
+ sh:property [
183
+ sh:path apreg:verifiedCheck ; sh:disjoint apreg:failedCheck ;
184
+ sh:message "A check cannot be both verified and failed." ;
185
+ ] ;
186
+ sh:property [
187
+ sh:path apreg:verifiedCheck ; sh:disjoint apreg:notVerifiedCheck ;
188
+ sh:message "A check cannot be both verified and not-verified." ;
189
+ ] ;
190
+ sh:property [
191
+ sh:path apreg:failedCheck ; sh:disjoint apreg:notVerifiedCheck ;
192
+ sh:message "A check cannot be both failed and not-verified." ;
193
+ ] ;
194
+ # … and in AT LEAST one. Together: exactly one. Omission is the dangerous direction — a missing
195
+ # line is read as 'verified' by anyone who does not know to look for it.
196
+ sh:sparql [
197
+ sh:message "Every AdmissionCheck in apreg:admissionCheckScheme MUST appear in exactly one of verifiedCheck / failedCheck / notVerifiedCheck. 'Not verified' is a first-class outcome and is RECORDED, never omitted (spec 346 §7.1)." ;
198
+ sh:select """
199
+ SELECT $this ?check WHERE {
200
+ ?check <http://www.w3.org/2004/02/skos/core#inScheme> <https://agenticprimitives.dev/ns/registry#admissionCheckScheme> .
201
+ FILTER NOT EXISTS { $this <https://agenticprimitives.dev/ns/registry#verifiedCheck> ?check }
202
+ FILTER NOT EXISTS { $this <https://agenticprimitives.dev/ns/registry#failedCheck> ?check }
203
+ FILTER NOT EXISTS { $this <https://agenticprimitives.dev/ns/registry#notVerifiedCheck> ?check }
204
+ }
205
+ """ ;
206
+ ] .
207
+
208
+ # ─── The append-only lifecycle log (§7.3) ───────────────────────────────────
209
+
210
+ apreg:RegistryLifecycleEventShape a sh:NodeShape ;
211
+ rdfs:label "RegistryLifecycleEvent shape" ;
212
+ sh:targetClass apreg:RegistryLifecycleEvent ;
213
+
214
+ sh:property [
215
+ sh:path apreg:inRegistry ;
216
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class apreg:Registry ;
217
+ sh:message "An event belongs to exactly one Registry — the log whose sequence it occupies." ;
218
+ ] ;
219
+ sh:property [
220
+ sh:path apreg:eventKind ;
221
+ sh:minCount 1 ; sh:maxCount 1 ;
222
+ sh:node [ sh:property [ sh:path skos:inScheme ; sh:hasValue apreg:lifecycleEventScheme ] ] ;
223
+ sh:message "eventKind is exactly one apreg:lifecycleEventScheme concept." ;
224
+ ] ;
225
+ sh:property [
226
+ sh:path apreg:eventSequence ;
227
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:nonNegativeInteger ;
228
+ sh:message "Exactly one eventSequence (xsd:nonNegativeInteger) — the event's position in the log." ;
229
+ ] ;
230
+ sh:property [
231
+ sh:path apreg:eventDigest ;
232
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
233
+ sh:message "Exactly one eventDigest — the value the next event chains to." ;
234
+ ] ;
235
+ sh:property [
236
+ sh:path apreg:occurredAt ;
237
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:dateTime ;
238
+ sh:message "occurredAt is required." ;
239
+ ] ;
240
+ sh:property [
241
+ sh:path apreg:previousEventDigest ;
242
+ sh:maxCount 1 ; sh:datatype xsd:string ;
243
+ sh:message "At most one previousEventDigest." ;
244
+ ] ;
245
+ sh:sparql [
246
+ sh:message "Every event with eventSequence > 0 MUST carry previousEventDigest — without the chain link the log is append-only in name only (spec 346 §7.3)." ;
247
+ sh:select """
248
+ SELECT $this ?seq WHERE {
249
+ $this <https://agenticprimitives.dev/ns/registry#eventSequence> ?seq .
250
+ FILTER (?seq > 0)
251
+ FILTER NOT EXISTS { $this <https://agenticprimitives.dev/ns/registry#previousEventDigest> ?prev }
252
+ }
253
+ """ ;
254
+ ] .
255
+
256
+ # Kept as its OWN NodeShape: shacl-engine 1.1.2 compiles the sh:sparql constraints of one shape as a
257
+ # single unit (one select, all messages), so two sh:sparql on one shape mis-report. One per shape.
258
+ apreg:RegistryLogSequenceShape a sh:NodeShape ;
259
+ rdfs:label "RegistryLogSequence shape" ;
260
+ sh:targetClass apreg:RegistryLifecycleEvent ;
261
+ sh:sparql [
262
+ sh:message "eventSequence MUST be unique within a registry — two events at one position means the log was forked or rewritten (spec 346 §7.3: strictly increasing per registry)." ;
263
+ sh:select """
264
+ SELECT $this ?other ?seq WHERE {
265
+ $this <https://agenticprimitives.dev/ns/registry#inRegistry> ?registry ;
266
+ <https://agenticprimitives.dev/ns/registry#eventSequence> ?seq .
267
+ ?other <https://agenticprimitives.dev/ns/registry#inRegistry> ?registry ;
268
+ <https://agenticprimitives.dev/ns/registry#eventSequence> ?seq .
269
+ FILTER (?other != $this)
270
+ }
271
+ """ ;
272
+ ] .
@@ -0,0 +1,184 @@
1
+ # C-box — SHACL shapes for team affiliation, the workspace plane, representations and
2
+ # responsibilities (spec 344 §4.6).
3
+ #
4
+ # STRUCTURE, NEVER PERMISSION (ADR-0043/ADR-0048). A conformant TeamAffiliation is not a charter, a
5
+ # conformant Workspace grants nobody anything, and a conformant ResponsibilityAssignment authorizes
6
+ # no act. Each shape exists because its absence lets a record be written that cannot later be
7
+ # interpreted — or, in one case, that would be interpreted as PERMISSIVE by default:
8
+ #
9
+ # an affiliation with no kind / two teams — which side is the team, and chartered or engaged?
10
+ # a workspace with no governor — whose policy, whose vault, whose audit context?
11
+ # an open workspace with asserted members — two participation models on one plane
12
+ # a representation with no sharing policy — THE FAIL-CLOSED FLOOR: absence of a policy is
13
+ # never public; an unclassified projection fails
14
+ # a responsibility carrying grant terms — a responsibility that looks like an authorization
15
+ #
16
+ # SUBCLASS HANDLING. Several constraints use sh:class against a SUPERCLASS (ap:Agent,
17
+ # ap:OrganizationAgent) and rely on SHACL-instance-of (rdf:type/rdfs:subClassOf*). shacl-engine 1.1.2
18
+ # does not compute that closure; the house test materializes it from tbox/core.ttl + tbox/org.ttl before
19
+ # validating. Any other consumer must do the same or load an RDFS-inferencing store.
20
+
21
+ @prefix aporg: <https://agenticprimitives.dev/ns/org#> .
22
+ @prefix ap: <https://agenticprimitives.dev/ns/core#> .
23
+ @prefix apdel: <https://agenticprimitives.dev/ns/delegation#> .
24
+ @prefix skos: <http://www.w3.org/2004/02/skos/core#> .
25
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
26
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
27
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
28
+
29
+ # ─── Team affiliation (§1.2) ────────────────────────────────────────────────
30
+
31
+ aporg:TeamAffiliationShape a sh:NodeShape ;
32
+ rdfs:label "TeamAffiliation shape" ;
33
+ sh:targetClass aporg:TeamAffiliation ;
34
+
35
+ sh:property [
36
+ sh:path aporg:teamAgent ;
37
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:TeamAgent ;
38
+ sh:message "A TeamAffiliation names exactly one teamAgent, and it MUST be an ap:TeamAgent (profileType 'team') — an informal WorkingGroup cannot be affiliated, it is not an agent (spec 344 §1.1)." ;
39
+ ] ;
40
+ sh:property [
41
+ sh:path aporg:affiliatedOrganization ;
42
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:OrganizationAgent ;
43
+ sh:message "A TeamAffiliation names exactly one affiliatedOrganization (an org, team or alliance)." ;
44
+ ] ;
45
+ sh:property [
46
+ sh:path aporg:affiliationKind ;
47
+ sh:minCount 1 ; sh:maxCount 1 ;
48
+ sh:in ( aporg:CharteredAffiliation aporg:EngagedAffiliation ) ;
49
+ sh:message "affiliationKind is exactly one of aporg:affiliationKindScheme: chartered | engaged. An affiliation of no kind cannot be read as a charter OR as an engagement." ;
50
+ ] ;
51
+ # A team is itself an OrganizationAgent, so nothing else stops it from being 'affiliated' with itself.
52
+ sh:property [
53
+ sh:path aporg:teamAgent ;
54
+ sh:disjoint aporg:affiliatedOrganization ;
55
+ sh:message "The two sides of a TeamAffiliation MUST be distinct agents — a team cannot charter or engage itself." ;
56
+ ] ;
57
+ sh:property [
58
+ sh:path aporg:mandatedByDelegation ;
59
+ sh:maxCount 1 ; sh:class apdel:Delegation ;
60
+ sh:message "At most one chartering mandate, and it is a Delegation reference — the gate verifies the delegation, never this record." ;
61
+ ] .
62
+
63
+ # ─── The workspace plane (§2) ───────────────────────────────────────────────
64
+
65
+ aporg:WorkspaceShape a sh:NodeShape ;
66
+ rdfs:label "Workspace shape" ;
67
+ sh:targetClass aporg:Workspace ;
68
+
69
+ sh:property [
70
+ sh:path aporg:governedBy ;
71
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:OrganizationAgent ;
72
+ sh:message "A Workspace is governed by exactly one OrganizationAgent (org, team or alliance) — the source of every policy it has and the owner of the vault its records live in (ADR-0055). A workspace has no authority of its own." ;
73
+ ] ;
74
+ sh:property [
75
+ sh:path aporg:workspaceParticipationPolicy ;
76
+ sh:minCount 1 ; sh:maxCount 1 ;
77
+ sh:in ( aporg:OpenWorkspace aporg:RestrictedWorkspace ) ;
78
+ sh:message "Exactly one workspaceParticipationPolicy from aporg:workspacePolicyScheme: open | restricted. Absence would have to be read as one of them, and the convenient reading is 'open'." ;
79
+ ] ;
80
+ sh:property [
81
+ sh:path aporg:workspaceProfile ;
82
+ sh:minCount 1 ; sh:maxCount 1 ;
83
+ sh:node [ sh:property [ sh:path skos:inScheme ; sh:hasValue aporg:workspaceProfileScheme ] ] ;
84
+ sh:message "One primary workspaceProfile, a concept of aporg:workspaceProfileScheme (domain packs extend the scheme, so membership is checked rather than a closed list)." ;
85
+ ] ;
86
+ sh:property [
87
+ sh:path aporg:coordinatedBy ;
88
+ sh:maxCount 1 ; sh:class ap:WorkspaceAgent ;
89
+ sh:message "At most one workspace agent, and it is an ap:WorkspaceAgent — the workspace's single agentive face (ADR-0061 §4). Two workspace agents would be two names for one context." ;
90
+ ] ;
91
+ # An 'open' workspace DERIVES participation from the governor's membership; an asserted
92
+ # WorkspaceParticipation on it would be a second, contradicting participation model.
93
+ sh:sparql [
94
+ sh:message "An OPEN workspace MUST NOT have asserted WorkspaceParticipation records — participation is derived from the governor's membership, never asserted (spec 344 §2.1). Make it restricted, or drop the assertions." ;
95
+ sh:select """
96
+ SELECT $this ?participation WHERE {
97
+ $this <https://agenticprimitives.dev/ns/org#workspaceParticipationPolicy> <https://agenticprimitives.dev/ns/org#OpenWorkspace> .
98
+ ?participation <https://agenticprimitives.dev/ns/org#inWorkspace> $this .
99
+ }
100
+ """ ;
101
+ ] .
102
+
103
+ aporg:WorkspaceParticipationShape a sh:NodeShape ;
104
+ rdfs:label "WorkspaceParticipation shape" ;
105
+ sh:targetClass aporg:WorkspaceParticipation ;
106
+
107
+ sh:property [
108
+ sh:path aporg:participantAgent ;
109
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
110
+ sh:message "Exactly one participantAgent — ANY agent kind (a person, or an org/team that projects its own live roster in; the Gather27 GatherHost shape)." ;
111
+ ] ;
112
+ sh:property [
113
+ sh:path aporg:inWorkspace ;
114
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class aporg:Workspace ;
115
+ sh:message "Exactly one inWorkspace — a participation that names no workspace, or two, is not a participation in anything." ;
116
+ ] .
117
+
118
+ # ─── Representations (§2.2) — the fail-closed floor ─────────────────────────
119
+
120
+ aporg:WorkspaceRepresentationShape a sh:NodeShape ;
121
+ rdfs:label "WorkspaceRepresentation shape" ;
122
+ sh:targetClass aporg:WorkspaceRepresentation ;
123
+
124
+ sh:property [
125
+ sh:path aporg:represents ;
126
+ sh:minCount 1 ; sh:maxCount 1 ;
127
+ sh:message "A representation projects exactly one domain entity." ;
128
+ ] ;
129
+ sh:property [
130
+ sh:path aporg:representationOfWorkspace ;
131
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class aporg:Workspace ;
132
+ sh:message "A representation is scoped to exactly one Workspace — the plane whose policy bounds it." ;
133
+ ] ;
134
+ sh:property [
135
+ sh:path aporg:sourceCustodian ;
136
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
137
+ sh:message "Exactly one sourceCustodian — whose vault holds the authoritative record. Custody NEVER moves into the workspace." ;
138
+ ] ;
139
+ # THE FLOOR. Not a default, not a warning: a representation with no disclosure bound is refused
140
+ # at the structural level, because the only alternative reading of 'no policy' is 'public'.
141
+ sh:property [
142
+ sh:path aporg:sharingPolicy ;
143
+ sh:minCount 1 ;
144
+ sh:message "A WorkspaceRepresentation MUST carry a sharingPolicy. Absence of a policy is never public — an unclassified representation fails closed (spec 344 §2.2 normative floor)." ;
145
+ ] .
146
+
147
+ # ─── Responsibility (§1.5) — never an authorization ─────────────────────────
148
+
149
+ aporg:ResponsibilityShape a sh:NodeShape ;
150
+ rdfs:label "ResponsibilityAssignment shape" ;
151
+ sh:targetClass aporg:ResponsibilityAssignment ;
152
+
153
+ sh:property [
154
+ sh:path aporg:responsibleAgent ;
155
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
156
+ sh:message "Exactly one responsibleAgent — the one expected to care for the outcome." ;
157
+ ] ;
158
+ sh:property [
159
+ sh:path aporg:accountableAgent ;
160
+ sh:maxCount 1 ; sh:class ap:Agent ;
161
+ sh:message "At most one accountableAgent — who answers for the result; MAY differ from the responsible agent." ;
162
+ ] ;
163
+ sh:property [
164
+ sh:path aporg:responsibilityKind ;
165
+ sh:minCount 1 ; sh:maxCount 1 ;
166
+ sh:message "A responsibility has exactly one kind." ;
167
+ ] ;
168
+ sh:property [
169
+ sh:path aporg:underMandate ;
170
+ sh:maxCount 1 ; sh:class apdel:Delegation ;
171
+ sh:message "underMandate is a REFERENCE to the delegation the responsible agent exercises — at most one, and never the grant itself." ;
172
+ ] ;
173
+ # A ResponsibilityAssignment MUST NOT carry the authority-materialization terms a RoleAssignment
174
+ # does. The moment one does, a reader has a record that looks like an authorization and is not.
175
+ sh:property [
176
+ sh:path aporg:materializedByDelegation ;
177
+ sh:maxCount 0 ;
178
+ sh:message "A ResponsibilityAssignment MUST NOT carry aporg:materializedByDelegation — a responsibility is never an authorization; that term belongs to RoleAssignment (spec 344 §1.5)." ;
179
+ ] ;
180
+ sh:property [
181
+ sh:path aporg:supportedByEntitlement ;
182
+ sh:maxCount 0 ;
183
+ sh:message "A ResponsibilityAssignment MUST NOT carry aporg:supportedByEntitlement — grant terms on a responsibility make it read as authority." ;
184
+ ] .
@@ -0,0 +1,187 @@
1
+ # C-box — SHACL shapes for anonymous credentials (tbox/privacy-credential.ttl; specs 304 / 305 / 442 §7.2 / 443 W5).
2
+ #
3
+ # STRUCTURE, NEVER PERMISSION. A conformant presentation is still only a claim a verifier has yet to check; a
4
+ # conformant mandate authorizes nothing by being well-formed; conformant evidence is evidence. What these refuse is a
5
+ # record that would MISLEAD ON ITS FACE or LEAK BY ITS SHAPE:
6
+ #
7
+ # a pairwise account linked to a person — the one join this vocabulary exists to withhold (INV-305-1)
8
+ # a presentation carrying a claim value — the suite reveals none; a record that does was not made by it
9
+ # a presentation answering no request — a proof of nothing in particular
10
+ # a nullifier with no audience or no grade — "one visit" per what, worth how much?
11
+ # a facet whose subject is a person — a person's agent holds credentials; it does not issue them
12
+ # a facet with no attestation — a document alone proves nothing; the chain does
13
+ # a mandate naming no audience — a device key that may sign for anyone
14
+ # evidence with no facet or no predicate digest — "a predicate held" with neither named is not evidence
15
+ #
16
+ # SUBCLASS HANDLING. sh:class against ap:Agent relies on the rdfs:subClassOf* closure; the house test materializes it
17
+ # from the T-box first. The SPARQL constraints need the cbox codelists in the data graph (they join on skos:inScheme).
18
+
19
+ @prefix appc: <https://agenticprimitives.dev/ns/privacy-credential#> .
20
+ @prefix apatt: <https://agenticprimitives.dev/ns/attestation#> .
21
+ @prefix ap: <https://agenticprimitives.dev/ns/core#> .
22
+ @prefix skos: <http://www.w3.org/2004/02/skos/core#> .
23
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
24
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
25
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
26
+
27
+ # ─── The pairwise account names no person ────────────────────────────────────────────────────────
28
+ appc:PairwiseAccountShape a sh:NodeShape ;
29
+ rdfs:label "PairwiseAccount shape" ;
30
+ sh:targetClass appc:PairwiseAccount ;
31
+ sh:property [
32
+ sh:path appc:pairwiseFor ;
33
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:anyURI ;
34
+ sh:message "A pairwise account exists for exactly ONE verifier origin (appc:pairwiseFor). The same holder at another origin is another account." ;
35
+ ] ;
36
+ sh:sparql [
37
+ sh:message "A pairwise account MUST NOT be linked to any Agent: the join from the account a verifier sees to the person exists only in her vault (INV-305-1, ADR-0025). A triple from this account to an ap:Agent, under any property, is the disclosure this vocabulary withholds." ;
38
+ sh:select """
39
+ SELECT $this ?p ?agent WHERE {
40
+ $this ?p ?agent .
41
+ ?agent a/<http://www.w3.org/2000/01/rdf-schema#subClassOf>* <https://agenticprimitives.dev/ns/core#Agent> .
42
+ }
43
+ """ ;
44
+ ] .
45
+
46
+ # ─── A presentation answers one request, names its facet, and carries no claim value ────────────
47
+ appc:PrivatePresentationShape a sh:NodeShape ;
48
+ rdfs:label "PrivatePresentation shape" ;
49
+ sh:targetClass appc:PrivatePresentation ;
50
+ sh:property [
51
+ sh:path appc:answersRequest ;
52
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class appc:ProofRequest ;
53
+ sh:message "A presentation answers exactly ONE proof request — the verifier's own, with its audience and single-use nonce. A proof answering no request is a proof of nothing in particular." ;
54
+ ] ;
55
+ sh:property [
56
+ sh:path appc:presentedUnder ;
57
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class appc:IssuerKeyFacet ;
58
+ sh:message "A presentation names the ONE issuer facet it was made under; the verifier resolves it through the chain and checks the proven key against it." ;
59
+ ] ;
60
+ sh:property [
61
+ sh:path appc:provesPredicate ;
62
+ sh:maxCount 1 ; sh:class appc:PredicateProgram ;
63
+ sh:message "At most one predicate program per presentation — the request's." ;
64
+ ] ;
65
+ sh:property [
66
+ sh:path appc:carriesNullifier ;
67
+ sh:maxCount 1 ; sh:class appc:Nullifier ;
68
+ sh:message "At most one nullifier, for the request's audience." ;
69
+ ] ;
70
+ sh:property [
71
+ sh:path appc:predicateClaim ;
72
+ sh:maxCount 0 ;
73
+ sh:message "A presentation carries NO claim name or value of its own: the suite reveals none, and a record that does was not made by it. Claims belong to the predicate PROGRAM (the verifier's thresholds), never to the presentation." ;
74
+ ] ;
75
+ sh:property [
76
+ sh:path appc:predicateOperand ;
77
+ sh:maxCount 0 ;
78
+ sh:message "A presentation carries no operand — see appc:predicateClaim." ;
79
+ ] .
80
+
81
+ # ─── A nullifier is scoped and graded ─────────────────────────────────────────────────────────────
82
+ appc:NullifierShape a sh:NodeShape ;
83
+ rdfs:label "Nullifier shape" ;
84
+ sh:targetClass appc:Nullifier ;
85
+ sh:property [
86
+ sh:path appc:audience ;
87
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:anyURI ;
88
+ sh:message "A nullifier is one-per-AUDIENCE: without the audience it is a value that links nothing to nothing, or everything to everything." ;
89
+ ] ;
90
+ sh:property [
91
+ sh:path appc:nullifierValue ;
92
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
93
+ sh:message "Exactly one value." ;
94
+ ] ;
95
+ sh:property [
96
+ sh:path appc:nullifierGrade ;
97
+ sh:minCount 1 ; sh:maxCount 1 ;
98
+ sh:message "A nullifier says what it is worth: its grade (appc:nullifierGradeScheme — asserted | in-circuit). An ungraded nullifier would be read as the stronger one." ;
99
+ ] ;
100
+ sh:sparql [
101
+ sh:message "The grade MUST be a concept of appc:nullifierGradeScheme." ;
102
+ sh:select """
103
+ SELECT $this ?g WHERE {
104
+ $this <https://agenticprimitives.dev/ns/privacy-credential#nullifierGrade> ?g .
105
+ FILTER NOT EXISTS { ?g <http://www.w3.org/2004/02/skos/core#inScheme> <https://agenticprimitives.dev/ns/privacy-credential#nullifierGradeScheme> }
106
+ }
107
+ """ ;
108
+ ] .
109
+
110
+ # ─── An issuer facet is an organization's or a service's, anchored ───────────────────────────────
111
+ appc:IssuerKeyFacetShape a sh:NodeShape ;
112
+ rdfs:label "IssuerKeyFacet shape" ;
113
+ sh:targetClass appc:IssuerKeyFacet ;
114
+ sh:property [
115
+ sh:path appc:facetSubject ;
116
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
117
+ sh:message "A facet speaks for exactly one agent." ;
118
+ ] ;
119
+ sh:property [
120
+ sh:path appc:facetKeyId ;
121
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
122
+ sh:message "One key id — what a credential names and a verifier resolves by." ;
123
+ ] ;
124
+ sh:property [
125
+ sh:path appc:facetHash ;
126
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
127
+ sh:message "The facet hash the agent signed and the attestation carries." ;
128
+ ] ;
129
+ sh:property [
130
+ sh:path appc:anchoredBy ;
131
+ sh:minCount 1 ; sh:class apatt:Attestation ;
132
+ sh:message "A facet is ANCHORED: an attestation on the issuer's chain binds it to the agent. A facet document with no attestation proves nothing to a stranger — the chain does." ;
133
+ ] ;
134
+ sh:sparql [
135
+ sh:message "A facet's subject is an organization or a service — NEVER a person. A person's agent holds credentials; it does not issue them (spec 443 §2)." ;
136
+ sh:select """
137
+ SELECT $this ?subject WHERE {
138
+ $this <https://agenticprimitives.dev/ns/privacy-credential#facetSubject> ?subject .
139
+ ?subject a/<http://www.w3.org/2000/01/rdf-schema#subClassOf>* <https://agenticprimitives.dev/ns/core#PersonAgent> .
140
+ }
141
+ """ ;
142
+ ] .
143
+
144
+ # ─── A presentation mandate is bounded ───────────────────────────────────────────────────────────
145
+ appc:PresentationMandateShape a sh:NodeShape ;
146
+ rdfs:label "PresentationMandate shape" ;
147
+ sh:targetClass appc:PresentationMandate ;
148
+ sh:property [
149
+ sh:path appc:mandateAudience ;
150
+ sh:minCount 1 ; sh:datatype xsd:anyURI ;
151
+ sh:message "A presentation mandate names at least one verifier origin. A device key that may sign for ANY audience is a key that may be phished by any door." ;
152
+ ] ;
153
+ sh:property [
154
+ sh:path appc:mandatePredicateDigest ;
155
+ sh:minCount 1 ; sh:datatype xsd:string ;
156
+ sh:message "A presentation mandate names at least one predicate program by digest — what the person agreed may be proved." ;
157
+ ] ;
158
+ sh:property [
159
+ sh:path appc:mandateIssuerKeyId ;
160
+ sh:minCount 1 ; sh:datatype xsd:string ;
161
+ sh:message "A presentation mandate names at least one issuer facet." ;
162
+ ] .
163
+
164
+ # ─── Evidence names what held ────────────────────────────────────────────────────────────────────
165
+ appc:PredicateAdmissionEvidenceShape a sh:NodeShape ;
166
+ rdfs:label "PredicateAdmissionEvidence shape" ;
167
+ sh:targetClass appc:PredicateAdmissionEvidence ;
168
+ sh:property [
169
+ sh:path appc:evidenceFacet ;
170
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class appc:IssuerKeyFacet ;
171
+ sh:message "Evidence names the facet the proof verified under." ;
172
+ ] ;
173
+ sh:property [
174
+ sh:path appc:evidencePredicateDigest ;
175
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
176
+ sh:message "Evidence names the predicate program the DOOR asked, by digest. \"A predicate held\" with none named is not evidence." ;
177
+ ] ;
178
+ sh:property [
179
+ sh:path appc:verifierPlacement ;
180
+ sh:minCount 1 ; sh:maxCount 1 ;
181
+ sh:message "Evidence says WHERE the proof was verified (appc:verifierPlacementScheme). A receipt that cannot is not a receipt." ;
182
+ ] ;
183
+ sh:property [
184
+ sh:path appc:predicateOperand ;
185
+ sh:maxCount 0 ;
186
+ sh:message "Evidence carries no claim value and no operand — the digest of the program is what it names." ;
187
+ ] .