@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,309 @@
1
+ import {
2
+ COMPANY_BRAIN_INSPECTOR_DEFAULT_LIMIT,
3
+ COMPANY_BRAIN_INSPECTOR_MAX_LIMIT,
4
+ COMPANY_BRAIN_PROPOSAL_CONTENT_MAX_BYTES,
5
+ COMPANY_BRAIN_PROPOSAL_RESPONSE_MAX_BYTES,
6
+ type CompanyBrainKnowledgeProposal,
7
+ type CompanyBrainKnowledgeProposalPage,
8
+ } from "@opengeni/contracts";
9
+ import { and, asc, desc, eq, inArray, notInArray } from "drizzle-orm";
10
+
11
+ import type { Database } from "./database";
12
+ import { withWorkspaceSubjectRls } from "./database";
13
+ import * as schema from "./schema";
14
+
15
+ export const COMPANY_BRAIN_PREFERENCE_MAX_COUNT = 100;
16
+ export const COMPANY_BRAIN_PREFERENCE_MAX_REVISIONS = 256;
17
+ export const COMPANY_BRAIN_PREFERENCE_MAX_CONTENT_BYTES = 2 * 1024 * 1024;
18
+
19
+ export type CompanyBrainPreferenceGuidanceRow = {
20
+ preferenceId: string;
21
+ stableKey: string;
22
+ scope: string;
23
+ status: string;
24
+ supersededByPreferenceId: string | null;
25
+ revisionId: string;
26
+ revision: number;
27
+ title: string;
28
+ description: string;
29
+ content: string;
30
+ contentHash: string;
31
+ provenanceSource: string;
32
+ provenanceSourceId: string | null;
33
+ trust: string;
34
+ correctsRevisionId: string | null;
35
+ expiresAt: Date | null;
36
+ createdAt: Date;
37
+ active: boolean;
38
+ };
39
+
40
+ export type CompanyBrainPreferenceGuidancePage = {
41
+ rows: CompanyBrainPreferenceGuidanceRow[];
42
+ preferenceCountTruncated: boolean;
43
+ revisionCountTruncated: boolean;
44
+ contentBytesTruncated: boolean;
45
+ };
46
+
47
+ function boundedUtf8Projection(
48
+ value: string,
49
+ maxBytes: number,
50
+ ): {
51
+ value: string;
52
+ originalBytes: number;
53
+ truncated: boolean;
54
+ } {
55
+ const originalBytes = Buffer.byteLength(value, "utf8");
56
+ if (originalBytes <= maxBytes) return { value, originalBytes, truncated: false };
57
+ const marker = `\n[truncated; original UTF-8 bytes=${originalBytes}]`;
58
+ const budget = Math.max(0, maxBytes - Buffer.byteLength(marker, "utf8"));
59
+ let low = 0;
60
+ let high = value.length;
61
+ while (low < high) {
62
+ const midpoint = Math.ceil((low + high) / 2);
63
+ if (Buffer.byteLength(value.slice(0, midpoint), "utf8") <= budget) low = midpoint;
64
+ else high = midpoint - 1;
65
+ }
66
+ return { value: value.slice(0, low) + marker, originalBytes, truncated: true };
67
+ }
68
+
69
+ function proposalPageBytes(page: CompanyBrainKnowledgeProposalPage): number {
70
+ return Buffer.byteLength(JSON.stringify(page), "utf8");
71
+ }
72
+
73
+ function finalizeProposalPage(
74
+ proposals: CompanyBrainKnowledgeProposal[],
75
+ truncatedForCount: boolean,
76
+ truncatedForResponseBytes: boolean,
77
+ ): CompanyBrainKnowledgeProposalPage {
78
+ const page: CompanyBrainKnowledgeProposalPage = {
79
+ proposals,
80
+ truncatedForCount,
81
+ truncatedForResponseBytes,
82
+ responseBytes: 0,
83
+ };
84
+ for (let pass = 0; pass < 3; pass += 1) page.responseBytes = proposalPageBytes(page);
85
+ return page;
86
+ }
87
+
88
+ /**
89
+ * Read-only review projection over governed Knowledge change proposals. RLS
90
+ * filters scope before rows enter this independent item/aggregate byte bound.
91
+ */
92
+ export async function listCompanyBrainKnowledgeProposals(
93
+ db: Database,
94
+ input: { workspaceId: string; subjectId: string; limit?: number },
95
+ ): Promise<CompanyBrainKnowledgeProposalPage> {
96
+ const limit = input.limit ?? COMPANY_BRAIN_INSPECTOR_DEFAULT_LIMIT;
97
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > COMPANY_BRAIN_INSPECTOR_MAX_LIMIT) {
98
+ throw new Error("Company Brain proposal limit must be between 1 and 50");
99
+ }
100
+ return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
101
+ const rows = await scopedDb
102
+ .select()
103
+ .from(schema.knowledgeChangeProposals)
104
+ .where(eq(schema.knowledgeChangeProposals.status, "proposed"))
105
+ .orderBy(
106
+ desc(schema.knowledgeChangeProposals.createdAt),
107
+ desc(schema.knowledgeChangeProposals.id),
108
+ )
109
+ .limit(limit + 1);
110
+ const truncatedForCount = rows.length > limit;
111
+ const selected: CompanyBrainKnowledgeProposal[] = [];
112
+ let truncatedForResponseBytes = false;
113
+ for (const row of rows.slice(0, limit)) {
114
+ const content = boundedUtf8Projection(row.content, COMPANY_BRAIN_PROPOSAL_CONTENT_MAX_BYTES);
115
+ const projected: CompanyBrainKnowledgeProposal = {
116
+ id: row.id,
117
+ authority: { kind: row.scopeKind as CompanyBrainKnowledgeProposal["authority"]["kind"] },
118
+ targetKind: row.targetKind as CompanyBrainKnowledgeProposal["targetKind"],
119
+ targetScope: row.targetScope,
120
+ targetKey: row.targetKey,
121
+ content: content.value,
122
+ contentHash: row.contentHash,
123
+ source: { claimId: row.claimId, evidenceId: row.evidenceId },
124
+ status: "proposed",
125
+ createdAt: row.createdAt.toISOString(),
126
+ projection: {
127
+ truncated: content.truncated,
128
+ originalContentUtf8Bytes: content.originalBytes,
129
+ },
130
+ };
131
+ const candidate = finalizeProposalPage(
132
+ [...selected, projected],
133
+ truncatedForCount,
134
+ truncatedForResponseBytes,
135
+ );
136
+ if (candidate.responseBytes > COMPANY_BRAIN_PROPOSAL_RESPONSE_MAX_BYTES) {
137
+ truncatedForResponseBytes = true;
138
+ continue;
139
+ }
140
+ selected.push(projected);
141
+ }
142
+ const page = finalizeProposalPage(selected, truncatedForCount, truncatedForResponseBytes);
143
+ if (page.responseBytes > COMPANY_BRAIN_PROPOSAL_RESPONSE_MAX_BYTES) {
144
+ throw new Error("Company Brain proposal projection exceeded its response boundary");
145
+ }
146
+ return page;
147
+ });
148
+ }
149
+
150
+ export async function listActivatedCompanyBrainPolicyRevisionIds(
151
+ db: Database,
152
+ input: { workspaceId: string; subjectId: string; revisionIds: string[] },
153
+ ): Promise<string[]> {
154
+ const revisionIds = [...new Set(input.revisionIds)].sort();
155
+ if (revisionIds.length === 0) return [];
156
+ return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
157
+ const rows = await scopedDb
158
+ .select({ revisionId: schema.workspaceInstructionPolicyActivationEvents.newRevisionId })
159
+ .from(schema.workspaceInstructionPolicyActivationEvents)
160
+ .where(
161
+ and(
162
+ eq(schema.workspaceInstructionPolicyActivationEvents.workspaceId, input.workspaceId),
163
+ inArray(schema.workspaceInstructionPolicyActivationEvents.newRevisionId, revisionIds),
164
+ ),
165
+ );
166
+ return [
167
+ ...new Set(rows.map((row) => row.revisionId).filter((id): id is string => id !== null)),
168
+ ].sort();
169
+ });
170
+ }
171
+
172
+ /**
173
+ * Read bounded full guidance only after applying the existing subject-aware
174
+ * Preference Registry RLS context. Personal rows for another subject never
175
+ * enter the candidate set, and relationship targets are filtered by the API
176
+ * projection against this authorized page.
177
+ */
178
+ export async function listCompanyBrainPreferenceGuidance(
179
+ db: Database,
180
+ input: { workspaceId: string; subjectId: string },
181
+ ): Promise<CompanyBrainPreferenceGuidancePage> {
182
+ return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
183
+ const preferences = await scopedDb
184
+ .select()
185
+ .from(schema.preferenceRegistryPreferences)
186
+ .orderBy(
187
+ asc(schema.preferenceRegistryPreferences.scope),
188
+ asc(schema.preferenceRegistryPreferences.stableKey),
189
+ asc(schema.preferenceRegistryPreferences.id),
190
+ )
191
+ .limit(COMPANY_BRAIN_PREFERENCE_MAX_COUNT + 1);
192
+
193
+ const preferenceCountTruncated = preferences.length > COMPANY_BRAIN_PREFERENCE_MAX_COUNT;
194
+ const boundedPreferences = preferences.slice(0, COMPANY_BRAIN_PREFERENCE_MAX_COUNT);
195
+ if (boundedPreferences.length === 0) {
196
+ return {
197
+ rows: [],
198
+ preferenceCountTruncated,
199
+ revisionCountTruncated: false,
200
+ contentBytesTruncated: false,
201
+ };
202
+ }
203
+
204
+ const preferenceById = new Map(
205
+ boundedPreferences.map((preference) => [preference.id, preference] as const),
206
+ );
207
+ const preferenceIds = boundedPreferences.map((preference) => preference.id);
208
+ const activeRevisionIds = [
209
+ ...new Set(
210
+ boundedPreferences.flatMap((preference) =>
211
+ preference.activeRevisionId ? [preference.activeRevisionId] : [],
212
+ ),
213
+ ),
214
+ ].sort();
215
+ const activeRevisions =
216
+ activeRevisionIds.length === 0
217
+ ? []
218
+ : await scopedDb
219
+ .select()
220
+ .from(schema.preferenceRegistryRevisions)
221
+ .where(inArray(schema.preferenceRegistryRevisions.id, activeRevisionIds))
222
+ .orderBy(
223
+ asc(schema.preferenceRegistryRevisions.preferenceId),
224
+ desc(schema.preferenceRegistryRevisions.revision),
225
+ asc(schema.preferenceRegistryRevisions.id),
226
+ );
227
+ const historicalLimit = Math.max(
228
+ 0,
229
+ COMPANY_BRAIN_PREFERENCE_MAX_REVISIONS - activeRevisions.length,
230
+ );
231
+ const historicalRevisions = await scopedDb
232
+ .select()
233
+ .from(schema.preferenceRegistryRevisions)
234
+ .where(
235
+ and(
236
+ inArray(schema.preferenceRegistryRevisions.preferenceId, preferenceIds),
237
+ activeRevisionIds.length > 0
238
+ ? notInArray(schema.preferenceRegistryRevisions.id, activeRevisionIds)
239
+ : undefined,
240
+ ),
241
+ )
242
+ .orderBy(
243
+ asc(schema.preferenceRegistryRevisions.preferenceId),
244
+ desc(schema.preferenceRegistryRevisions.revision),
245
+ asc(schema.preferenceRegistryRevisions.id),
246
+ )
247
+ .limit(historicalLimit + 1);
248
+ const revisionCountTruncated = historicalRevisions.length > historicalLimit;
249
+ const revisions = [...activeRevisions, ...historicalRevisions.slice(0, historicalLimit)];
250
+
251
+ // Active bodies are the most important portable truth. Put them first,
252
+ // then retain newest authorized history under independent count/byte caps.
253
+ const ordered = [...revisions].sort((left, right) => {
254
+ const leftPreference = preferenceById.get(left.preferenceId)!;
255
+ const rightPreference = preferenceById.get(right.preferenceId)!;
256
+ const leftActive = left.id === leftPreference.activeRevisionId ? 0 : 1;
257
+ const rightActive = right.id === rightPreference.activeRevisionId ? 0 : 1;
258
+ if (leftActive !== rightActive) return leftActive - rightActive;
259
+ const preferenceOrder = left.preferenceId.localeCompare(right.preferenceId);
260
+ if (preferenceOrder !== 0) return preferenceOrder;
261
+ if (left.revision !== right.revision) return right.revision - left.revision;
262
+ return left.id.localeCompare(right.id);
263
+ });
264
+
265
+ const rows: CompanyBrainPreferenceGuidanceRow[] = [];
266
+ let contentBytes = 0;
267
+ let contentBytesTruncated = false;
268
+ for (const revision of ordered) {
269
+ const nextBytes = new TextEncoder().encode(revision.content).byteLength;
270
+ if (contentBytes + nextBytes > COMPANY_BRAIN_PREFERENCE_MAX_CONTENT_BYTES) {
271
+ contentBytesTruncated = true;
272
+ continue;
273
+ }
274
+ const preference = preferenceById.get(revision.preferenceId);
275
+ if (!preference) continue;
276
+ rows.push({
277
+ preferenceId: preference.id,
278
+ stableKey: preference.stableKey,
279
+ scope: preference.scope,
280
+ status: preference.status,
281
+ supersededByPreferenceId: preference.supersededByPreferenceId,
282
+ revisionId: revision.id,
283
+ revision: revision.revision,
284
+ title: revision.title,
285
+ description: revision.description,
286
+ content: revision.content,
287
+ contentHash: revision.contentHash,
288
+ provenanceSource: revision.provenanceSource,
289
+ provenanceSourceId: revision.provenanceSourceId,
290
+ trust: revision.trust,
291
+ correctsRevisionId: revision.correctsRevisionId,
292
+ expiresAt: revision.expiresAt,
293
+ createdAt: revision.createdAt,
294
+ active: revision.id === preference.activeRevisionId,
295
+ });
296
+ contentBytes += nextBytes;
297
+ }
298
+
299
+ if (rows.length < ordered.length) {
300
+ contentBytesTruncated = true;
301
+ }
302
+ return {
303
+ rows,
304
+ preferenceCountTruncated,
305
+ revisionCountTruncated,
306
+ contentBytesTruncated,
307
+ };
308
+ });
309
+ }
@@ -0,0 +1,225 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ CompanyProfileAgentAttempt,
4
+ CompanyProfileAgentConfirmRequest,
5
+ CompanyProfileAgentConfirmationReceipt,
6
+ CompanyProfileAgentHumanInputPrompt,
7
+ CompanyProfileAgentProposalReceipt,
8
+ CompanyProfileAgentProposalRequest,
9
+ CompanyProfileContent,
10
+ type CompanyProfileAgentAttempt as CompanyProfileAgentAttemptType,
11
+ type CompanyProfileAgentConfirmRequest as CompanyProfileAgentConfirmRequestType,
12
+ type CompanyProfileAgentConfirmationReceipt as CompanyProfileAgentConfirmationReceiptType,
13
+ type CompanyProfileAgentProposalReceipt as CompanyProfileAgentProposalReceiptType,
14
+ type CompanyProfileAgentProposalRequest as CompanyProfileAgentProposalRequestType,
15
+ } from "@opengeni/contracts";
16
+ import { sql } from "drizzle-orm";
17
+ import { rawRows, withRlsContext, withSessionRlsActorContext, type Database } from "./database";
18
+ import {
19
+ getCompanyProfileActivationEvent,
20
+ getCompanyProfileRevision,
21
+ listCompanyProfile,
22
+ } from "./company-profile";
23
+ import { nestedPostgresSqlState } from "./persistence-errors";
24
+
25
+ export class CompanyProfileAgentAdminError extends Error {
26
+ readonly name = "CompanyProfileAgentAdminError";
27
+
28
+ constructor(
29
+ readonly code:
30
+ | "authority_unavailable"
31
+ | "confirmation_unavailable"
32
+ | "profile_conflict"
33
+ | "operation_reused"
34
+ | "invalid_operation",
35
+ message: string,
36
+ options?: ErrorOptions,
37
+ ) {
38
+ super(message, options);
39
+ }
40
+ }
41
+
42
+ function canonicalProfileJson(value: unknown): string {
43
+ const profile = CompanyProfileContent.parse(value);
44
+ return JSON.stringify({
45
+ identity: profile.identity,
46
+ mission: profile.mission,
47
+ products: profile.products.map(({ key, content }) => ({ key, content })),
48
+ customers: profile.customers.map(({ key, content }) => ({ key, content })),
49
+ goals: profile.goals.map(({ key, content }) => ({ key, content })),
50
+ constraints: profile.constraints.map(({ key, content }) => ({ key, content })),
51
+ });
52
+ }
53
+
54
+ function translate(error: unknown, stage: "propose" | "confirm"): never {
55
+ const state = nestedPostgresSqlState(error);
56
+ if (state === "42501") {
57
+ throw new CompanyProfileAgentAdminError(
58
+ stage === "confirm" ? "confirmation_unavailable" : "authority_unavailable",
59
+ stage === "confirm"
60
+ ? "The bound organization-owner confirmation is unavailable or no longer valid."
61
+ : "An exact live turn initiated by the active organization owner is required.",
62
+ { cause: error },
63
+ );
64
+ }
65
+ if (state === "40001") {
66
+ throw new CompanyProfileAgentAdminError(
67
+ "profile_conflict",
68
+ "The organization company profile changed after this proposal was prepared. Create a new proposal against the current profile.",
69
+ { cause: error },
70
+ );
71
+ }
72
+ if (state === "P1851" || state === "23505") {
73
+ throw new CompanyProfileAgentAdminError(
74
+ "operation_reused",
75
+ "The company-profile operation id was already used for different input.",
76
+ { cause: error },
77
+ );
78
+ }
79
+ if (state === "22023" || state === "23514" || state === "55000") {
80
+ throw new CompanyProfileAgentAdminError(
81
+ "invalid_operation",
82
+ "The company-profile administration request is invalid or no longer eligible.",
83
+ { cause: error },
84
+ );
85
+ }
86
+ throw error;
87
+ }
88
+
89
+ async function withAgentAttemptContext<T>(
90
+ db: Database,
91
+ attempt: CompanyProfileAgentAttemptType,
92
+ fn: (scoped: Database) => Promise<T>,
93
+ ): Promise<T> {
94
+ return await withSessionRlsActorContext({ subjectId: attempt.agentSubjectId }, async () =>
95
+ withRlsContext(
96
+ db,
97
+ { accountId: attempt.accountId, workspaceId: attempt.workspaceId },
98
+ async (scoped) => {
99
+ await scoped.execute(
100
+ sql`select set_config('opengeni.principal_kind', 'agent_attempt', true)`,
101
+ );
102
+ return await fn(scoped);
103
+ },
104
+ ),
105
+ );
106
+ }
107
+
108
+ export async function proposeCompanyProfileForAgent(
109
+ db: Database,
110
+ raw: { attempt: CompanyProfileAgentAttemptType; request: CompanyProfileAgentProposalRequestType },
111
+ ): Promise<CompanyProfileAgentProposalReceiptType> {
112
+ const attempt = CompanyProfileAgentAttempt.parse(raw.attempt);
113
+ const request = CompanyProfileAgentProposalRequest.parse(raw.request);
114
+ const contentJson = canonicalProfileJson(request.profile);
115
+ const contentHash = createHash("sha256").update(contentJson, "utf8").digest("hex");
116
+ try {
117
+ const result = await withAgentAttemptContext(db, attempt, async (scoped) => {
118
+ const [row] = await rawRows<{
119
+ receipt_id: string;
120
+ revision_id: string;
121
+ human_input: unknown;
122
+ replayed: boolean;
123
+ }>(
124
+ scoped,
125
+ sql`select * from propose_company_profile_for_attempt(
126
+ ${attempt.accountId}::uuid,
127
+ ${attempt.workspaceId}::uuid,
128
+ ${attempt.sessionId}::uuid,
129
+ ${attempt.turnId}::uuid,
130
+ ${attempt.attemptId}::uuid,
131
+ ${attempt.executionGeneration},
132
+ ${request.operationId}::uuid,
133
+ ${contentJson},
134
+ ${contentHash},
135
+ ${request.reason}
136
+ )`,
137
+ );
138
+ if (!row) throw new Error("Company-profile proposal returned no receipt");
139
+ return row;
140
+ });
141
+ const revision = await getCompanyProfileRevision(db, {
142
+ accountId: attempt.accountId,
143
+ workspaceId: attempt.workspaceId,
144
+ revisionId: result.revision_id,
145
+ });
146
+ return CompanyProfileAgentProposalReceipt.parse({
147
+ status: "confirmation_required",
148
+ operationId: request.operationId,
149
+ proposalReceiptId: result.receipt_id,
150
+ revision,
151
+ humanInput: CompanyProfileAgentHumanInputPrompt.parse(result.human_input),
152
+ confirmWith: "company_profile_confirm",
153
+ replayed: result.replayed,
154
+ });
155
+ } catch (error) {
156
+ translate(error, "propose");
157
+ }
158
+ }
159
+
160
+ export async function confirmCompanyProfileForAgent(
161
+ db: Database,
162
+ raw: { attempt: CompanyProfileAgentAttemptType; request: CompanyProfileAgentConfirmRequestType },
163
+ ): Promise<CompanyProfileAgentConfirmationReceiptType> {
164
+ const attempt = CompanyProfileAgentAttempt.parse(raw.attempt);
165
+ const request = CompanyProfileAgentConfirmRequest.parse(raw.request);
166
+ try {
167
+ const result = await withAgentAttemptContext(db, attempt, async (scoped) => {
168
+ const [row] = await rawRows<{
169
+ receipt_id: string;
170
+ activation_event_id: string;
171
+ replayed: boolean;
172
+ }>(
173
+ scoped,
174
+ sql`select * from confirm_company_profile_for_attempt(
175
+ ${attempt.accountId}::uuid,
176
+ ${attempt.workspaceId}::uuid,
177
+ ${attempt.sessionId}::uuid,
178
+ ${attempt.turnId}::uuid,
179
+ ${attempt.attemptId}::uuid,
180
+ ${attempt.executionGeneration},
181
+ ${request.operationId}::uuid,
182
+ ${request.proposalReceiptId}::uuid,
183
+ ${request.humanInputRequestId}::uuid
184
+ )`,
185
+ );
186
+ if (!row) throw new Error("Company-profile confirmation returned no receipt");
187
+ return row;
188
+ });
189
+ const [inventory, event] = await Promise.all([
190
+ listCompanyProfile(db, {
191
+ accountId: attempt.accountId,
192
+ workspaceId: attempt.workspaceId,
193
+ limit: 1,
194
+ }),
195
+ getCompanyProfileActivationEvent(db, {
196
+ accountId: attempt.accountId,
197
+ workspaceId: attempt.workspaceId,
198
+ eventId: result.activation_event_id,
199
+ }),
200
+ ]);
201
+ if (!event?.newRevision) {
202
+ throw new Error("Company-profile confirmation activation event is unavailable");
203
+ }
204
+ const revision = await getCompanyProfileRevision(db, {
205
+ accountId: attempt.accountId,
206
+ workspaceId: attempt.workspaceId,
207
+ revisionId: event.newRevision.id,
208
+ });
209
+ return CompanyProfileAgentConfirmationReceipt.parse({
210
+ status: "activated",
211
+ operationId: request.operationId,
212
+ confirmationReceiptId: result.receipt_id,
213
+ proposalReceiptId: request.proposalReceiptId,
214
+ humanInputRequestId: request.humanInputRequestId,
215
+ mutation: {
216
+ revision,
217
+ head: inventory.current?.revisionId === revision.id ? inventory.current : null,
218
+ event,
219
+ },
220
+ replayed: result.replayed,
221
+ });
222
+ } catch (error) {
223
+ translate(error, "confirm");
224
+ }
225
+ }
@@ -1,5 +1,8 @@
1
1
  import { sql } from "drizzle-orm";
2
- import type { CompanyProfileSnapshotEntry } from "@opengeni/contracts";
2
+ import type {
3
+ CompanyProfileAgentHumanInputPrompt,
4
+ CompanyProfileSnapshotEntry,
5
+ } from "@opengeni/contracts";
3
6
  import {
4
7
  bigint,
5
8
  check,
@@ -37,6 +40,7 @@ export const companyProfileRevisions = pgTable(
37
40
  table.accountId,
38
41
  table.operationId,
39
42
  ),
43
+ idAccount: uniqueIndex("company_profile_revisions_id_account_uq").on(table.id, table.accountId),
40
44
  accountRevision: uniqueIndex("company_profile_revisions_account_revision_uq").on(
41
45
  table.accountId,
42
46
  table.revision,
@@ -89,6 +93,7 @@ export const companyProfileActivationEvents = pgTable(
89
93
  table.accountId,
90
94
  table.operationId,
91
95
  ),
96
+ idAccount: uniqueIndex("company_profile_events_id_account_uq").on(table.id, table.accountId),
92
97
  accountActivationVersion: uniqueIndex("company_profile_events_account_version_uq").on(
93
98
  table.accountId,
94
99
  table.activationVersion,
@@ -141,3 +146,118 @@ export const companyProfileSnapshots = pgTable(
141
146
  ),
142
147
  }),
143
148
  );
149
+
150
+ export const companyProfileAgentProposalReceipts = pgTable(
151
+ "company_profile_agent_proposal_receipts",
152
+ {
153
+ id: uuid("id").primaryKey().defaultRandom(),
154
+ operationId: uuid("operation_id").notNull(),
155
+ inputHash: text("input_hash").notNull(),
156
+ accountId: uuid("account_id").notNull(),
157
+ workspaceId: uuid("workspace_id").notNull(),
158
+ sessionId: uuid("session_id").notNull(),
159
+ turnId: uuid("turn_id").notNull(),
160
+ creationAttemptId: uuid("creation_attempt_id").notNull(),
161
+ executionGeneration: integer("execution_generation").notNull(),
162
+ initiatingHumanSubjectId: text("initiating_human_subject_id").notNull(),
163
+ initiatingMembershipId: uuid("initiating_membership_id").notNull(),
164
+ revisionId: uuid("revision_id").notNull(),
165
+ expectedCurrentRevisionId: uuid("expected_current_revision_id"),
166
+ expectedActivationVersion: bigint("expected_activation_version", { mode: "number" }).notNull(),
167
+ reason: text("reason").notNull(),
168
+ humanInput: jsonb("human_input").$type<CompanyProfileAgentHumanInputPrompt>().notNull(),
169
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
170
+ },
171
+ (table) => ({
172
+ accountOperation: uniqueIndex("company_profile_agent_proposals_account_operation_uq").on(
173
+ table.accountId,
174
+ table.operationId,
175
+ ),
176
+ accountRevision: uniqueIndex("company_profile_agent_proposals_account_revision_uq").on(
177
+ table.accountId,
178
+ table.revisionId,
179
+ ),
180
+ idAccount: uniqueIndex("company_profile_agent_proposals_id_account_uq").on(
181
+ table.id,
182
+ table.accountId,
183
+ ),
184
+ turn: index("company_profile_agent_proposals_turn_idx").on(
185
+ table.workspaceId,
186
+ table.sessionId,
187
+ table.turnId,
188
+ table.executionGeneration,
189
+ ),
190
+ hash: check(
191
+ "company_profile_agent_proposals_input_hash_check",
192
+ sql`${table.inputHash} ~ '^[0-9a-f]{64}$'`,
193
+ ),
194
+ generation: check(
195
+ "company_profile_agent_proposals_generation_check",
196
+ sql`${table.executionGeneration} > 0 and ${table.expectedActivationVersion} >= 0`,
197
+ ),
198
+ subject: check(
199
+ "company_profile_agent_proposals_subject_check",
200
+ sql`octet_length(btrim(${table.initiatingHumanSubjectId})) between 1 and 1024`,
201
+ ),
202
+ reason: check(
203
+ "company_profile_agent_proposals_reason_check",
204
+ sql`char_length(btrim(${table.reason})) between 1 and 4096
205
+ and octet_length(convert_to(btrim(${table.reason}), 'UTF8')) <= 16384`,
206
+ ),
207
+ humanInputShape: check(
208
+ "company_profile_agent_proposals_human_input_check",
209
+ sql`jsonb_typeof(${table.humanInput}) = 'object'
210
+ and jsonb_array_length(${table.humanInput}->'questions') = 1
211
+ and ${table.humanInput}->>'allowSkip' = 'false'
212
+ and octet_length(${table.humanInput}::text) <= 49152`,
213
+ ),
214
+ }),
215
+ );
216
+
217
+ export const companyProfileAgentConfirmationReceipts = pgTable(
218
+ "company_profile_agent_confirmation_receipts",
219
+ {
220
+ id: uuid("id").primaryKey().defaultRandom(),
221
+ operationId: uuid("operation_id").notNull(),
222
+ inputHash: text("input_hash").notNull(),
223
+ accountId: uuid("account_id").notNull(),
224
+ workspaceId: uuid("workspace_id").notNull(),
225
+ sessionId: uuid("session_id").notNull(),
226
+ turnId: uuid("turn_id").notNull(),
227
+ confirmationAttemptId: uuid("confirmation_attempt_id").notNull(),
228
+ executionGeneration: integer("execution_generation").notNull(),
229
+ proposalReceiptId: uuid("proposal_receipt_id").notNull(),
230
+ proposalRevisionId: uuid("proposal_revision_id").notNull(),
231
+ humanInputRequestId: uuid("human_input_request_id").notNull(),
232
+ approverSubjectId: text("approver_subject_id").notNull(),
233
+ approverMembershipId: uuid("approver_membership_id").notNull(),
234
+ activationEventId: uuid("activation_event_id").notNull(),
235
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
236
+ },
237
+ (table) => ({
238
+ accountOperation: uniqueIndex("company_profile_agent_confirmations_account_operation_uq").on(
239
+ table.accountId,
240
+ table.operationId,
241
+ ),
242
+ proposal: uniqueIndex("company_profile_agent_confirmations_proposal_uq").on(
243
+ table.accountId,
244
+ table.proposalReceiptId,
245
+ ),
246
+ activationEvent: uniqueIndex("company_profile_agent_confirmations_event_uq").on(
247
+ table.accountId,
248
+ table.activationEventId,
249
+ ),
250
+ hash: check(
251
+ "company_profile_agent_confirmations_input_hash_check",
252
+ sql`${table.inputHash} ~ '^[0-9a-f]{64}$'`,
253
+ ),
254
+ generation: check(
255
+ "company_profile_agent_confirmations_generation_check",
256
+ sql`${table.executionGeneration} > 0`,
257
+ ),
258
+ subject: check(
259
+ "company_profile_agent_confirmations_subject_check",
260
+ sql`octet_length(btrim(${table.approverSubjectId})) between 1 and 1024`,
261
+ ),
262
+ }),
263
+ );