@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,1874 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
SET lock_timeout = '5s';
|
|
3
|
+
SET statement_timeout = '60s';
|
|
4
|
+
|
|
5
|
+
-- Consume one final governed-learning automatic verdict without turning that
|
|
6
|
+
-- inert receipt into a reusable grant. The controller revalidates every live
|
|
7
|
+
-- authority and calls only destination-owned service lifecycle functions.
|
|
8
|
+
|
|
9
|
+
CREATE TABLE "governed_learning_activation_receipts" (
|
|
10
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
11
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
12
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
13
|
+
"operation_id" uuid NOT NULL,
|
|
14
|
+
"input_hash" text NOT NULL,
|
|
15
|
+
"decision_receipt_id" uuid NOT NULL
|
|
16
|
+
REFERENCES "governed_learning_decision_receipts"("id") ON DELETE RESTRICT,
|
|
17
|
+
"initiating_human_subject_id" text NOT NULL,
|
|
18
|
+
"service_actor_subject_id" text NOT NULL,
|
|
19
|
+
"policy_revision_id" uuid NOT NULL
|
|
20
|
+
REFERENCES "workspace_learning_policy_revisions"("id") ON DELETE RESTRICT,
|
|
21
|
+
"policy_hash" text NOT NULL,
|
|
22
|
+
"policy_activation_version" bigint NOT NULL,
|
|
23
|
+
"source_kind" text NOT NULL,
|
|
24
|
+
"source_id" uuid NOT NULL,
|
|
25
|
+
"source_authority_hash" text NOT NULL,
|
|
26
|
+
"proposal_id" uuid NOT NULL REFERENCES "knowledge_change_proposals"("id") ON DELETE RESTRICT,
|
|
27
|
+
"claim_id" uuid NOT NULL REFERENCES "knowledge_claims"("id") ON DELETE RESTRICT,
|
|
28
|
+
"evidence_id" uuid NOT NULL REFERENCES "knowledge_claim_evidence"("id") ON DELETE RESTRICT,
|
|
29
|
+
"knowledge_previous_review_id" uuid NOT NULL
|
|
30
|
+
REFERENCES "knowledge_claim_reviews"("id") ON DELETE RESTRICT,
|
|
31
|
+
"knowledge_previous_review_revision" bigint NOT NULL,
|
|
32
|
+
"knowledge_approval_review_id" uuid NOT NULL
|
|
33
|
+
REFERENCES "knowledge_claim_reviews"("id") ON DELETE RESTRICT,
|
|
34
|
+
"knowledge_approval_review_revision" bigint NOT NULL,
|
|
35
|
+
"knowledge_approval_input_hash" text NOT NULL,
|
|
36
|
+
"destination" text NOT NULL,
|
|
37
|
+
"destination_proposal_id" uuid NOT NULL,
|
|
38
|
+
"destination_revision_id" uuid NOT NULL,
|
|
39
|
+
"destination_old_revision_id" uuid,
|
|
40
|
+
"destination_old_content_hash" text,
|
|
41
|
+
"destination_old_version" bigint NOT NULL,
|
|
42
|
+
"destination_new_content_hash" text NOT NULL,
|
|
43
|
+
"destination_new_version" bigint NOT NULL,
|
|
44
|
+
"destination_event_id" uuid NOT NULL,
|
|
45
|
+
"effective_at" timestamptz NOT NULL,
|
|
46
|
+
"created_at" timestamptz NOT NULL DEFAULT transaction_timestamp(),
|
|
47
|
+
CONSTRAINT "governed_learning_activation_receipts_operation_uq"
|
|
48
|
+
UNIQUE ("workspace_id", "operation_id"),
|
|
49
|
+
CONSTRAINT "governed_learning_activation_receipts_decision_uq"
|
|
50
|
+
UNIQUE ("decision_receipt_id"),
|
|
51
|
+
CONSTRAINT "governed_learning_activation_receipts_identity_chk" CHECK (
|
|
52
|
+
length(btrim("initiating_human_subject_id")) BETWEEN 1 AND 1024
|
|
53
|
+
AND octet_length(convert_to("initiating_human_subject_id", 'UTF8')) <= 4096
|
|
54
|
+
AND length(btrim("service_actor_subject_id")) BETWEEN 1 AND 1024
|
|
55
|
+
AND "service_actor_subject_id" LIKE 'service:governed-learning-activation:%'
|
|
56
|
+
),
|
|
57
|
+
CONSTRAINT "governed_learning_activation_receipts_hash_chk" CHECK (
|
|
58
|
+
"input_hash" ~ '^[0-9a-f]{64}$'
|
|
59
|
+
AND "policy_hash" ~ '^[0-9a-f]{64}$'
|
|
60
|
+
AND "source_authority_hash" ~ '^[0-9a-f]{64}$'
|
|
61
|
+
AND "knowledge_approval_input_hash" ~ '^[0-9a-f]{64}$'
|
|
62
|
+
AND "destination_new_content_hash" ~ '^[0-9a-f]{64}$'
|
|
63
|
+
AND ("destination_old_content_hash" IS NULL
|
|
64
|
+
OR "destination_old_content_hash" ~ '^[0-9a-f]{64}$')
|
|
65
|
+
),
|
|
66
|
+
CONSTRAINT "governed_learning_activation_receipts_boundary_chk" CHECK (
|
|
67
|
+
"policy_activation_version" > 0
|
|
68
|
+
AND "source_kind" IN ('scoped-knowledge-evidence', 'task-note')
|
|
69
|
+
AND "knowledge_previous_review_revision" > 0
|
|
70
|
+
AND "knowledge_approval_review_revision" > "knowledge_previous_review_revision"
|
|
71
|
+
AND "destination" IN ('instruction_policy', 'preference')
|
|
72
|
+
AND "destination_old_version" >= 0
|
|
73
|
+
AND "destination_new_version" > "destination_old_version"
|
|
74
|
+
AND (("destination_old_revision_id" IS NULL AND "destination_old_content_hash" IS NULL)
|
|
75
|
+
OR ("destination_old_revision_id" IS NOT NULL
|
|
76
|
+
AND "destination_old_content_hash" IS NOT NULL))
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
CREATE INDEX "governed_learning_activation_receipts_workspace_time_idx"
|
|
81
|
+
ON "governed_learning_activation_receipts" ("workspace_id", "created_at" DESC, "id" DESC);
|
|
82
|
+
|
|
83
|
+
CREATE TABLE "governed_learning_activation_undo_receipts" (
|
|
84
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
85
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
86
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
87
|
+
"operation_id" uuid NOT NULL,
|
|
88
|
+
"input_hash" text NOT NULL,
|
|
89
|
+
"activation_receipt_id" uuid NOT NULL
|
|
90
|
+
REFERENCES "governed_learning_activation_receipts"("id") ON DELETE RESTRICT,
|
|
91
|
+
"initiating_human_subject_id" text NOT NULL,
|
|
92
|
+
"service_actor_subject_id" text NOT NULL,
|
|
93
|
+
"destination" text NOT NULL,
|
|
94
|
+
"knowledge_approval_review_id" uuid NOT NULL
|
|
95
|
+
REFERENCES "knowledge_claim_reviews"("id") ON DELETE RESTRICT,
|
|
96
|
+
"knowledge_revocation_review_id" uuid NOT NULL
|
|
97
|
+
REFERENCES "knowledge_claim_reviews"("id") ON DELETE RESTRICT,
|
|
98
|
+
"knowledge_revocation_review_revision" bigint NOT NULL,
|
|
99
|
+
"knowledge_revocation_input_hash" text NOT NULL,
|
|
100
|
+
"destination_activated_revision_id" uuid NOT NULL,
|
|
101
|
+
"destination_restored_revision_id" uuid,
|
|
102
|
+
"destination_activated_content_hash" text NOT NULL,
|
|
103
|
+
"destination_restored_content_hash" text,
|
|
104
|
+
"destination_old_version" bigint NOT NULL,
|
|
105
|
+
"destination_new_version" bigint NOT NULL,
|
|
106
|
+
"destination_event_id" uuid NOT NULL,
|
|
107
|
+
"effective_at" timestamptz NOT NULL,
|
|
108
|
+
"created_at" timestamptz NOT NULL DEFAULT transaction_timestamp(),
|
|
109
|
+
CONSTRAINT "governed_learning_activation_undo_receipts_operation_uq"
|
|
110
|
+
UNIQUE ("workspace_id", "operation_id"),
|
|
111
|
+
CONSTRAINT "governed_learning_activation_undo_receipts_activation_uq"
|
|
112
|
+
UNIQUE ("activation_receipt_id"),
|
|
113
|
+
CONSTRAINT "governed_learning_activation_undo_receipts_identity_chk" CHECK (
|
|
114
|
+
length(btrim("initiating_human_subject_id")) BETWEEN 1 AND 1024
|
|
115
|
+
AND length(btrim("service_actor_subject_id")) BETWEEN 1 AND 1024
|
|
116
|
+
AND "service_actor_subject_id" LIKE 'service:governed-learning-activation:%'
|
|
117
|
+
),
|
|
118
|
+
CONSTRAINT "governed_learning_activation_undo_receipts_hash_chk" CHECK (
|
|
119
|
+
"input_hash" ~ '^[0-9a-f]{64}$'
|
|
120
|
+
AND "knowledge_revocation_input_hash" ~ '^[0-9a-f]{64}$'
|
|
121
|
+
AND "destination_activated_content_hash" ~ '^[0-9a-f]{64}$'
|
|
122
|
+
AND ("destination_restored_content_hash" IS NULL
|
|
123
|
+
OR "destination_restored_content_hash" ~ '^[0-9a-f]{64}$')
|
|
124
|
+
),
|
|
125
|
+
CONSTRAINT "governed_learning_activation_undo_receipts_boundary_chk" CHECK (
|
|
126
|
+
"destination" IN ('instruction_policy', 'preference')
|
|
127
|
+
AND "knowledge_revocation_review_revision" > 0
|
|
128
|
+
AND "destination_old_version" > 0
|
|
129
|
+
AND "destination_new_version" > "destination_old_version"
|
|
130
|
+
AND (("destination_restored_revision_id" IS NULL
|
|
131
|
+
AND "destination_restored_content_hash" IS NULL)
|
|
132
|
+
OR ("destination_restored_revision_id" IS NOT NULL
|
|
133
|
+
AND "destination_restored_content_hash" IS NOT NULL))
|
|
134
|
+
)
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
CREATE INDEX "governed_learning_activation_undo_receipts_workspace_time_idx"
|
|
138
|
+
ON "governed_learning_activation_undo_receipts" ("workspace_id", "created_at" DESC, "id" DESC);
|
|
139
|
+
|
|
140
|
+
ALTER TABLE "governed_learning_activation_receipts" ENABLE ROW LEVEL SECURITY;
|
|
141
|
+
ALTER TABLE "governed_learning_activation_receipts" FORCE ROW LEVEL SECURITY;
|
|
142
|
+
ALTER TABLE "governed_learning_activation_undo_receipts" ENABLE ROW LEVEL SECURITY;
|
|
143
|
+
ALTER TABLE "governed_learning_activation_undo_receipts" FORCE ROW LEVEL SECURITY;
|
|
144
|
+
|
|
145
|
+
CREATE POLICY governed_learning_activation_receipts_tenant
|
|
146
|
+
ON "governed_learning_activation_receipts"
|
|
147
|
+
USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
|
|
148
|
+
WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
|
|
149
|
+
CREATE POLICY governed_learning_activation_receipts_subject
|
|
150
|
+
ON "governed_learning_activation_receipts" AS RESTRICTIVE
|
|
151
|
+
USING ("initiating_human_subject_id" = nullif(current_setting('opengeni.subject_id', true), ''))
|
|
152
|
+
WITH CHECK ("initiating_human_subject_id" = nullif(current_setting('opengeni.subject_id', true), ''));
|
|
153
|
+
CREATE POLICY governed_learning_activation_undo_receipts_tenant
|
|
154
|
+
ON "governed_learning_activation_undo_receipts"
|
|
155
|
+
USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
|
|
156
|
+
WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
|
|
157
|
+
CREATE POLICY governed_learning_activation_undo_receipts_subject
|
|
158
|
+
ON "governed_learning_activation_undo_receipts" AS RESTRICTIVE
|
|
159
|
+
USING ("initiating_human_subject_id" = nullif(current_setting('opengeni.subject_id', true), ''))
|
|
160
|
+
WITH CHECK ("initiating_human_subject_id" = nullif(current_setting('opengeni.subject_id', true), ''));
|
|
161
|
+
|
|
162
|
+
CREATE OR REPLACE FUNCTION governed_learning_reject_activation_receipt_mutation()
|
|
163
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
164
|
+
BEGIN
|
|
165
|
+
IF TG_OP = 'DELETE' AND pg_trigger_depth() > 1 AND (
|
|
166
|
+
NOT EXISTS (SELECT 1 FROM managed_accounts WHERE id = OLD.account_id)
|
|
167
|
+
OR NOT EXISTS (SELECT 1 FROM workspaces WHERE id = OLD.workspace_id)
|
|
168
|
+
) THEN
|
|
169
|
+
RETURN OLD;
|
|
170
|
+
END IF;
|
|
171
|
+
RAISE EXCEPTION 'governed-learning activation receipts are immutable'
|
|
172
|
+
USING ERRCODE = '55000';
|
|
173
|
+
END;
|
|
174
|
+
$$;
|
|
175
|
+
|
|
176
|
+
CREATE TRIGGER governed_learning_activation_receipts_immutable
|
|
177
|
+
BEFORE UPDATE OR DELETE ON "governed_learning_activation_receipts"
|
|
178
|
+
FOR EACH ROW EXECUTE FUNCTION governed_learning_reject_activation_receipt_mutation();
|
|
179
|
+
CREATE TRIGGER governed_learning_activation_undo_receipts_immutable
|
|
180
|
+
BEFORE UPDATE OR DELETE ON "governed_learning_activation_undo_receipts"
|
|
181
|
+
FOR EACH ROW EXECUTE FUNCTION governed_learning_reject_activation_receipt_mutation();
|
|
182
|
+
|
|
183
|
+
CREATE OR REPLACE FUNCTION opengeni_private.governed_learning_derived_uuid(
|
|
184
|
+
p_operation_id uuid,
|
|
185
|
+
p_label text
|
|
186
|
+
) RETURNS uuid LANGUAGE sql IMMUTABLE STRICT AS $$
|
|
187
|
+
SELECT (
|
|
188
|
+
substr(value, 1, 8) || '-' || substr(value, 9, 4) || '-5' || substr(value, 14, 3)
|
|
189
|
+
|| '-' || substr('89ab', 1 + (get_byte(decode(substr(value, 17, 2), 'hex'), 0) & 3), 1)
|
|
190
|
+
|| substr(value, 18, 3) || '-' || substr(value, 21, 12)
|
|
191
|
+
)::uuid
|
|
192
|
+
FROM (
|
|
193
|
+
SELECT encode(sha256(convert_to(
|
|
194
|
+
concat('governed-learning-activation:v1:', p_operation_id, ':', p_label), 'UTF8'
|
|
195
|
+
)), 'hex') AS value
|
|
196
|
+
) digest;
|
|
197
|
+
$$;
|
|
198
|
+
REVOKE ALL ON FUNCTION opengeni_private.governed_learning_derived_uuid(uuid, text) FROM PUBLIC;
|
|
199
|
+
|
|
200
|
+
-- Service approvals/revocations are admitted only through the private native
|
|
201
|
+
-- adapter below. Broadening the row check without this trigger would let any
|
|
202
|
+
-- service-shaped direct insert manufacture accepted Knowledge authority.
|
|
203
|
+
ALTER TABLE "knowledge_claim_reviews"
|
|
204
|
+
DROP CONSTRAINT "knowledge_claim_reviews_review_chk";
|
|
205
|
+
ALTER TABLE "knowledge_claim_reviews"
|
|
206
|
+
ADD CONSTRAINT "knowledge_claim_reviews_review_chk" CHECK (
|
|
207
|
+
"state" IN ('proposed', 'approved', 'rejected', 'revoked')
|
|
208
|
+
AND "review_revision" > 0
|
|
209
|
+
AND length(btrim("reason")) BETWEEN 1 AND 4096
|
|
210
|
+
AND (
|
|
211
|
+
"state" = 'proposed'
|
|
212
|
+
OR ("actor_kind" = 'human' AND "actor_subject_id" = "initiating_human_subject_id")
|
|
213
|
+
OR (
|
|
214
|
+
"actor_kind" = 'service'
|
|
215
|
+
AND "actor_subject_id" LIKE 'service:governed-learning-activation:%'
|
|
216
|
+
AND "initiating_human_subject_id" IS NOT NULL
|
|
217
|
+
)
|
|
218
|
+
)
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
CREATE OR REPLACE FUNCTION governed_learning_guard_service_review()
|
|
222
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
223
|
+
DECLARE capability_writer boolean;
|
|
224
|
+
BEGIN
|
|
225
|
+
SELECT current_user = pg_catalog.pg_get_userbyid(procedure_row.proowner)
|
|
226
|
+
INTO capability_writer
|
|
227
|
+
FROM pg_catalog.pg_proc procedure_row
|
|
228
|
+
WHERE procedure_row.oid = pg_catalog.to_regprocedure(pg_catalog.format(
|
|
229
|
+
'%I.governed_learning_apply_knowledge_review(uuid,uuid,uuid,uuid,uuid,bigint,text,text,text)',
|
|
230
|
+
TG_TABLE_SCHEMA
|
|
231
|
+
));
|
|
232
|
+
IF NEW.state <> 'proposed' AND NEW.actor_kind = 'service' AND (
|
|
233
|
+
NOT coalesce(capability_writer, false)
|
|
234
|
+
OR current_setting('opengeni.governed_learning_review_operation', true)
|
|
235
|
+
IS DISTINCT FROM NEW.operation_id
|
|
236
|
+
OR current_setting('opengeni.governed_learning_review_claim', true)
|
|
237
|
+
IS DISTINCT FROM NEW.claim_id::text
|
|
238
|
+
) THEN
|
|
239
|
+
RAISE EXCEPTION 'service Knowledge review requires exact governed-learning capability'
|
|
240
|
+
USING ERRCODE = '42501';
|
|
241
|
+
END IF;
|
|
242
|
+
RETURN NEW;
|
|
243
|
+
END;
|
|
244
|
+
$$;
|
|
245
|
+
CREATE TRIGGER knowledge_claim_reviews_05_governed_learning_guard
|
|
246
|
+
BEFORE INSERT ON "knowledge_claim_reviews"
|
|
247
|
+
FOR EACH ROW EXECUTE FUNCTION governed_learning_guard_service_review();
|
|
248
|
+
|
|
249
|
+
CREATE OR REPLACE FUNCTION governed_learning_apply_knowledge_review(
|
|
250
|
+
p_account_id uuid,
|
|
251
|
+
p_workspace_id uuid,
|
|
252
|
+
p_operation_id uuid,
|
|
253
|
+
p_claim_id uuid,
|
|
254
|
+
p_expected_review_id uuid,
|
|
255
|
+
p_expected_review_revision bigint,
|
|
256
|
+
p_state text,
|
|
257
|
+
p_actor_subject_id text,
|
|
258
|
+
p_initiating_human_subject_id text
|
|
259
|
+
) RETURNS SETOF knowledge_claim_reviews
|
|
260
|
+
LANGUAGE plpgsql SECURITY DEFINER AS $$
|
|
261
|
+
DECLARE
|
|
262
|
+
claim_row knowledge_claims%ROWTYPE;
|
|
263
|
+
current_review knowledge_claim_reviews%ROWTYPE;
|
|
264
|
+
result_row knowledge_claim_reviews%ROWTYPE;
|
|
265
|
+
input_hash_value text;
|
|
266
|
+
BEGIN
|
|
267
|
+
IF p_state NOT IN ('approved', 'revoked')
|
|
268
|
+
OR p_actor_subject_id NOT LIKE 'service:governed-learning-activation:%'
|
|
269
|
+
OR length(btrim(p_initiating_human_subject_id)) NOT BETWEEN 1 AND 1024
|
|
270
|
+
THEN
|
|
271
|
+
RAISE EXCEPTION 'governed-learning Knowledge review input is invalid'
|
|
272
|
+
USING ERRCODE = '22023';
|
|
273
|
+
END IF;
|
|
274
|
+
SELECT * INTO claim_row FROM knowledge_claims claim
|
|
275
|
+
WHERE claim.account_id = p_account_id AND claim.id = p_claim_id
|
|
276
|
+
AND claim.scope_kind = 'workspace'
|
|
277
|
+
AND claim.scope_workspace_id = p_workspace_id
|
|
278
|
+
AND claim.scope_subject_id IS NULL
|
|
279
|
+
AND claim.initiating_human_subject_id = p_initiating_human_subject_id
|
|
280
|
+
FOR UPDATE;
|
|
281
|
+
IF NOT FOUND THEN
|
|
282
|
+
RAISE EXCEPTION 'governed-learning Knowledge claim is unavailable' USING ERRCODE = '42501';
|
|
283
|
+
END IF;
|
|
284
|
+
SELECT * INTO current_review FROM knowledge_claim_reviews review
|
|
285
|
+
WHERE review.account_id = p_account_id AND review.claim_id = p_claim_id
|
|
286
|
+
ORDER BY review.review_revision DESC LIMIT 1 FOR SHARE;
|
|
287
|
+
IF current_review.id IS DISTINCT FROM p_expected_review_id
|
|
288
|
+
OR current_review.review_revision IS DISTINCT FROM p_expected_review_revision
|
|
289
|
+
OR (p_state = 'approved' AND current_review.state <> 'proposed')
|
|
290
|
+
OR (p_state = 'revoked' AND current_review.state <> 'approved')
|
|
291
|
+
THEN
|
|
292
|
+
RAISE EXCEPTION 'governed-learning Knowledge review was superseded'
|
|
293
|
+
USING ERRCODE = '40001';
|
|
294
|
+
END IF;
|
|
295
|
+
input_hash_value := encode(sha256(convert_to(jsonb_build_array(
|
|
296
|
+
'governed-learning-native-review', 1, p_account_id, p_workspace_id,
|
|
297
|
+
p_operation_id, p_claim_id, p_expected_review_id,
|
|
298
|
+
p_expected_review_revision, p_state, p_actor_subject_id,
|
|
299
|
+
p_initiating_human_subject_id
|
|
300
|
+
)::text, 'UTF8')), 'hex');
|
|
301
|
+
PERFORM set_config('opengeni.governed_learning_review_operation', p_operation_id::text, true);
|
|
302
|
+
PERFORM set_config('opengeni.governed_learning_review_claim', p_claim_id::text, true);
|
|
303
|
+
INSERT INTO knowledge_claim_reviews (
|
|
304
|
+
account_id, scope_kind, scope_workspace_id, scope_subject_id, scope_key,
|
|
305
|
+
claim_id, state, reason, operation_id, input_hash, actor_kind,
|
|
306
|
+
actor_subject_id, initiating_human_subject_id
|
|
307
|
+
) VALUES (
|
|
308
|
+
p_account_id, claim_row.scope_kind, claim_row.scope_workspace_id,
|
|
309
|
+
claim_row.scope_subject_id, claim_row.scope_key, p_claim_id, p_state,
|
|
310
|
+
CASE p_state WHEN 'approved' THEN 'Automatic governed-learning activation.'
|
|
311
|
+
ELSE 'Exact governed-learning activation undo.' END,
|
|
312
|
+
p_operation_id::text, input_hash_value, 'service', p_actor_subject_id,
|
|
313
|
+
p_initiating_human_subject_id
|
|
314
|
+
) RETURNING * INTO result_row;
|
|
315
|
+
PERFORM set_config('opengeni.governed_learning_review_operation', '', true);
|
|
316
|
+
PERFORM set_config('opengeni.governed_learning_review_claim', '', true);
|
|
317
|
+
RETURN NEXT result_row;
|
|
318
|
+
END;
|
|
319
|
+
$$;
|
|
320
|
+
REVOKE ALL ON FUNCTION governed_learning_apply_knowledge_review(
|
|
321
|
+
uuid, uuid, uuid, uuid, uuid, bigint, text, text, text
|
|
322
|
+
) FROM PUBLIC;
|
|
323
|
+
|
|
324
|
+
-- Deactivation history is additive so rolling old API binaries continue to
|
|
325
|
+
-- read the legacy activation-event shape with a required new revision.
|
|
326
|
+
CREATE TABLE "workspace_instruction_policy_deactivation_events" (
|
|
327
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
328
|
+
"operation_id" uuid NOT NULL,
|
|
329
|
+
"request_fingerprint" text NOT NULL,
|
|
330
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
331
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
332
|
+
"kind" text NOT NULL,
|
|
333
|
+
"scope" text NOT NULL,
|
|
334
|
+
"role_key" text,
|
|
335
|
+
"type" text NOT NULL DEFAULT 'automatic_deactivate',
|
|
336
|
+
"activation_version" bigint NOT NULL,
|
|
337
|
+
"old_revision_id" uuid NOT NULL
|
|
338
|
+
REFERENCES "workspace_instruction_policy_revisions"("id") ON DELETE RESTRICT,
|
|
339
|
+
"old_revision" bigint NOT NULL,
|
|
340
|
+
"old_content_hash" text NOT NULL,
|
|
341
|
+
"actor_subject_id" text NOT NULL,
|
|
342
|
+
"reason" text NOT NULL,
|
|
343
|
+
"created_at" timestamptz NOT NULL DEFAULT transaction_timestamp(),
|
|
344
|
+
CONSTRAINT "workspace_instruction_policy_deactivations_receipt_chk" CHECK (
|
|
345
|
+
"request_fingerprint" ~ '^[0-9a-f]{64}$'
|
|
346
|
+
),
|
|
347
|
+
CONSTRAINT "workspace_instruction_policy_deactivations_target_chk" CHECK (
|
|
348
|
+
("kind" = 'charter' AND "scope" = 'global' AND "role_key" IS NULL)
|
|
349
|
+
OR ("kind" = 'policy' AND "scope" = 'global' AND "role_key" IS NULL)
|
|
350
|
+
OR ("kind" = 'policy' AND "scope" = 'role' AND "role_key" IS NOT NULL)
|
|
351
|
+
),
|
|
352
|
+
CONSTRAINT "workspace_instruction_policy_deactivations_boundary_chk" CHECK (
|
|
353
|
+
"type" = 'automatic_deactivate'
|
|
354
|
+
AND "activation_version" > 0
|
|
355
|
+
AND "old_revision" > 0
|
|
356
|
+
AND "old_content_hash" ~ '^[0-9a-f]{64}$'
|
|
357
|
+
AND "actor_subject_id" LIKE 'service:governed-learning-activation:%'
|
|
358
|
+
AND length(btrim("actor_subject_id")) BETWEEN 1 AND 1024
|
|
359
|
+
AND length(btrim("reason")) BETWEEN 1 AND 4096
|
|
360
|
+
),
|
|
361
|
+
CONSTRAINT "workspace_instruction_policy_deactivate_workspace_operation_uq"
|
|
362
|
+
UNIQUE ("workspace_id", "operation_id")
|
|
363
|
+
);
|
|
364
|
+
CREATE UNIQUE INDEX "workspace_instruction_policy_deactivations_target_version_uq"
|
|
365
|
+
ON "workspace_instruction_policy_deactivation_events"
|
|
366
|
+
("workspace_id", "kind", "scope", coalesce("role_key", ''), "activation_version");
|
|
367
|
+
CREATE INDEX "workspace_instruction_policy_deactivations_workspace_time_idx"
|
|
368
|
+
ON "workspace_instruction_policy_deactivation_events"
|
|
369
|
+
("workspace_id", "created_at" DESC, "id" DESC);
|
|
370
|
+
|
|
371
|
+
ALTER TABLE "workspace_instruction_policy_deactivation_events" ENABLE ROW LEVEL SECURITY;
|
|
372
|
+
ALTER TABLE "workspace_instruction_policy_deactivation_events" FORCE ROW LEVEL SECURITY;
|
|
373
|
+
CREATE POLICY workspace_isolation ON "workspace_instruction_policy_deactivation_events"
|
|
374
|
+
USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
|
|
375
|
+
WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
|
|
376
|
+
CREATE TRIGGER workspace_instruction_policy_deactivations_immutable
|
|
377
|
+
BEFORE UPDATE OR DELETE ON "workspace_instruction_policy_deactivation_events"
|
|
378
|
+
FOR EACH ROW EXECUTE FUNCTION workspace_instruction_policy_reject_mutation();
|
|
379
|
+
|
|
380
|
+
CREATE OR REPLACE FUNCTION workspace_instruction_policy_validate_deactivation_event()
|
|
381
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
382
|
+
BEGIN
|
|
383
|
+
IF NOT EXISTS (
|
|
384
|
+
SELECT 1 FROM workspace_instruction_policy_revisions revision
|
|
385
|
+
WHERE revision.id = NEW.old_revision_id
|
|
386
|
+
AND revision.account_id = NEW.account_id
|
|
387
|
+
AND revision.workspace_id = NEW.workspace_id
|
|
388
|
+
AND revision.kind = NEW.kind
|
|
389
|
+
AND revision.scope = NEW.scope
|
|
390
|
+
AND revision.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
391
|
+
AND revision.revision = NEW.old_revision
|
|
392
|
+
AND revision.content_hash = NEW.old_content_hash
|
|
393
|
+
) THEN
|
|
394
|
+
RAISE EXCEPTION 'instruction-policy deactivation event has an invalid old revision'
|
|
395
|
+
USING ERRCODE = '23514';
|
|
396
|
+
END IF;
|
|
397
|
+
RETURN NEW;
|
|
398
|
+
END;
|
|
399
|
+
$$;
|
|
400
|
+
CREATE TRIGGER workspace_instruction_policy_deactivations_validate_revision
|
|
401
|
+
BEFORE INSERT ON "workspace_instruction_policy_deactivation_events"
|
|
402
|
+
FOR EACH ROW EXECUTE FUNCTION workspace_instruction_policy_validate_deactivation_event();
|
|
403
|
+
|
|
404
|
+
CREATE OR REPLACE FUNCTION workspace_instruction_policy_guard_lifecycle_operation()
|
|
405
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
406
|
+
BEGIN
|
|
407
|
+
IF TG_TABLE_NAME = 'workspace_instruction_policy_deactivation_events' THEN
|
|
408
|
+
IF EXISTS (
|
|
409
|
+
SELECT 1 FROM workspace_instruction_policy_activation_events event
|
|
410
|
+
WHERE event.workspace_id = NEW.workspace_id
|
|
411
|
+
AND event.operation_id = NEW.operation_id
|
|
412
|
+
) THEN
|
|
413
|
+
RAISE EXCEPTION 'instruction-policy lifecycle operation was already used'
|
|
414
|
+
USING ERRCODE = '23505';
|
|
415
|
+
END IF;
|
|
416
|
+
ELSIF NEW.operation_id IS NOT NULL AND EXISTS (
|
|
417
|
+
SELECT 1 FROM workspace_instruction_policy_deactivation_events event
|
|
418
|
+
WHERE event.workspace_id = NEW.workspace_id
|
|
419
|
+
AND event.operation_id = NEW.operation_id
|
|
420
|
+
) THEN
|
|
421
|
+
RAISE EXCEPTION 'instruction-policy lifecycle operation was already used'
|
|
422
|
+
USING ERRCODE = '23505';
|
|
423
|
+
END IF;
|
|
424
|
+
RETURN NEW;
|
|
425
|
+
END;
|
|
426
|
+
$$;
|
|
427
|
+
CREATE TRIGGER workspace_instruction_policy_activations_operation_guard
|
|
428
|
+
BEFORE INSERT ON "workspace_instruction_policy_activation_events"
|
|
429
|
+
FOR EACH ROW EXECUTE FUNCTION workspace_instruction_policy_guard_lifecycle_operation();
|
|
430
|
+
CREATE TRIGGER workspace_instruction_policy_deactivations_operation_guard
|
|
431
|
+
BEFORE INSERT ON "workspace_instruction_policy_deactivation_events"
|
|
432
|
+
FOR EACH ROW EXECUTE FUNCTION workspace_instruction_policy_guard_lifecycle_operation();
|
|
433
|
+
|
|
434
|
+
CREATE OR REPLACE FUNCTION workspace_instruction_policy_guard_head_delete()
|
|
435
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
436
|
+
DECLARE capability_writer boolean;
|
|
437
|
+
BEGIN
|
|
438
|
+
IF pg_trigger_depth() > 1 AND NOT EXISTS (
|
|
439
|
+
SELECT 1 FROM workspaces workspace WHERE workspace.id = OLD.workspace_id
|
|
440
|
+
) THEN
|
|
441
|
+
RETURN OLD;
|
|
442
|
+
END IF;
|
|
443
|
+
SELECT current_user = pg_catalog.pg_get_userbyid(procedure_row.proowner)
|
|
444
|
+
INTO capability_writer
|
|
445
|
+
FROM pg_catalog.pg_proc procedure_row
|
|
446
|
+
WHERE procedure_row.oid = pg_catalog.to_regprocedure(pg_catalog.format(
|
|
447
|
+
'%I.governed_learning_deactivate_instruction_policy(uuid,uuid,uuid,uuid,uuid,bigint,text)',
|
|
448
|
+
TG_TABLE_SCHEMA
|
|
449
|
+
));
|
|
450
|
+
IF NOT coalesce(capability_writer, false)
|
|
451
|
+
OR current_setting('opengeni.governed_learning_deactivation_operation', true) IS NULL
|
|
452
|
+
OR current_setting('opengeni.governed_learning_deactivation_operation', true) = ''
|
|
453
|
+
THEN
|
|
454
|
+
RAISE EXCEPTION 'instruction-policy head deletion requires governed-learning capability'
|
|
455
|
+
USING ERRCODE = '42501';
|
|
456
|
+
END IF;
|
|
457
|
+
RETURN OLD;
|
|
458
|
+
END;
|
|
459
|
+
$$;
|
|
460
|
+
CREATE TRIGGER workspace_instruction_policy_heads_deactivation_guard
|
|
461
|
+
BEFORE DELETE ON "workspace_instruction_policy_heads"
|
|
462
|
+
FOR EACH ROW EXECUTE FUNCTION workspace_instruction_policy_guard_head_delete();
|
|
463
|
+
|
|
464
|
+
ALTER TABLE "workspace_instruction_policy_onboarding_proposals"
|
|
465
|
+
DROP CONSTRAINT "workspace_instruction_policy_onboarding_proposals_baseline_chk";
|
|
466
|
+
ALTER TABLE "workspace_instruction_policy_onboarding_proposals"
|
|
467
|
+
ADD CONSTRAINT "workspace_instruction_policy_onboarding_proposals_baseline_chk" CHECK (
|
|
468
|
+
(
|
|
469
|
+
"baseline_revision_id" IS NULL
|
|
470
|
+
AND "baseline_revision" IS NULL
|
|
471
|
+
AND "baseline_content_hash" IS NULL
|
|
472
|
+
AND "baseline_activation_version" >= 0
|
|
473
|
+
AND "baseline_activated_at" IS NULL
|
|
474
|
+
) OR (
|
|
475
|
+
"baseline_revision_id" IS NOT NULL
|
|
476
|
+
AND "baseline_revision" > 0
|
|
477
|
+
AND "baseline_content_hash" ~ '^[0-9a-f]{64}$'
|
|
478
|
+
AND "baseline_activation_version" > 0
|
|
479
|
+
AND "baseline_activated_at" IS NOT NULL
|
|
480
|
+
)
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
CREATE OR REPLACE FUNCTION workspace_instruction_policy_validate_onboarding_proposal()
|
|
484
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
485
|
+
BEGIN
|
|
486
|
+
IF NEW.baseline_revision_id IS NULL THEN
|
|
487
|
+
IF EXISTS (
|
|
488
|
+
SELECT 1 FROM workspace_instruction_policy_heads head
|
|
489
|
+
WHERE head.account_id = NEW.account_id
|
|
490
|
+
AND head.workspace_id = NEW.workspace_id
|
|
491
|
+
AND head.kind = NEW.kind
|
|
492
|
+
AND head.scope = NEW.scope
|
|
493
|
+
AND head.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
494
|
+
) THEN
|
|
495
|
+
RAISE EXCEPTION 'instruction-policy proposal must capture the exact active head baseline'
|
|
496
|
+
USING ERRCODE = '23514';
|
|
497
|
+
END IF;
|
|
498
|
+
IF NOT (
|
|
499
|
+
(
|
|
500
|
+
NEW.baseline_activation_version = 0
|
|
501
|
+
AND NOT EXISTS (
|
|
502
|
+
SELECT 1 FROM workspace_instruction_policy_heads head
|
|
503
|
+
WHERE head.account_id = NEW.account_id
|
|
504
|
+
AND head.workspace_id = NEW.workspace_id
|
|
505
|
+
AND head.kind = NEW.kind
|
|
506
|
+
AND head.scope = NEW.scope
|
|
507
|
+
AND head.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
508
|
+
)
|
|
509
|
+
AND NOT EXISTS (
|
|
510
|
+
SELECT 1 FROM workspace_instruction_policy_deactivation_events event
|
|
511
|
+
WHERE event.account_id = NEW.account_id
|
|
512
|
+
AND event.workspace_id = NEW.workspace_id
|
|
513
|
+
AND event.kind = NEW.kind
|
|
514
|
+
AND event.scope = NEW.scope
|
|
515
|
+
AND event.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
516
|
+
)
|
|
517
|
+
) OR (
|
|
518
|
+
NEW.baseline_activation_version > 0
|
|
519
|
+
AND NOT EXISTS (
|
|
520
|
+
SELECT 1 FROM workspace_instruction_policy_heads head
|
|
521
|
+
WHERE head.account_id = NEW.account_id
|
|
522
|
+
AND head.workspace_id = NEW.workspace_id
|
|
523
|
+
AND head.kind = NEW.kind
|
|
524
|
+
AND head.scope = NEW.scope
|
|
525
|
+
AND head.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
526
|
+
)
|
|
527
|
+
AND EXISTS (
|
|
528
|
+
SELECT 1 FROM workspace_instruction_policy_deactivation_events event
|
|
529
|
+
WHERE event.account_id = NEW.account_id
|
|
530
|
+
AND event.workspace_id = NEW.workspace_id
|
|
531
|
+
AND event.kind = NEW.kind
|
|
532
|
+
AND event.scope = NEW.scope
|
|
533
|
+
AND event.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
534
|
+
AND event.activation_version = NEW.baseline_activation_version
|
|
535
|
+
AND NOT EXISTS (
|
|
536
|
+
SELECT 1 FROM workspace_instruction_policy_deactivation_events newer
|
|
537
|
+
WHERE newer.account_id = event.account_id
|
|
538
|
+
AND newer.workspace_id = event.workspace_id
|
|
539
|
+
AND newer.kind = event.kind
|
|
540
|
+
AND newer.scope = event.scope
|
|
541
|
+
AND newer.role_key IS NOT DISTINCT FROM event.role_key
|
|
542
|
+
AND newer.activation_version > event.activation_version
|
|
543
|
+
)
|
|
544
|
+
)
|
|
545
|
+
)
|
|
546
|
+
) THEN
|
|
547
|
+
RAISE EXCEPTION 'instruction-policy proposal must capture the exact inactive boundary'
|
|
548
|
+
USING ERRCODE = '23514';
|
|
549
|
+
END IF;
|
|
550
|
+
ELSIF NOT EXISTS (
|
|
551
|
+
SELECT 1 FROM workspace_instruction_policy_heads head
|
|
552
|
+
WHERE head.account_id = NEW.account_id
|
|
553
|
+
AND head.workspace_id = NEW.workspace_id
|
|
554
|
+
AND head.kind = NEW.kind
|
|
555
|
+
AND head.scope = NEW.scope
|
|
556
|
+
AND head.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
557
|
+
AND head.revision_id = NEW.baseline_revision_id
|
|
558
|
+
AND head.revision = NEW.baseline_revision
|
|
559
|
+
AND head.content_hash = NEW.baseline_content_hash
|
|
560
|
+
AND head.activation_version = NEW.baseline_activation_version
|
|
561
|
+
AND head.activated_at = NEW.baseline_activated_at
|
|
562
|
+
) THEN
|
|
563
|
+
RAISE EXCEPTION 'instruction-policy proposal must capture the exact active head baseline'
|
|
564
|
+
USING ERRCODE = '23514';
|
|
565
|
+
END IF;
|
|
566
|
+
|
|
567
|
+
IF NEW.baseline_revision_id IS NOT NULL AND NOT EXISTS (
|
|
568
|
+
SELECT 1 FROM workspace_instruction_policy_revisions revision
|
|
569
|
+
WHERE revision.id = NEW.baseline_revision_id
|
|
570
|
+
AND revision.account_id = NEW.account_id
|
|
571
|
+
AND revision.workspace_id = NEW.workspace_id
|
|
572
|
+
AND revision.kind = NEW.kind
|
|
573
|
+
AND revision.scope = NEW.scope
|
|
574
|
+
AND revision.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
575
|
+
AND revision.revision = NEW.baseline_revision
|
|
576
|
+
AND revision.content_hash = NEW.baseline_content_hash
|
|
577
|
+
) THEN
|
|
578
|
+
RAISE EXCEPTION 'instruction-policy proposal has an invalid baseline revision'
|
|
579
|
+
USING ERRCODE = '23514';
|
|
580
|
+
END IF;
|
|
581
|
+
|
|
582
|
+
IF NOT EXISTS (
|
|
583
|
+
SELECT 1 FROM workspace_instruction_policy_revisions revision
|
|
584
|
+
WHERE revision.id = NEW.draft_revision_id
|
|
585
|
+
AND revision.operation_id = NEW.operation_id
|
|
586
|
+
AND revision.request_fingerprint = NEW.request_fingerprint
|
|
587
|
+
AND revision.account_id = NEW.account_id
|
|
588
|
+
AND revision.workspace_id = NEW.workspace_id
|
|
589
|
+
AND revision.kind = NEW.kind
|
|
590
|
+
AND revision.scope = NEW.scope
|
|
591
|
+
AND revision.role_key IS NOT DISTINCT FROM NEW.role_key
|
|
592
|
+
AND revision.revision = NEW.draft_revision
|
|
593
|
+
AND revision.content_hash = NEW.draft_content_hash
|
|
594
|
+
AND revision.supersedes_revision_id IS NOT DISTINCT FROM NEW.baseline_revision_id
|
|
595
|
+
AND revision.created_by_subject_id = NEW.created_by_subject_id
|
|
596
|
+
AND (
|
|
597
|
+
(
|
|
598
|
+
revision.provenance_source = 'onboarding'
|
|
599
|
+
AND revision.provenance_source_id = NEW.id::text
|
|
600
|
+
) OR (
|
|
601
|
+
revision.provenance_source = 'knowledge_proposal'
|
|
602
|
+
AND revision.provenance_source_id = NEW.source_id
|
|
603
|
+
AND NEW.source_version = NEW.draft_content_hash
|
|
604
|
+
AND EXISTS (
|
|
605
|
+
SELECT 1 FROM knowledge_change_proposals proposal
|
|
606
|
+
WHERE proposal.id::text = NEW.source_id
|
|
607
|
+
AND proposal.account_id = NEW.account_id
|
|
608
|
+
AND proposal.scope_kind = 'workspace'
|
|
609
|
+
AND proposal.scope_workspace_id = NEW.workspace_id
|
|
610
|
+
AND proposal.scope_subject_id IS NULL
|
|
611
|
+
AND proposal.target_kind = 'instruction_policy'
|
|
612
|
+
AND proposal.target_scope = NEW.scope
|
|
613
|
+
AND proposal.target_key IS NOT DISTINCT FROM CASE
|
|
614
|
+
WHEN NEW.scope = 'role' THEN NEW.role_key
|
|
615
|
+
ELSE NULL
|
|
616
|
+
END
|
|
617
|
+
AND proposal.content_hash = NEW.source_version
|
|
618
|
+
AND proposal.actor_kind = 'service'
|
|
619
|
+
AND proposal.actor_subject_id = NEW.created_by_subject_id
|
|
620
|
+
AND proposal.initiating_human_subject_id
|
|
621
|
+
= current_setting('opengeni.subject_id', true)
|
|
622
|
+
AND proposal.claim_id IS NOT NULL
|
|
623
|
+
AND proposal.evidence_id IS NOT NULL
|
|
624
|
+
AND proposal.status = 'proposed'
|
|
625
|
+
)
|
|
626
|
+
)
|
|
627
|
+
)
|
|
628
|
+
) THEN
|
|
629
|
+
RAISE EXCEPTION 'instruction-policy proposal must identify its exact inactive draft'
|
|
630
|
+
USING ERRCODE = '23514';
|
|
631
|
+
END IF;
|
|
632
|
+
|
|
633
|
+
IF EXISTS (
|
|
634
|
+
SELECT 1 FROM workspace_instruction_policy_heads head
|
|
635
|
+
WHERE head.account_id = NEW.account_id
|
|
636
|
+
AND head.workspace_id = NEW.workspace_id
|
|
637
|
+
AND head.revision_id = NEW.draft_revision_id
|
|
638
|
+
) OR EXISTS (
|
|
639
|
+
SELECT 1 FROM workspace_instruction_policy_activation_events event
|
|
640
|
+
WHERE event.account_id = NEW.account_id
|
|
641
|
+
AND event.workspace_id = NEW.workspace_id
|
|
642
|
+
AND event.new_revision_id = NEW.draft_revision_id
|
|
643
|
+
) THEN
|
|
644
|
+
RAISE EXCEPTION 'instruction-policy proposal must identify a never-activated inactive draft'
|
|
645
|
+
USING ERRCODE = '23514';
|
|
646
|
+
END IF;
|
|
647
|
+
RETURN NEW;
|
|
648
|
+
END;
|
|
649
|
+
$$;
|
|
650
|
+
|
|
651
|
+
CREATE OR REPLACE FUNCTION governed_learning_apply_instruction_policy(
|
|
652
|
+
p_action text,
|
|
653
|
+
p_account_id uuid,
|
|
654
|
+
p_workspace_id uuid,
|
|
655
|
+
p_operation_id uuid,
|
|
656
|
+
p_proposal_id uuid,
|
|
657
|
+
p_expected_current_revision_id uuid,
|
|
658
|
+
p_expected_activation_version bigint,
|
|
659
|
+
p_target_revision_id uuid,
|
|
660
|
+
p_actor_subject_id text
|
|
661
|
+
) RETURNS SETOF workspace_instruction_policy_activation_events
|
|
662
|
+
LANGUAGE plpgsql SECURITY DEFINER AS $$
|
|
663
|
+
DECLARE
|
|
664
|
+
proposal_row workspace_instruction_policy_onboarding_proposals%ROWTYPE;
|
|
665
|
+
current_head workspace_instruction_policy_heads%ROWTYPE;
|
|
666
|
+
active_revision workspace_instruction_policy_revisions%ROWTYPE;
|
|
667
|
+
target_revision workspace_instruction_policy_revisions%ROWTYPE;
|
|
668
|
+
event_row workspace_instruction_policy_activation_events%ROWTYPE;
|
|
669
|
+
inactive_activation_version bigint;
|
|
670
|
+
current_activation_version bigint;
|
|
671
|
+
next_version bigint;
|
|
672
|
+
fingerprint text;
|
|
673
|
+
event_time timestamptz;
|
|
674
|
+
BEGIN
|
|
675
|
+
IF p_action NOT IN ('activate', 'undo')
|
|
676
|
+
OR p_actor_subject_id NOT LIKE 'service:governed-learning-activation:%'
|
|
677
|
+
OR p_expected_activation_version < 0
|
|
678
|
+
OR (p_action = 'undo' AND p_target_revision_id IS NULL)
|
|
679
|
+
THEN
|
|
680
|
+
RAISE EXCEPTION 'governed-learning instruction-policy input is invalid'
|
|
681
|
+
USING ERRCODE = '22023';
|
|
682
|
+
END IF;
|
|
683
|
+
PERFORM 1 FROM workspaces workspace
|
|
684
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
|
|
685
|
+
FOR UPDATE;
|
|
686
|
+
IF NOT FOUND THEN
|
|
687
|
+
RAISE EXCEPTION 'governed-learning workspace is unavailable' USING ERRCODE = '42501';
|
|
688
|
+
END IF;
|
|
689
|
+
SELECT * INTO proposal_row FROM workspace_instruction_policy_onboarding_proposals proposal
|
|
690
|
+
WHERE proposal.account_id = p_account_id
|
|
691
|
+
AND proposal.workspace_id = p_workspace_id
|
|
692
|
+
AND proposal.id = p_proposal_id
|
|
693
|
+
AND proposal.status = 'proposed'
|
|
694
|
+
AND proposal.source_id ~ '^[0-9a-f-]{36}$'
|
|
695
|
+
FOR SHARE;
|
|
696
|
+
IF NOT FOUND THEN
|
|
697
|
+
RAISE EXCEPTION 'governed-learning instruction-policy proposal is unavailable'
|
|
698
|
+
USING ERRCODE = '42501';
|
|
699
|
+
END IF;
|
|
700
|
+
SELECT * INTO active_revision FROM workspace_instruction_policy_revisions revision
|
|
701
|
+
WHERE revision.account_id = p_account_id
|
|
702
|
+
AND revision.workspace_id = p_workspace_id
|
|
703
|
+
AND revision.id = proposal_row.draft_revision_id
|
|
704
|
+
AND revision.content_hash = proposal_row.draft_content_hash
|
|
705
|
+
AND revision.provenance_source = 'knowledge_proposal'
|
|
706
|
+
AND revision.provenance_source_id = proposal_row.source_id
|
|
707
|
+
FOR SHARE;
|
|
708
|
+
IF NOT FOUND THEN
|
|
709
|
+
RAISE EXCEPTION 'governed-learning instruction-policy draft is unavailable'
|
|
710
|
+
USING ERRCODE = '42501';
|
|
711
|
+
END IF;
|
|
712
|
+
SELECT * INTO current_head FROM workspace_instruction_policy_heads head
|
|
713
|
+
WHERE head.account_id = p_account_id AND head.workspace_id = p_workspace_id
|
|
714
|
+
AND head.kind = proposal_row.kind AND head.scope = proposal_row.scope
|
|
715
|
+
AND head.role_key IS NOT DISTINCT FROM proposal_row.role_key
|
|
716
|
+
FOR UPDATE;
|
|
717
|
+
IF NOT FOUND THEN
|
|
718
|
+
SELECT event.activation_version INTO inactive_activation_version
|
|
719
|
+
FROM workspace_instruction_policy_deactivation_events event
|
|
720
|
+
WHERE event.account_id = p_account_id AND event.workspace_id = p_workspace_id
|
|
721
|
+
AND event.kind = proposal_row.kind AND event.scope = proposal_row.scope
|
|
722
|
+
AND event.role_key IS NOT DISTINCT FROM proposal_row.role_key
|
|
723
|
+
ORDER BY event.activation_version DESC, event.id DESC
|
|
724
|
+
LIMIT 1;
|
|
725
|
+
END IF;
|
|
726
|
+
current_activation_version := coalesce(current_head.activation_version, inactive_activation_version, 0);
|
|
727
|
+
IF current_head.revision_id IS DISTINCT FROM p_expected_current_revision_id
|
|
728
|
+
OR current_activation_version IS DISTINCT FROM p_expected_activation_version
|
|
729
|
+
THEN
|
|
730
|
+
RAISE EXCEPTION 'governed-learning instruction-policy head changed'
|
|
731
|
+
USING ERRCODE = '40001';
|
|
732
|
+
END IF;
|
|
733
|
+
IF p_action = 'activate' THEN
|
|
734
|
+
IF p_target_revision_id IS DISTINCT FROM proposal_row.draft_revision_id
|
|
735
|
+
OR proposal_row.baseline_revision_id IS DISTINCT FROM p_expected_current_revision_id
|
|
736
|
+
OR proposal_row.baseline_activation_version IS DISTINCT FROM p_expected_activation_version
|
|
737
|
+
THEN
|
|
738
|
+
RAISE EXCEPTION 'governed-learning instruction-policy proposal baseline changed'
|
|
739
|
+
USING ERRCODE = '40001';
|
|
740
|
+
END IF;
|
|
741
|
+
target_revision := active_revision;
|
|
742
|
+
ELSE
|
|
743
|
+
IF current_head.revision_id IS DISTINCT FROM proposal_row.draft_revision_id THEN
|
|
744
|
+
RAISE EXCEPTION 'governed-learning instruction-policy activation was superseded'
|
|
745
|
+
USING ERRCODE = '40001';
|
|
746
|
+
END IF;
|
|
747
|
+
IF p_target_revision_id IS NOT NULL THEN
|
|
748
|
+
SELECT * INTO target_revision FROM workspace_instruction_policy_revisions revision
|
|
749
|
+
WHERE revision.account_id = p_account_id AND revision.workspace_id = p_workspace_id
|
|
750
|
+
AND revision.id = p_target_revision_id
|
|
751
|
+
AND revision.kind = proposal_row.kind AND revision.scope = proposal_row.scope
|
|
752
|
+
AND revision.role_key IS NOT DISTINCT FROM proposal_row.role_key
|
|
753
|
+
FOR SHARE;
|
|
754
|
+
IF NOT FOUND THEN
|
|
755
|
+
RAISE EXCEPTION 'governed-learning rollback target is unavailable'
|
|
756
|
+
USING ERRCODE = '42501';
|
|
757
|
+
END IF;
|
|
758
|
+
END IF;
|
|
759
|
+
END IF;
|
|
760
|
+
fingerprint := encode(sha256(convert_to(jsonb_build_array(
|
|
761
|
+
'governed-learning-instruction-policy', 1, p_action, p_account_id,
|
|
762
|
+
p_workspace_id, p_operation_id, p_proposal_id, p_expected_current_revision_id,
|
|
763
|
+
p_expected_activation_version, p_target_revision_id, p_actor_subject_id
|
|
764
|
+
)::text, 'UTF8')), 'hex');
|
|
765
|
+
event_time := clock_timestamp();
|
|
766
|
+
next_version := current_activation_version + 1;
|
|
767
|
+
IF p_action = 'activate' THEN
|
|
768
|
+
IF current_head.id IS NULL THEN
|
|
769
|
+
INSERT INTO workspace_instruction_policy_heads (
|
|
770
|
+
account_id, workspace_id, kind, scope, role_key, revision_id, revision,
|
|
771
|
+
content_hash, activation_version, activated_at
|
|
772
|
+
) VALUES (
|
|
773
|
+
p_account_id, p_workspace_id, proposal_row.kind, proposal_row.scope,
|
|
774
|
+
proposal_row.role_key, target_revision.id, target_revision.revision,
|
|
775
|
+
target_revision.content_hash, next_version, event_time
|
|
776
|
+
);
|
|
777
|
+
ELSE
|
|
778
|
+
UPDATE workspace_instruction_policy_heads SET
|
|
779
|
+
revision_id = target_revision.id, revision = target_revision.revision,
|
|
780
|
+
content_hash = target_revision.content_hash,
|
|
781
|
+
activation_version = next_version, activated_at = event_time
|
|
782
|
+
WHERE id = current_head.id;
|
|
783
|
+
END IF;
|
|
784
|
+
ELSE
|
|
785
|
+
UPDATE workspace_instruction_policy_heads SET
|
|
786
|
+
revision_id = target_revision.id, revision = target_revision.revision,
|
|
787
|
+
content_hash = target_revision.content_hash,
|
|
788
|
+
activation_version = next_version, activated_at = event_time
|
|
789
|
+
WHERE id = current_head.id;
|
|
790
|
+
END IF;
|
|
791
|
+
INSERT INTO workspace_instruction_policy_activation_events (
|
|
792
|
+
operation_id, request_fingerprint, account_id, workspace_id, kind, scope,
|
|
793
|
+
role_key, type, activation_version, old_revision_id, old_revision,
|
|
794
|
+
old_content_hash, new_revision_id, new_revision, new_content_hash,
|
|
795
|
+
actor_subject_id, reason, created_at
|
|
796
|
+
) VALUES (
|
|
797
|
+
p_operation_id, fingerprint, p_account_id, p_workspace_id, proposal_row.kind,
|
|
798
|
+
proposal_row.scope, proposal_row.role_key,
|
|
799
|
+
CASE WHEN p_action = 'activate' THEN 'activate' ELSE 'rollback' END,
|
|
800
|
+
next_version, current_head.revision_id, current_head.revision,
|
|
801
|
+
current_head.content_hash, target_revision.id, target_revision.revision,
|
|
802
|
+
target_revision.content_hash, p_actor_subject_id,
|
|
803
|
+
CASE WHEN p_action = 'activate' THEN 'Automatic governed-learning activation.'
|
|
804
|
+
ELSE 'Exact governed-learning activation undo.' END,
|
|
805
|
+
event_time
|
|
806
|
+
) RETURNING * INTO event_row;
|
|
807
|
+
RETURN NEXT event_row;
|
|
808
|
+
END;
|
|
809
|
+
$$;
|
|
810
|
+
REVOKE ALL ON FUNCTION governed_learning_apply_instruction_policy(
|
|
811
|
+
text, uuid, uuid, uuid, uuid, uuid, bigint, uuid, text
|
|
812
|
+
) FROM PUBLIC;
|
|
813
|
+
|
|
814
|
+
CREATE OR REPLACE FUNCTION governed_learning_deactivate_instruction_policy(
|
|
815
|
+
p_account_id uuid,
|
|
816
|
+
p_workspace_id uuid,
|
|
817
|
+
p_operation_id uuid,
|
|
818
|
+
p_proposal_id uuid,
|
|
819
|
+
p_expected_current_revision_id uuid,
|
|
820
|
+
p_expected_activation_version bigint,
|
|
821
|
+
p_actor_subject_id text
|
|
822
|
+
) RETURNS SETOF workspace_instruction_policy_deactivation_events
|
|
823
|
+
LANGUAGE plpgsql SECURITY DEFINER AS $$
|
|
824
|
+
DECLARE
|
|
825
|
+
proposal_row workspace_instruction_policy_onboarding_proposals%ROWTYPE;
|
|
826
|
+
current_head workspace_instruction_policy_heads%ROWTYPE;
|
|
827
|
+
result_row workspace_instruction_policy_deactivation_events%ROWTYPE;
|
|
828
|
+
fingerprint text;
|
|
829
|
+
event_time timestamptz;
|
|
830
|
+
next_version bigint;
|
|
831
|
+
BEGIN
|
|
832
|
+
IF p_expected_current_revision_id IS NULL
|
|
833
|
+
OR p_expected_activation_version <= 0
|
|
834
|
+
OR p_actor_subject_id NOT LIKE 'service:governed-learning-activation:%'
|
|
835
|
+
THEN
|
|
836
|
+
RAISE EXCEPTION 'governed-learning instruction-policy deactivation input is invalid'
|
|
837
|
+
USING ERRCODE = '22023';
|
|
838
|
+
END IF;
|
|
839
|
+
PERFORM 1 FROM workspaces workspace
|
|
840
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
|
|
841
|
+
FOR UPDATE;
|
|
842
|
+
IF NOT FOUND THEN
|
|
843
|
+
RAISE EXCEPTION 'governed-learning workspace is unavailable' USING ERRCODE = '42501';
|
|
844
|
+
END IF;
|
|
845
|
+
SELECT * INTO proposal_row FROM workspace_instruction_policy_onboarding_proposals proposal
|
|
846
|
+
WHERE proposal.account_id = p_account_id AND proposal.workspace_id = p_workspace_id
|
|
847
|
+
AND proposal.id = p_proposal_id AND proposal.status = 'proposed'
|
|
848
|
+
FOR SHARE;
|
|
849
|
+
IF NOT FOUND OR proposal_row.draft_revision_id IS DISTINCT FROM p_expected_current_revision_id
|
|
850
|
+
THEN
|
|
851
|
+
RAISE EXCEPTION 'governed-learning instruction-policy proposal is unavailable'
|
|
852
|
+
USING ERRCODE = '42501';
|
|
853
|
+
END IF;
|
|
854
|
+
SELECT * INTO current_head FROM workspace_instruction_policy_heads head
|
|
855
|
+
WHERE head.account_id = p_account_id AND head.workspace_id = p_workspace_id
|
|
856
|
+
AND head.kind = proposal_row.kind AND head.scope = proposal_row.scope
|
|
857
|
+
AND head.role_key IS NOT DISTINCT FROM proposal_row.role_key
|
|
858
|
+
FOR UPDATE;
|
|
859
|
+
IF current_head.revision_id IS DISTINCT FROM p_expected_current_revision_id
|
|
860
|
+
OR current_head.activation_version IS DISTINCT FROM p_expected_activation_version
|
|
861
|
+
THEN
|
|
862
|
+
RAISE EXCEPTION 'governed-learning instruction-policy activation was superseded'
|
|
863
|
+
USING ERRCODE = '40001';
|
|
864
|
+
END IF;
|
|
865
|
+
fingerprint := encode(sha256(convert_to(jsonb_build_array(
|
|
866
|
+
'governed-learning-instruction-policy-deactivation', 1, p_account_id,
|
|
867
|
+
p_workspace_id, p_operation_id, p_proposal_id,
|
|
868
|
+
p_expected_current_revision_id, p_expected_activation_version,
|
|
869
|
+
p_actor_subject_id
|
|
870
|
+
)::text, 'UTF8')), 'hex');
|
|
871
|
+
event_time := clock_timestamp();
|
|
872
|
+
next_version := p_expected_activation_version + 1;
|
|
873
|
+
PERFORM set_config(
|
|
874
|
+
'opengeni.governed_learning_deactivation_operation', p_operation_id::text, true
|
|
875
|
+
);
|
|
876
|
+
DELETE FROM workspace_instruction_policy_heads WHERE id = current_head.id;
|
|
877
|
+
INSERT INTO workspace_instruction_policy_deactivation_events (
|
|
878
|
+
operation_id, request_fingerprint, account_id, workspace_id, kind, scope,
|
|
879
|
+
role_key, type, activation_version, old_revision_id, old_revision,
|
|
880
|
+
old_content_hash, actor_subject_id, reason, created_at
|
|
881
|
+
) VALUES (
|
|
882
|
+
p_operation_id, fingerprint, p_account_id, p_workspace_id, proposal_row.kind,
|
|
883
|
+
proposal_row.scope, proposal_row.role_key, 'automatic_deactivate', next_version,
|
|
884
|
+
current_head.revision_id, current_head.revision, current_head.content_hash,
|
|
885
|
+
p_actor_subject_id, 'Exact governed-learning activation undo.', event_time
|
|
886
|
+
) RETURNING * INTO result_row;
|
|
887
|
+
PERFORM set_config('opengeni.governed_learning_deactivation_operation', '', true);
|
|
888
|
+
RETURN NEXT result_row;
|
|
889
|
+
END;
|
|
890
|
+
$$;
|
|
891
|
+
REVOKE ALL ON FUNCTION governed_learning_deactivate_instruction_policy(
|
|
892
|
+
uuid, uuid, uuid, uuid, uuid, bigint, text
|
|
893
|
+
) FROM PUBLIC;
|
|
894
|
+
|
|
895
|
+
CREATE OR REPLACE FUNCTION workspace_instruction_policy_canonical_snapshot_entries(
|
|
896
|
+
p_account_id uuid,
|
|
897
|
+
p_workspace_id uuid,
|
|
898
|
+
p_policy_role text,
|
|
899
|
+
p_accepted_at timestamptz
|
|
900
|
+
) RETURNS jsonb
|
|
901
|
+
LANGUAGE sql STABLE AS $$
|
|
902
|
+
SELECT coalesce(jsonb_agg(candidate.entry ORDER BY candidate.ordinal), '[]'::jsonb)
|
|
903
|
+
FROM (
|
|
904
|
+
SELECT
|
|
905
|
+
CASE
|
|
906
|
+
WHEN event.kind = 'charter' THEN 0
|
|
907
|
+
WHEN event.scope = 'global' THEN 1
|
|
908
|
+
ELSE 2
|
|
909
|
+
END AS ordinal,
|
|
910
|
+
jsonb_build_object(
|
|
911
|
+
'kind', event.kind,
|
|
912
|
+
'scope', event.scope,
|
|
913
|
+
'roleKey', event.role_key,
|
|
914
|
+
'revisionId', revision.id::text,
|
|
915
|
+
'revision', revision.revision,
|
|
916
|
+
'contentHash', revision.content_hash,
|
|
917
|
+
'activationVersion', event.activation_version,
|
|
918
|
+
'activatedAt', to_char(
|
|
919
|
+
event.created_at AT TIME ZONE 'UTC',
|
|
920
|
+
'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'
|
|
921
|
+
),
|
|
922
|
+
'provenance', jsonb_build_object(
|
|
923
|
+
'source', revision.provenance_source,
|
|
924
|
+
'sourceIdHash', CASE
|
|
925
|
+
WHEN revision.provenance_source_id IS NULL THEN NULL
|
|
926
|
+
ELSE encode(sha256(convert_to(revision.provenance_source_id, 'UTF8')), 'hex')
|
|
927
|
+
END
|
|
928
|
+
)
|
|
929
|
+
) AS entry
|
|
930
|
+
FROM (
|
|
931
|
+
SELECT DISTINCT ON (lifecycle.kind, lifecycle.scope, coalesce(lifecycle.role_key, ''))
|
|
932
|
+
lifecycle.*
|
|
933
|
+
FROM (
|
|
934
|
+
SELECT
|
|
935
|
+
activation.id, activation.account_id, activation.workspace_id,
|
|
936
|
+
activation.kind, activation.scope, activation.role_key,
|
|
937
|
+
activation.activation_version, activation.new_revision_id,
|
|
938
|
+
activation.new_revision, activation.new_content_hash,
|
|
939
|
+
activation.created_at
|
|
940
|
+
FROM workspace_instruction_policy_activation_events activation
|
|
941
|
+
UNION ALL
|
|
942
|
+
SELECT
|
|
943
|
+
deactivation.id, deactivation.account_id, deactivation.workspace_id,
|
|
944
|
+
deactivation.kind, deactivation.scope, deactivation.role_key,
|
|
945
|
+
deactivation.activation_version, NULL::uuid, NULL::bigint, NULL::text,
|
|
946
|
+
deactivation.created_at
|
|
947
|
+
FROM workspace_instruction_policy_deactivation_events deactivation
|
|
948
|
+
) lifecycle
|
|
949
|
+
WHERE lifecycle.account_id = p_account_id
|
|
950
|
+
AND lifecycle.workspace_id = p_workspace_id
|
|
951
|
+
AND lifecycle.created_at <= p_accepted_at
|
|
952
|
+
AND (
|
|
953
|
+
(lifecycle.kind = 'charter' AND lifecycle.scope = 'global')
|
|
954
|
+
OR (lifecycle.kind = 'policy' AND lifecycle.scope = 'global')
|
|
955
|
+
OR (
|
|
956
|
+
p_policy_role IS NOT NULL
|
|
957
|
+
AND lifecycle.kind = 'policy'
|
|
958
|
+
AND lifecycle.scope = 'role'
|
|
959
|
+
AND lifecycle.role_key = p_policy_role
|
|
960
|
+
)
|
|
961
|
+
)
|
|
962
|
+
ORDER BY
|
|
963
|
+
lifecycle.kind,
|
|
964
|
+
lifecycle.scope,
|
|
965
|
+
coalesce(lifecycle.role_key, ''),
|
|
966
|
+
lifecycle.activation_version DESC,
|
|
967
|
+
lifecycle.created_at DESC,
|
|
968
|
+
lifecycle.id DESC
|
|
969
|
+
) event
|
|
970
|
+
JOIN workspace_instruction_policy_revisions revision
|
|
971
|
+
ON revision.account_id = event.account_id
|
|
972
|
+
AND revision.workspace_id = event.workspace_id
|
|
973
|
+
AND revision.id = event.new_revision_id
|
|
974
|
+
AND revision.revision = event.new_revision
|
|
975
|
+
AND revision.content_hash = event.new_content_hash
|
|
976
|
+
) candidate;
|
|
977
|
+
$$;
|
|
978
|
+
REVOKE ALL ON FUNCTION workspace_instruction_policy_canonical_snapshot_entries(
|
|
979
|
+
uuid, uuid, text, timestamptz
|
|
980
|
+
) FROM PUBLIC;
|
|
981
|
+
|
|
982
|
+
CREATE OR REPLACE FUNCTION governed_learning_apply_preference(
|
|
983
|
+
p_action text,
|
|
984
|
+
p_account_id uuid,
|
|
985
|
+
p_workspace_id uuid,
|
|
986
|
+
p_operation_id uuid,
|
|
987
|
+
p_knowledge_proposal_id uuid,
|
|
988
|
+
p_preference_id uuid,
|
|
989
|
+
p_revision_id uuid,
|
|
990
|
+
p_expected_active_revision_id uuid,
|
|
991
|
+
p_expected_activation_version integer,
|
|
992
|
+
p_actor_subject_id text
|
|
993
|
+
) RETURNS SETOF preference_registry_events
|
|
994
|
+
LANGUAGE plpgsql SECURITY DEFINER AS $$
|
|
995
|
+
DECLARE
|
|
996
|
+
proposal_receipt company_brain_preference_proposal_receipts%ROWTYPE;
|
|
997
|
+
preference_row preference_registry_preferences%ROWTYPE;
|
|
998
|
+
revision_row preference_registry_revisions%ROWTYPE;
|
|
999
|
+
event_row preference_registry_events%ROWTYPE;
|
|
1000
|
+
next_event_version integer;
|
|
1001
|
+
BEGIN
|
|
1002
|
+
IF p_action NOT IN ('activate', 'undo')
|
|
1003
|
+
OR p_actor_subject_id NOT LIKE 'service:governed-learning-activation:%'
|
|
1004
|
+
OR p_expected_activation_version < 0
|
|
1005
|
+
THEN
|
|
1006
|
+
RAISE EXCEPTION 'governed-learning preference input is invalid' USING ERRCODE = '22023';
|
|
1007
|
+
END IF;
|
|
1008
|
+
SELECT * INTO proposal_receipt FROM company_brain_preference_proposal_receipts receipt
|
|
1009
|
+
WHERE receipt.account_id = p_account_id AND receipt.workspace_id = p_workspace_id
|
|
1010
|
+
AND receipt.knowledge_proposal_id = p_knowledge_proposal_id
|
|
1011
|
+
AND receipt.preference_id = p_preference_id AND receipt.revision_id = p_revision_id
|
|
1012
|
+
FOR SHARE;
|
|
1013
|
+
IF NOT FOUND THEN
|
|
1014
|
+
RAISE EXCEPTION 'governed-learning preference proposal is unavailable' USING ERRCODE = '42501';
|
|
1015
|
+
END IF;
|
|
1016
|
+
SELECT * INTO preference_row FROM preference_registry_preferences preference
|
|
1017
|
+
WHERE preference.account_id = p_account_id AND preference.id = p_preference_id
|
|
1018
|
+
AND preference.scope = 'workspace' AND preference.scope_workspace_id = p_workspace_id
|
|
1019
|
+
AND preference.scope_subject_id IS NULL
|
|
1020
|
+
FOR UPDATE;
|
|
1021
|
+
IF NOT FOUND OR preference_row.scope_version <> 1
|
|
1022
|
+
OR preference_row.active_revision_id IS DISTINCT FROM p_expected_active_revision_id
|
|
1023
|
+
OR preference_row.activation_version IS DISTINCT FROM p_expected_activation_version
|
|
1024
|
+
THEN
|
|
1025
|
+
RAISE EXCEPTION 'governed-learning preference head changed' USING ERRCODE = '40001';
|
|
1026
|
+
END IF;
|
|
1027
|
+
SELECT * INTO revision_row FROM preference_registry_revisions revision
|
|
1028
|
+
WHERE revision.account_id = p_account_id AND revision.preference_id = p_preference_id
|
|
1029
|
+
AND revision.id = p_revision_id
|
|
1030
|
+
AND revision.provenance_source = 'knowledge_proposal'
|
|
1031
|
+
AND revision.provenance_source_id = p_knowledge_proposal_id::text
|
|
1032
|
+
AND revision.trust = 'untrusted_proposal'
|
|
1033
|
+
AND (revision.expires_at IS NULL OR revision.expires_at > transaction_timestamp())
|
|
1034
|
+
FOR SHARE;
|
|
1035
|
+
IF NOT FOUND THEN
|
|
1036
|
+
RAISE EXCEPTION 'governed-learning preference revision is unavailable' USING ERRCODE = '42501';
|
|
1037
|
+
END IF;
|
|
1038
|
+
IF (p_action = 'activate' AND (
|
|
1039
|
+
preference_row.status <> 'proposed'
|
|
1040
|
+
OR p_expected_active_revision_id IS NOT NULL
|
|
1041
|
+
OR p_expected_activation_version <> 0
|
|
1042
|
+
)) OR (p_action = 'undo' AND (
|
|
1043
|
+
preference_row.status <> 'active'
|
|
1044
|
+
OR p_expected_active_revision_id IS DISTINCT FROM p_revision_id
|
|
1045
|
+
))
|
|
1046
|
+
THEN
|
|
1047
|
+
RAISE EXCEPTION 'governed-learning preference lifecycle was superseded'
|
|
1048
|
+
USING ERRCODE = '40001';
|
|
1049
|
+
END IF;
|
|
1050
|
+
PERFORM set_config('opengeni.preference_lifecycle_head_id', preference_row.id::text, true);
|
|
1051
|
+
PERFORM set_config('opengeni.preference_lifecycle_operation',
|
|
1052
|
+
CASE WHEN p_action = 'activate' THEN 'activate' ELSE 'deactivate' END, true);
|
|
1053
|
+
IF p_action = 'activate' THEN
|
|
1054
|
+
UPDATE preference_registry_preferences SET
|
|
1055
|
+
status = 'active', active_revision_id = revision_row.id,
|
|
1056
|
+
active_revision = revision_row.revision,
|
|
1057
|
+
active_content_hash = revision_row.content_hash,
|
|
1058
|
+
activation_version = activation_version + 1,
|
|
1059
|
+
updated_at = clock_timestamp()
|
|
1060
|
+
WHERE id = preference_row.id;
|
|
1061
|
+
ELSE
|
|
1062
|
+
UPDATE preference_registry_preferences SET
|
|
1063
|
+
status = 'inactive', active_revision_id = NULL, active_revision = NULL,
|
|
1064
|
+
active_content_hash = NULL, activation_version = activation_version + 1,
|
|
1065
|
+
updated_at = clock_timestamp()
|
|
1066
|
+
WHERE id = preference_row.id;
|
|
1067
|
+
END IF;
|
|
1068
|
+
PERFORM set_config('opengeni.preference_lifecycle_head_id', '', true);
|
|
1069
|
+
PERFORM set_config('opengeni.preference_lifecycle_operation', '', true);
|
|
1070
|
+
SELECT coalesce(max(event.version), 0) + 1 INTO next_event_version
|
|
1071
|
+
FROM preference_registry_events event WHERE event.preference_id = preference_row.id;
|
|
1072
|
+
INSERT INTO preference_registry_events (
|
|
1073
|
+
account_id, preference_id, type, version, old_revision_id, new_revision_id,
|
|
1074
|
+
actor_subject_id, reason
|
|
1075
|
+
) VALUES (
|
|
1076
|
+
p_account_id, p_preference_id,
|
|
1077
|
+
CASE WHEN p_action = 'activate' THEN 'activated' ELSE 'deactivated' END,
|
|
1078
|
+
next_event_version,
|
|
1079
|
+
CASE WHEN p_action = 'undo' THEN revision_row.id ELSE NULL END,
|
|
1080
|
+
CASE WHEN p_action = 'activate' THEN revision_row.id ELSE NULL END,
|
|
1081
|
+
p_actor_subject_id,
|
|
1082
|
+
CASE WHEN p_action = 'activate' THEN 'Automatic governed-learning activation.'
|
|
1083
|
+
ELSE 'Exact governed-learning activation undo.' END
|
|
1084
|
+
) RETURNING * INTO event_row;
|
|
1085
|
+
RETURN NEXT event_row;
|
|
1086
|
+
END;
|
|
1087
|
+
$$;
|
|
1088
|
+
REVOKE ALL ON FUNCTION governed_learning_apply_preference(
|
|
1089
|
+
text, uuid, uuid, uuid, uuid, uuid, uuid, uuid, integer, text
|
|
1090
|
+
) FROM PUBLIC;
|
|
1091
|
+
|
|
1092
|
+
CREATE OR REPLACE FUNCTION activate_governed_learning_decision(
|
|
1093
|
+
p_account_id uuid,
|
|
1094
|
+
p_workspace_id uuid,
|
|
1095
|
+
p_operation_id uuid,
|
|
1096
|
+
p_decision_receipt_id uuid
|
|
1097
|
+
) RETURNS SETOF governed_learning_activation_receipts
|
|
1098
|
+
LANGUAGE plpgsql SECURITY DEFINER AS $$
|
|
1099
|
+
DECLARE
|
|
1100
|
+
caller_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
1101
|
+
decision_row governed_learning_decision_receipts%ROWTYPE;
|
|
1102
|
+
result_row governed_learning_activation_receipts%ROWTYPE;
|
|
1103
|
+
proposal_row knowledge_change_proposals%ROWTYPE;
|
|
1104
|
+
claim_row knowledge_claims%ROWTYPE;
|
|
1105
|
+
evidence_row knowledge_claim_evidence%ROWTYPE;
|
|
1106
|
+
review_row knowledge_claim_reviews%ROWTYPE;
|
|
1107
|
+
approval_row knowledge_claim_reviews%ROWTYPE;
|
|
1108
|
+
policy_head workspace_learning_policy_heads%ROWTYPE;
|
|
1109
|
+
policy_revision workspace_learning_policy_revisions%ROWTYPE;
|
|
1110
|
+
policy_snapshot workspace_learning_policy_snapshots%ROWTYPE;
|
|
1111
|
+
task_note_row task_notes%ROWTYPE;
|
|
1112
|
+
document_authority record;
|
|
1113
|
+
instruction_proposal workspace_instruction_policy_onboarding_proposals%ROWTYPE;
|
|
1114
|
+
instruction_event workspace_instruction_policy_activation_events%ROWTYPE;
|
|
1115
|
+
preference_receipt company_brain_preference_proposal_receipts%ROWTYPE;
|
|
1116
|
+
preference_row preference_registry_preferences%ROWTYPE;
|
|
1117
|
+
preference_revision preference_registry_revisions%ROWTYPE;
|
|
1118
|
+
preference_event preference_registry_events%ROWTYPE;
|
|
1119
|
+
current_instruction_head workspace_instruction_policy_heads%ROWTYPE;
|
|
1120
|
+
current_instruction_activation_version bigint;
|
|
1121
|
+
input_hash_value text;
|
|
1122
|
+
service_actor text;
|
|
1123
|
+
current_authority_hash text;
|
|
1124
|
+
current_mode text;
|
|
1125
|
+
conflict_count integer;
|
|
1126
|
+
destination_value text;
|
|
1127
|
+
destination_proposal_id_value uuid;
|
|
1128
|
+
destination_revision_id_value uuid;
|
|
1129
|
+
destination_old_revision_id_value uuid;
|
|
1130
|
+
destination_old_content_hash_value text;
|
|
1131
|
+
destination_old_version_value bigint;
|
|
1132
|
+
destination_new_content_hash_value text;
|
|
1133
|
+
destination_new_version_value bigint;
|
|
1134
|
+
destination_event_id_value uuid;
|
|
1135
|
+
effective_at_value timestamptz;
|
|
1136
|
+
review_operation_id uuid;
|
|
1137
|
+
destination_operation_id uuid;
|
|
1138
|
+
BEGIN
|
|
1139
|
+
IF p_account_id IS NULL OR p_workspace_id IS NULL OR p_operation_id IS NULL
|
|
1140
|
+
OR p_decision_receipt_id IS NULL OR caller_subject_id IS NULL
|
|
1141
|
+
OR length(btrim(caller_subject_id)) NOT BETWEEN 1 AND 1024
|
|
1142
|
+
OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
|
|
1143
|
+
OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
|
|
1144
|
+
THEN
|
|
1145
|
+
RAISE EXCEPTION 'governed-learning activation requires exact tenant authority'
|
|
1146
|
+
USING ERRCODE = '42501';
|
|
1147
|
+
END IF;
|
|
1148
|
+
input_hash_value := encode(sha256(convert_to(jsonb_build_array(
|
|
1149
|
+
'governed-learning-activation', 1, p_account_id, p_workspace_id,
|
|
1150
|
+
p_operation_id, p_decision_receipt_id
|
|
1151
|
+
)::text, 'UTF8')), 'hex');
|
|
1152
|
+
SELECT * INTO result_row FROM governed_learning_activation_receipts receipt
|
|
1153
|
+
WHERE receipt.workspace_id = p_workspace_id AND receipt.operation_id = p_operation_id
|
|
1154
|
+
FOR SHARE;
|
|
1155
|
+
IF FOUND THEN
|
|
1156
|
+
IF result_row.account_id <> p_account_id OR result_row.input_hash <> input_hash_value
|
|
1157
|
+
OR result_row.decision_receipt_id <> p_decision_receipt_id
|
|
1158
|
+
OR result_row.initiating_human_subject_id <> caller_subject_id
|
|
1159
|
+
THEN
|
|
1160
|
+
RAISE EXCEPTION 'governed-learning activation operation conflicts with immutable receipt'
|
|
1161
|
+
USING ERRCODE = '23505';
|
|
1162
|
+
END IF;
|
|
1163
|
+
RETURN NEXT result_row;
|
|
1164
|
+
RETURN;
|
|
1165
|
+
END IF;
|
|
1166
|
+
|
|
1167
|
+
-- Canonical shared prefix. The workspace UPDATE lock also gives all three
|
|
1168
|
+
-- destination adapters one order, avoiding claim/head inversion.
|
|
1169
|
+
PERFORM 1 FROM workspaces workspace
|
|
1170
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
|
|
1171
|
+
FOR UPDATE;
|
|
1172
|
+
IF NOT FOUND THEN
|
|
1173
|
+
RAISE EXCEPTION 'governed-learning workspace is unavailable' USING ERRCODE = '42501';
|
|
1174
|
+
END IF;
|
|
1175
|
+
SELECT * INTO result_row FROM governed_learning_activation_receipts receipt
|
|
1176
|
+
WHERE receipt.workspace_id = p_workspace_id AND receipt.operation_id = p_operation_id
|
|
1177
|
+
FOR SHARE;
|
|
1178
|
+
IF FOUND THEN
|
|
1179
|
+
IF result_row.account_id <> p_account_id OR result_row.input_hash <> input_hash_value
|
|
1180
|
+
OR result_row.decision_receipt_id <> p_decision_receipt_id
|
|
1181
|
+
OR result_row.initiating_human_subject_id <> caller_subject_id
|
|
1182
|
+
THEN
|
|
1183
|
+
RAISE EXCEPTION 'governed-learning activation operation conflicts with immutable receipt'
|
|
1184
|
+
USING ERRCODE = '23505';
|
|
1185
|
+
END IF;
|
|
1186
|
+
RETURN NEXT result_row;
|
|
1187
|
+
RETURN;
|
|
1188
|
+
END IF;
|
|
1189
|
+
SELECT * INTO decision_row FROM governed_learning_decision_receipts receipt
|
|
1190
|
+
WHERE receipt.id = p_decision_receipt_id AND receipt.account_id = p_account_id
|
|
1191
|
+
AND receipt.workspace_id = p_workspace_id
|
|
1192
|
+
AND receipt.initiating_human_subject_id = caller_subject_id
|
|
1193
|
+
AND receipt.outcome = 'automatic' AND receipt.automatic_eligible
|
|
1194
|
+
FOR UPDATE;
|
|
1195
|
+
IF NOT FOUND OR NOT session_reference_visible(
|
|
1196
|
+
decision_row.account_id, decision_row.workspace_id, decision_row.session_id
|
|
1197
|
+
) THEN
|
|
1198
|
+
RAISE EXCEPTION 'final automatic evaluator receipt is unavailable'
|
|
1199
|
+
USING ERRCODE = '42501';
|
|
1200
|
+
END IF;
|
|
1201
|
+
IF EXISTS (
|
|
1202
|
+
SELECT 1 FROM governed_learning_activation_receipts receipt
|
|
1203
|
+
WHERE receipt.decision_receipt_id = p_decision_receipt_id
|
|
1204
|
+
) THEN
|
|
1205
|
+
RAISE EXCEPTION 'automatic evaluator receipt was consumed by another operation'
|
|
1206
|
+
USING ERRCODE = '23505';
|
|
1207
|
+
END IF;
|
|
1208
|
+
PERFORM 1 FROM sessions session
|
|
1209
|
+
WHERE session.account_id = p_account_id AND session.workspace_id = p_workspace_id
|
|
1210
|
+
AND session.id = decision_row.session_id AND session.active_turn_id = decision_row.turn_id
|
|
1211
|
+
AND session_reference_visible(session.account_id, session.workspace_id, session.id)
|
|
1212
|
+
FOR SHARE;
|
|
1213
|
+
IF NOT FOUND THEN
|
|
1214
|
+
RAISE EXCEPTION 'governed-learning activation session is unavailable' USING ERRCODE = '42501';
|
|
1215
|
+
END IF;
|
|
1216
|
+
PERFORM 1 FROM session_turns turn
|
|
1217
|
+
WHERE turn.account_id = p_account_id AND turn.workspace_id = p_workspace_id
|
|
1218
|
+
AND turn.session_id = decision_row.session_id AND turn.id = decision_row.turn_id
|
|
1219
|
+
AND turn.active_attempt_id = decision_row.attempt_id
|
|
1220
|
+
AND turn.execution_generation = decision_row.execution_generation
|
|
1221
|
+
AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
|
|
1222
|
+
AND coalesce(turn.initiating_human_subject_id,
|
|
1223
|
+
CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
|
|
1224
|
+
) = caller_subject_id
|
|
1225
|
+
FOR SHARE;
|
|
1226
|
+
IF NOT FOUND THEN
|
|
1227
|
+
RAISE EXCEPTION 'governed-learning activation turn is unavailable' USING ERRCODE = '42501';
|
|
1228
|
+
END IF;
|
|
1229
|
+
PERFORM 1 FROM session_turn_attempts attempt
|
|
1230
|
+
WHERE attempt.account_id = p_account_id AND attempt.workspace_id = p_workspace_id
|
|
1231
|
+
AND attempt.session_id = decision_row.session_id AND attempt.turn_id = decision_row.turn_id
|
|
1232
|
+
AND attempt.id = decision_row.attempt_id
|
|
1233
|
+
AND attempt.execution_generation = decision_row.execution_generation
|
|
1234
|
+
AND attempt.state IN ('claimed', 'running')
|
|
1235
|
+
AND NOT EXISTS (
|
|
1236
|
+
SELECT 1 FROM session_attempt_interruptions interruption
|
|
1237
|
+
WHERE interruption.workspace_id = p_workspace_id
|
|
1238
|
+
AND interruption.attempt_id = decision_row.attempt_id
|
|
1239
|
+
AND interruption.state IN ('pending', 'delivered', 'acknowledged')
|
|
1240
|
+
)
|
|
1241
|
+
FOR SHARE;
|
|
1242
|
+
IF NOT FOUND THEN
|
|
1243
|
+
RAISE EXCEPTION 'governed-learning activation attempt is unavailable' USING ERRCODE = '42501';
|
|
1244
|
+
END IF;
|
|
1245
|
+
|
|
1246
|
+
SELECT * INTO policy_snapshot FROM workspace_learning_policy_snapshots snapshot
|
|
1247
|
+
WHERE snapshot.id = decision_row.policy_snapshot_id
|
|
1248
|
+
AND snapshot.account_id = p_account_id AND snapshot.workspace_id = p_workspace_id
|
|
1249
|
+
AND snapshot.session_id = decision_row.session_id
|
|
1250
|
+
AND snapshot.turn_id = decision_row.turn_id
|
|
1251
|
+
AND snapshot.attempt_id = decision_row.attempt_id
|
|
1252
|
+
AND snapshot.execution_generation = decision_row.execution_generation
|
|
1253
|
+
AND snapshot.snapshot_hash = decision_row.policy_snapshot_hash
|
|
1254
|
+
FOR SHARE;
|
|
1255
|
+
SELECT * INTO policy_head FROM workspace_learning_policy_heads head
|
|
1256
|
+
WHERE head.account_id = p_account_id AND head.workspace_id = p_workspace_id
|
|
1257
|
+
FOR SHARE;
|
|
1258
|
+
SELECT * INTO policy_revision FROM workspace_learning_policy_revisions revision
|
|
1259
|
+
WHERE revision.account_id = p_account_id AND revision.workspace_id = p_workspace_id
|
|
1260
|
+
AND revision.id = policy_head.revision_id
|
|
1261
|
+
FOR SHARE;
|
|
1262
|
+
IF policy_snapshot.id IS NULL
|
|
1263
|
+
OR policy_head.revision_id IS DISTINCT FROM decision_row.policy_revision_id
|
|
1264
|
+
OR policy_head.policy_hash IS DISTINCT FROM policy_snapshot.policy_hash
|
|
1265
|
+
OR policy_head.activation_version IS DISTINCT FROM decision_row.policy_activation_version
|
|
1266
|
+
OR policy_revision.policy_hash IS DISTINCT FROM policy_snapshot.policy_hash
|
|
1267
|
+
THEN
|
|
1268
|
+
RAISE EXCEPTION 'governed-learning policy authority changed after evaluation'
|
|
1269
|
+
USING ERRCODE = '40001';
|
|
1270
|
+
END IF;
|
|
1271
|
+
current_mode := coalesce((
|
|
1272
|
+
SELECT override.value->>'mode'
|
|
1273
|
+
FROM jsonb_array_elements(policy_revision.source_overrides) override(value)
|
|
1274
|
+
WHERE override.value->>'kind' = decision_row.source_kind
|
|
1275
|
+
AND override.value->>'id' = decision_row.source_id::text LIMIT 1
|
|
1276
|
+
), policy_revision.workspace_mode);
|
|
1277
|
+
IF current_mode <> 'automatic' THEN
|
|
1278
|
+
RAISE EXCEPTION 'governed-learning source is no longer automatic' USING ERRCODE = '42501';
|
|
1279
|
+
END IF;
|
|
1280
|
+
|
|
1281
|
+
SELECT * INTO proposal_row FROM knowledge_change_proposals proposal
|
|
1282
|
+
WHERE proposal.id = decision_row.proposal_id AND proposal.account_id = p_account_id
|
|
1283
|
+
AND proposal.scope_kind = 'workspace' AND proposal.scope_workspace_id = p_workspace_id
|
|
1284
|
+
AND proposal.scope_subject_id IS NULL AND proposal.status = 'proposed'
|
|
1285
|
+
AND proposal.input_hash = decision_row.proposal_input_hash
|
|
1286
|
+
AND proposal.content_hash = decision_row.proposal_content_hash
|
|
1287
|
+
AND proposal.claim_id = decision_row.claim_id
|
|
1288
|
+
AND proposal.evidence_id = decision_row.evidence_id
|
|
1289
|
+
AND proposal.initiating_human_subject_id = caller_subject_id
|
|
1290
|
+
FOR SHARE;
|
|
1291
|
+
SELECT * INTO claim_row FROM knowledge_claims claim
|
|
1292
|
+
WHERE claim.id = decision_row.claim_id AND claim.account_id = p_account_id
|
|
1293
|
+
AND claim.scope_kind = 'workspace' AND claim.scope_workspace_id = p_workspace_id
|
|
1294
|
+
AND claim.scope_subject_id IS NULL AND claim.input_hash = decision_row.claim_input_hash
|
|
1295
|
+
AND claim.initiating_human_subject_id = caller_subject_id
|
|
1296
|
+
AND claim.confidence_bps >= decision_row.confidence_floor_bps
|
|
1297
|
+
AND claim.effective_at <= transaction_timestamp()
|
|
1298
|
+
AND (claim.expires_at IS NULL OR claim.expires_at > transaction_timestamp())
|
|
1299
|
+
FOR UPDATE;
|
|
1300
|
+
SELECT * INTO evidence_row FROM knowledge_claim_evidence evidence
|
|
1301
|
+
WHERE evidence.id = decision_row.evidence_id AND evidence.account_id = p_account_id
|
|
1302
|
+
AND evidence.scope_kind = 'workspace' AND evidence.scope_workspace_id = p_workspace_id
|
|
1303
|
+
AND evidence.scope_subject_id IS NULL AND evidence.claim_id = decision_row.claim_id
|
|
1304
|
+
AND evidence.polarity = 'supports' AND evidence.input_hash = decision_row.evidence_input_hash
|
|
1305
|
+
AND evidence.content_hash = decision_row.evidence_content_hash
|
|
1306
|
+
AND evidence.initiating_human_subject_id = caller_subject_id
|
|
1307
|
+
FOR SHARE;
|
|
1308
|
+
IF proposal_row.id IS NULL OR claim_row.id IS NULL OR evidence_row.id IS NULL THEN
|
|
1309
|
+
RAISE EXCEPTION 'governed-learning proposal lineage changed after evaluation'
|
|
1310
|
+
USING ERRCODE = '42501';
|
|
1311
|
+
END IF;
|
|
1312
|
+
SELECT * INTO review_row FROM knowledge_claim_reviews review
|
|
1313
|
+
WHERE review.account_id = p_account_id AND review.claim_id = decision_row.claim_id
|
|
1314
|
+
ORDER BY review.review_revision DESC LIMIT 1 FOR SHARE;
|
|
1315
|
+
IF review_row.id IS NULL OR review_row.state <> 'proposed'
|
|
1316
|
+
OR review_row.review_revision <> decision_row.review_revision
|
|
1317
|
+
THEN
|
|
1318
|
+
RAISE EXCEPTION 'governed-learning review was superseded after evaluation'
|
|
1319
|
+
USING ERRCODE = '40001';
|
|
1320
|
+
END IF;
|
|
1321
|
+
SELECT least(1000, count(*))::integer INTO conflict_count FROM (
|
|
1322
|
+
SELECT relation.id FROM knowledge_claim_relations relation
|
|
1323
|
+
WHERE relation.account_id = p_account_id AND relation.scope_kind = 'workspace'
|
|
1324
|
+
AND relation.scope_workspace_id = p_workspace_id AND relation.scope_subject_id IS NULL
|
|
1325
|
+
AND relation.relation_type = 'conflicts_with'
|
|
1326
|
+
AND (relation.from_claim_id = decision_row.claim_id
|
|
1327
|
+
OR relation.to_claim_id = decision_row.claim_id)
|
|
1328
|
+
UNION ALL
|
|
1329
|
+
SELECT contradiction.id FROM knowledge_claim_evidence contradiction
|
|
1330
|
+
WHERE contradiction.account_id = p_account_id AND contradiction.scope_kind = 'workspace'
|
|
1331
|
+
AND contradiction.scope_workspace_id = p_workspace_id
|
|
1332
|
+
AND contradiction.scope_subject_id IS NULL
|
|
1333
|
+
AND contradiction.claim_id = decision_row.claim_id
|
|
1334
|
+
AND contradiction.polarity = 'contradicts'
|
|
1335
|
+
) conflicts;
|
|
1336
|
+
IF conflict_count <> 0 THEN
|
|
1337
|
+
RAISE EXCEPTION 'governed-learning evidence now conflicts' USING ERRCODE = '23514';
|
|
1338
|
+
END IF;
|
|
1339
|
+
|
|
1340
|
+
IF evidence_row.task_note_id IS NOT NULL THEN
|
|
1341
|
+
SELECT * INTO task_note_row FROM task_notes note
|
|
1342
|
+
WHERE note.id = evidence_row.task_note_id AND note.account_id = p_account_id
|
|
1343
|
+
AND note.workspace_id = p_workspace_id
|
|
1344
|
+
AND note.root_session_id = evidence_row.task_note_root_session_id
|
|
1345
|
+
AND note.version = evidence_row.task_note_version
|
|
1346
|
+
AND note.text_hash = evidence_row.content_hash
|
|
1347
|
+
AND note.status = 'active' AND note.expires_at > transaction_timestamp()
|
|
1348
|
+
AND session_reference_visible(note.account_id, note.workspace_id, note.root_session_id)
|
|
1349
|
+
FOR SHARE;
|
|
1350
|
+
IF NOT FOUND THEN
|
|
1351
|
+
RAISE EXCEPTION 'governed-learning Task-note authority was revoked' USING ERRCODE = '42501';
|
|
1352
|
+
END IF;
|
|
1353
|
+
current_authority_hash := encode(sha256(convert_to(jsonb_build_array(
|
|
1354
|
+
'task-note-authority', 1, evidence_row.task_note_id,
|
|
1355
|
+
evidence_row.task_note_root_session_id, evidence_row.task_note_version,
|
|
1356
|
+
evidence_row.content_hash, task_note_row.status, task_note_row.expires_at
|
|
1357
|
+
)::text, 'UTF8')), 'hex');
|
|
1358
|
+
ELSE
|
|
1359
|
+
SELECT provider.id AS provider_id, provider.lifecycle_state AS provider_state,
|
|
1360
|
+
provider.lifecycle_generation AS provider_generation, source.id AS source_id,
|
|
1361
|
+
source.lifecycle_state AS source_state, source.lifecycle_generation AS source_generation,
|
|
1362
|
+
source.current_acl_generation, object.id AS object_id,
|
|
1363
|
+
object.lifecycle_state AS object_state, object.lifecycle_generation AS object_generation,
|
|
1364
|
+
object.version_generation AS object_version_generation, object.current_version_id,
|
|
1365
|
+
version.id AS version_id, version.version_generation, version.content_sha256,
|
|
1366
|
+
version.acl_version_id, version.acl_generation, version.document_id,
|
|
1367
|
+
evidence_acl.acl_hash AS evidence_acl_hash,
|
|
1368
|
+
evidence_acl.agent_access AS evidence_agent_access,
|
|
1369
|
+
current_acl.id AS current_acl_id, current_acl.acl_hash AS current_acl_hash,
|
|
1370
|
+
current_acl.agent_access AS current_agent_access
|
|
1371
|
+
INTO document_authority
|
|
1372
|
+
FROM knowledge_document_versions version
|
|
1373
|
+
JOIN knowledge_source_objects object ON object.account_id = version.account_id
|
|
1374
|
+
AND object.id = version.object_id AND object.scope_key = version.scope_key
|
|
1375
|
+
JOIN knowledge_sources source ON source.account_id = version.account_id
|
|
1376
|
+
AND source.id = version.source_id AND source.scope_key = version.scope_key
|
|
1377
|
+
JOIN knowledge_providers provider ON provider.account_id = source.account_id
|
|
1378
|
+
AND provider.id = source.provider_id AND provider.scope_key = source.scope_key
|
|
1379
|
+
JOIN knowledge_source_acl_versions evidence_acl ON evidence_acl.account_id = version.account_id
|
|
1380
|
+
AND evidence_acl.id = version.acl_version_id AND evidence_acl.source_id = version.source_id
|
|
1381
|
+
AND evidence_acl.generation = version.acl_generation
|
|
1382
|
+
LEFT JOIN knowledge_source_acl_versions current_acl ON current_acl.account_id = source.account_id
|
|
1383
|
+
AND current_acl.source_id = source.id AND current_acl.generation = source.current_acl_generation
|
|
1384
|
+
WHERE version.id = evidence_row.document_version_id AND version.account_id = p_account_id
|
|
1385
|
+
AND version.scope_kind = 'workspace' AND version.scope_workspace_id = p_workspace_id
|
|
1386
|
+
AND version.scope_subject_id IS NULL
|
|
1387
|
+
FOR SHARE OF version, object, source, provider, evidence_acl;
|
|
1388
|
+
IF document_authority.version_id IS NULL
|
|
1389
|
+
OR document_authority.provider_state IS DISTINCT FROM 'active'
|
|
1390
|
+
OR document_authority.source_state IS DISTINCT FROM 'active'
|
|
1391
|
+
OR document_authority.object_state IS DISTINCT FROM 'active'
|
|
1392
|
+
OR document_authority.current_version_id IS DISTINCT FROM document_authority.version_id
|
|
1393
|
+
OR document_authority.object_version_generation IS DISTINCT FROM document_authority.version_generation
|
|
1394
|
+
OR document_authority.current_acl_id IS NULL
|
|
1395
|
+
OR NOT coalesce(document_authority.evidence_agent_access, false)
|
|
1396
|
+
OR NOT coalesce(document_authority.current_agent_access, false)
|
|
1397
|
+
OR (document_authority.document_id IS NOT NULL AND NOT EXISTS (
|
|
1398
|
+
SELECT 1 FROM documents document WHERE document.id = document_authority.document_id
|
|
1399
|
+
AND document.account_id = p_account_id AND document.workspace_id = p_workspace_id
|
|
1400
|
+
AND document.status = 'ready' AND document.agent_access
|
|
1401
|
+
AND (document.visibility <> 'private' OR document.created_by = caller_subject_id)
|
|
1402
|
+
))
|
|
1403
|
+
OR (evidence_row.document_chunk_id IS NOT NULL AND NOT EXISTS (
|
|
1404
|
+
SELECT 1 FROM document_chunks chunk WHERE chunk.id = evidence_row.document_chunk_id
|
|
1405
|
+
AND chunk.account_id = p_account_id AND chunk.workspace_id = p_workspace_id
|
|
1406
|
+
AND chunk.document_id = document_authority.document_id
|
|
1407
|
+
))
|
|
1408
|
+
THEN
|
|
1409
|
+
RAISE EXCEPTION 'governed-learning document authority was revoked' USING ERRCODE = '42501';
|
|
1410
|
+
END IF;
|
|
1411
|
+
current_authority_hash := encode(sha256(convert_to(jsonb_build_array(
|
|
1412
|
+
'document-evidence-authority', 1, evidence_row.document_version_id,
|
|
1413
|
+
document_authority.provider_id, document_authority.provider_state,
|
|
1414
|
+
document_authority.provider_generation, document_authority.source_id,
|
|
1415
|
+
document_authority.source_state, document_authority.source_generation,
|
|
1416
|
+
document_authority.current_acl_generation, document_authority.object_id,
|
|
1417
|
+
document_authority.object_state, document_authority.object_generation,
|
|
1418
|
+
document_authority.object_version_generation, document_authority.current_version_id,
|
|
1419
|
+
document_authority.version_id, document_authority.version_generation,
|
|
1420
|
+
document_authority.content_sha256, document_authority.acl_version_id,
|
|
1421
|
+
document_authority.acl_generation, document_authority.evidence_acl_hash,
|
|
1422
|
+
document_authority.current_acl_id, document_authority.current_acl_hash,
|
|
1423
|
+
evidence_row.document_chunk_id, false
|
|
1424
|
+
)::text, 'UTF8')), 'hex');
|
|
1425
|
+
END IF;
|
|
1426
|
+
IF current_authority_hash IS DISTINCT FROM decision_row.evidence_authority_hash THEN
|
|
1427
|
+
RAISE EXCEPTION 'governed-learning evidence authority changed after evaluation'
|
|
1428
|
+
USING ERRCODE = '40001';
|
|
1429
|
+
END IF;
|
|
1430
|
+
|
|
1431
|
+
IF proposal_row.target_kind = 'instruction_policy' THEN
|
|
1432
|
+
SELECT * INTO instruction_proposal
|
|
1433
|
+
FROM workspace_instruction_policy_onboarding_proposals proposal
|
|
1434
|
+
WHERE proposal.account_id = p_account_id AND proposal.workspace_id = p_workspace_id
|
|
1435
|
+
AND proposal.source_id = proposal_row.id::text
|
|
1436
|
+
AND proposal.source_version = proposal_row.content_hash
|
|
1437
|
+
AND proposal.status = 'proposed'
|
|
1438
|
+
FOR SHARE;
|
|
1439
|
+
IF NOT FOUND OR instruction_proposal.draft_content_hash <> proposal_row.content_hash THEN
|
|
1440
|
+
RAISE EXCEPTION 'exact inactive instruction-policy proposal is unavailable'
|
|
1441
|
+
USING ERRCODE = '42501';
|
|
1442
|
+
END IF;
|
|
1443
|
+
SELECT * INTO current_instruction_head FROM workspace_instruction_policy_heads head
|
|
1444
|
+
WHERE head.account_id = p_account_id AND head.workspace_id = p_workspace_id
|
|
1445
|
+
AND head.kind = instruction_proposal.kind AND head.scope = instruction_proposal.scope
|
|
1446
|
+
AND head.role_key IS NOT DISTINCT FROM instruction_proposal.role_key FOR SHARE;
|
|
1447
|
+
IF NOT FOUND THEN
|
|
1448
|
+
SELECT event.activation_version INTO current_instruction_activation_version
|
|
1449
|
+
FROM workspace_instruction_policy_deactivation_events event
|
|
1450
|
+
WHERE event.account_id = p_account_id AND event.workspace_id = p_workspace_id
|
|
1451
|
+
AND event.kind = instruction_proposal.kind AND event.scope = instruction_proposal.scope
|
|
1452
|
+
AND event.role_key IS NOT DISTINCT FROM instruction_proposal.role_key
|
|
1453
|
+
ORDER BY event.activation_version DESC, event.id DESC
|
|
1454
|
+
LIMIT 1;
|
|
1455
|
+
END IF;
|
|
1456
|
+
current_instruction_activation_version := coalesce(
|
|
1457
|
+
current_instruction_head.activation_version,
|
|
1458
|
+
current_instruction_activation_version,
|
|
1459
|
+
0
|
|
1460
|
+
);
|
|
1461
|
+
IF current_instruction_head.revision_id IS DISTINCT FROM instruction_proposal.baseline_revision_id
|
|
1462
|
+
OR current_instruction_activation_version
|
|
1463
|
+
IS DISTINCT FROM instruction_proposal.baseline_activation_version
|
|
1464
|
+
THEN
|
|
1465
|
+
RAISE EXCEPTION 'instruction-policy proposal baseline is stale' USING ERRCODE = '40001';
|
|
1466
|
+
END IF;
|
|
1467
|
+
destination_value := 'instruction_policy';
|
|
1468
|
+
destination_proposal_id_value := instruction_proposal.id;
|
|
1469
|
+
destination_revision_id_value := instruction_proposal.draft_revision_id;
|
|
1470
|
+
destination_old_revision_id_value := instruction_proposal.baseline_revision_id;
|
|
1471
|
+
destination_old_content_hash_value := instruction_proposal.baseline_content_hash;
|
|
1472
|
+
destination_old_version_value := instruction_proposal.baseline_activation_version;
|
|
1473
|
+
destination_new_content_hash_value := instruction_proposal.draft_content_hash;
|
|
1474
|
+
ELSIF proposal_row.target_kind = 'preference' THEN
|
|
1475
|
+
SELECT * INTO preference_receipt FROM company_brain_preference_proposal_receipts receipt
|
|
1476
|
+
WHERE receipt.account_id = p_account_id AND receipt.workspace_id = p_workspace_id
|
|
1477
|
+
AND receipt.knowledge_proposal_id = proposal_row.id FOR SHARE;
|
|
1478
|
+
SELECT * INTO preference_row FROM preference_registry_preferences preference
|
|
1479
|
+
WHERE preference.account_id = p_account_id AND preference.id = preference_receipt.preference_id
|
|
1480
|
+
AND preference.scope = 'workspace' AND preference.scope_workspace_id = p_workspace_id
|
|
1481
|
+
AND preference.scope_subject_id IS NULL AND preference.status = 'proposed'
|
|
1482
|
+
AND preference.active_revision_id IS NULL AND preference.activation_version = 0
|
|
1483
|
+
AND preference.scope_version = 1 FOR SHARE;
|
|
1484
|
+
SELECT * INTO preference_revision FROM preference_registry_revisions revision
|
|
1485
|
+
WHERE revision.account_id = p_account_id AND revision.id = preference_receipt.revision_id
|
|
1486
|
+
AND revision.preference_id = preference_receipt.preference_id
|
|
1487
|
+
AND revision.provenance_source = 'knowledge_proposal'
|
|
1488
|
+
AND revision.provenance_source_id = proposal_row.id::text
|
|
1489
|
+
AND revision.trust = 'untrusted_proposal'
|
|
1490
|
+
AND (revision.expires_at IS NULL OR revision.expires_at > transaction_timestamp())
|
|
1491
|
+
FOR SHARE;
|
|
1492
|
+
IF preference_receipt.id IS NULL OR preference_row.id IS NULL OR preference_revision.id IS NULL
|
|
1493
|
+
OR proposal_row.target_scope <> 'workspace'
|
|
1494
|
+
OR proposal_row.target_key <> preference_row.stable_key
|
|
1495
|
+
THEN
|
|
1496
|
+
RAISE EXCEPTION 'exact inactive preference proposal is unavailable'
|
|
1497
|
+
USING ERRCODE = '42501';
|
|
1498
|
+
END IF;
|
|
1499
|
+
destination_value := 'preference';
|
|
1500
|
+
destination_proposal_id_value := preference_row.id;
|
|
1501
|
+
destination_revision_id_value := preference_revision.id;
|
|
1502
|
+
destination_old_revision_id_value := NULL;
|
|
1503
|
+
destination_old_content_hash_value := NULL;
|
|
1504
|
+
destination_old_version_value := 0;
|
|
1505
|
+
destination_new_content_hash_value := preference_revision.content_hash;
|
|
1506
|
+
ELSE
|
|
1507
|
+
RAISE EXCEPTION 'unsupported governed-learning destination' USING ERRCODE = '23514';
|
|
1508
|
+
END IF;
|
|
1509
|
+
|
|
1510
|
+
service_actor := 'service:governed-learning-activation:' || input_hash_value;
|
|
1511
|
+
review_operation_id := opengeni_private.governed_learning_derived_uuid(
|
|
1512
|
+
p_operation_id, 'knowledge-approve'
|
|
1513
|
+
);
|
|
1514
|
+
destination_operation_id := opengeni_private.governed_learning_derived_uuid(
|
|
1515
|
+
p_operation_id, 'destination-activate'
|
|
1516
|
+
);
|
|
1517
|
+
SELECT * INTO approval_row FROM governed_learning_apply_knowledge_review(
|
|
1518
|
+
p_account_id, p_workspace_id, review_operation_id, decision_row.claim_id,
|
|
1519
|
+
review_row.id, review_row.review_revision, 'approved', service_actor, caller_subject_id
|
|
1520
|
+
);
|
|
1521
|
+
IF destination_value = 'instruction_policy' THEN
|
|
1522
|
+
SELECT * INTO instruction_event FROM governed_learning_apply_instruction_policy(
|
|
1523
|
+
'activate', p_account_id, p_workspace_id, destination_operation_id,
|
|
1524
|
+
destination_proposal_id_value, destination_old_revision_id_value,
|
|
1525
|
+
destination_old_version_value, destination_revision_id_value, service_actor
|
|
1526
|
+
);
|
|
1527
|
+
destination_new_version_value := instruction_event.activation_version;
|
|
1528
|
+
destination_event_id_value := instruction_event.id;
|
|
1529
|
+
effective_at_value := instruction_event.created_at;
|
|
1530
|
+
ELSE
|
|
1531
|
+
SELECT * INTO preference_event FROM governed_learning_apply_preference(
|
|
1532
|
+
'activate', p_account_id, p_workspace_id, destination_operation_id,
|
|
1533
|
+
proposal_row.id, destination_proposal_id_value, destination_revision_id_value,
|
|
1534
|
+
NULL, 0, service_actor
|
|
1535
|
+
);
|
|
1536
|
+
SELECT activation_version INTO destination_new_version_value
|
|
1537
|
+
FROM preference_registry_preferences WHERE id = destination_proposal_id_value;
|
|
1538
|
+
destination_event_id_value := preference_event.id;
|
|
1539
|
+
effective_at_value := preference_event.created_at;
|
|
1540
|
+
END IF;
|
|
1541
|
+
|
|
1542
|
+
INSERT INTO governed_learning_activation_receipts (
|
|
1543
|
+
account_id, workspace_id, operation_id, input_hash, decision_receipt_id,
|
|
1544
|
+
initiating_human_subject_id, service_actor_subject_id, policy_revision_id,
|
|
1545
|
+
policy_hash, policy_activation_version, source_kind, source_id,
|
|
1546
|
+
source_authority_hash, proposal_id, claim_id, evidence_id,
|
|
1547
|
+
knowledge_previous_review_id, knowledge_previous_review_revision,
|
|
1548
|
+
knowledge_approval_review_id, knowledge_approval_review_revision,
|
|
1549
|
+
knowledge_approval_input_hash, destination, destination_proposal_id,
|
|
1550
|
+
destination_revision_id, destination_old_revision_id,
|
|
1551
|
+
destination_old_content_hash, destination_old_version,
|
|
1552
|
+
destination_new_content_hash, destination_new_version, destination_event_id,
|
|
1553
|
+
effective_at
|
|
1554
|
+
) VALUES (
|
|
1555
|
+
p_account_id, p_workspace_id, p_operation_id, input_hash_value,
|
|
1556
|
+
p_decision_receipt_id, caller_subject_id, service_actor, policy_revision.id,
|
|
1557
|
+
policy_revision.policy_hash, policy_head.activation_version,
|
|
1558
|
+
decision_row.source_kind, decision_row.source_id, current_authority_hash,
|
|
1559
|
+
decision_row.proposal_id, decision_row.claim_id, decision_row.evidence_id,
|
|
1560
|
+
review_row.id, review_row.review_revision, approval_row.id,
|
|
1561
|
+
approval_row.review_revision, approval_row.input_hash, destination_value,
|
|
1562
|
+
destination_proposal_id_value, destination_revision_id_value,
|
|
1563
|
+
destination_old_revision_id_value, destination_old_content_hash_value,
|
|
1564
|
+
destination_old_version_value, destination_new_content_hash_value,
|
|
1565
|
+
destination_new_version_value, destination_event_id_value, effective_at_value
|
|
1566
|
+
) RETURNING * INTO result_row;
|
|
1567
|
+
RETURN NEXT result_row;
|
|
1568
|
+
END;
|
|
1569
|
+
$$;
|
|
1570
|
+
REVOKE ALL ON FUNCTION activate_governed_learning_decision(uuid, uuid, uuid, uuid) FROM PUBLIC;
|
|
1571
|
+
|
|
1572
|
+
CREATE OR REPLACE FUNCTION undo_governed_learning_activation(
|
|
1573
|
+
p_account_id uuid,
|
|
1574
|
+
p_workspace_id uuid,
|
|
1575
|
+
p_operation_id uuid,
|
|
1576
|
+
p_activation_receipt_id uuid
|
|
1577
|
+
) RETURNS SETOF governed_learning_activation_undo_receipts
|
|
1578
|
+
LANGUAGE plpgsql SECURITY DEFINER AS $$
|
|
1579
|
+
DECLARE
|
|
1580
|
+
caller_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
1581
|
+
activation_row governed_learning_activation_receipts%ROWTYPE;
|
|
1582
|
+
decision_row governed_learning_decision_receipts%ROWTYPE;
|
|
1583
|
+
result_row governed_learning_activation_undo_receipts%ROWTYPE;
|
|
1584
|
+
latest_review knowledge_claim_reviews%ROWTYPE;
|
|
1585
|
+
revocation_row knowledge_claim_reviews%ROWTYPE;
|
|
1586
|
+
instruction_head workspace_instruction_policy_heads%ROWTYPE;
|
|
1587
|
+
instruction_event workspace_instruction_policy_activation_events%ROWTYPE;
|
|
1588
|
+
instruction_deactivation workspace_instruction_policy_deactivation_events%ROWTYPE;
|
|
1589
|
+
preference_row preference_registry_preferences%ROWTYPE;
|
|
1590
|
+
preference_event preference_registry_events%ROWTYPE;
|
|
1591
|
+
input_hash_value text;
|
|
1592
|
+
service_actor text;
|
|
1593
|
+
review_operation_id uuid;
|
|
1594
|
+
destination_operation_id uuid;
|
|
1595
|
+
destination_new_version_value bigint;
|
|
1596
|
+
destination_event_id_value uuid;
|
|
1597
|
+
effective_at_value timestamptz;
|
|
1598
|
+
BEGIN
|
|
1599
|
+
IF p_account_id IS NULL OR p_workspace_id IS NULL OR p_operation_id IS NULL
|
|
1600
|
+
OR p_activation_receipt_id IS NULL OR caller_subject_id IS NULL
|
|
1601
|
+
OR length(btrim(caller_subject_id)) NOT BETWEEN 1 AND 1024
|
|
1602
|
+
OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
|
|
1603
|
+
OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
|
|
1604
|
+
THEN
|
|
1605
|
+
RAISE EXCEPTION 'governed-learning undo requires exact tenant authority'
|
|
1606
|
+
USING ERRCODE = '42501';
|
|
1607
|
+
END IF;
|
|
1608
|
+
input_hash_value := encode(sha256(convert_to(jsonb_build_array(
|
|
1609
|
+
'governed-learning-activation-undo', 1, p_account_id, p_workspace_id,
|
|
1610
|
+
p_operation_id, p_activation_receipt_id
|
|
1611
|
+
)::text, 'UTF8')), 'hex');
|
|
1612
|
+
SELECT * INTO result_row FROM governed_learning_activation_undo_receipts receipt
|
|
1613
|
+
WHERE receipt.workspace_id = p_workspace_id AND receipt.operation_id = p_operation_id
|
|
1614
|
+
FOR SHARE;
|
|
1615
|
+
IF FOUND THEN
|
|
1616
|
+
IF result_row.account_id <> p_account_id OR result_row.input_hash <> input_hash_value
|
|
1617
|
+
OR result_row.activation_receipt_id <> p_activation_receipt_id
|
|
1618
|
+
OR result_row.initiating_human_subject_id <> caller_subject_id
|
|
1619
|
+
THEN
|
|
1620
|
+
RAISE EXCEPTION 'governed-learning undo operation conflicts with immutable receipt'
|
|
1621
|
+
USING ERRCODE = '23505';
|
|
1622
|
+
END IF;
|
|
1623
|
+
RETURN NEXT result_row;
|
|
1624
|
+
RETURN;
|
|
1625
|
+
END IF;
|
|
1626
|
+
PERFORM 1 FROM workspaces workspace
|
|
1627
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
|
|
1628
|
+
FOR UPDATE;
|
|
1629
|
+
IF NOT FOUND THEN
|
|
1630
|
+
RAISE EXCEPTION 'governed-learning workspace is unavailable' USING ERRCODE = '42501';
|
|
1631
|
+
END IF;
|
|
1632
|
+
SELECT * INTO result_row FROM governed_learning_activation_undo_receipts receipt
|
|
1633
|
+
WHERE receipt.workspace_id = p_workspace_id AND receipt.operation_id = p_operation_id
|
|
1634
|
+
FOR SHARE;
|
|
1635
|
+
IF FOUND THEN
|
|
1636
|
+
IF result_row.account_id <> p_account_id OR result_row.input_hash <> input_hash_value
|
|
1637
|
+
OR result_row.activation_receipt_id <> p_activation_receipt_id
|
|
1638
|
+
OR result_row.initiating_human_subject_id <> caller_subject_id
|
|
1639
|
+
THEN
|
|
1640
|
+
RAISE EXCEPTION 'governed-learning undo operation conflicts with immutable receipt'
|
|
1641
|
+
USING ERRCODE = '23505';
|
|
1642
|
+
END IF;
|
|
1643
|
+
RETURN NEXT result_row;
|
|
1644
|
+
RETURN;
|
|
1645
|
+
END IF;
|
|
1646
|
+
SELECT * INTO activation_row FROM governed_learning_activation_receipts receipt
|
|
1647
|
+
WHERE receipt.id = p_activation_receipt_id AND receipt.account_id = p_account_id
|
|
1648
|
+
AND receipt.workspace_id = p_workspace_id
|
|
1649
|
+
AND receipt.initiating_human_subject_id = caller_subject_id
|
|
1650
|
+
FOR UPDATE;
|
|
1651
|
+
IF NOT FOUND THEN
|
|
1652
|
+
RAISE EXCEPTION 'governed-learning activation receipt is unavailable' USING ERRCODE = '42501';
|
|
1653
|
+
END IF;
|
|
1654
|
+
SELECT * INTO decision_row FROM governed_learning_decision_receipts receipt
|
|
1655
|
+
WHERE receipt.id = activation_row.decision_receipt_id
|
|
1656
|
+
AND receipt.account_id = p_account_id AND receipt.workspace_id = p_workspace_id
|
|
1657
|
+
AND receipt.initiating_human_subject_id = caller_subject_id FOR SHARE;
|
|
1658
|
+
IF NOT FOUND OR NOT session_reference_visible(
|
|
1659
|
+
decision_row.account_id, decision_row.workspace_id, decision_row.session_id
|
|
1660
|
+
) THEN
|
|
1661
|
+
RAISE EXCEPTION 'governed-learning undo source is unavailable' USING ERRCODE = '42501';
|
|
1662
|
+
END IF;
|
|
1663
|
+
IF EXISTS (
|
|
1664
|
+
SELECT 1 FROM governed_learning_activation_undo_receipts receipt
|
|
1665
|
+
WHERE receipt.activation_receipt_id = p_activation_receipt_id
|
|
1666
|
+
) THEN
|
|
1667
|
+
RAISE EXCEPTION 'governed-learning activation was undone by another operation'
|
|
1668
|
+
USING ERRCODE = '23505';
|
|
1669
|
+
END IF;
|
|
1670
|
+
SELECT * INTO latest_review FROM knowledge_claim_reviews review
|
|
1671
|
+
WHERE review.account_id = p_account_id AND review.claim_id = activation_row.claim_id
|
|
1672
|
+
ORDER BY review.review_revision DESC LIMIT 1 FOR UPDATE;
|
|
1673
|
+
IF latest_review.id IS DISTINCT FROM activation_row.knowledge_approval_review_id
|
|
1674
|
+
OR latest_review.review_revision IS DISTINCT FROM activation_row.knowledge_approval_review_revision
|
|
1675
|
+
OR latest_review.state <> 'approved'
|
|
1676
|
+
THEN
|
|
1677
|
+
RAISE EXCEPTION 'automatic Knowledge activation was superseded' USING ERRCODE = '40001';
|
|
1678
|
+
END IF;
|
|
1679
|
+
service_actor := 'service:governed-learning-activation:' || input_hash_value;
|
|
1680
|
+
review_operation_id := opengeni_private.governed_learning_derived_uuid(
|
|
1681
|
+
p_operation_id, 'knowledge-revoke'
|
|
1682
|
+
);
|
|
1683
|
+
destination_operation_id := opengeni_private.governed_learning_derived_uuid(
|
|
1684
|
+
p_operation_id, 'destination-undo'
|
|
1685
|
+
);
|
|
1686
|
+
|
|
1687
|
+
IF activation_row.destination = 'instruction_policy' THEN
|
|
1688
|
+
SELECT head.* INTO instruction_head FROM workspace_instruction_policy_heads head
|
|
1689
|
+
JOIN workspace_instruction_policy_onboarding_proposals proposal
|
|
1690
|
+
ON proposal.account_id = head.account_id AND proposal.workspace_id = head.workspace_id
|
|
1691
|
+
AND proposal.id = activation_row.destination_proposal_id
|
|
1692
|
+
AND proposal.kind = head.kind AND proposal.scope = head.scope
|
|
1693
|
+
AND proposal.role_key IS NOT DISTINCT FROM head.role_key
|
|
1694
|
+
WHERE head.account_id = p_account_id AND head.workspace_id = p_workspace_id
|
|
1695
|
+
AND head.revision_id = activation_row.destination_revision_id
|
|
1696
|
+
AND head.content_hash = activation_row.destination_new_content_hash
|
|
1697
|
+
AND head.activation_version = activation_row.destination_new_version
|
|
1698
|
+
FOR UPDATE OF head;
|
|
1699
|
+
IF NOT FOUND THEN
|
|
1700
|
+
RAISE EXCEPTION 'automatic instruction-policy activation was superseded'
|
|
1701
|
+
USING ERRCODE = '40001';
|
|
1702
|
+
END IF;
|
|
1703
|
+
IF activation_row.destination_old_revision_id IS NULL THEN
|
|
1704
|
+
SELECT * INTO instruction_deactivation
|
|
1705
|
+
FROM governed_learning_deactivate_instruction_policy(
|
|
1706
|
+
p_account_id, p_workspace_id, destination_operation_id,
|
|
1707
|
+
activation_row.destination_proposal_id, activation_row.destination_revision_id,
|
|
1708
|
+
activation_row.destination_new_version, service_actor
|
|
1709
|
+
);
|
|
1710
|
+
destination_new_version_value := instruction_deactivation.activation_version;
|
|
1711
|
+
destination_event_id_value := instruction_deactivation.id;
|
|
1712
|
+
effective_at_value := instruction_deactivation.created_at;
|
|
1713
|
+
ELSE
|
|
1714
|
+
SELECT * INTO instruction_event FROM governed_learning_apply_instruction_policy(
|
|
1715
|
+
'undo', p_account_id, p_workspace_id, destination_operation_id,
|
|
1716
|
+
activation_row.destination_proposal_id, activation_row.destination_revision_id,
|
|
1717
|
+
activation_row.destination_new_version, activation_row.destination_old_revision_id,
|
|
1718
|
+
service_actor
|
|
1719
|
+
);
|
|
1720
|
+
destination_new_version_value := instruction_event.activation_version;
|
|
1721
|
+
destination_event_id_value := instruction_event.id;
|
|
1722
|
+
effective_at_value := instruction_event.created_at;
|
|
1723
|
+
END IF;
|
|
1724
|
+
ELSIF activation_row.destination = 'preference' THEN
|
|
1725
|
+
SELECT * INTO preference_row FROM preference_registry_preferences preference
|
|
1726
|
+
WHERE preference.account_id = p_account_id AND preference.id = activation_row.destination_proposal_id
|
|
1727
|
+
AND preference.scope = 'workspace' AND preference.scope_workspace_id = p_workspace_id
|
|
1728
|
+
AND preference.status = 'active'
|
|
1729
|
+
AND preference.active_revision_id = activation_row.destination_revision_id
|
|
1730
|
+
AND preference.active_content_hash = activation_row.destination_new_content_hash
|
|
1731
|
+
AND preference.activation_version = activation_row.destination_new_version
|
|
1732
|
+
FOR UPDATE;
|
|
1733
|
+
IF NOT FOUND THEN
|
|
1734
|
+
RAISE EXCEPTION 'automatic preference activation was superseded' USING ERRCODE = '40001';
|
|
1735
|
+
END IF;
|
|
1736
|
+
SELECT * INTO preference_event FROM governed_learning_apply_preference(
|
|
1737
|
+
'undo', p_account_id, p_workspace_id, destination_operation_id,
|
|
1738
|
+
activation_row.proposal_id, activation_row.destination_proposal_id,
|
|
1739
|
+
activation_row.destination_revision_id, activation_row.destination_revision_id,
|
|
1740
|
+
activation_row.destination_new_version::integer, service_actor
|
|
1741
|
+
);
|
|
1742
|
+
SELECT activation_version INTO destination_new_version_value
|
|
1743
|
+
FROM preference_registry_preferences WHERE id = activation_row.destination_proposal_id;
|
|
1744
|
+
destination_event_id_value := preference_event.id;
|
|
1745
|
+
effective_at_value := preference_event.created_at;
|
|
1746
|
+
ELSE
|
|
1747
|
+
RAISE EXCEPTION 'governed-learning activation destination is invalid' USING ERRCODE = '23514';
|
|
1748
|
+
END IF;
|
|
1749
|
+
SELECT * INTO revocation_row FROM governed_learning_apply_knowledge_review(
|
|
1750
|
+
p_account_id, p_workspace_id, review_operation_id, activation_row.claim_id,
|
|
1751
|
+
latest_review.id, latest_review.review_revision, 'revoked', service_actor,
|
|
1752
|
+
caller_subject_id
|
|
1753
|
+
);
|
|
1754
|
+
INSERT INTO governed_learning_activation_undo_receipts (
|
|
1755
|
+
account_id, workspace_id, operation_id, input_hash, activation_receipt_id,
|
|
1756
|
+
initiating_human_subject_id, service_actor_subject_id, destination,
|
|
1757
|
+
knowledge_approval_review_id, knowledge_revocation_review_id,
|
|
1758
|
+
knowledge_revocation_review_revision, knowledge_revocation_input_hash,
|
|
1759
|
+
destination_activated_revision_id, destination_restored_revision_id,
|
|
1760
|
+
destination_activated_content_hash, destination_restored_content_hash,
|
|
1761
|
+
destination_old_version, destination_new_version, destination_event_id,
|
|
1762
|
+
effective_at
|
|
1763
|
+
) VALUES (
|
|
1764
|
+
p_account_id, p_workspace_id, p_operation_id, input_hash_value,
|
|
1765
|
+
activation_row.id, caller_subject_id, service_actor, activation_row.destination,
|
|
1766
|
+
activation_row.knowledge_approval_review_id, revocation_row.id,
|
|
1767
|
+
revocation_row.review_revision, revocation_row.input_hash,
|
|
1768
|
+
activation_row.destination_revision_id, activation_row.destination_old_revision_id,
|
|
1769
|
+
activation_row.destination_new_content_hash, activation_row.destination_old_content_hash,
|
|
1770
|
+
activation_row.destination_new_version, destination_new_version_value,
|
|
1771
|
+
destination_event_id_value, effective_at_value
|
|
1772
|
+
) RETURNING * INTO result_row;
|
|
1773
|
+
RETURN NEXT result_row;
|
|
1774
|
+
END;
|
|
1775
|
+
$$;
|
|
1776
|
+
REVOKE ALL ON FUNCTION undo_governed_learning_activation(uuid, uuid, uuid, uuid) FROM PUBLIC;
|
|
1777
|
+
|
|
1778
|
+
-- Target-schema hardening is mandatory because runtime roles may have TEMP.
|
|
1779
|
+
DO $governed_learning_activation_hardening$
|
|
1780
|
+
DECLARE
|
|
1781
|
+
target_schema text := current_schema();
|
|
1782
|
+
runtime_role text := nullif(current_setting('opengeni.runtime_role', true), '');
|
|
1783
|
+
BEGIN
|
|
1784
|
+
IF runtime_role IS NULL AND EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
1785
|
+
runtime_role := 'opengeni_app';
|
|
1786
|
+
END IF;
|
|
1787
|
+
EXECUTE format(
|
|
1788
|
+
'ALTER FUNCTION %I.governed_learning_reject_activation_receipt_mutation() '
|
|
1789
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1790
|
+
);
|
|
1791
|
+
EXECUTE format(
|
|
1792
|
+
'ALTER FUNCTION %I.governed_learning_guard_service_review() '
|
|
1793
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1794
|
+
);
|
|
1795
|
+
EXECUTE format(
|
|
1796
|
+
'ALTER FUNCTION %I.governed_learning_apply_knowledge_review('
|
|
1797
|
+
|| 'uuid,uuid,uuid,uuid,uuid,bigint,text,text,text) '
|
|
1798
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1799
|
+
);
|
|
1800
|
+
EXECUTE format(
|
|
1801
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_reject_mutation() '
|
|
1802
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1803
|
+
);
|
|
1804
|
+
EXECUTE format(
|
|
1805
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_guard_lifecycle_operation() '
|
|
1806
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1807
|
+
);
|
|
1808
|
+
EXECUTE format(
|
|
1809
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_guard_head_delete() '
|
|
1810
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1811
|
+
);
|
|
1812
|
+
EXECUTE format(
|
|
1813
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_validate_head() '
|
|
1814
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1815
|
+
);
|
|
1816
|
+
EXECUTE format(
|
|
1817
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_validate_onboarding_proposal() '
|
|
1818
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1819
|
+
);
|
|
1820
|
+
EXECUTE format(
|
|
1821
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_validate_event() '
|
|
1822
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1823
|
+
);
|
|
1824
|
+
EXECUTE format(
|
|
1825
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_validate_deactivation_event() '
|
|
1826
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1827
|
+
);
|
|
1828
|
+
EXECUTE format(
|
|
1829
|
+
'ALTER FUNCTION %I.governed_learning_apply_instruction_policy('
|
|
1830
|
+
|| 'text,uuid,uuid,uuid,uuid,uuid,bigint,uuid,text) '
|
|
1831
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1832
|
+
);
|
|
1833
|
+
EXECUTE format(
|
|
1834
|
+
'ALTER FUNCTION %I.governed_learning_deactivate_instruction_policy('
|
|
1835
|
+
|| 'uuid,uuid,uuid,uuid,uuid,bigint,text) '
|
|
1836
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1837
|
+
);
|
|
1838
|
+
EXECUTE format(
|
|
1839
|
+
'ALTER FUNCTION %I.workspace_instruction_policy_canonical_snapshot_entries('
|
|
1840
|
+
|| 'uuid,uuid,text,timestamp with time zone) '
|
|
1841
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1842
|
+
);
|
|
1843
|
+
EXECUTE format(
|
|
1844
|
+
'ALTER FUNCTION %I.governed_learning_apply_preference('
|
|
1845
|
+
|| 'text,uuid,uuid,uuid,uuid,uuid,uuid,uuid,integer,text) '
|
|
1846
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1847
|
+
);
|
|
1848
|
+
EXECUTE format(
|
|
1849
|
+
'ALTER FUNCTION %I.activate_governed_learning_decision(uuid,uuid,uuid,uuid) '
|
|
1850
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1851
|
+
);
|
|
1852
|
+
EXECUTE format(
|
|
1853
|
+
'ALTER FUNCTION %I.undo_governed_learning_activation(uuid,uuid,uuid,uuid) '
|
|
1854
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
|
|
1855
|
+
);
|
|
1856
|
+
EXECUTE format('REVOKE ALL ON TABLE %I.governed_learning_activation_receipts FROM PUBLIC', target_schema);
|
|
1857
|
+
EXECUTE format('REVOKE ALL ON TABLE %I.governed_learning_activation_undo_receipts FROM PUBLIC', target_schema);
|
|
1858
|
+
EXECUTE format('REVOKE ALL ON TABLE %I.workspace_instruction_policy_deactivation_events FROM PUBLIC', target_schema);
|
|
1859
|
+
IF runtime_role IS NOT NULL THEN
|
|
1860
|
+
EXECUTE format('REVOKE ALL ON TABLE %I.governed_learning_activation_receipts FROM %I', target_schema, runtime_role);
|
|
1861
|
+
EXECUTE format('REVOKE ALL ON TABLE %I.governed_learning_activation_undo_receipts FROM %I', target_schema, runtime_role);
|
|
1862
|
+
EXECUTE format('REVOKE ALL ON TABLE %I.workspace_instruction_policy_deactivation_events FROM %I', target_schema, runtime_role);
|
|
1863
|
+
EXECUTE format('GRANT SELECT ON TABLE %I.workspace_instruction_policy_deactivation_events TO %I', target_schema, runtime_role);
|
|
1864
|
+
EXECUTE format(
|
|
1865
|
+
'GRANT EXECUTE ON FUNCTION %I.activate_governed_learning_decision(uuid,uuid,uuid,uuid) TO %I',
|
|
1866
|
+
target_schema, runtime_role
|
|
1867
|
+
);
|
|
1868
|
+
EXECUTE format(
|
|
1869
|
+
'GRANT EXECUTE ON FUNCTION %I.undo_governed_learning_activation(uuid,uuid,uuid,uuid) TO %I',
|
|
1870
|
+
target_schema, runtime_role
|
|
1871
|
+
);
|
|
1872
|
+
END IF;
|
|
1873
|
+
END
|
|
1874
|
+
$governed_learning_activation_hardening$;
|