@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
package/roster.js CHANGED
@@ -1,265 +1,4 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
- /**
3
- * EMILIA Gate — signer-roster sync from an enterprise IdP (EP-GATE-ROSTER-v1).
4
- *
5
- * The boring key story: WHO may approve is an HR fact, not a crypto fact. This
6
- * module turns a SCIM-like IdP export into a versioned signer roster and
7
- * reconciles a key registry (key-registry.js) against it, so a deprovisioned
8
- * employee STOPS being an acceptable approver on the next sync. Fail closed:
9
- * - only `active === true` users' keys are ever pinned; anything else
10
- * (false, missing, truthy-but-not-boolean) never pins;
11
- * - a user absent from the import — offboarded, or silently dropped by a
12
- * broken IdP export — has every previously pinned key revoked;
13
- * - a kid claimed by two principals (or carrying two different key
14
- * materials) is CONTESTED: it pins nothing and is revoked if present;
15
- * - an import that would leave ZERO active signers requires an explicit
16
- * `allowEmpty` acknowledgment, so an empty/broken IdP response cannot
17
- * silently mass-revoke every approver.
18
- *
19
- * importRoster/diffRoster are pure (inputs in, artifact out; `importedAt` is
20
- * the caller-supplied clock). applyRosterToRegistry mutates the given registry
21
- * through its real API: key-registry CAN express revocation (`revoke(kid, at)`,
22
- * hard and fail-closed), so reconciliation performs it directly and the
23
- * returned `revoked` list is the exact set of revocations performed.
24
- */
25
-
26
- export const ROSTER_VERSION = 'EP-GATE-ROSTER-v1';
27
-
28
- /**
29
- * Import a SCIM-like IdP user export into a signer roster.
30
- * @param {Array<{id:string, userName:string, active:boolean, emails?:any, keys?:Array<{kid:string, publicKey:string}>}>} idpUsers
31
- * @param {object} o
32
- * @param {string} o.source IdP provenance, e.g. 'scim:okta:acme' (required)
33
- * @param {string|number} [o.importedAt] import time (ISO or ms); the caller's clock
34
- * @param {boolean} [o.allowEmpty=false] acknowledge an import with zero active signers
35
- * @returns {{version:string, source:string, imported_at:string, signers:Array<{principal:string, kid:string, publicKey:string, active:boolean}>, integrity_warnings:object[]}}
36
- */
37
- export function importRoster(idpUsers, { source, importedAt, allowEmpty = false } = {}) {
38
- if (!Array.isArray(idpUsers)) throw new Error('roster import: idpUsers must be an array');
39
- if (!source || typeof source !== 'string') {
40
- throw new Error('roster import: source (IdP provenance, e.g. "scim:okta:acme") is required');
41
- }
42
- const atMs = importedAt == null
43
- ? Date.now()
44
- : (typeof importedAt === 'number' ? importedAt : Date.parse(importedAt));
45
- if (!Number.isFinite(atMs)) throw new Error('roster import: importedAt is not a valid time');
46
-
47
- const warnings = [];
48
- const candidates = [];
49
- const usersByPrincipal = new Map();
50
-
51
- for (const u of idpUsers) {
52
- // A user without a stable id AND a userName cannot be diffed or revoked
53
- // reliably later — excluded, never an approver.
54
- if (!u || typeof u !== 'object'
55
- || typeof u.id !== 'string' || !u.id
56
- || typeof u.userName !== 'string' || !u.userName) {
57
- warnings.push({ code: 'malformed_user', id: u?.id ?? null, userName: u?.userName ?? null });
58
- continue;
59
- }
60
- const principal = u.userName;
61
- usersByPrincipal.set(principal, (usersByPrincipal.get(principal) || 0) + 1);
62
- const active = u.active === true; // strictly boolean true; anything else never pins
63
- for (const k of Array.isArray(u.keys) ? u.keys : []) {
64
- if (!k || typeof k.kid !== 'string' || !k.kid
65
- || typeof k.publicKey !== 'string' || !k.publicKey) {
66
- warnings.push({ code: 'malformed_key', principal, kid: k?.kid ?? null });
67
- continue;
68
- }
69
- candidates.push({ principal, kid: k.kid, publicKey: k.publicKey, active });
70
- }
71
- }
72
-
73
- // Two IdP users claiming one principal: identity is ambiguous — neither pins.
74
- const contestedPrincipals = new Set();
75
- for (const [principal, count] of usersByPrincipal) {
76
- if (count > 1) {
77
- contestedPrincipals.add(principal);
78
- warnings.push({ code: 'duplicate_principal', principal, users: count });
79
- }
80
- }
81
- let entries = candidates.filter((c) => !contestedPrincipals.has(c.principal));
82
-
83
- // Exact-duplicate rows collapse silently (same principal + kid + key).
84
- const seen = new Set();
85
- entries = entries.filter((c) => {
86
- const id = `${c.principal}\n${c.kid}\n${c.publicKey}`;
87
- if (seen.has(id)) return false;
88
- seen.add(id);
89
- return true;
90
- });
91
-
92
- // One kid claimed by two principals, or one kid carrying two key materials,
93
- // is an integrity failure: the contested kid pins NOTHING for anyone.
94
- const byKid = new Map();
95
- for (const c of entries) {
96
- const g = byKid.get(c.kid) || { principals: new Set(), keys: new Set() };
97
- g.principals.add(c.principal);
98
- g.keys.add(c.publicKey);
99
- byKid.set(c.kid, g);
100
- }
101
- const contestedKids = new Set();
102
- for (const [kid, g] of byKid) {
103
- if (g.principals.size > 1 || g.keys.size > 1) {
104
- contestedKids.add(kid);
105
- warnings.push({ code: 'duplicate_kid', kid, principals: [...g.principals].sort() });
106
- }
107
- }
108
- entries = entries.filter((c) => !contestedKids.has(c.kid));
109
-
110
- // Mass-deprovision guard: a roster with zero active signers would, on apply,
111
- // revoke EVERY approver. That is indistinguishable from a broken IdP export,
112
- // so it requires the operator's explicit acknowledgment.
113
- if (!allowEmpty && !entries.some((e) => e.active)) {
114
- throw new Error('roster import: zero active signers (mass-deprovision guard) — pass allowEmpty:true to acknowledge revoking every approver');
115
- }
116
-
117
- entries.sort((a, b) => (a.principal < b.principal ? -1 : a.principal > b.principal ? 1
118
- : a.kid < b.kid ? -1 : a.kid > b.kid ? 1 : 0));
119
-
120
- return {
121
- version: ROSTER_VERSION,
122
- source,
123
- imported_at: new Date(atMs).toISOString(),
124
- signers: entries.map(({ principal, kid, publicKey, active }) => ({ principal, kid, publicKey, active })),
125
- integrity_warnings: warnings,
126
- };
127
- }
128
-
129
- /** A roster must be well-formed before it can drive a diff or a registry mutation. */
130
- function assertRoster(r, name) {
131
- if (!r || r.version !== ROSTER_VERSION || !Array.isArray(r.signers)) {
132
- throw new Error(`roster: ${name} is not an ${ROSTER_VERSION} roster`);
133
- }
134
- for (const s of r.signers) {
135
- if (!s || typeof s.principal !== 'string' || !s.principal
136
- || typeof s.kid !== 'string' || !s.kid
137
- || typeof s.publicKey !== 'string' || !s.publicKey
138
- || typeof s.active !== 'boolean') {
139
- throw new Error(`roster: ${name} contains a malformed signer entry`);
140
- }
141
- }
142
- }
143
-
144
- function groupByPrincipal(roster) {
145
- const m = new Map();
146
- for (const s of roster.signers) {
147
- const g = m.get(s.principal) || { kids: new Set(), active: false };
148
- g.kids.add(s.kid);
149
- if (s.active === true) g.active = true;
150
- m.set(s.principal, g);
151
- }
152
- return m;
153
- }
154
-
155
- /**
156
- * Diff two rosters at the principal level.
157
- * `removed`/`deactivated` carry the PREVIOUS roster's kids — the revocation
158
- * candidates; `added` carries the next roster's kids.
159
- * @returns {{added:Array<{principal:string,kids:string[]}>, removed:Array<{principal:string,kids:string[]}>, deactivated:Array<{principal:string,kids:string[]}>}}
160
- */
161
- export function diffRoster(previous, next) {
162
- assertRoster(previous, 'previous');
163
- assertRoster(next, 'next');
164
- const prev = groupByPrincipal(previous);
165
- const nxt = groupByPrincipal(next);
166
- const added = [];
167
- const removed = [];
168
- const deactivated = [];
169
- for (const [principal, g] of nxt) {
170
- if (!prev.has(principal)) added.push({ principal, kids: [...g.kids].sort() });
171
- }
172
- for (const [principal, g] of prev) {
173
- if (!nxt.has(principal)) { removed.push({ principal, kids: [...g.kids].sort() }); continue; }
174
- if (g.active && !nxt.get(principal).active) deactivated.push({ principal, kids: [...g.kids].sort() });
175
- }
176
- const byPrincipal = (a, b) => (a.principal < b.principal ? -1 : a.principal > b.principal ? 1 : 0);
177
- added.sort(byPrincipal); removed.sort(byPrincipal); deactivated.sort(byPrincipal);
178
- return { added, removed, deactivated };
179
- }
180
-
181
- /**
182
- * Reconcile a key registry (createKeyRegistry) against a roster:
183
- * - PIN each ACTIVE, uncontested signer's key not already present;
184
- * - REVOKE every registry kid not owned by an active roster signer — absent
185
- * or inactive means deprovisioned. The registry passed here must therefore
186
- * be DEDICATED to roster-managed approver keys.
187
- * key-registry's API DOES express revocation (revoke(kid, at) — hard,
188
- * fail-closed), so revocations are performed directly; `revoked` is the exact
189
- * set performed, returned for the caller's evidence trail.
190
- * A kid the registry has EVER revoked is never re-pinned (a rehire gets a new
191
- * key; revoked key material stays dead).
192
- * @param {object} roster an EP-GATE-ROSTER-v1 roster
193
- * @param {object} registry createKeyRegistry() instance (add/revoke/status)
194
- * @param {object} [o]
195
- * @param {string|number} [o.revokedAt=roster.imported_at] revocation timestamp
196
- * @returns {{pinned:Array<{principal:string,kid:string}>, already_pinned:string[], revoked:Array<{kid:string,revoked_at:string|number,reason:string}>, refused:Array<{principal:string,kid:string,reason:string}>}}
197
- */
198
- export function applyRosterToRegistry(roster, registry, { revokedAt } = {}) {
199
- assertRoster(roster, 'roster');
200
- // Fail closed on the registry too: never coerce a flat key array here —
201
- // asKeyRegistry would build a DETACHED registry and every revocation this
202
- // function performs would be silently lost.
203
- if (!registry || typeof registry.add !== 'function'
204
- || typeof registry.revoke !== 'function' || typeof registry.status !== 'function') {
205
- throw new Error('roster apply: registry must expose add/revoke/status (createKeyRegistry)');
206
- }
207
- const at = revokedAt ?? roster.imported_at;
208
-
209
- // Recompute kid contests here as well — a hand-built roster must not bypass
210
- // the import-time duplicate-kid integrity check.
211
- const byKid = new Map();
212
- for (const s of roster.signers) {
213
- const g = byKid.get(s.kid) || { principals: new Set(), keys: new Set() };
214
- g.principals.add(s.principal);
215
- g.keys.add(s.publicKey);
216
- byKid.set(s.kid, g);
217
- }
218
- const contested = new Set();
219
- for (const [kid, g] of byKid) {
220
- if (g.principals.size > 1 || g.keys.size > 1) contested.add(kid);
221
- }
222
-
223
- const activeByKid = new Map();
224
- for (const s of roster.signers) {
225
- if (s.active === true && !contested.has(s.kid)) activeByKid.set(s.kid, s);
226
- }
227
-
228
- const status = registry.status();
229
- const everRevoked = new Set(status.filter((e) => e.revoked).map((e) => e.kid));
230
- const present = new Set(status.map((e) => e.kid));
231
-
232
- const pinned = [];
233
- const alreadyPinned = [];
234
- const revoked = [];
235
- const refused = [];
236
-
237
- for (const s of roster.signers) {
238
- if (s.active === true && contested.has(s.kid)) {
239
- refused.push({ principal: s.principal, kid: s.kid, reason: 'contested_kid' });
240
- }
241
- }
242
-
243
- for (const [kid, s] of activeByKid) {
244
- if (everRevoked.has(kid)) {
245
- refused.push({ principal: s.principal, kid, reason: 'kid_previously_revoked' });
246
- continue;
247
- }
248
- if (present.has(kid)) { alreadyPinned.push(kid); continue; }
249
- registry.add({ kid, key: s.publicKey });
250
- pinned.push({ principal: s.principal, kid });
251
- }
252
-
253
- // Absent-or-inactive (and contested) kids stop being acceptable NOW.
254
- const done = new Set();
255
- for (const e of status) {
256
- if (e.revoked || done.has(e.kid) || activeByKid.has(e.kid)) continue;
257
- registry.revoke(e.kid, at);
258
- done.add(e.kid);
259
- revoked.push({ kid: e.kid, revoked_at: at, reason: contested.has(e.kid) ? 'contested_kid' : 'absent_or_inactive' });
260
- }
261
-
262
- return { pinned, already_pinned: alreadyPinned, revoked, refused };
263
- }
264
-
265
- export default { ROSTER_VERSION, importRoster, diffRoster, applyRosterToRegistry };
2
+ // Compatibility entry point for the TypeScript roster module.
3
+ export * from './dist/roster.js';
4
+ export { default } from './dist/roster.js';
@@ -0,0 +1,4 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Compatibility entry point for the TypeScript runtime-monitor module.
3
+ export * from './dist/runtime-monitor.js';
4
+ export { default } from './dist/runtime-monitor.js';
package/settlement.js CHANGED
@@ -1,300 +1,4 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
- /**
3
- * Deterministic evidence-completeness decision for settlement workflows.
4
- *
5
- * This is not a payment rail and does not decide legal liability. It answers a
6
- * narrower question: does a relying-party-pinned profile have every verified,
7
- * digest-joined artifact it required before its own settlement system acts?
8
- */
9
- import { canonicalize, hashCanonical } from './execution-binding.js';
10
- import {
11
- NETWORK_WITNESS_EVENTS,
12
- acceptNetworkWitnessStatement,
13
- networkWitnessDigest,
14
- validateTrustedNetworkWitnessAcceptance,
15
- } from './network-witness.js';
16
-
17
- export const SETTLEMENT_PROFILE_VERSION = 'EP-GATE-SETTLEMENT-PROFILE-v1';
18
- export const SETTLEMENT_RESULT_VERSION = 'EP-GATE-SETTLEMENT-RESULT-v1';
19
- export const SETTLEMENT_VERDICTS = Object.freeze([
20
- 'eligible',
21
- 'refuse_profile_invalid',
22
- 'refuse_authorization',
23
- 'refuse_execution',
24
- 'refuse_witness',
25
- 'refuse_outcome',
26
- 'refuse_coverage',
27
- 'refuse_binding',
28
- ]);
29
-
30
- const DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
31
-
32
- function isPlainObject(value) {
33
- if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;
34
- const prototype = Object.getPrototypeOf(value);
35
- return prototype === Object.prototype || prototype === null;
36
- }
37
-
38
- function exactKeys(value, allowed) {
39
- return isPlainObject(value) && Object.keys(value).every((key) => allowed.has(key));
40
- }
41
-
42
- function string(value, max = 512) {
43
- return typeof value === 'string' && value.length > 0 && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
44
- }
45
-
46
- function digest(value) {
47
- return typeof value === 'string' && DIGEST_RE.test(value);
48
- }
49
-
50
- function canonicalSnapshot(value) {
51
- return JSON.parse(canonicalize(value));
52
- }
53
-
54
- function validateProfile(profile) {
55
- if (!exactKeys(profile, new Set([
56
- '@version', 'profile_id', 'require_witness', 'require_outcome', 'require_coverage',
57
- 'required_witness_event', 'required_witness_id', 'required_capture_point_id',
58
- 'required_coverage_state', 'required_surface_id',
59
- ]))) return 'profile_shape_invalid';
60
- if (profile['@version'] !== SETTLEMENT_PROFILE_VERSION || !string(profile.profile_id)) return 'profile_identity_invalid';
61
- for (const field of ['require_witness', 'require_outcome', 'require_coverage']) {
62
- if (profile[field] !== true && profile[field] !== false) return `profile_${field}_invalid`;
63
- }
64
- if (profile.require_witness && (!string(profile.required_witness_event)
65
- || !NETWORK_WITNESS_EVENTS.includes(profile.required_witness_event)
66
- || !string(profile.required_witness_id) || !string(profile.required_capture_point_id))) {
67
- return 'profile_witness_binding_invalid';
68
- }
69
- if (!profile.require_witness && (profile.required_witness_event !== undefined
70
- || profile.required_witness_id !== undefined || profile.required_capture_point_id !== undefined)) {
71
- return 'profile_witness_fields_forbidden';
72
- }
73
- if (profile.require_coverage && (profile.required_coverage_state !== 'gated'
74
- || !string(profile.required_surface_id))) return 'profile_coverage_binding_invalid';
75
- if (!profile.require_coverage && (profile.required_coverage_state !== undefined
76
- || profile.required_surface_id !== undefined)) return 'profile_coverage_fields_forbidden';
77
- try { canonicalize(profile); } catch { return 'profile_canonicalization_invalid'; }
78
- return null;
79
- }
80
-
81
- export function settlementProfileDigest(profile) {
82
- const invalid = validateProfile(profile);
83
- if (invalid) throw new TypeError(invalid);
84
- return `sha256:${hashCanonical(profile)}`;
85
- }
86
-
87
- function refused(verdict, reason, profileHash, checks, actionDigest = null) {
88
- const body = {
89
- '@version': SETTLEMENT_RESULT_VERSION,
90
- verdict,
91
- eligible: false,
92
- reason,
93
- profile_hash: profileHash,
94
- action_digest: actionDigest,
95
- checks,
96
- limitations: [
97
- 'This result is evidence-completeness input to a relying party; it is not a legal settlement instruction or warranty.',
98
- 'A valid evidence bundle does not establish physical truth beyond the separately verified outcome source.',
99
- ],
100
- };
101
- return Object.freeze({ ...body, result_hash: `sha256:${hashCanonical(body)}` });
102
- }
103
-
104
- async function invokeVerifier(verifier, artifact, context) {
105
- if (typeof verifier !== 'function') return { accepted: false, reason: 'pinned_verifier_missing' };
106
- try {
107
- const result = await verifier(artifact, Object.freeze({ ...context }));
108
- if (!isPlainObject(result)) return { accepted: false, reason: 'verifier_result_invalid' };
109
- return canonicalSnapshot(result);
110
- } catch {
111
- return { accepted: false, reason: 'pinned_verifier_error' };
112
- }
113
- }
114
-
115
- /**
116
- * Evaluate a raw evidence bundle. Authorization, execution, outcome, and
117
- * coverage are interpreted only by verifier functions pinned in code by the
118
- * relying party; no artifact may select its own verifier.
119
- */
120
- export async function evaluateSettlementEligibility(bundle = {}, options = {}) {
121
- let profileInput;
122
- let profileInputInvalid = false;
123
- try { profileInput = canonicalSnapshot(options.profile); } catch { profileInputInvalid = true; }
124
- let verifyAuthorization;
125
- let verifyExecution;
126
- let verifyOutcome;
127
- let verifyCoverage;
128
- let pinnedWitnesses;
129
- let trustedWitnessAcceptance = null;
130
- let hasTrustedWitnessAcceptance = false;
131
- let witnessSequenceStore;
132
- let allowEphemeralWitnessStore = false;
133
- let witnessNow;
134
- let witnessMaxAgeSec;
135
- let maxFutureSkewSec;
136
- try {
137
- verifyAuthorization = options.verifyAuthorization;
138
- verifyExecution = options.verifyExecution;
139
- verifyOutcome = options.verifyOutcome;
140
- verifyCoverage = options.verifyCoverage;
141
- pinnedWitnesses = options.pinnedWitnesses === undefined
142
- ? undefined
143
- : canonicalSnapshot(options.pinnedWitnesses);
144
- hasTrustedWitnessAcceptance = Object.hasOwn(options, 'trustedWitnessAcceptance');
145
- if (hasTrustedWitnessAcceptance) {
146
- trustedWitnessAcceptance = canonicalSnapshot(options.trustedWitnessAcceptance);
147
- }
148
- witnessSequenceStore = options.witnessSequenceStore;
149
- allowEphemeralWitnessStore = options.allowEphemeralWitnessStore === true;
150
- witnessNow = options.now;
151
- witnessMaxAgeSec = options.witnessMaxAgeSec;
152
- maxFutureSkewSec = options.maxFutureSkewSec;
153
- } catch {
154
- pinnedWitnesses = [];
155
- hasTrustedWitnessAcceptance = true;
156
- trustedWitnessAcceptance = null;
157
- }
158
- let profile;
159
- let invalid;
160
- if (profileInputInvalid) {
161
- invalid = 'profile_hostile_input';
162
- profile = null;
163
- } else {
164
- invalid = validateProfile(profileInput);
165
- profile = profileInput;
166
- }
167
- const baseChecks = {
168
- profile: !invalid,
169
- authorization: false,
170
- execution: false,
171
- witness: profile?.require_witness === false,
172
- outcome: profile?.require_outcome === false,
173
- coverage: profile?.require_coverage === false,
174
- digest_join: false,
175
- };
176
- if (invalid) return refused('refuse_profile_invalid', invalid, null, baseChecks);
177
- const profileHash = settlementProfileDigest(profile);
178
- let evidence;
179
- try {
180
- evidence = JSON.parse(canonicalize(bundle));
181
- } catch {
182
- return refused('refuse_binding', 'evidence_bundle_not_canonical_json', profileHash, baseChecks);
183
- }
184
- const actionDigest = evidence.action_digest;
185
- if (!digest(actionDigest)) {
186
- return refused('refuse_binding', 'action_digest_invalid', profileHash, baseChecks);
187
- }
188
- const context = { action_digest: actionDigest, profile_hash: profileHash };
189
-
190
- const authorization = await invokeVerifier(verifyAuthorization, evidence.authorization, context);
191
- if (authorization.accepted !== true || authorization.action_digest !== actionDigest
192
- || !digest(authorization.decision_digest)) {
193
- return refused('refuse_authorization', authorization.reason ?? 'authorization_not_verified', profileHash, baseChecks, actionDigest);
194
- }
195
- baseChecks.authorization = true;
196
-
197
- const execution = await invokeVerifier(verifyExecution, evidence.execution, {
198
- ...context,
199
- authorization_digest: authorization.decision_digest,
200
- });
201
- if (execution.accepted !== true || execution.outcome !== 'executed'
202
- || execution.action_digest !== actionDigest || !digest(execution.execution_digest)) {
203
- return refused('refuse_execution', execution.reason ?? 'execution_not_verified', profileHash, baseChecks, actionDigest);
204
- }
205
- baseChecks.execution = true;
206
- if (execution.authorization_digest !== authorization.decision_digest) {
207
- return refused('refuse_binding', 'execution_authorization_digest_mismatch', profileHash, baseChecks, actionDigest);
208
- }
209
-
210
- let witness = null;
211
- if (profile.require_witness) {
212
- const witnessOptions = {
213
- expectedActionDigest: actionDigest,
214
- expectedEvent: profile.required_witness_event,
215
- maxAgeSec: witnessMaxAgeSec,
216
- maxFutureSkewSec,
217
- now: witnessNow,
218
- allowEphemeralStore: allowEphemeralWitnessStore,
219
- };
220
- if (hasTrustedWitnessAcceptance) {
221
- let expectedStatementDigest;
222
- try { expectedStatementDigest = networkWitnessDigest(evidence.witness); } catch {
223
- return refused('refuse_witness', 'witness_statement_digest_invalid', profileHash, baseChecks, actionDigest);
224
- }
225
- witness = validateTrustedNetworkWitnessAcceptance(trustedWitnessAcceptance, {
226
- ...witnessOptions,
227
- expectedStatementDigest,
228
- });
229
- } else {
230
- witness = await acceptNetworkWitnessStatement(evidence.witness, {
231
- ...witnessOptions,
232
- pinnedWitnesses,
233
- sequenceStore: witnessSequenceStore,
234
- });
235
- }
236
- if (!witness.accepted) {
237
- return refused('refuse_witness', witness.reason ?? 'witness_not_verified', profileHash, baseChecks, actionDigest);
238
- }
239
- if (witness.witness_id !== profile.required_witness_id
240
- || witness.capture_point_id !== profile.required_capture_point_id) {
241
- return refused('refuse_binding', 'witness_capture_point_mismatch', profileHash, baseChecks, actionDigest);
242
- }
243
- baseChecks.witness = true;
244
- }
245
-
246
- let outcome = null;
247
- if (profile.require_outcome) {
248
- outcome = await invokeVerifier(verifyOutcome, evidence.outcome, {
249
- ...context,
250
- execution_digest: execution.execution_digest,
251
- });
252
- if (outcome.accepted !== true || outcome.within_tolerance !== true
253
- || outcome.action_digest !== actionDigest || !digest(outcome.outcome_digest)
254
- || outcome.execution_digest !== execution.execution_digest) {
255
- return refused('refuse_outcome', outcome.reason ?? 'outcome_not_verified', profileHash, baseChecks, actionDigest);
256
- }
257
- baseChecks.outcome = true;
258
- }
259
-
260
- let coverage = null;
261
- if (profile.require_coverage) {
262
- coverage = await invokeVerifier(verifyCoverage, evidence.coverage, context);
263
- if (coverage.accepted !== true || coverage.state !== profile.required_coverage_state
264
- || coverage.surface_id !== profile.required_surface_id || !digest(coverage.report_hash)) {
265
- return refused('refuse_coverage', coverage.reason ?? 'coverage_not_verified', profileHash, baseChecks, actionDigest);
266
- }
267
- baseChecks.coverage = true;
268
- }
269
-
270
- baseChecks.digest_join = true;
271
- const body = {
272
- '@version': SETTLEMENT_RESULT_VERSION,
273
- verdict: 'eligible',
274
- eligible: true,
275
- reason: null,
276
- profile_hash: profileHash,
277
- action_digest: actionDigest,
278
- evidence: {
279
- authorization_digest: authorization.decision_digest,
280
- execution_digest: execution.execution_digest,
281
- ...(witness ? { witness_digest: witness.statement_digest } : {}),
282
- ...(outcome ? { outcome_digest: outcome.outcome_digest } : {}),
283
- ...(coverage ? { coverage_report_hash: coverage.report_hash, surface_id: coverage.surface_id } : {}),
284
- },
285
- checks: baseChecks,
286
- limitations: [
287
- 'Eligible means the relying party\'s pinned evidence profile was satisfied; the relying party still owns pricing, legal effect, and payment execution.',
288
- 'The witness proves observation, not authorization or physical outcome; those are separate verified rows.',
289
- ],
290
- };
291
- return Object.freeze({ ...body, result_hash: `sha256:${hashCanonical(body)}` });
292
- }
293
-
294
- export default {
295
- SETTLEMENT_PROFILE_VERSION,
296
- SETTLEMENT_RESULT_VERSION,
297
- SETTLEMENT_VERDICTS,
298
- settlementProfileDigest,
299
- evaluateSettlementEligibility,
300
- };
2
+ // Compatibility entry point for the TypeScript settlement module.
3
+ export * from './dist/settlement.js';
4
+ export { default } from './dist/settlement.js';