@opengeni/db 0.36.1 → 3.1.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 (274) 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-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
  7. package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
  8. package/dist/{chunk-HSOWSYOX.js → chunk-NMUBV7Z5.js} +19 -11
  9. package/dist/chunk-NMUBV7Z5.js.map +1 -0
  10. package/dist/chunk-OF5OBB76.js +4457 -0
  11. package/dist/chunk-OF5OBB76.js.map +1 -0
  12. package/dist/{chunk-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
  13. package/dist/chunk-PR2WMLOQ.js.map +1 -0
  14. package/dist/{chunk-Z7VYMNPZ.js → chunk-SCPUJS53.js} +41 -4
  15. package/dist/chunk-SCPUJS53.js.map +1 -0
  16. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  17. package/dist/chunk-SIBYBA2D.js.map +1 -0
  18. package/dist/chunk-TIKF3KTI.js +383 -0
  19. package/dist/chunk-TIKF3KTI.js.map +1 -0
  20. package/dist/chunk-ZZ5LJEFX.js +516 -0
  21. package/dist/chunk-ZZ5LJEFX.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 +41 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +19 -0
  35. package/dist/editable-artifact-durable-export.d.ts +10 -0
  36. package/dist/editable-artifact-durable-export.js +18 -3
  37. package/dist/editable-artifact-durable-export.js.map +1 -1
  38. package/dist/editable-artifacts.d.ts +2 -2
  39. package/dist/editable-artifacts.js +3 -3
  40. package/dist/governed-learning-activation-schema.d.ts +984 -0
  41. package/dist/governed-learning-activation.d.ts +98 -0
  42. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  43. package/dist/governed-learning-evaluator.d.ts +28 -0
  44. package/dist/index.d.ts +1633 -87
  45. package/dist/index.js +22004 -8109
  46. package/dist/index.js.map +1 -1
  47. package/dist/insights.d.ts +18 -0
  48. package/dist/integration-bindings.d.ts +1 -0
  49. package/dist/integration-facets.d.ts +30 -0
  50. package/dist/interaction-placement-loss.d.ts +22 -0
  51. package/dist/knowledge-source-sync-schema.d.ts +730 -0
  52. package/dist/knowledge-source-sync.d.ts +60 -0
  53. package/dist/managed-human-provisioning.d.ts +25 -0
  54. package/dist/memory-domain.d.ts +3 -3
  55. package/dist/migrate.d.ts +11 -1
  56. package/dist/migrate.js +1 -1
  57. package/dist/new-session-drafts.d.ts +43 -5
  58. package/dist/organization-membership-backfill.d.ts +174 -0
  59. package/dist/organization-membership-lifecycle.d.ts +162 -0
  60. package/dist/pr-review.d.ts +107 -0
  61. package/dist/preference-registry-schema.d.ts +2 -0
  62. package/dist/preference-registry.d.ts +2 -0
  63. package/dist/provision-roles.js +1 -1
  64. package/dist/runtime-posture.d.ts +23 -9
  65. package/dist/schema.d.ts +24925 -13697
  66. package/dist/schema.js +103 -1
  67. package/dist/scoped-knowledge-schema.d.ts +52 -1
  68. package/dist/session-background-commands.d.ts +125 -0
  69. package/dist/session-background-commands.js +34 -0
  70. package/dist/session-background-commands.js.map +1 -0
  71. package/dist/session-control.d.ts +156 -3
  72. package/dist/session-goal-pacing.d.ts +68 -0
  73. package/dist/session-queue-commands.d.ts +42 -5
  74. package/dist/session-realtime-ledger.d.ts +3 -0
  75. package/dist/session-tenancy.d.ts +71 -1
  76. package/dist/session-tenancy.js +25 -3
  77. package/dist/session-tool-call-settlement.d.ts +9 -4
  78. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  79. package/dist/slack-routing.d.ts +153 -0
  80. package/dist/slack-task-policy-schema.d.ts +34 -0
  81. package/dist/slack-task-policy.d.ts +8 -0
  82. package/dist/slack-user-link-access.d.ts +1 -0
  83. package/dist/task-notes-schema.d.ts +594 -0
  84. package/dist/task-notes.d.ts +39 -0
  85. package/dist/turn-initiator.d.ts +2 -0
  86. package/dist/user-resource-authority.d.ts +109 -0
  87. package/dist/video-generation.js +3 -3
  88. package/dist/workspace-authority.d.ts +81 -0
  89. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  90. package/dist/workspace-instruction-policies.d.ts +62 -0
  91. package/dist/workspace-learning-policy.d.ts +1 -0
  92. package/dist/workspace-membership-permissions.d.ts +2 -0
  93. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  94. package/drizzle/0240_model_context_user_messages.sql +204 -0
  95. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  96. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  97. package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
  98. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  99. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  100. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  101. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  102. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  103. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  104. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  105. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  106. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  107. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  108. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  109. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  110. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  111. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  112. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  113. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  114. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  115. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  116. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  117. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  118. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  119. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  120. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  121. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  122. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  123. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  124. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  125. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  126. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  127. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  128. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  129. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  130. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  131. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  132. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  133. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  134. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  135. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  136. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  137. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  138. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  139. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  140. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  141. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  142. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  143. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  144. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  145. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  146. package/drizzle/0294_preference_activation_authority.sql +237 -0
  147. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  148. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  149. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  150. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  151. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  152. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  153. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  154. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  155. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  156. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  157. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  158. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  159. package/drizzle/0307_session_attention_state.sql +51 -0
  160. package/drizzle/0308_session_archives.sql +35 -0
  161. package/drizzle/0309_channel_project_pins.sql +6 -0
  162. package/drizzle/0310_channel_project_order.sql +27 -0
  163. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  164. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  165. package/drizzle/0313_private_child_session_authority.sql +365 -0
  166. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  167. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  168. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  169. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  170. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  171. package/drizzle/0319_event_triggered_automations.sql +254 -0
  172. package/drizzle/0320_pr_review_pack.sql +113 -0
  173. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  174. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  175. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  176. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  177. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  178. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  179. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  180. package/drizzle/0328_session_background_commands.sql +590 -0
  181. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  182. package/drizzle/0330_api_key_descriptions.sql +20 -0
  183. package/drizzle/0331_managed_organization_creation.sql +163 -0
  184. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  185. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  186. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  187. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  188. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  189. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  190. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  191. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  192. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  193. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -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 +81 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +75 -2
  214. package/src/editable-artifact-durable-export.ts +27 -0
  215. package/src/editable-artifacts-schema.ts +10 -5
  216. package/src/editable-artifacts.ts +21 -11
  217. package/src/governed-learning-activation-schema.ts +121 -0
  218. package/src/governed-learning-activation.ts +588 -0
  219. package/src/governed-learning-evaluator-schema.ts +72 -0
  220. package/src/governed-learning-evaluator.ts +217 -0
  221. package/src/index.ts +12001 -1699
  222. package/src/insights.ts +107 -0
  223. package/src/integration-bindings.ts +88 -6
  224. package/src/integration-facets.ts +287 -84
  225. package/src/interaction-placement-loss.ts +234 -0
  226. package/src/knowledge-source-sync-schema.ts +83 -0
  227. package/src/knowledge-source-sync.ts +530 -0
  228. package/src/managed-human-provisioning.ts +116 -0
  229. package/src/memory-domain.ts +27 -32
  230. package/src/migrate.ts +77 -1
  231. package/src/new-session-drafts.ts +229 -35
  232. package/src/organization-membership-backfill.ts +735 -0
  233. package/src/organization-membership-lifecycle.ts +985 -0
  234. package/src/pr-review.ts +890 -0
  235. package/src/preference-registry.ts +31 -1
  236. package/src/provision-roles.ts +931 -24
  237. package/src/runtime-posture-cli.ts +2 -0
  238. package/src/runtime-posture.ts +1315 -52
  239. package/src/schema.ts +3336 -438
  240. package/src/scoped-knowledge-schema.ts +16 -8
  241. package/src/scoped-knowledge.ts +1 -1
  242. package/src/session-background-commands.ts +759 -0
  243. package/src/session-control.ts +640 -74
  244. package/src/session-goal-pacing.ts +126 -0
  245. package/src/session-queue-commands.ts +450 -98
  246. package/src/session-realtime-context.ts +19 -3
  247. package/src/session-realtime-ledger.ts +75 -12
  248. package/src/session-realtime-mirror.ts +1 -1
  249. package/src/session-tenancy.ts +403 -49
  250. package/src/session-tool-call-settlement.ts +38 -29
  251. package/src/slack-routing-personal-workspace.ts +67 -0
  252. package/src/slack-routing.ts +469 -0
  253. package/src/slack-task-policy-schema.ts +5 -0
  254. package/src/slack-task-policy.ts +18 -0
  255. package/src/slack-user-link-access.ts +17 -1
  256. package/src/task-notes-schema.ts +74 -0
  257. package/src/task-notes.ts +124 -2
  258. package/src/turn-initiator.ts +8 -0
  259. package/src/user-resource-authority.ts +377 -0
  260. package/src/workspace-authority.ts +160 -0
  261. package/src/workspace-instruction-policies-schema.ts +53 -1
  262. package/src/workspace-instruction-policies.ts +528 -77
  263. package/src/workspace-learning-policy.ts +21 -5
  264. package/src/workspace-membership-permissions.ts +9 -0
  265. package/dist/chunk-5KTIEDX7.js.map +0 -1
  266. package/dist/chunk-FPVAD4CO.js +0 -117
  267. package/dist/chunk-FPVAD4CO.js.map +0 -1
  268. package/dist/chunk-HSOWSYOX.js.map +0 -1
  269. package/dist/chunk-SK7YYHBI.js.map +0 -1
  270. package/dist/chunk-VKLB2ZGI.js +0 -2389
  271. package/dist/chunk-VKLB2ZGI.js.map +0 -1
  272. package/dist/chunk-Z7VYMNPZ.js.map +0 -1
  273. /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
  274. /package/dist/{chunk-VTPRIXKG.js.map → chunk-NJVZPWXY.js.map} +0 -0
@@ -0,0 +1,489 @@
1
+ -- deployment-mode: rolling
2
+ -- Adds the owner/admin organization product setting for Only-me chats in
3
+ -- SHARED organization workspaces. The operator readiness receipt from
4
+ -- migration 0303 (`session_tenancy_activations`, version 1) remains the
5
+ -- separate, unchanged prerequisite for every private create: this migration
6
+ -- only adds a second, owner/admin-controlled condition for shared workspaces.
7
+ -- A managed human's own Personal workspace keeps the exact 0311 rule (receipt
8
+ -- only) and is not affected by the setting.
9
+ --
10
+ -- Rolling compatibility: every organization that already holds the 0303
11
+ -- receipt is backfilled enabled, so nothing that works today stops working
12
+ -- when this migration commits. Only a new binary can disable the setting. An
13
+ -- old binary that races such a disable inside the rollout window reaches the
14
+ -- repaired `open_private_session_create_capability`, which raises SQLSTATE
15
+ -- 55000 before any capability or session row exists; the old binary fails that
16
+ -- one private create closed (it maps no new SQLSTATE) and creates nothing.
17
+ --
18
+ -- Lock order: the repaired TypeScript create path takes the organization
19
+ -- advisory fence (`organization-membership:<organization id>`) BEFORE its
20
+ -- workspace prefix for every user_private create (0299 order), so the setting
21
+ -- read inside `open_private_session_create_capability` is serialized against
22
+ -- settings changes and membership commands. The function itself never BLOCKS
23
+ -- on that fence: a pre-0323 binary reaches it already holding
24
+ -- workspace_inference_controls FOR SHARE and organization_memberships FOR KEY
25
+ -- SHARE, and a blocking acquisition there would deadlock (40P01) against a
26
+ -- membership command holding the fence and waiting on organization_memberships
27
+ -- FOR UPDATE. It therefore only tries the fence: a repaired caller already
28
+ -- holds it (re-entrant, no-op); an old binary either acquires the free fence or,
29
+ -- when a membership/settings command holds it, proceeds with an UNFENCED
30
+ -- read-committed read of the setting for that one create during the rollout
31
+ -- window. That is a benign product-toggle race, never an authority race: the
32
+ -- 0303 receipt, membership, and workspace-membership checks are unchanged.
33
+
34
+ SET LOCAL lock_timeout = '5s';
35
+ SET LOCAL statement_timeout = '10min';
36
+
37
+ CREATE TABLE organization_private_session_settings (
38
+ account_id uuid PRIMARY KEY REFERENCES managed_accounts(id) ON DELETE CASCADE,
39
+ enabled boolean NOT NULL DEFAULT false,
40
+ version bigint NOT NULL DEFAULT 1,
41
+ updated_by_membership_id uuid,
42
+ updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
43
+ CONSTRAINT organization_private_session_settings_updater_fk
44
+ FOREIGN KEY (updated_by_membership_id, account_id)
45
+ REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
46
+ CONSTRAINT organization_private_session_settings_version_check CHECK (version > 0)
47
+ );
48
+ ALTER TABLE organization_private_session_settings ENABLE ROW LEVEL SECURITY;
49
+ ALTER TABLE organization_private_session_settings FORCE ROW LEVEL SECURITY;
50
+ REVOKE ALL ON TABLE organization_private_session_settings FROM PUBLIC;
51
+ CREATE POLICY organization_private_session_settings_lifecycle
52
+ ON organization_private_session_settings
53
+ USING (current_setting('opengeni.organization_tenancy_lifecycle', true)
54
+ = 'organization_private_session_settings')
55
+ WITH CHECK (current_setting('opengeni.organization_tenancy_lifecycle', true)
56
+ = 'organization_private_session_settings');
57
+ CREATE POLICY organization_private_session_settings_scoped_read
58
+ ON organization_private_session_settings
59
+ FOR SELECT USING (
60
+ account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
61
+ );
62
+
63
+ -- Organizations that completed the older operator activation already had the
64
+ -- product surface enabled. Preserve that behavior; only organizations activated
65
+ -- after this migration require an owner/admin product decision.
66
+ --
67
+ -- Both the source and target are FORCE-RLS tables. Production migrations run as
68
+ -- their NOSUPERUSER/NOBYPASSRLS owner with no tenant GUC, so the owner would
69
+ -- otherwise see zero activation rows and be unable to insert the compatibility
70
+ -- settings. The migration runner executes this file in one transaction: NO
71
+ -- FORCE relaxes only the owner, the application role remains policy-bound, and
72
+ -- any failed verification rolls the data and posture changes back together.
73
+ ALTER TABLE session_tenancy_activations NO FORCE ROW LEVEL SECURITY;
74
+ ALTER TABLE organization_private_session_settings NO FORCE ROW LEVEL SECURITY;
75
+ INSERT INTO organization_private_session_settings (
76
+ account_id, enabled, version, updated_by_membership_id, updated_at
77
+ )
78
+ SELECT activation.account_id, true, 1, NULL, activation.activated_at
79
+ FROM session_tenancy_activations activation
80
+ ON CONFLICT (account_id) DO NOTHING;
81
+ DO $organization_private_session_compatibility_backfill$
82
+ DECLARE
83
+ missing_enabled_settings bigint;
84
+ BEGIN
85
+ SELECT count(*) INTO missing_enabled_settings
86
+ FROM session_tenancy_activations activation
87
+ LEFT JOIN organization_private_session_settings setting
88
+ ON setting.account_id = activation.account_id
89
+ WHERE setting.account_id IS NULL OR NOT setting.enabled;
90
+ IF missing_enabled_settings > 0 THEN
91
+ RAISE EXCEPTION
92
+ 'organization private-session compatibility backfill did not converge: % activated organization(s) remain disabled',
93
+ missing_enabled_settings
94
+ USING ERRCODE = '55000';
95
+ END IF;
96
+ END
97
+ $organization_private_session_compatibility_backfill$;
98
+ ALTER TABLE organization_private_session_settings FORCE ROW LEVEL SECURITY;
99
+ ALTER TABLE session_tenancy_activations FORCE ROW LEVEL SECURITY;
100
+
101
+ CREATE TABLE organization_private_session_setting_events (
102
+ id uuid PRIMARY KEY,
103
+ account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
104
+ actor_membership_id uuid NOT NULL,
105
+ requested_enabled boolean NOT NULL,
106
+ expected_version bigint NOT NULL,
107
+ result_enabled boolean NOT NULL,
108
+ result_version bigint NOT NULL,
109
+ result_updated_at timestamptz NOT NULL,
110
+ changed boolean NOT NULL,
111
+ created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
112
+ CONSTRAINT organization_private_session_setting_events_actor_fk
113
+ FOREIGN KEY (actor_membership_id, account_id)
114
+ REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
115
+ CONSTRAINT organization_private_session_setting_events_versions_check CHECK (
116
+ expected_version >= 0 AND result_version > 0
117
+ )
118
+ );
119
+ ALTER TABLE organization_private_session_setting_events ENABLE ROW LEVEL SECURITY;
120
+ ALTER TABLE organization_private_session_setting_events FORCE ROW LEVEL SECURITY;
121
+ REVOKE ALL ON TABLE organization_private_session_setting_events FROM PUBLIC;
122
+ CREATE POLICY organization_private_session_setting_events_lifecycle
123
+ ON organization_private_session_setting_events
124
+ USING (current_setting('opengeni.organization_tenancy_lifecycle', true)
125
+ = 'organization_private_session_settings')
126
+ WITH CHECK (current_setting('opengeni.organization_tenancy_lifecycle', true)
127
+ = 'organization_private_session_settings');
128
+
129
+ CREATE FUNCTION organization_private_sessions_enabled(p_account_id uuid)
130
+ RETURNS boolean
131
+ LANGUAGE sql STABLE SECURITY DEFINER
132
+ SET search_path FROM CURRENT
133
+ AS $body$
134
+ SELECT p_account_id IS NOT DISTINCT FROM
135
+ nullif(current_setting('opengeni.account_id', true), '')::uuid
136
+ AND session_tenancy_product_activated(p_account_id, 1)
137
+ AND EXISTS (
138
+ SELECT 1 FROM organization_private_session_settings setting
139
+ WHERE setting.account_id = p_account_id AND setting.enabled
140
+ )
141
+ $body$;
142
+ REVOKE ALL ON FUNCTION organization_private_sessions_enabled(uuid) FROM PUBLIC;
143
+
144
+ CREATE FUNCTION get_private_session_create_policy(
145
+ p_account_id uuid,
146
+ p_workspace_id uuid,
147
+ p_actor_subject_id text
148
+ ) RETURNS TABLE (
149
+ personal_workspace boolean,
150
+ platform_available boolean,
151
+ organization_enabled boolean
152
+ )
153
+ LANGUAGE plpgsql STABLE SECURITY DEFINER
154
+ SET search_path FROM CURRENT
155
+ AS $body$
156
+ DECLARE
157
+ actor organization_memberships%ROWTYPE;
158
+ BEGIN
159
+ IF p_account_id IS NULL OR p_workspace_id IS NULL OR p_actor_subject_id IS NULL
160
+ OR p_actor_subject_id IS DISTINCT FROM opengeni_private.current_subject_id()
161
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
162
+ OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
163
+ THEN
164
+ RAISE EXCEPTION 'private session create policy authority required'
165
+ USING ERRCODE = '42501';
166
+ END IF;
167
+ SELECT membership.* INTO actor FROM organization_memberships membership
168
+ WHERE membership.account_id = p_account_id
169
+ AND membership.subject_id = p_actor_subject_id
170
+ AND membership.status = 'active';
171
+ IF NOT FOUND OR NOT EXISTS (
172
+ SELECT 1 FROM workspaces workspace
173
+ WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
174
+ ) OR NOT (
175
+ actor.personal_workspace_id = p_workspace_id
176
+ OR EXISTS (
177
+ SELECT 1 FROM workspace_memberships access
178
+ WHERE access.account_id = p_account_id
179
+ AND access.workspace_id = p_workspace_id
180
+ AND access.subject_id = p_actor_subject_id
181
+ )
182
+ ) THEN
183
+ RAISE EXCEPTION 'private session create policy authority required'
184
+ USING ERRCODE = '42501';
185
+ END IF;
186
+ personal_workspace := actor.personal_workspace_id = p_workspace_id;
187
+ platform_available := session_tenancy_product_activated(p_account_id, 1);
188
+ organization_enabled := organization_private_sessions_enabled(p_account_id);
189
+ RETURN NEXT;
190
+ END
191
+ $body$;
192
+ REVOKE ALL ON FUNCTION get_private_session_create_policy(uuid,uuid,text) FROM PUBLIC;
193
+
194
+ CREATE FUNCTION get_organization_private_session_settings(
195
+ p_account_id uuid,
196
+ p_actor_subject_id text
197
+ ) RETURNS jsonb
198
+ LANGUAGE plpgsql SECURITY DEFINER
199
+ SET search_path FROM CURRENT
200
+ AS $body$
201
+ DECLARE
202
+ actor organization_memberships%ROWTYPE;
203
+ setting organization_private_session_settings%ROWTYPE;
204
+ account_created_at timestamptz;
205
+ BEGIN
206
+ IF p_account_id IS NULL
207
+ OR p_actor_subject_id IS DISTINCT FROM opengeni_private.current_subject_id()
208
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
209
+ THEN
210
+ RAISE EXCEPTION 'organization administration authority required' USING ERRCODE = '42501';
211
+ END IF;
212
+ PERFORM pg_catalog.set_config(
213
+ 'opengeni.organization_tenancy_lifecycle',
214
+ 'organization_private_session_settings', true
215
+ );
216
+ -- Read-only projection: no row locks. Staleness is bounded by the version
217
+ -- the caller must echo back on update.
218
+ SELECT account.created_at INTO account_created_at FROM managed_accounts account
219
+ WHERE account.id = p_account_id;
220
+ IF NOT FOUND THEN RAISE EXCEPTION 'organization not found' USING ERRCODE = 'P0002'; END IF;
221
+ SELECT membership.* INTO actor FROM organization_memberships membership
222
+ WHERE membership.account_id = p_account_id
223
+ AND membership.subject_id = p_actor_subject_id;
224
+ IF NOT FOUND OR actor.status <> 'active' OR actor.role NOT IN ('owner', 'admin') THEN
225
+ RAISE EXCEPTION 'organization administration required' USING ERRCODE = '42501';
226
+ END IF;
227
+ SELECT * INTO setting FROM organization_private_session_settings candidate
228
+ WHERE candidate.account_id = p_account_id;
229
+ RETURN pg_catalog.jsonb_build_object(
230
+ 'organizationId', p_account_id,
231
+ 'enabled', coalesce(setting.enabled, false),
232
+ 'available', session_tenancy_product_activated(p_account_id, 1),
233
+ 'version', coalesce(setting.version, 0),
234
+ 'updatedAt', coalesce(setting.updated_at, account_created_at)
235
+ );
236
+ END
237
+ $body$;
238
+ REVOKE ALL ON FUNCTION get_organization_private_session_settings(uuid,text) FROM PUBLIC;
239
+
240
+ CREATE FUNCTION update_organization_private_session_settings(
241
+ p_account_id uuid,
242
+ p_actor_subject_id text,
243
+ p_enabled boolean,
244
+ p_expected_version bigint,
245
+ p_operation_id uuid
246
+ ) RETURNS jsonb
247
+ LANGUAGE plpgsql SECURITY DEFINER
248
+ SET search_path FROM CURRENT
249
+ AS $body$
250
+ DECLARE
251
+ actor organization_memberships%ROWTYPE;
252
+ setting organization_private_session_settings%ROWTYPE;
253
+ prior organization_private_session_setting_events%ROWTYPE;
254
+ next_version bigint;
255
+ did_change boolean;
256
+ BEGIN
257
+ IF p_account_id IS NULL OR p_enabled IS NULL OR p_operation_id IS NULL
258
+ OR p_expected_version IS NULL OR p_expected_version < 0
259
+ OR p_actor_subject_id IS DISTINCT FROM opengeni_private.current_subject_id()
260
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
261
+ THEN
262
+ RAISE EXCEPTION 'organization private-session settings request is invalid'
263
+ USING ERRCODE = '22023';
264
+ END IF;
265
+ -- Organization lifecycle prefix (0299): the advisory organization fence, then
266
+ -- no lock stronger than managed_accounts FOR KEY SHARE. This seam touches no
267
+ -- workspace row, so it can never invert against an ordinary workspace writer.
268
+ PERFORM pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
269
+ 'organization-membership:' || p_account_id::text, 0
270
+ ));
271
+ PERFORM pg_catalog.set_config(
272
+ 'opengeni.organization_tenancy_lifecycle',
273
+ 'organization_private_session_settings', true
274
+ );
275
+ PERFORM 1 FROM managed_accounts account WHERE account.id = p_account_id FOR KEY SHARE;
276
+ IF NOT FOUND THEN RAISE EXCEPTION 'organization not found' USING ERRCODE = 'P0002'; END IF;
277
+ SELECT membership.* INTO actor FROM organization_memberships membership
278
+ WHERE membership.account_id = p_account_id
279
+ AND membership.subject_id = p_actor_subject_id
280
+ FOR SHARE;
281
+ IF NOT FOUND OR actor.status <> 'active' OR actor.role NOT IN ('owner', 'admin') THEN
282
+ RAISE EXCEPTION 'organization administration required' USING ERRCODE = '42501';
283
+ END IF;
284
+ SELECT * INTO prior FROM organization_private_session_setting_events event
285
+ WHERE event.id = p_operation_id;
286
+ IF FOUND THEN
287
+ IF prior.account_id IS DISTINCT FROM p_account_id
288
+ OR prior.actor_membership_id IS DISTINCT FROM actor.id
289
+ OR prior.requested_enabled IS DISTINCT FROM p_enabled
290
+ OR prior.expected_version IS DISTINCT FROM p_expected_version
291
+ THEN
292
+ RAISE EXCEPTION 'organization private-session operation key was reused'
293
+ USING ERRCODE = '23505';
294
+ END IF;
295
+ RETURN pg_catalog.jsonb_build_object(
296
+ 'organizationId', p_account_id,
297
+ 'enabled', prior.result_enabled,
298
+ 'available', session_tenancy_product_activated(p_account_id, 1),
299
+ 'version', prior.result_version,
300
+ 'updatedAt', prior.result_updated_at,
301
+ 'changed', prior.changed
302
+ );
303
+ END IF;
304
+ SELECT * INTO setting FROM organization_private_session_settings candidate
305
+ WHERE candidate.account_id = p_account_id FOR UPDATE;
306
+ IF coalesce(setting.version, 0) IS DISTINCT FROM p_expected_version THEN
307
+ RAISE EXCEPTION 'organization private-session settings changed before update'
308
+ USING ERRCODE = '40001';
309
+ END IF;
310
+ IF p_enabled AND NOT session_tenancy_product_activated(p_account_id, 1) THEN
311
+ RAISE EXCEPTION 'session tenancy product surface is not available for this organization'
312
+ USING ERRCODE = '55000';
313
+ END IF;
314
+ did_change := coalesce(setting.enabled, false) IS DISTINCT FROM p_enabled;
315
+ next_version := CASE WHEN setting.account_id IS NULL THEN 1 ELSE setting.version + 1 END;
316
+ INSERT INTO organization_private_session_settings (
317
+ account_id, enabled, version, updated_by_membership_id, updated_at
318
+ ) VALUES (
319
+ p_account_id, p_enabled, next_version, actor.id, clock_timestamp()
320
+ ) ON CONFLICT (account_id) DO UPDATE SET
321
+ enabled = excluded.enabled,
322
+ version = excluded.version,
323
+ updated_by_membership_id = excluded.updated_by_membership_id,
324
+ updated_at = excluded.updated_at
325
+ RETURNING * INTO setting;
326
+ INSERT INTO organization_private_session_setting_events (
327
+ id, account_id, actor_membership_id, requested_enabled,
328
+ expected_version, result_enabled, result_version, result_updated_at, changed
329
+ ) VALUES (
330
+ p_operation_id, p_account_id, actor.id, p_enabled,
331
+ p_expected_version, setting.enabled, setting.version, setting.updated_at, did_change
332
+ );
333
+ RETURN pg_catalog.jsonb_build_object(
334
+ 'organizationId', p_account_id,
335
+ 'enabled', setting.enabled,
336
+ 'available', session_tenancy_product_activated(p_account_id, 1),
337
+ 'version', setting.version,
338
+ 'updatedAt', setting.updated_at,
339
+ 'changed', did_change
340
+ );
341
+ END
342
+ $body$;
343
+ REVOKE ALL ON FUNCTION
344
+ update_organization_private_session_settings(uuid,text,boolean,bigint,uuid) FROM PUBLIC;
345
+
346
+ -- Same contract as 0311 plus one additional condition for SHARED workspaces:
347
+ -- the organization owner/admin setting must be enabled. The 0303 readiness
348
+ -- receipt stays in the entry guard for every caller and every workspace kind,
349
+ -- and a managed human's own Personal workspace is otherwise unchanged.
350
+ CREATE OR REPLACE FUNCTION open_private_session_create_capability(
351
+ p_account_id uuid,
352
+ p_workspace_id uuid,
353
+ p_session_id uuid,
354
+ p_actor_subject_id text
355
+ ) RETURNS TABLE (capability_id uuid, owner_membership_id uuid)
356
+ LANGUAGE plpgsql SECURITY DEFINER
357
+ SET search_path FROM CURRENT
358
+ AS $body$
359
+ DECLARE
360
+ new_capability_id uuid := gen_random_uuid();
361
+ actor_membership_id uuid;
362
+ actor_personal_workspace boolean;
363
+ workspace_access_id uuid;
364
+ BEGIN
365
+ IF p_account_id IS NULL OR p_workspace_id IS NULL OR p_session_id IS NULL
366
+ OR p_actor_subject_id IS NULL OR p_actor_subject_id NOT LIKE 'user:%'
367
+ OR p_actor_subject_id IS DISTINCT FROM opengeni_private.current_subject_id()
368
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
369
+ OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
370
+ OR NOT session_tenancy_product_activated(p_account_id, 1)
371
+ THEN
372
+ RAISE EXCEPTION 'private session create authority required' USING ERRCODE = '42501';
373
+ END IF;
374
+ -- The organization advisory fence is the same transaction-scoped lock taken
375
+ -- by organization settings changes and membership suspend/offboard. A
376
+ -- repaired writer already holds it before its workspace prefix (0299 order),
377
+ -- so this try is a re-entrant no-op and the enablement read below cannot
378
+ -- authorize while the setting is enabled and commit after a concurrent
379
+ -- disablement. Never block here: a pre-0323 binary arrives already holding
380
+ -- control/membership row locks, and waiting on the fence would deadlock
381
+ -- against a membership command (see the migration header). When the fence is
382
+ -- held elsewhere, such an old caller proceeds with an unfenced read-committed
383
+ -- read of the product setting for this one create.
384
+ PERFORM pg_catalog.pg_try_advisory_xact_lock(pg_catalog.hashtextextended(
385
+ 'organization-membership:' || p_account_id::text, 0
386
+ ));
387
+ -- Match the organization lifecycle's workspace -> membership prefix so
388
+ -- suspension/offboarding cannot pass between authorization and INSERT.
389
+ PERFORM 1 FROM workspace_inference_controls control
390
+ WHERE control.account_id = p_account_id AND control.workspace_id = p_workspace_id
391
+ FOR SHARE;
392
+ PERFORM 1 FROM workspaces workspace
393
+ WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
394
+ FOR KEY SHARE;
395
+ SELECT membership.id, membership.personal_workspace_id = p_workspace_id
396
+ INTO actor_membership_id, actor_personal_workspace
397
+ FROM organization_memberships membership
398
+ WHERE membership.account_id = p_account_id
399
+ AND membership.subject_id = p_actor_subject_id
400
+ AND membership.status = 'active'
401
+ FOR KEY SHARE;
402
+ IF NOT FOUND THEN
403
+ RAISE EXCEPTION 'private session create authority required' USING ERRCODE = '42501';
404
+ END IF;
405
+ -- An ordinary workspace's exact access row is authority, not just evidence.
406
+ -- Lock it after the canonical workspace + organization-membership prefix so
407
+ -- workspace-membership removal cannot miss an uncommitted private session,
408
+ -- delete access, and let this transaction commit from an older snapshot.
409
+ IF NOT actor_personal_workspace THEN
410
+ SELECT access.id INTO workspace_access_id
411
+ FROM workspace_memberships access
412
+ WHERE access.account_id = p_account_id
413
+ AND access.workspace_id = p_workspace_id
414
+ AND access.subject_id = p_actor_subject_id
415
+ FOR KEY SHARE;
416
+ IF NOT FOUND THEN
417
+ RAISE EXCEPTION 'private session create authority required' USING ERRCODE = '42501';
418
+ END IF;
419
+ -- Product decision, distinct from authority: fail closed before any
420
+ -- capability row exists. Repaired callers map this exact SQLSTATE to the
421
+ -- not-activated create error; old binaries fail the create closed.
422
+ IF NOT organization_private_sessions_enabled(p_account_id) THEN
423
+ RAISE EXCEPTION
424
+ 'private sessions are not enabled for this organization''s shared workspaces'
425
+ USING ERRCODE = '55000';
426
+ END IF;
427
+ END IF;
428
+ PERFORM pg_catalog.set_config(
429
+ 'opengeni.private_session_create_lifecycle', 'private_session_create', true
430
+ );
431
+ INSERT INTO private_session_create_capabilities (
432
+ backend_pid, transaction_id, capability_id, account_id, workspace_id,
433
+ session_id, actor_subject_id, owner_membership_id
434
+ ) VALUES (
435
+ pg_backend_pid(), pg_current_xact_id(), new_capability_id, p_account_id,
436
+ p_workspace_id, p_session_id, p_actor_subject_id, actor_membership_id
437
+ );
438
+ PERFORM pg_catalog.set_config(
439
+ 'opengeni.private_session_create_capability', new_capability_id::text, true
440
+ );
441
+ capability_id := new_capability_id;
442
+ owner_membership_id := actor_membership_id;
443
+ RETURN NEXT;
444
+ END
445
+ $body$;
446
+
447
+ DO $pin_organization_private_session_routines$
448
+ DECLARE data_schema text := current_schema();
449
+ BEGIN
450
+ EXECUTE format(
451
+ 'ALTER FUNCTION %I.organization_private_sessions_enabled(uuid) SET search_path = pg_catalog, %I, pg_temp',
452
+ data_schema, data_schema
453
+ );
454
+ EXECUTE format(
455
+ 'ALTER FUNCTION %I.get_private_session_create_policy(uuid,uuid,text) SET search_path = pg_catalog, %I, pg_temp',
456
+ data_schema, data_schema
457
+ );
458
+ EXECUTE format(
459
+ 'ALTER FUNCTION %I.get_organization_private_session_settings(uuid,text) SET search_path = pg_catalog, %I, pg_temp',
460
+ data_schema, data_schema
461
+ );
462
+ EXECUTE format(
463
+ 'ALTER FUNCTION %I.update_organization_private_session_settings(uuid,text,boolean,bigint,uuid) SET search_path = pg_catalog, %I, pg_temp',
464
+ data_schema, data_schema
465
+ );
466
+ EXECUTE format(
467
+ 'ALTER FUNCTION %I.open_private_session_create_capability(uuid,uuid,uuid,text) SET search_path = pg_catalog, %I, pg_temp',
468
+ data_schema, data_schema
469
+ );
470
+ END
471
+ $pin_organization_private_session_routines$;
472
+
473
+ DO $grants$
474
+ BEGIN
475
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
476
+ GRANT EXECUTE ON FUNCTION get_private_session_create_policy(uuid,uuid,text) TO opengeni_app;
477
+ GRANT EXECUTE ON FUNCTION get_organization_private_session_settings(uuid,text)
478
+ TO opengeni_app;
479
+ GRANT EXECUTE ON FUNCTION
480
+ update_organization_private_session_settings(uuid,text,boolean,bigint,uuid)
481
+ TO opengeni_app;
482
+ END IF;
483
+ END
484
+ $grants$;
485
+
486
+ COMMENT ON TABLE organization_private_session_settings IS
487
+ 'Organization owner/admin product setting for new private sessions in shared workspaces; the 0303 readiness receipt remains the separate operator prerequisite.';
488
+ COMMENT ON FUNCTION open_private_session_create_capability(uuid,uuid,uuid,text) IS
489
+ 'Opens the exact transaction-local private-create capability (0311). Since 0323 a shared-workspace create additionally requires the enabled organization_private_session_settings row, read under the organization advisory fence when the caller already holds it (repaired TypeScript order) and otherwise unfenced after a non-blocking try so pre-0323 callers cannot deadlock; SQLSTATE 55000 means the owner/admin setting is disabled, every authority failure stays 42501.';