eval-quality 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +355 -0
  3. package/corpus/dev/README.md +36 -0
  4. package/corpus/dev/compile-seal-example/brief.json +1 -0
  5. package/corpus/dev/compile-seal-example/contract.json +1 -0
  6. package/corpus/dev/contracts/absent-collection-locations.json +1 -0
  7. package/corpus/dev/contracts/absent-sibling-groups.json +1 -0
  8. package/corpus/dev/contracts/absent-success-indicator.json +1 -0
  9. package/corpus/dev/contracts/empty-channel-roles.json +1 -0
  10. package/corpus/dev/contracts/empty-collection-locations.json +1 -0
  11. package/corpus/dev/contracts/empty-request-shapes.json +1 -0
  12. package/corpus/dev/contracts/empty-sibling-groups.json +1 -0
  13. package/corpus/dev/contracts/no-collection-quantifier.json +1 -0
  14. package/corpus/dev/contracts/no-operation-inventory.json +1 -0
  15. package/corpus/dev/contracts/no-read-back-relation.json +1 -0
  16. package/corpus/dev/contracts/no-state-change-marker.json +1 -0
  17. package/corpus/dev/contracts/no-type-violating-step.json +1 -0
  18. package/corpus/dev/contracts/per-key-split-oracles.json +1 -0
  19. package/corpus/dev/contracts/satisfied-declarations.json +1 -0
  20. package/corpus/dev/contracts/single-required-response-key.json +1 -0
  21. package/corpus/dev/contracts/split-indicator-oracle.json +1 -0
  22. package/corpus/dev/contracts/unaddressed-parameter-sibling.json +1 -0
  23. package/corpus/dev/contracts/unnamed-reference-set.json +1 -0
  24. package/corpus/dev/contracts/wrong-cardinality-form.json +1 -0
  25. package/corpus/dev/index.json +1 -0
  26. package/dist/adapters/index.d.ts +12 -0
  27. package/dist/adapters/index.js +3 -0
  28. package/dist/adapters/local-corpus-adapter.d.ts +7 -0
  29. package/dist/adapters/local-corpus-adapter.js +78 -0
  30. package/dist/adapters/node-file-system-adapter.d.ts +7 -0
  31. package/dist/adapters/node-file-system-adapter.js +39 -0
  32. package/dist/adapters/port-boundary.d.ts +18 -0
  33. package/dist/adapters/port-boundary.js +83 -0
  34. package/dist/adapters/system-clock-adapter.d.ts +10 -0
  35. package/dist/adapters/system-clock-adapter.js +18 -0
  36. package/dist/application/compile.d.ts +4 -0
  37. package/dist/application/compile.js +24 -0
  38. package/dist/application/diagnostics.d.ts +22 -0
  39. package/dist/application/diagnostics.js +18 -0
  40. package/dist/application/index.d.ts +23 -0
  41. package/dist/application/index.js +17 -0
  42. package/dist/application/invoke-port.d.ts +2 -0
  43. package/dist/application/invoke-port.js +45 -0
  44. package/dist/application/preflight.d.ts +27 -0
  45. package/dist/application/preflight.js +131 -0
  46. package/dist/application/seal.d.ts +4 -0
  47. package/dist/application/seal.js +28 -0
  48. package/dist/application/serialize.d.ts +6 -0
  49. package/dist/application/serialize.js +9 -0
  50. package/dist/cli/arguments.d.ts +28 -0
  51. package/dist/cli/arguments.js +167 -0
  52. package/dist/cli/exit-codes.d.ts +36 -0
  53. package/dist/cli/exit-codes.js +39 -0
  54. package/dist/cli/main.d.ts +2 -0
  55. package/dist/cli/main.js +143 -0
  56. package/dist/cli/render.d.ts +26 -0
  57. package/dist/cli/render.js +53 -0
  58. package/dist/cli/run.d.ts +41 -0
  59. package/dist/cli/run.js +203 -0
  60. package/dist/core/canonical/canonicalize.d.ts +1 -0
  61. package/dist/core/canonical/canonicalize.js +113 -0
  62. package/dist/core/canonical/digest.d.ts +7 -0
  63. package/dist/core/canonical/digest.js +81 -0
  64. package/dist/core/canonical/scan-json.d.ts +1 -0
  65. package/dist/core/canonical/scan-json.js +298 -0
  66. package/dist/core/canonical/value-domain.d.ts +4 -0
  67. package/dist/core/canonical/value-domain.js +113 -0
  68. package/dist/core/compile/compile.d.ts +24 -0
  69. package/dist/core/compile/compile.js +67 -0
  70. package/dist/core/compile/declarations.d.ts +5 -0
  71. package/dist/core/compile/declarations.js +22 -0
  72. package/dist/core/compile/expression-legality.d.ts +14 -0
  73. package/dist/core/compile/expression-legality.js +346 -0
  74. package/dist/core/compile/forbidden-inputs.d.ts +5 -0
  75. package/dist/core/compile/forbidden-inputs.js +19 -0
  76. package/dist/core/compile/interface-inventory.d.ts +10 -0
  77. package/dist/core/compile/interface-inventory.js +55 -0
  78. package/dist/core/compile/oracle-alignment.d.ts +14 -0
  79. package/dist/core/compile/oracle-alignment.js +93 -0
  80. package/dist/core/compile/reachability.d.ts +17 -0
  81. package/dist/core/compile/reachability.js +177 -0
  82. package/dist/core/compile/rubrics.d.ts +55 -0
  83. package/dist/core/compile/rubrics.js +198 -0
  84. package/dist/core/compile/scripting-bound.d.ts +5 -0
  85. package/dist/core/compile/scripting-bound.js +151 -0
  86. package/dist/core/compile/sensitivity-witness.d.ts +73 -0
  87. package/dist/core/compile/sensitivity-witness.js +232 -0
  88. package/dist/core/compile/waivers.d.ts +3 -0
  89. package/dist/core/compile/waivers.js +21 -0
  90. package/dist/core/coverage/coverage.d.ts +18 -0
  91. package/dist/core/coverage/coverage.js +47 -0
  92. package/dist/core/coverage/relevance.d.ts +75 -0
  93. package/dist/core/coverage/relevance.js +186 -0
  94. package/dist/core/coverage/rules.d.ts +7 -0
  95. package/dist/core/coverage/rules.js +18 -0
  96. package/dist/core/coverage/satisfaction.d.ts +107 -0
  97. package/dist/core/coverage/satisfaction.js +415 -0
  98. package/dist/core/coverage/table.d.ts +26 -0
  99. package/dist/core/coverage/table.js +222 -0
  100. package/dist/core/declared-inputs.d.ts +16 -0
  101. package/dist/core/declared-inputs.js +18 -0
  102. package/dist/core/evaluate/evidence-resolution.d.ts +54 -0
  103. package/dist/core/evaluate/evidence-resolution.js +153 -0
  104. package/dist/core/evaluate/operators.d.ts +87 -0
  105. package/dist/core/evaluate/operators.js +350 -0
  106. package/dist/core/evaluate/resolution.d.ts +40 -0
  107. package/dist/core/evaluate/resolution.js +336 -0
  108. package/dist/core/evaluate/resolved-value.d.ts +9 -0
  109. package/dist/core/evaluate/resolved-value.js +6 -0
  110. package/dist/core/failure-codes.d.ts +18 -0
  111. package/dist/core/failure-codes.js +50 -0
  112. package/dist/core/lineage/chain.d.ts +49 -0
  113. package/dist/core/lineage/chain.js +210 -0
  114. package/dist/core/lineage/freeze.d.ts +12 -0
  115. package/dist/core/lineage/freeze.js +35 -0
  116. package/dist/core/lineage/stage-table.d.ts +43 -0
  117. package/dist/core/lineage/stage-table.js +106 -0
  118. package/dist/core/preflight/plan.d.ts +67 -0
  119. package/dist/core/preflight/plan.js +313 -0
  120. package/dist/core/preflight/projection.d.ts +40 -0
  121. package/dist/core/preflight/projection.js +96 -0
  122. package/dist/core/preflight/reduce.d.ts +8 -0
  123. package/dist/core/preflight/reduce.js +180 -0
  124. package/dist/core/preflight/witness-evidence.d.ts +42 -0
  125. package/dist/core/preflight/witness-evidence.js +88 -0
  126. package/dist/core/probe/target-policy.d.ts +63 -0
  127. package/dist/core/probe/target-policy.js +328 -0
  128. package/dist/core/schemas/artifact-reference.d.ts +19 -0
  129. package/dist/core/schemas/artifact-reference.js +30 -0
  130. package/dist/core/schemas/artifact.d.ts +1153 -0
  131. package/dist/core/schemas/artifact.js +84 -0
  132. package/dist/core/schemas/constraint-ledger.d.ts +57 -0
  133. package/dist/core/schemas/constraint-ledger.js +143 -0
  134. package/dist/core/schemas/eval-contract.d.ts +402 -0
  135. package/dist/core/schemas/eval-contract.js +147 -0
  136. package/dist/core/schemas/evaluator-configuration.d.ts +37 -0
  137. package/dist/core/schemas/evaluator-configuration.js +43 -0
  138. package/dist/core/schemas/evidence-artifact.d.ts +471 -0
  139. package/dist/core/schemas/evidence-artifact.js +232 -0
  140. package/dist/core/schemas/expression.d.ts +197 -0
  141. package/dist/core/schemas/expression.js +284 -0
  142. package/dist/core/schemas/faults.d.ts +9 -0
  143. package/dist/core/schemas/faults.js +32 -0
  144. package/dist/core/schemas/interface.d.ts +417 -0
  145. package/dist/core/schemas/interface.js +115 -0
  146. package/dist/core/schemas/isolation-manifest.d.ts +136 -0
  147. package/dist/core/schemas/isolation-manifest.js +92 -0
  148. package/dist/core/schemas/lineage.d.ts +21 -0
  149. package/dist/core/schemas/lineage.js +28 -0
  150. package/dist/core/schemas/oracle.d.ts +72 -0
  151. package/dist/core/schemas/oracle.js +35 -0
  152. package/dist/core/schemas/plan.d.ts +115 -0
  153. package/dist/core/schemas/plan.js +58 -0
  154. package/dist/core/schemas/pointer.d.ts +63 -0
  155. package/dist/core/schemas/pointer.js +94 -0
  156. package/dist/core/schemas/port-messages.d.ts +103 -0
  157. package/dist/core/schemas/port-messages.js +90 -0
  158. package/dist/core/schemas/preflight-verdict.d.ts +60 -0
  159. package/dist/core/schemas/preflight-verdict.js +38 -0
  160. package/dist/core/schemas/primitives.d.ts +78 -0
  161. package/dist/core/schemas/primitives.js +121 -0
  162. package/dist/core/schemas/private-artifact-manifest.d.ts +56 -0
  163. package/dist/core/schemas/private-artifact-manifest.js +46 -0
  164. package/dist/core/schemas/probe-body.d.ts +25 -0
  165. package/dist/core/schemas/probe-body.js +23 -0
  166. package/dist/core/schemas/probe-policy.d.ts +76 -0
  167. package/dist/core/schemas/probe-policy.js +33 -0
  168. package/dist/core/schemas/probe.d.ts +189 -0
  169. package/dist/core/schemas/probe.js +82 -0
  170. package/dist/core/schemas/publish.d.ts +30 -0
  171. package/dist/core/schemas/publish.js +135 -0
  172. package/dist/core/schemas/reference-set.d.ts +18 -0
  173. package/dist/core/schemas/reference-set.js +27 -0
  174. package/dist/core/schemas/rubric.d.ts +62 -0
  175. package/dist/core/schemas/rubric.js +68 -0
  176. package/dist/core/schemas/scoring-policy.d.ts +28 -0
  177. package/dist/core/schemas/scoring-policy.js +51 -0
  178. package/dist/core/schemas/sealed-evaluator-brief.d.ts +80 -0
  179. package/dist/core/schemas/sealed-evaluator-brief.js +59 -0
  180. package/dist/core/schemas/sealed-run-record.d.ts +382 -0
  181. package/dist/core/schemas/sealed-run-record.js +215 -0
  182. package/dist/core/schemas/sensitivity-witness.d.ts +138 -0
  183. package/dist/core/schemas/sensitivity-witness.js +86 -0
  184. package/dist/core/schemas/verdict.d.ts +25 -0
  185. package/dist/core/schemas/verdict.js +20 -0
  186. package/dist/core/schemas/waiver.d.ts +17 -0
  187. package/dist/core/schemas/waiver.js +24 -0
  188. package/dist/core/seal/derived-reference.d.ts +36 -0
  189. package/dist/core/seal/derived-reference.js +383 -0
  190. package/dist/core/seal/direction-prose.d.ts +13 -0
  191. package/dist/core/seal/direction-prose.js +120 -0
  192. package/dist/core/seal/plan-index.d.ts +63 -0
  193. package/dist/core/seal/plan-index.js +155 -0
  194. package/dist/core/seal/scripting-audit.d.ts +15 -0
  195. package/dist/core/seal/scripting-audit.js +51 -0
  196. package/dist/core/seal/seal.d.ts +18 -0
  197. package/dist/core/seal/seal.js +155 -0
  198. package/dist/core/stage-contracts.d.ts +30 -0
  199. package/dist/core/stage-contracts.js +1 -0
  200. package/dist/index.d.ts +15 -0
  201. package/dist/index.js +22 -0
  202. package/dist/ports/clock-port.d.ts +13 -0
  203. package/dist/ports/clock-port.js +7 -0
  204. package/dist/ports/corpus-port.d.ts +16 -0
  205. package/dist/ports/corpus-port.js +7 -0
  206. package/dist/ports/environment-probe-port.d.ts +76 -0
  207. package/dist/ports/environment-probe-port.js +32 -0
  208. package/dist/ports/file-system-port.d.ts +27 -0
  209. package/dist/ports/file-system-port.js +11 -0
  210. package/dist/ports/port.d.ts +33 -0
  211. package/dist/ports/port.js +14 -0
  212. package/dist/testing/conformance.d.ts +88 -0
  213. package/dist/testing/conformance.js +281 -0
  214. package/dist/testing/index.d.ts +26 -0
  215. package/dist/testing/index.js +18 -0
  216. package/dist/testing/probe-conformance.d.ts +45 -0
  217. package/dist/testing/probe-conformance.js +186 -0
  218. package/package.json +130 -0
  219. package/schemas/artifact-reference.schema.json +64 -0
  220. package/schemas/eval-contract.schema.json +2145 -0
  221. package/schemas/evaluator-configuration.schema.json +199 -0
  222. package/schemas/evidence-artifact.schema.json +1229 -0
  223. package/schemas/isolation-manifest.schema.json +394 -0
  224. package/schemas/preflight-verdict.schema.json +114 -0
  225. package/schemas/private-artifact-manifest.schema.json +103 -0
  226. package/schemas/probe.schema.json +1151 -0
  227. package/schemas/rubric.schema.json +148 -0
  228. package/schemas/scoring-policy.schema.json +90 -0
  229. package/schemas/sealed-evaluator-brief.schema.json +268 -0
  230. package/schemas/sealed-run-record.schema.json +875 -0
@@ -0,0 +1,2145 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:eval-quality:schema:eval-contract",
4
+ "type": "object",
5
+ "properties": {
6
+ "schemaVersion": {
7
+ "type": "integer",
8
+ "minimum": 1,
9
+ "maximum": 9007199254740991,
10
+ "description": "AD-11 requires an integer under this exact name. Deliberately not `z.literal(1)`: the literal exports as `{\"type\":\"number\",\"const\":1}`, losing `integer` for a non-TypeScript consumer, and it would turn a version-2 artifact into an anonymous schema-parse failure instead of AD-28's dedicated `schema-version-mismatch` fault. Version equality belongs to the reader that throws that fault."
11
+ },
12
+ "parentDigest": {
13
+ "anyOf": [
14
+ {
15
+ "type": "string",
16
+ "pattern": "^sha256:[0-9a-f]{64}$",
17
+ "description": "AD-27 digest: \"sha256:\" plus 64 lowercase hexadecimal characters."
18
+ },
19
+ {
20
+ "type": "null"
21
+ }
22
+ ],
23
+ "description": "AD-29 lineage. `null` if and only if `revisionCount` is 0. That biconditional is stated here rather than refined: a refinement is silently dropped from the published schema, so a non-TypeScript consumer would never see it, and the constraint ledger records it as not expressible."
24
+ },
25
+ "revisionCount": {
26
+ "type": "integer",
27
+ "minimum": 0,
28
+ "maximum": 9007199254740991,
29
+ "description": "AD-29: one greater than the parent artifact's."
30
+ },
31
+ "contractId": {
32
+ "type": "string",
33
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
34
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
35
+ },
36
+ "sourceSpecDigest": {
37
+ "anyOf": [
38
+ {
39
+ "type": "string",
40
+ "pattern": "^sha256:[0-9a-f]{64}$",
41
+ "description": "AD-27 digest: \"sha256:\" plus 64 lowercase hexadecimal characters."
42
+ },
43
+ {
44
+ "type": "null"
45
+ }
46
+ ],
47
+ "description": "AD-18 permits a digest where the content is forbidden, so the contract may name the specification it was authored against without carrying it."
48
+ },
49
+ "behaviors": {
50
+ "minItems": 1,
51
+ "type": "array",
52
+ "items": {
53
+ "type": "object",
54
+ "properties": {
55
+ "id": {
56
+ "type": "string",
57
+ "pattern": "^B-[0-9]{3,}$"
58
+ },
59
+ "description": {
60
+ "type": "string"
61
+ },
62
+ "severity": {
63
+ "type": "string",
64
+ "enum": [
65
+ "low",
66
+ "material",
67
+ "critical"
68
+ ]
69
+ },
70
+ "observableSuccessCriterion": {
71
+ "anyOf": [
72
+ {
73
+ "type": "string"
74
+ },
75
+ {
76
+ "type": "null"
77
+ }
78
+ ],
79
+ "description": "AD-19: what observable condition means this behaviour was met, which is not the nominated success indicator of any one operation. `null` is the shape `no-observable-success-criterion` fires on, and that code fires on exactly this condition and never on an empty oracle list."
80
+ },
81
+ "requirementLinks": {
82
+ "type": "array",
83
+ "items": {
84
+ "type": "object",
85
+ "properties": {
86
+ "scheme": {
87
+ "type": "string",
88
+ "minLength": 1
89
+ },
90
+ "id": {
91
+ "type": "string",
92
+ "minLength": 1
93
+ }
94
+ },
95
+ "required": [
96
+ "scheme",
97
+ "id"
98
+ ],
99
+ "additionalProperties": false
100
+ },
101
+ "description": "Coin flip (c), settled: requirement and risk linkage lives per behaviour rather than at contract level, because `missing-requirement-linkage` fires when \"a behaviour declares no requirement or risk identifier\" and a contract-level array cannot make that predicate decidable per behaviour. Empty is legal, and both link arrays empty is exactly what the code fires on; a schema demanding non-empty makes it fire never."
102
+ },
103
+ "riskLinks": {
104
+ "type": "array",
105
+ "items": {
106
+ "type": "object",
107
+ "properties": {
108
+ "scheme": {
109
+ "type": "string",
110
+ "minLength": 1
111
+ },
112
+ "id": {
113
+ "type": "string",
114
+ "minLength": 1
115
+ }
116
+ },
117
+ "required": [
118
+ "scheme",
119
+ "id"
120
+ ],
121
+ "additionalProperties": false
122
+ }
123
+ },
124
+ "oracles": {
125
+ "type": "array",
126
+ "items": {
127
+ "type": "string",
128
+ "pattern": "^O-[0-9]{3,}$"
129
+ },
130
+ "description": "Identifiers of the oracles this behaviour is discharged by. Deliberately not refined against the contract's declared oracles: no AD-5 code names a behaviour citing an undeclared oracle, so it joins the cross-field rules with no code, unenforced in v0 rather than silently pushed into the schema."
131
+ }
132
+ },
133
+ "required": [
134
+ "id",
135
+ "description",
136
+ "severity",
137
+ "observableSuccessCriterion",
138
+ "requirementLinks",
139
+ "riskLinks",
140
+ "oracles"
141
+ ],
142
+ "additionalProperties": false
143
+ },
144
+ "description": "US spelling, matching the prior art and both hand-authored contracts. A contract with no behaviour declares nothing to evaluate."
145
+ },
146
+ "oracles": {
147
+ "type": "array",
148
+ "items": {
149
+ "type": "object",
150
+ "properties": {
151
+ "id": {
152
+ "type": "string",
153
+ "pattern": "^O-[0-9]{3,}$"
154
+ },
155
+ "direction": {
156
+ "anyOf": [
157
+ {
158
+ "type": "object",
159
+ "properties": {
160
+ "evidenceTargets": {
161
+ "type": "array",
162
+ "items": {
163
+ "type": "string",
164
+ "pattern": "^\\/interactions\\/[a-z0-9]+(?:-[a-z0-9]+)*\\/(?:(?:response-body|response-headers|stdout|stderr)(?:\\/(?:[^/~]|~[01])*)*|(?:response-status|exit-code)|call-inputs\\/(?:path|query|header|body)(?:\\/(?:[^/~]|~[01])*)*)$",
165
+ "description": "AD-26 interaction-rooted pointer: \"/interactions/{stepId}/\" followed by one channel of the closed vocabulary. `call-inputs` takes one of the four transport channels as its next segment; `response-status` and `exit-code` take no tail. Syntax only: whether the step exists and whether the evidence is reachable are compile-time checks, not schema checks."
166
+ },
167
+ "description": "Interaction-rooted pointers only. AD-3 computes containment after quantifier substitution, so a target is always fully rooted and the bound-element spelling never appears here."
168
+ },
169
+ "relation": {
170
+ "type": "string",
171
+ "enum": [
172
+ "equality",
173
+ "deep-equality",
174
+ "containment",
175
+ "existence",
176
+ "absence",
177
+ "regex",
178
+ "set-membership",
179
+ "ordering",
180
+ "count-tolerance",
181
+ "shape",
182
+ "covers-by-key",
183
+ "all",
184
+ "any",
185
+ "not",
186
+ "for-all",
187
+ "for-any"
188
+ ],
189
+ "description": "Drawn from AD-4's full sixteen-member vocabulary \u2014 eleven operators, three connectives, two quantifiers \u2014 not the operators alone."
190
+ },
191
+ "polarity": {
192
+ "type": "string",
193
+ "enum": [
194
+ "expects-hold",
195
+ "expects-violation"
196
+ ],
197
+ "description": "Coin flip (a), settled: polarity is declared twice, here and on the oracle. AD-3 names it as one of the three axes the alignment predicate binds and AD-33 gives every check one, so declaring it once makes the alignment predicate vacuous on a third of its content. Duplication is what makes drift detectable, and the drift is deliberately not refined away: `direction-check-misaligned` needs the disagreement to stay representable."
198
+ },
199
+ "scope": {
200
+ "anyOf": [
201
+ {
202
+ "type": "string"
203
+ },
204
+ {
205
+ "type": "null"
206
+ }
207
+ ],
208
+ "description": "Evaluator-facing, and exempt from the alignment predicate, which binds evidence targets, relation, and polarity only."
209
+ },
210
+ "negativeDomain": {
211
+ "anyOf": [
212
+ {
213
+ "type": "string"
214
+ },
215
+ {
216
+ "type": "null"
217
+ }
218
+ ],
219
+ "description": "Evaluator-facing and exempt from alignment. `seal` renders it as an unordered set so the brief is byte-identical under reordering."
220
+ }
221
+ },
222
+ "required": [
223
+ "evidenceTargets",
224
+ "relation",
225
+ "polarity",
226
+ "scope",
227
+ "negativeDomain"
228
+ ],
229
+ "additionalProperties": false
230
+ },
231
+ {
232
+ "type": "null"
233
+ }
234
+ ],
235
+ "description": "`null` is half of what `oracle-missing-channel` fires on, so it must parse."
236
+ },
237
+ "check": {
238
+ "anyOf": [
239
+ {
240
+ "$ref": "#/$defs/Expression"
241
+ },
242
+ {
243
+ "type": "null"
244
+ }
245
+ ],
246
+ "description": "`null` is the other half of `oracle-missing-channel`."
247
+ },
248
+ "polarity": {
249
+ "type": "string",
250
+ "enum": [
251
+ "expects-hold",
252
+ "expects-violation"
253
+ ],
254
+ "description": "AD-33: every check declares one polarity, and it lives at oracle level rather than inside the expression tree. Required and explicit rather than defaulted to `expects-hold`: a Zod default diverges input and output mode and the explicit-null convention forbids implicit absence."
255
+ },
256
+ "commentary": {
257
+ "anyOf": [
258
+ {
259
+ "type": "string"
260
+ },
261
+ {
262
+ "type": "null"
263
+ }
264
+ ],
265
+ "description": "AD-3's author documentation. No predicate reads it and `seal` never emits it, because a channel the evaluator reads and no predicate audits is the free-prose channel AD-3 exists to close."
266
+ }
267
+ },
268
+ "required": [
269
+ "id",
270
+ "direction",
271
+ "check",
272
+ "polarity",
273
+ "commentary"
274
+ ],
275
+ "additionalProperties": false
276
+ },
277
+ "description": "No minimum. AD-19 is explicit that `no-observable-success-criterion` \"never fires on an empty oracle list\", so an empty list must parse."
278
+ },
279
+ "rubrics": {
280
+ "type": "array",
281
+ "items": {
282
+ "$ref": "#/$defs/RubricBody"
283
+ },
284
+ "description": "Empty is legal: a zero-rubric contract compiles clean."
285
+ },
286
+ "waivers": {
287
+ "type": "array",
288
+ "items": {
289
+ "type": "object",
290
+ "properties": {
291
+ "id": {
292
+ "type": "string",
293
+ "pattern": "^W-[0-9]{3,}$"
294
+ },
295
+ "rule": {
296
+ "anyOf": [
297
+ {
298
+ "type": "string"
299
+ },
300
+ {
301
+ "type": "null"
302
+ }
303
+ ],
304
+ "description": "The AD-20 discipline rule this waiver names. An opaque string rather than an enum: AD-20 enumerates seven rules in prose and assigns them no identifiers, and minting them here would invent a vocabulary that AD-20 enforcement would then have to match."
305
+ },
306
+ "rationale": {
307
+ "anyOf": [
308
+ {
309
+ "type": "string"
310
+ },
311
+ {
312
+ "type": "null"
313
+ }
314
+ ]
315
+ },
316
+ "condition": {
317
+ "anyOf": [
318
+ {
319
+ "type": "string"
320
+ },
321
+ {
322
+ "type": "null"
323
+ }
324
+ ],
325
+ "description": "A machine-checkable context condition. AD-5 requires one \"where one exists\", so `null` here is a complete waiver rather than an incomplete one."
326
+ },
327
+ "approval": {
328
+ "anyOf": [
329
+ {
330
+ "type": "string"
331
+ },
332
+ {
333
+ "type": "null"
334
+ }
335
+ ]
336
+ },
337
+ "expiresAt": {
338
+ "anyOf": [
339
+ {
340
+ "type": "string",
341
+ "format": "date-time",
342
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
343
+ "description": "RFC 3339 timestamp in UTC. A numeric offset is not accepted."
344
+ },
345
+ {
346
+ "type": "null"
347
+ }
348
+ ]
349
+ }
350
+ },
351
+ "required": [
352
+ "id",
353
+ "rule",
354
+ "rationale",
355
+ "condition",
356
+ "approval",
357
+ "expiresAt"
358
+ ],
359
+ "additionalProperties": false
360
+ }
361
+ },
362
+ "permittedInterfaces": {
363
+ "type": "array",
364
+ "items": {
365
+ "type": "object",
366
+ "properties": {
367
+ "logicalId": {
368
+ "type": "string",
369
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
370
+ "description": "AD-35: a logical identifier for the interface, never a URL, host, or port. Mapping it to a target is the caller's, outside the contract."
371
+ },
372
+ "kind": {
373
+ "type": "string",
374
+ "enum": [
375
+ "api",
376
+ "web",
377
+ "cli",
378
+ "mcp"
379
+ ],
380
+ "description": "All four kinds are admitted so `unsupported-interface-kind` stays fireable. v0 supports `api`; the other three fail compilation under that code rather than failing to parse."
381
+ },
382
+ "operations": {
383
+ "type": "array",
384
+ "items": {
385
+ "type": "object",
386
+ "properties": {
387
+ "operationId": {
388
+ "type": "string",
389
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
390
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
391
+ },
392
+ "method": {
393
+ "type": "string",
394
+ "enum": [
395
+ "GET",
396
+ "HEAD",
397
+ "POST",
398
+ "PUT",
399
+ "PATCH",
400
+ "DELETE",
401
+ "OPTIONS"
402
+ ]
403
+ },
404
+ "pathTemplate": {
405
+ "type": "string",
406
+ "pattern": "^(?:\\/(?:[^/{}:]|\\{[A-Za-z0-9_-]+\\})*)+$",
407
+ "description": "A path template whose parameters are spelled `{name}` in braces. The `:name` spelling is rejected: AD-40 resolves a defect signature by comparing method and path template, and that comparison is not implementable against an unstated syntax."
408
+ },
409
+ "stateChangeMarker": {
410
+ "type": "boolean",
411
+ "description": "AD-19: whether the operation is intended to change state. AD-20 rule 7 relevance reads it, and AD-10 selects the sensitivity channel by it. Both values are legal and neither is a default."
412
+ },
413
+ "requestShape": {
414
+ "type": "object",
415
+ "properties": {
416
+ "path": {
417
+ "type": "object",
418
+ "properties": {
419
+ "requiredKeys": {
420
+ "type": "array",
421
+ "items": {
422
+ "type": "string",
423
+ "minLength": 1
424
+ }
425
+ },
426
+ "permittedKeys": {
427
+ "type": "array",
428
+ "items": {
429
+ "type": "string",
430
+ "minLength": 1
431
+ },
432
+ "description": "The closed set of keys the shape admits. Deliberately not refined to be a superset of `requiredKeys`: no AD-5 code names that contradiction, so it joins the cross-field rules left to the compiler in v0. There is no spelling for \"these keys are required and extras are unconstrained\" \u2014 AD-4 calls the descriptor closed, so an open mode would be a different grammar."
433
+ },
434
+ "types": {
435
+ "type": "object",
436
+ "propertyNames": {
437
+ "type": "string",
438
+ "minLength": 1
439
+ },
440
+ "additionalProperties": {
441
+ "anyOf": [
442
+ {
443
+ "type": "string",
444
+ "enum": [
445
+ "string",
446
+ "number",
447
+ "boolean",
448
+ "object",
449
+ "array",
450
+ "null"
451
+ ]
452
+ },
453
+ {
454
+ "type": "null"
455
+ }
456
+ ]
457
+ },
458
+ "description": "Caller-keyed by plain key name, never by pointer: the descriptor-relative pointer spelling does not apply to these keys and must not be extended to them by analogy. A missing key means \"not declared\"; an explicit `null` value means \"declared, type not stated\"."
459
+ }
460
+ },
461
+ "required": [
462
+ "requiredKeys",
463
+ "permittedKeys",
464
+ "types"
465
+ ],
466
+ "additionalProperties": false
467
+ },
468
+ "query": {
469
+ "type": "object",
470
+ "properties": {
471
+ "requiredKeys": {
472
+ "type": "array",
473
+ "items": {
474
+ "type": "string",
475
+ "minLength": 1
476
+ }
477
+ },
478
+ "permittedKeys": {
479
+ "type": "array",
480
+ "items": {
481
+ "type": "string",
482
+ "minLength": 1
483
+ },
484
+ "description": "The closed set of keys the shape admits. Deliberately not refined to be a superset of `requiredKeys`: no AD-5 code names that contradiction, so it joins the cross-field rules left to the compiler in v0. There is no spelling for \"these keys are required and extras are unconstrained\" \u2014 AD-4 calls the descriptor closed, so an open mode would be a different grammar."
485
+ },
486
+ "types": {
487
+ "type": "object",
488
+ "propertyNames": {
489
+ "type": "string",
490
+ "minLength": 1
491
+ },
492
+ "additionalProperties": {
493
+ "anyOf": [
494
+ {
495
+ "type": "string",
496
+ "enum": [
497
+ "string",
498
+ "number",
499
+ "boolean",
500
+ "object",
501
+ "array",
502
+ "null"
503
+ ]
504
+ },
505
+ {
506
+ "type": "null"
507
+ }
508
+ ]
509
+ },
510
+ "description": "Caller-keyed by plain key name, never by pointer: the descriptor-relative pointer spelling does not apply to these keys and must not be extended to them by analogy. A missing key means \"not declared\"; an explicit `null` value means \"declared, type not stated\"."
511
+ }
512
+ },
513
+ "required": [
514
+ "requiredKeys",
515
+ "permittedKeys",
516
+ "types"
517
+ ],
518
+ "additionalProperties": false
519
+ },
520
+ "header": {
521
+ "type": "object",
522
+ "properties": {
523
+ "requiredKeys": {
524
+ "type": "array",
525
+ "items": {
526
+ "type": "string",
527
+ "minLength": 1
528
+ }
529
+ },
530
+ "permittedKeys": {
531
+ "type": "array",
532
+ "items": {
533
+ "type": "string",
534
+ "minLength": 1
535
+ },
536
+ "description": "The closed set of keys the shape admits. Deliberately not refined to be a superset of `requiredKeys`: no AD-5 code names that contradiction, so it joins the cross-field rules left to the compiler in v0. There is no spelling for \"these keys are required and extras are unconstrained\" \u2014 AD-4 calls the descriptor closed, so an open mode would be a different grammar."
537
+ },
538
+ "types": {
539
+ "type": "object",
540
+ "propertyNames": {
541
+ "type": "string",
542
+ "minLength": 1
543
+ },
544
+ "additionalProperties": {
545
+ "anyOf": [
546
+ {
547
+ "type": "string",
548
+ "enum": [
549
+ "string",
550
+ "number",
551
+ "boolean",
552
+ "object",
553
+ "array",
554
+ "null"
555
+ ]
556
+ },
557
+ {
558
+ "type": "null"
559
+ }
560
+ ]
561
+ },
562
+ "description": "Caller-keyed by plain key name, never by pointer: the descriptor-relative pointer spelling does not apply to these keys and must not be extended to them by analogy. A missing key means \"not declared\"; an explicit `null` value means \"declared, type not stated\"."
563
+ }
564
+ },
565
+ "required": [
566
+ "requiredKeys",
567
+ "permittedKeys",
568
+ "types"
569
+ ],
570
+ "additionalProperties": false,
571
+ "description": "AD-18: a header channel declaration names a header and its type and never carries a credential value."
572
+ },
573
+ "body": {
574
+ "type": "object",
575
+ "properties": {
576
+ "requiredKeys": {
577
+ "type": "array",
578
+ "items": {
579
+ "type": "string",
580
+ "minLength": 1
581
+ }
582
+ },
583
+ "permittedKeys": {
584
+ "type": "array",
585
+ "items": {
586
+ "type": "string",
587
+ "minLength": 1
588
+ },
589
+ "description": "The closed set of keys the shape admits. Deliberately not refined to be a superset of `requiredKeys`: no AD-5 code names that contradiction, so it joins the cross-field rules left to the compiler in v0. There is no spelling for \"these keys are required and extras are unconstrained\" \u2014 AD-4 calls the descriptor closed, so an open mode would be a different grammar."
590
+ },
591
+ "types": {
592
+ "type": "object",
593
+ "propertyNames": {
594
+ "type": "string",
595
+ "minLength": 1
596
+ },
597
+ "additionalProperties": {
598
+ "anyOf": [
599
+ {
600
+ "type": "string",
601
+ "enum": [
602
+ "string",
603
+ "number",
604
+ "boolean",
605
+ "object",
606
+ "array",
607
+ "null"
608
+ ]
609
+ },
610
+ {
611
+ "type": "null"
612
+ }
613
+ ]
614
+ },
615
+ "description": "Caller-keyed by plain key name, never by pointer: the descriptor-relative pointer spelling does not apply to these keys and must not be extended to them by analogy. A missing key means \"not declared\"; an explicit `null` value means \"declared, type not stated\"."
616
+ }
617
+ },
618
+ "required": [
619
+ "requiredKeys",
620
+ "permittedKeys",
621
+ "types"
622
+ ],
623
+ "additionalProperties": false
624
+ }
625
+ },
626
+ "required": [
627
+ "path",
628
+ "query",
629
+ "header",
630
+ "body"
631
+ ],
632
+ "additionalProperties": false
633
+ },
634
+ "responseDescriptor": {
635
+ "type": "object",
636
+ "properties": {
637
+ "requiredKeys": {
638
+ "type": "array",
639
+ "items": {
640
+ "type": "string",
641
+ "minLength": 1
642
+ },
643
+ "description": "No minimum of two anywhere in this shape: AD-20 rule 2 relevance is \"the descriptor declares more than one pointer\", so a one-pointer descriptor must parse in order to be the irrelevant case."
644
+ },
645
+ "permittedKeys": {
646
+ "type": "array",
647
+ "items": {
648
+ "type": "string",
649
+ "minLength": 1
650
+ }
651
+ },
652
+ "types": {
653
+ "type": "object",
654
+ "propertyNames": {
655
+ "type": "string",
656
+ "minLength": 1
657
+ },
658
+ "additionalProperties": {
659
+ "anyOf": [
660
+ {
661
+ "type": "string",
662
+ "enum": [
663
+ "string",
664
+ "number",
665
+ "boolean",
666
+ "object",
667
+ "array",
668
+ "null"
669
+ ]
670
+ },
671
+ {
672
+ "type": "null"
673
+ }
674
+ ]
675
+ },
676
+ "description": "Caller-keyed by plain key name, never by pointer: this is the shape where that trap bites, since `requiredKeys` sits beside a pointer-keyed `channelRoles` and a pointer-valued `successIndicator`, and the descriptor-relative spelling must not be extended here by analogy. A missing key means \"not declared\"; an explicit `null` value means \"declared, type not stated\", which is AD-31's enumerated indeterminate descriptor state and the shape `quantifier-over-non-collection` reads."
677
+ },
678
+ "successIndicator": {
679
+ "anyOf": [
680
+ {
681
+ "type": "string",
682
+ "pattern": "^(?:\\/(?:[^/~]|~[01])*)*$",
683
+ "description": "A plain RFC 6901 pointer into one operation's response descriptor. It resolves through the operation an interaction step names, never through the interaction root. A request or response shape's descriptor keys are plain key names rather than pointers, so this spelling does not apply there. The empty string is admitted and carries RFC 6901's own meaning, the whole document: as a nominated success indicator it says success is visible in the response taken as a whole rather than at any one key, and as a channel-role key it assigns a role to the whole body."
684
+ },
685
+ {
686
+ "type": "null"
687
+ }
688
+ ],
689
+ "description": "AD-20 rule 1 relevance reads this as its first conjunct, so `null` must stay representable."
690
+ },
691
+ "channelRoles": {
692
+ "anyOf": [
693
+ {
694
+ "type": "object",
695
+ "propertyNames": {
696
+ "type": "string",
697
+ "pattern": "^(?:\\/(?:[^/~]|~[01])*)*$",
698
+ "description": "A plain RFC 6901 pointer into one operation's response descriptor. It resolves through the operation an interaction step names, never through the interaction root. A request or response shape's descriptor keys are plain key names rather than pointers, so this spelling does not apply there. The empty string is admitted and carries RFC 6901's own meaning, the whole document: as a nominated success indicator it says success is visible in the response taken as a whole rather than at any one key, and as a channel-role key it assigns a role to the whole body."
699
+ },
700
+ "additionalProperties": {
701
+ "type": "string",
702
+ "enum": [
703
+ "success-indicator",
704
+ "diagnostic",
705
+ "payload",
706
+ "collection"
707
+ ]
708
+ }
709
+ },
710
+ {
711
+ "type": "null"
712
+ }
713
+ ],
714
+ "description": "Caller-keyed, and expected to be partial: a missing key means \"no role declared for that pointer\". AD-31 grades absent and explicitly empty differently, so `null`, `{}`, and a populated map are three distinct answers. Deliberately not refined to require a role for every descriptor key: no AD-5 code names that rule, the AD-31 predicates degrade gracefully on partial roles, and a refinement buys nothing an export can carry."
715
+ },
716
+ "collectionLocations": {
717
+ "anyOf": [
718
+ {
719
+ "type": "array",
720
+ "items": {
721
+ "type": "object",
722
+ "properties": {
723
+ "pointer": {
724
+ "type": "string",
725
+ "pattern": "^(?:\\/(?:[^/~]|~[01])*)*$",
726
+ "description": "A plain RFC 6901 pointer into one operation's response descriptor. It resolves through the operation an interaction step names, never through the interaction root. A request or response shape's descriptor keys are plain key names rather than pointers, so this spelling does not apply there. The empty string is admitted and carries RFC 6901's own meaning, the whole document: as a nominated success indicator it says success is visible in the response taken as a whole rather than at any one key, and as a channel-role key it assigns a role to the whole body."
727
+ },
728
+ "expectedCardinality": {
729
+ "oneOf": [
730
+ {
731
+ "type": "object",
732
+ "properties": {
733
+ "mode": {
734
+ "type": "string",
735
+ "const": "exact"
736
+ },
737
+ "count": {
738
+ "type": "integer",
739
+ "minimum": 0,
740
+ "maximum": 9007199254740991
741
+ }
742
+ },
743
+ "required": [
744
+ "mode",
745
+ "count"
746
+ ],
747
+ "additionalProperties": false
748
+ },
749
+ {
750
+ "type": "object",
751
+ "properties": {
752
+ "mode": {
753
+ "type": "string",
754
+ "const": "at-most"
755
+ },
756
+ "max": {
757
+ "type": "integer",
758
+ "minimum": 0,
759
+ "maximum": 9007199254740991
760
+ }
761
+ },
762
+ "required": [
763
+ "mode",
764
+ "max"
765
+ ],
766
+ "additionalProperties": false
767
+ },
768
+ {
769
+ "type": "object",
770
+ "properties": {
771
+ "mode": {
772
+ "type": "string",
773
+ "const": "page-bounded"
774
+ },
775
+ "max": {
776
+ "type": "integer",
777
+ "minimum": 0,
778
+ "maximum": 9007199254740991
779
+ }
780
+ },
781
+ "required": [
782
+ "mode",
783
+ "max"
784
+ ],
785
+ "additionalProperties": false
786
+ }
787
+ ]
788
+ },
789
+ "referenceSet": {
790
+ "anyOf": [
791
+ {
792
+ "type": "string",
793
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
794
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
795
+ },
796
+ {
797
+ "type": "null"
798
+ }
799
+ ],
800
+ "description": "AD-20 rule 6 is relevant when a declared collection location names a reference set, so `null` is the shape that makes the rule irrelevant and must stay representable."
801
+ }
802
+ },
803
+ "required": [
804
+ "pointer",
805
+ "expectedCardinality",
806
+ "referenceSet"
807
+ ],
808
+ "additionalProperties": false
809
+ }
810
+ },
811
+ {
812
+ "type": "null"
813
+ }
814
+ ],
815
+ "description": "AD-20 rule 4 relevance reads this, and AD-31 grades an absent declaration and an explicit empty one differently, so `null` and `[]` are distinct answers."
816
+ }
817
+ },
818
+ "required": [
819
+ "requiredKeys",
820
+ "permittedKeys",
821
+ "types",
822
+ "successIndicator",
823
+ "channelRoles",
824
+ "collectionLocations"
825
+ ],
826
+ "additionalProperties": false
827
+ },
828
+ "volatilePointers": {
829
+ "type": "array",
830
+ "items": {
831
+ "type": "string",
832
+ "pattern": "^(?:\\/(?:[^/~]|~[01])*)*$",
833
+ "description": "A plain RFC 6901 pointer into one operation's response descriptor. It resolves through the operation an interaction step names, never through the interaction root. A request or response shape's descriptor keys are plain key names rather than pointers, so this spelling does not apply there. The empty string is admitted and carries RFC 6901's own meaning, the whole document: as a nominated success indicator it says success is visible in the response taken as a whole rather than at any one key, and as a channel-role key it assigns a role to the whole body."
834
+ }
835
+ },
836
+ "sensitivityWitness": {
837
+ "anyOf": [
838
+ {
839
+ "type": "object",
840
+ "properties": {
841
+ "witnessId": {
842
+ "type": "string",
843
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
844
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
845
+ },
846
+ "channel": {
847
+ "type": "string",
848
+ "enum": [
849
+ "path",
850
+ "query",
851
+ "body"
852
+ ]
853
+ },
854
+ "legs": {
855
+ "minItems": 2,
856
+ "maxItems": 2,
857
+ "type": "array",
858
+ "items": {
859
+ "type": "object",
860
+ "properties": {
861
+ "legId": {
862
+ "type": "string",
863
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
864
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
865
+ },
866
+ "inputs": {
867
+ "$ref": "#/$defs/WitnessInputs"
868
+ }
869
+ },
870
+ "required": [
871
+ "legId",
872
+ "inputs"
873
+ ],
874
+ "additionalProperties": false
875
+ }
876
+ },
877
+ "relation": {
878
+ "$ref": "#/$defs/Expression"
879
+ }
880
+ },
881
+ "required": [
882
+ "witnessId",
883
+ "channel",
884
+ "legs",
885
+ "relation"
886
+ ],
887
+ "additionalProperties": false
888
+ },
889
+ {
890
+ "type": "null"
891
+ }
892
+ ],
893
+ "description": "AD-10, mandatory per declared operation rather than per interface. `null` is legal only for an operation declaring no keys in any request channel; AD-10 exempts that operation and requires the exemption to be recorded, which pre-flight does as an `exempt` check. An input-bearing operation declaring `null` fails a strict compilation under `undeclared-mandatory-input`, alongside the other declaration-completeness check that code already gates."
894
+ }
895
+ },
896
+ "required": [
897
+ "operationId",
898
+ "method",
899
+ "pathTemplate",
900
+ "stateChangeMarker",
901
+ "requestShape",
902
+ "responseDescriptor",
903
+ "volatilePointers",
904
+ "sensitivityWitness"
905
+ ],
906
+ "additionalProperties": false
907
+ },
908
+ "description": "No uniqueness constraint: two operations colliding on method plus path template after parameter-name erasure is `duplicate-operation-signature`, a coded compile-time error, and a schema that deduped them would delete it."
909
+ }
910
+ },
911
+ "required": [
912
+ "logicalId",
913
+ "kind",
914
+ "operations"
915
+ ],
916
+ "additionalProperties": false
917
+ },
918
+ "description": "AD-35: logical identifiers only. No entry here is ever a URL, a host, or a port."
919
+ },
920
+ "referenceSets": {
921
+ "anyOf": [
922
+ {
923
+ "type": "object",
924
+ "propertyNames": {
925
+ "type": "string",
926
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
927
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
928
+ },
929
+ "additionalProperties": {
930
+ "type": "object",
931
+ "properties": {
932
+ "keys": {
933
+ "minItems": 1,
934
+ "type": "array",
935
+ "items": {
936
+ "type": "string",
937
+ "minLength": 1
938
+ },
939
+ "description": "The key names members are compared on. A reference set with no keys names nothing to compare, and no AD-5 code fires on it, so the schema is the enforcement point."
940
+ },
941
+ "members": {
942
+ "type": "array",
943
+ "items": {
944
+ "type": "object",
945
+ "propertyNames": {
946
+ "type": "string"
947
+ },
948
+ "additionalProperties": {
949
+ "$ref": "#/$defs/JsonValue"
950
+ }
951
+ },
952
+ "description": "Objects carrying at least the declared keys. That they do is deliberately not refined: no AD-5 code names it, and a refinement would be invisible to a non-TypeScript consumer and become a disagreement in the published-schema differential check."
953
+ },
954
+ "commentary": {
955
+ "anyOf": [
956
+ {
957
+ "type": "string"
958
+ },
959
+ {
960
+ "type": "null"
961
+ }
962
+ ],
963
+ "description": "Author documentation. Named `commentary` rather than the Gate C fixture's `note` so the sealed brief has one word to exclude, matching the oracle field of the same name. No predicate reads it."
964
+ }
965
+ },
966
+ "required": [
967
+ "keys",
968
+ "members",
969
+ "commentary"
970
+ ],
971
+ "additionalProperties": false
972
+ }
973
+ },
974
+ {
975
+ "type": "null"
976
+ }
977
+ ],
978
+ "description": "Caller-keyed by reference-set identifier. AD-31 grades an absent declaration and an explicit empty one differently, so `null`, `{}`, and a populated map are three distinct answers."
979
+ },
980
+ "siblingGroups": {
981
+ "anyOf": [
982
+ {
983
+ "type": "object",
984
+ "properties": {
985
+ "operations": {
986
+ "type": "array",
987
+ "items": {
988
+ "minItems": 2,
989
+ "type": "array",
990
+ "items": {
991
+ "type": "string",
992
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
993
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
994
+ }
995
+ }
996
+ },
997
+ "parameters": {
998
+ "type": "array",
999
+ "items": {
1000
+ "minItems": 2,
1001
+ "type": "array",
1002
+ "items": {
1003
+ "type": "string",
1004
+ "minLength": 1
1005
+ }
1006
+ }
1007
+ }
1008
+ },
1009
+ "required": [
1010
+ "operations",
1011
+ "parameters"
1012
+ ],
1013
+ "additionalProperties": false
1014
+ },
1015
+ {
1016
+ "type": "null"
1017
+ }
1018
+ ],
1019
+ "description": "AD-20 rule 5 relevance reads this. `null` is absent, `{ \"operations\": [], \"parameters\": [] }` is the explicit empty answer AD-19 calls a declaration, and a populated group makes the rule relevant."
1020
+ },
1021
+ "interactionPlan": {
1022
+ "type": "array",
1023
+ "items": {
1024
+ "type": "object",
1025
+ "properties": {
1026
+ "stepId": {
1027
+ "type": "string",
1028
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1029
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
1030
+ },
1031
+ "operationId": {
1032
+ "type": "string",
1033
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1034
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
1035
+ },
1036
+ "inputBinding": {
1037
+ "type": "object",
1038
+ "properties": {
1039
+ "path": {
1040
+ "$ref": "#/$defs/InputBindingChannel"
1041
+ },
1042
+ "query": {
1043
+ "$ref": "#/$defs/InputBindingChannel"
1044
+ },
1045
+ "header": {
1046
+ "$ref": "#/$defs/InputBindingChannel"
1047
+ },
1048
+ "body": {
1049
+ "$ref": "#/$defs/InputBindingChannel"
1050
+ }
1051
+ },
1052
+ "required": [
1053
+ "path",
1054
+ "query",
1055
+ "header",
1056
+ "body"
1057
+ ],
1058
+ "additionalProperties": false
1059
+ },
1060
+ "after": {
1061
+ "anyOf": [
1062
+ {
1063
+ "type": "string",
1064
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1065
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
1066
+ },
1067
+ {
1068
+ "type": "null"
1069
+ }
1070
+ ],
1071
+ "description": "The temporal clause: the identifier of an earlier step, or `null`. That the named step carries no clause of its own is AD-39's one-level bound, which fires `nested-temporal-clause` at compile time and is deliberately not enforced here, so the code keeps a shape to fire on."
1072
+ }
1073
+ },
1074
+ "required": [
1075
+ "stepId",
1076
+ "operationId",
1077
+ "inputBinding",
1078
+ "after"
1079
+ ],
1080
+ "additionalProperties": false
1081
+ },
1082
+ "description": "No maximum and no bound on `after` chains. `plan-exceeds-scripting-bound` needs the sixty-four-pair and eight-chain plans representable, and the compiler owns the graph predicate. An empty plan is the cheapest `unreachable-check-evidence` fixture."
1083
+ },
1084
+ "scopedResources": {
1085
+ "anyOf": [
1086
+ {
1087
+ "type": "array",
1088
+ "items": {
1089
+ "type": "object",
1090
+ "properties": {
1091
+ "reference": {
1092
+ "type": "string",
1093
+ "minLength": 1
1094
+ },
1095
+ "kind": {
1096
+ "type": "string",
1097
+ "minLength": 1
1098
+ }
1099
+ },
1100
+ "required": [
1101
+ "reference",
1102
+ "kind"
1103
+ ],
1104
+ "additionalProperties": false
1105
+ }
1106
+ },
1107
+ {
1108
+ "type": "null"
1109
+ }
1110
+ ],
1111
+ "description": "Absent, empty, and populated are three distinct answers. A reference at all is what `scoped-reference-resolves-forbidden` fires on."
1112
+ },
1113
+ "forbiddenInputs": {
1114
+ "type": "array",
1115
+ "items": {
1116
+ "type": "string",
1117
+ "enum": [
1118
+ "original-spec",
1119
+ "source-code",
1120
+ "repository",
1121
+ "builder-transcript",
1122
+ "implementation-logs",
1123
+ "comparator-results",
1124
+ "human-labels"
1125
+ ]
1126
+ },
1127
+ "description": "A list short of the seven is `forbidden-input-floor-incomplete`, a coded compile-time error, so a short list must parse."
1128
+ },
1129
+ "testData": {
1130
+ "type": "object",
1131
+ "properties": {
1132
+ "setup": {
1133
+ "anyOf": [
1134
+ {
1135
+ "type": "string"
1136
+ },
1137
+ {
1138
+ "type": "null"
1139
+ }
1140
+ ]
1141
+ },
1142
+ "cleanup": {
1143
+ "anyOf": [
1144
+ {
1145
+ "type": "string"
1146
+ },
1147
+ {
1148
+ "type": "null"
1149
+ }
1150
+ ]
1151
+ }
1152
+ },
1153
+ "required": [
1154
+ "setup",
1155
+ "cleanup"
1156
+ ],
1157
+ "additionalProperties": false
1158
+ },
1159
+ "budgets": {
1160
+ "type": "object",
1161
+ "properties": {
1162
+ "maxToolCalls": {
1163
+ "type": "integer",
1164
+ "minimum": 0,
1165
+ "maximum": 9007199254740991
1166
+ },
1167
+ "maxWallClockMinutes": {
1168
+ "type": "integer",
1169
+ "minimum": 0,
1170
+ "maximum": 9007199254740991
1171
+ },
1172
+ "maxCostUsd": {
1173
+ "type": "string",
1174
+ "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
1175
+ "description": "Money, so AD-36 carries it as a string in a declared format rather than as a JSON number. Constrained to the unsigned form: a negative ceiling is not a ceiling."
1176
+ }
1177
+ },
1178
+ "required": [
1179
+ "maxToolCalls",
1180
+ "maxWallClockMinutes",
1181
+ "maxCostUsd"
1182
+ ],
1183
+ "additionalProperties": false
1184
+ },
1185
+ "safetyLimits": {
1186
+ "type": "array",
1187
+ "items": {
1188
+ "type": "string"
1189
+ }
1190
+ },
1191
+ "requiredEvidence": {
1192
+ "type": "array",
1193
+ "items": {
1194
+ "type": "string"
1195
+ }
1196
+ },
1197
+ "probeStepBound": {
1198
+ "anyOf": [
1199
+ {
1200
+ "type": "integer",
1201
+ "minimum": 0,
1202
+ "maximum": 9007199254740991
1203
+ },
1204
+ {
1205
+ "type": "null"
1206
+ }
1207
+ ],
1208
+ "description": "AD-16's declared bound on enumerated probe steps, which the brief-side scripting audit reads. No AD gives it a home and the Configuration convention's policy-artifact list omits it, so it lands here beside the other ceilings. The AD-5 code that audit fires is `brief-exceeds-scripting-bound`."
1209
+ },
1210
+ "fixtureReset": {
1211
+ "anyOf": [
1212
+ {
1213
+ "type": "object",
1214
+ "properties": {
1215
+ "legId": {
1216
+ "type": "string",
1217
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1218
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
1219
+ },
1220
+ "interfaceId": {
1221
+ "type": "string",
1222
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1223
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
1224
+ },
1225
+ "operationId": {
1226
+ "type": "string",
1227
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1228
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
1229
+ },
1230
+ "inputs": {
1231
+ "$ref": "#/$defs/WitnessInputs"
1232
+ }
1233
+ },
1234
+ "required": [
1235
+ "legId",
1236
+ "interfaceId",
1237
+ "operationId",
1238
+ "inputs"
1239
+ ],
1240
+ "additionalProperties": false
1241
+ },
1242
+ {
1243
+ "type": "null"
1244
+ }
1245
+ ],
1246
+ "description": "AD-10's per-run state reset, declared as the operation that performs it, so the reset is one more probe leg through the environment-probe port. `null` selects AD-10's repeated-read immutability branch, which is also the check that catches a volatile response field the contract failed to declare."
1247
+ }
1248
+ },
1249
+ "required": [
1250
+ "schemaVersion",
1251
+ "parentDigest",
1252
+ "revisionCount",
1253
+ "contractId",
1254
+ "sourceSpecDigest",
1255
+ "behaviors",
1256
+ "oracles",
1257
+ "rubrics",
1258
+ "waivers",
1259
+ "permittedInterfaces",
1260
+ "referenceSets",
1261
+ "siblingGroups",
1262
+ "interactionPlan",
1263
+ "scopedResources",
1264
+ "forbiddenInputs",
1265
+ "testData",
1266
+ "budgets",
1267
+ "safetyLimits",
1268
+ "requiredEvidence",
1269
+ "probeStepBound",
1270
+ "fixtureReset"
1271
+ ],
1272
+ "additionalProperties": false,
1273
+ "description": "The Eval Contract. Succeeds the prior-art `eval-contract` schema per AD-24. It carries every declaration AD-19 requires so that AD-31's fourteen relevance and satisfaction predicates are decidable from declarations alone. AD-10's sensitivity witnesses arrived in this version, on each operation, as the additive `schemaVersion` bump AD-11 requires; the bump is recorded in each new field's own description, since no reader in this version declares an expected version constant to compare against.",
1274
+ "$defs": {
1275
+ "Expression": {
1276
+ "description": "A `check` expression tree over AD-4's closed vocabulary, discriminated on `op`. Exports as a `oneOf` of sixteen branches, each identified by its `op` const; a constraint ledger entry names a branch by that const rather than by position.",
1277
+ "oneOf": [
1278
+ {
1279
+ "type": "object",
1280
+ "properties": {
1281
+ "op": {
1282
+ "type": "string",
1283
+ "const": "equality"
1284
+ },
1285
+ "operands": {
1286
+ "type": "array",
1287
+ "prefixItems": [
1288
+ {
1289
+ "$ref": "#/$defs/Operand"
1290
+ },
1291
+ {
1292
+ "$ref": "#/$defs/Operand"
1293
+ }
1294
+ ],
1295
+ "description": "Two operands, each legally a pointer or a literal. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1296
+ "minItems": 2,
1297
+ "items": false
1298
+ }
1299
+ },
1300
+ "required": [
1301
+ "op",
1302
+ "operands"
1303
+ ],
1304
+ "additionalProperties": false
1305
+ },
1306
+ {
1307
+ "type": "object",
1308
+ "properties": {
1309
+ "op": {
1310
+ "type": "string",
1311
+ "const": "deep-equality"
1312
+ },
1313
+ "operands": {
1314
+ "type": "array",
1315
+ "prefixItems": [
1316
+ {
1317
+ "$ref": "#/$defs/Operand"
1318
+ },
1319
+ {
1320
+ "$ref": "#/$defs/Operand"
1321
+ }
1322
+ ],
1323
+ "description": "Two operands, each legally a pointer or a literal. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1324
+ "minItems": 2,
1325
+ "items": false
1326
+ }
1327
+ },
1328
+ "required": [
1329
+ "op",
1330
+ "operands"
1331
+ ],
1332
+ "additionalProperties": false
1333
+ },
1334
+ {
1335
+ "type": "object",
1336
+ "properties": {
1337
+ "op": {
1338
+ "type": "string",
1339
+ "const": "containment"
1340
+ },
1341
+ "operands": {
1342
+ "type": "array",
1343
+ "prefixItems": [
1344
+ {
1345
+ "$ref": "#/$defs/Operand"
1346
+ },
1347
+ {
1348
+ "$ref": "#/$defs/Operand"
1349
+ }
1350
+ ],
1351
+ "description": "Two operands: the container is legally a pointer, and the set is legally a pointer, a literal, or a reference set. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1352
+ "minItems": 2,
1353
+ "items": false
1354
+ }
1355
+ },
1356
+ "required": [
1357
+ "op",
1358
+ "operands"
1359
+ ],
1360
+ "additionalProperties": false
1361
+ },
1362
+ {
1363
+ "type": "object",
1364
+ "properties": {
1365
+ "op": {
1366
+ "type": "string",
1367
+ "const": "existence"
1368
+ },
1369
+ "operands": {
1370
+ "type": "array",
1371
+ "prefixItems": [
1372
+ {
1373
+ "$ref": "#/$defs/Operand"
1374
+ }
1375
+ ],
1376
+ "description": "One operand, legally a pointer. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1377
+ "minItems": 1,
1378
+ "items": false
1379
+ }
1380
+ },
1381
+ "required": [
1382
+ "op",
1383
+ "operands"
1384
+ ],
1385
+ "additionalProperties": false
1386
+ },
1387
+ {
1388
+ "type": "object",
1389
+ "properties": {
1390
+ "op": {
1391
+ "type": "string",
1392
+ "const": "absence"
1393
+ },
1394
+ "operands": {
1395
+ "type": "array",
1396
+ "prefixItems": [
1397
+ {
1398
+ "$ref": "#/$defs/Operand"
1399
+ }
1400
+ ],
1401
+ "description": "One operand, legally a pointer. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1402
+ "minItems": 1,
1403
+ "items": false
1404
+ }
1405
+ },
1406
+ "required": [
1407
+ "op",
1408
+ "operands"
1409
+ ],
1410
+ "additionalProperties": false
1411
+ },
1412
+ {
1413
+ "type": "object",
1414
+ "properties": {
1415
+ "op": {
1416
+ "type": "string",
1417
+ "const": "regex"
1418
+ },
1419
+ "operands": {
1420
+ "type": "array",
1421
+ "prefixItems": [
1422
+ {
1423
+ "$ref": "#/$defs/Operand"
1424
+ }
1425
+ ],
1426
+ "description": "One operand, legally a pointer. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1427
+ "minItems": 1,
1428
+ "items": false
1429
+ },
1430
+ "pattern": {
1431
+ "type": "string",
1432
+ "pattern": "^\\^[\\s\\S]*\\$$",
1433
+ "description": "An ECMA-262 pattern, fully anchored: it begins with \"^\" and ends with \"$\". A named field rather than a `{ literal }` operand, so the compiler's backreference and lookbehind check has one place to look instead of a JsonValue that may hold anything. The check is positional and is wrong in both directions. It admits patterns that are not anchored, such as the alternation \"^a|b$\" or a trailing \"$\" that is escaped; those are the compiler's, alongside backreferences and lookbehind. It also rejects patterns that are anchored but wrapped in a group, such as \"(^a$)\" \u2014 write \"^(?:a|b)$\" rather than \"(?:^a$|^b$)\" and the form accepts it. Deciding anchoring properly requires parsing the pattern, which no JSON Schema keyword can express."
1434
+ }
1435
+ },
1436
+ "required": [
1437
+ "op",
1438
+ "operands",
1439
+ "pattern"
1440
+ ],
1441
+ "additionalProperties": false
1442
+ },
1443
+ {
1444
+ "type": "object",
1445
+ "properties": {
1446
+ "op": {
1447
+ "type": "string",
1448
+ "const": "set-membership"
1449
+ },
1450
+ "operands": {
1451
+ "type": "array",
1452
+ "prefixItems": [
1453
+ {
1454
+ "$ref": "#/$defs/Operand"
1455
+ },
1456
+ {
1457
+ "anyOf": [
1458
+ {
1459
+ "type": "object",
1460
+ "properties": {
1461
+ "referenceSet": {
1462
+ "type": "string",
1463
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1464
+ "description": "A plain identifier. Deliberately not an enum of the contract's declared reference sets and deliberately not refined against them: an identifier the contract does not declare is `unresolved-reference-set`, a coded compile-time error, and a schema that rejected it would convert that code into an anonymous parse fault."
1465
+ }
1466
+ },
1467
+ "required": [
1468
+ "referenceSet"
1469
+ ],
1470
+ "additionalProperties": false
1471
+ },
1472
+ {
1473
+ "type": "object",
1474
+ "properties": {
1475
+ "literal": {
1476
+ "minItems": 1,
1477
+ "type": "array",
1478
+ "items": {
1479
+ "$ref": "#/$defs/JsonValue"
1480
+ },
1481
+ "description": "Coin flip (b), settled: a literal set operand is admitted alongside the reference-set form, and is constrained to a non-empty array because `set-membership` against an empty set is unfalsifiable authoring rather than an observation about the world. This is the one deliberately narrowed operand position in the grammar; the cost is that `{ \"literal\": [] }` and a `{ \"pointer\" }` in this position are schema rejections rather than `malformed-operator-expression`."
1482
+ }
1483
+ },
1484
+ "required": [
1485
+ "literal"
1486
+ ],
1487
+ "additionalProperties": false
1488
+ }
1489
+ ]
1490
+ }
1491
+ ],
1492
+ "description": "Two operands: the value is legally a pointer, and the set is a reference set or a non-empty literal array. The set position is the one place the schema does narrow, and coin flip (b) records what that costs. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1493
+ "minItems": 2,
1494
+ "items": false
1495
+ }
1496
+ },
1497
+ "required": [
1498
+ "op",
1499
+ "operands"
1500
+ ],
1501
+ "additionalProperties": false
1502
+ },
1503
+ {
1504
+ "type": "object",
1505
+ "properties": {
1506
+ "op": {
1507
+ "type": "string",
1508
+ "const": "ordering"
1509
+ },
1510
+ "operands": {
1511
+ "type": "array",
1512
+ "prefixItems": [
1513
+ {
1514
+ "$ref": "#/$defs/Operand"
1515
+ }
1516
+ ],
1517
+ "description": "One operand, legally a pointer to a collection. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1518
+ "minItems": 1,
1519
+ "items": false
1520
+ },
1521
+ "key": {
1522
+ "type": "string",
1523
+ "minLength": 1
1524
+ },
1525
+ "order": {
1526
+ "type": "string",
1527
+ "enum": [
1528
+ "ascending",
1529
+ "descending"
1530
+ ]
1531
+ }
1532
+ },
1533
+ "required": [
1534
+ "op",
1535
+ "operands",
1536
+ "key",
1537
+ "order"
1538
+ ],
1539
+ "additionalProperties": false
1540
+ },
1541
+ {
1542
+ "type": "object",
1543
+ "properties": {
1544
+ "op": {
1545
+ "type": "string",
1546
+ "const": "count-tolerance"
1547
+ },
1548
+ "operands": {
1549
+ "type": "array",
1550
+ "prefixItems": [
1551
+ {
1552
+ "$ref": "#/$defs/Operand"
1553
+ }
1554
+ ],
1555
+ "description": "One operand, legally a pointer to a collection. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1556
+ "minItems": 1,
1557
+ "items": false
1558
+ },
1559
+ "expected": {
1560
+ "type": "integer",
1561
+ "minimum": 0,
1562
+ "maximum": 9007199254740991,
1563
+ "description": "The expected element count. Non-negative: a negative count is not a count, and no AD-5 code fires on one, so the schema is the enforcement point."
1564
+ },
1565
+ "tolerance": {
1566
+ "type": "integer",
1567
+ "minimum": 0,
1568
+ "maximum": 9007199254740991,
1569
+ "description": "The permitted deviation from `expected`, non-negative for the same reason. When `relative` is declared the tolerance is read as whole percentage points, which is stated because AD-4 supplies no value space for the magnitude and any reader that resolves this check inherits the semantics. An integer therefore cannot express a fractional relative tolerance such as 2.5 percent; widening the value space later is an additive `schemaVersion` bump under AD-11, and was not taken here because it would export as a bare `type: \"number\"` and cost a constraint ledger entry for a case no declaration needs yet."
1570
+ },
1571
+ "relative": {
1572
+ "type": "boolean",
1573
+ "description": "AD-4: the tolerance is absolute unless this flag is declared. Required and explicit rather than defaulted, because a Zod default diverges input and output mode and drops the key from the exported `required` list."
1574
+ }
1575
+ },
1576
+ "required": [
1577
+ "op",
1578
+ "operands",
1579
+ "expected",
1580
+ "tolerance",
1581
+ "relative"
1582
+ ],
1583
+ "additionalProperties": false
1584
+ },
1585
+ {
1586
+ "type": "object",
1587
+ "properties": {
1588
+ "op": {
1589
+ "type": "string",
1590
+ "const": "shape"
1591
+ },
1592
+ "operands": {
1593
+ "type": "array",
1594
+ "prefixItems": [
1595
+ {
1596
+ "$ref": "#/$defs/Operand"
1597
+ }
1598
+ ],
1599
+ "description": "One operand, legally a pointer. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1600
+ "minItems": 1,
1601
+ "items": false
1602
+ },
1603
+ "descriptor": {
1604
+ "type": "object",
1605
+ "properties": {
1606
+ "requiredKeys": {
1607
+ "type": "array",
1608
+ "items": {
1609
+ "type": "string",
1610
+ "minLength": 1
1611
+ }
1612
+ },
1613
+ "permittedKeys": {
1614
+ "type": "array",
1615
+ "items": {
1616
+ "type": "string",
1617
+ "minLength": 1
1618
+ },
1619
+ "description": "The closed set of keys the shape admits. Deliberately not refined to be a superset of `requiredKeys`: no AD-5 code names that contradiction, so it joins the cross-field rules left to the compiler in v0. There is no spelling for \"these keys are required and extras are unconstrained\" \u2014 AD-4 calls the descriptor closed, so an open mode would be a different grammar."
1620
+ },
1621
+ "types": {
1622
+ "type": "object",
1623
+ "propertyNames": {
1624
+ "type": "string",
1625
+ "minLength": 1
1626
+ },
1627
+ "additionalProperties": {
1628
+ "anyOf": [
1629
+ {
1630
+ "type": "string",
1631
+ "enum": [
1632
+ "string",
1633
+ "number",
1634
+ "boolean",
1635
+ "object",
1636
+ "array",
1637
+ "null"
1638
+ ]
1639
+ },
1640
+ {
1641
+ "type": "null"
1642
+ }
1643
+ ]
1644
+ },
1645
+ "description": "Caller-keyed by plain key name, never by pointer: the descriptor-relative pointer spelling does not apply to these keys and must not be extended to them by analogy. A missing key means \"not declared\"; an explicit `null` value means \"declared, type not stated\"."
1646
+ }
1647
+ },
1648
+ "required": [
1649
+ "requiredKeys",
1650
+ "permittedKeys",
1651
+ "types"
1652
+ ],
1653
+ "additionalProperties": false,
1654
+ "description": "AD-4: a closed descriptor, never an embedded JSON Schema. Typing it as a named field is what makes that structural, and it is a deliberate divergence from the Gate C fixture's `{ \"literal\": { \u2026 } }` spelling, where any JSON could sit."
1655
+ }
1656
+ },
1657
+ "required": [
1658
+ "op",
1659
+ "operands",
1660
+ "descriptor"
1661
+ ],
1662
+ "additionalProperties": false
1663
+ },
1664
+ {
1665
+ "type": "object",
1666
+ "properties": {
1667
+ "op": {
1668
+ "type": "string",
1669
+ "const": "covers-by-key"
1670
+ },
1671
+ "operands": {
1672
+ "type": "array",
1673
+ "prefixItems": [
1674
+ {
1675
+ "$ref": "#/$defs/Operand"
1676
+ },
1677
+ {
1678
+ "$ref": "#/$defs/Operand"
1679
+ }
1680
+ ],
1681
+ "description": "Two operands: `expected` is legally a reference set, and `actual` is legally a pointer to a collection. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it.",
1682
+ "minItems": 2,
1683
+ "items": false
1684
+ },
1685
+ "expectedKey": {
1686
+ "type": "string",
1687
+ "minLength": 1
1688
+ },
1689
+ "actualKey": {
1690
+ "type": "string",
1691
+ "minLength": 1
1692
+ }
1693
+ },
1694
+ "required": [
1695
+ "op",
1696
+ "operands",
1697
+ "expectedKey",
1698
+ "actualKey"
1699
+ ],
1700
+ "additionalProperties": false
1701
+ },
1702
+ {
1703
+ "type": "object",
1704
+ "properties": {
1705
+ "op": {
1706
+ "type": "string",
1707
+ "const": "not"
1708
+ },
1709
+ "operands": {
1710
+ "type": "array",
1711
+ "prefixItems": [
1712
+ {
1713
+ "$ref": "#/$defs/Expression"
1714
+ }
1715
+ ],
1716
+ "description": "One nested expression rather than an operand. A connective composes the tree; it never addresses evidence itself.",
1717
+ "minItems": 1,
1718
+ "items": false
1719
+ }
1720
+ },
1721
+ "required": [
1722
+ "op",
1723
+ "operands"
1724
+ ],
1725
+ "additionalProperties": false
1726
+ },
1727
+ {
1728
+ "type": "object",
1729
+ "properties": {
1730
+ "op": {
1731
+ "type": "string",
1732
+ "const": "all"
1733
+ },
1734
+ "operands": {
1735
+ "minItems": 2,
1736
+ "type": "array",
1737
+ "items": {
1738
+ "$ref": "#/$defs/Expression"
1739
+ },
1740
+ "description": "Two or more nested expressions rather than operands. The minimum is settled here because AD-4 leaves connective arity unstated: zero operands would certify vacuously and one is the identity."
1741
+ }
1742
+ },
1743
+ "required": [
1744
+ "op",
1745
+ "operands"
1746
+ ],
1747
+ "additionalProperties": false
1748
+ },
1749
+ {
1750
+ "type": "object",
1751
+ "properties": {
1752
+ "op": {
1753
+ "type": "string",
1754
+ "const": "any"
1755
+ },
1756
+ "operands": {
1757
+ "minItems": 2,
1758
+ "type": "array",
1759
+ "items": {
1760
+ "$ref": "#/$defs/Expression"
1761
+ },
1762
+ "description": "Two or more nested expressions rather than operands, for the same reason `all` carries the same minimum."
1763
+ }
1764
+ },
1765
+ "required": [
1766
+ "op",
1767
+ "operands"
1768
+ ],
1769
+ "additionalProperties": false
1770
+ },
1771
+ {
1772
+ "type": "object",
1773
+ "properties": {
1774
+ "op": {
1775
+ "type": "string",
1776
+ "const": "for-all"
1777
+ },
1778
+ "collection": {
1779
+ "$ref": "#/$defs/Operand"
1780
+ },
1781
+ "predicate": {
1782
+ "$ref": "#/$defs/Expression"
1783
+ }
1784
+ },
1785
+ "required": [
1786
+ "op",
1787
+ "collection",
1788
+ "predicate"
1789
+ ],
1790
+ "additionalProperties": false,
1791
+ "description": "`collection` is legally a pointer to a collection, and `predicate` is the expression each bound element is tested against, addressed by the `@/` pointer spelling. A quantifier inside the predicate is structurally admitted so `quantifier-nesting-exceeded` keeps a shape to fire on. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it."
1792
+ },
1793
+ {
1794
+ "type": "object",
1795
+ "properties": {
1796
+ "op": {
1797
+ "type": "string",
1798
+ "const": "for-any"
1799
+ },
1800
+ "collection": {
1801
+ "$ref": "#/$defs/Operand"
1802
+ },
1803
+ "predicate": {
1804
+ "$ref": "#/$defs/Expression"
1805
+ }
1806
+ },
1807
+ "required": [
1808
+ "op",
1809
+ "collection",
1810
+ "predicate"
1811
+ ],
1812
+ "additionalProperties": false,
1813
+ "description": "`collection` is legally a pointer to a collection, and `predicate` is the expression each bound element is tested against, addressed by the `@/` pointer spelling. Every position admits the full operand union on purpose. AD-26 makes a reference-set operand outside its three legal positions \u2014 `covers-by-key`'s expected operand, and the set operand of `set-membership` or `containment` \u2014 fail compilation under `malformed-operator-expression`, which only stays fireable if the other positions admit it. Compilation enforces the legality stated here; the schema does not narrow it."
1814
+ }
1815
+ ]
1816
+ },
1817
+ "Operand": {
1818
+ "anyOf": [
1819
+ {
1820
+ "type": "object",
1821
+ "properties": {
1822
+ "pointer": {
1823
+ "anyOf": [
1824
+ {
1825
+ "type": "string",
1826
+ "pattern": "^\\/interactions\\/[a-z0-9]+(?:-[a-z0-9]+)*\\/(?:(?:response-body|response-headers|stdout|stderr)(?:\\/(?:[^/~]|~[01])*)*|(?:response-status|exit-code)|call-inputs\\/(?:path|query|header|body)(?:\\/(?:[^/~]|~[01])*)*)$",
1827
+ "description": "AD-26 interaction-rooted pointer: \"/interactions/{stepId}/\" followed by one channel of the closed vocabulary. `call-inputs` takes one of the four transport channels as its next segment; `response-status` and `exit-code` take no tail. Syntax only: whether the step exists and whether the evidence is reachable are compile-time checks, not schema checks."
1828
+ },
1829
+ {
1830
+ "type": "string",
1831
+ "pattern": "^@(?:\\/(?:[^/~]|~[01])*)+$",
1832
+ "description": "AD-26 bound-element pointer: \"@/\" plus an RFC 6901 tail, addressing the element a quantifier binds. Bare \"@/\" addresses the element itself. That it appears only inside a quantifier is a compile-time check, not a schema check."
1833
+ }
1834
+ ]
1835
+ }
1836
+ },
1837
+ "required": [
1838
+ "pointer"
1839
+ ],
1840
+ "additionalProperties": false
1841
+ },
1842
+ {
1843
+ "type": "object",
1844
+ "properties": {
1845
+ "literal": {
1846
+ "$ref": "#/$defs/JsonValue"
1847
+ }
1848
+ },
1849
+ "required": [
1850
+ "literal"
1851
+ ],
1852
+ "additionalProperties": false
1853
+ },
1854
+ {
1855
+ "type": "object",
1856
+ "properties": {
1857
+ "referenceSet": {
1858
+ "type": "string",
1859
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1860
+ "description": "A plain identifier. Deliberately not an enum of the contract's declared reference sets and deliberately not refined against them: an identifier the contract does not declare is `unresolved-reference-set`, a coded compile-time error, and a schema that rejected it would convert that code into an anonymous parse fault."
1861
+ }
1862
+ },
1863
+ "required": [
1864
+ "referenceSet"
1865
+ ],
1866
+ "additionalProperties": false
1867
+ }
1868
+ ],
1869
+ "description": "One of the three operand forms, each a single-keyed object. Named so the published schema carries it once as a shared definition rather than inlining it at seventeen use sites. Which forms are legal in which position is declared on each operator's own `operands`, never narrowed here."
1870
+ },
1871
+ "JsonValue": {
1872
+ "description": "AD-36 value domain. Every number is a finite IEEE 754 double-precision value, and every integer lies in the safe-integer range; a larger integer, and any value needing exact decimal semantics such as money, is carried as a string in its own declared format. JSON Schema cannot express finiteness, so this restriction is stated rather than encoded: producers are told the rule here instead of discovering it through a digest mismatch, and the canonical scanner rejects a violating value before any parse.",
1873
+ "anyOf": [
1874
+ {
1875
+ "type": "string"
1876
+ },
1877
+ {
1878
+ "type": "number"
1879
+ },
1880
+ {
1881
+ "type": "boolean"
1882
+ },
1883
+ {
1884
+ "type": "null"
1885
+ },
1886
+ {
1887
+ "type": "array",
1888
+ "items": {
1889
+ "$ref": "#/$defs/JsonValue"
1890
+ }
1891
+ },
1892
+ {
1893
+ "type": "object",
1894
+ "propertyNames": {
1895
+ "type": "string"
1896
+ },
1897
+ "additionalProperties": {
1898
+ "$ref": "#/$defs/JsonValue"
1899
+ }
1900
+ }
1901
+ ]
1902
+ },
1903
+ "RubricBody": {
1904
+ "type": "object",
1905
+ "properties": {
1906
+ "id": {
1907
+ "type": "string",
1908
+ "pattern": "^R-[0-9]{3,}$"
1909
+ },
1910
+ "scaleLevels": {
1911
+ "anyOf": [
1912
+ {
1913
+ "type": "array",
1914
+ "items": {
1915
+ "type": "object",
1916
+ "properties": {
1917
+ "level": {
1918
+ "type": "integer",
1919
+ "minimum": -9007199254740991,
1920
+ "maximum": 9007199254740991,
1921
+ "description": "The ordinal this level sits at. A repeated ordinal is the one half the compiler closes, failing under `rubric-unanchored`, since two levels at one ordinal make the ordinal address two anchors. Magnitude, sign, ordering, and contiguity stay free everywhere, because a scale running -2 to 2 or 1, 3, 5 is an ordinary authoring choice."
1922
+ },
1923
+ "anchor": {
1924
+ "type": "string",
1925
+ "description": "The observable condition that anchors this level. AD-22 calls an unanchored scale a compile-time failure under `rubric-unanchored`, so the anchor is a declared field rather than a convention."
1926
+ }
1927
+ },
1928
+ "required": [
1929
+ "level",
1930
+ "anchor"
1931
+ ],
1932
+ "additionalProperties": false
1933
+ }
1934
+ },
1935
+ {
1936
+ "type": "null"
1937
+ }
1938
+ ],
1939
+ "description": "`null` and `[]` are both the unanchored shape `rubric-unanchored` fires on, and both must parse."
1940
+ },
1941
+ "failureModePenalties": {
1942
+ "anyOf": [
1943
+ {
1944
+ "type": "array",
1945
+ "items": {
1946
+ "type": "object",
1947
+ "properties": {
1948
+ "name": {
1949
+ "type": "string",
1950
+ "minLength": 1
1951
+ },
1952
+ "description": {
1953
+ "type": "string",
1954
+ "description": "AD-22 requires named failure-mode penalties and states no magnitude. None is invented here: a penalty weight would be a scoring semantic no module below `score` has authority to mint, and AD-7 keeps weighted composites out of the reported result. AD-22's compile checks ship without one, so a penalty carries a name and a description and nothing else."
1955
+ }
1956
+ },
1957
+ "required": [
1958
+ "name",
1959
+ "description"
1960
+ ],
1961
+ "additionalProperties": false
1962
+ }
1963
+ },
1964
+ {
1965
+ "type": "null"
1966
+ }
1967
+ ],
1968
+ "description": "Missing named penalties is `rubric-unanchored`, not a parse failure."
1969
+ },
1970
+ "maxLength": {
1971
+ "anyOf": [
1972
+ {
1973
+ "type": "integer",
1974
+ "minimum": 1,
1975
+ "maximum": 9007199254740991
1976
+ },
1977
+ {
1978
+ "type": "null"
1979
+ }
1980
+ ],
1981
+ "description": "An unbounded length is `null`, which is one of the shapes `rubric-unanchored` fires on."
1982
+ },
1983
+ "criteria": {
1984
+ "type": "array",
1985
+ "items": {
1986
+ "type": "object",
1987
+ "properties": {
1988
+ "id": {
1989
+ "type": "string",
1990
+ "pattern": "^RC-[0-9]{3,}$"
1991
+ },
1992
+ "text": {
1993
+ "type": "string",
1994
+ "description": "A criterion whose wording matches the compiler's closed stated-reasoning vocabulary fails compilation under `rubric-scores-reasoning-prose`, so such a criterion must stay representable here. A blank text parses for the same reason and fails under `rubric-unanchored`."
1995
+ },
1996
+ "evidence": {
1997
+ "type": "string",
1998
+ "pattern": "^\\/interactions\\/[a-z0-9]+(?:-[a-z0-9]+)*\\/(?:(?:response-body|response-headers|stdout|stderr)(?:\\/(?:[^/~]|~[01])*)*|(?:response-status|exit-code)|call-inputs\\/(?:path|query|header|body)(?:\\/(?:[^/~]|~[01])*)*)$",
1999
+ "description": "Where the criterion is answerable from. A pointer that resolves nowhere is `rubric-evidence-unreachable`, a compile-time code, and is deliberately not a schema rejection."
2000
+ }
2001
+ },
2002
+ "required": [
2003
+ "id",
2004
+ "text",
2005
+ "evidence"
2006
+ ],
2007
+ "additionalProperties": false
2008
+ }
2009
+ }
2010
+ },
2011
+ "required": [
2012
+ "id",
2013
+ "scaleLevels",
2014
+ "failureModePenalties",
2015
+ "maxLength",
2016
+ "criteria"
2017
+ ],
2018
+ "additionalProperties": false,
2019
+ "description": "The embeddable rubric body. Named so the shared body has a stable `$defs` key distinct from the published `Rubric` artifact, which is this body plus `schemaVersion` and AD-29 lineage; without the name the two collide in the published-schema drift check under a generated positional name."
2020
+ },
2021
+ "WitnessInputs": {
2022
+ "type": "object",
2023
+ "properties": {
2024
+ "path": {
2025
+ "type": "object",
2026
+ "propertyNames": {
2027
+ "type": "string"
2028
+ },
2029
+ "additionalProperties": {
2030
+ "$ref": "#/$defs/JsonValue"
2031
+ }
2032
+ },
2033
+ "query": {
2034
+ "type": "object",
2035
+ "propertyNames": {
2036
+ "type": "string"
2037
+ },
2038
+ "additionalProperties": {
2039
+ "$ref": "#/$defs/JsonValue"
2040
+ }
2041
+ },
2042
+ "header": {
2043
+ "type": "object",
2044
+ "propertyNames": {
2045
+ "type": "string",
2046
+ "minLength": 1
2047
+ },
2048
+ "additionalProperties": {
2049
+ "type": "string"
2050
+ }
2051
+ },
2052
+ "body": {
2053
+ "oneOf": [
2054
+ {
2055
+ "type": "object",
2056
+ "properties": {
2057
+ "kind": {
2058
+ "type": "string",
2059
+ "const": "json"
2060
+ },
2061
+ "value": {
2062
+ "$ref": "#/$defs/JsonValue"
2063
+ }
2064
+ },
2065
+ "required": [
2066
+ "kind",
2067
+ "value"
2068
+ ],
2069
+ "additionalProperties": false
2070
+ },
2071
+ {
2072
+ "type": "object",
2073
+ "properties": {
2074
+ "kind": {
2075
+ "type": "string",
2076
+ "const": "absent"
2077
+ }
2078
+ },
2079
+ "required": [
2080
+ "kind"
2081
+ ],
2082
+ "additionalProperties": false
2083
+ }
2084
+ ]
2085
+ }
2086
+ },
2087
+ "required": [
2088
+ "path",
2089
+ "query",
2090
+ "header",
2091
+ "body"
2092
+ ],
2093
+ "additionalProperties": false,
2094
+ "description": "One probe leg's supplied inputs, keyed by AD-19 transport channel, in the spelling the environment-probe port accepts. Shared by both witness kinds and by the fixture reset, so the export carries it once."
2095
+ },
2096
+ "InputBindingChannel": {
2097
+ "anyOf": [
2098
+ {
2099
+ "type": "object",
2100
+ "propertyNames": {
2101
+ "type": "string",
2102
+ "minLength": 1
2103
+ },
2104
+ "additionalProperties": {
2105
+ "anyOf": [
2106
+ {
2107
+ "type": "object",
2108
+ "properties": {
2109
+ "literal": {
2110
+ "$ref": "#/$defs/JsonValue"
2111
+ }
2112
+ },
2113
+ "required": [
2114
+ "literal"
2115
+ ],
2116
+ "additionalProperties": false
2117
+ },
2118
+ {
2119
+ "type": "object",
2120
+ "properties": {
2121
+ "matcher": {
2122
+ "type": "string",
2123
+ "enum": [
2124
+ "any",
2125
+ "type-violating"
2126
+ ]
2127
+ }
2128
+ },
2129
+ "required": [
2130
+ "matcher"
2131
+ ],
2132
+ "additionalProperties": false
2133
+ }
2134
+ ]
2135
+ }
2136
+ },
2137
+ {
2138
+ "type": "null"
2139
+ }
2140
+ ],
2141
+ "description": "A parameter-name-to-binding-value map, or `null` for a channel this step binds nothing in. An empty map is rejected: `null` is the only spelling for unbound. That rejection is a Zod check and does not survive the export, so the constraint ledger carries it for injection on the object branch.",
2142
+ "minProperties": 1
2143
+ }
2144
+ }
2145
+ }