@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.
Files changed (265) hide show
  1. package/dist/attached-browser-devices.d.ts +7 -0
  2. package/dist/automations.d.ts +154 -0
  3. package/dist/canonical-human-identities.js +3 -3
  4. package/dist/capability-integrations.d.ts +13 -0
  5. package/dist/child-lifecycle-notices.d.ts +68 -0
  6. package/dist/{chunk-LTG3S6ZY.js → chunk-EULAN2NP.js} +2 -2
  7. package/dist/{chunk-CUPM3FGB.js → chunk-NJVZPWXY.js} +3 -3
  8. package/dist/{chunk-4SR4HKKA.js → chunk-NMUBV7Z5.js} +19 -11
  9. package/dist/chunk-NMUBV7Z5.js.map +1 -0
  10. package/dist/chunk-OF5OBB76.js +4457 -0
  11. package/dist/chunk-OF5OBB76.js.map +1 -0
  12. package/dist/{chunk-6ZYKCRFO.js → chunk-PR2WMLOQ.js} +7580 -4417
  13. package/dist/chunk-PR2WMLOQ.js.map +1 -0
  14. package/dist/{chunk-ZWREYEWA.js → chunk-SCPUJS53.js} +41 -4
  15. package/dist/chunk-SCPUJS53.js.map +1 -0
  16. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  17. package/dist/chunk-SIBYBA2D.js.map +1 -0
  18. package/dist/chunk-TIKF3KTI.js +383 -0
  19. package/dist/chunk-TIKF3KTI.js.map +1 -0
  20. package/dist/chunk-ZZ5LJEFX.js +516 -0
  21. package/dist/chunk-ZZ5LJEFX.js.map +1 -0
  22. package/dist/codemode-operations.d.ts +1 -6
  23. package/dist/company-brain-context-selection-schema.d.ts +705 -0
  24. package/dist/company-brain-context-selection.d.ts +94 -0
  25. package/dist/company-brain-governed-writes.d.ts +24 -0
  26. package/dist/company-brain.d.ts +55 -0
  27. package/dist/company-profile-agent-admin.d.ts +15 -0
  28. package/dist/company-profile-schema.d.ts +619 -2
  29. package/dist/company-profile.d.ts +9 -4
  30. package/dist/connection-authority.d.ts +95 -0
  31. package/dist/connection-scopes.d.ts +8 -0
  32. package/dist/connection-tenancy-backfill.d.ts +41 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +19 -0
  35. package/dist/editable-artifact-durable-export.js +2 -2
  36. package/dist/editable-artifacts.d.ts +2 -2
  37. package/dist/editable-artifacts.js +3 -3
  38. package/dist/governed-learning-activation-schema.d.ts +984 -0
  39. package/dist/governed-learning-activation.d.ts +98 -0
  40. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  41. package/dist/governed-learning-evaluator.d.ts +28 -0
  42. package/dist/index.d.ts +1595 -81
  43. package/dist/index.js +21571 -8126
  44. package/dist/index.js.map +1 -1
  45. package/dist/insights.d.ts +18 -0
  46. package/dist/integration-bindings.d.ts +1 -0
  47. package/dist/integration-facets.d.ts +30 -0
  48. package/dist/interaction-placement-loss.d.ts +22 -0
  49. package/dist/managed-human-provisioning.d.ts +25 -0
  50. package/dist/memory-domain.d.ts +3 -3
  51. package/dist/migrate.d.ts +11 -1
  52. package/dist/migrate.js +1 -1
  53. package/dist/new-session-drafts.d.ts +43 -5
  54. package/dist/organization-membership-backfill.d.ts +174 -0
  55. package/dist/organization-membership-lifecycle.d.ts +162 -0
  56. package/dist/pr-review.d.ts +107 -0
  57. package/dist/preference-registry-schema.d.ts +2 -0
  58. package/dist/preference-registry.d.ts +2 -0
  59. package/dist/provision-roles.js +1 -1
  60. package/dist/runtime-posture.d.ts +22 -8
  61. package/dist/schema.d.ts +24914 -13703
  62. package/dist/schema.js +99 -1
  63. package/dist/scoped-knowledge-schema.d.ts +52 -1
  64. package/dist/session-background-commands.d.ts +125 -0
  65. package/dist/session-background-commands.js +34 -0
  66. package/dist/session-background-commands.js.map +1 -0
  67. package/dist/session-control.d.ts +156 -3
  68. package/dist/session-goal-pacing.d.ts +68 -0
  69. package/dist/session-queue-commands.d.ts +41 -4
  70. package/dist/session-realtime-ledger.d.ts +2 -0
  71. package/dist/session-tenancy.d.ts +71 -1
  72. package/dist/session-tenancy.js +25 -3
  73. package/dist/session-tool-call-settlement.d.ts +9 -4
  74. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  75. package/dist/slack-routing.d.ts +153 -0
  76. package/dist/slack-task-policy-schema.d.ts +34 -0
  77. package/dist/slack-task-policy.d.ts +8 -0
  78. package/dist/slack-user-link-access.d.ts +1 -0
  79. package/dist/task-notes-schema.d.ts +594 -0
  80. package/dist/task-notes.d.ts +39 -0
  81. package/dist/turn-initiator.d.ts +2 -0
  82. package/dist/user-resource-authority.d.ts +109 -0
  83. package/dist/video-generation.js +3 -3
  84. package/dist/workspace-authority.d.ts +81 -0
  85. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  86. package/dist/workspace-instruction-policies.d.ts +62 -0
  87. package/dist/workspace-learning-policy.d.ts +1 -0
  88. package/dist/workspace-membership-permissions.d.ts +2 -0
  89. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  90. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  91. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  92. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  93. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  94. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  95. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  96. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  97. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  98. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  99. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  100. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  101. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  102. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  103. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  104. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  105. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  106. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  107. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  108. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  109. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  110. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  111. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  112. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  113. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  114. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  115. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  116. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  117. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  118. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  119. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  120. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  121. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  122. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  123. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  124. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  125. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  126. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  127. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  128. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  129. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  130. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  131. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  132. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  133. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  134. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  135. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  136. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  137. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  138. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  139. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  140. package/drizzle/0294_preference_activation_authority.sql +237 -0
  141. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  142. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  143. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  144. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  145. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  146. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  147. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  148. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  149. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  150. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  151. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  152. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  153. package/drizzle/0307_session_attention_state.sql +51 -0
  154. package/drizzle/0308_session_archives.sql +35 -0
  155. package/drizzle/0309_channel_project_pins.sql +6 -0
  156. package/drizzle/0310_channel_project_order.sql +27 -0
  157. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  158. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  159. package/drizzle/0313_private_child_session_authority.sql +365 -0
  160. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  161. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  162. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  163. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  164. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  165. package/drizzle/0319_event_triggered_automations.sql +254 -0
  166. package/drizzle/0320_pr_review_pack.sql +113 -0
  167. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  168. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  169. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  170. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  171. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  172. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  173. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  174. package/drizzle/0328_session_background_commands.sql +590 -0
  175. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  176. package/drizzle/0330_api_key_descriptions.sql +20 -0
  177. package/drizzle/0331_managed_organization_creation.sql +163 -0
  178. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  179. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  180. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  181. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  182. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  183. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  184. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  185. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  186. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  187. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
  188. package/package.json +10 -6
  189. package/src/attached-browser-devices.ts +233 -5
  190. package/src/automations.ts +911 -0
  191. package/src/browser-sessions.ts +10 -0
  192. package/src/capability-integrations.ts +175 -1
  193. package/src/child-lifecycle-notices.ts +241 -0
  194. package/src/codemode-operations.ts +1 -35
  195. package/src/company-brain-context-selection-schema.ts +100 -0
  196. package/src/company-brain-context-selection.ts +359 -0
  197. package/src/company-brain-governed-writes.ts +1170 -0
  198. package/src/company-brain.ts +309 -0
  199. package/src/company-profile-agent-admin.ts +225 -0
  200. package/src/company-profile-schema.ts +121 -1
  201. package/src/company-profile.ts +21 -0
  202. package/src/computer-sessions.ts +10 -1
  203. package/src/connection-authority.ts +290 -0
  204. package/src/connection-scopes.ts +20 -0
  205. package/src/connection-tenancy-backfill.ts +81 -0
  206. package/src/connection-token-resolver.ts +263 -31
  207. package/src/database.ts +75 -2
  208. package/src/editable-artifacts-schema.ts +10 -5
  209. package/src/editable-artifacts.ts +21 -11
  210. package/src/governed-learning-activation-schema.ts +121 -0
  211. package/src/governed-learning-activation.ts +588 -0
  212. package/src/governed-learning-evaluator-schema.ts +72 -0
  213. package/src/governed-learning-evaluator.ts +217 -0
  214. package/src/index.ts +11651 -1548
  215. package/src/insights.ts +107 -0
  216. package/src/integration-bindings.ts +88 -6
  217. package/src/integration-facets.ts +287 -84
  218. package/src/interaction-placement-loss.ts +234 -0
  219. package/src/managed-human-provisioning.ts +116 -0
  220. package/src/memory-domain.ts +27 -32
  221. package/src/migrate.ts +77 -1
  222. package/src/new-session-drafts.ts +229 -35
  223. package/src/organization-membership-backfill.ts +735 -0
  224. package/src/organization-membership-lifecycle.ts +985 -0
  225. package/src/pr-review.ts +890 -0
  226. package/src/preference-registry.ts +31 -1
  227. package/src/provision-roles.ts +877 -6
  228. package/src/runtime-posture-cli.ts +2 -0
  229. package/src/runtime-posture.ts +1291 -76
  230. package/src/schema.ts +3303 -428
  231. package/src/scoped-knowledge-schema.ts +16 -8
  232. package/src/scoped-knowledge.ts +1 -1
  233. package/src/session-background-commands.ts +759 -0
  234. package/src/session-control.ts +640 -74
  235. package/src/session-goal-pacing.ts +126 -0
  236. package/src/session-queue-commands.ts +437 -84
  237. package/src/session-realtime-context.ts +3 -3
  238. package/src/session-realtime-ledger.ts +22 -11
  239. package/src/session-realtime-mirror.ts +1 -1
  240. package/src/session-tenancy.ts +403 -49
  241. package/src/session-tool-call-settlement.ts +38 -29
  242. package/src/slack-routing-personal-workspace.ts +67 -0
  243. package/src/slack-routing.ts +469 -0
  244. package/src/slack-task-policy-schema.ts +5 -0
  245. package/src/slack-task-policy.ts +18 -0
  246. package/src/slack-user-link-access.ts +17 -1
  247. package/src/task-notes-schema.ts +74 -0
  248. package/src/task-notes.ts +124 -2
  249. package/src/turn-initiator.ts +8 -0
  250. package/src/user-resource-authority.ts +377 -0
  251. package/src/workspace-authority.ts +160 -0
  252. package/src/workspace-instruction-policies-schema.ts +53 -1
  253. package/src/workspace-instruction-policies.ts +528 -77
  254. package/src/workspace-learning-policy.ts +21 -5
  255. package/src/workspace-membership-permissions.ts +9 -0
  256. package/dist/chunk-4SR4HKKA.js.map +0 -1
  257. package/dist/chunk-6ZYKCRFO.js.map +0 -1
  258. package/dist/chunk-NXAFLCQX.js +0 -2468
  259. package/dist/chunk-NXAFLCQX.js.map +0 -1
  260. package/dist/chunk-SK7YYHBI.js.map +0 -1
  261. package/dist/chunk-WD5ROSLL.js +0 -117
  262. package/dist/chunk-WD5ROSLL.js.map +0 -1
  263. package/dist/chunk-ZWREYEWA.js.map +0 -1
  264. /package/dist/{chunk-LTG3S6ZY.js.map → chunk-EULAN2NP.js.map} +0 -0
  265. /package/dist/{chunk-CUPM3FGB.js.map → chunk-NJVZPWXY.js.map} +0 -0
@@ -0,0 +1,869 @@
1
+ -- deployment-mode: rolling
2
+ SET lock_timeout = '5s';
3
+ SET statement_timeout = '10min';
4
+
5
+ -- Human-confirmed activation across the human-input resume generation.
6
+ --
7
+ -- `remember` on the instruction-policy and preference lanes returns
8
+ -- `confirmation_required`; the agent then asks the bound question through
9
+ -- `request_human_input`, which freezes the turn as `requires_action`. Resuming
10
+ -- that turn always increments the logical turn's execution generation and
11
+ -- claims a new attempt (`claimSessionWorkForAttempt`). The human-input row is
12
+ -- bound to the generation in which the question was asked, so by the time
13
+ -- `remember_confirm` runs, the live attempt of the same logical turn is one
14
+ -- generation later. Migrations 0272/0284/0293 required the live turn and its
15
+ -- active attempt to sit at exactly the decision receipt's (minting) generation,
16
+ -- which can never hold after a real human answer: every mandatory rule
17
+ -- confirmation failed with 42501 ("governed-learning activation attempt is
18
+ -- unavailable").
19
+ --
20
+ -- The real invariant: the human answer is bound to the same logical turn and
21
+ -- to exactly this proposal (same session and turn id, the reconstructed
22
+ -- `remember:<proposalId>` question, the `save` answer, the initiating human as
23
+ -- responder, one activation per decision receipt), not to one execution
24
+ -- generation. Generations only move forward on that turn: the human-input row
25
+ -- is created at the generation in which the question was asked, which is the
26
+ -- minting generation or later (a worker death between `remember` and the pause
27
+ -- re-claims at the next generation, and a different interruption answered
28
+ -- first re-freezes a still-pending row under the next generation); the live
29
+ -- attempt must be the active attempt of the same logical turn at the minting
30
+ -- generation or later, still claimed/running with no pending interruption.
31
+ -- Nothing widens to another turn or an earlier generation.
32
+ --
33
+ -- `confirm_remember_knowledge_claim` (0274/0284) had the same defect in a
34
+ -- different shape: its caller passes the live attempt's generation, which the
35
+ -- turn/attempt check requires exactly, and the same value was also required to
36
+ -- equal the human-input row's `turn_generation`. The live-generation checks
37
+ -- stay exact; the human-input row now binds to the asked generation, which is
38
+ -- the live generation or earlier on the same logical turn.
39
+
40
+ -- Body is byte-identical to migration 0293 except the three generation
41
+ -- comparisons (`>=` instead of `=`) and their explanatory comments.
42
+ CREATE OR REPLACE FUNCTION activate_human_confirmed_learning_decision(
43
+ p_account_id uuid,
44
+ p_workspace_id uuid,
45
+ p_operation_id uuid,
46
+ p_decision_receipt_id uuid,
47
+ p_human_input_request_id uuid
48
+ ) RETURNS SETOF governed_learning_activation_receipts
49
+ LANGUAGE plpgsql SECURITY DEFINER AS $$
50
+ DECLARE
51
+ caller_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
52
+ decision_row governed_learning_decision_receipts%ROWTYPE;
53
+ result_row governed_learning_activation_receipts%ROWTYPE;
54
+ proposal_row knowledge_change_proposals%ROWTYPE;
55
+ claim_row knowledge_claims%ROWTYPE;
56
+ evidence_row knowledge_claim_evidence%ROWTYPE;
57
+ review_row knowledge_claim_reviews%ROWTYPE;
58
+ approval_row knowledge_claim_reviews%ROWTYPE;
59
+ policy_head workspace_learning_policy_heads%ROWTYPE;
60
+ policy_revision workspace_learning_policy_revisions%ROWTYPE;
61
+ policy_snapshot workspace_learning_policy_snapshots%ROWTYPE;
62
+ task_note_row task_notes%ROWTYPE;
63
+ document_authority record;
64
+ instruction_proposal workspace_instruction_policy_onboarding_proposals%ROWTYPE;
65
+ instruction_event workspace_instruction_policy_activation_events%ROWTYPE;
66
+ preference_receipt company_brain_preference_proposal_receipts%ROWTYPE;
67
+ preference_row preference_registry_preferences%ROWTYPE;
68
+ preference_revision preference_registry_revisions%ROWTYPE;
69
+ preference_event preference_registry_events%ROWTYPE;
70
+ current_instruction_head workspace_instruction_policy_heads%ROWTYPE;
71
+ current_instruction_activation_version bigint;
72
+ input_hash_value text;
73
+ service_actor text;
74
+ current_authority_hash text;
75
+ current_mode text;
76
+ conflict_count integer;
77
+ destination_value text;
78
+ destination_proposal_id_value uuid;
79
+ destination_revision_id_value uuid;
80
+ destination_old_revision_id_value uuid;
81
+ destination_old_content_hash_value text;
82
+ destination_old_version_value bigint;
83
+ destination_new_content_hash_value text;
84
+ destination_new_version_value bigint;
85
+ destination_event_id_value uuid;
86
+ effective_at_value timestamptz;
87
+ review_operation_id uuid;
88
+ destination_operation_id uuid;
89
+ human_input_row session_human_input_requests%ROWTYPE;
90
+ human_question_id text;
91
+ human_question_lane text;
92
+ human_question_prompt text;
93
+ human_question_help text;
94
+ human_question_options jsonb := jsonb_build_array(
95
+ jsonb_build_object('id', 'save', 'label', 'Save'),
96
+ jsonb_build_object('id', 'skip', 'label', 'Don''t save')
97
+ );
98
+ BEGIN
99
+ IF p_account_id IS NULL OR p_workspace_id IS NULL OR p_operation_id IS NULL
100
+ OR p_decision_receipt_id IS NULL OR p_human_input_request_id IS NULL
101
+ OR caller_subject_id IS NULL
102
+ OR length(btrim(caller_subject_id)) NOT BETWEEN 1 AND 1024
103
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
104
+ OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
105
+ THEN
106
+ RAISE EXCEPTION 'governed-learning activation requires exact tenant authority'
107
+ USING ERRCODE = '42501';
108
+ END IF;
109
+ input_hash_value := encode(sha256(convert_to(jsonb_build_array(
110
+ 'governed-learning-human-confirmed-activation', 1, p_account_id, p_workspace_id,
111
+ p_operation_id, p_decision_receipt_id, p_human_input_request_id
112
+ )::text, 'UTF8')), 'hex');
113
+ SELECT * INTO result_row FROM governed_learning_activation_receipts receipt
114
+ WHERE receipt.workspace_id = p_workspace_id AND receipt.operation_id = p_operation_id
115
+ FOR SHARE;
116
+ IF FOUND THEN
117
+ IF result_row.account_id <> p_account_id OR result_row.input_hash <> input_hash_value
118
+ OR result_row.decision_receipt_id <> p_decision_receipt_id
119
+ OR result_row.initiating_human_subject_id <> caller_subject_id
120
+ OR result_row.authority_kind <> 'human_confirmed'
121
+ OR result_row.human_input_request_id IS DISTINCT FROM p_human_input_request_id
122
+ THEN
123
+ RAISE EXCEPTION 'governed-learning activation operation conflicts with immutable receipt'
124
+ USING ERRCODE = '23505';
125
+ END IF;
126
+ RETURN NEXT result_row;
127
+ RETURN;
128
+ END IF;
129
+
130
+ -- Canonical shared prefix. The workspace UPDATE lock also gives all three
131
+ -- destination adapters one order, avoiding claim/head inversion.
132
+ PERFORM 1 FROM workspaces workspace
133
+ WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
134
+ FOR UPDATE;
135
+ IF NOT FOUND THEN
136
+ RAISE EXCEPTION 'governed-learning workspace is unavailable' USING ERRCODE = '42501';
137
+ END IF;
138
+ SELECT * INTO result_row FROM governed_learning_activation_receipts receipt
139
+ WHERE receipt.workspace_id = p_workspace_id AND receipt.operation_id = p_operation_id
140
+ FOR SHARE;
141
+ IF FOUND THEN
142
+ IF result_row.account_id <> p_account_id OR result_row.input_hash <> input_hash_value
143
+ OR result_row.decision_receipt_id <> p_decision_receipt_id
144
+ OR result_row.initiating_human_subject_id <> caller_subject_id
145
+ OR result_row.authority_kind <> 'human_confirmed'
146
+ OR result_row.human_input_request_id IS DISTINCT FROM p_human_input_request_id
147
+ THEN
148
+ RAISE EXCEPTION 'governed-learning activation operation conflicts with immutable receipt'
149
+ USING ERRCODE = '23505';
150
+ END IF;
151
+ RETURN NEXT result_row;
152
+ RETURN;
153
+ END IF;
154
+ SELECT * INTO decision_row FROM governed_learning_decision_receipts receipt
155
+ WHERE receipt.id = p_decision_receipt_id AND receipt.account_id = p_account_id
156
+ AND receipt.workspace_id = p_workspace_id
157
+ AND receipt.initiating_human_subject_id = caller_subject_id
158
+ AND receipt.outcome IN ('suggest', 'automatic', 'confidence')
159
+ FOR UPDATE;
160
+ IF NOT FOUND OR NOT session_reference_visible(
161
+ decision_row.account_id, decision_row.workspace_id, decision_row.session_id
162
+ ) THEN
163
+ RAISE EXCEPTION 'confirmable evaluator receipt is unavailable'
164
+ USING ERRCODE = '42501';
165
+ END IF;
166
+ IF EXISTS (
167
+ SELECT 1 FROM governed_learning_activation_receipts receipt
168
+ WHERE receipt.decision_receipt_id = p_decision_receipt_id
169
+ ) THEN
170
+ RAISE EXCEPTION 'automatic evaluator receipt was consumed by another operation'
171
+ USING ERRCODE = '23505';
172
+ END IF;
173
+ PERFORM 1 FROM sessions session
174
+ WHERE session.account_id = p_account_id AND session.workspace_id = p_workspace_id
175
+ AND session.id = decision_row.session_id AND session.active_turn_id = decision_row.turn_id
176
+ AND session_reference_visible(session.account_id, session.workspace_id, session.id)
177
+ FOR SHARE;
178
+ IF NOT FOUND THEN
179
+ RAISE EXCEPTION 'governed-learning activation session is unavailable' USING ERRCODE = '42501';
180
+ END IF;
181
+ -- The decision receipt was minted before the human-input pause. Resuming a
182
+ -- requires_action turn always increments the logical turn's execution
183
+ -- generation and claims a new attempt, so the live attempt of the same
184
+ -- logical turn is a later generation. Require that live attempt on the same
185
+ -- logical turn (session active turn, turn id) at the minting generation or
186
+ -- later; never an earlier generation and never another turn.
187
+ PERFORM 1 FROM session_turns turn
188
+ WHERE turn.account_id = p_account_id AND turn.workspace_id = p_workspace_id
189
+ AND turn.session_id = decision_row.session_id AND turn.id = decision_row.turn_id
190
+ AND turn.execution_generation >= decision_row.execution_generation
191
+ AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
192
+ AND coalesce(turn.initiating_human_subject_id,
193
+ CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
194
+ ) = caller_subject_id
195
+ FOR SHARE;
196
+ IF NOT FOUND THEN
197
+ RAISE EXCEPTION 'governed-learning activation turn is unavailable' USING ERRCODE = '42501';
198
+ END IF;
199
+ PERFORM 1 FROM session_turns turn
200
+ JOIN session_turn_attempts attempt
201
+ ON attempt.account_id = turn.account_id AND attempt.workspace_id = turn.workspace_id
202
+ AND attempt.session_id = turn.session_id AND attempt.turn_id = turn.id
203
+ AND attempt.id = turn.active_attempt_id
204
+ WHERE turn.account_id = p_account_id AND turn.workspace_id = p_workspace_id
205
+ AND turn.session_id = decision_row.session_id AND turn.id = decision_row.turn_id
206
+ AND attempt.execution_generation >= decision_row.execution_generation
207
+ AND attempt.state IN ('claimed', 'running')
208
+ AND NOT EXISTS (
209
+ SELECT 1 FROM session_attempt_interruptions interruption
210
+ WHERE interruption.workspace_id = p_workspace_id
211
+ AND interruption.attempt_id = attempt.id
212
+ AND interruption.state IN ('pending', 'delivered', 'acknowledged')
213
+ )
214
+ FOR SHARE OF attempt;
215
+ IF NOT FOUND THEN
216
+ RAISE EXCEPTION 'governed-learning activation attempt is unavailable' USING ERRCODE = '42501';
217
+ END IF;
218
+
219
+ SELECT * INTO policy_snapshot FROM workspace_learning_policy_snapshots snapshot
220
+ WHERE snapshot.id = decision_row.policy_snapshot_id
221
+ AND snapshot.account_id = p_account_id AND snapshot.workspace_id = p_workspace_id
222
+ AND snapshot.session_id = decision_row.session_id
223
+ AND snapshot.turn_id = decision_row.turn_id
224
+ AND snapshot.attempt_id = decision_row.attempt_id
225
+ AND snapshot.execution_generation = decision_row.execution_generation
226
+ AND snapshot.snapshot_hash = decision_row.policy_snapshot_hash
227
+ FOR SHARE;
228
+ SELECT * INTO policy_head FROM workspace_learning_policy_heads head
229
+ WHERE head.account_id = p_account_id AND head.workspace_id = p_workspace_id
230
+ FOR SHARE;
231
+ SELECT * INTO policy_revision FROM workspace_learning_policy_revisions revision
232
+ WHERE revision.account_id = p_account_id AND revision.workspace_id = p_workspace_id
233
+ AND revision.id = policy_head.revision_id
234
+ FOR SHARE;
235
+ IF policy_snapshot.id IS NULL
236
+ OR policy_head.revision_id IS DISTINCT FROM decision_row.policy_revision_id
237
+ OR policy_head.policy_hash IS DISTINCT FROM policy_snapshot.policy_hash
238
+ OR policy_head.activation_version IS DISTINCT FROM decision_row.policy_activation_version
239
+ OR policy_revision.policy_hash IS DISTINCT FROM policy_snapshot.policy_hash
240
+ THEN
241
+ RAISE EXCEPTION 'governed-learning policy authority changed after evaluation'
242
+ USING ERRCODE = '40001';
243
+ END IF;
244
+ current_mode := coalesce((
245
+ SELECT override.value->>'mode'
246
+ FROM jsonb_array_elements(policy_revision.source_overrides) override(value)
247
+ WHERE override.value->>'kind' = decision_row.source_kind
248
+ AND override.value->>'id' = decision_row.source_id::text LIMIT 1
249
+ ), policy_revision.workspace_mode);
250
+ IF current_mode = 'off' THEN
251
+ RAISE EXCEPTION 'governed-learning source is off' USING ERRCODE = '42501';
252
+ END IF;
253
+
254
+ SELECT * INTO proposal_row FROM knowledge_change_proposals proposal
255
+ WHERE proposal.id = decision_row.proposal_id AND proposal.account_id = p_account_id
256
+ AND proposal.scope_kind = 'workspace' AND proposal.scope_workspace_id = p_workspace_id
257
+ AND proposal.scope_subject_id IS NULL AND proposal.status = 'proposed'
258
+ AND proposal.input_hash = decision_row.proposal_input_hash
259
+ AND proposal.content_hash = decision_row.proposal_content_hash
260
+ AND proposal.claim_id = decision_row.claim_id
261
+ AND proposal.evidence_id = decision_row.evidence_id
262
+ AND proposal.initiating_human_subject_id = caller_subject_id
263
+ FOR SHARE;
264
+ SELECT * INTO claim_row FROM knowledge_claims claim
265
+ WHERE claim.id = decision_row.claim_id AND claim.account_id = p_account_id
266
+ AND claim.scope_kind = 'workspace' AND claim.scope_workspace_id = p_workspace_id
267
+ AND claim.scope_subject_id IS NULL AND claim.input_hash = decision_row.claim_input_hash
268
+ AND claim.initiating_human_subject_id = caller_subject_id
269
+ AND claim.confidence_bps >= decision_row.confidence_floor_bps
270
+ AND claim.effective_at <= transaction_timestamp()
271
+ AND (claim.expires_at IS NULL OR claim.expires_at > transaction_timestamp())
272
+ FOR UPDATE;
273
+ SELECT * INTO evidence_row FROM knowledge_claim_evidence evidence
274
+ WHERE evidence.id = decision_row.evidence_id AND evidence.account_id = p_account_id
275
+ AND evidence.scope_kind = 'workspace' AND evidence.scope_workspace_id = p_workspace_id
276
+ AND evidence.scope_subject_id IS NULL AND evidence.claim_id = decision_row.claim_id
277
+ AND evidence.polarity = 'supports' AND evidence.input_hash = decision_row.evidence_input_hash
278
+ AND evidence.content_hash = decision_row.evidence_content_hash
279
+ AND evidence.initiating_human_subject_id = caller_subject_id
280
+ FOR SHARE;
281
+ IF proposal_row.id IS NULL OR claim_row.id IS NULL OR evidence_row.id IS NULL THEN
282
+ RAISE EXCEPTION 'governed-learning proposal lineage changed after evaluation'
283
+ USING ERRCODE = '42501';
284
+ END IF;
285
+ SELECT * INTO review_row FROM knowledge_claim_reviews review
286
+ WHERE review.account_id = p_account_id AND review.claim_id = decision_row.claim_id
287
+ ORDER BY review.review_revision DESC LIMIT 1 FOR SHARE;
288
+ IF review_row.id IS NULL OR review_row.state <> 'proposed'
289
+ OR review_row.review_revision <> decision_row.review_revision
290
+ THEN
291
+ RAISE EXCEPTION 'governed-learning review was superseded after evaluation'
292
+ USING ERRCODE = '40001';
293
+ END IF;
294
+ SELECT least(1000, count(*))::integer INTO conflict_count FROM (
295
+ SELECT relation.id FROM knowledge_claim_relations relation
296
+ WHERE relation.account_id = p_account_id AND relation.scope_kind = 'workspace'
297
+ AND relation.scope_workspace_id = p_workspace_id AND relation.scope_subject_id IS NULL
298
+ AND relation.relation_type = 'conflicts_with'
299
+ AND (relation.from_claim_id = decision_row.claim_id
300
+ OR relation.to_claim_id = decision_row.claim_id)
301
+ UNION ALL
302
+ SELECT contradiction.id FROM knowledge_claim_evidence contradiction
303
+ WHERE contradiction.account_id = p_account_id AND contradiction.scope_kind = 'workspace'
304
+ AND contradiction.scope_workspace_id = p_workspace_id
305
+ AND contradiction.scope_subject_id IS NULL
306
+ AND contradiction.claim_id = decision_row.claim_id
307
+ AND contradiction.polarity = 'contradicts'
308
+ ) conflicts;
309
+ IF conflict_count <> 0 THEN
310
+ RAISE EXCEPTION 'governed-learning evidence now conflicts' USING ERRCODE = '23514';
311
+ END IF;
312
+
313
+ IF evidence_row.task_note_id IS NOT NULL THEN
314
+ SELECT * INTO task_note_row FROM task_notes note
315
+ WHERE note.id = evidence_row.task_note_id AND note.account_id = p_account_id
316
+ AND note.workspace_id = p_workspace_id
317
+ AND note.root_session_id = evidence_row.task_note_root_session_id
318
+ AND note.version = evidence_row.task_note_version
319
+ AND note.text_hash = evidence_row.content_hash
320
+ AND note.status = 'active' AND note.expires_at > transaction_timestamp()
321
+ AND session_reference_visible(note.account_id, note.workspace_id, note.root_session_id)
322
+ FOR SHARE;
323
+ IF NOT FOUND THEN
324
+ RAISE EXCEPTION 'governed-learning Task-note authority was revoked' USING ERRCODE = '42501';
325
+ END IF;
326
+ current_authority_hash := encode(sha256(convert_to(jsonb_build_array(
327
+ 'task-note-authority', 1, evidence_row.task_note_id,
328
+ evidence_row.task_note_root_session_id, evidence_row.task_note_version,
329
+ evidence_row.content_hash, task_note_row.status, task_note_row.expires_at
330
+ )::text, 'UTF8')), 'hex');
331
+ ELSE
332
+ SELECT provider.id AS provider_id, provider.lifecycle_state AS provider_state,
333
+ provider.lifecycle_generation AS provider_generation, source.id AS source_id,
334
+ source.lifecycle_state AS source_state, source.lifecycle_generation AS source_generation,
335
+ source.current_acl_generation, object.id AS object_id,
336
+ object.lifecycle_state AS object_state, object.lifecycle_generation AS object_generation,
337
+ object.version_generation AS object_version_generation, object.current_version_id,
338
+ version.id AS version_id, version.version_generation, version.content_sha256,
339
+ version.acl_version_id, version.acl_generation, version.document_id,
340
+ evidence_acl.acl_hash AS evidence_acl_hash,
341
+ evidence_acl.agent_access AS evidence_agent_access,
342
+ current_acl.id AS current_acl_id, current_acl.acl_hash AS current_acl_hash,
343
+ current_acl.agent_access AS current_agent_access
344
+ INTO document_authority
345
+ FROM knowledge_document_versions version
346
+ JOIN knowledge_source_objects object ON object.account_id = version.account_id
347
+ AND object.id = version.object_id AND object.scope_key = version.scope_key
348
+ JOIN knowledge_sources source ON source.account_id = version.account_id
349
+ AND source.id = version.source_id AND source.scope_key = version.scope_key
350
+ JOIN knowledge_providers provider ON provider.account_id = source.account_id
351
+ AND provider.id = source.provider_id AND provider.scope_key = source.scope_key
352
+ JOIN knowledge_source_acl_versions evidence_acl ON evidence_acl.account_id = version.account_id
353
+ AND evidence_acl.id = version.acl_version_id AND evidence_acl.source_id = version.source_id
354
+ AND evidence_acl.generation = version.acl_generation
355
+ LEFT JOIN knowledge_source_acl_versions current_acl ON current_acl.account_id = source.account_id
356
+ AND current_acl.source_id = source.id AND current_acl.generation = source.current_acl_generation
357
+ WHERE version.id = evidence_row.document_version_id AND version.account_id = p_account_id
358
+ AND version.scope_kind = 'workspace' AND version.scope_workspace_id = p_workspace_id
359
+ AND version.scope_subject_id IS NULL
360
+ FOR SHARE OF version, object, source, provider, evidence_acl;
361
+ IF document_authority.version_id IS NULL
362
+ OR document_authority.provider_state IS DISTINCT FROM 'active'
363
+ OR document_authority.source_state IS DISTINCT FROM 'active'
364
+ OR document_authority.object_state IS DISTINCT FROM 'active'
365
+ OR document_authority.current_version_id IS DISTINCT FROM document_authority.version_id
366
+ OR document_authority.object_version_generation IS DISTINCT FROM document_authority.version_generation
367
+ OR document_authority.current_acl_id IS NULL
368
+ OR NOT coalesce(document_authority.evidence_agent_access, false)
369
+ OR NOT coalesce(document_authority.current_agent_access, false)
370
+ OR (document_authority.document_id IS NOT NULL AND NOT EXISTS (
371
+ SELECT 1 FROM documents document WHERE document.id = document_authority.document_id
372
+ AND document.account_id = p_account_id AND document.workspace_id = p_workspace_id
373
+ AND document.status = 'ready' AND document.agent_access
374
+ AND (document.visibility <> 'private' OR document.created_by = caller_subject_id)
375
+ ))
376
+ OR (evidence_row.document_chunk_id IS NOT NULL AND NOT EXISTS (
377
+ SELECT 1 FROM document_chunks chunk WHERE chunk.id = evidence_row.document_chunk_id
378
+ AND chunk.account_id = p_account_id AND chunk.workspace_id = p_workspace_id
379
+ AND chunk.document_id = document_authority.document_id
380
+ ))
381
+ THEN
382
+ RAISE EXCEPTION 'governed-learning document authority was revoked' USING ERRCODE = '42501';
383
+ END IF;
384
+ current_authority_hash := encode(sha256(convert_to(jsonb_build_array(
385
+ 'document-evidence-authority', 1, evidence_row.document_version_id,
386
+ document_authority.provider_id, document_authority.provider_state,
387
+ document_authority.provider_generation, document_authority.source_id,
388
+ document_authority.source_state, document_authority.source_generation,
389
+ document_authority.current_acl_generation, document_authority.object_id,
390
+ document_authority.object_state, document_authority.object_generation,
391
+ document_authority.object_version_generation, document_authority.current_version_id,
392
+ document_authority.version_id, document_authority.version_generation,
393
+ document_authority.content_sha256, document_authority.acl_version_id,
394
+ document_authority.acl_generation, document_authority.evidence_acl_hash,
395
+ document_authority.current_acl_id, document_authority.current_acl_hash,
396
+ evidence_row.document_chunk_id, false
397
+ )::text, 'UTF8')), 'hex');
398
+ END IF;
399
+
400
+ -- The exact human must have answered the bound question for this proposal
401
+ -- on the same session/turn with `save`. The row carries the generation in
402
+ -- which the question was asked: the minting generation, or a later one of
403
+ -- the same turn when a recovery re-claimed before the pause or another
404
+ -- interruption answered first re-froze the pending row.
405
+ -- The question the human saw is reconstructed here from the proposal itself
406
+ -- (canonical prompt, exact proposal content as help text, fixed options), so
407
+ -- an agent cannot obtain confirmation through a misleading prompt.
408
+ human_question_id := 'remember:' || decision_row.proposal_id::text;
409
+ -- Only Task-note evidence (the exact user-directed text) is confirmable; the
410
+ -- proposal content of a preference is a normalized envelope, not the words
411
+ -- the human was shown.
412
+ IF task_note_row.id IS NULL THEN
413
+ RAISE EXCEPTION 'human confirmation requires exact Task-note evidence' USING ERRCODE = '42501';
414
+ END IF;
415
+ human_question_lane := proposal_row.target_kind;
416
+ human_question_help := left(task_note_row.text, 2000);
417
+ human_question_prompt := 'Save this as a ' || CASE human_question_lane
418
+ WHEN 'instruction_policy' THEN 'mandatory workspace rule'
419
+ WHEN 'preference' THEN 'workspace preference'
420
+ ELSE 'workspace knowledge' END
421
+ || ' for everyone in this workspace?';
422
+ SELECT * INTO human_input_row FROM session_human_input_requests request
423
+ WHERE request.id = p_human_input_request_id
424
+ AND request.account_id = p_account_id AND request.workspace_id = p_workspace_id
425
+ AND request.session_id = decision_row.session_id
426
+ AND request.turn_id = decision_row.turn_id
427
+ AND request.turn_generation >= decision_row.execution_generation
428
+ AND request.status = 'answered'
429
+ AND request.responded_by = caller_subject_id
430
+ AND request.response->>'outcome' = 'answered'
431
+ AND EXISTS (
432
+ SELECT 1 FROM jsonb_array_elements(request.questions) question(value)
433
+ WHERE question.value->>'id' = human_question_id
434
+ AND question.value->>'kind' = 'single_select'
435
+ AND question.value->>'prompt' = human_question_prompt
436
+ AND question.value->>'helpText' = human_question_help
437
+ AND question.value->'options' = human_question_options
438
+ AND coalesce((question.value->>'allowOther')::boolean, false) = false
439
+ )
440
+ AND EXISTS (
441
+ SELECT 1 FROM jsonb_array_elements(request.response->'answers') answer(value)
442
+ WHERE answer.value->>'questionId' = human_question_id
443
+ AND answer.value->'values' = to_jsonb(ARRAY['save'])
444
+ )
445
+ FOR SHARE;
446
+ IF NOT FOUND THEN
447
+ RAISE EXCEPTION 'human confirmation for this proposal is unavailable'
448
+ USING ERRCODE = '42501';
449
+ END IF;
450
+ IF current_authority_hash IS DISTINCT FROM decision_row.evidence_authority_hash THEN
451
+ RAISE EXCEPTION 'governed-learning evidence authority changed after evaluation'
452
+ USING ERRCODE = '40001';
453
+ END IF;
454
+
455
+ IF proposal_row.target_kind = 'instruction_policy' THEN
456
+ -- One knowledge proposal may now own more than one inactive
457
+ -- instruction-policy proposal: when the head moves after the human already
458
+ -- confirmed, the confirm path rebaselines by adding a successor against the
459
+ -- current head rather than stranding the human's answer. Exactly one of
460
+ -- them can match the live head, so resolve the head first and select by it
461
+ -- instead of assuming a single row.
462
+ SELECT * INTO instruction_proposal
463
+ FROM workspace_instruction_policy_onboarding_proposals proposal
464
+ WHERE proposal.account_id = p_account_id AND proposal.workspace_id = p_workspace_id
465
+ AND proposal.source_id = proposal_row.id::text
466
+ AND proposal.source_version = proposal_row.content_hash
467
+ AND proposal.status = 'proposed'
468
+ ORDER BY proposal.baseline_activation_version DESC, proposal.created_at DESC, proposal.id DESC
469
+ LIMIT 1
470
+ FOR SHARE;
471
+ IF NOT FOUND OR instruction_proposal.draft_content_hash <> proposal_row.content_hash THEN
472
+ RAISE EXCEPTION 'exact inactive instruction-policy proposal is unavailable'
473
+ USING ERRCODE = '42501';
474
+ END IF;
475
+ SELECT * INTO current_instruction_head FROM workspace_instruction_policy_heads head
476
+ WHERE head.account_id = p_account_id AND head.workspace_id = p_workspace_id
477
+ AND head.kind = instruction_proposal.kind AND head.scope = instruction_proposal.scope
478
+ AND head.role_key IS NOT DISTINCT FROM instruction_proposal.role_key FOR SHARE;
479
+ IF NOT FOUND THEN
480
+ SELECT event.activation_version INTO current_instruction_activation_version
481
+ FROM workspace_instruction_policy_deactivation_events event
482
+ WHERE event.account_id = p_account_id AND event.workspace_id = p_workspace_id
483
+ AND event.kind = instruction_proposal.kind AND event.scope = instruction_proposal.scope
484
+ AND event.role_key IS NOT DISTINCT FROM instruction_proposal.role_key
485
+ ORDER BY event.activation_version DESC, event.id DESC
486
+ LIMIT 1;
487
+ END IF;
488
+ current_instruction_activation_version := coalesce(
489
+ current_instruction_head.activation_version,
490
+ current_instruction_activation_version,
491
+ 0
492
+ );
493
+ -- Prefer the successor bound to the live head. The ordering above already
494
+ -- puts the newest baseline first, so this only re-selects when an older
495
+ -- proposal is the matching one.
496
+ IF current_instruction_head.revision_id IS DISTINCT FROM instruction_proposal.baseline_revision_id
497
+ OR current_instruction_activation_version
498
+ IS DISTINCT FROM instruction_proposal.baseline_activation_version
499
+ THEN
500
+ SELECT * INTO instruction_proposal
501
+ FROM workspace_instruction_policy_onboarding_proposals proposal
502
+ WHERE proposal.account_id = p_account_id AND proposal.workspace_id = p_workspace_id
503
+ AND proposal.source_id = proposal_row.id::text
504
+ AND proposal.source_version = proposal_row.content_hash
505
+ AND proposal.status = 'proposed'
506
+ AND proposal.baseline_revision_id IS NOT DISTINCT FROM current_instruction_head.revision_id
507
+ AND proposal.baseline_activation_version = current_instruction_activation_version
508
+ FOR SHARE;
509
+ IF NOT FOUND OR instruction_proposal.draft_content_hash <> proposal_row.content_hash THEN
510
+ RAISE EXCEPTION 'instruction-policy proposal baseline is stale' USING ERRCODE = '40001';
511
+ END IF;
512
+ END IF;
513
+ destination_value := 'instruction_policy';
514
+ destination_proposal_id_value := instruction_proposal.id;
515
+ destination_revision_id_value := instruction_proposal.draft_revision_id;
516
+ destination_old_revision_id_value := instruction_proposal.baseline_revision_id;
517
+ destination_old_content_hash_value := instruction_proposal.baseline_content_hash;
518
+ destination_old_version_value := instruction_proposal.baseline_activation_version;
519
+ destination_new_content_hash_value := instruction_proposal.draft_content_hash;
520
+ ELSIF proposal_row.target_kind = 'preference' THEN
521
+ SELECT * INTO preference_receipt FROM company_brain_preference_proposal_receipts receipt
522
+ WHERE receipt.account_id = p_account_id AND receipt.workspace_id = p_workspace_id
523
+ AND receipt.knowledge_proposal_id = proposal_row.id FOR SHARE;
524
+ SELECT * INTO preference_row FROM preference_registry_preferences preference
525
+ WHERE preference.account_id = p_account_id AND preference.id = preference_receipt.preference_id
526
+ AND preference.scope = 'workspace' AND preference.scope_workspace_id = p_workspace_id
527
+ AND preference.scope_subject_id IS NULL AND preference.status = 'proposed'
528
+ AND preference.active_revision_id IS NULL AND preference.activation_version = 0
529
+ AND preference.scope_version = 1 FOR SHARE;
530
+ SELECT * INTO preference_revision FROM preference_registry_revisions revision
531
+ WHERE revision.account_id = p_account_id AND revision.id = preference_receipt.revision_id
532
+ AND revision.preference_id = preference_receipt.preference_id
533
+ AND revision.provenance_source = 'knowledge_proposal'
534
+ AND revision.provenance_source_id = proposal_row.id::text
535
+ AND revision.trust = 'untrusted_proposal'
536
+ AND (revision.expires_at IS NULL OR revision.expires_at > transaction_timestamp())
537
+ FOR SHARE;
538
+ IF preference_receipt.id IS NULL OR preference_row.id IS NULL OR preference_revision.id IS NULL
539
+ OR proposal_row.target_scope <> 'workspace'
540
+ OR proposal_row.target_key <> preference_row.stable_key
541
+ THEN
542
+ RAISE EXCEPTION 'exact inactive preference proposal is unavailable'
543
+ USING ERRCODE = '42501';
544
+ END IF;
545
+ destination_value := 'preference';
546
+ destination_proposal_id_value := preference_row.id;
547
+ destination_revision_id_value := preference_revision.id;
548
+ destination_old_revision_id_value := NULL;
549
+ destination_old_content_hash_value := NULL;
550
+ destination_old_version_value := 0;
551
+ destination_new_content_hash_value := preference_revision.content_hash;
552
+ ELSE
553
+ RAISE EXCEPTION 'unsupported governed-learning destination' USING ERRCODE = '23514';
554
+ END IF;
555
+
556
+ service_actor := 'service:governed-learning-activation:' || input_hash_value;
557
+ review_operation_id := opengeni_private.governed_learning_derived_uuid(
558
+ p_operation_id, 'knowledge-approve'
559
+ );
560
+ destination_operation_id := opengeni_private.governed_learning_derived_uuid(
561
+ p_operation_id, 'destination-activate'
562
+ );
563
+ SELECT * INTO approval_row FROM governed_learning_apply_knowledge_review(
564
+ p_account_id, p_workspace_id, review_operation_id, decision_row.claim_id,
565
+ review_row.id, review_row.review_revision, 'approved', service_actor, caller_subject_id,
566
+ 'Approved by the exact initiating human through human-confirmed learning activation.'
567
+ );
568
+ IF destination_value = 'instruction_policy' THEN
569
+ SELECT * INTO instruction_event FROM governed_learning_apply_instruction_policy(
570
+ 'activate', p_account_id, p_workspace_id, destination_operation_id,
571
+ destination_proposal_id_value, destination_old_revision_id_value,
572
+ destination_old_version_value, destination_revision_id_value, service_actor
573
+ );
574
+ destination_new_version_value := instruction_event.activation_version;
575
+ destination_event_id_value := instruction_event.id;
576
+ effective_at_value := instruction_event.created_at;
577
+ ELSE
578
+ SELECT * INTO preference_event FROM governed_learning_apply_preference(
579
+ 'activate', p_account_id, p_workspace_id, destination_operation_id,
580
+ proposal_row.id, destination_proposal_id_value, destination_revision_id_value,
581
+ NULL, 0, service_actor
582
+ );
583
+ SELECT activation_version INTO destination_new_version_value
584
+ FROM preference_registry_preferences WHERE id = destination_proposal_id_value;
585
+ destination_event_id_value := preference_event.id;
586
+ effective_at_value := preference_event.created_at;
587
+ END IF;
588
+
589
+ INSERT INTO governed_learning_activation_receipts (
590
+ account_id, workspace_id, operation_id, input_hash, decision_receipt_id,
591
+ initiating_human_subject_id, service_actor_subject_id, policy_revision_id,
592
+ policy_hash, policy_activation_version, source_kind, source_id,
593
+ source_authority_hash, proposal_id, claim_id, evidence_id,
594
+ knowledge_previous_review_id, knowledge_previous_review_revision,
595
+ knowledge_approval_review_id, knowledge_approval_review_revision,
596
+ knowledge_approval_input_hash, destination, destination_proposal_id,
597
+ destination_revision_id, destination_old_revision_id,
598
+ destination_old_content_hash, destination_old_version,
599
+ destination_new_content_hash, destination_new_version, destination_event_id,
600
+ effective_at, authority_kind, human_input_request_id
601
+ ) VALUES (
602
+ p_account_id, p_workspace_id, p_operation_id, input_hash_value,
603
+ p_decision_receipt_id, caller_subject_id, service_actor, policy_revision.id,
604
+ policy_revision.policy_hash, policy_head.activation_version,
605
+ decision_row.source_kind, decision_row.source_id, current_authority_hash,
606
+ decision_row.proposal_id, decision_row.claim_id, decision_row.evidence_id,
607
+ review_row.id, review_row.review_revision, approval_row.id,
608
+ approval_row.review_revision, approval_row.input_hash, destination_value,
609
+ destination_proposal_id_value, destination_revision_id_value,
610
+ destination_old_revision_id_value, destination_old_content_hash_value,
611
+ destination_old_version_value, destination_new_content_hash_value,
612
+ destination_new_version_value, destination_event_id_value, effective_at_value,
613
+ 'human_confirmed', p_human_input_request_id
614
+ ) RETURNING * INTO result_row;
615
+ RETURN NEXT result_row;
616
+ END;
617
+ $$;
618
+ REVOKE ALL ON FUNCTION activate_human_confirmed_learning_decision(uuid, uuid, uuid, uuid, uuid) FROM PUBLIC;
619
+
620
+ -- Body is byte-identical to migration 0284 except the human-input generation
621
+ -- comparison (`<=` instead of `=`) and its explanatory comments.
622
+ CREATE OR REPLACE FUNCTION confirm_remember_knowledge_claim(
623
+ p_account_id uuid,
624
+ p_workspace_id uuid,
625
+ p_session_id uuid,
626
+ p_turn_id uuid,
627
+ p_execution_generation integer,
628
+ p_operation_id uuid,
629
+ p_claim_id uuid,
630
+ p_human_input_request_id uuid
631
+ ) RETURNS SETOF remember_knowledge_confirmation_receipts
632
+ LANGUAGE plpgsql SECURITY DEFINER AS $$
633
+ DECLARE
634
+ caller_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
635
+ result_row remember_knowledge_confirmation_receipts%ROWTYPE;
636
+ claim_row knowledge_claims%ROWTYPE;
637
+ evidence_row knowledge_claim_evidence%ROWTYPE;
638
+ task_note_row task_notes%ROWTYPE;
639
+ review_row knowledge_claim_reviews%ROWTYPE;
640
+ approval_row knowledge_claim_reviews%ROWTYPE;
641
+ human_input_row session_human_input_requests%ROWTYPE;
642
+ input_hash_value text;
643
+ service_actor text;
644
+ human_question_id text;
645
+ human_question_prompt text := 'Save this as workspace knowledge for everyone in this workspace?';
646
+ human_question_help text;
647
+ human_question_options jsonb := jsonb_build_array(
648
+ jsonb_build_object('id', 'save', 'label', 'Save'),
649
+ jsonb_build_object('id', 'skip', 'label', 'Don''t save')
650
+ );
651
+ conflict_count integer;
652
+ BEGIN
653
+ IF p_account_id IS NULL OR p_workspace_id IS NULL OR p_session_id IS NULL OR p_turn_id IS NULL
654
+ OR p_execution_generation IS NULL OR p_execution_generation <= 0
655
+ OR p_operation_id IS NULL OR p_claim_id IS NULL OR p_human_input_request_id IS NULL
656
+ OR caller_subject_id IS NULL OR length(btrim(caller_subject_id)) NOT BETWEEN 1 AND 1024
657
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
658
+ OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
659
+ THEN
660
+ RAISE EXCEPTION 'remember Knowledge confirmation requires exact tenant authority'
661
+ USING ERRCODE = '42501';
662
+ END IF;
663
+ input_hash_value := encode(sha256(convert_to(jsonb_build_array(
664
+ 'remember-knowledge-confirmation', 1, p_account_id, p_workspace_id, p_session_id,
665
+ p_turn_id, p_execution_generation, p_operation_id, p_claim_id, p_human_input_request_id
666
+ )::text, 'UTF8')), 'hex');
667
+ service_actor := 'service:governed-learning-activation:' || input_hash_value;
668
+
669
+ PERFORM 1 FROM workspaces workspace
670
+ WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id FOR UPDATE;
671
+ IF NOT FOUND THEN
672
+ RAISE EXCEPTION 'remember Knowledge workspace is unavailable' USING ERRCODE = '42501';
673
+ END IF;
674
+ SELECT * INTO result_row FROM remember_knowledge_confirmation_receipts receipt
675
+ WHERE receipt.workspace_id = p_workspace_id AND receipt.operation_id = p_operation_id FOR SHARE;
676
+ IF FOUND THEN
677
+ IF result_row.account_id <> p_account_id OR result_row.input_hash <> input_hash_value
678
+ OR result_row.initiating_human_subject_id <> caller_subject_id
679
+ THEN
680
+ RAISE EXCEPTION 'remember Knowledge confirmation conflicts with immutable receipt'
681
+ USING ERRCODE = '23505';
682
+ END IF;
683
+ RETURN NEXT result_row;
684
+ RETURN;
685
+ END IF;
686
+ IF EXISTS (SELECT 1 FROM remember_knowledge_confirmation_receipts receipt WHERE receipt.claim_id = p_claim_id) THEN
687
+ RAISE EXCEPTION 'remember Knowledge claim was already confirmed by another operation'
688
+ USING ERRCODE = '23505';
689
+ END IF;
690
+
691
+ -- The live turn must belong to the caller (the initiating human) and hold a
692
+ -- running attempt of the given execution generation without a pending
693
+ -- interruption. The human-input pause resumes on a later attempt of the same
694
+ -- logical turn at a later execution generation, so the caller's live
695
+ -- generation is exact here while the human-input row below is bound to the
696
+ -- generation in which the question was asked.
697
+ PERFORM 1 FROM sessions session
698
+ WHERE session.account_id = p_account_id AND session.workspace_id = p_workspace_id
699
+ AND session.id = p_session_id AND session.active_turn_id = p_turn_id
700
+ AND session_reference_visible(session.account_id, session.workspace_id, session.id)
701
+ FOR SHARE;
702
+ IF NOT FOUND THEN
703
+ RAISE EXCEPTION 'remember Knowledge session is unavailable' USING ERRCODE = '42501';
704
+ END IF;
705
+ PERFORM 1 FROM session_turns turn
706
+ JOIN session_turn_attempts attempt
707
+ ON attempt.account_id = turn.account_id AND attempt.workspace_id = turn.workspace_id
708
+ AND attempt.session_id = turn.session_id AND attempt.turn_id = turn.id
709
+ AND attempt.id = turn.active_attempt_id
710
+ WHERE turn.account_id = p_account_id AND turn.workspace_id = p_workspace_id
711
+ AND turn.session_id = p_session_id AND turn.id = p_turn_id
712
+ AND turn.execution_generation = p_execution_generation
713
+ AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
714
+ AND coalesce(turn.initiating_human_subject_id,
715
+ CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
716
+ ) = caller_subject_id
717
+ AND attempt.execution_generation = p_execution_generation
718
+ AND attempt.state IN ('claimed', 'running')
719
+ AND NOT EXISTS (
720
+ SELECT 1 FROM session_attempt_interruptions interruption
721
+ WHERE interruption.workspace_id = p_workspace_id
722
+ AND interruption.attempt_id = attempt.id
723
+ AND interruption.state IN ('pending', 'delivered', 'acknowledged')
724
+ )
725
+ FOR SHARE OF attempt;
726
+ IF NOT FOUND THEN
727
+ RAISE EXCEPTION 'remember Knowledge turn is unavailable' USING ERRCODE = '42501';
728
+ END IF;
729
+
730
+ SELECT * INTO claim_row FROM knowledge_claims claim
731
+ WHERE claim.id = p_claim_id AND claim.account_id = p_account_id
732
+ AND claim.scope_kind = 'workspace' AND claim.scope_workspace_id = p_workspace_id
733
+ AND claim.scope_subject_id IS NULL
734
+ AND claim.initiating_human_subject_id = caller_subject_id
735
+ AND claim.effective_at <= transaction_timestamp()
736
+ AND (claim.expires_at IS NULL OR claim.expires_at > transaction_timestamp())
737
+ FOR UPDATE;
738
+ IF NOT FOUND THEN
739
+ RAISE EXCEPTION 'remember Knowledge claim is unavailable' USING ERRCODE = '42501';
740
+ END IF;
741
+ SELECT * INTO evidence_row FROM knowledge_claim_evidence evidence
742
+ WHERE evidence.account_id = p_account_id AND evidence.scope_kind = 'workspace'
743
+ AND evidence.scope_workspace_id = p_workspace_id AND evidence.scope_subject_id IS NULL
744
+ AND evidence.claim_id = p_claim_id AND evidence.polarity = 'supports'
745
+ AND evidence.task_note_id IS NOT NULL
746
+ AND evidence.initiating_human_subject_id = caller_subject_id
747
+ ORDER BY evidence.created_at ASC LIMIT 1 FOR SHARE;
748
+ IF NOT FOUND THEN
749
+ RAISE EXCEPTION 'remember Knowledge confirmation requires exact Task-note evidence'
750
+ USING ERRCODE = '42501';
751
+ END IF;
752
+ SELECT count(*) INTO conflict_count FROM knowledge_claim_evidence contradiction
753
+ WHERE contradiction.account_id = p_account_id AND contradiction.scope_kind = 'workspace'
754
+ AND contradiction.scope_workspace_id = p_workspace_id AND contradiction.scope_subject_id IS NULL
755
+ AND contradiction.claim_id = p_claim_id AND contradiction.polarity = 'contradicts';
756
+ IF conflict_count <> 0 THEN
757
+ RAISE EXCEPTION 'remember Knowledge evidence now conflicts' USING ERRCODE = '23514';
758
+ END IF;
759
+ SELECT * INTO task_note_row FROM task_notes note
760
+ WHERE note.id = evidence_row.task_note_id AND note.account_id = p_account_id
761
+ AND note.workspace_id = p_workspace_id
762
+ AND note.root_session_id = evidence_row.task_note_root_session_id
763
+ AND note.version = evidence_row.task_note_version
764
+ AND note.text_hash = evidence_row.content_hash
765
+ AND note.status = 'active' AND note.expires_at > transaction_timestamp()
766
+ AND session_reference_visible(note.account_id, note.workspace_id, note.root_session_id)
767
+ FOR SHARE;
768
+ IF NOT FOUND THEN
769
+ RAISE EXCEPTION 'remember Knowledge Task-note authority was revoked' USING ERRCODE = '42501';
770
+ END IF;
771
+ SELECT * INTO review_row FROM knowledge_claim_reviews review
772
+ WHERE review.account_id = p_account_id AND review.claim_id = p_claim_id
773
+ ORDER BY review.review_revision DESC LIMIT 1 FOR SHARE;
774
+ IF NOT FOUND OR review_row.state <> 'proposed' THEN
775
+ RAISE EXCEPTION 'remember Knowledge claim is not awaiting confirmation' USING ERRCODE = '42501';
776
+ END IF;
777
+
778
+ -- The exact human must have answered the canonical bound question with
779
+ -- `save` on this session/turn. The row carries the exact execution
780
+ -- generation in which the question was asked; the live generation proven
781
+ -- above is that generation or a later resume of the same logical turn. The
782
+ -- question is reconstructed here from the note text, so an agent cannot
783
+ -- obtain confirmation through a misleading prompt.
784
+ human_question_id := 'remember:' || p_claim_id::text;
785
+ human_question_help := left(task_note_row.text, 2000);
786
+ SELECT * INTO human_input_row FROM session_human_input_requests request
787
+ WHERE request.id = p_human_input_request_id
788
+ AND request.account_id = p_account_id AND request.workspace_id = p_workspace_id
789
+ AND request.session_id = p_session_id AND request.turn_id = p_turn_id
790
+ AND request.turn_generation <= p_execution_generation
791
+ AND request.status = 'answered'
792
+ AND request.responded_by = caller_subject_id
793
+ AND request.response->>'outcome' = 'answered'
794
+ AND EXISTS (
795
+ SELECT 1 FROM jsonb_array_elements(request.questions) question(value)
796
+ WHERE question.value->>'id' = human_question_id
797
+ AND question.value->>'kind' = 'single_select'
798
+ AND question.value->>'prompt' = human_question_prompt
799
+ AND question.value->>'helpText' = human_question_help
800
+ AND question.value->'options' = human_question_options
801
+ AND coalesce((question.value->>'allowOther')::boolean, false) = false
802
+ )
803
+ AND EXISTS (
804
+ SELECT 1 FROM jsonb_array_elements(request.response->'answers') answer(value)
805
+ WHERE answer.value->>'questionId' = human_question_id
806
+ AND answer.value->'values' = to_jsonb(ARRAY['save'])
807
+ )
808
+ FOR SHARE;
809
+ IF NOT FOUND THEN
810
+ RAISE EXCEPTION 'human confirmation for this Knowledge claim is unavailable'
811
+ USING ERRCODE = '42501';
812
+ END IF;
813
+
814
+ SELECT * INTO approval_row FROM governed_learning_apply_knowledge_review(
815
+ p_account_id, p_workspace_id,
816
+ opengeni_private.governed_learning_derived_uuid(p_operation_id, 'remember-knowledge-approval'),
817
+ p_claim_id, review_row.id, review_row.review_revision, 'approved',
818
+ service_actor, caller_subject_id,
819
+ 'Approved by the exact initiating human through the bound remember confirmation.'
820
+ );
821
+
822
+ INSERT INTO remember_knowledge_confirmation_receipts (
823
+ account_id, workspace_id, operation_id, input_hash, session_id, turn_id,
824
+ execution_generation, initiating_human_subject_id, service_actor_subject_id,
825
+ claim_id, evidence_id, task_note_id, task_note_text_hash, human_input_request_id,
826
+ previous_review_id, previous_review_revision, approval_review_id, approval_review_revision
827
+ ) VALUES (
828
+ p_account_id, p_workspace_id, p_operation_id, input_hash_value, p_session_id, p_turn_id,
829
+ p_execution_generation, caller_subject_id, service_actor,
830
+ p_claim_id, evidence_row.id, task_note_row.id, task_note_row.text_hash, p_human_input_request_id,
831
+ review_row.id, review_row.review_revision, approval_row.id, approval_row.review_revision
832
+ ) RETURNING * INTO result_row;
833
+ RETURN NEXT result_row;
834
+ END;
835
+ $$;
836
+ REVOKE ALL ON FUNCTION confirm_remember_knowledge_claim(uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid) FROM PUBLIC;
837
+
838
+ DO $human_confirmed_resumed_generation_hardening$
839
+ DECLARE
840
+ target_schema text := current_schema();
841
+ runtime_role text := nullif(current_setting('opengeni.runtime_role', true), '');
842
+ BEGIN
843
+ IF runtime_role IS NULL AND EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
844
+ runtime_role := 'opengeni_app';
845
+ END IF;
846
+ -- CREATE OR REPLACE drops proconfig; re-apply the pin 0272/0274/0284/0293 established.
847
+ EXECUTE format(
848
+ 'ALTER FUNCTION %I.activate_human_confirmed_learning_decision(uuid,uuid,uuid,uuid,uuid) '
849
+ || 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
850
+ );
851
+ EXECUTE format(
852
+ 'ALTER FUNCTION %I.confirm_remember_knowledge_claim(uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid) '
853
+ || 'SET search_path = pg_catalog, %I, pg_temp', target_schema, target_schema
854
+ );
855
+ IF runtime_role IS NOT NULL THEN
856
+ EXECUTE format(
857
+ 'GRANT EXECUTE ON FUNCTION %I.activate_human_confirmed_learning_decision(uuid,uuid,uuid,uuid,uuid) TO %I',
858
+ target_schema, runtime_role
859
+ );
860
+ EXECUTE format(
861
+ 'GRANT EXECUTE ON FUNCTION %I.confirm_remember_knowledge_claim(uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid) TO %I',
862
+ target_schema, runtime_role
863
+ );
864
+ END IF;
865
+ END
866
+ $human_confirmed_resumed_generation_hardening$;
867
+
868
+ RESET statement_timeout;
869
+ RESET lock_timeout;