@stigmer/server 3.22.1 → 3.23.1-dev.20260923075205

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 (329) 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 +4 -8
  10. package/dist/authorization/authorizer.d.ts.map +1 -1
  11. package/dist/authorization/authorizer.js +5 -9
  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 +10 -25
  15. package/dist/authorization/derived-tuples.js.map +1 -1
  16. package/dist/authorization/evaluator.d.ts +7 -8
  17. package/dist/authorization/evaluator.d.ts.map +1 -1
  18. package/dist/authorization/evaluator.js +4 -20
  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 +5 -9
  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 +4 -5
  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 +3 -4
  34. package/dist/authorization/model/plugin.js.map +1 -1
  35. package/dist/authorization/model/rewrite.d.ts +8 -10
  36. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  37. package/dist/authorization/model/rewrite.js +0 -3
  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 +2 -3
  50. package/dist/authorization/organization-directory.js.map +1 -1
  51. package/dist/authorization/store-test-kit.d.ts +0 -6
  52. package/dist/authorization/store-test-kit.d.ts.map +1 -1
  53. package/dist/authorization/store-test-kit.js +16 -62
  54. package/dist/authorization/store-test-kit.js.map +1 -1
  55. package/dist/authorization/tuples.d.ts +13 -32
  56. package/dist/authorization/tuples.d.ts.map +1 -1
  57. package/dist/authorization/tuples.js +3 -11
  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 +3 -1
  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 +3 -1
  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 +3 -4
  80. package/dist/domain/agentinstance/controller.js.map +1 -1
  81. package/dist/domain/agentshare/constants.d.ts +6 -11
  82. package/dist/domain/agentshare/constants.d.ts.map +1 -1
  83. package/dist/domain/agentshare/constants.js +8 -16
  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 +3 -1
  87. package/dist/domain/agentshare/controller.js.map +1 -1
  88. package/dist/domain/agentshare/steps.d.ts +18 -25
  89. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  90. package/dist/domain/agentshare/steps.js +41 -142
  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 +2 -3
  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 +2 -1
  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 +3 -4
  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 +9 -11
  104. package/dist/domain/plugin/controller.js.map +1 -1
  105. package/dist/domain/plugin/push.d.ts +7 -5
  106. package/dist/domain/plugin/push.d.ts.map +1 -1
  107. package/dist/domain/plugin/push.js +8 -14
  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 +3 -1
  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 +3 -2
  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 +33 -24
  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/agent-call-references.d.ts +54 -0
  140. package/dist/domain/workflow/agent-call-references.d.ts.map +1 -0
  141. package/dist/domain/workflow/agent-call-references.js +97 -0
  142. package/dist/domain/workflow/agent-call-references.js.map +1 -0
  143. package/dist/domain/workflow/controller.d.ts.map +1 -1
  144. package/dist/domain/workflow/controller.js +14 -6
  145. package/dist/domain/workflow/controller.js.map +1 -1
  146. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
  147. package/dist/domain/workflow/validation/task-config-constraints.d.ts +10 -1
  148. package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
  149. package/dist/domain/workflow/validation/task-config-constraints.js +3 -2
  150. package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
  151. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  152. package/dist/domain/workflowexecution/controller.js +4 -2
  153. package/dist/domain/workflowexecution/controller.js.map +1 -1
  154. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  155. package/dist/domain/workflowinstance/controller.js +3 -4
  156. package/dist/domain/workflowinstance/controller.js.map +1 -1
  157. package/dist/extensions/authorization-queries.d.ts +6 -5
  158. package/dist/extensions/authorization-queries.d.ts.map +1 -1
  159. package/dist/extensions/list-read-scope.d.ts +1 -1
  160. package/dist/extensions/resource-authorization.d.ts +3 -2
  161. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  162. package/dist/index.d.ts +1 -1
  163. package/dist/index.d.ts.map +1 -1
  164. package/dist/index.js.map +1 -1
  165. package/dist/pipeline/apiresource-meta.d.ts +12 -3
  166. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  167. package/dist/pipeline/apiresource-meta.js +21 -10
  168. package/dist/pipeline/apiresource-meta.js.map +1 -1
  169. package/dist/pipeline/steps/authorization-tuples.d.ts +9 -3
  170. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  171. package/dist/pipeline/steps/authorization-tuples.js +9 -11
  172. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  173. package/dist/pipeline/steps/references.d.ts +178 -20
  174. package/dist/pipeline/steps/references.d.ts.map +1 -1
  175. package/dist/pipeline/steps/references.js +344 -43
  176. package/dist/pipeline/steps/references.js.map +1 -1
  177. package/dist/pipeline/steps/resolve-artifact-source.d.ts +11 -8
  178. package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -1
  179. package/dist/pipeline/steps/resolve-artifact-source.js +8 -4
  180. package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -1
  181. package/dist/query/search/controller.js +0 -1
  182. package/dist/query/search/controller.js.map +1 -1
  183. package/dist/query/search/criteria.d.ts +1 -5
  184. package/dist/query/search/criteria.d.ts.map +1 -1
  185. package/dist/query/search/criteria.js +3 -13
  186. package/dist/query/search/criteria.js.map +1 -1
  187. package/dist/query/search/handler.d.ts +5 -4
  188. package/dist/query/search/handler.d.ts.map +1 -1
  189. package/dist/query/search/handler.js +7 -6
  190. package/dist/query/search/handler.js.map +1 -1
  191. package/dist/query/search/query-store.d.ts.map +1 -1
  192. package/dist/query/search/query-store.js +0 -2
  193. package/dist/query/search/query-store.js.map +1 -1
  194. package/dist/store/interface.d.ts +3 -6
  195. package/dist/store/interface.d.ts.map +1 -1
  196. package/dist/store/interface.js.map +1 -1
  197. package/dist/store/postgres/migrations.d.ts +3 -1
  198. package/dist/store/postgres/migrations.d.ts.map +1 -1
  199. package/dist/store/postgres/migrations.js +35 -1
  200. package/dist/store/postgres/migrations.js.map +1 -1
  201. package/dist/store/postgres/store.d.ts.map +1 -1
  202. package/dist/store/postgres/store.js +4 -9
  203. package/dist/store/postgres/store.js.map +1 -1
  204. package/dist/store/public-visibility-retired.d.ts +67 -0
  205. package/dist/store/public-visibility-retired.d.ts.map +1 -0
  206. package/dist/store/public-visibility-retired.js +55 -0
  207. package/dist/store/public-visibility-retired.js.map +1 -0
  208. package/dist/store/sqlite/migrations.d.ts +3 -1
  209. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  210. package/dist/store/sqlite/migrations.js +36 -1
  211. package/dist/store/sqlite/migrations.js.map +1 -1
  212. package/dist/store/sqlite/store.d.ts.map +1 -1
  213. package/dist/store/sqlite/store.js +4 -8
  214. package/dist/store/sqlite/store.js.map +1 -1
  215. package/package.json +6 -6
  216. package/src/artifactstorage/__tests__/artifact-storage.test.ts +36 -33
  217. package/src/artifactstorage/__tests__/r2-storage.test.ts +11 -13
  218. package/src/artifactstorage/artifact-storage.ts +37 -33
  219. package/src/artifactstorage/r2-storage.ts +6 -15
  220. package/src/authorization/README.md +24 -26
  221. package/src/authorization/__tests__/authorizer.test.ts +10 -9
  222. package/src/authorization/__tests__/derived-tuples.test.ts +4 -11
  223. package/src/authorization/__tests__/evaluator.test.ts +14 -73
  224. package/src/authorization/__tests__/facts.test.ts +2 -2
  225. package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +19 -27
  226. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +6 -98
  227. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +4 -61
  228. package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +1 -15
  229. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +1 -21
  230. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +1 -25
  231. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +1 -3
  232. package/src/authorization/__tests__/list-read-scope.test.ts +18 -17
  233. package/src/authorization/__tests__/store-tests.test.ts +2 -6
  234. package/src/authorization/__tests__/tuples.test.ts +12 -11
  235. package/src/authorization/authorizer.ts +4 -9
  236. package/src/authorization/derived-tuples.ts +14 -31
  237. package/src/authorization/evaluator.ts +8 -44
  238. package/src/authorization/list-read-scope.ts +5 -11
  239. package/src/authorization/model/agent.ts +2 -5
  240. package/src/authorization/model/agent_instance.ts +0 -2
  241. package/src/authorization/model/mcp_server.ts +0 -2
  242. package/src/authorization/model/plugin.ts +1 -4
  243. package/src/authorization/model/rewrite.ts +8 -13
  244. package/src/authorization/model/skill.ts +0 -2
  245. package/src/authorization/model/workflow.ts +0 -2
  246. package/src/authorization/model/workflow_instance.ts +0 -2
  247. package/src/authorization/organization-directory.ts +1 -3
  248. package/src/authorization/store-test-kit.ts +16 -75
  249. package/src/authorization/tuples.ts +16 -39
  250. package/src/boot/__tests__/skill-transfer-origin.test.ts +72 -0
  251. package/src/boot/compose.ts +62 -25
  252. package/src/boot/config.ts +4 -3
  253. package/src/boot/skill-transfer-origin.ts +76 -0
  254. package/src/domain/agent/__tests__/agent.test.ts +11 -4
  255. package/src/domain/agent/controller.ts +7 -7
  256. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +223 -48
  257. package/src/domain/agentchannel/controller.ts +6 -1
  258. package/src/domain/agentexecution/controller.ts +6 -1
  259. package/src/domain/agentinstance/controller.ts +6 -12
  260. package/src/domain/agentshare/__tests__/agentshare.test.ts +196 -172
  261. package/src/domain/agentshare/__tests__/create-authorization.test.ts +16 -31
  262. package/src/domain/agentshare/constants.ts +14 -26
  263. package/src/domain/agentshare/controller.ts +6 -1
  264. package/src/domain/agentshare/steps.ts +41 -194
  265. package/src/domain/environment/controller.ts +5 -8
  266. package/src/domain/executioncontext/controller.ts +5 -1
  267. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +115 -28
  268. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +53 -18
  269. package/src/domain/mcpserver/controller.ts +6 -12
  270. package/src/domain/plugin/controller.ts +16 -25
  271. package/src/domain/plugin/push.ts +8 -16
  272. package/src/domain/schedule/controller.ts +6 -1
  273. package/src/domain/session/controller.ts +12 -4
  274. package/src/domain/skill/__tests__/skill.test.ts +5 -3
  275. package/src/domain/skill/__tests__/slots.test.ts +113 -60
  276. package/src/domain/skill/__tests__/staging.test.ts +304 -0
  277. package/src/domain/skill/constants.ts +28 -3
  278. package/src/domain/skill/controller.ts +44 -42
  279. package/src/domain/skill/push.ts +3 -3
  280. package/src/domain/skill/transfer/handler.ts +33 -15
  281. package/src/domain/skill/transfer/slots.ts +89 -100
  282. package/src/domain/skill/transfer/staging.ts +191 -0
  283. package/src/domain/workflow/__tests__/agent-call-references.test.ts +222 -0
  284. package/src/domain/workflow/agent-call-references.ts +157 -0
  285. package/src/domain/workflow/controller.ts +28 -10
  286. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
  287. package/src/domain/workflow/validation/task-config-constraints.ts +7 -3
  288. package/src/domain/workflowexecution/controller.ts +7 -2
  289. package/src/domain/workflowinstance/controller.ts +6 -12
  290. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +32 -19
  291. package/src/extensions/__tests__/extension-composition.test.ts +4 -4
  292. package/src/extensions/__tests__/list-read-scope-composed.test.ts +9 -6
  293. package/src/extensions/authorization-queries.ts +6 -5
  294. package/src/extensions/list-read-scope.ts +1 -1
  295. package/src/extensions/resource-authorization.ts +3 -5
  296. package/src/index.ts +0 -1
  297. package/src/pipeline/__tests__/supports-visibility.test.ts +112 -0
  298. package/src/pipeline/apiresource-meta.ts +21 -10
  299. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +18 -31
  300. package/src/pipeline/steps/__tests__/references.test.ts +703 -0
  301. package/src/pipeline/steps/authorization-tuples.ts +9 -11
  302. package/src/pipeline/steps/references.ts +578 -70
  303. package/src/pipeline/steps/resolve-artifact-source.ts +20 -13
  304. package/src/query/search/__tests__/criteria.test.ts +0 -4
  305. package/src/query/search/__tests__/query-store.test.ts +11 -40
  306. package/src/query/search/controller.ts +0 -1
  307. package/src/query/search/criteria.ts +0 -14
  308. package/src/query/search/handler.ts +6 -7
  309. package/src/query/search/query-store.ts +0 -2
  310. package/src/store/__tests__/public-visibility-retired.test.ts +127 -0
  311. package/src/store/__tests__/store-contract.ts +6 -51
  312. package/src/store/interface.ts +3 -6
  313. package/src/store/postgres/__tests__/migrations.test.ts +187 -6
  314. package/src/store/postgres/__tests__/store-contract.test.ts +0 -2
  315. package/src/store/postgres/migrations.ts +48 -1
  316. package/src/store/postgres/store.ts +4 -11
  317. package/src/store/public-visibility-retired.ts +119 -0
  318. package/src/store/sqlite/__tests__/migrations.test.ts +191 -5
  319. package/src/store/sqlite/migrations.ts +45 -1
  320. package/src/store/sqlite/store.ts +4 -10
  321. package/src/transport/registry/__tests__/lanes.test.ts +1 -1
  322. package/dist/pipeline/steps/visibility-gates.d.ts +0 -27
  323. package/dist/pipeline/steps/visibility-gates.d.ts.map +0 -1
  324. package/dist/pipeline/steps/visibility-gates.js +0 -139
  325. package/dist/pipeline/steps/visibility-gates.js.map +0 -1
  326. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +0 -98
  327. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +0 -52
  328. package/src/pipeline/steps/__tests__/visibility-gates.test.ts +0 -187
  329. package/src/pipeline/steps/visibility-gates.ts +0 -174
@@ -58,17 +58,15 @@ export class ArtifactStorageNotFoundError extends Error {
58
58
  }
59
59
 
60
60
  /**
61
- * A staged upload minted by presignPut: the URL receives the bytes, the
62
- * stagingKey reads them back through the same driver. Staged blobs are
63
- * short-lived by contract — the local lane sweeps them on TTL expiry and
64
- * boot; R2 deployments configure a bucket lifecycle rule on the staging
65
- * prefix (the §6b driver-side sweep expectation).
61
+ * A staged upload minted by presignPut: the URL receives the bytes, which
62
+ * the caller reads back through download() under the key IT named. Staged
63
+ * blobs are short-lived by contract — the local lane sweeps them on TTL
64
+ * expiry and boot; a bucket deployment configures a lifecycle rule on the
65
+ * domain's staging prefix (the §6b driver-side sweep expectation).
66
66
  */
67
67
  export interface PresignedUpload {
68
- /** Accepts one HTTP PUT of exactly the declared byte count. */
68
+ /** Accepts an HTTP PUT of exactly the declared byte count. */
69
69
  readonly url: string;
70
- /** Driver key where the staged bytes land, readable via download(). */
71
- readonly stagingKey: string;
72
70
  /** The TTL actually granted, after per-driver clamping. */
73
71
  readonly ttlMs: number;
74
72
  }
@@ -98,18 +96,25 @@ export interface ArtifactStorage {
98
96
  downloadFilename: string,
99
97
  ): Promise<string>;
100
98
  /**
101
- * A time-limited upload URL for a staging-prefixed blob of exactly
102
- * declaredSizeBytes (§6b). Per-driver semantics differ DELIBERATELY and
103
- * are contract, not accident: the local backend rides the skill transfer
104
- * lane's URL-as-credential slot mechanism (single-use, exact-size
105
- * enforced by the lane, TTL clamped to the lane's slot TTL) and answers
106
- * only on instances with a staged-upload lane wired — unwired instances
107
- * throw the explicit not-configured error, never a silent no-op. The R2
108
- * backend presigns a PUT (repeatable within its TTL, size enforced by
109
- * the signed Content-Length header, TTL clamped to the 7-day R2
110
- * maximum).
99
+ * A time-limited upload URL for a blob of exactly declaredSizeBytes at
100
+ * the key the CALLER names (§6b). The key is the domain's: it chooses
101
+ * the staging prefix its sweep targets and the mapping from its wire
102
+ * reference, and reads the bytes back through download(key) — the
103
+ * driver never invents a key of its own. Per-driver semantics differ
104
+ * DELIBERATELY and are contract, not accident: the local backend rides
105
+ * the skill transfer lane's URL-as-credential slot mechanism
106
+ * (single-use, exact-size enforced by the lane, TTL clamped to the
107
+ * lane's slot TTL) and answers only on instances with a staged-upload
108
+ * lane wired — unwired instances throw the explicit not-configured
109
+ * error, never a silent no-op. The R2 backend presigns a PUT
110
+ * (repeatable within its TTL, size enforced by the signed
111
+ * Content-Length header, TTL clamped to the 7-day R2 maximum).
111
112
  */
112
- presignPut(declaredSizeBytes: number, ttlMs: number): Promise<PresignedUpload>;
113
+ presignPut(
114
+ key: string,
115
+ declaredSizeBytes: number,
116
+ ttlMs: number,
117
+ ): Promise<PresignedUpload>;
113
118
  /** Removes the artifact; missing is not an error. */
114
119
  delete(key: string): Promise<void>;
115
120
  /** Whether an artifact with the key exists. */
@@ -136,16 +141,16 @@ export type ArtifactStorageDriverFactory = () => ArtifactStorage;
136
141
  * the shape it needs and stays ignorant of who provides it.
137
142
  */
138
143
  export interface StagedUploadLane {
139
- /** Reserves a single-use upload slot; returns its reference + TTL. */
140
- mint(declaredSizeBytes: number): { ref: string; ttlMs: number };
141
- /** The externally-reachable PUT URL for a minted reference. */
142
- uploadUrl(ref: string): string;
143
144
  /**
144
- * The driver key where the reference's staged bytes land — MUST resolve
145
- * inside the driver instance's root, or download(stagingKey) could
146
- * never read what the lane received.
145
+ * Reserves a single-use upload slot whose bytes land at `key` under this
146
+ * driver instance's root — the lane stages into the driver's own tree,
147
+ * so download(key) reads exactly what the lane received. Returns the
148
+ * externally-reachable PUT URL and the TTL the lane grants.
147
149
  */
148
- stagedKey(ref: string): string;
150
+ reserve(
151
+ key: string,
152
+ declaredSizeBytes: number,
153
+ ): { url: string; ttlMs: number };
149
154
  }
150
155
 
151
156
  export interface ArtifactStorageConfig {
@@ -259,6 +264,7 @@ export class LocalArtifactStorage implements ArtifactStorage {
259
264
  }
260
265
 
261
266
  async presignPut(
267
+ key: string,
262
268
  declaredSizeBytes: number,
263
269
  _ttlMs: number,
264
270
  ): Promise<PresignedUpload> {
@@ -267,15 +273,13 @@ export class LocalArtifactStorage implements ArtifactStorage {
267
273
  "local presigned uploads not configured - no staged-upload lane is wired to this store instance",
268
274
  );
269
275
  }
276
+ // The key must be one this instance can read back, or the lane would
277
+ // stage bytes download(key) can never reach.
278
+ this.resolveWithinRoot(key);
270
279
  // The lane's slot TTL governs, not the caller's ask — the slot
271
280
  // registry sweeps on ITS clock, and a URL outliving its slot would be
272
281
  // a credential for nothing.
273
- const { ref, ttlMs } = this.stagedUploadLane.mint(declaredSizeBytes);
274
- return {
275
- url: this.stagedUploadLane.uploadUrl(ref),
276
- stagingKey: this.stagedUploadLane.stagedKey(ref),
277
- ttlMs,
278
- };
282
+ return this.stagedUploadLane.reserve(key, declaredSizeBytes);
279
283
  }
280
284
 
281
285
  async getSignedUrl(
@@ -9,8 +9,6 @@
9
9
  * that have logic: config validation copy, the 7-day presign clamp, the
10
10
  * signed Content-Disposition, and the not-found mapping.
11
11
  */
12
- import { randomBytes } from "node:crypto";
13
-
14
12
  import {
15
13
  DeleteObjectCommand,
16
14
  GetObjectCommand,
@@ -30,13 +28,6 @@ import {
30
28
  /** Go: "R2 has a maximum expiration of 7 days" — presigns clamp here. */
31
29
  export const R2_MAX_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000;
32
30
 
33
- /**
34
- * Key prefix for presignPut staging blobs (§6b). Pinned as the surface a
35
- * deployment's bucket lifecycle rule targets: the driver mints under it,
36
- * operations sweeps it — changing it orphans staged blobs from the sweep.
37
- */
38
- export const R2_STAGING_PREFIX = "staging/";
39
-
40
31
  /**
41
32
  * Go get_content/get_download_url wrap their storage calls in a 30s
42
33
  * context timeout. The TS ArtifactStorage interface carries no signal, so
@@ -167,17 +158,17 @@ export class R2ArtifactStorage implements ArtifactStorage {
167
158
  }
168
159
 
169
160
  async presignPut(
161
+ key: string,
170
162
  declaredSizeBytes: number,
171
163
  ttlMs: number,
172
164
  ): Promise<PresignedUpload> {
173
165
  const clampedMs = Math.min(ttlMs, R2_MAX_EXPIRATION_MS);
174
- // Random staging key: the URL is the credential (unguessable), and the
175
- // prefix is the contract surface a bucket lifecycle rule sweeps (§6b —
176
- // staged uploads the domain never committed must not accrete forever).
177
- const stagingKey = `${R2_STAGING_PREFIX}${randomBytes(16).toString("hex")}`;
166
+ // The key is the caller's: the domain names its staging prefix (the
167
+ // surface a bucket lifecycle rule sweeps) and keeps the unguessable
168
+ // part of the URL-as-credential in the reference it hands the client.
178
169
  const command = new PutObjectCommand({
179
170
  Bucket: this.bucket,
180
- Key: stagingKey,
171
+ Key: key,
181
172
  // Signed into the URL: a PUT whose body disagrees with the declared
182
173
  // size fails the signature check — R2's arm of the exact-size
183
174
  // contract the local lane enforces by counting bytes.
@@ -187,7 +178,7 @@ export class R2ArtifactStorage implements ArtifactStorage {
187
178
  const url = await this.presign(this.client, command, {
188
179
  expiresIn: Math.floor(clampedMs / 1000),
189
180
  });
190
- return { url, stagingKey, ttlMs: clampedMs };
181
+ return { url, ttlMs: clampedMs };
191
182
  } catch (error) {
192
183
  throw new Error(`r2 presign failed: ${errorText(error)}`, { cause: error });
193
184
  }
@@ -34,9 +34,9 @@ editions; the cloud stores what open source computes.
34
34
  `spec.execution_visibility`).
35
35
  - `tuples.ts` — the tuple vocabulary (object, relation, subject; the string
36
36
  notation), the `Person` type (the caller as the model sees them: account id
37
- plus the aliases a creator stamp may carry), `CheckContext` (the
38
- `allow_public` parameter: `allow: true` on a point check, `false` in a listing
39
- — the cloud's own posture).
37
+ plus the aliases a creator stamp may carry). The model declares no wildcard
38
+ subject and no condition, so a check carries no context and the parser refuses
39
+ the `type:*` notation.
40
40
  - `person.ts` — the one construction of a `Person`: `resolvePerson` reads the
41
41
  caller's account through the port the way whoAmI does, `personFor` builds the
42
42
  aliases (the account id and the issuer subject; an email is nobody's) and
@@ -70,8 +70,8 @@ editions; the cloud stores what open source computes.
70
70
 
71
71
  - `authorizer.ts` — the `Authorizer` driver, arm for arm the cloud's
72
72
  (`stigmer-cloud src/authorizer/fga-authorizer.ts`): the four pre-check denials
73
- with the Java copy; a kind this edition does not serve denied (so nobody sets
74
- public visibility on a self-host); the target loaded once through the source;
73
+ with the Java copy; a kind this edition does not serve denied (a platform
74
+ capability no self-host holds); the target loaded once through the source;
75
75
  `not-found` for a missing row except on the kinds the cloud never probes
76
76
  (`NOT_FOUND_EXEMPT_KINDS`: `identity_account`, `iam_policy` — account ids
77
77
  cannot be enumerated); the model's answer with an empty reason on a denial so
@@ -87,15 +87,14 @@ editions; the cloud stores what open source computes.
87
87
  counts against the schedule instead of retrying forever.
88
88
  - `list-read-scope.ts` — the `ListReadScope` driver, the cloud's twin
89
89
  (`stigmer-cloud src/iam/list-read-scope.ts`): every candidate a list lane
90
- offers is answered by `can_view` under the listing context (`allow: false`,
91
- the public wildcard suppressed) — one evaluator walk per candidate over one
92
- source seeded with the candidates' facts, so no candidate row is read twice
93
- and a parent hop reads each distinct parent once; the enumeration verb
94
- (search, recent activity, the two execution summaries — the console library
95
- rides it) scans the kind and evaluates the same way, a row that does not
96
- decode skipped; the `internal` class keeps everything (the in-process skip); a
97
- fault throws and is never an empty answer; an undeclared kind is a consumer
98
- bug, loud.
90
+ offers is answered by `can_view`, the same question a get asks — one evaluator
91
+ walk per candidate over one source seeded with the candidates' facts, so no
92
+ candidate row is read twice and a parent hop reads each distinct parent once;
93
+ the enumeration verb (search, recent activity, the two execution summaries —
94
+ the console library rides it) scans the kind and evaluates the same way, a row
95
+ that does not decode skipped; the `internal` class keeps everything (the
96
+ in-process skip); a fault throws and is never an empty answer; an undeclared
97
+ kind is a consumer bug, loud.
99
98
  - `posture.ts` — the three postures, named once for the composition root and the
100
99
  boot log.
101
100
 
@@ -110,15 +109,14 @@ kind. `model/__tests__/registry.test.ts` pins the declared set to the
110
109
  open-source tier and each kind's wire permissions to its file;
111
110
  `__tests__/wire-permissions.test.ts` pins that every static `(kind, permission)`
112
111
  a served RPC asks about is a declared relation. The rest pin the machinery:
113
- alias matching, the wildcard's condition, the memo, the bounds, the source and
114
- the two derived rules on both store drivers. The four drivers are pinned arm by
115
- arm on both store drivers (`__tests__/authorizer.test.ts`,
116
- `organization-directory.test.ts`, `schedule-fire-caller.test.ts`,
117
- `list-read-scope.test.ts` — the adversarial cells first: the outsider, the
118
- viewer rung, the admin who does not read members' conversations, the orphaned
119
- execution, the memory with no subject), the posture at the wire over three real
120
- boots (`extensions/__tests__/built-in-authorization-composed.test.ts`, the list
121
- lanes included, and the two-boot proof that the sole person's lists are
122
- byte-identical with and without the scope), and the scope's cost is measured
123
- rather than assumed (`list-read-scope.measure.test.ts`, gated on
124
- `AUTHORIZATION_MEASURE=1`).
112
+ alias matching, the memo, the bounds, the source and the two derived rules on
113
+ both store drivers. The four drivers are pinned arm by arm on both store drivers
114
+ (`__tests__/authorizer.test.ts`, `organization-directory.test.ts`,
115
+ `schedule-fire-caller.test.ts`, `list-read-scope.test.ts` — the adversarial
116
+ cells first: the outsider, the viewer rung, the admin who does not read members'
117
+ conversations, the orphaned execution, the memory with no subject), the posture
118
+ at the wire over three real boots
119
+ (`extensions/__tests__/built-in-authorization-composed.test.ts`, the list lanes
120
+ included, and the two-boot proof that the sole person's lists are byte-identical
121
+ with and without the scope), and the scope's cost is measured rather than
122
+ assumed (`list-read-scope.measure.test.ts`, gated on `AUTHORIZATION_MEASURE=1`).
@@ -2,8 +2,7 @@
2
2
  * Pins the built-in Authorizer arm by arm, on both store drivers, against
3
3
  * the cloud's driver it mirrors (stigmer-cloud src/authorizer/
4
4
  * fga-authorizer.ts): the four pre-check denials with the Java copy; the
5
- * unserved-kind denial (the server-side half of "nobody sets public
6
- visibility on a self-host"); not-found for a
5
+ * unserved-kind denial (a platform capability no self-host holds); not-found for a
7
6
  * missing target and a DENIAL for a missing row of an exempt kind (the
8
7
  * cloud's probe scope, so account ids cannot be enumerated); allow and
9
8
  * deny from the model over a seeded organization — the owner, an admin, a
@@ -222,9 +221,11 @@ describe.each(driverFixtures(SEEDED_KINDS))(
222
221
  await grant(orgRole(FOUNDER.accountId, "owner", "acme"));
223
222
  await grant(orgRole(ADMIN.accountId, "admin", "acme"));
224
223
  await grant(orgRole(MEMBER.accountId, "member", "acme"));
225
- // The founder's blueprints: one private, one org-visible, one
226
- // public; the org-visible one stamped with the founder's RAW
227
- // subject (a row a 3.14.x verifier wrote), the others with the id.
224
+ // The founder's blueprints: one private, one org-visible, and one
225
+ // still carrying the retired public level (a row the store
226
+ // migration has not met); the org-visible one stamped with the
227
+ // founder's RAW subject (a row a 3.14.x verifier wrote), the
228
+ // others with the id.
228
229
  await seed("agent", "agt_private", {
229
230
  org: "acme",
230
231
  visibility: ApiResourceVisibility.visibility_private,
@@ -287,10 +288,10 @@ describe.each(driverFixtures(SEEDED_KINDS))(
287
288
  UNKNOWN_KIND_DENY_REASON,
288
289
  ],
289
290
  [
290
- "a kind this edition does not serve (platform — nobody sets public visibility)",
291
+ "a kind this edition does not serve (platform — nobody holds an operator capability)",
291
292
  resolved(FOUNDER),
292
293
  check(
293
- IamPermission.can_set_public_visibility,
294
+ IamPermission.can_view_provider_standing,
294
295
  ApiResourceKind.platform,
295
296
  "stigmer",
296
297
  ),
@@ -465,7 +466,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
465
466
  });
466
467
  });
467
468
 
468
- it("an unprovisioned subject reads a PUBLIC agent (the point-check context honours the wildcard) and nothing private", async () => {
469
+ it("an unprovisioned subject reads nothing — not a private agent, and not a row still carrying the retired public level, which grants no one anything", async () => {
469
470
  const auth = authorizer();
470
471
  expect(
471
472
  await auth.authorize(
@@ -476,7 +477,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
476
477
  "agt_public",
477
478
  ),
478
479
  ),
479
- ).toEqual({ kind: "allow" });
480
+ ).toEqual({ kind: "deny", reason: "" });
480
481
  expect(
481
482
  await auth.authorize(
482
483
  idpShaped(STRANGER),
@@ -3,8 +3,7 @@
3
3
  * built-in authorizer: which tuples a stored row stands for, in exactly
4
4
  * the shapes the cloud's tuple driver writes (stigmer-cloud
5
5
  * iam/tuple-lifecycle.ts: `organization:<org>#viewer` for the org level,
6
- * the conditional `identity_account:*` for public, the owner by the
7
- * kind's attribution, the parent links by `kind_meta`). Two facts are the
6
+ * the owner by the kind's attribution, the parent links by `kind_meta`). Two facts are the
8
7
  * OSS edition's own and are pinned here by name: the organization's owner
9
8
  * is a ROW (2b's role lifecycle), never derived from its creator stamp,
10
9
  * or a revoked founder would stay owner; and a stamp that names no person
@@ -96,7 +95,7 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
96
95
  ]);
97
96
  });
98
97
 
99
- it("a public blueprint adds the conditional wildcard AND keeps the org floor", () => {
98
+ it("a row that still carries the retired public level derives no viewer tuple at all — no shape reaches every account, and the level's own org floor left with it", () => {
100
99
  expect(
101
100
  derivedFor("skill", {
102
101
  visibility: ApiResourceVisibility.visibility_public,
@@ -104,8 +103,6 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
104
103
  ).toEqual([
105
104
  "skill:skill-1#organization@organization:acme",
106
105
  "skill:skill-1#owner@identity_account:ida_carol",
107
- "skill:skill-1#viewer@identity_account:* with allow_public",
108
- "skill:skill-1#viewer@organization:acme#viewer",
109
106
  ]);
110
107
  });
111
108
 
@@ -166,7 +163,7 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
166
163
  ).toEqual(["memory:memory-1#organization@organization:acme"]);
167
164
  });
168
165
 
169
- it("an environment carries its creator tuple, an org-viewer at org level, and NO public wildcard (the kind's ceiling)", () => {
166
+ it("an environment carries its creator tuple and an org-viewer at org level, and nothing beyond its org ceiling", () => {
170
167
  expect(
171
168
  derivedFor("environment", {
172
169
  visibility: ApiResourceVisibility.visibility_org,
@@ -179,7 +176,7 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
179
176
  ]);
180
177
  expect(
181
178
  derivedFor("environment", {
182
- visibility: ApiResourceVisibility.visibility_public,
179
+ visibility: ApiResourceVisibility.visibility_platform,
183
180
  }),
184
181
  ).toEqual([
185
182
  "environment:environment-1#organization@organization:acme",
@@ -509,9 +506,6 @@ describe.each(driverFixtures(SEEDED_KINDS))(
509
506
  object,
510
507
  "can_view",
511
508
  DAVE,
512
- {
513
- allow: false,
514
- },
515
509
  ),
516
510
  ).toBe(true);
517
511
  expect(rowReads).toBe(1);
@@ -707,7 +701,6 @@ describe.each(driverFixtures(SEEDED_KINDS))(
707
701
  parseObjectRef(object),
708
702
  relation,
709
703
  person,
710
- { allow: true },
711
704
  );
712
705
  }
713
706
 
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * Pins the evaluator's semantics the store tests cannot express (the
3
3
  * cloud's `.fga.yaml` documents prove the model's answers; this file
4
- * proves the machinery under them): how a person matches a tuple, what
5
- * the `allow_public` context does, that a direct tuple outside the line's
6
- * type restriction is ignored (model drift fails closed), how far a
7
- * resolution may walk, and that a declaration cycle or an undeclared
8
- * target is a thrown fault and never a silent deny.
4
+ * proves the machinery under them): how a person matches a tuple, that a
5
+ * direct tuple outside the line's type restriction is ignored (model drift
6
+ * fails closed), how far a resolution may walk, and that a declaration
7
+ * cycle or an undeclared target is a thrown fault and never a silent deny.
9
8
  *
10
9
  * The fixture source is the in-memory one the store-test kit uses, so the
11
10
  * two proofs share one tuple vocabulary. Where a case needs a shape the
@@ -30,7 +29,6 @@ import {
30
29
  direct,
31
30
  from,
32
31
  objectOf,
33
- publicWith,
34
32
  union,
35
33
  usersetOf,
36
34
  } from "../model/rewrite.js";
@@ -56,22 +54,17 @@ function person(accountId: string, ...aliases: string[]): Person {
56
54
  return { accountId, aliases: new Set([accountId, ...aliases]) };
57
55
  }
58
56
 
59
- const RESOLVE = { allow: true };
60
- const LIST = { allow: false };
61
-
62
57
  async function allowed(
63
58
  source: TupleSource,
64
59
  object: string,
65
60
  relation: string,
66
61
  who: Person,
67
- context = RESOLVE,
68
62
  ): Promise<boolean> {
69
63
  return checkRelation(
70
64
  { model: builtInModel, source },
71
65
  parseObjectRef(object),
72
66
  relation,
73
67
  who,
74
- context,
75
68
  );
76
69
  }
77
70
 
@@ -100,67 +93,17 @@ describe("a person against a direct tuple", () => {
100
93
  });
101
94
  });
102
95
 
103
- describe("the public wildcard and its condition", () => {
104
- const publicViewer = (object: string): Tuple => ({
105
- object: parseObjectRef(object),
106
- relation: "viewer",
107
- subject: {
108
- form: "wildcard",
109
- type: "identity_account",
110
- condition: "allow_public",
111
- },
112
- });
113
- const source = newInMemoryTupleSource([
114
- tuple("agent:open#organization@organization:acme"),
115
- publicViewer("agent:open"),
116
- ]);
117
- const stranger = person("ida_mallory");
118
-
119
- it("reads for anyone on a point check (the cloud's `allow: true`) and for nobody in a listing (`allow: false`)", async () => {
96
+ describe("a stranger against a row with no grant that names them", () => {
97
+ it("reads nothing: no subject form reaches every account, so a stranger holds no relation on a row they were not granted", async () => {
98
+ const source = newInMemoryTupleSource([
99
+ tuple("agent:open#organization@organization:acme"),
100
+ tuple("agent:open#owner@identity_account:ida_carol"),
101
+ tuple("agent:open#viewer@organization:acme#viewer"),
102
+ ]);
103
+ const stranger = person("ida_mallory");
120
104
  expect(await allowed(source, "agent:open", "can_view", stranger)).toBe(
121
- true,
105
+ false,
122
106
  );
123
- expect(
124
- await allowed(source, "agent:open", "can_view", stranger, LIST),
125
- ).toBe(false);
126
- });
127
-
128
- it("ignores a wildcard tuple that carries no condition where the line demands one — a tuple the cloud could never have written", async () => {
129
- const bare = newInMemoryTupleSource([
130
- tuple("agent:open#viewer@identity_account:*"),
131
- ]);
132
- expect(await allowed(bare, "agent:open", "can_view", stranger)).toBe(false);
133
- });
134
-
135
- it("is a thrown fault under a condition the transcript names but the evaluator does not know — a model that grew a condition", async () => {
136
- const grown = declareKind({
137
- kind: ApiResourceKind.agent,
138
- schema: AgentSchema,
139
- source: "test/grown.fga",
140
- relations: [
141
- ["viewer", direct(publicWith("identity_account", "after_hours"))],
142
- ],
143
- });
144
- const afterHours = newInMemoryTupleSource([
145
- {
146
- object: parseObjectRef("agent:open"),
147
- relation: "viewer",
148
- subject: {
149
- form: "wildcard",
150
- type: "identity_account",
151
- condition: "after_hours",
152
- },
153
- },
154
- ]);
155
- await expect(
156
- checkRelation(
157
- { model: newModel([grown]), source: afterHours },
158
- parseObjectRef("agent:open"),
159
- "viewer",
160
- stranger,
161
- RESOLVE,
162
- ),
163
- ).rejects.toMatchObject({ reason: "unknown-condition" });
164
107
  });
165
108
  });
166
109
 
@@ -277,7 +220,6 @@ describe("the walk itself", () => {
277
220
  parseObjectRef("agent:n0"),
278
221
  "next",
279
222
  person("ida_nobody"),
280
- RESOLVE,
281
223
  ),
282
224
  ).rejects.toMatchObject({ reason: "resolution-depth-exceeded" });
283
225
  });
@@ -298,7 +240,6 @@ describe("the walk itself", () => {
298
240
  parseObjectRef("agent:x"),
299
241
  "a",
300
242
  person("ida_nobody"),
301
- RESOLVE,
302
243
  ),
303
244
  ).rejects.toBeInstanceOf(AuthorizationEvaluationError);
304
245
  });
@@ -332,7 +273,7 @@ describe("declareKind validates a transcript at load", () => {
332
273
  source: "test/bad.fga",
333
274
  relations: [
334
275
  ["viewer", direct(objectOf("identity_account"))],
335
- ["viewer", direct(publicWith("identity_account", "allow_public"))],
276
+ ["viewer", direct(usersetOf("organization", "viewer"))],
336
277
  ],
337
278
  }),
338
279
  ).toThrow("declared twice");
@@ -50,7 +50,7 @@ describe("rowFactsOf against the tuple lifecycle's own resolution", () => {
50
50
  for (const visibility of [
51
51
  ApiResourceVisibility.visibility_private,
52
52
  ApiResourceVisibility.visibility_org,
53
- ApiResourceVisibility.visibility_public,
53
+ ApiResourceVisibility.visibility_platform,
54
54
  ]) {
55
55
  it(`${declaration.type} at ${ApiResourceVisibility[visibility]}: the same parent links and visibility shapes`, () => {
56
56
  const row = fixtureRow(declaration, {
@@ -133,7 +133,7 @@ describe("a list candidate against the loaded row — the facts' two producers",
133
133
  for (const visibility of [
134
134
  ApiResourceVisibility.visibility_private,
135
135
  ApiResourceVisibility.visibility_org,
136
- ApiResourceVisibility.visibility_public,
136
+ ApiResourceVisibility.visibility_platform,
137
137
  ]) {
138
138
  it(`${declaration.type} at ${ApiResourceVisibility[visibility]}: the candidate the helper builds carries the facts the driver derives from`, async () => {
139
139
  const row = fixtureRow(declaration, {
@@ -1,5 +1,5 @@
1
1
  # Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/agent-instance-creation.fga.yaml
2
- # at commit 4c03c38d2 (the OpenFGA store test the cloud runs against its live model).
2
+ # as changed by stigmer-cloud#765 (the OpenFGA store test the cloud runs against its live model).
3
3
  # The body below is byte-identical to the source; the cloud re-runs the LIVE
4
4
  # file against this evaluator at the re-pin, so a stale copy is caught there.
5
5
  # Store tests for agent-instance creation: two halves, asked together by
@@ -8,15 +8,15 @@
8
8
  # agent may instantiate it). The organization half is
9
9
  # can_create_agent_instance: member on the organization the instance is
10
10
  # created IN, which is the caller's own, not the agent's: a personal
11
- # instance of another organization's public agent lives in the caller's
12
- # organization (the marketplace case), so the agent's permission alone
13
- # would let a row be planted in any organization named on the request.
11
+ # instance of another organization's platform-visible agent lives in the
12
+ # caller's organization (the tenant-family case), so the agent's permission
13
+ # alone would let a row be planted in any organization named on the request.
14
14
  #
15
15
  # What these pin: owners, admins and members hold the organization half;
16
16
  # a viewer-role account may run an org-visible agent (the agent half) and
17
17
  # still lacks the organization half; a guest holds neither; an outsider
18
- # holds neither; and the marketplace case passes on the caller's own
19
- # organization while the agent half comes from the public wildcard.
18
+ # holds neither; and the tenant-family case passes on the caller's own
19
+ # organization while the agent half comes from the platform_viewer grant.
20
20
  #
21
21
  # Run: fga model test --tests agent-instance-creation.fga.yaml
22
22
 
@@ -47,6 +47,15 @@ tuples:
47
47
  relation: member
48
48
  object: organization:consumer
49
49
 
50
+ # acme owns identity_provider:idp1, which manages consumer: the two are
51
+ # one tenant family, the audience a platform-visible agent reaches.
52
+ - user: organization:acme
53
+ relation: organization
54
+ object: identity_provider:idp1
55
+ - user: organization:consumer
56
+ relation: managed_org
57
+ object: identity_provider:idp1
58
+
50
59
  # An ORG-visible agent in acme, authored by oscar.
51
60
  - user: organization:acme
52
61
  relation: organization
@@ -66,7 +75,7 @@ tuples:
66
75
  relation: owner
67
76
  object: agent:secret-bot
68
77
 
69
- # A PUBLIC marketplace agent in acme (the conditional wildcard plus the
78
+ # A PLATFORM-visible agent in acme (the platform_viewer grant plus the
70
79
  # org floor tuple the visibility writer emits).
71
80
  - user: organization:acme
72
81
  relation: organization
@@ -74,12 +83,9 @@ tuples:
74
83
  - user: identity_account:oscar
75
84
  relation: owner
76
85
  object: agent:open-bot
77
- - user: identity_account:*
78
- relation: viewer
86
+ - user: identity_provider:idp1#platform_user
87
+ relation: platform_viewer
79
88
  object: agent:open-bot
80
- condition:
81
- name: allow_public
82
- context: {}
83
89
  - user: organization:acme#viewer
84
90
  relation: viewer
85
91
  object: agent:open-bot
@@ -121,8 +127,6 @@ tests:
121
127
  check:
122
128
  - user: identity_account:dave
123
129
  object: agent:team-bot
124
- context:
125
- allow: false
126
130
  assertions:
127
131
  can_create_instance: true
128
132
  can_execute: true
@@ -131,8 +135,6 @@ tests:
131
135
  check:
132
136
  - user: identity_account:vera
133
137
  object: agent:team-bot
134
- context:
135
- allow: false
136
138
  assertions:
137
139
  can_create_instance: true
138
140
  - user: identity_account:vera
@@ -144,35 +146,25 @@ tests:
144
146
  check:
145
147
  - user: identity_account:oscar
146
148
  object: agent:secret-bot
147
- context:
148
- allow: false
149
149
  assertions:
150
150
  can_create_instance: true
151
151
  - user: identity_account:olivia
152
152
  object: agent:secret-bot
153
- context:
154
- allow: false
155
153
  assertions:
156
154
  can_create_instance: true
157
155
  - user: identity_account:dave
158
156
  object: agent:secret-bot
159
- context:
160
- allow: false
161
157
  assertions:
162
158
  can_create_instance: false
163
159
  - user: identity_account:mia
164
160
  object: agent:secret-bot
165
- context:
166
- allow: false
167
161
  assertions:
168
162
  can_create_instance: false
169
163
 
170
- - name: the marketplace case, the agent half from the wildcard and the organization half at home
164
+ - name: the tenant-family case, the agent half from platform_viewer and the organization half at home
171
165
  check:
172
166
  - user: identity_account:mia
173
167
  object: agent:open-bot
174
- context:
175
- allow: true
176
168
  assertions:
177
169
  can_create_instance: true
178
170
  - user: identity_account:mia