@agenticprimitives/ontology 1.0.0-alpha.17 → 1.0.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,6 +21,10 @@ src/index.ts typed IRI constants + artifact paths
21
21
 
22
22
  T-box = terminology, C-box = constraints + controlled vocabularies, A-box = instances.
23
23
 
24
+ UML class-diagram documentation of the T-box — inheritance + relationships per domain area —
25
+ lives in [`docs/tbox/`](docs/tbox/README.md). For the plain-language version — the principles
26
+ the vocabulary protects and why — start with [`docs/story.md`](docs/story.md).
27
+
24
28
  ## Usage
25
29
 
26
30
  ```ts
@@ -0,0 +1,130 @@
1
+ # C-box — SHACL over the public agent PROFILE facet and the projected TRUST FABRIC (spec 331).
2
+ #
3
+ # Validates the A-box the discovery indexer writes: approf:* profile properties (including the
4
+ # three facets registered by governor tx 0x53acec54…) and the aptrust:TrustGraphEdge /
5
+ # apatt:Attestation nodes whose vocabulary tbox/trust.ttl now declares.
6
+ #
7
+ # Enforcement posture (spec 225 §11 / PD-19): these shapes are DECLARED here and enforced by the
8
+ # indexer's TS validators at projection time and by a SHACL engine over graph snapshots. They are
9
+ # never on a hot path and never an authorization input.
10
+ #
11
+ # WHAT A VIOLATION MEANS: a conformance failure here means the WRITER published a malformed facet
12
+ # — it does not mean the agent is untrustworthy, and it must never silently drop the agent from a
13
+ # result set. Fail LOUD to the indexer's audit, fail OPEN to fewer signals for the matcher
14
+ # (ADR-0013 / spec 329 §4: degrade to fewer signals, never to fewer candidates).
15
+
16
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
17
+ @prefix approf: <https://agenticprimitives.dev/ns/profile#> .
18
+ @prefix aptrust: <https://agenticprimitives.dev/ns/trust#> .
19
+ @prefix apatt: <https://agenticprimitives.dev/ns/attestation#> .
20
+ @prefix ap: <https://agenticprimitives.dev/ns/core#> .
21
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
22
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
23
+
24
+ # ═══ The public profile facet ═══════════════════════════════════════════════
25
+
26
+ approf:AgentProfileShape a sh:NodeShape ;
27
+ sh:targetClass approf:AgentProfile ;
28
+ rdfs:label "AgentProfileShape" ;
29
+ rdfs:comment "Every property is OPTIONAL. A public profile is opt-in in whole and in part (facet-registries invariant 3/4): an agent that publishes nothing is conformant, and absence is never a defect." ;
30
+
31
+ sh:property [
32
+ sh:path approf:displayName ; sh:datatype xsd:string ; sh:maxCount 1 ; sh:maxLength 128 ;
33
+ ] ;
34
+ sh:property [
35
+ sh:path approf:description ; sh:datatype xsd:string ; sh:maxCount 1 ; sh:maxLength 2048 ;
36
+ sh:description "SA-keyed. The node-keyed name-record description is apnam:description and MUST NOT be emitted under this IRI (facet-registries G8)." ;
37
+ ] ;
38
+ sh:property [
39
+ sh:path approf:skills ; sh:datatype xsd:string ; sh:maxCount 1 ; sh:maxLength 2048 ;
40
+ sh:description "Comma-joined declared capability projections. Spec 331 migrates the value space to canonical catalog ids; both are legal during the dual-publish window." ;
41
+ ] ;
42
+
43
+ # ── approf:declaresCapabilityId — one triple per parsed id (spec 331) ────
44
+ sh:property [
45
+ sh:path approf:declaresCapabilityId ;
46
+ sh:datatype xsd:string ;
47
+ sh:pattern "^[a-z][a-z0-9]*:[a-z0-9]+(-[a-z0-9]+)*$" ;
48
+ sh:message "A capability id is a lowercase CURIE: '<prefix>:<kebab-slug>', e.g. 'adv:succession-plan-design'. keccak256 of this exact string is the on-chain skillId, so spelling is identity — it is never normalized, corrected, or case-folded at read time." ;
49
+ ] ;
50
+
51
+ # ── G2: languages, BCP-47 ───────────────────────────────────────────────
52
+ sh:property [
53
+ sh:path approf:languages ; sh:datatype xsd:string ; sh:maxCount 1 ; sh:maxLength 256 ;
54
+ sh:pattern "^[a-z]{2,3}(-[a-z0-9]{2,8})*(,[a-z]{2,3}(-[a-z0-9]{2,8})*)*$" ;
55
+ sh:message "atl:languages must be comma-separated, lowercase, well-formed BCP-47 tags with no spaces: 'es,en,pt-br'. See cbox/profile-facet-vocabulary.ttl for the subtag-prefix matching rule — substring matching is forbidden." ;
56
+ ] ;
57
+
58
+ # ── G3: regions, GeoFeatureRegistry-drawn ───────────────────────────────
59
+ sh:property [
60
+ sh:path approf:regions ; sh:datatype xsd:string ; sh:maxCount 1 ; sh:maxLength 256 ;
61
+ sh:pattern "^[A-Z0-9]{2,8}(-[A-Z0-9]{1,3})?(,[A-Z0-9]{2,8}(-[A-Z0-9]{1,3})?)*$" ;
62
+ sh:message "atl:regions must be comma-separated UPPERCASE codes with no spaces: 'EU,ES,ES-CT'. Each code must resolve to an ISO 3166 entry or a registered GeoFeatureRegistry feature; a code that resolves to neither is a conformance failure, NOT a free-text fallback (spec 251 forward-compatibility)." ;
63
+ ] ;
64
+
65
+ # ── G4: focus areas, open but shaped ────────────────────────────────────
66
+ sh:property [
67
+ sh:path approf:focusAreas ; sh:datatype xsd:string ; sh:maxCount 1 ; sh:maxLength 512 ;
68
+ sh:pattern "^[a-z0-9]+(-[a-z0-9]+)*(,[a-z0-9]+(-[a-z0-9]+)*)*$" ;
69
+ sh:message "atl:focusAreas must be comma-separated lowercase-hyphenated subject labels. A focus area is a subject domain (apctx:KnowledgeDomain), never a declared capability, and never a hard filter." ;
70
+ ] .
71
+
72
+ # ── The encoding this migration removes, stated as a shape ──────────────────
73
+
74
+ approf:NoEncodedFacetInSkillsShape a sh:NodeShape ;
75
+ sh:targetClass approf:AgentProfile ;
76
+ rdfs:label "NoEncodedFacetInSkillsShape" ;
77
+ rdfs:comment "Spec 331 §hack-1. Before the three facet predicates existed, languages, regions, jurisdictions and focus areas were stuffed into atl:skills as prefixed tokens (lang-es, region-eu, jurisdiction-spain, focus-*). The prefixes were deliberate and honest — they kept the encoding VISIBLE rather than silently conflating a language with a capability. Now that real predicates exist, the encoding is debt: a token matching these prefixes is a facet that belongs in atl:languages / atl:regions / atl:focusAreas. SEVERITY IS sh:Warning, not sh:Violation, and stays that way until the migration's dual-publish window closes — a live agent mid-migration is correct, not broken." ;
78
+ sh:property [
79
+ sh:path approf:skills ;
80
+ sh:severity sh:Warning ;
81
+ sh:not [ sh:pattern "(^|,\\s*)(lang|region|jurisdiction|focus)-" ] ;
82
+ sh:message "atl:skills carries an ENCODED facet token (lang-*/region-*/jurisdiction-*/focus-*). Publish it as atl:languages, atl:regions or atl:focusAreas instead — a subject domain, a place and a language are not declared capabilities (ADR-0051)." ;
83
+ ] .
84
+
85
+ # ═══ The projected trust fabric ═════════════════════════════════════════════
86
+
87
+ aptrust:TrustGraphEdgeShape a sh:NodeShape ;
88
+ sh:targetClass aptrust:TrustGraphEdge ;
89
+ rdfs:label "TrustGraphEdgeShape" ;
90
+ rdfs:comment "A projected AgentRelationship edge. Subject and object are ABSOLUTE and required: one on-chain record is shared by both endpoints under one derived IRI, so the node must state the edge without reference to who is reading it. The endpoint-relative views (ap:relatedAgent, ap:edgeDirection) hang on the agent and are validated by AgentTrustFabricShape below." ;
91
+ sh:property [ sh:path ap:edgeId ; sh:datatype xsd:string ; sh:minCount 1 ; sh:maxCount 1 ;
92
+ sh:pattern "^0x[0-9a-f]{64}$" ;
93
+ sh:message "edgeId is the deterministic on-chain computeEdgeId(subject, object, type) as lowercase 0x-hex." ] ;
94
+ sh:property [ sh:path ap:edgeSubject ; sh:minCount 1 ; sh:maxCount 1 ;
95
+ sh:message "Every edge has exactly one proposing subject — proposeEdge requires msg.sender == subject." ] ;
96
+ sh:property [ sh:path ap:edgeObject ; sh:minCount 1 ; sh:maxCount 1 ] ;
97
+ sh:property [ sh:path ap:relationshipTypeId ; sh:datatype xsd:string ; sh:minCount 1 ; sh:maxCount 1 ;
98
+ sh:message "The raw bytes32 type id is ALWAYS emitted, including for governor-registered types whose label does not resolve (ADR-0013: no silent gaps)." ] ;
99
+ sh:property [ sh:path ap:relationshipType ; sh:datatype xsd:string ; sh:maxCount 1 ;
100
+ sh:description "The resolved well-known label. Optional by design — an unresolved type is queryable via relationshipTypeId." ] ;
101
+ sh:property [ sh:path ap:edgeStatus ; sh:datatype xsd:string ; sh:minCount 1 ; sh:maxCount 1 ;
102
+ sh:in ( "PROPOSED" "CONFIRMED" "ACTIVE" "REVOKED" ) ;
103
+ sh:message "Only ACTIVE edges may inform trust scoring: a PROPOSED edge is one party talking to itself, and REVOKED is terminal." ] ;
104
+ sh:property [ sh:path ap:edgeSubject ;
105
+ sh:disjoint ap:edgeObject ;
106
+ sh:message "An agent cannot relate to itself — the contract rejects subject == object, and a self-edge in the graph is a projection defect." ] .
107
+
108
+ apatt:AttestationShape a sh:NodeShape ;
109
+ sh:targetClass apatt:Attestation ;
110
+ rdfs:label "AttestationShape" ;
111
+ rdfs:comment "A projected AttestationRegistry row. The chain holds a COMMITMENT (credentialHash); the body is off-chain and never reaches the knowledge graph (ADR-0040). Discovery may therefore learn THAT an attestation of type X from issuer Y exists — never what it says." ;
112
+ sh:property [ sh:path apatt:uid ; sh:datatype xsd:string ; sh:minCount 1 ; sh:maxCount 1 ;
113
+ sh:pattern "^0x[0-9a-f]{64}$" ] ;
114
+ sh:property [ sh:path apatt:credentialType ; sh:datatype xsd:string ; sh:maxCount 1 ] ;
115
+ sh:property [ sh:path ap:attestationIssuer ; sh:minCount 1 ; sh:maxCount 1 ;
116
+ sh:description "The SIGNER, recomputed from the EIP-712 digest on chain — never msg.sender, which the registry leaves unconstrained. This is what lets an endorsement be relayed by a third party while the authority stays with the issuer." ] ;
117
+ sh:property [ sh:path ap:attestationValid ; sh:datatype xsd:boolean ; sh:minCount 1 ; sh:maxCount 1 ;
118
+ sh:description "isValid(uid) at index time. NOTE AR-06: there is no issuer-revoke entrypoint, so issuer-side revocation (offchainCredentialStatusList) is NOT reflected here. A consumer treating this as a full revocation check is wrong." ] ;
119
+ sh:property [ sh:path apatt:credentialHash ; sh:maxCount 1 ;
120
+ sh:description "A commitment. Never dereferenced by discovery, never a searchable field." ] .
121
+
122
+ ap:AgentTrustFabricShape a sh:NodeShape ;
123
+ sh:targetClass ap:Agent ;
124
+ rdfs:label "AgentTrustFabricShape" ;
125
+ rdfs:comment "The endpoint-RELATIVE denormalizations and the counts trustScore reads." ;
126
+ sh:property [ sh:path ap:edgeDirection ; sh:datatype xsd:string ; sh:in ( "subject" "object" ) ] ;
127
+ sh:property [ sh:path ap:edgeCount ; sh:datatype xsd:integer ; sh:maxCount 1 ; sh:minInclusive 0 ] ;
128
+ sh:property [ sh:path ap:activeEdgeCount ; sh:datatype xsd:integer ; sh:maxCount 1 ; sh:minInclusive 0 ] ;
129
+ sh:property [ sh:path ap:attestationCount ; sh:datatype xsd:integer ; sh:maxCount 1 ; sh:minInclusive 0 ] ;
130
+ sh:property [ sh:path ap:validAttestationCount ; sh:datatype xsd:integer ; sh:maxCount 1 ; sh:minInclusive 0 ] .
@@ -0,0 +1,284 @@
1
+ # C-box — SHACL for capability CATALOGS and REALIZATION CONTRACTS
2
+ # (spec 330 W0 §7, unparked by spec 331; capability-architecture.md §2 + §5).
3
+ #
4
+ # Three groups:
5
+ # 1. What a well-formed capability + definition + catalog looks like.
6
+ # 2. The ANTI-PATTERN AXIOMS from architecture §2, expressed as shapes rather than prose.
7
+ # 3. The realization-contract META-SHAPE, plus the ONE contract this substrate can actually
8
+ # enforce today (spec 329's routed member consultation).
9
+ #
10
+ # On (3), the governing discipline: an unenforceable contract is worse than an absent one.
11
+ # A capability whose realizations this substrate cannot observe declares
12
+ # `aps:contractStatus "deferred"` with a rationale naming the missing evidence. The
13
+ # DeferredContractShape below makes that declaration MANDATORY — you may omit a contract, but
14
+ # you may not omit saying why.
15
+
16
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
17
+ @prefix aps: <https://agenticprimitives.dev/ns/skill#> .
18
+ @prefix apctx: <https://agenticprimitives.dev/ns/context#> .
19
+ @prefix apguide: <https://agenticprimitives.dev/ns/guidance#> .
20
+ @prefix apexec: <https://agenticprimitives.dev/ns/execution#> .
21
+ @prefix aprole: <https://agenticprimitives.dev/ns/role#> .
22
+ @prefix apmsg: <https://agenticprimitives.dev/ns/messaging#> .
23
+ @prefix apint: <https://agenticprimitives.dev/ns/intent#> .
24
+ @prefix ap: <https://agenticprimitives.dev/ns/core#> .
25
+ @prefix prov: <http://www.w3.org/ns/prov#> .
26
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
27
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
28
+
29
+ # ═══ 1. Well-formedness ═════════════════════════════════════════════════════
30
+
31
+ aps:CapabilityShape a sh:NodeShape ;
32
+ sh:targetClass aps:Capability ;
33
+ rdfs:label "CapabilityShape" ;
34
+ sh:property [ sh:path aps:capabilityId ; sh:datatype xsd:string ; sh:minCount 1 ; sh:maxCount 1 ;
35
+ sh:pattern "^[a-z][a-z0-9]*:[a-z0-9]+(-[a-z0-9]+)*$" ;
36
+ sh:message "A capability id is a lowercase CURIE '<prefix>:<kebab-slug>'. keccak256 of this exact string is the on-chain skillId, so the spelling IS the identity: a rename is a new capability plus a skos:exactMatch, never an edit." ] ;
37
+ sh:property [ sh:path apctx:ownedByContext ; sh:minCount 1 ; sh:maxCount 1 ;
38
+ sh:message "Exactly ONE accountable owning bounded context (architecture invariant 2). A capability may PARTICIPATE in many contexts via apctx:classifiedBy — but 'everyone owns it' means nobody versions it." ] ;
39
+ sh:property [ sh:path apctx:levelInMap ; sh:maxCount 0 ;
40
+ sh:message "levelInMap belongs on an apctx:CapabilityMapEntry, never on a capability. A map is a VIEW projected from the graph; baking a presentation level into the capability is how a reporting hierarchy becomes an ontology (architecture §3)." ] ;
41
+ sh:property [ sh:path aps:specializesCapability ;
42
+ sh:disjoint aps:hasComponentCapability ;
43
+ sh:message "A capability cannot both BE a narrower form of X and HAVE X as a part. If both feel true, the relation is probably requiresCapability." ] .
44
+
45
+ aps:CapabilityDefinitionShape a sh:NodeShape ;
46
+ sh:targetClass aps:CapabilityDefinition ;
47
+ rdfs:label "CapabilityDefinitionShape" ;
48
+ sh:property [ sh:path aps:definesCapability ; sh:minCount 1 ; sh:maxCount 1 ;
49
+ sh:message "A definition defines exactly one capability. Many definition VERSIONS may define the same identity — that is the point of separating them." ] ;
50
+ sh:property [ sh:path aps:outcomeStatement ; sh:datatype xsd:string ; sh:minCount 1 ; sh:maxCount 1 ;
51
+ sh:minLength 20 ; sh:maxLength 400 ;
52
+ sh:message "Required, and required to be a sentence. An outcome statement that can only be phrased as an activity ('advises on X') is the tell that the term is a service or a subject domain, not a capability." ] ;
53
+ sh:property [ sh:path aps:contractStatus ; sh:datatype xsd:string ; sh:minCount 1 ; sh:maxCount 1 ;
54
+ sh:in ( "enforced" "deferred" ) ;
55
+ sh:message "Every definition states whether its realization contract is enforced or deferred. Silence is not an option: it would let a catalog imply verification it does not perform." ] .
56
+
57
+ aps:DeferredContractShape a sh:NodeShape ;
58
+ sh:targetClass aps:CapabilityDefinition ;
59
+ rdfs:label "DeferredContractShape" ;
60
+ rdfs:comment "Deferral is first-class and honest — but it must be ARGUED. This shape is the whole reason the catalog can ship with two enforced contracts and forty-three deferred ones without that being a cop-out." ;
61
+ sh:sparql [
62
+ sh:message "aps:contractStatus 'deferred' requires aps:deferredContractRationale naming the evidence that would make a contract enforceable; 'enforced' requires an aps:hasRealizationContract." ;
63
+ sh:prefixes aps: ;
64
+ sh:select """
65
+ SELECT $this WHERE {
66
+ { $this <https://agenticprimitives.dev/ns/skill#contractStatus> "deferred" .
67
+ FILTER NOT EXISTS { $this <https://agenticprimitives.dev/ns/skill#deferredContractRationale> ?r } }
68
+ UNION
69
+ { $this <https://agenticprimitives.dev/ns/skill#contractStatus> "enforced" .
70
+ FILTER NOT EXISTS { $this <https://agenticprimitives.dev/ns/skill#hasRealizationContract> ?c } }
71
+ }
72
+ """ ;
73
+ ] .
74
+
75
+ aps:CapabilityCatalogShape a sh:NodeShape ;
76
+ sh:targetClass aps:CapabilityCatalog ;
77
+ sh:property [ sh:path aps:catalogSteward ; sh:minCount 1 ; sh:maxCount 1 ;
78
+ sh:message "One steward per catalog — the account SkillDefinitionRegistry will require as msg.sender to publish or version any definition in it." ] .
79
+
80
+ # ═══ 2. The anti-pattern axioms as shapes (architecture §2) ═════════════════
81
+
82
+ aps:CapabilityProtocolProjectionShape a sh:NodeShape ;
83
+ sh:targetClass aps:CapabilityProtocolProjection ;
84
+ rdfs:label "CapabilityProtocolProjectionShape" ;
85
+ rdfs:comment "AXIOM 1 + INVARIANT 6. A card AgentSkill / atl:skills token / offering declares exactly ONE primary capability and NEVER identifies an internal plan. The forbidden shape is `implementedBy exactly-1` between a projection and a SKILL.md: a descriptor is fulfilled through a realization whose execution plan may use zero, one, or several playbooks, plus tools, delegated agents and human steps." ;
86
+ sh:property [ sh:path aps:declaresCapability ; sh:minCount 1 ; sh:maxCount 1 ;
87
+ sh:message "Exactly one primary declared capability per projection. An advertisement that declares three outcomes is three advertisements." ] ;
88
+ sh:property [ sh:path apguide:supportsCapability ; sh:maxCount 0 ;
89
+ sh:message "A projection must not reference a playbook. supportsCapability runs from the PACKAGE to the capability, never from the advertisement — a card skill is not 'the SKILL.md's public face' (axiom 1)." ] .
90
+
91
+ aps:NoDeclarationOnProtocolFeaturesShape a sh:NodeShape ;
92
+ rdfs:label "NoDeclarationOnProtocolFeaturesShape" ;
93
+ rdfs:comment "AXIOM 2. A2A AgentCapabilities (streaming, pushNotifications, extensions) are PROTOCOL FEATURES. `streaming: true` declares transport behaviour, not an outcome." ;
94
+ sh:targetObjectsOf aps:declaresCapability ;
95
+ sh:not [ sh:class <https://a2aproject.github.io/A2A/ns#AgentCapabilities> ] ;
96
+ sh:message "An A2A AgentCapabilities node may never be the subject of declaresCapability — protocol features are not business capabilities." .
97
+
98
+ aps:NoAuthorityFromClassificationShape a sh:NodeShape ;
99
+ rdfs:label "NoAuthorityFromClassificationShape" ;
100
+ rdfs:comment "AXIOM 4 + 5, stated for readers rather than validators: bearing a taxon, a declared label, a claim credential, or a demonstrated edge grants NOTHING. Authorization is delegation ∩ entitlement ∩ policy, evaluated at the gate at the moment of use. No shape can enforce this — it is enforced by the gate never reading any of these predicates — so it is recorded here as doctrine at the point where a reader would otherwise be tempted." ;
101
+ sh:targetNode aps:assertsCapability ;
102
+ sh:deactivated true .
103
+
104
+ # ═══ 3. Realization contracts ═══════════════════════════════════════════════
105
+
106
+ aps:CapabilityRealizationContractShape a sh:NodeShape ;
107
+ sh:targetClass aps:CapabilityRealizationContract ;
108
+ rdfs:label "CapabilityRealizationContractShape (the META-SHAPE)" ;
109
+ rdfs:comment "What every realization contract must itself contain. A contract is a SHACL shape over PROV; this shape validates the contracts, not the executions. THE PATTERN, in five required parts: (a) sh:targetClass — the activity type; (b) prov:used — required input entity types; (c) prov:generated — required output entity types; (d) prov:qualifiedAssociation — an association carrying BOTH a prov:agent with a prov:hadRole AND a prov:hadPlan; (e) completion conditions — an end time and a terminal state. Part (e) is what makes a contract about REALIZATION rather than about attempt." ;
110
+ sh:property [ sh:path sh:targetClass ; sh:minCount 1 ;
111
+ sh:message "A contract targets an activity class. A contract with no target validates nothing and is the exact failure mode this meta-shape exists to catch." ] ;
112
+ sh:property [ sh:path aps:definesCapability ; sh:minCount 1 ; sh:maxCount 1 ;
113
+ sh:message "A contract states which capability a conforming activity realizes." ] ;
114
+ sh:sparql [
115
+ sh:message "A realization contract must constrain all five parts: prov:used, prov:generated, prov:qualifiedAssociation, prov:endedAtTime, and a terminal completion state." ;
116
+ sh:select """
117
+ SELECT $this WHERE {
118
+ FILTER NOT EXISTS {
119
+ $this <http://www.w3.org/ns/shacl#property> ?u . ?u <http://www.w3.org/ns/shacl#path> <http://www.w3.org/ns/prov#used> .
120
+ $this <http://www.w3.org/ns/shacl#property> ?g . ?g <http://www.w3.org/ns/shacl#path> <http://www.w3.org/ns/prov#generated> .
121
+ $this <http://www.w3.org/ns/shacl#property> ?a . ?a <http://www.w3.org/ns/shacl#path> <http://www.w3.org/ns/prov#qualifiedAssociation> .
122
+ $this <http://www.w3.org/ns/shacl#property> ?e . ?e <http://www.w3.org/ns/shacl#path> <http://www.w3.org/ns/prov#endedAtTime> .
123
+ $this <http://www.w3.org/ns/shacl#property> ?c . ?c <http://www.w3.org/ns/shacl#path> <https://agenticprimitives.dev/ns/execution#completionState> .
124
+ }
125
+ }
126
+ """ ;
127
+ ] .
128
+
129
+ # ── The one contract this substrate can enforce TODAY ───────────────────────
130
+ #
131
+ # The spec-329 routed member consultation is the substrate's only capability whose realizations
132
+ # are already fully observable: the harness pre-reads a vault playbook (activation pins its
133
+ # content hash), the turn consumes a signed ConsultRequestV1 and emits an answered-XOR-declined
134
+ # ConsultAnswerV1 with the actor pinned to the member, and the org-side synthesis derives from
135
+ # each contributing answer. Every clause below cites something the live code already produces.
136
+
137
+ aps:MemberConsultationRealizationContract
138
+ a sh:NodeShape , aps:CapabilityRealizationContract ;
139
+ rdfs:label "MemberConsultationRealizationContract" ;
140
+ aps:definesCapability aps:MemberConsultationCapability ;
141
+ sh:targetClass apexec:MemberConsultationActivity ;
142
+ rdfs:comment "Realization contract for aps:MemberConsultationCapability — one member agent answering one routed consultation under its own playbook. A DECLINE IS A CONFORMING REALIZATION: the contract governs shape, not outcome, and buildConsultAnswer makes answered-xor-declined structural. Treating a decline as non-realization would create an incentive to answer outside one's documented positions, which is the opposite of what the consult path is for." ;
143
+
144
+ sh:property [ sh:path prov:used ;
145
+ sh:qualifiedValueShape [ sh:class apmsg:ConsultRequest ] ; sh:qualifiedMinCount 1 ;
146
+ sh:message "The turn must have consumed the ConsultRequestV1 it is answering." ] ;
147
+ sh:property [ sh:path prov:used ;
148
+ sh:qualifiedValueShape [ sh:class apguide:AgentSkillPackage ] ; sh:qualifiedMinCount 1 ;
149
+ sh:message "The turn must have consumed the member's playbook — guidance, never authority (ADR-0050)." ] ;
150
+ sh:property [ sh:path prov:generated ;
151
+ sh:qualifiedValueShape [ sh:class apmsg:ConsultAnswer ] ; sh:qualifiedMinCount 1 ; sh:qualifiedMaxCount 1 ] ;
152
+ sh:property [ sh:path prov:qualifiedAssociation ;
153
+ sh:qualifiedValueShape [
154
+ sh:class prov:Association ;
155
+ sh:property [ sh:path prov:agent ; sh:class apexec:AgentRuntime ; sh:minCount 1 ] ;
156
+ sh:property [ sh:path prov:hadRole ; sh:hasValue aprole:ConsultResponder ; sh:minCount 1 ] ;
157
+ sh:property [ sh:path prov:hadPlan ; sh:class apguide:AgentSkillPackage ; sh:minCount 1 ] ;
158
+ ] ;
159
+ sh:qualifiedMinCount 1 ;
160
+ sh:message "One qualified association carrying the runtime that bore responsibility, the capacity it acted in, and the plan that guided it." ] ;
161
+ sh:property [ sh:path apexec:usedPlanContentHash ; sh:minCount 1 ; sh:datatype xsd:string ;
162
+ sh:message "The playbook's content hash AT ACTIVATION. Without it the record cannot answer 'which executions must repeat after this playbook changed?' — and a demonstrated-capability signal computed over unpinned plans is unfalsifiable." ] ;
163
+ sh:property [ sh:path prov:endedAtTime ; sh:minCount 1 ; sh:datatype xsd:dateTime ] ;
164
+ sh:property [ sh:path apexec:completionState ; sh:minCount 1 ;
165
+ sh:in ( apexec:Answered apexec:Declined ) ] .
166
+
167
+ aps:OrgConsultationSynthesisRealizationContract
168
+ a sh:NodeShape , aps:CapabilityRealizationContract ;
169
+ rdfs:label "OrgConsultationSynthesisRealizationContract" ;
170
+ aps:definesCapability aps:ConsultationRoutingCapability ;
171
+ sh:targetClass apexec:ConsultationSynthesisActivity ;
172
+ rdfs:comment "Realization contract for aps:ConsultationRoutingCapability — the ORG side: selecting the right members and synthesizing their attributed answers. Enforced today because spec 329 already produces every part: an eligibility set derived structurally, a ranked candidate set with evidence paths, and a synthesis post whose attribution names each contributing member. This is the capability whose demonstrated-signal the advisor catalog's routing quality actually rides on." ;
173
+ sh:property [ sh:path prov:used ;
174
+ sh:qualifiedValueShape [ sh:class apint:ConsultationIntent ] ; sh:qualifiedMinCount 1 ] ;
175
+ sh:property [ sh:path prov:used ;
176
+ sh:qualifiedValueShape [ sh:class apmsg:ConsultAnswer ] ; sh:qualifiedMinCount 1 ;
177
+ sh:message "A synthesis with no contributing answer is not a realization of routing — it is the org agent talking to itself." ] ;
178
+ sh:property [ sh:path prov:generated ;
179
+ sh:qualifiedValueShape [ sh:class apmsg:MessageEvent ] ; sh:qualifiedMinCount 1 ] ;
180
+ sh:property [ sh:path prov:qualifiedAssociation ;
181
+ sh:qualifiedValueShape [
182
+ sh:class prov:Association ;
183
+ sh:property [ sh:path prov:agent ; sh:class apexec:AgentRuntime ; sh:minCount 1 ] ;
184
+ sh:property [ sh:path prov:hadRole ; sh:hasValue aprole:ConsultRouter ; sh:minCount 1 ] ;
185
+ sh:property [ sh:path prov:hadPlan ; sh:class apguide:AgentSkillPackage ; sh:minCount 1 ] ;
186
+ ] ; sh:qualifiedMinCount 1 ] ;
187
+ sh:property [ sh:path prov:endedAtTime ; sh:minCount 1 ; sh:datatype xsd:dateTime ] ;
188
+ sh:property [ sh:path apexec:completionState ; sh:minCount 1 ;
189
+ sh:in ( apexec:Answered apexec:Declined apexec:NoEligibleMember ) ] .
190
+
191
+ # ═══ 4. The parameterised ADVISORY realization contract ═════════════════════════════════════════
192
+ #
193
+ # THE INSIGHT THIS SECTION TESTS (the owner's item-3 question, stated precisely):
194
+ # A spec-329 consult answer, where the answering member DECLARED the advisory capability the
195
+ # question was routed on, IS a realization of that advisory capability. The substrate already
196
+ # emits every part of the proof — the request, the pinned playbook, the attributed answer, the
197
+ # terminal state — for `aps:MemberConsultationCapability`. An advisory realization is the SAME
198
+ # activity graph plus ONE more edge: which advisory id the routing selected the responder on.
199
+ #
200
+ # WHY ONE PARAMETERISED CONTRACT, NOT 43 SHAPES. Every consult-realizable advisory capability has
201
+ # the identical execution shape — they differ ONLY in the capability id on the routed-on edge.
202
+ # Authoring 43 near-identical NodeShapes would be repetition mistaken for rigour (the owner's
203
+ # words), and worse: 43 shapes drift, this one cannot. The capability id is DATA on the activity
204
+ # (`apexec:routedOnCapability`), matched against DATA on the definition, by SPARQL — so the contract
205
+ # is written once and every advisory definition that opts in is validated by it. This is the direct
206
+ # application of architecture §5's "the contract is a shape over PROV": the shape is over the shape
207
+ # of the graph, and the capability identity rides in the graph, not in the shape's name.
208
+ #
209
+ # ── WHY IT IS NOT ENFORCED TODAY, AND EXACTLY WHAT WOULD FLIP IT ────────────────────────────────
210
+ # One edge is missing from live PROV: `apexec:routedOnCapability`. The org's `rankConsultCandidates`
211
+ # ALREADY computes the routed-on id (the exact-match intersection of resolved need and declared ids,
212
+ # `capabilityHits`), and then discards it into a free-text evidence line. Spec 330 W1 has to emit it
213
+ # as a triple on the responder's turn. Until it does, this contract's target set is empty and it
214
+ # would pass by vacuity — so every advisory definition keeps `contractStatus "deferred"`, and this
215
+ # shape ships DEACTIVATED, as an executable specification of the one datum that is missing rather
216
+ # than as a live check pretending to observe something it cannot. `sh:deactivated true` is the
217
+ # honest state: the shape is correct, its input does not exist yet, and the test in §3's validation
218
+ # path drives it against a FIXTURE that supplies the missing edge — so the day W1 emits the edge,
219
+ # flipping `sh:deactivated` to false is the whole change, and the fixture proves it will validate.
220
+ #
221
+ # The evidence needed, in one line (this is the mandatory deferredContractRationale for all 43):
222
+ # a spec-330-W1 `apexec:routedOnCapability` edge on the member's consult turn, naming the
223
+ # advisory capability id the org's ranking selected the responder on.
224
+
225
+ aps:AdvisoryConsultRealizationContract
226
+ a sh:NodeShape , aps:CapabilityRealizationContract ;
227
+ rdfs:label "AdvisoryConsultRealizationContract (parameterised — ONE shape, every consult-realizable adv:*)" ;
228
+ aps:definesCapability aps:AdvisoryConsultRealizationParameter ;
229
+ sh:targetClass apexec:MemberConsultationActivity ;
230
+ sh:deactivated true ; # ← the one edit that flips it live, once W1 emits apexec:routedOnCapability
231
+ rdfs:comment "Parameterised realization contract for any advisory capability whose realization the consult path can carry. It is aps:MemberConsultationRealizationContract PLUS one clause: the turn must carry an apexec:routedOnCapability edge, and that capability must be one the responder actually declared (aps:declaresCapability). The capability identity is a PARAMETER read from the graph, not baked into 43 shape names. DEACTIVATED until spec 330 W1 emits the routed-on edge — see the header block for why an active-but-unobservable contract is the exact failure mode the catalog forbids." ;
232
+
233
+ # Everything aps:MemberConsultationRealizationContract requires, unchanged — an advisory
234
+ # realization is a member consultation, so it inherits the member consultation's whole shape.
235
+ sh:property [ sh:path prov:used ;
236
+ sh:qualifiedValueShape [ sh:class apmsg:ConsultRequest ] ; sh:qualifiedMinCount 1 ] ;
237
+ sh:property [ sh:path prov:used ;
238
+ sh:qualifiedValueShape [ sh:class apguide:AgentSkillPackage ] ; sh:qualifiedMinCount 1 ] ;
239
+ sh:property [ sh:path prov:generated ;
240
+ sh:qualifiedValueShape [ sh:class apmsg:ConsultAnswer ] ; sh:qualifiedMinCount 1 ; sh:qualifiedMaxCount 1 ] ;
241
+ sh:property [ sh:path prov:qualifiedAssociation ;
242
+ sh:qualifiedValueShape [
243
+ sh:class prov:Association ;
244
+ sh:property [ sh:path prov:agent ; sh:class apexec:AgentRuntime ; sh:minCount 1 ] ;
245
+ sh:property [ sh:path prov:hadRole ; sh:hasValue aprole:ConsultResponder ; sh:minCount 1 ] ;
246
+ sh:property [ sh:path prov:hadPlan ; sh:class apguide:AgentSkillPackage ; sh:minCount 1 ] ;
247
+ ] ; sh:qualifiedMinCount 1 ] ;
248
+ sh:property [ sh:path apexec:usedPlanContentHash ; sh:minCount 1 ; sh:datatype xsd:string ] ;
249
+ sh:property [ sh:path prov:endedAtTime ; sh:minCount 1 ; sh:datatype xsd:dateTime ] ;
250
+ sh:property [ sh:path apexec:completionState ; sh:minCount 1 ;
251
+ sh:in ( apexec:Answered apexec:Declined ) ] ;
252
+
253
+ # THE ONE ADDED CLAUSE (parts a): the turn names the advisory capability it was routed on.
254
+ sh:property [ sh:path apexec:routedOnCapability ; sh:minCount 1 ; sh:class aps:Capability ;
255
+ sh:message "An advisory realization must name the capability the org's routing selected the responder on — the parameter that says WHICH adv:* id this turn realizes. Without it the turn is a member consultation but not an advisory realization." ] ;
256
+
257
+ # THE ONE ADDED CLAUSE (part b): routed-on ⊆ declared. The realization only counts for a
258
+ # capability the responder actually put its name behind. This is the whole anti-inflation guard,
259
+ # in one FILTER: a member cannot earn a demonstrated edge for a capability it never declared, so
260
+ # routing an unrelated question at someone does not manufacture evidence they can do the thing.
261
+ sh:sparql [
262
+ sh:message "The routed-on advisory capability must be one the responding member DECLARED (aps:declaresCapability). Crediting a realization for an undeclared capability would let routing manufacture demonstrated-capability evidence the member never asserted — inverting the one signal that is supposed to be unfakeable." ;
263
+ sh:select """
264
+ SELECT $this ?cap WHERE {
265
+ $this <https://agenticprimitives.dev/ns/execution#routedOnCapability> ?cap .
266
+ $this <http://www.w3.org/ns/prov#qualifiedAssociation> ?assoc .
267
+ ?assoc <http://www.w3.org/ns/prov#agent> ?runtime .
268
+ ?runtime <http://www.w3.org/ns/prov#actedOnBehalfOf> ?member .
269
+ FILTER NOT EXISTS { ?member <https://agenticprimitives.dev/ns/skill#declaresCapability> ?cap }
270
+ }
271
+ """ ;
272
+ ] .
273
+
274
+ # The PARAMETER capability the contract "defines". Not an advisory capability itself — it is the
275
+ # substrate-owned identity that says "a conforming activity realizes WHICHEVER adv:* its routed-on
276
+ # edge names". This keeps the meta-shape's `aps:definesCapability minCount 1` satisfied (a contract
277
+ # states which capability a conforming activity realizes) while being honest that the specific
278
+ # advisory id is late-bound from the graph. The 43 advisory definitions point their
279
+ # aps:hasRealizationContract here ONCE W1 lands; today they stay deferred.
280
+ aps:AdvisoryConsultRealizationParameter a aps:Capability ;
281
+ aps:capabilityId "aps:advisory-consult-realization-parameter" ;
282
+ apctx:ownedByContext apctx:SubstrateContext ;
283
+ rdfs:label "Advisory-consult realization parameter" ;
284
+ rdfs:comment "A substrate-owned meta-capability standing for 'the advisory capability this consult turn was routed on'. It exists so one parameterised contract can serve 43 advisory definitions without either baking 43 names into 43 shapes or leaving the meta-shape's definesCapability unsatisfied." .
@@ -0,0 +1,85 @@
1
+ # C-box — SHACL shapes for the routed-consultation artifacts (spec 329 §6).
2
+ # Shapes for the two DURABLE artifacts only: the ConsultationIntent (the org's routing
3
+ # description, tbox/intents.ttl) and the ConsultAnswer (the member agent's structured
4
+ # answer, tbox/messaging.ttl). Projections — pending-routing rings, candidate rankings —
5
+ # get NO classes and therefore NO shapes: a derived view must never be mistaken for a fact.
6
+ # Like the messaging shapes, these are declared here and ENFORCED by fabric's TS validators
7
+ # (golden-vectored); they are graph/documentation shapes, never authority checks.
8
+
9
+ @prefix ap: <https://agenticprimitives.dev/ns/core#> .
10
+ @prefix apint: <https://agenticprimitives.dev/ns/intent#> .
11
+ @prefix apmsg: <https://agenticprimitives.dev/ns/messaging#> .
12
+ @prefix apful: <https://agenticprimitives.dev/ns/fulfillment#> .
13
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
14
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
15
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
16
+
17
+ apint:ConsultationIntentShape a sh:NodeShape ;
18
+ rdfs:label "ConsultationIntent shape" ;
19
+ sh:targetClass apint:ConsultationIntent ;
20
+ # A consultation is always the org RECEIVING an answer — exactly one direction, fixed.
21
+ sh:property [
22
+ sh:path apint:direction ;
23
+ sh:minCount 1 ;
24
+ sh:maxCount 1 ;
25
+ sh:hasValue "receive" ;
26
+ sh:message "ConsultationIntent.direction must be exactly 'receive'."
27
+ ] ;
28
+ sh:property [
29
+ sh:path apint:expressedBy ;
30
+ sh:minCount 1 ;
31
+ sh:maxCount 1 ;
32
+ sh:class ap:Agent ;
33
+ sh:message "ConsultationIntent must be expressed by exactly one org agent."
34
+ ] ;
35
+ # Depth-1 by construction (spec 329 §4.1): ONE member agent per consultation.
36
+ sh:property [
37
+ sh:path apint:addressedTo ;
38
+ sh:minCount 1 ;
39
+ sh:maxCount 1 ;
40
+ sh:class ap:Agent ;
41
+ sh:message "ConsultationIntent must be addressed to exactly one member agent."
42
+ ] ;
43
+ # The timeout/topic constraint set is REQUIRED — an unbounded consult is not expressible.
44
+ sh:property [
45
+ sh:path apint:hasConstraintSet ;
46
+ sh:minCount 1 ;
47
+ sh:maxCount 1 ;
48
+ sh:message "ConsultationIntent must carry exactly one constraint set (timeout + topic scope)."
49
+ ] ;
50
+ sh:property [
51
+ sh:path apint:status ;
52
+ sh:minCount 1 ;
53
+ sh:maxCount 1 ;
54
+ sh:in ( "drafted" "expressed" "fulfilled" "abandoned" ) ;
55
+ sh:message "ConsultationIntent.status must be one of drafted|expressed|fulfilled|abandoned (spine SKOS lifecycle)."
56
+ ] .
57
+
58
+ apmsg:ConsultAnswerShape a sh:NodeShape ;
59
+ rdfs:label "ConsultAnswer shape" ;
60
+ sh:targetClass apmsg:ConsultAnswer ;
61
+ # Agent-authored by construction: exactly one actor (the member SA the answer is attributed to).
62
+ sh:property [
63
+ sh:path apmsg:actingAgent ;
64
+ sh:minCount 1 ;
65
+ sh:maxCount 1 ;
66
+ sh:class ap:Agent ;
67
+ sh:message "ConsultAnswer must carry exactly one acting agent (the member SA)."
68
+ ] ;
69
+ # Body integrity: the artifact's bodyHash binding — REUSED from the fulfillment layer
70
+ # (the answer rides the a2a task Artifact, whose runtime computes + records apful:bodyHash).
71
+ sh:property [
72
+ sh:path apful:bodyHash ;
73
+ sh:minCount 1 ;
74
+ sh:maxCount 1 ;
75
+ sh:datatype xsd:string ;
76
+ sh:pattern "^0x[0-9a-fA-F]{64}$" ;
77
+ sh:message "ConsultAnswer must carry exactly one apful:bodyHash bound to the artifact body."
78
+ ] ;
79
+ # answered XOR declined — a consult terminal is always exactly one of the two.
80
+ sh:xone (
81
+ [ sh:property [ sh:path apmsg:answerText ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ; sh:minLength 1 ] ;
82
+ sh:property [ sh:path apmsg:declined ; sh:maxCount 0 ] ]
83
+ [ sh:property [ sh:path apmsg:declined ; sh:minCount 1 ; sh:maxCount 1 ; sh:hasValue true ] ;
84
+ sh:property [ sh:path apmsg:answerText ; sh:maxCount 0 ] ]
85
+ ) .
@@ -232,3 +232,53 @@ apsec:ExposureFindingShape a sh:NodeShape ;
232
232
  sh:class apdisc:EvidencePath ;
233
233
  sh:message "ExposureFinding must cite an evidence path."
234
234
  ] .
235
+
236
+ # ── Offering (spec 286) ────────────────────────────────────────────────────────────────────────
237
+ # `apdisc:OfferingShape` has been named by the indexer (`SHAPE.Offering`, recorded as the facet's
238
+ # shapeIri on every crawl) since spec 286, and has never existed. This is it.
239
+ #
240
+ # WHAT IT CONSTRAINS, AND WHAT IT DELIBERATELY DOES NOT. Everything an Offering says about ITSELF —
241
+ # effect, exposure, family, status, version, name, blurb — is the host's own claim about its own
242
+ # service, so there is no codelist this repo could impose that would be more than a guess, and a
243
+ # pinned value space would make an unrecognised value indistinguishable from an absent one. Those
244
+ # properties are therefore unconstrained here ON PURPOSE.
245
+ #
246
+ # What IS constrained is the part the substrate itself produces and consumes: identity (skillId,
247
+ # ofAgent), the two-valued lexical space the MCP reads with `=== 'true'`, and the three provenance
248
+ # properties without which a crawled assertion cannot be aged, diffed or challenged.
249
+ apdisc:OfferingShape a sh:NodeShape ;
250
+ rdfs:label "Offering shape" ;
251
+ sh:targetClass apdisc:Offering ;
252
+ sh:property [
253
+ sh:path apdisc:skillId ;
254
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
255
+ sh:message "Offering must carry exactly one skillId — it is the offering's identity component (the A-box IRI derives from it), and the projector drops any card entry without one."
256
+ ] ;
257
+ sh:property [
258
+ sh:path apdisc:ofAgent ;
259
+ sh:minCount 1 ; sh:maxCount 1 ; sh:class ap:Agent ;
260
+ sh:message "Offering must back-link to exactly one Agent. An offering advertising two agents' services is two offerings, and a single-tenant crawl already requires the card's self-reported agentId to equal the SA being crawled."
261
+ ] ;
262
+ sh:property [
263
+ sh:path apdisc:hasInputSchema ;
264
+ sh:maxCount 1 ; sh:in ( "true" "false" ) ;
265
+ sh:message "Offering.hasInputSchema, if present, is the lexical string 'true' or 'false'. The MCP reads it as `value === 'true'`, so ANY third value reads as false — a silent miss, which is exactly what ADR-0013 forbids. The set is pinned here rather than in the T-box because it is a fact about the live serialization, not about the concept."
266
+ ] ;
267
+ # ── Provenance of the crawl. A host-asserted fact with no observation point and no observation
268
+ # time is a rumour with a subject IRI; these three are what make an Offering evidence.
269
+ sh:property [
270
+ sh:path apdisc:sourceEndpoint ;
271
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
272
+ sh:message "Offering must record the endpoint it was crawled from. Without it, 'who asserted this?' has no answer."
273
+ ] ;
274
+ sh:property [
275
+ sh:path apdisc:observedAt ;
276
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:integer ;
277
+ sh:message "Offering must record WHEN it was observed, in unix seconds (xsd:integer — the projector writes a bare Turtle integer). Without it nothing can decay, and a 2019 advertisement ranks as fresh."
278
+ ] ;
279
+ sh:property [
280
+ sh:path apdisc:cardDigest ;
281
+ sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
282
+ sh:pattern "^sha256:[0-9a-f]{64}$" ;
283
+ sh:message "Offering.cardDigest must be sha256:<64 lowercase hex> over the raw card body. It is what makes 'which advertisements must be re-examined now this host's card changed?' answerable without having stored the card — the same role a pinned playbook content hash plays in a realization contract."
284
+ ] .