@agenticprimitives/ontology 1.0.0-alpha.45 → 1.0.0-alpha.47

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 (51) hide show
  1. package/cbox/controlled-vocabularies.ttl +10 -6
  2. package/cbox/interaction-shapes.shacl.ttl +22 -5
  3. package/cbox/naming-registry-shapes.shacl.ttl +38 -6
  4. package/cbox/run-provenance-shapes.shacl.ttl +10 -4
  5. package/cbox/value-rail-shapes.shacl.ttl +60 -0
  6. package/dist/artifacts.d.ts +2 -2
  7. package/dist/artifacts.d.ts.map +1 -1
  8. package/dist/artifacts.js +19 -0
  9. package/dist/artifacts.js.map +1 -1
  10. package/dist/household.d.ts.map +1 -1
  11. package/dist/household.js +7 -3
  12. package/dist/household.js.map +1 -1
  13. package/dist/index.d.ts +13 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +13 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/party-roles.d.ts.map +1 -1
  18. package/dist/party-roles.js +6 -3
  19. package/dist/party-roles.js.map +1 -1
  20. package/dist/stewardship.d.ts +34 -0
  21. package/dist/stewardship.d.ts.map +1 -0
  22. package/dist/stewardship.js +38 -0
  23. package/dist/stewardship.js.map +1 -0
  24. package/dist/transitions.d.ts +10 -1
  25. package/dist/transitions.d.ts.map +1 -1
  26. package/dist/transitions.js +12 -2
  27. package/dist/transitions.js.map +1 -1
  28. package/dist/vault-records.d.ts +33 -5
  29. package/dist/vault-records.d.ts.map +1 -1
  30. package/dist/vault-records.js +123 -96
  31. package/dist/vault-records.js.map +1 -1
  32. package/dist/versions.generated.d.ts +34 -34
  33. package/dist/versions.generated.js +33 -33
  34. package/dist/versions.generated.js.map +1 -1
  35. package/package.json +3 -3
  36. package/tbox/actor-context.ttl +1 -0
  37. package/tbox/content.ttl +5 -0
  38. package/tbox/core.ttl +34 -4
  39. package/tbox/estate.ttl +7 -1
  40. package/tbox/geo.ttl +6 -0
  41. package/tbox/household.ttl +5 -3
  42. package/tbox/identity.ttl +12 -1
  43. package/tbox/inference.ttl +7 -2
  44. package/tbox/naming.ttl +2 -2
  45. package/tbox/payload.ttl +35 -31
  46. package/tbox/payment.ttl +10 -6
  47. package/tbox/privacy-credential.ttl +21 -1
  48. package/tbox/skills.ttl +5 -0
  49. package/tbox/transition.ttl +60 -3
  50. package/tbox/values.ttl +2 -1
  51. package/versions.adoption.json +18 -0
@@ -47,6 +47,9 @@ const PPLAN = 'http://purl.org/net/p-plan#';
47
47
  const EPPLAN = 'https://w3id.org/ep-plan#';
48
48
  const APEVAL = 'https://agenticprimitives.dev/ns/evaluation#';
49
49
  const DQV = 'http://www.w3.org/ns/dqv#';
50
+ export const VAULT_RECORD_ROLES = ['entity', 'index', 'secret'];
51
+ /** What a `secret` row IS, in the T-box — bound by IRI so the role is not vocabulary this file invented. */
52
+ export const HELD_SECRET_CLASS = 'https://agenticprimitives.dev/ns/core#HeldSecret';
50
53
  /**
51
54
  * The record kinds this substrate stores, each bound to what it IS.
52
55
  *
@@ -63,14 +66,14 @@ export const VAULT_RECORD_BINDINGS = [
63
66
  // it was here until the check started reading record bindings. You ask about endeavors; the log is how
64
67
  // one of them got where it is.
65
68
  { match: { prefix: 'coordination.endeavor:events:' }, class: `${APCOORD}Endeavor`, label: 'endeavor history', plural: 'endeavor history', ownedBy: 'either', role: 'index' },
66
- { match: { prefix: 'coordination.endeavor:' }, class: `${APCOORD}Endeavor`, label: 'endeavor', plural: 'endeavors', ownedBy: 'either' },
67
- { match: { exact: 'coordination.requests' }, class: `${APCOORD}EndeavorRequest`, label: 'request for work', plural: 'requests for work', ownedBy: 'either' },
69
+ { match: { prefix: 'coordination.endeavor:' }, class: `${APCOORD}Endeavor`, label: 'endeavor', plural: 'endeavors', ownedBy: 'either', role: 'entity' },
70
+ { match: { exact: 'coordination.requests' }, class: `${APCOORD}EndeavorRequest`, label: 'request for work', plural: 'requests for work', ownedBy: 'either', role: 'entity' },
68
71
  // ── The parties' own evidence of a transfer (spec 360) ────────────────────────────────────────
69
72
  // A payment's StepReceipt is AUTHORITY evidence and lives in the audit sink. This is the different
70
73
  // artifact the two PARTIES hold: what Alice can point at to say she paid, and what tells Bob he was
71
74
  // paid, to which treasury, in what amount. Keyed by the transaction, because that is the one identifier
72
75
  // both sides can check against the chain rather than take on trust.
73
- { match: { prefix: 'payment.receipt:' }, class: `${APIX}PaymentReceipt`, label: 'payment receipt', plural: 'payment receipts', ownedBy: 'either',
76
+ { match: { prefix: 'payment.receipt:' }, class: `${APIX}PaymentReceipt`, label: 'payment receipt', plural: 'payment receipts', ownedBy: 'either', role: 'entity',
74
77
  properties: {
75
78
  payer: `${APIX}receiptPayer`,
76
79
  payee: `${APIX}receiptPayee`,
@@ -82,12 +85,13 @@ export const VAULT_RECORD_BINDINGS = [
82
85
  // ── Organization membership (spec 324, ADR-0025) ──────────────────────────────────────────────
83
86
  // The ROSTER an organization keeps of its own members. This is the record `organization.membership.list`
84
87
  // reads today through its own hand-written invoker — W4 retires that in favour of this binding.
85
- { match: { exact: 'directory.data' }, class: `${APORG}DirectoryListing`, label: 'member listing', plural: 'member listings', ownedBy: 'organization' },
86
- { match: { prefix: 'org.invite:agent:' }, class: `${APORG}MembershipInvitation`, label: 'membership invitation', plural: 'membership invitations', ownedBy: 'organization' },
88
+ { match: { exact: 'directory.data' }, class: `${APORG}DirectoryListing`, label: 'member listing', plural: 'member listings', ownedBy: 'organization', role: 'entity' },
89
+ { match: { prefix: 'org.invite:agent:' }, class: `${APORG}MembershipInvitation`, label: 'membership invitation', plural: 'membership invitations', ownedBy: 'organization', role: 'entity' },
87
90
  // Spec 401 (amended 2026-10-26) — ONE HALF of a friendship: a person's own offer to another person (`friend:<their sa>`),
88
91
  // with the grant they signed. A friendship is never a record — it is derived from two of these, one in each vault.
89
- { match: { prefix: 'friend:' }, class: `${APORG}FriendshipOffer`, label: 'friendship offer', plural: 'friendship offers', ownedBy: 'person' },
90
- { match: { exact: 'org.applications' }, class: `${APORG}MembershipApplication`, label: 'membership application', plural: 'membership applications', ownedBy: 'organization' },
92
+ { match: { prefix: 'friend:' }, class: `${APORG}FriendshipOffer`, label: 'friendship offer', plural: 'friendship offers', ownedBy: 'person', role: 'entity',
93
+ properties: { offeredTo: `${APORG}offeredTo`, friendType: `${APORG}friendTypeLabel`, delegation: `${APORG}offerGrant`, status: `${APORG}offerStatus`, withdrawnAt: `${APORG}offerWithdrawnAt` } },
94
+ { match: { exact: 'org.applications' }, class: `${APORG}MembershipApplication`, label: 'membership application', plural: 'membership applications', ownedBy: 'organization', role: 'entity' },
91
95
  // THE MEMBERSHIP ITSELF — spec 325's shape, in the organization's own vault. Distinct from the
92
96
  // invitation, which the T-box files under "Enrollment instruments (NOT membership)": an invitation is
93
97
  // how somebody came to be admitted, and satisfying one creates nothing. The membership is the record
@@ -97,7 +101,7 @@ export const VAULT_RECORD_BINDINGS = [
97
101
  // already carries, and clear of `org.membership:local-names`, which is a name map and not a member.
98
102
  {
99
103
  match: { prefix: 'org.membership:member:' }, class: `${APORG}OrganizationMembership`,
100
- label: 'member', plural: 'members', ownedBy: 'organization',
104
+ label: 'member', plural: 'members', ownedBy: 'organization', role: 'entity',
101
105
  // Spec 325's shape, field for field — this is what "readable by the ontology" looks like in practice.
102
106
  properties: {
103
107
  memberAgent: `${APORG}memberAgent`,
@@ -123,7 +127,7 @@ export const VAULT_RECORD_BINDINGS = [
123
127
  // Ask that can change a name can change a street address, and the record's write allow-list agrees.
124
128
  {
125
129
  match: { exact: 'impact-profile' }, class: `${APCON}ContactProfile`,
126
- label: 'contact profile', plural: 'contact profiles', ownedBy: 'person',
130
+ label: 'contact profile', plural: 'contact profiles', ownedBy: 'person', role: 'entity',
127
131
  properties: { ...CONTACT_PROFILE_PROPERTIES, 'contact.location.precision': `${APCON}locationPrecision` },
128
132
  },
129
133
  // A PERSON's own record of who they are connected to — private, a vault credential and never an
@@ -134,14 +138,14 @@ export const VAULT_RECORD_BINDINGS = [
134
138
  // per person holding their own household — not a shared roster, because two people's records can
135
139
  // disagree and the honest model says whose you are reading.
136
140
  match: { exact: 'household.data' }, class: `${APHH}Household`,
137
- label: 'household', plural: 'household', ownedBy: 'person',
141
+ label: 'household', plural: 'household', ownedBy: 'person', role: 'entity',
138
142
  properties: {
139
143
  'members[].agent': `${APHH}householdMember`,
140
144
  'members[].role': `${APHH}householdRole`,
141
145
  'members[].kin': `${APHH}kinRelation`,
142
146
  },
143
147
  },
144
- { match: { exact: 'relationships.data' }, class: `${APORG}OrganizationMembership`, label: 'organization you belong to', plural: 'organizations you belong to', ownedBy: 'person',
148
+ { match: { exact: 'relationships.data' }, class: `${APORG}OrganizationMembership`, label: 'organization you belong to', plural: 'organizations you belong to', ownedBy: 'person', role: 'entity',
145
149
  // The map is KEYED by the organization — the thing a reader most often gets wrong here.
146
150
  properties: {
147
151
  'orgs{}': `${APORG}organizationAgent`,
@@ -150,7 +154,7 @@ export const VAULT_RECORD_BINDINGS = [
150
154
  },
151
155
  },
152
156
  // ── Content (spec 347 / the field artifacts) ──────────────────────────────────────────────────
153
- { match: { prefix: 'content.artifact.' }, class: `${APFUL}Artifact`, label: 'artifact', plural: 'artifacts', ownedBy: 'either',
157
+ { match: { prefix: 'content.artifact.' }, class: `${APFUL}Artifact`, label: 'artifact', plural: 'artifacts', ownedBy: 'either', role: 'entity',
154
158
  properties: {
155
159
  'kind': `${APFUL}artifactKind`,
156
160
  'commitment': `${APFUL}bodyHash`,
@@ -158,49 +162,49 @@ export const VAULT_RECORD_BINDINGS = [
158
162
  },
159
163
  // ── Conversation (spec 313/316) ───────────────────────────────────────────────────────────────
160
164
  // A message BODY is the content of one message; a topic is the conversation it sits in.
161
- { match: { prefix: 'message.body:' }, class: `${APFUL}Message`, label: 'message', plural: 'messages', ownedBy: 'either' },
162
- { match: { prefix: 'conversation.topic:' }, class: `${APMSG}DiscussionTopic`, label: 'discussion', plural: 'discussions', ownedBy: 'either' },
165
+ { match: { prefix: 'message.body:' }, class: `${APFUL}Message`, label: 'message', plural: 'messages', ownedBy: 'either', role: 'entity' },
166
+ { match: { prefix: 'conversation.topic:' }, class: `${APMSG}DiscussionTopic`, label: 'discussion', plural: 'discussions', ownedBy: 'either', role: 'entity' },
163
167
  // ── Relationship credentials (spec 410 §8) ───────────────────────────────────────────────────
164
168
  // The countersigned form of a relationship, one copy in each party's vault; the revocation likewise.
165
- { match: { prefix: 'relationships.credential:' }, class: `${AP}RelationshipCredential`, label: 'relationship credential', plural: 'relationship credentials', ownedBy: 'either',
169
+ { match: { prefix: 'relationships.credential:' }, class: `${AP}RelationshipCredential`, label: 'relationship credential', plural: 'relationship credentials', ownedBy: 'either', role: 'entity',
166
170
  properties: { kind: `${AP}relationshipKind` },
167
171
  },
168
- { match: { prefix: 'relationships.revocation:' }, class: `${AP}RelationshipCredential`, label: 'relationship revocation', plural: 'relationship revocations', ownedBy: 'either',
172
+ { match: { prefix: 'relationships.revocation:' }, class: `${AP}RelationshipCredential`, label: 'relationship revocation', plural: 'relationship revocations', ownedBy: 'either', role: 'entity',
169
173
  properties: { credential: `${AP}revokes` },
170
174
  },
171
175
  // ── Governance of the common model (spec 410 §10) ────────────────────────────────────────────
172
- { match: { prefix: 'ontology.meaning:' }, class: `${APGOV}LocalMeaning`, label: 'local meaning of a common term', plural: 'local meanings', ownedBy: 'organization',
176
+ { match: { prefix: 'ontology.meaning:' }, class: `${APGOV}LocalMeaning`, label: 'local meaning of a common term', plural: 'local meanings', ownedBy: 'organization', role: 'entity',
173
177
  properties: { term: `${APGOV}ofTerm`, organization: `${APGOV}heldBy`, relation: `${APGOV}mappingRelation` },
174
178
  },
175
- { match: { exact: 'ontology.adopted' }, class: `${APGOV}AdoptedVersion`, label: 'adopted ontology version', plural: 'adopted ontology versions', ownedBy: 'either',
179
+ { match: { exact: 'ontology.adopted' }, class: `${APGOV}AdoptedVersion`, label: 'adopted ontology version', plural: 'adopted ontology versions', ownedBy: 'either', role: 'entity',
176
180
  properties: { manifestDigest: `${APGOV}manifestDigest`, adoptedAt: `${APGOV}adoptedAt`, proposalRef: `${APGOV}proposalRef` },
177
181
  },
178
- { match: { prefix: 'ontology.steward:' }, class: `${APGOV}Steward`, label: 'steward of a term', plural: 'stewards', ownedBy: 'either',
182
+ { match: { prefix: 'ontology.steward:' }, class: `${APGOV}Steward`, label: 'steward of a term', plural: 'stewards', ownedBy: 'either', role: 'entity',
179
183
  properties: { subject: `${APGOV}stewards`, stewardAgent: `${APGOV}stewardAgent`, charterRef: `${APGOV}charterRef` },
180
184
  },
181
185
  // ── Delegation lineage (spec 410 §1.2) ───────────────────────────────────────────────────────
182
186
  // A key-signed wire re-issued for a credential rotation, and which wire it replaces. The delegator's vault holds
183
187
  // it; the delegate fetches the head of the lineage from the delegator's agent. Never a grant of anything new.
184
- { match: { prefix: 'delegation.lineage:' }, class: `${APDEL}Delegation`, label: 'delegation re-issued for a rotation', plural: 'delegations re-issued for a rotation', ownedBy: 'either',
188
+ { match: { prefix: 'delegation.lineage:' }, class: `${APDEL}Delegation`, label: 'delegation re-issued for a rotation', plural: 'delegations re-issued for a rotation', ownedBy: 'either', role: 'entity',
185
189
  properties: { supersedes: `${APDEL}supersedes` },
186
190
  },
187
191
  // ── Resolution (spec 338) ─────────────────────────────────────────────────────────────────────
188
- { match: { exact: 'resolution.grants' }, class: `${APAR}PrivateResolutionGrant`, label: 'way to reach someone', plural: 'ways to reach people', ownedBy: 'either',
192
+ { match: { exact: 'resolution.grants' }, class: `${APAR}PrivateResolutionGrant`, label: 'way to reach someone', plural: 'ways to reach people', ownedBy: 'either', role: 'entity',
189
193
  // The held record names WHOSE agent it opens; the address itself comes from the resolver, per use.
190
194
  properties: {
191
195
  'grants[].owner': `${APAR}permitsDiscoveryOf`,
192
196
  },
193
197
  },
194
- { match: { exact: 'resolution.requests' }, class: `${APAR}AgentConnectionInvitation`, label: 'request for a way to reach an agent', plural: 'requests for a way to reach an agent', ownedBy: 'either' },
198
+ { match: { exact: 'resolution.requests' }, class: `${APAR}AgentConnectionInvitation`, label: 'request for a way to reach an agent', plural: 'requests for a way to reach an agent', ownedBy: 'either', role: 'entity' },
195
199
  // ── What an agent IS and CAN DO ───────────────────────────────────────────────────────────────
196
- { match: { exact: 'capabilities.data' }, class: `${APS}CapabilityCatalog`, label: 'capability', plural: 'capabilities', ownedBy: 'either',
200
+ { match: { exact: 'capabilities.data' }, class: `${APS}CapabilityCatalog`, label: 'capability', plural: 'capabilities', ownedBy: 'either', role: 'entity',
197
201
  // The record is the catalogue; each ENTRY is a claim, so its fields map to SkillClaim's properties.
198
202
  properties: {
199
203
  '[].relation': `${APS}claimRelation`,
200
204
  '[].label': `${APS}semanticType`,
201
205
  },
202
206
  },
203
- { match: { exact: 'skills.data' }, class: `${APS}SkillClaim`, label: 'skill claim', plural: 'skill claims', ownedBy: 'either',
207
+ { match: { exact: 'skills.data' }, class: `${APS}SkillClaim`, label: 'skill claim', plural: 'skill claims', ownedBy: 'either', role: 'entity',
204
208
  properties: {
205
209
  '[].definitionId': `${APS}definitionId`,
206
210
  '[].subject': `${APS}claimSubject`,
@@ -216,7 +220,7 @@ export const VAULT_RECORD_BINDINGS = [
216
220
  properties: { '[].kind': `${APCR}credentialKind` } },
217
221
  // The emails and phones that open this home and are told when something changes. Never a signer.
218
222
  { match: { exact: 'security.channels' }, class: `${APCR}ChannelFacet`, label: 'contact channel', plural: 'contact channels', ownedBy: 'person', role: 'index' },
219
- { match: { exact: 'impact-profile' }, class: `${APROF}AgentProfile`, label: 'profile', plural: 'profile', ownedBy: 'either',
223
+ { match: { exact: 'impact-profile' }, class: `${APROF}AgentProfile`, label: 'profile', plural: 'profile', ownedBy: 'either', role: 'entity',
220
224
  // Observed records carry only `contact`, which the T-box has no property for — see the coverage ledger.
221
225
  properties: {
222
226
  'displayName': `${APROF}displayName`,
@@ -226,11 +230,11 @@ export const VAULT_RECORD_BINDINGS = [
226
230
  // An index over the artifacts, not a thing beside them.
227
231
  { match: { exact: 'content.catalog' }, class: `${APFUL}Artifact`, label: 'content index', plural: 'content index', ownedBy: 'either', role: 'index' },
228
232
  // ── The card studio (spec 347) ────────────────────────────────────────────────────────────────
229
- { match: { prefix: 'agent-cards:' }, class: `${AP}A2AAgentCard`, label: 'agent card', plural: 'agent cards', ownedBy: 'either' },
233
+ { match: { prefix: 'agent-cards:' }, class: `${AP}A2AAgentCard`, label: 'agent card', plural: 'agent cards', ownedBy: 'either', role: 'entity' },
230
234
  // ── The playbook an agent runs under (spec 354) ───────────────────────────────────────────────
231
235
  {
232
236
  match: { exact: 'archetype.assignment' }, class: `${APS}ArchetypeAssignment`,
233
- label: 'playbook', plural: 'playbook', ownedBy: 'either',
237
+ label: 'playbook', plural: 'playbook', ownedBy: 'either', role: 'entity',
234
238
  properties: {
235
239
  archetypeId: `${APS}assignedArchetype`,
236
240
  definitionDigest: `${APS}definitionDigest`,
@@ -245,7 +249,7 @@ export const VAULT_RECORD_BINDINGS = [
245
249
  // the same IRI the context maps it to — bound twice on purpose, checked once by the build.
246
250
  {
247
251
  match: { prefix: 'run.provenance:' }, class: `${EPPLAN}ExecutionTraceBundle`,
248
- label: 'run provenance', plural: 'run provenances', ownedBy: 'either',
252
+ label: 'run provenance', plural: 'run provenances', ownedBy: 'either', role: 'entity',
249
253
  properties: {
250
254
  wasAttributedTo: `${PROV}wasAttributedTo`,
251
255
  wasInformedBy: `${PROV}wasInformedBy`,
@@ -337,7 +341,7 @@ export const VAULT_RECORD_BINDINGS = [
337
341
  // estate it was (`estate`). A claim about where to look — the holder recomputes the digest and reads the registry.
338
342
  {
339
343
  match: { prefix: 'run.anchor:' }, class: `${APEXEC}ReceiptAnchor`,
340
- label: 'run anchor', plural: 'run anchors', ownedBy: 'either',
344
+ label: 'run anchor', plural: 'run anchors', ownedBy: 'either', role: 'entity',
341
345
  properties: {
342
346
  digest: `${APEXEC}anchorDigest`,
343
347
  registry: `${APEXEC}anchorRegistry`,
@@ -351,7 +355,7 @@ export const VAULT_RECORD_BINDINGS = [
351
355
  // metric (and per step where the number is a step's). Descriptive, never judged; no words (shape M3).
352
356
  {
353
357
  match: { prefix: 'run.measures:' }, class: `${APEVAL}RunMeasures`,
354
- label: 'run measurements', plural: 'run measurements', ownedBy: 'either',
358
+ label: 'run measurements', plural: 'run measurements', ownedBy: 'either', role: 'entity',
355
359
  properties: {
356
360
  wasDerivedFrom: `${PROV}wasDerivedFrom`,
357
361
  wasAttributedTo: `${PROV}wasAttributedTo`,
@@ -375,7 +379,7 @@ export const VAULT_RECORD_BINDINGS = [
375
379
  // (the service-agent-signing rule), or by a person's SA at her Home.
376
380
  {
377
381
  match: { prefix: 'run.assessment:' }, class: `${APEVAL}Assessment`,
378
- label: 'run assessment', plural: 'run assessments', ownedBy: 'either',
382
+ label: 'run assessment', plural: 'run assessments', ownedBy: 'either', role: 'entity',
379
383
  properties: {
380
384
  subject: `${PROV}used`,
381
385
  recordDigest: `${APEXEC}anchorDigest`,
@@ -394,7 +398,7 @@ export const VAULT_RECORD_BINDINGS = [
394
398
  // That is the whole reason this is a record and not a handoff token.
395
399
  {
396
400
  match: { prefix: 'endeavor.continuation:' }, class: `${APCOORD}Endeavor`,
397
- label: 'continuation package', plural: 'continuation packages', ownedBy: 'either',
401
+ label: 'continuation package', plural: 'continuation packages', ownedBy: 'either', role: 'entity',
398
402
  properties: {
399
403
  // The objective is the Endeavor's OutcomeSpecification — the observable success definition that already
400
404
  // exists, not a prose restatement of it. An agent picking the work up is told what "done" means in the
@@ -410,7 +414,7 @@ export const VAULT_RECORD_BINDINGS = [
410
414
  // Every exchange is one signed unit by its author; a steward's determination closes it; it reverses nothing.
411
415
  {
412
416
  match: { prefix: 'interaction.dispute:' }, class: `${APIX}Interaction`,
413
- label: 'dispute', plural: 'disputes', ownedBy: 'either',
417
+ label: 'dispute', plural: 'disputes', ownedBy: 'either', role: 'entity',
414
418
  properties: {
415
419
  profileVersion: `${APIX}profileVersion`,
416
420
  'exchanges[].performative': `${APIX}performative`,
@@ -419,7 +423,7 @@ export const VAULT_RECORD_BINDINGS = [
419
423
  // ── The run's pointer to the dispute that cites it (spec 410 §10, `apexec:disputedBy`) ──
420
424
  {
421
425
  match: { prefix: 'run.dispute:' }, class: `${APEXEC}ServiceExecution`,
422
- label: 'run dispute', plural: 'run disputes', ownedBy: 'either',
426
+ label: 'run dispute', plural: 'run disputes', ownedBy: 'either', role: 'entity',
423
427
  properties: {
424
428
  disputedBy: `${APEXEC}disputedBy`,
425
429
  },
@@ -428,7 +432,7 @@ export const VAULT_RECORD_BINDINGS = [
428
432
  // The body a resume or a person fetches under the agent's grant; the receipt's outputDigest commits to it.
429
433
  {
430
434
  match: { prefix: 'run.artifact:' }, class: `${APEXEC}RunArtifact`,
431
- label: 'run artifact', plural: 'run artifacts', ownedBy: 'either',
435
+ label: 'run artifact', plural: 'run artifacts', ownedBy: 'either', role: 'entity',
432
436
  properties: {
433
437
  digest: `${APEXEC}artifactDigest`,
434
438
  bytes: `${APEXEC}artifactBytes`,
@@ -438,7 +442,7 @@ export const VAULT_RECORD_BINDINGS = [
438
442
  // The files the model wrote and the test evidence as recorded; the PR opened from it names this record.
439
443
  {
440
444
  match: { prefix: 'build.run:' }, class: `${APEXEC}BuildArtifact`,
441
- label: 'build run', plural: 'build runs', ownedBy: 'either',
445
+ label: 'build run', plural: 'build runs', ownedBy: 'either', role: 'entity',
442
446
  properties: {
443
447
  repository: `${APEXEC}buildRepository`,
444
448
  base: `${APEXEC}buildBase`,
@@ -454,7 +458,7 @@ export const VAULT_RECORD_BINDINGS = [
454
458
  // ── Build promotions (spec 398 §9.4 / ap-build B5) — the exact tuple a steward's signature was over ──
455
459
  {
456
460
  match: { prefix: 'build.promotion:' }, class: `${APEXEC}BuildPromotion`,
457
- label: 'build promotion', plural: 'build promotions', ownedBy: 'either',
461
+ label: 'build promotion', plural: 'build promotions', ownedBy: 'either', role: 'entity',
458
462
  properties: {
459
463
  repository: `${APEXEC}buildRepository`,
460
464
  commit: `${APEXEC}promotedCommit`,
@@ -467,7 +471,7 @@ export const VAULT_RECORD_BINDINGS = [
467
471
  // ── The agent's budget (P1.4) — what it may do in a day, declared by its steward ──
468
472
  {
469
473
  match: { exact: 'agent.budget' }, class: `${APCTX}AgentBudget`,
470
- label: 'agent budget', plural: 'agent budget', ownedBy: 'either',
474
+ label: 'agent budget', plural: 'agent budget', ownedBy: 'either', role: 'entity',
471
475
  properties: { asksPerDay: `${APCTX}asksPerDay`, vaultCallsPerDay: `${APCTX}vaultCallsPerDay` },
472
476
  },
473
477
  // ── The town's model gateway (spec 434) — inference.svc's OWN records: policy, entitlements, receipts ──
@@ -475,28 +479,28 @@ export const VAULT_RECORD_BINDINGS = [
475
479
  // service's own policy over its own resource, never a delegation (G8). `assertedAgent` is what the caller SAID.
476
480
  {
477
481
  match: { prefix: 'inference.receipt:' }, class: `${APINF}InferenceReceipt`,
478
- label: 'inference receipt', plural: 'inference receipts', ownedBy: 'either',
482
+ label: 'inference receipt', plural: 'inference receipts', ownedBy: 'either', role: 'entity',
479
483
  properties: { profile: `${APINF}profileId`, profileVersion: `${APINF}profileVersion`, provider: `${APINF}modelProvider`, model: `${APINF}modelId`, principal: `${APINF}principal`, assertedAgent: `${APINF}assertedAgent`, costMicroUsd: `${APINF}costMicroUsd`, attempt: `${APINF}attempt`, fallbackOf: `${APINF}fallbackOf`, reconciliation: `${APINF}reconciliationState`, outcome: `${APINF}outcome`, purpose: `${APINF}purpose`, estate: `${APINF}estate`, clientKind: `${APINF}clientKind` },
480
484
  },
481
- { match: { prefix: 'inference.profile:' }, class: `${APINF}ModelProfile`, label: 'model profile', plural: 'model profiles', ownedBy: 'either', properties: { id: `${APINF}profileId`, 'servesCapability[]': `${APINF}servesCapability` } },
482
- { match: { prefix: 'inference.model:' }, class: `${APINF}ModelCatalogEntry`, label: 'model catalog entry', plural: 'model catalog entries', ownedBy: 'either', properties: { provider: `${APINF}modelProvider`, model: `${APINF}modelId`, enabled: `${APINF}enabled` } },
483
- { match: { prefix: 'inference.client:' }, class: `${APINF}ClientEntitlement`, label: 'inference client', plural: 'inference clients', ownedBy: 'either', properties: { principal: `${APINF}principal`, estate: `${APINF}estate`, kind: `${APINF}clientKind` } },
484
- { match: { prefix: 'inference.policy-change:' }, class: `${APINF}PolicyChange`, label: 'inference policy change', plural: 'inference policy changes', ownedBy: 'either', properties: { recordKey: `${APINF}changedRecord`, reason: `${APINF}reason` } },
485
+ { match: { prefix: 'inference.profile:' }, class: `${APINF}ModelProfile`, label: 'model profile', plural: 'model profiles', ownedBy: 'either', role: 'entity', properties: { id: `${APINF}profileId`, 'servesCapability[]': `${APINF}servesCapability` } },
486
+ { match: { prefix: 'inference.model:' }, class: `${APINF}ModelCatalogEntry`, label: 'model catalog entry', plural: 'model catalog entries', ownedBy: 'either', role: 'entity', properties: { provider: `${APINF}modelProvider`, model: `${APINF}modelId`, enabled: `${APINF}enabled` } },
487
+ { match: { prefix: 'inference.client:' }, class: `${APINF}ClientEntitlement`, label: 'inference client', plural: 'inference clients', ownedBy: 'either', role: 'entity', properties: { principal: `${APINF}principal`, estate: `${APINF}estate`, kind: `${APINF}clientKind` } },
488
+ { match: { prefix: 'inference.policy-change:' }, class: `${APINF}PolicyChange`, label: 'inference policy change', plural: 'inference policy changes', ownedBy: 'either', role: 'entity', properties: { recordKey: `${APINF}changedRecord`, reason: `${APINF}reason` } },
485
489
  // ── Spec 435 / 436 / 437 — standing, manifests, the Town Ask's records ──
486
490
  // The agent's own copy of its TownStanding VC (the chain holds the hash): read to show and renew; no gate reads it.
487
- { match: { prefix: 'town.standing:' }, class: `${APATT}TownStanding`, label: 'town standing', plural: 'town standings', ownedBy: 'either', properties: { town: `${APATT}standingTown`, estate: `${APATT}standingEstate`, steward: `${APATT}standingSteward`, validUntil: `${APATT}standingValidUntil` } },
491
+ { match: { prefix: 'town.standing:' }, class: `${APATT}TownStanding`, label: 'town standing', plural: 'town standings', ownedBy: 'either', role: 'entity', properties: { town: `${APATT}standingTown`, estate: `${APATT}standingEstate`, steward: `${APATT}standingSteward`, validUntil: `${APATT}standingValidUntil` } },
488
492
  // A service's own signed MCP tool manifest, as published; a holder pins its digest on `connector.mcp:` (spec 404).
489
- { match: { prefix: 'mcp.manifest:' }, class: `${APAR}McpToolManifest`, label: 'MCP tool manifest', plural: 'MCP tool manifests', ownedBy: 'either', properties: { 'server.url': `${APAR}manifestServerUrl` } },
490
- { match: { prefix: 'mcp.bundle:' }, class: `${APAR}McpToolBundle`, label: 'MCP tool bundle', plural: 'MCP tool bundles', ownedBy: 'either' },
493
+ { match: { prefix: 'mcp.manifest:' }, class: `${APAR}McpToolManifest`, label: 'MCP tool manifest', plural: 'MCP tool manifests', ownedBy: 'either', role: 'entity', properties: { 'server.url': `${APAR}manifestServerUrl` } },
494
+ { match: { prefix: 'mcp.bundle:' }, class: `${APAR}McpToolBundle`, label: 'MCP tool bundle', plural: 'MCP tool bundles', ownedBy: 'either', role: 'entity' },
491
495
  // The Town Ask (spec 436 §5.5, 437): the context agents' memory of the Pulse — counts, never a person.
492
- { match: { prefix: 'pulse.day:' }, class: `${APINF}TownPulse`, label: "day's pulse", plural: 'daily pulses', ownedBy: 'either', properties: { day: `${APINF}pulseDay` } },
493
- { match: { prefix: 'pulse.sample:' }, class: `${APINF}TownPulse`, label: 'pulse sample', plural: 'pulse samples', ownedBy: 'either' },
494
- { match: { prefix: 'estate.checklist:' }, class: `${APINF}StandingChecklist`, label: 'standing checklist', plural: 'standing checklists', ownedBy: 'either' },
495
- { match: { prefix: 'estate.manifest:' }, class: `${APINF}EstateManifest`, label: 'estate manifest', plural: 'estate manifests', ownedBy: 'either' },
496
+ { match: { prefix: 'pulse.day:' }, class: `${APINF}TownPulse`, label: "day's pulse", plural: 'daily pulses', ownedBy: 'either', role: 'entity', properties: { day: `${APINF}pulseDay` } },
497
+ { match: { prefix: 'pulse.sample:' }, class: `${APINF}TownPulse`, label: 'pulse sample', plural: 'pulse samples', ownedBy: 'either', role: 'entity' },
498
+ { match: { prefix: 'estate.checklist:' }, class: `${APINF}StandingChecklist`, label: 'standing checklist', plural: 'standing checklists', ownedBy: 'either', role: 'entity' },
499
+ { match: { prefix: 'estate.manifest:' }, class: `${APINF}EstateManifest`, label: 'estate manifest', plural: 'estate manifests', ownedBy: 'either', role: 'entity' },
496
500
  // ── External MCP servers as connectors (spec 404) — the holder's own; the token is NOT in the record ──
497
501
  {
498
502
  match: { prefix: 'connector.mcp:' }, class: `${APCTX}McpConnector`,
499
- label: 'MCP connector', plural: 'MCP connectors', ownedBy: 'either',
503
+ label: 'MCP connector', plural: 'MCP connectors', ownedBy: 'either', role: 'entity',
500
504
  properties: {
501
505
  name: `${APCTX}connectorName`,
502
506
  url: `${APCTX}connectorUrl`,
@@ -508,7 +512,7 @@ export const VAULT_RECORD_BINDINGS = [
508
512
  // ── Conversation memory (spec 370 P7) — what the agent RESOLVED for the owner lately, in their vault ──
509
513
  {
510
514
  match: { exact: 'conversation.recent' }, class: `${APCTX}ConversationMemory`,
511
- label: 'recent conversation', plural: 'recent conversations', ownedBy: 'person',
515
+ label: 'recent conversation', plural: 'recent conversations', ownedBy: 'person', role: 'entity',
512
516
  properties: {
513
517
  'turns[].at': `${APCTX}recalledAt`,
514
518
  'turns[].parties[].agent': `${APCTX}recalledParty`,
@@ -518,7 +522,7 @@ export const VAULT_RECORD_BINDINGS = [
518
522
  // ── Learned memory (spec 358 W5) — what the owner TOLD the agent, in their own vault ────────────
519
523
  {
520
524
  match: { prefix: 'preference:' }, class: `${APCTX}LearnedPreference`,
521
- label: 'thing you told me', plural: 'things you told me', ownedBy: 'person',
525
+ label: 'thing you told me', plural: 'things you told me', ownedBy: 'person', role: 'entity',
522
526
  properties: {
523
527
  subject: `${APCTX}preferenceSubject`,
524
528
  trigger: `${APCTX}preferenceTrigger`,
@@ -528,7 +532,7 @@ export const VAULT_RECORD_BINDINGS = [
528
532
  // ── Confirmation memory (spec 385; bound here by spec 394) — which "David" the owner chose, per scope ──
529
533
  {
530
534
  match: { exact: 'confirmation.preferences' }, class: `${APCTX}ConfirmationMemory`,
531
- label: 'remembered choice', plural: 'remembered choices', ownedBy: 'person',
535
+ label: 'remembered choice', plural: 'remembered choices', ownedBy: 'person', role: 'entity',
532
536
  properties: {
533
537
  'entries[].agent': `${APCTX}confirmedParty`,
534
538
  'entries[].word': `${APCTX}confirmedWords`,
@@ -538,7 +542,7 @@ export const VAULT_RECORD_BINDINGS = [
538
542
  // ── Playbook memory — the agent's own counts on the subjects of one skill family ───────────────
539
543
  {
540
544
  match: { prefix: 'playbook.memory:' }, class: `${APCTX}PlaybookMemory`,
541
- label: 'playbook memory', plural: 'playbook memories', ownedBy: 'either',
545
+ label: 'playbook memory', plural: 'playbook memories', ownedBy: 'either', role: 'entity',
542
546
  properties: {
543
547
  family: `${APCTX}memoryFamily`,
544
548
  rounds: `${APCTX}memoryRounds`,
@@ -547,50 +551,50 @@ export const VAULT_RECORD_BINDINGS = [
547
551
  // ── Card-room study records — the person's own play, read by a named coach service under a grant ──
548
552
  {
549
553
  match: { exact: 'cardroom.hand' }, class: `${APCTX}CardRoomHandRecord`,
550
- label: 'hand record', plural: 'hand records', ownedBy: 'person',
554
+ label: 'hand record', plural: 'hand records', ownedBy: 'person', role: 'entity',
551
555
  properties: { hands: `${APCTX}handsRecorded` },
552
556
  },
553
- { match: { exact: 'cardroom.style' }, class: `${APCTX}CardRoomStyleRecord`, label: 'playing style', plural: 'playing styles', ownedBy: 'person' },
554
- { match: { exact: 'cardroom.read' }, class: `${APCTX}CardRoomPlayerRead`, label: 'player read', plural: 'player reads', ownedBy: 'person' },
557
+ { match: { exact: 'cardroom.style' }, class: `${APCTX}CardRoomStyleRecord`, label: 'playing style', plural: 'playing styles', ownedBy: 'person', role: 'entity' },
558
+ { match: { exact: 'cardroom.read' }, class: `${APCTX}CardRoomPlayerRead`, label: 'player read', plural: 'player reads', ownedBy: 'person', role: 'entity' },
555
559
  {
556
560
  match: { exact: 'cardroom.note' }, class: `${APCTX}CardRoomCoachNote`,
557
- label: 'coach note', plural: 'coach notes', ownedBy: 'person',
561
+ label: 'coach note', plural: 'coach notes', ownedBy: 'person', role: 'entity',
558
562
  properties: { 'entries[].by': `${APCTX}coachedBy` },
559
563
  },
560
- { match: { exact: 'cardroom.client' }, class: `${APCTX}CardRoomCoachClient`, label: 'coaching client', plural: 'coaching clients', ownedBy: 'either' },
561
- { match: { prefix: 'cardroom.hands:' }, class: `${APCTX}CardRoomHandRecord`, label: 'a day’s hands', plural: 'days of hands', ownedBy: 'person' },
562
- { match: { exact: 'cardroom.prefs' }, class: `${APCTX}CardRoomPreferences`, label: 'card-room preferences', plural: 'card-room preferences', ownedBy: 'person' },
564
+ { match: { exact: 'cardroom.client' }, class: `${APCTX}CardRoomCoachClient`, label: 'coaching client', plural: 'coaching clients', ownedBy: 'either', role: 'entity' },
565
+ { match: { prefix: 'cardroom.hands:' }, class: `${APCTX}CardRoomHandRecord`, label: 'a day’s hands', plural: 'days of hands', ownedBy: 'person', role: 'entity' },
566
+ { match: { exact: 'cardroom.prefs' }, class: `${APCTX}CardRoomPreferences`, label: 'card-room preferences', plural: 'card-room preferences', ownedBy: 'person', role: 'entity' },
563
567
  // Who the person is as a player — ONE record across games (cr:PlayerProfile in the card-room ontology).
564
- { match: { exact: 'cardroom.profile' }, class: `${APCTX}CardRoomPlayerProfile`, label: 'player profile', plural: 'player profiles', ownedBy: 'person' },
568
+ { match: { exact: 'cardroom.profile' }, class: `${APCTX}CardRoomPlayerProfile`, label: 'player profile', plural: 'player profiles', ownedBy: 'person', role: 'entity' },
565
569
  // A CLUB, kept by its own workspace agent (apctx:CardRoomClub…): the profile, the rule it meets by, and
566
570
  // the nights as they diverge from the rule. The roster is the organization's own membership records.
567
- { match: { exact: 'cardroom.club.profile' }, class: `${APCTX}CardRoomClub`, label: 'club', plural: 'clubs', ownedBy: 'organization' },
568
- { match: { exact: 'cardroom.club.schedule' }, class: `${APCTX}CardRoomClubSchedule`, label: 'club schedule', plural: 'club schedules', ownedBy: 'organization' },
569
- { match: { exact: 'cardroom.club.nights' }, class: `${APCTX}CardRoomClubNights`, label: 'club nights', plural: 'club nights', ownedBy: 'organization' },
571
+ { match: { exact: 'cardroom.club.profile' }, class: `${APCTX}CardRoomClub`, label: 'club', plural: 'clubs', ownedBy: 'organization', role: 'entity' },
572
+ { match: { exact: 'cardroom.club.schedule' }, class: `${APCTX}CardRoomClubSchedule`, label: 'club schedule', plural: 'club schedules', ownedBy: 'organization', role: 'entity' },
573
+ { match: { exact: 'cardroom.club.nights' }, class: `${APCTX}CardRoomClubNights`, label: 'club nights', plural: 'club nights', ownedBy: 'organization', role: 'entity' },
570
574
  // A MISSION, kept by its own organization (apctx:CardRoomMission…): the presence a card room's map shows,
571
575
  // the steward's signed covenant, and the confidential contact — written in the registration ceremony.
572
- { match: { exact: 'cardroom.mission.presence' }, class: `${APCTX}CardRoomMission`, label: 'mission presence', plural: 'mission presences', ownedBy: 'organization' },
573
- { match: { exact: 'cardroom.mission.covenant' }, class: `${APCTX}CardRoomMissionCovenant`, label: 'mission covenant', plural: 'mission covenants', ownedBy: 'organization' },
574
- { match: { exact: 'cardroom.mission.contact' }, class: `${APCTX}CardRoomMissionContact`, label: 'mission contact', plural: 'mission contacts', ownedBy: 'organization' },
576
+ { match: { exact: 'cardroom.mission.presence' }, class: `${APCTX}CardRoomMission`, label: 'mission presence', plural: 'mission presences', ownedBy: 'organization', role: 'entity' },
577
+ { match: { exact: 'cardroom.mission.covenant' }, class: `${APCTX}CardRoomMissionCovenant`, label: 'mission covenant', plural: 'mission covenants', ownedBy: 'organization', role: 'entity' },
578
+ { match: { exact: 'cardroom.mission.contact' }, class: `${APCTX}CardRoomMissionContact`, label: 'mission contact', plural: 'mission contacts', ownedBy: 'organization', role: 'entity' },
575
579
  // ONE CABINET PER GAME: hold'em's study records are the bare names above; every other game's carry the
576
580
  // family — canasta's here, the same classes, a different coach's grant.
577
581
  {
578
582
  match: { exact: 'cardroom.canasta.hand' }, class: `${APCTX}CardRoomHandRecord`,
579
- label: 'canasta round record', plural: 'canasta round records', ownedBy: 'person',
583
+ label: 'canasta round record', plural: 'canasta round records', ownedBy: 'person', role: 'entity',
580
584
  properties: { hands: `${APCTX}handsRecorded` },
581
585
  },
582
- { match: { exact: 'cardroom.canasta.style' }, class: `${APCTX}CardRoomStyleRecord`, label: 'canasta playing style', plural: 'canasta playing styles', ownedBy: 'person' },
583
- { match: { exact: 'cardroom.canasta.read' }, class: `${APCTX}CardRoomPlayerRead`, label: 'canasta player read', plural: 'canasta player reads', ownedBy: 'person' },
586
+ { match: { exact: 'cardroom.canasta.style' }, class: `${APCTX}CardRoomStyleRecord`, label: 'canasta playing style', plural: 'canasta playing styles', ownedBy: 'person', role: 'entity' },
587
+ { match: { exact: 'cardroom.canasta.read' }, class: `${APCTX}CardRoomPlayerRead`, label: 'canasta player read', plural: 'canasta player reads', ownedBy: 'person', role: 'entity' },
584
588
  {
585
589
  match: { exact: 'cardroom.canasta.note' }, class: `${APCTX}CardRoomCoachNote`,
586
- label: 'canasta coach note', plural: 'canasta coach notes', ownedBy: 'person',
590
+ label: 'canasta coach note', plural: 'canasta coach notes', ownedBy: 'person', role: 'entity',
587
591
  properties: { 'entries[].by': `${APCTX}coachedBy` },
588
592
  },
589
- { match: { prefix: 'cardroom.canasta.hands:' }, class: `${APCTX}CardRoomHandRecord`, label: 'a day’s canasta rounds', plural: 'days of canasta rounds', ownedBy: 'person' },
593
+ { match: { prefix: 'cardroom.canasta.hands:' }, class: `${APCTX}CardRoomHandRecord`, label: 'a day’s canasta rounds', plural: 'days of canasta rounds', ownedBy: 'person', role: 'entity' },
590
594
  // ── Standing instructions (spec 394) — the owner's declared defaults, per room ──────────────────
591
595
  {
592
596
  match: { exact: 'standing.instructions' }, class: `${APCTX}StandingInstruction`,
593
- label: 'standing instruction', plural: 'standing instructions', ownedBy: 'person',
597
+ label: 'standing instruction', plural: 'standing instructions', ownedBy: 'person', role: 'entity',
594
598
  properties: {
595
599
  'entries[].capability': `${APCTX}instructionCapability`,
596
600
  'entries[].arg': `${APCTX}instructionArgument`,
@@ -602,7 +606,7 @@ export const VAULT_RECORD_BINDINGS = [
602
606
  // ── Declared routines (spec 402 W3 · 323 W6) — the owner's routines as a record that travels ─────
603
607
  {
604
608
  match: { exact: 'routines.data' }, class: `${APCTX}DeclaredRoutine`,
605
- label: 'declared routine', plural: 'declared routines', ownedBy: 'person',
609
+ label: 'declared routine', plural: 'declared routines', ownedBy: 'person', role: 'entity',
606
610
  properties: {
607
611
  'entries[].ask': `${APCTX}routineAsk`,
608
612
  'entries[].every': `${APCTX}routineEvery`,
@@ -613,13 +617,13 @@ export const VAULT_RECORD_BINDINGS = [
613
617
  // ── The person's preferences (spec 403 W2/W4) — nudges and how to answer ─────────────────────────
614
618
  {
615
619
  match: { exact: 'person.preferences' }, class: `${APCTX}PersonPreferences`,
616
- label: 'preferences', plural: 'preferences', ownedBy: 'person',
620
+ label: 'preferences', plural: 'preferences', ownedBy: 'person', role: 'entity',
617
621
  properties: { 'notify.email': `${APCTX}nudgeByEmail`, 'answer.style': `${APCTX}answerStyle`, 'answer.language': `${APCTX}answerLanguage` },
618
622
  },
619
623
  // ── Remembered facts (spec 402 W1) — what the owner's agent knows about the owner ────────────────
620
624
  {
621
625
  match: { exact: 'memory.facts' }, class: `${APCTX}RememberedFact`,
622
- label: 'remembered fact', plural: 'remembered facts', ownedBy: 'person',
626
+ label: 'remembered fact', plural: 'remembered facts', ownedBy: 'person', role: 'entity',
623
627
  properties: {
624
628
  'entries[].fact': `${APCTX}factWords`,
625
629
  'entries[].source': `${APCTX}factSource`,
@@ -633,8 +637,8 @@ export const VAULT_RECORD_BINDINGS = [
633
637
  // against. A rebuild is fine; this would be a bereavement. The Durable Object stays as the serving
634
638
  // projection, rebuilt from these records and never their only copy.
635
639
  {
636
- match: { prefix: 'federation.projection-submission:' }, class: `${APEST}ProjectionSubmission`,
637
- label: 'projection submission', plural: 'projection submissions', ownedBy: 'either',
640
+ match: { prefix: 'federation.projection-submission:' }, class: `${APEST}HeldProjectionSubmission`, // ⊑ apest:ProjectionSubmission, ap:HeldSecret (ONT-2)
641
+ label: 'projection submission', plural: 'projection submissions', ownedBy: 'either', role: 'secret', // carries the leaf's BLIND
638
642
  properties: {
639
643
  set: `${APEST}projectionSet`,
640
644
  digest: `${APEST}vouchedDigest`,
@@ -655,9 +659,11 @@ export const VAULT_RECORD_BINDINGS = [
655
659
  // holds only its digest; lose the device key and no presentation can ever be made; lose the secret and every
656
660
  // pairwise account at every verifier is unreachable. Bereavements, all three — vault records, never a cache.
657
661
  // None of these is read by any gate: the mandate is judged per signature by the presentation release (ADR-0041).
662
+ // The credential, the device key and the holder secret are `secret` (REM-2): held, used by the release under its
663
+ // own grant, and never opened by a question. The mandate, the issuer's records and the door's evidence are things.
658
664
  {
659
- match: { prefix: 'credential.anonymous:' }, class: `${APPC}AnonymousCredential`,
660
- label: 'anonymous credential', plural: 'anonymous credentials', ownedBy: 'person',
665
+ match: { prefix: 'credential.anonymous:' }, class: `${APPC}HeldAnonymousCredential`, // ⊑ appc:AnonymousCredential, ap:HeldSecret (ONT-2)
666
+ label: 'anonymous credential', plural: 'anonymous credentials', ownedBy: 'person', role: 'secret', // the credential itself, claim values included
661
667
  properties: {
662
668
  issuerKeyId: `${APPC}facetKeyId`,
663
669
  digest: `${APPC}credentialDigest`,
@@ -667,23 +673,24 @@ export const VAULT_RECORD_BINDINGS = [
667
673
  },
668
674
  },
669
675
  {
670
- match: { prefix: 'credential.device-key:' }, class: `${APPC}DeviceKey`,
671
- label: 'device key', plural: 'device keys', ownedBy: 'person',
676
+ match: { prefix: 'credential.device-key:' }, class: `${APPC}DeviceKeyMaterial`, // ⊑ appc:DeviceKey, ap:HeldSecret (ONT-2)
677
+ label: 'device key', plural: 'device keys', ownedBy: 'person', role: 'secret', // key material in a deployment that predates the managed key
672
678
  properties: { thumbprint: `${APPC}deviceKeyThumbprint`, createdAt: `${PROV}generatedAtTime` },
673
679
  },
674
- { match: { prefix: 'credential.holder-secret:' }, class: `${APPC}PairwiseAccount`, label: 'holder secret (pairwise accounts derive from it)', plural: 'holder secrets', ownedBy: 'person' },
680
+ // ONT-2: the SECRET (appc:HolderSecret ⊑ ap:HeldSecret), never the PairwiseAccount derived from it — the classes are disjoint.
681
+ { match: { prefix: 'credential.holder-secret:' }, class: `${APPC}HolderSecret`, label: 'holder secret (pairwise accounts derive from it)', plural: 'holder secrets', ownedBy: 'person', role: 'secret' },
675
682
  // Her standing `credential.present` wire — a delegation, kept under its own family because what it bounds (venues,
676
683
  // programs, facets) is this module's vocabulary. The release judges it per signature (ADR-0041); no gate reads it.
677
684
  {
678
685
  match: { prefix: 'credential.presentation-mandate:' }, class: `${APPC}PresentationMandate`,
679
- label: 'presentation mandate', plural: 'presentation mandates', ownedBy: 'person',
686
+ label: 'presentation mandate', plural: 'presentation mandates', ownedBy: 'person', role: 'entity',
680
687
  properties: { audiences: `${APPC}mandateAudience`, predicateDigests: `${APPC}mandatePredicateDigest`, issuerKeyIds: `${APPC}mandateIssuerKeyId`, maxPresentations: `${APPC}maxPresentations`, issuedAt: `${PROV}generatedAtTime` },
681
688
  },
682
689
  // THE ISSUER'S records: what the ORGANIZATION issued (spec 444) — one record per issuance, so it can revoke what it
683
690
  // issued; the member it went to, never the claim values (those are the holder's).
684
691
  {
685
692
  match: { prefix: 'credential.issued:' }, class: `${APPC}Issuance`,
686
- label: 'issued credential', plural: 'issued credentials', ownedBy: 'organization',
693
+ label: 'issued credential', plural: 'issued credentials', ownedBy: 'organization', role: 'entity',
687
694
  properties: {
688
695
  digest: `${APPC}issuedDigest`,
689
696
  issuerKeyId: `${APPC}facetKeyId`,
@@ -698,7 +705,7 @@ export const VAULT_RECORD_BINDINGS = [
698
705
  // to revoke) — the live set's leaves are `federation.projection-submission:` rows in the `live-credential` set.
699
706
  {
700
707
  match: { prefix: 'credential.issuer-facet:' }, class: `${APPC}IssuerKeyFacet`,
701
- label: 'issuer key facet', plural: 'issuer key facets', ownedBy: 'organization',
708
+ label: 'issuer key facet', plural: 'issuer key facets', ownedBy: 'organization', role: 'entity',
702
709
  properties: {
703
710
  keyId: `${APPC}facetKeyId`,
704
711
  thumbprint: `${APPC}facetPublicKeyThumbprint`,
@@ -711,7 +718,7 @@ export const VAULT_RECORD_BINDINGS = [
711
718
  // THE DOOR'S record of a predicate held — beside the admission decision; the digests, never the bundle.
712
719
  {
713
720
  match: { prefix: 'door.credential:' }, class: `${APPC}PredicateAdmissionEvidence`,
714
- label: 'predicate admission', plural: 'predicate admissions', ownedBy: 'either',
721
+ label: 'predicate admission', plural: 'predicate admissions', ownedBy: 'either', role: 'entity',
715
722
  properties: {
716
723
  issuerKeyId: `${APPC}facetKeyId`,
717
724
  predicateDigest: `${APPC}evidencePredicateDigest`,
@@ -730,7 +737,7 @@ export const VAULT_RECORD_BINDINGS = [
730
737
  // verifier (ADR-0041): what the agent may DO at a door is a mandate, judged per step.
731
738
  {
732
739
  match: { prefix: 'identity.client-key-binding:' }, class: `${AP}ClientKeyBinding`,
733
- label: 'client key binding', plural: 'client key bindings', ownedBy: 'either',
740
+ label: 'client key binding', plural: 'client key bindings', ownedBy: 'either', role: 'entity',
734
741
  properties: {
735
742
  clientId: `${AP}clientId`,
736
743
  jwkThumbprint: `${AP}jwkThumbprint`,
@@ -741,10 +748,11 @@ export const VAULT_RECORD_BINDINGS = [
741
748
  },
742
749
  },
743
750
  // The secret her pairwise subjects derive from — one record, per person; a rotation is a new `sub` everywhere.
744
- { match: { exact: 'identity.pairwise-secret' }, class: `${AP}PairwiseSubject`, label: 'pairwise secret (company subjects derive from it)', plural: 'pairwise secrets', ownedBy: 'person' },
751
+ // ONT-2: ap:PairwiseSecret ⊑ ap:HeldSecret, disjoint from the ap:PairwiseSubject derived from it.
752
+ { match: { exact: 'identity.pairwise-secret' }, class: `${AP}PairwiseSecret`, label: 'pairwise secret (company subjects derive from it)', plural: 'pairwise secrets', ownedBy: 'person', role: 'secret' },
745
753
  {
746
754
  match: { prefix: 'identity.external-account-link:' }, class: `${AP}ExternalAccountLink`,
747
- label: 'account at a company', plural: 'accounts at companies', ownedBy: 'person',
755
+ label: 'account at a company', plural: 'accounts at companies', ownedBy: 'person', role: 'entity',
748
756
  properties: {
749
757
  issuer: `${AP}pairwiseIssuer`,
750
758
  pairwiseSubjectDigest: `${AP}pairwiseSubjectDigest`,
@@ -778,16 +786,35 @@ export function askableRecordKinds() {
778
786
  const seen = new Set();
779
787
  const out = [];
780
788
  for (const b of VAULT_RECORD_BINDINGS) {
781
- // An index is not a thing to ask about — see `VaultRecordRole`.
782
- if ((b.role ?? 'entity') !== 'entity' || seen.has(b.class))
789
+ // An index is not a thing to ask about, and a secret is never told — see `VaultRecordRole`.
790
+ if (b.role !== 'entity' || seen.has(b.class))
783
791
  continue;
784
792
  seen.add(b.class);
785
793
  out.push({ label: b.label, plural: b.plural, class: b.class });
786
794
  }
787
795
  return out;
788
796
  }
789
- /** Every record type bound to this class — what a query over a kind must actually read. */
797
+ /** Every record type bound to this class THAT A QUESTION MAY READ — what a query over a kind must actually read.
798
+ * A class is often bound twice (the thing and its index): only the `entity` rows. A secret has its own class
799
+ * under `ap:HeldSecret` (ONT-2), so it never shares one with an entity. */
790
800
  export function recordTypesForClass(classIri) {
791
- return VAULT_RECORD_BINDINGS.filter((b) => b.class === classIri);
801
+ return VAULT_RECORD_BINDINGS.filter((b) => b.class === classIri && b.role === 'entity');
802
+ }
803
+ /** Is this record key one that is held and never told (`role: 'secret'`)? The check every reader that hands a
804
+ * record's content — or its key — to a model makes at the point of use (REM-2). */
805
+ export function isSecretRecordType(recordType) {
806
+ return bindingForRecordType(recordType)?.role === 'secret';
807
+ }
808
+ /** Rows that carry no decision about what they are FOR — none, in a table that compiles. For a gate
809
+ * (`check:ontology-bindings`) and the unit test: a row built outside the compiler's sight (a cast, a JSON import,
810
+ * a JS caller) must not reach the table as askable-by-default. */
811
+ export function bindingsWithoutRole(rows = VAULT_RECORD_BINDINGS) {
812
+ return rows
813
+ .filter((b) => !VAULT_RECORD_ROLES.includes(b.role))
814
+ .map((b) => b.match?.exact ?? b.match?.prefix ?? '(no key)');
815
+ }
816
+ /** The record kinds classified secret — for a gate, a doc, or a grant builder that must leave them out. */
817
+ export function secretRecordKinds() {
818
+ return VAULT_RECORD_BINDINGS.filter((b) => b.role === 'secret');
792
819
  }
793
820
  //# sourceMappingURL=vault-records.js.map