@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,856 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Add an explicit, exact-attempt organization-administration path for company
|
|
3
|
+
-- profile proposals. Agents may stage one immutable proposal only for the live
|
|
4
|
+
-- turn's initiating human when that human is the organization's active owner
|
|
5
|
+
-- (the same authority the manual `account:admin` route requires); activation
|
|
6
|
+
-- requires that same human's canonical structured-input confirmation and
|
|
7
|
+
-- records a dedicated receipt.
|
|
8
|
+
--
|
|
9
|
+
-- Lock order (AGENTS.md canonical event-write prefix, migration 0299):
|
|
10
|
+
-- workspaces FOR KEY SHARE
|
|
11
|
+
-- -> organization_memberships FOR KEY SHARE (the 0299 membership seam takes
|
|
12
|
+
-- workspaces, then memberships, then sessions)
|
|
13
|
+
-- -> sessions / session_turns / session_turn_attempts FOR SHARE
|
|
14
|
+
-- -> managed_accounts: propose takes FOR KEY SHARE only; confirm reaches the
|
|
15
|
+
-- organization row FOR UPDATE solely through the nested
|
|
16
|
+
-- company_profile_apply_activation call, AFTER the session prefix.
|
|
17
|
+
-- No lock stronger than managed_accounts FOR KEY SHARE may precede the session
|
|
18
|
+
-- prefix: the canonical event writer holds sessions FOR NO KEY UPDATE and then
|
|
19
|
+
-- reaches managed_accounts FOR KEY SHARE through the session_events account FK,
|
|
20
|
+
-- so an organization-row FOR UPDATE taken before the session rows would form an
|
|
21
|
+
-- ABBA cycle with every concurrent same-session event append.
|
|
22
|
+
-- Residual: the nested company_profile_apply_activation (0201) still takes
|
|
23
|
+
-- managed_accounts FOR UPDATE after the session/turn/attempt FOR SHARE rows,
|
|
24
|
+
-- while the post-0299 membership seam (0263 suspend/offboard) opens
|
|
25
|
+
-- managed_accounts FOR KEY SHARE and then locks the target human's sessions FOR
|
|
26
|
+
-- NO KEY UPDATE; an owner confirming while being suspended/offboarded can
|
|
27
|
+
-- therefore be deadlock-detected (40P01, both sides retry-safe). The fix is
|
|
28
|
+
-- downgrading company_profile_apply_activation to KEY SHARE plus the
|
|
29
|
+
-- organization advisory key in the 0299 style (follow-up).
|
|
30
|
+
--
|
|
31
|
+
-- Idempotency: the propose/confirm input hashes bind account, workspace,
|
|
32
|
+
-- session, logical turn, operation id, content/proposal identity, and the
|
|
33
|
+
-- initiating membership, never the attempt id or execution generation (those
|
|
34
|
+
-- are persisted on the receipt rows). A replacement attempt of the same logical
|
|
35
|
+
-- turn re-issuing the same operation id therefore replays; a confirm retry
|
|
36
|
+
-- under a fresh operation id after a successful activation replays the
|
|
37
|
+
-- existing confirmation for that proposal instead of failing the head CAS.
|
|
38
|
+
|
|
39
|
+
SET LOCAL lock_timeout = '5s';
|
|
40
|
+
SET LOCAL statement_timeout = '10min';
|
|
41
|
+
|
|
42
|
+
ALTER TABLE company_profile_revisions
|
|
43
|
+
ADD CONSTRAINT company_profile_revisions_id_account_uq UNIQUE (id, account_id);
|
|
44
|
+
ALTER TABLE company_profile_activation_events
|
|
45
|
+
ADD CONSTRAINT company_profile_events_id_account_uq UNIQUE (id, account_id);
|
|
46
|
+
ALTER TABLE company_profile_revisions
|
|
47
|
+
DROP CONSTRAINT company_profile_revisions_provenance_chk;
|
|
48
|
+
ALTER TABLE company_profile_revisions
|
|
49
|
+
ADD CONSTRAINT company_profile_revisions_provenance_chk CHECK (
|
|
50
|
+
provenance_source IN ('human', 'agent_admin', 'durable_learning', 'migration')
|
|
51
|
+
AND (
|
|
52
|
+
provenance_source_id IS NULL
|
|
53
|
+
OR length(provenance_source_id) BETWEEN 1 AND 512
|
|
54
|
+
)
|
|
55
|
+
) NOT VALID;
|
|
56
|
+
ALTER TABLE company_profile_revisions
|
|
57
|
+
VALIDATE CONSTRAINT company_profile_revisions_provenance_chk;
|
|
58
|
+
|
|
59
|
+
CREATE TABLE company_profile_agent_proposal_receipts (
|
|
60
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
61
|
+
operation_id uuid NOT NULL,
|
|
62
|
+
input_hash text NOT NULL,
|
|
63
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
64
|
+
workspace_id uuid NOT NULL,
|
|
65
|
+
session_id uuid NOT NULL,
|
|
66
|
+
turn_id uuid NOT NULL,
|
|
67
|
+
creation_attempt_id uuid NOT NULL,
|
|
68
|
+
execution_generation integer NOT NULL,
|
|
69
|
+
initiating_human_subject_id text NOT NULL,
|
|
70
|
+
initiating_membership_id uuid NOT NULL,
|
|
71
|
+
revision_id uuid NOT NULL,
|
|
72
|
+
expected_current_revision_id uuid,
|
|
73
|
+
expected_activation_version bigint NOT NULL,
|
|
74
|
+
reason text NOT NULL,
|
|
75
|
+
human_input jsonb NOT NULL,
|
|
76
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
77
|
+
CONSTRAINT company_profile_agent_proposals_workspace_fk
|
|
78
|
+
FOREIGN KEY (workspace_id, account_id)
|
|
79
|
+
REFERENCES workspaces(id, account_id) ON DELETE CASCADE,
|
|
80
|
+
CONSTRAINT company_profile_agent_proposals_session_fk
|
|
81
|
+
FOREIGN KEY (workspace_id, session_id)
|
|
82
|
+
REFERENCES sessions(workspace_id, id) ON DELETE CASCADE,
|
|
83
|
+
CONSTRAINT company_profile_agent_proposals_turn_fk
|
|
84
|
+
FOREIGN KEY (workspace_id, turn_id)
|
|
85
|
+
REFERENCES session_turns(workspace_id, id) ON DELETE CASCADE,
|
|
86
|
+
CONSTRAINT company_profile_agent_proposals_attempt_fk
|
|
87
|
+
FOREIGN KEY (account_id, workspace_id, session_id, turn_id, creation_attempt_id)
|
|
88
|
+
REFERENCES session_turn_attempts(account_id, workspace_id, session_id, turn_id, id)
|
|
89
|
+
ON DELETE CASCADE,
|
|
90
|
+
CONSTRAINT company_profile_agent_proposals_membership_fk
|
|
91
|
+
FOREIGN KEY (initiating_membership_id, account_id)
|
|
92
|
+
REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
|
|
93
|
+
CONSTRAINT company_profile_agent_proposals_revision_fk
|
|
94
|
+
FOREIGN KEY (revision_id, account_id)
|
|
95
|
+
REFERENCES company_profile_revisions(id, account_id) ON DELETE RESTRICT,
|
|
96
|
+
CONSTRAINT company_profile_agent_proposals_expected_revision_fk
|
|
97
|
+
FOREIGN KEY (expected_current_revision_id, account_id)
|
|
98
|
+
REFERENCES company_profile_revisions(id, account_id) ON DELETE RESTRICT,
|
|
99
|
+
CONSTRAINT company_profile_agent_proposals_input_hash_check CHECK (
|
|
100
|
+
input_hash ~ '^[0-9a-f]{64}$'
|
|
101
|
+
),
|
|
102
|
+
CONSTRAINT company_profile_agent_proposals_generation_check CHECK (
|
|
103
|
+
execution_generation > 0 AND expected_activation_version >= 0
|
|
104
|
+
),
|
|
105
|
+
CONSTRAINT company_profile_agent_proposals_subject_check CHECK (
|
|
106
|
+
octet_length(btrim(initiating_human_subject_id)) BETWEEN 1 AND 1024
|
|
107
|
+
),
|
|
108
|
+
CONSTRAINT company_profile_agent_proposals_reason_check CHECK (
|
|
109
|
+
char_length(btrim(reason)) BETWEEN 1 AND 4096
|
|
110
|
+
AND octet_length(convert_to(btrim(reason), 'UTF8')) <= 16384
|
|
111
|
+
),
|
|
112
|
+
CONSTRAINT company_profile_agent_proposals_human_input_check CHECK (
|
|
113
|
+
jsonb_typeof(human_input) = 'object'
|
|
114
|
+
AND jsonb_array_length(human_input->'questions') = 1
|
|
115
|
+
AND human_input->>'allowSkip' = 'false'
|
|
116
|
+
AND octet_length(human_input::text) <= 49152
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
CREATE UNIQUE INDEX company_profile_agent_proposals_account_operation_uq
|
|
120
|
+
ON company_profile_agent_proposal_receipts (account_id, operation_id);
|
|
121
|
+
CREATE UNIQUE INDEX company_profile_agent_proposals_account_revision_uq
|
|
122
|
+
ON company_profile_agent_proposal_receipts (account_id, revision_id);
|
|
123
|
+
ALTER TABLE company_profile_agent_proposal_receipts
|
|
124
|
+
ADD CONSTRAINT company_profile_agent_proposals_id_account_uq UNIQUE (id, account_id);
|
|
125
|
+
CREATE INDEX company_profile_agent_proposals_turn_idx
|
|
126
|
+
ON company_profile_agent_proposal_receipts (
|
|
127
|
+
workspace_id, session_id, turn_id, execution_generation
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
CREATE TABLE company_profile_agent_confirmation_receipts (
|
|
131
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
132
|
+
operation_id uuid NOT NULL,
|
|
133
|
+
input_hash text NOT NULL,
|
|
134
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
135
|
+
workspace_id uuid NOT NULL,
|
|
136
|
+
session_id uuid NOT NULL,
|
|
137
|
+
turn_id uuid NOT NULL,
|
|
138
|
+
confirmation_attempt_id uuid NOT NULL,
|
|
139
|
+
execution_generation integer NOT NULL,
|
|
140
|
+
proposal_receipt_id uuid NOT NULL,
|
|
141
|
+
proposal_revision_id uuid NOT NULL,
|
|
142
|
+
human_input_request_id uuid NOT NULL,
|
|
143
|
+
approver_subject_id text NOT NULL,
|
|
144
|
+
approver_membership_id uuid NOT NULL,
|
|
145
|
+
activation_event_id uuid NOT NULL,
|
|
146
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
147
|
+
CONSTRAINT company_profile_agent_confirmations_workspace_fk
|
|
148
|
+
FOREIGN KEY (workspace_id, account_id)
|
|
149
|
+
REFERENCES workspaces(id, account_id) ON DELETE CASCADE,
|
|
150
|
+
CONSTRAINT company_profile_agent_confirmations_session_fk
|
|
151
|
+
FOREIGN KEY (workspace_id, session_id)
|
|
152
|
+
REFERENCES sessions(workspace_id, id) ON DELETE CASCADE,
|
|
153
|
+
CONSTRAINT company_profile_agent_confirmations_turn_fk
|
|
154
|
+
FOREIGN KEY (workspace_id, turn_id)
|
|
155
|
+
REFERENCES session_turns(workspace_id, id) ON DELETE CASCADE,
|
|
156
|
+
CONSTRAINT company_profile_agent_confirmations_attempt_fk
|
|
157
|
+
FOREIGN KEY (account_id, workspace_id, session_id, turn_id, confirmation_attempt_id)
|
|
158
|
+
REFERENCES session_turn_attempts(account_id, workspace_id, session_id, turn_id, id)
|
|
159
|
+
ON DELETE CASCADE,
|
|
160
|
+
CONSTRAINT company_profile_agent_confirmations_proposal_fk
|
|
161
|
+
FOREIGN KEY (proposal_receipt_id, account_id)
|
|
162
|
+
REFERENCES company_profile_agent_proposal_receipts(id, account_id) ON DELETE RESTRICT,
|
|
163
|
+
CONSTRAINT company_profile_agent_confirmations_revision_fk
|
|
164
|
+
FOREIGN KEY (proposal_revision_id, account_id)
|
|
165
|
+
REFERENCES company_profile_revisions(id, account_id) ON DELETE RESTRICT,
|
|
166
|
+
CONSTRAINT company_profile_agent_confirmations_human_input_fk
|
|
167
|
+
FOREIGN KEY (human_input_request_id)
|
|
168
|
+
REFERENCES session_human_input_requests(id) ON DELETE CASCADE,
|
|
169
|
+
CONSTRAINT company_profile_agent_confirmations_membership_fk
|
|
170
|
+
FOREIGN KEY (approver_membership_id, account_id)
|
|
171
|
+
REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
|
|
172
|
+
CONSTRAINT company_profile_agent_confirmations_event_fk
|
|
173
|
+
FOREIGN KEY (activation_event_id, account_id)
|
|
174
|
+
REFERENCES company_profile_activation_events(id, account_id) ON DELETE RESTRICT,
|
|
175
|
+
CONSTRAINT company_profile_agent_confirmations_input_hash_check CHECK (
|
|
176
|
+
input_hash ~ '^[0-9a-f]{64}$'
|
|
177
|
+
),
|
|
178
|
+
CONSTRAINT company_profile_agent_confirmations_generation_check CHECK (
|
|
179
|
+
execution_generation > 0
|
|
180
|
+
),
|
|
181
|
+
CONSTRAINT company_profile_agent_confirmations_subject_check CHECK (
|
|
182
|
+
octet_length(btrim(approver_subject_id)) BETWEEN 1 AND 1024
|
|
183
|
+
)
|
|
184
|
+
);
|
|
185
|
+
CREATE UNIQUE INDEX company_profile_agent_confirmations_account_operation_uq
|
|
186
|
+
ON company_profile_agent_confirmation_receipts (account_id, operation_id);
|
|
187
|
+
CREATE UNIQUE INDEX company_profile_agent_confirmations_proposal_uq
|
|
188
|
+
ON company_profile_agent_confirmation_receipts (account_id, proposal_receipt_id);
|
|
189
|
+
CREATE UNIQUE INDEX company_profile_agent_confirmations_event_uq
|
|
190
|
+
ON company_profile_agent_confirmation_receipts (account_id, activation_event_id);
|
|
191
|
+
|
|
192
|
+
ALTER TABLE company_profile_agent_proposal_receipts ENABLE ROW LEVEL SECURITY;
|
|
193
|
+
ALTER TABLE company_profile_agent_proposal_receipts FORCE ROW LEVEL SECURITY;
|
|
194
|
+
ALTER TABLE company_profile_agent_confirmation_receipts ENABLE ROW LEVEL SECURITY;
|
|
195
|
+
ALTER TABLE company_profile_agent_confirmation_receipts FORCE ROW LEVEL SECURITY;
|
|
196
|
+
REVOKE ALL ON TABLE company_profile_agent_proposal_receipts FROM PUBLIC;
|
|
197
|
+
REVOKE ALL ON TABLE company_profile_agent_confirmation_receipts FROM PUBLIC;
|
|
198
|
+
CREATE POLICY company_profile_agent_admin_lifecycle
|
|
199
|
+
ON company_profile_agent_proposal_receipts
|
|
200
|
+
USING (current_setting('opengeni.company_profile_agent_admin_lifecycle', true)
|
|
201
|
+
= 'company_profile_agent_admin')
|
|
202
|
+
WITH CHECK (current_setting('opengeni.company_profile_agent_admin_lifecycle', true)
|
|
203
|
+
= 'company_profile_agent_admin');
|
|
204
|
+
CREATE POLICY company_profile_agent_admin_lifecycle
|
|
205
|
+
ON company_profile_agent_confirmation_receipts
|
|
206
|
+
USING (current_setting('opengeni.company_profile_agent_admin_lifecycle', true)
|
|
207
|
+
= 'company_profile_agent_admin')
|
|
208
|
+
WITH CHECK (current_setting('opengeni.company_profile_agent_admin_lifecycle', true)
|
|
209
|
+
= 'company_profile_agent_admin');
|
|
210
|
+
CREATE POLICY session_visibility_isolation
|
|
211
|
+
ON company_profile_agent_proposal_receipts AS RESTRICTIVE
|
|
212
|
+
USING (session_reference_visible(account_id, workspace_id, session_id))
|
|
213
|
+
WITH CHECK (session_reference_visible(account_id, workspace_id, session_id));
|
|
214
|
+
CREATE POLICY session_visibility_isolation
|
|
215
|
+
ON company_profile_agent_confirmation_receipts AS RESTRICTIVE
|
|
216
|
+
USING (session_reference_visible(account_id, workspace_id, session_id))
|
|
217
|
+
WITH CHECK (session_reference_visible(account_id, workspace_id, session_id));
|
|
218
|
+
|
|
219
|
+
CREATE FUNCTION company_profile_agent_receipts_immutable()
|
|
220
|
+
RETURNS trigger
|
|
221
|
+
LANGUAGE plpgsql
|
|
222
|
+
AS $body$
|
|
223
|
+
BEGIN
|
|
224
|
+
IF TG_OP = 'DELETE'
|
|
225
|
+
AND pg_trigger_depth() > 1
|
|
226
|
+
AND (
|
|
227
|
+
NOT EXISTS (SELECT 1 FROM managed_accounts account WHERE account.id = OLD.account_id)
|
|
228
|
+
OR NOT EXISTS (
|
|
229
|
+
SELECT 1 FROM sessions session
|
|
230
|
+
WHERE session.account_id = OLD.account_id
|
|
231
|
+
AND session.workspace_id = OLD.workspace_id
|
|
232
|
+
AND session.id = OLD.session_id
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
THEN
|
|
236
|
+
RETURN OLD;
|
|
237
|
+
END IF;
|
|
238
|
+
RAISE EXCEPTION 'company-profile agent administration receipts are immutable'
|
|
239
|
+
USING ERRCODE = '55000';
|
|
240
|
+
END
|
|
241
|
+
$body$;
|
|
242
|
+
CREATE TRIGGER company_profile_agent_proposals_immutable
|
|
243
|
+
BEFORE UPDATE OR DELETE ON company_profile_agent_proposal_receipts
|
|
244
|
+
FOR EACH ROW EXECUTE FUNCTION company_profile_agent_receipts_immutable();
|
|
245
|
+
CREATE TRIGGER company_profile_agent_confirmations_immutable
|
|
246
|
+
BEFORE UPDATE OR DELETE ON company_profile_agent_confirmation_receipts
|
|
247
|
+
FOR EACH ROW EXECUTE FUNCTION company_profile_agent_receipts_immutable();
|
|
248
|
+
|
|
249
|
+
CREATE FUNCTION company_profile_agent_confirmation_summary(p_content_json text)
|
|
250
|
+
RETURNS text
|
|
251
|
+
LANGUAGE plpgsql IMMUTABLE
|
|
252
|
+
AS $body$
|
|
253
|
+
DECLARE
|
|
254
|
+
profile jsonb := p_content_json::jsonb;
|
|
255
|
+
summary text;
|
|
256
|
+
list_name text;
|
|
257
|
+
list_text text;
|
|
258
|
+
BEGIN
|
|
259
|
+
summary := 'Identity: ' || coalesce(nullif(btrim(profile->>'identity'), ''), '(none)')
|
|
260
|
+
|| E'\nMission: ' || coalesce(nullif(btrim(profile->>'mission'), ''), '(none)');
|
|
261
|
+
FOREACH list_name IN ARRAY ARRAY['products', 'customers', 'goals', 'constraints'] LOOP
|
|
262
|
+
SELECT string_agg('- ' || (item->>'key') || ': ' || (item->>'content'), E'\n'
|
|
263
|
+
ORDER BY entries.ordinality)
|
|
264
|
+
INTO list_text
|
|
265
|
+
FROM jsonb_array_elements(coalesce(profile->list_name, '[]'::jsonb))
|
|
266
|
+
WITH ORDINALITY AS entries(item, ordinality);
|
|
267
|
+
summary := summary || E'\n' || initcap(list_name) || ':' || E'\n'
|
|
268
|
+
|| coalesce(list_text, '- (none)');
|
|
269
|
+
END LOOP;
|
|
270
|
+
-- HumanInputQuestion.helpText is capped at 2048 UTF-16 code units; the
|
|
271
|
+
-- revision/hash prefix uses under 100. Bound the rendered bytes (a UTF-16 unit
|
|
272
|
+
-- never needs more bytes than it needs units) without splitting a character.
|
|
273
|
+
IF octet_length(summary) > 1800 THEN
|
|
274
|
+
WHILE octet_length(summary) > 1797 LOOP
|
|
275
|
+
summary := left(
|
|
276
|
+
summary,
|
|
277
|
+
length(summary) - greatest(1, (octet_length(summary) - 1797) / 4)
|
|
278
|
+
);
|
|
279
|
+
END LOOP;
|
|
280
|
+
summary := summary || '...';
|
|
281
|
+
END IF;
|
|
282
|
+
RETURN summary;
|
|
283
|
+
END
|
|
284
|
+
$body$;
|
|
285
|
+
REVOKE ALL ON FUNCTION company_profile_agent_confirmation_summary(text) FROM PUBLIC;
|
|
286
|
+
|
|
287
|
+
CREATE FUNCTION company_profile_agent_confirmation_prompt(
|
|
288
|
+
p_revision_id uuid,
|
|
289
|
+
p_revision bigint,
|
|
290
|
+
p_content_hash text,
|
|
291
|
+
p_content_json text
|
|
292
|
+
) RETURNS jsonb
|
|
293
|
+
LANGUAGE sql IMMUTABLE
|
|
294
|
+
AS $body$
|
|
295
|
+
SELECT jsonb_build_object(
|
|
296
|
+
'questions', jsonb_build_array(jsonb_build_object(
|
|
297
|
+
'id', 'company-profile:' || p_revision_id::text,
|
|
298
|
+
'kind', 'single_select',
|
|
299
|
+
'prompt', 'Activate this organization company profile and strategic goals?',
|
|
300
|
+
'label', 'Company profile',
|
|
301
|
+
'helpText', 'Revision ' || p_revision::text || '; SHA-256 ' || p_content_hash
|
|
302
|
+
|| E'.\n\n' || company_profile_agent_confirmation_summary(p_content_json),
|
|
303
|
+
'options', jsonb_build_array(
|
|
304
|
+
jsonb_build_object('id', 'activate', 'label', 'Activate'),
|
|
305
|
+
jsonb_build_object('id', 'skip', 'label', 'Do not activate')
|
|
306
|
+
),
|
|
307
|
+
'required', true,
|
|
308
|
+
-- The stock runtime exposes Other on every choice question. Keep the
|
|
309
|
+
-- persisted contract byte-for-byte stable across that normalization;
|
|
310
|
+
-- confirmation below still accepts only the exact `activate` value.
|
|
311
|
+
'allowOther', true
|
|
312
|
+
)),
|
|
313
|
+
'allowSkip', false
|
|
314
|
+
)
|
|
315
|
+
$body$;
|
|
316
|
+
REVOKE ALL ON FUNCTION company_profile_agent_confirmation_prompt(uuid, bigint, text, text)
|
|
317
|
+
FROM PUBLIC;
|
|
318
|
+
|
|
319
|
+
CREATE FUNCTION propose_company_profile_for_attempt(
|
|
320
|
+
p_account_id uuid,
|
|
321
|
+
p_workspace_id uuid,
|
|
322
|
+
p_session_id uuid,
|
|
323
|
+
p_turn_id uuid,
|
|
324
|
+
p_attempt_id uuid,
|
|
325
|
+
p_execution_generation integer,
|
|
326
|
+
p_operation_id uuid,
|
|
327
|
+
p_content_json text,
|
|
328
|
+
p_content_hash text,
|
|
329
|
+
p_reason text
|
|
330
|
+
) RETURNS TABLE (
|
|
331
|
+
receipt_id uuid,
|
|
332
|
+
revision_id uuid,
|
|
333
|
+
human_input jsonb,
|
|
334
|
+
replayed boolean
|
|
335
|
+
)
|
|
336
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
337
|
+
SET search_path FROM CURRENT
|
|
338
|
+
AS $body$
|
|
339
|
+
DECLARE
|
|
340
|
+
context_account_id uuid := nullif(current_setting('opengeni.account_id', true), '')::uuid;
|
|
341
|
+
context_workspace_id uuid := nullif(current_setting('opengeni.workspace_id', true), '')::uuid;
|
|
342
|
+
context_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
343
|
+
context_principal_kind text := nullif(current_setting('opengeni.principal_kind', true), '');
|
|
344
|
+
initiating_subject text;
|
|
345
|
+
actor_membership organization_memberships%ROWTYPE;
|
|
346
|
+
active_head company_profile_heads%ROWTYPE;
|
|
347
|
+
prior company_profile_agent_proposal_receipts%ROWTYPE;
|
|
348
|
+
inserted_revision company_profile_revisions%ROWTYPE;
|
|
349
|
+
input_hash_value text;
|
|
350
|
+
new_receipt_id uuid := gen_random_uuid();
|
|
351
|
+
new_revision_id uuid := gen_random_uuid();
|
|
352
|
+
normalized_reason text := btrim(p_reason);
|
|
353
|
+
prompt jsonb;
|
|
354
|
+
BEGIN
|
|
355
|
+
IF context_account_id IS DISTINCT FROM p_account_id
|
|
356
|
+
OR context_workspace_id IS DISTINCT FROM p_workspace_id
|
|
357
|
+
OR context_subject_id IS NULL
|
|
358
|
+
OR context_principal_kind IS DISTINCT FROM 'agent_attempt'
|
|
359
|
+
OR p_execution_generation < 1
|
|
360
|
+
OR p_operation_id IS NULL
|
|
361
|
+
OR p_content_json IS NULL
|
|
362
|
+
OR p_content_hash !~ '^[0-9a-f]{64}$'
|
|
363
|
+
OR p_content_hash IS DISTINCT FROM encode(sha256(convert_to(p_content_json, 'UTF8')), 'hex')
|
|
364
|
+
OR octet_length(convert_to(p_content_json, 'UTF8')) NOT BETWEEN 1 AND 28672
|
|
365
|
+
OR octet_length(convert_to(normalized_reason, 'UTF8')) NOT BETWEEN 1 AND 16384
|
|
366
|
+
THEN
|
|
367
|
+
RAISE EXCEPTION 'company-profile agent proposal is invalid' USING ERRCODE = '22023';
|
|
368
|
+
END IF;
|
|
369
|
+
|
|
370
|
+
-- Resolve the exact logical turn's initiating human with a plain read; no
|
|
371
|
+
-- row lock may precede the canonical workspace/session prefix below.
|
|
372
|
+
SELECT coalesce(
|
|
373
|
+
turn.initiating_human_subject_id,
|
|
374
|
+
CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
|
|
375
|
+
) INTO initiating_subject
|
|
376
|
+
FROM session_turns turn
|
|
377
|
+
WHERE turn.account_id = p_account_id
|
|
378
|
+
AND turn.workspace_id = p_workspace_id
|
|
379
|
+
AND turn.session_id = p_session_id
|
|
380
|
+
AND turn.id = p_turn_id;
|
|
381
|
+
IF initiating_subject IS NULL THEN
|
|
382
|
+
RAISE EXCEPTION
|
|
383
|
+
'company-profile agent proposals require the exact live turn of the active organization owner'
|
|
384
|
+
USING ERRCODE = '42501';
|
|
385
|
+
END IF;
|
|
386
|
+
|
|
387
|
+
-- Canonical prefix: workspaces FOR KEY SHARE, then the membership row FOR KEY
|
|
388
|
+
-- SHARE (the 0299 membership seam orders workspaces -> memberships ->
|
|
389
|
+
-- sessions), then the exact session/turn/attempt rows FOR SHARE.
|
|
390
|
+
PERFORM 1 FROM workspaces workspace
|
|
391
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
|
|
392
|
+
FOR KEY SHARE;
|
|
393
|
+
IF NOT FOUND THEN
|
|
394
|
+
RAISE EXCEPTION 'organization workspace is unavailable' USING ERRCODE = '42501';
|
|
395
|
+
END IF;
|
|
396
|
+
SELECT membership.* INTO actor_membership
|
|
397
|
+
FROM organization_memberships membership
|
|
398
|
+
WHERE membership.account_id = p_account_id
|
|
399
|
+
AND membership.subject_id = initiating_subject
|
|
400
|
+
AND membership.status = 'active'
|
|
401
|
+
AND membership.role = 'owner'
|
|
402
|
+
FOR KEY SHARE;
|
|
403
|
+
IF NOT FOUND THEN
|
|
404
|
+
RAISE EXCEPTION
|
|
405
|
+
'company-profile agent proposals require the exact live turn of the active organization owner'
|
|
406
|
+
USING ERRCODE = '42501';
|
|
407
|
+
END IF;
|
|
408
|
+
PERFORM 1
|
|
409
|
+
FROM sessions session
|
|
410
|
+
JOIN session_turns turn
|
|
411
|
+
ON turn.account_id = session.account_id
|
|
412
|
+
AND turn.workspace_id = session.workspace_id
|
|
413
|
+
AND turn.session_id = session.id
|
|
414
|
+
JOIN session_turn_attempts attempt
|
|
415
|
+
ON attempt.account_id = turn.account_id
|
|
416
|
+
AND attempt.workspace_id = turn.workspace_id
|
|
417
|
+
AND attempt.session_id = turn.session_id
|
|
418
|
+
AND attempt.turn_id = turn.id
|
|
419
|
+
WHERE session.account_id = p_account_id
|
|
420
|
+
AND session.workspace_id = p_workspace_id
|
|
421
|
+
AND session.id = p_session_id
|
|
422
|
+
AND session.active_turn_id = p_turn_id
|
|
423
|
+
AND turn.id = p_turn_id
|
|
424
|
+
AND turn.active_attempt_id = p_attempt_id
|
|
425
|
+
AND turn.execution_generation = p_execution_generation
|
|
426
|
+
AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
|
|
427
|
+
AND coalesce(
|
|
428
|
+
turn.initiating_human_subject_id,
|
|
429
|
+
CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
|
|
430
|
+
) = actor_membership.subject_id
|
|
431
|
+
AND attempt.id = p_attempt_id
|
|
432
|
+
AND attempt.execution_generation = p_execution_generation
|
|
433
|
+
AND attempt.state IN ('claimed', 'running')
|
|
434
|
+
AND NOT EXISTS (
|
|
435
|
+
SELECT 1 FROM session_attempt_interruptions interruption
|
|
436
|
+
WHERE interruption.workspace_id = attempt.workspace_id
|
|
437
|
+
AND interruption.attempt_id = attempt.id
|
|
438
|
+
AND interruption.state IN ('pending', 'delivered', 'acknowledged')
|
|
439
|
+
)
|
|
440
|
+
FOR SHARE OF session, turn, attempt;
|
|
441
|
+
IF NOT FOUND THEN
|
|
442
|
+
RAISE EXCEPTION
|
|
443
|
+
'company-profile agent proposals require the exact live turn of the active organization owner'
|
|
444
|
+
USING ERRCODE = '42501';
|
|
445
|
+
END IF;
|
|
446
|
+
|
|
447
|
+
-- Organization row AFTER the session prefix, FOR KEY SHARE only: compatible
|
|
448
|
+
-- with every ordinary writer's FK check, while the manual route's FOR UPDATE
|
|
449
|
+
-- (held across its head mutation) cannot interleave with the head read below.
|
|
450
|
+
PERFORM 1 FROM managed_accounts account
|
|
451
|
+
WHERE account.id = p_account_id FOR KEY SHARE;
|
|
452
|
+
IF NOT FOUND THEN
|
|
453
|
+
RAISE EXCEPTION 'organization account is unavailable' USING ERRCODE = '42501';
|
|
454
|
+
END IF;
|
|
455
|
+
|
|
456
|
+
-- The hash binds the logical turn, never the attempt id or execution
|
|
457
|
+
-- generation: a replacement attempt re-issuing the same operation id replays.
|
|
458
|
+
input_hash_value := encode(sha256(convert_to(jsonb_build_array(
|
|
459
|
+
'company-profile-agent-proposal', 1, p_account_id, p_workspace_id,
|
|
460
|
+
p_session_id, p_turn_id, p_operation_id, p_content_hash, normalized_reason,
|
|
461
|
+
actor_membership.id, actor_membership.subject_id
|
|
462
|
+
)::text, 'UTF8')), 'hex');
|
|
463
|
+
PERFORM set_config(
|
|
464
|
+
'opengeni.company_profile_agent_admin_lifecycle',
|
|
465
|
+
'company_profile_agent_admin', true
|
|
466
|
+
);
|
|
467
|
+
SELECT * INTO prior FROM company_profile_agent_proposal_receipts receipt
|
|
468
|
+
WHERE receipt.account_id = p_account_id AND receipt.operation_id = p_operation_id;
|
|
469
|
+
IF FOUND THEN
|
|
470
|
+
IF prior.input_hash IS DISTINCT FROM input_hash_value THEN
|
|
471
|
+
RAISE EXCEPTION 'company-profile agent proposal operation id was reused'
|
|
472
|
+
USING ERRCODE = 'P1851';
|
|
473
|
+
END IF;
|
|
474
|
+
receipt_id := prior.id;
|
|
475
|
+
revision_id := prior.revision_id;
|
|
476
|
+
human_input := prior.human_input;
|
|
477
|
+
replayed := true;
|
|
478
|
+
RETURN NEXT;
|
|
479
|
+
RETURN;
|
|
480
|
+
END IF;
|
|
481
|
+
IF EXISTS (
|
|
482
|
+
SELECT 1 FROM company_profile_revisions revision
|
|
483
|
+
WHERE revision.account_id = p_account_id AND revision.operation_id = p_operation_id
|
|
484
|
+
) THEN
|
|
485
|
+
RAISE EXCEPTION 'company-profile agent proposal operation id was reused'
|
|
486
|
+
USING ERRCODE = 'P1851';
|
|
487
|
+
END IF;
|
|
488
|
+
|
|
489
|
+
SELECT * INTO active_head FROM company_profile_heads head
|
|
490
|
+
WHERE head.account_id = p_account_id;
|
|
491
|
+
INSERT INTO company_profile_revisions (
|
|
492
|
+
id, operation_id, request_fingerprint, account_id, intent,
|
|
493
|
+
content_json, content_hash, provenance_source, provenance_source_id,
|
|
494
|
+
supersedes_revision_id, created_by_subject_id
|
|
495
|
+
) VALUES (
|
|
496
|
+
new_revision_id, p_operation_id, input_hash_value, p_account_id, 'proposal',
|
|
497
|
+
p_content_json, p_content_hash, 'agent_admin',
|
|
498
|
+
'agent-admin-proposal:' || new_receipt_id::text,
|
|
499
|
+
active_head.revision_id, context_subject_id
|
|
500
|
+
) RETURNING * INTO inserted_revision;
|
|
501
|
+
prompt := company_profile_agent_confirmation_prompt(
|
|
502
|
+
inserted_revision.id, inserted_revision.revision,
|
|
503
|
+
inserted_revision.content_hash, inserted_revision.content_json
|
|
504
|
+
);
|
|
505
|
+
INSERT INTO company_profile_agent_proposal_receipts (
|
|
506
|
+
id, operation_id, input_hash, account_id, workspace_id, session_id,
|
|
507
|
+
turn_id, creation_attempt_id, execution_generation,
|
|
508
|
+
initiating_human_subject_id, initiating_membership_id, revision_id,
|
|
509
|
+
expected_current_revision_id, expected_activation_version, reason, human_input
|
|
510
|
+
) VALUES (
|
|
511
|
+
new_receipt_id, p_operation_id, input_hash_value, p_account_id, p_workspace_id,
|
|
512
|
+
p_session_id, p_turn_id, p_attempt_id, p_execution_generation,
|
|
513
|
+
actor_membership.subject_id, actor_membership.id, inserted_revision.id,
|
|
514
|
+
active_head.revision_id, coalesce(active_head.activation_version, 0),
|
|
515
|
+
normalized_reason, prompt
|
|
516
|
+
);
|
|
517
|
+
receipt_id := new_receipt_id;
|
|
518
|
+
revision_id := inserted_revision.id;
|
|
519
|
+
human_input := prompt;
|
|
520
|
+
replayed := false;
|
|
521
|
+
RETURN NEXT;
|
|
522
|
+
END
|
|
523
|
+
$body$;
|
|
524
|
+
|
|
525
|
+
CREATE FUNCTION confirm_company_profile_for_attempt(
|
|
526
|
+
p_account_id uuid,
|
|
527
|
+
p_workspace_id uuid,
|
|
528
|
+
p_session_id uuid,
|
|
529
|
+
p_turn_id uuid,
|
|
530
|
+
p_attempt_id uuid,
|
|
531
|
+
p_execution_generation integer,
|
|
532
|
+
p_operation_id uuid,
|
|
533
|
+
p_proposal_receipt_id uuid,
|
|
534
|
+
p_human_input_request_id uuid
|
|
535
|
+
) RETURNS TABLE (
|
|
536
|
+
receipt_id uuid,
|
|
537
|
+
activation_event_id uuid,
|
|
538
|
+
replayed boolean
|
|
539
|
+
)
|
|
540
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
541
|
+
SET search_path FROM CURRENT
|
|
542
|
+
AS $body$
|
|
543
|
+
DECLARE
|
|
544
|
+
context_account_id uuid := nullif(current_setting('opengeni.account_id', true), '')::uuid;
|
|
545
|
+
context_workspace_id uuid := nullif(current_setting('opengeni.workspace_id', true), '')::uuid;
|
|
546
|
+
context_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
547
|
+
context_principal_kind text := nullif(current_setting('opengeni.principal_kind', true), '');
|
|
548
|
+
initiating_subject text;
|
|
549
|
+
actor_membership organization_memberships%ROWTYPE;
|
|
550
|
+
proposal company_profile_agent_proposal_receipts%ROWTYPE;
|
|
551
|
+
proposal_revision company_profile_revisions%ROWTYPE;
|
|
552
|
+
human_input_row session_human_input_requests%ROWTYPE;
|
|
553
|
+
active_head company_profile_heads%ROWTYPE;
|
|
554
|
+
prior company_profile_agent_confirmation_receipts%ROWTYPE;
|
|
555
|
+
input_hash_value text;
|
|
556
|
+
event_id_value uuid;
|
|
557
|
+
new_receipt_id uuid := gen_random_uuid();
|
|
558
|
+
question_id text;
|
|
559
|
+
BEGIN
|
|
560
|
+
IF context_account_id IS DISTINCT FROM p_account_id
|
|
561
|
+
OR context_workspace_id IS DISTINCT FROM p_workspace_id
|
|
562
|
+
OR context_subject_id IS NULL
|
|
563
|
+
OR context_principal_kind IS DISTINCT FROM 'agent_attempt'
|
|
564
|
+
OR p_execution_generation < 1
|
|
565
|
+
OR p_operation_id IS NULL
|
|
566
|
+
OR p_proposal_receipt_id IS NULL
|
|
567
|
+
OR p_human_input_request_id IS NULL
|
|
568
|
+
THEN
|
|
569
|
+
RAISE EXCEPTION 'company-profile agent confirmation is invalid' USING ERRCODE = '22023';
|
|
570
|
+
END IF;
|
|
571
|
+
|
|
572
|
+
-- Resolve the exact logical turn's initiating human with a plain read; no
|
|
573
|
+
-- row lock may precede the canonical workspace/session prefix below.
|
|
574
|
+
SELECT coalesce(
|
|
575
|
+
turn.initiating_human_subject_id,
|
|
576
|
+
CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
|
|
577
|
+
) INTO initiating_subject
|
|
578
|
+
FROM session_turns turn
|
|
579
|
+
WHERE turn.account_id = p_account_id
|
|
580
|
+
AND turn.workspace_id = p_workspace_id
|
|
581
|
+
AND turn.session_id = p_session_id
|
|
582
|
+
AND turn.id = p_turn_id;
|
|
583
|
+
IF initiating_subject IS NULL THEN
|
|
584
|
+
RAISE EXCEPTION
|
|
585
|
+
'company-profile confirmation requires the exact live turn of the active organization owner'
|
|
586
|
+
USING ERRCODE = '42501';
|
|
587
|
+
END IF;
|
|
588
|
+
|
|
589
|
+
-- Canonical prefix: workspaces FOR KEY SHARE, then the membership row FOR KEY
|
|
590
|
+
-- SHARE (the 0299 membership seam orders workspaces -> memberships ->
|
|
591
|
+
-- sessions), then the exact session/turn/attempt rows FOR SHARE.
|
|
592
|
+
PERFORM 1 FROM workspaces workspace
|
|
593
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
|
|
594
|
+
FOR KEY SHARE;
|
|
595
|
+
IF NOT FOUND THEN
|
|
596
|
+
RAISE EXCEPTION 'organization workspace is unavailable' USING ERRCODE = '42501';
|
|
597
|
+
END IF;
|
|
598
|
+
SELECT membership.* INTO actor_membership
|
|
599
|
+
FROM organization_memberships membership
|
|
600
|
+
WHERE membership.account_id = p_account_id
|
|
601
|
+
AND membership.subject_id = initiating_subject
|
|
602
|
+
AND membership.status = 'active'
|
|
603
|
+
AND membership.role = 'owner'
|
|
604
|
+
FOR KEY SHARE;
|
|
605
|
+
IF NOT FOUND THEN
|
|
606
|
+
RAISE EXCEPTION
|
|
607
|
+
'company-profile confirmation requires the exact live turn of the active organization owner'
|
|
608
|
+
USING ERRCODE = '42501';
|
|
609
|
+
END IF;
|
|
610
|
+
PERFORM 1
|
|
611
|
+
FROM sessions session
|
|
612
|
+
JOIN session_turns turn
|
|
613
|
+
ON turn.account_id = session.account_id
|
|
614
|
+
AND turn.workspace_id = session.workspace_id
|
|
615
|
+
AND turn.session_id = session.id
|
|
616
|
+
JOIN session_turn_attempts attempt
|
|
617
|
+
ON attempt.account_id = turn.account_id
|
|
618
|
+
AND attempt.workspace_id = turn.workspace_id
|
|
619
|
+
AND attempt.session_id = turn.session_id
|
|
620
|
+
AND attempt.turn_id = turn.id
|
|
621
|
+
WHERE session.account_id = p_account_id
|
|
622
|
+
AND session.workspace_id = p_workspace_id
|
|
623
|
+
AND session.id = p_session_id
|
|
624
|
+
AND session.active_turn_id = p_turn_id
|
|
625
|
+
AND turn.id = p_turn_id
|
|
626
|
+
AND turn.active_attempt_id = p_attempt_id
|
|
627
|
+
AND turn.execution_generation = p_execution_generation
|
|
628
|
+
AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
|
|
629
|
+
AND coalesce(
|
|
630
|
+
turn.initiating_human_subject_id,
|
|
631
|
+
CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
|
|
632
|
+
) = actor_membership.subject_id
|
|
633
|
+
AND attempt.id = p_attempt_id
|
|
634
|
+
AND attempt.execution_generation = p_execution_generation
|
|
635
|
+
AND attempt.state IN ('claimed', 'running')
|
|
636
|
+
AND NOT EXISTS (
|
|
637
|
+
SELECT 1 FROM session_attempt_interruptions interruption
|
|
638
|
+
WHERE interruption.workspace_id = attempt.workspace_id
|
|
639
|
+
AND interruption.attempt_id = attempt.id
|
|
640
|
+
AND interruption.state IN ('pending', 'delivered', 'acknowledged')
|
|
641
|
+
)
|
|
642
|
+
FOR SHARE OF session, turn, attempt;
|
|
643
|
+
IF NOT FOUND THEN
|
|
644
|
+
RAISE EXCEPTION
|
|
645
|
+
'company-profile confirmation requires the exact live turn of the active organization owner'
|
|
646
|
+
USING ERRCODE = '42501';
|
|
647
|
+
END IF;
|
|
648
|
+
|
|
649
|
+
PERFORM set_config(
|
|
650
|
+
'opengeni.company_profile_agent_admin_lifecycle',
|
|
651
|
+
'company_profile_agent_admin', true
|
|
652
|
+
);
|
|
653
|
+
SELECT * INTO proposal FROM company_profile_agent_proposal_receipts receipt
|
|
654
|
+
WHERE receipt.id = p_proposal_receipt_id
|
|
655
|
+
AND receipt.account_id = p_account_id
|
|
656
|
+
AND receipt.workspace_id = p_workspace_id
|
|
657
|
+
AND receipt.session_id = p_session_id
|
|
658
|
+
AND receipt.turn_id = p_turn_id
|
|
659
|
+
FOR SHARE;
|
|
660
|
+
IF NOT FOUND
|
|
661
|
+
OR proposal.initiating_human_subject_id IS DISTINCT FROM actor_membership.subject_id
|
|
662
|
+
OR proposal.initiating_membership_id IS DISTINCT FROM actor_membership.id
|
|
663
|
+
THEN
|
|
664
|
+
RAISE EXCEPTION 'company-profile proposal is unavailable for this authority'
|
|
665
|
+
USING ERRCODE = '42501';
|
|
666
|
+
END IF;
|
|
667
|
+
|
|
668
|
+
-- The hash binds the logical turn, never the execution generation: a
|
|
669
|
+
-- replacement attempt re-issuing the same operation id replays.
|
|
670
|
+
input_hash_value := encode(sha256(convert_to(jsonb_build_array(
|
|
671
|
+
'company-profile-agent-confirmation', 1, p_account_id, p_workspace_id,
|
|
672
|
+
p_session_id, p_turn_id, p_operation_id,
|
|
673
|
+
proposal.id, proposal.revision_id, p_human_input_request_id,
|
|
674
|
+
actor_membership.id, actor_membership.subject_id
|
|
675
|
+
)::text, 'UTF8')), 'hex');
|
|
676
|
+
SELECT * INTO prior FROM company_profile_agent_confirmation_receipts receipt
|
|
677
|
+
WHERE receipt.account_id = p_account_id AND receipt.operation_id = p_operation_id;
|
|
678
|
+
IF FOUND THEN
|
|
679
|
+
IF prior.input_hash IS DISTINCT FROM input_hash_value THEN
|
|
680
|
+
RAISE EXCEPTION 'company-profile agent confirmation operation id was reused'
|
|
681
|
+
USING ERRCODE = 'P1851';
|
|
682
|
+
END IF;
|
|
683
|
+
receipt_id := prior.id;
|
|
684
|
+
activation_event_id := prior.activation_event_id;
|
|
685
|
+
replayed := true;
|
|
686
|
+
RETURN NEXT;
|
|
687
|
+
RETURN;
|
|
688
|
+
END IF;
|
|
689
|
+
-- A proposal activates at most once (company_profile_agent_confirmations_
|
|
690
|
+
-- proposal_uq). A retry under a fresh operation id after a successful
|
|
691
|
+
-- activation, for the same proposal and the same bound human-input request,
|
|
692
|
+
-- replays the existing confirmation instead of failing the head CAS below.
|
|
693
|
+
SELECT * INTO prior FROM company_profile_agent_confirmation_receipts receipt
|
|
694
|
+
WHERE receipt.account_id = p_account_id AND receipt.proposal_receipt_id = proposal.id;
|
|
695
|
+
IF FOUND THEN
|
|
696
|
+
IF prior.human_input_request_id IS DISTINCT FROM p_human_input_request_id THEN
|
|
697
|
+
RAISE EXCEPTION
|
|
698
|
+
'company-profile proposal was already activated through a different human confirmation'
|
|
699
|
+
USING ERRCODE = '42501';
|
|
700
|
+
END IF;
|
|
701
|
+
receipt_id := prior.id;
|
|
702
|
+
activation_event_id := prior.activation_event_id;
|
|
703
|
+
replayed := true;
|
|
704
|
+
RETURN NEXT;
|
|
705
|
+
RETURN;
|
|
706
|
+
END IF;
|
|
707
|
+
|
|
708
|
+
SELECT * INTO proposal_revision FROM company_profile_revisions revision
|
|
709
|
+
WHERE revision.account_id = p_account_id
|
|
710
|
+
AND revision.id = proposal.revision_id
|
|
711
|
+
AND revision.intent = 'proposal'
|
|
712
|
+
AND revision.provenance_source = 'agent_admin'
|
|
713
|
+
AND revision.provenance_source_id = 'agent-admin-proposal:' || proposal.id::text
|
|
714
|
+
FOR SHARE;
|
|
715
|
+
IF NOT FOUND THEN
|
|
716
|
+
RAISE EXCEPTION 'company-profile proposal revision is unavailable'
|
|
717
|
+
USING ERRCODE = '42501';
|
|
718
|
+
END IF;
|
|
719
|
+
question_id := 'company-profile:' || proposal_revision.id::text;
|
|
720
|
+
SELECT * INTO human_input_row FROM session_human_input_requests request
|
|
721
|
+
WHERE request.id = p_human_input_request_id
|
|
722
|
+
AND request.account_id = p_account_id
|
|
723
|
+
AND request.workspace_id = p_workspace_id
|
|
724
|
+
AND request.session_id = p_session_id
|
|
725
|
+
AND request.turn_id = p_turn_id
|
|
726
|
+
AND proposal.execution_generation <= request.turn_generation
|
|
727
|
+
AND request.turn_generation < p_execution_generation
|
|
728
|
+
AND request.status = 'answered'
|
|
729
|
+
AND request.responded_by = actor_membership.subject_id
|
|
730
|
+
AND request.allow_skip = false
|
|
731
|
+
AND request.questions = proposal.human_input->'questions'
|
|
732
|
+
AND request.response->>'outcome' = 'answered'
|
|
733
|
+
AND EXISTS (
|
|
734
|
+
SELECT 1 FROM jsonb_array_elements(request.response->'answers') answer(value)
|
|
735
|
+
WHERE answer.value->>'questionId' = question_id
|
|
736
|
+
AND answer.value->'values' = '["activate"]'::jsonb
|
|
737
|
+
)
|
|
738
|
+
FOR SHARE;
|
|
739
|
+
IF NOT FOUND THEN
|
|
740
|
+
RAISE EXCEPTION 'human confirmation for this company profile is unavailable'
|
|
741
|
+
USING ERRCODE = '42501';
|
|
742
|
+
END IF;
|
|
743
|
+
|
|
744
|
+
SELECT * INTO active_head FROM company_profile_heads head
|
|
745
|
+
WHERE head.account_id = p_account_id;
|
|
746
|
+
IF active_head.revision_id IS DISTINCT FROM proposal.expected_current_revision_id
|
|
747
|
+
OR coalesce(active_head.activation_version, 0)
|
|
748
|
+
IS DISTINCT FROM proposal.expected_activation_version
|
|
749
|
+
THEN
|
|
750
|
+
RAISE EXCEPTION 'company profile changed after the proposal was reviewed'
|
|
751
|
+
USING ERRCODE = '40001';
|
|
752
|
+
END IF;
|
|
753
|
+
|
|
754
|
+
-- The nested lifecycle function takes managed_accounts FOR UPDATE and then
|
|
755
|
+
-- company_profile_heads FOR UPDATE; both happen after the session prefix
|
|
756
|
+
-- above, matching the canonical event writer's sessions -> managed_accounts
|
|
757
|
+
-- direction.
|
|
758
|
+
PERFORM set_config('opengeni.subject_id', actor_membership.subject_id, true);
|
|
759
|
+
PERFORM set_config('opengeni.principal_kind', 'human_session', true);
|
|
760
|
+
SELECT activation.event_id INTO event_id_value
|
|
761
|
+
FROM company_profile_apply_activation(
|
|
762
|
+
p_operation_id, input_hash_value, p_account_id, p_workspace_id,
|
|
763
|
+
proposal_revision.id, proposal.expected_current_revision_id,
|
|
764
|
+
proposal.expected_activation_version, 'activate',
|
|
765
|
+
actor_membership.subject_id, 'human_session', proposal.reason
|
|
766
|
+
) activation;
|
|
767
|
+
IF event_id_value IS NULL THEN
|
|
768
|
+
RAISE EXCEPTION 'company-profile activation returned no event' USING ERRCODE = '55000';
|
|
769
|
+
END IF;
|
|
770
|
+
PERFORM set_config('opengeni.subject_id', context_subject_id, true);
|
|
771
|
+
PERFORM set_config('opengeni.principal_kind', context_principal_kind, true);
|
|
772
|
+
|
|
773
|
+
INSERT INTO company_profile_agent_confirmation_receipts (
|
|
774
|
+
id, operation_id, input_hash, account_id, workspace_id, session_id, turn_id,
|
|
775
|
+
confirmation_attempt_id, execution_generation, proposal_receipt_id,
|
|
776
|
+
proposal_revision_id, human_input_request_id, approver_subject_id,
|
|
777
|
+
approver_membership_id, activation_event_id
|
|
778
|
+
) VALUES (
|
|
779
|
+
new_receipt_id, p_operation_id, input_hash_value, p_account_id, p_workspace_id,
|
|
780
|
+
p_session_id, p_turn_id, p_attempt_id, p_execution_generation, proposal.id,
|
|
781
|
+
proposal_revision.id, human_input_row.id, actor_membership.subject_id,
|
|
782
|
+
actor_membership.id, event_id_value
|
|
783
|
+
);
|
|
784
|
+
receipt_id := new_receipt_id;
|
|
785
|
+
activation_event_id := event_id_value;
|
|
786
|
+
replayed := false;
|
|
787
|
+
RETURN NEXT;
|
|
788
|
+
END
|
|
789
|
+
$body$;
|
|
790
|
+
|
|
791
|
+
REVOKE ALL ON FUNCTION propose_company_profile_for_attempt(
|
|
792
|
+
uuid, uuid, uuid, uuid, uuid, integer, uuid, text, text, text
|
|
793
|
+
) FROM PUBLIC;
|
|
794
|
+
REVOKE ALL ON FUNCTION confirm_company_profile_for_attempt(
|
|
795
|
+
uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid
|
|
796
|
+
) FROM PUBLIC;
|
|
797
|
+
|
|
798
|
+
DO $company_profile_agent_admin_hardening$
|
|
799
|
+
DECLARE
|
|
800
|
+
target_schema text := current_schema();
|
|
801
|
+
runtime_role text := nullif(current_setting('opengeni.runtime_role', true), '');
|
|
802
|
+
BEGIN
|
|
803
|
+
EXECUTE format(
|
|
804
|
+
'ALTER FUNCTION %I.company_profile_agent_receipts_immutable() '
|
|
805
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
806
|
+
target_schema, target_schema
|
|
807
|
+
);
|
|
808
|
+
EXECUTE format(
|
|
809
|
+
'ALTER FUNCTION %I.company_profile_agent_confirmation_summary(text) '
|
|
810
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
811
|
+
target_schema, target_schema
|
|
812
|
+
);
|
|
813
|
+
EXECUTE format(
|
|
814
|
+
'ALTER FUNCTION %I.company_profile_agent_confirmation_prompt(uuid,bigint,text,text) '
|
|
815
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
816
|
+
target_schema, target_schema
|
|
817
|
+
);
|
|
818
|
+
EXECUTE format(
|
|
819
|
+
'ALTER FUNCTION %I.propose_company_profile_for_attempt('
|
|
820
|
+
|| 'uuid,uuid,uuid,uuid,uuid,integer,uuid,text,text,text) '
|
|
821
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
822
|
+
target_schema, target_schema
|
|
823
|
+
);
|
|
824
|
+
EXECUTE format(
|
|
825
|
+
'ALTER FUNCTION %I.confirm_company_profile_for_attempt('
|
|
826
|
+
|| 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid) '
|
|
827
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
828
|
+
target_schema, target_schema
|
|
829
|
+
);
|
|
830
|
+
IF runtime_role IS NULL AND EXISTS (
|
|
831
|
+
SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app'
|
|
832
|
+
) THEN
|
|
833
|
+
runtime_role := 'opengeni_app';
|
|
834
|
+
END IF;
|
|
835
|
+
IF runtime_role IS NOT NULL THEN
|
|
836
|
+
EXECUTE format(
|
|
837
|
+
'GRANT EXECUTE ON FUNCTION %I.propose_company_profile_for_attempt('
|
|
838
|
+
|| 'uuid,uuid,uuid,uuid,uuid,integer,uuid,text,text,text) TO %I',
|
|
839
|
+
target_schema, runtime_role
|
|
840
|
+
);
|
|
841
|
+
EXECUTE format(
|
|
842
|
+
'GRANT EXECUTE ON FUNCTION %I.confirm_company_profile_for_attempt('
|
|
843
|
+
|| 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid) TO %I',
|
|
844
|
+
target_schema, runtime_role
|
|
845
|
+
);
|
|
846
|
+
EXECUTE format(
|
|
847
|
+
'REVOKE ALL ON TABLE %I.company_profile_agent_proposal_receipts FROM %I',
|
|
848
|
+
target_schema, runtime_role
|
|
849
|
+
);
|
|
850
|
+
EXECUTE format(
|
|
851
|
+
'REVOKE ALL ON TABLE %I.company_profile_agent_confirmation_receipts FROM %I',
|
|
852
|
+
target_schema, runtime_role
|
|
853
|
+
);
|
|
854
|
+
END IF;
|
|
855
|
+
END
|
|
856
|
+
$company_profile_agent_admin_hardening$;
|