eval-quality 0.1.0 → 0.3.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 (179) hide show
  1. package/README.md +142 -67
  2. package/corpus/dev/README.md +20 -13
  3. package/corpus/dev/compile-seal-example/brief.json +1 -1
  4. package/corpus/dev/compile-seal-example/contract.json +1 -1
  5. package/corpus/dev/contracts/absent-collection-locations.json +1 -1
  6. package/corpus/dev/contracts/absent-sibling-groups.json +1 -1
  7. package/corpus/dev/contracts/absent-success-indicator.json +1 -1
  8. package/corpus/dev/contracts/empty-channel-roles.json +1 -1
  9. package/corpus/dev/contracts/empty-collection-locations.json +1 -1
  10. package/corpus/dev/contracts/empty-request-shapes.json +1 -1
  11. package/corpus/dev/contracts/empty-sibling-groups.json +1 -1
  12. package/corpus/dev/contracts/fragment-selection.json +1 -0
  13. package/corpus/dev/contracts/no-collection-quantifier.json +1 -1
  14. package/corpus/dev/contracts/no-operation-inventory.json +1 -1
  15. package/corpus/dev/contracts/no-read-back-relation.json +1 -1
  16. package/corpus/dev/contracts/no-state-change-marker.json +1 -1
  17. package/corpus/dev/contracts/no-type-violating-step.json +1 -1
  18. package/corpus/dev/contracts/per-key-split-oracles.json +1 -1
  19. package/corpus/dev/contracts/review-corpus.json +1 -0
  20. package/corpus/dev/contracts/satisfied-declarations.json +1 -1
  21. package/corpus/dev/contracts/single-required-response-key.json +1 -1
  22. package/corpus/dev/contracts/split-indicator-oracle.json +1 -1
  23. package/corpus/dev/contracts/unaddressed-parameter-sibling.json +1 -1
  24. package/corpus/dev/contracts/unnamed-reference-set.json +1 -1
  25. package/corpus/dev/contracts/wrong-cardinality-form.json +1 -1
  26. package/corpus/dev/index.json +1 -1
  27. package/dist/application/index.d.ts +2 -0
  28. package/dist/application/index.js +1 -0
  29. package/dist/application/score.d.ts +48 -0
  30. package/dist/application/score.js +186 -0
  31. package/dist/cli/arguments.d.ts +7 -3
  32. package/dist/cli/arguments.js +73 -5
  33. package/dist/cli/exit-codes.d.ts +6 -2
  34. package/dist/cli/exit-codes.js +8 -9
  35. package/dist/cli/main.js +9 -0
  36. package/dist/cli/render.d.ts +3 -6
  37. package/dist/cli/render.js +57 -5
  38. package/dist/cli/run.d.ts +13 -3
  39. package/dist/cli/run.js +136 -16
  40. package/dist/core/canonical/canonicalize.d.ts +12 -0
  41. package/dist/core/canonical/canonicalize.js +18 -4
  42. package/dist/core/compile/bindings.d.ts +89 -0
  43. package/dist/core/compile/bindings.js +334 -0
  44. package/dist/core/compile/compile.d.ts +17 -0
  45. package/dist/core/compile/compile.js +37 -1
  46. package/dist/core/compile/excluded-content.d.ts +11 -0
  47. package/dist/core/compile/excluded-content.js +42 -0
  48. package/dist/core/compile/expression-legality.d.ts +49 -0
  49. package/dist/core/compile/expression-legality.js +158 -38
  50. package/dist/core/compile/forbidden-inputs.d.ts +8 -1
  51. package/dist/core/compile/forbidden-inputs.js +16 -3
  52. package/dist/core/compile/interface-inventory.d.ts +57 -2
  53. package/dist/core/compile/interface-inventory.js +119 -13
  54. package/dist/core/compile/reachability.d.ts +28 -1
  55. package/dist/core/compile/reachability.js +167 -35
  56. package/dist/core/compile/schema-version.d.ts +2 -0
  57. package/dist/core/compile/schema-version.js +25 -0
  58. package/dist/core/compile/sensitivity-witness.d.ts +31 -12
  59. package/dist/core/compile/sensitivity-witness.js +110 -23
  60. package/dist/core/compile/step-reference.d.ts +2 -0
  61. package/dist/core/compile/step-reference.js +49 -0
  62. package/dist/core/coverage/operations.d.ts +62 -0
  63. package/dist/core/coverage/operations.js +57 -0
  64. package/dist/core/coverage/relevance.d.ts +4 -2
  65. package/dist/core/coverage/relevance.js +22 -23
  66. package/dist/core/coverage/satisfaction.d.ts +2 -2
  67. package/dist/core/coverage/satisfaction.js +73 -48
  68. package/dist/core/declared-inputs.d.ts +83 -4
  69. package/dist/core/declared-inputs.js +105 -8
  70. package/dist/core/emit/emit.d.ts +9 -0
  71. package/dist/core/emit/emit.js +214 -0
  72. package/dist/core/emit/private-artifact-digest.d.ts +11 -0
  73. package/dist/core/emit/private-artifact-digest.js +31 -0
  74. package/dist/core/evaluate/evidence-resolution.d.ts +10 -3
  75. package/dist/core/evaluate/evidence-resolution.js +74 -11
  76. package/dist/core/evaluate/operators.d.ts +22 -0
  77. package/dist/core/evaluate/operators.js +17 -1
  78. package/dist/core/evaluate/resolution.d.ts +14 -3
  79. package/dist/core/evaluate/resolution.js +63 -3
  80. package/dist/core/excluded-content.d.ts +65 -0
  81. package/dist/core/excluded-content.js +113 -0
  82. package/dist/core/failure-codes.d.ts +2 -2
  83. package/dist/core/failure-codes.js +7 -2
  84. package/dist/core/ingest/conditions.d.ts +201 -0
  85. package/dist/core/ingest/conditions.js +48 -0
  86. package/dist/core/ingest/index.d.ts +13 -0
  87. package/dist/core/ingest/index.js +11 -0
  88. package/dist/core/ingest/ingest.d.ts +68 -0
  89. package/dist/core/ingest/ingest.js +318 -0
  90. package/dist/core/lineage/stage-table.d.ts +21 -4
  91. package/dist/core/lineage/stage-table.js +35 -3
  92. package/dist/core/preflight/plan.d.ts +7 -5
  93. package/dist/core/preflight/plan.js +75 -32
  94. package/dist/core/preflight/projection.d.ts +6 -3
  95. package/dist/core/preflight/projection.js +22 -2
  96. package/dist/core/preflight/reduce.js +47 -7
  97. package/dist/core/preflight/witness-evidence.d.ts +5 -5
  98. package/dist/core/preflight/witness-evidence.js +73 -20
  99. package/dist/core/schemas/artifact.d.ts +1049 -30
  100. package/dist/core/schemas/constraint-ledger.js +51 -0
  101. package/dist/core/schemas/defect-signature.d.ts +695 -0
  102. package/dist/core/schemas/defect-signature.js +175 -0
  103. package/dist/core/schemas/eval-contract.d.ts +550 -12
  104. package/dist/core/schemas/eval-contract.js +32 -2
  105. package/dist/core/schemas/evidence-artifact.d.ts +109 -19
  106. package/dist/core/schemas/evidence-artifact.js +64 -8
  107. package/dist/core/schemas/interface.d.ts +741 -13
  108. package/dist/core/schemas/interface.js +120 -7
  109. package/dist/core/schemas/isolation-manifest.js +16 -9
  110. package/dist/core/schemas/plan.d.ts +329 -3
  111. package/dist/core/schemas/plan.js +89 -3
  112. package/dist/core/schemas/pointer.d.ts +47 -1
  113. package/dist/core/schemas/pointer.js +89 -8
  114. package/dist/core/schemas/port-messages.d.ts +194 -10
  115. package/dist/core/schemas/port-messages.js +73 -6
  116. package/dist/core/schemas/probe-body.d.ts +18 -0
  117. package/dist/core/schemas/probe-body.js +13 -0
  118. package/dist/core/schemas/probe-qualification.d.ts +168 -0
  119. package/dist/core/schemas/probe-qualification.js +106 -0
  120. package/dist/core/schemas/probe.d.ts +431 -0
  121. package/dist/core/schemas/probe.js +6 -2
  122. package/dist/core/schemas/scoring-policy.d.ts +1 -0
  123. package/dist/core/schemas/scoring-policy.js +6 -1
  124. package/dist/core/schemas/sealed-evaluator-brief.d.ts +1 -0
  125. package/dist/core/schemas/sealed-evaluator-brief.js +4 -1
  126. package/dist/core/schemas/sealed-run-record.d.ts +161 -12
  127. package/dist/core/schemas/sealed-run-record.js +92 -15
  128. package/dist/core/schemas/sensitivity-witness.d.ts +108 -6
  129. package/dist/core/schemas/sensitivity-witness.js +61 -5
  130. package/dist/core/score/binding-order.d.ts +31 -0
  131. package/dist/core/score/binding-order.js +88 -0
  132. package/dist/core/score/bindings.d.ts +93 -0
  133. package/dist/core/score/bindings.js +309 -0
  134. package/dist/core/score/ladder-table.d.ts +23 -0
  135. package/dist/core/score/ladder-table.js +109 -0
  136. package/dist/core/score/ladder.d.ts +229 -0
  137. package/dist/core/score/ladder.js +464 -0
  138. package/dist/core/score/mode-agreement.d.ts +30 -0
  139. package/dist/core/score/mode-agreement.js +16 -0
  140. package/dist/core/score/outcome-table.d.ts +17 -0
  141. package/dist/core/score/outcome-table.js +172 -0
  142. package/dist/core/score/outcome.d.ts +466 -0
  143. package/dist/core/score/outcome.js +562 -0
  144. package/dist/core/score/qualification.d.ts +83 -0
  145. package/dist/core/score/qualification.js +645 -0
  146. package/dist/core/score/quotation.d.ts +56 -0
  147. package/dist/core/score/quotation.js +226 -0
  148. package/dist/core/score/reduce-trials.d.ts +80 -0
  149. package/dist/core/score/reduce-trials.js +90 -0
  150. package/dist/core/score/score.d.ts +72 -0
  151. package/dist/core/score/score.js +607 -0
  152. package/dist/core/score/selection.d.ts +80 -0
  153. package/dist/core/score/selection.js +98 -0
  154. package/dist/core/score/strength.d.ts +58 -0
  155. package/dist/core/score/strength.js +227 -0
  156. package/dist/core/score/witness.d.ts +138 -0
  157. package/dist/core/score/witness.js +320 -0
  158. package/dist/core/seal/derived-reference.d.ts +2 -9
  159. package/dist/core/seal/derived-reference.js +293 -46
  160. package/dist/core/seal/plan-index.d.ts +18 -3
  161. package/dist/core/seal/plan-index.js +44 -8
  162. package/dist/core/seal/seal.js +8 -3
  163. package/dist/core/stage-contracts.d.ts +62 -2
  164. package/dist/index.d.ts +1 -1
  165. package/dist/index.js +1 -1
  166. package/dist/ports/environment-probe-port.d.ts +60 -4
  167. package/dist/testing/index.d.ts +2 -0
  168. package/dist/testing/index.js +1 -0
  169. package/dist/testing/probe-conformance.d.ts +29 -0
  170. package/dist/testing/probe-conformance.js +34 -5
  171. package/package.json +12 -3
  172. package/schemas/eval-contract.schema.json +1787 -797
  173. package/schemas/evidence-artifact.schema.json +126 -9
  174. package/schemas/isolation-manifest.schema.json +17 -10
  175. package/schemas/probe.schema.json +636 -5
  176. package/schemas/rubric.schema.json +1 -1
  177. package/schemas/scoring-policy.schema.json +8 -1
  178. package/schemas/sealed-evaluator-brief.schema.json +11 -1
  179. package/schemas/sealed-run-record.schema.json +314 -40
@@ -72,6 +72,177 @@
72
72
  "type": "string",
73
73
  "minLength": 1
74
74
  },
75
+ "qualification": {
76
+ "oneOf": [
77
+ {
78
+ "type": "object",
79
+ "properties": {
80
+ "route": {
81
+ "type": "string",
82
+ "const": "historical"
83
+ },
84
+ "failBeforeEvidence": {
85
+ "description": "The recorded failure at the parent revision. AD-9 exists because 2 of 18 mined fix commits had a test that already passed at the parent, so this is the half that cannot be assumed.",
86
+ "$ref": "#/$defs/ArtifactReference"
87
+ },
88
+ "passAfterEvidence": {
89
+ "$ref": "#/$defs/ArtifactReference"
90
+ },
91
+ "fixCommitDigest": {
92
+ "type": "string",
93
+ "pattern": "^sha256:[0-9a-f]{64}$",
94
+ "description": "The causally isolated fix boundary AD-9 requires the two evidence records to straddle."
95
+ },
96
+ "oracleStableAcrossRevisions": {
97
+ "type": "boolean",
98
+ "description": "AD-9 requires the oracle to be stable across both revisions. `false` parses and fails the gate: a route that cannot record its own unmet precondition cannot be audited, and the schema is not where AD-9's admission decision is made."
99
+ }
100
+ },
101
+ "required": [
102
+ "route",
103
+ "failBeforeEvidence",
104
+ "passAfterEvidence",
105
+ "fixCommitDigest",
106
+ "oracleStableAcrossRevisions"
107
+ ],
108
+ "additionalProperties": false,
109
+ "description": "A historical probe: a defect mined from a real fix boundary, seeded by reverting it."
110
+ },
111
+ {
112
+ "type": "object",
113
+ "properties": {
114
+ "route": {
115
+ "type": "string",
116
+ "const": "controlled-mutation"
117
+ },
118
+ "mutationSource": {
119
+ "type": "string",
120
+ "minLength": 1,
121
+ "description": "Where the mutation came from, in the corpus author's own terms. An opaque caller string, unrelated to `Defect.source`'s two-member enum, which records whether the defect is natural or introduced."
122
+ },
123
+ "mutationOperator": {
124
+ "type": "string",
125
+ "minLength": 1
126
+ },
127
+ "targetArtifact": {
128
+ "$ref": "#/$defs/ArtifactReference"
129
+ },
130
+ "expectedObservableFailure": {
131
+ "type": "string",
132
+ "minLength": 1
133
+ },
134
+ "baselinePassEvidence": {
135
+ "$ref": "#/$defs/ArtifactReference"
136
+ },
137
+ "mutatedFailEvidence": {
138
+ "$ref": "#/$defs/ArtifactReference"
139
+ },
140
+ "rollbackVerified": {
141
+ "type": "boolean",
142
+ "description": "AD-9's verified rollback or cleanup. `false` parses and fails the gate, for the same reason `oracleStableAcrossRevisions` does."
143
+ }
144
+ },
145
+ "required": [
146
+ "route",
147
+ "mutationSource",
148
+ "mutationOperator",
149
+ "targetArtifact",
150
+ "expectedObservableFailure",
151
+ "baselinePassEvidence",
152
+ "mutatedFailEvidence",
153
+ "rollbackVerified"
154
+ ],
155
+ "additionalProperties": false,
156
+ "description": "A controlled mutation: a defect introduced by a named operator against a named artifact."
157
+ },
158
+ {
159
+ "type": "object",
160
+ "properties": {
161
+ "route": {
162
+ "type": "string",
163
+ "const": "gameability"
164
+ },
165
+ "degenerateResponse": {
166
+ "type": "string",
167
+ "minLength": 1,
168
+ "description": "The compliant-looking degenerate response, described rather than embedded: AD-8 forbids sealed-case content from entering any artifact."
169
+ },
170
+ "naiveOracleSatisfiedEvidence": {
171
+ "$ref": "#/$defs/ArtifactReference"
172
+ },
173
+ "disciplinedOracleRejectedEvidence": {
174
+ "$ref": "#/$defs/ArtifactReference"
175
+ }
176
+ },
177
+ "required": [
178
+ "route",
179
+ "degenerateResponse",
180
+ "naiveOracleSatisfiedEvidence",
181
+ "disciplinedOracleRejectedEvidence"
182
+ ],
183
+ "additionalProperties": false,
184
+ "description": "A gameability probe: the demonstration that a degenerate response satisfies a naive oracle and is rejected by a disciplined one."
185
+ },
186
+ {
187
+ "type": "object",
188
+ "properties": {
189
+ "route": {
190
+ "type": "string",
191
+ "const": "canary"
192
+ },
193
+ "indicts": {
194
+ "type": "string",
195
+ "enum": [
196
+ "corpus",
197
+ "fixture"
198
+ ],
199
+ "description": "AD-9's canary qualifies by demonstrating that non-detection indicts one of these two rather than the contract. Which one it indicts is the demonstration's own result and is recorded rather than left to the reader."
200
+ },
201
+ "nonDetectionEvidence": {
202
+ "$ref": "#/$defs/ArtifactReference"
203
+ }
204
+ },
205
+ "required": [
206
+ "route",
207
+ "indicts",
208
+ "nonDetectionEvidence"
209
+ ],
210
+ "additionalProperties": false,
211
+ "description": "A canary: a probe whose non-detection is evidence about the instrument, never about the contract."
212
+ },
213
+ {
214
+ "type": "object",
215
+ "properties": {
216
+ "route": {
217
+ "type": "string",
218
+ "const": "clean-control"
219
+ },
220
+ "baselinePassEvidence": {
221
+ "$ref": "#/$defs/ArtifactReference"
222
+ },
223
+ "revisionCommitDigest": {
224
+ "type": "string",
225
+ "pattern": "^sha256:[0-9a-f]{64}$",
226
+ "description": "AD-27 digest: \"sha256:\" plus 64 lowercase hexadecimal characters."
227
+ },
228
+ "noKnownDefectStatement": {
229
+ "type": "string",
230
+ "minLength": 1,
231
+ "description": "AD-9 qualifies a clean control at \"a revision with no known defect in the probed interface\". No field can prove an absence, so the statement is recorded as an attestation under AD-32 and read as trust rather than as a computed fact."
232
+ }
233
+ },
234
+ "required": [
235
+ "route",
236
+ "baselinePassEvidence",
237
+ "revisionCommitDigest",
238
+ "noKnownDefectStatement"
239
+ ],
240
+ "additionalProperties": false,
241
+ "description": "A known-clean control: recorded baseline-pass evidence at a revision with no known defect in the probed interface."
242
+ }
243
+ ],
244
+ "description": "AD-9's qualification record: which of the five routes earned this probe its ground truth, and the evidence that route demands. Required on every branch and on every class, canaries included, because AD-9 closes with \"an unqualified probe cannot enter a sealed set\" and spells a route for all five kinds. That the route is compatible with this probe's class and `expectedClean` flag is a cross-field rule the export cannot carry; the corpus qualification gate enforces it and returns a reason code. Required, not optional, which with `defectSignature` below makes the probe's `schemaVersion` 1 -> 2 BREAKING bump under AD-11, whose rule is that \"adding an optional field is a `schemaVersion` bump recorded in the field's own description; removing or retyping is breaking\". This field is on both branches, so it alone is what stops every version-1 probe from parsing."
245
+ },
75
246
  "expectedClean": {
76
247
  "type": "boolean",
77
248
  "const": true
@@ -185,6 +356,7 @@
185
356
  "artifactDigest",
186
357
  "commitDigest",
187
358
  "rationale",
359
+ "qualification",
188
360
  "expectedClean",
189
361
  "defects"
190
362
  ],
@@ -261,6 +433,177 @@
261
433
  "type": "string",
262
434
  "minLength": 1
263
435
  },
436
+ "qualification": {
437
+ "oneOf": [
438
+ {
439
+ "type": "object",
440
+ "properties": {
441
+ "route": {
442
+ "type": "string",
443
+ "const": "historical"
444
+ },
445
+ "failBeforeEvidence": {
446
+ "description": "The recorded failure at the parent revision. AD-9 exists because 2 of 18 mined fix commits had a test that already passed at the parent, so this is the half that cannot be assumed.",
447
+ "$ref": "#/$defs/ArtifactReference"
448
+ },
449
+ "passAfterEvidence": {
450
+ "$ref": "#/$defs/ArtifactReference"
451
+ },
452
+ "fixCommitDigest": {
453
+ "type": "string",
454
+ "pattern": "^sha256:[0-9a-f]{64}$",
455
+ "description": "The causally isolated fix boundary AD-9 requires the two evidence records to straddle."
456
+ },
457
+ "oracleStableAcrossRevisions": {
458
+ "type": "boolean",
459
+ "description": "AD-9 requires the oracle to be stable across both revisions. `false` parses and fails the gate: a route that cannot record its own unmet precondition cannot be audited, and the schema is not where AD-9's admission decision is made."
460
+ }
461
+ },
462
+ "required": [
463
+ "route",
464
+ "failBeforeEvidence",
465
+ "passAfterEvidence",
466
+ "fixCommitDigest",
467
+ "oracleStableAcrossRevisions"
468
+ ],
469
+ "additionalProperties": false,
470
+ "description": "A historical probe: a defect mined from a real fix boundary, seeded by reverting it."
471
+ },
472
+ {
473
+ "type": "object",
474
+ "properties": {
475
+ "route": {
476
+ "type": "string",
477
+ "const": "controlled-mutation"
478
+ },
479
+ "mutationSource": {
480
+ "type": "string",
481
+ "minLength": 1,
482
+ "description": "Where the mutation came from, in the corpus author's own terms. An opaque caller string, unrelated to `Defect.source`'s two-member enum, which records whether the defect is natural or introduced."
483
+ },
484
+ "mutationOperator": {
485
+ "type": "string",
486
+ "minLength": 1
487
+ },
488
+ "targetArtifact": {
489
+ "$ref": "#/$defs/ArtifactReference"
490
+ },
491
+ "expectedObservableFailure": {
492
+ "type": "string",
493
+ "minLength": 1
494
+ },
495
+ "baselinePassEvidence": {
496
+ "$ref": "#/$defs/ArtifactReference"
497
+ },
498
+ "mutatedFailEvidence": {
499
+ "$ref": "#/$defs/ArtifactReference"
500
+ },
501
+ "rollbackVerified": {
502
+ "type": "boolean",
503
+ "description": "AD-9's verified rollback or cleanup. `false` parses and fails the gate, for the same reason `oracleStableAcrossRevisions` does."
504
+ }
505
+ },
506
+ "required": [
507
+ "route",
508
+ "mutationSource",
509
+ "mutationOperator",
510
+ "targetArtifact",
511
+ "expectedObservableFailure",
512
+ "baselinePassEvidence",
513
+ "mutatedFailEvidence",
514
+ "rollbackVerified"
515
+ ],
516
+ "additionalProperties": false,
517
+ "description": "A controlled mutation: a defect introduced by a named operator against a named artifact."
518
+ },
519
+ {
520
+ "type": "object",
521
+ "properties": {
522
+ "route": {
523
+ "type": "string",
524
+ "const": "gameability"
525
+ },
526
+ "degenerateResponse": {
527
+ "type": "string",
528
+ "minLength": 1,
529
+ "description": "The compliant-looking degenerate response, described rather than embedded: AD-8 forbids sealed-case content from entering any artifact."
530
+ },
531
+ "naiveOracleSatisfiedEvidence": {
532
+ "$ref": "#/$defs/ArtifactReference"
533
+ },
534
+ "disciplinedOracleRejectedEvidence": {
535
+ "$ref": "#/$defs/ArtifactReference"
536
+ }
537
+ },
538
+ "required": [
539
+ "route",
540
+ "degenerateResponse",
541
+ "naiveOracleSatisfiedEvidence",
542
+ "disciplinedOracleRejectedEvidence"
543
+ ],
544
+ "additionalProperties": false,
545
+ "description": "A gameability probe: the demonstration that a degenerate response satisfies a naive oracle and is rejected by a disciplined one."
546
+ },
547
+ {
548
+ "type": "object",
549
+ "properties": {
550
+ "route": {
551
+ "type": "string",
552
+ "const": "canary"
553
+ },
554
+ "indicts": {
555
+ "type": "string",
556
+ "enum": [
557
+ "corpus",
558
+ "fixture"
559
+ ],
560
+ "description": "AD-9's canary qualifies by demonstrating that non-detection indicts one of these two rather than the contract. Which one it indicts is the demonstration's own result and is recorded rather than left to the reader."
561
+ },
562
+ "nonDetectionEvidence": {
563
+ "$ref": "#/$defs/ArtifactReference"
564
+ }
565
+ },
566
+ "required": [
567
+ "route",
568
+ "indicts",
569
+ "nonDetectionEvidence"
570
+ ],
571
+ "additionalProperties": false,
572
+ "description": "A canary: a probe whose non-detection is evidence about the instrument, never about the contract."
573
+ },
574
+ {
575
+ "type": "object",
576
+ "properties": {
577
+ "route": {
578
+ "type": "string",
579
+ "const": "clean-control"
580
+ },
581
+ "baselinePassEvidence": {
582
+ "$ref": "#/$defs/ArtifactReference"
583
+ },
584
+ "revisionCommitDigest": {
585
+ "type": "string",
586
+ "pattern": "^sha256:[0-9a-f]{64}$",
587
+ "description": "AD-27 digest: \"sha256:\" plus 64 lowercase hexadecimal characters."
588
+ },
589
+ "noKnownDefectStatement": {
590
+ "type": "string",
591
+ "minLength": 1,
592
+ "description": "AD-9 qualifies a clean control at \"a revision with no known defect in the probed interface\". No field can prove an absence, so the statement is recorded as an attestation under AD-32 and read as trust rather than as a computed fact."
593
+ }
594
+ },
595
+ "required": [
596
+ "route",
597
+ "baselinePassEvidence",
598
+ "revisionCommitDigest",
599
+ "noKnownDefectStatement"
600
+ ],
601
+ "additionalProperties": false,
602
+ "description": "A known-clean control: recorded baseline-pass evidence at a revision with no known defect in the probed interface."
603
+ }
604
+ ],
605
+ "description": "AD-9's qualification record: which of the five routes earned this probe its ground truth, and the evidence that route demands. Required on every branch and on every class, canaries included, because AD-9 closes with \"an unqualified probe cannot enter a sealed set\" and spells a route for all five kinds. That the route is compatible with this probe's class and `expectedClean` flag is a cross-field rule the export cannot carry; the corpus qualification gate enforces it and returns a reason code. Required, not optional, which with `defectSignature` below makes the probe's `schemaVersion` 1 -> 2 BREAKING bump under AD-11, whose rule is that \"adding an optional field is a `schemaVersion` bump recorded in the field's own description; removing or retyping is breaking\". This field is on both branches, so it alone is what stops every version-1 probe from parsing."
606
+ },
264
607
  "expectedClean": {
265
608
  "type": "boolean",
266
609
  "const": false
@@ -359,6 +702,230 @@
359
702
  "additionalProperties": false
360
703
  },
361
704
  "description": "No minimum. AD-9 states none, and a minimum would make a canary unrepresentable, since a canary indicts the fixture rather than seeding a defect."
705
+ },
706
+ "defectSignature": {
707
+ "anyOf": [
708
+ {
709
+ "anyOf": [
710
+ {
711
+ "type": "object",
712
+ "properties": {
713
+ "interfaceKind": {
714
+ "type": "string",
715
+ "enum": [
716
+ "api",
717
+ "web",
718
+ "mcp"
719
+ ]
720
+ },
721
+ "method": {
722
+ "type": "string",
723
+ "enum": [
724
+ "GET",
725
+ "HEAD",
726
+ "POST",
727
+ "PUT",
728
+ "PATCH",
729
+ "DELETE",
730
+ "OPTIONS"
731
+ ]
732
+ },
733
+ "pathTemplate": {
734
+ "type": "string",
735
+ "pattern": "^(?:\\/(?:[^/{}:]|\\{[A-Za-z0-9_-]+\\})*)+$",
736
+ "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."
737
+ },
738
+ "observableChannel": {
739
+ "description": "AD-26's channel the seeded defect manifests in. The qualification gate reads it: a condition passes only if its pointers name this channel, or name two channels with at least one response-side member. That rule exists to reject a condition collapsing to \"the evidence contains the string I sent\", which is satisfied by a finding that merely echoes its own input. It must also be a channel the declared kind produces: an api interface writes nothing to standard output and a command returns no HTTP status.",
740
+ "$ref": "#/$defs/EvidenceChannel"
741
+ },
742
+ "condition": {
743
+ "type": "object",
744
+ "properties": {
745
+ "selector": {
746
+ "type": "object",
747
+ "properties": {
748
+ "inputBinding": {
749
+ "type": "object",
750
+ "properties": {
751
+ "path": {
752
+ "$ref": "#/$defs/ProbeInputBindingChannel"
753
+ },
754
+ "query": {
755
+ "$ref": "#/$defs/ProbeInputBindingChannel"
756
+ },
757
+ "header": {
758
+ "$ref": "#/$defs/ProbeInputBindingChannel"
759
+ },
760
+ "body": {
761
+ "$ref": "#/$defs/ProbeInputBindingChannel"
762
+ },
763
+ "argument": {
764
+ "$ref": "#/$defs/ProbeInputBindingChannel"
765
+ },
766
+ "option": {
767
+ "$ref": "#/$defs/ProbeInputBindingChannel"
768
+ },
769
+ "environment": {
770
+ "$ref": "#/$defs/ProbeInputBindingChannel"
771
+ },
772
+ "stdin": {
773
+ "$ref": "#/$defs/ProbeInputBindingChannel"
774
+ }
775
+ },
776
+ "required": [
777
+ "path",
778
+ "query",
779
+ "header",
780
+ "body",
781
+ "argument",
782
+ "option",
783
+ "environment",
784
+ "stdin"
785
+ ],
786
+ "additionalProperties": false
787
+ }
788
+ },
789
+ "required": [
790
+ "inputBinding"
791
+ ],
792
+ "additionalProperties": false
793
+ },
794
+ "predicate": {
795
+ "description": "An AD-4 expression over AD-26 response channels, every pointer rooted at the reserved step identifier `observed`. Legality is the corpus qualification gate's: an unchecked predicate admits `existence` over a literal, which is true of every observation and makes the catch rate 1.00 by construction.",
796
+ "$ref": "#/$defs/Expression"
797
+ }
798
+ },
799
+ "required": [
800
+ "selector",
801
+ "predicate"
802
+ ],
803
+ "additionalProperties": false
804
+ }
805
+ },
806
+ "required": [
807
+ "interfaceKind",
808
+ "method",
809
+ "pathTemplate",
810
+ "observableChannel",
811
+ "condition"
812
+ ],
813
+ "additionalProperties": false
814
+ },
815
+ {
816
+ "type": "object",
817
+ "properties": {
818
+ "interfaceKind": {
819
+ "type": "string",
820
+ "const": "cli"
821
+ },
822
+ "invocation": {
823
+ "type": "object",
824
+ "properties": {
825
+ "executable": {
826
+ "type": "string",
827
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
828
+ "description": "A logical executable name, never a filesystem path, a URL, a host, or a port (AD-35). The caller maps it to an authorized target through configuration outside the contract."
829
+ },
830
+ "subcommandPath": {
831
+ "type": "array",
832
+ "items": {
833
+ "type": "string",
834
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
835
+ "description": "A kebab-case slug. Excludes \"/\" and \"~\" so an identifier can be embedded in an interaction-rooted pointer without escaping."
836
+ },
837
+ "description": "The subcommand segments after the executable, outermost first. Empty is legal and means the executable is invoked with no subcommand."
838
+ }
839
+ },
840
+ "required": [
841
+ "executable",
842
+ "subcommandPath"
843
+ ],
844
+ "additionalProperties": false
845
+ },
846
+ "observableChannel": {
847
+ "description": "AD-26's channel the seeded defect manifests in. The qualification gate reads it: a condition passes only if its pointers name this channel, or name two channels with at least one response-side member. That rule exists to reject a condition collapsing to \"the evidence contains the string I sent\", which is satisfied by a finding that merely echoes its own input. It must also be a channel the declared kind produces: an api interface writes nothing to standard output and a command returns no HTTP status.",
848
+ "$ref": "#/$defs/EvidenceChannel"
849
+ },
850
+ "condition": {
851
+ "type": "object",
852
+ "properties": {
853
+ "selector": {
854
+ "type": "object",
855
+ "properties": {
856
+ "inputBinding": {
857
+ "type": "object",
858
+ "properties": {
859
+ "path": {
860
+ "$ref": "#/$defs/ProbeInputBindingChannel"
861
+ },
862
+ "query": {
863
+ "$ref": "#/$defs/ProbeInputBindingChannel"
864
+ },
865
+ "header": {
866
+ "$ref": "#/$defs/ProbeInputBindingChannel"
867
+ },
868
+ "body": {
869
+ "$ref": "#/$defs/ProbeInputBindingChannel"
870
+ },
871
+ "argument": {
872
+ "$ref": "#/$defs/ProbeInputBindingChannel"
873
+ },
874
+ "option": {
875
+ "$ref": "#/$defs/ProbeInputBindingChannel"
876
+ },
877
+ "environment": {
878
+ "$ref": "#/$defs/ProbeInputBindingChannel"
879
+ },
880
+ "stdin": {
881
+ "$ref": "#/$defs/ProbeInputBindingChannel"
882
+ }
883
+ },
884
+ "required": [
885
+ "path",
886
+ "query",
887
+ "header",
888
+ "body",
889
+ "argument",
890
+ "option",
891
+ "environment",
892
+ "stdin"
893
+ ],
894
+ "additionalProperties": false
895
+ }
896
+ },
897
+ "required": [
898
+ "inputBinding"
899
+ ],
900
+ "additionalProperties": false
901
+ },
902
+ "predicate": {
903
+ "description": "An AD-4 expression over AD-26 response channels, every pointer rooted at the reserved step identifier `observed`. Legality is the corpus qualification gate's: an unchecked predicate admits `existence` over a literal, which is true of every observation and makes the catch rate 1.00 by construction.",
904
+ "$ref": "#/$defs/Expression"
905
+ }
906
+ },
907
+ "required": [
908
+ "selector",
909
+ "predicate"
910
+ ],
911
+ "additionalProperties": false
912
+ }
913
+ },
914
+ "required": [
915
+ "interfaceKind",
916
+ "invocation",
917
+ "observableChannel",
918
+ "condition"
919
+ ],
920
+ "additionalProperties": false
921
+ }
922
+ ]
923
+ },
924
+ {
925
+ "type": "null"
926
+ }
927
+ ],
928
+ "description": "AD-40's machine-readable defect signature, declared on this branch alone: a clean control seeds nothing, so its branch has no signature to carry. Nullable rather than plain, because the one class that legitimately carries none is `canary`, and a union-level refinement expressing that is dropped from the published export, which would leave Zod rejecting a probe ajv accepts. The corpus qualification gate is the enforcement point and the constraint ledger records the gap; the shipped precedent is `compile/interface-inventory.ts`, which put the principal check in the compiler for the same reason. The other half of the probe's `schemaVersion` 1 -> 2 BREAKING bump under AD-11, recorded here as that rule requires: the key is required on this branch, and `null` is the legal value a canary carries."
362
929
  }
363
930
  },
364
931
  "required": [
@@ -373,14 +940,16 @@
373
940
  "artifactDigest",
374
941
  "commitDigest",
375
942
  "rationale",
943
+ "qualification",
376
944
  "expectedClean",
377
- "defects"
945
+ "defects",
946
+ "defectSignature"
378
947
  ],
379
948
  "additionalProperties": false,
380
- "description": "A probe that is not a known-clean control."
949
+ "description": "A probe that is not a known-clean control. The one branch AD-40 gives a defect signature."
381
950
  }
382
951
  ],
383
- "description": "One corpus probe. Succeeds the prior-art `h0-ground-truth` schema per AD-24, carrying its system identifier, implementation digest, `expectedClean` flag, seeded defects, and rationale, and adding AD-9's probe class and AD-9's per-probe artifact and commit digests. Divergences: `implementationSha` becomes `implementationDigest`, `taskId` does not survive because the probe pins what it describes by digest, and `expectedGate` does not survive because AD-40 makes detection a signature match rather than a verdict comparison and AD-7 keeps comparisons inside the dominance vector, so carrying an expected gate would invite a comparison the architecture forbids. Two constructions are deliberately absent: AD-9's per-class QUALIFICATION record, whose five prose routes name no fields and whose acceptance criteria of record do not command it, and AD-40's machine-readable DEFECT SIGNATURE, which Owed item 7 records as having no fixture to land in because this repository contains no probe at all. Both arrive as additive `schemaVersion` bumps under AD-11 once a corpus exists to carry them. The cost is named rather than hidden: AD-9's \"an unqualified probe cannot enter a sealed set\" is enforced by nothing in v0: not this schema, not an AD-5 code, and not an AD-21 rung.",
952
+ "description": "One corpus probe. Succeeds the prior-art `h0-ground-truth` schema per AD-24, carrying its system identifier, implementation digest, `expectedClean` flag, seeded defects, and rationale, and adding AD-9's probe class and AD-9's per-probe artifact and commit digests. Divergences: `implementationSha` becomes `implementationDigest`, `taskId` does not survive because the probe pins what it describes by digest, and `expectedGate` does not survive because AD-40 makes detection a signature match rather than a verdict comparison and AD-7 keeps comparisons inside the dominance vector, so carrying an expected gate would invite a comparison the architecture forbids. Two constructions landed here together under one BREAKING `schemaVersion` bump: AD-9's per-class QUALIFICATION record, as a five-route tagged union required on every branch, and AD-40's machine-readable DEFECT SIGNATURE on the `expectedClean: false` branch, carrying the interface kind, the home operation as a method and a path template, the observable channel, and the discriminating condition. Both are required rather than optional, which is what makes the bump breaking under AD-11: every corpus written against version 1 fails to parse. Version 3 opened the signature to a second interface kind: it is a union on `interfaceKind`, where the `cli` branch declares a logical invocation in place of a method and a path template, and the selector's input binding carries the four command channels beside the four transport ones. What the schema still does not decide is stated rather than hidden. AD-9's \"an unqualified probe cannot enter a sealed set\" is a corpus-construction invariant enforced by the qualification gate in `core/score/qualification.ts`, not by this schema: all eight class-and-`expectedClean` pairings parse, a route incompatible with the pair parses, and a signature-less non-canary parses, each so the gate can return a reason code carrying an artifact path instead of an anonymous parse failure. The constraint ledger carries both gaps.",
384
953
  "$defs": {
385
954
  "ArtifactReference": {
386
955
  "oneOf": [
@@ -1102,8 +1671,8 @@
1102
1671
  "anyOf": [
1103
1672
  {
1104
1673
  "type": "string",
1105
- "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])*)*)$",
1106
- "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."
1674
+ "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|argument|option|environment|stdin)(?:\\/(?:[^/~]|~[01])*)*|artifact\\/[a-z0-9]+(?:-[a-z0-9]+)*(?:\\/(?:[^/~]|~[01])*)*)$",
1675
+ "description": "AD-26 interaction-rooted pointer: \"/interactions/{stepId}/\" followed by one channel of the closed vocabulary. `call-inputs` takes one input channel as its next segment, one of the four transport channels or one of the four command channels; `artifact` takes the identifier of a file the operation declares it writes; `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."
1107
1676
  },
1108
1677
  {
1109
1678
  "type": "string",
@@ -1146,6 +1715,68 @@
1146
1715
  }
1147
1716
  ],
1148
1717
  "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."
1718
+ },
1719
+ "EvidenceChannel": {
1720
+ "type": "string",
1721
+ "enum": [
1722
+ "response-body",
1723
+ "response-headers",
1724
+ "response-status",
1725
+ "call-inputs",
1726
+ "stdout",
1727
+ "stderr",
1728
+ "exit-code",
1729
+ "artifact"
1730
+ ],
1731
+ "description": "AD-26's closed evidence channel vocabulary. The same eight the interaction-rooted pointer addresses; a channel outside this set is a syntax error rather than an unreachable-evidence finding."
1732
+ },
1733
+ "ProbeInputBindingChannel": {
1734
+ "anyOf": [
1735
+ {
1736
+ "type": "object",
1737
+ "propertyNames": {
1738
+ "type": "string",
1739
+ "minLength": 1
1740
+ },
1741
+ "additionalProperties": {
1742
+ "anyOf": [
1743
+ {
1744
+ "type": "object",
1745
+ "properties": {
1746
+ "literal": {
1747
+ "$ref": "#/$defs/JsonValue"
1748
+ }
1749
+ },
1750
+ "required": [
1751
+ "literal"
1752
+ ],
1753
+ "additionalProperties": false
1754
+ },
1755
+ {
1756
+ "type": "object",
1757
+ "properties": {
1758
+ "matcher": {
1759
+ "type": "string",
1760
+ "enum": [
1761
+ "any",
1762
+ "type-violating"
1763
+ ]
1764
+ }
1765
+ },
1766
+ "required": [
1767
+ "matcher"
1768
+ ],
1769
+ "additionalProperties": false
1770
+ }
1771
+ ]
1772
+ }
1773
+ },
1774
+ {
1775
+ "type": "null"
1776
+ }
1777
+ ],
1778
+ "description": "A parameter-name-to-binding-value map for one input channel of a defect signature's selector, or `null` for a channel the selector binds nothing in. An empty map is rejected: `null` is the only spelling for unbound. Admits `{ literal }` and `{ matcher }` only; `{ captured }` and `{ principal }` are contract-local vocabulary and a corpus signature cannot carry either.",
1779
+ "minProperties": 1
1149
1780
  }
1150
1781
  }
1151
1782
  }