@opengeni/db 0.36.1 → 3.1.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) 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-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
  7. package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
  8. package/dist/{chunk-HSOWSYOX.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-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
  13. package/dist/chunk-PR2WMLOQ.js.map +1 -0
  14. package/dist/{chunk-Z7VYMNPZ.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.d.ts +10 -0
  36. package/dist/editable-artifact-durable-export.js +18 -3
  37. package/dist/editable-artifact-durable-export.js.map +1 -1
  38. package/dist/editable-artifacts.d.ts +2 -2
  39. package/dist/editable-artifacts.js +3 -3
  40. package/dist/governed-learning-activation-schema.d.ts +984 -0
  41. package/dist/governed-learning-activation.d.ts +98 -0
  42. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  43. package/dist/governed-learning-evaluator.d.ts +28 -0
  44. package/dist/index.d.ts +1633 -87
  45. package/dist/index.js +22004 -8109
  46. package/dist/index.js.map +1 -1
  47. package/dist/insights.d.ts +18 -0
  48. package/dist/integration-bindings.d.ts +1 -0
  49. package/dist/integration-facets.d.ts +30 -0
  50. package/dist/interaction-placement-loss.d.ts +22 -0
  51. package/dist/knowledge-source-sync-schema.d.ts +730 -0
  52. package/dist/knowledge-source-sync.d.ts +60 -0
  53. package/dist/managed-human-provisioning.d.ts +25 -0
  54. package/dist/memory-domain.d.ts +3 -3
  55. package/dist/migrate.d.ts +11 -1
  56. package/dist/migrate.js +1 -1
  57. package/dist/new-session-drafts.d.ts +43 -5
  58. package/dist/organization-membership-backfill.d.ts +174 -0
  59. package/dist/organization-membership-lifecycle.d.ts +162 -0
  60. package/dist/pr-review.d.ts +107 -0
  61. package/dist/preference-registry-schema.d.ts +2 -0
  62. package/dist/preference-registry.d.ts +2 -0
  63. package/dist/provision-roles.js +1 -1
  64. package/dist/runtime-posture.d.ts +23 -9
  65. package/dist/schema.d.ts +24925 -13697
  66. package/dist/schema.js +103 -1
  67. package/dist/scoped-knowledge-schema.d.ts +52 -1
  68. package/dist/session-background-commands.d.ts +125 -0
  69. package/dist/session-background-commands.js +34 -0
  70. package/dist/session-background-commands.js.map +1 -0
  71. package/dist/session-control.d.ts +156 -3
  72. package/dist/session-goal-pacing.d.ts +68 -0
  73. package/dist/session-queue-commands.d.ts +42 -5
  74. package/dist/session-realtime-ledger.d.ts +3 -0
  75. package/dist/session-tenancy.d.ts +71 -1
  76. package/dist/session-tenancy.js +25 -3
  77. package/dist/session-tool-call-settlement.d.ts +9 -4
  78. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  79. package/dist/slack-routing.d.ts +153 -0
  80. package/dist/slack-task-policy-schema.d.ts +34 -0
  81. package/dist/slack-task-policy.d.ts +8 -0
  82. package/dist/slack-user-link-access.d.ts +1 -0
  83. package/dist/task-notes-schema.d.ts +594 -0
  84. package/dist/task-notes.d.ts +39 -0
  85. package/dist/turn-initiator.d.ts +2 -0
  86. package/dist/user-resource-authority.d.ts +109 -0
  87. package/dist/video-generation.js +3 -3
  88. package/dist/workspace-authority.d.ts +81 -0
  89. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  90. package/dist/workspace-instruction-policies.d.ts +62 -0
  91. package/dist/workspace-learning-policy.d.ts +1 -0
  92. package/dist/workspace-membership-permissions.d.ts +2 -0
  93. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  94. package/drizzle/0240_model_context_user_messages.sql +204 -0
  95. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  96. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  97. package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
  98. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  99. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  100. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  101. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  102. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  103. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  104. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  105. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  106. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  107. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  108. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  109. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  110. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  111. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  112. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  113. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  114. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  115. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  116. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  117. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  118. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  119. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  120. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  121. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  122. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  123. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  124. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  125. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  126. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  127. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  128. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  129. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  130. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  131. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  132. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  133. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  134. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  135. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  136. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  137. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  138. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  139. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  140. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  141. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  142. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  143. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  144. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  145. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  146. package/drizzle/0294_preference_activation_authority.sql +237 -0
  147. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  148. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  149. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  150. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  151. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  152. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  153. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  154. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  155. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  156. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  157. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  158. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  159. package/drizzle/0307_session_attention_state.sql +51 -0
  160. package/drizzle/0308_session_archives.sql +35 -0
  161. package/drizzle/0309_channel_project_pins.sql +6 -0
  162. package/drizzle/0310_channel_project_order.sql +27 -0
  163. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  164. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  165. package/drizzle/0313_private_child_session_authority.sql +365 -0
  166. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  167. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  168. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  169. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  170. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  171. package/drizzle/0319_event_triggered_automations.sql +254 -0
  172. package/drizzle/0320_pr_review_pack.sql +113 -0
  173. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  174. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  175. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  176. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  177. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  178. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  179. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  180. package/drizzle/0328_session_background_commands.sql +590 -0
  181. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  182. package/drizzle/0330_api_key_descriptions.sql +20 -0
  183. package/drizzle/0331_managed_organization_creation.sql +163 -0
  184. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  185. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  186. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  187. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  188. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  189. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  190. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  191. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  192. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  193. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
  194. package/package.json +10 -6
  195. package/src/attached-browser-devices.ts +233 -5
  196. package/src/automations.ts +911 -0
  197. package/src/browser-sessions.ts +10 -0
  198. package/src/capability-integrations.ts +175 -1
  199. package/src/child-lifecycle-notices.ts +241 -0
  200. package/src/codemode-operations.ts +1 -35
  201. package/src/company-brain-context-selection-schema.ts +100 -0
  202. package/src/company-brain-context-selection.ts +359 -0
  203. package/src/company-brain-governed-writes.ts +1170 -0
  204. package/src/company-brain.ts +309 -0
  205. package/src/company-profile-agent-admin.ts +225 -0
  206. package/src/company-profile-schema.ts +121 -1
  207. package/src/company-profile.ts +21 -0
  208. package/src/computer-sessions.ts +10 -1
  209. package/src/connection-authority.ts +290 -0
  210. package/src/connection-scopes.ts +20 -0
  211. package/src/connection-tenancy-backfill.ts +81 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +75 -2
  214. package/src/editable-artifact-durable-export.ts +27 -0
  215. package/src/editable-artifacts-schema.ts +10 -5
  216. package/src/editable-artifacts.ts +21 -11
  217. package/src/governed-learning-activation-schema.ts +121 -0
  218. package/src/governed-learning-activation.ts +588 -0
  219. package/src/governed-learning-evaluator-schema.ts +72 -0
  220. package/src/governed-learning-evaluator.ts +217 -0
  221. package/src/index.ts +12001 -1699
  222. package/src/insights.ts +107 -0
  223. package/src/integration-bindings.ts +88 -6
  224. package/src/integration-facets.ts +287 -84
  225. package/src/interaction-placement-loss.ts +234 -0
  226. package/src/knowledge-source-sync-schema.ts +83 -0
  227. package/src/knowledge-source-sync.ts +530 -0
  228. package/src/managed-human-provisioning.ts +116 -0
  229. package/src/memory-domain.ts +27 -32
  230. package/src/migrate.ts +77 -1
  231. package/src/new-session-drafts.ts +229 -35
  232. package/src/organization-membership-backfill.ts +735 -0
  233. package/src/organization-membership-lifecycle.ts +985 -0
  234. package/src/pr-review.ts +890 -0
  235. package/src/preference-registry.ts +31 -1
  236. package/src/provision-roles.ts +931 -24
  237. package/src/runtime-posture-cli.ts +2 -0
  238. package/src/runtime-posture.ts +1315 -52
  239. package/src/schema.ts +3336 -438
  240. package/src/scoped-knowledge-schema.ts +16 -8
  241. package/src/scoped-knowledge.ts +1 -1
  242. package/src/session-background-commands.ts +759 -0
  243. package/src/session-control.ts +640 -74
  244. package/src/session-goal-pacing.ts +126 -0
  245. package/src/session-queue-commands.ts +450 -98
  246. package/src/session-realtime-context.ts +19 -3
  247. package/src/session-realtime-ledger.ts +75 -12
  248. package/src/session-realtime-mirror.ts +1 -1
  249. package/src/session-tenancy.ts +403 -49
  250. package/src/session-tool-call-settlement.ts +38 -29
  251. package/src/slack-routing-personal-workspace.ts +67 -0
  252. package/src/slack-routing.ts +469 -0
  253. package/src/slack-task-policy-schema.ts +5 -0
  254. package/src/slack-task-policy.ts +18 -0
  255. package/src/slack-user-link-access.ts +17 -1
  256. package/src/task-notes-schema.ts +74 -0
  257. package/src/task-notes.ts +124 -2
  258. package/src/turn-initiator.ts +8 -0
  259. package/src/user-resource-authority.ts +377 -0
  260. package/src/workspace-authority.ts +160 -0
  261. package/src/workspace-instruction-policies-schema.ts +53 -1
  262. package/src/workspace-instruction-policies.ts +528 -77
  263. package/src/workspace-learning-policy.ts +21 -5
  264. package/src/workspace-membership-permissions.ts +9 -0
  265. package/dist/chunk-5KTIEDX7.js.map +0 -1
  266. package/dist/chunk-FPVAD4CO.js +0 -117
  267. package/dist/chunk-FPVAD4CO.js.map +0 -1
  268. package/dist/chunk-HSOWSYOX.js.map +0 -1
  269. package/dist/chunk-SK7YYHBI.js.map +0 -1
  270. package/dist/chunk-VKLB2ZGI.js +0 -2389
  271. package/dist/chunk-VKLB2ZGI.js.map +0 -1
  272. package/dist/chunk-Z7VYMNPZ.js.map +0 -1
  273. /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
  274. /package/dist/{chunk-VTPRIXKG.js.map → chunk-NJVZPWXY.js.map} +0 -0
@@ -0,0 +1,820 @@
1
+ -- deployment-mode: rolling
2
+ -- Migration 0260 follows the released 0258 three-scope Document authority.
3
+ -- Task notes may be promoted only into workspace-local proposed Knowledge.
4
+ -- The evidence row retains a value-free immutable source receipt after the
5
+ -- short-lived task tree is cleaned up; the source bytes remain in the ordinary
6
+ -- Task-note lifecycle and are never copied into evidence metadata.
7
+ -- Every new path and the complete invoked 0239/0225 Task-note authority
8
+ -- closure explicitly put pg_temp last so caller-created temporary relations
9
+ -- cannot shadow target-schema authority relations.
10
+
11
+ SET LOCAL lock_timeout = '5s';
12
+ SET LOCAL statement_timeout = '10min';
13
+
14
+ ALTER TABLE "knowledge_claim_evidence"
15
+ ALTER COLUMN "document_version_id" DROP NOT NULL,
16
+ ADD COLUMN "task_note_id" uuid,
17
+ ADD COLUMN "task_note_root_session_id" uuid,
18
+ ADD COLUMN "task_note_version" integer,
19
+ ADD CONSTRAINT "knowledge_claim_evidence_source_shape_chk" CHECK (
20
+ (
21
+ "document_version_id" IS NOT NULL
22
+ AND "task_note_id" IS NULL
23
+ AND "task_note_root_session_id" IS NULL
24
+ AND "task_note_version" IS NULL
25
+ ) OR (
26
+ "document_version_id" IS NULL
27
+ AND "task_note_id" IS NOT NULL
28
+ AND "task_note_root_session_id" IS NOT NULL
29
+ AND "task_note_version" = 1
30
+ AND "scope_kind" = 'workspace'
31
+ AND "scope_workspace_id" IS NOT NULL
32
+ AND "scope_subject_id" IS NULL
33
+ AND "document_chunk_id" IS NULL
34
+ AND "chunk_index" IS NULL
35
+ AND "locator" IS NULL
36
+ AND "quote_hash" IS NULL
37
+ )
38
+ ) NOT VALID;
39
+
40
+ ALTER TABLE "knowledge_claim_evidence"
41
+ VALIDATE CONSTRAINT "knowledge_claim_evidence_source_shape_chk";
42
+
43
+ DROP INDEX "knowledge_claim_evidence_natural_identity_uq";
44
+ CREATE UNIQUE INDEX "knowledge_claim_evidence_document_natural_identity_uq"
45
+ ON "knowledge_claim_evidence" (
46
+ "claim_id", "document_version_id", "polarity",
47
+ coalesce("document_chunk_id"::text, ''), coalesce("locator", '')
48
+ ) WHERE "document_version_id" IS NOT NULL;
49
+ CREATE UNIQUE INDEX "knowledge_claim_evidence_task_note_natural_identity_uq"
50
+ ON "knowledge_claim_evidence" ("claim_id", "task_note_id", "polarity")
51
+ WHERE "task_note_id" IS NOT NULL;
52
+
53
+ CREATE TABLE "task_note_knowledge_promotion_capabilities" (
54
+ "backend_pid" integer NOT NULL,
55
+ "transaction_id" xid8 NOT NULL,
56
+ "capability_id" uuid NOT NULL,
57
+ "account_id" uuid NOT NULL,
58
+ "workspace_id" uuid NOT NULL,
59
+ "note_id" uuid NOT NULL,
60
+ "root_session_id" uuid NOT NULL,
61
+ "note_version" integer NOT NULL CHECK ("note_version" = 1),
62
+ "note_text_hash" text NOT NULL,
63
+ "evidence_operation_id" text NOT NULL,
64
+ "claim_operation_id" text NOT NULL,
65
+ "actor_subject_id" text NOT NULL,
66
+ "initiating_human_subject_id" text NOT NULL,
67
+ "learning_policy_snapshot_id" uuid NOT NULL,
68
+ PRIMARY KEY ("backend_pid", "transaction_id", "capability_id")
69
+ );
70
+
71
+ -- A replacement is one atomic, append-only correction receipt. The old note
72
+ -- remains immutable and archived; the replacement is a fresh version-one note.
73
+ -- The receipt deliberately stores no note text.
74
+ CREATE TABLE "task_note_replacement_receipts" (
75
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
76
+ "account_id" uuid NOT NULL,
77
+ "workspace_id" uuid NOT NULL,
78
+ "root_session_id" uuid NOT NULL,
79
+ "operation_id" uuid NOT NULL,
80
+ "input_hash" text NOT NULL,
81
+ "replaced_note_id" uuid NOT NULL,
82
+ "replaced_note_version" integer NOT NULL CHECK ("replaced_note_version" = 2),
83
+ "replacement_note_id" uuid NOT NULL,
84
+ "replacement_note_version" integer NOT NULL CHECK ("replacement_note_version" = 1),
85
+ "archive_operation_id" uuid NOT NULL,
86
+ "create_operation_id" uuid NOT NULL,
87
+ "actor_kind" text NOT NULL,
88
+ "actor_subject_id" text NOT NULL,
89
+ "initiating_human_subject_id" text,
90
+ "actor_session_id" uuid NOT NULL,
91
+ "actor_turn_id" uuid NOT NULL,
92
+ "actor_attempt_id" uuid NOT NULL,
93
+ "actor_execution_generation" integer NOT NULL,
94
+ "created_at" timestamptz NOT NULL DEFAULT now(),
95
+ CONSTRAINT "task_note_replacement_receipts_workspace_account_fk"
96
+ FOREIGN KEY ("workspace_id", "account_id")
97
+ REFERENCES "workspaces" ("id", "account_id") ON DELETE CASCADE,
98
+ CONSTRAINT "task_note_replacement_receipts_root_session_fk"
99
+ FOREIGN KEY ("workspace_id", "root_session_id")
100
+ REFERENCES "sessions" ("workspace_id", "id") ON DELETE CASCADE,
101
+ CONSTRAINT "task_note_replacement_receipts_replaced_note_fk"
102
+ FOREIGN KEY ("workspace_id", "replaced_note_id")
103
+ REFERENCES "task_notes" ("workspace_id", "id") ON DELETE CASCADE,
104
+ CONSTRAINT "task_note_replacement_receipts_replacement_note_fk"
105
+ FOREIGN KEY ("workspace_id", "replacement_note_id")
106
+ REFERENCES "task_notes" ("workspace_id", "id") ON DELETE CASCADE,
107
+ CONSTRAINT "task_note_replacement_receipts_actor_session_fk"
108
+ FOREIGN KEY ("workspace_id", "actor_session_id")
109
+ REFERENCES "sessions" ("workspace_id", "id") ON DELETE RESTRICT,
110
+ CONSTRAINT "task_note_replacement_receipts_actor_turn_fk"
111
+ FOREIGN KEY ("workspace_id", "actor_turn_id")
112
+ REFERENCES "session_turns" ("workspace_id", "id") ON DELETE RESTRICT,
113
+ CONSTRAINT "task_note_replacement_receipts_actor_attempt_fk"
114
+ FOREIGN KEY ("workspace_id", "actor_attempt_id")
115
+ REFERENCES "session_turn_attempts" ("workspace_id", "id") ON DELETE RESTRICT,
116
+ CONSTRAINT "task_note_replacement_receipts_shape_chk" CHECK (
117
+ "replaced_note_id" <> "replacement_note_id"
118
+ AND "archive_operation_id" <> "create_operation_id"
119
+ AND "operation_id" <> "archive_operation_id"
120
+ AND "operation_id" <> "create_operation_id"
121
+ AND "input_hash" ~ '^[0-9a-f]{64}$'
122
+ AND "actor_kind" IN ('human', 'service')
123
+ AND length("actor_subject_id") BETWEEN 1 AND 1024
124
+ AND octet_length("actor_subject_id") <= 4096
125
+ AND ("initiating_human_subject_id" IS NULL OR (
126
+ length("initiating_human_subject_id") BETWEEN 1 AND 1024
127
+ AND octet_length("initiating_human_subject_id") <= 4096
128
+ ))
129
+ AND "actor_execution_generation" > 0
130
+ ),
131
+ CONSTRAINT "task_note_replacement_receipts_workspace_operation_uq"
132
+ UNIQUE ("workspace_id", "operation_id"),
133
+ CONSTRAINT "task_note_replacement_receipts_workspace_replacement_uq"
134
+ UNIQUE ("workspace_id", "replacement_note_id")
135
+ );
136
+
137
+ CREATE INDEX "task_note_replacement_receipts_root_timeline_idx"
138
+ ON "task_note_replacement_receipts" (
139
+ "workspace_id", "root_session_id", "created_at" DESC, "id" DESC
140
+ );
141
+
142
+ ALTER TABLE "task_note_knowledge_promotion_capabilities" ENABLE ROW LEVEL SECURITY;
143
+ ALTER TABLE "task_note_knowledge_promotion_capabilities" FORCE ROW LEVEL SECURITY;
144
+ ALTER TABLE "task_note_replacement_receipts" ENABLE ROW LEVEL SECURITY;
145
+ ALTER TABLE "task_note_replacement_receipts" FORCE ROW LEVEL SECURITY;
146
+ CREATE POLICY session_visibility_isolation ON "task_note_replacement_receipts"
147
+ AS RESTRICTIVE
148
+ FOR ALL
149
+ USING (session_reference_visible(
150
+ "account_id", "workspace_id", "actor_session_id"
151
+ ))
152
+ WITH CHECK (session_reference_visible(
153
+ "account_id", "workspace_id", "actor_session_id"
154
+ ));
155
+
156
+ DO $promotion_capability_policy$
157
+ DECLARE
158
+ data_schema text := current_schema();
159
+ migration_owner text := current_user;
160
+ BEGIN
161
+ EXECUTE format(
162
+ 'CREATE POLICY task_note_knowledge_promotion_capability_owner '
163
+ || 'ON %I.task_note_knowledge_promotion_capabilities '
164
+ || 'FOR ALL USING (current_user = %L) WITH CHECK (current_user = %L)',
165
+ data_schema, migration_owner, migration_owner
166
+ );
167
+ EXECUTE format(
168
+ 'REVOKE ALL ON %I.task_note_knowledge_promotion_capabilities FROM PUBLIC',
169
+ data_schema
170
+ );
171
+ EXECUTE format(
172
+ 'CREATE POLICY task_note_replacement_receipts_owner '
173
+ || 'ON %I.task_note_replacement_receipts '
174
+ || 'FOR ALL USING (current_user = %L) WITH CHECK (current_user = %L)',
175
+ data_schema, migration_owner, migration_owner
176
+ );
177
+ EXECUTE format(
178
+ 'REVOKE ALL ON %I.task_note_replacement_receipts FROM PUBLIC',
179
+ data_schema
180
+ );
181
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
182
+ EXECUTE format(
183
+ 'REVOKE ALL ON %I.task_note_knowledge_promotion_capabilities FROM opengeni_app',
184
+ data_schema
185
+ );
186
+ EXECUTE format(
187
+ 'REVOKE ALL ON %I.task_note_replacement_receipts FROM opengeni_app',
188
+ data_schema
189
+ );
190
+ END IF;
191
+ END
192
+ $promotion_capability_policy$;
193
+
194
+ CREATE OR REPLACE FUNCTION reject_task_note_replacement_receipt_mutation()
195
+ RETURNS trigger
196
+ LANGUAGE plpgsql
197
+ SECURITY DEFINER
198
+ SET search_path FROM CURRENT
199
+ AS $$
200
+ BEGIN
201
+ IF TG_OP = 'DELETE'
202
+ AND pg_trigger_depth() > 1
203
+ AND (
204
+ NOT EXISTS (SELECT 1 FROM workspaces WHERE id = OLD.workspace_id)
205
+ OR NOT EXISTS (SELECT 1 FROM sessions WHERE id = OLD.root_session_id)
206
+ OR NOT EXISTS (
207
+ SELECT 1 FROM task_notes
208
+ WHERE workspace_id = OLD.workspace_id AND id = OLD.replaced_note_id
209
+ )
210
+ OR NOT EXISTS (
211
+ SELECT 1 FROM task_notes
212
+ WHERE workspace_id = OLD.workspace_id AND id = OLD.replacement_note_id
213
+ )
214
+ )
215
+ THEN
216
+ RETURN OLD;
217
+ END IF;
218
+ RAISE EXCEPTION 'Task-note replacement receipts are immutable' USING ERRCODE = '55000';
219
+ END;
220
+ $$;
221
+
222
+ CREATE TRIGGER task_note_replacement_receipts_immutable
223
+ BEFORE UPDATE OR DELETE ON "task_note_replacement_receipts"
224
+ FOR EACH ROW EXECUTE FUNCTION reject_task_note_replacement_receipt_mutation();
225
+
226
+ CREATE OR REPLACE FUNCTION validate_task_note_knowledge_evidence()
227
+ RETURNS trigger
228
+ LANGUAGE plpgsql
229
+ SECURITY DEFINER
230
+ SET search_path FROM CURRENT
231
+ AS $$
232
+ DECLARE
233
+ note_row task_notes%ROWTYPE;
234
+ capability_row task_note_knowledge_promotion_capabilities%ROWTYPE;
235
+ BEGIN
236
+ IF NEW.task_note_id IS NULL THEN
237
+ RETURN NEW;
238
+ END IF;
239
+
240
+ SELECT capability.* INTO capability_row
241
+ FROM task_note_knowledge_promotion_capabilities capability
242
+ WHERE capability.backend_pid = pg_catalog.pg_backend_pid()
243
+ AND capability.transaction_id = pg_catalog.pg_current_xact_id()
244
+ AND capability.capability_id = nullif(
245
+ pg_catalog.current_setting('opengeni.task_note_knowledge_promotion_capability', true), ''
246
+ )::uuid
247
+ AND capability.account_id = NEW.account_id
248
+ AND capability.workspace_id = NEW.scope_workspace_id
249
+ AND capability.note_id = NEW.task_note_id
250
+ AND capability.root_session_id = NEW.task_note_root_session_id
251
+ AND capability.note_version = NEW.task_note_version
252
+ AND capability.note_text_hash = NEW.content_hash
253
+ AND capability.evidence_operation_id = NEW.operation_id
254
+ AND capability.actor_subject_id = NEW.actor_subject_id
255
+ AND capability.initiating_human_subject_id = NEW.initiating_human_subject_id;
256
+ IF NOT FOUND THEN
257
+ RAISE EXCEPTION 'Task-note Knowledge evidence requires exact promotion capability'
258
+ USING ERRCODE = '42501';
259
+ END IF;
260
+
261
+ SELECT note.* INTO note_row
262
+ FROM task_notes note
263
+ WHERE note.id = NEW.task_note_id
264
+ AND note.account_id = NEW.account_id
265
+ AND note.workspace_id = NEW.scope_workspace_id;
266
+ IF NOT FOUND
267
+ OR NEW.task_note_root_session_id IS DISTINCT FROM note_row.root_session_id
268
+ OR NEW.task_note_version IS DISTINCT FROM note_row.version
269
+ OR NEW.content_hash IS DISTINCT FROM note_row.text_hash
270
+ THEN
271
+ RAISE EXCEPTION 'Knowledge evidence does not match the exact Task-note source receipt'
272
+ USING ERRCODE = '23514';
273
+ END IF;
274
+ IF NOT EXISTS (
275
+ SELECT 1
276
+ FROM knowledge_claims claim
277
+ JOIN knowledge_facts fact
278
+ ON fact.account_id = claim.account_id
279
+ AND fact.id = claim.fact_id
280
+ AND fact.scope_key = claim.scope_key
281
+ WHERE claim.id = NEW.claim_id
282
+ AND claim.account_id = NEW.account_id
283
+ AND claim.scope_kind = 'workspace'
284
+ AND claim.scope_workspace_id = NEW.scope_workspace_id
285
+ AND claim.scope_subject_id IS NULL
286
+ AND claim.operation_id = capability_row.claim_operation_id
287
+ AND claim.actor_kind = NEW.actor_kind
288
+ AND claim.actor_subject_id = capability_row.actor_subject_id
289
+ AND claim.initiating_human_subject_id = capability_row.initiating_human_subject_id
290
+ AND claim.extraction_method = 'task-note-promotion-v1'
291
+ AND claim.extraction_metadata = pg_catalog.jsonb_build_object(
292
+ 'taskNoteId', note_row.id,
293
+ 'taskNoteRootSessionId', note_row.root_session_id,
294
+ 'taskNoteVersion', note_row.version,
295
+ 'taskNoteTextHash', note_row.text_hash
296
+ )
297
+ AND fact.scope_kind = 'workspace'
298
+ AND fact.scope_workspace_id = NEW.scope_workspace_id
299
+ AND fact.scope_subject_id IS NULL
300
+ AND fact.object_kind = 'text'
301
+ AND fact.object_entity_id IS NULL
302
+ AND fact.object_value = pg_catalog.to_jsonb(note_row.text)
303
+ AND fact.actor_kind = NEW.actor_kind
304
+ AND fact.actor_subject_id = capability_row.actor_subject_id
305
+ AND fact.initiating_human_subject_id = capability_row.initiating_human_subject_id
306
+ ) THEN
307
+ RAISE EXCEPTION 'Task-note Knowledge evidence claim/fact is outside the admitted promotion lineage'
308
+ USING ERRCODE = '42501';
309
+ END IF;
310
+ DELETE FROM task_note_knowledge_promotion_capabilities capability
311
+ WHERE capability.backend_pid = capability_row.backend_pid
312
+ AND capability.transaction_id = capability_row.transaction_id
313
+ AND capability.capability_id = capability_row.capability_id;
314
+ PERFORM pg_catalog.set_config('opengeni.task_note_knowledge_promotion_capability', '', true);
315
+ RETURN NEW;
316
+ END;
317
+ $$;
318
+
319
+ CREATE TRIGGER knowledge_claim_evidence_15_validate_task_note
320
+ BEFORE INSERT ON "knowledge_claim_evidence"
321
+ FOR EACH ROW EXECUTE FUNCTION validate_task_note_knowledge_evidence();
322
+
323
+ CREATE OR REPLACE FUNCTION resolve_task_note_knowledge_promotion_source(
324
+ p_account_id uuid,
325
+ p_workspace_id uuid,
326
+ p_session_id uuid,
327
+ p_turn_id uuid,
328
+ p_attempt_id uuid,
329
+ p_execution_generation integer,
330
+ p_note_id uuid,
331
+ p_expected_note_version integer,
332
+ p_evidence_operation_id text,
333
+ p_claim_operation_id text,
334
+ p_actor_subject_id text
335
+ ) RETURNS TABLE (
336
+ note_id uuid,
337
+ root_session_id uuid,
338
+ note_version integer,
339
+ note_text text,
340
+ note_text_hash text,
341
+ note_created_at timestamptz,
342
+ initiating_human_subject_id text
343
+ )
344
+ LANGUAGE plpgsql
345
+ SECURITY DEFINER
346
+ SET search_path FROM CURRENT
347
+ AS $$
348
+ DECLARE
349
+ authority record;
350
+ note_row task_notes%ROWTYPE;
351
+ learning_policy_snapshot_id uuid;
352
+ effective_learning_mode text;
353
+ previous_subject_id text := pg_catalog.current_setting('opengeni.subject_id', true);
354
+ previous_initiating_human_subject_id text := pg_catalog.current_setting(
355
+ 'opengeni.initiating_human_subject_id', true
356
+ );
357
+ write_capability_id uuid := pg_catalog.gen_random_uuid();
358
+ previous_write_capability text := pg_catalog.current_setting(
359
+ 'opengeni.task_note_knowledge_promotion_capability', true
360
+ );
361
+ BEGIN
362
+ IF p_note_id IS NULL
363
+ OR p_expected_note_version IS DISTINCT FROM 1
364
+ OR p_evidence_operation_id IS NULL
365
+ OR p_claim_operation_id IS NULL
366
+ OR length(btrim(coalesce(p_actor_subject_id, ''))) NOT BETWEEN 1 AND 1024
367
+ THEN
368
+ RAISE EXCEPTION 'Task-note promotion requires exact active version one'
369
+ USING ERRCODE = '23514';
370
+ END IF;
371
+
372
+ SELECT * INTO authority
373
+ FROM resolve_task_note_attempt_authority(
374
+ p_account_id, p_workspace_id, p_session_id, p_turn_id,
375
+ p_attempt_id, p_execution_generation
376
+ );
377
+ IF authority.initiating_human_subject_id IS NULL THEN
378
+ RAISE EXCEPTION 'Task-note promotion requires an immutable initiating human'
379
+ USING ERRCODE = '42501';
380
+ END IF;
381
+
382
+ SELECT snapshot.id,
383
+ coalesce(
384
+ (
385
+ SELECT override.value->>'mode'
386
+ FROM pg_catalog.jsonb_array_elements(snapshot.source_overrides) override(value)
387
+ WHERE override.value->>'kind' = 'task-note'
388
+ AND override.value->>'id' = p_note_id::text
389
+ LIMIT 1
390
+ ),
391
+ snapshot.workspace_mode
392
+ )
393
+ INTO learning_policy_snapshot_id, effective_learning_mode
394
+ FROM workspace_learning_policy_snapshots snapshot
395
+ WHERE snapshot.account_id = p_account_id
396
+ AND snapshot.workspace_id = p_workspace_id
397
+ AND snapshot.session_id = p_session_id
398
+ AND snapshot.turn_id = p_turn_id
399
+ AND snapshot.attempt_id = p_attempt_id
400
+ AND snapshot.execution_generation = p_execution_generation;
401
+ IF learning_policy_snapshot_id IS NULL
402
+ OR effective_learning_mode NOT IN ('suggest', 'automatic')
403
+ THEN
404
+ RAISE EXCEPTION 'Task-note promotion is disabled by the exact learning-policy snapshot'
405
+ USING ERRCODE = '42501';
406
+ END IF;
407
+
408
+ PERFORM pg_catalog.set_config(
409
+ 'opengeni.subject_id', authority.initiating_human_subject_id, true
410
+ );
411
+ PERFORM pg_catalog.set_config(
412
+ 'opengeni.initiating_human_subject_id', authority.initiating_human_subject_id, true
413
+ );
414
+ SELECT note.* INTO note_row
415
+ FROM task_notes note
416
+ WHERE note.account_id = p_account_id
417
+ AND note.workspace_id = p_workspace_id
418
+ AND note.root_session_id = authority.root_session_id
419
+ AND note.id = p_note_id
420
+ AND note.status = 'active'
421
+ AND note.version = p_expected_note_version
422
+ AND note.expires_at > statement_timestamp()
423
+ FOR SHARE;
424
+
425
+ PERFORM pg_catalog.set_config(
426
+ 'opengeni.subject_id', coalesce(previous_subject_id, ''), true
427
+ );
428
+ PERFORM pg_catalog.set_config(
429
+ 'opengeni.initiating_human_subject_id',
430
+ coalesce(previous_initiating_human_subject_id, ''), true
431
+ );
432
+ IF note_row.id IS NULL THEN
433
+ RAISE EXCEPTION 'Task note is unavailable, archived, expired, or outside this root tree'
434
+ USING ERRCODE = '42501';
435
+ END IF;
436
+
437
+ INSERT INTO task_note_knowledge_promotion_capabilities (
438
+ backend_pid, transaction_id, capability_id,
439
+ account_id, workspace_id, note_id, root_session_id, note_version,
440
+ note_text_hash, evidence_operation_id, claim_operation_id,
441
+ actor_subject_id, initiating_human_subject_id, learning_policy_snapshot_id
442
+ ) VALUES (
443
+ pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), write_capability_id,
444
+ p_account_id, p_workspace_id, note_row.id, note_row.root_session_id, note_row.version,
445
+ note_row.text_hash, p_evidence_operation_id, p_claim_operation_id,
446
+ p_actor_subject_id, authority.initiating_human_subject_id, learning_policy_snapshot_id
447
+ );
448
+ PERFORM pg_catalog.set_config(
449
+ 'opengeni.task_note_knowledge_promotion_capability', write_capability_id::text, true
450
+ );
451
+
452
+ RETURN QUERY SELECT
453
+ note_row.id,
454
+ note_row.root_session_id,
455
+ note_row.version,
456
+ note_row.text,
457
+ note_row.text_hash,
458
+ note_row.created_at,
459
+ authority.initiating_human_subject_id;
460
+ EXCEPTION WHEN OTHERS THEN
461
+ DELETE FROM task_note_knowledge_promotion_capabilities capability
462
+ WHERE capability.backend_pid = pg_catalog.pg_backend_pid()
463
+ AND capability.transaction_id = pg_catalog.pg_current_xact_id()
464
+ AND capability.capability_id = write_capability_id;
465
+ PERFORM pg_catalog.set_config(
466
+ 'opengeni.task_note_knowledge_promotion_capability',
467
+ coalesce(previous_write_capability, ''), true
468
+ );
469
+ PERFORM pg_catalog.set_config(
470
+ 'opengeni.subject_id', coalesce(previous_subject_id, ''), true
471
+ );
472
+ PERFORM pg_catalog.set_config(
473
+ 'opengeni.initiating_human_subject_id',
474
+ coalesce(previous_initiating_human_subject_id, ''), true
475
+ );
476
+ RAISE;
477
+ END;
478
+ $$;
479
+
480
+ CREATE OR REPLACE FUNCTION replace_task_note_for_attempt(
481
+ p_account_id uuid,
482
+ p_workspace_id uuid,
483
+ p_session_id uuid,
484
+ p_turn_id uuid,
485
+ p_attempt_id uuid,
486
+ p_execution_generation integer,
487
+ p_operation_id uuid,
488
+ p_archive_operation_id uuid,
489
+ p_create_operation_id uuid,
490
+ p_replaced_note_id uuid,
491
+ p_expected_replaced_version integer,
492
+ p_replacement_kind text,
493
+ p_replacement_text text,
494
+ p_replacement_expires_in_days integer,
495
+ p_reason text
496
+ ) RETURNS TABLE (
497
+ operation_id uuid,
498
+ input_hash text,
499
+ replaced_note_id uuid,
500
+ replaced_note_version integer,
501
+ replacement_note_id uuid,
502
+ root_session_id uuid,
503
+ replacement_kind text,
504
+ replacement_text text,
505
+ replacement_status text,
506
+ replacement_version integer,
507
+ replacement_expires_at timestamptz,
508
+ replacement_created_at timestamptz,
509
+ replacement_updated_at timestamptz,
510
+ replacement_archived_at timestamptz,
511
+ replacement_actor_kind text,
512
+ replacement_source_session_id uuid,
513
+ replacement_source_turn_id uuid,
514
+ replayed boolean
515
+ )
516
+ LANGUAGE plpgsql
517
+ SECURITY DEFINER
518
+ SET search_path FROM CURRENT
519
+ AS $$
520
+ DECLARE
521
+ authority record;
522
+ receipt_row task_note_replacement_receipts%ROWTYPE;
523
+ replaced_row task_notes%ROWTYPE;
524
+ replacement_row task_notes%ROWTYPE;
525
+ archived_result record;
526
+ created_result record;
527
+ calculated_replacement_text_hash text;
528
+ calculated_input_hash text;
529
+ BEGIN
530
+ SELECT * INTO STRICT authority FROM resolve_task_note_attempt_authority(
531
+ p_account_id, p_workspace_id, p_session_id, p_turn_id,
532
+ p_attempt_id, p_execution_generation
533
+ );
534
+ IF p_operation_id IS NULL
535
+ OR p_archive_operation_id IS NULL
536
+ OR p_create_operation_id IS NULL
537
+ OR p_operation_id = p_archive_operation_id
538
+ OR p_operation_id = p_create_operation_id
539
+ OR p_archive_operation_id = p_create_operation_id
540
+ OR p_replaced_note_id IS NULL
541
+ OR p_expected_replaced_version IS DISTINCT FROM 1
542
+ OR p_replacement_kind NOT IN ('finding','decision','blocker','ownership','artifact','handoff')
543
+ OR p_replacement_text IS NULL
544
+ OR octet_length(p_replacement_text) NOT BETWEEN 1 AND 4096
545
+ OR p_replacement_text <> btrim(p_replacement_text)
546
+ OR p_replacement_expires_in_days IS NULL
547
+ OR p_replacement_expires_in_days NOT BETWEEN 1 AND 30
548
+ OR p_reason IS NULL
549
+ OR octet_length(p_reason) NOT BETWEEN 1 AND 2048
550
+ OR p_reason <> btrim(p_reason)
551
+ THEN
552
+ RAISE EXCEPTION 'Task-note replacement input is invalid' USING ERRCODE = '22023';
553
+ END IF;
554
+
555
+ calculated_replacement_text_hash := encode(
556
+ sha256(convert_to(p_replacement_text, 'UTF8')), 'hex'
557
+ );
558
+ calculated_input_hash := encode(sha256(convert_to(jsonb_build_object(
559
+ 'accountId', p_account_id,
560
+ 'workspaceId', p_workspace_id,
561
+ 'rootSessionId', authority.root_session_id,
562
+ 'sessionId', p_session_id,
563
+ 'turnId', p_turn_id,
564
+ 'attemptId', p_attempt_id,
565
+ 'executionGeneration', p_execution_generation,
566
+ 'operationId', p_operation_id,
567
+ 'archiveOperationId', p_archive_operation_id,
568
+ 'createOperationId', p_create_operation_id,
569
+ 'replacedNoteId', p_replaced_note_id,
570
+ 'expectedReplacedVersion', p_expected_replaced_version,
571
+ 'replacementKind', p_replacement_kind,
572
+ 'replacementTextHash', calculated_replacement_text_hash,
573
+ 'replacementExpiresInDays', p_replacement_expires_in_days,
574
+ 'reason', p_reason
575
+ )::text, 'UTF8')), 'hex');
576
+
577
+ SELECT receipt.* INTO receipt_row
578
+ FROM task_note_replacement_receipts receipt
579
+ WHERE receipt.workspace_id = p_workspace_id
580
+ AND receipt.operation_id = p_operation_id
581
+ FOR SHARE;
582
+ IF FOUND THEN
583
+ IF receipt_row.account_id IS DISTINCT FROM p_account_id
584
+ OR receipt_row.root_session_id IS DISTINCT FROM authority.root_session_id
585
+ OR receipt_row.input_hash IS DISTINCT FROM calculated_input_hash
586
+ OR receipt_row.replaced_note_id IS DISTINCT FROM p_replaced_note_id
587
+ OR receipt_row.archive_operation_id IS DISTINCT FROM p_archive_operation_id
588
+ OR receipt_row.create_operation_id IS DISTINCT FROM p_create_operation_id
589
+ OR receipt_row.actor_session_id IS DISTINCT FROM p_session_id
590
+ OR receipt_row.actor_turn_id IS DISTINCT FROM p_turn_id
591
+ OR receipt_row.actor_attempt_id IS DISTINCT FROM p_attempt_id
592
+ OR receipt_row.actor_execution_generation IS DISTINCT FROM p_execution_generation
593
+ OR receipt_row.actor_kind IS DISTINCT FROM authority.actor_kind
594
+ OR receipt_row.actor_subject_id IS DISTINCT FROM authority.actor_subject_id
595
+ OR receipt_row.initiating_human_subject_id
596
+ IS DISTINCT FROM authority.initiating_human_subject_id
597
+ THEN
598
+ RAISE EXCEPTION 'Task-note replacement operation conflicts with another input or attempt'
599
+ USING ERRCODE = '23505';
600
+ END IF;
601
+ SELECT note.* INTO STRICT replacement_row
602
+ FROM task_notes note
603
+ WHERE note.workspace_id = p_workspace_id
604
+ AND note.root_session_id = authority.root_session_id
605
+ AND note.id = receipt_row.replacement_note_id;
606
+ replayed := true;
607
+ ELSE
608
+ SELECT note.* INTO replaced_row
609
+ FROM task_notes note
610
+ WHERE note.workspace_id = p_workspace_id
611
+ AND note.root_session_id = authority.root_session_id
612
+ AND note.id = p_replaced_note_id
613
+ FOR UPDATE;
614
+ IF NOT FOUND THEN
615
+ RAISE EXCEPTION 'Task note is unavailable for replacement' USING ERRCODE = 'P0002';
616
+ END IF;
617
+ IF replaced_row.status <> 'active'
618
+ OR replaced_row.version <> p_expected_replaced_version
619
+ OR replaced_row.expires_at <= transaction_timestamp()
620
+ THEN
621
+ RAISE EXCEPTION 'Task-note replacement version or lifecycle conflict'
622
+ USING ERRCODE = '40001';
623
+ END IF;
624
+
625
+ SELECT * INTO STRICT archived_result FROM archive_task_note_for_attempt(
626
+ p_account_id, p_workspace_id, p_session_id, p_turn_id,
627
+ p_attempt_id, p_execution_generation, p_archive_operation_id,
628
+ p_replaced_note_id, p_expected_replaced_version, p_reason
629
+ );
630
+ SELECT * INTO STRICT created_result FROM create_task_note_for_attempt(
631
+ p_account_id, p_workspace_id, p_session_id, p_turn_id,
632
+ p_attempt_id, p_execution_generation, p_create_operation_id,
633
+ p_replacement_kind, p_replacement_text, p_replacement_expires_in_days
634
+ );
635
+ IF archived_result.note_id IS DISTINCT FROM p_replaced_note_id
636
+ OR archived_result.status IS DISTINCT FROM 'archived'
637
+ OR archived_result.version IS DISTINCT FROM 2
638
+ OR created_result.status IS DISTINCT FROM 'active'
639
+ OR created_result.version IS DISTINCT FROM 1
640
+ OR created_result.root_session_id IS DISTINCT FROM authority.root_session_id
641
+ THEN
642
+ RAISE EXCEPTION 'Task-note replacement lifecycle returned an invalid projection'
643
+ USING ERRCODE = '23514';
644
+ END IF;
645
+ SELECT note.* INTO STRICT replacement_row
646
+ FROM task_notes note
647
+ WHERE note.workspace_id = p_workspace_id
648
+ AND note.root_session_id = authority.root_session_id
649
+ AND note.id = created_result.note_id;
650
+
651
+ INSERT INTO task_note_replacement_receipts (
652
+ account_id, workspace_id, root_session_id, operation_id, input_hash,
653
+ replaced_note_id, replaced_note_version, replacement_note_id,
654
+ replacement_note_version, archive_operation_id, create_operation_id,
655
+ actor_kind, actor_subject_id, initiating_human_subject_id,
656
+ actor_session_id, actor_turn_id, actor_attempt_id, actor_execution_generation
657
+ ) VALUES (
658
+ p_account_id, p_workspace_id, authority.root_session_id,
659
+ p_operation_id, calculated_input_hash, p_replaced_note_id, 2,
660
+ replacement_row.id, 1, p_archive_operation_id, p_create_operation_id,
661
+ authority.actor_kind, authority.actor_subject_id,
662
+ authority.initiating_human_subject_id, p_session_id, p_turn_id,
663
+ p_attempt_id, p_execution_generation
664
+ ) RETURNING * INTO STRICT receipt_row;
665
+ replayed := false;
666
+ END IF;
667
+
668
+ operation_id := receipt_row.operation_id;
669
+ input_hash := receipt_row.input_hash;
670
+ replaced_note_id := receipt_row.replaced_note_id;
671
+ replaced_note_version := receipt_row.replaced_note_version;
672
+ replacement_note_id := replacement_row.id;
673
+ root_session_id := replacement_row.root_session_id;
674
+ replacement_kind := replacement_row.kind;
675
+ replacement_text := replacement_row.text;
676
+ replacement_status := replacement_row.status;
677
+ replacement_version := replacement_row.version;
678
+ replacement_expires_at := replacement_row.expires_at;
679
+ replacement_created_at := replacement_row.created_at;
680
+ replacement_updated_at := replacement_row.updated_at;
681
+ replacement_archived_at := replacement_row.archived_at;
682
+ replacement_actor_kind := replacement_row.created_by_actor_kind;
683
+ replacement_source_session_id := replacement_row.created_by_session_id;
684
+ replacement_source_turn_id := replacement_row.created_by_turn_id;
685
+ RETURN NEXT;
686
+ END;
687
+ $$;
688
+
689
+ DO $function_access$
690
+ DECLARE
691
+ data_schema text := current_schema();
692
+ required_routine text;
693
+ BEGIN
694
+ -- Migration 0239 predates the explicit pg_temp-last posture. Its lifecycle
695
+ -- functions are invoked by both 0260 entry points, while their RLS path also
696
+ -- invokes the 0225 session-reference/private-actor helpers. A caller with
697
+ -- database TEMP privilege must not be able to shadow any authority relation
698
+ -- reached through that nested closure. Fail closed if the exact predecessor
699
+ -- signatures are absent, then repair only their persisted search paths.
700
+ FOREACH required_routine IN ARRAY ARRAY[
701
+ 'guard_task_note_mutation()',
702
+ 'guard_task_note_event_mutation()',
703
+ 'resolve_task_note_attempt_authority(uuid,uuid,uuid,uuid,uuid,integer)',
704
+ 'create_task_note_for_attempt(uuid,uuid,uuid,uuid,uuid,integer,uuid,text,text,integer)',
705
+ 'archive_task_note_for_attempt(uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,integer,text)',
706
+ 'list_task_notes_for_attempt(uuid,uuid,uuid,uuid,uuid,integer,boolean,integer)',
707
+ 'session_private_actor_visible(uuid,uuid,uuid,text)',
708
+ 'session_reference_visible(uuid,uuid,uuid)'
709
+ ]
710
+ LOOP
711
+ IF pg_catalog.to_regprocedure(
712
+ pg_catalog.format('%I.%s', data_schema, required_routine)
713
+ ) IS NULL THEN
714
+ RAISE EXCEPTION 'Task-note authority closure routine is missing: %.%',
715
+ data_schema, required_routine
716
+ USING ERRCODE = '42883';
717
+ END IF;
718
+ END LOOP;
719
+
720
+ EXECUTE format(
721
+ 'ALTER FUNCTION %I.guard_task_note_mutation() '
722
+ || 'SET search_path = pg_catalog, %I, pg_temp',
723
+ data_schema, data_schema
724
+ );
725
+ EXECUTE format(
726
+ 'ALTER FUNCTION %I.guard_task_note_event_mutation() '
727
+ || 'SET search_path = pg_catalog, %I, pg_temp',
728
+ data_schema, data_schema
729
+ );
730
+ EXECUTE format(
731
+ 'ALTER FUNCTION %I.resolve_task_note_attempt_authority('
732
+ || 'uuid,uuid,uuid,uuid,uuid,integer) '
733
+ || 'SET search_path = pg_catalog, %I, pg_temp',
734
+ data_schema, data_schema
735
+ );
736
+ EXECUTE format(
737
+ 'ALTER FUNCTION %I.create_task_note_for_attempt('
738
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,text,text,integer) '
739
+ || 'SET search_path = pg_catalog, %I, pg_temp',
740
+ data_schema, data_schema
741
+ );
742
+ EXECUTE format(
743
+ 'ALTER FUNCTION %I.archive_task_note_for_attempt('
744
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,integer,text) '
745
+ || 'SET search_path = pg_catalog, %I, pg_temp',
746
+ data_schema, data_schema
747
+ );
748
+ EXECUTE format(
749
+ 'ALTER FUNCTION %I.list_task_notes_for_attempt('
750
+ || 'uuid,uuid,uuid,uuid,uuid,integer,boolean,integer) '
751
+ || 'SET search_path = pg_catalog, %I, pg_temp',
752
+ data_schema, data_schema
753
+ );
754
+ EXECUTE format(
755
+ 'ALTER FUNCTION %I.session_private_actor_visible(uuid,uuid,uuid,text) '
756
+ || 'SET search_path = pg_catalog, %I, pg_temp',
757
+ data_schema, data_schema
758
+ );
759
+ EXECUTE format(
760
+ 'ALTER FUNCTION %I.session_reference_visible(uuid,uuid,uuid) '
761
+ || 'SET search_path = pg_catalog, %I, pg_temp',
762
+ data_schema, data_schema
763
+ );
764
+
765
+ EXECUTE format(
766
+ 'REVOKE ALL ON FUNCTION %I.validate_task_note_knowledge_evidence() FROM PUBLIC',
767
+ data_schema
768
+ );
769
+ EXECUTE format(
770
+ 'REVOKE ALL ON FUNCTION %I.reject_task_note_replacement_receipt_mutation() FROM PUBLIC',
771
+ data_schema
772
+ );
773
+ EXECUTE format(
774
+ 'REVOKE ALL ON FUNCTION %I.replace_task_note_for_attempt('
775
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid,uuid,integer,text,text,integer,text) '
776
+ || 'FROM PUBLIC',
777
+ data_schema
778
+ );
779
+ EXECUTE format(
780
+ 'REVOKE ALL ON FUNCTION %I.resolve_task_note_knowledge_promotion_source('
781
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,integer,text,text,text) FROM PUBLIC',
782
+ data_schema
783
+ );
784
+ EXECUTE format(
785
+ 'ALTER FUNCTION %I.validate_task_note_knowledge_evidence() '
786
+ || 'SET search_path = pg_catalog, %I, pg_temp',
787
+ data_schema, data_schema
788
+ );
789
+ EXECUTE format(
790
+ 'ALTER FUNCTION %I.reject_task_note_replacement_receipt_mutation() '
791
+ || 'SET search_path = pg_catalog, %I, pg_temp',
792
+ data_schema, data_schema
793
+ );
794
+ EXECUTE format(
795
+ 'ALTER FUNCTION %I.replace_task_note_for_attempt('
796
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid,uuid,integer,text,text,integer,text) '
797
+ || 'SET search_path = pg_catalog, %I, pg_temp',
798
+ data_schema, data_schema
799
+ );
800
+ EXECUTE format(
801
+ 'ALTER FUNCTION %I.resolve_task_note_knowledge_promotion_source('
802
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,integer,text,text,text) '
803
+ || 'SET search_path = pg_catalog, %I, pg_temp',
804
+ data_schema, data_schema
805
+ );
806
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
807
+ EXECUTE format(
808
+ 'GRANT EXECUTE ON FUNCTION %I.resolve_task_note_knowledge_promotion_source('
809
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,integer,text,text,text) TO opengeni_app',
810
+ data_schema
811
+ );
812
+ EXECUTE format(
813
+ 'GRANT EXECUTE ON FUNCTION %I.replace_task_note_for_attempt('
814
+ || 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid,uuid,integer,text,text,integer,text) '
815
+ || 'TO opengeni_app',
816
+ data_schema
817
+ );
818
+ END IF;
819
+ END
820
+ $function_access$;