@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.
- package/dist/attached-browser-devices.d.ts +7 -0
- package/dist/automations.d.ts +154 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-integrations.d.ts +13 -0
- package/dist/child-lifecycle-notices.d.ts +68 -0
- package/dist/{chunk-LTG3S6ZY.js → chunk-EULAN2NP.js} +2 -2
- package/dist/{chunk-CUPM3FGB.js → chunk-NJVZPWXY.js} +3 -3
- package/dist/{chunk-4SR4HKKA.js → chunk-NMUBV7Z5.js} +19 -11
- package/dist/chunk-NMUBV7Z5.js.map +1 -0
- package/dist/chunk-OF5OBB76.js +4457 -0
- package/dist/chunk-OF5OBB76.js.map +1 -0
- package/dist/{chunk-6ZYKCRFO.js → chunk-PR2WMLOQ.js} +7580 -4417
- package/dist/chunk-PR2WMLOQ.js.map +1 -0
- package/dist/{chunk-ZWREYEWA.js → chunk-SCPUJS53.js} +41 -4
- package/dist/chunk-SCPUJS53.js.map +1 -0
- package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
- package/dist/chunk-SIBYBA2D.js.map +1 -0
- package/dist/chunk-TIKF3KTI.js +383 -0
- package/dist/chunk-TIKF3KTI.js.map +1 -0
- package/dist/chunk-ZZ5LJEFX.js +516 -0
- package/dist/chunk-ZZ5LJEFX.js.map +1 -0
- package/dist/codemode-operations.d.ts +1 -6
- package/dist/company-brain-context-selection-schema.d.ts +705 -0
- package/dist/company-brain-context-selection.d.ts +94 -0
- package/dist/company-brain-governed-writes.d.ts +24 -0
- package/dist/company-brain.d.ts +55 -0
- package/dist/company-profile-agent-admin.d.ts +15 -0
- package/dist/company-profile-schema.d.ts +619 -2
- package/dist/company-profile.d.ts +9 -4
- package/dist/connection-authority.d.ts +95 -0
- package/dist/connection-scopes.d.ts +8 -0
- package/dist/connection-tenancy-backfill.d.ts +41 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +19 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.d.ts +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation-schema.d.ts +984 -0
- package/dist/governed-learning-activation.d.ts +98 -0
- package/dist/governed-learning-evaluator-schema.d.ts +633 -0
- package/dist/governed-learning-evaluator.d.ts +28 -0
- package/dist/index.d.ts +1595 -81
- package/dist/index.js +21571 -8126
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +18 -0
- package/dist/integration-bindings.d.ts +1 -0
- package/dist/integration-facets.d.ts +30 -0
- package/dist/interaction-placement-loss.d.ts +22 -0
- package/dist/managed-human-provisioning.d.ts +25 -0
- package/dist/memory-domain.d.ts +3 -3
- package/dist/migrate.d.ts +11 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +43 -5
- package/dist/organization-membership-backfill.d.ts +174 -0
- package/dist/organization-membership-lifecycle.d.ts +162 -0
- package/dist/pr-review.d.ts +107 -0
- package/dist/preference-registry-schema.d.ts +2 -0
- package/dist/preference-registry.d.ts +2 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +22 -8
- package/dist/schema.d.ts +24914 -13703
- package/dist/schema.js +99 -1
- package/dist/scoped-knowledge-schema.d.ts +52 -1
- package/dist/session-background-commands.d.ts +125 -0
- package/dist/session-background-commands.js +34 -0
- package/dist/session-background-commands.js.map +1 -0
- package/dist/session-control.d.ts +156 -3
- package/dist/session-goal-pacing.d.ts +68 -0
- package/dist/session-queue-commands.d.ts +41 -4
- package/dist/session-realtime-ledger.d.ts +2 -0
- package/dist/session-tenancy.d.ts +71 -1
- package/dist/session-tenancy.js +25 -3
- package/dist/session-tool-call-settlement.d.ts +9 -4
- package/dist/slack-routing-personal-workspace.d.ts +23 -0
- package/dist/slack-routing.d.ts +153 -0
- package/dist/slack-task-policy-schema.d.ts +34 -0
- package/dist/slack-task-policy.d.ts +8 -0
- package/dist/slack-user-link-access.d.ts +1 -0
- package/dist/task-notes-schema.d.ts +594 -0
- package/dist/task-notes.d.ts +39 -0
- package/dist/turn-initiator.d.ts +2 -0
- package/dist/user-resource-authority.d.ts +109 -0
- package/dist/video-generation.js +3 -3
- package/dist/workspace-authority.d.ts +81 -0
- package/dist/workspace-instruction-policies-schema.d.ts +279 -0
- package/dist/workspace-instruction-policies.d.ts +62 -0
- package/dist/workspace-learning-policy.d.ts +1 -0
- package/dist/workspace-membership-permissions.d.ts +2 -0
- package/drizzle/0240_enrollment_connection_authority.sql +39 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
- package/drizzle/0245_model_context_contribution_facts.sql +88 -0
- package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
- package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
- package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
- package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
- package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
- package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
- package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
- package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
- package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
- package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
- package/drizzle/0256_connection_authority_delegation.sql +703 -0
- package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
- package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
- package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
- package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
- package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
- package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
- package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
- package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
- package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
- package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
- package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
- package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
- package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
- package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
- package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
- package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
- package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
- package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
- package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
- package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
- package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
- package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
- package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
- package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
- package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
- package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
- package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
- package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
- package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
- package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
- package/drizzle/0289_session_composer_policy_authority.sql +597 -0
- package/drizzle/0290_organization_membership_backfill.sql +268 -0
- package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
- package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
- package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
- package/drizzle/0294_preference_activation_authority.sql +237 -0
- package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
- package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
- package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
- package/drizzle/0298_organization_tenancy_parity.sql +609 -0
- package/drizzle/0299_organization_membership_lock_order.sql +291 -0
- package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
- package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
- package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
- package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
- package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
- package/drizzle/0305_personal_resource_grant_management.sql +584 -0
- package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
- package/drizzle/0307_session_attention_state.sql +51 -0
- package/drizzle/0308_session_archives.sql +35 -0
- package/drizzle/0309_channel_project_pins.sql +6 -0
- package/drizzle/0310_channel_project_order.sql +27 -0
- package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
- package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
- package/drizzle/0313_private_child_session_authority.sql +365 -0
- package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
- package/drizzle/0315_personal_github_repository_selection.sql +624 -0
- package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
- package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
- package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
- package/drizzle/0319_event_triggered_automations.sql +254 -0
- package/drizzle/0320_pr_review_pack.sql +113 -0
- package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
- package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
- package/drizzle/0323_organization_private_session_enablement.sql +489 -0
- package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
- package/drizzle/0325_child_lifecycle_notices.sql +44 -0
- package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
- package/drizzle/0327_slack_first_task_hint.sql +29 -0
- package/drizzle/0328_session_background_commands.sql +590 -0
- package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
- package/drizzle/0330_api_key_descriptions.sql +20 -0
- package/drizzle/0331_managed_organization_creation.sql +163 -0
- package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
- package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
- package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
- package/drizzle/0335_slack_workspace_routing.sql +460 -0
- package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
- package/drizzle/0337_slack_routed_action_handles.sql +189 -0
- package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
- package/drizzle/0339_document_authority_reclassification.sql +1153 -0
- package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
- package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
- package/package.json +10 -6
- package/src/attached-browser-devices.ts +233 -5
- package/src/automations.ts +911 -0
- package/src/browser-sessions.ts +10 -0
- package/src/capability-integrations.ts +175 -1
- package/src/child-lifecycle-notices.ts +241 -0
- package/src/codemode-operations.ts +1 -35
- package/src/company-brain-context-selection-schema.ts +100 -0
- package/src/company-brain-context-selection.ts +359 -0
- package/src/company-brain-governed-writes.ts +1170 -0
- package/src/company-brain.ts +309 -0
- package/src/company-profile-agent-admin.ts +225 -0
- package/src/company-profile-schema.ts +121 -1
- package/src/company-profile.ts +21 -0
- package/src/computer-sessions.ts +10 -1
- package/src/connection-authority.ts +290 -0
- package/src/connection-scopes.ts +20 -0
- package/src/connection-tenancy-backfill.ts +81 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +75 -2
- package/src/editable-artifacts-schema.ts +10 -5
- package/src/editable-artifacts.ts +21 -11
- package/src/governed-learning-activation-schema.ts +121 -0
- package/src/governed-learning-activation.ts +588 -0
- package/src/governed-learning-evaluator-schema.ts +72 -0
- package/src/governed-learning-evaluator.ts +217 -0
- package/src/index.ts +11651 -1548
- package/src/insights.ts +107 -0
- package/src/integration-bindings.ts +88 -6
- package/src/integration-facets.ts +287 -84
- package/src/interaction-placement-loss.ts +234 -0
- package/src/managed-human-provisioning.ts +116 -0
- package/src/memory-domain.ts +27 -32
- package/src/migrate.ts +77 -1
- package/src/new-session-drafts.ts +229 -35
- package/src/organization-membership-backfill.ts +735 -0
- package/src/organization-membership-lifecycle.ts +985 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +877 -6
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1291 -76
- package/src/schema.ts +3303 -428
- package/src/scoped-knowledge-schema.ts +16 -8
- package/src/scoped-knowledge.ts +1 -1
- package/src/session-background-commands.ts +759 -0
- package/src/session-control.ts +640 -74
- package/src/session-goal-pacing.ts +126 -0
- package/src/session-queue-commands.ts +437 -84
- package/src/session-realtime-context.ts +3 -3
- package/src/session-realtime-ledger.ts +22 -11
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +403 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +469 -0
- package/src/slack-task-policy-schema.ts +5 -0
- package/src/slack-task-policy.ts +18 -0
- package/src/slack-user-link-access.ts +17 -1
- package/src/task-notes-schema.ts +74 -0
- package/src/task-notes.ts +124 -2
- package/src/turn-initiator.ts +8 -0
- package/src/user-resource-authority.ts +377 -0
- package/src/workspace-authority.ts +160 -0
- package/src/workspace-instruction-policies-schema.ts +53 -1
- package/src/workspace-instruction-policies.ts +528 -77
- package/src/workspace-learning-policy.ts +21 -5
- package/src/workspace-membership-permissions.ts +9 -0
- package/dist/chunk-4SR4HKKA.js.map +0 -1
- package/dist/chunk-6ZYKCRFO.js.map +0 -1
- package/dist/chunk-NXAFLCQX.js +0 -2468
- package/dist/chunk-NXAFLCQX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-WD5ROSLL.js +0 -117
- package/dist/chunk-WD5ROSLL.js.map +0 -1
- package/dist/chunk-ZWREYEWA.js.map +0 -1
- /package/dist/{chunk-LTG3S6ZY.js.map → chunk-EULAN2NP.js.map} +0 -0
- /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.';
|