@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,667 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Rolling expansion of migration 0303's activated fork surface. The original
|
|
3
|
+
-- nine-argument private-only overload stays executable so an in-flight old
|
|
4
|
+
-- caller can replay its receipt. New callers use the ten-argument overload;
|
|
5
|
+
-- destination visibility and the private-to-workspace acknowledgement are
|
|
6
|
+
-- bound into the caller-supplied canonical request hash.
|
|
7
|
+
|
|
8
|
+
-- Exact receipt recovery is a separate read-only capability so the application
|
|
9
|
+
-- can resolve a committed result before asking mutable source-session authority
|
|
10
|
+
-- again. It returns nothing for a fresh key, conflicts on changed intent, and
|
|
11
|
+
-- requires the exact authenticated actor plus current workspace authority. The
|
|
12
|
+
-- result is therefore not a general session or destination discovery oracle.
|
|
13
|
+
CREATE FUNCTION replay_applied_session_fork(
|
|
14
|
+
p_account_id uuid,
|
|
15
|
+
p_source_workspace_id uuid,
|
|
16
|
+
p_source_session_id uuid,
|
|
17
|
+
p_actor_subject_id text,
|
|
18
|
+
p_destination_workspace_id uuid,
|
|
19
|
+
p_destination_visibility text,
|
|
20
|
+
p_workspace_shared_acknowledged boolean,
|
|
21
|
+
p_operation_key text,
|
|
22
|
+
p_canonical_request_hash text,
|
|
23
|
+
p_activation_version integer
|
|
24
|
+
) RETURNS TABLE (
|
|
25
|
+
operation_id uuid,
|
|
26
|
+
event_id uuid,
|
|
27
|
+
event_sequence integer,
|
|
28
|
+
session_id uuid,
|
|
29
|
+
workspace_id uuid,
|
|
30
|
+
visibility text,
|
|
31
|
+
authority_epoch integer,
|
|
32
|
+
copied_history_item_count integer,
|
|
33
|
+
replay boolean
|
|
34
|
+
)
|
|
35
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
36
|
+
SET search_path FROM CURRENT
|
|
37
|
+
AS $$
|
|
38
|
+
DECLARE
|
|
39
|
+
actor_membership organization_memberships%ROWTYPE;
|
|
40
|
+
receipt_row session_command_receipts%ROWTYPE;
|
|
41
|
+
BEGIN
|
|
42
|
+
IF p_account_id IS NULL OR p_source_workspace_id IS NULL
|
|
43
|
+
OR p_source_session_id IS NULL OR p_actor_subject_id IS NULL
|
|
44
|
+
OR p_destination_workspace_id IS NULL OR p_destination_visibility IS NULL
|
|
45
|
+
OR p_workspace_shared_acknowledged IS NULL
|
|
46
|
+
OR p_operation_key IS NULL OR p_canonical_request_hash IS NULL
|
|
47
|
+
OR p_activation_version IS NULL
|
|
48
|
+
THEN RAISE EXCEPTION 'session fork replay requires complete authority'
|
|
49
|
+
USING ERRCODE = '42501'; END IF;
|
|
50
|
+
IF p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
|
|
51
|
+
OR p_source_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
|
|
52
|
+
OR p_actor_subject_id IS DISTINCT FROM opengeni_private.current_subject_id()
|
|
53
|
+
THEN RAISE EXCEPTION 'session fork replay authority is invalid'
|
|
54
|
+
USING ERRCODE = '42501'; END IF;
|
|
55
|
+
IF p_destination_workspace_id IS DISTINCT FROM p_source_workspace_id
|
|
56
|
+
OR p_destination_visibility NOT IN ('user_private', 'workspace_shared')
|
|
57
|
+
OR (p_destination_visibility = 'user_private' AND p_workspace_shared_acknowledged)
|
|
58
|
+
OR p_actor_subject_id <> btrim(p_actor_subject_id)
|
|
59
|
+
OR length(p_actor_subject_id) NOT BETWEEN 1 AND 1024
|
|
60
|
+
OR p_operation_key <> btrim(p_operation_key)
|
|
61
|
+
OR length(p_operation_key) NOT BETWEEN 1 AND 1024
|
|
62
|
+
OR p_canonical_request_hash !~ '^[0-9a-f]{64}$'
|
|
63
|
+
OR p_activation_version <> 1
|
|
64
|
+
THEN RAISE EXCEPTION 'session fork replay request is invalid'
|
|
65
|
+
USING ERRCODE = '22023'; END IF;
|
|
66
|
+
IF NOT session_tenancy_product_activated(p_account_id, p_activation_version) THEN
|
|
67
|
+
RAISE EXCEPTION 'session tenancy product surface is not activated for this organization'
|
|
68
|
+
USING ERRCODE = '55000';
|
|
69
|
+
END IF;
|
|
70
|
+
|
|
71
|
+
PERFORM pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
|
|
72
|
+
'organization-membership:' || p_account_id::text, 0
|
|
73
|
+
));
|
|
74
|
+
PERFORM 1 FROM workspaces workspace_row
|
|
75
|
+
WHERE workspace_row.account_id = p_account_id
|
|
76
|
+
AND workspace_row.id = p_source_workspace_id
|
|
77
|
+
FOR KEY SHARE;
|
|
78
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'session fork replay workspace is unavailable'
|
|
79
|
+
USING ERRCODE = '42501'; END IF;
|
|
80
|
+
|
|
81
|
+
SELECT membership.* INTO actor_membership
|
|
82
|
+
FROM organization_memberships membership
|
|
83
|
+
WHERE membership.account_id = p_account_id
|
|
84
|
+
AND membership.subject_id = p_actor_subject_id
|
|
85
|
+
AND membership.status = 'active'
|
|
86
|
+
FOR KEY SHARE;
|
|
87
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'session fork replay requires active workspace authority'
|
|
88
|
+
USING ERRCODE = '42501'; END IF;
|
|
89
|
+
IF actor_membership.personal_workspace_id IS DISTINCT FROM p_source_workspace_id THEN
|
|
90
|
+
PERFORM 1 FROM workspace_memberships workspace_membership
|
|
91
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
92
|
+
AND workspace_membership.workspace_id = p_source_workspace_id
|
|
93
|
+
AND workspace_membership.subject_id = p_actor_subject_id
|
|
94
|
+
FOR KEY SHARE;
|
|
95
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'session fork replay requires active workspace authority'
|
|
96
|
+
USING ERRCODE = '42501'; END IF;
|
|
97
|
+
END IF;
|
|
98
|
+
|
|
99
|
+
SELECT receipt.* INTO receipt_row FROM session_command_receipts receipt
|
|
100
|
+
WHERE receipt.account_id = p_account_id
|
|
101
|
+
AND receipt.workspace_id = p_source_workspace_id
|
|
102
|
+
AND receipt.actor_type = 'human' AND receipt.actor_subject_id = p_actor_subject_id
|
|
103
|
+
AND receipt.actor_attempt_id IS NULL AND receipt.action = 'session.fork'
|
|
104
|
+
AND receipt.target_session_id = p_source_session_id
|
|
105
|
+
AND receipt.target_turn_id IS NULL AND receipt.operation_key = p_operation_key;
|
|
106
|
+
IF NOT FOUND OR receipt_row.result ->> 'status' <> 'applied' THEN RETURN; END IF;
|
|
107
|
+
IF receipt_row.canonical_request_hash <> p_canonical_request_hash THEN
|
|
108
|
+
RAISE EXCEPTION 'session fork idempotency conflict' USING ERRCODE = '23505';
|
|
109
|
+
END IF;
|
|
110
|
+
|
|
111
|
+
operation_id := receipt_row.id;
|
|
112
|
+
event_id := nullif(receipt_row.result ->> 'eventId', '')::uuid;
|
|
113
|
+
event_sequence := (receipt_row.result ->> 'eventSequence')::integer;
|
|
114
|
+
session_id := (receipt_row.result ->> 'sessionId')::uuid;
|
|
115
|
+
workspace_id := (receipt_row.result ->> 'workspaceId')::uuid;
|
|
116
|
+
visibility := receipt_row.result ->> 'visibility';
|
|
117
|
+
authority_epoch := 1;
|
|
118
|
+
copied_history_item_count :=
|
|
119
|
+
(receipt_row.result ->> 'copiedHistoryItemCount')::integer;
|
|
120
|
+
replay := true;
|
|
121
|
+
RETURN NEXT;
|
|
122
|
+
END
|
|
123
|
+
$$;
|
|
124
|
+
|
|
125
|
+
CREATE FUNCTION fork_session_content(
|
|
126
|
+
p_account_id uuid,
|
|
127
|
+
p_source_workspace_id uuid,
|
|
128
|
+
p_source_session_id uuid,
|
|
129
|
+
p_actor_subject_id text,
|
|
130
|
+
p_destination_workspace_id uuid,
|
|
131
|
+
p_destination_visibility text,
|
|
132
|
+
p_workspace_shared_acknowledged boolean,
|
|
133
|
+
p_operation_key text,
|
|
134
|
+
p_canonical_request_hash text,
|
|
135
|
+
p_activation_version integer
|
|
136
|
+
) RETURNS TABLE (
|
|
137
|
+
operation_id uuid,
|
|
138
|
+
event_id uuid,
|
|
139
|
+
event_sequence integer,
|
|
140
|
+
session_id uuid,
|
|
141
|
+
workspace_id uuid,
|
|
142
|
+
visibility text,
|
|
143
|
+
authority_epoch integer,
|
|
144
|
+
copied_history_item_count integer,
|
|
145
|
+
replay boolean
|
|
146
|
+
)
|
|
147
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
148
|
+
SET search_path FROM CURRENT
|
|
149
|
+
AS $$
|
|
150
|
+
DECLARE
|
|
151
|
+
actor_membership organization_memberships%ROWTYPE;
|
|
152
|
+
source_session sessions%ROWTYPE;
|
|
153
|
+
destination_workspace workspaces%ROWTYPE;
|
|
154
|
+
receipt_row session_command_receipts%ROWTYPE;
|
|
155
|
+
destination_session_id uuid;
|
|
156
|
+
history_count integer := 0;
|
|
157
|
+
destination_activity_revision bigint;
|
|
158
|
+
destination_depth integer;
|
|
159
|
+
destination_depth_source text;
|
|
160
|
+
destination_resources jsonb := '[]'::jsonb;
|
|
161
|
+
event_row_id uuid;
|
|
162
|
+
public_destination_visibility text;
|
|
163
|
+
visibility_write_capability_id uuid := gen_random_uuid();
|
|
164
|
+
previous_lifecycle text := current_setting('opengeni.organization_tenancy_lifecycle', true);
|
|
165
|
+
previous_gate_state text := current_setting('opengeni.session_activity_gate_state', true);
|
|
166
|
+
previous_gate_workspace text := current_setting(
|
|
167
|
+
'opengeni.session_activity_gate_workspace_id', true
|
|
168
|
+
);
|
|
169
|
+
previous_visibility_capability text := current_setting(
|
|
170
|
+
'opengeni.session_visibility_write_capability', true
|
|
171
|
+
);
|
|
172
|
+
BEGIN
|
|
173
|
+
IF p_account_id IS NULL OR p_source_workspace_id IS NULL
|
|
174
|
+
OR p_source_session_id IS NULL OR p_actor_subject_id IS NULL
|
|
175
|
+
OR p_destination_workspace_id IS NULL OR p_destination_visibility IS NULL
|
|
176
|
+
OR p_workspace_shared_acknowledged IS NULL
|
|
177
|
+
OR p_operation_key IS NULL OR p_canonical_request_hash IS NULL
|
|
178
|
+
OR p_activation_version IS NULL
|
|
179
|
+
THEN RAISE EXCEPTION 'session fork requires complete authority'
|
|
180
|
+
USING ERRCODE = '42501'; END IF;
|
|
181
|
+
IF p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
|
|
182
|
+
OR p_source_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
|
|
183
|
+
OR p_actor_subject_id IS DISTINCT FROM opengeni_private.current_subject_id()
|
|
184
|
+
THEN RAISE EXCEPTION 'session fork authority is invalid'
|
|
185
|
+
USING ERRCODE = '42501'; END IF;
|
|
186
|
+
IF p_destination_workspace_id IS DISTINCT FROM p_source_workspace_id
|
|
187
|
+
OR p_destination_visibility NOT IN ('user_private', 'workspace_shared')
|
|
188
|
+
OR (p_destination_visibility = 'user_private' AND p_workspace_shared_acknowledged)
|
|
189
|
+
OR p_actor_subject_id <> btrim(p_actor_subject_id)
|
|
190
|
+
OR length(p_actor_subject_id) NOT BETWEEN 1 AND 1024
|
|
191
|
+
OR p_operation_key <> btrim(p_operation_key)
|
|
192
|
+
OR length(p_operation_key) NOT BETWEEN 1 AND 1024
|
|
193
|
+
OR p_canonical_request_hash !~ '^[0-9a-f]{64}$'
|
|
194
|
+
OR p_activation_version <> 1
|
|
195
|
+
THEN RAISE EXCEPTION 'session fork request is invalid'
|
|
196
|
+
USING ERRCODE = '22023'; END IF;
|
|
197
|
+
IF nullif(previous_gate_state, '') IS NOT NULL
|
|
198
|
+
OR nullif(previous_gate_workspace, '') IS NOT NULL
|
|
199
|
+
THEN RAISE EXCEPTION 'session fork requires ownership of the activity gate'
|
|
200
|
+
USING ERRCODE = '55000'; END IF;
|
|
201
|
+
IF NOT session_tenancy_product_activated(p_account_id, p_activation_version) THEN
|
|
202
|
+
RAISE EXCEPTION 'session tenancy product surface is not activated for this organization'
|
|
203
|
+
USING ERRCODE = '55000';
|
|
204
|
+
END IF;
|
|
205
|
+
|
|
206
|
+
PERFORM pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
|
|
207
|
+
'organization-membership:' || p_account_id::text, 0
|
|
208
|
+
));
|
|
209
|
+
|
|
210
|
+
LOCK TABLE sessions, session_turns, session_turn_attempts,
|
|
211
|
+
session_attempt_interruptions, session_system_updates,
|
|
212
|
+
session_human_input_requests, session_pending_tool_calls, agent_run_states,
|
|
213
|
+
session_goals, codex_capacity_waiters, xai_capacity_waiters,
|
|
214
|
+
session_realtime_modes, session_realtime_connections, scheduled_tasks,
|
|
215
|
+
sandbox_workspace_mutation_admissions, sandbox_retained_processes,
|
|
216
|
+
sandbox_lease_holders IN SHARE ROW EXCLUSIVE MODE;
|
|
217
|
+
|
|
218
|
+
PERFORM set_config('opengeni.organization_tenancy_lifecycle',
|
|
219
|
+
'session_visibility_activation', true);
|
|
220
|
+
SELECT * INTO destination_workspace FROM workspaces workspace_row
|
|
221
|
+
WHERE workspace_row.account_id = p_account_id
|
|
222
|
+
AND workspace_row.id = p_source_workspace_id
|
|
223
|
+
FOR UPDATE;
|
|
224
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'session fork workspace is unavailable'
|
|
225
|
+
USING ERRCODE = '42501'; END IF;
|
|
226
|
+
|
|
227
|
+
SELECT membership.* INTO actor_membership
|
|
228
|
+
FROM organization_memberships membership
|
|
229
|
+
WHERE membership.account_id = p_account_id
|
|
230
|
+
AND membership.subject_id = p_actor_subject_id
|
|
231
|
+
AND membership.status = 'active'
|
|
232
|
+
FOR UPDATE;
|
|
233
|
+
IF NOT FOUND OR NOT (
|
|
234
|
+
actor_membership.personal_workspace_id = p_source_workspace_id
|
|
235
|
+
OR EXISTS (
|
|
236
|
+
SELECT 1 FROM workspace_memberships workspace_membership
|
|
237
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
238
|
+
AND workspace_membership.workspace_id = p_source_workspace_id
|
|
239
|
+
AND workspace_membership.subject_id = p_actor_subject_id
|
|
240
|
+
)
|
|
241
|
+
) THEN RAISE EXCEPTION 'session fork requires active workspace authority'
|
|
242
|
+
USING ERRCODE = '42501'; END IF;
|
|
243
|
+
|
|
244
|
+
-- Resolve an already-applied receipt before inspecting mutable source state.
|
|
245
|
+
-- The same still-authorized workspace actor can therefore recover the exact
|
|
246
|
+
-- destination after a lost response even if the source owner later makes the
|
|
247
|
+
-- source private. A new key still reaches the current source authorization
|
|
248
|
+
-- check below and is denied.
|
|
249
|
+
SELECT receipt.* INTO receipt_row FROM session_command_receipts receipt
|
|
250
|
+
WHERE receipt.account_id = p_account_id
|
|
251
|
+
AND receipt.workspace_id = p_source_workspace_id
|
|
252
|
+
AND receipt.actor_type = 'human' AND receipt.actor_subject_id = p_actor_subject_id
|
|
253
|
+
AND receipt.actor_attempt_id IS NULL AND receipt.action = 'session.fork'
|
|
254
|
+
AND receipt.target_session_id = p_source_session_id
|
|
255
|
+
AND receipt.target_turn_id IS NULL AND receipt.operation_key = p_operation_key
|
|
256
|
+
AND receipt.result ->> 'status' = 'applied';
|
|
257
|
+
IF receipt_row.canonical_request_hash <> p_canonical_request_hash THEN
|
|
258
|
+
RAISE EXCEPTION 'session fork idempotency conflict' USING ERRCODE = '23505';
|
|
259
|
+
END IF;
|
|
260
|
+
IF receipt_row.result ->> 'status' = 'applied' THEN
|
|
261
|
+
operation_id := receipt_row.id;
|
|
262
|
+
event_id := nullif(receipt_row.result ->> 'eventId', '')::uuid;
|
|
263
|
+
event_sequence := (receipt_row.result ->> 'eventSequence')::integer;
|
|
264
|
+
session_id := (receipt_row.result ->> 'sessionId')::uuid;
|
|
265
|
+
workspace_id := (receipt_row.result ->> 'workspaceId')::uuid;
|
|
266
|
+
visibility := receipt_row.result ->> 'visibility'; authority_epoch := 1;
|
|
267
|
+
copied_history_item_count :=
|
|
268
|
+
(receipt_row.result ->> 'copiedHistoryItemCount')::integer;
|
|
269
|
+
replay := true; RETURN NEXT; RETURN;
|
|
270
|
+
END IF;
|
|
271
|
+
|
|
272
|
+
-- Product decision, distinct from authority, and the same one migration 0323
|
|
273
|
+
-- makes on the create path: a private destination inside a shared workspace
|
|
274
|
+
-- requires the organization's private-session setting. A personal workspace
|
|
275
|
+
-- is exempt exactly as it is there. This is deliberately placed after the
|
|
276
|
+
-- keyed replay above and before any source read, so a fork that already
|
|
277
|
+
-- committed still replays byte-identically after an owner disables the
|
|
278
|
+
-- setting, while a fresh key fails closed with the same SQLSTATE the create
|
|
279
|
+
-- path raises.
|
|
280
|
+
IF p_destination_visibility = 'user_private'
|
|
281
|
+
AND actor_membership.personal_workspace_id IS DISTINCT FROM p_source_workspace_id
|
|
282
|
+
AND NOT organization_private_sessions_enabled(p_account_id)
|
|
283
|
+
THEN
|
|
284
|
+
RAISE EXCEPTION
|
|
285
|
+
'private sessions are not enabled for this organization''s shared workspaces'
|
|
286
|
+
USING ERRCODE = '55000';
|
|
287
|
+
END IF;
|
|
288
|
+
|
|
289
|
+
SELECT session.* INTO source_session FROM sessions session
|
|
290
|
+
WHERE session.account_id = p_account_id
|
|
291
|
+
AND session.workspace_id = p_source_workspace_id
|
|
292
|
+
AND session.id = p_source_session_id
|
|
293
|
+
FOR UPDATE;
|
|
294
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'session fork source session is unavailable'
|
|
295
|
+
USING ERRCODE = 'P0002'; END IF;
|
|
296
|
+
-- A private source remains owner-only. A workspace-shared source follows
|
|
297
|
+
-- current workspace authority, and the fork becomes a fresh session owned
|
|
298
|
+
-- by the actor. This is what lets any authorized collaborator fork shared
|
|
299
|
+
-- work privately without retaining the source owner's authority.
|
|
300
|
+
IF source_session.visibility = 'user_private' AND (
|
|
301
|
+
source_session.owner_organization_membership_id IS DISTINCT FROM actor_membership.id
|
|
302
|
+
OR source_session.owner_subject_id IS DISTINCT FROM actor_membership.subject_id
|
|
303
|
+
)
|
|
304
|
+
THEN RAISE EXCEPTION 'session fork source session is private'
|
|
305
|
+
USING ERRCODE = '42501'; END IF;
|
|
306
|
+
|
|
307
|
+
INSERT INTO session_command_receipts (
|
|
308
|
+
account_id, workspace_id, actor_type, actor_subject_id, action,
|
|
309
|
+
target_session_id, operation_key, canonical_request_hash
|
|
310
|
+
) VALUES (
|
|
311
|
+
p_account_id, p_source_workspace_id, 'human', p_actor_subject_id,
|
|
312
|
+
'session.fork', p_source_session_id, p_operation_key, p_canonical_request_hash
|
|
313
|
+
) ON CONFLICT DO NOTHING;
|
|
314
|
+
SELECT receipt.* INTO receipt_row FROM session_command_receipts receipt
|
|
315
|
+
WHERE receipt.account_id = p_account_id
|
|
316
|
+
AND receipt.workspace_id = p_source_workspace_id
|
|
317
|
+
AND receipt.actor_type = 'human' AND receipt.actor_subject_id = p_actor_subject_id
|
|
318
|
+
AND receipt.actor_attempt_id IS NULL AND receipt.action = 'session.fork'
|
|
319
|
+
AND receipt.target_session_id = p_source_session_id
|
|
320
|
+
AND receipt.target_turn_id IS NULL AND receipt.operation_key = p_operation_key
|
|
321
|
+
FOR UPDATE;
|
|
322
|
+
IF receipt_row.canonical_request_hash <> p_canonical_request_hash THEN
|
|
323
|
+
RAISE EXCEPTION 'session fork idempotency conflict' USING ERRCODE = '23505';
|
|
324
|
+
END IF;
|
|
325
|
+
IF receipt_row.result ->> 'status' = 'applied' THEN
|
|
326
|
+
operation_id := receipt_row.id;
|
|
327
|
+
event_id := nullif(receipt_row.result ->> 'eventId', '')::uuid;
|
|
328
|
+
event_sequence := (receipt_row.result ->> 'eventSequence')::integer;
|
|
329
|
+
session_id := (receipt_row.result ->> 'sessionId')::uuid;
|
|
330
|
+
workspace_id := (receipt_row.result ->> 'workspaceId')::uuid;
|
|
331
|
+
visibility := receipt_row.result ->> 'visibility'; authority_epoch := 1;
|
|
332
|
+
copied_history_item_count :=
|
|
333
|
+
(receipt_row.result ->> 'copiedHistoryItemCount')::integer;
|
|
334
|
+
replay := true; RETURN NEXT; RETURN;
|
|
335
|
+
END IF;
|
|
336
|
+
|
|
337
|
+
-- The acknowledgement is content-exposure evidence, not a blanket checkbox:
|
|
338
|
+
-- it is required only when private source content crosses into workspace scope.
|
|
339
|
+
IF source_session.visibility = 'user_private'
|
|
340
|
+
AND p_destination_visibility = 'workspace_shared'
|
|
341
|
+
AND NOT p_workspace_shared_acknowledged
|
|
342
|
+
THEN RAISE EXCEPTION 'private-to-workspace fork requires explicit acknowledgement'
|
|
343
|
+
USING ERRCODE = '22023'; END IF;
|
|
344
|
+
|
|
345
|
+
PERFORM assert_session_tenancy_quiescent(
|
|
346
|
+
p_account_id, p_source_workspace_id, p_source_session_id, true
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
SELECT coalesce(jsonb_agg(
|
|
350
|
+
CASE WHEN resource.value ->> 'connectionType' = 'github_personal'
|
|
351
|
+
THEN resource.value
|
|
352
|
+
- 'provider' - 'connectionType' - 'credentialBindingId' - 'access'
|
|
353
|
+
- 'repositoryId' - 'installationId' - 'projectId' - 'connectionId'
|
|
354
|
+
- 'githubInstallationId' - 'githubRepositoryId'
|
|
355
|
+
ELSE resource.value
|
|
356
|
+
- 'credentialBindingId' - 'connectionId' - 'installationId'
|
|
357
|
+
- 'projectId' - 'githubInstallationId'
|
|
358
|
+
END
|
|
359
|
+
ORDER BY resource.ordinality
|
|
360
|
+
), '[]'::jsonb) INTO destination_resources
|
|
361
|
+
FROM jsonb_array_elements(source_session.resources)
|
|
362
|
+
WITH ORDINALITY AS resource(value, ordinality);
|
|
363
|
+
|
|
364
|
+
DROP TABLE IF EXISTS pg_temp.opengeni_session_fork_history_spool;
|
|
365
|
+
CREATE TEMP TABLE opengeni_session_fork_history_spool (
|
|
366
|
+
position numeric NOT NULL,
|
|
367
|
+
item jsonb NOT NULL,
|
|
368
|
+
item_codec_version integer,
|
|
369
|
+
active boolean NOT NULL,
|
|
370
|
+
provider_artifact_invalidated_at timestamptz,
|
|
371
|
+
provider_artifact_invalidation_reason text,
|
|
372
|
+
provider_artifact_invalidated_by_attempt_id uuid,
|
|
373
|
+
created_at timestamptz NOT NULL
|
|
374
|
+
) ON COMMIT DROP;
|
|
375
|
+
INSERT INTO pg_temp.opengeni_session_fork_history_spool (
|
|
376
|
+
position, item, item_codec_version, active,
|
|
377
|
+
provider_artifact_invalidated_at, provider_artifact_invalidation_reason,
|
|
378
|
+
provider_artifact_invalidated_by_attempt_id, created_at
|
|
379
|
+
) SELECT source_item.position, source_item.item,
|
|
380
|
+
source_item.item_codec_version, source_item.active,
|
|
381
|
+
source_item.provider_artifact_invalidated_at,
|
|
382
|
+
source_item.provider_artifact_invalidation_reason,
|
|
383
|
+
source_item.provider_artifact_invalidated_by_attempt_id,
|
|
384
|
+
source_item.created_at
|
|
385
|
+
FROM session_history_items source_item
|
|
386
|
+
WHERE source_item.account_id = p_account_id
|
|
387
|
+
AND source_item.workspace_id = p_source_workspace_id
|
|
388
|
+
AND source_item.session_id = p_source_session_id
|
|
389
|
+
ORDER BY source_item.position;
|
|
390
|
+
GET DIAGNOSTICS history_count = ROW_COUNT;
|
|
391
|
+
|
|
392
|
+
SELECT coalesce(
|
|
393
|
+
CASE WHEN (destination_workspace.settings ->> 'maxNestedAgentDepth') ~ '^\d+$'
|
|
394
|
+
THEN (destination_workspace.settings ->> 'maxNestedAgentDepth')::integer END,
|
|
395
|
+
configuration.max_nested_agent_depth
|
|
396
|
+
),
|
|
397
|
+
CASE WHEN (destination_workspace.settings ->> 'maxNestedAgentDepth') ~ '^\d+$'
|
|
398
|
+
THEN 'workspace' ELSE configuration.policy_source END
|
|
399
|
+
INTO destination_depth, destination_depth_source
|
|
400
|
+
FROM nested_agent_depth_configuration configuration
|
|
401
|
+
WHERE configuration.singleton = true;
|
|
402
|
+
IF destination_depth IS NULL OR destination_depth_source IS NULL THEN
|
|
403
|
+
RAISE EXCEPTION 'session fork destination depth policy is unavailable'
|
|
404
|
+
USING ERRCODE = '55000';
|
|
405
|
+
END IF;
|
|
406
|
+
|
|
407
|
+
destination_session_id := gen_random_uuid();
|
|
408
|
+
public_destination_visibility := CASE p_destination_visibility
|
|
409
|
+
WHEN 'user_private' THEN 'private' ELSE 'workspace' END;
|
|
410
|
+
INSERT INTO session_visibility_write_capabilities (
|
|
411
|
+
backend_pid, transaction_id, capability_id
|
|
412
|
+
) VALUES (pg_backend_pid(), pg_current_xact_id(), visibility_write_capability_id);
|
|
413
|
+
PERFORM set_config('opengeni.session_visibility_write_capability',
|
|
414
|
+
visibility_write_capability_id::text, true);
|
|
415
|
+
PERFORM set_config('opengeni.session_activity_gate_state', 'open', true);
|
|
416
|
+
PERFORM set_config('opengeni.session_activity_gate_workspace_id',
|
|
417
|
+
p_source_workspace_id::text, true);
|
|
418
|
+
|
|
419
|
+
-- This one insert establishes fresh ownership, authority epoch, provenance,
|
|
420
|
+
-- root identity and singleton sandbox group. No live source authority is copied.
|
|
421
|
+
INSERT INTO sessions (
|
|
422
|
+
id, account_id, workspace_id, status,
|
|
423
|
+
initial_message, initial_message_codec_version,
|
|
424
|
+
title, title_source, instructions, policy_role,
|
|
425
|
+
resources, skills, tools, metadata,
|
|
426
|
+
created_by_kind, created_by_subject_id, created_by_context,
|
|
427
|
+
owner_organization_membership_id, owner_subject_id,
|
|
428
|
+
visibility, create_requested_visibility, authority_epoch,
|
|
429
|
+
forked_from_session_id, forked_from_authority_epoch,
|
|
430
|
+
forked_from_visibility, forked_at, forked_by_organization_membership_id,
|
|
431
|
+
model, reasoning_effort, latency_mode, sandbox_backend, sandbox_os, sandbox_group_id,
|
|
432
|
+
first_party_mcp_permissions, first_party_mcp_tools,
|
|
433
|
+
initial_personal_connection_delegations, tool_policy,
|
|
434
|
+
root_session_id, nested_agent_depth,
|
|
435
|
+
max_nested_agent_depth_override, effective_max_nested_agent_depth,
|
|
436
|
+
nested_agent_depth_policy_source, nested_agent_depth_policy_session_id,
|
|
437
|
+
temporal_workflow_id, active_turn_id, variable_set_id,
|
|
438
|
+
rig_id, rig_version_id, active_sandbox_id, active_epoch,
|
|
439
|
+
working_dir, codex_pinned_credential_id, codex_last_credential_id,
|
|
440
|
+
codex_pin_source, codex_compaction_mode,
|
|
441
|
+
queue_version, queue_head_position, queue_tail_position, last_sequence
|
|
442
|
+
) VALUES (
|
|
443
|
+
destination_session_id, p_account_id, p_source_workspace_id, 'idle',
|
|
444
|
+
source_session.initial_message, source_session.initial_message_codec_version,
|
|
445
|
+
source_session.title, source_session.title_source,
|
|
446
|
+
source_session.instructions, source_session.policy_role,
|
|
447
|
+
destination_resources, '[]'::jsonb, '[]'::jsonb, '{}'::jsonb,
|
|
448
|
+
'subject', p_actor_subject_id, jsonb_build_object(
|
|
449
|
+
'fork', true,
|
|
450
|
+
'sourceSessionId', p_source_session_id,
|
|
451
|
+
'sourceAuthorityEpoch', source_session.authority_epoch,
|
|
452
|
+
'sourceVisibility', CASE source_session.visibility
|
|
453
|
+
WHEN 'user_private' THEN 'private' ELSE 'workspace' END,
|
|
454
|
+
'workspaceSharedAcknowledged', p_workspace_shared_acknowledged
|
|
455
|
+
),
|
|
456
|
+
actor_membership.id, actor_membership.subject_id,
|
|
457
|
+
-- create_requested_visibility mirrors the destination the caller actually
|
|
458
|
+
-- asked for. Leaving it at the column default made a private fork row
|
|
459
|
+
-- internally inconsistent with its own visibility.
|
|
460
|
+
p_destination_visibility, p_destination_visibility, 1,
|
|
461
|
+
p_source_session_id, source_session.authority_epoch,
|
|
462
|
+
source_session.visibility, clock_timestamp(), actor_membership.id,
|
|
463
|
+
source_session.model, source_session.reasoning_effort, source_session.latency_mode,
|
|
464
|
+
source_session.sandbox_backend, source_session.sandbox_os, destination_session_id,
|
|
465
|
+
NULL, '[]'::jsonb, '[]'::jsonb,
|
|
466
|
+
'{"mode":"explicit","inheritedFromSessionId":null}'::jsonb,
|
|
467
|
+
destination_session_id, 0, NULL, destination_depth,
|
|
468
|
+
destination_depth_source, NULL,
|
|
469
|
+
NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL,
|
|
470
|
+
source_session.codex_compaction_mode,
|
|
471
|
+
0, 0, 0, 1
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
INSERT INTO session_history_items (
|
|
475
|
+
account_id, workspace_id, session_id, turn_id,
|
|
476
|
+
position, item, item_codec_version, active,
|
|
477
|
+
provider_artifact_invalidated_at, provider_artifact_invalidation_reason,
|
|
478
|
+
provider_artifact_invalidated_by_attempt_id, created_at
|
|
479
|
+
) SELECT p_account_id, p_source_workspace_id, destination_session_id, NULL,
|
|
480
|
+
source_item.position, source_item.item, source_item.item_codec_version,
|
|
481
|
+
source_item.active, source_item.provider_artifact_invalidated_at,
|
|
482
|
+
source_item.provider_artifact_invalidation_reason,
|
|
483
|
+
source_item.provider_artifact_invalidated_by_attempt_id, source_item.created_at
|
|
484
|
+
FROM pg_temp.opengeni_session_fork_history_spool source_item
|
|
485
|
+
ORDER BY source_item.position;
|
|
486
|
+
|
|
487
|
+
INSERT INTO session_events (
|
|
488
|
+
account_id, workspace_id, session_id, sequence, type, payload, occurred_at
|
|
489
|
+
) VALUES (
|
|
490
|
+
p_account_id, p_source_workspace_id, destination_session_id, 1,
|
|
491
|
+
'session.created', jsonb_build_object(
|
|
492
|
+
'forked', true, 'sourceSessionId', p_source_session_id,
|
|
493
|
+
'sourceAuthorityEpoch', source_session.authority_epoch,
|
|
494
|
+
'sourceVisibility', CASE source_session.visibility
|
|
495
|
+
WHEN 'user_private' THEN 'private' ELSE 'workspace' END,
|
|
496
|
+
'visibility', public_destination_visibility,
|
|
497
|
+
'workspaceSharedAcknowledged', p_workspace_shared_acknowledged,
|
|
498
|
+
'copiedHistoryItemCount', history_count
|
|
499
|
+
), clock_timestamp()
|
|
500
|
+
) RETURNING id INTO event_row_id;
|
|
501
|
+
|
|
502
|
+
PERFORM set_config('opengeni.session_activity_gate_state', 'preparing', true);
|
|
503
|
+
SET CONSTRAINTS ALL IMMEDIATE;
|
|
504
|
+
SET CONSTRAINTS sessions_activity_insert_commit_guard,
|
|
505
|
+
sessions_activity_update_commit_guard DEFERRED;
|
|
506
|
+
PERFORM set_config('opengeni.session_activity_gate_state', 'finalizing', true);
|
|
507
|
+
UPDATE workspace_session_activity_revisions counter
|
|
508
|
+
SET revision = counter.revision + 1
|
|
509
|
+
WHERE counter.workspace_id = p_source_workspace_id
|
|
510
|
+
RETURNING counter.revision INTO destination_activity_revision;
|
|
511
|
+
IF destination_activity_revision IS NULL THEN
|
|
512
|
+
RAISE EXCEPTION 'session fork destination activity counter is unavailable'
|
|
513
|
+
USING ERRCODE = '55000';
|
|
514
|
+
END IF;
|
|
515
|
+
UPDATE sessions destination_session SET
|
|
516
|
+
activity_revision = destination_activity_revision,
|
|
517
|
+
activity_revision_pending_xid = NULL
|
|
518
|
+
WHERE destination_session.id = destination_session_id
|
|
519
|
+
AND destination_session.activity_revision_pending_xid
|
|
520
|
+
= pg_current_xact_id()::text::bigint;
|
|
521
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'session fork activity was not finalized'
|
|
522
|
+
USING ERRCODE = '55000'; END IF;
|
|
523
|
+
SET CONSTRAINTS sessions_activity_insert_commit_guard,
|
|
524
|
+
sessions_activity_update_commit_guard IMMEDIATE;
|
|
525
|
+
|
|
526
|
+
PERFORM set_config('opengeni.session_activity_gate_state', '', true);
|
|
527
|
+
PERFORM set_config('opengeni.session_activity_gate_workspace_id', '', true);
|
|
528
|
+
DELETE FROM session_visibility_write_capabilities capability
|
|
529
|
+
WHERE capability.backend_pid = pg_backend_pid()
|
|
530
|
+
AND capability.transaction_id = pg_current_xact_id()
|
|
531
|
+
AND capability.capability_id = visibility_write_capability_id;
|
|
532
|
+
PERFORM set_config('opengeni.session_visibility_write_capability',
|
|
533
|
+
CASE WHEN previous_visibility_capability IS NULL THEN '' ELSE previous_visibility_capability END,
|
|
534
|
+
true);
|
|
535
|
+
|
|
536
|
+
UPDATE session_command_receipts SET result = jsonb_build_object(
|
|
537
|
+
'status', 'applied', 'eventId', event_row_id, 'eventSequence', 1,
|
|
538
|
+
'sessionId', destination_session_id, 'workspaceId', p_source_workspace_id,
|
|
539
|
+
'visibility', p_destination_visibility, 'authorityEpoch', 1,
|
|
540
|
+
'workspaceSharedAcknowledged', p_workspace_shared_acknowledged,
|
|
541
|
+
'copiedHistoryItemCount', history_count
|
|
542
|
+
), updated_at = clock_timestamp() WHERE id = receipt_row.id;
|
|
543
|
+
|
|
544
|
+
operation_id := receipt_row.id; event_id := event_row_id; event_sequence := 1;
|
|
545
|
+
session_id := destination_session_id; workspace_id := p_source_workspace_id;
|
|
546
|
+
visibility := p_destination_visibility; authority_epoch := 1;
|
|
547
|
+
copied_history_item_count := history_count; replay := false;
|
|
548
|
+
PERFORM set_config('opengeni.organization_tenancy_lifecycle',
|
|
549
|
+
CASE WHEN previous_lifecycle IS NULL THEN '' ELSE previous_lifecycle END, true);
|
|
550
|
+
RETURN NEXT;
|
|
551
|
+
EXCEPTION WHEN OTHERS THEN
|
|
552
|
+
PERFORM set_config('opengeni.organization_tenancy_lifecycle',
|
|
553
|
+
CASE WHEN previous_lifecycle IS NULL THEN '' ELSE previous_lifecycle END, true);
|
|
554
|
+
PERFORM set_config('opengeni.session_activity_gate_state',
|
|
555
|
+
CASE WHEN previous_gate_state IS NULL THEN '' ELSE previous_gate_state END, true);
|
|
556
|
+
PERFORM set_config('opengeni.session_activity_gate_workspace_id',
|
|
557
|
+
CASE WHEN previous_gate_workspace IS NULL THEN '' ELSE previous_gate_workspace END, true);
|
|
558
|
+
PERFORM set_config('opengeni.session_visibility_write_capability',
|
|
559
|
+
CASE WHEN previous_visibility_capability IS NULL THEN '' ELSE previous_visibility_capability END,
|
|
560
|
+
true);
|
|
561
|
+
RAISE;
|
|
562
|
+
END
|
|
563
|
+
$$;
|
|
564
|
+
|
|
565
|
+
-- Keep the old private-only signature for exact rolling retries, but converge
|
|
566
|
+
-- its implementation on the repaired atomic body. Private forks use the same
|
|
567
|
+
-- version-1 request hash on both signatures, so an already-applied 0303 receipt
|
|
568
|
+
-- replays unchanged while a not-yet-applied old request gets the corrected
|
|
569
|
+
-- history-copy and security posture.
|
|
570
|
+
CREATE OR REPLACE FUNCTION fork_session_content(
|
|
571
|
+
p_account_id uuid,
|
|
572
|
+
p_source_workspace_id uuid,
|
|
573
|
+
p_source_session_id uuid,
|
|
574
|
+
p_actor_subject_id text,
|
|
575
|
+
p_destination_workspace_id uuid,
|
|
576
|
+
p_destination_visibility text,
|
|
577
|
+
p_operation_key text,
|
|
578
|
+
p_canonical_request_hash text,
|
|
579
|
+
p_activation_version integer
|
|
580
|
+
) RETURNS TABLE (
|
|
581
|
+
operation_id uuid,
|
|
582
|
+
event_id uuid,
|
|
583
|
+
event_sequence integer,
|
|
584
|
+
session_id uuid,
|
|
585
|
+
workspace_id uuid,
|
|
586
|
+
visibility text,
|
|
587
|
+
authority_epoch integer,
|
|
588
|
+
copied_history_item_count integer,
|
|
589
|
+
replay boolean
|
|
590
|
+
)
|
|
591
|
+
LANGUAGE sql SECURITY DEFINER
|
|
592
|
+
SET search_path FROM CURRENT
|
|
593
|
+
AS $$
|
|
594
|
+
SELECT * FROM fork_session_content(
|
|
595
|
+
p_account_id,
|
|
596
|
+
p_source_workspace_id,
|
|
597
|
+
p_source_session_id,
|
|
598
|
+
p_actor_subject_id,
|
|
599
|
+
p_destination_workspace_id,
|
|
600
|
+
p_destination_visibility,
|
|
601
|
+
false,
|
|
602
|
+
p_operation_key,
|
|
603
|
+
p_canonical_request_hash,
|
|
604
|
+
p_activation_version
|
|
605
|
+
)
|
|
606
|
+
$$;
|
|
607
|
+
|
|
608
|
+
-- Both overloads and exact receipt recovery remain runtime-callable during this
|
|
609
|
+
-- rolling expansion. Pin each SECURITY DEFINER body and their private nested quiescence helper to the
|
|
610
|
+
-- exact migration target schema, with pg_temp last, so a caller-created
|
|
611
|
+
-- temporary relation cannot shadow authority, activity, or receipt tables. The
|
|
612
|
+
-- broad creation-time paths are replaced before this transaction can commit.
|
|
613
|
+
DO $atomic_session_fork_search_path$
|
|
614
|
+
DECLARE
|
|
615
|
+
target_schema text := current_schema();
|
|
616
|
+
BEGIN
|
|
617
|
+
EXECUTE format(
|
|
618
|
+
'ALTER FUNCTION %I.replay_applied_session_fork(uuid,uuid,uuid,text,uuid,text,boolean,text,text,integer) '
|
|
619
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
620
|
+
target_schema, target_schema
|
|
621
|
+
);
|
|
622
|
+
EXECUTE format(
|
|
623
|
+
'ALTER FUNCTION %I.fork_session_content(uuid,uuid,uuid,text,uuid,text,text,text,integer) '
|
|
624
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
625
|
+
target_schema, target_schema
|
|
626
|
+
);
|
|
627
|
+
EXECUTE format(
|
|
628
|
+
'ALTER FUNCTION %I.fork_session_content(uuid,uuid,uuid,text,uuid,text,boolean,text,text,integer) '
|
|
629
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
630
|
+
target_schema, target_schema
|
|
631
|
+
);
|
|
632
|
+
EXECUTE format(
|
|
633
|
+
'ALTER FUNCTION %I.assert_session_tenancy_quiescent(uuid,uuid,uuid,boolean) '
|
|
634
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
635
|
+
target_schema, target_schema
|
|
636
|
+
);
|
|
637
|
+
END
|
|
638
|
+
$atomic_session_fork_search_path$;
|
|
639
|
+
|
|
640
|
+
REVOKE ALL ON FUNCTION replay_applied_session_fork(
|
|
641
|
+
uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer
|
|
642
|
+
) FROM PUBLIC;
|
|
643
|
+
|
|
644
|
+
REVOKE ALL ON FUNCTION fork_session_content(
|
|
645
|
+
uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer
|
|
646
|
+
) FROM PUBLIC;
|
|
647
|
+
|
|
648
|
+
DO $atomic_session_fork_runtime_grant$
|
|
649
|
+
BEGIN
|
|
650
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
651
|
+
GRANT EXECUTE ON FUNCTION replay_applied_session_fork(
|
|
652
|
+
uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer
|
|
653
|
+
) TO opengeni_app;
|
|
654
|
+
GRANT EXECUTE ON FUNCTION fork_session_content(
|
|
655
|
+
uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer
|
|
656
|
+
) TO opengeni_app;
|
|
657
|
+
END IF;
|
|
658
|
+
END
|
|
659
|
+
$atomic_session_fork_runtime_grant$;
|
|
660
|
+
|
|
661
|
+
COMMENT ON FUNCTION replay_applied_session_fork(
|
|
662
|
+
uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer
|
|
663
|
+
) IS 'Exact actor/workspace/source/key/hash-bound recovery of one already-applied fork receipt; fresh keys return no row and mutable source authority is not consulted.';
|
|
664
|
+
|
|
665
|
+
COMMENT ON FUNCTION fork_session_content(
|
|
666
|
+
uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer
|
|
667
|
+
) IS 'Activated atomic same-workspace fork with explicit private/workspace visibility, durable private-to-workspace acknowledgement, fresh authority/root/group identity, exact history, and no copied live state.';
|