@opengeni/db 0.36.1 → 3.1.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
- package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
- package/dist/{chunk-HSOWSYOX.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-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
- package/dist/chunk-PR2WMLOQ.js.map +1 -0
- package/dist/{chunk-Z7VYMNPZ.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.d.ts +10 -0
- package/dist/editable-artifact-durable-export.js +18 -3
- package/dist/editable-artifact-durable-export.js.map +1 -1
- 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 +1633 -87
- package/dist/index.js +22004 -8109
- 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/knowledge-source-sync-schema.d.ts +730 -0
- package/dist/knowledge-source-sync.d.ts +60 -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 +23 -9
- package/dist/schema.d.ts +24925 -13697
- package/dist/schema.js +103 -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 +42 -5
- package/dist/session-realtime-ledger.d.ts +3 -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/0240_model_context_user_messages.sql +204 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0243_google_drive_object_acl_authority.sql +554 -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-artifact-durable-export.ts +27 -0
- 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 +12001 -1699
- 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/knowledge-source-sync-schema.ts +83 -0
- package/src/knowledge-source-sync.ts +530 -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 +931 -24
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1315 -52
- package/src/schema.ts +3336 -438
- 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 +450 -98
- package/src/session-realtime-context.ts +19 -3
- package/src/session-realtime-ledger.ts +75 -12
- 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-5KTIEDX7.js.map +0 -1
- package/dist/chunk-FPVAD4CO.js +0 -117
- package/dist/chunk-FPVAD4CO.js.map +0 -1
- package/dist/chunk-HSOWSYOX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-VKLB2ZGI.js +0 -2389
- package/dist/chunk-VKLB2ZGI.js.map +0 -1
- package/dist/chunk-Z7VYMNPZ.js.map +0 -1
- /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
- /package/dist/{chunk-VTPRIXKG.js.map → chunk-NJVZPWXY.js.map} +0 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Durable session-owned background commands. The command row is the
|
|
3
|
+
-- provider-neutral lifecycle/control authority; managed commands link one-to-one
|
|
4
|
+
-- to the exact retained process that still owns immutable launch authority.
|
|
5
|
+
SET LOCAL lock_timeout = '5s';
|
|
6
|
+
SET LOCAL statement_timeout = '10min';
|
|
7
|
+
|
|
8
|
+
CREATE TABLE session_background_commands (
|
|
9
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
10
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
11
|
+
workspace_id uuid NOT NULL,
|
|
12
|
+
session_id uuid NOT NULL,
|
|
13
|
+
provider text NOT NULL,
|
|
14
|
+
state text NOT NULL DEFAULT 'running',
|
|
15
|
+
retained_process_id uuid,
|
|
16
|
+
control_workspace_id uuid,
|
|
17
|
+
enrollment_id uuid,
|
|
18
|
+
connection_instance_id text,
|
|
19
|
+
op_id text,
|
|
20
|
+
command_preview text NOT NULL DEFAULT '',
|
|
21
|
+
cancel_requested_at timestamptz,
|
|
22
|
+
cancel_requested_by text,
|
|
23
|
+
exit_code integer,
|
|
24
|
+
settlement_reason text,
|
|
25
|
+
started_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
26
|
+
settled_at timestamptz,
|
|
27
|
+
reconcile_after timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
28
|
+
reconcile_claim_id uuid,
|
|
29
|
+
reconcile_claimed_at timestamptz,
|
|
30
|
+
reconcile_attempts integer NOT NULL DEFAULT 0,
|
|
31
|
+
last_reconcile_outcome text,
|
|
32
|
+
reconcile_proof_outcome text,
|
|
33
|
+
reconcile_proof_exit_code integer,
|
|
34
|
+
reconcile_proof_reason text,
|
|
35
|
+
reconcile_proof_observed_at timestamptz,
|
|
36
|
+
updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
37
|
+
CONSTRAINT session_background_commands_workspace_fk
|
|
38
|
+
FOREIGN KEY (workspace_id, account_id)
|
|
39
|
+
REFERENCES workspaces(id, account_id) ON DELETE CASCADE,
|
|
40
|
+
CONSTRAINT session_background_commands_session_fk
|
|
41
|
+
FOREIGN KEY (workspace_id, session_id)
|
|
42
|
+
REFERENCES sessions(workspace_id, id) ON DELETE CASCADE,
|
|
43
|
+
CONSTRAINT session_background_commands_control_workspace_fk
|
|
44
|
+
FOREIGN KEY (control_workspace_id, account_id)
|
|
45
|
+
REFERENCES workspaces(id, account_id) ON DELETE RESTRICT,
|
|
46
|
+
CONSTRAINT session_background_commands_process_fk
|
|
47
|
+
FOREIGN KEY (retained_process_id)
|
|
48
|
+
REFERENCES sandbox_retained_processes(id) ON DELETE RESTRICT,
|
|
49
|
+
CONSTRAINT session_background_commands_provider_check CHECK (
|
|
50
|
+
provider IN ('managed', 'connected_machine')
|
|
51
|
+
),
|
|
52
|
+
CONSTRAINT session_background_commands_state_check CHECK (
|
|
53
|
+
state IN ('running', 'stopping', 'exited', 'lost')
|
|
54
|
+
),
|
|
55
|
+
CONSTRAINT session_background_commands_provider_identity_check CHECK (
|
|
56
|
+
(
|
|
57
|
+
provider = 'managed'
|
|
58
|
+
AND retained_process_id IS NOT NULL
|
|
59
|
+
AND control_workspace_id IS NULL
|
|
60
|
+
AND enrollment_id IS NULL
|
|
61
|
+
AND connection_instance_id IS NULL
|
|
62
|
+
AND op_id IS NULL
|
|
63
|
+
) OR (
|
|
64
|
+
provider = 'connected_machine'
|
|
65
|
+
AND retained_process_id IS NULL
|
|
66
|
+
AND control_workspace_id IS NOT NULL
|
|
67
|
+
AND enrollment_id IS NOT NULL
|
|
68
|
+
AND connection_instance_id IS NOT NULL
|
|
69
|
+
AND octet_length(connection_instance_id) BETWEEN 1 AND 128
|
|
70
|
+
AND op_id IS NOT NULL
|
|
71
|
+
AND octet_length(op_id) BETWEEN 1 AND 256
|
|
72
|
+
)
|
|
73
|
+
),
|
|
74
|
+
CONSTRAINT session_background_commands_lifecycle_check CHECK (
|
|
75
|
+
(
|
|
76
|
+
state = 'running'
|
|
77
|
+
AND cancel_requested_at IS NULL
|
|
78
|
+
AND cancel_requested_by IS NULL
|
|
79
|
+
AND exit_code IS NULL
|
|
80
|
+
AND settlement_reason IS NULL
|
|
81
|
+
AND settled_at IS NULL
|
|
82
|
+
) OR (
|
|
83
|
+
state = 'stopping'
|
|
84
|
+
AND cancel_requested_at IS NOT NULL
|
|
85
|
+
AND cancel_requested_by IS NOT NULL
|
|
86
|
+
AND octet_length(btrim(cancel_requested_by)) BETWEEN 1 AND 1024
|
|
87
|
+
AND exit_code IS NULL
|
|
88
|
+
AND settlement_reason IS NULL
|
|
89
|
+
AND settled_at IS NULL
|
|
90
|
+
) OR (
|
|
91
|
+
state = 'exited'
|
|
92
|
+
AND settled_at IS NOT NULL
|
|
93
|
+
AND octet_length(btrim(settlement_reason)) BETWEEN 1 AND 512
|
|
94
|
+
) OR (
|
|
95
|
+
state = 'lost'
|
|
96
|
+
AND exit_code IS NULL
|
|
97
|
+
AND settled_at IS NOT NULL
|
|
98
|
+
AND octet_length(btrim(settlement_reason)) BETWEEN 1 AND 512
|
|
99
|
+
)
|
|
100
|
+
),
|
|
101
|
+
CONSTRAINT session_background_commands_preview_check CHECK (
|
|
102
|
+
octet_length(command_preview) <= 2048
|
|
103
|
+
),
|
|
104
|
+
CONSTRAINT session_background_commands_reconcile_check CHECK (
|
|
105
|
+
reconcile_attempts >= 0
|
|
106
|
+
AND (
|
|
107
|
+
(reconcile_claim_id IS NULL AND reconcile_claimed_at IS NULL)
|
|
108
|
+
OR (reconcile_claim_id IS NOT NULL AND reconcile_claimed_at IS NOT NULL)
|
|
109
|
+
)
|
|
110
|
+
AND (
|
|
111
|
+
last_reconcile_outcome IS NULL
|
|
112
|
+
OR octet_length(last_reconcile_outcome) BETWEEN 1 AND 64
|
|
113
|
+
)
|
|
114
|
+
AND (
|
|
115
|
+
(
|
|
116
|
+
reconcile_proof_outcome IS NULL
|
|
117
|
+
AND reconcile_proof_exit_code IS NULL
|
|
118
|
+
AND reconcile_proof_reason IS NULL
|
|
119
|
+
AND reconcile_proof_observed_at IS NULL
|
|
120
|
+
) OR (
|
|
121
|
+
reconcile_proof_outcome = 'exited'
|
|
122
|
+
AND reconcile_proof_exit_code IS NOT NULL
|
|
123
|
+
AND octet_length(btrim(reconcile_proof_reason)) BETWEEN 1 AND 512
|
|
124
|
+
AND reconcile_proof_observed_at IS NOT NULL
|
|
125
|
+
) OR (
|
|
126
|
+
reconcile_proof_outcome = 'lost'
|
|
127
|
+
AND reconcile_proof_exit_code IS NULL
|
|
128
|
+
AND octet_length(btrim(reconcile_proof_reason)) BETWEEN 1 AND 512
|
|
129
|
+
AND reconcile_proof_observed_at IS NOT NULL
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
CREATE UNIQUE INDEX session_background_commands_process_uq
|
|
136
|
+
ON session_background_commands (retained_process_id)
|
|
137
|
+
WHERE retained_process_id IS NOT NULL;
|
|
138
|
+
CREATE UNIQUE INDEX session_background_commands_connected_op_uq
|
|
139
|
+
ON session_background_commands (
|
|
140
|
+
control_workspace_id, enrollment_id, connection_instance_id, op_id
|
|
141
|
+
) WHERE provider = 'connected_machine';
|
|
142
|
+
CREATE INDEX session_background_commands_active_session_idx
|
|
143
|
+
ON session_background_commands (workspace_id, session_id, state, started_at, id)
|
|
144
|
+
WHERE state IN ('running', 'stopping');
|
|
145
|
+
CREATE INDEX session_background_commands_stopping_idx
|
|
146
|
+
ON session_background_commands (reconcile_after, cancel_requested_at, id)
|
|
147
|
+
WHERE state IN ('running', 'stopping');
|
|
148
|
+
|
|
149
|
+
ALTER TABLE session_background_commands ENABLE ROW LEVEL SECURITY;
|
|
150
|
+
ALTER TABLE session_background_commands FORCE ROW LEVEL SECURITY;
|
|
151
|
+
CREATE POLICY workspace_isolation ON session_background_commands
|
|
152
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
153
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
154
|
+
CREATE POLICY session_visibility_isolation ON session_background_commands AS RESTRICTIVE
|
|
155
|
+
USING (session_reference_visible(account_id, workspace_id, session_id))
|
|
156
|
+
WITH CHECK (session_reference_visible(account_id, workspace_id, session_id));
|
|
157
|
+
|
|
158
|
+
DO $grants$
|
|
159
|
+
DECLARE data_schema text := current_schema();
|
|
160
|
+
BEGIN
|
|
161
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
162
|
+
EXECUTE format(
|
|
163
|
+
'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE %I.session_background_commands TO opengeni_app',
|
|
164
|
+
data_schema
|
|
165
|
+
);
|
|
166
|
+
END IF;
|
|
167
|
+
END
|
|
168
|
+
$grants$;
|
|
169
|
+
|
|
170
|
+
COMMENT ON TABLE session_background_commands IS
|
|
171
|
+
'Provider-neutral durable lifecycle for commands explicitly transferred from a turn to its session.';
|
|
172
|
+
COMMENT ON COLUMN session_background_commands.retained_process_id IS
|
|
173
|
+
'Managed provider link. The retained process preserves immutable launch authority and exact provider identity.';
|
|
174
|
+
COMMENT ON COLUMN session_background_commands.connection_instance_id IS
|
|
175
|
+
'Connected Machine daemon instance admitted at launch; switching the session machine never rewrites it.';
|
|
176
|
+
COMMENT ON COLUMN session_background_commands.control_workspace_id IS
|
|
177
|
+
'Connected Machine origin workspace used in the exact physical NATS subject; never rewritten from the session workspace.';
|
|
178
|
+
|
|
179
|
+
-- Workspace deletion takes the application-level background-command prefix
|
|
180
|
+
-- before its parent rows. These SECURITY DEFINER seams can therefore inspect
|
|
181
|
+
-- cross-workspace origin references without weakening ordinary workspace RLS:
|
|
182
|
+
-- active authority is checked before any other deletion work, while terminal
|
|
183
|
+
-- history is pruned only at the final successful cascade boundary.
|
|
184
|
+
DO $workspace_delete_function$
|
|
185
|
+
DECLARE data_schema text := current_schema();
|
|
186
|
+
BEGIN
|
|
187
|
+
EXECUTE format($create$
|
|
188
|
+
CREATE FUNCTION opengeni_private.prepare_workspace_background_command_deletion(
|
|
189
|
+
p_account_id uuid,
|
|
190
|
+
p_workspace_id uuid
|
|
191
|
+
)
|
|
192
|
+
RETURNS integer
|
|
193
|
+
LANGUAGE plpgsql
|
|
194
|
+
SECURITY DEFINER
|
|
195
|
+
SET search_path = pg_catalog
|
|
196
|
+
AS $function$
|
|
197
|
+
DECLARE
|
|
198
|
+
active_count integer := 0;
|
|
199
|
+
BEGIN
|
|
200
|
+
IF pg_catalog.current_setting('opengeni.account_id', true)
|
|
201
|
+
IS DISTINCT FROM p_account_id::text
|
|
202
|
+
OR pg_catalog.current_setting('opengeni.workspace_id', true)
|
|
203
|
+
IS DISTINCT FROM p_workspace_id::text THEN
|
|
204
|
+
RAISE EXCEPTION 'workspace background-command deletion scope mismatch'
|
|
205
|
+
USING ERRCODE = '42501';
|
|
206
|
+
END IF;
|
|
207
|
+
|
|
208
|
+
BEGIN
|
|
209
|
+
PERFORM command.id
|
|
210
|
+
FROM %1$I.session_background_commands command
|
|
211
|
+
WHERE command.account_id = p_account_id
|
|
212
|
+
AND command.state IN ('running', 'stopping')
|
|
213
|
+
AND (
|
|
214
|
+
command.workspace_id = p_workspace_id
|
|
215
|
+
OR command.control_workspace_id = p_workspace_id
|
|
216
|
+
)
|
|
217
|
+
ORDER BY command.id
|
|
218
|
+
FOR UPDATE NOWAIT;
|
|
219
|
+
GET DIAGNOSTICS active_count = ROW_COUNT;
|
|
220
|
+
EXCEPTION WHEN lock_not_available THEN
|
|
221
|
+
-- A reconciler currently owns lifecycle proof for a matching command;
|
|
222
|
+
-- deletion remains blocked rather than waiting or losing its locator.
|
|
223
|
+
RETURN 1;
|
|
224
|
+
END;
|
|
225
|
+
|
|
226
|
+
RETURN active_count;
|
|
227
|
+
END
|
|
228
|
+
$function$;
|
|
229
|
+
$create$, data_schema);
|
|
230
|
+
END
|
|
231
|
+
$workspace_delete_function$;
|
|
232
|
+
|
|
233
|
+
DO $workspace_prune_function$
|
|
234
|
+
DECLARE data_schema text := current_schema();
|
|
235
|
+
BEGIN
|
|
236
|
+
EXECUTE format($create$
|
|
237
|
+
CREATE FUNCTION opengeni_private.prune_settled_cross_workspace_background_commands(
|
|
238
|
+
p_account_id uuid,
|
|
239
|
+
p_workspace_id uuid
|
|
240
|
+
)
|
|
241
|
+
RETURNS integer
|
|
242
|
+
LANGUAGE plpgsql
|
|
243
|
+
SECURITY DEFINER
|
|
244
|
+
SET search_path = pg_catalog
|
|
245
|
+
AS $function$
|
|
246
|
+
DECLARE
|
|
247
|
+
deleted_count integer := 0;
|
|
248
|
+
BEGIN
|
|
249
|
+
IF pg_catalog.current_setting('opengeni.account_id', true)
|
|
250
|
+
IS DISTINCT FROM p_account_id::text
|
|
251
|
+
OR pg_catalog.current_setting('opengeni.workspace_id', true)
|
|
252
|
+
IS DISTINCT FROM p_workspace_id::text THEN
|
|
253
|
+
RAISE EXCEPTION 'workspace background-command deletion scope mismatch'
|
|
254
|
+
USING ERRCODE = '42501';
|
|
255
|
+
END IF;
|
|
256
|
+
|
|
257
|
+
DELETE FROM %1$I.session_background_commands command
|
|
258
|
+
WHERE command.account_id = p_account_id
|
|
259
|
+
AND command.control_workspace_id = p_workspace_id
|
|
260
|
+
AND command.workspace_id <> p_workspace_id
|
|
261
|
+
AND command.state IN ('exited', 'lost');
|
|
262
|
+
GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
|
263
|
+
RETURN deleted_count;
|
|
264
|
+
END
|
|
265
|
+
$function$;
|
|
266
|
+
$create$, data_schema);
|
|
267
|
+
END
|
|
268
|
+
$workspace_prune_function$;
|
|
269
|
+
|
|
270
|
+
REVOKE ALL ON FUNCTION opengeni_private.prepare_workspace_background_command_deletion(
|
|
271
|
+
uuid, uuid
|
|
272
|
+
) FROM PUBLIC;
|
|
273
|
+
REVOKE ALL ON FUNCTION opengeni_private.prune_settled_cross_workspace_background_commands(
|
|
274
|
+
uuid, uuid
|
|
275
|
+
) FROM PUBLIC;
|
|
276
|
+
|
|
277
|
+
DO $workspace_delete_grant$
|
|
278
|
+
BEGIN
|
|
279
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
280
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.prepare_workspace_background_command_deletion(
|
|
281
|
+
uuid, uuid
|
|
282
|
+
) TO opengeni_app;
|
|
283
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.prune_settled_cross_workspace_background_commands(
|
|
284
|
+
uuid, uuid
|
|
285
|
+
) TO opengeni_app;
|
|
286
|
+
END IF;
|
|
287
|
+
END
|
|
288
|
+
$workspace_delete_grant$;
|
|
289
|
+
|
|
290
|
+
DO $settlement_function$
|
|
291
|
+
DECLARE data_schema text := current_schema();
|
|
292
|
+
BEGIN
|
|
293
|
+
EXECUTE format($create$
|
|
294
|
+
CREATE FUNCTION opengeni_private.settle_background_command_from_retained_process()
|
|
295
|
+
RETURNS trigger
|
|
296
|
+
LANGUAGE plpgsql
|
|
297
|
+
SET search_path = pg_catalog
|
|
298
|
+
AS $function$
|
|
299
|
+
BEGIN
|
|
300
|
+
IF OLD.state = 'active' AND NEW.state IN ('exited', 'lost') THEN
|
|
301
|
+
UPDATE %1$I.session_background_commands command SET
|
|
302
|
+
state = NEW.state,
|
|
303
|
+
exit_code = CASE WHEN NEW.state = 'exited' THEN NEW.exit_code ELSE NULL END,
|
|
304
|
+
settlement_reason = NEW.settlement_reason,
|
|
305
|
+
settled_at = NEW.settled_at,
|
|
306
|
+
reconcile_claim_id = NULL,
|
|
307
|
+
reconcile_claimed_at = NULL,
|
|
308
|
+
last_reconcile_outcome = 'settled_' || NEW.state,
|
|
309
|
+
updated_at = pg_catalog.clock_timestamp()
|
|
310
|
+
WHERE command.retained_process_id = NEW.id
|
|
311
|
+
AND command.state IN ('running', 'stopping');
|
|
312
|
+
END IF;
|
|
313
|
+
RETURN NEW;
|
|
314
|
+
END
|
|
315
|
+
$function$;
|
|
316
|
+
$create$, data_schema);
|
|
317
|
+
END
|
|
318
|
+
$settlement_function$;
|
|
319
|
+
|
|
320
|
+
CREATE TRIGGER settle_background_command_from_retained_process
|
|
321
|
+
AFTER UPDATE OF state, exit_code, settlement_reason, settled_at
|
|
322
|
+
ON sandbox_retained_processes
|
|
323
|
+
FOR EACH ROW
|
|
324
|
+
EXECUTE FUNCTION opengeni_private.settle_background_command_from_retained_process();
|
|
325
|
+
|
|
326
|
+
REVOKE ALL ON FUNCTION opengeni_private.settle_background_command_from_retained_process()
|
|
327
|
+
FROM PUBLIC;
|
|
328
|
+
|
|
329
|
+
-- Background-owned managed processes remain eligible for exact polling even
|
|
330
|
+
-- while their launch attempt is open/closed independently. Stopping state is
|
|
331
|
+
-- projected through owner_state so the reaper can issue one exact cancellation
|
|
332
|
+
-- before observing terminal proof.
|
|
333
|
+
DO $claim_function$
|
|
334
|
+
DECLARE data_schema text := current_schema();
|
|
335
|
+
BEGIN
|
|
336
|
+
EXECUTE format($create$
|
|
337
|
+
CREATE OR REPLACE FUNCTION opengeni_private.claim_terminal_retained_processes(
|
|
338
|
+
p_claim_id uuid,
|
|
339
|
+
p_limit integer,
|
|
340
|
+
p_claim_ttl_ms bigint
|
|
341
|
+
)
|
|
342
|
+
RETURNS TABLE (
|
|
343
|
+
account_id uuid,
|
|
344
|
+
workspace_id uuid,
|
|
345
|
+
session_id uuid,
|
|
346
|
+
process_id uuid,
|
|
347
|
+
claim_id uuid,
|
|
348
|
+
owner_state text,
|
|
349
|
+
owner_attempt_outcome text
|
|
350
|
+
)
|
|
351
|
+
LANGUAGE plpgsql
|
|
352
|
+
SECURITY DEFINER
|
|
353
|
+
SET search_path = pg_catalog
|
|
354
|
+
AS $function$
|
|
355
|
+
BEGIN
|
|
356
|
+
IF p_limit < 1 OR p_limit > 100 THEN
|
|
357
|
+
RAISE EXCEPTION 'retained-process reconciliation limit must be between 1 and 100'
|
|
358
|
+
USING ERRCODE = '22023';
|
|
359
|
+
END IF;
|
|
360
|
+
IF p_claim_ttl_ms < 0 OR p_claim_ttl_ms > 3600000 THEN
|
|
361
|
+
RAISE EXCEPTION 'retained-process reconciliation claim TTL is invalid'
|
|
362
|
+
USING ERRCODE = '22023';
|
|
363
|
+
END IF;
|
|
364
|
+
|
|
365
|
+
PERFORM pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2', '1', true);
|
|
366
|
+
|
|
367
|
+
RETURN QUERY
|
|
368
|
+
WITH candidate_window AS MATERIALIZED (
|
|
369
|
+
SELECT process.id,
|
|
370
|
+
process.workspace_id,
|
|
371
|
+
process.parent_admission_id,
|
|
372
|
+
process.owner_actor_kind,
|
|
373
|
+
process.owner_turn_id,
|
|
374
|
+
process.owner_attempt_id,
|
|
375
|
+
process.reconcile_after AS due_at,
|
|
376
|
+
process.started_at
|
|
377
|
+
FROM %1$I.sandbox_retained_processes process
|
|
378
|
+
WHERE process.state = 'active'
|
|
379
|
+
AND process.reconcile_after <= pg_catalog.now()
|
|
380
|
+
ORDER BY process.reconcile_after, process.started_at, process.id
|
|
381
|
+
FOR UPDATE OF process SKIP LOCKED
|
|
382
|
+
LIMIT p_limit
|
|
383
|
+
), classified AS MATERIALIZED (
|
|
384
|
+
SELECT candidate.id,
|
|
385
|
+
candidate.due_at,
|
|
386
|
+
candidate.started_at,
|
|
387
|
+
command.state AS command_state,
|
|
388
|
+
command.id IS NOT NULL OR CASE
|
|
389
|
+
WHEN candidate.owner_actor_kind = 'direct' THEN direct_owner.live IS NULL
|
|
390
|
+
ELSE attempt.state = 'closed'
|
|
391
|
+
END AS eligible,
|
|
392
|
+
CASE
|
|
393
|
+
WHEN command.state = 'stopping' THEN 'background_stopping'
|
|
394
|
+
WHEN command.state = 'running' THEN 'background_running'
|
|
395
|
+
WHEN candidate.owner_actor_kind = 'direct' THEN 'direct'
|
|
396
|
+
ELSE COALESCE(turn_row.status, 'missing')
|
|
397
|
+
END AS owner_state,
|
|
398
|
+
attempt.outcome AS owner_attempt_outcome
|
|
399
|
+
FROM candidate_window candidate
|
|
400
|
+
LEFT JOIN %1$I.session_background_commands command
|
|
401
|
+
ON command.retained_process_id = candidate.id
|
|
402
|
+
AND command.state IN ('running', 'stopping')
|
|
403
|
+
LEFT JOIN LATERAL (
|
|
404
|
+
SELECT true AS live
|
|
405
|
+
FROM %1$I.sandbox_workspace_mutation_admissions admission
|
|
406
|
+
JOIN %1$I.sandbox_lease_holders holder
|
|
407
|
+
ON holder.lease_id = admission.lease_id
|
|
408
|
+
AND holder.account_id = admission.account_id
|
|
409
|
+
AND holder.workspace_id = admission.workspace_id
|
|
410
|
+
AND holder.kind = 'direct'
|
|
411
|
+
AND holder.holder_id = admission.holder_id
|
|
412
|
+
AND holder.subject_id = admission.session_id
|
|
413
|
+
WHERE candidate.owner_actor_kind = 'direct'
|
|
414
|
+
AND admission.id = candidate.parent_admission_id
|
|
415
|
+
AND admission.actor_kind = 'direct'
|
|
416
|
+
LIMIT 1
|
|
417
|
+
) direct_owner ON true
|
|
418
|
+
LEFT JOIN LATERAL (
|
|
419
|
+
SELECT source_turn.status
|
|
420
|
+
FROM %1$I.session_turns source_turn
|
|
421
|
+
WHERE source_turn.workspace_id = candidate.workspace_id
|
|
422
|
+
AND source_turn.id = candidate.owner_turn_id
|
|
423
|
+
LIMIT 1
|
|
424
|
+
) turn_row ON true
|
|
425
|
+
LEFT JOIN LATERAL (
|
|
426
|
+
SELECT source_attempt.state, source_attempt.outcome
|
|
427
|
+
FROM %1$I.session_turn_attempts source_attempt
|
|
428
|
+
WHERE source_attempt.workspace_id = candidate.workspace_id
|
|
429
|
+
AND source_attempt.id = candidate.owner_attempt_id
|
|
430
|
+
LIMIT 1
|
|
431
|
+
) attempt ON true
|
|
432
|
+
), inspected AS (
|
|
433
|
+
UPDATE %1$I.sandbox_retained_processes process SET
|
|
434
|
+
reconcile_after = CASE
|
|
435
|
+
WHEN classified.eligible THEN pg_catalog.now()
|
|
436
|
+
+ pg_catalog.make_interval(secs => p_claim_ttl_ms / 1000.0)
|
|
437
|
+
ELSE pg_catalog.now() + interval '30 seconds'
|
|
438
|
+
END,
|
|
439
|
+
reconcile_claim_id = CASE WHEN classified.eligible THEN p_claim_id ELSE NULL END,
|
|
440
|
+
reconcile_claimed_at = CASE
|
|
441
|
+
WHEN classified.eligible THEN pg_catalog.now() ELSE NULL
|
|
442
|
+
END,
|
|
443
|
+
reconcile_attempts = process.reconcile_attempts
|
|
444
|
+
+ CASE WHEN classified.eligible THEN 1 ELSE 0 END,
|
|
445
|
+
last_reconcile_outcome = CASE
|
|
446
|
+
WHEN classified.eligible THEN 'claimed' ELSE 'owner_active'
|
|
447
|
+
END
|
|
448
|
+
FROM classified
|
|
449
|
+
WHERE process.id = classified.id
|
|
450
|
+
AND process.state = 'active'
|
|
451
|
+
RETURNING process.account_id,
|
|
452
|
+
process.workspace_id,
|
|
453
|
+
process.session_id,
|
|
454
|
+
process.id,
|
|
455
|
+
process.reconcile_claim_id,
|
|
456
|
+
classified.due_at,
|
|
457
|
+
classified.started_at,
|
|
458
|
+
classified.eligible,
|
|
459
|
+
classified.owner_state,
|
|
460
|
+
classified.owner_attempt_outcome
|
|
461
|
+
)
|
|
462
|
+
SELECT inspected.account_id,
|
|
463
|
+
inspected.workspace_id,
|
|
464
|
+
inspected.session_id,
|
|
465
|
+
inspected.id,
|
|
466
|
+
inspected.reconcile_claim_id,
|
|
467
|
+
inspected.owner_state,
|
|
468
|
+
inspected.owner_attempt_outcome
|
|
469
|
+
FROM inspected
|
|
470
|
+
WHERE inspected.eligible
|
|
471
|
+
ORDER BY inspected.due_at, inspected.started_at, inspected.id;
|
|
472
|
+
|
|
473
|
+
SET CONSTRAINTS %1$I.sandbox_retained_processes_identity_v2 IMMEDIATE;
|
|
474
|
+
SET CONSTRAINTS %1$I.sandbox_retained_processes_identity_v2 DEFERRED;
|
|
475
|
+
END;
|
|
476
|
+
$function$;
|
|
477
|
+
$create$, data_schema);
|
|
478
|
+
END
|
|
479
|
+
$claim_function$;
|
|
480
|
+
|
|
481
|
+
-- Connected Machine commands are reconciled directly against the immutable
|
|
482
|
+
-- launch locator. Claim expiry recovers a dead reaper only; it is never treated
|
|
483
|
+
-- as provider exit/loss evidence.
|
|
484
|
+
DO $connected_claim_function$
|
|
485
|
+
DECLARE data_schema text := current_schema();
|
|
486
|
+
BEGIN
|
|
487
|
+
EXECUTE format($create$
|
|
488
|
+
CREATE FUNCTION opengeni_private.claim_connected_machine_background_commands(
|
|
489
|
+
p_claim_id uuid,
|
|
490
|
+
p_limit integer,
|
|
491
|
+
p_claim_ttl_ms bigint
|
|
492
|
+
)
|
|
493
|
+
RETURNS TABLE (
|
|
494
|
+
account_id uuid,
|
|
495
|
+
workspace_id uuid,
|
|
496
|
+
session_id uuid,
|
|
497
|
+
command_id uuid,
|
|
498
|
+
claim_id uuid,
|
|
499
|
+
command_state text,
|
|
500
|
+
control_workspace_id uuid,
|
|
501
|
+
enrollment_id uuid,
|
|
502
|
+
connection_instance_id text,
|
|
503
|
+
op_id text,
|
|
504
|
+
reconcile_attempts integer,
|
|
505
|
+
reconcile_proof_outcome text,
|
|
506
|
+
reconcile_proof_exit_code integer,
|
|
507
|
+
reconcile_proof_reason text,
|
|
508
|
+
reconcile_proof_observed_at timestamptz
|
|
509
|
+
)
|
|
510
|
+
LANGUAGE plpgsql
|
|
511
|
+
SECURITY DEFINER
|
|
512
|
+
SET search_path = pg_catalog
|
|
513
|
+
AS $function$
|
|
514
|
+
BEGIN
|
|
515
|
+
IF p_limit < 1 OR p_limit > 100 THEN
|
|
516
|
+
RAISE EXCEPTION 'connected-command reconciliation limit must be between 1 and 100'
|
|
517
|
+
USING ERRCODE = '22023';
|
|
518
|
+
END IF;
|
|
519
|
+
IF p_claim_ttl_ms < 0 OR p_claim_ttl_ms > 3600000 THEN
|
|
520
|
+
RAISE EXCEPTION 'connected-command reconciliation claim TTL is invalid'
|
|
521
|
+
USING ERRCODE = '22023';
|
|
522
|
+
END IF;
|
|
523
|
+
|
|
524
|
+
RETURN QUERY
|
|
525
|
+
WITH candidates AS MATERIALIZED (
|
|
526
|
+
SELECT command.id, command.reconcile_after, command.started_at
|
|
527
|
+
FROM %1$I.session_background_commands command
|
|
528
|
+
WHERE command.provider = 'connected_machine'
|
|
529
|
+
AND command.state IN ('running', 'stopping')
|
|
530
|
+
AND command.reconcile_after <= pg_catalog.now()
|
|
531
|
+
AND (
|
|
532
|
+
command.reconcile_claim_id IS NULL
|
|
533
|
+
OR command.reconcile_claimed_at <= pg_catalog.now()
|
|
534
|
+
- pg_catalog.make_interval(secs => p_claim_ttl_ms / 1000.0)
|
|
535
|
+
)
|
|
536
|
+
ORDER BY command.reconcile_after, command.started_at, command.id
|
|
537
|
+
FOR UPDATE OF command SKIP LOCKED
|
|
538
|
+
LIMIT p_limit
|
|
539
|
+
), claimed AS (
|
|
540
|
+
UPDATE %1$I.session_background_commands command SET
|
|
541
|
+
reconcile_after = pg_catalog.now()
|
|
542
|
+
+ pg_catalog.make_interval(secs => p_claim_ttl_ms / 1000.0),
|
|
543
|
+
reconcile_claim_id = p_claim_id,
|
|
544
|
+
reconcile_claimed_at = pg_catalog.now(),
|
|
545
|
+
reconcile_attempts = command.reconcile_attempts + 1,
|
|
546
|
+
last_reconcile_outcome = 'claimed',
|
|
547
|
+
updated_at = pg_catalog.clock_timestamp()
|
|
548
|
+
FROM candidates
|
|
549
|
+
WHERE command.id = candidates.id
|
|
550
|
+
AND command.provider = 'connected_machine'
|
|
551
|
+
AND command.state IN ('running', 'stopping')
|
|
552
|
+
RETURNING command.*, candidates.reconcile_after AS due_at,
|
|
553
|
+
candidates.started_at AS candidate_started_at
|
|
554
|
+
)
|
|
555
|
+
SELECT claimed.account_id,
|
|
556
|
+
claimed.workspace_id,
|
|
557
|
+
claimed.session_id,
|
|
558
|
+
claimed.id,
|
|
559
|
+
claimed.reconcile_claim_id,
|
|
560
|
+
claimed.state,
|
|
561
|
+
claimed.control_workspace_id,
|
|
562
|
+
claimed.enrollment_id,
|
|
563
|
+
claimed.connection_instance_id,
|
|
564
|
+
claimed.op_id,
|
|
565
|
+
claimed.reconcile_attempts,
|
|
566
|
+
claimed.reconcile_proof_outcome,
|
|
567
|
+
claimed.reconcile_proof_exit_code,
|
|
568
|
+
claimed.reconcile_proof_reason,
|
|
569
|
+
claimed.reconcile_proof_observed_at
|
|
570
|
+
FROM claimed
|
|
571
|
+
ORDER BY claimed.due_at, claimed.candidate_started_at, claimed.id;
|
|
572
|
+
END;
|
|
573
|
+
$function$;
|
|
574
|
+
$create$, data_schema);
|
|
575
|
+
END
|
|
576
|
+
$connected_claim_function$;
|
|
577
|
+
|
|
578
|
+
REVOKE ALL ON FUNCTION opengeni_private.claim_connected_machine_background_commands(
|
|
579
|
+
uuid, integer, bigint
|
|
580
|
+
) FROM PUBLIC;
|
|
581
|
+
|
|
582
|
+
DO $connected_claim_grant$
|
|
583
|
+
BEGIN
|
|
584
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
585
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.claim_connected_machine_background_commands(
|
|
586
|
+
uuid, integer, bigint
|
|
587
|
+
) TO opengeni_app;
|
|
588
|
+
END IF;
|
|
589
|
+
END
|
|
590
|
+
$connected_claim_grant$;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Slack delivery eligibility is decided by this SECURITY DEFINER claim before
|
|
3
|
+
-- the pump ever reads a page. A blocked child worker announces itself on its
|
|
4
|
+
-- Slack-originated parent as system.update.pending, and a budget or
|
|
5
|
+
-- continuation-cap goal pause as goal.paused, so both types must arm a claim.
|
|
6
|
+
-- The pump still decides what is worth posting: only a child_requires_action
|
|
7
|
+
-- notice and a limits / max_auto_continuations pause produce a message.
|
|
8
|
+
-- Rolling-safe: an old API image simply drains the extra claim without posting.
|
|
9
|
+
|
|
10
|
+
SET lock_timeout = '5s';
|
|
11
|
+
SET statement_timeout = '10min';
|
|
12
|
+
|
|
13
|
+
DO $migration$
|
|
14
|
+
DECLARE data_schema text := current_schema();
|
|
15
|
+
BEGIN
|
|
16
|
+
EXECUTE format($ddl$
|
|
17
|
+
CREATE OR REPLACE FUNCTION opengeni_private.claim_slack_interaction_delivery(
|
|
18
|
+
p_holder uuid,
|
|
19
|
+
p_lease_ms integer
|
|
20
|
+
)
|
|
21
|
+
RETURNS SETOF %1$I.slack_interactions
|
|
22
|
+
LANGUAGE plpgsql
|
|
23
|
+
SECURITY DEFINER
|
|
24
|
+
SET search_path = pg_catalog
|
|
25
|
+
AS $function$
|
|
26
|
+
BEGIN
|
|
27
|
+
IF p_lease_ms < 1000 OR p_lease_ms > 300000 THEN
|
|
28
|
+
RAISE EXCEPTION 'invalid Slack delivery claim lease';
|
|
29
|
+
END IF;
|
|
30
|
+
RETURN QUERY
|
|
31
|
+
WITH candidate AS (
|
|
32
|
+
SELECT I.id
|
|
33
|
+
FROM %1$I.slack_interactions I
|
|
34
|
+
WHERE I.session_id IS NOT NULL
|
|
35
|
+
AND I.terminal_delivery_state = 'open'
|
|
36
|
+
AND (I.delivery_retry_at IS NULL OR I.delivery_retry_at <= now())
|
|
37
|
+
AND (I.delivery_claim_holder_id IS NULL OR I.delivery_claim_expires_at <= now())
|
|
38
|
+
AND NOT (
|
|
39
|
+
I.visibility = 'private'
|
|
40
|
+
AND I.triggering_provider_event_id LIKE 'shortcut:%%'
|
|
41
|
+
AND I.ack_slack_message_ts IS NULL
|
|
42
|
+
)
|
|
43
|
+
AND EXISTS (
|
|
44
|
+
SELECT 1
|
|
45
|
+
FROM %1$I.session_events E
|
|
46
|
+
WHERE E.workspace_id = I.workspace_id
|
|
47
|
+
AND E.session_id = I.session_id
|
|
48
|
+
AND E.sequence > I.last_delivered_session_event_sequence
|
|
49
|
+
AND E.type IN (
|
|
50
|
+
'agent.message.completed',
|
|
51
|
+
'session.humanInput.requested',
|
|
52
|
+
'turn.completed',
|
|
53
|
+
'turn.failed',
|
|
54
|
+
'turn.cancelled',
|
|
55
|
+
'session.status.changed',
|
|
56
|
+
'system.update.pending',
|
|
57
|
+
'goal.paused'
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
ORDER BY I.delivery_retry_at NULLS FIRST, I.updated_at, I.id
|
|
61
|
+
FOR UPDATE SKIP LOCKED
|
|
62
|
+
LIMIT 1
|
|
63
|
+
)
|
|
64
|
+
UPDATE %1$I.slack_interactions I
|
|
65
|
+
SET delivery_claim_holder_id = p_holder,
|
|
66
|
+
delivery_claim_expires_at = now() + make_interval(secs => p_lease_ms::double precision / 1000),
|
|
67
|
+
delivery_attempt_count = I.delivery_attempt_count + 1,
|
|
68
|
+
updated_at = now()
|
|
69
|
+
FROM candidate C
|
|
70
|
+
WHERE I.id = C.id
|
|
71
|
+
RETURNING I.*;
|
|
72
|
+
END
|
|
73
|
+
$function$
|
|
74
|
+
$ddl$, data_schema);
|
|
75
|
+
END
|
|
76
|
+
$migration$;
|
|
77
|
+
|
|
78
|
+
REVOKE ALL ON FUNCTION opengeni_private.claim_slack_interaction_delivery(uuid, integer)
|
|
79
|
+
FROM PUBLIC;
|
|
80
|
+
|
|
81
|
+
DO $grants$
|
|
82
|
+
BEGIN
|
|
83
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
84
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.claim_slack_interaction_delivery(uuid, integer)
|
|
85
|
+
TO opengeni_app;
|
|
86
|
+
END IF;
|
|
87
|
+
END
|
|
88
|
+
$grants$;
|
|
89
|
+
|
|
90
|
+
RESET statement_timeout;
|
|
91
|
+
RESET lock_timeout;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Human-readable API-key descriptions let workspace administrators record the
|
|
3
|
+
-- intended caller or automation without exposing the secret token. Existing
|
|
4
|
+
-- keys remain valid and return a NULL description.
|
|
5
|
+
SET LOCAL lock_timeout = '5s';
|
|
6
|
+
SET LOCAL statement_timeout = '10min';
|
|
7
|
+
|
|
8
|
+
ALTER TABLE "api_keys"
|
|
9
|
+
ADD COLUMN "description" text;
|
|
10
|
+
|
|
11
|
+
ALTER TABLE "api_keys"
|
|
12
|
+
ADD CONSTRAINT "api_keys_description_check"
|
|
13
|
+
CHECK ("description" IS NULL OR length("description") BETWEEN 1 AND 500)
|
|
14
|
+
NOT VALID;
|
|
15
|
+
|
|
16
|
+
ALTER TABLE "api_keys"
|
|
17
|
+
VALIDATE CONSTRAINT "api_keys_description_check";
|
|
18
|
+
|
|
19
|
+
RESET statement_timeout;
|
|
20
|
+
RESET lock_timeout;
|