@opengeni/db 3.2.0-canary.0 → 3.4.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 (81) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-SIBYBA2D.js → chunk-6DPJA36C.js} +30 -11
  3. package/dist/chunk-6DPJA36C.js.map +1 -0
  4. package/dist/{chunk-KRLPEMLH.js → chunk-C2AFP7SB.js} +184 -6
  5. package/dist/chunk-C2AFP7SB.js.map +1 -0
  6. package/dist/{chunk-AZHW7R5V.js → chunk-H7MXYG7R.js} +12 -8
  7. package/dist/chunk-H7MXYG7R.js.map +1 -0
  8. package/dist/{chunk-2PRS4J5Q.js → chunk-HY3F5Q4E.js} +3 -3
  9. package/dist/{chunk-NAB6FKFN.js → chunk-O6FTELKH.js} +3 -3
  10. package/dist/{chunk-UZNXG44K.js → chunk-PYMY3AJW.js} +324 -8
  11. package/dist/chunk-PYMY3AJW.js.map +1 -0
  12. package/dist/{chunk-6HMM2R5T.js → chunk-TRBOWUG3.js} +98 -4
  13. package/dist/chunk-TRBOWUG3.js.map +1 -0
  14. package/dist/{chunk-E6CLMKEE.js → chunk-V3TRUXFJ.js} +2 -2
  15. package/dist/{chunk-2EH4WRHL.js → chunk-ZWRIPCTR.js} +2 -2
  16. package/dist/editable-artifact-durable-export.js +2 -2
  17. package/dist/editable-artifacts.js +3 -3
  18. package/dist/governed-learning-activation.d.ts +16 -0
  19. package/dist/index.d.ts +108 -7
  20. package/dist/index.js +3605 -1417
  21. package/dist/index.js.map +1 -1
  22. package/dist/insights-model-bundle.d.ts +30 -0
  23. package/dist/insights-usage-bundle.d.ts +32 -0
  24. package/dist/insights.d.ts +10 -2
  25. package/dist/lossless-json.d.ts +1 -1
  26. package/dist/managed-user-setup.d.ts +82 -0
  27. package/dist/memory-domain.d.ts +2 -2
  28. package/dist/migrate.d.ts +3 -1
  29. package/dist/migrate.js +1 -1
  30. package/dist/new-session-drafts.d.ts +4 -4
  31. package/dist/organization-membership-lifecycle.d.ts +60 -1
  32. package/dist/pr-review.d.ts +44 -3
  33. package/dist/provision-roles.js +1 -1
  34. package/dist/runtime-posture.d.ts +12 -7
  35. package/dist/schema.d.ts +839 -101
  36. package/dist/schema.js +9 -1
  37. package/dist/session-background-commands.js +3 -3
  38. package/dist/session-tenancy.d.ts +12 -1
  39. package/dist/session-tenancy.js +3 -3
  40. package/dist/video-generation.js +3 -3
  41. package/drizzle/0348_named_signup_and_user_setup.sql +838 -0
  42. package/drizzle/0349_greenfield_session_tenancy_activation.sql +792 -0
  43. package/drizzle/0350_organization_shared_workspace_administration.sql +889 -0
  44. package/drizzle/0351_organization_user_setup_delivery.sql +978 -0
  45. package/drizzle/0352_session_variable_set_attachments.sql +1661 -0
  46. package/drizzle/0353_automatic_session_title_policy_fence.sql +476 -0
  47. package/drizzle/0354_automatic_session_title_quarantine_index.sql +9 -0
  48. package/drizzle/0355_automatic_session_title_quarantine.sql +92 -0
  49. package/drizzle/0356_set_based_insights_session_visibility.sql +237 -0
  50. package/drizzle/0357_rig_platform_base_only.sql +44 -0
  51. package/drizzle/0358_pr_review_managed_github_app.sql +108 -0
  52. package/drizzle/0359_insights_force_rls_read_capability.sql +936 -0
  53. package/drizzle/0360_organization_identity_confirmation_prompt.sql +103 -0
  54. package/drizzle/0361_remember_knowledge_memory_materialization.sql +249 -0
  55. package/package.json +6 -6
  56. package/src/database.ts +12 -8
  57. package/src/governed-learning-activation.ts +74 -2
  58. package/src/index.ts +879 -92
  59. package/src/insights-model-bundle.ts +681 -0
  60. package/src/insights-usage-bundle.ts +240 -0
  61. package/src/insights.ts +265 -152
  62. package/src/lossless-json.ts +2 -1
  63. package/src/managed-user-setup.ts +316 -0
  64. package/src/memory-domain.ts +3 -3
  65. package/src/migrate.ts +38 -14
  66. package/src/new-session-drafts.ts +22 -15
  67. package/src/organization-membership-lifecycle.ts +253 -1
  68. package/src/pr-review.ts +449 -6
  69. package/src/provision-roles.ts +92 -0
  70. package/src/runtime-posture.ts +247 -4
  71. package/src/schema.ts +210 -4
  72. package/src/session-tenancy.ts +120 -2
  73. package/dist/chunk-6HMM2R5T.js.map +0 -1
  74. package/dist/chunk-AZHW7R5V.js.map +0 -1
  75. package/dist/chunk-KRLPEMLH.js.map +0 -1
  76. package/dist/chunk-SIBYBA2D.js.map +0 -1
  77. package/dist/chunk-UZNXG44K.js.map +0 -1
  78. /package/dist/{chunk-2PRS4J5Q.js.map → chunk-HY3F5Q4E.js.map} +0 -0
  79. /package/dist/{chunk-NAB6FKFN.js.map → chunk-O6FTELKH.js.map} +0 -0
  80. /package/dist/{chunk-E6CLMKEE.js.map → chunk-V3TRUXFJ.js.map} +0 -0
  81. /package/dist/{chunk-2EH4WRHL.js.map → chunk-ZWRIPCTR.js.map} +0 -0
@@ -5,7 +5,7 @@ import {
5
5
  withWorkspaceRls,
6
6
  withWorkspaceSubjectRls,
7
7
  withWorkspaceSubjectSessionActivityRls
8
- } from "./chunk-AZHW7R5V.js";
8
+ } from "./chunk-H7MXYG7R.js";
9
9
 
10
10
  // src/session-tenancy.ts
11
11
  import { createHash } from "crypto";
@@ -199,6 +199,18 @@ function canonicalSessionVisibilityTransitionHash(input) {
199
199
  ).digest("hex");
200
200
  }
201
201
  function canonicalSessionForkHash(input) {
202
+ if (input.runtimeRequest) {
203
+ return createHash("sha256").update(
204
+ JSON.stringify({
205
+ version: 3,
206
+ sourceSessionId: input.sourceSessionId,
207
+ destinationWorkspaceId: input.destinationWorkspaceId,
208
+ destinationVisibility: input.destinationVisibility,
209
+ workspaceSharedAcknowledged: input.workspaceSharedAcknowledged,
210
+ runtime: input.runtimeRequest
211
+ })
212
+ ).digest("hex");
213
+ }
202
214
  const legacyCompatiblePrivateRequest = input.destinationVisibility === "user_private" && !input.workspaceSharedAcknowledged;
203
215
  return createHash("sha256").update(
204
216
  JSON.stringify(
@@ -217,6 +229,9 @@ function canonicalSessionForkHash(input) {
217
229
  )
218
230
  ).digest("hex");
219
231
  }
232
+ function canonicalForkRuntimeConfigurationDigest(input) {
233
+ return createHash("sha256").update(JSON.stringify({ version: 1, ...input })).digest("hex");
234
+ }
220
235
  async function transitionSessionVisibility(db, input) {
221
236
  if (!Number.isSafeInteger(input.expectedAuthorityEpoch) || input.expectedAuthorityEpoch < 1) {
222
237
  throw new Error("expectedAuthorityEpoch must be a positive safe integer");
@@ -275,6 +290,12 @@ async function forkSessionContent(db, input) {
275
290
  if (input.destinationWorkspaceId !== input.sourceWorkspaceId) {
276
291
  throw new Error("The first session fork contract is same-workspace only");
277
292
  }
293
+ if (Boolean(input.runtimeRequest) !== Boolean(input.runtimeConfiguration)) {
294
+ throw new Error("A fresh session fork runtime request requires its resolved configuration");
295
+ }
296
+ if (input.runtimeRequest && (input.runtimeRequest.rigId !== input.runtimeConfiguration?.rigId || JSON.stringify(input.runtimeRequest.variableSetIds) !== JSON.stringify(input.runtimeConfiguration?.variableSetIds))) {
297
+ throw new Error("Resolved session fork runtime configuration does not match its request");
298
+ }
278
299
  const { accountId } = await rlsContextForWorkspace(db, input.sourceWorkspaceId);
279
300
  await assertSessionTenancyProductActivated(db, input.sourceWorkspaceId);
280
301
  const requestHash = canonicalSessionForkHash(input);
@@ -284,6 +305,43 @@ async function forkSessionContent(db, input) {
284
305
  input.sourceWorkspaceId,
285
306
  input.actorSubjectId,
286
307
  async (scopedDb) => {
308
+ if (input.runtimeRequest && input.runtimeConfiguration) {
309
+ const runtimeDigest = canonicalForkRuntimeConfigurationDigest(input.runtimeRequest);
310
+ const rows2 = await rawRows(
311
+ scopedDb,
312
+ sql`select
313
+ operation_id as "operationId",
314
+ event_id as "eventId",
315
+ event_sequence as "eventSequence",
316
+ session_id as "sessionId",
317
+ workspace_id as "workspaceId",
318
+ visibility,
319
+ authority_epoch as "authorityEpoch",
320
+ copied_history_item_count as "copiedHistoryItemCount",
321
+ replay,
322
+ runtime_event_id as "runtimeEventId",
323
+ runtime_event_sequence as "runtimeEventSequence"
324
+ from fork_session_content_with_runtime(
325
+ ${accountId}::uuid,
326
+ ${input.sourceWorkspaceId}::uuid,
327
+ ${input.sourceSessionId}::uuid,
328
+ ${input.actorSubjectId},
329
+ ${input.destinationWorkspaceId}::uuid,
330
+ ${input.destinationVisibility},
331
+ ${input.workspaceSharedAcknowledged},
332
+ ${input.operationKey},
333
+ ${requestHash},
334
+ ${SESSION_TENANCY_ACTIVATION_VERSION},
335
+ ${JSON.stringify(input.runtimeConfiguration.variableSetIds)}::jsonb,
336
+ ${input.runtimeConfiguration.rigId}::uuid,
337
+ ${input.runtimeConfiguration.rigVersionId}::uuid,
338
+ ${runtimeDigest}
339
+ )`
340
+ );
341
+ const result2 = rows2[0];
342
+ if (!result2) throw new Error("Session fork returned no result");
343
+ return result2;
344
+ }
287
345
  const rows = await rawRows(
288
346
  scopedDb,
289
347
  sql`select
@@ -295,7 +353,9 @@ async function forkSessionContent(db, input) {
295
353
  visibility,
296
354
  authority_epoch as "authorityEpoch",
297
355
  copied_history_item_count as "copiedHistoryItemCount",
298
- replay
356
+ replay,
357
+ null::uuid as "runtimeEventId",
358
+ null::integer as "runtimeEventSequence"
299
359
  from fork_session_content(
300
360
  ${accountId}::uuid,
301
361
  ${input.sourceWorkspaceId}::uuid,
@@ -337,6 +397,38 @@ async function replayAppliedSessionFork(db, input) {
337
397
  input.sourceWorkspaceId,
338
398
  input.actorSubjectId,
339
399
  async (scopedDb) => {
400
+ if (input.runtimeRequest) {
401
+ const runtimeDigest = canonicalForkRuntimeConfigurationDigest(input.runtimeRequest);
402
+ const rows2 = await rawRows(
403
+ scopedDb,
404
+ sql`select
405
+ operation_id as "operationId",
406
+ event_id as "eventId",
407
+ event_sequence as "eventSequence",
408
+ session_id as "sessionId",
409
+ workspace_id as "workspaceId",
410
+ visibility,
411
+ authority_epoch as "authorityEpoch",
412
+ copied_history_item_count as "copiedHistoryItemCount",
413
+ replay,
414
+ runtime_event_id as "runtimeEventId",
415
+ runtime_event_sequence as "runtimeEventSequence"
416
+ from replay_applied_session_fork_with_runtime(
417
+ ${accountId}::uuid,
418
+ ${input.sourceWorkspaceId}::uuid,
419
+ ${input.sourceSessionId}::uuid,
420
+ ${input.actorSubjectId},
421
+ ${input.destinationWorkspaceId}::uuid,
422
+ ${input.destinationVisibility},
423
+ ${input.workspaceSharedAcknowledged},
424
+ ${input.operationKey},
425
+ ${requestHash},
426
+ ${SESSION_TENANCY_ACTIVATION_VERSION},
427
+ ${runtimeDigest}
428
+ )`
429
+ );
430
+ return rows2[0] ?? null;
431
+ }
340
432
  const rows = await rawRows(
341
433
  scopedDb,
342
434
  sql`select
@@ -348,7 +440,9 @@ async function replayAppliedSessionFork(db, input) {
348
440
  visibility,
349
441
  authority_epoch as "authorityEpoch",
350
442
  copied_history_item_count as "copiedHistoryItemCount",
351
- replay
443
+ replay,
444
+ null::uuid as "runtimeEventId",
445
+ null::integer as "runtimeEventSequence"
352
446
  from replay_applied_session_fork(
353
447
  ${accountId}::uuid,
354
448
  ${input.sourceWorkspaceId}::uuid,
@@ -387,4 +481,4 @@ export {
387
481
  forkSessionContent,
388
482
  replayAppliedSessionFork
389
483
  };
390
- //# sourceMappingURL=chunk-6HMM2R5T.js.map
484
+ //# sourceMappingURL=chunk-TRBOWUG3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session-tenancy.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { sql } from \"drizzle-orm\";\nimport {\n SessionTenancyBlocker as SessionTenancyBlockerSchema,\n type SessionTenancyBlocker,\n} from \"@opengeni/contracts\";\nimport {\n rawRows,\n type Database,\n rlsContextForWorkspace,\n withWorkspaceRls,\n withWorkspaceSubjectRls,\n withWorkspaceSubjectSessionActivityRls,\n} from \"./database\";\nimport { nestedPostgresSqlState } from \"./persistence-errors\";\n\nconst SESSION_TENANCY_ACTIVATION_VERSION = 1;\n\nexport class SessionTenancyConflictError extends Error {\n readonly name = \"SessionTenancyConflictError\";\n constructor(\n readonly reason: \"not_quiescent\" | \"authority_epoch\" | \"operation_reuse\",\n readonly blocker: SessionTenancyBlocker | null = null,\n options?: ErrorOptions,\n ) {\n super(\n reason === \"not_quiescent\"\n ? \"Session must be fully quiescent before its tenancy can change\"\n : reason === \"authority_epoch\"\n ? \"Session authority changed before the operation committed\"\n : \"Session tenancy operation key was reused with different input\",\n options,\n );\n }\n}\n\nexport class SessionTenancyNotActivatedError extends Error {\n readonly name = \"SessionTenancyNotActivatedError\";\n constructor(options?: ErrorOptions) {\n super(\"Session tenancy product surface is not activated for this organization\", options);\n }\n}\n\nexport class SessionTenancyAccessError extends Error {\n readonly name = \"SessionTenancyAccessError\";\n constructor(options?: ErrorOptions) {\n super(\"Session tenancy target is unavailable\", options);\n }\n}\n\nexport class SessionTenancyInvalidRequestError extends Error {\n readonly name = \"SessionTenancyInvalidRequestError\";\n constructor(options?: ErrorOptions) {\n super(\"Session tenancy request is invalid\", options);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\");\n}\n\n/** Extract only the fixed quiescence DETAIL vocabulary, never arbitrary driver detail. */\nexport function nestedSessionTenancyBlocker(error: unknown): SessionTenancyBlocker | null {\n const queue: unknown[] = [error];\n const seen = new Set<unknown>();\n while (queue.length > 0 && seen.size < 64) {\n const current = queue.shift();\n if (!isRecord(current) || seen.has(current)) continue;\n seen.add(current);\n for (const key of [\"detail\", \"detailMessage\"] as const) {\n const parsed = SessionTenancyBlockerSchema.safeParse(current[key]);\n if (parsed.success) return parsed.data;\n }\n for (const key of [\"cause\", \"original\", \"driverError\", \"error\", \"errors\"] as const) {\n const nested = current[key];\n if (Array.isArray(nested)) queue.push(...nested);\n else if (nested !== undefined) queue.push(nested);\n }\n }\n return null;\n}\n\nexport type SessionTenancyVisibility = \"user_private\" | \"workspace_shared\";\n\nexport type PrivateSessionCreatePolicy = {\n personalWorkspace: boolean;\n platformAvailable: boolean;\n organizationEnabled: boolean;\n};\n\nexport type TransitionSessionVisibilityInput = {\n workspaceId: string;\n sessionId: string;\n actorSubjectId: string;\n targetVisibility: SessionTenancyVisibility;\n expectedAuthorityEpoch: number;\n operationKey: string;\n};\n\nexport type TransitionSessionVisibilityResult = {\n operationId: string;\n eventId: string | null;\n eventSequence: number | null;\n visibility: SessionTenancyVisibility;\n authorityEpoch: number;\n ownerOrganizationMembershipId: string | null;\n changed: boolean;\n replay: boolean;\n interruptedAttemptCount: number;\n cancelledTurnCount: number;\n cancelledUpdateCount: number;\n pausedGoalCount: number;\n revokedGrantCount: number;\n};\n\nexport type ForkSessionContentInput = {\n sourceWorkspaceId: string;\n sourceSessionId: string;\n actorSubjectId: string;\n destinationWorkspaceId: string;\n destinationVisibility: SessionTenancyVisibility;\n workspaceSharedAcknowledged: boolean;\n operationKey: string;\n runtimeRequest?: ForkSessionRuntimeRequest;\n runtimeConfiguration?: ForkSessionRuntimeConfiguration;\n};\n\nexport type ForkSessionRuntimeRequest = {\n variableSetIds: string[];\n rigId: string | null;\n};\n\nexport type ForkSessionRuntimeConfiguration = ForkSessionRuntimeRequest & {\n rigVersionId: string | null;\n};\n\nexport type ForkSessionContentResult = {\n operationId: string;\n eventId: string;\n eventSequence: number;\n sessionId: string;\n workspaceId: string;\n visibility: SessionTenancyVisibility;\n authorityEpoch: number;\n copiedHistoryItemCount: number;\n replay: boolean;\n runtimeEventId: string | null;\n runtimeEventSequence: number | null;\n};\n\nexport async function sessionTenancyProductActivated(\n db: Database,\n workspaceId: string,\n): Promise<boolean> {\n const { accountId } = await rlsContextForWorkspace(db, workspaceId);\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await rawRows<{ activated: boolean }>(\n scopedDb,\n sql`select session_tenancy_product_activated(\n ${accountId}::uuid,\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n ) as activated`,\n );\n return rows[0]?.activated === true;\n });\n}\n\nexport async function getPrivateSessionCreatePolicy(\n db: Database,\n input: { workspaceId: string; actorSubjectId: string },\n): Promise<PrivateSessionCreatePolicy> {\n const { accountId } = await rlsContextForWorkspace(db, input.workspaceId);\n return await withWorkspaceSubjectRls(\n db,\n input.workspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n const rows = await rawRows<{\n personalWorkspace: boolean;\n platformAvailable: boolean;\n organizationEnabled: boolean;\n }>(\n scopedDb,\n sql`select\n personal_workspace as \"personalWorkspace\",\n platform_available as \"platformAvailable\",\n organization_enabled as \"organizationEnabled\"\n from get_private_session_create_policy(\n ${accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.actorSubjectId}\n )`,\n );\n const policy = rows[0];\n if (!policy) throw new SessionTenancyAccessError();\n return policy;\n },\n );\n}\n\n/** Open the exact transaction-local trigger capability used by atomic private create. */\nexport async function openPrivateSessionCreateCapability(\n db: Database,\n input: { accountId: string; workspaceId: string; sessionId: string; actorSubjectId: string },\n): Promise<{ capabilityId: string; ownerMembershipId: string }> {\n let rows: Array<{ capabilityId: string; ownerMembershipId: string }>;\n try {\n rows = await rawRows<{ capabilityId: string; ownerMembershipId: string }>(\n db,\n sql`select\n capability_id as \"capabilityId\",\n owner_membership_id as \"ownerMembershipId\"\n from open_private_session_create_capability(\n ${input.accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.sessionId}::uuid,\n ${input.actorSubjectId}\n )`,\n );\n } catch (error) {\n // The definer raises 55000 only when the organization owner/admin setting\n // does not permit a new private session in this shared workspace; every\n // authority failure remains 42501 and propagates unchanged.\n if (nestedPostgresSqlState(error) === \"55000\") {\n throw new SessionTenancyNotActivatedError({ cause: error });\n }\n throw error;\n }\n const capabilityId = rows[0]?.capabilityId;\n const ownerMembershipId = rows[0]?.ownerMembershipId;\n if (!capabilityId || !ownerMembershipId) {\n throw new Error(\"Private session create capability was not returned\");\n }\n return { capabilityId, ownerMembershipId };\n}\n\n/** Open the exact transaction-local capability for one private child insert. */\nexport async function openPrivateChildSessionCreateCapability(\n db: Database,\n input: {\n accountId: string;\n workspaceId: string;\n sessionId: string;\n parentSessionId: string;\n actorTurnId: string;\n actorAttemptId: string;\n actorExecutionGeneration: number;\n },\n): Promise<{ capabilityId: string; ownerMembershipId: string; ownerSubjectId: string }> {\n const rows = await rawRows<{\n capabilityId: string;\n ownerMembershipId: string;\n ownerSubjectId: string;\n }>(\n db,\n sql`select\n capability_id as \"capabilityId\",\n owner_membership_id as \"ownerMembershipId\",\n owner_subject_id as \"ownerSubjectId\"\n from open_private_child_session_create_capability(\n ${input.accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.sessionId}::uuid,\n ${input.parentSessionId}::uuid,\n ${input.actorTurnId}::uuid,\n ${input.actorAttemptId}::uuid,\n ${input.actorExecutionGeneration}::integer\n )`,\n );\n const capabilityId = rows[0]?.capabilityId;\n const ownerMembershipId = rows[0]?.ownerMembershipId;\n const ownerSubjectId = rows[0]?.ownerSubjectId;\n if (!capabilityId || !ownerMembershipId || !ownerSubjectId) {\n throw new Error(\"Private child session create capability was not returned\");\n }\n return { capabilityId, ownerMembershipId, ownerSubjectId };\n}\n\nexport async function closePrivateSessionCreateCapability(\n db: Database,\n capabilityId: string,\n): Promise<void> {\n await db.execute(sql`select close_private_session_create_capability(${capabilityId}::uuid)`);\n}\n\nasync function assertSessionTenancyProductActivated(\n db: Database,\n workspaceId: string,\n): Promise<void> {\n if (!(await sessionTenancyProductActivated(db, workspaceId))) {\n throw new SessionTenancyNotActivatedError();\n }\n}\n\nfunction mapSessionTenancyPersistenceError(\n error: unknown,\n options: { authorityEpochConflict: boolean },\n): never {\n const state = nestedPostgresSqlState(error);\n if (state === \"55P03\") {\n throw new SessionTenancyConflictError(\"not_quiescent\", nestedSessionTenancyBlocker(error), {\n cause: error,\n });\n }\n if (state === \"40001\" && options.authorityEpochConflict) {\n throw new SessionTenancyConflictError(\"authority_epoch\", null, { cause: error });\n }\n if (state === \"23505\") {\n throw new SessionTenancyConflictError(\"operation_reuse\", null, { cause: error });\n }\n if (state === \"55000\") {\n throw new SessionTenancyNotActivatedError({ cause: error });\n }\n if (state === \"42501\" || state === \"P0002\") {\n throw new SessionTenancyAccessError({ cause: error });\n }\n if (state === \"22023\") {\n throw new SessionTenancyInvalidRequestError({ cause: error });\n }\n throw error;\n}\n\nexport function canonicalSessionVisibilityTransitionHash(\n input: Pick<\n TransitionSessionVisibilityInput,\n \"sessionId\" | \"targetVisibility\" | \"expectedAuthorityEpoch\"\n >,\n): string {\n return createHash(\"sha256\")\n .update(\n JSON.stringify({\n version: 1,\n sessionId: input.sessionId,\n targetVisibility: input.targetVisibility,\n expectedAuthorityEpoch: input.expectedAuthorityEpoch,\n }),\n )\n .digest(\"hex\");\n}\n\nexport function canonicalSessionForkHash(\n input: Pick<\n ForkSessionContentInput,\n | \"sourceSessionId\"\n | \"destinationWorkspaceId\"\n | \"destinationVisibility\"\n | \"workspaceSharedAcknowledged\"\n | \"runtimeRequest\"\n >,\n): string {\n if (input.runtimeRequest) {\n return createHash(\"sha256\")\n .update(\n JSON.stringify({\n version: 3,\n sourceSessionId: input.sourceSessionId,\n destinationWorkspaceId: input.destinationWorkspaceId,\n destinationVisibility: input.destinationVisibility,\n workspaceSharedAcknowledged: input.workspaceSharedAcknowledged,\n runtime: input.runtimeRequest,\n }),\n )\n .digest(\"hex\");\n }\n const legacyCompatiblePrivateRequest =\n input.destinationVisibility === \"user_private\" && !input.workspaceSharedAcknowledged;\n return createHash(\"sha256\")\n .update(\n JSON.stringify(\n legacyCompatiblePrivateRequest\n ? {\n version: 1,\n sourceSessionId: input.sourceSessionId,\n destinationWorkspaceId: input.destinationWorkspaceId,\n destinationVisibility: input.destinationVisibility,\n }\n : {\n version: 2,\n sourceSessionId: input.sourceSessionId,\n destinationWorkspaceId: input.destinationWorkspaceId,\n destinationVisibility: input.destinationVisibility,\n workspaceSharedAcknowledged: input.workspaceSharedAcknowledged,\n },\n ),\n )\n .digest(\"hex\");\n}\n\nfunction canonicalForkRuntimeConfigurationDigest(input: ForkSessionRuntimeRequest): string {\n return createHash(\"sha256\")\n .update(JSON.stringify({ version: 1, ...input }))\n .digest(\"hex\");\n}\n\nexport async function transitionSessionVisibility(\n db: Database,\n input: TransitionSessionVisibilityInput,\n): Promise<TransitionSessionVisibilityResult> {\n if (!Number.isSafeInteger(input.expectedAuthorityEpoch) || input.expectedAuthorityEpoch < 1) {\n throw new Error(\"expectedAuthorityEpoch must be a positive safe integer\");\n }\n if (!input.operationKey.trim()) throw new Error(\"operationKey must not be empty\");\n const requestHash = canonicalSessionVisibilityTransitionHash(input);\n const { accountId } = await rlsContextForWorkspace(db, input.workspaceId);\n await assertSessionTenancyProductActivated(db, input.workspaceId);\n try {\n return await withWorkspaceSubjectSessionActivityRls(\n db,\n input.workspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n const rows = await rawRows<{\n operationId: string;\n eventId: string | null;\n eventSequence: number | null;\n visibility: SessionTenancyVisibility;\n authorityEpoch: number;\n ownerOrganizationMembershipId: string | null;\n changed: boolean;\n replay: boolean;\n interruptedAttemptCount: number;\n cancelledTurnCount: number;\n cancelledUpdateCount: number;\n pausedGoalCount: number;\n revokedGrantCount: number;\n }>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n owner_organization_membership_id as \"ownerOrganizationMembershipId\",\n changed,\n replay,\n interrupted_attempt_count as \"interruptedAttemptCount\",\n cancelled_turn_count as \"cancelledTurnCount\",\n cancelled_update_count as \"cancelledUpdateCount\",\n paused_goal_count as \"pausedGoalCount\",\n revoked_grant_count as \"revokedGrantCount\"\n from transition_session_visibility(\n ${accountId}::uuid,\n ${input.workspaceId}::uuid,\n ${input.sessionId}::uuid,\n ${input.actorSubjectId},\n ${input.targetVisibility},\n ${input.expectedAuthorityEpoch},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n )`,\n );\n const result = rows[0];\n if (!result) throw new Error(\"Session visibility transition returned no result\");\n return result;\n },\n undefined,\n \"none\",\n );\n } catch (error) {\n mapSessionTenancyPersistenceError(error, { authorityEpochConflict: true });\n }\n}\n\nexport async function forkSessionContent(\n db: Database,\n input: ForkSessionContentInput,\n): Promise<ForkSessionContentResult> {\n if (!input.operationKey.trim()) throw new Error(\"operationKey must not be empty\");\n if (input.destinationWorkspaceId !== input.sourceWorkspaceId) {\n throw new Error(\"The first session fork contract is same-workspace only\");\n }\n if (Boolean(input.runtimeRequest) !== Boolean(input.runtimeConfiguration)) {\n throw new Error(\"A fresh session fork runtime request requires its resolved configuration\");\n }\n if (\n input.runtimeRequest &&\n (input.runtimeRequest.rigId !== input.runtimeConfiguration?.rigId ||\n JSON.stringify(input.runtimeRequest.variableSetIds) !==\n JSON.stringify(input.runtimeConfiguration?.variableSetIds))\n ) {\n throw new Error(\"Resolved session fork runtime configuration does not match its request\");\n }\n const { accountId } = await rlsContextForWorkspace(db, input.sourceWorkspaceId);\n await assertSessionTenancyProductActivated(db, input.sourceWorkspaceId);\n const requestHash = canonicalSessionForkHash(input);\n try {\n return await withWorkspaceSubjectRls(\n db,\n input.sourceWorkspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n if (input.runtimeRequest && input.runtimeConfiguration) {\n const runtimeDigest = canonicalForkRuntimeConfigurationDigest(input.runtimeRequest);\n const rows = await rawRows<ForkSessionContentResult>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n session_id as \"sessionId\",\n workspace_id as \"workspaceId\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n copied_history_item_count as \"copiedHistoryItemCount\",\n replay,\n runtime_event_id as \"runtimeEventId\",\n runtime_event_sequence as \"runtimeEventSequence\"\n from fork_session_content_with_runtime(\n ${accountId}::uuid,\n ${input.sourceWorkspaceId}::uuid,\n ${input.sourceSessionId}::uuid,\n ${input.actorSubjectId},\n ${input.destinationWorkspaceId}::uuid,\n ${input.destinationVisibility},\n ${input.workspaceSharedAcknowledged},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION},\n ${JSON.stringify(input.runtimeConfiguration.variableSetIds)}::jsonb,\n ${input.runtimeConfiguration.rigId}::uuid,\n ${input.runtimeConfiguration.rigVersionId}::uuid,\n ${runtimeDigest}\n )`,\n );\n const result = rows[0];\n if (!result) throw new Error(\"Session fork returned no result\");\n return result;\n }\n const rows = await rawRows<ForkSessionContentResult>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n session_id as \"sessionId\",\n workspace_id as \"workspaceId\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n copied_history_item_count as \"copiedHistoryItemCount\",\n replay,\n null::uuid as \"runtimeEventId\",\n null::integer as \"runtimeEventSequence\"\n from fork_session_content(\n ${accountId}::uuid,\n ${input.sourceWorkspaceId}::uuid,\n ${input.sourceSessionId}::uuid,\n ${input.actorSubjectId},\n ${input.destinationWorkspaceId}::uuid,\n ${input.destinationVisibility},\n ${input.workspaceSharedAcknowledged},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n )`,\n );\n const result = rows[0];\n if (!result) throw new Error(\"Session fork returned no result\");\n return result;\n },\n undefined,\n \"none\",\n );\n } catch (error) {\n // A private destination inside a shared workspace carries the same\n // organization owner/admin product decision the create path enforces\n // (migration 0323), and the fork routine raises the same 55000. Surface it\n // as the not-activated product state rather than an opaque database error.\n if (nestedPostgresSqlState(error) === \"55000\") {\n throw new SessionTenancyNotActivatedError({ cause: error });\n }\n mapSessionTenancyPersistenceError(error, { authorityEpochConflict: false });\n }\n}\n\n/**\n * Recover one exact committed fork before mutable source-session authorization.\n *\n * The database capability requires the authenticated actor's active workspace\n * authority and matches the complete actor/workspace/source/key/request-hash\n * tuple. A fresh key returns null; changed intent raises the ordinary tenancy\n * idempotency conflict. This is receipt recovery, not session discovery.\n */\nexport async function replayAppliedSessionFork(\n db: Database,\n input: ForkSessionContentInput,\n): Promise<ForkSessionContentResult | null> {\n if (!input.operationKey.trim()) throw new Error(\"operationKey must not be empty\");\n if (input.destinationWorkspaceId !== input.sourceWorkspaceId) {\n throw new Error(\"The first session fork contract is same-workspace only\");\n }\n const { accountId } = await rlsContextForWorkspace(db, input.sourceWorkspaceId);\n await assertSessionTenancyProductActivated(db, input.sourceWorkspaceId);\n const requestHash = canonicalSessionForkHash(input);\n try {\n return await withWorkspaceSubjectRls(\n db,\n input.sourceWorkspaceId,\n input.actorSubjectId,\n async (scopedDb) => {\n if (input.runtimeRequest) {\n const runtimeDigest = canonicalForkRuntimeConfigurationDigest(input.runtimeRequest);\n const rows = await rawRows<ForkSessionContentResult>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n session_id as \"sessionId\",\n workspace_id as \"workspaceId\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n copied_history_item_count as \"copiedHistoryItemCount\",\n replay,\n runtime_event_id as \"runtimeEventId\",\n runtime_event_sequence as \"runtimeEventSequence\"\n from replay_applied_session_fork_with_runtime(\n ${accountId}::uuid,\n ${input.sourceWorkspaceId}::uuid,\n ${input.sourceSessionId}::uuid,\n ${input.actorSubjectId},\n ${input.destinationWorkspaceId}::uuid,\n ${input.destinationVisibility},\n ${input.workspaceSharedAcknowledged},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION},\n ${runtimeDigest}\n )`,\n );\n return rows[0] ?? null;\n }\n const rows = await rawRows<ForkSessionContentResult>(\n scopedDb,\n sql`select\n operation_id as \"operationId\",\n event_id as \"eventId\",\n event_sequence as \"eventSequence\",\n session_id as \"sessionId\",\n workspace_id as \"workspaceId\",\n visibility,\n authority_epoch as \"authorityEpoch\",\n copied_history_item_count as \"copiedHistoryItemCount\",\n replay,\n null::uuid as \"runtimeEventId\",\n null::integer as \"runtimeEventSequence\"\n from replay_applied_session_fork(\n ${accountId}::uuid,\n ${input.sourceWorkspaceId}::uuid,\n ${input.sourceSessionId}::uuid,\n ${input.actorSubjectId},\n ${input.destinationWorkspaceId}::uuid,\n ${input.destinationVisibility},\n ${input.workspaceSharedAcknowledged},\n ${input.operationKey},\n ${requestHash},\n ${SESSION_TENANCY_ACTIVATION_VERSION}\n )`,\n );\n return rows[0] ?? null;\n },\n );\n } catch (error) {\n mapSessionTenancyPersistenceError(error, { authorityEpochConflict: false });\n }\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,WAAW;AACpB;AAAA,EACE,yBAAyB;AAAA,OAEpB;AAWP,IAAM,qCAAqC;AAEpC,IAAM,8BAAN,cAA0C,MAAM;AAAA,EAErD,YACW,QACA,UAAwC,MACjD,SACA;AACA;AAAA,MACE,WAAW,kBACP,kEACA,WAAW,oBACT,6DACA;AAAA,MACN;AAAA,IACF;AAXS;AACA;AAAA,EAWX;AAAA,EAdS,OAAO;AAelB;AAEO,IAAM,kCAAN,cAA8C,MAAM;AAAA,EAChD,OAAO;AAAA,EAChB,YAAY,SAAwB;AAClC,UAAM,0EAA0E,OAAO;AAAA,EACzF;AACF;AAEO,IAAM,4BAAN,cAAwC,MAAM;AAAA,EAC1C,OAAO;AAAA,EAChB,YAAY,SAAwB;AAClC,UAAM,yCAAyC,OAAO;AAAA,EACxD;AACF;AAEO,IAAM,oCAAN,cAAgD,MAAM;AAAA,EAClD,OAAO;AAAA,EAChB,YAAY,SAAwB;AAClC,UAAM,sCAAsC,OAAO;AAAA,EACrD;AACF;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,QAAQ,SAAS,OAAO,UAAU,QAAQ;AACnD;AAGO,SAAS,4BAA4B,OAA8C;AACxF,QAAM,QAAmB,CAAC,KAAK;AAC/B,QAAM,OAAO,oBAAI,IAAa;AAC9B,SAAO,MAAM,SAAS,KAAK,KAAK,OAAO,IAAI;AACzC,UAAM,UAAU,MAAM,MAAM;AAC5B,QAAI,CAAC,SAAS,OAAO,KAAK,KAAK,IAAI,OAAO,EAAG;AAC7C,SAAK,IAAI,OAAO;AAChB,eAAW,OAAO,CAAC,UAAU,eAAe,GAAY;AACtD,YAAM,SAAS,4BAA4B,UAAU,QAAQ,GAAG,CAAC;AACjE,UAAI,OAAO,QAAS,QAAO,OAAO;AAAA,IACpC;AACA,eAAW,OAAO,CAAC,SAAS,YAAY,eAAe,SAAS,QAAQ,GAAY;AAClF,YAAM,SAAS,QAAQ,GAAG;AAC1B,UAAI,MAAM,QAAQ,MAAM,EAAG,OAAM,KAAK,GAAG,MAAM;AAAA,eACtC,WAAW,OAAW,OAAM,KAAK,MAAM;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAsEA,eAAsB,+BACpB,IACA,aACkB;AAClB,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,WAAW;AAClE,SAAO,MAAM,iBAAiB,IAAI,aAAa,OAAO,aAAa;AACjE,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA;AAAA,UACI,SAAS;AAAA,UACT,kCAAkC;AAAA;AAAA,IAExC;AACA,WAAO,KAAK,CAAC,GAAG,cAAc;AAAA,EAChC,CAAC;AACH;AAEA,eAAsB,8BACpB,IACA,OACqC;AACrC,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,WAAW;AACxE,SAAO,MAAM;AAAA,IACX;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO,aAAa;AAClB,YAAM,OAAO,MAAM;AAAA,QAKjB;AAAA,QACA;AAAA;AAAA;AAAA;AAAA;AAAA,YAKI,SAAS;AAAA,YACT,MAAM,WAAW;AAAA,YACjB,MAAM,cAAc;AAAA;AAAA,MAE1B;AACA,YAAM,SAAS,KAAK,CAAC;AACrB,UAAI,CAAC,OAAQ,OAAM,IAAI,0BAA0B;AACjD,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGA,eAAsB,mCACpB,IACA,OAC8D;AAC9D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA;AAAA;AAAA;AAAA;AAAA,UAII,MAAM,SAAS;AAAA,UACf,MAAM,WAAW;AAAA,UACjB,MAAM,SAAS;AAAA,UACf,MAAM,cAAc;AAAA;AAAA,IAE1B;AAAA,EACF,SAAS,OAAO;AAId,QAAI,uBAAuB,KAAK,MAAM,SAAS;AAC7C,YAAM,IAAI,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,IAC5D;AACA,UAAM;AAAA,EACR;AACA,QAAM,eAAe,KAAK,CAAC,GAAG;AAC9B,QAAM,oBAAoB,KAAK,CAAC,GAAG;AACnC,MAAI,CAAC,gBAAgB,CAAC,mBAAmB;AACvC,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,SAAO,EAAE,cAAc,kBAAkB;AAC3C;AAGA,eAAsB,wCACpB,IACA,OASsF;AACtF,QAAM,OAAO,MAAM;AAAA,IAKjB;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKI,MAAM,SAAS;AAAA,QACf,MAAM,WAAW;AAAA,QACjB,MAAM,SAAS;AAAA,QACf,MAAM,eAAe;AAAA,QACrB,MAAM,WAAW;AAAA,QACjB,MAAM,cAAc;AAAA,QACpB,MAAM,wBAAwB;AAAA;AAAA,EAEpC;AACA,QAAM,eAAe,KAAK,CAAC,GAAG;AAC9B,QAAM,oBAAoB,KAAK,CAAC,GAAG;AACnC,QAAM,iBAAiB,KAAK,CAAC,GAAG;AAChC,MAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,gBAAgB;AAC1D,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,SAAO,EAAE,cAAc,mBAAmB,eAAe;AAC3D;AAEA,eAAsB,oCACpB,IACA,cACe;AACf,QAAM,GAAG,QAAQ,qDAAqD,YAAY,SAAS;AAC7F;AAEA,eAAe,qCACb,IACA,aACe;AACf,MAAI,CAAE,MAAM,+BAA+B,IAAI,WAAW,GAAI;AAC5D,UAAM,IAAI,gCAAgC;AAAA,EAC5C;AACF;AAEA,SAAS,kCACP,OACA,SACO;AACP,QAAM,QAAQ,uBAAuB,KAAK;AAC1C,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,4BAA4B,iBAAiB,4BAA4B,KAAK,GAAG;AAAA,MACzF,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,UAAU,WAAW,QAAQ,wBAAwB;AACvD,UAAM,IAAI,4BAA4B,mBAAmB,MAAM,EAAE,OAAO,MAAM,CAAC;AAAA,EACjF;AACA,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,4BAA4B,mBAAmB,MAAM,EAAE,OAAO,MAAM,CAAC;AAAA,EACjF;AACA,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,EAC5D;AACA,MAAI,UAAU,WAAW,UAAU,SAAS;AAC1C,UAAM,IAAI,0BAA0B,EAAE,OAAO,MAAM,CAAC;AAAA,EACtD;AACA,MAAI,UAAU,SAAS;AACrB,UAAM,IAAI,kCAAkC,EAAE,OAAO,MAAM,CAAC;AAAA,EAC9D;AACA,QAAM;AACR;AAEO,SAAS,yCACd,OAIQ;AACR,SAAO,WAAW,QAAQ,EACvB;AAAA,IACC,KAAK,UAAU;AAAA,MACb,SAAS;AAAA,MACT,WAAW,MAAM;AAAA,MACjB,kBAAkB,MAAM;AAAA,MACxB,wBAAwB,MAAM;AAAA,IAChC,CAAC;AAAA,EACH,EACC,OAAO,KAAK;AACjB;AAEO,SAAS,yBACd,OAQQ;AACR,MAAI,MAAM,gBAAgB;AACxB,WAAO,WAAW,QAAQ,EACvB;AAAA,MACC,KAAK,UAAU;AAAA,QACb,SAAS;AAAA,QACT,iBAAiB,MAAM;AAAA,QACvB,wBAAwB,MAAM;AAAA,QAC9B,uBAAuB,MAAM;AAAA,QAC7B,6BAA6B,MAAM;AAAA,QACnC,SAAS,MAAM;AAAA,MACjB,CAAC;AAAA,IACH,EACC,OAAO,KAAK;AAAA,EACjB;AACA,QAAM,iCACJ,MAAM,0BAA0B,kBAAkB,CAAC,MAAM;AAC3D,SAAO,WAAW,QAAQ,EACvB;AAAA,IACC,KAAK;AAAA,MACH,iCACI;AAAA,QACE,SAAS;AAAA,QACT,iBAAiB,MAAM;AAAA,QACvB,wBAAwB,MAAM;AAAA,QAC9B,uBAAuB,MAAM;AAAA,MAC/B,IACA;AAAA,QACE,SAAS;AAAA,QACT,iBAAiB,MAAM;AAAA,QACvB,wBAAwB,MAAM;AAAA,QAC9B,uBAAuB,MAAM;AAAA,QAC7B,6BAA6B,MAAM;AAAA,MACrC;AAAA,IACN;AAAA,EACF,EACC,OAAO,KAAK;AACjB;AAEA,SAAS,wCAAwC,OAA0C;AACzF,SAAO,WAAW,QAAQ,EACvB,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG,GAAG,MAAM,CAAC,CAAC,EAC/C,OAAO,KAAK;AACjB;AAEA,eAAsB,4BACpB,IACA,OAC4C;AAC5C,MAAI,CAAC,OAAO,cAAc,MAAM,sBAAsB,KAAK,MAAM,yBAAyB,GAAG;AAC3F,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,MAAI,CAAC,MAAM,aAAa,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAChF,QAAM,cAAc,yCAAyC,KAAK;AAClE,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,WAAW;AACxE,QAAM,qCAAqC,IAAI,MAAM,WAAW;AAChE,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,aAAa;AAClB,cAAM,OAAO,MAAM;AAAA,UAejB;AAAA,UACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAeE,SAAS;AAAA,YACT,MAAM,WAAW;AAAA,YACjB,MAAM,SAAS;AAAA,YACf,MAAM,cAAc;AAAA,YACpB,MAAM,gBAAgB;AAAA,YACtB,MAAM,sBAAsB;AAAA,YAC5B,MAAM,YAAY;AAAA,YAClB,WAAW;AAAA,YACX,kCAAkC;AAAA;AAAA,QAEtC;AACA,cAAM,SAAS,KAAK,CAAC;AACrB,YAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kDAAkD;AAC/E,eAAO;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,sCAAkC,OAAO,EAAE,wBAAwB,KAAK,CAAC;AAAA,EAC3E;AACF;AAEA,eAAsB,mBACpB,IACA,OACmC;AACnC,MAAI,CAAC,MAAM,aAAa,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAChF,MAAI,MAAM,2BAA2B,MAAM,mBAAmB;AAC5D,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,MAAI,QAAQ,MAAM,cAAc,MAAM,QAAQ,MAAM,oBAAoB,GAAG;AACzE,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC5F;AACA,MACE,MAAM,mBACL,MAAM,eAAe,UAAU,MAAM,sBAAsB,SAC1D,KAAK,UAAU,MAAM,eAAe,cAAc,MAChD,KAAK,UAAU,MAAM,sBAAsB,cAAc,IAC7D;AACA,UAAM,IAAI,MAAM,wEAAwE;AAAA,EAC1F;AACA,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,iBAAiB;AAC9E,QAAM,qCAAqC,IAAI,MAAM,iBAAiB;AACtE,QAAM,cAAc,yBAAyB,KAAK;AAClD,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,aAAa;AAClB,YAAI,MAAM,kBAAkB,MAAM,sBAAsB;AACtD,gBAAM,gBAAgB,wCAAwC,MAAM,cAAc;AAClF,gBAAMA,QAAO,MAAM;AAAA,YACjB;AAAA,YACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAaE,SAAS;AAAA,cACT,MAAM,iBAAiB;AAAA,cACvB,MAAM,eAAe;AAAA,cACrB,MAAM,cAAc;AAAA,cACpB,MAAM,sBAAsB;AAAA,cAC5B,MAAM,qBAAqB;AAAA,cAC3B,MAAM,2BAA2B;AAAA,cACjC,MAAM,YAAY;AAAA,cAClB,WAAW;AAAA,cACX,kCAAkC;AAAA,cAClC,KAAK,UAAU,MAAM,qBAAqB,cAAc,CAAC;AAAA,cACzD,MAAM,qBAAqB,KAAK;AAAA,cAChC,MAAM,qBAAqB,YAAY;AAAA,cACvC,aAAa;AAAA;AAAA,UAEjB;AACA,gBAAMC,UAASD,MAAK,CAAC;AACrB,cAAI,CAACC,QAAQ,OAAM,IAAI,MAAM,iCAAiC;AAC9D,iBAAOA;AAAA,QACT;AACA,cAAM,OAAO,MAAM;AAAA,UACjB;AAAA,UACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAaE,SAAS;AAAA,YACT,MAAM,iBAAiB;AAAA,YACvB,MAAM,eAAe;AAAA,YACrB,MAAM,cAAc;AAAA,YACpB,MAAM,sBAAsB;AAAA,YAC5B,MAAM,qBAAqB;AAAA,YAC3B,MAAM,2BAA2B;AAAA,YACjC,MAAM,YAAY;AAAA,YAClB,WAAW;AAAA,YACX,kCAAkC;AAAA;AAAA,QAEtC;AACA,cAAM,SAAS,KAAK,CAAC;AACrB,YAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,iCAAiC;AAC9D,eAAO;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAKd,QAAI,uBAAuB,KAAK,MAAM,SAAS;AAC7C,YAAM,IAAI,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,IAC5D;AACA,sCAAkC,OAAO,EAAE,wBAAwB,MAAM,CAAC;AAAA,EAC5E;AACF;AAUA,eAAsB,yBACpB,IACA,OAC0C;AAC1C,MAAI,CAAC,MAAM,aAAa,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAChF,MAAI,MAAM,2BAA2B,MAAM,mBAAmB;AAC5D,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,QAAM,EAAE,UAAU,IAAI,MAAM,uBAAuB,IAAI,MAAM,iBAAiB;AAC9E,QAAM,qCAAqC,IAAI,MAAM,iBAAiB;AACtE,QAAM,cAAc,yBAAyB,KAAK;AAClD,MAAI;AACF,WAAO,MAAM;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,aAAa;AAClB,YAAI,MAAM,gBAAgB;AACxB,gBAAM,gBAAgB,wCAAwC,MAAM,cAAc;AAClF,gBAAMD,QAAO,MAAM;AAAA,YACjB;AAAA,YACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAaE,SAAS;AAAA,cACT,MAAM,iBAAiB;AAAA,cACvB,MAAM,eAAe;AAAA,cACrB,MAAM,cAAc;AAAA,cACpB,MAAM,sBAAsB;AAAA,cAC5B,MAAM,qBAAqB;AAAA,cAC3B,MAAM,2BAA2B;AAAA,cACjC,MAAM,YAAY;AAAA,cAClB,WAAW;AAAA,cACX,kCAAkC;AAAA,cAClC,aAAa;AAAA;AAAA,UAEjB;AACA,iBAAOA,MAAK,CAAC,KAAK;AAAA,QACpB;AACA,cAAM,OAAO,MAAM;AAAA,UACjB;AAAA,UACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAaE,SAAS;AAAA,YACT,MAAM,iBAAiB;AAAA,YACvB,MAAM,eAAe;AAAA,YACrB,MAAM,cAAc;AAAA,YACpB,MAAM,sBAAsB;AAAA,YAC5B,MAAM,qBAAqB;AAAA,YAC3B,MAAM,2BAA2B;AAAA,YACjC,MAAM,YAAY;AAAA,YAClB,WAAW;AAAA,YACX,kCAAkC;AAAA;AAAA,QAEtC;AACA,eAAO,KAAK,CAAC,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,sCAAkC,OAAO,EAAE,wBAAwB,MAAM,CAAC;AAAA,EAC5E;AACF;","names":["rows","result"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  nestedPostgresSqlState,
3
3
  rawRows
4
- } from "./chunk-AZHW7R5V.js";
4
+ } from "./chunk-H7MXYG7R.js";
5
5
 
6
6
  // src/canonical-human-identities.ts
7
7
  import { createHash } from "crypto";
@@ -256,4 +256,4 @@ export {
256
256
  getCanonicalHumanIdentityProjection,
257
257
  applyCanonicalHumanIdentityOperation
258
258
  };
259
- //# sourceMappingURL=chunk-E6CLMKEE.js.map
259
+ //# sourceMappingURL=chunk-V3TRUXFJ.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  rawRows,
3
3
  withRlsContext
4
- } from "./chunk-AZHW7R5V.js";
4
+ } from "./chunk-H7MXYG7R.js";
5
5
 
6
6
  // src/editable-artifacts.ts
7
7
  import { createHash } from "crypto";
@@ -3540,4 +3540,4 @@ export {
3540
3540
  PostgresEditableArtifactStore,
3541
3541
  PostgresEditableArtifactLiveReadStore
3542
3542
  };
3543
- //# sourceMappingURL=chunk-2EH4WRHL.js.map
3543
+ //# sourceMappingURL=chunk-ZWRIPCTR.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  rawRows,
3
3
  withRlsContext
4
- } from "./chunk-AZHW7R5V.js";
5
- import "./chunk-KRLPEMLH.js";
4
+ } from "./chunk-H7MXYG7R.js";
5
+ import "./chunk-C2AFP7SB.js";
6
6
  import "./chunk-PZ5AY32C.js";
7
7
 
8
8
  // src/editable-artifact-durable-export.ts
@@ -8,9 +8,9 @@ import {
8
8
  PostgresEditableArtifactStore,
9
9
  listEditableArtifactIdsForSession,
10
10
  touchEditableArtifactSessionLink
11
- } from "./chunk-2EH4WRHL.js";
12
- import "./chunk-AZHW7R5V.js";
13
- import "./chunk-KRLPEMLH.js";
11
+ } from "./chunk-ZWRIPCTR.js";
12
+ import "./chunk-H7MXYG7R.js";
13
+ import "./chunk-C2AFP7SB.js";
14
14
  import "./chunk-PZ5AY32C.js";
15
15
  export {
16
16
  EDITABLE_ARTIFACT_INTENT_MAX_BYTES,
@@ -87,6 +87,22 @@ export declare function confirmRememberKnowledgeClaim(db: Database, raw: {
87
87
  };
88
88
  request: ConfirmRememberKnowledgeClaimRequestType;
89
89
  }): Promise<RememberKnowledgeConfirmationReceiptType>;
90
+ export type RememberKnowledgeMemoryMaterialization = {
91
+ confirmationReceiptId: string;
92
+ accountId: string;
93
+ workspaceId: string;
94
+ sessionId: string;
95
+ memoryId: string;
96
+ taskNoteTextHash: string;
97
+ createdAt: string;
98
+ };
99
+ /**
100
+ * Materialize the exact approved Task-note text behind one completed remember
101
+ * confirmation. The database capability owns the insert and its immutable
102
+ * confirmation-to-Memory mapping, so generic deduplication cannot substitute a
103
+ * normalized lookalike and replay keeps the same Memory id after archival.
104
+ */
105
+ export declare function materializeConfirmedRememberKnowledgeMemory(db: Database, receipt: RememberKnowledgeConfirmationReceiptType): Promise<RememberKnowledgeMemoryMaterialization>;
90
106
  /**
91
107
  * Read the initiating human bound to one workspace-scoped Knowledge claim under
92
108
  * workspace RLS. Used by `remember_confirm` for the Knowledge lane; exposes no
package/dist/index.d.ts CHANGED
@@ -37,6 +37,7 @@ export * from "./company-brain-context-selection.js";
37
37
  export * from "./knowledge-source-sync.js";
38
38
  export * from "./task-notes.js";
39
39
  export * from "./managed-human-provisioning.js";
40
+ export * from "./managed-user-setup.js";
40
41
  export * from "./organization-membership-backfill.js";
41
42
  export * from "./connection-tenancy-backfill.js";
42
43
  export * from "./generated-images.js";
@@ -57,6 +58,8 @@ export * from "./capability-integrations.js";
57
58
  export * from "./integration-bindings.js";
58
59
  export * from "./integration-facets.js";
59
60
  export * from "./insights.js";
61
+ export * from "./insights-model-bundle.js";
62
+ export * from "./insights-usage-bundle.js";
60
63
  export * from "./organization-membership-lifecycle.js";
61
64
  export { rlsSubjectIdOrEmpty, subjectHasLiveWorkspaceAuthorityInScope, } from "./workspace-authority.js";
62
65
  export { memoryTextForStorage } from "./memory-domain.js";
@@ -277,6 +280,7 @@ export declare function ensureManagedAccessForUser(db: Database, input: {
277
280
  email: string;
278
281
  name: string;
279
282
  emailVerified?: boolean;
283
+ provisionFallbackOrganization?: boolean;
280
284
  }): Promise<AccessContext>;
281
285
  export type ManagedAccessProvisioningResult = {
282
286
  accessContext: AccessContext;
@@ -287,6 +291,7 @@ export declare function ensureManagedAccessForUserWithOrganizationMemberships(db
287
291
  email: string;
288
292
  name: string;
289
293
  emailVerified?: boolean;
294
+ provisionFallbackOrganization?: boolean;
290
295
  }): Promise<ManagedAccessProvisioningResult>;
291
296
  export declare function getWorkspace(db: Database, workspaceId: string): Promise<Workspace | null>;
292
297
  export declare function getManagedAccount(db: Database, accountId: string): Promise<ManagedAccount | null>;
@@ -2823,7 +2828,11 @@ export declare class RigChangeAlreadyVerifyingError extends Error {
2823
2828
  readonly changeId: string;
2824
2829
  constructor(changeId: string);
2825
2830
  }
2831
+ export declare class RigImageOverrideUnsupportedError extends Error {
2832
+ constructor();
2833
+ }
2826
2834
  export type RigVersionContentInput = {
2835
+ /** @deprecated Rig versions always use the deployment platform sandbox image. */
2827
2836
  image?: string | null;
2828
2837
  setupScript?: string | null;
2829
2838
  checks?: RigCheck[];
@@ -2874,6 +2883,10 @@ export declare class ChannelNameConflictError extends Error {
2874
2883
  export declare class ChannelNotFoundError extends Error {
2875
2884
  constructor(channelId: string);
2876
2885
  }
2886
+ export declare class SessionVariableSetSelectionUnavailableError extends Error {
2887
+ readonly variableSetIds: string[];
2888
+ constructor(variableSetIds: string[], cause?: unknown);
2889
+ }
2877
2890
  export declare function createChannel(db: Database, input: {
2878
2891
  accountId: string;
2879
2892
  workspaceId: string;
@@ -2900,6 +2913,37 @@ export declare function setSessionChannel(db: Database, input: {
2900
2913
  sessionId: string;
2901
2914
  channelId: string | null;
2902
2915
  }): Promise<boolean>;
2916
+ export type UpdateSessionVariableSetsResult = {
2917
+ status: "updated";
2918
+ event: SessionEvent;
2919
+ } | {
2920
+ status: "unchanged";
2921
+ } | {
2922
+ status: "invalid_variable_sets";
2923
+ variableSetIds: string[];
2924
+ } | {
2925
+ status: "blocked";
2926
+ reason: "turn_in_flight" | "shared_sandbox_group" | "live_sandbox_holders";
2927
+ } | {
2928
+ status: "not_found";
2929
+ };
2930
+ /**
2931
+ * Replace the complete ordered session Variable Set selection at a quiescent
2932
+ * turn boundary. The session row + FK-backed attachment trigger + audit/event
2933
+ * evidence commit together. A live managed box is fenced for rotation so its
2934
+ * baked environment can never serve the next turn after a detach.
2935
+ */
2936
+ export declare function updateSessionVariableSets(db: Database, input: {
2937
+ accountId: string;
2938
+ workspaceId: string;
2939
+ sessionId: string;
2940
+ subjectId: string;
2941
+ variableSets: Array<{
2942
+ id: string;
2943
+ name: string;
2944
+ scope: VariableSet["scope"];
2945
+ }>;
2946
+ }): Promise<UpdateSessionVariableSetsResult>;
2903
2947
  export declare function countRigs(db: Database, access: string | RigAccessContext, scope?: Rig["scope"]): Promise<number>;
2904
2948
  export declare function countSessionsUsingRig(db: Database, workspaceId: string, rigId: string): Promise<number>;
2905
2949
  export declare function createRigVersion(db: Database, workspaceId: string, rigId: string, input: RigVersionContentInput, options?: {
@@ -2969,9 +3013,9 @@ export type RigProviderImageBuildClaim = {
2969
3013
  };
2970
3014
  /**
2971
3015
  * Claim the one provider-image build slot for an existing immutable rig
2972
- * version. A finalized ready image is never overwritten in place: if the
2973
- * effective base/content identity changed, callers must mint/verify a new rig
2974
- * version and runtime setup remains the truthful fallback for this one.
3016
+ * version. The setup hash fences definition drift. Deployment base-image and
3017
+ * provider-image protocol rotations may replace operational metadata for the
3018
+ * same setup; late finalizers remain fenced by the build request id.
2975
3019
  */
2976
3020
  export declare function claimRigVersionProviderImageBuild(db: Database, input: {
2977
3021
  workspaceId: string;
@@ -4532,6 +4576,7 @@ export type SessionCreateInput = {
4532
4576
  reasoningEffort: ReasoningEffort;
4533
4577
  latencyMode: LatencyMode;
4534
4578
  sandboxBackend: SandboxBackend;
4579
+ variableSetIds?: string[];
4535
4580
  variableSetId?: string | null;
4536
4581
  rigId?: string | null;
4537
4582
  rigVersionId?: string | null;
@@ -4652,6 +4697,8 @@ export declare function getAnySessionInGroup(db: Database, workspaceId: string,
4652
4697
  * whose members carry mixed variableSetIds.
4653
4698
  */
4654
4699
  export declare function listDistinctVariableSetIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Array<string | null>>;
4700
+ /** Ordered Variable Set selections across every member of a sandbox group. */
4701
+ export declare function listDistinctVariableSetSelectionsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<string[][]>;
4655
4702
  export declare function listDistinctRigVersionIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Array<string | null>>;
4656
4703
  export declare function getWorkspaceDefaultRigId(db: Database, workspaceId: string): Promise<string | null>;
4657
4704
  export type ListSessionsOptions = {
@@ -8346,10 +8393,21 @@ export declare function recordSessionGoalProgressWithEvent(db: Database, workspa
8346
8393
  replay: boolean;
8347
8394
  }>;
8348
8395
  /**
8349
- * Sets a session's display title. The clobber guard lives entirely in this
8350
- * single atomic UPDATE: a user-set title is permanent, so agent/auto writes
8351
- * carry an `AND title_source IS DISTINCT FROM 'user'` guard (NULL-safe in
8352
- * Postgres) while user writes are unconditional. Never read-modify-write.
8396
+ * Low-level row-only session-title update used by database-specific callers and
8397
+ * tests. Public product writers should use `updateSessionTitleWithEvent` so the
8398
+ * observable event commits atomically with this state transition. The clobber
8399
+ * guard lives entirely in this single atomic UPDATE: a user-set title is
8400
+ * permanent, so agent/auto writes
8401
+ * are first normalized through the shared short/sensitive-safe automatic-title
8402
+ * policy, then carry an `AND title_source IS DISTINCT FROM 'user'` guard
8403
+ * (NULL-safe in Postgres) while user writes are unconditional. Automatic
8404
+ * writes also bind the exact normalized candidate to a transaction-local
8405
+ * database capability, so a pre-policy binary cannot bypass normalization
8406
+ * during a rolling deployment. Never read-modify-write.
8407
+ *
8408
+ * `expectedCurrent`, when supplied, is an additional NULL-safe compare-and-set
8409
+ * fence. It is used by stale/retry-prone producers such as scheduled dispatch:
8410
+ * the write succeeds only if both the durable title and source still match.
8353
8411
  * Re-applying the exact title is also a no-op so a confused agent cannot churn
8354
8412
  * `updated_at` every turn. Returns `{ updated, title }`: `updated` is false when
8355
8413
  * the value was unchanged or an agent write was skipped because a user title
@@ -8361,9 +8419,39 @@ export declare function updateSessionTitle(db: Database, input: {
8361
8419
  sessionId: string;
8362
8420
  title: string;
8363
8421
  source: "user" | "agent";
8422
+ expectedCurrent?: {
8423
+ title: string | null;
8424
+ source: "user" | "agent" | null;
8425
+ };
8426
+ }): Promise<{
8427
+ updated: boolean;
8428
+ title: string | null;
8429
+ }>;
8430
+ /**
8431
+ * Atomically set a session title and append its public `session.title_set`
8432
+ * event under the canonical workspace/session event-write lock. The row CAS,
8433
+ * durable sequence, and event either all commit or all roll back, so a newer
8434
+ * title writer can never commit between the authoritative update and an older
8435
+ * event append.
8436
+ *
8437
+ * Exact retries are naturally idempotent: the unchanged-title predicate (and,
8438
+ * for stale producers, `expectedCurrent`) makes a committed retry a no-op with
8439
+ * no duplicate event. Automatic titles retain the rolling-deployment trigger's
8440
+ * exact transaction-local candidate capability.
8441
+ */
8442
+ export declare function updateSessionTitleWithEvent(db: Database, input: {
8443
+ workspaceId: string;
8444
+ sessionId: string;
8445
+ title: string;
8446
+ source: "user" | "agent";
8447
+ expectedCurrent?: {
8448
+ title: string | null;
8449
+ source: "user" | "agent" | null;
8450
+ };
8364
8451
  }): Promise<{
8365
8452
  updated: boolean;
8366
8453
  title: string | null;
8454
+ events: SessionEvent[];
8367
8455
  }>;
8368
8456
  /**
8369
8457
  * Status transition helper. Idempotent: requesting the current status returns
@@ -9074,6 +9162,19 @@ export declare function getSessionSystemUpdateOutboxByDedupeKey(db: Database, in
9074
9162
  dedupeKey: string;
9075
9163
  }): Promise<SessionSystemUpdateOutboxDelivery | null>;
9076
9164
  export declare function claimPendingSessionSystemUpdateOutbox(db: Database, limit?: number): Promise<SessionSystemUpdateOutboxDelivery[]>;
9165
+ export type AutomaticSessionTitleFanoutDelivery = {
9166
+ outboxId: string;
9167
+ event: SessionEvent;
9168
+ };
9169
+ /**
9170
+ * Claim migration-created title events for deployment-wide NATS fanout. The
9171
+ * function is SECURITY DEFINER because one control worker drains obligations
9172
+ * across workspaces; callers receive only the exact already-public event
9173
+ * projection, never arbitrary session rows.
9174
+ */
9175
+ export declare function claimAutomaticSessionTitleFanout(db: Database, limit?: number): Promise<AutomaticSessionTitleFanoutDelivery[]>;
9176
+ export declare function markAutomaticSessionTitleFanoutDelivered(db: Database, delivery: AutomaticSessionTitleFanoutDelivery): Promise<boolean>;
9177
+ export declare function markAutomaticSessionTitleFanoutFailed(db: Database, delivery: AutomaticSessionTitleFanoutDelivery, error: string): Promise<boolean>;
9077
9178
  export type SessionWorkflowWake = {
9078
9179
  accountId: string;
9079
9180
  workspaceId: string;