@vorionsys/atsf-core 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE +1 -1
  3. package/README.md +82 -29
  4. package/dist/adapters/base-adapter.d.ts +94 -0
  5. package/dist/adapters/base-adapter.d.ts.map +1 -0
  6. package/dist/adapters/base-adapter.js +233 -0
  7. package/dist/adapters/base-adapter.js.map +1 -0
  8. package/dist/adapters/index.d.ts +9 -0
  9. package/dist/adapters/index.d.ts.map +1 -0
  10. package/dist/adapters/index.js +5 -0
  11. package/dist/adapters/index.js.map +1 -0
  12. package/dist/adapters/types.d.ts +83 -0
  13. package/dist/adapters/types.d.ts.map +1 -0
  14. package/dist/adapters/types.js +4 -0
  15. package/dist/adapters/types.js.map +1 -0
  16. package/dist/adapters/webhook-handler.d.ts +64 -0
  17. package/dist/adapters/webhook-handler.d.ts.map +1 -0
  18. package/dist/adapters/webhook-handler.js +170 -0
  19. package/dist/adapters/webhook-handler.js.map +1 -0
  20. package/dist/api/index.d.ts.map +1 -1
  21. package/dist/api/index.js +2 -0
  22. package/dist/api/index.js.map +1 -1
  23. package/dist/api/server.d.ts.map +1 -1
  24. package/dist/api/server.js +2 -0
  25. package/dist/api/server.js.map +1 -1
  26. package/dist/arbitration/index.d.ts +0 -8
  27. package/dist/arbitration/index.d.ts.map +1 -1
  28. package/dist/arbitration/index.js +2 -0
  29. package/dist/arbitration/index.js.map +1 -1
  30. package/dist/arbitration/types.d.ts.map +1 -1
  31. package/dist/arbitration/types.js +2 -8
  32. package/dist/arbitration/types.js.map +1 -1
  33. package/dist/basis/evaluator.d.ts +0 -5
  34. package/dist/basis/evaluator.d.ts.map +1 -1
  35. package/dist/basis/evaluator.js +2 -0
  36. package/dist/basis/evaluator.js.map +1 -1
  37. package/dist/basis/index.d.ts.map +1 -1
  38. package/dist/basis/index.js +2 -0
  39. package/dist/basis/index.js.map +1 -1
  40. package/dist/basis/parser.d.ts +28 -28
  41. package/dist/basis/parser.d.ts.map +1 -1
  42. package/dist/basis/parser.js +2 -0
  43. package/dist/basis/parser.js.map +1 -1
  44. package/dist/basis/types.d.ts.map +1 -1
  45. package/dist/basis/types.js +2 -3
  46. package/dist/basis/types.js.map +1 -1
  47. package/dist/chain/index.d.ts +0 -8
  48. package/dist/chain/index.d.ts.map +1 -1
  49. package/dist/chain/index.js +2 -0
  50. package/dist/chain/index.js.map +1 -1
  51. package/dist/cognigate/index.d.ts +0 -8
  52. package/dist/cognigate/index.d.ts.map +1 -1
  53. package/dist/cognigate/index.js +2 -0
  54. package/dist/cognigate/index.js.map +1 -1
  55. package/dist/common/adapters.d.ts.map +1 -1
  56. package/dist/common/adapters.js +2 -8
  57. package/dist/common/adapters.js.map +1 -1
  58. package/dist/common/config.d.ts.map +1 -1
  59. package/dist/common/config.js +2 -0
  60. package/dist/common/config.js.map +1 -1
  61. package/dist/common/index.d.ts.map +1 -1
  62. package/dist/common/index.js +2 -0
  63. package/dist/common/index.js.map +1 -1
  64. package/dist/common/logger.d.ts.map +1 -1
  65. package/dist/common/logger.js +2 -0
  66. package/dist/common/logger.js.map +1 -1
  67. package/dist/common/types.d.ts +7 -7
  68. package/dist/common/types.d.ts.map +1 -1
  69. package/dist/common/types.js +2 -9
  70. package/dist/common/types.js.map +1 -1
  71. package/dist/containment/index.d.ts +0 -8
  72. package/dist/containment/index.d.ts.map +1 -1
  73. package/dist/containment/index.js +2 -0
  74. package/dist/containment/index.js.map +1 -1
  75. package/dist/containment/types.d.ts.map +1 -1
  76. package/dist/containment/types.js +2 -8
  77. package/dist/containment/types.js.map +1 -1
  78. package/dist/contracts/index.d.ts +0 -8
  79. package/dist/contracts/index.d.ts.map +1 -1
  80. package/dist/contracts/index.js +2 -0
  81. package/dist/contracts/index.js.map +1 -1
  82. package/dist/contracts/types.d.ts.map +1 -1
  83. package/dist/contracts/types.js +2 -8
  84. package/dist/contracts/types.js.map +1 -1
  85. package/dist/crewai/callback.d.ts +0 -7
  86. package/dist/crewai/callback.d.ts.map +1 -1
  87. package/dist/crewai/callback.js +2 -0
  88. package/dist/crewai/callback.js.map +1 -1
  89. package/dist/crewai/executor.d.ts +0 -7
  90. package/dist/crewai/executor.d.ts.map +1 -1
  91. package/dist/crewai/executor.js +2 -0
  92. package/dist/crewai/executor.js.map +1 -1
  93. package/dist/crewai/index.d.ts.map +1 -1
  94. package/dist/crewai/index.js +2 -0
  95. package/dist/crewai/index.js.map +1 -1
  96. package/dist/crewai/tools.d.ts.map +1 -1
  97. package/dist/crewai/tools.js +2 -7
  98. package/dist/crewai/tools.js.map +1 -1
  99. package/dist/crewai/types.d.ts.map +1 -1
  100. package/dist/crewai/types.js +2 -7
  101. package/dist/crewai/types.js.map +1 -1
  102. package/dist/enforce/index.d.ts +0 -15
  103. package/dist/enforce/index.d.ts.map +1 -1
  104. package/dist/enforce/index.js +3 -1
  105. package/dist/enforce/index.js.map +1 -1
  106. package/dist/enforce/trust-aware-enforcement-service.d.ts +0 -15
  107. package/dist/enforce/trust-aware-enforcement-service.d.ts.map +1 -1
  108. package/dist/enforce/trust-aware-enforcement-service.js +2 -0
  109. package/dist/enforce/trust-aware-enforcement-service.js.map +1 -1
  110. package/dist/governance/fluid-workflow.d.ts +0 -8
  111. package/dist/governance/fluid-workflow.d.ts.map +1 -1
  112. package/dist/governance/fluid-workflow.js +2 -0
  113. package/dist/governance/fluid-workflow.js.map +1 -1
  114. package/dist/governance/index.d.ts +0 -8
  115. package/dist/governance/index.d.ts.map +1 -1
  116. package/dist/governance/index.js +2 -0
  117. package/dist/governance/index.js.map +1 -1
  118. package/dist/governance/proof-bridge.d.ts.map +1 -1
  119. package/dist/governance/proof-bridge.js +2 -12
  120. package/dist/governance/proof-bridge.js.map +1 -1
  121. package/dist/governance/types.d.ts.map +1 -1
  122. package/dist/governance/types.js +2 -8
  123. package/dist/governance/types.js.map +1 -1
  124. package/dist/index.d.ts +3 -0
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +8 -0
  127. package/dist/index.js.map +1 -1
  128. package/dist/intent/index.d.ts +0 -13
  129. package/dist/intent/index.d.ts.map +1 -1
  130. package/dist/intent/index.js +4 -2
  131. package/dist/intent/index.js.map +1 -1
  132. package/dist/intent/persistent-intent-service.d.ts +0 -15
  133. package/dist/intent/persistent-intent-service.d.ts.map +1 -1
  134. package/dist/intent/persistent-intent-service.js +2 -0
  135. package/dist/intent/persistent-intent-service.js.map +1 -1
  136. package/dist/intent/supabase-intent-repository.d.ts +0 -17
  137. package/dist/intent/supabase-intent-repository.d.ts.map +1 -1
  138. package/dist/intent/supabase-intent-repository.js +2 -0
  139. package/dist/intent/supabase-intent-repository.js.map +1 -1
  140. package/dist/intent-gateway/index.d.ts +499 -0
  141. package/dist/intent-gateway/index.d.ts.map +1 -0
  142. package/dist/intent-gateway/index.js +1332 -0
  143. package/dist/intent-gateway/index.js.map +1 -0
  144. package/dist/langchain/callback.d.ts +0 -7
  145. package/dist/langchain/callback.d.ts.map +1 -1
  146. package/dist/langchain/callback.js +2 -0
  147. package/dist/langchain/callback.js.map +1 -1
  148. package/dist/langchain/executor.d.ts +0 -7
  149. package/dist/langchain/executor.d.ts.map +1 -1
  150. package/dist/langchain/executor.js +2 -0
  151. package/dist/langchain/executor.js.map +1 -1
  152. package/dist/langchain/index.d.ts.map +1 -1
  153. package/dist/langchain/index.js +2 -0
  154. package/dist/langchain/index.js.map +1 -1
  155. package/dist/langchain/tools.d.ts.map +1 -1
  156. package/dist/langchain/tools.js +2 -7
  157. package/dist/langchain/tools.js.map +1 -1
  158. package/dist/langchain/types.d.ts.map +1 -1
  159. package/dist/langchain/types.js +2 -7
  160. package/dist/langchain/types.js.map +1 -1
  161. package/dist/layers/implementations/L0-request-format.d.ts.map +1 -1
  162. package/dist/layers/implementations/L0-request-format.js +2 -0
  163. package/dist/layers/implementations/L0-request-format.js.map +1 -1
  164. package/dist/layers/implementations/L1-input-size.d.ts.map +1 -1
  165. package/dist/layers/implementations/L1-input-size.js +2 -0
  166. package/dist/layers/implementations/L1-input-size.js.map +1 -1
  167. package/dist/layers/implementations/L2-charset-sanitizer.d.ts.map +1 -1
  168. package/dist/layers/implementations/L2-charset-sanitizer.js +2 -0
  169. package/dist/layers/implementations/L2-charset-sanitizer.js.map +1 -1
  170. package/dist/layers/implementations/L3-schema-conformance.d.ts.map +1 -1
  171. package/dist/layers/implementations/L3-schema-conformance.js +2 -0
  172. package/dist/layers/implementations/L3-schema-conformance.js.map +1 -1
  173. package/dist/layers/implementations/L4-injection-detector.d.ts.map +1 -1
  174. package/dist/layers/implementations/L4-injection-detector.js +2 -0
  175. package/dist/layers/implementations/L4-injection-detector.js.map +1 -1
  176. package/dist/layers/implementations/L5-rate-limiter.d.ts.map +1 -1
  177. package/dist/layers/implementations/L5-rate-limiter.js +2 -0
  178. package/dist/layers/implementations/L5-rate-limiter.js.map +1 -1
  179. package/dist/layers/implementations/index.d.ts.map +1 -1
  180. package/dist/layers/implementations/index.js +2 -0
  181. package/dist/layers/implementations/index.js.map +1 -1
  182. package/dist/layers/index.d.ts +0 -8
  183. package/dist/layers/index.d.ts.map +1 -1
  184. package/dist/layers/index.js +2 -0
  185. package/dist/layers/index.js.map +1 -1
  186. package/dist/layers/types.d.ts.map +1 -1
  187. package/dist/layers/types.js +2 -8
  188. package/dist/layers/types.js.map +1 -1
  189. package/dist/paramesphere/activation-collector.d.ts +128 -0
  190. package/dist/paramesphere/activation-collector.d.ts.map +1 -0
  191. package/dist/paramesphere/activation-collector.js +260 -0
  192. package/dist/paramesphere/activation-collector.js.map +1 -0
  193. package/dist/paramesphere/cognitive-envelope.d.ts +73 -0
  194. package/dist/paramesphere/cognitive-envelope.d.ts.map +1 -0
  195. package/dist/paramesphere/cognitive-envelope.js +209 -0
  196. package/dist/paramesphere/cognitive-envelope.js.map +1 -0
  197. package/dist/paramesphere/envelope-integration.d.ts +60 -0
  198. package/dist/paramesphere/envelope-integration.d.ts.map +1 -0
  199. package/dist/paramesphere/envelope-integration.js +93 -0
  200. package/dist/paramesphere/envelope-integration.js.map +1 -0
  201. package/dist/paramesphere/fingerprint-monitor.d.ts +136 -0
  202. package/dist/paramesphere/fingerprint-monitor.d.ts.map +1 -0
  203. package/dist/paramesphere/fingerprint-monitor.js +212 -0
  204. package/dist/paramesphere/fingerprint-monitor.js.map +1 -0
  205. package/dist/paramesphere/fingerprint-store.d.ts +85 -0
  206. package/dist/paramesphere/fingerprint-store.d.ts.map +1 -0
  207. package/dist/paramesphere/fingerprint-store.js +68 -0
  208. package/dist/paramesphere/fingerprint-store.js.map +1 -0
  209. package/dist/paramesphere/index.d.ts +21 -0
  210. package/dist/paramesphere/index.d.ts.map +1 -0
  211. package/dist/paramesphere/index.js +18 -0
  212. package/dist/paramesphere/index.js.map +1 -0
  213. package/dist/paramesphere/monitor-integration.d.ts +37 -0
  214. package/dist/paramesphere/monitor-integration.d.ts.map +1 -0
  215. package/dist/paramesphere/monitor-integration.js +81 -0
  216. package/dist/paramesphere/monitor-integration.js.map +1 -0
  217. package/dist/paramesphere/paramesphere-engine.d.ts +111 -0
  218. package/dist/paramesphere/paramesphere-engine.d.ts.map +1 -0
  219. package/dist/paramesphere/paramesphere-engine.js +542 -0
  220. package/dist/paramesphere/paramesphere-engine.js.map +1 -0
  221. package/dist/paramesphere/types.d.ts +142 -0
  222. package/dist/paramesphere/types.d.ts.map +1 -0
  223. package/dist/paramesphere/types.js +4 -0
  224. package/dist/paramesphere/types.js.map +1 -0
  225. package/dist/persistence/file.d.ts +0 -7
  226. package/dist/persistence/file.d.ts.map +1 -1
  227. package/dist/persistence/file.js +2 -0
  228. package/dist/persistence/file.js.map +1 -1
  229. package/dist/persistence/index.d.ts.map +1 -1
  230. package/dist/persistence/index.js +2 -0
  231. package/dist/persistence/index.js.map +1 -1
  232. package/dist/persistence/memory.d.ts.map +1 -1
  233. package/dist/persistence/memory.js +2 -7
  234. package/dist/persistence/memory.js.map +1 -1
  235. package/dist/persistence/sqlite.d.ts +0 -8
  236. package/dist/persistence/sqlite.d.ts.map +1 -1
  237. package/dist/persistence/sqlite.js +3 -1
  238. package/dist/persistence/sqlite.js.map +1 -1
  239. package/dist/persistence/supabase.d.ts.map +1 -1
  240. package/dist/persistence/supabase.js +3 -8
  241. package/dist/persistence/supabase.js.map +1 -1
  242. package/dist/persistence/types.d.ts.map +1 -1
  243. package/dist/persistence/types.js +2 -7
  244. package/dist/persistence/types.js.map +1 -1
  245. package/dist/phase6/ceiling.d.ts +0 -16
  246. package/dist/phase6/ceiling.d.ts.map +1 -1
  247. package/dist/phase6/ceiling.js +2 -0
  248. package/dist/phase6/ceiling.js.map +1 -1
  249. package/dist/phase6/context.d.ts +0 -17
  250. package/dist/phase6/context.d.ts.map +1 -1
  251. package/dist/phase6/context.js +2 -0
  252. package/dist/phase6/context.js.map +1 -1
  253. package/dist/phase6/index.d.ts.map +1 -1
  254. package/dist/phase6/index.js +2 -0
  255. package/dist/phase6/index.js.map +1 -1
  256. package/dist/phase6/presets.d.ts +0 -16
  257. package/dist/phase6/presets.d.ts.map +1 -1
  258. package/dist/phase6/presets.js +5 -3
  259. package/dist/phase6/presets.js.map +1 -1
  260. package/dist/phase6/provenance.d.ts +0 -15
  261. package/dist/phase6/provenance.d.ts.map +1 -1
  262. package/dist/phase6/provenance.js +2 -0
  263. package/dist/phase6/provenance.js.map +1 -1
  264. package/dist/phase6/role-gates/index.d.ts.map +1 -1
  265. package/dist/phase6/role-gates/index.js +2 -0
  266. package/dist/phase6/role-gates/index.js.map +1 -1
  267. package/dist/phase6/role-gates/kernel.d.ts.map +1 -1
  268. package/dist/phase6/role-gates/kernel.js +2 -0
  269. package/dist/phase6/role-gates/kernel.js.map +1 -1
  270. package/dist/phase6/role-gates/policy.d.ts.map +1 -1
  271. package/dist/phase6/role-gates/policy.js +2 -11
  272. package/dist/phase6/role-gates/policy.js.map +1 -1
  273. package/dist/phase6/role-gates.d.ts +0 -16
  274. package/dist/phase6/role-gates.d.ts.map +1 -1
  275. package/dist/phase6/role-gates.js +2 -0
  276. package/dist/phase6/role-gates.js.map +1 -1
  277. package/dist/phase6/types.d.ts +45 -16
  278. package/dist/phase6/types.d.ts.map +1 -1
  279. package/dist/phase6/types.js +49 -0
  280. package/dist/phase6/types.js.map +1 -1
  281. package/dist/phase6/weight-presets/canonical.d.ts.map +1 -1
  282. package/dist/phase6/weight-presets/canonical.js +2 -0
  283. package/dist/phase6/weight-presets/canonical.js.map +1 -1
  284. package/dist/phase6/weight-presets/deltas.d.ts.map +1 -1
  285. package/dist/phase6/weight-presets/deltas.js +2 -10
  286. package/dist/phase6/weight-presets/deltas.js.map +1 -1
  287. package/dist/phase6/weight-presets/index.d.ts.map +1 -1
  288. package/dist/phase6/weight-presets/index.js +2 -0
  289. package/dist/phase6/weight-presets/index.js.map +1 -1
  290. package/dist/phase6/weight-presets/merger.d.ts +0 -10
  291. package/dist/phase6/weight-presets/merger.d.ts.map +1 -1
  292. package/dist/phase6/weight-presets/merger.js +2 -0
  293. package/dist/phase6/weight-presets/merger.js.map +1 -1
  294. package/dist/proof/index.d.ts +3 -10
  295. package/dist/proof/index.d.ts.map +1 -1
  296. package/dist/proof/index.js +27 -9
  297. package/dist/proof/index.js.map +1 -1
  298. package/dist/proof/merkle.d.ts +0 -16
  299. package/dist/proof/merkle.d.ts.map +1 -1
  300. package/dist/proof/merkle.js +2 -0
  301. package/dist/proof/merkle.js.map +1 -1
  302. package/dist/proof/zk-proofs.d.ts +0 -18
  303. package/dist/proof/zk-proofs.d.ts.map +1 -1
  304. package/dist/proof/zk-proofs.js +2 -0
  305. package/dist/proof/zk-proofs.js.map +1 -1
  306. package/dist/provenance/index.d.ts +0 -8
  307. package/dist/provenance/index.d.ts.map +1 -1
  308. package/dist/provenance/index.js +2 -0
  309. package/dist/provenance/index.js.map +1 -1
  310. package/dist/provenance/types.d.ts.map +1 -1
  311. package/dist/provenance/types.js +2 -8
  312. package/dist/provenance/types.js.map +1 -1
  313. package/dist/sandbox-training/challenges.d.ts.map +1 -1
  314. package/dist/sandbox-training/challenges.js +2 -8
  315. package/dist/sandbox-training/challenges.js.map +1 -1
  316. package/dist/sandbox-training/graduation.d.ts.map +1 -1
  317. package/dist/sandbox-training/graduation.js +2 -8
  318. package/dist/sandbox-training/graduation.js.map +1 -1
  319. package/dist/sandbox-training/index.d.ts.map +1 -1
  320. package/dist/sandbox-training/index.js +2 -0
  321. package/dist/sandbox-training/index.js.map +1 -1
  322. package/dist/sandbox-training/promotion-service.d.ts.map +1 -1
  323. package/dist/sandbox-training/promotion-service.js +2 -11
  324. package/dist/sandbox-training/promotion-service.js.map +1 -1
  325. package/dist/sandbox-training/runner.d.ts.map +1 -1
  326. package/dist/sandbox-training/runner.js +2 -8
  327. package/dist/sandbox-training/runner.js.map +1 -1
  328. package/dist/sandbox-training/scorer.d.ts.map +1 -1
  329. package/dist/sandbox-training/scorer.js +2 -8
  330. package/dist/sandbox-training/scorer.js.map +1 -1
  331. package/dist/sandbox-training/types.d.ts.map +1 -1
  332. package/dist/sandbox-training/types.js +2 -8
  333. package/dist/sandbox-training/types.js.map +1 -1
  334. package/dist/trust-engine/ceiling-enforcement/audit.d.ts +0 -8
  335. package/dist/trust-engine/ceiling-enforcement/audit.d.ts.map +1 -1
  336. package/dist/trust-engine/ceiling-enforcement/audit.js +2 -8
  337. package/dist/trust-engine/ceiling-enforcement/audit.js.map +1 -1
  338. package/dist/trust-engine/ceiling-enforcement/index.d.ts.map +1 -1
  339. package/dist/trust-engine/ceiling-enforcement/index.js +2 -0
  340. package/dist/trust-engine/ceiling-enforcement/index.js.map +1 -1
  341. package/dist/trust-engine/ceiling-enforcement/kernel.d.ts.map +1 -1
  342. package/dist/trust-engine/ceiling-enforcement/kernel.js +2 -0
  343. package/dist/trust-engine/ceiling-enforcement/kernel.js.map +1 -1
  344. package/dist/trust-engine/context-policy/enforcement.d.ts +0 -9
  345. package/dist/trust-engine/context-policy/enforcement.d.ts.map +1 -1
  346. package/dist/trust-engine/context-policy/enforcement.js +2 -9
  347. package/dist/trust-engine/context-policy/enforcement.js.map +1 -1
  348. package/dist/trust-engine/context-policy/factory.d.ts.map +1 -1
  349. package/dist/trust-engine/context-policy/factory.js +2 -0
  350. package/dist/trust-engine/context-policy/factory.js.map +1 -1
  351. package/dist/trust-engine/context-policy/index.d.ts.map +1 -1
  352. package/dist/trust-engine/context-policy/index.js +2 -0
  353. package/dist/trust-engine/context-policy/index.js.map +1 -1
  354. package/dist/trust-engine/creation-modifiers/index.d.ts.map +1 -1
  355. package/dist/trust-engine/creation-modifiers/index.js +2 -0
  356. package/dist/trust-engine/creation-modifiers/index.js.map +1 -1
  357. package/dist/trust-engine/creation-modifiers/types.d.ts.map +1 -1
  358. package/dist/trust-engine/creation-modifiers/types.js +2 -0
  359. package/dist/trust-engine/creation-modifiers/types.js.map +1 -1
  360. package/dist/trust-engine/decay-profiles.d.ts.map +1 -1
  361. package/dist/trust-engine/decay-profiles.js +2 -14
  362. package/dist/trust-engine/decay-profiles.js.map +1 -1
  363. package/dist/trust-engine/index.d.ts +418 -80
  364. package/dist/trust-engine/index.d.ts.map +1 -1
  365. package/dist/trust-engine/index.js +1048 -186
  366. package/dist/trust-engine/index.js.map +1 -1
  367. package/dist/trust-engine/phase6-types.d.ts +3 -13
  368. package/dist/trust-engine/phase6-types.d.ts.map +1 -1
  369. package/dist/trust-engine/phase6-types.js +5 -13
  370. package/dist/trust-engine/phase6-types.js.map +1 -1
  371. package/dist/trust-engine/trust-verifier.d.ts +121 -0
  372. package/dist/trust-engine/trust-verifier.d.ts.map +1 -0
  373. package/dist/trust-engine/trust-verifier.js +226 -0
  374. package/dist/trust-engine/trust-verifier.js.map +1 -0
  375. package/package.json +140 -135
@@ -0,0 +1,1332 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2024-2026 Vorion LLC
3
+ /**
4
+ * INTENT GATEWAY - Jurisdictional Router & Governance Topology Selector
5
+ *
6
+ * The Intent Gateway is the policy-aware front door for all agent intents.
7
+ * It resolves the operational jurisdiction from tenant context, composes
8
+ * applicable policy bundles (with deterministic conflict resolution), selects
9
+ * the governance regime that will supervise execution, and enriches the
10
+ * submit options with the regime's minimum trust level and metadata.
11
+ *
12
+ * Pipeline: intake -> jurisdiction resolution -> policy composition
13
+ * -> regime selection -> enriched submit
14
+ *
15
+ * Key design decisions exposed in this open-source version:
16
+ * - Jurisdiction is a first-class concept, not an afterthought.
17
+ * - Policy conflicts are detected eagerly and resolved deterministically
18
+ * (strictest-wins for ordered dimensions, additive for unordered ones).
19
+ * - EU AI Act risk classification runs inline for EU jurisdictions.
20
+ * - Every regime carries a minimum trust level; the gateway enforces it.
21
+ * - The gateway degrades gracefully: on error it falls through to
22
+ * passthrough mode with a warning, never silently drops an intent.
23
+ *
24
+ * @packageDocumentation
25
+ */
26
+ import { createLogger } from '../common/logger.js';
27
+ // ---------------------------------------------------------------------------
28
+ // Logger
29
+ // ---------------------------------------------------------------------------
30
+ const logger = createLogger({ component: 'intent-gateway' });
31
+ // ---------------------------------------------------------------------------
32
+ // Constants & Union Types
33
+ // ---------------------------------------------------------------------------
34
+ /** Supported jurisdictional scopes. */
35
+ export const JURISDICTIONS = [
36
+ 'GLOBAL', 'EU', 'US', 'APAC', 'UK', 'CA', 'AU', 'JP', 'SG', 'CH',
37
+ ];
38
+ /** Industry verticals that affect policy selection. */
39
+ export const INDUSTRIES = [
40
+ 'general', 'healthcare', 'finance', 'defense', 'government',
41
+ 'education', 'energy',
42
+ ];
43
+ /** Cryptographic suite requirements, ordered by strictness. */
44
+ export const CRYPTO_SUITES = [
45
+ 'standard', 'fips-140-2', 'post-quantum',
46
+ ];
47
+ /** Proof anchoring methods, ordered by assurance level. */
48
+ export const PROOF_ANCHORING_METHODS = [
49
+ 'database', 'merkle-tree', 'blockchain-l2', 'tsa-rfc3161',
50
+ ];
51
+ /** Consent models, ordered by strictness. */
52
+ export const CONSENT_MODELS = [
53
+ 'implicit', 'opt-out', 'opt-in', 'explicit-granular',
54
+ ];
55
+ /** Escalation modes, ordered by severity. */
56
+ export const ESCALATION_MODES = [
57
+ 'log-only', 'flag-review', 'block-escalate', 'hard-block',
58
+ ];
59
+ /** EU AI Act risk classification tiers. */
60
+ export const AI_ACT_CLASSIFICATIONS = [
61
+ 'unacceptable', 'high-risk', 'limited-risk', 'minimal-risk',
62
+ ];
63
+ /** High-risk categories under Annex III of the EU AI Act. */
64
+ export const AI_ACT_HIGH_RISK_CATEGORIES = [
65
+ 'biometric-identification',
66
+ 'critical-infrastructure',
67
+ 'education-vocational',
68
+ 'employment-worker-management',
69
+ 'essential-services',
70
+ 'law-enforcement',
71
+ 'migration-asylum-border',
72
+ 'justice-democratic',
73
+ ];
74
+ // ---------------------------------------------------------------------------
75
+ // Default Configuration
76
+ // ---------------------------------------------------------------------------
77
+ export const DEFAULT_GATEWAY_CONFIG = {
78
+ enabled: true,
79
+ defaultJurisdiction: 'GLOBAL',
80
+ defaultIndustry: 'general',
81
+ regimeCacheTtlMs: 5 * 60 * 1000, // 5 minutes
82
+ blockOnConflicts: true,
83
+ logRegimeDecisions: true,
84
+ };
85
+ // ---------------------------------------------------------------------------
86
+ // Jurisdiction Resolver
87
+ // ---------------------------------------------------------------------------
88
+ /**
89
+ * Data residency zones mapped to each jurisdiction.
90
+ */
91
+ export const JURISDICTION_RESIDENCY_ZONES = {
92
+ GLOBAL: 'global',
93
+ EU: 'eu-west',
94
+ US: 'us-east',
95
+ APAC: 'ap-southeast-1',
96
+ UK: 'uk-south',
97
+ CA: 'ca-central',
98
+ AU: 'au-southeast',
99
+ JP: 'ap-northeast-1',
100
+ SG: 'ap-southeast-1',
101
+ CH: 'eu-central',
102
+ };
103
+ /** EU/EEA member state ISO 3166-1 alpha-2 codes. */
104
+ const EU_MEMBER_STATE_CODES = new Set([
105
+ 'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR',
106
+ 'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL',
107
+ 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'IS', 'LI', 'NO',
108
+ ]);
109
+ /** APAC country codes for regional mapping. */
110
+ const APAC_COUNTRY_CODES = new Set([
111
+ 'JP', 'KR', 'SG', 'AU', 'NZ', 'IN', 'TH', 'MY', 'ID', 'PH', 'VN', 'TW', 'HK',
112
+ ]);
113
+ /** Direct country-to-jurisdiction mapping for countries with specific regimes. */
114
+ const COUNTRY_JURISDICTION_MAP = {
115
+ US: 'US',
116
+ GB: 'UK',
117
+ CA: 'CA',
118
+ AU: 'AU',
119
+ JP: 'JP',
120
+ SG: 'SG',
121
+ CH: 'CH',
122
+ };
123
+ /**
124
+ * Resolves jurisdictional context from tenant configuration, intent metadata,
125
+ * or defaults. Uses a three-tier resolution strategy:
126
+ *
127
+ * 1. Tenant configuration (explicit, highest priority)
128
+ * 2. Intent metadata inference (country codes, region hints)
129
+ * 3. Gateway defaults (fallback)
130
+ */
131
+ export class JurisdictionResolver {
132
+ tenantConfigs = new Map();
133
+ config;
134
+ constructor(config) {
135
+ this.config = config;
136
+ }
137
+ /**
138
+ * Resolve jurisdiction context for a tenant + optional intent metadata.
139
+ */
140
+ resolve(ctx, intentMetadata) {
141
+ const tenantId = ctx.tenantId;
142
+ // Tier 1: Explicit tenant configuration
143
+ const tenantResult = this.resolveFromTenantConfig(tenantId);
144
+ if (tenantResult) {
145
+ logger.debug({ tenantId, source: 'tenant-config' }, 'Jurisdiction from tenant config');
146
+ return tenantResult;
147
+ }
148
+ // Tier 2: Infer from intent metadata
149
+ const metadataResult = this.resolveFromMetadata(intentMetadata);
150
+ if (metadataResult) {
151
+ logger.debug({ tenantId, source: 'metadata' }, 'Jurisdiction from metadata');
152
+ return metadataResult;
153
+ }
154
+ // Tier 3: Gateway defaults
155
+ logger.debug({ tenantId, source: 'default' }, 'Jurisdiction from defaults');
156
+ return this.resolveDefault();
157
+ }
158
+ /**
159
+ * Register a tenant's jurisdiction configuration.
160
+ */
161
+ registerTenantConfig(tenantId, config) {
162
+ this.tenantConfigs.set(tenantId, config);
163
+ logger.info({ tenantId, jurisdictions: config.jurisdictions }, 'Tenant config registered');
164
+ }
165
+ /**
166
+ * Retrieve a tenant's jurisdiction configuration.
167
+ */
168
+ getTenantConfig(tenantId) {
169
+ return this.tenantConfigs.get(tenantId);
170
+ }
171
+ /**
172
+ * Determine if a set of jurisdictions implies cross-border data transfer
173
+ * by checking whether they map to different residency zones.
174
+ */
175
+ detectCrossBorderTransfer(jurisdictions) {
176
+ if (jurisdictions.length <= 1)
177
+ return false;
178
+ const zones = new Set(jurisdictions.map(j => JURISDICTION_RESIDENCY_ZONES[j]));
179
+ return zones.size > 1;
180
+ }
181
+ resolveFromTenantConfig(tenantId) {
182
+ const config = this.tenantConfigs.get(tenantId);
183
+ if (!config)
184
+ return null;
185
+ return {
186
+ primaryJurisdictions: config.jurisdictions,
187
+ industry: config.industry,
188
+ dataResidency: config.dataResidency ??
189
+ JURISDICTION_RESIDENCY_ZONES[config.jurisdictions[0]] ??
190
+ 'global',
191
+ crossBorderTransfer: this.detectCrossBorderTransfer(config.jurisdictions),
192
+ source: 'tenant-config',
193
+ };
194
+ }
195
+ resolveFromMetadata(metadata) {
196
+ if (!metadata)
197
+ return null;
198
+ const jurisdictions = this.extractJurisdictionsFromMetadata(metadata);
199
+ if (jurisdictions.length === 0)
200
+ return null;
201
+ const industry = typeof metadata.industry === 'string' && this.isValidIndustry(metadata.industry)
202
+ ? metadata.industry
203
+ : this.config.defaultIndustry;
204
+ const dataResidency = (typeof metadata.dataResidency === 'string' ? metadata.dataResidency : undefined) ??
205
+ JURISDICTION_RESIDENCY_ZONES[jurisdictions[0]] ??
206
+ 'global';
207
+ return {
208
+ primaryJurisdictions: jurisdictions,
209
+ industry,
210
+ dataResidency,
211
+ crossBorderTransfer: this.detectCrossBorderTransfer(jurisdictions),
212
+ source: 'metadata-inference',
213
+ };
214
+ }
215
+ resolveDefault() {
216
+ return {
217
+ primaryJurisdictions: [this.config.defaultJurisdiction],
218
+ industry: this.config.defaultIndustry,
219
+ dataResidency: JURISDICTION_RESIDENCY_ZONES[this.config.defaultJurisdiction] ?? 'global',
220
+ crossBorderTransfer: false,
221
+ source: 'default',
222
+ };
223
+ }
224
+ /**
225
+ * Extract jurisdictions from metadata fields: jurisdiction, jurisdictions,
226
+ * countryCode, region. EU member state codes map to "EU", APAC codes map
227
+ * to "APAC", and known countries map to their specific jurisdiction.
228
+ */
229
+ extractJurisdictionsFromMetadata(metadata) {
230
+ const jurisdictions = [];
231
+ // Direct jurisdiction field
232
+ if (typeof metadata.jurisdiction === 'string') {
233
+ const j = metadata.jurisdiction.toUpperCase();
234
+ if (this.isValidJurisdiction(j))
235
+ jurisdictions.push(j);
236
+ }
237
+ // Jurisdictions array
238
+ if (Array.isArray(metadata.jurisdictions)) {
239
+ for (const item of metadata.jurisdictions) {
240
+ if (typeof item === 'string') {
241
+ const j = item.toUpperCase();
242
+ if (this.isValidJurisdiction(j) && !jurisdictions.includes(j)) {
243
+ jurisdictions.push(j);
244
+ }
245
+ }
246
+ }
247
+ }
248
+ // Country code inference
249
+ if (typeof metadata.countryCode === 'string') {
250
+ const code = metadata.countryCode.toUpperCase();
251
+ if (EU_MEMBER_STATE_CODES.has(code)) {
252
+ if (!jurisdictions.includes('EU'))
253
+ jurisdictions.push('EU');
254
+ }
255
+ else if (COUNTRY_JURISDICTION_MAP[code]) {
256
+ const j = COUNTRY_JURISDICTION_MAP[code];
257
+ if (!jurisdictions.includes(j))
258
+ jurisdictions.push(j);
259
+ }
260
+ else if (APAC_COUNTRY_CODES.has(code)) {
261
+ if (!jurisdictions.includes('APAC'))
262
+ jurisdictions.push('APAC');
263
+ }
264
+ }
265
+ // Region string inference
266
+ if (typeof metadata.region === 'string') {
267
+ const region = metadata.region.toUpperCase();
268
+ if (['EU', 'EUROPE', 'EEA'].includes(region)) {
269
+ if (!jurisdictions.includes('EU'))
270
+ jurisdictions.push('EU');
271
+ }
272
+ else if (['US', 'UNITED STATES', 'NORTH AMERICA'].includes(region)) {
273
+ if (!jurisdictions.includes('US'))
274
+ jurisdictions.push('US');
275
+ }
276
+ else if (['APAC', 'ASIA', 'ASIA-PACIFIC'].includes(region)) {
277
+ if (!jurisdictions.includes('APAC'))
278
+ jurisdictions.push('APAC');
279
+ }
280
+ }
281
+ return jurisdictions;
282
+ }
283
+ isValidJurisdiction(v) {
284
+ return JURISDICTIONS.includes(v);
285
+ }
286
+ isValidIndustry(v) {
287
+ return INDUSTRIES.includes(v);
288
+ }
289
+ }
290
+ // ---------------------------------------------------------------------------
291
+ // Policy Composer
292
+ // ---------------------------------------------------------------------------
293
+ /**
294
+ * Strictness rankings used for deterministic conflict resolution.
295
+ * Higher number = stricter requirement. When policies conflict,
296
+ * the strictest value wins.
297
+ */
298
+ const CRYPTO_SUITE_STRICTNESS = {
299
+ 'standard': 0,
300
+ 'fips-140-2': 1,
301
+ 'post-quantum': 2,
302
+ };
303
+ const CONSENT_STRICTNESS = {
304
+ 'implicit': 0,
305
+ 'opt-out': 1,
306
+ 'opt-in': 2,
307
+ 'explicit-granular': 3,
308
+ };
309
+ const ESCALATION_STRICTNESS = {
310
+ 'log-only': 0,
311
+ 'flag-review': 1,
312
+ 'block-escalate': 2,
313
+ 'hard-block': 3,
314
+ };
315
+ const PROOF_ANCHORING_STRICTNESS = {
316
+ 'database': 0,
317
+ 'merkle-tree': 1,
318
+ 'blockchain-l2': 2,
319
+ 'tsa-rfc3161': 3,
320
+ };
321
+ const ENFORCEMENT_ORDER = {
322
+ 'advisory': 0,
323
+ 'required': 1,
324
+ 'mandatory': 2,
325
+ 'blocking': 3,
326
+ };
327
+ /**
328
+ * Helper to create a PolicyConstraint with less boilerplate.
329
+ */
330
+ function constraint(id, type, rule, enforcement, bundleId, jurisdiction, value) {
331
+ return { id, type, rule, enforcement, sourceBundleId: bundleId, sourceJurisdiction: jurisdiction, value };
332
+ }
333
+ /**
334
+ * Built-in policy bundles covering the major jurisdictional scopes.
335
+ * These are the baseline; consumers can register additional bundles.
336
+ */
337
+ function createBuiltinBundles() {
338
+ return [
339
+ // -- GLOBAL DEFAULT --
340
+ {
341
+ id: 'global-default',
342
+ name: 'Global Default',
343
+ jurisdictions: ['GLOBAL'],
344
+ priority: 0,
345
+ constraints: [
346
+ constraint('global-retention', 'retention', 'Min 365-day audit retention', 'required', 'global-default', 'GLOBAL', 365),
347
+ constraint('global-crypto', 'crypto', 'Standard cryptographic suite', 'required', 'global-default', 'GLOBAL', 'standard'),
348
+ constraint('global-consent', 'consent', 'Implicit consent model', 'required', 'global-default', 'GLOBAL', 'implicit'),
349
+ constraint('global-escalation', 'escalation', 'Flag for human review', 'required', 'global-default', 'GLOBAL', 'flag-review'),
350
+ constraint('global-trust', 'trust-level', 'Minimum trust T2 (Provisional)', 'required', 'global-default', 'GLOBAL', 2),
351
+ constraint('global-proof', 'proof-anchoring', 'Database proof anchoring', 'required', 'global-default', 'GLOBAL', 'database'),
352
+ constraint('global-external', 'external-services', 'External services allowed', 'advisory', 'global-default', 'GLOBAL', true),
353
+ ],
354
+ },
355
+ // -- EU (GDPR + AI Act) --
356
+ {
357
+ id: 'eu-gdpr',
358
+ name: 'EU GDPR',
359
+ jurisdictions: ['EU'],
360
+ priority: 10,
361
+ constraints: [
362
+ constraint('eu-retention', 'retention', 'GDPR: 5-year audit retention', 'mandatory', 'eu-gdpr', 'EU', 1825),
363
+ constraint('eu-consent', 'consent', 'GDPR: Explicit granular consent', 'mandatory', 'eu-gdpr', 'EU', 'explicit-granular'),
364
+ constraint('eu-residency', 'data-residency', 'GDPR: EU data residency', 'mandatory', 'eu-gdpr', 'EU', 'eu-west'),
365
+ constraint('eu-proof', 'proof-anchoring', 'GDPR: Merkle tree proof anchoring', 'required', 'eu-gdpr', 'EU', 'merkle-tree'),
366
+ constraint('eu-trust', 'trust-level', 'GDPR: Minimum trust T3 (Monitored)', 'required', 'eu-gdpr', 'EU', 3),
367
+ constraint('eu-processing', 'processing-restriction', 'GDPR: Purpose limitation', 'mandatory', 'eu-gdpr', 'EU', 'purpose-limitation'),
368
+ constraint('eu-audit', 'audit-requirement', 'GDPR: Full audit trail', 'mandatory', 'eu-gdpr', 'EU', 'full-audit-trail'),
369
+ ],
370
+ },
371
+ {
372
+ id: 'eu-ai-act',
373
+ name: 'EU AI Act',
374
+ jurisdictions: ['EU'],
375
+ priority: 15,
376
+ constraints: [
377
+ constraint('euai-escalation', 'escalation', 'AI Act: Block and escalate on violations', 'mandatory', 'eu-ai-act', 'EU', 'block-escalate'),
378
+ constraint('euai-audit', 'audit-requirement', 'AI Act: AI system audit trail', 'mandatory', 'eu-ai-act', 'EU', 'ai-system-audit'),
379
+ constraint('euai-processing', 'processing-restriction', 'AI Act: Risk assessment required', 'mandatory', 'eu-ai-act', 'EU', 'risk-assessment-required'),
380
+ ],
381
+ },
382
+ // -- US --
383
+ {
384
+ id: 'us-standard',
385
+ name: 'US Standard',
386
+ jurisdictions: ['US'],
387
+ priority: 10,
388
+ constraints: [
389
+ constraint('us-retention', 'retention', 'US: 7-year audit retention', 'mandatory', 'us-standard', 'US', 2555),
390
+ constraint('us-crypto', 'crypto', 'US: FIPS 140-2 cryptographic suite', 'mandatory', 'us-standard', 'US', 'fips-140-2'),
391
+ constraint('us-proof', 'proof-anchoring', 'US: TSA RFC 3161 proof anchoring', 'required', 'us-standard', 'US', 'tsa-rfc3161'),
392
+ constraint('us-trust', 'trust-level', 'US: Minimum trust T3 (Monitored)', 'required', 'us-standard', 'US', 3),
393
+ constraint('us-escalation', 'escalation', 'US: Block and escalate', 'mandatory', 'us-standard', 'US', 'block-escalate'),
394
+ constraint('us-consent', 'consent', 'US: Opt-out consent model', 'required', 'us-standard', 'US', 'opt-out'),
395
+ ],
396
+ },
397
+ // -- APAC --
398
+ {
399
+ id: 'apac-standard',
400
+ name: 'APAC Standard',
401
+ jurisdictions: ['APAC'],
402
+ priority: 8,
403
+ constraints: [
404
+ constraint('apac-retention', 'retention', 'APAC: 3-year audit retention', 'required', 'apac-standard', 'APAC', 1095),
405
+ constraint('apac-consent', 'consent', 'APAC: Opt-in consent model', 'required', 'apac-standard', 'APAC', 'opt-in'),
406
+ constraint('apac-trust', 'trust-level', 'APAC: Minimum trust T2 (Provisional)', 'required', 'apac-standard', 'APAC', 2),
407
+ constraint('apac-proof', 'proof-anchoring', 'APAC: Merkle tree proof anchoring', 'required', 'apac-standard', 'APAC', 'merkle-tree'),
408
+ ],
409
+ },
410
+ // -- UK (post-Brexit, GDPR-adjacent) --
411
+ {
412
+ id: 'uk-dpa',
413
+ name: 'UK Data Protection Act',
414
+ jurisdictions: ['UK'],
415
+ priority: 10,
416
+ constraints: [
417
+ constraint('uk-retention', 'retention', 'UK DPA: 5-year retention', 'mandatory', 'uk-dpa', 'UK', 1825),
418
+ constraint('uk-consent', 'consent', 'UK DPA: Explicit granular consent', 'mandatory', 'uk-dpa', 'UK', 'explicit-granular'),
419
+ constraint('uk-trust', 'trust-level', 'UK DPA: Minimum trust T3 (Monitored)', 'required', 'uk-dpa', 'UK', 3),
420
+ constraint('uk-residency', 'data-residency', 'UK DPA: UK data residency', 'mandatory', 'uk-dpa', 'UK', 'uk-south'),
421
+ ],
422
+ },
423
+ // -- Canada --
424
+ {
425
+ id: 'ca-pipeda',
426
+ name: 'Canada PIPEDA',
427
+ jurisdictions: ['CA'],
428
+ priority: 10,
429
+ constraints: [
430
+ constraint('ca-consent', 'consent', 'PIPEDA: Opt-in consent', 'mandatory', 'ca-pipeda', 'CA', 'opt-in'),
431
+ constraint('ca-trust', 'trust-level', 'PIPEDA: Minimum trust T3', 'required', 'ca-pipeda', 'CA', 3),
432
+ constraint('ca-retention', 'retention', 'PIPEDA: 3-year retention', 'required', 'ca-pipeda', 'CA', 1095),
433
+ ],
434
+ },
435
+ ];
436
+ }
437
+ /**
438
+ * Composes policy constraints from multiple bundles into a single resolved set.
439
+ *
440
+ * Conflict resolution strategy:
441
+ * - Numeric constraints (retention, trust-level): highest value wins.
442
+ * - Ordered enums (crypto, consent, escalation, proof-anchoring): strictest wins.
443
+ * - Data residency: enforcement level decides; incompatible mandatory zones = critical conflict.
444
+ * - External services: restrictive (false) wins over permissive (true).
445
+ * - Additive constraints (audit, processing): all unique values are kept.
446
+ */
447
+ export class PolicyComposer {
448
+ bundles = new Map();
449
+ constructor() {
450
+ for (const bundle of createBuiltinBundles()) {
451
+ this.bundles.set(bundle.id, bundle);
452
+ }
453
+ }
454
+ /** Number of registered bundles. */
455
+ get bundleCount() {
456
+ return this.bundles.size;
457
+ }
458
+ /** IDs of all registered bundles. */
459
+ get registeredBundleIds() {
460
+ return Array.from(this.bundles.keys());
461
+ }
462
+ /**
463
+ * Register or overwrite a policy bundle.
464
+ */
465
+ registerBundle(bundle) {
466
+ if (this.bundles.has(bundle.id)) {
467
+ logger.warn({ bundleId: bundle.id }, 'Overwriting existing policy bundle');
468
+ }
469
+ this.bundles.set(bundle.id, bundle);
470
+ logger.info({ bundleId: bundle.id, priority: bundle.priority }, 'Policy bundle registered');
471
+ }
472
+ /**
473
+ * Compose a policy set by selecting applicable bundles for the given
474
+ * jurisdiction context, merging their constraints, and resolving conflicts.
475
+ */
476
+ compose(ctx, additionalBundleIds) {
477
+ const applicable = this.selectApplicable(ctx, additionalBundleIds);
478
+ // Always include global default as a fallback
479
+ if (applicable.length === 0) {
480
+ const global = this.bundles.get('global-default');
481
+ if (global)
482
+ applicable.push(global);
483
+ }
484
+ // Sort by priority (lower first, so higher-priority overrides later)
485
+ applicable.sort((a, b) => a.priority - b.priority);
486
+ // Collect all constraints
487
+ const allConstraints = [];
488
+ for (const bundle of applicable) {
489
+ allConstraints.push(...bundle.constraints);
490
+ }
491
+ // Group by constraint type
492
+ const grouped = new Map();
493
+ for (const c of allConstraints) {
494
+ const group = grouped.get(c.type) ?? [];
495
+ group.push(c);
496
+ grouped.set(c.type, group);
497
+ }
498
+ // Resolve each group
499
+ const resolved = [];
500
+ const resolvedConflicts = [];
501
+ const unresolvedConflicts = [];
502
+ for (const [type, constraints] of grouped.entries()) {
503
+ const result = this.resolveGroup(type, constraints, applicable);
504
+ resolved.push(...result.resolved);
505
+ resolvedConflicts.push(...result.resolvedConflicts);
506
+ unresolvedConflicts.push(...result.unresolvedConflicts);
507
+ }
508
+ const isValid = unresolvedConflicts.every(c => c.severity !== 'critical');
509
+ return {
510
+ constraints: resolved,
511
+ sourceBundles: applicable.map(b => b.id),
512
+ resolvedConflicts,
513
+ unresolvedConflicts,
514
+ isValid,
515
+ composedAt: Date.now(),
516
+ };
517
+ }
518
+ /**
519
+ * Select bundles that apply to the given jurisdiction context.
520
+ * A bundle applies if any of its jurisdictions match the context's
521
+ * primary jurisdictions, or if the bundle is GLOBAL.
522
+ */
523
+ selectApplicable(ctx, additionalIds) {
524
+ const selected = [];
525
+ const used = new Set();
526
+ for (const [id, bundle] of this.bundles) {
527
+ const applies = bundle.jurisdictions.some(j => j === 'GLOBAL' || ctx.primaryJurisdictions.includes(j));
528
+ if (applies && !used.has(id)) {
529
+ selected.push(bundle);
530
+ used.add(id);
531
+ }
532
+ }
533
+ // Include explicitly requested additional bundles
534
+ if (additionalIds) {
535
+ for (const id of additionalIds) {
536
+ if (!used.has(id)) {
537
+ const bundle = this.bundles.get(id);
538
+ if (bundle) {
539
+ selected.push(bundle);
540
+ used.add(id);
541
+ }
542
+ }
543
+ }
544
+ }
545
+ return selected;
546
+ }
547
+ /**
548
+ * Resolve conflicts within a group of same-type constraints.
549
+ */
550
+ resolveGroup(type, constraints, bundles) {
551
+ // No conflict possible with a single constraint
552
+ if (constraints.length <= 1) {
553
+ return { resolved: constraints, resolvedConflicts: [], unresolvedConflicts: [] };
554
+ }
555
+ switch (type) {
556
+ // Numeric max-wins
557
+ case 'retention':
558
+ case 'trust-level':
559
+ return this.resolveByMax(type, constraints);
560
+ // Ordered-enum strictest-wins
561
+ case 'crypto':
562
+ return this.resolveByStrictness(type, constraints, CRYPTO_SUITE_STRICTNESS);
563
+ case 'consent':
564
+ return this.resolveByStrictness(type, constraints, CONSENT_STRICTNESS);
565
+ case 'escalation':
566
+ return this.resolveByStrictness(type, constraints, ESCALATION_STRICTNESS);
567
+ case 'proof-anchoring':
568
+ return this.resolveByStrictness(type, constraints, PROOF_ANCHORING_STRICTNESS);
569
+ // Special resolution
570
+ case 'data-residency':
571
+ return this.resolveDataResidency(constraints);
572
+ case 'external-services':
573
+ return this.resolveExternalServices(constraints);
574
+ // Additive (keep all unique values)
575
+ case 'audit-requirement':
576
+ case 'processing-restriction':
577
+ return this.resolveAdditive(constraints);
578
+ // Fallback: by bundle priority
579
+ default:
580
+ return this.resolveByPriority(type, constraints, bundles);
581
+ }
582
+ }
583
+ /** Resolve numeric constraints by taking the maximum value. */
584
+ resolveByMax(type, constraints) {
585
+ const valued = constraints.map(c => ({
586
+ constraint: c,
587
+ numericValue: typeof c.value === 'number' ? c.value : 0,
588
+ }));
589
+ const winner = valued.reduce((max, v) => v.numericValue > max.numericValue ? v : max);
590
+ const hasConflict = new Set(valued.map(v => v.numericValue)).size > 1;
591
+ return {
592
+ resolved: [winner.constraint],
593
+ resolvedConflicts: hasConflict
594
+ ? [{
595
+ constraintType: type,
596
+ constraints,
597
+ description: `${type}: resolved to max value ${winner.numericValue}`,
598
+ severity: 'low',
599
+ }]
600
+ : [],
601
+ unresolvedConflicts: [],
602
+ };
603
+ }
604
+ /** Resolve ordered-enum constraints by taking the strictest value. */
605
+ resolveByStrictness(type, constraints, strictnessMap) {
606
+ const valued = constraints.map(c => ({
607
+ constraint: c,
608
+ strictness: strictnessMap[String(c.value)] ?? 0,
609
+ }));
610
+ const winner = valued.reduce((max, v) => v.strictness > max.strictness ? v : max);
611
+ const hasConflict = new Set(valued.map(v => v.strictness)).size > 1;
612
+ return {
613
+ resolved: [winner.constraint],
614
+ resolvedConflicts: hasConflict
615
+ ? [{
616
+ constraintType: type,
617
+ constraints,
618
+ description: `${type}: resolved to strictest value "${winner.constraint.value}"`,
619
+ severity: 'low',
620
+ }]
621
+ : [],
622
+ unresolvedConflicts: [],
623
+ };
624
+ }
625
+ /**
626
+ * Data residency conflicts are potentially critical: if two mandatory
627
+ * constraints require different zones, the data literally cannot be in
628
+ * both places. This is surfaced as an unresolved critical conflict.
629
+ */
630
+ resolveDataResidency(constraints) {
631
+ const zones = new Set(constraints.map(c => String(c.value)));
632
+ if (zones.size <= 1) {
633
+ return { resolved: [constraints[0]], resolvedConflicts: [], unresolvedConflicts: [] };
634
+ }
635
+ // Sort by enforcement level (strictest first)
636
+ const sorted = [...constraints].sort((a, b) => (ENFORCEMENT_ORDER[b.enforcement] ?? 0) - (ENFORCEMENT_ORDER[a.enforcement] ?? 0));
637
+ const hasMandatory = sorted.some(c => c.enforcement === 'blocking' || c.enforcement === 'mandatory');
638
+ if (hasMandatory) {
639
+ return {
640
+ resolved: [sorted[0]],
641
+ resolvedConflicts: [],
642
+ unresolvedConflicts: [{
643
+ constraintType: 'data-residency',
644
+ constraints,
645
+ description: `Incompatible data residency requirements: ${[...zones].join(' vs ')}`,
646
+ severity: 'critical',
647
+ }],
648
+ };
649
+ }
650
+ return {
651
+ resolved: [sorted[0]],
652
+ resolvedConflicts: [{
653
+ constraintType: 'data-residency',
654
+ constraints,
655
+ description: `Data residency resolved to ${sorted[0].value}`,
656
+ severity: 'medium',
657
+ }],
658
+ unresolvedConflicts: [],
659
+ };
660
+ }
661
+ /** External services: false (restrictive) wins over true (permissive). */
662
+ resolveExternalServices(constraints) {
663
+ const blocked = constraints.some(c => c.value === false);
664
+ const winner = blocked ? constraints.find(c => c.value === false) : constraints[0];
665
+ const hasConflict = new Set(constraints.map(c => c.value)).size > 1;
666
+ return {
667
+ resolved: [winner],
668
+ resolvedConflicts: hasConflict
669
+ ? [{
670
+ constraintType: 'external-services',
671
+ constraints,
672
+ description: `External services: resolved to ${winner.value}`,
673
+ severity: 'low',
674
+ }]
675
+ : [],
676
+ unresolvedConflicts: [],
677
+ };
678
+ }
679
+ /** Additive constraints keep all unique values (e.g., audit requirements). */
680
+ resolveAdditive(constraints) {
681
+ const seen = new Set();
682
+ const unique = [];
683
+ for (const c of constraints) {
684
+ const key = String(c.value);
685
+ if (!seen.has(key)) {
686
+ seen.add(key);
687
+ unique.push(c);
688
+ }
689
+ }
690
+ return { resolved: unique, resolvedConflicts: [], unresolvedConflicts: [] };
691
+ }
692
+ /** Fallback: resolve by bundle priority (highest priority wins). */
693
+ resolveByPriority(type, constraints, bundles) {
694
+ const priorityMap = new Map(bundles.map(b => [b.id, b.priority]));
695
+ const sorted = [...constraints].sort((a, b) => (priorityMap.get(b.sourceBundleId) ?? 0) - (priorityMap.get(a.sourceBundleId) ?? 0));
696
+ return {
697
+ resolved: [sorted[0]],
698
+ resolvedConflicts: constraints.length > 1
699
+ ? [{
700
+ constraintType: type,
701
+ constraints,
702
+ description: `${type}: resolved by priority to bundle "${sorted[0].sourceBundleId}"`,
703
+ severity: 'low',
704
+ }]
705
+ : [],
706
+ unresolvedConflicts: [],
707
+ };
708
+ }
709
+ }
710
+ // ---------------------------------------------------------------------------
711
+ // EU AI Act Classifier
712
+ // ---------------------------------------------------------------------------
713
+ /** Keywords that trigger "unacceptable" (prohibited) classification under Art. 5. */
714
+ const PROHIBITED_KEYWORDS = [
715
+ 'social scoring', 'social credit', 'subliminal manipulation',
716
+ 'subliminal technique', 'exploit vulnerability', 'exploit vulnerabilities',
717
+ 'real-time biometric identification', 'real-time facial recognition',
718
+ 'mass surveillance', 'emotion recognition workplace',
719
+ 'emotion recognition education', 'predictive policing individual',
720
+ 'cognitive behavioral manipulation', 'biometric categorisation sensitive',
721
+ 'untargeted scraping facial',
722
+ ];
723
+ /** Keywords mapped to Annex III high-risk categories. */
724
+ const HIGH_RISK_KEYWORDS = {
725
+ 'biometric-identification': [
726
+ 'biometric identification', 'biometric verification', 'facial recognition',
727
+ 'fingerprint matching', 'voice identification', 'iris recognition',
728
+ ],
729
+ 'critical-infrastructure': [
730
+ 'critical infrastructure', 'power grid', 'water supply',
731
+ 'traffic management', 'electricity distribution', 'energy management',
732
+ ],
733
+ 'education-vocational': [
734
+ 'student assessment', 'educational admission', 'learning evaluation',
735
+ 'exam scoring', 'academic grading', 'educational placement',
736
+ ],
737
+ 'employment-worker-management': [
738
+ 'recruitment', 'hiring decision', 'cv screening', 'resume screening',
739
+ 'employee evaluation', 'performance monitoring', 'promotion decision',
740
+ 'termination decision', 'worker management',
741
+ ],
742
+ 'essential-services': [
743
+ 'credit scoring', 'creditworthiness', 'insurance pricing',
744
+ 'insurance risk', 'social benefit', 'public assistance',
745
+ 'emergency services dispatch', 'loan application', 'mortgage decision',
746
+ ],
747
+ 'law-enforcement': [
748
+ 'law enforcement', 'criminal risk assessment', 'recidivism prediction',
749
+ 'crime prediction', 'evidence analysis', 'suspect profiling',
750
+ ],
751
+ 'migration-asylum-border': [
752
+ 'border control', 'immigration', 'asylum application',
753
+ 'visa application', 'migration management', 'refugee assessment',
754
+ ],
755
+ 'justice-democratic': [
756
+ 'judicial decision', 'court ruling', 'sentencing',
757
+ 'legal outcome prediction', 'electoral', 'voting',
758
+ 'election', 'democratic process',
759
+ ],
760
+ };
761
+ /** Keywords that trigger "limited-risk" classification (transparency obligations). */
762
+ const LIMITED_RISK_KEYWORDS = [
763
+ 'chatbot', 'conversational ai', 'virtual assistant', 'deepfake',
764
+ 'synthetic media', 'generated content', 'ai-generated text',
765
+ 'ai-generated image', 'ai-generated video', 'emotion detection',
766
+ 'content generation', 'text generation', 'image generation',
767
+ ];
768
+ /** Regulatory obligations per classification tier. */
769
+ const OBLIGATIONS_MAP = {
770
+ 'unacceptable': [
771
+ 'PROHIBITED - System must not be deployed in EU/EEA',
772
+ 'Immediate cessation required for EU market',
773
+ 'Notify national supervisory authority',
774
+ ],
775
+ 'high-risk': [
776
+ 'Risk management system (Art. 9)',
777
+ 'Data governance and management (Art. 10)',
778
+ 'Technical documentation (Art. 11)',
779
+ 'Record-keeping and logging (Art. 12)',
780
+ 'Transparency and user information (Art. 13)',
781
+ 'Human oversight measures (Art. 14)',
782
+ 'Accuracy, robustness, cybersecurity (Art. 15)',
783
+ 'Conformity assessment (Art. 43)',
784
+ 'Post-market monitoring (Art. 61)',
785
+ 'Serious incident reporting (Art. 62)',
786
+ ],
787
+ 'limited-risk': [
788
+ 'Inform users of AI interaction (Art. 50)',
789
+ 'Label AI-generated content (Art. 50)',
790
+ 'Disclose deepfake/synthetic content (Art. 50)',
791
+ ],
792
+ 'minimal-risk': [
793
+ 'Voluntary codes of conduct (Art. 95)',
794
+ 'No mandatory obligations',
795
+ ],
796
+ };
797
+ /**
798
+ * Classifies AI system usage against the EU AI Act risk framework.
799
+ *
800
+ * Uses keyword-based heuristics against the intent goal, metadata, and type
801
+ * to produce a risk classification. This is a simplified, open-source
802
+ * implementation suitable for initial screening; production deployments
803
+ * should supplement this with domain-expert review for high-risk and
804
+ * unacceptable classifications.
805
+ *
806
+ * Classification priority: unacceptable > high-risk > limited-risk > minimal-risk
807
+ */
808
+ export class AiActClassifier {
809
+ /**
810
+ * Classify an intent's AI Act risk level.
811
+ *
812
+ * @param goal - The intent's stated goal
813
+ * @param context - Optional intent context/metadata
814
+ * @param intentType - Optional intent type string
815
+ * @returns Classification result with obligations
816
+ */
817
+ classify(goal, context, intentType) {
818
+ const searchText = this.buildSearchText(goal, context, intentType);
819
+ // Check in priority order: unacceptable > high-risk > limited > minimal
820
+ const prohibited = this.checkProhibited(searchText);
821
+ if (prohibited)
822
+ return prohibited;
823
+ const highRisk = this.checkHighRisk(searchText);
824
+ if (highRisk)
825
+ return highRisk;
826
+ const limited = this.checkLimitedRisk(searchText);
827
+ if (limited)
828
+ return limited;
829
+ return {
830
+ classification: 'minimal-risk',
831
+ confidence: 0.6,
832
+ reasoning: 'No risk indicators detected; classified as minimal-risk',
833
+ obligations: OBLIGATIONS_MAP['minimal-risk'],
834
+ };
835
+ }
836
+ buildSearchText(goal, context, intentType) {
837
+ const parts = [goal.toLowerCase()];
838
+ if (intentType)
839
+ parts.push(intentType.toLowerCase());
840
+ if (context) {
841
+ for (const [key, value] of Object.entries(context)) {
842
+ if (typeof value === 'string') {
843
+ parts.push(`${key}: ${value}`.toLowerCase());
844
+ }
845
+ else if (Array.isArray(value)) {
846
+ for (const item of value) {
847
+ if (typeof item === 'string')
848
+ parts.push(item.toLowerCase());
849
+ }
850
+ }
851
+ }
852
+ }
853
+ return parts.join(' ');
854
+ }
855
+ checkProhibited(text) {
856
+ for (const keyword of PROHIBITED_KEYWORDS) {
857
+ if (text.includes(keyword)) {
858
+ logger.warn({ keyword }, 'EU AI Act: PROHIBITED system detected');
859
+ return {
860
+ classification: 'unacceptable',
861
+ confidence: 0.9,
862
+ reasoning: `Prohibited practice detected: "${keyword}" (Art. 5)`,
863
+ annexReference: 'Article 5',
864
+ obligations: OBLIGATIONS_MAP['unacceptable'],
865
+ };
866
+ }
867
+ }
868
+ return null;
869
+ }
870
+ checkHighRisk(text) {
871
+ let bestMatch = null;
872
+ for (const [category, keywords] of Object.entries(HIGH_RISK_KEYWORDS)) {
873
+ let count = 0;
874
+ let firstKeyword = '';
875
+ for (const keyword of keywords) {
876
+ if (text.includes(keyword)) {
877
+ count++;
878
+ if (!firstKeyword)
879
+ firstKeyword = keyword;
880
+ }
881
+ }
882
+ if (count > 0 && (!bestMatch || count > bestMatch.count)) {
883
+ bestMatch = { category, keyword: firstKeyword, count };
884
+ }
885
+ }
886
+ if (bestMatch) {
887
+ const confidence = Math.min(0.5 + bestMatch.count * 0.15, 0.95);
888
+ logger.info({ category: bestMatch.category, confidence }, 'EU AI Act: High-risk classification');
889
+ return {
890
+ classification: 'high-risk',
891
+ highRiskCategory: bestMatch.category,
892
+ confidence,
893
+ reasoning: `High-risk system (Annex III: ${bestMatch.category}). Matched: "${bestMatch.keyword}"`,
894
+ annexReference: 'Article 6, Annex III',
895
+ obligations: OBLIGATIONS_MAP['high-risk'],
896
+ };
897
+ }
898
+ return null;
899
+ }
900
+ checkLimitedRisk(text) {
901
+ for (const keyword of LIMITED_RISK_KEYWORDS) {
902
+ if (text.includes(keyword)) {
903
+ return {
904
+ classification: 'limited-risk',
905
+ confidence: 0.7,
906
+ reasoning: `Limited-risk transparency obligation: "${keyword}"`,
907
+ annexReference: 'Article 50',
908
+ obligations: OBLIGATIONS_MAP['limited-risk'],
909
+ };
910
+ }
911
+ }
912
+ return null;
913
+ }
914
+ }
915
+ // ---------------------------------------------------------------------------
916
+ // Regime Selector
917
+ // ---------------------------------------------------------------------------
918
+ /**
919
+ * Pick the strictest value from an ordered enum, given jurisdiction defaults
920
+ * and an optional policy-composed value.
921
+ */
922
+ function pickStrictest(defaults, policyValue, strictnessMap) {
923
+ const all = policyValue ? [...defaults, policyValue] : defaults;
924
+ return all.reduce((strictest, current) => (strictnessMap[current] ?? 0) > (strictnessMap[strictest] ?? 0) ? current : strictest);
925
+ }
926
+ /** Check if a jurisdiction context includes any of the given jurisdictions. */
927
+ function hasJurisdiction(ctx, ...jurisdictions) {
928
+ return jurisdictions.some(j => ctx.primaryJurisdictions.includes(j));
929
+ }
930
+ /** Extract a typed constraint value from a composed policy set. */
931
+ function extractPolicyValue(policySet, type) {
932
+ return policySet.constraints.find(c => c.type === type)?.value;
933
+ }
934
+ /**
935
+ * Assembles a complete GovernanceRegime from a jurisdiction context and
936
+ * composed policy set. Each regime parameter is resolved independently
937
+ * by combining jurisdiction-based defaults with policy-composed values,
938
+ * always selecting the strictest option.
939
+ */
940
+ export class RegimeSelector {
941
+ /**
942
+ * Select the governance regime for the given context and policy set.
943
+ */
944
+ select(ctx, policySet) {
945
+ const cryptoSuite = this.resolveCryptoSuite(ctx, policySet);
946
+ const proofAnchoring = this.resolveProofAnchoring(ctx, policySet);
947
+ const consentModel = this.resolveConsentModel(ctx, policySet);
948
+ const escalationMode = this.resolveEscalationMode(ctx, policySet);
949
+ const auditRetentionDays = this.resolveAuditRetentionDays(ctx, policySet);
950
+ const externalServicesAllowed = this.resolveExternalServicesAllowed(ctx, policySet);
951
+ const minimumTrustLevel = this.resolveMinimumTrustLevel(ctx, policySet);
952
+ // Build a deterministic regime ID from the resolved parameters
953
+ const regimeId = this.generateRegimeId({
954
+ jurisdictions: ctx.primaryJurisdictions,
955
+ cryptoSuite,
956
+ proofAnchoring,
957
+ consentModel,
958
+ escalationMode,
959
+ auditRetentionDays,
960
+ dataResidency: ctx.dataResidency,
961
+ externalServicesAllowed,
962
+ minimumTrustLevel,
963
+ });
964
+ // Build human-readable name
965
+ const jurisdictionPart = ctx.primaryJurisdictions.length === 1
966
+ ? ctx.primaryJurisdictions[0]
967
+ : `Multi(${ctx.primaryJurisdictions.join('+')})`;
968
+ const name = ctx.industry !== 'general'
969
+ ? `${jurisdictionPart}-${ctx.industry}`
970
+ : jurisdictionPart;
971
+ const regime = {
972
+ regimeId,
973
+ name: name || 'default',
974
+ jurisdictions: ctx.primaryJurisdictions,
975
+ policyNamespaces: policySet.sourceBundles,
976
+ cryptoSuite,
977
+ proofAnchoring,
978
+ auditRetentionDays,
979
+ consentModel,
980
+ escalationMode,
981
+ dataResidency: ctx.dataResidency,
982
+ externalServicesAllowed,
983
+ minimumTrustLevel,
984
+ conformityAssessmentRequired: hasJurisdiction(ctx, 'EU'),
985
+ transparencyRequired: hasJurisdiction(ctx, 'EU', 'CA', 'UK'),
986
+ metadata: {},
987
+ };
988
+ logger.info({ regimeId, name, cryptoSuite, minimumTrustLevel }, 'Governance regime assembled');
989
+ return regime;
990
+ }
991
+ resolveCryptoSuite(ctx, ps) {
992
+ const pv = extractPolicyValue(ps, 'crypto');
993
+ const defaults = ['standard'];
994
+ if (hasJurisdiction(ctx, 'US'))
995
+ defaults.push('fips-140-2');
996
+ return pickStrictest(defaults, pv, CRYPTO_SUITE_STRICTNESS);
997
+ }
998
+ resolveProofAnchoring(ctx, ps) {
999
+ const pv = extractPolicyValue(ps, 'proof-anchoring');
1000
+ const defaults = ['database'];
1001
+ if (hasJurisdiction(ctx, 'US'))
1002
+ defaults.push('tsa-rfc3161');
1003
+ else if (hasJurisdiction(ctx, 'EU'))
1004
+ defaults.push('merkle-tree');
1005
+ return pickStrictest(defaults, pv, PROOF_ANCHORING_STRICTNESS);
1006
+ }
1007
+ resolveConsentModel(ctx, ps) {
1008
+ const pv = extractPolicyValue(ps, 'consent');
1009
+ const defaults = ['implicit'];
1010
+ if (hasJurisdiction(ctx, 'EU', 'UK'))
1011
+ defaults.push('explicit-granular');
1012
+ else if (hasJurisdiction(ctx, 'CA'))
1013
+ defaults.push('opt-in');
1014
+ else if (hasJurisdiction(ctx, 'US'))
1015
+ defaults.push('opt-out');
1016
+ return pickStrictest(defaults, pv, CONSENT_STRICTNESS);
1017
+ }
1018
+ resolveEscalationMode(ctx, ps) {
1019
+ const pv = extractPolicyValue(ps, 'escalation');
1020
+ const defaults = ['flag-review'];
1021
+ if (hasJurisdiction(ctx, 'US', 'EU'))
1022
+ defaults.push('block-escalate');
1023
+ return pickStrictest(defaults, pv, ESCALATION_STRICTNESS);
1024
+ }
1025
+ resolveAuditRetentionDays(ctx, ps) {
1026
+ const pv = extractPolicyValue(ps, 'retention');
1027
+ const defaults = [365];
1028
+ if (hasJurisdiction(ctx, 'EU', 'UK'))
1029
+ defaults.push(1825);
1030
+ if (hasJurisdiction(ctx, 'US'))
1031
+ defaults.push(2555);
1032
+ return Math.max(...(pv !== undefined ? [...defaults, pv] : defaults));
1033
+ }
1034
+ resolveExternalServicesAllowed(ctx, ps) {
1035
+ const pv = extractPolicyValue(ps, 'external-services');
1036
+ return pv !== undefined ? pv : true;
1037
+ }
1038
+ resolveMinimumTrustLevel(ctx, ps) {
1039
+ const pv = extractPolicyValue(ps, 'trust-level');
1040
+ const defaults = [2];
1041
+ if (hasJurisdiction(ctx, 'EU', 'US', 'UK', 'CA'))
1042
+ defaults.push(3);
1043
+ return Math.max(...(pv !== undefined ? [...defaults, pv] : defaults));
1044
+ }
1045
+ /**
1046
+ * Generate a deterministic regime ID by hashing the canonical parameter set.
1047
+ * Same parameters always produce the same ID.
1048
+ */
1049
+ generateRegimeId(params) {
1050
+ const canonical = {
1051
+ auditRetentionDays: params.auditRetentionDays,
1052
+ consentModel: params.consentModel,
1053
+ cryptoSuite: params.cryptoSuite,
1054
+ dataResidency: params.dataResidency,
1055
+ escalationMode: params.escalationMode,
1056
+ externalServicesAllowed: params.externalServicesAllowed,
1057
+ jurisdictions: [...params.jurisdictions].sort(),
1058
+ minimumTrustLevel: params.minimumTrustLevel,
1059
+ proofAnchoring: params.proofAnchoring,
1060
+ };
1061
+ // Simple hash for deterministic ID generation
1062
+ const str = JSON.stringify(canonical);
1063
+ let hash = 0;
1064
+ for (let i = 0; i < str.length; i++) {
1065
+ const char = str.charCodeAt(i);
1066
+ hash = ((hash << 5) - hash) + char;
1067
+ hash = hash & hash; // Convert to 32-bit integer
1068
+ }
1069
+ return `regime-${Math.abs(hash).toString(16).padStart(8, '0')}`;
1070
+ }
1071
+ }
1072
+ // ---------------------------------------------------------------------------
1073
+ // Gateway Conflict Error
1074
+ // ---------------------------------------------------------------------------
1075
+ /**
1076
+ * Thrown when the gateway encounters unresolved policy conflicts that
1077
+ * block intent processing (only when blockOnConflicts is enabled).
1078
+ */
1079
+ export class GatewayConflictError extends Error {
1080
+ conflicts;
1081
+ constructor(conflicts) {
1082
+ super('Intent blocked by unresolved policy conflicts: ' +
1083
+ conflicts.map(c => c.description).join('; '));
1084
+ this.name = 'GatewayConflictError';
1085
+ this.conflicts = conflicts;
1086
+ }
1087
+ }
1088
+ // ---------------------------------------------------------------------------
1089
+ // Intent Gateway (Orchestrator)
1090
+ // ---------------------------------------------------------------------------
1091
+ /** EU/EEA jurisdiction codes that trigger AI Act classification. */
1092
+ const EU_JURISDICTION_CODES = new Set(['EU']);
1093
+ /**
1094
+ * The Intent Gateway is the policy-aware orchestrator for all agent intents.
1095
+ *
1096
+ * It implements the full governance pipeline:
1097
+ * 1. **Intake** - Receives the intent submission and options
1098
+ * 2. **Jurisdiction Resolution** - Determines applicable jurisdictions
1099
+ * 3. **Policy Composition** - Merges applicable policy bundles with conflict detection
1100
+ * 4. **AI Act Classification** - Classifies EU-bound intents against the AI Act
1101
+ * 5. **Regime Selection** - Assembles the governance regime
1102
+ * 6. **Enriched Submit** - Submits with regime metadata and enforced trust levels
1103
+ *
1104
+ * On error, the gateway degrades to passthrough mode (never drops intents).
1105
+ *
1106
+ * @example
1107
+ * ```typescript
1108
+ * const gateway = new IntentGateway(intentService, { enabled: true });
1109
+ *
1110
+ * // Register tenant-specific jurisdiction
1111
+ * gateway.registerTenantConfig('tenant-acme', {
1112
+ * jurisdictions: ['EU'],
1113
+ * industry: 'finance',
1114
+ * });
1115
+ *
1116
+ * // Dispatch an intent through the governance pipeline
1117
+ * const result = await gateway.dispatch(
1118
+ * { goal: 'Analyze customer data', entityId: 'agent-1' },
1119
+ * { ctx: { tenantId: 'tenant-acme' } },
1120
+ * );
1121
+ *
1122
+ * console.log(result.regime.name); // "EU-finance"
1123
+ * console.log(result.regime.consentModel); // "explicit-granular"
1124
+ * console.log(result.regime.aiActClassification); // classification result
1125
+ * ```
1126
+ */
1127
+ export class IntentGateway {
1128
+ intentService;
1129
+ config;
1130
+ jurisdictionResolver;
1131
+ policyComposer;
1132
+ regimeSelector;
1133
+ aiActClassifier;
1134
+ constructor(intentService, config) {
1135
+ this.intentService = intentService;
1136
+ this.config = { ...DEFAULT_GATEWAY_CONFIG, ...config };
1137
+ this.jurisdictionResolver = new JurisdictionResolver(this.config);
1138
+ this.policyComposer = new PolicyComposer();
1139
+ this.regimeSelector = new RegimeSelector();
1140
+ this.aiActClassifier = new AiActClassifier();
1141
+ logger.info({ enabled: this.config.enabled, defaultJurisdiction: this.config.defaultJurisdiction }, 'IntentGateway initialized');
1142
+ }
1143
+ /**
1144
+ * Dispatch an intent through the full governance pipeline.
1145
+ *
1146
+ * When the gateway is disabled, intents pass through directly.
1147
+ * When enabled, the intent is enriched with jurisdiction, policy, and
1148
+ * regime metadata before submission. The trust level is enforced to
1149
+ * meet the regime's minimum.
1150
+ *
1151
+ * On unexpected errors, the gateway falls through to passthrough mode
1152
+ * with a degradation warning (never silently fails).
1153
+ */
1154
+ async dispatch(submission, options) {
1155
+ // Passthrough when disabled
1156
+ if (!this.config.enabled) {
1157
+ const intent = await this.intentService.submit(submission, options);
1158
+ return this.createPassthroughResult(intent);
1159
+ }
1160
+ try {
1161
+ // Step 1: Resolve jurisdiction
1162
+ const intentMetadata = submission.context;
1163
+ const jurisdictionContext = this.jurisdictionResolver.resolve(options.ctx, intentMetadata);
1164
+ const tenantId = options.ctx.tenantId;
1165
+ // Step 2: Compose policies
1166
+ const tenantConfig = this.jurisdictionResolver.getTenantConfig(tenantId);
1167
+ const policySet = this.policyComposer.compose(jurisdictionContext, tenantConfig?.customPolicyBundles);
1168
+ // Check for blocking conflicts
1169
+ const warnings = [];
1170
+ if (policySet.unresolvedConflicts.length > 0) {
1171
+ if (this.config.blockOnConflicts && !policySet.isValid) {
1172
+ throw new GatewayConflictError(policySet.unresolvedConflicts);
1173
+ }
1174
+ for (const conflict of policySet.unresolvedConflicts) {
1175
+ warnings.push(`Unresolved policy conflict: ${conflict.description}`);
1176
+ }
1177
+ }
1178
+ // Step 3: EU AI Act classification (when EU jurisdiction applies)
1179
+ let aiActResult;
1180
+ if (jurisdictionContext.primaryJurisdictions.some(j => EU_JURISDICTION_CODES.has(j))) {
1181
+ const goal = typeof submission.goal === 'string' ? submission.goal : '';
1182
+ const intentType = typeof submission.intentType === 'string' ? submission.intentType : undefined;
1183
+ aiActResult = this.aiActClassifier.classify(goal, intentMetadata, intentType);
1184
+ if (aiActResult.classification === 'unacceptable') {
1185
+ warnings.push(`EU AI Act: PROHIBITED - ${aiActResult.reasoning}`);
1186
+ }
1187
+ }
1188
+ // Step 4: Select governance regime
1189
+ const regime = this.regimeSelector.select(jurisdictionContext, policySet);
1190
+ // Attach AI Act classification to regime
1191
+ if (aiActResult) {
1192
+ regime.aiActClassification = aiActResult.classification;
1193
+ regime.aiActHighRiskCategory = aiActResult.highRiskCategory;
1194
+ }
1195
+ // Step 5: Enrich submit options with regime metadata
1196
+ const enrichedOptions = {
1197
+ ...options,
1198
+ trustSnapshot: {
1199
+ ...(options.trustSnapshot ?? {}),
1200
+ __governanceRegime: {
1201
+ regimeId: regime.regimeId,
1202
+ name: regime.name,
1203
+ jurisdictions: regime.jurisdictions,
1204
+ cryptoSuite: regime.cryptoSuite,
1205
+ minimumTrustLevel: regime.minimumTrustLevel,
1206
+ aiActClassification: regime.aiActClassification,
1207
+ conformityAssessmentRequired: regime.conformityAssessmentRequired,
1208
+ },
1209
+ },
1210
+ };
1211
+ // Enforce minimum trust level
1212
+ if (!enrichedOptions.trustLevel || enrichedOptions.trustLevel < regime.minimumTrustLevel) {
1213
+ enrichedOptions.trustLevel = regime.minimumTrustLevel;
1214
+ }
1215
+ // Log regime decision
1216
+ if (this.config.logRegimeDecisions) {
1217
+ logger.info({
1218
+ regimeId: regime.regimeId,
1219
+ name: regime.name,
1220
+ tenantId,
1221
+ cryptoSuite: regime.cryptoSuite,
1222
+ minimumTrustLevel: regime.minimumTrustLevel,
1223
+ aiActClassification: regime.aiActClassification,
1224
+ bundles: policySet.sourceBundles,
1225
+ }, 'Gateway regime decision');
1226
+ }
1227
+ // Submit the intent
1228
+ const intent = await this.intentService.submit(submission, enrichedOptions);
1229
+ return { intent, regime, jurisdictionContext, policySet, warnings };
1230
+ }
1231
+ catch (error) {
1232
+ // Re-throw conflict errors (intentional blocks)
1233
+ if (error instanceof GatewayConflictError)
1234
+ throw error;
1235
+ // Degrade gracefully: submit without governance enrichment
1236
+ logger.error({ error: error instanceof Error ? error.message : 'Unknown error' }, 'Gateway error - falling through to passthrough');
1237
+ const intent = await this.intentService.submit(submission, options);
1238
+ const result = this.createPassthroughResult(intent);
1239
+ result.warnings.push(`Gateway degraded: ${error instanceof Error ? error.message : 'Unknown error'}`);
1240
+ return result;
1241
+ }
1242
+ }
1243
+ /**
1244
+ * Resolve the governance regime for a tenant context without submitting
1245
+ * an intent. Useful for pre-flight checks and UI display.
1246
+ */
1247
+ resolveRegime(ctx, metadata) {
1248
+ const jurisdictionContext = this.jurisdictionResolver.resolve(ctx, metadata);
1249
+ const tenantConfig = this.jurisdictionResolver.getTenantConfig(ctx.tenantId);
1250
+ const policySet = this.policyComposer.compose(jurisdictionContext, tenantConfig?.customPolicyBundles);
1251
+ const regime = this.regimeSelector.select(jurisdictionContext, policySet);
1252
+ return { regime, jurisdictionContext, policySet };
1253
+ }
1254
+ /**
1255
+ * Register a tenant's jurisdiction configuration.
1256
+ * This is the primary way to tell the gateway where a tenant operates.
1257
+ */
1258
+ registerTenantConfig(tenantId, config) {
1259
+ this.jurisdictionResolver.registerTenantConfig(tenantId, config);
1260
+ }
1261
+ /**
1262
+ * Retrieve the current gateway configuration (read-only).
1263
+ */
1264
+ getConfig() {
1265
+ return { ...this.config };
1266
+ }
1267
+ /**
1268
+ * Access the underlying intent service.
1269
+ */
1270
+ getIntentService() {
1271
+ return this.intentService;
1272
+ }
1273
+ /**
1274
+ * Create a passthrough result (used when gateway is disabled or on error).
1275
+ */
1276
+ createPassthroughResult(intent) {
1277
+ return {
1278
+ intent,
1279
+ regime: {
1280
+ regimeId: 'regime-passthrough',
1281
+ name: 'passthrough',
1282
+ jurisdictions: [this.config.defaultJurisdiction],
1283
+ policyNamespaces: [],
1284
+ cryptoSuite: 'standard',
1285
+ proofAnchoring: 'database',
1286
+ auditRetentionDays: 365,
1287
+ consentModel: 'implicit',
1288
+ escalationMode: 'flag-review',
1289
+ dataResidency: 'global',
1290
+ externalServicesAllowed: true,
1291
+ minimumTrustLevel: 2,
1292
+ conformityAssessmentRequired: false,
1293
+ transparencyRequired: false,
1294
+ metadata: {},
1295
+ },
1296
+ jurisdictionContext: {
1297
+ primaryJurisdictions: [this.config.defaultJurisdiction],
1298
+ industry: this.config.defaultIndustry,
1299
+ dataResidency: 'global',
1300
+ crossBorderTransfer: false,
1301
+ source: 'default',
1302
+ },
1303
+ policySet: {
1304
+ constraints: [],
1305
+ sourceBundles: [],
1306
+ resolvedConflicts: [],
1307
+ unresolvedConflicts: [],
1308
+ isValid: true,
1309
+ composedAt: Date.now(),
1310
+ },
1311
+ warnings: [],
1312
+ };
1313
+ }
1314
+ }
1315
+ // ---------------------------------------------------------------------------
1316
+ // Factory
1317
+ // ---------------------------------------------------------------------------
1318
+ /**
1319
+ * Create an IntentGateway instance with the given service and configuration.
1320
+ *
1321
+ * @example
1322
+ * ```typescript
1323
+ * const gateway = createIntentGateway(myIntentService, {
1324
+ * defaultJurisdiction: 'EU',
1325
+ * blockOnConflicts: true,
1326
+ * });
1327
+ * ```
1328
+ */
1329
+ export function createIntentGateway(intentService, config) {
1330
+ return new IntentGateway(intentService, config);
1331
+ }
1332
+ //# sourceMappingURL=index.js.map