@stigmer/server 3.22.1-dev.20260922095755 → 3.23.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 (330) hide show
  1. package/dist/artifactstorage/artifact-storage.d.ts +29 -31
  2. package/dist/artifactstorage/artifact-storage.d.ts.map +1 -1
  3. package/dist/artifactstorage/artifact-storage.js +5 -7
  4. package/dist/artifactstorage/artifact-storage.js.map +1 -1
  5. package/dist/artifactstorage/r2-storage.d.ts +12 -7
  6. package/dist/artifactstorage/r2-storage.d.ts.map +1 -1
  7. package/dist/artifactstorage/r2-storage.js +6 -14
  8. package/dist/artifactstorage/r2-storage.js.map +1 -1
  9. package/dist/authorization/authorizer.d.ts +8 -4
  10. package/dist/authorization/authorizer.d.ts.map +1 -1
  11. package/dist/authorization/authorizer.js +9 -5
  12. package/dist/authorization/authorizer.js.map +1 -1
  13. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  14. package/dist/authorization/derived-tuples.js +25 -10
  15. package/dist/authorization/derived-tuples.js.map +1 -1
  16. package/dist/authorization/evaluator.d.ts +8 -7
  17. package/dist/authorization/evaluator.d.ts.map +1 -1
  18. package/dist/authorization/evaluator.js +20 -4
  19. package/dist/authorization/evaluator.js.map +1 -1
  20. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  21. package/dist/authorization/list-read-scope.js +9 -5
  22. package/dist/authorization/list-read-scope.js.map +1 -1
  23. package/dist/authorization/model/agent.d.ts.map +1 -1
  24. package/dist/authorization/model/agent.js +5 -4
  25. package/dist/authorization/model/agent.js.map +1 -1
  26. package/dist/authorization/model/agent_instance.d.ts.map +1 -1
  27. package/dist/authorization/model/agent_instance.js +2 -2
  28. package/dist/authorization/model/agent_instance.js.map +1 -1
  29. package/dist/authorization/model/mcp_server.d.ts.map +1 -1
  30. package/dist/authorization/model/mcp_server.js +2 -2
  31. package/dist/authorization/model/mcp_server.js.map +1 -1
  32. package/dist/authorization/model/plugin.d.ts.map +1 -1
  33. package/dist/authorization/model/plugin.js +4 -3
  34. package/dist/authorization/model/plugin.js.map +1 -1
  35. package/dist/authorization/model/rewrite.d.ts +10 -8
  36. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  37. package/dist/authorization/model/rewrite.js +3 -0
  38. package/dist/authorization/model/rewrite.js.map +1 -1
  39. package/dist/authorization/model/skill.d.ts.map +1 -1
  40. package/dist/authorization/model/skill.js +2 -2
  41. package/dist/authorization/model/skill.js.map +1 -1
  42. package/dist/authorization/model/workflow.d.ts.map +1 -1
  43. package/dist/authorization/model/workflow.js +2 -2
  44. package/dist/authorization/model/workflow.js.map +1 -1
  45. package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
  46. package/dist/authorization/model/workflow_instance.js +2 -2
  47. package/dist/authorization/model/workflow_instance.js.map +1 -1
  48. package/dist/authorization/organization-directory.d.ts.map +1 -1
  49. package/dist/authorization/organization-directory.js +3 -2
  50. package/dist/authorization/organization-directory.js.map +1 -1
  51. package/dist/authorization/store-test-kit.d.ts +6 -0
  52. package/dist/authorization/store-test-kit.d.ts.map +1 -1
  53. package/dist/authorization/store-test-kit.js +62 -16
  54. package/dist/authorization/store-test-kit.js.map +1 -1
  55. package/dist/authorization/tuples.d.ts +32 -13
  56. package/dist/authorization/tuples.d.ts.map +1 -1
  57. package/dist/authorization/tuples.js +11 -3
  58. package/dist/authorization/tuples.js.map +1 -1
  59. package/dist/boot/compose.d.ts.map +1 -1
  60. package/dist/boot/compose.js +49 -24
  61. package/dist/boot/compose.js.map +1 -1
  62. package/dist/boot/config.d.ts +4 -3
  63. package/dist/boot/config.d.ts.map +1 -1
  64. package/dist/boot/config.js.map +1 -1
  65. package/dist/boot/skill-transfer-origin.d.ts +52 -0
  66. package/dist/boot/skill-transfer-origin.d.ts.map +1 -0
  67. package/dist/boot/skill-transfer-origin.js +54 -0
  68. package/dist/boot/skill-transfer-origin.js.map +1 -0
  69. package/dist/domain/agent/controller.d.ts.map +1 -1
  70. package/dist/domain/agent/controller.js +4 -4
  71. package/dist/domain/agent/controller.js.map +1 -1
  72. package/dist/domain/agentchannel/controller.d.ts.map +1 -1
  73. package/dist/domain/agentchannel/controller.js +1 -3
  74. package/dist/domain/agentchannel/controller.js.map +1 -1
  75. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  76. package/dist/domain/agentexecution/controller.js +1 -3
  77. package/dist/domain/agentexecution/controller.js.map +1 -1
  78. package/dist/domain/agentinstance/controller.d.ts.map +1 -1
  79. package/dist/domain/agentinstance/controller.js +4 -3
  80. package/dist/domain/agentinstance/controller.js.map +1 -1
  81. package/dist/domain/agentshare/constants.d.ts +11 -6
  82. package/dist/domain/agentshare/constants.d.ts.map +1 -1
  83. package/dist/domain/agentshare/constants.js +16 -8
  84. package/dist/domain/agentshare/constants.js.map +1 -1
  85. package/dist/domain/agentshare/controller.d.ts.map +1 -1
  86. package/dist/domain/agentshare/controller.js +1 -3
  87. package/dist/domain/agentshare/controller.js.map +1 -1
  88. package/dist/domain/agentshare/steps.d.ts +25 -18
  89. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  90. package/dist/domain/agentshare/steps.js +142 -41
  91. package/dist/domain/agentshare/steps.js.map +1 -1
  92. package/dist/domain/environment/controller.d.ts.map +1 -1
  93. package/dist/domain/environment/controller.js +3 -2
  94. package/dist/domain/environment/controller.js.map +1 -1
  95. package/dist/domain/executioncontext/controller.d.ts.map +1 -1
  96. package/dist/domain/executioncontext/controller.js +1 -2
  97. package/dist/domain/executioncontext/controller.js.map +1 -1
  98. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  99. package/dist/domain/mcpserver/controller.js +4 -3
  100. package/dist/domain/mcpserver/controller.js.map +1 -1
  101. package/dist/domain/plugin/controller.d.ts +3 -7
  102. package/dist/domain/plugin/controller.d.ts.map +1 -1
  103. package/dist/domain/plugin/controller.js +11 -9
  104. package/dist/domain/plugin/controller.js.map +1 -1
  105. package/dist/domain/plugin/push.d.ts +5 -7
  106. package/dist/domain/plugin/push.d.ts.map +1 -1
  107. package/dist/domain/plugin/push.js +14 -8
  108. package/dist/domain/plugin/push.js.map +1 -1
  109. package/dist/domain/schedule/controller.d.ts.map +1 -1
  110. package/dist/domain/schedule/controller.js +1 -3
  111. package/dist/domain/schedule/controller.js.map +1 -1
  112. package/dist/domain/session/controller.d.ts.map +1 -1
  113. package/dist/domain/session/controller.js +2 -3
  114. package/dist/domain/session/controller.js.map +1 -1
  115. package/dist/domain/skill/constants.d.ts +26 -3
  116. package/dist/domain/skill/constants.d.ts.map +1 -1
  117. package/dist/domain/skill/constants.js +26 -3
  118. package/dist/domain/skill/constants.js.map +1 -1
  119. package/dist/domain/skill/controller.d.ts +6 -11
  120. package/dist/domain/skill/controller.d.ts.map +1 -1
  121. package/dist/domain/skill/controller.js +35 -22
  122. package/dist/domain/skill/controller.js.map +1 -1
  123. package/dist/domain/skill/push.d.ts +2 -2
  124. package/dist/domain/skill/push.d.ts.map +1 -1
  125. package/dist/domain/skill/push.js +2 -2
  126. package/dist/domain/skill/push.js.map +1 -1
  127. package/dist/domain/skill/transfer/handler.d.ts +17 -9
  128. package/dist/domain/skill/transfer/handler.d.ts.map +1 -1
  129. package/dist/domain/skill/transfer/handler.js +19 -8
  130. package/dist/domain/skill/transfer/handler.js.map +1 -1
  131. package/dist/domain/skill/transfer/slots.d.ts +26 -41
  132. package/dist/domain/skill/transfer/slots.d.ts.map +1 -1
  133. package/dist/domain/skill/transfer/slots.js +80 -87
  134. package/dist/domain/skill/transfer/slots.js.map +1 -1
  135. package/dist/domain/skill/transfer/staging.d.ts +48 -0
  136. package/dist/domain/skill/transfer/staging.d.ts.map +1 -0
  137. package/dist/domain/skill/transfer/staging.js +127 -0
  138. package/dist/domain/skill/transfer/staging.js.map +1 -0
  139. package/dist/domain/workflow/controller.d.ts.map +1 -1
  140. package/dist/domain/workflow/controller.js +6 -14
  141. package/dist/domain/workflow/controller.js.map +1 -1
  142. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
  143. package/dist/domain/workflow/validation/task-config-constraints.d.ts +1 -10
  144. package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
  145. package/dist/domain/workflow/validation/task-config-constraints.js +2 -3
  146. package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
  147. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  148. package/dist/domain/workflowexecution/controller.js +2 -4
  149. package/dist/domain/workflowexecution/controller.js.map +1 -1
  150. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  151. package/dist/domain/workflowinstance/controller.js +4 -3
  152. package/dist/domain/workflowinstance/controller.js.map +1 -1
  153. package/dist/extensions/authorization-queries.d.ts +5 -6
  154. package/dist/extensions/authorization-queries.d.ts.map +1 -1
  155. package/dist/extensions/list-read-scope.d.ts +1 -1
  156. package/dist/extensions/resource-authorization.d.ts +2 -3
  157. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  158. package/dist/index.d.ts +3 -1
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +13 -0
  161. package/dist/index.js.map +1 -1
  162. package/dist/pipeline/apiresource-meta.d.ts +3 -12
  163. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  164. package/dist/pipeline/apiresource-meta.js +10 -21
  165. package/dist/pipeline/apiresource-meta.js.map +1 -1
  166. package/dist/pipeline/steps/authorization-tuples.d.ts +3 -9
  167. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  168. package/dist/pipeline/steps/authorization-tuples.js +11 -9
  169. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  170. package/dist/pipeline/steps/references.d.ts +20 -178
  171. package/dist/pipeline/steps/references.d.ts.map +1 -1
  172. package/dist/pipeline/steps/references.js +43 -344
  173. package/dist/pipeline/steps/references.js.map +1 -1
  174. package/dist/pipeline/steps/resolve-artifact-source.d.ts +11 -8
  175. package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -1
  176. package/dist/pipeline/steps/resolve-artifact-source.js +8 -4
  177. package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -1
  178. package/dist/pipeline/steps/visibility-gates.d.ts +27 -0
  179. package/dist/pipeline/steps/visibility-gates.d.ts.map +1 -0
  180. package/dist/pipeline/steps/visibility-gates.js +139 -0
  181. package/dist/pipeline/steps/visibility-gates.js.map +1 -0
  182. package/dist/query/search/controller.js +1 -0
  183. package/dist/query/search/controller.js.map +1 -1
  184. package/dist/query/search/criteria.d.ts +5 -1
  185. package/dist/query/search/criteria.d.ts.map +1 -1
  186. package/dist/query/search/criteria.js +13 -3
  187. package/dist/query/search/criteria.js.map +1 -1
  188. package/dist/query/search/handler.d.ts +4 -5
  189. package/dist/query/search/handler.d.ts.map +1 -1
  190. package/dist/query/search/handler.js +6 -7
  191. package/dist/query/search/handler.js.map +1 -1
  192. package/dist/query/search/query-store.d.ts.map +1 -1
  193. package/dist/query/search/query-store.js +2 -0
  194. package/dist/query/search/query-store.js.map +1 -1
  195. package/dist/store/interface.d.ts +6 -3
  196. package/dist/store/interface.d.ts.map +1 -1
  197. package/dist/store/interface.js.map +1 -1
  198. package/dist/store/postgres/migrations.d.ts +1 -3
  199. package/dist/store/postgres/migrations.d.ts.map +1 -1
  200. package/dist/store/postgres/migrations.js +1 -35
  201. package/dist/store/postgres/migrations.js.map +1 -1
  202. package/dist/store/postgres/store.d.ts.map +1 -1
  203. package/dist/store/postgres/store.js +9 -4
  204. package/dist/store/postgres/store.js.map +1 -1
  205. package/dist/store/sqlite/migrations.d.ts +1 -3
  206. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  207. package/dist/store/sqlite/migrations.js +1 -36
  208. package/dist/store/sqlite/migrations.js.map +1 -1
  209. package/dist/store/sqlite/store.d.ts.map +1 -1
  210. package/dist/store/sqlite/store.js +8 -4
  211. package/dist/store/sqlite/store.js.map +1 -1
  212. package/package.json +6 -6
  213. package/src/artifactstorage/__tests__/artifact-storage.test.ts +36 -33
  214. package/src/artifactstorage/__tests__/r2-storage.test.ts +11 -13
  215. package/src/artifactstorage/artifact-storage.ts +37 -33
  216. package/src/artifactstorage/r2-storage.ts +6 -15
  217. package/src/authorization/README.md +26 -24
  218. package/src/authorization/__tests__/authorizer.test.ts +9 -10
  219. package/src/authorization/__tests__/derived-tuples.test.ts +11 -4
  220. package/src/authorization/__tests__/evaluator.test.ts +73 -14
  221. package/src/authorization/__tests__/facts.test.ts +2 -2
  222. package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +185 -0
  223. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +98 -6
  224. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +98 -0
  225. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +61 -4
  226. package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +143 -0
  227. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +21 -1
  228. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +25 -1
  229. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +52 -0
  230. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +3 -1
  231. package/src/authorization/__tests__/list-read-scope.test.ts +17 -18
  232. package/src/authorization/__tests__/store-tests.test.ts +8 -1
  233. package/src/authorization/__tests__/tuples.test.ts +11 -12
  234. package/src/authorization/authorizer.ts +9 -4
  235. package/src/authorization/derived-tuples.ts +31 -14
  236. package/src/authorization/evaluator.ts +44 -8
  237. package/src/authorization/list-read-scope.ts +11 -5
  238. package/src/authorization/model/agent.ts +5 -2
  239. package/src/authorization/model/agent_instance.ts +2 -0
  240. package/src/authorization/model/mcp_server.ts +2 -0
  241. package/src/authorization/model/plugin.ts +4 -1
  242. package/src/authorization/model/rewrite.ts +13 -8
  243. package/src/authorization/model/skill.ts +2 -0
  244. package/src/authorization/model/workflow.ts +2 -0
  245. package/src/authorization/model/workflow_instance.ts +2 -0
  246. package/src/authorization/organization-directory.ts +3 -1
  247. package/src/authorization/store-test-kit.ts +75 -16
  248. package/src/authorization/tuples.ts +39 -16
  249. package/src/boot/__tests__/skill-transfer-origin.test.ts +72 -0
  250. package/src/boot/compose.ts +62 -25
  251. package/src/boot/config.ts +4 -3
  252. package/src/boot/skill-transfer-origin.ts +76 -0
  253. package/src/domain/agent/__tests__/agent.test.ts +4 -11
  254. package/src/domain/agent/controller.ts +7 -7
  255. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +48 -223
  256. package/src/domain/agentchannel/controller.ts +1 -6
  257. package/src/domain/agentexecution/controller.ts +1 -6
  258. package/src/domain/agentinstance/controller.ts +12 -6
  259. package/src/domain/agentshare/__tests__/agentshare.test.ts +172 -196
  260. package/src/domain/agentshare/__tests__/create-authorization.test.ts +31 -16
  261. package/src/domain/agentshare/constants.ts +26 -14
  262. package/src/domain/agentshare/controller.ts +1 -6
  263. package/src/domain/agentshare/steps.ts +194 -41
  264. package/src/domain/environment/controller.ts +8 -5
  265. package/src/domain/executioncontext/controller.ts +1 -5
  266. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +28 -115
  267. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +18 -53
  268. package/src/domain/mcpserver/controller.ts +12 -6
  269. package/src/domain/plugin/controller.ts +23 -18
  270. package/src/domain/plugin/push.ts +16 -8
  271. package/src/domain/schedule/controller.ts +1 -6
  272. package/src/domain/session/controller.ts +4 -12
  273. package/src/domain/skill/__tests__/skill.test.ts +5 -3
  274. package/src/domain/skill/__tests__/slots.test.ts +113 -60
  275. package/src/domain/skill/__tests__/staging.test.ts +304 -0
  276. package/src/domain/skill/constants.ts +28 -3
  277. package/src/domain/skill/controller.ts +51 -35
  278. package/src/domain/skill/push.ts +3 -3
  279. package/src/domain/skill/transfer/handler.ts +33 -15
  280. package/src/domain/skill/transfer/slots.ts +89 -100
  281. package/src/domain/skill/transfer/staging.ts +191 -0
  282. package/src/domain/workflow/controller.ts +10 -28
  283. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
  284. package/src/domain/workflow/validation/task-config-constraints.ts +3 -7
  285. package/src/domain/workflowexecution/controller.ts +2 -7
  286. package/src/domain/workflowinstance/controller.ts +12 -6
  287. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +19 -32
  288. package/src/extensions/__tests__/extension-composition.test.ts +4 -4
  289. package/src/extensions/__tests__/list-read-scope-composed.test.ts +6 -9
  290. package/src/extensions/authorization-queries.ts +5 -6
  291. package/src/extensions/list-read-scope.ts +1 -1
  292. package/src/extensions/resource-authorization.ts +5 -3
  293. package/src/index.ts +14 -0
  294. package/src/pipeline/apiresource-meta.ts +10 -21
  295. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +31 -18
  296. package/src/pipeline/steps/__tests__/visibility-gates.test.ts +187 -0
  297. package/src/pipeline/steps/authorization-tuples.ts +11 -9
  298. package/src/pipeline/steps/references.ts +70 -578
  299. package/src/pipeline/steps/resolve-artifact-source.ts +20 -13
  300. package/src/pipeline/steps/visibility-gates.ts +174 -0
  301. package/src/query/search/__tests__/criteria.test.ts +4 -0
  302. package/src/query/search/__tests__/query-store.test.ts +40 -11
  303. package/src/query/search/controller.ts +1 -0
  304. package/src/query/search/criteria.ts +14 -0
  305. package/src/query/search/handler.ts +7 -6
  306. package/src/query/search/query-store.ts +2 -0
  307. package/src/store/__tests__/store-contract.ts +51 -6
  308. package/src/store/interface.ts +6 -3
  309. package/src/store/postgres/__tests__/migrations.test.ts +6 -187
  310. package/src/store/postgres/__tests__/store-contract.test.ts +2 -0
  311. package/src/store/postgres/migrations.ts +1 -48
  312. package/src/store/postgres/store.ts +11 -4
  313. package/src/store/sqlite/__tests__/migrations.test.ts +5 -191
  314. package/src/store/sqlite/migrations.ts +1 -45
  315. package/src/store/sqlite/store.ts +10 -4
  316. package/src/transport/registry/__tests__/lanes.test.ts +1 -1
  317. package/dist/domain/workflow/agent-call-references.d.ts +0 -54
  318. package/dist/domain/workflow/agent-call-references.d.ts.map +0 -1
  319. package/dist/domain/workflow/agent-call-references.js +0 -97
  320. package/dist/domain/workflow/agent-call-references.js.map +0 -1
  321. package/dist/store/public-visibility-retired.d.ts +0 -67
  322. package/dist/store/public-visibility-retired.d.ts.map +0 -1
  323. package/dist/store/public-visibility-retired.js +0 -55
  324. package/dist/store/public-visibility-retired.js.map +0 -1
  325. package/src/domain/workflow/__tests__/agent-call-references.test.ts +0 -222
  326. package/src/domain/workflow/agent-call-references.ts +0 -157
  327. package/src/pipeline/__tests__/supports-visibility.test.ts +0 -112
  328. package/src/pipeline/steps/__tests__/references.test.ts +0 -703
  329. package/src/store/__tests__/public-visibility-retired.test.ts +0 -127
  330. package/src/store/public-visibility-retired.ts +0 -119
@@ -1,12 +1,10 @@
1
1
  /**
2
- * Pins the create lane's two questions (steps.ts, resolveShareCreateTargets):
3
- * can_edit on the referenced agent, then can_create_agent_share on the
4
- * share's organization, in that order, each with its byte-pinned copy. A
5
- * share's agent lives in the share's organization (the resolve step refuses
6
- * anything else before this runs), so the two bars are one organization's:
7
- * sharing puts the agent in front of a wider audience (an editor's act) and
8
- * spends the organization's credits on the open internet (an admin's). A
9
- * missing referenced agent throws.
2
+ * Pins the create lane's two-arm consent bar (steps.ts,
3
+ * resolveShareCreateTargets), the Java handler's: a same-org share asks
4
+ * can_edit on the referenced agent; a cross-org share asks can_execute on
5
+ * the agent and then can_create_agent_share on the SHARING organization,
6
+ * agent first; each question carries its byte-pinned copy; a missing
7
+ * referenced agent throws.
10
8
  */
11
9
  import { describe, expect, it } from "vitest";
12
10
  import { create } from "@bufbuild/protobuf";
@@ -26,15 +24,15 @@ import {
26
24
  } from "../steps.js";
27
25
 
28
26
  const agent = create(AgentSchema, {
29
- metadata: { id: "agt_01helper", name: "helper", org: "publisher-org" },
27
+ metadata: { id: "agt_01public", name: "helper", org: "publisher-org" },
30
28
  });
31
29
 
32
- function ctxFor(shareOrg: string, stash = true) {
30
+ function ctxFor(shareOrg: string, agentOrg: string, stash = true) {
33
31
  const ctx = new RequestContext(
34
32
  AgentShareSchema,
35
33
  create(AgentShareSchema, {
36
34
  metadata: { name: "helper", org: shareOrg },
37
- spec: { agentRef: { org: shareOrg, slug: "helper" } },
35
+ spec: { agentRef: { org: agentOrg, slug: "helper" } },
38
36
  }),
39
37
  testCallerIdentity(),
40
38
  ApiResourceKind.agent_share,
@@ -46,18 +44,33 @@ function ctxFor(shareOrg: string, stash = true) {
46
44
  }
47
45
 
48
46
  describe("resolveShareCreateTargets", () => {
49
- it("asks can_edit on the referenced agent, then can_create_agent_share on the share's organization", () => {
50
- expect(resolveShareCreateTargets(ctxFor("publisher-org"))).toEqual([
47
+ it("a same-org share asks can_edit on the referenced agent", () => {
48
+ expect(
49
+ resolveShareCreateTargets(ctxFor("publisher-org", "publisher-org")),
50
+ ).toEqual([
51
51
  {
52
52
  permission: IamPermission.can_edit,
53
53
  resourceKind: ApiResourceKind.agent,
54
- resourceId: "agt_01helper",
54
+ resourceId: "agt_01public",
55
+ deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
56
+ },
57
+ ]);
58
+ });
59
+
60
+ it("a cross-org share asks can_execute on the agent, then can_create_agent_share on the sharing organization", () => {
61
+ expect(
62
+ resolveShareCreateTargets(ctxFor("consumer-org", "publisher-org")),
63
+ ).toEqual([
64
+ {
65
+ permission: IamPermission.can_execute,
66
+ resourceKind: ApiResourceKind.agent,
67
+ resourceId: "agt_01public",
55
68
  deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
56
69
  },
57
70
  {
58
71
  permission: IamPermission.can_create_agent_share,
59
72
  resourceKind: ApiResourceKind.organization,
60
- resourceId: "publisher-org",
73
+ resourceId: "consumer-org",
61
74
  deniedMessage: SHARE_ORGANIZATION_DENIED_MESSAGE,
62
75
  },
63
76
  ]);
@@ -65,7 +78,9 @@ describe("resolveShareCreateTargets", () => {
65
78
 
66
79
  it("a missing referenced agent is a broken chain invariant and throws", () => {
67
80
  expect(() =>
68
- resolveShareCreateTargets(ctxFor("publisher-org", false)),
81
+ resolveShareCreateTargets(
82
+ ctxFor("publisher-org", "publisher-org", false),
83
+ ),
69
84
  ).toThrow("referenced agent not found in context");
70
85
  });
71
86
  });
@@ -17,12 +17,10 @@ export const SHARE_LINK_TOKEN_BYTES = 20;
17
17
  * resolveShareDefaultsStep, byte-pinned. The share's org appears in the
18
18
  * hosted chat URL and is the billing org, so it can never be inferred.
19
19
  */
20
- export const ORG_REQUIRED_MESSAGE =
21
- "metadata.org is required for an agent share";
20
+ export const ORG_REQUIRED_MESSAGE = "metadata.org is required for an agent share";
22
21
 
23
22
  /** InvalidArgument copy when spec.agent_ref.slug is absent — Go, pinned. */
24
- export const AGENT_REF_SLUG_REQUIRED_MESSAGE =
25
- "spec.agent_ref.slug is required";
23
+ export const AGENT_REF_SLUG_REQUIRED_MESSAGE = "spec.agent_ref.slug is required";
26
24
 
27
25
  /**
28
26
  * InvalidArgument copy for BOTH profile lanes when org is absent — Go
@@ -30,20 +28,34 @@ export const AGENT_REF_SLUG_REQUIRED_MESSAGE =
30
28
  * Anti-enumeration: an empty org would mean "match slug across all orgs"
31
29
  * on a public endpoint.
32
30
  */
33
- export const ORG_REQUIRED_FOR_LOOKUP_MESSAGE =
34
- "org is required for shared agent lookup";
31
+ export const ORG_REQUIRED_FOR_LOOKUP_MESSAGE = "org is required for shared agent lookup";
35
32
 
36
33
  /**
37
- * FailedPrecondition copy when spec.agent_ref names another organization's
38
- * agent — the schedule's and the channel's same-organization sentence in
39
- * the share's own words. A share offers an agent its own organization
40
- * owns; to share another organization's agent, install the plugin that
41
- * carries it and share the installed copy.
34
+ * FailedPrecondition copy for an org-audience cross-org share (decision
35
+ * 013 D3) — Go validateCrossOrgShare AND validateShareUpdateStep (update
36
+ * replaces the spec wholesale and must not open a side door), byte-pinned.
42
37
  */
43
- export function sameOrgInvariantMessage(refOrg: string): string {
38
+ export function crossOrgAudienceMessage(agentOrg: string): string {
44
39
  return (
45
- "spec.agent_ref.org must match metadata.org — a share must live in " +
46
- `the referenced agent's organization (${refOrg})`
40
+ "a cross-org share must have a public audience — org-audience shares " +
41
+ `are limited to the agent's own organization (${agentOrg})`
42
+ );
43
+ }
44
+
45
+ /**
46
+ * FailedPrecondition copy naming every non-public dependency blocking a
47
+ * cross-org share (decision 013 D5) — Go validateCrossOrgShare,
48
+ * byte-pinned. Blockers are deduped, formatted "<kind> <org>/<slug>", and
49
+ * sorted, so the refusal is deterministic.
50
+ */
51
+ export function crossOrgBlockersMessage(
52
+ agentOrg: string,
53
+ agentSlug: string,
54
+ blockers: readonly string[],
55
+ ): string {
56
+ return (
57
+ `cannot share ${agentOrg}/${agentSlug} across organizations: ` +
58
+ `it references resources that are not public: ${blockers.join(", ")}`
47
59
  );
48
60
  }
49
61
 
@@ -93,10 +93,7 @@ import {
93
93
  TARGET_RESOURCE_KEY,
94
94
  newLoadTargetStep,
95
95
  } from "../../pipeline/steps/load-target.js";
96
- import {
97
- newNormalizeReferencesStep,
98
- newValidateReferencesStep,
99
- } from "../../pipeline/steps/references.js";
96
+ import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
100
97
  import {
101
98
  newCleanupIamPoliciesStep,
102
99
  newCreateAuthorizationTuplesStep,
@@ -198,7 +195,6 @@ async function createShare(
198
195
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
199
196
  .addStep(newStampAgentPinStep())
200
197
  .addStep(newNormalizeReferencesStep())
201
- .addStep(newValidateReferencesStep(deps.store))
202
198
  .addStep(newPersistStep(deps.store))
203
199
  .addStep(
204
200
  newCreateAuthorizationTuplesStep(
@@ -243,7 +239,6 @@ async function update(
243
239
  .addStep(newBuildUpdateStateStep())
244
240
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
245
241
  .addStep(newNormalizeReferencesStep())
246
- .addStep(newValidateReferencesStep(deps.store))
247
242
  .addStep(newPersistStep(deps.store))
248
243
  .build()
249
244
  .execute(reqCtx);
@@ -1,19 +1,10 @@
1
1
  /**
2
2
  * AgentShare domain steps — ports pkg/domain/agentshare/controller/steps.go
3
- * and the get_shared_profile.go helpers: share defaults and the
4
- * same-organization invariant on agent_ref, the agent-id rebind pin, the
3
+ * and the get_shared_profile.go helpers: share defaults + the cross-org
4
+ * public-dependency contract (decision 013), the agent-id rebind pin, the
5
5
  * update immutability rules, the uniform-NotFound profile resolution
6
6
  * helpers, and the constant-time link-token predicate.
7
7
  *
8
- * A share's agent lives in the share's own organization. The
9
- * cross-organization arm this domain once carried (a share of another
10
- * organization's public agent, gated on a public audience and a sweep of
11
- * the agent's dependencies for public visibility) left with the public
12
- * level; sharing another organization's agent is done by installing the
13
- * plugin that carries it and sharing the installed copy. A stored share
14
- * whose agent is in another organization — a row from before — fails
15
- * closed at the profile like a dangling reference.
16
- *
17
8
  * OD-1 (deliberate exclusion): Go's boot migration
18
9
  * (pkg/domain/agentshare/migration/bootstrap_shares.go — protowire
19
10
  * decoding of the REMOVED Agent.spec.sharing fields into AgentShare rows)
@@ -38,6 +29,11 @@ import type { AgentShare } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v
38
29
  import { AgentShareStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/status_pb";
39
30
  import { SharedAgentProfileSchema } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/io_pb";
40
31
  import type { SharedAgentProfile } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/io_pb";
32
+ import { AgentShareAudience } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/spec_pb";
33
+ import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
34
+ import { SkillSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
35
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
36
+ import type { ApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
41
37
  import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
42
38
  import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
43
39
 
@@ -56,6 +52,7 @@ import {
56
52
  } from "../../pipeline/steps/authorize.js";
57
53
  import type { AuthorizationTarget } from "../../pipeline/steps/authorize.js";
58
54
  import type { GetByReferenceDesc } from "../../pipeline/steps/authorize-resolved-target.js";
55
+ import { findResourceBySlug } from "../../pipeline/steps/helpers.js";
59
56
  import { EXISTING_RESOURCE_KEY } from "../../pipeline/steps/load-existing.js";
60
57
  import type { Store } from "../../store/interface.js";
61
58
  import {
@@ -63,7 +60,8 @@ import {
63
60
  ORG_REQUIRED_MESSAGE,
64
61
  SHARE_LINK_TOKEN_BYTES,
65
62
  agentRefImmutableMessage,
66
- sameOrgInvariantMessage,
63
+ crossOrgAudienceMessage,
64
+ crossOrgBlockersMessage,
67
65
  } from "./constants.js";
68
66
 
69
67
  type AgentShareDesc = typeof AgentShareSchema;
@@ -86,14 +84,21 @@ export const SHARE_ORGANIZATION_DENIED_MESSAGE =
86
84
 
87
85
  /**
88
86
  * The create lane's authorization questions, for AuthorizeResolvedTarget
89
- * after ResolveShareDefaults, agent first: can_edit on the agent (sharing
90
- * puts it in front of a wider audience, an editor's act) and then
91
- * can_create_agent_share on the organization (a share spends the
92
- * organization's credits on the open internet, an admin-level act). The
93
- * RPC is is_skip_authorization because the target is the referenced agent,
94
- * resolved from a slug, not a request field. The resolve step has already
95
- * made the reference absolute and refused an agent outside the share's
96
- * organization, so the two bars are always the same organization's.
87
+ * after ResolveShareDefaults: the two-arm consent bar the Java handler
88
+ * enforced and the model's comment on can_create_agent_share describes.
89
+ * The RPC is is_skip_authorization because the target is the referenced
90
+ * agent, resolved from a slug, not a request field.
91
+ *
92
+ * A same-org share (spec.agent_ref.org equals metadata.org, after the
93
+ * resolve step made the reference absolute) asks can_edit on the agent:
94
+ * sharing puts the agent in front of a wider audience, an editor's act.
95
+ *
96
+ * A cross-org share of another organization's public agent asks two
97
+ * questions, agent first as Java did: can_execute on the agent (whoever may
98
+ * run it may offer it) and then can_create_agent_share on the SHARING
99
+ * organization — a public share spends that organization's credits on the
100
+ * open internet, an admin-level act. The cross-org validity rules (public
101
+ * agent, no org audience, public dependencies) stay the resolve step's.
97
102
  */
98
103
  export function resolveShareCreateTargets(
99
104
  ctx: RequestContext<AgentShareDesc>,
@@ -102,17 +107,24 @@ export function resolveShareCreateTargets(
102
107
  if (agent === undefined) {
103
108
  throw new Error("referenced agent not found in context");
104
109
  }
110
+ const share = ctx.newState;
111
+ const shareOrg = share.metadata?.org ?? "";
112
+ const crossOrg = (share.spec?.agentRef?.org ?? "") !== shareOrg;
113
+ const agentBar: AuthorizationTarget = {
114
+ permission: crossOrg ? IamPermission.can_execute : IamPermission.can_edit,
115
+ resourceKind: ApiResourceKind.agent,
116
+ resourceId: agent.metadata?.id ?? "",
117
+ deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
118
+ };
119
+ if (!crossOrg) {
120
+ return [agentBar];
121
+ }
105
122
  return [
106
- {
107
- permission: IamPermission.can_edit,
108
- resourceKind: ApiResourceKind.agent,
109
- resourceId: agent.metadata?.id ?? "",
110
- deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
111
- },
123
+ agentBar,
112
124
  {
113
125
  permission: IamPermission.can_create_agent_share,
114
126
  resourceKind: ApiResourceKind.organization,
115
- resourceId: ctx.newState.metadata?.org ?? "",
127
+ resourceId: shareOrg,
116
128
  deniedMessage: SHARE_ORGANIZATION_DENIED_MESSAGE,
117
129
  },
118
130
  ];
@@ -294,12 +306,10 @@ export async function findShareByOrgAndSlug(
294
306
  /**
295
307
  * ResolveShareDefaults — Go resolveShareDefaultsStep:
296
308
  * 1. Requires metadata.org (URL + billing identity, never inferred).
297
- * 2. Normalizes spec.agent_ref.org (empty means same-org) and refuses an
298
- * agent_ref that names another organization (the module header) with
299
- * the same-organization sentence, BEFORE any lookup, so the share
300
- * lane never says whether another organization's slug exists.
301
- * 3. Loads the referenced agent — a nonexistent agent is refused with
302
- * the same NOT_FOUND a direct agent lookup would produce.
309
+ * 2. Normalizes spec.agent_ref.org (empty means same-org) and loads the
310
+ * referenced agent — a nonexistent agent is refused with the same
311
+ * NOT_FOUND a direct agent lookup would produce.
312
+ * 3. For a CROSS-ORG share, enforces the decision-013 contract.
303
313
  * 4. Defaults metadata.slug (and name) from the agent when the caller
304
314
  * provided neither — the canonical share keeps the agent's hosted URL.
305
315
  * Runs before ResolveSlug, which skips already-set slugs.
@@ -327,9 +337,6 @@ export function newResolveShareDefaultsStep(
327
337
  if (agentRef!.org === "") {
328
338
  agentRef!.org = metadata!.org;
329
339
  }
330
- if (agentRef!.org !== metadata!.org) {
331
- throw failedPreconditionError(sameOrgInvariantMessage(agentRef!.org));
332
- }
333
340
 
334
341
  const agent = await findAgentByOrgAndSlug(
335
342
  store,
@@ -340,6 +347,10 @@ export function newResolveShareDefaultsStep(
340
347
  throw notFoundError("Agent", agentRef!.slug);
341
348
  }
342
349
 
350
+ if (agentRef!.org !== metadata!.org) {
351
+ await validateCrossOrgShare(store, share, agent);
352
+ }
353
+
343
354
  ctx.set(REFERENCED_AGENT_KEY, agent);
344
355
 
345
356
  // Canonical-share default: no slug and no name means "share this
@@ -353,6 +364,133 @@ export function newResolveShareDefaultsStep(
353
364
  };
354
365
  }
355
366
 
367
+ /**
368
+ * The cross-org share contract (decision 013) — Go validateCrossOrgShare:
369
+ * - The agent must be marketplace-public; a non-public agent is refused
370
+ * with the same NOT_FOUND as a missing one (no existence probe for
371
+ * private slugs).
372
+ * - The audience must be public — org-audience semantics don't carry
373
+ * across the org boundary.
374
+ * - Every declared dependency must itself be public; the refusal names
375
+ * every blocker (sorted) so the sharing org knows exactly what to ask
376
+ * the agent's org to publish.
377
+ * Runtime re-enforcement is cloud-side; this create-time sweep is the
378
+ * fail-loud half, mirrored in both editions.
379
+ */
380
+ async function validateCrossOrgShare(
381
+ store: Store,
382
+ share: AgentShare,
383
+ agent: Agent,
384
+ ): Promise<void> {
385
+ const agentMeta = agent.metadata;
386
+
387
+ if (agentMeta?.visibility !== ApiResourceVisibility.visibility_public) {
388
+ throw notFoundError("Agent", agentMeta?.slug ?? "");
389
+ }
390
+
391
+ // protobuf-es strips the shared enum prefix: proto
392
+ // agent_share_audience_org generates as AgentShareAudience.org.
393
+ if (share.spec?.audience === AgentShareAudience.org) {
394
+ throw failedPreconditionError(crossOrgAudienceMessage(agentMeta.org));
395
+ }
396
+
397
+ const blockers = await findNonPublicDependencies(store, agent);
398
+ if (blockers.length > 0) {
399
+ throw failedPreconditionError(
400
+ crossOrgBlockersMessage(agentMeta.org, agentMeta.slug, blockers),
401
+ );
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Sweeps the agent's declared blueprint dependencies — skill_refs
407
+ * (including every sub-agent's) and mcp_server_usages — and returns a
408
+ * deterministic "kind org/slug" entry for each that is missing or not
409
+ * visibility_public — Go findNonPublicDependencies. A reference with an
410
+ * empty org is relative to the AGENT's org (defensive parity with the
411
+ * cloud edition's referenceMatches; agent writes normalize refs to
412
+ * absolute form).
413
+ */
414
+ async function findNonPublicDependencies(
415
+ store: Store,
416
+ agent: Agent,
417
+ ): Promise<string[]> {
418
+ const spec = agent.spec;
419
+ const agentOrg = agent.metadata?.org ?? "";
420
+
421
+ interface DepRef {
422
+ kind: ApiResourceKind;
423
+ org: string;
424
+ slug: string;
425
+ }
426
+
427
+ const seen = new Set<string>();
428
+ const deps: DepRef[] = [];
429
+ const add = (
430
+ kind: ApiResourceKind,
431
+ ref: ApiResourceReference | undefined,
432
+ ): void => {
433
+ if (ref === undefined || ref.slug === "") {
434
+ return;
435
+ }
436
+ const org = ref.org !== "" ? ref.org : agentOrg;
437
+ const key = `${kind}|${org}|${ref.slug}`;
438
+ if (!seen.has(key)) {
439
+ seen.add(key);
440
+ deps.push({ kind, org, slug: ref.slug });
441
+ }
442
+ };
443
+
444
+ for (const ref of spec?.skillRefs ?? []) {
445
+ add(ApiResourceKind.skill, ref);
446
+ }
447
+ for (const sub of spec?.subAgents ?? []) {
448
+ for (const ref of sub.skillRefs) {
449
+ add(ApiResourceKind.skill, ref);
450
+ }
451
+ }
452
+ for (const usage of spec?.mcpServerUsages ?? []) {
453
+ add(ApiResourceKind.mcp_server, usage.mcpServerRef);
454
+ }
455
+
456
+ const blockers: string[] = [];
457
+ for (const dep of deps) {
458
+ let visibility: ApiResourceVisibility | undefined;
459
+ try {
460
+ // Per-kind resolution, exactly Go's switch — skill and mcp_server
461
+ // are the only dependency kinds an agent blueprint declares.
462
+ const resolved =
463
+ dep.kind === ApiResourceKind.skill
464
+ ? await findResourceBySlug(
465
+ store,
466
+ dep.kind,
467
+ SkillSchema,
468
+ dep.slug,
469
+ dep.org,
470
+ )
471
+ : await findResourceBySlug(
472
+ store,
473
+ dep.kind,
474
+ McpServerSchema,
475
+ dep.slug,
476
+ dep.org,
477
+ );
478
+ visibility = resolved?.metadata?.visibility;
479
+ } catch (error) {
480
+ throw internalError(
481
+ error,
482
+ `failed to resolve ${ApiResourceKind[dep.kind]} ${dep.org}/${dep.slug} while validating cross-org share`,
483
+ );
484
+ }
485
+ if (visibility !== ApiResourceVisibility.visibility_public) {
486
+ blockers.push(`${ApiResourceKind[dep.kind]} ${dep.org}/${dep.slug}`);
487
+ }
488
+ }
489
+
490
+ blockers.sort();
491
+ return blockers;
492
+ }
493
+
356
494
  /**
357
495
  * StampAgentPin — Go stampAgentPinStep: writes status.agent_id, the
358
496
  * server-owned rebind pin (decision 013). agent_ref is org+slug and slugs
@@ -386,8 +524,10 @@ export function newStampAgentPinStep(): PipelineStep<AgentShareDesc> {
386
524
 
387
525
  /**
388
526
  * ValidateShareUpdate — Go validateShareUpdateStep: spec.agent_ref must
389
- * keep referencing the same agent. Runs after LoadExisting.
390
- * metadata.slug/org immutability needs no step — the generic
527
+ * keep referencing the same agent, and the cross-org public-audience rule
528
+ * must hold on update too (update replaces the spec wholesale and must not
529
+ * open a side door to an org-audience cross-org share). Runs after
530
+ * LoadExisting. metadata.slug/org immutability needs no step — the generic
391
531
  * BuildUpdateState preserves both, and status (including the pin and link
392
532
  * token) wholesale.
393
533
  */
@@ -424,6 +564,14 @@ export function newValidateShareUpdateStep(): PipelineStep<AgentShareDesc> {
424
564
  ),
425
565
  );
426
566
  }
567
+
568
+ const isCrossOrg =
569
+ (existingRef?.org ?? "") !== (existing.metadata?.org ?? "");
570
+ if (isCrossOrg && ctx.input.spec?.audience === AgentShareAudience.org) {
571
+ throw failedPreconditionError(
572
+ crossOrgAudienceMessage(existingRef?.org ?? ""),
573
+ );
574
+ }
427
575
  },
428
576
  };
429
577
  }
@@ -435,8 +583,8 @@ export function newValidateShareUpdateStep(): PipelineStep<AgentShareDesc> {
435
583
  * SHARE; display fields and default_instance_id from the AGENT. Three
436
584
  * misses all fail closed with the uniform refusal, indistinguishable from
437
585
  * absence: a dangling agent_ref, a stale agent-id pin (the rebind guard),
438
- * and an agent in another organization (a share written before the
439
- * same-organization invariant; this release serves no such share).
586
+ * and a cross-org agent no longer visibility_public (withdrawing public
587
+ * visibility must kill every external channel).
440
588
  */
441
589
  export async function buildSharedAgentProfile(
442
590
  store: Store,
@@ -457,7 +605,12 @@ export async function buildSharedAgentProfile(
457
605
  throw sharedNotFound(share.metadata?.slug ?? "");
458
606
  }
459
607
 
460
- if ((share.metadata?.org ?? "") !== (agent.metadata?.org ?? "")) {
608
+ const isCrossOrg =
609
+ (share.metadata?.org ?? "") !== (agent.metadata?.org ?? "");
610
+ if (
611
+ isCrossOrg &&
612
+ agent.metadata?.visibility !== ApiResourceVisibility.visibility_public
613
+ ) {
461
614
  throw sharedNotFound(share.metadata?.slug ?? "");
462
615
  }
463
616
 
@@ -63,6 +63,7 @@ import {
63
63
  newAuthorizeResolvedTargetStep,
64
64
  } from "../../pipeline/steps/authorize-resolved-target.js";
65
65
  import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
66
+ import { newAuthorizeVisibilityTransitionStep } from "../../pipeline/steps/visibility-gates.js";
66
67
  import {
67
68
  newBuildNewStateStep,
68
69
  setAuditFieldsForUpdate,
@@ -96,10 +97,7 @@ import {
96
97
  TARGET_RESOURCE_KEY,
97
98
  newLoadTargetStep,
98
99
  } from "../../pipeline/steps/load-target.js";
99
- import {
100
- newNormalizeReferencesStep,
101
- newValidateReferencesStep,
102
- } from "../../pipeline/steps/references.js";
100
+ import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
103
101
  import {
104
102
  newCleanupIamPoliciesStep,
105
103
  newCreateAuthorizationTuplesStep,
@@ -246,7 +244,6 @@ async function update(
246
244
  .addStep(newPreserveRedactedSecretsStep())
247
245
  .addStep(newEncryptSecretValuesStep(deps.secretService, deps.logger))
248
246
  .addStep(newNormalizeReferencesStep())
249
- .addStep(newValidateReferencesStep(deps.store))
250
247
  .addStep(newPersistStep(deps.store))
251
248
  .addStep(
252
249
  newDestroyDroppedEnvironmentSecretsStep(deps.secretService, deps.logger),
@@ -401,6 +398,12 @@ async function updateVisibility(
401
398
  // After load, per the cross-edition error precedence: unknown id +
402
399
  // bad level = NOT_FOUND on both editions.
403
400
  .addStep(newValidateVisibilityUpdateStep())
401
+ .addStep(
402
+ newAuthorizeVisibilityTransitionStep(
403
+ UPDATE_VISIBILITY_ENVIRONMENT_KEY,
404
+ deps.authorizer,
405
+ ),
406
+ )
404
407
  .addStep(newValidateEnvironmentShareRestrictionStep())
405
408
  .addStep(newSetEnvironmentVisibilityStep())
406
409
  .addStep(newPersistEnvironmentForVisibilityUpdateStep(deps.store))
@@ -82,10 +82,7 @@ import {
82
82
  TARGET_RESOURCE_KEY,
83
83
  newLoadTargetStep,
84
84
  } from "../../pipeline/steps/load-target.js";
85
- import {
86
- newNormalizeReferencesStep,
87
- newValidateReferencesStep,
88
- } from "../../pipeline/steps/references.js";
85
+ import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
89
86
  import {
90
87
  newCleanupIamPoliciesStep,
91
88
  newCreateAuthorizationTuplesStep,
@@ -189,7 +186,6 @@ async function createExecutionContext(
189
186
  .addStep(newBuildNewStateStep())
190
187
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
191
188
  .addStep(newNormalizeReferencesStep())
192
- .addStep(newValidateReferencesStep(deps.store))
193
189
  .addStep(newEncryptSecretValuesStep(deps.secretService, deps.logger))
194
190
  .addStep(newPersistStep(deps.store))
195
191
  .addStep(