@opengeni/db 1.0.1 → 3.2.0-canary.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 (271) hide show
  1. package/dist/attached-browser-devices.d.ts +7 -0
  2. package/dist/automations.d.ts +154 -0
  3. package/dist/canonical-human-identities.js +3 -3
  4. package/dist/capability-integrations.d.ts +13 -0
  5. package/dist/child-lifecycle-notices.d.ts +68 -0
  6. package/dist/{chunk-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
  7. package/dist/chunk-2EH4WRHL.js.map +1 -0
  8. package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
  9. package/dist/chunk-6HMM2R5T.js +390 -0
  10. package/dist/chunk-6HMM2R5T.js.map +1 -0
  11. package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
  12. package/dist/chunk-AZHW7R5V.js.map +1 -0
  13. package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
  14. package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
  15. package/dist/chunk-KRLPEMLH.js.map +1 -0
  16. package/dist/chunk-NAB6FKFN.js +516 -0
  17. package/dist/chunk-NAB6FKFN.js.map +1 -0
  18. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  19. package/dist/chunk-SIBYBA2D.js.map +1 -0
  20. package/dist/chunk-UZNXG44K.js +4508 -0
  21. package/dist/chunk-UZNXG44K.js.map +1 -0
  22. package/dist/codemode-operations.d.ts +1 -6
  23. package/dist/company-brain-context-selection-schema.d.ts +705 -0
  24. package/dist/company-brain-context-selection.d.ts +94 -0
  25. package/dist/company-brain-governed-writes.d.ts +24 -0
  26. package/dist/company-brain.d.ts +55 -0
  27. package/dist/company-profile-agent-admin.d.ts +15 -0
  28. package/dist/company-profile-schema.d.ts +619 -2
  29. package/dist/company-profile.d.ts +9 -4
  30. package/dist/connection-authority.d.ts +95 -0
  31. package/dist/connection-scopes.d.ts +8 -0
  32. package/dist/connection-tenancy-backfill.d.ts +85 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +23 -4
  35. package/dist/editable-artifact-durable-export.js +2 -2
  36. package/dist/editable-artifacts.d.ts +2 -2
  37. package/dist/editable-artifacts.js +3 -3
  38. package/dist/governed-learning-activation-schema.d.ts +984 -0
  39. package/dist/governed-learning-activation.d.ts +98 -0
  40. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  41. package/dist/governed-learning-evaluator.d.ts +28 -0
  42. package/dist/index.d.ts +1606 -81
  43. package/dist/index.js +21898 -8147
  44. package/dist/index.js.map +1 -1
  45. package/dist/insights.d.ts +18 -0
  46. package/dist/integration-bindings.d.ts +1 -0
  47. package/dist/integration-facets.d.ts +30 -0
  48. package/dist/interaction-placement-loss.d.ts +22 -0
  49. package/dist/managed-human-provisioning.d.ts +25 -0
  50. package/dist/memory-domain.d.ts +3 -3
  51. package/dist/migrate.d.ts +11 -1
  52. package/dist/migrate.js +1 -1
  53. package/dist/new-session-drafts.d.ts +43 -5
  54. package/dist/organization-membership-backfill.d.ts +174 -0
  55. package/dist/organization-membership-lifecycle.d.ts +162 -0
  56. package/dist/pr-review.d.ts +107 -0
  57. package/dist/preference-registry-schema.d.ts +2 -0
  58. package/dist/preference-registry.d.ts +2 -0
  59. package/dist/provision-roles.js +1 -1
  60. package/dist/runtime-posture.d.ts +29 -8
  61. package/dist/schema.d.ts +24914 -13703
  62. package/dist/schema.js +99 -1
  63. package/dist/scoped-knowledge-schema.d.ts +52 -1
  64. package/dist/session-background-commands.d.ts +125 -0
  65. package/dist/session-background-commands.js +34 -0
  66. package/dist/session-background-commands.js.map +1 -0
  67. package/dist/session-control.d.ts +156 -3
  68. package/dist/session-goal-pacing.d.ts +68 -0
  69. package/dist/session-queue-commands.d.ts +43 -4
  70. package/dist/session-realtime-ledger.d.ts +2 -0
  71. package/dist/session-tenancy.d.ts +71 -1
  72. package/dist/session-tenancy.js +25 -3
  73. package/dist/session-tool-call-settlement.d.ts +9 -4
  74. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  75. package/dist/slack-routing.d.ts +268 -0
  76. package/dist/slack-task-policy-schema.d.ts +34 -0
  77. package/dist/slack-task-policy.d.ts +8 -0
  78. package/dist/slack-user-link-access.d.ts +28 -0
  79. package/dist/task-notes-schema.d.ts +594 -0
  80. package/dist/task-notes.d.ts +39 -0
  81. package/dist/turn-initiator.d.ts +2 -0
  82. package/dist/user-resource-authority.d.ts +109 -0
  83. package/dist/video-generation.js +3 -3
  84. package/dist/workspace-authority.d.ts +81 -0
  85. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  86. package/dist/workspace-instruction-policies.d.ts +62 -0
  87. package/dist/workspace-learning-policy.d.ts +1 -0
  88. package/dist/workspace-membership-permissions.d.ts +2 -0
  89. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  90. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  91. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  92. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  93. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  94. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  95. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  96. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  97. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  98. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  99. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  100. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  101. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  102. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  103. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  104. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  105. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  106. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  107. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  108. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  109. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  110. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  111. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  112. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  113. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  114. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  115. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  116. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  117. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  118. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  119. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  120. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  121. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  122. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  123. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  124. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  125. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  126. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  127. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  128. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  129. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  130. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  131. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  132. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  133. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  134. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  135. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  136. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  137. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  138. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  139. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  140. package/drizzle/0294_preference_activation_authority.sql +237 -0
  141. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  142. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  143. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  144. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  145. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  146. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  147. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  148. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  149. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  150. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  151. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  152. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  153. package/drizzle/0307_session_attention_state.sql +51 -0
  154. package/drizzle/0308_session_archives.sql +35 -0
  155. package/drizzle/0309_channel_project_pins.sql +6 -0
  156. package/drizzle/0310_channel_project_order.sql +27 -0
  157. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  158. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  159. package/drizzle/0313_private_child_session_authority.sql +365 -0
  160. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  161. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  162. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  163. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  164. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  165. package/drizzle/0319_event_triggered_automations.sql +254 -0
  166. package/drizzle/0320_pr_review_pack.sql +113 -0
  167. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  168. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  169. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  170. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  171. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  172. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  173. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  174. package/drizzle/0328_session_background_commands.sql +590 -0
  175. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  176. package/drizzle/0330_api_key_descriptions.sql +20 -0
  177. package/drizzle/0331_managed_organization_creation.sql +163 -0
  178. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  179. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  180. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  181. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  182. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  183. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  184. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  185. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  186. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  187. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
  188. package/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
  189. package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
  190. package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
  191. package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
  192. package/drizzle/0346_document_migration_audit_surface.sql +454 -0
  193. package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -0
  194. package/package.json +10 -6
  195. package/src/attached-browser-devices.ts +233 -5
  196. package/src/automations.ts +911 -0
  197. package/src/browser-sessions.ts +10 -0
  198. package/src/capability-integrations.ts +175 -1
  199. package/src/child-lifecycle-notices.ts +241 -0
  200. package/src/codemode-operations.ts +1 -35
  201. package/src/company-brain-context-selection-schema.ts +100 -0
  202. package/src/company-brain-context-selection.ts +359 -0
  203. package/src/company-brain-governed-writes.ts +1170 -0
  204. package/src/company-brain.ts +309 -0
  205. package/src/company-profile-agent-admin.ts +225 -0
  206. package/src/company-profile-schema.ts +121 -1
  207. package/src/company-profile.ts +21 -0
  208. package/src/computer-sessions.ts +10 -1
  209. package/src/connection-authority.ts +290 -0
  210. package/src/connection-scopes.ts +20 -0
  211. package/src/connection-tenancy-backfill.ts +167 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +87 -2
  214. package/src/editable-artifacts-schema.ts +10 -5
  215. package/src/editable-artifacts.ts +21 -11
  216. package/src/governed-learning-activation-schema.ts +121 -0
  217. package/src/governed-learning-activation.ts +588 -0
  218. package/src/governed-learning-evaluator-schema.ts +72 -0
  219. package/src/governed-learning-evaluator.ts +217 -0
  220. package/src/index.ts +11676 -1550
  221. package/src/insights.ts +107 -0
  222. package/src/integration-bindings.ts +88 -6
  223. package/src/integration-facets.ts +287 -84
  224. package/src/interaction-placement-loss.ts +234 -0
  225. package/src/managed-human-provisioning.ts +116 -0
  226. package/src/memory-domain.ts +27 -32
  227. package/src/migrate.ts +77 -1
  228. package/src/new-session-drafts.ts +229 -35
  229. package/src/organization-membership-backfill.ts +735 -0
  230. package/src/organization-membership-lifecycle.ts +995 -0
  231. package/src/pr-review.ts +890 -0
  232. package/src/preference-registry.ts +31 -1
  233. package/src/provision-roles.ts +905 -6
  234. package/src/runtime-posture-cli.ts +2 -0
  235. package/src/runtime-posture.ts +1317 -72
  236. package/src/schema.ts +3316 -428
  237. package/src/scoped-knowledge-schema.ts +16 -8
  238. package/src/scoped-knowledge.ts +1 -1
  239. package/src/session-background-commands.ts +759 -0
  240. package/src/session-control.ts +640 -74
  241. package/src/session-goal-pacing.ts +126 -0
  242. package/src/session-queue-commands.ts +441 -85
  243. package/src/session-realtime-context.ts +4 -6
  244. package/src/session-realtime-ledger.ts +28 -14
  245. package/src/session-realtime-mirror.ts +1 -1
  246. package/src/session-tenancy.ts +410 -49
  247. package/src/session-tool-call-settlement.ts +38 -29
  248. package/src/slack-routing-personal-workspace.ts +67 -0
  249. package/src/slack-routing.ts +867 -0
  250. package/src/slack-task-policy-schema.ts +5 -0
  251. package/src/slack-task-policy.ts +18 -0
  252. package/src/slack-user-link-access.ts +138 -11
  253. package/src/task-notes-schema.ts +74 -0
  254. package/src/task-notes.ts +124 -2
  255. package/src/turn-initiator.ts +8 -0
  256. package/src/user-resource-authority.ts +377 -0
  257. package/src/workspace-authority.ts +160 -0
  258. package/src/workspace-instruction-policies-schema.ts +53 -1
  259. package/src/workspace-instruction-policies.ts +528 -77
  260. package/src/workspace-learning-policy.ts +21 -5
  261. package/src/workspace-membership-permissions.ts +9 -0
  262. package/dist/chunk-4SR4HKKA.js.map +0 -1
  263. package/dist/chunk-6ZYKCRFO.js.map +0 -1
  264. package/dist/chunk-NXAFLCQX.js +0 -2468
  265. package/dist/chunk-NXAFLCQX.js.map +0 -1
  266. package/dist/chunk-SK7YYHBI.js.map +0 -1
  267. package/dist/chunk-WD5ROSLL.js +0 -117
  268. package/dist/chunk-WD5ROSLL.js.map +0 -1
  269. package/dist/chunk-ZWREYEWA.js.map +0 -1
  270. /package/dist/{chunk-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
  271. /package/dist/{chunk-LTG3S6ZY.js.map → chunk-E6CLMKEE.js.map} +0 -0
@@ -0,0 +1,1000 @@
1
+ -- deployment-mode: rolling
2
+ -- Admit personal Variable Set and Rig selections at the exact accepted session
3
+ -- attempt. This slice stores immutable authority snapshots and atomically
4
+ -- consumes once grants. It does not load secrets, materialize resources,
5
+ -- activate scheduled tasks, or expose Variable Set/Rig CRUD.
6
+
7
+ SET LOCAL lock_timeout = '5s';
8
+ SET LOCAL statement_timeout = '10min';
9
+
10
+ CREATE TABLE opengeni_private.personal_resource_delegation_capabilities (
11
+ "backend_pid" integer NOT NULL,
12
+ "transaction_id" xid8 NOT NULL,
13
+ "capability_kind" text NOT NULL,
14
+ "created_at" timestamptz NOT NULL DEFAULT clock_timestamp(),
15
+ CONSTRAINT "personal_resource_delegation_capabilities_kind_chk" CHECK (
16
+ "capability_kind" IN ('admit', 'resolve')
17
+ ),
18
+ CONSTRAINT "personal_resource_delegation_capabilities_pk" PRIMARY KEY (
19
+ "backend_pid", "transaction_id", "capability_kind"
20
+ )
21
+ );
22
+ REVOKE ALL ON TABLE opengeni_private.personal_resource_delegation_capabilities FROM PUBLIC;
23
+
24
+ DO $personal_resource_capability_revoke$
25
+ BEGIN
26
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
27
+ REVOKE ALL ON TABLE opengeni_private.personal_resource_delegation_capabilities
28
+ FROM opengeni_app;
29
+ END IF;
30
+ END
31
+ $personal_resource_capability_revoke$;
32
+
33
+ CREATE OR REPLACE FUNCTION opengeni_private.personal_resource_delegation_capability_active(
34
+ p_capability_kind text DEFAULT NULL
35
+ )
36
+ RETURNS boolean
37
+ LANGUAGE sql
38
+ STABLE
39
+ SECURITY DEFINER
40
+ SET search_path = pg_catalog
41
+ AS $personal_resource_capability_active$
42
+ SELECT EXISTS (
43
+ SELECT 1
44
+ FROM opengeni_private.personal_resource_delegation_capabilities capability
45
+ WHERE capability.backend_pid = pg_catalog.pg_backend_pid()
46
+ AND capability.transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
47
+ AND (
48
+ p_capability_kind IS NULL
49
+ OR capability.capability_kind = p_capability_kind
50
+ )
51
+ )
52
+ $personal_resource_capability_active$;
53
+
54
+ REVOKE ALL ON FUNCTION
55
+ opengeni_private.personal_resource_delegation_capability_active(text)
56
+ FROM PUBLIC;
57
+
58
+ DO $personal_resource_capability_grant$
59
+ BEGIN
60
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
61
+ GRANT EXECUTE ON FUNCTION
62
+ opengeni_private.personal_resource_delegation_capability_active(text)
63
+ TO opengeni_app;
64
+ END IF;
65
+ END
66
+ $personal_resource_capability_grant$;
67
+
68
+ CREATE TABLE "session_attempt_personal_resource_admissions" (
69
+ "attempt_id" uuid PRIMARY KEY REFERENCES "session_turn_attempts"("id") ON DELETE CASCADE,
70
+ "account_id" uuid NOT NULL,
71
+ "workspace_id" uuid NOT NULL,
72
+ "session_id" uuid NOT NULL,
73
+ "turn_id" uuid NOT NULL,
74
+ "execution_generation" integer NOT NULL,
75
+ "initiating_human_subject_id" text NOT NULL,
76
+ "owner_organization_membership_id" uuid NOT NULL,
77
+ "membership_authorization_revision" bigint NOT NULL,
78
+ "session_visibility" text NOT NULL,
79
+ "session_authority_epoch" integer NOT NULL,
80
+ "resource_count" integer NOT NULL,
81
+ "admitted_at" timestamptz NOT NULL DEFAULT clock_timestamp(),
82
+ CONSTRAINT "session_attempt_personal_resource_admissions_attempt_fk"
83
+ FOREIGN KEY (
84
+ "account_id", "workspace_id", "session_id", "turn_id", "attempt_id"
85
+ ) REFERENCES "session_turn_attempts"(
86
+ "account_id", "workspace_id", "session_id", "turn_id", "id"
87
+ ) ON DELETE CASCADE,
88
+ CONSTRAINT "session_attempt_personal_resource_admissions_owner_fk"
89
+ FOREIGN KEY ("owner_organization_membership_id", "account_id")
90
+ REFERENCES "organization_memberships"("id", "account_id") ON DELETE RESTRICT,
91
+ CONSTRAINT "session_attempt_personal_resource_admissions_generation_chk" CHECK (
92
+ "execution_generation" > 0
93
+ AND "membership_authorization_revision" > 0
94
+ AND "session_authority_epoch" > 0
95
+ AND "resource_count" > 0
96
+ ),
97
+ CONSTRAINT "session_attempt_personal_resource_admissions_visibility_chk" CHECK (
98
+ "session_visibility" IN ('user_private', 'workspace_shared')
99
+ ),
100
+ CONSTRAINT "session_attempt_personal_resource_admissions_subject_chk" CHECK (
101
+ length(btrim("initiating_human_subject_id")) BETWEEN 1 AND 1024
102
+ )
103
+ );
104
+
105
+ CREATE UNIQUE INDEX "session_attempt_personal_resource_admissions_identity_uq"
106
+ ON "session_attempt_personal_resource_admissions" (
107
+ "account_id", "workspace_id", "session_id", "turn_id", "attempt_id",
108
+ "execution_generation"
109
+ );
110
+
111
+ CREATE TABLE "session_attempt_personal_resource_snapshots" (
112
+ "attempt_id" uuid NOT NULL,
113
+ "account_id" uuid NOT NULL,
114
+ "workspace_id" uuid NOT NULL,
115
+ "session_id" uuid NOT NULL,
116
+ "turn_id" uuid NOT NULL,
117
+ "execution_generation" integer NOT NULL,
118
+ "resource_kind" text NOT NULL,
119
+ "resource_id" uuid NOT NULL,
120
+ "resource_version_id" uuid,
121
+ "selection_sources" text[] NOT NULL,
122
+ "action" text NOT NULL,
123
+ "origin_workspace_id" uuid NOT NULL,
124
+ "owner_organization_membership_id" uuid NOT NULL,
125
+ "membership_authorization_revision" bigint NOT NULL,
126
+ "authority_id" uuid NOT NULL,
127
+ "authority_generation" bigint NOT NULL,
128
+ "target_workspace_id" uuid NOT NULL,
129
+ "session_visibility" text NOT NULL,
130
+ "session_authority_epoch" integer NOT NULL,
131
+ "grant_id" uuid NOT NULL,
132
+ "grant_generation" bigint NOT NULL,
133
+ "grant_mode" text NOT NULL,
134
+ "grant_context" text NOT NULL,
135
+ "grant_session_id" uuid,
136
+ "grant_authority_epoch" integer,
137
+ "created_at" timestamptz NOT NULL DEFAULT clock_timestamp(),
138
+ CONSTRAINT "session_attempt_personal_resource_snapshots_pk" PRIMARY KEY (
139
+ "attempt_id", "resource_kind", "resource_id"
140
+ ),
141
+ CONSTRAINT "session_attempt_personal_resource_snapshots_admission_fk"
142
+ FOREIGN KEY (
143
+ "account_id", "workspace_id", "session_id", "turn_id", "attempt_id",
144
+ "execution_generation"
145
+ ) REFERENCES "session_attempt_personal_resource_admissions"(
146
+ "account_id", "workspace_id", "session_id", "turn_id", "attempt_id",
147
+ "execution_generation"
148
+ ) ON DELETE CASCADE,
149
+ CONSTRAINT "session_attempt_personal_resource_snapshots_authority_fk"
150
+ FOREIGN KEY (
151
+ "authority_id", "account_id", "owner_organization_membership_id"
152
+ ) REFERENCES "organization_user_resource_authorities"(
153
+ "id", "account_id", "organization_membership_id"
154
+ ) ON DELETE RESTRICT,
155
+ CONSTRAINT "session_attempt_personal_resource_snapshots_grant_fk"
156
+ FOREIGN KEY ("grant_id", "account_id")
157
+ REFERENCES "organization_user_resource_grants"("id", "account_id") ON DELETE RESTRICT,
158
+ CONSTRAINT "session_attempt_personal_resource_snapshots_kind_chk" CHECK (
159
+ ("resource_kind" = 'variable_set' AND "resource_version_id" IS NULL)
160
+ OR ("resource_kind" = 'rig' AND "resource_version_id" IS NOT NULL)
161
+ ),
162
+ CONSTRAINT "session_attempt_personal_resource_snapshots_action_chk" CHECK (
163
+ ("resource_kind" = 'variable_set' AND "action" = 'variable_set.use')
164
+ OR ("resource_kind" = 'rig' AND "action" = 'rig.use')
165
+ ),
166
+ CONSTRAINT "session_attempt_personal_resource_snapshots_sources_chk" CHECK (
167
+ cardinality("selection_sources") > 0
168
+ ),
169
+ CONSTRAINT "session_attempt_personal_resource_snapshots_generation_chk" CHECK (
170
+ "execution_generation" > 0
171
+ AND "membership_authorization_revision" > 0
172
+ AND "authority_generation" > 0
173
+ AND "session_authority_epoch" > 0
174
+ AND "grant_generation" > 0
175
+ ),
176
+ CONSTRAINT "session_attempt_personal_resource_snapshots_visibility_chk" CHECK (
177
+ "session_visibility" IN ('user_private', 'workspace_shared')
178
+ AND "grant_context" = "session_visibility"
179
+ ),
180
+ CONSTRAINT "session_attempt_personal_resource_snapshots_workspace_chk" CHECK (
181
+ "target_workspace_id" = "workspace_id"
182
+ ),
183
+ CONSTRAINT "session_attempt_personal_resource_snapshots_grant_fence_chk" CHECK (
184
+ (
185
+ "grant_mode" = 'always'
186
+ AND "grant_session_id" IS NULL
187
+ AND "grant_authority_epoch" IS NULL
188
+ ) OR (
189
+ "grant_mode" IN ('once', 'session')
190
+ AND "grant_session_id" = "session_id"
191
+ AND "grant_authority_epoch" = "session_authority_epoch"
192
+ )
193
+ )
194
+ );
195
+
196
+ CREATE INDEX "session_attempt_personal_resource_snapshots_authority_idx"
197
+ ON "session_attempt_personal_resource_snapshots" (
198
+ "account_id", "authority_id", "authority_generation"
199
+ );
200
+ CREATE INDEX "session_attempt_personal_resource_snapshots_grant_idx"
201
+ ON "session_attempt_personal_resource_snapshots" (
202
+ "account_id", "grant_id", "grant_generation"
203
+ );
204
+
205
+ CREATE TABLE "personal_resource_once_consumption_receipts" (
206
+ "grant_id" uuid PRIMARY KEY,
207
+ "account_id" uuid NOT NULL,
208
+ "attempt_id" uuid NOT NULL,
209
+ "workspace_id" uuid NOT NULL,
210
+ "session_id" uuid NOT NULL,
211
+ "turn_id" uuid NOT NULL,
212
+ "execution_generation" integer NOT NULL,
213
+ "authority_id" uuid NOT NULL,
214
+ "authority_generation" bigint NOT NULL,
215
+ "grant_generation" bigint NOT NULL,
216
+ "consumed_at" timestamptz NOT NULL DEFAULT clock_timestamp(),
217
+ CONSTRAINT "personal_resource_once_consumption_receipts_grant_fk"
218
+ FOREIGN KEY ("grant_id", "account_id")
219
+ REFERENCES "organization_user_resource_grants"("id", "account_id") ON DELETE RESTRICT,
220
+ CONSTRAINT "personal_resource_once_consumption_receipts_attempt_fk"
221
+ FOREIGN KEY (
222
+ "account_id", "workspace_id", "session_id", "turn_id", "attempt_id",
223
+ "execution_generation"
224
+ ) REFERENCES "session_attempt_personal_resource_admissions"(
225
+ "account_id", "workspace_id", "session_id", "turn_id", "attempt_id",
226
+ "execution_generation"
227
+ ) ON DELETE CASCADE,
228
+ CONSTRAINT "personal_resource_once_consumption_receipts_generation_chk" CHECK (
229
+ "execution_generation" > 0
230
+ AND "authority_generation" > 0
231
+ AND "grant_generation" > 0
232
+ )
233
+ );
234
+
235
+ ALTER TABLE "session_attempt_personal_resource_admissions" ENABLE ROW LEVEL SECURITY;
236
+ ALTER TABLE "session_attempt_personal_resource_admissions" FORCE ROW LEVEL SECURITY;
237
+ ALTER TABLE "session_attempt_personal_resource_snapshots" ENABLE ROW LEVEL SECURITY;
238
+ ALTER TABLE "session_attempt_personal_resource_snapshots" FORCE ROW LEVEL SECURITY;
239
+ ALTER TABLE "personal_resource_once_consumption_receipts" ENABLE ROW LEVEL SECURITY;
240
+ ALTER TABLE "personal_resource_once_consumption_receipts" FORCE ROW LEVEL SECURITY;
241
+
242
+ DO $personal_resource_capability_policies$
243
+ DECLARE
244
+ data_schema text := current_schema();
245
+ migration_owner text := current_user;
246
+ table_name text;
247
+ BEGIN
248
+ FOREACH table_name IN ARRAY ARRAY[
249
+ 'session_attempt_personal_resource_admissions',
250
+ 'session_attempt_personal_resource_snapshots',
251
+ 'personal_resource_once_consumption_receipts'
252
+ ] LOOP
253
+ EXECUTE format(
254
+ 'CREATE POLICY personal_resource_delegation_capability_read ON %I.%I '
255
+ || 'FOR SELECT USING ('
256
+ || 'current_user = %L AND '
257
+ || 'opengeni_private.personal_resource_delegation_capability_active()'
258
+ || ')',
259
+ data_schema,
260
+ table_name,
261
+ migration_owner
262
+ );
263
+ EXECUTE format(
264
+ 'CREATE POLICY personal_resource_delegation_capability_insert ON %I.%I '
265
+ || 'FOR INSERT WITH CHECK ('
266
+ || 'current_user = %L AND '
267
+ || 'opengeni_private.personal_resource_delegation_capability_active(''admit'')'
268
+ || ')',
269
+ data_schema,
270
+ table_name,
271
+ migration_owner
272
+ );
273
+ END LOOP;
274
+
275
+ FOREACH table_name IN ARRAY ARRAY[
276
+ 'organization_memberships',
277
+ 'organization_user_resource_authorities',
278
+ 'workspace_variable_sets',
279
+ 'rigs',
280
+ 'rig_versions'
281
+ ] LOOP
282
+ EXECUTE format(
283
+ 'CREATE POLICY personal_resource_delegation_read ON %I.%I '
284
+ || 'FOR SELECT USING ('
285
+ || 'current_user = %L AND '
286
+ || 'opengeni_private.personal_resource_delegation_capability_active()'
287
+ || ')',
288
+ data_schema,
289
+ table_name,
290
+ migration_owner
291
+ );
292
+ END LOOP;
293
+
294
+ EXECUTE format(
295
+ 'CREATE POLICY personal_resource_delegation_grant_read '
296
+ || 'ON %I.organization_user_resource_grants FOR SELECT USING ('
297
+ || 'current_user = %L AND '
298
+ || 'opengeni_private.personal_resource_delegation_capability_active()'
299
+ || ')',
300
+ data_schema,
301
+ migration_owner
302
+ );
303
+ EXECUTE format(
304
+ 'CREATE POLICY personal_resource_delegation_grant_update '
305
+ || 'ON %I.organization_user_resource_grants FOR UPDATE USING ('
306
+ || 'current_user = %L AND '
307
+ || 'opengeni_private.personal_resource_delegation_capability_active(''admit'')'
308
+ || ') WITH CHECK ('
309
+ || 'current_user = %L AND '
310
+ || 'opengeni_private.personal_resource_delegation_capability_active(''admit'')'
311
+ || ')',
312
+ data_schema,
313
+ migration_owner,
314
+ migration_owner
315
+ );
316
+ END
317
+ $personal_resource_capability_policies$;
318
+
319
+ DO $personal_resource_delegation_functions$
320
+ DECLARE
321
+ data_schema text := current_schema();
322
+ BEGIN
323
+ EXECUTE format($ddl$
324
+ CREATE OR REPLACE FUNCTION %1$I.admit_session_attempt_personal_resources()
325
+ RETURNS trigger
326
+ LANGUAGE plpgsql
327
+ SECURITY DEFINER
328
+ SET search_path = %1$I, pg_catalog
329
+ AS $body$
330
+ DECLARE
331
+ session_row sessions%%ROWTYPE;
332
+ turn_row session_turns%%ROWTYPE;
333
+ member_row organization_memberships%%ROWTYPE;
334
+ resource_row record;
335
+ grant_row organization_user_resource_grants%%ROWTYPE;
336
+ resource_total integer := 0;
337
+ snapshot_total integer := 0;
338
+ initiating_subject text;
339
+ affected integer;
340
+ BEGIN
341
+ INSERT INTO opengeni_private.personal_resource_delegation_capabilities (
342
+ backend_pid, transaction_id, capability_kind
343
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'admit')
344
+ ON CONFLICT DO NOTHING;
345
+
346
+ SELECT session_value.* INTO STRICT session_row
347
+ FROM sessions session_value
348
+ WHERE session_value.id = NEW.session_id
349
+ AND session_value.account_id = NEW.account_id
350
+ AND session_value.workspace_id = NEW.workspace_id
351
+ FOR SHARE;
352
+
353
+ SELECT turn_value.* INTO STRICT turn_row
354
+ FROM session_turns turn_value
355
+ WHERE turn_value.id = NEW.turn_id
356
+ AND turn_value.account_id = NEW.account_id
357
+ AND turn_value.workspace_id = NEW.workspace_id
358
+ AND turn_value.session_id = NEW.session_id
359
+ FOR SHARE;
360
+
361
+ SELECT count(*)::integer INTO resource_total
362
+ FROM (
363
+ SELECT DISTINCT selected.resource_kind, selected.resource_id
364
+ FROM (
365
+ SELECT 'variable_set'::text AS resource_kind, variable_set.id AS resource_id
366
+ FROM workspace_variable_sets variable_set
367
+ WHERE variable_set.id = session_row.variable_set_id
368
+ AND variable_set.account_id = NEW.account_id
369
+ AND variable_set.authority_scope = 'user'
370
+ UNION ALL
371
+ SELECT 'rig'::text, rig.id
372
+ FROM rigs rig
373
+ WHERE rig.id = session_row.rig_id
374
+ AND rig.account_id = NEW.account_id
375
+ AND rig.authority_scope = 'user'
376
+ UNION ALL
377
+ SELECT 'variable_set'::text, default_variable_set.id
378
+ FROM rig_versions rig_version
379
+ CROSS JOIN LATERAL jsonb_array_elements_text(
380
+ rig_version.default_variable_set_ids
381
+ ) default_id(value)
382
+ JOIN workspace_variable_sets default_variable_set
383
+ ON default_variable_set.id = default_id.value::uuid
384
+ AND default_variable_set.account_id = NEW.account_id
385
+ AND default_variable_set.authority_scope = 'user'
386
+ WHERE rig_version.id = session_row.rig_version_id
387
+ AND rig_version.rig_id = session_row.rig_id
388
+ AND rig_version.account_id = NEW.account_id
389
+ ) selected
390
+ ) selected_personal_resources;
391
+
392
+ IF resource_total = 0 THEN
393
+ DELETE FROM opengeni_private.personal_resource_delegation_capabilities
394
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
395
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
396
+ AND capability_kind = 'admit';
397
+ RETURN NEW;
398
+ END IF;
399
+
400
+ IF NEW.execution_generation <= 0
401
+ OR NEW.state NOT IN ('claimed', 'running')
402
+ OR NEW.closed_at IS NOT NULL
403
+ OR NEW.quiesced_at IS NOT NULL
404
+ OR session_row.active_turn_id IS DISTINCT FROM NEW.turn_id
405
+ OR turn_row.active_attempt_id IS DISTINCT FROM NEW.id
406
+ OR turn_row.execution_generation IS DISTINCT FROM NEW.execution_generation
407
+ OR turn_row.status NOT IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
408
+ OR EXISTS (
409
+ SELECT 1
410
+ FROM session_attempt_interruptions interruption
411
+ WHERE interruption.account_id = NEW.account_id
412
+ AND interruption.workspace_id = NEW.workspace_id
413
+ AND interruption.session_id = NEW.session_id
414
+ AND interruption.attempt_id = NEW.id
415
+ AND interruption.state IN ('pending', 'delivered', 'acknowledged')
416
+ )
417
+ THEN
418
+ RAISE EXCEPTION 'personal-resource admission requires the exact current uninterrupted attempt'
419
+ USING ERRCODE = '42501';
420
+ END IF;
421
+
422
+ IF NEW.authority_visibility IS DISTINCT FROM session_row.visibility
423
+ OR NEW.authority_epoch IS DISTINCT FROM session_row.authority_epoch
424
+ OR NEW.authority_owner_organization_membership_id
425
+ IS DISTINCT FROM session_row.owner_organization_membership_id
426
+ THEN
427
+ RAISE EXCEPTION 'personal-resource admission requires the exact session authority'
428
+ USING ERRCODE = '42501';
429
+ END IF;
430
+
431
+ initiating_subject := coalesce(
432
+ nullif(btrim(turn_row.initiating_human_subject_id), ''),
433
+ CASE WHEN turn_row.initiator_kind = 'subject'
434
+ THEN nullif(btrim(turn_row.initiator_subject_id), '') END
435
+ );
436
+ IF initiating_subject IS NULL THEN
437
+ RAISE EXCEPTION 'personal-resource admission requires an initiating human subject'
438
+ USING ERRCODE = '42501';
439
+ END IF;
440
+
441
+ SELECT membership.* INTO STRICT member_row
442
+ FROM organization_memberships membership
443
+ WHERE membership.account_id = NEW.account_id
444
+ AND membership.subject_id = initiating_subject
445
+ AND membership.status = 'active'
446
+ AND membership.revoked_at IS NULL
447
+ AND membership.personal_workspace_id IS NOT NULL
448
+ FOR SHARE;
449
+
450
+ PERFORM 1
451
+ FROM workspace_memberships workspace_membership
452
+ WHERE workspace_membership.account_id = NEW.account_id
453
+ AND workspace_membership.workspace_id = NEW.workspace_id
454
+ AND workspace_membership.subject_id = initiating_subject
455
+ FOR KEY SHARE;
456
+ IF NOT FOUND THEN
457
+ RAISE EXCEPTION 'initiating human lacks target-workspace membership'
458
+ USING ERRCODE = '42501';
459
+ END IF;
460
+
461
+ INSERT INTO session_attempt_personal_resource_admissions (
462
+ attempt_id, account_id, workspace_id, session_id, turn_id,
463
+ execution_generation, initiating_human_subject_id,
464
+ owner_organization_membership_id, membership_authorization_revision,
465
+ session_visibility, session_authority_epoch, resource_count
466
+ ) VALUES (
467
+ NEW.id, NEW.account_id, NEW.workspace_id, NEW.session_id, NEW.turn_id,
468
+ NEW.execution_generation, initiating_subject, member_row.id,
469
+ member_row.authorization_revision, session_row.visibility,
470
+ session_row.authority_epoch, resource_total
471
+ );
472
+
473
+ FOR resource_row IN
474
+ WITH selected AS (
475
+ SELECT
476
+ 'variable_set'::text AS resource_kind,
477
+ variable_set.id AS resource_id,
478
+ NULL::uuid AS resource_version_id,
479
+ 'variable_set.use'::text AS action,
480
+ 'session_variable_set'::text AS selection_source,
481
+ variable_set.workspace_id AS resource_workspace_id,
482
+ variable_set.authority_id,
483
+ variable_set.owner_organization_membership_id,
484
+ variable_set.origin_workspace_id
485
+ FROM workspace_variable_sets variable_set
486
+ WHERE variable_set.id = session_row.variable_set_id
487
+ AND variable_set.account_id = NEW.account_id
488
+ AND variable_set.authority_scope = 'user'
489
+ UNION ALL
490
+ SELECT
491
+ 'rig'::text, rig.id, session_row.rig_version_id, 'rig.use'::text,
492
+ 'session_rig'::text, rig.workspace_id, rig.authority_id,
493
+ rig.owner_organization_membership_id, rig.origin_workspace_id
494
+ FROM rigs rig
495
+ WHERE rig.id = session_row.rig_id
496
+ AND rig.account_id = NEW.account_id
497
+ AND rig.authority_scope = 'user'
498
+ UNION ALL
499
+ SELECT
500
+ 'variable_set'::text, default_variable_set.id, NULL::uuid,
501
+ 'variable_set.use'::text,
502
+ ('rig_default_variable_set:' || default_id.ordinality::text)::text,
503
+ default_variable_set.workspace_id, default_variable_set.authority_id,
504
+ default_variable_set.owner_organization_membership_id,
505
+ default_variable_set.origin_workspace_id
506
+ FROM rig_versions rig_version
507
+ CROSS JOIN LATERAL jsonb_array_elements_text(
508
+ rig_version.default_variable_set_ids
509
+ ) WITH ORDINALITY default_id(value, ordinality)
510
+ JOIN workspace_variable_sets default_variable_set
511
+ ON default_variable_set.id = default_id.value::uuid
512
+ AND default_variable_set.account_id = NEW.account_id
513
+ AND default_variable_set.authority_scope = 'user'
514
+ WHERE rig_version.id = session_row.rig_version_id
515
+ AND rig_version.rig_id = session_row.rig_id
516
+ AND rig_version.account_id = NEW.account_id
517
+ )
518
+ SELECT resource_kind, resource_id,
519
+ min(resource_version_id::text)::uuid AS resource_version_id,
520
+ action, array_agg(selection_source ORDER BY selection_source) AS selection_sources,
521
+ min(resource_workspace_id::text)::uuid AS resource_workspace_id,
522
+ min(authority_id::text)::uuid AS authority_id,
523
+ min(owner_organization_membership_id::text)::uuid
524
+ AS owner_organization_membership_id,
525
+ min(origin_workspace_id::text)::uuid AS origin_workspace_id
526
+ FROM selected
527
+ GROUP BY resource_kind, resource_id, action
528
+ ORDER BY resource_kind, resource_id
529
+ LOOP
530
+ IF resource_row.owner_organization_membership_id IS DISTINCT FROM member_row.id
531
+ OR resource_row.resource_workspace_id IS DISTINCT FROM member_row.personal_workspace_id
532
+ OR resource_row.origin_workspace_id IS DISTINCT FROM member_row.personal_workspace_id
533
+ THEN
534
+ RAISE EXCEPTION 'personal resource owner/origin does not match initiating membership'
535
+ USING ERRCODE = '42501';
536
+ END IF;
537
+
538
+ IF resource_row.resource_kind = 'variable_set' THEN
539
+ PERFORM 1 FROM workspace_variable_sets variable_set
540
+ WHERE variable_set.id = resource_row.resource_id
541
+ AND variable_set.account_id = NEW.account_id
542
+ AND variable_set.workspace_id = member_row.personal_workspace_id
543
+ AND variable_set.authority_scope = 'user'
544
+ AND variable_set.authority_id = resource_row.authority_id
545
+ AND variable_set.owner_organization_membership_id = member_row.id
546
+ AND variable_set.origin_workspace_id = member_row.personal_workspace_id
547
+ FOR SHARE;
548
+ ELSE
549
+ PERFORM 1 FROM rigs rig
550
+ WHERE rig.id = resource_row.resource_id
551
+ AND rig.account_id = NEW.account_id
552
+ AND rig.workspace_id = member_row.personal_workspace_id
553
+ AND rig.authority_scope = 'user'
554
+ AND rig.authority_id = resource_row.authority_id
555
+ AND rig.owner_organization_membership_id = member_row.id
556
+ AND rig.origin_workspace_id = member_row.personal_workspace_id
557
+ FOR SHARE;
558
+ IF FOUND THEN
559
+ PERFORM 1 FROM rig_versions rig_version
560
+ WHERE rig_version.id = resource_row.resource_version_id
561
+ AND rig_version.account_id = NEW.account_id
562
+ AND rig_version.rig_id = resource_row.resource_id
563
+ AND rig_version.workspace_id = member_row.personal_workspace_id
564
+ FOR SHARE;
565
+ END IF;
566
+ END IF;
567
+ IF NOT FOUND THEN
568
+ RAISE EXCEPTION 'personal resource identity changed during admission'
569
+ USING ERRCODE = '42501';
570
+ END IF;
571
+
572
+ PERFORM 1
573
+ FROM organization_user_resource_authorities authority
574
+ WHERE authority.id = resource_row.authority_id
575
+ AND authority.account_id = NEW.account_id
576
+ AND authority.organization_membership_id = member_row.id
577
+ AND authority.resource_kind = resource_row.resource_kind
578
+ AND authority.resource_id = resource_row.resource_id
579
+ AND authority.origin_workspace_id = member_row.personal_workspace_id
580
+ AND authority.status = 'active'
581
+ AND authority.revoked_at IS NULL
582
+ FOR SHARE;
583
+ IF NOT FOUND THEN
584
+ RAISE EXCEPTION 'personal resource authority is not live'
585
+ USING ERRCODE = '42501';
586
+ END IF;
587
+
588
+ SELECT grant_value.* INTO grant_row
589
+ FROM organization_user_resource_grants grant_value
590
+ WHERE grant_value.account_id = NEW.account_id
591
+ AND grant_value.authority_id = resource_row.authority_id
592
+ AND grant_value.owner_organization_membership_id = member_row.id
593
+ AND grant_value.workspace_id = NEW.workspace_id
594
+ AND grant_value.action = resource_row.action
595
+ AND grant_value.context = session_row.visibility
596
+ AND grant_value.status = 'active'
597
+ AND (grant_value.expires_at IS NULL OR grant_value.expires_at > clock_timestamp())
598
+ AND (
599
+ (
600
+ grant_value.mode IN ('once', 'session')
601
+ AND grant_value.session_id = NEW.session_id
602
+ AND grant_value.authority_epoch = session_row.authority_epoch
603
+ ) OR (
604
+ grant_value.mode = 'always'
605
+ AND grant_value.session_id IS NULL
606
+ AND grant_value.authority_epoch IS NULL
607
+ )
608
+ )
609
+ ORDER BY
610
+ CASE grant_value.mode WHEN 'once' THEN 1 WHEN 'session' THEN 2 ELSE 3 END,
611
+ grant_value.generation DESC,
612
+ grant_value.id
613
+ LIMIT 1
614
+ FOR UPDATE;
615
+ IF NOT FOUND THEN
616
+ RAISE EXCEPTION 'matching personal-resource grant required'
617
+ USING ERRCODE = '42501';
618
+ END IF;
619
+
620
+ INSERT INTO session_attempt_personal_resource_snapshots (
621
+ attempt_id, account_id, workspace_id, session_id, turn_id,
622
+ execution_generation, resource_kind, resource_id, resource_version_id,
623
+ selection_sources, action, origin_workspace_id,
624
+ owner_organization_membership_id, membership_authorization_revision,
625
+ authority_id, authority_generation, target_workspace_id,
626
+ session_visibility, session_authority_epoch, grant_id, grant_generation,
627
+ grant_mode, grant_context, grant_session_id, grant_authority_epoch
628
+ )
629
+ SELECT
630
+ NEW.id, NEW.account_id, NEW.workspace_id, NEW.session_id, NEW.turn_id,
631
+ NEW.execution_generation, resource_row.resource_kind, resource_row.resource_id,
632
+ resource_row.resource_version_id, resource_row.selection_sources,
633
+ resource_row.action, member_row.personal_workspace_id, member_row.id,
634
+ member_row.authorization_revision, authority.id, authority.generation,
635
+ NEW.workspace_id, session_row.visibility, session_row.authority_epoch,
636
+ grant_row.id, grant_row.generation, grant_row.mode, grant_row.context,
637
+ grant_row.session_id, grant_row.authority_epoch
638
+ FROM organization_user_resource_authorities authority
639
+ WHERE authority.id = resource_row.authority_id
640
+ AND authority.account_id = NEW.account_id;
641
+
642
+ IF grant_row.mode = 'once' THEN
643
+ UPDATE organization_user_resource_grants
644
+ SET status = 'consumed', updated_at = clock_timestamp()
645
+ WHERE id = grant_row.id
646
+ AND account_id = NEW.account_id
647
+ AND generation = grant_row.generation
648
+ AND status = 'active';
649
+ GET DIAGNOSTICS affected = ROW_COUNT;
650
+ IF affected <> 1 THEN
651
+ RAISE EXCEPTION 'once grant lost its first-use race'
652
+ USING ERRCODE = '40001';
653
+ END IF;
654
+ INSERT INTO personal_resource_once_consumption_receipts (
655
+ grant_id, account_id, attempt_id, workspace_id, session_id, turn_id,
656
+ execution_generation, authority_id, authority_generation, grant_generation
657
+ ) SELECT
658
+ grant_row.id, NEW.account_id, NEW.id, NEW.workspace_id, NEW.session_id,
659
+ NEW.turn_id, NEW.execution_generation, authority.id, authority.generation,
660
+ grant_row.generation
661
+ FROM organization_user_resource_authorities authority
662
+ WHERE authority.id = resource_row.authority_id
663
+ AND authority.account_id = NEW.account_id;
664
+ END IF;
665
+ snapshot_total := snapshot_total + 1;
666
+ END LOOP;
667
+
668
+ IF snapshot_total <> resource_total THEN
669
+ RAISE EXCEPTION 'personal-resource snapshot collection is not exact'
670
+ USING ERRCODE = '23514';
671
+ END IF;
672
+
673
+ DELETE FROM opengeni_private.personal_resource_delegation_capabilities
674
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
675
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
676
+ AND capability_kind = 'admit';
677
+ RETURN NEW;
678
+ EXCEPTION WHEN OTHERS THEN
679
+ DELETE FROM opengeni_private.personal_resource_delegation_capabilities
680
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
681
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
682
+ AND capability_kind = 'admit';
683
+ RAISE;
684
+ END;
685
+ $body$;
686
+ $ddl$, data_schema);
687
+
688
+ EXECUTE format($ddl$
689
+ CREATE OR REPLACE FUNCTION %1$I.resolve_session_attempt_personal_resources(
690
+ p_account_id uuid,
691
+ p_workspace_id uuid,
692
+ p_attempt_id uuid
693
+ ) RETURNS TABLE (
694
+ resource_kind text,
695
+ resource_id uuid,
696
+ resource_version_id uuid,
697
+ selection_sources text[],
698
+ action text,
699
+ authority_id uuid,
700
+ authority_generation bigint,
701
+ grant_id uuid,
702
+ grant_generation bigint,
703
+ grant_mode text
704
+ )
705
+ LANGUAGE plpgsql
706
+ SECURITY DEFINER
707
+ SET search_path = %1$I, pg_catalog
708
+ AS $body$
709
+ DECLARE
710
+ admission_row session_attempt_personal_resource_admissions%%ROWTYPE;
711
+ invalid_count integer;
712
+ caller_subject text := coalesce(
713
+ nullif(pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''),
714
+ nullif(pg_catalog.current_setting('opengeni.subject_id', true), '')
715
+ );
716
+ BEGIN
717
+ IF p_account_id IS DISTINCT FROM nullif(
718
+ pg_catalog.current_setting('opengeni.account_id', true), ''
719
+ )::uuid
720
+ OR p_workspace_id IS DISTINCT FROM nullif(
721
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
722
+ )::uuid
723
+ THEN
724
+ RAISE EXCEPTION 'personal-resource resolve scope mismatch'
725
+ USING ERRCODE = '42501';
726
+ END IF;
727
+
728
+ INSERT INTO opengeni_private.personal_resource_delegation_capabilities (
729
+ backend_pid, transaction_id, capability_kind
730
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'resolve')
731
+ ON CONFLICT DO NOTHING;
732
+
733
+ SELECT admission.* INTO STRICT admission_row
734
+ FROM session_attempt_personal_resource_admissions admission
735
+ WHERE admission.attempt_id = p_attempt_id
736
+ AND admission.account_id = p_account_id
737
+ AND admission.workspace_id = p_workspace_id;
738
+
739
+ IF caller_subject IS DISTINCT FROM admission_row.initiating_human_subject_id THEN
740
+ RAISE EXCEPTION 'personal-resource resolve initiating human mismatch'
741
+ USING ERRCODE = '42501';
742
+ END IF;
743
+
744
+ PERFORM 1
745
+ FROM sessions session_value
746
+ JOIN session_turns turn_value
747
+ ON turn_value.account_id = session_value.account_id
748
+ AND turn_value.workspace_id = session_value.workspace_id
749
+ AND turn_value.session_id = session_value.id
750
+ JOIN session_turn_attempts attempt
751
+ ON attempt.account_id = turn_value.account_id
752
+ AND attempt.workspace_id = turn_value.workspace_id
753
+ AND attempt.session_id = turn_value.session_id
754
+ AND attempt.turn_id = turn_value.id
755
+ WHERE session_value.id = admission_row.session_id
756
+ AND session_value.account_id = admission_row.account_id
757
+ AND session_value.workspace_id = admission_row.workspace_id
758
+ AND session_value.active_turn_id = admission_row.turn_id
759
+ AND turn_value.id = admission_row.turn_id
760
+ AND turn_value.active_attempt_id = admission_row.attempt_id
761
+ AND turn_value.execution_generation = admission_row.execution_generation
762
+ AND turn_value.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
763
+ AND attempt.id = admission_row.attempt_id
764
+ AND attempt.execution_generation = admission_row.execution_generation
765
+ AND attempt.state IN ('claimed', 'running')
766
+ AND attempt.closed_at IS NULL
767
+ AND attempt.quiesced_at IS NULL
768
+ FOR SHARE OF session_value, turn_value
769
+ FOR UPDATE OF attempt;
770
+ IF NOT FOUND THEN
771
+ RAISE EXCEPTION 'personal-resource resolve requires the exact current uninterrupted attempt'
772
+ USING ERRCODE = '42501';
773
+ END IF;
774
+
775
+ IF EXISTS (
776
+ SELECT 1
777
+ FROM session_attempt_interruptions interruption
778
+ WHERE interruption.account_id = admission_row.account_id
779
+ AND interruption.workspace_id = admission_row.workspace_id
780
+ AND interruption.session_id = admission_row.session_id
781
+ AND interruption.attempt_id = admission_row.attempt_id
782
+ AND interruption.state IN ('pending', 'delivered', 'acknowledged')
783
+ )
784
+ THEN
785
+ RAISE EXCEPTION 'personal-resource resolve requires the exact current uninterrupted attempt'
786
+ USING ERRCODE = '42501';
787
+ END IF;
788
+
789
+ SELECT count(*)::integer INTO invalid_count
790
+ FROM session_attempt_personal_resource_snapshots snapshot
791
+ WHERE snapshot.attempt_id = admission_row.attempt_id
792
+ AND NOT (
793
+ EXISTS (
794
+ SELECT 1
795
+ FROM session_turn_attempts attempt
796
+ JOIN sessions session_value
797
+ ON session_value.id = attempt.session_id
798
+ AND session_value.account_id = attempt.account_id
799
+ AND session_value.workspace_id = attempt.workspace_id
800
+ JOIN session_turns turn_value
801
+ ON turn_value.id = attempt.turn_id
802
+ AND turn_value.account_id = attempt.account_id
803
+ AND turn_value.workspace_id = attempt.workspace_id
804
+ AND turn_value.session_id = attempt.session_id
805
+ WHERE attempt.id = snapshot.attempt_id
806
+ AND attempt.account_id = snapshot.account_id
807
+ AND attempt.workspace_id = snapshot.workspace_id
808
+ AND attempt.session_id = snapshot.session_id
809
+ AND attempt.turn_id = snapshot.turn_id
810
+ AND attempt.execution_generation = snapshot.execution_generation
811
+ AND attempt.state IN ('claimed', 'running')
812
+ AND attempt.quiesced_at IS NULL
813
+ AND attempt.authority_visibility = snapshot.session_visibility
814
+ AND attempt.authority_epoch = snapshot.session_authority_epoch
815
+ AND session_value.visibility = snapshot.session_visibility
816
+ AND session_value.authority_epoch = snapshot.session_authority_epoch
817
+ AND coalesce(
818
+ nullif(btrim(turn_value.initiating_human_subject_id), ''),
819
+ CASE WHEN turn_value.initiator_kind = 'subject'
820
+ THEN nullif(btrim(turn_value.initiator_subject_id), '') END
821
+ ) = admission_row.initiating_human_subject_id
822
+ )
823
+ AND EXISTS (
824
+ SELECT 1
825
+ FROM organization_memberships membership
826
+ JOIN workspace_memberships workspace_membership
827
+ ON workspace_membership.account_id = membership.account_id
828
+ AND workspace_membership.workspace_id = snapshot.workspace_id
829
+ AND workspace_membership.subject_id = membership.subject_id
830
+ WHERE membership.id = snapshot.owner_organization_membership_id
831
+ AND membership.account_id = snapshot.account_id
832
+ AND membership.subject_id = admission_row.initiating_human_subject_id
833
+ AND membership.status = 'active'
834
+ AND membership.revoked_at IS NULL
835
+ AND membership.personal_workspace_id = snapshot.origin_workspace_id
836
+ AND membership.authorization_revision
837
+ = snapshot.membership_authorization_revision
838
+ )
839
+ AND EXISTS (
840
+ SELECT 1
841
+ FROM organization_user_resource_authorities authority
842
+ WHERE authority.id = snapshot.authority_id
843
+ AND authority.account_id = snapshot.account_id
844
+ AND authority.organization_membership_id
845
+ = snapshot.owner_organization_membership_id
846
+ AND authority.resource_kind = snapshot.resource_kind
847
+ AND authority.resource_id = snapshot.resource_id
848
+ AND authority.origin_workspace_id = snapshot.origin_workspace_id
849
+ AND authority.generation = snapshot.authority_generation
850
+ AND authority.status = 'active'
851
+ AND authority.revoked_at IS NULL
852
+ )
853
+ AND (
854
+ (
855
+ snapshot.resource_kind = 'variable_set'
856
+ AND EXISTS (
857
+ SELECT 1 FROM workspace_variable_sets variable_set
858
+ WHERE variable_set.id = snapshot.resource_id
859
+ AND variable_set.account_id = snapshot.account_id
860
+ AND variable_set.workspace_id = snapshot.origin_workspace_id
861
+ AND variable_set.authority_scope = 'user'
862
+ AND variable_set.authority_id = snapshot.authority_id
863
+ AND variable_set.owner_organization_membership_id
864
+ = snapshot.owner_organization_membership_id
865
+ AND variable_set.origin_workspace_id = snapshot.origin_workspace_id
866
+ )
867
+ ) OR (
868
+ snapshot.resource_kind = 'rig'
869
+ AND EXISTS (
870
+ SELECT 1 FROM rigs rig
871
+ JOIN rig_versions rig_version
872
+ ON rig_version.id = snapshot.resource_version_id
873
+ AND rig_version.rig_id = rig.id
874
+ AND rig_version.account_id = rig.account_id
875
+ AND rig_version.workspace_id = snapshot.origin_workspace_id
876
+ WHERE rig.id = snapshot.resource_id
877
+ AND rig.account_id = snapshot.account_id
878
+ AND rig.workspace_id = snapshot.origin_workspace_id
879
+ AND rig.authority_scope = 'user'
880
+ AND rig.authority_id = snapshot.authority_id
881
+ AND rig.owner_organization_membership_id
882
+ = snapshot.owner_organization_membership_id
883
+ AND rig.origin_workspace_id = snapshot.origin_workspace_id
884
+ )
885
+ )
886
+ )
887
+ AND EXISTS (
888
+ SELECT 1
889
+ FROM organization_user_resource_grants grant_value
890
+ WHERE grant_value.id = snapshot.grant_id
891
+ AND grant_value.account_id = snapshot.account_id
892
+ AND grant_value.authority_id = snapshot.authority_id
893
+ AND grant_value.owner_organization_membership_id
894
+ = snapshot.owner_organization_membership_id
895
+ AND grant_value.workspace_id = snapshot.target_workspace_id
896
+ AND grant_value.action = snapshot.action
897
+ AND grant_value.mode = snapshot.grant_mode
898
+ AND grant_value.context = snapshot.grant_context
899
+ AND grant_value.generation = snapshot.grant_generation
900
+ AND grant_value.session_id IS NOT DISTINCT FROM snapshot.grant_session_id
901
+ AND grant_value.authority_epoch
902
+ IS NOT DISTINCT FROM snapshot.grant_authority_epoch
903
+ AND (grant_value.expires_at IS NULL OR grant_value.expires_at > clock_timestamp())
904
+ AND (
905
+ (
906
+ snapshot.grant_mode = 'once'
907
+ AND grant_value.status = 'consumed'
908
+ AND EXISTS (
909
+ SELECT 1 FROM personal_resource_once_consumption_receipts receipt
910
+ WHERE receipt.grant_id = snapshot.grant_id
911
+ AND receipt.account_id = snapshot.account_id
912
+ AND receipt.attempt_id = snapshot.attempt_id
913
+ AND receipt.authority_id = snapshot.authority_id
914
+ AND receipt.authority_generation = snapshot.authority_generation
915
+ AND receipt.grant_generation = snapshot.grant_generation
916
+ )
917
+ ) OR (
918
+ snapshot.grant_mode IN ('session', 'always')
919
+ AND grant_value.status = 'active'
920
+ )
921
+ )
922
+ )
923
+ );
924
+
925
+ IF invalid_count <> 0 THEN
926
+ RAISE EXCEPTION 'personal-resource authority snapshot is no longer live'
927
+ USING ERRCODE = '42501';
928
+ END IF;
929
+
930
+ SELECT count(*)::integer INTO invalid_count
931
+ FROM session_attempt_personal_resource_snapshots snapshot
932
+ WHERE snapshot.attempt_id = admission_row.attempt_id;
933
+ IF invalid_count <> admission_row.resource_count THEN
934
+ RAISE EXCEPTION 'personal-resource snapshot collection is incomplete'
935
+ USING ERRCODE = '42501';
936
+ END IF;
937
+
938
+ RETURN QUERY
939
+ SELECT snapshot.resource_kind, snapshot.resource_id,
940
+ snapshot.resource_version_id, snapshot.selection_sources, snapshot.action,
941
+ snapshot.authority_id, snapshot.authority_generation, snapshot.grant_id,
942
+ snapshot.grant_generation, snapshot.grant_mode
943
+ FROM session_attempt_personal_resource_snapshots snapshot
944
+ WHERE snapshot.attempt_id = admission_row.attempt_id
945
+ ORDER BY snapshot.resource_kind, snapshot.resource_id;
946
+
947
+ DELETE FROM opengeni_private.personal_resource_delegation_capabilities
948
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
949
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
950
+ AND capability_kind = 'resolve';
951
+ RETURN;
952
+ EXCEPTION WHEN OTHERS THEN
953
+ DELETE FROM opengeni_private.personal_resource_delegation_capabilities
954
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
955
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
956
+ AND capability_kind = 'resolve';
957
+ RAISE;
958
+ END;
959
+ $body$;
960
+ $ddl$, data_schema);
961
+
962
+ EXECUTE format(
963
+ 'DROP TRIGGER IF EXISTS session_attempt_personal_resource_admission '
964
+ || 'ON %I.session_turn_attempts',
965
+ data_schema
966
+ );
967
+ EXECUTE format(
968
+ 'CREATE TRIGGER session_attempt_personal_resource_admission '
969
+ || 'AFTER INSERT ON %I.session_turn_attempts FOR EACH ROW '
970
+ || 'EXECUTE FUNCTION %I.admit_session_attempt_personal_resources()',
971
+ data_schema,
972
+ data_schema
973
+ );
974
+ END
975
+ $personal_resource_delegation_functions$;
976
+
977
+ REVOKE ALL ON FUNCTION resolve_session_attempt_personal_resources(uuid, uuid, uuid)
978
+ FROM PUBLIC;
979
+ REVOKE ALL ON FUNCTION admit_session_attempt_personal_resources() FROM PUBLIC;
980
+
981
+ DO $personal_resource_runtime_grants$
982
+ BEGIN
983
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
984
+ GRANT EXECUTE ON FUNCTION resolve_session_attempt_personal_resources(uuid, uuid, uuid)
985
+ TO opengeni_app;
986
+ REVOKE ALL ON TABLE "session_attempt_personal_resource_admissions" FROM opengeni_app;
987
+ REVOKE ALL ON TABLE "session_attempt_personal_resource_snapshots" FROM opengeni_app;
988
+ REVOKE ALL ON TABLE "personal_resource_once_consumption_receipts" FROM opengeni_app;
989
+ END IF;
990
+ END
991
+ $personal_resource_runtime_grants$;
992
+
993
+ COMMENT ON TABLE "session_attempt_personal_resource_admissions" IS
994
+ 'Exact accepted-attempt personal-resource authority receipt; no secrets or runtime materialization.';
995
+ COMMENT ON TABLE "session_attempt_personal_resource_snapshots" IS
996
+ 'Normalized immutable direct/transitive personal-resource delegation collection for one accepted attempt.';
997
+ COMMENT ON TABLE "personal_resource_once_consumption_receipts" IS
998
+ 'Unique first-use receipt binding one consumed once grant to its exact accepted attempt.';
999
+ COMMENT ON FUNCTION resolve_session_attempt_personal_resources(uuid, uuid, uuid) IS
1000
+ 'Fail-closed exact-attempt authority revalidation and identifier-only personal-resource collection read.';