@vauban-org/agent-sdk 1.0.0 → 1.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 (513) hide show
  1. package/CONTRACT.md +6918 -742
  2. package/dist/adapters/llm/anthropic-direct.d.ts +1 -0
  3. package/dist/adapters/llm/anthropic-direct.d.ts.map +1 -1
  4. package/dist/adapters/llm/anthropic-direct.js +43 -0
  5. package/dist/adapters/llm/anthropic-direct.js.map +1 -1
  6. package/dist/adapters/llm/cascade.d.ts.map +1 -1
  7. package/dist/adapters/llm/cascade.js +57 -14
  8. package/dist/adapters/llm/cascade.js.map +1 -1
  9. package/dist/adapters/llm/litellm.d.ts +2 -0
  10. package/dist/adapters/llm/litellm.d.ts.map +1 -1
  11. package/dist/adapters/llm/litellm.js +44 -0
  12. package/dist/adapters/llm/litellm.js.map +1 -1
  13. package/dist/compute/difficulty-estimator.d.ts +53 -0
  14. package/dist/compute/difficulty-estimator.d.ts.map +1 -0
  15. package/dist/compute/difficulty-estimator.js +82 -0
  16. package/dist/compute/difficulty-estimator.js.map +1 -0
  17. package/dist/compute/strategies/mixture-of-agents.d.ts +40 -0
  18. package/dist/compute/strategies/mixture-of-agents.d.ts.map +1 -0
  19. package/dist/compute/strategies/mixture-of-agents.js +110 -0
  20. package/dist/compute/strategies/mixture-of-agents.js.map +1 -0
  21. package/dist/compute/strategies/tree-of-thoughts.d.ts +48 -0
  22. package/dist/compute/strategies/tree-of-thoughts.d.ts.map +1 -0
  23. package/dist/compute/strategies/tree-of-thoughts.js +242 -0
  24. package/dist/compute/strategies/tree-of-thoughts.js.map +1 -0
  25. package/dist/compute/strategies/two-phase-orient.d.ts +72 -0
  26. package/dist/compute/strategies/two-phase-orient.d.ts.map +1 -0
  27. package/dist/compute/strategies/two-phase-orient.js +85 -0
  28. package/dist/compute/strategies/two-phase-orient.js.map +1 -0
  29. package/dist/constitution/types.d.ts +10 -10
  30. package/dist/container/protocol.d.ts +134 -0
  31. package/dist/container/protocol.d.ts.map +1 -0
  32. package/dist/container/protocol.js +157 -0
  33. package/dist/container/protocol.js.map +1 -0
  34. package/dist/container/runtime.d.ts +140 -0
  35. package/dist/container/runtime.d.ts.map +1 -0
  36. package/dist/container/runtime.js +256 -0
  37. package/dist/container/runtime.js.map +1 -0
  38. package/dist/events/catalogue.d.ts +46 -46
  39. package/dist/events/schemas/agent.completed.v1.d.ts +4 -4
  40. package/dist/events/schemas/agent.failed.v1.d.ts +2 -2
  41. package/dist/events/schemas/agent.hitl_resolved.v1.d.ts +2 -2
  42. package/dist/events/schemas/agent.started.v1.d.ts +2 -2
  43. package/dist/events/schemas/brain.skill.extracted.v1.d.ts +4 -4
  44. package/dist/events/schemas/cc.cost.anomaly_detected.v1.d.ts +2 -2
  45. package/dist/events/schemas/cc.cost.recorded.v1.d.ts +4 -4
  46. package/dist/events/schemas/citadel.sprint.analyzed.v1.d.ts +6 -6
  47. package/dist/events/schemas/citadel.sprint.closed.v1.d.ts +2 -2
  48. package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts +6 -6
  49. package/dist/events/schemas/forge.lead.qualified.v1.d.ts +2 -2
  50. package/dist/events/schemas/forge.outreach.sent.v1.d.ts +4 -4
  51. package/dist/events/schemas/incident.detected.v1.d.ts +2 -2
  52. package/dist/events/schemas/vauban.goal.checked.v1.d.ts +2 -2
  53. package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts +2 -2
  54. package/dist/events/schemas/vauban.tax.checked.v1.d.ts +2 -2
  55. package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts +6 -6
  56. package/dist/identity/agent-persona.d.ts +73 -0
  57. package/dist/identity/agent-persona.d.ts.map +1 -0
  58. package/dist/identity/agent-persona.js +165 -0
  59. package/dist/identity/agent-persona.js.map +1 -0
  60. package/dist/identity/persona-prompt.d.ts +25 -0
  61. package/dist/identity/persona-prompt.d.ts.map +1 -0
  62. package/dist/identity/persona-prompt.js +71 -0
  63. package/dist/identity/persona-prompt.js.map +1 -0
  64. package/dist/identity/persona-schema.d.ts +120 -0
  65. package/dist/identity/persona-schema.d.ts.map +1 -0
  66. package/dist/identity/persona-schema.js +103 -0
  67. package/dist/identity/persona-schema.js.map +1 -0
  68. package/dist/index.d.ts +41 -3
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +31 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/loop/minimal-loop.js +293 -287
  73. package/dist/memory/episodic-rrf.d.ts +114 -0
  74. package/dist/memory/episodic-rrf.d.ts.map +1 -0
  75. package/dist/memory/episodic-rrf.js +148 -0
  76. package/dist/memory/episodic-rrf.js.map +1 -0
  77. package/dist/mesh/attenuation.d.ts +78 -0
  78. package/dist/mesh/attenuation.d.ts.map +1 -0
  79. package/dist/mesh/attenuation.js +141 -0
  80. package/dist/mesh/attenuation.js.map +1 -0
  81. package/dist/mesh/delegate.d.ts +96 -0
  82. package/dist/mesh/delegate.d.ts.map +1 -0
  83. package/dist/mesh/delegate.js +172 -0
  84. package/dist/mesh/delegate.js.map +1 -0
  85. package/dist/mesh/dispatcher.d.ts +119 -0
  86. package/dist/mesh/dispatcher.d.ts.map +1 -0
  87. package/dist/mesh/dispatcher.js +207 -0
  88. package/dist/mesh/dispatcher.js.map +1 -0
  89. package/dist/mesh/index.d.ts +12 -0
  90. package/dist/mesh/index.d.ts.map +1 -0
  91. package/dist/mesh/index.js +11 -0
  92. package/dist/mesh/index.js.map +1 -0
  93. package/dist/mesh/types.d.ts +30 -0
  94. package/dist/mesh/types.d.ts.map +1 -0
  95. package/dist/mesh/types.js +11 -0
  96. package/dist/mesh/types.js.map +1 -0
  97. package/dist/orchestration/ooda/agent.d.ts.map +1 -1
  98. package/dist/orchestration/ooda/agent.js +36 -0
  99. package/dist/orchestration/ooda/agent.js.map +1 -1
  100. package/dist/orchestration/ooda/skills.d.ts +104 -0
  101. package/dist/orchestration/ooda/skills.d.ts.map +1 -1
  102. package/dist/orchestration/ooda/skills.js +106 -0
  103. package/dist/orchestration/ooda/skills.js.map +1 -1
  104. package/dist/orchestration/ooda/types.d.ts +11 -0
  105. package/dist/orchestration/ooda/types.d.ts.map +1 -1
  106. package/dist/ports/bastion-action.contract.test.d.ts +11 -0
  107. package/dist/ports/bastion-action.contract.test.d.ts.map +1 -0
  108. package/dist/ports/bastion-action.contract.test.js +238 -0
  109. package/dist/ports/bastion-action.contract.test.js.map +1 -0
  110. package/dist/ports/bastion-action.d.ts +133 -0
  111. package/dist/ports/bastion-action.d.ts.map +1 -0
  112. package/dist/ports/bastion-action.js +73 -0
  113. package/dist/ports/bastion-action.js.map +1 -0
  114. package/dist/ports/brain.d.ts +31 -0
  115. package/dist/ports/brain.d.ts.map +1 -1
  116. package/dist/ports/brain.js +115 -1
  117. package/dist/ports/brain.js.map +1 -1
  118. package/dist/ports/citadel-action.contract.test.d.ts +11 -0
  119. package/dist/ports/citadel-action.contract.test.d.ts.map +1 -0
  120. package/dist/ports/citadel-action.contract.test.js +317 -0
  121. package/dist/ports/citadel-action.contract.test.js.map +1 -0
  122. package/dist/ports/citadel-action.d.ts +111 -0
  123. package/dist/ports/citadel-action.d.ts.map +1 -0
  124. package/dist/ports/citadel-action.js +62 -0
  125. package/dist/ports/citadel-action.js.map +1 -0
  126. package/dist/ports/compliance-contract.d.ts +123 -0
  127. package/dist/ports/compliance-contract.d.ts.map +1 -0
  128. package/dist/ports/compliance-contract.js +35 -0
  129. package/dist/ports/compliance-contract.js.map +1 -0
  130. package/dist/ports/db.d.ts +38 -0
  131. package/dist/ports/db.d.ts.map +1 -1
  132. package/dist/ports/db.js +88 -1
  133. package/dist/ports/db.js.map +1 -1
  134. package/dist/ports/delegation.contract.test.d.ts +9 -0
  135. package/dist/ports/delegation.contract.test.d.ts.map +1 -0
  136. package/dist/ports/delegation.contract.test.js +337 -0
  137. package/dist/ports/delegation.contract.test.js.map +1 -0
  138. package/dist/ports/delegation.d.ts +134 -0
  139. package/dist/ports/delegation.d.ts.map +1 -0
  140. package/dist/ports/delegation.js +105 -0
  141. package/dist/ports/delegation.js.map +1 -0
  142. package/dist/ports/event-bus.d.ts +29 -0
  143. package/dist/ports/event-bus.d.ts.map +1 -1
  144. package/dist/ports/event-bus.js +106 -1
  145. package/dist/ports/event-bus.js.map +1 -1
  146. package/dist/ports/federation.contract.test.d.ts +9 -0
  147. package/dist/ports/federation.contract.test.d.ts.map +1 -0
  148. package/dist/ports/federation.contract.test.js +279 -0
  149. package/dist/ports/federation.contract.test.js.map +1 -0
  150. package/dist/ports/federation.d.ts +140 -0
  151. package/dist/ports/federation.d.ts.map +1 -0
  152. package/dist/ports/federation.js +57 -0
  153. package/dist/ports/federation.js.map +1 -0
  154. package/dist/ports/index.d.ts +28 -2
  155. package/dist/ports/index.d.ts.map +1 -1
  156. package/dist/ports/index.js +17 -2
  157. package/dist/ports/index.js.map +1 -1
  158. package/dist/ports/llm-provider.d.ts +37 -0
  159. package/dist/ports/llm-provider.d.ts.map +1 -1
  160. package/dist/ports/llm-provider.js +99 -1
  161. package/dist/ports/llm-provider.js.map +1 -1
  162. package/dist/ports/logger.d.ts +27 -0
  163. package/dist/ports/logger.d.ts.map +1 -1
  164. package/dist/ports/logger.js +87 -0
  165. package/dist/ports/logger.js.map +1 -1
  166. package/dist/ports/manifest-registry.contract.test.d.ts +9 -0
  167. package/dist/ports/manifest-registry.contract.test.d.ts.map +1 -0
  168. package/dist/ports/manifest-registry.contract.test.js +246 -0
  169. package/dist/ports/manifest-registry.contract.test.js.map +1 -0
  170. package/dist/ports/manifest-registry.d.ts +116 -0
  171. package/dist/ports/manifest-registry.d.ts.map +1 -0
  172. package/dist/ports/manifest-registry.js +79 -0
  173. package/dist/ports/manifest-registry.js.map +1 -0
  174. package/dist/ports/observability.contract.test.d.ts +12 -0
  175. package/dist/ports/observability.contract.test.d.ts.map +1 -0
  176. package/dist/ports/observability.contract.test.js +260 -0
  177. package/dist/ports/observability.contract.test.js.map +1 -0
  178. package/dist/ports/observability.d.ts +98 -0
  179. package/dist/ports/observability.d.ts.map +1 -0
  180. package/dist/ports/observability.js +59 -0
  181. package/dist/ports/observability.js.map +1 -0
  182. package/dist/ports/outcome.d.ts +26 -0
  183. package/dist/ports/outcome.d.ts.map +1 -1
  184. package/dist/ports/outcome.js +62 -1
  185. package/dist/ports/outcome.js.map +1 -1
  186. package/dist/ports/privacy.contract.test.d.ts +12 -0
  187. package/dist/ports/privacy.contract.test.d.ts.map +1 -0
  188. package/dist/ports/privacy.contract.test.js +325 -0
  189. package/dist/ports/privacy.contract.test.js.map +1 -0
  190. package/dist/ports/privacy.d.ts +132 -0
  191. package/dist/ports/privacy.d.ts.map +1 -0
  192. package/dist/ports/privacy.js +83 -0
  193. package/dist/ports/privacy.js.map +1 -0
  194. package/dist/ports/tenant-context.contract.test.d.ts +14 -0
  195. package/dist/ports/tenant-context.contract.test.d.ts.map +1 -0
  196. package/dist/ports/tenant-context.contract.test.js +352 -0
  197. package/dist/ports/tenant-context.contract.test.js.map +1 -0
  198. package/dist/ports/tenant-context.d.ts +103 -0
  199. package/dist/ports/tenant-context.d.ts.map +1 -0
  200. package/dist/ports/tenant-context.js +48 -0
  201. package/dist/ports/tenant-context.js.map +1 -0
  202. package/dist/ports/vauban-finance-action.contract.test.d.ts +11 -0
  203. package/dist/ports/vauban-finance-action.contract.test.d.ts.map +1 -0
  204. package/dist/ports/vauban-finance-action.contract.test.js +260 -0
  205. package/dist/ports/vauban-finance-action.contract.test.js.map +1 -0
  206. package/dist/ports/vauban-finance-action.d.ts +106 -0
  207. package/dist/ports/vauban-finance-action.d.ts.map +1 -0
  208. package/dist/ports/vauban-finance-action.js +60 -0
  209. package/dist/ports/vauban-finance-action.js.map +1 -0
  210. package/dist/ports/workflow-runtime.d.ts +204 -0
  211. package/dist/ports/workflow-runtime.d.ts.map +1 -0
  212. package/dist/ports/workflow-runtime.js +72 -0
  213. package/dist/ports/workflow-runtime.js.map +1 -0
  214. package/dist/proof/cert-verify.d.ts +80 -0
  215. package/dist/proof/cert-verify.d.ts.map +1 -0
  216. package/dist/proof/cert-verify.js +178 -0
  217. package/dist/proof/cert-verify.js.map +1 -0
  218. package/dist/replay/replay.d.ts.map +1 -1
  219. package/dist/replay/replay.js +5 -1
  220. package/dist/replay/replay.js.map +1 -1
  221. package/dist/retry/index.d.ts +129 -0
  222. package/dist/retry/index.d.ts.map +1 -0
  223. package/dist/retry/index.js +156 -0
  224. package/dist/retry/index.js.map +1 -0
  225. package/dist/retry/presets.d.ts +39 -0
  226. package/dist/retry/presets.d.ts.map +1 -0
  227. package/dist/retry/presets.js +69 -0
  228. package/dist/retry/presets.js.map +1 -0
  229. package/dist/skill-loop/ab-runner.d.ts +67 -0
  230. package/dist/skill-loop/ab-runner.d.ts.map +1 -0
  231. package/dist/skill-loop/ab-runner.js +160 -0
  232. package/dist/skill-loop/ab-runner.js.map +1 -0
  233. package/dist/skill-loop/adoption.d.ts +67 -0
  234. package/dist/skill-loop/adoption.d.ts.map +1 -0
  235. package/dist/skill-loop/adoption.js +126 -0
  236. package/dist/skill-loop/adoption.js.map +1 -0
  237. package/dist/skill-loop/candidate.d.ts +45 -0
  238. package/dist/skill-loop/candidate.d.ts.map +1 -0
  239. package/dist/skill-loop/candidate.js +43 -0
  240. package/dist/skill-loop/candidate.js.map +1 -0
  241. package/dist/skill-loop/evaluator.d.ts +42 -0
  242. package/dist/skill-loop/evaluator.d.ts.map +1 -0
  243. package/dist/skill-loop/evaluator.js +184 -0
  244. package/dist/skill-loop/evaluator.js.map +1 -0
  245. package/dist/skill-loop/index.d.ts +27 -0
  246. package/dist/skill-loop/index.d.ts.map +1 -0
  247. package/dist/skill-loop/index.js +27 -0
  248. package/dist/skill-loop/index.js.map +1 -0
  249. package/dist/skill-loop/reflexion-replay.d.ts +87 -0
  250. package/dist/skill-loop/reflexion-replay.d.ts.map +1 -0
  251. package/dist/skill-loop/reflexion-replay.js +110 -0
  252. package/dist/skill-loop/reflexion-replay.js.map +1 -0
  253. package/dist/skill-loop/sign-off.d.ts +88 -0
  254. package/dist/skill-loop/sign-off.d.ts.map +1 -0
  255. package/dist/skill-loop/sign-off.js +146 -0
  256. package/dist/skill-loop/sign-off.js.map +1 -0
  257. package/dist/skill-loop/value-metric.d.ts +55 -0
  258. package/dist/skill-loop/value-metric.d.ts.map +1 -0
  259. package/dist/skill-loop/value-metric.js +69 -0
  260. package/dist/skill-loop/value-metric.js.map +1 -0
  261. package/dist/skill-loop/versioning.d.ts +36 -0
  262. package/dist/skill-loop/versioning.d.ts.map +1 -0
  263. package/dist/skill-loop/versioning.js +47 -0
  264. package/dist/skill-loop/versioning.js.map +1 -0
  265. package/dist/skill-manifest/anchor.d.ts +91 -0
  266. package/dist/skill-manifest/anchor.d.ts.map +1 -0
  267. package/dist/skill-manifest/anchor.js +331 -0
  268. package/dist/skill-manifest/anchor.js.map +1 -0
  269. package/dist/skill-manifest/builder.d.ts +47 -0
  270. package/dist/skill-manifest/builder.d.ts.map +1 -0
  271. package/dist/skill-manifest/builder.js +93 -0
  272. package/dist/skill-manifest/builder.js.map +1 -0
  273. package/dist/skill-manifest/index.d.ts +13 -0
  274. package/dist/skill-manifest/index.d.ts.map +1 -0
  275. package/dist/skill-manifest/index.js +9 -0
  276. package/dist/skill-manifest/index.js.map +1 -0
  277. package/dist/skill-manifest/types.d.ts +67 -0
  278. package/dist/skill-manifest/types.d.ts.map +1 -0
  279. package/dist/skill-manifest/types.js +16 -0
  280. package/dist/skill-manifest/types.js.map +1 -0
  281. package/dist/skill-manifest/verifier.d.ts +42 -0
  282. package/dist/skill-manifest/verifier.d.ts.map +1 -0
  283. package/dist/skill-manifest/verifier.js +136 -0
  284. package/dist/skill-manifest/verifier.js.map +1 -0
  285. package/dist/skills/_secrets.d.ts +16 -0
  286. package/dist/skills/_secrets.d.ts.map +1 -0
  287. package/dist/skills/_secrets.js +20 -0
  288. package/dist/skills/_secrets.js.map +1 -0
  289. package/dist/skills/alpaca-quote.d.ts +2 -2
  290. package/dist/skills/alpaca-quote.d.ts.map +1 -1
  291. package/dist/skills/alpaca-quote.js +51 -20
  292. package/dist/skills/alpaca-quote.js.map +1 -1
  293. package/dist/skills/brain-query.d.ts +4 -4
  294. package/dist/skills/brain-store.d.ts +6 -6
  295. package/dist/skills/errors.d.ts +15 -0
  296. package/dist/skills/errors.d.ts.map +1 -1
  297. package/dist/skills/errors.js +21 -0
  298. package/dist/skills/errors.js.map +1 -1
  299. package/dist/skills/hitl-request.d.ts +2 -2
  300. package/dist/skills/index.d.ts +3 -1
  301. package/dist/skills/index.d.ts.map +1 -1
  302. package/dist/skills/index.js +4 -1
  303. package/dist/skills/index.js.map +1 -1
  304. package/dist/skills/markdown/loader.d.ts +52 -0
  305. package/dist/skills/markdown/loader.d.ts.map +1 -0
  306. package/dist/skills/markdown/loader.js +93 -0
  307. package/dist/skills/markdown/loader.js.map +1 -0
  308. package/dist/skills/markdown/schema.d.ts +432 -0
  309. package/dist/skills/markdown/schema.d.ts.map +1 -0
  310. package/dist/skills/markdown/schema.js +121 -0
  311. package/dist/skills/markdown/schema.js.map +1 -0
  312. package/dist/skills/poc-md-loader/markdown-loader.d.ts +77 -0
  313. package/dist/skills/poc-md-loader/markdown-loader.d.ts.map +1 -0
  314. package/dist/skills/poc-md-loader/markdown-loader.js +125 -0
  315. package/dist/skills/poc-md-loader/markdown-loader.js.map +1 -0
  316. package/dist/skills/poc-md-loader/runner.d.ts +24 -0
  317. package/dist/skills/poc-md-loader/runner.d.ts.map +1 -0
  318. package/dist/skills/poc-md-loader/runner.js +57 -0
  319. package/dist/skills/poc-md-loader/runner.js.map +1 -0
  320. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts +3 -0
  321. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts.map +1 -0
  322. package/dist/skills/poc-md-loader/vitest.poc.config.js +13 -0
  323. package/dist/skills/poc-md-loader/vitest.poc.config.js.map +1 -0
  324. package/dist/skills/poc-md-loader/web-search/script.d.ts +33 -0
  325. package/dist/skills/poc-md-loader/web-search/script.d.ts.map +1 -0
  326. package/dist/skills/poc-md-loader/web-search/script.js +75 -0
  327. package/dist/skills/poc-md-loader/web-search/script.js.map +1 -0
  328. package/dist/skills/record-outcome.d.ts +4 -4
  329. package/dist/skills/send-email.d.ts +2 -2
  330. package/dist/skills/send-email.d.ts.map +1 -1
  331. package/dist/skills/send-email.js +4 -3
  332. package/dist/skills/send-email.js.map +1 -1
  333. package/dist/skills/slack-notify.d.ts +4 -4
  334. package/dist/skills/slack-notify.d.ts.map +1 -1
  335. package/dist/skills/slack-notify.js +52 -21
  336. package/dist/skills/slack-notify.js.map +1 -1
  337. package/dist/skills/starknet-balance.d.ts +1 -1
  338. package/dist/skills/telegram-notify.d.ts +4 -4
  339. package/dist/skills/telegram-notify.d.ts.map +1 -1
  340. package/dist/skills/telegram-notify.js +48 -19
  341. package/dist/skills/telegram-notify.js.map +1 -1
  342. package/dist/skills/web-search.d.ts +1 -1
  343. package/dist/skills/web-search.d.ts.map +1 -1
  344. package/dist/skills/web-search.js +85 -40
  345. package/dist/skills/web-search.js.map +1 -1
  346. package/dist/telemetry/bus.d.ts +54 -0
  347. package/dist/telemetry/bus.d.ts.map +1 -0
  348. package/dist/telemetry/bus.js +159 -0
  349. package/dist/telemetry/bus.js.map +1 -0
  350. package/dist/telemetry/index.d.ts +35 -0
  351. package/dist/telemetry/index.d.ts.map +1 -0
  352. package/dist/telemetry/index.js +30 -0
  353. package/dist/telemetry/index.js.map +1 -0
  354. package/dist/telemetry/port.d.ts +121 -0
  355. package/dist/telemetry/port.d.ts.map +1 -0
  356. package/dist/telemetry/port.js +48 -0
  357. package/dist/telemetry/port.js.map +1 -0
  358. package/dist/telemetry/sinks/otlp.d.ts +45 -0
  359. package/dist/telemetry/sinks/otlp.d.ts.map +1 -0
  360. package/dist/telemetry/sinks/otlp.js +195 -0
  361. package/dist/telemetry/sinks/otlp.js.map +1 -0
  362. package/dist/telemetry/sinks/sqlite.d.ts +32 -0
  363. package/dist/telemetry/sinks/sqlite.d.ts.map +1 -0
  364. package/dist/telemetry/sinks/sqlite.js +170 -0
  365. package/dist/telemetry/sinks/sqlite.js.map +1 -0
  366. package/dist/telemetry/sinks/stdout.d.ts +22 -0
  367. package/dist/telemetry/sinks/stdout.d.ts.map +1 -0
  368. package/dist/telemetry/sinks/stdout.js +38 -0
  369. package/dist/telemetry/sinks/stdout.js.map +1 -0
  370. package/dist/testing/index.d.ts +3 -0
  371. package/dist/testing/test-brain-port.d.ts +4 -0
  372. package/dist/testing/test-brain-port.d.ts.map +1 -1
  373. package/dist/testing/test-brain-port.js +75 -20
  374. package/dist/testing/test-brain-port.js.map +1 -1
  375. package/dist/testing/test-event-bus.d.ts.map +1 -1
  376. package/dist/testing/test-event-bus.js +89 -36
  377. package/dist/testing/test-event-bus.js.map +1 -1
  378. package/dist/trace/schema.d.ts +1 -1
  379. package/dist/trace/schema.d.ts.map +1 -1
  380. package/dist/trace/schema.js +1 -1
  381. package/dist/trace/schema.js.map +1 -1
  382. package/dist/verify/formal/index.d.ts +44 -0
  383. package/dist/verify/formal/index.d.ts.map +1 -0
  384. package/dist/verify/formal/index.js +98 -0
  385. package/dist/verify/formal/index.js.map +1 -0
  386. package/dist/verify/formal/policy.d.ts +105 -0
  387. package/dist/verify/formal/policy.d.ts.map +1 -0
  388. package/dist/verify/formal/policy.js +159 -0
  389. package/dist/verify/formal/policy.js.map +1 -0
  390. package/dist/verify/formal/result.d.ts +50 -0
  391. package/dist/verify/formal/result.d.ts.map +1 -0
  392. package/dist/verify/formal/result.js +21 -0
  393. package/dist/verify/formal/result.js.map +1 -0
  394. package/dist/verify/formal/solver.d.ts +67 -0
  395. package/dist/verify/formal/solver.d.ts.map +1 -0
  396. package/dist/verify/formal/solver.js +184 -0
  397. package/dist/verify/formal/solver.js.map +1 -0
  398. package/dist/verify/formal/spec-language.d.ts +80 -0
  399. package/dist/verify/formal/spec-language.d.ts.map +1 -0
  400. package/dist/verify/formal/spec-language.js +219 -0
  401. package/dist/verify/formal/spec-language.js.map +1 -0
  402. package/docs/attestation.md +199 -0
  403. package/docs/identity.md +193 -0
  404. package/docs/telemetry/migration.md +155 -0
  405. package/docs/telemetry/overview.md +154 -0
  406. package/docs/telemetry/privacy.md +127 -0
  407. package/docs/telemetry/sinks/cc.md +155 -0
  408. package/docs/telemetry/sinks/otlp.md +146 -0
  409. package/docs/telemetry/sinks/sqlite.md +126 -0
  410. package/docs/telemetry/sinks/stdout.md +82 -0
  411. package/package.json +18 -2
  412. package/src/adapters/llm/anthropic-direct.ts +51 -0
  413. package/src/adapters/llm/cascade.ts +64 -19
  414. package/src/adapters/llm/litellm.ts +49 -0
  415. package/src/compute/difficulty-estimator.ts +111 -0
  416. package/src/compute/strategies/mixture-of-agents.ts +150 -0
  417. package/src/compute/strategies/tree-of-thoughts.ts +293 -0
  418. package/src/compute/strategies/two-phase-orient.ts +147 -0
  419. package/src/container/protocol.ts +243 -0
  420. package/src/container/runtime.ts +424 -0
  421. package/src/db/migrations/026_formal_verify_results.sql +30 -0
  422. package/src/identity/agent-persona.ts +203 -0
  423. package/src/identity/persona-prompt.ts +84 -0
  424. package/src/identity/persona-schema.ts +127 -0
  425. package/src/index.ts +368 -2
  426. package/src/memory/episodic-rrf.ts +224 -0
  427. package/src/mesh/attenuation.ts +190 -0
  428. package/src/mesh/delegate.ts +254 -0
  429. package/src/mesh/dispatcher.ts +301 -0
  430. package/src/mesh/index.ts +39 -0
  431. package/src/mesh/types.ts +31 -0
  432. package/src/orchestration/ooda/agent.ts +50 -0
  433. package/src/orchestration/ooda/skills.ts +177 -0
  434. package/src/orchestration/ooda/types.ts +12 -0
  435. package/src/ports/bastion-action.contract.test.ts +355 -0
  436. package/src/ports/bastion-action.ts +198 -0
  437. package/src/ports/brain.ts +177 -15
  438. package/src/ports/citadel-action.contract.test.ts +430 -0
  439. package/src/ports/citadel-action.ts +174 -0
  440. package/src/ports/compliance-contract.ts +191 -0
  441. package/src/ports/db.ts +98 -0
  442. package/src/ports/delegation.contract.test.ts +428 -0
  443. package/src/ports/delegation.ts +211 -0
  444. package/src/ports/event-bus.ts +133 -0
  445. package/src/ports/federation.contract.test.ts +355 -0
  446. package/src/ports/federation.ts +190 -0
  447. package/src/ports/index.ts +186 -1
  448. package/src/ports/llm-provider.ts +123 -0
  449. package/src/ports/logger.ts +104 -0
  450. package/src/ports/manifest-registry.contract.test.ts +324 -0
  451. package/src/ports/manifest-registry.ts +188 -0
  452. package/src/ports/observability.contract.test.ts +315 -0
  453. package/src/ports/observability.ts +150 -0
  454. package/src/ports/outcome.ts +69 -0
  455. package/src/ports/privacy.contract.test.ts +413 -0
  456. package/src/ports/privacy.ts +207 -0
  457. package/src/ports/tenant-context.contract.test.ts +454 -0
  458. package/src/ports/tenant-context.ts +150 -0
  459. package/src/ports/vauban-finance-action.contract.test.ts +335 -0
  460. package/src/ports/vauban-finance-action.ts +166 -0
  461. package/src/ports/workflow-runtime.ts +327 -0
  462. package/src/proof/cert-verify.ts +249 -0
  463. package/src/replay/replay.ts +11 -8
  464. package/src/retry/index.ts +227 -0
  465. package/src/retry/presets.ts +75 -0
  466. package/src/skill-loop/ab-runner.ts +196 -0
  467. package/src/skill-loop/adoption.ts +188 -0
  468. package/src/skill-loop/candidate.ts +75 -0
  469. package/src/skill-loop/evaluator.ts +238 -0
  470. package/src/skill-loop/index.ts +51 -0
  471. package/src/skill-loop/reflexion-replay.ts +173 -0
  472. package/src/skill-loop/sign-off.ts +247 -0
  473. package/src/skill-loop/value-metric.ts +120 -0
  474. package/src/skill-loop/versioning.ts +75 -0
  475. package/src/skill-manifest/anchor.ts +401 -0
  476. package/src/skill-manifest/builder.ts +129 -0
  477. package/src/skill-manifest/index.ts +18 -0
  478. package/src/skill-manifest/types.ts +72 -0
  479. package/src/skill-manifest/verifier.ts +198 -0
  480. package/src/skills/_secrets.ts +25 -0
  481. package/src/skills/alpaca-quote.ts +68 -23
  482. package/src/skills/errors.ts +30 -2
  483. package/src/skills/index.ts +19 -0
  484. package/src/skills/markdown/loader.ts +129 -0
  485. package/src/skills/markdown/schema.ts +144 -0
  486. package/src/skills/poc-md-loader/e2e-parity.test.ts +237 -0
  487. package/src/skills/poc-md-loader/markdown-loader.ts +161 -0
  488. package/src/skills/poc-md-loader/runner.ts +82 -0
  489. package/src/skills/poc-md-loader/vitest.poc.config.ts +13 -0
  490. package/src/skills/poc-md-loader/web-search/SKILL.md +42 -0
  491. package/src/skills/poc-md-loader/web-search/script.ts +109 -0
  492. package/src/skills/send-email.ts +4 -3
  493. package/src/skills/slack-notify.ts +73 -30
  494. package/src/skills/telegram-notify.ts +70 -24
  495. package/src/skills/web-search.ts +132 -50
  496. package/src/telemetry/bus.test.ts +231 -0
  497. package/src/telemetry/bus.ts +241 -0
  498. package/src/telemetry/index.ts +49 -0
  499. package/src/telemetry/port.ts +160 -0
  500. package/src/telemetry/sinks/otlp.test.ts +146 -0
  501. package/src/telemetry/sinks/otlp.ts +250 -0
  502. package/src/telemetry/sinks/sqlite.test.ts +121 -0
  503. package/src/telemetry/sinks/sqlite.ts +260 -0
  504. package/src/telemetry/sinks/stdout.test.ts +109 -0
  505. package/src/telemetry/sinks/stdout.ts +59 -0
  506. package/src/testing/test-brain-port.ts +98 -24
  507. package/src/testing/test-event-bus.ts +104 -43
  508. package/src/trace/schema.ts +1 -1
  509. package/src/verify/formal/index.ts +154 -0
  510. package/src/verify/formal/policy.ts +253 -0
  511. package/src/verify/formal/result.ts +52 -0
  512. package/src/verify/formal/solver.ts +235 -0
  513. package/src/verify/formal/spec-language.ts +274 -0
@@ -37,7 +37,12 @@ export interface BrainQueryFilters {
37
37
  // ─── Tier 1: Working memory ──────────────────────────────────────────────────
38
38
 
39
39
  export interface WorkingMemoryPort {
40
- set(runId: string, key: string, value: unknown, opts?: { ttlMs?: number }): Promise<void>;
40
+ set(
41
+ runId: string,
42
+ key: string,
43
+ value: unknown,
44
+ opts?: { ttlMs?: number }
45
+ ): Promise<void>;
41
46
  get(runId: string, key: string): Promise<unknown>;
42
47
  delete(runId: string, key: string): Promise<void>;
43
48
  }
@@ -45,8 +50,16 @@ export interface WorkingMemoryPort {
45
50
  export class InMemoryWorkingMemory implements WorkingMemoryPort {
46
51
  private store = new Map<string, { value: unknown; expiresAt: number }>();
47
52
 
48
- async set(runId: string, key: string, value: unknown, opts?: { ttlMs?: number }): Promise<void> {
49
- this.store.set(`${runId}:${key}`, { value, expiresAt: Date.now() + (opts?.ttlMs ?? 300_000) });
53
+ async set(
54
+ runId: string,
55
+ key: string,
56
+ value: unknown,
57
+ opts?: { ttlMs?: number }
58
+ ): Promise<void> {
59
+ this.store.set(`${runId}:${key}`, {
60
+ value,
61
+ expiresAt: Date.now() + (opts?.ttlMs ?? 300_000),
62
+ });
50
63
  }
51
64
 
52
65
  async get(runId: string, key: string): Promise<unknown> {
@@ -100,12 +113,12 @@ export interface EpisodicMemoryPort {
100
113
  runId: string,
101
114
  event: string,
102
115
  metadata?: Record<string, unknown>,
103
- opts?: { traceId?: string },
116
+ opts?: { traceId?: string }
104
117
  ): Promise<void>;
105
118
  since(
106
119
  agentId: string,
107
120
  sinceMs: number,
108
- opts?: { limit?: number },
121
+ opts?: { limit?: number }
109
122
  ): Promise<EpisodicMemoryEntry[]>;
110
123
  /**
111
124
  * Retrieve all episodic entries associated with a given OTel trace ID,
@@ -115,7 +128,10 @@ export interface EpisodicMemoryPort {
115
128
  * @param opts.limit - Maximum number of entries to return (default: unbounded).
116
129
  * @returns Entries matching traceId, oldest first.
117
130
  */
118
- queryByTrace(traceId: string, opts?: { limit?: number }): Promise<EpisodicMemoryEntry[]>;
131
+ queryByTrace(
132
+ traceId: string,
133
+ opts?: { limit?: number }
134
+ ): Promise<EpisodicMemoryEntry[]>;
119
135
  }
120
136
 
121
137
  export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
@@ -126,7 +142,7 @@ export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
126
142
  runId: string,
127
143
  event: string,
128
144
  metadata?: Record<string, unknown>,
129
- opts?: { traceId?: string },
145
+ opts?: { traceId?: string }
130
146
  ): Promise<void> {
131
147
  this.events.push({
132
148
  agentId,
@@ -141,7 +157,7 @@ export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
141
157
  async since(
142
158
  agentId: string,
143
159
  sinceMs: number,
144
- opts?: { limit?: number },
160
+ opts?: { limit?: number }
145
161
  ): Promise<EpisodicMemoryEntry[]> {
146
162
  const filtered = this.events
147
163
  .filter((e) => e.agentId === agentId && e.timestamp >= sinceMs)
@@ -149,7 +165,10 @@ export class InMemoryEpisodicMemory implements EpisodicMemoryPort {
149
165
  return opts?.limit ? filtered.slice(0, opts.limit) : filtered;
150
166
  }
151
167
 
152
- async queryByTrace(traceId: string, opts?: { limit?: number }): Promise<EpisodicMemoryEntry[]> {
168
+ async queryByTrace(
169
+ traceId: string,
170
+ opts?: { limit?: number }
171
+ ): Promise<EpisodicMemoryEntry[]> {
153
172
  // Insertion order is preserved (Array.filter is stable; events are pushed in order).
154
173
  const filtered = this.events.filter((e) => e.traceId === traceId);
155
174
  return opts?.limit ? filtered.slice(0, opts.limit) : filtered;
@@ -169,10 +188,15 @@ export class InMemorySemanticMemory implements SemanticMemoryPort {
169
188
  private entries: BrainEntry[] = [];
170
189
 
171
190
  async query(q: string, filters?: BrainQueryFilters): Promise<BrainEntry[]> {
172
- let results = this.entries.filter((e) => e.content.toLowerCase().includes(q.toLowerCase()));
173
- if (filters?.category) results = results.filter((e) => e.category === filters.category);
191
+ let results = this.entries.filter((e) =>
192
+ e.content.toLowerCase().includes(q.toLowerCase())
193
+ );
194
+ if (filters?.category)
195
+ results = results.filter((e) => e.category === filters.category);
174
196
  if (filters?.tags && filters.tags.length > 0) {
175
- results = results.filter((e) => e.tags?.some((t) => filters.tags?.includes(t)));
197
+ results = results.filter((e) =>
198
+ e.tags?.some((t) => filters.tags?.includes(t))
199
+ );
176
200
  }
177
201
  return filters?.limit ? results.slice(0, filters.limit) : results;
178
202
  }
@@ -207,7 +231,11 @@ export interface ProceduralMemoryPort {
207
231
  /** Register a learned skill for an agent. */
208
232
  registerSkill(agentId: string, skill: ProceduralSkill): Promise<void>;
209
233
  /** Share a skill with other agents. */
210
- shareSkill(skillName: string, fromAgentId: string, toAgentIds: string[]): Promise<void>;
234
+ shareSkill(
235
+ skillName: string,
236
+ fromAgentId: string,
237
+ toAgentIds: string[]
238
+ ): Promise<void>;
211
239
  }
212
240
 
213
241
  export class InMemoryProceduralMemory implements ProceduralMemoryPort {
@@ -232,7 +260,11 @@ export class InMemoryProceduralMemory implements ProceduralMemoryPort {
232
260
  this.skills.set(agentId, [...existing, skill]);
233
261
  }
234
262
 
235
- async shareSkill(skillName: string, fromAgentId: string, toAgentIds: string[]): Promise<void> {
263
+ async shareSkill(
264
+ skillName: string,
265
+ fromAgentId: string,
266
+ toAgentIds: string[]
267
+ ): Promise<void> {
236
268
  for (const _toAgent of toAgentIds) {
237
269
  const shared = this.shared.get(fromAgentId) ?? [];
238
270
  if (!shared.includes(skillName)) {
@@ -242,14 +274,144 @@ export class InMemoryProceduralMemory implements ProceduralMemoryPort {
242
274
  }
243
275
  }
244
276
 
277
+ // ─── Typed errors ─────────────────────────────────────────────────────────────
278
+
279
+ /**
280
+ * Thrown when the Brain API is unreachable (connection refused, DNS failure,
281
+ * timeout on connect). Callers can retry with backoff or fall back to a local cache.
282
+ */
283
+ export class BrainUnavailableError extends Error {
284
+ constructor(message: string, public readonly cause?: unknown) {
285
+ super(message);
286
+ this.name = "BrainUnavailableError";
287
+ Object.setPrototypeOf(this, new.target.prototype);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Thrown when the Brain API returns 429 (rate limit exceeded).
293
+ * Callers should retry after the delay indicated in the `retryAfterMs` field
294
+ * (extracted from the Retry-After header) or use exponential backoff.
295
+ */
296
+ export class BrainRateLimitError extends Error {
297
+ /** Retry-After delay in milliseconds. Derived from the HTTP Retry-After header. */
298
+ readonly retryAfterMs: number;
299
+
300
+ constructor(
301
+ message: string,
302
+ retryAfterMs: number,
303
+ public readonly cause?: unknown
304
+ ) {
305
+ super(message);
306
+ this.name = "BrainRateLimitError";
307
+ this.retryAfterMs = retryAfterMs;
308
+ Object.setPrototypeOf(this, new.target.prototype);
309
+ }
310
+ }
311
+
245
312
  // ─── Full BrainPort (4 tiers, additive non-breaking) ─────────────────────────
246
313
 
247
314
  export interface BrainPort {
248
315
  archiveKnowledge(entry: BrainEntryInput): Promise<BrainEntry | null>;
249
- queryKnowledge?(query: string, filters?: BrainQueryFilters): Promise<BrainEntry[]>;
316
+ queryKnowledge?(
317
+ query: string,
318
+ filters?: BrainQueryFilters
319
+ ): Promise<BrainEntry[]>;
250
320
 
251
321
  working?: WorkingMemoryPort;
252
322
  episodic?: EpisodicMemoryPort;
253
323
  semantic?: SemanticMemoryPort;
254
324
  procedural?: ProceduralMemoryPort;
255
325
  }
326
+
327
+ // ─── OTel-traced wrapper ──────────────────────────────────────────────────────
328
+
329
+ import type { Span } from "@opentelemetry/api";
330
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
331
+
332
+ const PORT_TRACER = trace.getTracer("vauban-agent-sdk.ports", "0.1.0");
333
+
334
+ /**
335
+ * Wrap any BrainPort implementation with OTel spans.
336
+ * archiveKnowledge and queryKnowledge calls each get a span with the category
337
+ * and content preview. Gracefully degrades to noop spans when no OTel SDK
338
+ * is installed.
339
+ *
340
+ * Usage:
341
+ * const raw: BrainPort = buildHttpBrain(...);
342
+ * const traced = createTracedBrainPort(raw);
343
+ * await traced.archiveKnowledge({ content: "..." }) // emits "brain.archiveKnowledge" span
344
+ */
345
+ export function createTracedBrainPort(impl: BrainPort): BrainPort {
346
+ return {
347
+ working: impl.working,
348
+ episodic: impl.episodic,
349
+ semantic: impl.semantic,
350
+ procedural: impl.procedural,
351
+
352
+ async archiveKnowledge(entry: BrainEntryInput): Promise<BrainEntry | null> {
353
+ return PORT_TRACER.startActiveSpan(
354
+ "brain.archiveKnowledge",
355
+ {
356
+ attributes: {
357
+ "brain.entry.category": entry.category ?? "unknown",
358
+ "brain.entry.content_preview": entry.content.slice(0, 200),
359
+ "brain.entry.tags": entry.tags?.join(",") ?? "",
360
+ "vauban.port.name": "brain",
361
+ },
362
+ },
363
+ async (span: Span) => {
364
+ try {
365
+ const result = await impl.archiveKnowledge(entry);
366
+ if (result) {
367
+ span.setAttribute("brain.entry.id", result.id);
368
+ }
369
+ span.setStatus({ code: SpanStatusCode.OK });
370
+ return result;
371
+ } catch (err) {
372
+ const message = err instanceof Error ? err.message : String(err);
373
+ span.setStatus({ code: SpanStatusCode.ERROR, message });
374
+ if (err instanceof Error) span.recordException(err);
375
+ throw err;
376
+ } finally {
377
+ span.end();
378
+ }
379
+ }
380
+ );
381
+ },
382
+
383
+ async queryKnowledge(
384
+ query: string,
385
+ filters?: BrainQueryFilters
386
+ ): Promise<BrainEntry[]> {
387
+ if (!impl.queryKnowledge) return [];
388
+ const qk = impl.queryKnowledge.bind(impl);
389
+ return PORT_TRACER.startActiveSpan(
390
+ "brain.queryKnowledge",
391
+ {
392
+ attributes: {
393
+ "brain.query.preview": query.slice(0, 200),
394
+ "brain.query.category": filters?.category ?? "none",
395
+ "brain.query.limit": filters?.limit ?? -1,
396
+ "vauban.port.name": "brain",
397
+ },
398
+ },
399
+ async (span: Span) => {
400
+ try {
401
+ const result = await qk(query, filters);
402
+ span.setAttribute("brain.query.result_count", result.length);
403
+ span.setStatus({ code: SpanStatusCode.OK });
404
+ return result;
405
+ } catch (err) {
406
+ const message = err instanceof Error ? err.message : String(err);
407
+ span.setStatus({ code: SpanStatusCode.ERROR, message });
408
+ if (err instanceof Error) span.recordException(err);
409
+ throw err;
410
+ } finally {
411
+ span.end();
412
+ }
413
+ }
414
+ );
415
+ },
416
+ };
417
+ }
@@ -0,0 +1,430 @@
1
+ /**
2
+ * CitadelActionPort contract tests.
3
+ *
4
+ * Applied to any CitadelActionPort implementation. Tests tiered access control,
5
+ * state transitions, and governance claim emission.
6
+ *
7
+ * Source: vauban-gouvernance/rules/ai/tiered-gates.md + MASTER-PLAN-v5.md §1.3
8
+ */
9
+
10
+ import { describe, expect, test } from "vitest";
11
+ import {
12
+ CitadelTierViolationError,
13
+ CitadelTaskRefNotFoundError,
14
+ CitadelSprintNotActiveError,
15
+ CitadelInvalidStateTransitionError,
16
+ type CitadelActionPort,
17
+ type ActionContext,
18
+ type SprintInput,
19
+ type TaskRef,
20
+ type VerificationEvidence,
21
+ type DecisionInput,
22
+ } from "./citadel-action.js";
23
+
24
+ function makeActionContext(
25
+ overrides: Partial<ActionContext> = {}
26
+ ): ActionContext {
27
+ return {
28
+ agentId: "test-agent-001",
29
+ agentTier: "T3",
30
+ runId: crypto.randomUUID(),
31
+ ...overrides,
32
+ };
33
+ }
34
+
35
+ function makeSprintInput(overrides: Partial<SprintInput> = {}): SprintInput {
36
+ return {
37
+ name: "Sprint Test",
38
+ goal: "Test sprint",
39
+ project_slug: "test-project",
40
+ start_date: new Date().toISOString(),
41
+ end_date: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
42
+ ...overrides,
43
+ };
44
+ }
45
+
46
+ function makeTaskRef(overrides: Partial<TaskRef> = {}): TaskRef {
47
+ return {
48
+ ref: "test-project:sprint-1:task-001",
49
+ project: "test-project",
50
+ sprint: "sprint-1",
51
+ task_id: "task-001",
52
+ ...overrides,
53
+ };
54
+ }
55
+
56
+ function makeVerificationEvidence(
57
+ overrides: Partial<VerificationEvidence> = {}
58
+ ): VerificationEvidence {
59
+ return {
60
+ passed: true,
61
+ evidence_text: "Verification scenario executed successfully",
62
+ evidence_hash: "abcd1234efgh5678ijkl9012mnop3456",
63
+ ...overrides,
64
+ };
65
+ }
66
+
67
+ function makeDecisionInput(
68
+ overrides: Partial<DecisionInput> = {}
69
+ ): DecisionInput {
70
+ return {
71
+ decision: "Adopt new architecture",
72
+ context: "Performance issues in current stack",
73
+ options: ["Refactor current", "Migrate to new stack", "Hybrid approach"],
74
+ chosen: "Hybrid approach",
75
+ rationale: "Balance performance and migration cost",
76
+ ...overrides,
77
+ };
78
+ }
79
+
80
+ export const citadelActionPortContract = (factory: () => CitadelActionPort) => {
81
+ describe("CitadelActionPort contract", () => {
82
+ test("createSprint requires T2+ tier", async () => {
83
+ const port = factory();
84
+ const input = makeSprintInput();
85
+ const ctx = makeActionContext({ agentTier: "T1" });
86
+
87
+ await expect(port.createSprint(input, ctx)).rejects.toThrow(
88
+ CitadelTierViolationError
89
+ );
90
+ });
91
+
92
+ test("createSprint succeeds for T2+ agents", async () => {
93
+ const port = factory();
94
+ const input = makeSprintInput();
95
+ const ctx = makeActionContext({ agentTier: "T2" });
96
+
97
+ const sprintRef = await port.createSprint(input, ctx);
98
+ expect(sprintRef.sprint_id).toBeDefined();
99
+ expect(sprintRef.project_slug).toBe(input.project_slug);
100
+ expect(sprintRef.name).toBe(input.name);
101
+ });
102
+
103
+ test("updateTaskStatus transitions task state", async () => {
104
+ const port = factory();
105
+ const taskRef = makeTaskRef();
106
+ const ctx = makeActionContext({ agentTier: "T2" });
107
+
108
+ // Transition todo → in_progress
109
+ await port.updateTaskStatus(taskRef, "in_progress", ctx);
110
+ // No throw = success
111
+
112
+ // Transition in_progress → done
113
+ await port.updateTaskStatus(taskRef, "done", ctx);
114
+ // No throw = success
115
+ });
116
+
117
+ test("updateTaskStatus blocks invalid transitions", async () => {
118
+ const port = factory();
119
+ const taskRef = makeTaskRef();
120
+ const ctx = makeActionContext({ agentTier: "T2" });
121
+
122
+ // Walk valid path: todo → in_progress → done
123
+ await port.updateTaskStatus(taskRef, "in_progress", ctx);
124
+ await port.updateTaskStatus(taskRef, "done", ctx);
125
+
126
+ // Now try invalid: done → in_progress (must throw)
127
+ await expect(
128
+ port.updateTaskStatus(taskRef, "in_progress", ctx)
129
+ ).rejects.toMatchObject({
130
+ name: "CitadelInvalidStateTransitionError",
131
+ current_status: "done",
132
+ requested_status: "in_progress",
133
+ });
134
+ });
135
+
136
+ test("sealSprint requires T3+ tier", async () => {
137
+ const port = factory();
138
+ const evidence = makeVerificationEvidence();
139
+ const ctx = makeActionContext({ agentTier: "T2" });
140
+
141
+ await expect(port.sealSprint("sprint-1", evidence, ctx)).rejects.toThrow(
142
+ CitadelTierViolationError
143
+ );
144
+ });
145
+
146
+ test("sealSprint succeeds for T3+ agents with evidence", async () => {
147
+ const port = factory();
148
+ const evidence = makeVerificationEvidence({ passed: true });
149
+ const ctx = makeActionContext({ agentTier: "T3" });
150
+
151
+ const claim = await port.sealSprint("sprint-1", evidence, ctx);
152
+ expect(claim.sprint_id).toBe("sprint-1");
153
+ expect(claim.sealed_at).toBeDefined();
154
+ expect(claim.sealed_by_agent).toBe(ctx.agentId);
155
+ expect(claim.verification_evidence_hash).toBe(evidence.evidence_hash);
156
+ });
157
+
158
+ test("sealSprint fails if sprint not active", async () => {
159
+ const port = factory();
160
+ const evidence = makeVerificationEvidence();
161
+ const ctx = makeActionContext({ agentTier: "T3" });
162
+
163
+ try {
164
+ // Attempting to seal a sprint that is not in active status
165
+ await port.sealSprint("sprint-999", evidence, ctx);
166
+ } catch (err) {
167
+ if (err instanceof CitadelSprintNotActiveError) {
168
+ expect(err.sprint_id).toBe("sprint-999");
169
+ }
170
+ }
171
+ });
172
+
173
+ test("sealSprint emits SealedSprintClaim with anchor_id", async () => {
174
+ const port = factory();
175
+ const evidence = makeVerificationEvidence();
176
+ const ctx = makeActionContext({ agentTier: "T3" });
177
+
178
+ const claim = await port.sealSprint("sprint-1", evidence, ctx);
179
+ // anchor_id is optional (Phase 1+ deferred), but test should verify if present
180
+ if (claim.anchor_id) {
181
+ expect(claim.anchor_id.length).toBeGreaterThan(0);
182
+ }
183
+ });
184
+
185
+ test("recordDecision requires T2+ tier", async () => {
186
+ const port = factory();
187
+ const decision = makeDecisionInput();
188
+ const ctx = makeActionContext({ agentTier: "T1" });
189
+
190
+ await expect(port.recordDecision(decision, ctx)).rejects.toThrow(
191
+ CitadelTierViolationError
192
+ );
193
+ });
194
+
195
+ test("recordDecision succeeds for T2+ agents", async () => {
196
+ const port = factory();
197
+ const decision = makeDecisionInput();
198
+ const ctx = makeActionContext({ agentTier: "T2" });
199
+
200
+ const claim = await port.recordDecision(decision, ctx);
201
+ expect(claim.decision_id).toBeDefined();
202
+ expect(claim.created_at).toBeDefined();
203
+ expect(claim.archived_to_brain).toBeDefined();
204
+ });
205
+
206
+ test("recordDecision T3+ triggers cascade hook", async () => {
207
+ const port = factory();
208
+ const decision = makeDecisionInput({
209
+ decision: "ADR-ECO-NNN: Architectural Decision",
210
+ });
211
+ const ctx = makeActionContext({ agentTier: "T3" });
212
+
213
+ const claim = await port.recordDecision(decision, ctx);
214
+ // T3+ should trigger cascade (optional, implementation-specific)
215
+ // Just verify claim is returned
216
+ expect(claim.decision_id).toBeDefined();
217
+ });
218
+
219
+ test("tier violation error includes required and actual tier", async () => {
220
+ const port = factory();
221
+ const input = makeSprintInput();
222
+ const ctx = makeActionContext({ agentTier: "T1" });
223
+
224
+ try {
225
+ await port.createSprint(input, ctx);
226
+ } catch (err) {
227
+ if (err instanceof CitadelTierViolationError) {
228
+ expect(err.required_tier).toBe("T2");
229
+ expect(err.actual_tier).toBe("T1");
230
+ expect(err.operation).toBeDefined();
231
+ }
232
+ }
233
+ });
234
+
235
+ test("task not found error includes task ref", async () => {
236
+ const port = factory();
237
+ const taskRef = makeTaskRef({ ref: "nonexistent:sprint-1:task-999" });
238
+ const ctx = makeActionContext({ agentTier: "T2" });
239
+
240
+ try {
241
+ await port.updateTaskStatus(taskRef, "done", ctx);
242
+ } catch (err) {
243
+ if (err instanceof CitadelTaskRefNotFoundError) {
244
+ expect(err.task_ref).toContain("nonexistent");
245
+ }
246
+ }
247
+ });
248
+
249
+ test("sprint not active error includes current status", async () => {
250
+ const port = factory();
251
+ const evidence = makeVerificationEvidence();
252
+ const ctx = makeActionContext({ agentTier: "T3" });
253
+
254
+ try {
255
+ await port.sealSprint("completed-sprint", evidence, ctx);
256
+ } catch (err) {
257
+ if (err instanceof CitadelSprintNotActiveError) {
258
+ expect(err.sprint_id).toBe("completed-sprint");
259
+ expect(err.current_status).toBeDefined();
260
+ }
261
+ }
262
+ });
263
+
264
+ test("T4 agents can seal sprints", async () => {
265
+ const port = factory();
266
+ const evidence = makeVerificationEvidence();
267
+ const ctx = makeActionContext({ agentTier: "T4" });
268
+
269
+ try {
270
+ const claim = await port.sealSprint("sprint-1", evidence, ctx);
271
+ expect(claim.sealed_by_agent).toBe(ctx.agentId);
272
+ } catch (err) {
273
+ // May fail for other reasons (sprint not found), but not tier violation
274
+ if (err instanceof CitadelTierViolationError) {
275
+ throw new Error("T4 should not have tier violation");
276
+ }
277
+ }
278
+ });
279
+ });
280
+ };
281
+
282
+ // ─── Mock implementation ──────────────────────────────────────────────────
283
+
284
+ class MockCitadelActionPort implements CitadelActionPort {
285
+ private sprintStates = new Map<
286
+ string,
287
+ {
288
+ status: "planned" | "active" | "completed";
289
+ tasks: Map<string, TaskStatus>;
290
+ }
291
+ >();
292
+ private taskStates = new Map<string, TaskStatus>();
293
+
294
+ constructor() {
295
+ // Pre-populate some sprint states
296
+ this.sprintStates.set("sprint-1", {
297
+ status: "active",
298
+ tasks: new Map([
299
+ ["test-project:sprint-1:task-001", "todo"],
300
+ ["test-project:sprint-1:task-002", "in_progress"],
301
+ ]),
302
+ });
303
+ this.sprintStates.set("completed-sprint", {
304
+ status: "completed",
305
+ tasks: new Map(),
306
+ });
307
+ }
308
+
309
+ async createSprint(
310
+ input: SprintInput,
311
+ ctx: ActionContext
312
+ ): Promise<SprintRef> {
313
+ // T2+ only
314
+ if (ctx.agentTier === "T1") {
315
+ throw new CitadelTierViolationError(
316
+ `T1 agents cannot create sprints`,
317
+ "T2",
318
+ ctx.agentTier,
319
+ "createSprint"
320
+ );
321
+ }
322
+
323
+ const sprintId = `sprint-${Math.floor(Math.random() * 10000)}`;
324
+ this.sprintStates.set(sprintId, {
325
+ status: "planned",
326
+ tasks: new Map(),
327
+ });
328
+
329
+ return {
330
+ sprint_id: sprintId,
331
+ project_slug: input.project_slug,
332
+ name: input.name,
333
+ created_at: new Date(),
334
+ };
335
+ }
336
+
337
+ async updateTaskStatus(
338
+ ref: TaskRef,
339
+ status: TaskStatus,
340
+ ctx: ActionContext
341
+ ): Promise<void> {
342
+ // Check if task exists
343
+ if (!this.taskStates.has(ref.ref) && !ref.ref.startsWith("test-project")) {
344
+ throw new CitadelTaskRefNotFoundError(ref.ref);
345
+ }
346
+
347
+ // Get current status
348
+ const currentStatus = this.taskStates.get(ref.ref) || "todo";
349
+
350
+ // Validate state transitions
351
+ const validTransitions: Record<TaskStatus, TaskStatus[]> = {
352
+ todo: ["in_progress", "blocked", "rejected"],
353
+ in_progress: ["done", "blocked", "rejected"],
354
+ done: ["blocked", "rejected"],
355
+ blocked: ["in_progress", "rejected"],
356
+ rejected: [],
357
+ };
358
+
359
+ if (!validTransitions[currentStatus]?.includes(status)) {
360
+ throw new CitadelInvalidStateTransitionError(currentStatus, status);
361
+ }
362
+
363
+ this.taskStates.set(ref.ref, status);
364
+ }
365
+
366
+ async sealSprint(
367
+ sprintId: string,
368
+ evidence: VerificationEvidence,
369
+ ctx: ActionContext
370
+ ): Promise<SealedSprintClaim> {
371
+ // T3+ only
372
+ if (ctx.agentTier !== "T3" && ctx.agentTier !== "T4") {
373
+ throw new CitadelTierViolationError(
374
+ `${ctx.agentTier} agents cannot seal sprints`,
375
+ "T3",
376
+ ctx.agentTier,
377
+ "sealSprint"
378
+ );
379
+ }
380
+
381
+ // Check if sprint exists and is active
382
+ const sprintState = this.sprintStates.get(sprintId);
383
+ if (!sprintState) {
384
+ throw new CitadelSprintNotActiveError(sprintId, "not_found");
385
+ }
386
+
387
+ if (sprintState.status !== "active") {
388
+ throw new CitadelSprintNotActiveError(sprintId, sprintState.status);
389
+ }
390
+
391
+ // Update sprint status to completed
392
+ sprintState.status = "completed";
393
+
394
+ return {
395
+ sprint_id: sprintId,
396
+ sealed_at: new Date(),
397
+ verification_evidence_hash: evidence.evidence_hash,
398
+ sealed_by_agent: ctx.agentId,
399
+ anchor_id: `anchor-${crypto.randomUUID()}`,
400
+ };
401
+ }
402
+
403
+ async recordDecision(
404
+ decision: DecisionInput,
405
+ ctx: ActionContext
406
+ ): Promise<DecisionClaim> {
407
+ // T2+ only
408
+ if (ctx.agentTier === "T1") {
409
+ throw new CitadelTierViolationError(
410
+ `T1 agents cannot record decisions`,
411
+ "T2",
412
+ ctx.agentTier,
413
+ "recordDecision"
414
+ );
415
+ }
416
+
417
+ const cascade = ctx.agentTier === "T3" || ctx.agentTier === "T4";
418
+
419
+ return {
420
+ decision_id: `decision-${crypto.randomUUID()}`,
421
+ created_at: new Date(),
422
+ archived_to_brain: true,
423
+ cascade_triggered: cascade,
424
+ };
425
+ }
426
+ }
427
+
428
+ // ─── Default contract application ──────────────────────────────────────────
429
+
430
+ citadelActionPortContract(() => new MockCitadelActionPort());