@emilia-protocol/gate 0.10.0 → 0.13.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 (419) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +272 -0
  3. package/action-control-manifest.js +3 -268
  4. package/action-escrow-custodian.js +4 -0
  5. package/action-escrow-evidence.js +4 -0
  6. package/action-escrow-package.js +4 -0
  7. package/action-escrow-postgres.js +4 -0
  8. package/action-escrow-state.js +4 -0
  9. package/action-escrow-verifiers.js +4 -0
  10. package/action-escrow.js +4 -0
  11. package/action-packs.js +3 -140
  12. package/adapters/_kit.js +3 -104
  13. package/adapters/aws.js +3 -108
  14. package/adapters/cloudflare.js +3 -54
  15. package/adapters/gcp.js +3 -70
  16. package/adapters/github.js +3 -109
  17. package/adapters/jira.js +3 -55
  18. package/adapters/k8s.js +3 -70
  19. package/adapters/linear.js +3 -55
  20. package/adapters/salesforce.js +3 -55
  21. package/adapters/stripe.js +3 -81
  22. package/adapters/supabase.js +3 -121
  23. package/adapters/terraform.js +3 -59
  24. package/adapters/vercel.js +3 -84
  25. package/aec-execution.js +3 -312
  26. package/breakglass.js +3 -582
  27. package/capability-receipt.js +4 -0
  28. package/cf1-conformance.js +3 -106
  29. package/challenge-store.js +3 -69
  30. package/control-plane.js +3 -340
  31. package/coverage.js +3 -721
  32. package/demo.mjs +1 -1
  33. package/deployment-attestation.js +3 -247
  34. package/dist/action-control-manifest.d.ts +82 -0
  35. package/dist/action-control-manifest.d.ts.map +1 -0
  36. package/dist/action-control-manifest.js +422 -0
  37. package/dist/action-control-manifest.js.map +1 -0
  38. package/dist/action-escrow-custodian.d.ts +74 -0
  39. package/dist/action-escrow-custodian.d.ts.map +1 -0
  40. package/dist/action-escrow-custodian.js +363 -0
  41. package/dist/action-escrow-custodian.js.map +1 -0
  42. package/dist/action-escrow-evidence.d.ts +130 -0
  43. package/dist/action-escrow-evidence.d.ts.map +1 -0
  44. package/dist/action-escrow-evidence.js +1012 -0
  45. package/dist/action-escrow-evidence.js.map +1 -0
  46. package/dist/action-escrow-package.d.ts +10 -0
  47. package/dist/action-escrow-package.d.ts.map +1 -0
  48. package/dist/action-escrow-package.js +1583 -0
  49. package/dist/action-escrow-package.js.map +1 -0
  50. package/dist/action-escrow-postgres.d.ts +62 -0
  51. package/dist/action-escrow-postgres.d.ts.map +1 -0
  52. package/dist/action-escrow-postgres.js +339 -0
  53. package/dist/action-escrow-postgres.js.map +1 -0
  54. package/dist/action-escrow-state.d.ts +141 -0
  55. package/dist/action-escrow-state.d.ts.map +1 -0
  56. package/dist/action-escrow-state.js +413 -0
  57. package/dist/action-escrow-state.js.map +1 -0
  58. package/dist/action-escrow-verifiers.d.ts +65 -0
  59. package/dist/action-escrow-verifiers.d.ts.map +1 -0
  60. package/dist/action-escrow-verifiers.js +421 -0
  61. package/dist/action-escrow-verifiers.js.map +1 -0
  62. package/dist/action-escrow.d.ts +112 -0
  63. package/dist/action-escrow.d.ts.map +1 -0
  64. package/dist/action-escrow.js +2661 -0
  65. package/dist/action-escrow.js.map +1 -0
  66. package/dist/action-packs.d.ts +54 -0
  67. package/dist/action-packs.d.ts.map +1 -0
  68. package/dist/action-packs.js +143 -0
  69. package/dist/action-packs.js.map +1 -0
  70. package/dist/adapters/_kit.d.ts +50 -0
  71. package/dist/adapters/_kit.d.ts.map +1 -0
  72. package/dist/adapters/_kit.js +98 -0
  73. package/dist/adapters/_kit.js.map +1 -0
  74. package/dist/adapters/aws.d.ts +158 -0
  75. package/dist/adapters/aws.d.ts.map +1 -0
  76. package/dist/adapters/aws.js +136 -0
  77. package/dist/adapters/aws.js.map +1 -0
  78. package/dist/adapters/cloudflare.d.ts +116 -0
  79. package/dist/adapters/cloudflare.d.ts.map +1 -0
  80. package/dist/adapters/cloudflare.js +75 -0
  81. package/dist/adapters/cloudflare.js.map +1 -0
  82. package/dist/adapters/gcp.d.ts +139 -0
  83. package/dist/adapters/gcp.d.ts.map +1 -0
  84. package/dist/adapters/gcp.js +69 -0
  85. package/dist/adapters/gcp.js.map +1 -0
  86. package/dist/adapters/github.d.ts +123 -0
  87. package/dist/adapters/github.d.ts.map +1 -0
  88. package/dist/adapters/github.js +105 -0
  89. package/dist/adapters/github.js.map +1 -0
  90. package/dist/adapters/jira.d.ts +109 -0
  91. package/dist/adapters/jira.d.ts.map +1 -0
  92. package/dist/adapters/jira.js +54 -0
  93. package/dist/adapters/jira.js.map +1 -0
  94. package/dist/adapters/k8s.d.ts +139 -0
  95. package/dist/adapters/k8s.d.ts.map +1 -0
  96. package/dist/adapters/k8s.js +69 -0
  97. package/dist/adapters/k8s.js.map +1 -0
  98. package/dist/adapters/linear.d.ts +109 -0
  99. package/dist/adapters/linear.d.ts.map +1 -0
  100. package/dist/adapters/linear.js +54 -0
  101. package/dist/adapters/linear.js.map +1 -0
  102. package/dist/adapters/salesforce.d.ts +109 -0
  103. package/dist/adapters/salesforce.d.ts.map +1 -0
  104. package/dist/adapters/salesforce.js +54 -0
  105. package/dist/adapters/salesforce.js.map +1 -0
  106. package/dist/adapters/stripe.d.ts +116 -0
  107. package/dist/adapters/stripe.d.ts.map +1 -0
  108. package/dist/adapters/stripe.js +77 -0
  109. package/dist/adapters/stripe.js.map +1 -0
  110. package/dist/adapters/supabase.d.ts +127 -0
  111. package/dist/adapters/supabase.d.ts.map +1 -0
  112. package/dist/adapters/supabase.js +112 -0
  113. package/dist/adapters/supabase.js.map +1 -0
  114. package/dist/adapters/terraform.d.ts +109 -0
  115. package/dist/adapters/terraform.d.ts.map +1 -0
  116. package/dist/adapters/terraform.js +58 -0
  117. package/dist/adapters/terraform.js.map +1 -0
  118. package/dist/adapters/vercel.d.ts +114 -0
  119. package/dist/adapters/vercel.d.ts.map +1 -0
  120. package/dist/adapters/vercel.js +81 -0
  121. package/dist/adapters/vercel.js.map +1 -0
  122. package/dist/aec-execution.d.ts +107 -0
  123. package/dist/aec-execution.d.ts.map +1 -0
  124. package/dist/aec-execution.js +334 -0
  125. package/dist/aec-execution.js.map +1 -0
  126. package/dist/breakglass.d.ts +205 -0
  127. package/dist/breakglass.d.ts.map +1 -0
  128. package/dist/breakglass.js +627 -0
  129. package/dist/breakglass.js.map +1 -0
  130. package/dist/capability-receipt.d.ts +601 -0
  131. package/dist/capability-receipt.d.ts.map +1 -0
  132. package/dist/capability-receipt.js +1177 -0
  133. package/dist/capability-receipt.js.map +1 -0
  134. package/dist/cf1-conformance.d.ts +83 -0
  135. package/dist/cf1-conformance.d.ts.map +1 -0
  136. package/dist/cf1-conformance.js +94 -0
  137. package/dist/cf1-conformance.js.map +1 -0
  138. package/dist/challenge-store.d.ts +20 -0
  139. package/dist/challenge-store.d.ts.map +1 -0
  140. package/dist/challenge-store.js +62 -0
  141. package/dist/challenge-store.js.map +1 -0
  142. package/dist/control-plane.d.ts +136 -0
  143. package/dist/control-plane.d.ts.map +1 -0
  144. package/dist/control-plane.js +349 -0
  145. package/dist/control-plane.js.map +1 -0
  146. package/dist/coverage.d.ts +156 -0
  147. package/dist/coverage.d.ts.map +1 -0
  148. package/dist/coverage.js +768 -0
  149. package/dist/coverage.js.map +1 -0
  150. package/dist/deployment-attestation.d.ts +93 -0
  151. package/dist/deployment-attestation.d.ts.map +1 -0
  152. package/dist/deployment-attestation.js +262 -0
  153. package/dist/deployment-attestation.js.map +1 -0
  154. package/dist/eg1-conformance.d.ts +286 -0
  155. package/dist/eg1-conformance.d.ts.map +1 -0
  156. package/dist/eg1-conformance.js +379 -0
  157. package/dist/eg1-conformance.js.map +1 -0
  158. package/dist/enterprise.d.ts +88 -0
  159. package/dist/enterprise.d.ts.map +1 -0
  160. package/dist/enterprise.js +194 -0
  161. package/dist/enterprise.js.map +1 -0
  162. package/dist/evidence-postgres.d.ts +123 -0
  163. package/dist/evidence-postgres.d.ts.map +1 -0
  164. package/dist/evidence-postgres.js +343 -0
  165. package/dist/evidence-postgres.js.map +1 -0
  166. package/dist/evidence.d.ts +113 -0
  167. package/dist/evidence.d.ts.map +1 -0
  168. package/dist/evidence.js +369 -0
  169. package/dist/evidence.js.map +1 -0
  170. package/dist/execution-binding.d.ts +49 -0
  171. package/dist/execution-binding.d.ts.map +1 -0
  172. package/dist/execution-binding.js +243 -0
  173. package/dist/execution-binding.js.map +1 -0
  174. package/dist/formal-runtime-map.d.ts +42 -0
  175. package/dist/formal-runtime-map.d.ts.map +1 -0
  176. package/dist/formal-runtime-map.js +23 -0
  177. package/dist/formal-runtime-map.js.map +1 -0
  178. package/dist/index.d.ts +1002 -0
  179. package/dist/index.d.ts.map +1 -0
  180. package/dist/index.js +1736 -0
  181. package/dist/index.js.map +1 -0
  182. package/dist/key-registry.d.ts +60 -0
  183. package/dist/key-registry.d.ts.map +1 -0
  184. package/dist/key-registry.js +144 -0
  185. package/dist/key-registry.js.map +1 -0
  186. package/dist/mcp.d.ts +53 -0
  187. package/dist/mcp.d.ts.map +1 -0
  188. package/dist/mcp.js +112 -0
  189. package/dist/mcp.js.map +1 -0
  190. package/dist/metering.d.ts +80 -0
  191. package/dist/metering.d.ts.map +1 -0
  192. package/dist/metering.js +227 -0
  193. package/dist/metering.js.map +1 -0
  194. package/dist/metrics.d.ts +68 -0
  195. package/dist/metrics.d.ts.map +1 -0
  196. package/dist/metrics.js +242 -0
  197. package/dist/metrics.js.map +1 -0
  198. package/dist/network-witness.d.ts +167 -0
  199. package/dist/network-witness.d.ts.map +1 -0
  200. package/dist/network-witness.js +520 -0
  201. package/dist/network-witness.js.map +1 -0
  202. package/dist/protocol-state.d.ts +141 -0
  203. package/dist/protocol-state.d.ts.map +1 -0
  204. package/dist/protocol-state.js +106 -0
  205. package/dist/protocol-state.js.map +1 -0
  206. package/dist/receipt-program.d.ts +59 -0
  207. package/dist/receipt-program.d.ts.map +1 -0
  208. package/dist/receipt-program.js +1053 -0
  209. package/dist/receipt-program.js.map +1 -0
  210. package/dist/reliance-kernel.d.ts +66 -0
  211. package/dist/reliance-kernel.d.ts.map +1 -0
  212. package/dist/reliance-kernel.js +103 -0
  213. package/dist/reliance-kernel.js.map +1 -0
  214. package/dist/reliance-packet.d.ts +67 -0
  215. package/dist/reliance-packet.d.ts.map +1 -0
  216. package/dist/reliance-packet.js +176 -0
  217. package/dist/reliance-packet.js.map +1 -0
  218. package/dist/remedy-program-postgres.d.ts +37 -0
  219. package/dist/remedy-program-postgres.d.ts.map +1 -0
  220. package/dist/remedy-program-postgres.js +291 -0
  221. package/dist/remedy-program-postgres.js.map +1 -0
  222. package/dist/remedy-program-receipt.d.ts +97 -0
  223. package/dist/remedy-program-receipt.d.ts.map +1 -0
  224. package/dist/remedy-program-receipt.js +817 -0
  225. package/dist/remedy-program-receipt.js.map +1 -0
  226. package/dist/remedy-program.d.ts +76 -0
  227. package/dist/remedy-program.d.ts.map +1 -0
  228. package/dist/remedy-program.js +1346 -0
  229. package/dist/remedy-program.js.map +1 -0
  230. package/dist/reports/art14.d.ts +101 -0
  231. package/dist/reports/art14.d.ts.map +1 -0
  232. package/dist/reports/art14.js +340 -0
  233. package/dist/reports/art14.js.map +1 -0
  234. package/dist/reports/assurance-package.d.ts +197 -0
  235. package/dist/reports/assurance-package.d.ts.map +1 -0
  236. package/dist/reports/assurance-package.js +313 -0
  237. package/dist/reports/assurance-package.js.map +1 -0
  238. package/dist/reports/auditor-workpaper.d.ts +194 -0
  239. package/dist/reports/auditor-workpaper.d.ts.map +1 -0
  240. package/dist/reports/auditor-workpaper.js +545 -0
  241. package/dist/reports/auditor-workpaper.js.map +1 -0
  242. package/dist/reports/external-verification.d.ts +76 -0
  243. package/dist/reports/external-verification.d.ts.map +1 -0
  244. package/dist/reports/external-verification.js +209 -0
  245. package/dist/reports/external-verification.js.map +1 -0
  246. package/dist/reports/reperform.d.ts +122 -0
  247. package/dist/reports/reperform.d.ts.map +1 -0
  248. package/dist/reports/reperform.js +432 -0
  249. package/dist/reports/reperform.js.map +1 -0
  250. package/dist/reports/underwriter.d.ts +127 -0
  251. package/dist/reports/underwriter.d.ts.map +1 -0
  252. package/dist/reports/underwriter.js +348 -0
  253. package/dist/reports/underwriter.js.map +1 -0
  254. package/dist/retention.d.ts +88 -0
  255. package/dist/retention.d.ts.map +1 -0
  256. package/dist/retention.js +90 -0
  257. package/dist/retention.js.map +1 -0
  258. package/dist/roster.d.ts +113 -0
  259. package/dist/roster.d.ts.map +1 -0
  260. package/dist/roster.js +261 -0
  261. package/dist/roster.js.map +1 -0
  262. package/dist/runtime-monitor.d.ts +132 -0
  263. package/dist/runtime-monitor.d.ts.map +1 -0
  264. package/dist/runtime-monitor.js +197 -0
  265. package/dist/runtime-monitor.js.map +1 -0
  266. package/dist/settlement.d.ts +68 -0
  267. package/dist/settlement.d.ts.map +1 -0
  268. package/dist/settlement.js +306 -0
  269. package/dist/settlement.js.map +1 -0
  270. package/dist/siem.d.ts +261 -0
  271. package/dist/siem.d.ts.map +1 -0
  272. package/dist/siem.js +247 -0
  273. package/dist/siem.js.map +1 -0
  274. package/dist/store-postgres.d.ts +107 -0
  275. package/dist/store-postgres.d.ts.map +1 -0
  276. package/dist/store-postgres.js +152 -0
  277. package/dist/store-postgres.js.map +1 -0
  278. package/dist/store.d.ts +95 -0
  279. package/dist/store.d.ts.map +1 -0
  280. package/dist/store.js +202 -0
  281. package/dist/store.js.map +1 -0
  282. package/dist/strict-json.d.ts +14 -0
  283. package/dist/strict-json.d.ts.map +1 -0
  284. package/dist/strict-json.js +132 -0
  285. package/dist/strict-json.js.map +1 -0
  286. package/dist/trust-program-adapters.d.ts +122 -0
  287. package/dist/trust-program-adapters.d.ts.map +1 -0
  288. package/dist/trust-program-adapters.js +802 -0
  289. package/dist/trust-program-adapters.js.map +1 -0
  290. package/dist/trust-program-postgres.d.ts +41 -0
  291. package/dist/trust-program-postgres.d.ts.map +1 -0
  292. package/dist/trust-program-postgres.js +346 -0
  293. package/dist/trust-program-postgres.js.map +1 -0
  294. package/dist/trust-program-revocation.d.ts +206 -0
  295. package/dist/trust-program-revocation.d.ts.map +1 -0
  296. package/dist/trust-program-revocation.js +600 -0
  297. package/dist/trust-program-revocation.js.map +1 -0
  298. package/dist/trust-program.d.ts +197 -0
  299. package/dist/trust-program.d.ts.map +1 -0
  300. package/dist/trust-program.js +1351 -0
  301. package/dist/trust-program.js.map +1 -0
  302. package/dist/witness-postgres.d.ts +43 -0
  303. package/dist/witness-postgres.d.ts.map +1 -0
  304. package/dist/witness-postgres.js +92 -0
  305. package/dist/witness-postgres.js.map +1 -0
  306. package/dist/zk-range-proof.d.ts +78 -0
  307. package/dist/zk-range-proof.d.ts.map +1 -0
  308. package/dist/zk-range-proof.js +228 -0
  309. package/dist/zk-range-proof.js.map +1 -0
  310. package/eg1-conformance.js +3 -404
  311. package/enterprise.js +3 -180
  312. package/ep-assure.mjs +1 -0
  313. package/evidence-postgres.js +3 -356
  314. package/evidence.js +4 -360
  315. package/execution-binding.js +3 -212
  316. package/formal-runtime-map.js +4 -0
  317. package/index.js +4 -1249
  318. package/key-registry.js +3 -134
  319. package/mcp.js +3 -109
  320. package/metering.js +3 -226
  321. package/metrics.js +3 -231
  322. package/network-witness.js +3 -499
  323. package/package.json +47 -4
  324. package/receipt-program.js +4 -0
  325. package/reliance-kernel.js +3 -112
  326. package/reliance-packet.js +3 -175
  327. package/remedy-program-postgres.js +4 -0
  328. package/remedy-program-receipt.js +4 -0
  329. package/remedy-program.js +4 -0
  330. package/reports/art14.js +0 -0
  331. package/reports/assurance-package.js +2 -312
  332. package/reports/auditor-workpaper.js +3 -537
  333. package/reports/external-verification.js +3 -222
  334. package/reports/reperform.js +3 -424
  335. package/reports/underwriter.js +3 -339
  336. package/retention.js +3 -84
  337. package/roster.js +3 -264
  338. package/runtime-monitor.js +4 -0
  339. package/settlement.js +3 -299
  340. package/siem.js +3 -235
  341. package/src/action-control-manifest.ts +424 -0
  342. package/src/action-escrow-custodian.ts +427 -0
  343. package/src/action-escrow-evidence.ts +1178 -0
  344. package/src/action-escrow-package.ts +1821 -0
  345. package/src/action-escrow-postgres.ts +366 -0
  346. package/src/action-escrow-state.ts +498 -0
  347. package/src/action-escrow-verifiers.ts +484 -0
  348. package/src/action-escrow.ts +3039 -0
  349. package/src/action-packs.ts +170 -0
  350. package/src/adapters/_kit.ts +117 -0
  351. package/src/adapters/aws.ts +142 -0
  352. package/src/adapters/cloudflare.ts +78 -0
  353. package/src/adapters/gcp.ts +71 -0
  354. package/src/adapters/github.ts +110 -0
  355. package/src/adapters/jira.ts +56 -0
  356. package/src/adapters/k8s.ts +71 -0
  357. package/src/adapters/linear.ts +56 -0
  358. package/src/adapters/salesforce.ts +56 -0
  359. package/src/adapters/stripe.ts +82 -0
  360. package/src/adapters/supabase.ts +122 -0
  361. package/src/adapters/terraform.ts +60 -0
  362. package/src/adapters/vercel.ts +85 -0
  363. package/src/aec-execution.ts +354 -0
  364. package/src/breakglass.ts +647 -0
  365. package/src/capability-receipt.ts +1258 -0
  366. package/src/cf1-conformance.ts +120 -0
  367. package/src/challenge-store.ts +70 -0
  368. package/src/control-plane.ts +374 -0
  369. package/src/coverage.ts +832 -0
  370. package/src/deployment-attestation.ts +259 -0
  371. package/src/eg1-conformance.ts +471 -0
  372. package/src/enterprise.ts +195 -0
  373. package/src/evidence-postgres.ts +374 -0
  374. package/src/evidence.ts +367 -0
  375. package/src/execution-binding.ts +236 -0
  376. package/src/formal-runtime-map.ts +24 -0
  377. package/src/index.ts +2122 -0
  378. package/src/key-registry.ts +150 -0
  379. package/src/mcp.ts +120 -0
  380. package/src/metering.ts +237 -0
  381. package/src/metrics.ts +232 -0
  382. package/src/network-witness.ts +585 -0
  383. package/src/protocol-state.ts +143 -0
  384. package/src/protocol-state.typecheck.ts +94 -0
  385. package/src/receipt-program.ts +1105 -0
  386. package/src/reliance-kernel.ts +119 -0
  387. package/src/reliance-packet.ts +206 -0
  388. package/src/remedy-program-postgres.ts +367 -0
  389. package/src/remedy-program-receipt.ts +891 -0
  390. package/src/remedy-program.ts +1388 -0
  391. package/src/reports/art14.ts +361 -0
  392. package/src/reports/assurance-package.ts +330 -0
  393. package/src/reports/auditor-workpaper.ts +558 -0
  394. package/src/reports/external-verification.ts +232 -0
  395. package/src/reports/reperform.ts +441 -0
  396. package/src/reports/underwriter.ts +356 -0
  397. package/src/retention.ts +100 -0
  398. package/src/roster.ts +273 -0
  399. package/src/runtime-monitor.ts +217 -0
  400. package/src/settlement.ts +313 -0
  401. package/src/siem.ts +247 -0
  402. package/src/store-postgres.ts +167 -0
  403. package/src/store.ts +214 -0
  404. package/src/strict-json.ts +115 -0
  405. package/src/trust-program-adapters.ts +847 -0
  406. package/src/trust-program-postgres.ts +429 -0
  407. package/src/trust-program-revocation.ts +751 -0
  408. package/src/trust-program.ts +1460 -0
  409. package/src/witness-postgres.ts +106 -0
  410. package/src/zk-range-proof.ts +250 -0
  411. package/store-postgres.js +3 -161
  412. package/store.js +4 -198
  413. package/strict-json.js +3 -85
  414. package/trust-program-adapters.js +4 -0
  415. package/trust-program-postgres.js +4 -0
  416. package/trust-program-revocation.js +4 -0
  417. package/trust-program.js +4 -0
  418. package/witness-postgres.js +3 -96
  419. package/zk-range-proof.js +4 -0
@@ -0,0 +1,1012 @@
1
+ // @ts-nocheck
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * EP-ACTION-ESCROW-EVIDENCE-PACKAGE-v1
5
+ *
6
+ * A content-addressed manifest for the artifacts used by Action Escrow. This
7
+ * module does not decide whether a contract is enforceable and does not move
8
+ * money. Verification replays caller-supplied, relying-party-owned component
9
+ * verifiers so a package cannot make an invalid nested artifact trustworthy by
10
+ * merely hashing it.
11
+ */
12
+ import crypto from 'node:crypto';
13
+ import { hashCanonical } from './execution-binding.js';
14
+ import { strictJsonGate } from './strict-json.js';
15
+ export const ACTION_ESCROW_EVIDENCE_PACKAGE_VERSION = 'EP-ACTION-ESCROW-EVIDENCE-PACKAGE-v1';
16
+ export const ACTION_ESCROW_CONTRACTOR_EVIDENCE_PACKAGE_VERSION = 'EP-ACTION-ESCROW-CONTRACTOR-EVIDENCE-PACKAGE-v1';
17
+ export const ACTION_ESCROW_EVIDENCE_STAGES = Object.freeze([
18
+ 'draft',
19
+ 'awaiting_acceptance',
20
+ 'effective',
21
+ 'awaiting_funding',
22
+ 'funded',
23
+ 'milestone_submitted',
24
+ 'release_reserved',
25
+ 'released',
26
+ 'disputed',
27
+ 'amendment_pending',
28
+ 'cancelled',
29
+ 'completed',
30
+ 'release_indeterminate',
31
+ ]);
32
+ const HASH = /^sha256:[0-9a-f]{64}$/;
33
+ const TOP_KEYS = new Set([
34
+ 'version',
35
+ 'agreement_id',
36
+ 'stage',
37
+ 'binding',
38
+ 'document',
39
+ 'document_execution',
40
+ 'agreement_acceptances',
41
+ 'release_approvals',
42
+ 'funding_statement',
43
+ 'milestones',
44
+ 'release',
45
+ 'state_record',
46
+ 'amendments',
47
+ 'verification_profile',
48
+ 'assembled_at',
49
+ 'limitations',
50
+ 'package_digest',
51
+ ]);
52
+ const CONTRACTOR_TOP_KEYS = new Set([
53
+ ...TOP_KEYS,
54
+ 'project_record',
55
+ ]);
56
+ const DOCUMENT_KEYS = new Set(['media_type', 'digest', 'byte_length', 'file_name']);
57
+ const PROJECT_RECORD_KEYS = new Set([
58
+ 'media_type',
59
+ 'digest',
60
+ 'byte_length',
61
+ 'file_name',
62
+ 'provider',
63
+ 'snapshot_digest',
64
+ ]);
65
+ const PARTY_EVIDENCE_KEYS = new Set(['party_id', 'role', 'evidence']);
66
+ const MILESTONE_KEYS = new Set(['milestone_id', 'evidence', 'resolution']);
67
+ const RELEASE_KEYS = new Set([
68
+ 'reservation',
69
+ 'provider_request',
70
+ 'provider_statement',
71
+ 'execution_record',
72
+ ]);
73
+ const STATE_RECORD_KEYS = new Set(['snapshot', 'statement']);
74
+ const LIMITATIONS = Object.freeze([
75
+ 'The package does not establish contract enforceability, comprehension, voluntariness, workmanship, physical truth, or legal compliance.',
76
+ 'The package does not establish custodian licensing, solvency, or that no payment path existed outside the integrated release boundary.',
77
+ 'A content digest does not upgrade an invalid component; each component must verify under relying-party-pinned trust roots.',
78
+ 'An indeterminate provider effect is not proof of failure and must not be retried before authoritative reconciliation.',
79
+ ]);
80
+ const DEFAULT_MAX_DOCUMENT_BYTES = 50 * 1024 * 1024;
81
+ const DEFAULT_MAX_PROJECT_RECORD_BYTES = 4 * 1024 * 1024;
82
+ const DEFAULT_MAX_PACKAGE_BYTES = 4 * 1024 * 1024;
83
+ /**
84
+ * @param {unknown} value
85
+ * @returns {value is Record<string, any>}
86
+ */
87
+ function isRecord(value) {
88
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
89
+ }
90
+ /**
91
+ * @param {*} value
92
+ * @param {Set<string>} allowed
93
+ * @param {Set<string>} [required]
94
+ */
95
+ function exactKeys(value, allowed, required = allowed) {
96
+ if (!isRecord(value))
97
+ return false;
98
+ const keys = Object.keys(value);
99
+ return keys.every((key) => allowed.has(key))
100
+ && [...required].every((key) => Object.hasOwn(value, key));
101
+ }
102
+ /**
103
+ * @param {number|string|Date|(() => (number|string|Date))} value
104
+ */
105
+ function toIso(value) {
106
+ const candidate = typeof value === 'function' ? value() : value;
107
+ const date = candidate instanceof Date ? candidate : new Date(candidate ?? 0);
108
+ if (!Number.isFinite(date.getTime())) {
109
+ throw new TypeError('action-escrow evidence: assembled_at must be a valid instant');
110
+ }
111
+ return date.toISOString();
112
+ }
113
+ /**
114
+ * @param {*} value
115
+ */
116
+ function portableJsonCopy(value) {
117
+ let nodes = 0;
118
+ let stringBytes = 0;
119
+ const active = new Set();
120
+ /**
121
+ * @param {*} current
122
+ * @param {number} depth
123
+ * @returns {*}
124
+ */
125
+ function copy(current, depth) {
126
+ nodes += 1;
127
+ if (nodes > 50_000 || depth > 64) {
128
+ throw new TypeError('action-escrow evidence: value exceeds resource limits');
129
+ }
130
+ if (current === null || typeof current === 'boolean')
131
+ return current;
132
+ if (typeof current === 'string') {
133
+ stringBytes += Buffer.byteLength(current, 'utf8');
134
+ if (stringBytes > 4 * 1024 * 1024) {
135
+ throw new TypeError('action-escrow evidence: strings exceed resource limits');
136
+ }
137
+ return current;
138
+ }
139
+ if (typeof current === 'number') {
140
+ if (!Number.isSafeInteger(current) || Object.is(current, -0)) {
141
+ throw new TypeError('action-escrow evidence: numbers must be safe integers');
142
+ }
143
+ return current;
144
+ }
145
+ if (!isRecord(current) && !Array.isArray(current)) {
146
+ throw new TypeError('action-escrow evidence: value is not canonical JSON');
147
+ }
148
+ if (active.has(current)) {
149
+ throw new TypeError('action-escrow evidence: cyclic or aliased value');
150
+ }
151
+ active.add(current);
152
+ try {
153
+ if (Array.isArray(current))
154
+ return current.map((entry) => copy(entry, depth + 1));
155
+ const prototype = Object.getPrototypeOf(current);
156
+ if (prototype !== Object.prototype && prototype !== null) {
157
+ throw new TypeError('action-escrow evidence: objects must use a plain prototype');
158
+ }
159
+ return Object.fromEntries(Object.entries(current).map(([key, entry]) => [key, copy(entry, depth + 1)]));
160
+ }
161
+ finally {
162
+ active.delete(current);
163
+ }
164
+ }
165
+ return copy(value, 0);
166
+ }
167
+ /**
168
+ * @param {*} value
169
+ */
170
+ function deepFreeze(value) {
171
+ if (!value || typeof value !== 'object' || Object.isFrozen(value))
172
+ return value;
173
+ Object.freeze(value);
174
+ for (const child of Object.values(value))
175
+ deepFreeze(child);
176
+ return value;
177
+ }
178
+ /**
179
+ * @param {*} value
180
+ * @param {number} maxBytes
181
+ */
182
+ function documentBytes(value, maxBytes) {
183
+ if (!(Buffer.isBuffer(value) || value instanceof Uint8Array)) {
184
+ throw new TypeError('action-escrow evidence: documentBytes must be bytes');
185
+ }
186
+ const bytes = Buffer.from(value);
187
+ if (bytes.length === 0 || bytes.length > maxBytes) {
188
+ throw new TypeError(`action-escrow evidence: documentBytes must be between 1 and ${maxBytes} bytes`);
189
+ }
190
+ return bytes;
191
+ }
192
+ /**
193
+ * @param {*} value
194
+ * @param {number} maxBytes
195
+ */
196
+ function projectRecordBytes(value, maxBytes) {
197
+ if (!(Buffer.isBuffer(value) || value instanceof Uint8Array)) {
198
+ throw new TypeError('action-escrow evidence: projectRecordBytes must be bytes');
199
+ }
200
+ const bytes = Buffer.from(value);
201
+ if (bytes.length === 0 || bytes.length > maxBytes) {
202
+ throw new TypeError(`action-escrow evidence: projectRecordBytes must be between 1 and ${maxBytes} bytes`);
203
+ }
204
+ return bytes;
205
+ }
206
+ /**
207
+ * @param {*} value
208
+ * @param {string} fieldName
209
+ */
210
+ function validFileName(value, fieldName) {
211
+ if (value === null)
212
+ return true;
213
+ if (typeof value !== 'string'
214
+ || value.length === 0
215
+ || value.length > 255
216
+ || /[/\\\u0000]/.test(value)) {
217
+ throw new TypeError(`action-escrow evidence: ${fieldName} is invalid`);
218
+ }
219
+ return true;
220
+ }
221
+ /**
222
+ * @param {Buffer} bytes
223
+ */
224
+ function sha256(bytes) {
225
+ return `sha256:${crypto.createHash('sha256').update(bytes).digest('hex')}`;
226
+ }
227
+ /**
228
+ * @param {*} value
229
+ */
230
+ function validInstant(value) {
231
+ if (typeof value !== 'string')
232
+ return false;
233
+ const parsed = Date.parse(value);
234
+ return Number.isFinite(parsed) && new Date(parsed).toISOString() === value;
235
+ }
236
+ /**
237
+ * @param {*} value
238
+ */
239
+ function canonicalSha256(value) {
240
+ return `sha256:${hashCanonical(value)}`;
241
+ }
242
+ /**
243
+ * @param {*} pkg
244
+ */
245
+ function digestScope(pkg) {
246
+ const { package_digest: _digest, ...scope } = pkg;
247
+ return scope;
248
+ }
249
+ /**
250
+ * Strict raw parser for security-bearing package transport.
251
+ * @param {*} raw
252
+ * @param {{ maxBytes?: number }} [options]
253
+ */
254
+ export function parseActionEscrowEvidencePackage(raw, { maxBytes = DEFAULT_MAX_PACKAGE_BYTES, } = {}) {
255
+ if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {
256
+ return { ok: false, reason: 'invalid_package_limit', value: null };
257
+ }
258
+ if (typeof raw !== 'string') {
259
+ return { ok: false, reason: 'package_must_be_json_text', value: null };
260
+ }
261
+ if (Buffer.byteLength(raw, 'utf8') > maxBytes) {
262
+ return { ok: false, reason: 'package_exceeds_size_limit', value: null };
263
+ }
264
+ const gated = strictJsonGate(raw);
265
+ if (!gated.ok)
266
+ return { ok: false, reason: gated.reason, value: null };
267
+ try {
268
+ return { ok: true, reason: 'parsed', value: JSON.parse(raw) };
269
+ }
270
+ catch {
271
+ return { ok: false, reason: 'invalid_json_syntax', value: null };
272
+ }
273
+ }
274
+ /**
275
+ * @param {*} value
276
+ */
277
+ function normalizedRequiredParties(value) {
278
+ if (!Array.isArray(value) || value.length === 0)
279
+ return null;
280
+ const result = [];
281
+ for (const entry of value) {
282
+ if (typeof entry === 'string' && entry.length > 0) {
283
+ result.push({ party_id: entry, role: null });
284
+ continue;
285
+ }
286
+ if (!isRecord(entry)
287
+ || typeof entry.party_id !== 'string' || entry.party_id.length === 0
288
+ || typeof entry.role !== 'string' || entry.role.length === 0) {
289
+ return null;
290
+ }
291
+ result.push({ party_id: entry.party_id, role: entry.role });
292
+ }
293
+ const identities = result.map((entry) => `${entry.role ?? ''}\u0000${entry.party_id}`);
294
+ return new Set(identities).size === identities.length ? result : null;
295
+ }
296
+ /**
297
+ * @param {string} stage
298
+ */
299
+ function stageRequiresExecutedAgreement(stage) {
300
+ return [
301
+ 'effective',
302
+ 'awaiting_funding',
303
+ 'funded',
304
+ 'milestone_submitted',
305
+ 'release_reserved',
306
+ 'released',
307
+ 'disputed',
308
+ 'completed',
309
+ 'release_indeterminate',
310
+ ].includes(stage);
311
+ }
312
+ /**
313
+ * @param {string} stage
314
+ */
315
+ function stageRequiresReleaseApprovals(stage) {
316
+ return ['release_reserved', 'released', 'completed', 'release_indeterminate'].includes(stage);
317
+ }
318
+ /**
319
+ * @param {string} stage
320
+ */
321
+ function stageRequiresFunding(stage) {
322
+ return [
323
+ 'funded',
324
+ 'milestone_submitted',
325
+ 'release_reserved',
326
+ 'released',
327
+ 'disputed',
328
+ 'completed',
329
+ 'release_indeterminate',
330
+ ].includes(stage);
331
+ }
332
+ /**
333
+ * @param {string} stage
334
+ */
335
+ function stageAllowsFunding(stage) {
336
+ return [
337
+ 'funded',
338
+ 'milestone_submitted',
339
+ 'release_reserved',
340
+ 'released',
341
+ 'disputed',
342
+ 'completed',
343
+ 'release_indeterminate',
344
+ ].includes(stage);
345
+ }
346
+ /**
347
+ * @param {string} stage
348
+ */
349
+ function stageRequiresMilestone(stage) {
350
+ return [
351
+ 'milestone_submitted',
352
+ 'release_reserved',
353
+ 'released',
354
+ 'disputed',
355
+ 'completed',
356
+ 'release_indeterminate',
357
+ ].includes(stage);
358
+ }
359
+ /**
360
+ * @param {string} stage
361
+ */
362
+ function stageAllowsMilestone(stage) {
363
+ return [
364
+ 'milestone_submitted',
365
+ 'release_reserved',
366
+ 'released',
367
+ 'disputed',
368
+ 'completed',
369
+ 'release_indeterminate',
370
+ ].includes(stage);
371
+ }
372
+ /**
373
+ * @param {string} stage
374
+ */
375
+ function stageAllowsReleaseApprovals(stage) {
376
+ return [
377
+ 'milestone_submitted',
378
+ 'release_reserved',
379
+ 'released',
380
+ 'disputed',
381
+ 'completed',
382
+ 'release_indeterminate',
383
+ ].includes(stage);
384
+ }
385
+ /**
386
+ * @param {string} stage
387
+ */
388
+ function stageRequiresRelease(stage) {
389
+ return ['release_reserved', 'released', 'completed', 'release_indeterminate'].includes(stage);
390
+ }
391
+ /**
392
+ * @param {string} stage
393
+ */
394
+ function stageAllowsRelease(stage) {
395
+ return [
396
+ 'milestone_submitted',
397
+ 'release_reserved',
398
+ 'released',
399
+ 'disputed',
400
+ 'amendment_pending',
401
+ 'completed',
402
+ 'release_indeterminate',
403
+ ].includes(stage);
404
+ }
405
+ /**
406
+ * Build a portable evidence manifest. The final document bytes are hashed but
407
+ * not embedded; transport them beside the JSON manifest.
408
+ *
409
+ * @param {{ now?: number, maxDocumentBytes?: number, maxProjectRecordBytes?: number }} [limits]
410
+ */
411
+ export function buildActionEscrowEvidencePackage({ agreementId, stage, binding, documentBytes: rawDocumentBytes, documentFileName = null, documentExecution = null, agreementAcceptances = [], releaseApprovals = [], fundingStatement = null, milestones = [], release = null, stateRecord, amendments = [], verificationProfile, projectRecordBytes: rawProjectRecordBytes = null, projectRecordFileName = null, projectRecordProvider = null, projectRecordSnapshotDigest = null, } = {}, { now = 0, maxDocumentBytes = DEFAULT_MAX_DOCUMENT_BYTES, maxProjectRecordBytes = DEFAULT_MAX_PROJECT_RECORD_BYTES, } = {}) {
412
+ if (typeof agreementId !== 'string' || agreementId.length === 0) {
413
+ throw new TypeError('action-escrow evidence: agreementId is required');
414
+ }
415
+ if (!ACTION_ESCROW_EVIDENCE_STAGES.includes(stage)) {
416
+ throw new TypeError('action-escrow evidence: stage is not in the closed set');
417
+ }
418
+ if (!Number.isSafeInteger(maxDocumentBytes) || maxDocumentBytes <= 0) {
419
+ throw new TypeError('action-escrow evidence: maxDocumentBytes must be a positive safe integer');
420
+ }
421
+ const bytes = documentBytes(rawDocumentBytes, maxDocumentBytes);
422
+ validFileName(documentFileName, 'documentFileName');
423
+ const hasProjectRecord = rawProjectRecordBytes !== null
424
+ || projectRecordProvider !== null
425
+ || projectRecordSnapshotDigest !== null
426
+ || projectRecordFileName !== null;
427
+ let projectBytes = null;
428
+ if (hasProjectRecord) {
429
+ if (!Number.isSafeInteger(maxProjectRecordBytes)
430
+ || maxProjectRecordBytes <= 0) {
431
+ throw new TypeError('action-escrow evidence: maxProjectRecordBytes must be a positive safe integer');
432
+ }
433
+ if (typeof projectRecordProvider !== 'string'
434
+ || projectRecordProvider.length === 0
435
+ || projectRecordProvider.length > 128
436
+ // HASH.test() ToString-coerces its argument at runtime regardless;
437
+ // String() here makes that coercion explicit for the type checker.
438
+ || !HASH.test(String(projectRecordSnapshotDigest))) {
439
+ throw new TypeError('action-escrow evidence: project-record provider and snapshot digest are required');
440
+ }
441
+ validFileName(projectRecordFileName, 'projectRecordFileName');
442
+ projectBytes = projectRecordBytes(rawProjectRecordBytes, maxProjectRecordBytes);
443
+ }
444
+ const body = portableJsonCopy({
445
+ version: hasProjectRecord
446
+ ? ACTION_ESCROW_CONTRACTOR_EVIDENCE_PACKAGE_VERSION
447
+ : ACTION_ESCROW_EVIDENCE_PACKAGE_VERSION,
448
+ agreement_id: agreementId,
449
+ stage,
450
+ binding,
451
+ document: {
452
+ media_type: 'application/pdf',
453
+ digest: sha256(bytes),
454
+ byte_length: bytes.length,
455
+ ...(documentFileName === null ? {} : { file_name: documentFileName }),
456
+ },
457
+ ...(hasProjectRecord
458
+ ? {
459
+ project_record: {
460
+ media_type: 'application/json',
461
+ // projectBytes is non-null here: hasProjectRecord true means the
462
+ // `if (hasProjectRecord)` block above already assigned it.
463
+ digest: sha256(projectBytes),
464
+ byte_length: projectBytes.length,
465
+ ...(projectRecordFileName === null
466
+ ? {}
467
+ : { file_name: projectRecordFileName }),
468
+ provider: projectRecordProvider,
469
+ snapshot_digest: projectRecordSnapshotDigest,
470
+ },
471
+ }
472
+ : {}),
473
+ document_execution: documentExecution,
474
+ agreement_acceptances: agreementAcceptances,
475
+ release_approvals: releaseApprovals,
476
+ funding_statement: fundingStatement,
477
+ milestones,
478
+ release: release ?? {
479
+ reservation: null,
480
+ provider_request: null,
481
+ provider_statement: null,
482
+ execution_record: null,
483
+ },
484
+ state_record: stateRecord,
485
+ amendments,
486
+ verification_profile: verificationProfile,
487
+ assembled_at: toIso(now),
488
+ limitations: [...LIMITATIONS],
489
+ });
490
+ return deepFreeze({
491
+ ...body,
492
+ package_digest: canonicalSha256(body),
493
+ });
494
+ }
495
+ function resultFailure(reason, checks, details = {}) {
496
+ return {
497
+ valid: false,
498
+ reason,
499
+ checks,
500
+ ...details,
501
+ };
502
+ }
503
+ async function callVerifier(verifier, value, context) {
504
+ if (typeof verifier !== 'function')
505
+ return { valid: false, reason: 'verifier_required' };
506
+ try {
507
+ const result = await verifier(value, context);
508
+ return isRecord(result) ? result : { valid: false, reason: 'malformed_verifier_result' };
509
+ }
510
+ catch {
511
+ return { valid: false, reason: 'verifier_threw' };
512
+ }
513
+ }
514
+ /**
515
+ * Re-perform every package join using relying-party-owned component verifiers.
516
+ *
517
+ * Component verifiers are configuration, never read from the package. Their
518
+ * returned binding fields are checked again here so a valid artifact for one
519
+ * agreement, document, party, or action cannot be relabeled into another slot.
520
+ *
521
+ * @param {*} pkg
522
+ */
523
+ export async function verifyActionEscrowEvidencePackage(pkg, { documentBytes: rawDocumentBytes, projectRecordBytes: rawProjectRecordBytes, verifyBinding, verifyProjectRecord, verifyProfile, verifyDocumentExecution, verifyAgreementAcceptance, verifyReleaseApproval, verifyFunding, verifyMilestone, verifyRelease, verifyAmendment, verifyState, expectedAgreementId, now, maxDocumentBytes = DEFAULT_MAX_DOCUMENT_BYTES, maxProjectRecordBytes = DEFAULT_MAX_PROJECT_RECORD_BYTES, } = {}) {
524
+ const checks = {
525
+ structure: false,
526
+ package_digest: false,
527
+ time: false,
528
+ document: false,
529
+ project_record: false,
530
+ binding: false,
531
+ profile: false,
532
+ document_execution: false,
533
+ agreement_acceptances: false,
534
+ amendments: false,
535
+ state: false,
536
+ release_approvals: false,
537
+ funding: false,
538
+ milestones: false,
539
+ release: false,
540
+ };
541
+ try {
542
+ const contractorPackage = pkg?.version
543
+ === ACTION_ESCROW_CONTRACTOR_EVIDENCE_PACKAGE_VERSION;
544
+ const allowedTop = contractorPackage ? CONTRACTOR_TOP_KEYS : TOP_KEYS;
545
+ const requiredTop = new Set(allowedTop);
546
+ checks.structure = exactKeys(pkg, allowedTop, requiredTop)
547
+ && (pkg.version === ACTION_ESCROW_EVIDENCE_PACKAGE_VERSION
548
+ || contractorPackage)
549
+ && typeof pkg.agreement_id === 'string' && pkg.agreement_id.length > 0
550
+ && ACTION_ESCROW_EVIDENCE_STAGES.includes(pkg.stage)
551
+ && HASH.test(pkg.package_digest)
552
+ && exactKeys(pkg.document, DOCUMENT_KEYS, new Set(['media_type', 'digest', 'byte_length']))
553
+ && pkg.document.media_type === 'application/pdf'
554
+ && HASH.test(pkg.document.digest)
555
+ && Number.isSafeInteger(pkg.document.byte_length) && pkg.document.byte_length > 0
556
+ && (!contractorPackage
557
+ || (exactKeys(pkg.project_record, PROJECT_RECORD_KEYS, new Set([
558
+ 'media_type',
559
+ 'digest',
560
+ 'byte_length',
561
+ 'provider',
562
+ 'snapshot_digest',
563
+ ]))
564
+ && pkg.project_record.media_type === 'application/json'
565
+ && HASH.test(pkg.project_record.digest)
566
+ && Number.isSafeInteger(pkg.project_record.byte_length)
567
+ && pkg.project_record.byte_length > 0
568
+ && typeof pkg.project_record.provider === 'string'
569
+ && pkg.project_record.provider.length > 0
570
+ && pkg.project_record.provider.length <= 128
571
+ && HASH.test(pkg.project_record.snapshot_digest)))
572
+ && (pkg.document_execution === null || isRecord(pkg.document_execution))
573
+ && Array.isArray(pkg.agreement_acceptances)
574
+ && Array.isArray(pkg.release_approvals)
575
+ && Array.isArray(pkg.milestones)
576
+ && exactKeys(pkg.release, RELEASE_KEYS)
577
+ && exactKeys(pkg.state_record, STATE_RECORD_KEYS)
578
+ && Array.isArray(pkg.amendments)
579
+ && Array.isArray(pkg.limitations)
580
+ && pkg.limitations.length === LIMITATIONS.length
581
+ && pkg.limitations.every((entry, index) => entry === LIMITATIONS[index]);
582
+ if (!checks.structure)
583
+ return resultFailure('malformed_evidence_package', checks);
584
+ if (expectedAgreementId !== undefined
585
+ && (typeof expectedAgreementId !== 'string' || pkg.agreement_id !== expectedAgreementId)) {
586
+ return resultFailure('agreement_id_mismatch', checks);
587
+ }
588
+ checks.package_digest = canonicalSha256(digestScope(pkg)) === pkg.package_digest;
589
+ if (!checks.package_digest)
590
+ return resultFailure('package_digest_mismatch', checks);
591
+ const assembledAt = Date.parse(pkg.assembled_at);
592
+ const evaluation = now === undefined
593
+ ? null
594
+ : (now instanceof Date ? now.getTime() : typeof now === 'number' ? now : Date.parse(now));
595
+ checks.time = Number.isFinite(assembledAt)
596
+ && (evaluation === null || (Number.isFinite(evaluation) && assembledAt <= evaluation));
597
+ if (!checks.time)
598
+ return resultFailure('invalid_or_future_assembled_at', checks);
599
+ if (!Number.isSafeInteger(maxDocumentBytes) || maxDocumentBytes <= 0) {
600
+ return resultFailure('invalid_document_limit', checks);
601
+ }
602
+ const bytes = documentBytes(rawDocumentBytes, maxDocumentBytes);
603
+ checks.document = bytes.length === pkg.document.byte_length && sha256(bytes) === pkg.document.digest;
604
+ if (!checks.document)
605
+ return resultFailure('document_bytes_mismatch', checks);
606
+ const bindingResult = await callVerifier(verifyBinding, pkg.binding, {
607
+ expectedAgreementId: pkg.agreement_id,
608
+ expectedDocumentDigest: pkg.document.digest,
609
+ });
610
+ const contractorBinding = HASH.test(pkg.binding?.release_action?.template?.project_record_snapshot_digest);
611
+ const requiredParties = normalizedRequiredParties(bindingResult.required_parties);
612
+ checks.binding = bindingResult.valid === true
613
+ && bindingResult.agreement_id === pkg.agreement_id
614
+ && bindingResult.document_digest === pkg.document.digest
615
+ && HASH.test(bindingResult.binding_digest)
616
+ && HASH.test(bindingResult.action_digest)
617
+ && (bindingResult.supersedes_digest === null || HASH.test(bindingResult.supersedes_digest))
618
+ && requiredParties !== null;
619
+ if (!checks.binding) {
620
+ return resultFailure('binding_verification_failed', checks, {
621
+ binding_reason: bindingResult.reason ?? null,
622
+ });
623
+ }
624
+ if (contractorBinding !== contractorPackage) {
625
+ return resultFailure('evidence_profile_mismatch', checks);
626
+ }
627
+ if (contractorPackage) {
628
+ if (!HASH.test(bindingResult.project_record_snapshot_digest)
629
+ || bindingResult.project_record_snapshot_digest
630
+ !== pkg.project_record.snapshot_digest
631
+ || !Number.isSafeInteger(maxProjectRecordBytes)
632
+ || maxProjectRecordBytes <= 0) {
633
+ return resultFailure('project_record_binding_failed', checks);
634
+ }
635
+ let sourceBytes;
636
+ try {
637
+ sourceBytes = projectRecordBytes(rawProjectRecordBytes, maxProjectRecordBytes);
638
+ }
639
+ catch {
640
+ return resultFailure('project_record_bytes_mismatch', checks);
641
+ }
642
+ if (sourceBytes.length !== pkg.project_record.byte_length
643
+ || sha256(sourceBytes) !== pkg.project_record.digest) {
644
+ return resultFailure('project_record_bytes_mismatch', checks);
645
+ }
646
+ const gated = strictJsonGate(sourceBytes.toString('utf8'));
647
+ let projectRecord = null;
648
+ if (gated.ok) {
649
+ try {
650
+ projectRecord = JSON.parse(sourceBytes.toString('utf8'));
651
+ }
652
+ catch {
653
+ projectRecord = null;
654
+ }
655
+ }
656
+ if (!isRecord(projectRecord)) {
657
+ return resultFailure('project_record_json_invalid', checks);
658
+ }
659
+ const projectResult = await callVerifier(verifyProjectRecord, projectRecord, {
660
+ agreementId: pkg.agreement_id,
661
+ bindingDigest: bindingResult.binding_digest,
662
+ actionDigest: bindingResult.action_digest,
663
+ provider: pkg.project_record.provider,
664
+ snapshotDigest: pkg.project_record.snapshot_digest,
665
+ });
666
+ checks.project_record = projectResult.valid === true
667
+ && projectResult.authorizes_action === false
668
+ && projectResult.establishes_acceptance === false
669
+ && projectResult.provider === pkg.project_record.provider
670
+ && projectResult.snapshot_digest === pkg.project_record.snapshot_digest;
671
+ if (!checks.project_record) {
672
+ return resultFailure('project_record_verification_failed', checks, {
673
+ project_record_reason: projectResult.reason ?? null,
674
+ });
675
+ }
676
+ }
677
+ else {
678
+ checks.project_record = true;
679
+ }
680
+ const profileResult = await callVerifier(verifyProfile, pkg.verification_profile, {
681
+ agreementId: pkg.agreement_id,
682
+ bindingDigest: bindingResult.binding_digest,
683
+ actionDigest: bindingResult.action_digest,
684
+ });
685
+ const requiredReleaseParties = normalizedRequiredParties(profileResult.required_release_parties);
686
+ checks.profile = profileResult.valid === true
687
+ && profileResult.agreement_id === pkg.agreement_id
688
+ && profileResult.binding_digest === bindingResult.binding_digest
689
+ && profileResult.action_digest === bindingResult.action_digest
690
+ && HASH.test(profileResult.profile_digest)
691
+ && requiredReleaseParties !== null;
692
+ if (!checks.profile) {
693
+ return resultFailure('verification_profile_failed', checks, {
694
+ profile_reason: profileResult.reason ?? null,
695
+ });
696
+ }
697
+ if (pkg.document_execution !== null) {
698
+ const executionResult = await callVerifier(verifyDocumentExecution, pkg.document_execution, {
699
+ agreementId: pkg.agreement_id,
700
+ bindingDigest: bindingResult.binding_digest,
701
+ documentDigest: pkg.document.digest,
702
+ });
703
+ checks.document_execution = executionResult.valid === true
704
+ && executionResult.authorizes_action === false
705
+ && executionResult.agreement_id === pkg.agreement_id
706
+ && executionResult.binding_digest === bindingResult.binding_digest
707
+ && executionResult.document_digest === pkg.document.digest
708
+ && executionResult.state === 'executed';
709
+ }
710
+ else {
711
+ checks.document_execution = !stageRequiresExecutedAgreement(pkg.stage);
712
+ }
713
+ if (!checks.document_execution) {
714
+ return resultFailure('document_execution_verification_failed', checks);
715
+ }
716
+ // requiredParties is non-null here: checks.binding (verified above, with
717
+ // an early return when false) requires requiredParties !== null.
718
+ const requiredAgreementByIdentity = new Map(requiredParties.map((entry) => [`${entry.role ?? ''}\u0000${entry.party_id}`, entry]));
719
+ const seenAgreementParties = new Set();
720
+ const seenAgreementKeys = new Set();
721
+ let agreementAcceptancesValid = true;
722
+ for (const acceptance of pkg.agreement_acceptances) {
723
+ if (!exactKeys(acceptance, PARTY_EVIDENCE_KEYS)
724
+ || typeof acceptance.party_id !== 'string'
725
+ || typeof acceptance.role !== 'string') {
726
+ agreementAcceptancesValid = false;
727
+ break;
728
+ }
729
+ const identity = `${acceptance.role}\u0000${acceptance.party_id}`;
730
+ if (!requiredAgreementByIdentity.has(identity) || seenAgreementParties.has(identity)) {
731
+ agreementAcceptancesValid = false;
732
+ break;
733
+ }
734
+ const result = await callVerifier(verifyAgreementAcceptance, acceptance.evidence, {
735
+ partyId: acceptance.party_id,
736
+ role: acceptance.role,
737
+ agreementId: pkg.agreement_id,
738
+ bindingDigest: bindingResult.binding_digest,
739
+ documentDigest: pkg.document.digest,
740
+ });
741
+ if (result.valid !== true
742
+ || result.accepts_agreement !== true
743
+ || result.authorizes_action !== false
744
+ || result.agreement_id !== pkg.agreement_id
745
+ || result.party_id !== acceptance.party_id
746
+ || result.role !== acceptance.role
747
+ || result.binding_digest !== bindingResult.binding_digest
748
+ || result.document_digest !== pkg.document.digest
749
+ || typeof result.principal_key_id !== 'string'
750
+ || result.principal_key_id.length === 0
751
+ || seenAgreementKeys.has(result.principal_key_id)) {
752
+ agreementAcceptancesValid = false;
753
+ break;
754
+ }
755
+ seenAgreementParties.add(identity);
756
+ seenAgreementKeys.add(result.principal_key_id);
757
+ }
758
+ if (stageRequiresExecutedAgreement(pkg.stage)) {
759
+ agreementAcceptancesValid = agreementAcceptancesValid
760
+ && seenAgreementParties.size === requiredAgreementByIdentity.size;
761
+ }
762
+ checks.agreement_acceptances = agreementAcceptancesValid;
763
+ if (!checks.agreement_acceptances) {
764
+ return resultFailure('agreement_acceptance_verification_failed', checks);
765
+ }
766
+ const amendmentResults = [];
767
+ let amendmentsValid = true;
768
+ let expectedNextBinding = bindingResult.binding_digest;
769
+ for (let index = pkg.amendments.length - 1; index >= 0; index -= 1) {
770
+ const result = await callVerifier(verifyAmendment, pkg.amendments[index], {
771
+ agreementId: pkg.agreement_id,
772
+ expectedNextBindingDigest: expectedNextBinding,
773
+ profileDigest: profileResult.profile_digest,
774
+ });
775
+ amendmentResults.unshift(result);
776
+ if (result.valid !== true
777
+ || !HASH.test(result.amendment_digest)
778
+ || !HASH.test(result.previous_binding_digest)
779
+ || result.next_binding_digest !== expectedNextBinding) {
780
+ amendmentsValid = false;
781
+ break;
782
+ }
783
+ expectedNextBinding = result.previous_binding_digest;
784
+ }
785
+ if (bindingResult.supersedes_digest === null) {
786
+ amendmentsValid = amendmentsValid && pkg.amendments.length === 0;
787
+ }
788
+ else {
789
+ const finalAmendment = amendmentResults.at(-1);
790
+ amendmentsValid = amendmentsValid
791
+ && pkg.amendments.length > 0
792
+ && finalAmendment?.previous_binding_digest === bindingResult.supersedes_digest
793
+ && finalAmendment?.next_binding_digest === bindingResult.binding_digest;
794
+ }
795
+ checks.amendments = amendmentsValid;
796
+ if (!checks.amendments) {
797
+ return resultFailure('amendment_chain_verification_failed', checks);
798
+ }
799
+ const amendmentDigests = amendmentResults.map((result) => result.amendment_digest);
800
+ const stateResult = await callVerifier(verifyState, pkg.state_record, {
801
+ agreementId: pkg.agreement_id,
802
+ bindingDigest: bindingResult.binding_digest,
803
+ actionDigest: bindingResult.action_digest,
804
+ profileDigest: profileResult.profile_digest,
805
+ amendmentDigests,
806
+ stage: pkg.stage,
807
+ });
808
+ checks.state = stateResult.valid === true
809
+ && stateResult.agreement_id === pkg.agreement_id
810
+ && stateResult.binding_digest === bindingResult.binding_digest
811
+ && stateResult.action_digest === bindingResult.action_digest
812
+ && stateResult.profile_digest === profileResult.profile_digest
813
+ && stateResult.state === pkg.stage
814
+ && Number.isSafeInteger(stateResult.revision) && stateResult.revision >= 0
815
+ && Array.isArray(stateResult.amendment_digests)
816
+ && stateResult.amendment_digests.length === amendmentDigests.length
817
+ && stateResult.amendment_digests.every((digest, index) => digest === amendmentDigests[index]);
818
+ if (!checks.state) {
819
+ return resultFailure('state_record_verification_failed', checks, {
820
+ state_reason: stateResult.reason ?? null,
821
+ });
822
+ }
823
+ if (pkg.funding_statement !== null) {
824
+ if (!stageAllowsFunding(pkg.stage)) {
825
+ return resultFailure('unexpected_funding_statement', checks);
826
+ }
827
+ const fundingResult = await callVerifier(verifyFunding, pkg.funding_statement, {
828
+ agreementId: pkg.agreement_id,
829
+ bindingDigest: bindingResult.binding_digest,
830
+ actionDigest: bindingResult.action_digest,
831
+ });
832
+ checks.funding = fundingResult.valid === true
833
+ && fundingResult.agreement_id === pkg.agreement_id
834
+ && fundingResult.binding_digest === bindingResult.binding_digest
835
+ && fundingResult.action_digest === bindingResult.action_digest
836
+ && fundingResult.state === 'funded';
837
+ if (!checks.funding) {
838
+ return resultFailure('funding_statement_verification_failed', checks, {
839
+ funding_reason: fundingResult.reason ?? null,
840
+ });
841
+ }
842
+ }
843
+ else {
844
+ checks.funding = !stageRequiresFunding(pkg.stage);
845
+ if (!checks.funding)
846
+ return resultFailure('funding_statement_missing', checks);
847
+ }
848
+ let milestonesValid = true;
849
+ const milestoneIds = new Set();
850
+ const milestoneEvidenceDigests = [];
851
+ if (pkg.milestones.length > 0 && !stageAllowsMilestone(pkg.stage)) {
852
+ return resultFailure('unexpected_milestone_evidence', checks);
853
+ }
854
+ for (const milestone of pkg.milestones) {
855
+ if (!exactKeys(milestone, MILESTONE_KEYS)
856
+ || typeof milestone.milestone_id !== 'string' || milestone.milestone_id.length === 0
857
+ || milestoneIds.has(milestone.milestone_id)) {
858
+ milestonesValid = false;
859
+ break;
860
+ }
861
+ milestoneIds.add(milestone.milestone_id);
862
+ const result = await callVerifier(verifyMilestone, milestone, {
863
+ agreementId: pkg.agreement_id,
864
+ bindingDigest: bindingResult.binding_digest,
865
+ actionDigest: bindingResult.action_digest,
866
+ });
867
+ if (result.valid !== true
868
+ || result.agreement_id !== pkg.agreement_id
869
+ || result.milestone_id !== milestone.milestone_id
870
+ || result.binding_digest !== bindingResult.binding_digest
871
+ || result.action_digest !== bindingResult.action_digest
872
+ || !HASH.test(result.evidence_digest)) {
873
+ milestonesValid = false;
874
+ break;
875
+ }
876
+ milestoneEvidenceDigests.push(result.evidence_digest);
877
+ }
878
+ if (stageRequiresMilestone(pkg.stage))
879
+ milestonesValid = milestonesValid && milestoneIds.size > 0;
880
+ checks.milestones = milestonesValid;
881
+ if (!checks.milestones)
882
+ return resultFailure('milestone_verification_failed', checks);
883
+ // requiredReleaseParties is non-null here: checks.profile (verified
884
+ // above, with an early return when false) requires it !== null.
885
+ const requiredReleaseByIdentity = new Map(requiredReleaseParties.map((entry) => [`${entry.role ?? ''}\u0000${entry.party_id}`, entry]));
886
+ const seenReleaseParties = new Set();
887
+ const seenReleaseKeys = new Set();
888
+ let releaseApprovalsValid = true;
889
+ if (pkg.release_approvals.length > 0 && !stageAllowsReleaseApprovals(pkg.stage)) {
890
+ return resultFailure('unexpected_release_approval', checks);
891
+ }
892
+ const releaseExecutionAt = pkg.release.execution_record?.at ?? null;
893
+ for (const [approvalIndex, approval] of pkg.release_approvals.entries()) {
894
+ if (!exactKeys(approval, PARTY_EVIDENCE_KEYS)
895
+ || typeof approval.party_id !== 'string'
896
+ || typeof approval.role !== 'string') {
897
+ releaseApprovalsValid = false;
898
+ break;
899
+ }
900
+ const identity = `${approval.role}\u0000${approval.party_id}`;
901
+ if (!requiredReleaseByIdentity.has(identity) || seenReleaseParties.has(identity)) {
902
+ releaseApprovalsValid = false;
903
+ break;
904
+ }
905
+ const result = await callVerifier(verifyReleaseApproval, approval.evidence, {
906
+ partyId: approval.party_id,
907
+ role: approval.role,
908
+ agreementId: pkg.agreement_id,
909
+ bindingDigest: bindingResult.binding_digest,
910
+ actionDigest: bindingResult.action_digest,
911
+ milestoneEvidenceDigests,
912
+ approvalIndex,
913
+ stateRecord: pkg.state_record,
914
+ });
915
+ if (result.valid !== true
916
+ || result.authorizes_action !== true
917
+ || result.outcome !== 'approved'
918
+ || result.agreement_id !== pkg.agreement_id
919
+ || result.party_id !== approval.party_id
920
+ || result.role !== approval.role
921
+ || result.binding_digest !== bindingResult.binding_digest
922
+ || result.action_digest !== bindingResult.action_digest
923
+ || !Array.isArray(result.milestone_evidence_digests)
924
+ || result.milestone_evidence_digests.length !== milestoneEvidenceDigests.length
925
+ || result.milestone_evidence_digests.some((digest, index) => digest !== milestoneEvidenceDigests[index])
926
+ || typeof result.principal_key_id !== 'string'
927
+ || result.principal_key_id.length === 0
928
+ || !validInstant(result.issued_at)
929
+ || !validInstant(result.expires_at)
930
+ || !validInstant(result.admitted_at)
931
+ || Date.parse(result.issued_at) > Date.parse(result.admitted_at)
932
+ || Date.parse(result.expires_at) <= Date.parse(result.admitted_at)
933
+ || (releaseExecutionAt !== null
934
+ && (!validInstant(releaseExecutionAt)
935
+ || Date.parse(result.issued_at) > Date.parse(releaseExecutionAt)
936
+ || Date.parse(result.expires_at) <= Date.parse(releaseExecutionAt)))
937
+ || seenReleaseKeys.has(result.principal_key_id)) {
938
+ releaseApprovalsValid = false;
939
+ break;
940
+ }
941
+ seenReleaseParties.add(identity);
942
+ seenReleaseKeys.add(result.principal_key_id);
943
+ }
944
+ if (stageRequiresReleaseApprovals(pkg.stage)) {
945
+ releaseApprovalsValid = releaseApprovalsValid
946
+ && seenReleaseParties.size === requiredReleaseByIdentity.size;
947
+ }
948
+ checks.release_approvals = releaseApprovalsValid;
949
+ if (!checks.release_approvals) {
950
+ return resultFailure('release_approval_verification_failed', checks);
951
+ }
952
+ const hasReleaseArtifacts = Object.values(pkg.release).some((entry) => entry !== null);
953
+ if (hasReleaseArtifacts) {
954
+ if (!stageAllowsRelease(pkg.stage)) {
955
+ return resultFailure('release_artifacts_not_allowed_for_stage', checks);
956
+ }
957
+ const releaseResult = await callVerifier(verifyRelease, pkg.release, {
958
+ agreementId: pkg.agreement_id,
959
+ bindingDigest: bindingResult.binding_digest,
960
+ actionDigest: bindingResult.action_digest,
961
+ stage: pkg.stage,
962
+ });
963
+ const expectedReleaseState = pkg.stage === 'release_indeterminate'
964
+ ? 'indeterminate'
965
+ : pkg.stage === 'release_reserved'
966
+ ? 'reserved'
967
+ : ['released', 'completed'].includes(pkg.stage)
968
+ ? 'released'
969
+ : 'not_released';
970
+ checks.release = releaseResult.valid === true
971
+ && releaseResult.agreement_id === pkg.agreement_id
972
+ && releaseResult.binding_digest === bindingResult.binding_digest
973
+ && releaseResult.action_digest === bindingResult.action_digest
974
+ && releaseResult.state === expectedReleaseState;
975
+ if (!checks.release) {
976
+ return resultFailure('release_verification_failed', checks, {
977
+ release_reason: releaseResult.reason ?? null,
978
+ });
979
+ }
980
+ }
981
+ else {
982
+ checks.release = !stageRequiresRelease(pkg.stage);
983
+ if (!checks.release)
984
+ return resultFailure('release_artifact_missing', checks);
985
+ }
986
+ return {
987
+ valid: true,
988
+ reason: 'verified',
989
+ checks,
990
+ package_digest: pkg.package_digest,
991
+ agreement_id: pkg.agreement_id,
992
+ binding_digest: bindingResult.binding_digest,
993
+ action_digest: bindingResult.action_digest,
994
+ profile_digest: profileResult.profile_digest,
995
+ project_record_snapshot_digest: bindingResult.project_record_snapshot_digest ?? null,
996
+ required_parties: requiredParties,
997
+ required_release_parties: requiredReleaseParties,
998
+ };
999
+ }
1000
+ catch {
1001
+ return resultFailure('malformed_evidence_package', checks);
1002
+ }
1003
+ }
1004
+ export default {
1005
+ ACTION_ESCROW_CONTRACTOR_EVIDENCE_PACKAGE_VERSION,
1006
+ ACTION_ESCROW_EVIDENCE_PACKAGE_VERSION,
1007
+ ACTION_ESCROW_EVIDENCE_STAGES,
1008
+ parseActionEscrowEvidencePackage,
1009
+ buildActionEscrowEvidencePackage,
1010
+ verifyActionEscrowEvidencePackage,
1011
+ };
1012
+ //# sourceMappingURL=action-escrow-evidence.js.map