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 @@
1
+ {"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractId":"split-indicator-oracle","fixtureReset":null,"forbiddenInputs":["original-spec","source-code","repository","builder-transcript","implementation-logs","comparator-results","human-labels"],"interactionPlan":[{"after":null,"inputBinding":{"body":{"name":{"matcher":"any"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"create"},{"after":"create","inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"literal":10}}},"operationId":"list-things","stepId":"list"},{"after":null,"inputBinding":{"body":{"name":{"matcher":"type-violating"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"malformed-create"},{"after":null,"inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"matcher":"type-violating"}}},"operationId":"list-things","stepId":"malformed-list"}],"oracles":[{"check":{"actualKey":"id","expectedKey":"id","op":"covers-by-key","operands":[{"referenceSet":"expected-things"},{"pointer":"/interactions/list/response-body/items"}]},"commentary":"Reconciles the whole list against the declared set.","direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list omitting a seeded thing, or repeating one.","polarity":"expects-hold","relation":"covers-by-key","scope":"One list call over the seeded set."},"id":"O-001","polarity":"expects-hold"},{"check":{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/ok"}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/response-body/ok"],"negativeDomain":"A create response carrying no indicator at all.","polarity":"expects-hold","relation":"existence","scope":"The create response indicator, read on its own."},"id":"O-002","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/list/response-body/items"}]},{"op":"absence","operands":[{"pointer":"/interactions/list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/list/response-body/error"],"negativeDomain":"A list carrying items alongside a diagnostic field.","polarity":"expects-hold","relation":"all","scope":"The list response taken as a whole."},"id":"O-003","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/malformed-create/response-body/error"}]},{"op":"existence","operands":[{"pointer":"/interactions/malformed-list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/malformed-create/response-body/error","/interactions/malformed-list/response-body/error"],"negativeDomain":"One sibling rejecting the malformed input while the other accepts it.","polarity":"expects-hold","relation":"all","scope":"Both sibling operations, each given an input that violates its declared type."},"id":"O-004","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/call-inputs/body/name"}]},{"op":"existence","operands":[{"pointer":"/interactions/list/call-inputs/query/limit"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/call-inputs/body/name","/interactions/list/call-inputs/query/limit"],"negativeDomain":"One parameter carried and the other dropped.","polarity":"expects-hold","relation":"all","scope":"The two sibling parameters, as sent."},"id":"O-005","polarity":"expects-hold"},{"check":{"op":"containment","operands":[{"pointer":"/interactions/list/response-body/items"},{"pointer":"/interactions/create/call-inputs/body/name"}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/create/call-inputs/body/name"],"negativeDomain":"A create reporting success whose thing never appears in a later list.","polarity":"expects-hold","relation":"containment","scope":"The list read after the create, against the name the create sent."},"id":"O-006","polarity":"expects-hold"},{"check":{"collection":{"pointer":"/interactions/list/response-body/items"},"op":"for-all","predicate":{"op":"existence","operands":[{"pointer":"@/id"}]}},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list whose first element carries an identifier and whose later elements do not.","polarity":"expects-hold","relation":"for-all","scope":"Every element of the returned list."},"id":"O-007","polarity":"expects-hold"}],"parentDigest":null,"permittedInterfaces":[{"kind":"api","logicalId":"thing-api","operations":[{"method":"POST","operationId":"create-thing","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":["name"],"requiredKeys":["name"],"types":{"name":"string"}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":[],"requiredKeys":[],"types":{}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/id":"payload","/ok":"success-indicator"},"collectionLocations":[],"permittedKeys":["id","ok","error"],"requiredKeys":["id","ok"],"successIndicator":"/ok","types":{"error":"string","id":"string","ok":"boolean"}},"sensitivityWitness":{"channel":"body","legs":[{"inputs":{"body":{"kind":"json","value":{"name":"alpha"}},"header":{},"path":{},"query":{}},"legId":"create-witness-a"},{"inputs":{"body":{"kind":"json","value":{"name":"beta"}},"header":{},"path":{},"query":{}},"legId":"create-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/create-witness-a/response-body"},{"pointer":"/interactions/create-witness-b/response-body"}]}]},"witnessId":"create-thing-sensitivity"},"stateChangeMarker":true,"volatilePointers":["/id"]},{"method":"GET","operationId":"list-things","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":[],"requiredKeys":[],"types":{}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":["limit"],"requiredKeys":[],"types":{"limit":"number"}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/items":"collection"},"collectionLocations":[{"expectedCardinality":{"count":3,"mode":"exact"},"pointer":"/items","referenceSet":"expected-things"}],"permittedKeys":["items","error"],"requiredKeys":["items"],"successIndicator":"/items","types":{"error":"string","items":"array"}},"sensitivityWitness":{"channel":"query","legs":[{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":1}},"legId":"list-witness-a"},{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":2}},"legId":"list-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/list-witness-a/response-body"},{"pointer":"/interactions/list-witness-b/response-body"}]}]},"witnessId":"list-things-sensitivity"},"stateChangeMarker":false,"volatilePointers":[]}]}],"probeStepBound":8,"referenceSets":{"expected-things":{"commentary":null,"keys":["id"],"members":[{"id":"t-1"},{"id":"t-2"},{"id":"t-3"}]}},"requiredEvidence":["Request and response pair for every call, in order."],"revisionCount":0,"rubrics":[{"criteria":[{"evidence":"/interactions/list/response-body/items","id":"RC-001","text":"Does the returned list carry every expected identifier?"}],"failureModePenalties":[{"description":"An expected thing is missing.","name":"omission"}],"id":"R-001","maxLength":400,"scaleLevels":[{"anchor":"Every expected thing is present.","level":1}]}],"safetyLimits":["No request to any host other than the mapped thing-api target."],"schemaVersion":1,"scopedResources":null,"siblingGroups":{"operations":[["create-thing","list-things"]],"parameters":[["limit","name"]]},"sourceSpecDigest":null,"testData":{"cleanup":"Delete every thing created during the run.","setup":"Seed exactly three things with identifiers t-1, t-2, t-3."},"waivers":[{"approval":"gate-c-reviewer","condition":null,"expiresAt":"2027-01-01T00:00:00Z","id":"W-001","rationale":"The upstream seed is unavailable in the sandbox environment.","rule":"omission-and-completeness"}]}
@@ -0,0 +1 @@
1
+ {"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractId":"unaddressed-parameter-sibling","fixtureReset":null,"forbiddenInputs":["original-spec","source-code","repository","builder-transcript","implementation-logs","comparator-results","human-labels"],"interactionPlan":[{"after":null,"inputBinding":{"body":{"name":{"matcher":"any"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"create"},{"after":"create","inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"literal":10}}},"operationId":"list-things","stepId":"list"},{"after":null,"inputBinding":{"body":{"name":{"matcher":"type-violating"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"malformed-create"},{"after":null,"inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"matcher":"type-violating"}}},"operationId":"list-things","stepId":"malformed-list"}],"oracles":[{"check":{"actualKey":"id","expectedKey":"id","op":"covers-by-key","operands":[{"referenceSet":"expected-things"},{"pointer":"/interactions/list/response-body/items"}]},"commentary":"Reconciles the whole list against the declared set.","direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list omitting a seeded thing, or repeating one.","polarity":"expects-hold","relation":"covers-by-key","scope":"One list call over the seeded set."},"id":"O-001","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/ok"}]},{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/id"}]},{"op":"absence","operands":[{"pointer":"/interactions/create/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/response-body/ok","/interactions/create/response-body/id","/interactions/create/response-body/error"],"negativeDomain":"A create reporting success with no identifier, or with a diagnostic beside it.","polarity":"expects-hold","relation":"all","scope":"The whole create response."},"id":"O-002","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/list/response-body/items"}]},{"op":"absence","operands":[{"pointer":"/interactions/list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/list/response-body/error"],"negativeDomain":"A list carrying items alongside a diagnostic field.","polarity":"expects-hold","relation":"all","scope":"The list response taken as a whole."},"id":"O-003","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/malformed-create/response-body/error"}]},{"op":"existence","operands":[{"pointer":"/interactions/malformed-list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/malformed-create/response-body/error","/interactions/malformed-list/response-body/error"],"negativeDomain":"One sibling rejecting the malformed input while the other accepts it.","polarity":"expects-hold","relation":"all","scope":"Both sibling operations, each given an input that violates its declared type."},"id":"O-004","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/call-inputs/body/name"}]},{"op":"existence","operands":[{"pointer":"/interactions/list/call-inputs/query/limit"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/call-inputs/body/name","/interactions/list/call-inputs/query/limit"],"negativeDomain":"One parameter carried and the other dropped.","polarity":"expects-hold","relation":"all","scope":"The two sibling parameters, as sent."},"id":"O-005","polarity":"expects-hold"},{"check":{"op":"containment","operands":[{"pointer":"/interactions/list/response-body/items"},{"pointer":"/interactions/create/call-inputs/body/name"}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/create/call-inputs/body/name"],"negativeDomain":"A create reporting success whose thing never appears in a later list.","polarity":"expects-hold","relation":"containment","scope":"The list read after the create, against the name the create sent."},"id":"O-006","polarity":"expects-hold"},{"check":{"collection":{"pointer":"/interactions/list/response-body/items"},"op":"for-all","predicate":{"op":"existence","operands":[{"pointer":"@/id"}]}},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list whose first element carries an identifier and whose later elements do not.","polarity":"expects-hold","relation":"for-all","scope":"Every element of the returned list."},"id":"O-007","polarity":"expects-hold"}],"parentDigest":null,"permittedInterfaces":[{"kind":"api","logicalId":"thing-api","operations":[{"method":"POST","operationId":"create-thing","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":["name"],"requiredKeys":["name"],"types":{"name":"string"}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":[],"requiredKeys":[],"types":{}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/id":"payload","/ok":"success-indicator"},"collectionLocations":[],"permittedKeys":["id","ok","error"],"requiredKeys":["id","ok"],"successIndicator":"/ok","types":{"error":"string","id":"string","ok":"boolean"}},"sensitivityWitness":{"channel":"body","legs":[{"inputs":{"body":{"kind":"json","value":{"name":"alpha"}},"header":{},"path":{},"query":{}},"legId":"create-witness-a"},{"inputs":{"body":{"kind":"json","value":{"name":"beta"}},"header":{},"path":{},"query":{}},"legId":"create-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/create-witness-a/response-body"},{"pointer":"/interactions/create-witness-b/response-body"}]}]},"witnessId":"create-thing-sensitivity"},"stateChangeMarker":true,"volatilePointers":["/id"]},{"method":"GET","operationId":"list-things","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":[],"requiredKeys":[],"types":{}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":["limit"],"requiredKeys":[],"types":{"limit":"number"}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/items":"collection"},"collectionLocations":[{"expectedCardinality":{"count":3,"mode":"exact"},"pointer":"/items","referenceSet":"expected-things"}],"permittedKeys":["items","error"],"requiredKeys":["items"],"successIndicator":"/items","types":{"error":"string","items":"array"}},"sensitivityWitness":{"channel":"query","legs":[{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":1}},"legId":"list-witness-a"},{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":2}},"legId":"list-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/list-witness-a/response-body"},{"pointer":"/interactions/list-witness-b/response-body"}]}]},"witnessId":"list-things-sensitivity"},"stateChangeMarker":false,"volatilePointers":[]}]}],"probeStepBound":8,"referenceSets":{"expected-things":{"commentary":null,"keys":["id"],"members":[{"id":"t-1"},{"id":"t-2"},{"id":"t-3"}]}},"requiredEvidence":["Request and response pair for every call, in order."],"revisionCount":0,"rubrics":[{"criteria":[{"evidence":"/interactions/list/response-body/items","id":"RC-001","text":"Does the returned list carry every expected identifier?"}],"failureModePenalties":[{"description":"An expected thing is missing.","name":"omission"}],"id":"R-001","maxLength":400,"scaleLevels":[{"anchor":"Every expected thing is present.","level":1}]}],"safetyLimits":["No request to any host other than the mapped thing-api target."],"schemaVersion":1,"scopedResources":null,"siblingGroups":{"operations":[["create-thing","list-things"]],"parameters":[["limit","offset"]]},"sourceSpecDigest":null,"testData":{"cleanup":"Delete every thing created during the run.","setup":"Seed exactly three things with identifiers t-1, t-2, t-3."},"waivers":[{"approval":"gate-c-reviewer","condition":null,"expiresAt":"2027-01-01T00:00:00Z","id":"W-001","rationale":"The upstream seed is unavailable in the sandbox environment.","rule":"omission-and-completeness"}]}
@@ -0,0 +1 @@
1
+ {"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractId":"unnamed-reference-set","fixtureReset":null,"forbiddenInputs":["original-spec","source-code","repository","builder-transcript","implementation-logs","comparator-results","human-labels"],"interactionPlan":[{"after":null,"inputBinding":{"body":{"name":{"matcher":"any"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"create"},{"after":"create","inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"literal":10}}},"operationId":"list-things","stepId":"list"},{"after":null,"inputBinding":{"body":{"name":{"matcher":"type-violating"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"malformed-create"},{"after":null,"inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"matcher":"type-violating"}}},"operationId":"list-things","stepId":"malformed-list"}],"oracles":[{"check":{"actualKey":"id","expectedKey":"id","op":"covers-by-key","operands":[{"referenceSet":"expected-things"},{"pointer":"/interactions/list/response-body/items"}]},"commentary":"Reconciles the whole list against the declared set.","direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list omitting a seeded thing, or repeating one.","polarity":"expects-hold","relation":"covers-by-key","scope":"One list call over the seeded set."},"id":"O-001","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/ok"}]},{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/id"}]},{"op":"absence","operands":[{"pointer":"/interactions/create/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/response-body/ok","/interactions/create/response-body/id","/interactions/create/response-body/error"],"negativeDomain":"A create reporting success with no identifier, or with a diagnostic beside it.","polarity":"expects-hold","relation":"all","scope":"The whole create response."},"id":"O-002","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/list/response-body/items"}]},{"op":"absence","operands":[{"pointer":"/interactions/list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/list/response-body/error"],"negativeDomain":"A list carrying items alongside a diagnostic field.","polarity":"expects-hold","relation":"all","scope":"The list response taken as a whole."},"id":"O-003","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/malformed-create/response-body/error"}]},{"op":"existence","operands":[{"pointer":"/interactions/malformed-list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/malformed-create/response-body/error","/interactions/malformed-list/response-body/error"],"negativeDomain":"One sibling rejecting the malformed input while the other accepts it.","polarity":"expects-hold","relation":"all","scope":"Both sibling operations, each given an input that violates its declared type."},"id":"O-004","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/call-inputs/body/name"}]},{"op":"existence","operands":[{"pointer":"/interactions/list/call-inputs/query/limit"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/call-inputs/body/name","/interactions/list/call-inputs/query/limit"],"negativeDomain":"One parameter carried and the other dropped.","polarity":"expects-hold","relation":"all","scope":"The two sibling parameters, as sent."},"id":"O-005","polarity":"expects-hold"},{"check":{"op":"containment","operands":[{"pointer":"/interactions/list/response-body/items"},{"pointer":"/interactions/create/call-inputs/body/name"}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/create/call-inputs/body/name"],"negativeDomain":"A create reporting success whose thing never appears in a later list.","polarity":"expects-hold","relation":"containment","scope":"The list read after the create, against the name the create sent."},"id":"O-006","polarity":"expects-hold"},{"check":{"collection":{"pointer":"/interactions/list/response-body/items"},"op":"for-all","predicate":{"op":"existence","operands":[{"pointer":"@/id"}]}},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list whose first element carries an identifier and whose later elements do not.","polarity":"expects-hold","relation":"for-all","scope":"Every element of the returned list."},"id":"O-007","polarity":"expects-hold"}],"parentDigest":null,"permittedInterfaces":[{"kind":"api","logicalId":"thing-api","operations":[{"method":"POST","operationId":"create-thing","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":["name"],"requiredKeys":["name"],"types":{"name":"string"}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":[],"requiredKeys":[],"types":{}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/id":"payload","/ok":"success-indicator"},"collectionLocations":[],"permittedKeys":["id","ok","error"],"requiredKeys":["id","ok"],"successIndicator":"/ok","types":{"error":"string","id":"string","ok":"boolean"}},"sensitivityWitness":{"channel":"body","legs":[{"inputs":{"body":{"kind":"json","value":{"name":"alpha"}},"header":{},"path":{},"query":{}},"legId":"create-witness-a"},{"inputs":{"body":{"kind":"json","value":{"name":"beta"}},"header":{},"path":{},"query":{}},"legId":"create-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/create-witness-a/response-body"},{"pointer":"/interactions/create-witness-b/response-body"}]}]},"witnessId":"create-thing-sensitivity"},"stateChangeMarker":true,"volatilePointers":["/id"]},{"method":"GET","operationId":"list-things","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":[],"requiredKeys":[],"types":{}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":["limit"],"requiredKeys":[],"types":{"limit":"number"}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/items":"collection"},"collectionLocations":[{"expectedCardinality":{"count":3,"mode":"exact"},"pointer":"/items","referenceSet":null}],"permittedKeys":["items","error"],"requiredKeys":["items"],"successIndicator":"/items","types":{"error":"string","items":"array"}},"sensitivityWitness":{"channel":"query","legs":[{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":1}},"legId":"list-witness-a"},{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":2}},"legId":"list-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/list-witness-a/response-body"},{"pointer":"/interactions/list-witness-b/response-body"}]}]},"witnessId":"list-things-sensitivity"},"stateChangeMarker":false,"volatilePointers":[]}]}],"probeStepBound":8,"referenceSets":{"expected-things":{"commentary":null,"keys":["id"],"members":[{"id":"t-1"},{"id":"t-2"},{"id":"t-3"}]}},"requiredEvidence":["Request and response pair for every call, in order."],"revisionCount":0,"rubrics":[{"criteria":[{"evidence":"/interactions/list/response-body/items","id":"RC-001","text":"Does the returned list carry every expected identifier?"}],"failureModePenalties":[{"description":"An expected thing is missing.","name":"omission"}],"id":"R-001","maxLength":400,"scaleLevels":[{"anchor":"Every expected thing is present.","level":1}]}],"safetyLimits":["No request to any host other than the mapped thing-api target."],"schemaVersion":1,"scopedResources":null,"siblingGroups":{"operations":[["create-thing","list-things"]],"parameters":[["limit","name"]]},"sourceSpecDigest":null,"testData":{"cleanup":"Delete every thing created during the run.","setup":"Seed exactly three things with identifiers t-1, t-2, t-3."},"waivers":[{"approval":"gate-c-reviewer","condition":null,"expiresAt":"2027-01-01T00:00:00Z","id":"W-001","rationale":"The upstream seed is unavailable in the sandbox environment.","rule":"omission-and-completeness"}]}
@@ -0,0 +1 @@
1
+ {"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractId":"wrong-cardinality-form","fixtureReset":null,"forbiddenInputs":["original-spec","source-code","repository","builder-transcript","implementation-logs","comparator-results","human-labels"],"interactionPlan":[{"after":null,"inputBinding":{"body":{"name":{"matcher":"any"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"create"},{"after":"create","inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"literal":10}}},"operationId":"list-things","stepId":"list"},{"after":null,"inputBinding":{"body":{"name":{"matcher":"type-violating"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"malformed-create"},{"after":null,"inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"matcher":"type-violating"}}},"operationId":"list-things","stepId":"malformed-list"}],"oracles":[{"check":{"actualKey":"id","expectedKey":"id","op":"covers-by-key","operands":[{"referenceSet":"expected-things"},{"pointer":"/interactions/list/response-body/items"}]},"commentary":"Reconciles the whole list against the declared set.","direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list omitting a seeded thing, or repeating one.","polarity":"expects-hold","relation":"covers-by-key","scope":"One list call over the seeded set."},"id":"O-001","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/ok"}]},{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/id"}]},{"op":"absence","operands":[{"pointer":"/interactions/create/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/response-body/ok","/interactions/create/response-body/id","/interactions/create/response-body/error"],"negativeDomain":"A create reporting success with no identifier, or with a diagnostic beside it.","polarity":"expects-hold","relation":"all","scope":"The whole create response."},"id":"O-002","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/list/response-body/items"}]},{"op":"absence","operands":[{"pointer":"/interactions/list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/list/response-body/error"],"negativeDomain":"A list carrying items alongside a diagnostic field.","polarity":"expects-hold","relation":"all","scope":"The list response taken as a whole."},"id":"O-003","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/malformed-create/response-body/error"}]},{"op":"existence","operands":[{"pointer":"/interactions/malformed-list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/malformed-create/response-body/error","/interactions/malformed-list/response-body/error"],"negativeDomain":"One sibling rejecting the malformed input while the other accepts it.","polarity":"expects-hold","relation":"all","scope":"Both sibling operations, each given an input that violates its declared type."},"id":"O-004","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/call-inputs/body/name"}]},{"op":"existence","operands":[{"pointer":"/interactions/list/call-inputs/query/limit"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/call-inputs/body/name","/interactions/list/call-inputs/query/limit"],"negativeDomain":"One parameter carried and the other dropped.","polarity":"expects-hold","relation":"all","scope":"The two sibling parameters, as sent."},"id":"O-005","polarity":"expects-hold"},{"check":{"op":"containment","operands":[{"pointer":"/interactions/list/response-body/items"},{"pointer":"/interactions/create/call-inputs/body/name"}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/create/call-inputs/body/name"],"negativeDomain":"A create reporting success whose thing never appears in a later list.","polarity":"expects-hold","relation":"containment","scope":"The list read after the create, against the name the create sent."},"id":"O-006","polarity":"expects-hold"},{"check":{"collection":{"pointer":"/interactions/list/response-body/items"},"op":"for-all","predicate":{"op":"existence","operands":[{"pointer":"@/id"}]}},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list whose first element carries an identifier and whose later elements do not.","polarity":"expects-hold","relation":"for-all","scope":"Every element of the returned list."},"id":"O-007","polarity":"expects-hold"}],"parentDigest":null,"permittedInterfaces":[{"kind":"api","logicalId":"thing-api","operations":[{"method":"POST","operationId":"create-thing","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":["name"],"requiredKeys":["name"],"types":{"name":"string"}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":[],"requiredKeys":[],"types":{}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/id":"payload","/ok":"success-indicator"},"collectionLocations":[],"permittedKeys":["id","ok","error"],"requiredKeys":["id","ok"],"successIndicator":"/ok","types":{"error":"string","id":"string","ok":"boolean"}},"sensitivityWitness":{"channel":"body","legs":[{"inputs":{"body":{"kind":"json","value":{"name":"alpha"}},"header":{},"path":{},"query":{}},"legId":"create-witness-a"},{"inputs":{"body":{"kind":"json","value":{"name":"beta"}},"header":{},"path":{},"query":{}},"legId":"create-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/create-witness-a/response-body"},{"pointer":"/interactions/create-witness-b/response-body"}]}]},"witnessId":"create-thing-sensitivity"},"stateChangeMarker":true,"volatilePointers":["/id"]},{"method":"GET","operationId":"list-things","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":[],"requiredKeys":[],"types":{}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":["limit"],"requiredKeys":[],"types":{"limit":"number"}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/items":"collection"},"collectionLocations":[{"expectedCardinality":{"max":20,"mode":"page-bounded"},"pointer":"/items","referenceSet":"expected-things"}],"permittedKeys":["items","error"],"requiredKeys":["items"],"successIndicator":"/items","types":{"error":"string","items":"array"}},"sensitivityWitness":{"channel":"query","legs":[{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":1}},"legId":"list-witness-a"},{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":2}},"legId":"list-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/list-witness-a/response-body"},{"pointer":"/interactions/list-witness-b/response-body"}]}]},"witnessId":"list-things-sensitivity"},"stateChangeMarker":false,"volatilePointers":[]}]}],"probeStepBound":8,"referenceSets":{"expected-things":{"commentary":null,"keys":["id"],"members":[{"id":"t-1"},{"id":"t-2"},{"id":"t-3"}]}},"requiredEvidence":["Request and response pair for every call, in order."],"revisionCount":0,"rubrics":[{"criteria":[{"evidence":"/interactions/list/response-body/items","id":"RC-001","text":"Does the returned list carry every expected identifier?"}],"failureModePenalties":[{"description":"An expected thing is missing.","name":"omission"}],"id":"R-001","maxLength":400,"scaleLevels":[{"anchor":"Every expected thing is present.","level":1}]}],"safetyLimits":["No request to any host other than the mapped thing-api target."],"schemaVersion":1,"scopedResources":null,"siblingGroups":{"operations":[["create-thing","list-things"]],"parameters":[["limit","name"]]},"sourceSpecDigest":null,"testData":{"cleanup":"Delete every thing created during the run.","setup":"Seed exactly three things with identifiers t-1, t-2, t-3."},"waivers":[{"approval":"gate-c-reviewer","condition":null,"expiresAt":"2027-01-01T00:00:00Z","id":"W-001","rationale":"The upstream seed is unavailable in the sandbox environment.","rule":"omission-and-completeness"}]}
@@ -0,0 +1 @@
1
+ {"entries":[{"digest":"sha256:678b28f21ed407e910d7a28d90c538fe1d538452c6e2aed73b63fa26bca6c261","kind":"readme","path":"corpus/dev/README.md"},{"digest":"sha256:93236f18b20c5e2e12695a02ae08029f5922969b309889cdf228acf1d8cbff0f","kind":"sealed-evaluator-brief","path":"corpus/dev/compile-seal-example/brief.json"},{"digest":"sha256:72bf8d824e4fca47c85a92a3da948ba4ff28e7f79fed5a8a2d5a9bbf77520c9f","kind":"contract","path":"corpus/dev/compile-seal-example/contract.json"},{"digest":"sha256:c704e4dde0274e37b5eece21426b9df08a3c100bcdaa2d942732af9496a1b864","kind":"contract","path":"corpus/dev/contracts/absent-collection-locations.json"},{"digest":"sha256:f14492a3c241ad25d733c156aaa6d22db2a3a98e213ffacf598ad3c56a702aa8","kind":"contract","path":"corpus/dev/contracts/absent-sibling-groups.json"},{"digest":"sha256:3beb5f7da47894a0012c3305acdad189c82c4ad0fb2c87f684c60ec97afd3fa2","kind":"contract","path":"corpus/dev/contracts/absent-success-indicator.json"},{"digest":"sha256:8975e0f522bf4b7061eab079d99e71066066131e6f0c2c6436a1cce4c7f83962","kind":"contract","path":"corpus/dev/contracts/empty-channel-roles.json"},{"digest":"sha256:c3074bb286c3b5511d46592e2651ce8197a67e7b7c11245e64b8225cbab33dba","kind":"contract","path":"corpus/dev/contracts/empty-collection-locations.json"},{"digest":"sha256:6134ce42e9527411547ade38350b01cc63cbb0f628f24f79ae44fdadfa8f9490","kind":"contract","path":"corpus/dev/contracts/empty-request-shapes.json","structuralFailure":"unreachable-check-evidence"},{"digest":"sha256:a185b05780198cbd3e34f11bd66f1ab6282db1ebe9039fc3eb5e6c4bbda10915","kind":"contract","path":"corpus/dev/contracts/empty-sibling-groups.json"},{"digest":"sha256:fdafe7821a1da815a10ecda53a4cb5aba140aad69b2aa8db5c9cbab0955a2255","kind":"contract","path":"corpus/dev/contracts/no-collection-quantifier.json"},{"digest":"sha256:ed3bce99108bb0962df4a165d28800428646b38d1a64be50a553a9da0356bbeb","kind":"contract","path":"corpus/dev/contracts/no-operation-inventory.json","structuralFailure":"unreachable-check-evidence"},{"digest":"sha256:358c1935f404c895c4f44c7da09747f22d1e11e0979f25f115242bc9021d4364","kind":"contract","path":"corpus/dev/contracts/no-read-back-relation.json"},{"digest":"sha256:e16fd44d0c867cba232623550b06772c7a3e8f34a9508aa667ab88104b18c125","kind":"contract","path":"corpus/dev/contracts/no-state-change-marker.json","structuralFailure":"undeclared-mandatory-input"},{"digest":"sha256:de356728c2da74ffc33068e0bb2613cb4ba9ac0e06541bfb184aa4726a7f345b","kind":"contract","path":"corpus/dev/contracts/no-type-violating-step.json"},{"digest":"sha256:7903eba8fbe4da5b54bb0b92f20e79603acb15d2b9967ae5328c7cfc402b0641","kind":"contract","path":"corpus/dev/contracts/per-key-split-oracles.json"},{"digest":"sha256:72bf8d824e4fca47c85a92a3da948ba4ff28e7f79fed5a8a2d5a9bbf77520c9f","kind":"contract","path":"corpus/dev/contracts/satisfied-declarations.json"},{"digest":"sha256:ef9efd8c852ba94f96c21d8b57fa25cf0c9aca0631fafb0e2bb3344cabd5c76d","kind":"contract","path":"corpus/dev/contracts/single-required-response-key.json"},{"digest":"sha256:ebda9682a128039dd426ca9698de86f648597670be67be8fec1f72a4896ef9cb","kind":"contract","path":"corpus/dev/contracts/split-indicator-oracle.json"},{"digest":"sha256:bf30708c3102e01a1e9a6797510a2e5a334f9f31b19750abdbfcbfcbc036f1eb","kind":"contract","path":"corpus/dev/contracts/unaddressed-parameter-sibling.json"},{"digest":"sha256:fd057febc0f27b82f949f0f5d57d78bc6249542502965739c021b0deb620cc4b","kind":"contract","path":"corpus/dev/contracts/unnamed-reference-set.json"},{"digest":"sha256:57d2e54261f6204eb77b99405a87ad8e5a69a87b85377ad3ce8f3e80eca446f3","kind":"contract","path":"corpus/dev/contracts/wrong-cardinality-form.json"}]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The reference adapters, published at the `./adapters` subpath. AD-28 calls
3
+ * them conveniences and never a required path, so they sit behind their own
4
+ * subpath and the root barrel keeps the `root -> adapters` edge the matrix
5
+ * does not grant.
6
+ */
7
+ export type { CorpusMechanism } from './local-corpus-adapter.ts';
8
+ export { createLocalCorpusAdapter } from './local-corpus-adapter.ts';
9
+ export type { FileSystemMechanism } from './node-file-system-adapter.ts';
10
+ export { createNodeFileSystemAdapter } from './node-file-system-adapter.ts';
11
+ export type { ClockMechanism } from './system-clock-adapter.ts';
12
+ export { createSystemClockAdapter } from './system-clock-adapter.ts';
@@ -0,0 +1,3 @@
1
+ export { createLocalCorpusAdapter } from './local-corpus-adapter.js';
2
+ export { createNodeFileSystemAdapter } from './node-file-system-adapter.js';
3
+ export { createSystemClockAdapter } from './system-clock-adapter.js';
@@ -0,0 +1,7 @@
1
+ import type { CorpusPort } from '../ports/corpus-port.ts';
2
+ /** Returns `unknown` so the response parse stays falsifiable; see `port-boundary.ts`. */
3
+ export type CorpusMechanism = (resolvedPath: string, signal: AbortSignal) => Promise<unknown>;
4
+ export declare function createLocalCorpusAdapter(options: {
5
+ readonly root: string;
6
+ readonly mechanism?: CorpusMechanism;
7
+ }): CorpusPort;
@@ -0,0 +1,78 @@
1
+ /** AD-8's corpus port over a caller-supplied root directory. */
2
+ import { readFile, realpath } from 'node:fs/promises';
3
+ import { isAbsolute, posix, relative, resolve, sep } from 'node:path';
4
+ import { RuntimeFault } from '../core/schemas/faults.js';
5
+ import { corpusResolveParsers } from '../ports/corpus-port.js';
6
+ import { runPortMethod } from './port-boundary.js';
7
+ const nodeCorpus = (path, signal) => readFile(path, { signal });
8
+ function escaped(privateRef, detail) {
9
+ return new RuntimeFault('port-failure', 'CorpusResolveRequest', `the private reference "${privateRef}" ${detail}`);
10
+ }
11
+ /**
12
+ * The lexical half of the escape check, before any filesystem call. AD-8 calls
13
+ * the reference opaque and AD-18 keeps a private path out of an artifact; an
14
+ * opaque handle spellable as `../../etc/passwd` is neither.
15
+ */
16
+ function assertNoLexicalEscape(privateRef) {
17
+ const normalized = posix.normalize(privateRef);
18
+ if (posix.isAbsolute(normalized)) {
19
+ throw escaped(privateRef, 'is absolute');
20
+ }
21
+ if (normalized.split('/').some((segment) => segment === '..')) {
22
+ throw escaped(privateRef, 'still contains a ".." segment after normalizing');
23
+ }
24
+ }
25
+ /**
26
+ * The real-path half. It needs a filesystem call, so it runs after the read,
27
+ * and it catches a symlink inside the root pointing outside it. The bytes are
28
+ * discarded. Running it first would make an absent file fail before the
29
+ * mechanism was called, and `single-underlying-call-on-failure` counts that
30
+ * call.
31
+ */
32
+ async function assertInsideRoot(root, privateRef, target) {
33
+ let realRoot;
34
+ let realTarget;
35
+ try {
36
+ realRoot = await realpath(root);
37
+ realTarget = await realpath(target);
38
+ }
39
+ catch (error) {
40
+ throw new RuntimeFault('port-failure', 'CorpusResolveRequest', `the private reference "${privateRef}" could not be resolved to a real path inside the root`, { cause: error });
41
+ }
42
+ // `relative`, never a prefix compare: a root of `/` makes the prefix `//`,
43
+ // which no valid target starts with, so a prefix check rejects every file
44
+ // under a filesystem-root corpus.
45
+ const inside = relative(realRoot, realTarget);
46
+ if (inside !== '' &&
47
+ (isAbsolute(inside) || inside === '..' || inside.startsWith(`..${sep}`))) {
48
+ throw escaped(privateRef, 'resolves outside the corpus root');
49
+ }
50
+ }
51
+ export function createLocalCorpusAdapter(options) {
52
+ const mechanism = options.mechanism ?? nodeCorpus;
53
+ return {
54
+ resolve: (request, signal) => {
55
+ // Captured per call so `postcheck` reads the same path the mechanism
56
+ // was given.
57
+ let target = '';
58
+ return runPortMethod({
59
+ request,
60
+ requestParser: corpusResolveParsers.request,
61
+ responseParser: corpusResolveParsers.response,
62
+ requestPath: 'CorpusResolveRequest',
63
+ responsePath: 'CorpusResolveResponse',
64
+ signal,
65
+ precheck: (parsed) => {
66
+ assertNoLexicalEscape(parsed.privateRef);
67
+ target = resolve(options.root, parsed.privateRef);
68
+ },
69
+ mechanism: (_parsed, innerSignal) => mechanism(target, innerSignal),
70
+ postcheck: (parsed) => assertInsideRoot(options.root, parsed.privateRef, target),
71
+ assemble: (raw, parsed) => ({
72
+ privateRef: parsed.privateRef,
73
+ bytes: raw,
74
+ }),
75
+ });
76
+ },
77
+ };
78
+ }
@@ -0,0 +1,7 @@
1
+ import type { FileSystemPort } from '../ports/file-system-port.ts';
2
+ /** Both return `unknown` so the response parse stays falsifiable; see `port-boundary.ts`. */
3
+ export type FileSystemMechanism = {
4
+ readonly readFile: (path: string, signal: AbortSignal) => Promise<unknown>;
5
+ readonly writeFile: (path: string, bytes: Uint8Array, signal: AbortSignal) => Promise<unknown>;
6
+ };
7
+ export declare function createNodeFileSystemAdapter(mechanism?: FileSystemMechanism): FileSystemPort;
@@ -0,0 +1,39 @@
1
+ /** the file-system port over `node:fs/promises`. */
2
+ import { readFile, writeFile } from 'node:fs/promises';
3
+ import { fileReadParsers, fileWriteParsers } from '../ports/file-system-port.js';
4
+ import { runPortMethod } from './port-boundary.js';
5
+ const nodeFileSystem = {
6
+ readFile: (path, signal) => readFile(path, { signal }),
7
+ // `fs.writeFile` resolves to `undefined`, so the mechanism returns the byte
8
+ // count itself. Take it from the request and `FileWriteResponse.byteLength`
9
+ // is assembled from a value the adapter already holds, so the parse could
10
+ // never reject for `writeFile`.
11
+ writeFile: async (path, bytes, signal) => {
12
+ await writeFile(path, bytes, { signal });
13
+ return bytes.length;
14
+ },
15
+ };
16
+ export function createNodeFileSystemAdapter(mechanism = nodeFileSystem) {
17
+ return {
18
+ readFile: (request, signal) => runPortMethod({
19
+ request,
20
+ requestParser: fileReadParsers.request,
21
+ responseParser: fileReadParsers.response,
22
+ requestPath: 'FileReadRequest',
23
+ responsePath: 'FileReadResponse',
24
+ signal,
25
+ mechanism: (parsed, innerSignal) => mechanism.readFile(parsed.path, innerSignal),
26
+ assemble: (raw, parsed) => ({ path: parsed.path, bytes: raw }),
27
+ }),
28
+ writeFile: (request, signal) => runPortMethod({
29
+ request,
30
+ requestParser: fileWriteParsers.request,
31
+ responseParser: fileWriteParsers.response,
32
+ requestPath: 'FileWriteRequest',
33
+ responsePath: 'FileWriteResponse',
34
+ signal,
35
+ mechanism: (parsed, innerSignal) => mechanism.writeFile(parsed.path, parsed.bytes, innerSignal),
36
+ assemble: (raw, parsed) => ({ path: parsed.path, byteLength: raw }),
37
+ }),
38
+ };
39
+ }
@@ -0,0 +1,18 @@
1
+ import type { BoundaryParser } from '../ports/port.ts';
2
+ export type PortMethodOptions<Request, Response> = {
3
+ readonly request: unknown;
4
+ readonly requestParser: BoundaryParser<Request>;
5
+ readonly responseParser: BoundaryParser<Response>;
6
+ /** the message schema's own name, matching `invokePort`. */
7
+ readonly requestPath: string;
8
+ readonly responsePath: string;
9
+ readonly signal: AbortSignal;
10
+ /** After the request parses, before the mechanism runs, so a refusal here costs no I/O. Throws its own `RuntimeFault`. */
11
+ readonly precheck?: (request: Request) => void;
12
+ readonly mechanism: (request: Request, signal: AbortSignal) => Promise<unknown>;
13
+ /** After the mechanism returns, for a check needing I/O of its own. Throws its own `RuntimeFault`. */
14
+ readonly postcheck?: (request: Request) => Promise<void>;
15
+ /** Builds the response shape from the mechanism's `unknown` result. */
16
+ readonly assemble: (raw: unknown, request: Request) => unknown;
17
+ };
18
+ export declare function runPortMethod<Request, Response>(options: PortMethodOptions<Request, Response>): Promise<Response>;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * The five steps every adapter method runs. Three adapters share four port
3
+ * methods, and four hand-copied bodies would be four chances for one boundary
4
+ * to drift.
5
+ *
6
+ * Step 3 is where these adapters differ from `src/application/invoke-port.ts`.
7
+ * `invokePort` awaits the port and reads `signal.aborted` only in its `catch`,
8
+ * so a port that never settles makes `invokePort` never settle. AD-28 obliges
9
+ * a caller-supplied port to honour the signal itself, so `invokePort` may
10
+ * assume it; an adapter is what that obligation lands on. Fixture 54 asserts
11
+ * the divergence.
12
+ */
13
+ import { RuntimeFault } from '../core/schemas/faults.js';
14
+ /** Races one mechanism call against the signal. The listener is `{ once: true }` and removed in a `finally`, so nothing leaks. */
15
+ async function raceAbort(signal, responsePath, call) {
16
+ if (signal.aborted) {
17
+ throw new RuntimeFault('aborted', responsePath, 'the signal aborted before the raced work began', { cause: signal.reason });
18
+ }
19
+ // Suppress unhandled late rejections if the race is won by abort
20
+ call.catch(() => { });
21
+ let listener;
22
+ try {
23
+ const aborted = new Promise((_resolve, reject) => {
24
+ listener = () => {
25
+ reject(new RuntimeFault('aborted', responsePath, 'the signal aborted while the mechanism was in flight', { cause: signal.reason }));
26
+ };
27
+ signal.addEventListener('abort', listener, { once: true });
28
+ });
29
+ return await Promise.race([call, aborted]);
30
+ }
31
+ finally {
32
+ if (listener !== undefined)
33
+ signal.removeEventListener('abort', listener);
34
+ }
35
+ }
36
+ export async function runPortMethod(options) {
37
+ const { request, requestParser, responseParser, requestPath, responsePath, signal, precheck, mechanism, postcheck, assemble, } = options;
38
+ // 1. An aborted call does not validate a request nobody will send.
39
+ if (signal.aborted) {
40
+ throw new RuntimeFault('aborted', requestPath, 'signal was already aborted before the port call', { cause: signal.reason });
41
+ }
42
+ // 2.
43
+ const parsedRequest = requestParser.safeParse(request);
44
+ if (!parsedRequest.success) {
45
+ throw new RuntimeFault('schema-parse-failure', requestPath, 'outbound request failed boundary validation', { cause: parsedRequest.error });
46
+ }
47
+ // 3. Exactly one mechanism call, raced against the abort.
48
+ let raw;
49
+ try {
50
+ precheck?.(parsedRequest.data);
51
+ raw = await raceAbort(signal, responsePath, mechanism(parsedRequest.data, signal));
52
+ }
53
+ catch (error) {
54
+ if (error instanceof RuntimeFault)
55
+ throw error;
56
+ if (signal.aborted) {
57
+ throw new RuntimeFault('aborted', responsePath, 'signal was aborted before the mechanism settled', { cause: error });
58
+ }
59
+ throw new RuntimeFault('port-failure', responsePath, 'the underlying mechanism threw or rejected', { cause: error });
60
+ }
61
+ // Raced too: `postcheck` does its own I/O (a `realpath` pair, for the corpus
62
+ // adapter), and an abort during that work has to reject rather than wait.
63
+ if (postcheck !== undefined) {
64
+ try {
65
+ await raceAbort(signal, responsePath, postcheck(parsedRequest.data));
66
+ }
67
+ catch (error) {
68
+ if (error instanceof RuntimeFault)
69
+ throw error;
70
+ throw new RuntimeFault('port-failure', responsePath, 'a post-call check threw or rejected', { cause: error });
71
+ }
72
+ }
73
+ // 4. A partial result or an in-band error object fails here like any other
74
+ // schema mismatch. That is why every mechanism returns `unknown`: give it a
75
+ // precise type and the adapter assembles the response from a value it
76
+ // already holds, so this parse could never reject.
77
+ const parsedResponse = responseParser.safeParse(assemble(raw, parsedRequest.data));
78
+ if (!parsedResponse.success) {
79
+ throw new RuntimeFault('port-contract-violation', responsePath, 'the mechanism result failed boundary validation', { cause: parsedResponse.error });
80
+ }
81
+ // 5.
82
+ return parsedResponse.data;
83
+ }
@@ -0,0 +1,10 @@
1
+ /** AD-1's clock read, in the layer where a clock read is legal. */
2
+ import type { ClockPort } from '../ports/clock-port.ts';
3
+ /**
4
+ * `unknown`, and an `AbortSignal` even though a clock read cannot block. The
5
+ * suite counts underlying calls and drives an `in-band-error` scenario;
6
+ * neither is constructible against a mechanism whose return type already
7
+ * satisfies the response schema.
8
+ */
9
+ export type ClockMechanism = (signal: AbortSignal) => Promise<unknown>;
10
+ export declare function createSystemClockAdapter(mechanism?: ClockMechanism): ClockPort;
@@ -0,0 +1,18 @@
1
+ /** AD-1's clock read, in the layer where a clock read is legal. */
2
+ import { clockReadParsers } from '../ports/clock-port.js';
3
+ import { runPortMethod } from './port-boundary.js';
4
+ const systemClock = async () => new Date().toISOString();
5
+ export function createSystemClockAdapter(mechanism = systemClock) {
6
+ return {
7
+ read: (request, signal) => runPortMethod({
8
+ request,
9
+ requestParser: clockReadParsers.request,
10
+ responseParser: clockReadParsers.response,
11
+ requestPath: 'ClockReadRequest',
12
+ responsePath: 'ClockReadResponse',
13
+ signal,
14
+ mechanism: (_parsed, innerSignal) => mechanism(innerSignal),
15
+ assemble: (raw) => ({ now: raw }),
16
+ }),
17
+ };
18
+ }
@@ -0,0 +1,4 @@
1
+ import { EvalContract } from '../core/schemas/eval-contract.ts';
2
+ export declare function compile(input: unknown, options?: {
3
+ readonly strict?: boolean;
4
+ }): EvalContract;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The synchronous application boundary for the compile stage: parses unknown
3
+ * input against `EvalContract`, applies AD-4's default-on strict mode, and
4
+ * delegates every structural decision to `core/compile/compile.ts`. Check
5
+ * selection, ordering, and structural decisions stay in core; this layer
6
+ * only validates and delegates.
7
+ *
8
+ * AD-34: compile needs no external observation, so this stays a plain
9
+ * synchronous function with no plan, reducer, promise, port, or `await`.
10
+ */
11
+ import { compile as compileContract } from '../core/compile/compile.js';
12
+ import { freezeArtifact } from '../core/lineage/freeze.js';
13
+ import { EvalContract } from '../core/schemas/eval-contract.js';
14
+ import { RuntimeFault } from '../core/schemas/faults.js';
15
+ export function compile(input, options) {
16
+ const parsed = EvalContract.safeParse(input);
17
+ if (!parsed.success) {
18
+ throw new RuntimeFault('schema-parse-failure', 'EvalContract', 'input does not conform to the EvalContract schema', { cause: parsed.error });
19
+ }
20
+ // `parsed.data` is Zod's own deep clone of `input` on success, so the
21
+ // returned contract shares no mutable state with the caller's object.
22
+ // Every failure below propagates unchanged: nothing here catches.
23
+ return freezeArtifact(compileContract(parsed.data, { strict: options?.strict ?? true }));
24
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The caller-supplied diagnostic sink and the shape it receives. A plain
3
+ * callback: it returns nothing the core reads, so there is nothing to validate
4
+ * and nothing to await, which is why the logging convention keeps it out of
5
+ * `ports/`.
6
+ *
7
+ * Only stages carrying a run identifier emit. `compile` and `seal` take no run
8
+ * identifier, so a line either of them wrote would carry no run id and no
9
+ * stage, and they emit nothing.
10
+ */
11
+ /** One diagnostic. `stage` is the emitting stage, never the command. */
12
+ export type Diagnostic = {
13
+ readonly runId: string;
14
+ readonly stage: 'preflight';
15
+ readonly message: string;
16
+ };
17
+ export type DiagnosticSink = (diagnostic: Diagnostic) => void;
18
+ /**
19
+ * Emits when a sink is present. A throwing sink is the caller's defect and
20
+ * propagates: discarding it would make a broken sink look like a quiet run.
21
+ */
22
+ export declare function emit(sink: DiagnosticSink | undefined, diagnostic: Diagnostic): void;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The caller-supplied diagnostic sink and the shape it receives. A plain
3
+ * callback: it returns nothing the core reads, so there is nothing to validate
4
+ * and nothing to await, which is why the logging convention keeps it out of
5
+ * `ports/`.
6
+ *
7
+ * Only stages carrying a run identifier emit. `compile` and `seal` take no run
8
+ * identifier, so a line either of them wrote would carry no run id and no
9
+ * stage, and they emit nothing.
10
+ */
11
+ /**
12
+ * Emits when a sink is present. A throwing sink is the caller's defect and
13
+ * propagates: discarding it would make a broken sink look like a quiet run.
14
+ */
15
+ export function emit(sink, diagnostic) {
16
+ if (sink !== undefined)
17
+ sink(diagnostic);
18
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The application layer's published surface. `cli/` may import this layer and
3
+ * `adapters/` and nothing else; `src/index.ts` may import this layer and
4
+ * `core/schemas` and nothing else. Anything either of them needs out of
5
+ * `core/` is re-exported here, which is what keeps the dependency matrix
6
+ * unamended.
7
+ */
8
+ export { digestArtifact, digestBytes, digestComposite, } from '../core/canonical/digest.ts';
9
+ export type { FailureCode } from '../core/failure-codes.ts';
10
+ export { FAILURE_CODES, StructuralFailure } from '../core/failure-codes.ts';
11
+ export type { LineageChainReport, LineageFinding, } from '../core/lineage/chain.ts';
12
+ export { validateLineageChain } from '../core/lineage/chain.ts';
13
+ export { INTERCHANGE_ARTIFACT_KEYS } from '../core/schemas/artifact.ts';
14
+ export type { RuntimeFaultCode } from '../core/schemas/faults.ts';
15
+ export { RUNTIME_FAULT_CODES, RuntimeFault } from '../core/schemas/faults.ts';
16
+ export type { EvaluatorRecommendation, Verdict, } from '../core/schemas/verdict.ts';
17
+ export { EVALUATOR_RECOMMENDATIONS, VERDICTS, } from '../core/schemas/verdict.ts';
18
+ export { compile } from './compile.ts';
19
+ export type { Diagnostic, DiagnosticSink } from './diagnostics.ts';
20
+ export type { PreflightFromObservationsOptions, RunPreflightOptions, } from './preflight.ts';
21
+ export { preflightFromObservations, runPreflight } from './preflight.ts';
22
+ export { seal } from './seal.ts';
23
+ export { serializeArtifact } from './serialize.ts';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The application layer's published surface. `cli/` may import this layer and
3
+ * `adapters/` and nothing else; `src/index.ts` may import this layer and
4
+ * `core/schemas` and nothing else. Anything either of them needs out of
5
+ * `core/` is re-exported here, which is what keeps the dependency matrix
6
+ * unamended.
7
+ */
8
+ export { digestArtifact, digestBytes, digestComposite, } from '../core/canonical/digest.js';
9
+ export { FAILURE_CODES, StructuralFailure } from '../core/failure-codes.js';
10
+ export { validateLineageChain } from '../core/lineage/chain.js';
11
+ export { INTERCHANGE_ARTIFACT_KEYS } from '../core/schemas/artifact.js';
12
+ export { RUNTIME_FAULT_CODES, RuntimeFault } from '../core/schemas/faults.js';
13
+ export { EVALUATOR_RECOMMENDATIONS, VERDICTS, } from '../core/schemas/verdict.js';
14
+ export { compile } from './compile.js';
15
+ export { preflightFromObservations, runPreflight } from './preflight.js';
16
+ export { seal } from './seal.js';
17
+ export { serializeArtifact } from './serialize.js';
@@ -0,0 +1,2 @@
1
+ import type { InvokePortOptions } from '../ports/port.ts';
2
+ export declare function invokePort<Request, Response>(options: InvokePortOptions<Request, Response>): Promise<Response>;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The sole generic seam that awaits a port (AD-34: `application/` is the
3
+ * only layer that awaits). Validates both sides of a port call, invokes the
4
+ * supplied port method exactly once, preserves any declared `RuntimeFault`
5
+ * unchanged, and translates every other boundary failure into one of AD-28's
6
+ * three port-boundary codes. No retry, back-off, fallback call, logging,
7
+ * caching, mutation, or verdict conversion. Re-execution is a trial/cap
8
+ * decision under AD-6.
9
+ */
10
+ import { RuntimeFault } from '../core/schemas/faults.js';
11
+ export async function invokePort(options) {
12
+ const { request, requestParser, responseParser, port, signal, requestPath, responsePath, } = options;
13
+ // Checked before request validation: an aborted call never spends effort
14
+ // validating a request nobody will send.
15
+ if (signal.aborted) {
16
+ throw new RuntimeFault('aborted', requestPath, 'signal was already aborted before the port call', { cause: signal.reason });
17
+ }
18
+ const parsedRequest = requestParser.safeParse(request);
19
+ if (!parsedRequest.success) {
20
+ throw new RuntimeFault('schema-parse-failure', requestPath, 'outbound request failed boundary validation', { cause: parsedRequest.error });
21
+ }
22
+ let resolved;
23
+ try {
24
+ resolved = await port(parsedRequest.data, signal);
25
+ }
26
+ catch (error) {
27
+ if (error instanceof RuntimeFault)
28
+ throw error;
29
+ // Undeclared error: if the signal aborted while the call was in
30
+ // flight, that abort is the more meaningful fault; otherwise it is a
31
+ // genuine port failure.
32
+ if (signal.aborted) {
33
+ throw new RuntimeFault('aborted', responsePath, 'signal was aborted before the port settled', { cause: error });
34
+ }
35
+ throw new RuntimeFault('port-failure', responsePath, 'the port implementation threw or rejected', { cause: error });
36
+ }
37
+ // A partial result or an in-band error object fails validation like any
38
+ // other schema mismatch: invokePort never special-cases a shape with an
39
+ // "error" field itself; that is the response schema's job.
40
+ const parsedResponse = responseParser.safeParse(resolved);
41
+ if (!parsedResponse.success) {
42
+ throw new RuntimeFault('port-contract-violation', responsePath, 'the resolved value failed boundary validation', { cause: parsedResponse.error });
43
+ }
44
+ return parsedResponse.data;
45
+ }