@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,343 @@
1
+ -- deployment-mode: rolling
2
+ -- Migration 0279: workspace-owned connections stop bypassing the accepted
3
+ -- connection-use authority.
4
+ --
5
+ -- Before this migration `resolve_accepted_connection_use` had two lanes -
6
+ -- the frozen per-turn personal snapshot ('user') and the bounded
7
+ -- 'legacy_user' compatibility lane - and the worker short-circuited every
8
+ -- workspace-scope request straight to credential resolution: no lifecycle
9
+ -- fences, no idempotent audit fact, no per-provider-request authorization.
10
+ -- This redefinition adds the workspace lane: the same canonical
11
+ -- control/workspace/session/turn/attempt fences and interruption checks, the
12
+ -- same physical-request idempotency, and a live validation that the exact
13
+ -- connection is workspace-owned ('workspace' authority scope), belongs to
14
+ -- this workspace, still matches its provider domain and kind, and is active.
15
+ -- The audit-fact shape already admits authority_scope 'workspace' (0264).
16
+ --
17
+ -- A frozen personal snapshot for the same turn+server keeps taking the
18
+ -- snapshot lane, so a workspace-scope request against a personally delegated
19
+ -- server denies with connection_identity_changed instead of borrowing the
20
+ -- workspace row. Requests with no connection id remain unresolvable in this
21
+ -- lane ('connection_missing'): the worker's bounded legacy path for
22
+ -- pre-snapshot turns stays TypeScript-side and unprivileged.
23
+ --
24
+ -- Rolling window: same function identity, so existing EXECUTE grants
25
+ -- survive; an old worker image keeps its short-circuit (exactly as weak as
26
+ -- before, never weaker) until replaced. CREATE OR REPLACE resets the
27
+ -- attached search_path, so the 0275 definer posture is re-applied below.
28
+
29
+ SET LOCAL lock_timeout = '5s';
30
+ SET LOCAL statement_timeout = '5min';
31
+
32
+ CREATE OR REPLACE FUNCTION resolve_accepted_connection_use(
33
+ p_account_id uuid, p_workspace_id uuid, p_session_id uuid, p_turn_id uuid,
34
+ p_attempt_id uuid, p_execution_generation integer, p_physical_request_id uuid,
35
+ p_use_phase text, p_server_id text, p_connection_id uuid,
36
+ p_provider_domain text, p_connection_kind text, p_subject_scope text,
37
+ p_owner_subject_id text DEFAULT NULL
38
+ ) RETURNS TABLE (
39
+ authorization_status text, denial_reason text, resolved_connection_id uuid,
40
+ connection_generation bigint, origin_workspace_id uuid,
41
+ resolved_connection_kind text, authority_scope text, owner_subject_id text,
42
+ authority_id uuid, grant_id uuid
43
+ )
44
+ LANGUAGE plpgsql SECURITY DEFINER
45
+ SET search_path = pg_catalog, pg_temp
46
+ AS $body$
47
+ #variable_conflict use_column
48
+ DECLARE
49
+ prior record;
50
+ connection_row record;
51
+ snapshot record;
52
+ session_row record;
53
+ grant_row record;
54
+ request_digest bytea;
55
+ has_prior boolean := false;
56
+ reason text;
57
+ scheduled_run_id uuid;
58
+ BEGIN
59
+ IF p_account_id IS DISTINCT FROM nullif(current_setting('opengeni.account_id', true), '')::uuid
60
+ OR p_workspace_id IS DISTINCT FROM nullif(current_setting('opengeni.workspace_id', true), '')::uuid
61
+ OR p_execution_generation <= 0
62
+ OR p_use_phase NOT IN ('credential_resolution', 'provider_request')
63
+ OR nullif(btrim(p_server_id), '') IS NULL OR octet_length(p_server_id) > 256
64
+ THEN RAISE EXCEPTION 'connection use scope mismatch' USING ERRCODE = '42501';
65
+ END IF;
66
+ request_digest := digest(convert_to(jsonb_build_object(
67
+ 'accountId', p_account_id, 'workspaceId', p_workspace_id,
68
+ 'sessionId', p_session_id, 'turnId', p_turn_id, 'attemptId', p_attempt_id,
69
+ 'executionGeneration', p_execution_generation, 'usePhase', p_use_phase,
70
+ 'serverId', p_server_id, 'connectionId', p_connection_id,
71
+ 'providerDomain', lower(p_provider_domain), 'connectionKind', p_connection_kind,
72
+ 'subjectScope', p_subject_scope, 'ownerSubjectId', p_owner_subject_id
73
+ )::text, 'UTF8'), 'sha256');
74
+
75
+ -- Canonical lifecycle lock prefix: control -> workspace -> session -> turn -> attempt.
76
+ PERFORM 1 FROM workspace_inference_controls control_row
77
+ WHERE control_row.account_id = p_account_id AND control_row.workspace_id = p_workspace_id
78
+ FOR SHARE;
79
+ IF NOT FOUND THEN reason := 'session_identity_changed'; END IF;
80
+ IF reason IS NULL THEN
81
+ PERFORM 1 FROM workspaces workspace_value
82
+ WHERE workspace_value.account_id = p_account_id AND workspace_value.id = p_workspace_id
83
+ FOR KEY SHARE;
84
+ IF NOT FOUND THEN reason := 'session_identity_changed'; END IF;
85
+ END IF;
86
+ IF reason IS NULL THEN
87
+ SELECT session_value.* INTO session_row FROM sessions session_value
88
+ WHERE session_value.id = p_session_id AND session_value.account_id = p_account_id
89
+ AND session_value.workspace_id = p_workspace_id
90
+ FOR NO KEY UPDATE;
91
+ IF NOT FOUND OR session_row.active_turn_id IS DISTINCT FROM p_turn_id
92
+ OR session_row.status = 'cancelled'
93
+ THEN reason := 'session_identity_changed'; END IF;
94
+ END IF;
95
+ IF reason IS NULL THEN
96
+ PERFORM 1 FROM session_turns turn_value
97
+ WHERE turn_value.id = p_turn_id AND turn_value.account_id = p_account_id
98
+ AND turn_value.workspace_id = p_workspace_id AND turn_value.session_id = p_session_id
99
+ AND turn_value.active_attempt_id = p_attempt_id
100
+ AND turn_value.execution_generation = p_execution_generation
101
+ AND turn_value.status = 'running'
102
+ FOR UPDATE;
103
+ IF NOT FOUND THEN reason := 'session_identity_changed'; END IF;
104
+ END IF;
105
+ IF reason IS NULL THEN
106
+ PERFORM 1 FROM session_turn_attempts attempt
107
+ WHERE attempt.id = p_attempt_id AND attempt.account_id = p_account_id
108
+ AND attempt.workspace_id = p_workspace_id AND attempt.session_id = p_session_id
109
+ AND attempt.turn_id = p_turn_id
110
+ AND attempt.execution_generation = p_execution_generation
111
+ AND attempt.state IN ('claimed', 'running')
112
+ AND attempt.closed_at IS NULL AND attempt.quiesced_at IS NULL
113
+ AND attempt.authority_visibility = session_row.visibility
114
+ AND attempt.authority_epoch = session_row.authority_epoch
115
+ AND attempt.authority_owner_organization_membership_id
116
+ IS NOT DISTINCT FROM session_row.owner_organization_membership_id
117
+ FOR UPDATE;
118
+ IF NOT FOUND OR EXISTS (
119
+ SELECT 1 FROM session_attempt_interruptions interruption
120
+ WHERE interruption.account_id = p_account_id
121
+ AND interruption.workspace_id = p_workspace_id
122
+ AND interruption.session_id = p_session_id
123
+ AND interruption.attempt_id = p_attempt_id
124
+ AND interruption.state IN ('pending', 'delivered', 'acknowledged')
125
+ ) THEN reason := 'session_identity_changed'; END IF;
126
+ END IF;
127
+
128
+ PERFORM pg_advisory_xact_lock(hashtextextended(p_physical_request_id::text, 0));
129
+ SELECT EXISTS (SELECT 1 FROM connection_use_audit_facts audit
130
+ WHERE audit.physical_request_id = p_physical_request_id) INTO has_prior;
131
+ -- Only dereference `prior` inside the guarded branch: PL/pgSQL evaluates
132
+ -- both operands of `has_prior AND prior.<field>`, and an unassigned record
133
+ -- raises instead of yielding NULL.
134
+ IF has_prior THEN
135
+ SELECT audit.* INTO STRICT prior FROM connection_use_audit_facts audit
136
+ WHERE audit.physical_request_id = p_physical_request_id;
137
+ IF prior.request_digest IS DISTINCT FROM request_digest THEN
138
+ RAISE EXCEPTION 'physical connection request id was reused for different work'
139
+ USING ERRCODE = '23505';
140
+ END IF;
141
+ IF reason IS NULL AND prior.outcome = 'denied' THEN
142
+ authorization_status := prior.outcome; denial_reason := prior.denial_reason;
143
+ RETURN NEXT; RETURN;
144
+ END IF;
145
+ END IF;
146
+
147
+ IF reason IS NULL THEN
148
+ SELECT authority_snapshot.* INTO snapshot
149
+ FROM turn_connection_authority_snapshots authority_snapshot
150
+ WHERE authority_snapshot.turn_id = p_turn_id
151
+ AND authority_snapshot.server_id = p_server_id
152
+ AND authority_snapshot.account_id = p_account_id
153
+ AND authority_snapshot.workspace_id = p_workspace_id
154
+ AND authority_snapshot.session_id = p_session_id;
155
+ IF FOUND THEN
156
+ scheduled_run_id := CASE
157
+ WHEN snapshot.canonical_snapshot -> 'acceptedWork' ->> 'kind' = 'scheduled_task'
158
+ THEN nullif(snapshot.canonical_snapshot -> 'acceptedWork' ->> 'runId', '')::uuid
159
+ ELSE NULL END;
160
+ SELECT connection_value.* INTO connection_row FROM connections connection_value
161
+ WHERE connection_value.id = snapshot.connection_id
162
+ AND connection_value.account_id = p_account_id;
163
+ IF snapshot.snapshot_digest IS DISTINCT FROM digest(
164
+ convert_to(snapshot.canonical_snapshot::text, 'UTF8'), 'sha256'
165
+ ) THEN reason := 'accepted_snapshot_digest_changed';
166
+ ELSIF NOT FOUND THEN reason := 'connection_missing';
167
+ ELSIF snapshot.authority_scope IS DISTINCT FROM 'user'
168
+ OR p_subject_scope IS DISTINCT FROM 'subject'
169
+ OR p_connection_id IS DISTINCT FROM snapshot.connection_id
170
+ OR lower(p_provider_domain) IS DISTINCT FROM snapshot.provider_domain
171
+ OR (p_connection_kind IS NOT NULL
172
+ AND p_connection_kind IS DISTINCT FROM snapshot.connection_kind)
173
+ THEN reason := 'connection_identity_changed';
174
+ ELSIF connection_row.status <> 'active' THEN reason := 'connection_status_inactive';
175
+ ELSIF connection_row.authority_scope IS DISTINCT FROM 'user'
176
+ OR connection_row.subject_id IS DISTINCT FROM snapshot.owner_subject_id
177
+ OR connection_row.owner_organization_membership_id
178
+ IS DISTINCT FROM snapshot.owner_organization_membership_id
179
+ OR connection_row.origin_workspace_id IS DISTINCT FROM snapshot.origin_workspace_id
180
+ THEN reason := 'connection_owner_changed';
181
+ ELSIF connection_row.authority_generation IS DISTINCT FROM snapshot.connection_generation
182
+ THEN reason := 'connection_generation_changed';
183
+ ELSIF session_row.visibility IS DISTINCT FROM snapshot.session_visibility
184
+ OR session_row.authority_epoch IS DISTINCT FROM snapshot.session_authority_epoch
185
+ THEN reason := 'session_authority_epoch_changed';
186
+ ELSIF NOT EXISTS (
187
+ SELECT 1 FROM organization_memberships membership
188
+ WHERE membership.id = snapshot.owner_organization_membership_id
189
+ AND membership.account_id = p_account_id
190
+ AND membership.subject_id = snapshot.owner_subject_id
191
+ AND membership.status = 'active' AND membership.revoked_at IS NULL
192
+ AND membership.authorization_revision = snapshot.membership_authorization_revision
193
+ AND (membership.personal_workspace_id = p_workspace_id OR EXISTS (
194
+ SELECT 1 FROM workspace_memberships workspace_membership
195
+ WHERE workspace_membership.account_id = p_account_id
196
+ AND workspace_membership.workspace_id = p_workspace_id
197
+ AND workspace_membership.subject_id = snapshot.owner_subject_id
198
+ ))
199
+ ) THEN reason := 'owner_membership_inactive';
200
+ ELSIF NOT EXISTS (
201
+ SELECT 1 FROM organization_user_resource_authorities authority
202
+ WHERE authority.id = snapshot.authority_id AND authority.account_id = p_account_id
203
+ AND authority.organization_membership_id = snapshot.owner_organization_membership_id
204
+ AND authority.resource_kind = 'connection'
205
+ AND authority.resource_id = snapshot.connection_id
206
+ AND authority.origin_workspace_id = snapshot.origin_workspace_id
207
+ AND authority.generation = snapshot.authority_generation
208
+ AND authority.status = 'active' AND authority.revoked_at IS NULL
209
+ ) THEN reason := 'authority_status_inactive';
210
+ ELSE
211
+ SELECT grant_value.* INTO grant_row FROM organization_user_resource_grants grant_value
212
+ WHERE grant_value.id = snapshot.grant_id AND grant_value.account_id = p_account_id
213
+ FOR UPDATE;
214
+ IF NOT FOUND THEN reason := 'grant_missing';
215
+ ELSIF grant_row.authority_id IS DISTINCT FROM snapshot.authority_id
216
+ OR grant_row.owner_organization_membership_id
217
+ IS DISTINCT FROM snapshot.owner_organization_membership_id
218
+ OR grant_row.workspace_id IS DISTINCT FROM p_workspace_id
219
+ OR grant_row.action <> 'connection.use'
220
+ OR grant_row.mode IS DISTINCT FROM snapshot.grant_mode
221
+ OR grant_row.context IS DISTINCT FROM snapshot.grant_context
222
+ OR grant_row.session_id IS DISTINCT FROM snapshot.grant_session_id
223
+ OR grant_row.authority_epoch IS DISTINCT FROM snapshot.grant_authority_epoch
224
+ THEN reason := 'grant_identity_changed';
225
+ ELSIF grant_row.generation IS DISTINCT FROM snapshot.grant_generation
226
+ THEN reason := 'grant_generation_changed';
227
+ ELSIF grant_row.expires_at IS NOT NULL AND grant_row.expires_at <= clock_timestamp()
228
+ THEN reason := 'grant_expired';
229
+ ELSIF grant_row.mode = 'once' THEN
230
+ IF grant_row.status <> 'consumed' OR NOT EXISTS (
231
+ SELECT 1 FROM connection_use_once_consumption_receipts receipt
232
+ WHERE receipt.grant_id = grant_row.id
233
+ AND receipt.authority_id = snapshot.authority_id
234
+ AND receipt.authority_generation = snapshot.authority_generation
235
+ AND receipt.grant_generation = snapshot.grant_generation
236
+ AND (
237
+ (receipt.accepted_work_kind = 'turn'
238
+ AND receipt.accepted_work_id = p_turn_id)
239
+ OR (receipt.accepted_work_kind = 'scheduled_task'
240
+ AND scheduled_run_id IS NOT NULL
241
+ AND receipt.accepted_work_id = scheduled_run_id)
242
+ )
243
+ ) THEN reason := 'grant_already_consumed'; END IF;
244
+ ELSIF grant_row.status <> 'active' THEN reason := 'grant_status_inactive';
245
+ END IF;
246
+ END IF;
247
+ resolved_connection_id := snapshot.connection_id;
248
+ connection_generation := snapshot.connection_generation;
249
+ origin_workspace_id := snapshot.origin_workspace_id;
250
+ resolved_connection_kind := snapshot.connection_kind;
251
+ authority_scope := snapshot.authority_scope;
252
+ owner_subject_id := snapshot.owner_subject_id;
253
+ authority_id := snapshot.authority_id;
254
+ grant_id := snapshot.grant_id;
255
+ ELSIF p_subject_scope = 'workspace' THEN
256
+ -- Workspace lane (0279): a workspace-owned connection is ambient shared
257
+ -- workspace capability, never frozen on the turn, so it is validated
258
+ -- against the live row inside the same canonical lifecycle fences and
259
+ -- recorded in the same idempotent audit facts. A frozen per-turn
260
+ -- personal snapshot for this server takes the snapshot lane above and
261
+ -- therefore denies a workspace-scope request outright (fail closed).
262
+ SELECT connection_value.* INTO connection_row FROM connections connection_value
263
+ WHERE connection_value.id = p_connection_id AND connection_value.account_id = p_account_id;
264
+ IF p_connection_id IS NULL OR NOT FOUND THEN reason := 'connection_missing';
265
+ ELSIF connection_row.authority_scope IS DISTINCT FROM 'workspace'
266
+ OR p_owner_subject_id IS NOT NULL
267
+ OR connection_row.workspace_id IS DISTINCT FROM p_workspace_id
268
+ OR connection_row.origin_workspace_id IS DISTINCT FROM p_workspace_id
269
+ OR lower(connection_row.provider_domain) IS DISTINCT FROM lower(p_provider_domain)
270
+ OR (p_connection_kind IS NOT NULL
271
+ AND connection_row.kind IS DISTINCT FROM p_connection_kind)
272
+ THEN reason := 'connection_identity_changed';
273
+ ELSIF connection_row.status <> 'active' THEN reason := 'connection_status_inactive';
274
+ ELSE
275
+ resolved_connection_id := connection_row.id;
276
+ connection_generation := connection_row.authority_generation;
277
+ origin_workspace_id := connection_row.origin_workspace_id;
278
+ resolved_connection_kind := connection_row.kind;
279
+ authority_scope := 'workspace';
280
+ END IF;
281
+ ELSE
282
+ SELECT connection_value.* INTO connection_row FROM connections connection_value
283
+ WHERE connection_value.id = p_connection_id AND connection_value.account_id = p_account_id;
284
+ IF NOT FOUND THEN reason := 'connection_missing';
285
+ ELSIF connection_row.authority_scope IS DISTINCT FROM 'legacy_user'
286
+ OR p_subject_scope IS DISTINCT FROM 'subject' OR p_owner_subject_id IS NULL
287
+ OR connection_row.subject_id IS DISTINCT FROM p_owner_subject_id
288
+ OR connection_row.workspace_id IS DISTINCT FROM p_workspace_id
289
+ OR connection_row.origin_workspace_id IS DISTINCT FROM p_workspace_id
290
+ OR lower(connection_row.provider_domain) IS DISTINCT FROM lower(p_provider_domain)
291
+ OR (p_connection_kind IS NOT NULL
292
+ AND connection_row.kind IS DISTINCT FROM p_connection_kind)
293
+ THEN reason := 'connection_identity_changed';
294
+ ELSIF connection_row.status <> 'active' THEN reason := 'connection_status_inactive';
295
+ ELSE
296
+ resolved_connection_id := connection_row.id;
297
+ connection_generation := connection_row.authority_generation;
298
+ origin_workspace_id := connection_row.origin_workspace_id;
299
+ resolved_connection_kind := connection_row.kind;
300
+ authority_scope := 'legacy_user'; owner_subject_id := connection_row.subject_id;
301
+ END IF;
302
+ END IF;
303
+ END IF;
304
+
305
+ authorization_status := CASE WHEN reason IS NULL THEN 'authorized' ELSE 'denied' END;
306
+ denial_reason := reason;
307
+ IF NOT has_prior THEN
308
+ INSERT INTO connection_use_audit_facts (
309
+ physical_request_id, use_phase, request_digest, account_id, workspace_id,
310
+ session_id, turn_id, attempt_id, execution_generation, server_id,
311
+ connection_id, connection_generation, authority_scope, owner_subject_id,
312
+ authority_id, grant_id, outcome, denial_reason
313
+ ) VALUES (
314
+ p_physical_request_id, p_use_phase, request_digest, p_account_id,
315
+ p_workspace_id, p_session_id, p_turn_id, p_attempt_id,
316
+ p_execution_generation, p_server_id, resolved_connection_id,
317
+ connection_generation, authority_scope, owner_subject_id, authority_id,
318
+ grant_id, authorization_status, denial_reason
319
+ ) ON CONFLICT (physical_request_id) DO NOTHING;
320
+ END IF;
321
+ RETURN NEXT;
322
+ END
323
+ $body$;
324
+
325
+ DO $workspace_connection_lane_posture$
326
+ DECLARE
327
+ data_schema text := pg_catalog.current_schema();
328
+ signature text := 'resolve_accepted_connection_use'
329
+ || '(uuid,uuid,uuid,uuid,uuid,integer,uuid,text,text,uuid,text,text,text,text)';
330
+ BEGIN
331
+ -- Re-pin the 0275 definer posture: CREATE OR REPLACE replaced the attached
332
+ -- search_path with the minimal header value. `public` stays in the path for
333
+ -- the pgcrypto digest() dependency, exactly as 0275 set it.
334
+ EXECUTE format(
335
+ 'ALTER FUNCTION %I.%s SET search_path = pg_catalog, %I, public, pg_temp',
336
+ data_schema, signature, data_schema
337
+ );
338
+ EXECUTE format('REVOKE ALL ON FUNCTION %I.%s FROM PUBLIC', data_schema, signature);
339
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
340
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.%s TO opengeni_app', data_schema, signature);
341
+ END IF;
342
+ END
343
+ $workspace_connection_lane_posture$;