@opengeni/db 1.0.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 (265) 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-LTG3S6ZY.js → chunk-EULAN2NP.js} +2 -2
  7. package/dist/{chunk-CUPM3FGB.js → chunk-NJVZPWXY.js} +3 -3
  8. package/dist/{chunk-4SR4HKKA.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-6ZYKCRFO.js → chunk-PR2WMLOQ.js} +7580 -4417
  13. package/dist/chunk-PR2WMLOQ.js.map +1 -0
  14. package/dist/{chunk-ZWREYEWA.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.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 +1595 -81
  43. package/dist/index.js +21571 -8126
  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 +22 -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 +41 -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 +153 -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 +1 -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/package.json +10 -6
  189. package/src/attached-browser-devices.ts +233 -5
  190. package/src/automations.ts +911 -0
  191. package/src/browser-sessions.ts +10 -0
  192. package/src/capability-integrations.ts +175 -1
  193. package/src/child-lifecycle-notices.ts +241 -0
  194. package/src/codemode-operations.ts +1 -35
  195. package/src/company-brain-context-selection-schema.ts +100 -0
  196. package/src/company-brain-context-selection.ts +359 -0
  197. package/src/company-brain-governed-writes.ts +1170 -0
  198. package/src/company-brain.ts +309 -0
  199. package/src/company-profile-agent-admin.ts +225 -0
  200. package/src/company-profile-schema.ts +121 -1
  201. package/src/company-profile.ts +21 -0
  202. package/src/computer-sessions.ts +10 -1
  203. package/src/connection-authority.ts +290 -0
  204. package/src/connection-scopes.ts +20 -0
  205. package/src/connection-tenancy-backfill.ts +81 -0
  206. package/src/connection-token-resolver.ts +263 -31
  207. package/src/database.ts +75 -2
  208. package/src/editable-artifacts-schema.ts +10 -5
  209. package/src/editable-artifacts.ts +21 -11
  210. package/src/governed-learning-activation-schema.ts +121 -0
  211. package/src/governed-learning-activation.ts +588 -0
  212. package/src/governed-learning-evaluator-schema.ts +72 -0
  213. package/src/governed-learning-evaluator.ts +217 -0
  214. package/src/index.ts +11651 -1548
  215. package/src/insights.ts +107 -0
  216. package/src/integration-bindings.ts +88 -6
  217. package/src/integration-facets.ts +287 -84
  218. package/src/interaction-placement-loss.ts +234 -0
  219. package/src/managed-human-provisioning.ts +116 -0
  220. package/src/memory-domain.ts +27 -32
  221. package/src/migrate.ts +77 -1
  222. package/src/new-session-drafts.ts +229 -35
  223. package/src/organization-membership-backfill.ts +735 -0
  224. package/src/organization-membership-lifecycle.ts +985 -0
  225. package/src/pr-review.ts +890 -0
  226. package/src/preference-registry.ts +31 -1
  227. package/src/provision-roles.ts +877 -6
  228. package/src/runtime-posture-cli.ts +2 -0
  229. package/src/runtime-posture.ts +1291 -76
  230. package/src/schema.ts +3303 -428
  231. package/src/scoped-knowledge-schema.ts +16 -8
  232. package/src/scoped-knowledge.ts +1 -1
  233. package/src/session-background-commands.ts +759 -0
  234. package/src/session-control.ts +640 -74
  235. package/src/session-goal-pacing.ts +126 -0
  236. package/src/session-queue-commands.ts +437 -84
  237. package/src/session-realtime-context.ts +3 -3
  238. package/src/session-realtime-ledger.ts +22 -11
  239. package/src/session-realtime-mirror.ts +1 -1
  240. package/src/session-tenancy.ts +403 -49
  241. package/src/session-tool-call-settlement.ts +38 -29
  242. package/src/slack-routing-personal-workspace.ts +67 -0
  243. package/src/slack-routing.ts +469 -0
  244. package/src/slack-task-policy-schema.ts +5 -0
  245. package/src/slack-task-policy.ts +18 -0
  246. package/src/slack-user-link-access.ts +17 -1
  247. package/src/task-notes-schema.ts +74 -0
  248. package/src/task-notes.ts +124 -2
  249. package/src/turn-initiator.ts +8 -0
  250. package/src/user-resource-authority.ts +377 -0
  251. package/src/workspace-authority.ts +160 -0
  252. package/src/workspace-instruction-policies-schema.ts +53 -1
  253. package/src/workspace-instruction-policies.ts +528 -77
  254. package/src/workspace-learning-policy.ts +21 -5
  255. package/src/workspace-membership-permissions.ts +9 -0
  256. package/dist/chunk-4SR4HKKA.js.map +0 -1
  257. package/dist/chunk-6ZYKCRFO.js.map +0 -1
  258. package/dist/chunk-NXAFLCQX.js +0 -2468
  259. package/dist/chunk-NXAFLCQX.js.map +0 -1
  260. package/dist/chunk-SK7YYHBI.js.map +0 -1
  261. package/dist/chunk-WD5ROSLL.js +0 -117
  262. package/dist/chunk-WD5ROSLL.js.map +0 -1
  263. package/dist/chunk-ZWREYEWA.js.map +0 -1
  264. /package/dist/{chunk-LTG3S6ZY.js.map → chunk-EULAN2NP.js.map} +0 -0
  265. /package/dist/{chunk-CUPM3FGB.js.map → chunk-NJVZPWXY.js.map} +0 -0
@@ -0,0 +1,291 @@
1
+ -- deployment-mode: rolling
2
+ -- Migration 0299: correct the organization-membership lifecycle lock
3
+ -- order.
4
+ --
5
+ -- THE BUG
6
+ -- -------
7
+ -- `prepare_organization_membership_protocol_settlements` (0263), the wrapped
8
+ -- `organization_membership_command_0263` (0263), and the
9
+ -- `organization_membership_command` wrapper (0275) all opened with
10
+ --
11
+ -- PERFORM 1 FROM managed_accounts account
12
+ -- WHERE account.id = account_id_value FOR UPDATE;
13
+ --
14
+ -- and only afterwards took the canonical per-workspace prefix
15
+ -- (`workspace_inference_controls FOR SHARE` -> `workspaces FOR KEY SHARE`).
16
+ -- That is organization-row-first, workspace-row-second.
17
+ --
18
+ -- Every ordinary workspace writer is forced into the opposite order and cannot
19
+ -- avoid it. It locks its `workspaces` row first (AGENTS.md's canonical
20
+ -- event-write prefix; a live workspace-scoped lifecycle function such as
21
+ -- `confirm_remember_knowledge_claim` from 0274 takes it `FOR UPDATE`), and then
22
+ -- reaches `managed_accounts` IMPLICITLY through the account foreign-key check
23
+ -- of a row it inserts - `sessions`, `session_events`, `session_turns`,
24
+ -- `session_goals` and `session_system_updates` all reference `managed_accounts`,
25
+ -- and an FK check takes `FOR KEY SHARE` on the referenced row. `FOR KEY SHARE`
26
+ -- conflicts with `FOR UPDATE`, so the two writers form a textbook cycle:
27
+ --
28
+ -- ordinary workspace writer holds workspaces waits managed_accounts
29
+ -- prepare_organization_membership holds managed_accounts waits workspaces
30
+ --
31
+ -- An administrator suspending or offboarding a member concurrently with any
32
+ -- ordinary workspace write in the same organization deadlocks (40P01).
33
+ --
34
+ -- THE FIX
35
+ -- -------
36
+ -- The organization row lock was doing two unrelated jobs: (a) proving the
37
+ -- organization exists and cannot be deleted underneath the command, and (b)
38
+ -- serializing concurrent membership commands for the same organization. Only
39
+ -- (b) needed `FOR UPDATE`, and (b) does not need a row lock at all.
40
+ --
41
+ -- * (b) moves to `pg_advisory_xact_lock` keyed on the organization id. Every
42
+ -- membership lifecycle entry point takes it, so two membership commands for
43
+ -- the same organization still serialize exactly as before. It lives in the
44
+ -- advisory lock space, which no ordinary workspace writer touches, so it can
45
+ -- never appear in a cycle with a `workspaces`/`managed_accounts` row lock.
46
+ -- It is transaction-scoped and re-grantable within one transaction, so the
47
+ -- 0275 wrapper, the preparation seam, and the wrapped 0263 body all take it
48
+ -- reentrantly inside the one `updateOrganizationMember` transaction.
49
+ -- * (a) stays as a row lock but downgrades to `FOR KEY SHARE`, which still
50
+ -- blocks DELETE and primary-key UPDATE of the organization row while being
51
+ -- compatible with the FK `FOR KEY SHARE` that every ordinary workspace
52
+ -- writer takes. The lifecycle therefore no longer holds a conflicting lock
53
+ -- on `managed_accounts` while it reaches for `workspaces`.
54
+ --
55
+ -- After this migration the lifecycle's first ROW lock is `workspaces
56
+ -- FOR KEY SHARE`, i.e. the canonical prefix AGENTS.md documents, and its
57
+ -- `managed_accounts` touch is compatible with every ordinary writer's FK check.
58
+ -- This is the same shape migration 0278 already uses for the workspace
59
+ -- membership removal seam (advisory fence + canonical workspace prefix, no
60
+ -- organization-row `FOR UPDATE`).
61
+ --
62
+ -- Availability note: the old `FOR UPDATE` also stalled EVERY session/event/turn
63
+ -- insert in the whole organization for the duration of a membership command,
64
+ -- because each of those inserts needs the account FK check. `FOR KEY SHARE`
65
+ -- removes that org-wide write stall as well.
66
+ --
67
+ -- WHY THIS IS A TEXT PATCH
68
+ -- ------------------------
69
+ -- The three bodies are ~1,300 lines of proven authority logic (CAS, receipts,
70
+ -- FORCE-RLS GUC juggling, per-workspace settlement). Restating them here to
71
+ -- change one statement each would fork them and risk a silent transcription
72
+ -- error. Instead each body is read back with `pg_get_functiondef` - which
73
+ -- reproduces the exact stored source plus the exact current `SET search_path`
74
+ -- and `SECURITY DEFINER` posture, and whose `CREATE OR REPLACE` preserves owner,
75
+ -- privileges and comments - and exactly one statement is rewritten. Every patch
76
+ -- fails closed: an entry point whose body matches none of the three known
77
+ -- account-lock spellings, or matches one of them more than once, aborts the
78
+ -- migration.
79
+ --
80
+ -- The three known spellings are tried against every entry point rather than
81
+ -- pinned per name, because `organization_membership_command` has two legitimate
82
+ -- shapes: the 0275 wrapper (when 0275 has run, with the 0263 body preserved
83
+ -- beside it as `organization_membership_command_0263`), or the 0263 body itself
84
+ -- (when it has not). The two always-present entry points are required;
85
+ -- `organization_membership_command_0263` is patched only when it exists, since
86
+ -- its absence simply means the pre-0275 shape.
87
+
88
+ SET LOCAL lock_timeout = '5s';
89
+ SET LOCAL statement_timeout = '5min';
90
+
91
+ DO $membership_lock_order$
92
+ DECLARE
93
+ signature text;
94
+ patch record;
95
+ definition text;
96
+ patched text;
97
+ occurrences integer;
98
+ applied integer;
99
+ BEGIN
100
+ FOREACH signature IN ARRAY ARRAY[
101
+ 'prepare_organization_membership_protocol_settlements(jsonb)',
102
+ 'organization_membership_command_0263(jsonb)',
103
+ 'organization_membership_command(jsonb)'
104
+ ] LOOP
105
+ -- Resolve in this deployment's own data schema rather than through the
106
+ -- search_path: a dedicated-schema migration run also carries `public`.
107
+ definition := pg_catalog.pg_get_functiondef(
108
+ pg_catalog.to_regprocedure(
109
+ pg_catalog.quote_ident(pg_catalog.current_schema()) || '.' || signature
110
+ )
111
+ );
112
+ IF definition IS NULL THEN
113
+ IF signature = 'organization_membership_command_0263(jsonb)' THEN
114
+ -- Pre-0275 shape: the 0263 body still lives under its original name and
115
+ -- is patched as `organization_membership_command` below.
116
+ CONTINUE;
117
+ END IF;
118
+ RAISE EXCEPTION
119
+ 'organization membership lifecycle function % is missing', signature
120
+ USING ERRCODE = '55000';
121
+ END IF;
122
+ applied := 0;
123
+ FOR patch IN
124
+ SELECT *
125
+ FROM (VALUES
126
+ (
127
+ $old_prepare$ PERFORM 1 FROM managed_accounts account
128
+ WHERE account.id = account_id_value FOR UPDATE;
129
+ $old_prepare$,
130
+ $new_prepare$ -- Lock-order repair: the organization fence is an advisory lock, not a row lock.
131
+ -- `FOR UPDATE` on managed_accounts conflicts with the FK `FOR KEY SHARE`
132
+ -- every ordinary workspace writer takes, and this seam reaches for
133
+ -- `workspaces` afterwards, so holding it inverted the canonical order.
134
+ PERFORM pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
135
+ 'organization-membership:' || account_id_value::text, 0
136
+ ));
137
+ PERFORM 1 FROM managed_accounts account
138
+ WHERE account.id = account_id_value FOR KEY SHARE;
139
+ $new_prepare$
140
+ ),
141
+ (
142
+ $old_command$ PERFORM 1 FROM managed_accounts account WHERE account.id = account_id_value FOR UPDATE;
143
+ $old_command$,
144
+ $new_command$ -- Lock-order repair: advisory organization fence plus a non-conflicting row lock
145
+ -- (see the header: `FOR UPDATE` here inverted the canonical order).
146
+ PERFORM pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
147
+ 'organization-membership:' || account_id_value::text, 0
148
+ ));
149
+ PERFORM 1 FROM managed_accounts account WHERE account.id = account_id_value FOR KEY SHARE;
150
+ $new_command$
151
+ ),
152
+ (
153
+ $old_wrapper$ -- The account row is the organization-lifecycle prefix. It makes the
154
+ -- following non-locking identity reads stable against another command.
155
+ PERFORM 1 FROM managed_accounts account
156
+ WHERE account.id = account_id_value
157
+ FOR UPDATE;
158
+ $old_wrapper$,
159
+ $new_wrapper$ -- The organization advisory fence is the organization-lifecycle prefix. It
160
+ -- makes the following non-locking identity reads stable against another
161
+ -- membership command without conflicting with the FK `FOR KEY SHARE` that
162
+ -- every ordinary workspace writer takes on this same row.
163
+ PERFORM pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
164
+ 'organization-membership:' || account_id_value::text, 0
165
+ ));
166
+ PERFORM 1 FROM managed_accounts account
167
+ WHERE account.id = account_id_value
168
+ FOR KEY SHARE;
169
+ $new_wrapper$
170
+ )
171
+ ) AS candidate(old_text, new_text)
172
+ LOOP
173
+ occurrences := (
174
+ pg_catalog.length(definition)
175
+ - pg_catalog.length(pg_catalog.replace(definition, patch.old_text, ''))
176
+ ) / pg_catalog.length(patch.old_text);
177
+ IF occurrences = 0 THEN
178
+ CONTINUE;
179
+ END IF;
180
+ IF occurrences <> 1 THEN
181
+ RAISE EXCEPTION
182
+ 'organization membership lifecycle function % has % copies of an '
183
+ 'expected account lock prefix (at most one required)',
184
+ signature, occurrences
185
+ USING ERRCODE = '55000';
186
+ END IF;
187
+ patched := pg_catalog.replace(definition, patch.old_text, patch.new_text);
188
+ IF pg_catalog.strpos(patched, patch.new_text) = 0
189
+ OR pg_catalog.strpos(patched, patch.old_text) > 0
190
+ THEN
191
+ RAISE EXCEPTION
192
+ 'organization membership lifecycle lock rewrite for % did not apply',
193
+ signature
194
+ USING ERRCODE = '55000';
195
+ END IF;
196
+ applied := applied + 1;
197
+ EXECUTE patched;
198
+ END LOOP;
199
+ IF applied <> 1 THEN
200
+ RAISE EXCEPTION
201
+ 'organization membership lifecycle function % matched % known account '
202
+ 'lock spellings (exactly one required)', signature, applied
203
+ USING ERRCODE = '55000';
204
+ END IF;
205
+ END LOOP;
206
+ END
207
+ $membership_lock_order$;
208
+
209
+ -- Fail closed if any lifecycle entry point still holds a conflicting
210
+ -- organization row lock, or lost the advisory fence that replaces it.
211
+ DO $membership_lock_order_verification$
212
+ DECLARE
213
+ signature text;
214
+ definition text;
215
+ BEGIN
216
+ FOREACH signature IN ARRAY ARRAY[
217
+ 'prepare_organization_membership_protocol_settlements(jsonb)',
218
+ 'organization_membership_command_0263(jsonb)',
219
+ 'organization_membership_command(jsonb)'
220
+ ] LOOP
221
+ definition := pg_catalog.pg_get_functiondef(
222
+ pg_catalog.to_regprocedure(
223
+ pg_catalog.quote_ident(pg_catalog.current_schema()) || '.' || signature
224
+ )
225
+ );
226
+ IF definition IS NULL THEN
227
+ IF signature = 'organization_membership_command_0263(jsonb)' THEN
228
+ CONTINUE;
229
+ END IF;
230
+ RAISE EXCEPTION
231
+ 'organization membership lifecycle function % is missing', signature
232
+ USING ERRCODE = '55000';
233
+ END IF;
234
+ IF pg_catalog.strpos(
235
+ definition,
236
+ 'pg_advisory_xact_lock(pg_catalog.hashtextextended('
237
+ ) = 0 OR pg_catalog.strpos(
238
+ definition, '''organization-membership:'' || account_id_value::text'
239
+ ) = 0 THEN
240
+ RAISE EXCEPTION
241
+ 'organization membership lifecycle function % lost its advisory organization fence',
242
+ signature USING ERRCODE = '55000';
243
+ END IF;
244
+ IF pg_catalog.strpos(definition, 'FROM managed_accounts account') = 0
245
+ OR definition ~ 'FROM managed_accounts account[^;]*FOR UPDATE'
246
+ THEN
247
+ RAISE EXCEPTION
248
+ 'organization membership lifecycle function % still locks the organization row FOR UPDATE',
249
+ signature USING ERRCODE = '55000';
250
+ END IF;
251
+ END LOOP;
252
+ END
253
+ $membership_lock_order_verification$;
254
+
255
+ COMMENT ON FUNCTION prepare_organization_membership_protocol_settlements(jsonb) IS
256
+ 'Locks the exact turns whose pending protocol state a suspend/offboard must settle. '
257
+ 'Lock order: advisory organization fence '
258
+ '(hashtextextended(''organization-membership:<organization id>'')) -> managed_accounts '
259
+ 'FOR KEY SHARE -> per-workspace workspace_inference_controls FOR SHARE + workspaces '
260
+ 'FOR KEY SHARE -> organization_memberships FOR UPDATE -> sessions FOR NO KEY UPDATE -> '
261
+ 'session_turns FOR UPDATE -> session_turn_attempts FOR UPDATE. Never take a conflicting '
262
+ 'row lock on managed_accounts here: ordinary workspace writers reach that row through an '
263
+ 'FK FOR KEY SHARE check while already holding their workspaces row.';
264
+
265
+ -- Only present in the post-0275 shape.
266
+ DO $membership_lock_order_body_comment$
267
+ BEGIN
268
+ IF pg_catalog.to_regprocedure(
269
+ pg_catalog.quote_ident(pg_catalog.current_schema())
270
+ || '.organization_membership_command_0263(jsonb)'
271
+ ) IS NOT NULL THEN
272
+ EXECUTE pg_catalog.format(
273
+ 'COMMENT ON FUNCTION %I.organization_membership_command_0263(jsonb) IS %L',
274
+ pg_catalog.current_schema(),
275
+ 'Migration 0263 organization membership lifecycle body, wrapped by '
276
+ 'organization_membership_command since migration 0275. Takes the same advisory '
277
+ 'organization fence and managed_accounts FOR KEY SHARE as its wrapper; the '
278
+ 'advisory lock is transaction-scoped and re-grantable, so the nested acquisition is a '
279
+ 'no-op within one command transaction.'
280
+ );
281
+ END IF;
282
+ END
283
+ $membership_lock_order_body_comment$;
284
+
285
+ COMMENT ON FUNCTION organization_membership_command(jsonb) IS
286
+ 'Organization membership lifecycle command (invite, accept, revoke_invitation, '
287
+ 'change_role, suspend, reactivate, offboard, retention). Mutual exclusion between '
288
+ 'concurrent commands for one organization is the advisory fence '
289
+ 'hashtextextended(''organization-membership:<organization id>''), not a managed_accounts '
290
+ 'row lock. CAS on organization_memberships.authorization_revision and the '
291
+ 'operation-receipt idempotency are unchanged.';