@stigmer/server 3.21.0 → 3.22.1-dev.20260922095755

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 (383) hide show
  1. package/dist/authorization/authorizer.d.ts +4 -8
  2. package/dist/authorization/authorizer.d.ts.map +1 -1
  3. package/dist/authorization/authorizer.js +5 -9
  4. package/dist/authorization/authorizer.js.map +1 -1
  5. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  6. package/dist/authorization/derived-tuples.js +10 -25
  7. package/dist/authorization/derived-tuples.js.map +1 -1
  8. package/dist/authorization/evaluator.d.ts +13 -8
  9. package/dist/authorization/evaluator.d.ts.map +1 -1
  10. package/dist/authorization/evaluator.js +4 -20
  11. package/dist/authorization/evaluator.js.map +1 -1
  12. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  13. package/dist/authorization/list-read-scope.js +24 -20
  14. package/dist/authorization/list-read-scope.js.map +1 -1
  15. package/dist/authorization/model/agent.d.ts.map +1 -1
  16. package/dist/authorization/model/agent.js +4 -5
  17. package/dist/authorization/model/agent.js.map +1 -1
  18. package/dist/authorization/model/agent_instance.d.ts.map +1 -1
  19. package/dist/authorization/model/agent_instance.js +2 -2
  20. package/dist/authorization/model/agent_instance.js.map +1 -1
  21. package/dist/authorization/model/mcp_server.d.ts.map +1 -1
  22. package/dist/authorization/model/mcp_server.js +2 -2
  23. package/dist/authorization/model/mcp_server.js.map +1 -1
  24. package/dist/authorization/model/organization.d.ts.map +1 -1
  25. package/dist/authorization/model/organization.js +2 -0
  26. package/dist/authorization/model/organization.js.map +1 -1
  27. package/dist/authorization/model/plugin.d.ts.map +1 -1
  28. package/dist/authorization/model/plugin.js +3 -4
  29. package/dist/authorization/model/plugin.js.map +1 -1
  30. package/dist/authorization/model/rewrite.d.ts +8 -10
  31. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  32. package/dist/authorization/model/rewrite.js +0 -3
  33. package/dist/authorization/model/rewrite.js.map +1 -1
  34. package/dist/authorization/model/skill.d.ts.map +1 -1
  35. package/dist/authorization/model/skill.js +2 -2
  36. package/dist/authorization/model/skill.js.map +1 -1
  37. package/dist/authorization/model/workflow.d.ts.map +1 -1
  38. package/dist/authorization/model/workflow.js +2 -2
  39. package/dist/authorization/model/workflow.js.map +1 -1
  40. package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
  41. package/dist/authorization/model/workflow_instance.js +2 -2
  42. package/dist/authorization/model/workflow_instance.js.map +1 -1
  43. package/dist/authorization/organization-directory.d.ts.map +1 -1
  44. package/dist/authorization/organization-directory.js +2 -3
  45. package/dist/authorization/organization-directory.js.map +1 -1
  46. package/dist/authorization/store-test-kit.d.ts +0 -6
  47. package/dist/authorization/store-test-kit.d.ts.map +1 -1
  48. package/dist/authorization/store-test-kit.js +16 -62
  49. package/dist/authorization/store-test-kit.js.map +1 -1
  50. package/dist/authorization/tuples.d.ts +13 -32
  51. package/dist/authorization/tuples.d.ts.map +1 -1
  52. package/dist/authorization/tuples.js +3 -11
  53. package/dist/authorization/tuples.js.map +1 -1
  54. package/dist/domain/agent/controller.d.ts.map +1 -1
  55. package/dist/domain/agent/controller.js +6 -4
  56. package/dist/domain/agent/controller.js.map +1 -1
  57. package/dist/domain/agentchannel/controller.d.ts.map +1 -1
  58. package/dist/domain/agentchannel/controller.js +9 -2
  59. package/dist/domain/agentchannel/controller.js.map +1 -1
  60. package/dist/domain/agentchannel/steps.d.ts +19 -0
  61. package/dist/domain/agentchannel/steps.d.ts.map +1 -1
  62. package/dist/domain/agentchannel/steps.js +32 -0
  63. package/dist/domain/agentchannel/steps.js.map +1 -1
  64. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  65. package/dist/domain/agentexecution/controller.js +3 -1
  66. package/dist/domain/agentexecution/controller.js.map +1 -1
  67. package/dist/domain/agentinstance/controller.d.ts +5 -5
  68. package/dist/domain/agentinstance/controller.d.ts.map +1 -1
  69. package/dist/domain/agentinstance/controller.js +9 -5
  70. package/dist/domain/agentinstance/controller.js.map +1 -1
  71. package/dist/domain/agentinstance/steps.d.ts +43 -8
  72. package/dist/domain/agentinstance/steps.d.ts.map +1 -1
  73. package/dist/domain/agentinstance/steps.js +71 -8
  74. package/dist/domain/agentinstance/steps.js.map +1 -1
  75. package/dist/domain/agentshare/constants.d.ts +6 -11
  76. package/dist/domain/agentshare/constants.d.ts.map +1 -1
  77. package/dist/domain/agentshare/constants.js +8 -16
  78. package/dist/domain/agentshare/constants.js.map +1 -1
  79. package/dist/domain/agentshare/controller.d.ts.map +1 -1
  80. package/dist/domain/agentshare/controller.js +10 -2
  81. package/dist/domain/agentshare/controller.js.map +1 -1
  82. package/dist/domain/agentshare/steps.d.ts +61 -10
  83. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  84. package/dist/domain/agentshare/steps.js +121 -117
  85. package/dist/domain/agentshare/steps.js.map +1 -1
  86. package/dist/domain/artifact/controller.js +21 -25
  87. package/dist/domain/artifact/controller.js.map +1 -1
  88. package/dist/domain/channelapp/controller.d.ts.map +1 -1
  89. package/dist/domain/channelapp/controller.js +2 -0
  90. package/dist/domain/channelapp/controller.js.map +1 -1
  91. package/dist/domain/environment/controller.d.ts.map +1 -1
  92. package/dist/domain/environment/controller.js +4 -3
  93. package/dist/domain/environment/controller.js.map +1 -1
  94. package/dist/domain/executioncontext/controller.d.ts.map +1 -1
  95. package/dist/domain/executioncontext/controller.js +4 -1
  96. package/dist/domain/executioncontext/controller.js.map +1 -1
  97. package/dist/domain/executioncontext/steps.d.ts.map +1 -1
  98. package/dist/domain/executioncontext/steps.js +2 -1
  99. package/dist/domain/executioncontext/steps.js.map +1 -1
  100. package/dist/domain/mcpserver/connect.d.ts.map +1 -1
  101. package/dist/domain/mcpserver/connect.js +8 -7
  102. package/dist/domain/mcpserver/connect.js.map +1 -1
  103. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  104. package/dist/domain/mcpserver/controller.js +5 -4
  105. package/dist/domain/mcpserver/controller.js.map +1 -1
  106. package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
  107. package/dist/domain/mcpserver/start-connect.js +8 -7
  108. package/dist/domain/mcpserver/start-connect.js.map +1 -1
  109. package/dist/domain/memory/controller.d.ts.map +1 -1
  110. package/dist/domain/memory/controller.js +6 -1
  111. package/dist/domain/memory/controller.js.map +1 -1
  112. package/dist/domain/memory/steps.d.ts +23 -0
  113. package/dist/domain/memory/steps.d.ts.map +1 -1
  114. package/dist/domain/memory/steps.js +35 -0
  115. package/dist/domain/memory/steps.js.map +1 -1
  116. package/dist/domain/oauthapp/controller.d.ts.map +1 -1
  117. package/dist/domain/oauthapp/controller.js +2 -0
  118. package/dist/domain/oauthapp/controller.js.map +1 -1
  119. package/dist/domain/plugin/controller.d.ts.map +1 -1
  120. package/dist/domain/plugin/controller.js +6 -27
  121. package/dist/domain/plugin/controller.js.map +1 -1
  122. package/dist/domain/plugin/push.d.ts +7 -5
  123. package/dist/domain/plugin/push.d.ts.map +1 -1
  124. package/dist/domain/plugin/push.js +8 -14
  125. package/dist/domain/plugin/push.js.map +1 -1
  126. package/dist/domain/schedule/controller.d.ts.map +1 -1
  127. package/dist/domain/schedule/controller.js +10 -2
  128. package/dist/domain/schedule/controller.js.map +1 -1
  129. package/dist/domain/schedule/steps.d.ts +19 -0
  130. package/dist/domain/schedule/steps.d.ts.map +1 -1
  131. package/dist/domain/schedule/steps.js +32 -0
  132. package/dist/domain/schedule/steps.js.map +1 -1
  133. package/dist/domain/session/controller.d.ts.map +1 -1
  134. package/dist/domain/session/controller.js +3 -2
  135. package/dist/domain/session/controller.js.map +1 -1
  136. package/dist/domain/session/steps.d.ts +8 -9
  137. package/dist/domain/session/steps.d.ts.map +1 -1
  138. package/dist/domain/session/steps.js +17 -21
  139. package/dist/domain/session/steps.js.map +1 -1
  140. package/dist/domain/skill/controller.d.ts.map +1 -1
  141. package/dist/domain/skill/controller.js +8 -19
  142. package/dist/domain/skill/controller.js.map +1 -1
  143. package/dist/domain/workflow/agent-call-references.d.ts +54 -0
  144. package/dist/domain/workflow/agent-call-references.d.ts.map +1 -0
  145. package/dist/domain/workflow/agent-call-references.js +97 -0
  146. package/dist/domain/workflow/agent-call-references.js.map +1 -0
  147. package/dist/domain/workflow/controller.d.ts.map +1 -1
  148. package/dist/domain/workflow/controller.js +44 -113
  149. package/dist/domain/workflow/controller.js.map +1 -1
  150. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
  151. package/dist/domain/workflow/validation/task-config-constraints.d.ts +10 -1
  152. package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
  153. package/dist/domain/workflow/validation/task-config-constraints.js +3 -2
  154. package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
  155. package/dist/domain/workflow/version-resolution.d.ts +5 -0
  156. package/dist/domain/workflow/version-resolution.d.ts.map +1 -0
  157. package/dist/domain/workflow/version-resolution.js +113 -0
  158. package/dist/domain/workflow/version-resolution.js.map +1 -0
  159. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  160. package/dist/domain/workflowexecution/controller.js +4 -2
  161. package/dist/domain/workflowexecution/controller.js.map +1 -1
  162. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  163. package/dist/domain/workflowinstance/controller.js +9 -5
  164. package/dist/domain/workflowinstance/controller.js.map +1 -1
  165. package/dist/domain/workflowinstance/steps.d.ts +20 -0
  166. package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
  167. package/dist/domain/workflowinstance/steps.js +39 -0
  168. package/dist/domain/workflowinstance/steps.js.map +1 -1
  169. package/dist/extensions/authorization-queries.d.ts +6 -5
  170. package/dist/extensions/authorization-queries.d.ts.map +1 -1
  171. package/dist/extensions/identity.d.ts +19 -0
  172. package/dist/extensions/identity.d.ts.map +1 -1
  173. package/dist/extensions/identity.js +22 -3
  174. package/dist/extensions/identity.js.map +1 -1
  175. package/dist/extensions/list-read-scope.d.ts +42 -8
  176. package/dist/extensions/list-read-scope.d.ts.map +1 -1
  177. package/dist/extensions/list-read-scope.js +13 -2
  178. package/dist/extensions/list-read-scope.js.map +1 -1
  179. package/dist/extensions/resource-authorization.d.ts +3 -2
  180. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  181. package/dist/index.d.ts +1 -1
  182. package/dist/index.d.ts.map +1 -1
  183. package/dist/index.js.map +1 -1
  184. package/dist/pipeline/apiresource-meta.d.ts +12 -3
  185. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  186. package/dist/pipeline/apiresource-meta.js +21 -10
  187. package/dist/pipeline/apiresource-meta.js.map +1 -1
  188. package/dist/pipeline/steps/authorization-tuples.d.ts +9 -3
  189. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  190. package/dist/pipeline/steps/authorization-tuples.js +9 -11
  191. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  192. package/dist/pipeline/steps/authorize-resolved-target.d.ts +88 -0
  193. package/dist/pipeline/steps/authorize-resolved-target.d.ts.map +1 -0
  194. package/dist/pipeline/steps/authorize-resolved-target.js +36 -0
  195. package/dist/pipeline/steps/authorize-resolved-target.js.map +1 -0
  196. package/dist/pipeline/steps/authorize.d.ts +27 -0
  197. package/dist/pipeline/steps/authorize.d.ts.map +1 -1
  198. package/dist/pipeline/steps/authorize.js +49 -10
  199. package/dist/pipeline/steps/authorize.js.map +1 -1
  200. package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
  201. package/dist/pipeline/steps/guard-memory-capture.js +2 -1
  202. package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
  203. package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
  204. package/dist/pipeline/steps/guard-reserved-labels.js +6 -7
  205. package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
  206. package/dist/pipeline/steps/helpers.d.ts +9 -5
  207. package/dist/pipeline/steps/helpers.d.ts.map +1 -1
  208. package/dist/pipeline/steps/helpers.js +11 -15
  209. package/dist/pipeline/steps/helpers.js.map +1 -1
  210. package/dist/pipeline/steps/references.d.ts +178 -20
  211. package/dist/pipeline/steps/references.d.ts.map +1 -1
  212. package/dist/pipeline/steps/references.js +344 -43
  213. package/dist/pipeline/steps/references.js.map +1 -1
  214. package/dist/pipeline/steps/version-history.d.ts +11 -0
  215. package/dist/pipeline/steps/version-history.d.ts.map +1 -1
  216. package/dist/pipeline/steps/version-history.js +26 -0
  217. package/dist/pipeline/steps/version-history.js.map +1 -1
  218. package/dist/query/search/controller.js +0 -1
  219. package/dist/query/search/controller.js.map +1 -1
  220. package/dist/query/search/criteria.d.ts +1 -5
  221. package/dist/query/search/criteria.d.ts.map +1 -1
  222. package/dist/query/search/criteria.js +3 -13
  223. package/dist/query/search/criteria.js.map +1 -1
  224. package/dist/query/search/handler.d.ts +5 -4
  225. package/dist/query/search/handler.d.ts.map +1 -1
  226. package/dist/query/search/handler.js +7 -6
  227. package/dist/query/search/handler.js.map +1 -1
  228. package/dist/query/search/query-store.d.ts.map +1 -1
  229. package/dist/query/search/query-store.js +0 -2
  230. package/dist/query/search/query-store.js.map +1 -1
  231. package/dist/store/interface.d.ts +3 -6
  232. package/dist/store/interface.d.ts.map +1 -1
  233. package/dist/store/interface.js.map +1 -1
  234. package/dist/store/postgres/migrations.d.ts +3 -1
  235. package/dist/store/postgres/migrations.d.ts.map +1 -1
  236. package/dist/store/postgres/migrations.js +35 -1
  237. package/dist/store/postgres/migrations.js.map +1 -1
  238. package/dist/store/postgres/store.d.ts.map +1 -1
  239. package/dist/store/postgres/store.js +4 -9
  240. package/dist/store/postgres/store.js.map +1 -1
  241. package/dist/store/public-visibility-retired.d.ts +67 -0
  242. package/dist/store/public-visibility-retired.d.ts.map +1 -0
  243. package/dist/store/public-visibility-retired.js +55 -0
  244. package/dist/store/public-visibility-retired.js.map +1 -0
  245. package/dist/store/sqlite/migrations.d.ts +3 -1
  246. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  247. package/dist/store/sqlite/migrations.js +36 -1
  248. package/dist/store/sqlite/migrations.js.map +1 -1
  249. package/dist/store/sqlite/store.d.ts.map +1 -1
  250. package/dist/store/sqlite/store.js +4 -8
  251. package/dist/store/sqlite/store.js.map +1 -1
  252. package/package.json +6 -6
  253. package/src/authorization/README.md +24 -26
  254. package/src/authorization/__tests__/authorizer.test.ts +10 -9
  255. package/src/authorization/__tests__/derived-tuples.test.ts +4 -11
  256. package/src/authorization/__tests__/evaluator.test.ts +14 -73
  257. package/src/authorization/__tests__/facts.test.ts +2 -2
  258. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +6 -98
  259. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +4 -61
  260. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +1 -21
  261. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +1 -25
  262. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +1 -3
  263. package/src/authorization/__tests__/list-read-scope.test.ts +41 -29
  264. package/src/authorization/__tests__/skip-lane-inventory.test.ts +160 -0
  265. package/src/authorization/__tests__/store-tests.test.ts +1 -6
  266. package/src/authorization/__tests__/tuples.test.ts +12 -11
  267. package/src/authorization/__tests__/wire-permissions.test.ts +5 -5
  268. package/src/authorization/authorizer.ts +4 -9
  269. package/src/authorization/derived-tuples.ts +14 -31
  270. package/src/authorization/evaluator.ts +15 -44
  271. package/src/authorization/list-read-scope.ts +27 -22
  272. package/src/authorization/model/__tests__/registry.test.ts +2 -0
  273. package/src/authorization/model/agent.ts +2 -5
  274. package/src/authorization/model/agent_instance.ts +0 -2
  275. package/src/authorization/model/mcp_server.ts +0 -2
  276. package/src/authorization/model/organization.ts +2 -0
  277. package/src/authorization/model/plugin.ts +1 -4
  278. package/src/authorization/model/rewrite.ts +8 -13
  279. package/src/authorization/model/skill.ts +0 -2
  280. package/src/authorization/model/workflow.ts +0 -2
  281. package/src/authorization/model/workflow_instance.ts +0 -2
  282. package/src/authorization/organization-directory.ts +1 -3
  283. package/src/authorization/store-test-kit.ts +16 -75
  284. package/src/authorization/tuples.ts +16 -39
  285. package/src/domain/agent/__tests__/agent.test.ts +11 -4
  286. package/src/domain/agent/controller.ts +17 -7
  287. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +223 -48
  288. package/src/domain/agentchannel/__tests__/create-authorization.test.ts +58 -0
  289. package/src/domain/agentchannel/controller.ts +25 -1
  290. package/src/domain/agentchannel/steps.ts +40 -0
  291. package/src/domain/agentexecution/controller.ts +6 -1
  292. package/src/domain/agentinstance/__tests__/create-authorization.composed.test.ts +243 -0
  293. package/src/domain/agentinstance/__tests__/create-authorization.test.ts +144 -0
  294. package/src/domain/agentinstance/controller.ts +30 -17
  295. package/src/domain/agentinstance/steps.ts +82 -8
  296. package/src/domain/agentshare/__tests__/agentshare.test.ts +196 -172
  297. package/src/domain/agentshare/__tests__/create-authorization.test.ts +71 -0
  298. package/src/domain/agentshare/__tests__/member-audience.test.ts +113 -0
  299. package/src/domain/agentshare/constants.ts +14 -26
  300. package/src/domain/agentshare/controller.ts +27 -1
  301. package/src/domain/agentshare/steps.ts +168 -155
  302. package/src/domain/artifact/controller.ts +18 -22
  303. package/src/domain/channelapp/controller.ts +10 -0
  304. package/src/domain/environment/controller.ts +15 -8
  305. package/src/domain/executioncontext/__tests__/executioncontext.test.ts +1 -0
  306. package/src/domain/executioncontext/controller.ts +15 -1
  307. package/src/domain/executioncontext/steps.ts +2 -1
  308. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +115 -28
  309. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +53 -18
  310. package/src/domain/mcpserver/connect.ts +11 -10
  311. package/src/domain/mcpserver/controller.ts +19 -13
  312. package/src/domain/mcpserver/start-connect.ts +17 -11
  313. package/src/domain/memory/__tests__/create-authorization.test.ts +59 -0
  314. package/src/domain/memory/controller.ts +11 -0
  315. package/src/domain/memory/steps.ts +41 -0
  316. package/src/domain/oauthapp/controller.ts +10 -0
  317. package/src/domain/plugin/controller.ts +23 -44
  318. package/src/domain/plugin/push.ts +8 -16
  319. package/src/domain/schedule/__tests__/create-authorization.test.ts +58 -0
  320. package/src/domain/schedule/controller.ts +26 -1
  321. package/src/domain/schedule/steps.ts +45 -2
  322. package/src/domain/session/controller.ts +12 -4
  323. package/src/domain/session/steps.ts +24 -32
  324. package/src/domain/skill/controller.ts +24 -30
  325. package/src/domain/workflow/__tests__/agent-call-references.test.ts +222 -0
  326. package/src/domain/workflow/agent-call-references.ts +157 -0
  327. package/src/domain/workflow/controller.ts +86 -155
  328. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
  329. package/src/domain/workflow/validation/task-config-constraints.ts +7 -3
  330. package/src/domain/workflow/version-resolution.ts +166 -0
  331. package/src/domain/workflowexecution/controller.ts +7 -2
  332. package/src/domain/workflowinstance/__tests__/create-authorization.test.ts +109 -0
  333. package/src/domain/workflowinstance/controller.ts +25 -12
  334. package/src/domain/workflowinstance/steps.ts +49 -1
  335. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +32 -19
  336. package/src/extensions/__tests__/composed-support.ts +38 -4
  337. package/src/extensions/__tests__/extension-composition.test.ts +4 -4
  338. package/src/extensions/__tests__/identity.test.ts +44 -1
  339. package/src/extensions/__tests__/list-read-scope-composed.test.ts +96 -7
  340. package/src/extensions/__tests__/list-read-scope.test.ts +63 -0
  341. package/src/extensions/authorization-queries.ts +6 -5
  342. package/src/extensions/identity.ts +23 -5
  343. package/src/extensions/list-read-scope.ts +48 -8
  344. package/src/extensions/resource-authorization.ts +3 -5
  345. package/src/index.ts +0 -1
  346. package/src/pipeline/__tests__/supports-visibility.test.ts +112 -0
  347. package/src/pipeline/apiresource-meta.ts +21 -10
  348. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +18 -31
  349. package/src/pipeline/steps/__tests__/authorize-resolved-target.test.ts +285 -0
  350. package/src/pipeline/steps/__tests__/references.test.ts +703 -0
  351. package/src/pipeline/steps/authorization-tuples.ts +9 -11
  352. package/src/pipeline/steps/authorize-resolved-target.ts +129 -0
  353. package/src/pipeline/steps/authorize.ts +70 -13
  354. package/src/pipeline/steps/guard-memory-capture.ts +2 -1
  355. package/src/pipeline/steps/guard-reserved-labels.ts +6 -9
  356. package/src/pipeline/steps/helpers.ts +11 -15
  357. package/src/pipeline/steps/references.ts +578 -70
  358. package/src/pipeline/steps/version-history.ts +34 -0
  359. package/src/query/search/__tests__/criteria.test.ts +0 -4
  360. package/src/query/search/__tests__/query-store.test.ts +11 -40
  361. package/src/query/search/controller.ts +0 -1
  362. package/src/query/search/criteria.ts +0 -14
  363. package/src/query/search/handler.ts +6 -7
  364. package/src/query/search/query-store.ts +0 -2
  365. package/src/store/__tests__/public-visibility-retired.test.ts +127 -0
  366. package/src/store/__tests__/store-contract.ts +6 -51
  367. package/src/store/interface.ts +3 -6
  368. package/src/store/postgres/__tests__/migrations.test.ts +187 -6
  369. package/src/store/postgres/__tests__/store-contract.test.ts +0 -2
  370. package/src/store/postgres/migrations.ts +48 -1
  371. package/src/store/postgres/store.ts +4 -11
  372. package/src/store/public-visibility-retired.ts +119 -0
  373. package/src/store/sqlite/__tests__/migrations.test.ts +191 -5
  374. package/src/store/sqlite/migrations.ts +45 -1
  375. package/src/store/sqlite/store.ts +4 -10
  376. package/dist/pipeline/steps/visibility-gates.d.ts +0 -27
  377. package/dist/pipeline/steps/visibility-gates.d.ts.map +0 -1
  378. package/dist/pipeline/steps/visibility-gates.js +0 -139
  379. package/dist/pipeline/steps/visibility-gates.js.map +0 -1
  380. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +0 -98
  381. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +0 -52
  382. package/src/pipeline/steps/__tests__/visibility-gates.test.ts +0 -187
  383. package/src/pipeline/steps/visibility-gates.ts +0 -174
@@ -45,7 +45,6 @@ import {
45
45
  ApiResourceKind,
46
46
  ApiResourceKindSchema,
47
47
  } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
48
- import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
49
48
  import type {
50
49
  ApiResourceReference,
51
50
  UpdateVisibilityInput,
@@ -71,14 +70,14 @@ import { callerIdentityOf } from "../../pipeline/interceptors/auth.js";
71
70
  import { RequestContext } from "../../pipeline/request-context.js";
72
71
  import {
73
72
  authorizeDirect,
74
- authorizeResolvedResource,
75
73
  newAuthorizeStep,
76
74
  } from "../../pipeline/steps/authorize.js";
77
- import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
78
75
  import {
79
- newAuthorizeVisibilityTransitionStep,
80
- newGuardPublicVisibilityStep,
81
- } from "../../pipeline/steps/visibility-gates.js";
76
+ loadedTargetAsMethod,
77
+ newAuthorizeResolvedTargetStep,
78
+ } from "../../pipeline/steps/authorize-resolved-target.js";
79
+ import { versionHistoryTarget } from "../../pipeline/steps/version-history.js";
80
+ import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
82
81
  import { newBuildUpdateStateStep } from "../../pipeline/steps/build-update-state.js";
83
82
  import {
84
83
  setAuditFieldsForUpdate,
@@ -90,10 +89,7 @@ import {
90
89
  newExtractResourceIdStep,
91
90
  newLoadExistingForDeleteStep,
92
91
  } from "../../pipeline/steps/delete.js";
93
- import {
94
- findResourceBySlug,
95
- requireOrgForReference,
96
- } from "../../pipeline/steps/helpers.js";
92
+ import { findResourceBySlug } from "../../pipeline/steps/helpers.js";
97
93
  import {
98
94
  newDeleteSearchIndexStep,
99
95
  newIndexSearchStep,
@@ -112,7 +108,16 @@ import {
112
108
  TARGET_RESOURCE_KEY,
113
109
  newLoadTargetStep,
114
110
  } from "../../pipeline/steps/load-target.js";
115
- import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
111
+ import {
112
+ collectSpecReferences,
113
+ newGuardReferenceFloorOnEscalationStep,
114
+ newNormalizeReferencesStep,
115
+ newValidateReferencesStep,
116
+ } from "../../pipeline/steps/references.js";
117
+ import {
118
+ collectAgentCallReferences,
119
+ newValidateAgentCallReferencesStep,
120
+ } from "./agent-call-references.js";
116
121
  import {
117
122
  newCleanupIamPoliciesStep,
118
123
  newCreateAuthorizationTuplesStep,
@@ -150,6 +155,7 @@ import {
150
155
  newValidateWorkflowSpecStep,
151
156
  truncateHash,
152
157
  } from "./steps.js";
158
+ import { newLoadWorkflowByReferenceStep } from "./version-resolution.js";
153
159
  import type { WorkflowInstanceCreatorProvider } from "./steps.js";
154
160
 
155
161
  export interface WorkflowControllerDeps {
@@ -192,7 +198,7 @@ export function registerWorkflowServices(
192
198
  });
193
199
  router.service(WorkflowQueryController, {
194
200
  get: (id, ctx) => get(deps, id, ctx),
195
- getByReference: (ref) => getByReference(deps, ref),
201
+ getByReference: (ref, ctx) => getByReference(deps, ref, ctx),
196
202
  listVersions: (input, ctx) => listVersions(deps, input, ctx),
197
203
  getVersion: (input, ctx) => getVersion(deps, input, callerIdentityOf(ctx)),
198
204
  });
@@ -237,9 +243,10 @@ async function createWorkflow(
237
243
  .addStep(newResolveSlugStep())
238
244
  .addStep(newCheckDuplicateStep(deps.store))
239
245
  .addStep(newBuildNewStateStep())
240
- .addStep(newGuardPublicVisibilityStep(deps.authorizer))
241
246
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
242
247
  .addStep(newNormalizeReferencesStep())
248
+ .addStep(newValidateReferencesStep(deps.store))
249
+ .addStep(newValidateAgentCallReferencesStep(deps.store))
243
250
  .addStep(newPopulateServerlessValidationStep(deps.logger))
244
251
  .addStep(newComputeVersionHashStep(deps.logger))
245
252
  .addStep(newPopulateVersionHashStep(true))
@@ -304,6 +311,8 @@ async function update(
304
311
  .addStep(newBuildUpdateStateStep())
305
312
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
306
313
  .addStep(newNormalizeReferencesStep())
314
+ .addStep(newValidateReferencesStep(deps.store))
315
+ .addStep(newValidateAgentCallReferencesStep(deps.store))
307
316
  .addStep(newPopulateServerlessValidationStepForUpdate(deps.logger))
308
317
  .addStep(newComputeVersionHashStep(deps.logger))
309
318
  .addStep(newCheckVersionChangedStep(deps.logger))
@@ -410,8 +419,8 @@ async function deleteWorkflow(
410
419
  // updateVisibility — update_visibility.go: a targeted metadata update (only
411
420
  // metadata.visibility changes; spec/status untouched). The level check runs
412
421
  // AFTER load, preserving the cross-edition error precedence: unknown id +
413
- // bad level = NOT_FOUND on both editions. CW-9's suite block is the wire
414
- // pin (clientPublicVisibilityWrites, true on local targets).
422
+ // bad level = NOT_FOUND on both editions. The workflow conformance suite's
423
+ // visibility block is the wire pin.
415
424
  // ---------------------------------------------------------------------------
416
425
 
417
426
  const UPDATE_VISIBILITY_WORKFLOW_KEY = "updateVisibilityWorkflow";
@@ -451,10 +460,20 @@ async function updateVisibility(
451
460
  newRecordVisibilityBeforeUpdateStep(UPDATE_VISIBILITY_WORKFLOW_KEY),
452
461
  )
453
462
  .addStep(newValidateVisibilityUpdateStep())
463
+ // The reference floor's second door: a workflow may not be raised above
464
+ // the agents its agent_call tasks run.
454
465
  .addStep(
455
- newAuthorizeVisibilityTransitionStep(
466
+ newGuardReferenceFloorOnEscalationStep(
467
+ deps.store,
456
468
  UPDATE_VISIBILITY_WORKFLOW_KEY,
457
- deps.authorizer,
469
+ [
470
+ (row) => collectSpecReferences(WorkflowSchema, row),
471
+ (row) =>
472
+ collectAgentCallReferences(
473
+ (row as Workflow).spec,
474
+ (row as Workflow).metadata?.org ?? "",
475
+ ),
476
+ ],
458
477
  ),
459
478
  )
460
479
  .addStep(newSetWorkflowVisibilityStep())
@@ -831,130 +850,47 @@ async function get(
831
850
  return reqCtx.get(TARGET_RESOURCE_KEY) as Workflow;
832
851
  }
833
852
 
834
- /** A 64-hex value is an exact content hash; anything else is a tag. */
835
- const WORKFLOW_HASH_PATTERN = /^[a-f0-9]{64}$/;
836
-
837
853
  /**
838
- * getByReference — query.go: slug/org resolution plus version resolution.
839
- * Empty/"latest" → the current head; a version matching the head's hash or
840
- * tag → the head; otherwise the audit store by hash or tag, with the
841
- * snapshot's tag overlaid from the audit column (the source of truth) so
842
- * callers never see a stale embedded tag after a tag move. Like
843
- * validateSpec, this branching read flow reads more honestly written
844
- * directly than as a pipeline (Go's own note).
854
+ * getByReference — the slug/org read plus the version ladder, as a chain:
855
+ * Authorize (a no-op under the lane's skip annotation) → ValidateProto →
856
+ * LoadWorkflowByReference (the ladder, version-resolution.ts) →
857
+ * AuthorizeResolvedTarget, which asks of the loaded head's id exactly what
858
+ * `get` asks by id, so a slug reveals nothing a member could not read
859
+ * through the id. The archived snapshot shares the head's id, so the check
860
+ * on a versioned read is the check on the head.
845
861
  */
846
862
  async function getByReference(
847
863
  deps: WorkflowControllerDeps,
848
864
  ref: ApiResourceReference,
865
+ ctx: HandlerContext,
849
866
  ): Promise<Workflow> {
850
- if (ref.slug === "") {
851
- throw invalidArgumentError("slug is required in reference");
852
- }
853
-
854
- // Workflow is org-scoped: its slug is unique only within an org, so an
855
- // empty-org reference is under-specified.
856
- requireOrgForReference(ApiResourceKind.workflow, ref.org);
857
-
858
- if (
859
- ref.kind !== ApiResourceKind.api_resource_kind_unknown &&
860
- ref.kind !== ApiResourceKind.workflow
861
- ) {
862
- // Go renders both sides with .String(): the NAME for defined values and
863
- // the bare NUMBER for unknown ones (proto3 open enums preserve them, and
864
- // ref.kind carries no defined_only rule) — enumToJson would throw on the
865
- // unknown arm (panel finding).
866
- const got = ApiResourceKind[ref.kind] ?? String(ref.kind);
867
- throw invalidArgumentError(
868
- `kind mismatch: expected ${ApiResourceKind[ApiResourceKind.workflow]}, got ${got}`,
869
- );
870
- }
871
-
872
- let mainWorkflow: Workflow | undefined;
873
- try {
874
- mainWorkflow = await findResourceBySlug(
875
- deps.store,
876
- ApiResourceKind.workflow,
877
- WorkflowSchema,
878
- ref.slug,
879
- ref.org,
880
- );
881
- } catch (error) {
882
- // Go wraps the slug scan's store failure (query.go:110) — without this
883
- // the raw storage error would cross the wire as Unknown (panel finding).
884
- throw internalError(error, "failed to list workflows");
885
- }
886
- if (mainWorkflow === undefined) {
887
- throw notFoundError("workflow", ref.slug);
888
- }
889
-
890
- const version = ref.version.trim();
891
- if (version === "" || version === "latest") {
892
- return mainWorkflow;
893
- }
894
-
895
- if (workflowMatchesVersion(mainWorkflow, version)) {
896
- return mainWorkflow;
897
- }
898
-
899
- const archived = await findAuditWorkflowByVersion(
900
- deps.store,
901
- mainWorkflow.metadata!.id,
902
- version,
867
+ const reqCtx = new RequestContext(
868
+ WorkflowQueryController.method.getByReference.input,
869
+ ref,
870
+ callerIdentityOf(ctx),
871
+ kindOf(ctx),
903
872
  );
904
- if (archived === undefined) {
905
- throw notFoundError("workflow version", `${ref.slug}:${version}`);
906
- }
907
- return archived;
908
- }
909
-
910
- function workflowMatchesVersion(wf: Workflow, version: string): boolean {
911
- if (wf.status === undefined) {
912
- return false;
913
- }
914
- if (WORKFLOW_HASH_PATTERN.test(version)) {
915
- return wf.status.versionHash === version;
916
- }
917
- return wf.metadata?.version?.tag === version;
918
- }
919
-
920
- async function findAuditWorkflowByVersion(
921
- store: Store,
922
- workflowId: string,
923
- version: string,
924
- ): Promise<Workflow | undefined> {
925
- let rec: AuditRecord;
926
- try {
927
- rec = WORKFLOW_HASH_PATTERN.test(version)
928
- ? await store.getAuditRecordByHash(
929
- ApiResourceKind.workflow,
930
- workflowId,
931
- version,
932
- )
933
- : await store.getAuditRecordByTag(
934
- ApiResourceKind.workflow,
935
- workflowId,
936
- version,
937
- );
938
- } catch (error) {
939
- if (error instanceof AuditNotFoundError) {
940
- return undefined;
941
- }
942
- throw internalError(error, "failed to query workflow audit by version");
943
- }
944
-
945
- let wf: Workflow;
946
- try {
947
- wf = fromBinary(WorkflowSchema, rec.data);
948
- } catch (error) {
949
- throw internalError(error, "failed to decode archived workflow version");
950
- }
951
- // Overlay the authoritative tag (audit column) onto the snapshot's
952
- // metadata.version.tag — the snapshot's embedded tag is only correct as
953
- // of archival time.
954
- wf.metadata ??= create(ApiResourceMetadataSchema);
955
- wf.metadata.version ??= create(ApiResourceMetadataVersionSchema);
956
- wf.metadata.version.tag = rec.tag;
957
- return wf;
873
+ await newPipeline<typeof WorkflowQueryController.method.getByReference.input>(
874
+ "workflow-get-by-reference",
875
+ deps.logger,
876
+ )
877
+ .addStep(
878
+ newAuthorizeStep(
879
+ WorkflowQueryController.method.getByReference,
880
+ deps.authorizer,
881
+ ),
882
+ )
883
+ .addStep(newValidateProtoStep())
884
+ .addStep(newLoadWorkflowByReferenceStep(deps.store))
885
+ .addStep(
886
+ newAuthorizeResolvedTargetStep(
887
+ deps.authorizer,
888
+ loadedTargetAsMethod(WorkflowQueryController.method.get),
889
+ ),
890
+ )
891
+ .build()
892
+ .execute(reqCtx);
893
+ return reqCtx.get(TARGET_RESOURCE_KEY) as Workflow;
958
894
  }
959
895
 
960
896
  // ---------------------------------------------------------------------------
@@ -996,28 +932,23 @@ async function listVersions(
996
932
  )
997
933
  .addStep(newValidateProtoStep())
998
934
  .addStep(newResolveWorkflowBySlugStep(deps.store))
999
- .addStep({
1000
- name: "AuthorizeResolvedWorkflow",
1001
- async execute(stepCtx): Promise<void> {
1002
- // The Java WorkflowListVersionsHandler's mid-chain can_view on the
1003
- // RESOLVED workflow id (20260830.01 ruling Q8 — the DD-007 pattern
1004
- // "the two traced ListVersions handlers port onto"; the skip
1005
- // annotation exists because the target resolves from org+slug, not
1006
- // a request field). Deny copy is the Java handler's byte-pinned
1007
- // error_msg. The resolve step above already answered NOT_FOUND for
1008
- // an unknown slug, the load-first order both editions share.
1009
- await authorizeResolvedResource(
1010
- deps.authorizer,
1011
- stepCtx.callerIdentity,
1012
- {
1013
- permission: IamPermission.can_view,
1014
- resourceKind: ApiResourceKind.workflow,
1015
- resourceId: stepCtx.get(LIST_VERSIONS_WORKFLOW_ID_KEY) as string,
1016
- },
935
+ // The Java WorkflowListVersionsHandler's mid-chain can_view on the
936
+ // RESOLVED workflow id (the skip annotation exists because the target
937
+ // resolves from org+slug, not a request field); the copy is the Java
938
+ // handler's byte-pinned error_msg, and the resolve step above already
939
+ // answered NOT_FOUND for an unknown slug, the load-first order both
940
+ // editions share.
941
+ .addStep(
942
+ newAuthorizeResolvedTargetStep(
943
+ deps.authorizer,
944
+ versionHistoryTarget(
945
+ ApiResourceKind.workflow,
1017
946
  "unauthorized to view workflow version history",
1018
- );
1019
- },
1020
- })
947
+ LIST_VERSIONS_WORKFLOW_ID_KEY,
948
+ ),
949
+ "AuthorizeResolvedWorkflow",
950
+ ),
951
+ )
1021
952
  .addStep(newLoadAndMapWorkflowVersionsStep(deps.store))
1022
953
  .build()
1023
954
  .execute(reqCtx);
@@ -1525,7 +1525,7 @@
1525
1525
  "type": "string"
1526
1526
  },
1527
1527
  "org": {
1528
- "description": "Organization that owns the referenced resource. When non-empty: must be a valid org slug (lowercase alphanumeric with hyphens, starts with a letter, 1-63 characters). Example: \"stigmer\", \"acme-corp\". When empty: the reference is relative — the server resolves it to the parent resource's organization at write time. All stored and returned references always have org populated (absolute form). Use empty org for same-org references (the common case). Use explicit org for cross-org references (e.g., marketplace resources).",
1528
+ "description": "Organization that owns the referenced resource. When non-empty: must be a valid org slug (lowercase alphanumeric with hyphens, starts with a letter, 1-63 characters). Example: \"stigmer\", \"acme-corp\". When empty: the reference is relative — the server resolves it to the parent resource's organization at write time. All stored and returned references always have org populated (absolute form). Use empty org for same-org references (the common case). An explicit other org is accepted only when that organization is a platform that shares the resource with yours (visibility_platform).",
1529
1529
  "maxLength": 63,
1530
1530
  "pattern": "^$|^[a-z][a-z0-9-]*[a-z0-9]$",
1531
1531
  "type": "string"
@@ -105,7 +105,10 @@ function taskConstraintViolations(task: WorkflowTask): string[] {
105
105
  * task_config is a Struct again — that is what the walker's recursion is
106
106
  * for).
107
107
  */
108
- function configConstraintViolations(task: WorkflowTask, cfg: Message): string[] {
108
+ function configConstraintViolations(
109
+ task: WorkflowTask,
110
+ cfg: Message,
111
+ ): string[] {
109
112
  const schema = taskConfigSchemaFor(task.kind);
110
113
  if (schema === undefined) {
111
114
  // Unknown kinds were already rejected by validateTaskKinds; an
@@ -129,9 +132,10 @@ function configConstraintViolations(task: WorkflowTask, cfg: Message): string[]
129
132
  * The WorkflowTask lists embedded in a control-flow task config, in
130
133
  * declaration order — the same recursion set the converter walks
131
134
  * (convertForTask/convertForkTask/convertTryTask) and the cloud Java
132
- * TaskConfigStrictParser mirrors.
135
+ * TaskConfigStrictParser mirrors. Exported for the write-time reference
136
+ * collector (../agent-call-references.ts), which walks the same tree.
133
137
  */
134
- function nestedTasks(cfg: Message): WorkflowTask[] {
138
+ export function nestedTasks(cfg: Message): WorkflowTask[] {
135
139
  switch (cfg.$typeName) {
136
140
  case ForTaskConfigSchema.typeName:
137
141
  return (cfg as ForTaskConfig).do;
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Workflow version resolution — the getByReference ladder as a pipeline
3
+ * step, so the lane can carry the resolved-target authorization the
4
+ * position-1 annotation cannot express (the target is a slug, not a field).
5
+ *
6
+ * The ladder is the Go query.go read, moved here from the direct handler
7
+ * without a behaviour change: slug required; org required (a workflow's slug
8
+ * is unique only within an org); kind mismatch refused with Go's rendering
9
+ * (the NAME for defined values, the bare NUMBER for unknown ones, because
10
+ * ref.kind carries no defined_only rule and enumToJson would throw on the
11
+ * unknown arm); the slug scan's store failure wrapped so a raw storage error
12
+ * never crosses the wire as Unknown; empty or "latest" is the current head;
13
+ * a version matching the head's hash or tag is the head; otherwise the
14
+ * audit store by hash or tag, with the snapshot's tag overlaid from the
15
+ * audit column (the source of truth) so callers never see a stale embedded
16
+ * tag after a tag move. The resolved row lands under TARGET_RESOURCE_KEY,
17
+ * the loader contract every getByReference chain shares.
18
+ *
19
+ * Deliberately NOT the shared ladder in pipeline/steps/version-history.ts:
20
+ * that one decodes through the typed audit reads and carries no tag
21
+ * overlay, so folding the two would change what one of them returns for a
22
+ * moved tag. Consolidating them is a separate change with its own proof.
23
+ *
24
+ * Proven by __tests__/workflow.test.ts's getByReference block and the
25
+ * conformance suite's workflow reference arms.
26
+ */
27
+ import { create, fromBinary } from "@bufbuild/protobuf";
28
+
29
+ import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
30
+ import type { Workflow } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
31
+ import {
32
+ ApiResourceMetadataSchema,
33
+ ApiResourceMetadataVersionSchema,
34
+ } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
35
+ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
36
+
37
+ import {
38
+ internalError,
39
+ invalidArgumentError,
40
+ notFoundError,
41
+ } from "../../pipeline/errors.js";
42
+ import type { PipelineStep } from "../../pipeline/pipeline.js";
43
+ import type { RequestContext } from "../../pipeline/request-context.js";
44
+ import type { GetByReferenceDesc } from "../../pipeline/steps/authorize-resolved-target.js";
45
+ import {
46
+ findResourceBySlug,
47
+ requireOrgForReference,
48
+ } from "../../pipeline/steps/helpers.js";
49
+ import { TARGET_RESOURCE_KEY } from "../../pipeline/steps/load-target.js";
50
+ import { AuditNotFoundError } from "../../store/interface.js";
51
+ import type { AuditRecord, Store } from "../../store/interface.js";
52
+
53
+ /** A 64-hex value is an exact content hash; anything else is a tag. */
54
+ const WORKFLOW_HASH_PATTERN = /^[a-f0-9]{64}$/;
55
+
56
+ export function newLoadWorkflowByReferenceStep(
57
+ store: Store,
58
+ ): PipelineStep<GetByReferenceDesc> {
59
+ return {
60
+ name: "LoadWorkflowByReference",
61
+ async execute(ctx: RequestContext<GetByReferenceDesc>): Promise<void> {
62
+ const ref = ctx.input;
63
+ if (ref.slug === "") {
64
+ throw invalidArgumentError("slug is required in reference");
65
+ }
66
+
67
+ requireOrgForReference(ApiResourceKind.workflow, ref.org);
68
+
69
+ if (
70
+ ref.kind !== ApiResourceKind.api_resource_kind_unknown &&
71
+ ref.kind !== ApiResourceKind.workflow
72
+ ) {
73
+ const got = ApiResourceKind[ref.kind] ?? String(ref.kind);
74
+ throw invalidArgumentError(
75
+ `kind mismatch: expected ${ApiResourceKind[ApiResourceKind.workflow]}, got ${got}`,
76
+ );
77
+ }
78
+
79
+ let mainWorkflow: Workflow | undefined;
80
+ try {
81
+ mainWorkflow = await findResourceBySlug(
82
+ store,
83
+ ApiResourceKind.workflow,
84
+ WorkflowSchema,
85
+ ref.slug,
86
+ ref.org,
87
+ );
88
+ } catch (error) {
89
+ throw internalError(error, "failed to list workflows");
90
+ }
91
+ if (mainWorkflow === undefined) {
92
+ throw notFoundError("workflow", ref.slug);
93
+ }
94
+
95
+ const version = ref.version.trim();
96
+ if (
97
+ version === "" ||
98
+ version === "latest" ||
99
+ workflowMatchesVersion(mainWorkflow, version)
100
+ ) {
101
+ ctx.set(TARGET_RESOURCE_KEY, mainWorkflow);
102
+ return;
103
+ }
104
+
105
+ const archived = await findAuditWorkflowByVersion(
106
+ store,
107
+ mainWorkflow.metadata!.id,
108
+ version,
109
+ );
110
+ if (archived === undefined) {
111
+ throw notFoundError("workflow version", `${ref.slug}:${version}`);
112
+ }
113
+ ctx.set(TARGET_RESOURCE_KEY, archived);
114
+ },
115
+ };
116
+ }
117
+
118
+ function workflowMatchesVersion(wf: Workflow, version: string): boolean {
119
+ if (wf.status === undefined) {
120
+ return false;
121
+ }
122
+ if (WORKFLOW_HASH_PATTERN.test(version)) {
123
+ return wf.status.versionHash === version;
124
+ }
125
+ return wf.metadata?.version?.tag === version;
126
+ }
127
+
128
+ async function findAuditWorkflowByVersion(
129
+ store: Store,
130
+ workflowId: string,
131
+ version: string,
132
+ ): Promise<Workflow | undefined> {
133
+ let rec: AuditRecord;
134
+ try {
135
+ rec = WORKFLOW_HASH_PATTERN.test(version)
136
+ ? await store.getAuditRecordByHash(
137
+ ApiResourceKind.workflow,
138
+ workflowId,
139
+ version,
140
+ )
141
+ : await store.getAuditRecordByTag(
142
+ ApiResourceKind.workflow,
143
+ workflowId,
144
+ version,
145
+ );
146
+ } catch (error) {
147
+ if (error instanceof AuditNotFoundError) {
148
+ return undefined;
149
+ }
150
+ throw internalError(error, "failed to query workflow audit by version");
151
+ }
152
+
153
+ let wf: Workflow;
154
+ try {
155
+ wf = fromBinary(WorkflowSchema, rec.data);
156
+ } catch (error) {
157
+ throw internalError(error, "failed to decode archived workflow version");
158
+ }
159
+ // Overlay the authoritative tag (audit column) onto the snapshot's
160
+ // metadata.version.tag — the snapshot's embedded tag is only correct as
161
+ // of archival time.
162
+ wf.metadata ??= create(ApiResourceMetadataSchema);
163
+ wf.metadata.version ??= create(ApiResourceMetadataVersionSchema);
164
+ wf.metadata.version.tag = rec.tag;
165
+ return wf;
166
+ }
@@ -72,7 +72,10 @@ import {
72
72
  TARGET_RESOURCE_KEY,
73
73
  newLoadTargetStep,
74
74
  } from "../../pipeline/steps/load-target.js";
75
- import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
75
+ import {
76
+ newNormalizeReferencesStep,
77
+ newValidateReferencesStep,
78
+ } from "../../pipeline/steps/references.js";
76
79
  import {
77
80
  newCleanupIamPoliciesStep,
78
81
  newCreateAuthorizationTuplesStep,
@@ -299,7 +302,8 @@ async function createExecution(
299
302
  .addStep(newCheckDuplicateStep(deps.store))
300
303
  .addStep(newBuildNewStateStep())
301
304
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
302
- .addStep(newNormalizeReferencesStep());
305
+ .addStep(newNormalizeReferencesStep())
306
+ .addStep(newValidateReferencesStep(deps.store));
303
307
  // The ratified sandbox-acquisition gate slot (blueprint 03 §3a; C4):
304
308
  // the Java-verified capacity-gate position — after Authorize and every
305
309
  // resolution step (the default instance, like Java's, side-effects
@@ -389,6 +393,7 @@ async function update(
389
393
  .addStep(newBuildUpdateStateStep())
390
394
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
391
395
  .addStep(newNormalizeReferencesStep())
396
+ .addStep(newValidateReferencesStep(deps.store))
392
397
  .addStep(newPersistStep(deps.store))
393
398
  .addStep(
394
399
  newIndexSearchStep(
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Pins the create lane's authorization question (steps.ts,
3
+ * resolveWorkflowInstanceCreateTargets): a personal instance asks
4
+ * can_execute on the parent workflow with the Java handler's copy; a
5
+ * default instance the server composed in-process for the parent's
6
+ * organization asks nothing; the same label from the wire or for another
7
+ * organization takes the bar; a missing parent throws.
8
+ */
9
+ import { describe, expect, it } from "vitest";
10
+ import { create } from "@bufbuild/protobuf";
11
+
12
+ import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
13
+ import { WorkflowInstanceSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/api_pb";
14
+ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
15
+ import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
16
+
17
+ import type { CallerIdentity } from "../../../extensions/identity.js";
18
+ import {
19
+ DEFAULT_INSTANCE_LABEL,
20
+ RESERVED_LABEL_TRUE,
21
+ } from "../../../pipeline/apiresource-labels.js";
22
+ import { testCallerIdentity } from "../../../pipeline/__tests__/support.js";
23
+ import { RequestContext } from "../../../pipeline/request-context.js";
24
+ import {
25
+ PARENT_WORKFLOW_KEY,
26
+ WORKFLOW_INSTANCE_PARENT_DENIED_MESSAGE,
27
+ resolveWorkflowInstanceCreateTargets,
28
+ } from "../steps.js";
29
+
30
+ const parent = create(WorkflowSchema, {
31
+ metadata: { id: "wf_01parent", name: "nightly", org: "acme" },
32
+ });
33
+
34
+ function ctxFor(
35
+ org: string,
36
+ caller: CallerIdentity,
37
+ labels: Record<string, string> = {},
38
+ stashParent = true,
39
+ ) {
40
+ const ctx = new RequestContext(
41
+ WorkflowInstanceSchema,
42
+ create(WorkflowInstanceSchema, {
43
+ metadata: { name: "mine", org, labels },
44
+ spec: { workflowId: parent.metadata!.id },
45
+ }),
46
+ caller,
47
+ ApiResourceKind.workflow_instance,
48
+ );
49
+ if (stashParent) {
50
+ ctx.set(PARENT_WORKFLOW_KEY, parent);
51
+ }
52
+ return ctx;
53
+ }
54
+
55
+ const DEFAULT_LABELS = { [DEFAULT_INSTANCE_LABEL]: RESERVED_LABEL_TRUE };
56
+
57
+ describe("resolveWorkflowInstanceCreateTargets", () => {
58
+ it("a personal instance asks can_execute on the parent workflow", () => {
59
+ expect(
60
+ resolveWorkflowInstanceCreateTargets(
61
+ ctxFor("acme", testCallerIdentity()),
62
+ ),
63
+ ).toEqual([
64
+ {
65
+ permission: IamPermission.can_execute,
66
+ resourceKind: ApiResourceKind.workflow,
67
+ resourceId: "wf_01parent",
68
+ deniedMessage: WORKFLOW_INSTANCE_PARENT_DENIED_MESSAGE,
69
+ },
70
+ ]);
71
+ });
72
+
73
+ it("a default instance the server composed in-process for the parent's organization asks nothing", () => {
74
+ expect(
75
+ resolveWorkflowInstanceCreateTargets(
76
+ ctxFor(
77
+ "acme",
78
+ testCallerIdentity({ callerClass: "user", origin: "in-process" }),
79
+ DEFAULT_LABELS,
80
+ ),
81
+ ),
82
+ ).toEqual([]);
83
+ });
84
+
85
+ it("the label from the wire, or for another organization, takes the bar", () => {
86
+ expect(
87
+ resolveWorkflowInstanceCreateTargets(
88
+ ctxFor("acme", testCallerIdentity(), DEFAULT_LABELS),
89
+ ),
90
+ ).toHaveLength(1);
91
+ expect(
92
+ resolveWorkflowInstanceCreateTargets(
93
+ ctxFor(
94
+ "other-org",
95
+ testCallerIdentity({ callerClass: "user", origin: "in-process" }),
96
+ DEFAULT_LABELS,
97
+ ),
98
+ ),
99
+ ).toHaveLength(1);
100
+ });
101
+
102
+ it("a missing parent is a broken chain invariant and throws", () => {
103
+ expect(() =>
104
+ resolveWorkflowInstanceCreateTargets(
105
+ ctxFor("acme", testCallerIdentity(), {}, false),
106
+ ),
107
+ ).toThrow("parent workflow not found in context");
108
+ });
109
+ });