eval-quality 0.2.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 (125) hide show
  1. package/README.md +3 -3
  2. package/corpus/dev/README.md +3 -2
  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/cli/render.d.ts +2 -5
  28. package/dist/cli/render.js +51 -1
  29. package/dist/core/compile/bindings.d.ts +26 -7
  30. package/dist/core/compile/bindings.js +49 -32
  31. package/dist/core/compile/compile.d.ts +12 -0
  32. package/dist/core/compile/compile.js +28 -1
  33. package/dist/core/compile/excluded-content.d.ts +11 -0
  34. package/dist/core/compile/excluded-content.js +42 -0
  35. package/dist/core/compile/expression-legality.d.ts +2 -2
  36. package/dist/core/compile/expression-legality.js +58 -12
  37. package/dist/core/compile/interface-inventory.d.ts +34 -1
  38. package/dist/core/compile/interface-inventory.js +88 -11
  39. package/dist/core/compile/reachability.d.ts +12 -2
  40. package/dist/core/compile/reachability.js +123 -36
  41. package/dist/core/compile/schema-version.d.ts +2 -0
  42. package/dist/core/compile/schema-version.js +25 -0
  43. package/dist/core/compile/sensitivity-witness.d.ts +31 -12
  44. package/dist/core/compile/sensitivity-witness.js +110 -23
  45. package/dist/core/compile/step-reference.d.ts +2 -0
  46. package/dist/core/compile/step-reference.js +49 -0
  47. package/dist/core/coverage/operations.d.ts +62 -0
  48. package/dist/core/coverage/operations.js +57 -0
  49. package/dist/core/coverage/relevance.d.ts +4 -2
  50. package/dist/core/coverage/relevance.js +22 -23
  51. package/dist/core/coverage/satisfaction.d.ts +2 -2
  52. package/dist/core/coverage/satisfaction.js +73 -48
  53. package/dist/core/declared-inputs.d.ts +83 -4
  54. package/dist/core/declared-inputs.js +105 -8
  55. package/dist/core/evaluate/evidence-resolution.d.ts +9 -12
  56. package/dist/core/evaluate/evidence-resolution.js +70 -10
  57. package/dist/core/evaluate/operators.d.ts +22 -0
  58. package/dist/core/evaluate/operators.js +17 -1
  59. package/dist/core/evaluate/resolution.d.ts +14 -3
  60. package/dist/core/evaluate/resolution.js +63 -3
  61. package/dist/core/excluded-content.d.ts +65 -0
  62. package/dist/core/excluded-content.js +113 -0
  63. package/dist/core/failure-codes.d.ts +2 -2
  64. package/dist/core/failure-codes.js +5 -2
  65. package/dist/core/ingest/conditions.d.ts +1 -1
  66. package/dist/core/ingest/ingest.js +8 -0
  67. package/dist/core/preflight/plan.d.ts +7 -5
  68. package/dist/core/preflight/plan.js +75 -32
  69. package/dist/core/preflight/projection.d.ts +6 -3
  70. package/dist/core/preflight/projection.js +22 -2
  71. package/dist/core/preflight/reduce.js +47 -7
  72. package/dist/core/preflight/witness-evidence.d.ts +5 -5
  73. package/dist/core/preflight/witness-evidence.js +63 -20
  74. package/dist/core/schemas/artifact.d.ts +683 -35
  75. package/dist/core/schemas/constraint-ledger.js +11 -0
  76. package/dist/core/schemas/defect-signature.d.ts +438 -16
  77. package/dist/core/schemas/defect-signature.js +58 -10
  78. package/dist/core/schemas/eval-contract.d.ts +517 -12
  79. package/dist/core/schemas/eval-contract.js +18 -2
  80. package/dist/core/schemas/evidence-artifact.d.ts +14 -4
  81. package/dist/core/schemas/evidence-artifact.js +1 -1
  82. package/dist/core/schemas/interface.d.ts +741 -13
  83. package/dist/core/schemas/interface.js +120 -7
  84. package/dist/core/schemas/isolation-manifest.js +16 -9
  85. package/dist/core/schemas/plan.d.ts +217 -3
  86. package/dist/core/schemas/plan.js +22 -1
  87. package/dist/core/schemas/pointer.d.ts +47 -1
  88. package/dist/core/schemas/pointer.js +89 -8
  89. package/dist/core/schemas/port-messages.d.ts +194 -10
  90. package/dist/core/schemas/port-messages.js +73 -6
  91. package/dist/core/schemas/probe-body.d.ts +18 -0
  92. package/dist/core/schemas/probe-body.js +13 -0
  93. package/dist/core/schemas/probe.d.ts +122 -3
  94. package/dist/core/schemas/probe.js +1 -1
  95. package/dist/core/schemas/sealed-run-record.d.ts +131 -9
  96. package/dist/core/schemas/sealed-run-record.js +56 -11
  97. package/dist/core/schemas/sensitivity-witness.d.ts +108 -6
  98. package/dist/core/schemas/sensitivity-witness.js +61 -5
  99. package/dist/core/score/bindings.d.ts +2 -2
  100. package/dist/core/score/bindings.js +25 -13
  101. package/dist/core/score/qualification.d.ts +5 -5
  102. package/dist/core/score/qualification.js +67 -37
  103. package/dist/core/score/quotation.d.ts +1 -24
  104. package/dist/core/score/quotation.js +29 -4
  105. package/dist/core/score/score.js +28 -2
  106. package/dist/core/score/strength.d.ts +9 -0
  107. package/dist/core/score/strength.js +35 -1
  108. package/dist/core/score/witness.d.ts +21 -0
  109. package/dist/core/score/witness.js +9 -4
  110. package/dist/core/seal/derived-reference.d.ts +2 -9
  111. package/dist/core/seal/derived-reference.js +62 -23
  112. package/dist/core/seal/plan-index.d.ts +18 -3
  113. package/dist/core/seal/plan-index.js +44 -8
  114. package/dist/index.d.ts +1 -1
  115. package/dist/index.js +1 -1
  116. package/dist/ports/environment-probe-port.d.ts +60 -4
  117. package/dist/testing/probe-conformance.d.ts +29 -0
  118. package/dist/testing/probe-conformance.js +34 -5
  119. package/package.json +1 -1
  120. package/schemas/eval-contract.schema.json +1356 -464
  121. package/schemas/evidence-artifact.schema.json +59 -29
  122. package/schemas/isolation-manifest.schema.json +17 -10
  123. package/schemas/probe.schema.json +197 -71
  124. package/schemas/rubric.schema.json +1 -1
  125. package/schemas/sealed-run-record.schema.json +296 -39
@@ -123,7 +123,7 @@
123
123
  "mode"
124
124
  ]
125
125
  },
126
- "description": "Which of the six scoring-version inputs were caller-attested rather than computed by this package. An enum over the six key names rather than free strings, because AD-32 requires the artifact to state *which* inputs were attested and an unconstrained string cannot be checked against anything. AD-11 names three of the six as caller-attested; the enum admits any subset so a stricter or looser integration stays representable."
126
+ "description": "Which of the six scoring-version inputs were caller-attested rather than computed by this package. An enum over the six key names rather than free strings, because AD-32 requires the artifact to state *which* inputs were attested and an unconstrained string cannot be checked against anything. AD-11 names three of the six as caller-attested; the enum admits any subset so a stricter or looser integration stays representable. `mode` is the one member that is not a choice: `ScoringVersionInputs.mode` is read from the sealed run record and never re-derived, so a list omitting it is a misdeclaration rather than a stricter integration. The schema admits that shape and the constraint ledger records why; `core/emit` always names it."
127
127
  },
128
128
  "trials": {
129
129
  "type": "object",
@@ -703,7 +703,7 @@
703
703
  "mode"
704
704
  ]
705
705
  },
706
- "description": "Which of the six scoring-version inputs were caller-attested rather than computed by this package. An enum over the six key names rather than free strings, because AD-32 requires the artifact to state *which* inputs were attested and an unconstrained string cannot be checked against anything. AD-11 names three of the six as caller-attested; the enum admits any subset so a stricter or looser integration stays representable."
706
+ "description": "Which of the six scoring-version inputs were caller-attested rather than computed by this package. An enum over the six key names rather than free strings, because AD-32 requires the artifact to state *which* inputs were attested and an unconstrained string cannot be checked against anything. AD-11 names three of the six as caller-attested; the enum admits any subset so a stricter or looser integration stays representable. `mode` is the one member that is not a choice: `ScoringVersionInputs.mode` is read from the sealed run record and never re-derived, so a list omitting it is a misdeclaration rather than a stricter integration. The schema admits that shape and the constraint ledger records why; `core/emit` always names it."
707
707
  },
708
708
  "trials": {
709
709
  "type": "object",
@@ -1159,22 +1159,65 @@
1159
1159
  "minItems": 1,
1160
1160
  "type": "array",
1161
1161
  "items": {
1162
- "type": "object",
1163
- "properties": {
1164
- "quote": {
1165
- "type": "string",
1166
- "minLength": 1,
1167
- "description": "The evaluator's verbatim quotation, per AD-23. Non-empty: an empty quotation quotes nothing, no AD-5 code names the condition, and under the admit-rule's second clause the schema is therefore the enforcement point. That this text appears in at least one of the finding's cited observations is NOT checked here; it is an AD-32 declared-versus-observed inconsistency that invalidates at ingest, and ADR-009 Decision 2 settles the precedence: \"cited identifiers govern the witness match; quotation audits it.\""
1162
+ "anyOf": [
1163
+ {
1164
+ "type": "object",
1165
+ "properties": {
1166
+ "quote": {
1167
+ "type": "string",
1168
+ "minLength": 1,
1169
+ "description": "The evaluator's verbatim quotation, per AD-23. Non-empty: an empty quotation quotes nothing, no AD-5 code names the condition, and under the admit-rule's second clause the schema is therefore the enforcement point. That this text appears in at least one of the finding's cited observations is NOT checked here; it is an AD-32 declared-versus-observed inconsistency that invalidates at ingest, and ADR-009 Decision 2 settles the precedence: \"cited identifiers govern the witness match; quotation audits it.\""
1170
+ },
1171
+ "channel": {
1172
+ "type": "string",
1173
+ "const": "artifact"
1174
+ },
1175
+ "artifactId": {
1176
+ "type": "string",
1177
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
1178
+ "description": "Which written file the quotation came from. A channel alone does not identify one: an operation may write several, and an audit that searched all of them at once accepted a quotation lifted from a file the finding never cited, which is the opposite of what AD-23's verbatim requirement is for."
1179
+ }
1180
+ },
1181
+ "required": [
1182
+ "quote",
1183
+ "channel",
1184
+ "artifactId"
1185
+ ],
1186
+ "additionalProperties": false
1168
1187
  },
1169
- "channel": {
1170
- "$ref": "#/$defs/EvidenceChannel"
1188
+ {
1189
+ "type": "object",
1190
+ "properties": {
1191
+ "quote": {
1192
+ "type": "string",
1193
+ "minLength": 1,
1194
+ "description": "The evaluator's verbatim quotation, per AD-23. Non-empty: an empty quotation quotes nothing, no AD-5 code names the condition, and under the admit-rule's second clause the schema is therefore the enforcement point. That this text appears in at least one of the finding's cited observations is NOT checked here; it is an AD-32 declared-versus-observed inconsistency that invalidates at ingest, and ADR-009 Decision 2 settles the precedence: \"cited identifiers govern the witness match; quotation audits it.\""
1195
+ },
1196
+ "channel": {
1197
+ "type": "string",
1198
+ "enum": [
1199
+ "response-body",
1200
+ "response-headers",
1201
+ "response-status",
1202
+ "call-inputs",
1203
+ "stdout",
1204
+ "stderr",
1205
+ "exit-code"
1206
+ ]
1207
+ },
1208
+ "artifactId": {
1209
+ "type": "null",
1210
+ "description": "Null on every channel but `artifact`, and required rather than optional so a record cannot omit the question. Only a written file needs naming; every other channel is one thing per observation."
1211
+ }
1212
+ },
1213
+ "required": [
1214
+ "quote",
1215
+ "channel",
1216
+ "artifactId"
1217
+ ],
1218
+ "additionalProperties": false
1171
1219
  }
1172
- },
1173
- "required": [
1174
- "quote",
1175
- "channel"
1176
- ],
1177
- "additionalProperties": false
1220
+ ]
1178
1221
  }
1179
1222
  },
1180
1223
  "severity": {
@@ -1290,19 +1333,6 @@
1290
1333
  ],
1291
1334
  "description": "AD-21's four verdicts. Uppercase is one of the two named exceptions to the lowercase kebab-case enum convention. Exit codes are AD-21's and belong to the CLI rather than to this value: PASS, WAIVED, and CONCERNS exit zero and FAIL exits two."
1292
1335
  },
1293
- "EvidenceChannel": {
1294
- "type": "string",
1295
- "enum": [
1296
- "response-body",
1297
- "response-headers",
1298
- "response-status",
1299
- "call-inputs",
1300
- "stdout",
1301
- "stderr",
1302
- "exit-code"
1303
- ],
1304
- "description": "AD-26's closed evidence channel vocabulary. The same seven the interaction-rooted pointer addresses; a channel outside this set is a syntax error rather than an unreachable-evidence finding."
1305
- },
1306
1336
  "EvaluatorRecommendation": {
1307
1337
  "type": "string",
1308
1338
  "enum": [
@@ -35,7 +35,7 @@
35
35
  "contractId": {
36
36
  "type": "string",
37
37
  "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
38
- "description": "The prior art's `taskId`, renamed. \"Task\" is experiment vocabulary with no product meaning, and the manifest keeps an identifier because it is the artifact `core/ingest` matches against a run; the run record and the probe pin what they describe by digest instead."
38
+ "description": "The prior art's `taskId`, renamed. \"Task\" is experiment vocabulary with no product meaning, and the manifest keeps an identifier so a reader can say which contract the run was isolated for. It is a label and not a second operand for any check: `core/ingest` matches this artifact to a run on `runId`, `contractDigest`, and `evaluatorConfigurationDigest`, which is the whole of the agreement the two artifacts make. Nothing in the pipeline carries a contract identifier to compare this against, since the sealed run record pins its contract by digest and the eval contract is not among ingest's inputs."
39
39
  },
40
40
  "conditionArm": {
41
41
  "type": "string",
@@ -68,38 +68,44 @@
68
68
  "allowedMounts": {
69
69
  "type": "array",
70
70
  "items": {
71
- "type": "string"
71
+ "type": "string",
72
+ "minLength": 1
72
73
  }
73
74
  },
74
75
  "observedMounts": {
75
76
  "type": "array",
76
77
  "items": {
77
- "type": "string"
78
+ "type": "string",
79
+ "minLength": 1
78
80
  },
79
- "description": "Observed mounts, network targets, and tool calls exceeding their allowlist is a violation AD-16 has `core/ingest` record; it is a cross-field rule with no AD-5 code and the schema admits it."
81
+ "description": "Observed mounts, network targets, and tool calls exceeding their allowlist is a violation AD-16 has `core/ingest` record; it is a cross-field rule with no AD-5 code and the schema admits it. Each entry is non-empty: an empty string is not a mount, and it renders as a basis line naming nothing after its colon."
80
82
  },
81
83
  "networkAllowlist": {
82
84
  "type": "array",
83
85
  "items": {
84
- "type": "string"
86
+ "type": "string",
87
+ "minLength": 1
85
88
  }
86
89
  },
87
90
  "observedNetworkTargets": {
88
91
  "type": "array",
89
92
  "items": {
90
- "type": "string"
93
+ "type": "string",
94
+ "minLength": 1
91
95
  }
92
96
  },
93
97
  "toolAllowlist": {
94
98
  "type": "array",
95
99
  "items": {
96
- "type": "string"
100
+ "type": "string",
101
+ "minLength": 1
97
102
  }
98
103
  },
99
104
  "observedToolCalls": {
100
105
  "type": "array",
101
106
  "items": {
102
- "type": "string"
107
+ "type": "string",
108
+ "minLength": 1
103
109
  }
104
110
  },
105
111
  "resourceCeilings": {
@@ -357,13 +363,14 @@
357
363
  "violation": {
358
364
  "anyOf": [
359
365
  {
360
- "type": "string"
366
+ "type": "string",
367
+ "minLength": 1
361
368
  },
362
369
  {
363
370
  "type": "null"
364
371
  }
365
372
  ],
366
- "description": "The sixteenth of the prior art's sixteen required members, and the one that is not a description of the run: a non-null violation invalidates it. AD-16 says the schema is \"seeded from the prior art's fifteen\"; the prior art's `required` array has sixteen. Settled by construction: the fifteen are the fields describing the run and this is the invalidation outcome. All sixteen are carried."
373
+ "description": "The sixteenth of the prior art's sixteen required members, and the one that is not a description of the run: a non-null violation invalidates it. Non-empty when present, on `QuotedEvidence.quote`'s precedent: `null` is the spelling for no violation, so an empty string is a violation that names nothing while still invalidating the run and rendering a blank basis entry. AD-16 says the schema is \"seeded from the prior art's fifteen\"; the prior art's `required` array has sixteen. Settled by construction: the fifteen are the fields describing the run and this is the invalidation outcome. All sixteen are carried."
367
374
  }
368
375
  },
369
376
  "required": [
@@ -706,95 +706,220 @@
706
706
  "defectSignature": {
707
707
  "anyOf": [
708
708
  {
709
- "type": "object",
710
- "properties": {
711
- "interfaceKind": {
712
- "type": "string",
713
- "enum": [
714
- "api",
715
- "web",
716
- "cli",
717
- "mcp"
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"
718
812
  ],
719
- "description": "The interface the seeded defect lives behind. All four kinds parse so `unsupported-interface-kind` stays fireable contract-side, and the qualification gate rejects every kind but `api`: `Operation` carries no interface kind and requires a method and a path template with no per-kind variation, so a `cli` or `mcp` signature would declare a meaningless `POST /path`."
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.",
740
- "$ref": "#/$defs/EvidenceChannel"
813
+ "additionalProperties": false
741
814
  },
742
- "condition": {
815
+ {
743
816
  "type": "object",
744
817
  "properties": {
745
- "selector": {
818
+ "interfaceKind": {
819
+ "type": "string",
820
+ "const": "cli"
821
+ },
822
+ "invocation": {
746
823
  "type": "object",
747
824
  "properties": {
748
- "inputBinding": {
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": {
749
854
  "type": "object",
750
855
  "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"
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
762
895
  }
763
896
  },
764
897
  "required": [
765
- "path",
766
- "query",
767
- "header",
768
- "body"
898
+ "inputBinding"
769
899
  ],
770
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"
771
905
  }
772
906
  },
773
907
  "required": [
774
- "inputBinding"
908
+ "selector",
909
+ "predicate"
775
910
  ],
776
911
  "additionalProperties": false
777
- },
778
- "predicate": {
779
- "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.",
780
- "$ref": "#/$defs/Expression"
781
912
  }
782
913
  },
783
914
  "required": [
784
- "selector",
785
- "predicate"
915
+ "interfaceKind",
916
+ "invocation",
917
+ "observableChannel",
918
+ "condition"
786
919
  ],
787
920
  "additionalProperties": false
788
921
  }
789
- },
790
- "required": [
791
- "interfaceKind",
792
- "method",
793
- "pathTemplate",
794
- "observableChannel",
795
- "condition"
796
- ],
797
- "additionalProperties": false
922
+ ]
798
923
  },
799
924
  {
800
925
  "type": "null"
@@ -824,7 +949,7 @@
824
949
  "description": "A probe that is not a known-clean control. The one branch AD-40 gives a defect signature."
825
950
  }
826
951
  ],
827
- "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. 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.",
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.",
828
953
  "$defs": {
829
954
  "ArtifactReference": {
830
955
  "oneOf": [
@@ -1546,8 +1671,8 @@
1546
1671
  "anyOf": [
1547
1672
  {
1548
1673
  "type": "string",
1549
- "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])*)*)$",
1550
- "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."
1551
1676
  },
1552
1677
  {
1553
1678
  "type": "string",
@@ -1600,9 +1725,10 @@
1600
1725
  "call-inputs",
1601
1726
  "stdout",
1602
1727
  "stderr",
1603
- "exit-code"
1728
+ "exit-code",
1729
+ "artifact"
1604
1730
  ],
1605
- "description": "AD-26's closed evidence channel vocabulary. The same seven the interaction-rooted pointer addresses; a channel outside this set is a syntax error rather than an unreachable-evidence finding."
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."
1606
1732
  },
1607
1733
  "ProbeInputBindingChannel": {
1608
1734
  "anyOf": [
@@ -1649,7 +1775,7 @@
1649
1775
  "type": "null"
1650
1776
  }
1651
1777
  ],
1652
- "description": "A parameter-name-to-binding-value map for one transport 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.",
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.",
1653
1779
  "minProperties": 1
1654
1780
  }
1655
1781
  }
@@ -95,7 +95,7 @@
95
95
  },
96
96
  "evidence": {
97
97
  "type": "string",
98
- "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])*)*)$",
98
+ "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])*)*)$",
99
99
  "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."
100
100
  }
101
101
  },