@opengeni/db 1.0.1 → 3.2.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 (271) 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-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
  7. package/dist/chunk-2EH4WRHL.js.map +1 -0
  8. package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
  9. package/dist/chunk-6HMM2R5T.js +390 -0
  10. package/dist/chunk-6HMM2R5T.js.map +1 -0
  11. package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
  12. package/dist/chunk-AZHW7R5V.js.map +1 -0
  13. package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
  14. package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
  15. package/dist/chunk-KRLPEMLH.js.map +1 -0
  16. package/dist/chunk-NAB6FKFN.js +516 -0
  17. package/dist/chunk-NAB6FKFN.js.map +1 -0
  18. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  19. package/dist/chunk-SIBYBA2D.js.map +1 -0
  20. package/dist/chunk-UZNXG44K.js +4508 -0
  21. package/dist/chunk-UZNXG44K.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 +85 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +23 -4
  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 +1606 -81
  43. package/dist/index.js +21898 -8147
  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 +29 -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 +43 -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 +268 -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 +28 -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/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
  189. package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
  190. package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
  191. package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
  192. package/drizzle/0346_document_migration_audit_surface.sql +454 -0
  193. package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -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 +167 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +87 -2
  214. package/src/editable-artifacts-schema.ts +10 -5
  215. package/src/editable-artifacts.ts +21 -11
  216. package/src/governed-learning-activation-schema.ts +121 -0
  217. package/src/governed-learning-activation.ts +588 -0
  218. package/src/governed-learning-evaluator-schema.ts +72 -0
  219. package/src/governed-learning-evaluator.ts +217 -0
  220. package/src/index.ts +11676 -1550
  221. package/src/insights.ts +107 -0
  222. package/src/integration-bindings.ts +88 -6
  223. package/src/integration-facets.ts +287 -84
  224. package/src/interaction-placement-loss.ts +234 -0
  225. package/src/managed-human-provisioning.ts +116 -0
  226. package/src/memory-domain.ts +27 -32
  227. package/src/migrate.ts +77 -1
  228. package/src/new-session-drafts.ts +229 -35
  229. package/src/organization-membership-backfill.ts +735 -0
  230. package/src/organization-membership-lifecycle.ts +995 -0
  231. package/src/pr-review.ts +890 -0
  232. package/src/preference-registry.ts +31 -1
  233. package/src/provision-roles.ts +905 -6
  234. package/src/runtime-posture-cli.ts +2 -0
  235. package/src/runtime-posture.ts +1317 -72
  236. package/src/schema.ts +3316 -428
  237. package/src/scoped-knowledge-schema.ts +16 -8
  238. package/src/scoped-knowledge.ts +1 -1
  239. package/src/session-background-commands.ts +759 -0
  240. package/src/session-control.ts +640 -74
  241. package/src/session-goal-pacing.ts +126 -0
  242. package/src/session-queue-commands.ts +441 -85
  243. package/src/session-realtime-context.ts +4 -6
  244. package/src/session-realtime-ledger.ts +28 -14
  245. package/src/session-realtime-mirror.ts +1 -1
  246. package/src/session-tenancy.ts +410 -49
  247. package/src/session-tool-call-settlement.ts +38 -29
  248. package/src/slack-routing-personal-workspace.ts +67 -0
  249. package/src/slack-routing.ts +867 -0
  250. package/src/slack-task-policy-schema.ts +5 -0
  251. package/src/slack-task-policy.ts +18 -0
  252. package/src/slack-user-link-access.ts +138 -11
  253. package/src/task-notes-schema.ts +74 -0
  254. package/src/task-notes.ts +124 -2
  255. package/src/turn-initiator.ts +8 -0
  256. package/src/user-resource-authority.ts +377 -0
  257. package/src/workspace-authority.ts +160 -0
  258. package/src/workspace-instruction-policies-schema.ts +53 -1
  259. package/src/workspace-instruction-policies.ts +528 -77
  260. package/src/workspace-learning-policy.ts +21 -5
  261. package/src/workspace-membership-permissions.ts +9 -0
  262. package/dist/chunk-4SR4HKKA.js.map +0 -1
  263. package/dist/chunk-6ZYKCRFO.js.map +0 -1
  264. package/dist/chunk-NXAFLCQX.js +0 -2468
  265. package/dist/chunk-NXAFLCQX.js.map +0 -1
  266. package/dist/chunk-SK7YYHBI.js.map +0 -1
  267. package/dist/chunk-WD5ROSLL.js +0 -117
  268. package/dist/chunk-WD5ROSLL.js.map +0 -1
  269. package/dist/chunk-ZWREYEWA.js.map +0 -1
  270. /package/dist/{chunk-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
  271. /package/dist/{chunk-LTG3S6ZY.js.map → chunk-E6CLMKEE.js.map} +0 -0
package/src/database.ts CHANGED
@@ -115,6 +115,18 @@ export type RlsStrategy = "force" | "scoped";
115
115
  */
116
116
  export type UserLookup = (db: Database, email: string) => Promise<string | null>;
117
117
 
118
+ export type ManagedUserProfile = {
119
+ id: string;
120
+ name: string | null;
121
+ email: string;
122
+ };
123
+
124
+ /** Host identity projection used by organization administration rosters. */
125
+ export type UserProfileLookup = (
126
+ db: Database,
127
+ userIds: readonly string[],
128
+ ) => Promise<ManagedUserProfile[]>;
129
+
118
130
  export type CreateDbOptions = {
119
131
  /**
120
132
  * The Postgres `search_path` for this connection (Step I, §7.8 runtime half).
@@ -132,6 +144,8 @@ export type CreateDbOptions = {
132
144
  rlsStrategy?: RlsStrategy;
133
145
  /** Host-provided user-by-email resolver; unset → today's raw `auth_users` query. */
134
146
  userLookup?: UserLookup;
147
+ /** Host-provided user profile projection; unset → standalone `auth_users`. */
148
+ userProfileLookup?: UserProfileLookup;
135
149
  /** postgres-js pool size; defaults to today's `10`. */
136
150
  max?: number;
137
151
  /**
@@ -150,7 +164,11 @@ export type CreateDbOptions = {
150
164
  * config (e.g. one built outside `createDb`, or in a test) falls back to the
151
165
  * standalone defaults: `rlsStrategy: "force"`, raw `auth_users` lookup.
152
166
  */
153
- type DbBinding = { rlsStrategy: RlsStrategy; userLookup?: UserLookup };
167
+ type DbBinding = {
168
+ rlsStrategy: RlsStrategy;
169
+ userLookup?: UserLookup;
170
+ userProfileLookup?: UserProfileLookup;
171
+ };
154
172
 
155
173
  const dbBindings = new WeakMap<object, DbBinding>();
156
174
 
@@ -314,6 +332,7 @@ export function createDb(databaseUrl: string, options: CreateDbOptions = {}): Db
314
332
  dbBindings.set(db as unknown as object, {
315
333
  rlsStrategy: options.rlsStrategy ?? "force",
316
334
  ...(options.userLookup ? { userLookup: options.userLookup } : {}),
335
+ ...(options.userProfileLookup ? { userProfileLookup: options.userProfileLookup } : {}),
317
336
  });
318
337
  return {
319
338
  db,
@@ -331,11 +350,16 @@ export function createDb(databaseUrl: string, options: CreateDbOptions = {}): Db
331
350
  */
332
351
  export function registerDbBinding(
333
352
  db: Database,
334
- binding: { rlsStrategy?: RlsStrategy; userLookup?: UserLookup },
353
+ binding: {
354
+ rlsStrategy?: RlsStrategy;
355
+ userLookup?: UserLookup;
356
+ userProfileLookup?: UserProfileLookup;
357
+ },
335
358
  ): void {
336
359
  dbBindings.set(db as unknown as object, {
337
360
  rlsStrategy: binding.rlsStrategy ?? "force",
338
361
  ...(binding.userLookup ? { userLookup: binding.userLookup } : {}),
362
+ ...(binding.userProfileLookup ? { userProfileLookup: binding.userProfileLookup } : {}),
339
363
  });
340
364
  }
341
365
 
@@ -429,12 +453,18 @@ export async function withRlsContext<T>(
429
453
  context: RlsContext,
430
454
  fn: (db: Database) => Promise<T>,
431
455
  transactionConfig?: PgTransactionConfig,
456
+ sessionTenancyFence: "shared" | "none" = "shared",
432
457
  ): Promise<T> {
433
458
  const restoreParentScope = isTransactionHandle(db);
434
459
  return await db.transaction(async (tx) => {
435
460
  const scoped = tx as unknown as Database;
436
461
  const parentScope = restoreParentScope ? await readRlsContextSettings(scoped) : null;
437
462
  await setRlsContext(scoped, context);
463
+ if (context.workspaceId && sessionTenancyFence === "shared") {
464
+ await scoped.execute(
465
+ sql`select pg_advisory_xact_lock_shared(hashtextextended(${`session-tenancy:${context.workspaceId}`}, 0))`,
466
+ );
467
+ }
438
468
  // Defense-in-depth: read the LOCAL GUC back on THIS backend BEFORE running
439
469
  // the scoped query. The set_config and this read share one db.transaction,
440
470
  // which a transaction pooler pins to a single backend — so a mismatch here
@@ -662,6 +692,14 @@ async function finalizeSessionActivityGate(
662
692
  await db.execute(
663
693
  sql`set constraints sessions_activity_insert_commit_guard, sessions_activity_update_commit_guard immediate`,
664
694
  );
695
+ // A restored activity scope can be followed by another workspace scope, or
696
+ // by a SECURITY DEFINER lifecycle that opens and finalizes its own gate in
697
+ // the same outer transaction. Keep the guards deferred after proving this
698
+ // scope's final state so those later writes reach their own finalizer instead
699
+ // of firing the commit guard at the first session update.
700
+ await db.execute(
701
+ sql`set constraints sessions_activity_insert_commit_guard, sessions_activity_update_commit_guard deferred`,
702
+ );
665
703
  }
666
704
 
667
705
  /**
@@ -674,6 +712,7 @@ export async function withSessionActivityRlsContext<T>(
674
712
  context: RlsContext & { workspaceId: string },
675
713
  fn: (db: SessionActivityDatabase) => Promise<T>,
676
714
  transactionConfig?: PgTransactionConfig,
715
+ fenceMode: "shared" | "none" = "shared",
677
716
  ): Promise<T> {
678
717
  await assertSessionActivityGateEntry(db);
679
718
  return await withRlsContext(
@@ -692,6 +731,7 @@ export async function withSessionActivityRlsContext<T>(
692
731
  return value;
693
732
  },
694
733
  transactionConfig,
734
+ fenceMode,
695
735
  );
696
736
  }
697
737
 
@@ -709,6 +749,47 @@ export async function withWorkspaceSessionActivityRls<T>(
709
749
  );
710
750
  }
711
751
 
752
+ /**
753
+ * Run one of several ordered workspace activity scopes inside a caller-owned
754
+ * transaction. Each scope is fully finalized before restoring the caller's
755
+ * gate GUCs, so the next workspace can reuse the same outer transaction.
756
+ */
757
+ export async function withRestoredSessionActivityRlsContext<T>(
758
+ db: Database,
759
+ context: RlsContext & { workspaceId: string },
760
+ fn: (db: SessionActivityDatabase) => Promise<T>,
761
+ ): Promise<T> {
762
+ if (!isTransactionHandle(db)) {
763
+ throw new Error("Sequential workspace activity scopes require a caller-owned transaction");
764
+ }
765
+ const [prior] = await rawRows<{ state: string; workspace_id: string }>(
766
+ db,
767
+ sql`select
768
+ coalesce(current_setting('opengeni.session_activity_gate_state', true), '') as state,
769
+ coalesce(
770
+ current_setting('opengeni.session_activity_gate_workspace_id', true), ''
771
+ ) as workspace_id`,
772
+ );
773
+ try {
774
+ return await withRlsContext(db, context, async (scopedDb) => {
775
+ const gate = await beginSessionActivityGate(scopedDb, context.workspaceId);
776
+ if (!gate.owner) {
777
+ throw new Error("Sequential workspace activity scope unexpectedly reused an open gate");
778
+ }
779
+ const value = await fn(gate.db);
780
+ await assertRlsContextApplied(gate.db, context);
781
+ await finalizeSessionActivityGate(gate.db, context.workspaceId);
782
+ return value;
783
+ });
784
+ } finally {
785
+ await db.execute(sql`select
786
+ set_config('opengeni.session_activity_gate_state', ${prior?.state ?? ""}, true),
787
+ set_config(
788
+ 'opengeni.session_activity_gate_workspace_id', ${prior?.workspace_id ?? ""}, true
789
+ )`);
790
+ }
791
+ }
792
+
712
793
  /**
713
794
  * Open one nested savepoint without losing the gate brand. Drizzle correctly
714
795
  * preserves the backend-local gate GUCs, but its structural transaction type
@@ -765,6 +846,7 @@ export async function withWorkspaceSubjectRls<T>(
765
846
  subjectId: string,
766
847
  fn: (db: Database) => Promise<T>,
767
848
  transactionConfig?: PgTransactionConfig,
849
+ sessionTenancyFence: "shared" | "none" = "shared",
768
850
  ): Promise<T> {
769
851
  if (!subjectId.trim()) {
770
852
  throw new Error("withWorkspaceSubjectRls: a non-empty subjectId is required");
@@ -778,6 +860,7 @@ export async function withWorkspaceSubjectRls<T>(
778
860
  return await fn(scopedDb);
779
861
  },
780
862
  transactionConfig,
863
+ sessionTenancyFence,
781
864
  );
782
865
  }
783
866
 
@@ -787,6 +870,7 @@ export async function withWorkspaceSubjectSessionActivityRls<T>(
787
870
  subjectId: string,
788
871
  fn: (db: SessionActivityDatabase) => Promise<T>,
789
872
  transactionConfig?: PgTransactionConfig,
873
+ fenceMode: "shared" | "none" = "shared",
790
874
  ): Promise<T> {
791
875
  if (!subjectId.trim()) {
792
876
  throw new Error("withWorkspaceSubjectSessionActivityRls: a non-empty subjectId is required");
@@ -800,6 +884,7 @@ export async function withWorkspaceSubjectSessionActivityRls<T>(
800
884
  return await fn(scopedDb);
801
885
  },
802
886
  transactionConfig,
887
+ fenceMode,
803
888
  );
804
889
  }
805
890
 
@@ -272,7 +272,6 @@ export const editableArtifactTransactions = pgTable(
272
272
  and ${table.intentHash} = ${table.requestHash}
273
273
  and ${table.intentEnvelopeVersion} = 1
274
274
  and ${table.intentProtocolVersion} = 1
275
- and ${table.commandProtocolVersion} > 0
276
275
  and ${table.intentByteSize} between 8 and 5242880
277
276
  and octet_length(${table.intentBytes}) = ${table.intentByteSize}
278
277
  and substring(${table.intentBytes} from 1 for 8) = convert_to('OGATX001', 'UTF8')
@@ -288,6 +287,8 @@ export const editableArtifactTransactions = pgTable(
288
287
  'sha256:' || encode(sha256(${table.committedTransactionBytes}), 'hex')
289
288
  and (
290
289
  (${table.modality} = 'spreadsheet'
290
+ and ${table.modelSchemaVersion} = 2
291
+ and ${table.commandProtocolVersion} = 2
291
292
  and ${table.operationCount} between 1 and 4096
292
293
  and ${table.sequenceEnd} = ${table.sequenceStart} + ${table.operationCount} - 1
293
294
  and jsonb_typeof(${table.causalBase}) = 'array'
@@ -296,7 +297,7 @@ export const editableArtifactTransactions = pgTable(
296
297
  and jsonb_typeof(${table.selectiveUndoTargets}) = 'array'
297
298
  and jsonb_typeof(${table.operationIds}) = 'array'
298
299
  and jsonb_array_length(${table.operationIds}) = ${table.operationCount}
299
- and ${table.operationProtocolVersion} = 1
300
+ and ${table.operationProtocolVersion} = 2
300
301
  and ${table.commitProtocolVersion} is null
301
302
  and ${table.priorNativeRevision} is null
302
303
  and ${table.nativeRevision} is null
@@ -304,9 +305,11 @@ export const editableArtifactTransactions = pgTable(
304
305
  and ${table.nativeReceiptByteSize} is null
305
306
  and ${table.nativeReceiptHash} is null
306
307
  and ${table.nativeReceiptBytes} is null
307
- and substring(${table.committedTransactionBytes} from 1 for 8) = convert_to('OGACO001', 'UTF8'))
308
+ and substring(${table.committedTransactionBytes} from 1 for 8) = convert_to('OGACO002', 'UTF8'))
308
309
  or
309
310
  (${table.modality} in ('document', 'presentation')
311
+ and ${table.modelSchemaVersion} = 1
312
+ and ${table.commandProtocolVersion} = 1
310
313
  and ${table.sequenceEnd} = ${table.sequenceStart}
311
314
  and ${table.causalBase} is null
312
315
  and ${table.resolvedCausalBase} is null
@@ -635,11 +638,13 @@ export const editableArtifactSnapshots = pgTable(
635
638
  sql`${stableIdSql(table.id)} and ${sha256Sql(table.contentHash)} and ${sha256Sql(table.stateHash)}
636
639
  and (
637
640
  (${table.modality} = 'spreadsheet'
641
+ and ${table.modelSchemaVersion} = 2
638
642
  and jsonb_typeof(${table.coveredCausalFrontier}) = 'array'
639
- and ${table.operationProtocolVersion} = 1
640
- and ${table.crdtStateVersion} > 0
643
+ and ${table.operationProtocolVersion} = 2
644
+ and ${table.crdtStateVersion} = 2
641
645
  and ${table.nativeRevision} is null)
642
646
  or (${table.modality} in ('document', 'presentation')
647
+ and ${table.modelSchemaVersion} = 1
643
648
  and ${table.coveredCausalFrontier} is null
644
649
  and ${table.operationProtocolVersion} is null
645
650
  and ${table.crdtStateVersion} is null
@@ -11,9 +11,11 @@ import {
11
11
  decodeEditableArtifactSerializedCommit,
12
12
  } from "@opengeni/contracts/editable-artifact-serialized-commit";
13
13
  import {
14
+ EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
14
15
  EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES,
15
16
  EDITABLE_ARTIFACT_PRODUCT_MAX_SNAPSHOT_BYTES,
16
17
  } from "@opengeni/contracts/editable-artifacts";
18
+ import { EDITABLE_ARTIFACT_LIVE_WIRE_VERSION } from "@opengeni/contracts/editable-artifact-versions";
17
19
  import { sql } from "drizzle-orm";
18
20
 
19
21
  import { rawRows, type Database, withRlsContext } from "./database";
@@ -331,7 +333,7 @@ export type PersistedEditableArtifactLiveHead =
331
333
 
332
334
  export type PersistedEditableArtifactLiveResume =
333
335
  | Readonly<{
334
- modality?: "spreadsheet";
336
+ modality: "spreadsheet";
335
337
  localCursor: number | null;
336
338
  localStateHash: string | null;
337
339
  localCausalFrontier: PersistedEditableArtifactCausalFrontier;
@@ -354,6 +356,7 @@ export type PersistedEditableArtifactLiveSnapshot =
354
356
  causalFrontier: PersistedEditableArtifactCausalFrontier;
355
357
  digest: string;
356
358
  operationProtocolVersion: number;
359
+ snapshotVersion: number;
357
360
  kernelVersion: string;
358
361
  modelSchemaVersion: number;
359
362
  bytes: Uint8Array;
@@ -1841,11 +1844,9 @@ export class PostgresEditableArtifactLiveReadStore {
1841
1844
  scope: PersistedEditableArtifactScope;
1842
1845
  artifactId: string;
1843
1846
  resume: PersistedEditableArtifactLiveResume;
1844
- protocolVersion: number;
1845
1847
  }): Promise<PersistedEditableArtifactLiveBootstrap> {
1846
1848
  const scope = validateScope(input.scope);
1847
1849
  const artifactId = validateStableId(input.artifactId, "artifact id");
1848
- validateInteger(input.protocolVersion, "live protocol version", 1);
1849
1850
  const resume = validateLiveResume(input.resume);
1850
1851
  const authority = await withRlsContext(
1851
1852
  this.db,
@@ -2103,6 +2104,7 @@ export class PostgresEditableArtifactLiveReadStore {
2103
2104
  modality: snapshot.modality,
2104
2105
  causalFrontier: snapshot.coveredCausalFrontier,
2105
2106
  operationProtocolVersion: snapshot.operationProtocolVersion,
2107
+ snapshotVersion: snapshot.crdtStateVersion,
2106
2108
  })
2107
2109
  : Object.freeze({
2108
2110
  ...common,
@@ -2872,7 +2874,7 @@ function validateLiveResume(
2872
2874
  input: PersistedEditableArtifactLiveResume,
2873
2875
  ): NormalizedPersistedEditableArtifactLiveResume {
2874
2876
  if (!isPlainRecord(input)) throw new TypeError("Editable artifact live resume is invalid");
2875
- const modality = input.modality ?? "spreadsheet";
2877
+ const modality = input.modality;
2876
2878
  if (modality !== "spreadsheet" && modality !== "document" && modality !== "presentation") {
2877
2879
  throw new TypeError("Editable artifact live resume modality is invalid");
2878
2880
  }
@@ -3443,7 +3445,7 @@ function committedTransactionFromRow(
3443
3445
  } catch (error) {
3444
3446
  throw new EditableArtifactPersistenceError(
3445
3447
  "corrupt_history",
3446
- "Stored canonical committed transaction is not a valid OGACO001 envelope",
3448
+ "Stored canonical committed transaction is not a valid OGACO002 envelope",
3447
3449
  { cause: error },
3448
3450
  );
3449
3451
  }
@@ -4144,7 +4146,7 @@ function validateCommittedTransactionProjection(
4144
4146
  try {
4145
4147
  summary = decodeCommittedTransactionSummary(transaction.committedTransactionBytes);
4146
4148
  } catch (error) {
4147
- throw new TypeError("Canonical committed transaction is not a valid OGACO001 envelope", {
4149
+ throw new TypeError("Canonical committed transaction is not a valid OGACO002 envelope", {
4148
4150
  cause: error,
4149
4151
  });
4150
4152
  }
@@ -4159,7 +4161,7 @@ function validateCommittedTransactionProjection(
4159
4161
  !sameFrontier(summary.resolvedCausalBase, resolvedCausalBase) ||
4160
4162
  !sameFrontier(summary.resultingCausalFrontier, resultingCausalFrontier)
4161
4163
  ) {
4162
- throw new TypeError("Canonical OGACO001 bytes disagree with their durable projection");
4164
+ throw new TypeError("Canonical OGACO002 bytes disagree with their durable projection");
4163
4165
  }
4164
4166
  return;
4165
4167
  }
@@ -4681,6 +4683,10 @@ function validateLiveTicketRecord(
4681
4683
  throw new TypeError("Live ticket lifetime must be 1-60 seconds");
4682
4684
  }
4683
4685
  const modality = validateLiveTicketModality(input.modality);
4686
+ const protocolVersion = validateInteger(input.protocolVersion, "live protocol version", 1);
4687
+ if (protocolVersion !== EDITABLE_ARTIFACT_LIVE_WIRE_VERSION) {
4688
+ throw new TypeError("Live ticket protocol version is unsupported");
4689
+ }
4684
4690
  return Object.freeze({
4685
4691
  tokenDigest: validateHash(input.tokenDigest, "live ticket digest"),
4686
4692
  scope: validateScope(input.scope),
@@ -4688,7 +4694,7 @@ function validateLiveTicketRecord(
4688
4694
  modality,
4689
4695
  actor: validateLiveTicketActor(input.actor),
4690
4696
  allowEdit: validateBoolean(input.allowEdit, "live ticket allowEdit"),
4691
- protocolVersion: validateInteger(input.protocolVersion, "live protocol version", 1),
4697
+ protocolVersion,
4692
4698
  issuedAt,
4693
4699
  expiresAt,
4694
4700
  });
@@ -4984,9 +4990,13 @@ function validateCanonicalIntentBytes(value: unknown, requestHashInput: unknown)
4984
4990
  return bytes;
4985
4991
  }
4986
4992
 
4987
- function validateIntentProtocolVersion(value: unknown): 1 {
4988
- if (value !== 1) throw new TypeError("Intent protocol version must be 1 for OGATX001");
4989
- return 1;
4993
+ function validateIntentProtocolVersion(
4994
+ value: unknown,
4995
+ ): typeof EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION {
4996
+ if (value !== EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION) {
4997
+ throw new TypeError("Intent protocol version is unsupported for current OGATX001");
4998
+ }
4999
+ return EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION;
4990
5000
  }
4991
5001
 
4992
5002
  function validateClientTransactionId(value: unknown): string {
@@ -0,0 +1,121 @@
1
+ import {
2
+ bigint,
3
+ check,
4
+ index,
5
+ pgTable,
6
+ text,
7
+ timestamp,
8
+ uniqueIndex,
9
+ uuid,
10
+ } from "drizzle-orm/pg-core";
11
+ import { sql } from "drizzle-orm";
12
+
13
+ /** Migration 0269 owns exact foreign keys, RLS, immutability and lifecycle checks. */
14
+ export const governedLearningActivationReceipts = pgTable(
15
+ "governed_learning_activation_receipts",
16
+ {
17
+ id: uuid("id").primaryKey().defaultRandom(),
18
+ accountId: uuid("account_id").notNull(),
19
+ workspaceId: uuid("workspace_id").notNull(),
20
+ operationId: uuid("operation_id").notNull(),
21
+ inputHash: text("input_hash").notNull(),
22
+ decisionReceiptId: uuid("decision_receipt_id").notNull(),
23
+ initiatingHumanSubjectId: text("initiating_human_subject_id").notNull(),
24
+ serviceActorSubjectId: text("service_actor_subject_id").notNull(),
25
+ policyRevisionId: uuid("policy_revision_id").notNull(),
26
+ policyHash: text("policy_hash").notNull(),
27
+ policyActivationVersion: bigint("policy_activation_version", { mode: "number" }).notNull(),
28
+ sourceKind: text("source_kind").notNull(),
29
+ sourceId: uuid("source_id").notNull(),
30
+ sourceAuthorityHash: text("source_authority_hash").notNull(),
31
+ proposalId: uuid("proposal_id").notNull(),
32
+ claimId: uuid("claim_id").notNull(),
33
+ evidenceId: uuid("evidence_id").notNull(),
34
+ knowledgePreviousReviewId: uuid("knowledge_previous_review_id").notNull(),
35
+ knowledgePreviousReviewRevision: bigint("knowledge_previous_review_revision", {
36
+ mode: "number",
37
+ }).notNull(),
38
+ knowledgeApprovalReviewId: uuid("knowledge_approval_review_id").notNull(),
39
+ knowledgeApprovalReviewRevision: bigint("knowledge_approval_review_revision", {
40
+ mode: "number",
41
+ }).notNull(),
42
+ knowledgeApprovalInputHash: text("knowledge_approval_input_hash").notNull(),
43
+ destination: text("destination").notNull(),
44
+ destinationProposalId: uuid("destination_proposal_id").notNull(),
45
+ destinationRevisionId: uuid("destination_revision_id").notNull(),
46
+ destinationOldRevisionId: uuid("destination_old_revision_id"),
47
+ destinationOldContentHash: text("destination_old_content_hash"),
48
+ destinationOldVersion: bigint("destination_old_version", { mode: "number" }).notNull(),
49
+ destinationNewContentHash: text("destination_new_content_hash").notNull(),
50
+ destinationNewVersion: bigint("destination_new_version", { mode: "number" }).notNull(),
51
+ destinationEventId: uuid("destination_event_id").notNull(),
52
+ // Added by migration 0272 alongside human-confirmed activation; the schema
53
+ // file had not caught up.
54
+ authorityKind: text("authority_kind").notNull().default("automatic"),
55
+ humanInputRequestId: uuid("human_input_request_id"),
56
+ effectiveAt: timestamp("effective_at", { withTimezone: true }).notNull(),
57
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
58
+ },
59
+ (table) => ({
60
+ operation: uniqueIndex("governed_learning_activation_receipts_operation_uq").on(
61
+ table.workspaceId,
62
+ table.operationId,
63
+ ),
64
+ decision: uniqueIndex("governed_learning_activation_receipts_decision_uq").on(
65
+ table.decisionReceiptId,
66
+ ),
67
+ timeline: index("governed_learning_activation_receipts_workspace_time_idx").on(
68
+ table.workspaceId,
69
+ table.createdAt,
70
+ table.id,
71
+ ),
72
+ hash: check(
73
+ "governed_learning_activation_receipts_hash_chk",
74
+ sql`${table.inputHash} ~ '^[0-9a-f]{64}$'`,
75
+ ),
76
+ }),
77
+ );
78
+
79
+ export const governedLearningActivationUndoReceipts = pgTable(
80
+ "governed_learning_activation_undo_receipts",
81
+ {
82
+ id: uuid("id").primaryKey().defaultRandom(),
83
+ accountId: uuid("account_id").notNull(),
84
+ workspaceId: uuid("workspace_id").notNull(),
85
+ operationId: uuid("operation_id").notNull(),
86
+ inputHash: text("input_hash").notNull(),
87
+ activationReceiptId: uuid("activation_receipt_id").notNull(),
88
+ initiatingHumanSubjectId: text("initiating_human_subject_id").notNull(),
89
+ serviceActorSubjectId: text("service_actor_subject_id").notNull(),
90
+ destination: text("destination").notNull(),
91
+ knowledgeApprovalReviewId: uuid("knowledge_approval_review_id").notNull(),
92
+ knowledgeRevocationReviewId: uuid("knowledge_revocation_review_id").notNull(),
93
+ knowledgeRevocationReviewRevision: bigint("knowledge_revocation_review_revision", {
94
+ mode: "number",
95
+ }).notNull(),
96
+ knowledgeRevocationInputHash: text("knowledge_revocation_input_hash").notNull(),
97
+ destinationActivatedRevisionId: uuid("destination_activated_revision_id").notNull(),
98
+ destinationRestoredRevisionId: uuid("destination_restored_revision_id"),
99
+ destinationActivatedContentHash: text("destination_activated_content_hash").notNull(),
100
+ destinationRestoredContentHash: text("destination_restored_content_hash"),
101
+ destinationOldVersion: bigint("destination_old_version", { mode: "number" }).notNull(),
102
+ destinationNewVersion: bigint("destination_new_version", { mode: "number" }).notNull(),
103
+ destinationEventId: uuid("destination_event_id").notNull(),
104
+ effectiveAt: timestamp("effective_at", { withTimezone: true }).notNull(),
105
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
106
+ },
107
+ (table) => ({
108
+ operation: uniqueIndex("governed_learning_activation_undo_receipts_operation_uq").on(
109
+ table.workspaceId,
110
+ table.operationId,
111
+ ),
112
+ activation: uniqueIndex("governed_learning_activation_undo_receipts_activation_uq").on(
113
+ table.activationReceiptId,
114
+ ),
115
+ timeline: index("governed_learning_activation_undo_receipts_workspace_time_idx").on(
116
+ table.workspaceId,
117
+ table.createdAt,
118
+ table.id,
119
+ ),
120
+ }),
121
+ );