@opengeni/db 0.14.3 → 0.17.1

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 (67) hide show
  1. package/dist/{chunk-Y5WZZVQK.js → chunk-SK7YYHBI.js} +5 -2
  2. package/dist/chunk-SK7YYHBI.js.map +1 -0
  3. package/dist/{chunk-ELMUCYZF.js → chunk-T6RSJT6C.js} +202 -43
  4. package/dist/chunk-T6RSJT6C.js.map +1 -0
  5. package/dist/chunk-TLAC622R.js +4990 -0
  6. package/dist/chunk-TLAC622R.js.map +1 -0
  7. package/dist/codex-token-resolver.d.ts +64 -0
  8. package/dist/connection-token-resolver.d.ts +90 -0
  9. package/dist/environment-crypto.d.ts +11 -0
  10. package/dist/event-payload-sanitizer.d.ts +32 -0
  11. package/dist/index.d.ts +6374 -10
  12. package/dist/index.js +8075 -2776
  13. package/dist/index.js.map +1 -1
  14. package/dist/insights.d.ts +157 -0
  15. package/dist/memory-domain.d.ts +44 -0
  16. package/dist/migrate.d.ts +5 -7
  17. package/dist/migrate.js +1 -1
  18. package/dist/new-session-drafts.d.ts +49 -0
  19. package/dist/persistence-errors.d.ts +69 -0
  20. package/dist/preference-registry-schema.d.ts +1147 -0
  21. package/dist/preference-registry.d.ts +878 -0
  22. package/dist/provision-roles.d.ts +4 -6489
  23. package/dist/provision-roles.js +1 -1
  24. package/dist/role-relationships.d.ts +35 -0
  25. package/dist/runtime-posture-cli.d.ts +1 -0
  26. package/dist/runtime-posture.d.ts +103 -0
  27. package/dist/schema.d.ts +25330 -3
  28. package/dist/schema.js +31 -1
  29. package/dist/session-control.d.ts +331 -0
  30. package/dist/session-queue-commands.d.ts +186 -0
  31. package/dist/session-tool-call-settlement.d.ts +32 -0
  32. package/dist/turn-initiator.d.ts +28 -0
  33. package/dist/workspace-artifacts.d.ts +62 -0
  34. package/dist/workspace-instruction-policies-schema.d.ts +735 -0
  35. package/dist/workspace-instruction-policies.d.ts +64 -0
  36. package/drizzle/0136_unified_session_tool_policy.sql +1 -1
  37. package/drizzle/0137_preference_registry.sql +1347 -0
  38. package/drizzle/0138_sandbox_checkpoint_artifacts_and_deadlines.sql +1074 -0
  39. package/drizzle/0139_codex_provider_artifact_invalidations.sql +51 -0
  40. package/drizzle/0140_sandbox_restore_and_reaper_fences.sql +276 -0
  41. package/drizzle/0142_sandbox_archive_capture_gate.sql +80 -0
  42. package/drizzle/0143_session_codex_compaction_mode.sql +20 -0
  43. package/drizzle/0144_sandbox_viewer_force_drain_gate.sql +95 -0
  44. package/drizzle/0145_model_call_facts.sql +96 -0
  45. package/drizzle/0146_slack_bot_delete_idempotency.sql +105 -0
  46. package/drizzle/0147_draft_latency_mode.sql +12 -0
  47. package/drizzle/0148_session_turn_latency_mode.sql +12 -0
  48. package/drizzle/0149_workspace_artifacts.sql +348 -0
  49. package/drizzle/0150_slack_task_interactions.sql +344 -0
  50. package/package.json +6 -6
  51. package/src/index.ts +5766 -275
  52. package/src/insights.ts +837 -0
  53. package/src/migrate.ts +9 -1
  54. package/src/new-session-drafts.ts +4 -0
  55. package/src/preference-registry-schema.ts +170 -0
  56. package/src/preference-registry.ts +1220 -0
  57. package/src/provision-roles.ts +95 -22
  58. package/src/role-relationships.ts +132 -0
  59. package/src/runtime-posture.ts +47 -27
  60. package/src/schema.ts +875 -19
  61. package/src/session-queue-commands.ts +39 -6
  62. package/src/workspace-artifacts.ts +751 -0
  63. package/dist/chunk-DW24CKCT.js +0 -4046
  64. package/dist/chunk-DW24CKCT.js.map +0 -1
  65. package/dist/chunk-ELMUCYZF.js.map +0 -1
  66. package/dist/chunk-Y5WZZVQK.js.map +0 -1
  67. package/dist/schema-DhkRhcuQ.d.ts +0 -22666
package/src/schema.ts CHANGED
@@ -73,6 +73,17 @@ export const workspaces = pgTable(
73
73
  // .references(), because `rigs` is declared later in this file (same
74
74
  // forward-reference pattern as sessions.activeSandboxId). Consumed in M3.
75
75
  defaultRigId: uuid("default_rig_id"),
76
+ // Workspace-wide viewer admission intent set by the warm-meter reaper when
77
+ // managed credits or the monthly warm allowance are exhausted. It is
78
+ // deliberately independent of a lease so a dashboard cannot re-arm a
79
+ // draining box or spawn a cold successor before a fresh limit evaluation
80
+ // clears the gate.
81
+ sandboxViewerForceDrainReason: text("sandbox_viewer_force_drain_reason", {
82
+ enum: ["balance", "warm_cap"],
83
+ }),
84
+ sandboxViewerForceDrainRequestedAt: timestamp("sandbox_viewer_force_drain_requested_at", {
85
+ withTimezone: true,
86
+ }),
76
87
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
77
88
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
78
89
  },
@@ -82,6 +93,182 @@ export const workspaces = pgTable(
82
93
  .on(table.accountId, table.slug)
83
94
  .where(sql`${table.slug} is not null`),
84
95
  external: uniqueIndex("workspaces_external_idx").on(table.externalSource, table.externalId),
96
+ sandboxViewerForceDrain: index("workspaces_sandbox_viewer_force_drain_idx")
97
+ .on(table.id)
98
+ .where(sql`${table.sandboxViewerForceDrainReason} is not null`),
99
+ sandboxViewerForceDrainValid: check(
100
+ "workspaces_sandbox_viewer_force_drain_check",
101
+ sql`(
102
+ ${table.sandboxViewerForceDrainReason} is null
103
+ and ${table.sandboxViewerForceDrainRequestedAt} is null
104
+ ) or (
105
+ ${table.sandboxViewerForceDrainReason} in ('balance', 'warm_cap')
106
+ and ${table.sandboxViewerForceDrainRequestedAt} is not null
107
+ )`,
108
+ ),
109
+ }),
110
+ );
111
+
112
+ // A single generic workspace-published surface. Presentation labels such as
113
+ // app, page, gallery, or document are intentionally not persisted as types.
114
+ export const workspaceArtifacts = pgTable(
115
+ "workspace_artifacts",
116
+ {
117
+ id: uuid("id").primaryKey().defaultRandom(),
118
+ accountId: uuid("account_id")
119
+ .notNull()
120
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
121
+ workspaceId: uuid("workspace_id")
122
+ .notNull()
123
+ .references(() => workspaces.id, { onDelete: "cascade" }),
124
+ slug: text("slug").notNull(),
125
+ title: text("title").notNull(),
126
+ description: text("description"),
127
+ status: text("status").$type<"active" | "archived">().notNull().default("active"),
128
+ // The FK to workspace_artifact_versions is installed by migration after
129
+ // that table exists. Keeping this pointer here makes reads inexpensive.
130
+ currentVersionId: uuid("current_version_id"),
131
+ createdBySubjectId: text("created_by_subject_id").notNull(),
132
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
133
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
134
+ },
135
+ (table) => ({
136
+ workspaceAccount: foreignKey({
137
+ name: "workspace_artifacts_workspace_account_fk",
138
+ columns: [table.workspaceId, table.accountId],
139
+ foreignColumns: [workspaces.id, workspaces.accountId],
140
+ }).onDelete("cascade"),
141
+ workspaceSlug: uniqueIndex("workspace_artifacts_workspace_slug_uq").on(
142
+ table.workspaceId,
143
+ table.slug,
144
+ ),
145
+ workspaceId: uniqueIndex("workspace_artifacts_workspace_id_uq").on(table.workspaceId, table.id),
146
+ list: index("workspace_artifacts_list_idx").on(table.workspaceId, table.updatedAt),
147
+ }),
148
+ );
149
+
150
+ export const workspaceArtifactVersions = pgTable(
151
+ "workspace_artifact_versions",
152
+ {
153
+ id: uuid("id").primaryKey().defaultRandom(),
154
+ accountId: uuid("account_id")
155
+ .notNull()
156
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
157
+ workspaceId: uuid("workspace_id")
158
+ .notNull()
159
+ .references(() => workspaces.id, { onDelete: "cascade" }),
160
+ artifactId: uuid("artifact_id").notNull(),
161
+ revision: integer("revision").notNull(),
162
+ contentKey: text("content_key").notNull(),
163
+ contentType: text("content_type").$type<"text/html">().notNull().default("text/html"),
164
+ contentSha256: text("content_sha256").notNull(),
165
+ sizeBytes: integer("size_bytes").notNull(),
166
+ operationKey: text("operation_key").notNull(),
167
+ sourceSessionId: uuid("source_session_id"),
168
+ sourceTurnId: uuid("source_turn_id"),
169
+ sourceAttemptId: uuid("source_attempt_id"),
170
+ sourceExecutionGeneration: integer("source_execution_generation"),
171
+ createdBySubjectId: text("created_by_subject_id").notNull(),
172
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
173
+ },
174
+ (table) => ({
175
+ workspaceAccount: foreignKey({
176
+ name: "workspace_artifact_versions_workspace_account_fk",
177
+ columns: [table.workspaceId, table.accountId],
178
+ foreignColumns: [workspaces.id, workspaces.accountId],
179
+ }).onDelete("cascade"),
180
+ artifact: foreignKey({
181
+ name: "workspace_artifact_versions_artifact_fk",
182
+ columns: [table.workspaceId, table.artifactId],
183
+ foreignColumns: [workspaceArtifacts.workspaceId, workspaceArtifacts.id],
184
+ }).onDelete("cascade"),
185
+ workspaceId: uniqueIndex("workspace_artifact_versions_workspace_id_uq").on(
186
+ table.workspaceId,
187
+ table.id,
188
+ ),
189
+ revision: uniqueIndex("workspace_artifact_versions_revision_uq").on(
190
+ table.workspaceId,
191
+ table.artifactId,
192
+ table.revision,
193
+ ),
194
+ operation: uniqueIndex("workspace_artifact_versions_operation_uq").on(
195
+ table.workspaceId,
196
+ table.operationKey,
197
+ ),
198
+ provenance: check(
199
+ "workspace_artifact_versions_provenance_chk",
200
+ sql`(
201
+ ${table.sourceSessionId} is null
202
+ and ${table.sourceTurnId} is null
203
+ and ${table.sourceAttemptId} is null
204
+ and ${table.sourceExecutionGeneration} is null
205
+ ) or (
206
+ ${table.sourceSessionId} is not null
207
+ and ${table.sourceTurnId} is not null
208
+ and ${table.sourceAttemptId} is not null
209
+ and ${table.sourceExecutionGeneration} > 0
210
+ )`,
211
+ ),
212
+ }),
213
+ );
214
+
215
+ export const workspaceArtifactEvents = pgTable(
216
+ "workspace_artifact_events",
217
+ {
218
+ id: uuid("id").primaryKey().defaultRandom(),
219
+ accountId: uuid("account_id")
220
+ .notNull()
221
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
222
+ workspaceId: uuid("workspace_id")
223
+ .notNull()
224
+ .references(() => workspaces.id, { onDelete: "cascade" }),
225
+ artifactId: uuid("artifact_id").notNull(),
226
+ type: text("type").$type<"published" | "rolled_back">().notNull(),
227
+ fromVersionId: uuid("from_version_id"),
228
+ toVersionId: uuid("to_version_id").notNull(),
229
+ operationKey: text("operation_key").notNull(),
230
+ sourceSessionId: uuid("source_session_id"),
231
+ sourceTurnId: uuid("source_turn_id"),
232
+ sourceAttemptId: uuid("source_attempt_id"),
233
+ sourceExecutionGeneration: integer("source_execution_generation"),
234
+ actorSubjectId: text("actor_subject_id").notNull(),
235
+ reason: text("reason").notNull(),
236
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
237
+ },
238
+ (table) => ({
239
+ workspaceAccount: foreignKey({
240
+ name: "workspace_artifact_events_workspace_account_fk",
241
+ columns: [table.workspaceId, table.accountId],
242
+ foreignColumns: [workspaces.id, workspaces.accountId],
243
+ }).onDelete("cascade"),
244
+ artifact: foreignKey({
245
+ name: "workspace_artifact_events_artifact_fk",
246
+ columns: [table.workspaceId, table.artifactId],
247
+ foreignColumns: [workspaceArtifacts.workspaceId, workspaceArtifacts.id],
248
+ }).onDelete("cascade"),
249
+ operation: uniqueIndex("workspace_artifact_events_operation_uq").on(
250
+ table.workspaceId,
251
+ table.operationKey,
252
+ ),
253
+ list: index("workspace_artifact_events_list_idx").on(
254
+ table.workspaceId,
255
+ table.artifactId,
256
+ table.createdAt,
257
+ ),
258
+ provenance: check(
259
+ "workspace_artifact_events_provenance_chk",
260
+ sql`(
261
+ ${table.sourceSessionId} is null
262
+ and ${table.sourceTurnId} is null
263
+ and ${table.sourceAttemptId} is null
264
+ and ${table.sourceExecutionGeneration} is null
265
+ ) or (
266
+ ${table.sourceSessionId} is not null
267
+ and ${table.sourceTurnId} is not null
268
+ and ${table.sourceAttemptId} is not null
269
+ and ${table.sourceExecutionGeneration} > 0
270
+ )`,
271
+ ),
85
272
  }),
86
273
  );
87
274
 
@@ -357,12 +544,16 @@ export const codexSubscriptionCredentials = pgTable(
357
544
  // continues to own `version`; quota/cache writes own neither counter.
358
545
  allocatorVersion: integer("allocator_version").notNull().default(1),
359
546
  allocatorUpdatedBySubjectId: text("allocator_updated_by_subject_id"),
360
- allocatorUpdatedAt: timestamp("allocator_updated_at", { withTimezone: true }),
547
+ allocatorUpdatedAt: timestamp("allocator_updated_at", {
548
+ withTimezone: true,
549
+ }),
361
550
  // Authoritative count-only summary cached from /wham/usage. Detailed rows
362
551
  // are never persisted as redemption authority; every first POST preflights
363
552
  // the provider's fresh detail endpoint.
364
553
  resetCreditAvailableCount: integer("reset_credit_available_count"),
365
- resetCreditsCheckedAt: timestamp("reset_credits_checked_at", { withTimezone: true }),
554
+ resetCreditsCheckedAt: timestamp("reset_credits_checked_at", {
555
+ withTimezone: true,
556
+ }),
366
557
  // Set only by a direct Better Auth cookie connection/reconnection. Legacy,
367
558
  // configured, delegated, API-key, and agent-created rows remain view-only.
368
559
  connectedBySubjectId: text("connected_by_subject_id"),
@@ -412,7 +603,9 @@ export const codexResetRedemptionAttempts = pgTable(
412
603
  outcome: text("outcome"),
413
604
  claimHolderId: uuid("claim_holder_id"),
414
605
  claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
415
- confirmationExpiresAt: timestamp("confirmation_expires_at", { withTimezone: true }).notNull(),
606
+ confirmationExpiresAt: timestamp("confirmation_expires_at", {
607
+ withTimezone: true,
608
+ }).notNull(),
416
609
  providerStartedAt: timestamp("provider_started_at", { withTimezone: true }),
417
610
  completedAt: timestamp("completed_at", { withTimezone: true }),
418
611
  lastFailureKind: text("last_failure_kind"),
@@ -520,6 +713,194 @@ export const connections = pgTable(
520
713
  }),
521
714
  );
522
715
 
716
+ export const slackBotUserLinks = pgTable(
717
+ "slack_bot_user_links",
718
+ {
719
+ id: uuid("id").primaryKey().defaultRandom(),
720
+ accountId: uuid("account_id")
721
+ .notNull()
722
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
723
+ workspaceId: uuid("workspace_id")
724
+ .notNull()
725
+ .references(() => workspaces.id, { onDelete: "cascade" }),
726
+ connectionId: uuid("connection_id")
727
+ .notNull()
728
+ .references(() => connections.id, { onDelete: "cascade" }),
729
+ slackTeamId: text("slack_team_id").notNull(),
730
+ slackUserId: text("slack_user_id").notNull(),
731
+ subjectId: text("subject_id").notNull(),
732
+ linkedBySubjectId: text("linked_by_subject_id").notNull(),
733
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
734
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
735
+ },
736
+ (table) => ({
737
+ connectionUser: uniqueIndex("slack_bot_user_links_connection_user_uq").on(
738
+ table.connectionId,
739
+ table.slackUserId,
740
+ ),
741
+ workspaceSubject: index("slack_bot_user_links_workspace_subject_idx").on(
742
+ table.workspaceId,
743
+ table.subjectId,
744
+ ),
745
+ }),
746
+ );
747
+
748
+ export const slackInteractionInbox = pgTable(
749
+ "slack_interaction_inbox",
750
+ {
751
+ id: uuid("id").primaryKey().defaultRandom(),
752
+ accountId: uuid("account_id")
753
+ .notNull()
754
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
755
+ workspaceId: uuid("workspace_id")
756
+ .notNull()
757
+ .references(() => workspaces.id, { onDelete: "cascade" }),
758
+ connectionId: uuid("connection_id")
759
+ .notNull()
760
+ .references(() => connections.id, { onDelete: "cascade" }),
761
+ providerEventId: text("provider_event_id").notNull(),
762
+ providerMessageId: text("provider_message_id").notNull(),
763
+ slackTeamId: text("slack_team_id").notNull(),
764
+ slackUserId: text("slack_user_id").notNull(),
765
+ slackChannelId: text("slack_channel_id").notNull(),
766
+ slackMessageTs: text("slack_message_ts").notNull(),
767
+ slackThreadTs: text("slack_thread_ts"),
768
+ triggerKind: text("trigger_kind")
769
+ .$type<"app_mention" | "dm" | "slash_command" | "message_shortcut" | "thread_reply">()
770
+ .notNull(),
771
+ text: text("text").notNull(),
772
+ status: text("status")
773
+ .$type<"pending" | "processing" | "processed" | "failed">()
774
+ .notNull()
775
+ .default("pending"),
776
+ claimHolderId: uuid("claim_holder_id"),
777
+ claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
778
+ attemptCount: integer("attempt_count").notNull().default(0),
779
+ lastErrorCode: text("last_error_code"),
780
+ processedAt: timestamp("processed_at", { withTimezone: true }),
781
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
782
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
783
+ },
784
+ (table) => ({
785
+ providerEvent: uniqueIndex("slack_interaction_inbox_provider_event_uq").on(
786
+ table.connectionId,
787
+ table.providerEventId,
788
+ ),
789
+ providerMessage: uniqueIndex("slack_interaction_inbox_provider_message_uq").on(
790
+ table.connectionId,
791
+ table.providerMessageId,
792
+ ),
793
+ pending: index("slack_interaction_inbox_pending_idx").on(
794
+ table.status,
795
+ table.createdAt,
796
+ table.id,
797
+ ),
798
+ }),
799
+ );
800
+
801
+ export const slackInteractions = pgTable(
802
+ "slack_interactions",
803
+ {
804
+ id: uuid("id").primaryKey().defaultRandom(),
805
+ accountId: uuid("account_id")
806
+ .notNull()
807
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
808
+ workspaceId: uuid("workspace_id")
809
+ .notNull()
810
+ .references(() => workspaces.id, { onDelete: "cascade" }),
811
+ connectionId: uuid("connection_id")
812
+ .notNull()
813
+ .references(() => connections.id, { onDelete: "cascade" }),
814
+ slackTeamId: text("slack_team_id").notNull(),
815
+ slackChannelId: text("slack_channel_id").notNull(),
816
+ slackThreadTs: text("slack_thread_ts").notNull(),
817
+ routeKey: text("route_key").notNull(),
818
+ triggeringProviderEventId: text("triggering_provider_event_id").notNull(),
819
+ owningSubjectId: text("owning_subject_id").notNull(),
820
+ visibility: text("visibility").$type<"private" | "workspace">().notNull(),
821
+ sessionReservationId: uuid("session_reservation_id").notNull().defaultRandom(),
822
+ sessionId: uuid("session_id").references(() => sessions.id, {
823
+ onDelete: "cascade",
824
+ }),
825
+ lastDeliveredSessionEventSequence: integer("last_delivered_session_event_sequence")
826
+ .notNull()
827
+ .default(0),
828
+ deliveryClaimHolderId: uuid("delivery_claim_holder_id"),
829
+ deliveryClaimExpiresAt: timestamp("delivery_claim_expires_at", {
830
+ withTimezone: true,
831
+ }),
832
+ ackSlackMessageTs: text("ack_slack_message_ts"),
833
+ progressCount: integer("progress_count").notNull().default(0),
834
+ terminalDeliveryState: text("terminal_delivery_state")
835
+ .$type<"open" | "completed" | "failed" | "cancelled" | "blocked">()
836
+ .notNull()
837
+ .default("open"),
838
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
839
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
840
+ },
841
+ (table) => ({
842
+ route: uniqueIndex("slack_interactions_route_uq").on(table.connectionId, table.routeKey),
843
+ identity: uniqueIndex("slack_interactions_identity_uq").on(
844
+ table.accountId,
845
+ table.workspaceId,
846
+ table.id,
847
+ ),
848
+ workspaceReservation: uniqueIndex("slack_interactions_workspace_reservation_uq").on(
849
+ table.workspaceId,
850
+ table.sessionReservationId,
851
+ ),
852
+ workspaceSession: uniqueIndex("slack_interactions_workspace_session_uq")
853
+ .on(table.workspaceId, table.sessionId)
854
+ .where(sql`${table.sessionId} is not null`),
855
+ delivery: index("slack_interactions_delivery_idx").on(
856
+ table.terminalDeliveryState,
857
+ table.updatedAt,
858
+ table.id,
859
+ ),
860
+ }),
861
+ );
862
+
863
+ export const slackInteractionProgressDeliveries = pgTable(
864
+ "slack_interaction_progress_deliveries",
865
+ {
866
+ id: uuid("id").primaryKey().defaultRandom(),
867
+ accountId: uuid("account_id")
868
+ .notNull()
869
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
870
+ workspaceId: uuid("workspace_id")
871
+ .notNull()
872
+ .references(() => workspaces.id, { onDelete: "cascade" }),
873
+ interactionId: uuid("interaction_id").notNull(),
874
+ sessionEventSequence: integer("session_event_sequence").notNull(),
875
+ slot: integer("slot").notNull(),
876
+ operationId: uuid("operation_id").notNull(),
877
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
878
+ },
879
+ (table) => ({
880
+ interactionIdentity: foreignKey({
881
+ columns: [table.accountId, table.workspaceId, table.interactionId],
882
+ foreignColumns: [
883
+ slackInteractions.accountId,
884
+ slackInteractions.workspaceId,
885
+ slackInteractions.id,
886
+ ],
887
+ name: "slack_interaction_progress_deliveries_interaction_fk",
888
+ }).onDelete("cascade"),
889
+ event: uniqueIndex("slack_interaction_progress_deliveries_event_uq").on(
890
+ table.interactionId,
891
+ table.sessionEventSequence,
892
+ ),
893
+ slot: uniqueIndex("slack_interaction_progress_deliveries_slot_uq").on(
894
+ table.interactionId,
895
+ table.slot,
896
+ ),
897
+ operation: uniqueIndex("slack_interaction_progress_deliveries_operation_uq").on(
898
+ table.workspaceId,
899
+ table.operationId,
900
+ ),
901
+ }),
902
+ );
903
+
523
904
  // Durable provider-operation identity for OpenGeni Slack bot posts. The
524
905
  // caller-supplied operation UUID is also Slack's client_msg_id; a bounded claim
525
906
  // serializes live attempts while an expired/released claim can safely retry the
@@ -599,6 +980,90 @@ export const slackBotPostOperations = pgTable(
599
980
  }),
600
981
  );
601
982
 
983
+ // Durable provider-operation identity for OpenGeni Slack bot deletions. Slack
984
+ // has no client-supplied idempotency key for chat.delete, so an expired
985
+ // provider_started claim becomes outcome_unknown and must be reconciled before
986
+ // another mutation is admitted.
987
+ export const slackBotDeleteOperations = pgTable(
988
+ "slack_bot_delete_operations",
989
+ {
990
+ id: uuid("id").primaryKey().defaultRandom(),
991
+ accountId: uuid("account_id")
992
+ .notNull()
993
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
994
+ workspaceId: uuid("workspace_id")
995
+ .notNull()
996
+ .references(() => workspaces.id, { onDelete: "cascade" }),
997
+ connectionId: uuid("connection_id")
998
+ .notNull()
999
+ .references(() => connections.id, { onDelete: "cascade" }),
1000
+ operationId: uuid("operation_id").notNull(),
1001
+ principalType: text("principal_type").$type<"subject" | "service">().notNull(),
1002
+ principalId: text("principal_id").notNull(),
1003
+ toolName: text("tool_name").notNull(),
1004
+ channelId: text("channel_id").notNull(),
1005
+ messageTimestamp: text("message_timestamp").notNull(),
1006
+ requestDigest: text("request_digest").notNull(),
1007
+ status: text("status")
1008
+ .$type<"pending" | "provider_started" | "outcome_unknown" | "completed">()
1009
+ .notNull(),
1010
+ claimHolderId: uuid("claim_holder_id"),
1011
+ claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
1012
+ attemptCount: integer("attempt_count").notNull().default(0),
1013
+ lastFailureCode: text("last_failure_code"),
1014
+ slackChannelId: text("slack_channel_id"),
1015
+ slackMessageTimestamp: text("slack_message_timestamp"),
1016
+ completedAt: timestamp("completed_at", { withTimezone: true }),
1017
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
1018
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
1019
+ },
1020
+ (table) => ({
1021
+ workspaceOperation: uniqueIndex("slack_bot_delete_operations_workspace_operation_uq").on(
1022
+ table.workspaceId,
1023
+ table.operationId,
1024
+ ),
1025
+ workspaceStatus: index("slack_bot_delete_operations_workspace_status_idx").on(
1026
+ table.workspaceId,
1027
+ table.status,
1028
+ table.updatedAt,
1029
+ ),
1030
+ principalValid: check(
1031
+ "slack_bot_delete_operations_principal_check",
1032
+ sql`${table.principalType} in ('subject', 'service')
1033
+ and length(${table.principalId}) between 1 and 512`,
1034
+ ),
1035
+ identityValid: check(
1036
+ "slack_bot_delete_operations_identity_check",
1037
+ sql`${table.toolName} = 'slack_bot_delete_message'
1038
+ and length(${table.channelId}) between 1 and 64
1039
+ and length(${table.messageTimestamp}) between 1 and 64
1040
+ and ${table.requestDigest} ~ '^[0-9a-f]{64}$'
1041
+ and ${table.attemptCount} > 0
1042
+ and ((${table.claimHolderId} is null) = (${table.claimExpiresAt} is null))`,
1043
+ ),
1044
+ statusValid: check(
1045
+ "slack_bot_delete_operations_status_check",
1046
+ sql`${table.status} in ('pending', 'provider_started', 'outcome_unknown', 'completed')`,
1047
+ ),
1048
+ completionValid: check(
1049
+ "slack_bot_delete_operations_completion_check",
1050
+ sql`(
1051
+ ${table.status} <> 'completed'
1052
+ and ${table.slackChannelId} is null
1053
+ and ${table.slackMessageTimestamp} is null
1054
+ and ${table.completedAt} is null
1055
+ ) or (
1056
+ ${table.status} = 'completed'
1057
+ and ${table.claimHolderId} is null
1058
+ and ${table.claimExpiresAt} is null
1059
+ and ${table.slackChannelId} is not null
1060
+ and ${table.slackMessageTimestamp} is not null
1061
+ and ${table.completedAt} is not null
1062
+ )`,
1063
+ ),
1064
+ }),
1065
+ );
1066
+
602
1067
  // OAuth client registrations minted through MCP DCR, keyed by authorization
603
1068
  // server issuer. This is deployment-wide client identity, not a workspace
604
1069
  // credential; per-user/provider tokens still live only in connections.
@@ -916,6 +1381,10 @@ export const sessions = pgTable(
916
1381
  // (manual|policy) lives in the migration; no FK (it describes the pin, not an
917
1382
  // account).
918
1383
  codexPinSource: text("codex_pin_source"),
1384
+ // Frozen at create: remote_v2 (Codex remote compaction + Codex-only models)
1385
+ // or portable (plaintext compaction + free provider switching). Existing
1386
+ // rows backfill to portable. CHECK lives in the migration.
1387
+ codexCompactionMode: text("codex_compaction_mode").notNull().default("portable"),
919
1388
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
920
1389
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
921
1390
  // Assigned by the database trigger whenever canonical updated_at activity
@@ -1473,6 +1942,8 @@ export const sessionTurns = pgTable(
1473
1942
  toolsProvided: boolean("tools_provided").notNull().default(false),
1474
1943
  model: text("model").notNull(),
1475
1944
  reasoningEffort: text("reasoning_effort").notNull(),
1945
+ // Peer of model + reasoning_effort for Fast/priority inheritance.
1946
+ latencyMode: text("latency_mode").notNull().default("standard"),
1476
1947
  sandboxBackend: text("sandbox_backend").notNull(),
1477
1948
  // Per-turn OS override. NULL = inherit the session's sandbox_os. CHECK-
1478
1949
  // constrained to the SandboxOs enum (or NULL) in migration 0018.
@@ -1519,6 +1990,10 @@ export const sessionTurns = pgTable(
1519
1990
  oneCurrentInference: uniqueIndex("session_turns_one_current_inference_uq")
1520
1991
  .on(table.workspaceId, table.sessionId)
1521
1992
  .where(sql`${table.status} in ('running','requires_action','recovering','waiting_capacity')`),
1993
+ latencyModeValid: check(
1994
+ "session_turns_latency_mode_check",
1995
+ sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
1996
+ ),
1522
1997
  }),
1523
1998
  );
1524
1999
 
@@ -1828,6 +2303,7 @@ export const composerDrafts = pgTable(
1828
2303
  toolsProvided: boolean("tools_provided").notNull().default(false),
1829
2304
  model: text("model").notNull(),
1830
2305
  reasoningEffort: text("reasoning_effort").notNull(),
2306
+ latencyMode: text("latency_mode").notNull().default("standard"),
1831
2307
  sourceTurnId: uuid("source_turn_id"),
1832
2308
  sourceTurnVersion: integer("source_turn_version"),
1833
2309
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
@@ -1859,6 +2335,10 @@ export const composerDrafts = pgTable(
1859
2335
  sql`length(btrim(${table.subjectId})) > 0`,
1860
2336
  ),
1861
2337
  revisionValid: check("composer_drafts_revision_check", sql`${table.revision} >= 1`),
2338
+ latencyModeValid: check(
2339
+ "composer_drafts_latency_mode_check",
2340
+ sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
2341
+ ),
1862
2342
  }),
1863
2343
  );
1864
2344
 
@@ -1877,6 +2357,7 @@ export const newSessionDrafts = pgTable(
1877
2357
  tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
1878
2358
  model: text("model").notNull(),
1879
2359
  reasoningEffort: text("reasoning_effort").notNull(),
2360
+ latencyMode: text("latency_mode").notNull().default("standard"),
1880
2361
  sessionOptions: jsonb("session_options").$type<Record<string, unknown>>().notNull().default({}),
1881
2362
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
1882
2363
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -1896,6 +2377,10 @@ export const newSessionDrafts = pgTable(
1896
2377
  sql`length(btrim(${table.subjectId})) > 0`,
1897
2378
  ),
1898
2379
  revisionValid: check("new_session_drafts_revision_check", sql`${table.revision} >= 1`),
2380
+ latencyModeValid: check(
2381
+ "new_session_drafts_latency_mode_check",
2382
+ sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
2383
+ ),
1899
2384
  }),
1900
2385
  );
1901
2386
 
@@ -2106,10 +2591,14 @@ export const sessionGoals = pgTable(
2106
2591
  // update, timeline events, usage row, and workflow-wake outbox row.
2107
2592
  // Temporal signals and workflow history are replaceable nudges over these
2108
2593
  // monotonic revisions.
2109
- continuationWakeRevision: bigint("continuation_wake_revision", { mode: "number" })
2594
+ continuationWakeRevision: bigint("continuation_wake_revision", {
2595
+ mode: "number",
2596
+ })
2110
2597
  .notNull()
2111
2598
  .default(0),
2112
- continuationObservedRevision: bigint("continuation_observed_revision", { mode: "number" })
2599
+ continuationObservedRevision: bigint("continuation_observed_revision", {
2600
+ mode: "number",
2601
+ })
2113
2602
  .notNull()
2114
2603
  .default(0),
2115
2604
  metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
@@ -2322,6 +2811,14 @@ export const agentRunStates = pgTable("agent_run_states", {
2322
2811
  // correct either way). NULL on both sides (non-codex freeze + non-codex
2323
2812
  // resume) is a no-op, so single-account and non-codex sessions are unchanged.
2324
2813
  frozenCodexCredentialId: uuid("frozen_codex_credential_id"),
2814
+ // Exact provider rejection invalidates only the opaque reasoning identity
2815
+ // inside this frozen state. The serialized receipt remains durable and
2816
+ // auditable; the resume path neutralizes its provider-bound identity.
2817
+ providerArtifactInvalidatedAt: timestamp("provider_artifact_invalidated_at", {
2818
+ withTimezone: true,
2819
+ }),
2820
+ providerArtifactInvalidationReason: text("provider_artifact_invalidation_reason"),
2821
+ providerArtifactInvalidatedByAttemptId: uuid("provider_artifact_invalidated_by_attempt_id"),
2325
2822
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2326
2823
  });
2327
2824
 
@@ -2451,6 +2948,16 @@ export const sessionHistoryItems = pgTable(
2451
2948
  // (an ON DELETE SET NULL would erase the tag, and a stale-but-null tag still
2452
2949
  // mismatches a live codex id so the strip stays correct either way).
2453
2950
  producerCodexCredentialId: uuid("producer_codex_credential_id"),
2951
+ // An exact provider 400 can prove that an otherwise same-credential opaque
2952
+ // reasoning artifact is no longer decryptable. Keep the original item and
2953
+ // producer provenance immutable, but record the attempt-fenced rejection so
2954
+ // later model reads omit only the provider-bound identity. No FK: the receipt
2955
+ // must outlive operational attempt retention just like producer provenance.
2956
+ providerArtifactInvalidatedAt: timestamp("provider_artifact_invalidated_at", {
2957
+ withTimezone: true,
2958
+ }),
2959
+ providerArtifactInvalidationReason: text("provider_artifact_invalidation_reason"),
2960
+ providerArtifactInvalidatedByAttemptId: uuid("provider_artifact_invalidated_by_attempt_id"),
2454
2961
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2455
2962
  },
2456
2963
  (table) => ({
@@ -2543,6 +3050,134 @@ export const sandboxSessionEnvelopes = pgTable(
2543
3050
  }),
2544
3051
  );
2545
3052
 
3053
+ export const sandboxCheckpointArtifactStateValues = [
3054
+ "candidate",
3055
+ "current",
3056
+ "previous",
3057
+ "delete_pending",
3058
+ "deleting",
3059
+ "delete_failed",
3060
+ "deleted",
3061
+ ] as const;
3062
+
3063
+ /**
3064
+ * Durable ownership ledger for provider-native workspace checkpoints. These
3065
+ * rows intentionally have no cascading parent FK: a workspace/lease can vanish
3066
+ * before the provider object is deleted, and global GC still needs the exact
3067
+ * non-secret provider binding and object id after that deletion.
3068
+ */
3069
+ export const sandboxCheckpointArtifacts = pgTable(
3070
+ "sandbox_checkpoint_artifacts",
3071
+ {
3072
+ id: uuid("id").primaryKey().defaultRandom(),
3073
+ accountId: uuid("account_id").notNull(),
3074
+ workspaceId: uuid("workspace_id").notNull(),
3075
+ sandboxGroupId: uuid("sandbox_group_id").notNull(),
3076
+ sourceLeaseId: uuid("source_lease_id").notNull(),
3077
+ sourceLeaseEpoch: integer("source_lease_epoch").notNull(),
3078
+ sourceInstanceId: text("source_instance_id"),
3079
+ sourceWorkspaceGeneration: integer("source_workspace_generation"),
3080
+ provenance: text("provenance", {
3081
+ enum: ["native_capture", "legacy_provider_adopted"],
3082
+ }).notNull(),
3083
+ providerBackend: text("provider_backend").notNull(),
3084
+ providerBindingKey: text("provider_binding_key").notNull(),
3085
+ providerBinding: jsonb("provider_binding").$type<Record<string, unknown>>().notNull(),
3086
+ objectKind: text("object_kind", {
3087
+ enum: ["modal_filesystem_snapshot", "modal_directory_snapshot"],
3088
+ }).notNull(),
3089
+ objectId: text("object_id").notNull(),
3090
+ archiveBase64: text("archive_base64").notNull(),
3091
+ archiveSha256: text("archive_sha256").notNull(),
3092
+ archiveBytes: integer("archive_bytes").notNull(),
3093
+ descriptor: jsonb("descriptor").$type<Record<string, unknown>>().notNull(),
3094
+ descriptorRevision: text("descriptor_revision").notNull(),
3095
+ state: text("state", { enum: sandboxCheckpointArtifactStateValues })
3096
+ .notNull()
3097
+ .default("candidate"),
3098
+ deleteAfter: timestamp("delete_after", { withTimezone: true }),
3099
+ deleteAttempts: integer("delete_attempts").notNull().default(0),
3100
+ deleteClaimId: uuid("delete_claim_id"),
3101
+ deleteClaimedAt: timestamp("delete_claimed_at", { withTimezone: true }),
3102
+ lastDeleteError: text("last_delete_error"),
3103
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
3104
+ publishedAt: timestamp("published_at", { withTimezone: true }),
3105
+ deletedAt: timestamp("deleted_at", { withTimezone: true }),
3106
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
3107
+ },
3108
+ (table) => ({
3109
+ providerObject: uniqueIndex("sandbox_checkpoint_artifacts_provider_object_uq").on(
3110
+ table.providerBackend,
3111
+ table.providerBindingKey,
3112
+ table.objectId,
3113
+ ),
3114
+ gc: index("sandbox_checkpoint_artifacts_gc_idx")
3115
+ .on(table.deleteAfter, table.createdAt, table.id)
3116
+ .where(
3117
+ sql`${table.state} in (
3118
+ 'candidate', 'current', 'previous',
3119
+ 'delete_pending', 'delete_failed', 'deleting'
3120
+ )`,
3121
+ ),
3122
+ source: index("sandbox_checkpoint_artifacts_source_idx").on(
3123
+ table.workspaceId,
3124
+ table.sandboxGroupId,
3125
+ table.sourceLeaseId,
3126
+ ),
3127
+ sourceValid: check(
3128
+ "sandbox_checkpoint_artifacts_source_check",
3129
+ sql`${table.sourceLeaseEpoch} >= 0
3130
+ and (
3131
+ (
3132
+ ${table.provenance} = 'native_capture'
3133
+ and ${table.sourceWorkspaceGeneration} is not null
3134
+ and ${table.sourceWorkspaceGeneration} >= 0
3135
+ and ${table.sourceInstanceId} is not null
3136
+ and octet_length(${table.sourceInstanceId}) between 1 and 512
3137
+ )
3138
+ or (
3139
+ ${table.provenance} = 'legacy_provider_adopted'
3140
+ and ${table.sourceWorkspaceGeneration} is null
3141
+ and ${table.sourceInstanceId} is null
3142
+ )
3143
+ )`,
3144
+ ),
3145
+ providerValid: check(
3146
+ "sandbox_checkpoint_artifacts_provider_check",
3147
+ sql`${table.providerBackend} = 'modal'
3148
+ and octet_length(${table.providerBindingKey}) between 1 and 1024
3149
+ and jsonb_typeof(${table.providerBinding}) = 'object'
3150
+ and ${table.providerBindingKey}::jsonb = ${table.providerBinding}
3151
+ and ${table.objectKind} in ('modal_filesystem_snapshot', 'modal_directory_snapshot')
3152
+ and octet_length(${table.objectId}) between 1 and 1024`,
3153
+ ),
3154
+ archiveValid: check(
3155
+ "sandbox_checkpoint_artifacts_archive_check",
3156
+ sql`${table.archiveBytes} > 0
3157
+ and octet_length(${table.archiveBase64}) > 0
3158
+ and ${table.archiveSha256} ~ '^[0-9a-f]{64}$'
3159
+ and jsonb_typeof(${table.descriptor}) = 'object'
3160
+ and octet_length(${table.descriptorRevision}) between 1 and 256`,
3161
+ ),
3162
+ stateValid: check(
3163
+ "sandbox_checkpoint_artifacts_state_check",
3164
+ sql`${table.state} in (
3165
+ 'candidate', 'current', 'previous', 'delete_pending',
3166
+ 'deleting', 'delete_failed', 'deleted'
3167
+ )`,
3168
+ ),
3169
+ deleteClaimValid: check(
3170
+ "sandbox_checkpoint_artifacts_delete_claim_check",
3171
+ sql`(${table.state} = 'deleting'
3172
+ and ${table.deleteClaimId} is not null
3173
+ and ${table.deleteClaimedAt} is not null)
3174
+ or (${table.state} <> 'deleting'
3175
+ and ${table.deleteClaimId} is null
3176
+ and ${table.deleteClaimedAt} is null)`,
3177
+ ),
3178
+ }),
3179
+ );
3180
+
2546
3181
  // The 4 liveness states of the singleton lease. Exported so the query layer and
2547
3182
  // the stateless resume-by-id path share one source of truth for the domain.
2548
3183
  export const sandboxLeaseLivenessValues = ["cold", "warming", "warm", "draining"] as const;
@@ -2578,14 +3213,14 @@ export const sandboxLeases = pgTable(
2578
3213
  // The container IMAGE the group box runs (Modal image ref / docker image). A shared
2579
3214
  // box is SHARED STATE: all its sessions run the SAME filesystem, so they must run the
2580
3215
  // same image. This column stamps the image the live box was created with; a resume
2581
- // whose resolved image DIFFERS is a conflict (B3): a solo holder recreates the box on
2582
- // the new image, N-holders are rejected (SandboxImageConflictError). Nullable — a
3216
+ // whose resolved image DIFFERS is a conflict (B3): a solo holder requests a
3217
+ // capture-and-drain rotation; N-holders are rejected (SandboxImageConflictError). Nullable — a
2583
3218
  // legacy/cold row reads NULL = "image unknown", which never conflicts.
2584
3219
  image: text("image"),
2585
3220
  // The frozen rig version the live box was created under (M3). Like `image`,
2586
3221
  // this is SHARED STATE: all the box's sessions run the same rig-baked setup,
2587
- // so a resume resolving a DIFFERENT rig_version_id conflicts (solo holder
2588
- // recreates cold on the new rig; N-holders throw SandboxRigConflictError).
3222
+ // so a resume resolving a DIFFERENT rig_version_id conflicts (a solo holder
3223
+ // requests capture-and-drain rotation; N-holders throw SandboxRigConflictError).
2589
3224
  // Nullable — a legacy/cold row or a rig-less session reads NULL = "rig
2590
3225
  // unknown", which never conflicts. No FK (symmetric with sandbox_group_id's
2591
3226
  // bare-uuid rationale: this lease outlives no single rig_versions row's RLS).
@@ -2611,6 +3246,19 @@ export const sandboxLeases = pgTable(
2611
3246
  // the same row update; equality is the only durable completeness proof.
2612
3247
  workspaceGeneration: integer("workspace_generation").notNull().default(0),
2613
3248
  archiveGeneration: integer("archive_generation"),
3249
+ // Provider-native capture may pause the live box. The exact claim is
3250
+ // acquired before provider I/O and cleared only after that capture settles;
3251
+ // new holders and workspace mutations fence on it. The SQL constraint also
3252
+ // requires the claimed generation to remain current, so an unaware writer
3253
+ // cannot advance generation through an active capture.
3254
+ archiveCaptureId: uuid("archive_capture_id"),
3255
+ archiveCaptureGeneration: integer("archive_capture_generation"),
3256
+ archiveCaptureStartedAt: timestamp("archive_capture_started_at", {
3257
+ withTimezone: true,
3258
+ }),
3259
+ archiveCaptureDeadlineAt: timestamp("archive_capture_deadline_at", {
3260
+ withTimezone: true,
3261
+ }),
2614
3262
 
2615
3263
  // The group box-envelope (the "envelope split" Critical): the small recovery
2616
3264
  // descriptor to resume()-by-id the group's box without a per-session join.
@@ -2623,6 +3271,22 @@ export const sandboxLeases = pgTable(
2623
3271
  lastMeterAt: timestamp("last_meter_at", { withTimezone: true }),
2624
3272
  lastMeterTick: integer("last_meter_tick").notNull().default(0),
2625
3273
 
3274
+ providerCreatedAt: timestamp("provider_created_at", { withTimezone: true }),
3275
+ providerDeadlineAt: timestamp("provider_deadline_at", {
3276
+ withTimezone: true,
3277
+ }),
3278
+ rotationRequestedAt: timestamp("rotation_requested_at", {
3279
+ withTimezone: true,
3280
+ }),
3281
+ rotationReason: text("rotation_reason", {
3282
+ enum: ["provider_deadline", "operator"],
3283
+ }),
3284
+ // The SQL migration owns the two DEFERRABLE foreign keys and deferred
3285
+ // scope/state constraint triggers. Drizzle does not model deferrability, so
3286
+ // these remain bare UUIDs here rather than generating a stricter wrong FK.
3287
+ currentCheckpointArtifactId: uuid("current_checkpoint_artifact_id"),
3288
+ previousCheckpointArtifactId: uuid("previous_checkpoint_artifact_id"),
3289
+
2626
3290
  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
2627
3291
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2628
3292
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -2646,6 +3310,13 @@ export const sandboxLeases = pgTable(
2646
3310
  expiredDrainingInventory: index("sandbox_leases_expired_draining_inventory_idx")
2647
3311
  .on(table.expiresAt, table.backend)
2648
3312
  .where(sql`${table.liveness} = 'draining'`),
3313
+ providerDeadline: index("sandbox_leases_provider_deadline_idx")
3314
+ .on(table.providerDeadlineAt, table.id)
3315
+ .where(
3316
+ sql`${table.backend} = 'modal'
3317
+ and ${table.liveness} in ('warming', 'warm')
3318
+ and ${table.rotationRequestedAt} is null`,
3319
+ ),
2649
3320
  workspaceGenerationValid: check(
2650
3321
  "sandbox_leases_workspace_generation_check",
2651
3322
  sql`${table.workspaceGeneration} >= 0`,
@@ -2656,6 +3327,43 @@ export const sandboxLeases = pgTable(
2656
3327
  or (${table.archiveGeneration} >= 0
2657
3328
  and ${table.archiveGeneration} <= ${table.workspaceGeneration})`,
2658
3329
  ),
3330
+ archiveCaptureValid: check(
3331
+ "sandbox_leases_archive_capture_check",
3332
+ sql`(
3333
+ ${table.archiveCaptureId} is null
3334
+ and ${table.archiveCaptureGeneration} is null
3335
+ and ${table.archiveCaptureStartedAt} is null
3336
+ and ${table.archiveCaptureDeadlineAt} is null
3337
+ ) or (
3338
+ ${table.archiveCaptureId} is not null
3339
+ and ${table.archiveCaptureGeneration} is not null
3340
+ and ${table.archiveCaptureGeneration} = ${table.workspaceGeneration}
3341
+ and ${table.archiveCaptureStartedAt} is not null
3342
+ and ${table.archiveCaptureDeadlineAt} > ${table.archiveCaptureStartedAt}
3343
+ )`,
3344
+ ),
3345
+ archiveCaptureDeadline: index("sandbox_leases_archive_capture_deadline_idx")
3346
+ .on(table.archiveCaptureDeadlineAt, table.id)
3347
+ .where(sql`${table.archiveCaptureId} is not null`),
3348
+ providerDeadlineValid: check(
3349
+ "sandbox_leases_provider_deadline_check",
3350
+ sql`(${table.providerCreatedAt} is null and ${table.providerDeadlineAt} is null)
3351
+ or (${table.providerCreatedAt} is not null
3352
+ and ${table.providerDeadlineAt} is not null
3353
+ and ${table.providerDeadlineAt} > ${table.providerCreatedAt})`,
3354
+ ),
3355
+ rotationValid: check(
3356
+ "sandbox_leases_rotation_check",
3357
+ sql`(${table.rotationRequestedAt} is null and ${table.rotationReason} is null)
3358
+ or (${table.rotationRequestedAt} is not null
3359
+ and ${table.rotationReason} in ('provider_deadline', 'operator'))`,
3360
+ ),
3361
+ checkpointDistinct: check(
3362
+ "sandbox_leases_checkpoint_distinct_check",
3363
+ sql`${table.currentCheckpointArtifactId} is null
3364
+ or ${table.previousCheckpointArtifactId} is null
3365
+ or ${table.currentCheckpointArtifactId} <> ${table.previousCheckpointArtifactId}`,
3366
+ ),
2659
3367
  }),
2660
3368
  );
2661
3369
 
@@ -2674,7 +3382,9 @@ export const sandboxLeaseHolders = pgTable(
2674
3382
  leaseId: uuid("lease_id")
2675
3383
  .notNull()
2676
3384
  .references(() => sandboxLeases.id, { onDelete: "cascade" }),
2677
- kind: text("kind", { enum: ["turn", "viewer", "direct", "process"] }).notNull(),
3385
+ kind: text("kind", {
3386
+ enum: ["turn", "viewer", "direct", "process"],
3387
+ }).notNull(),
2678
3388
  holderId: text("holder_id").notNull(),
2679
3389
  // The attributing session within the (possibly shared) group.
2680
3390
  subjectId: uuid("subject_id"),
@@ -2719,7 +3429,9 @@ export const sandboxWorkspaceMutationAdmissions = pgTable(
2719
3429
  .references(() => sandboxLeases.id, { onDelete: "cascade" }),
2720
3430
  sandboxGroupId: uuid("sandbox_group_id").notNull(),
2721
3431
  sessionId: uuid("session_id").notNull(),
2722
- actorKind: text("actor_kind", { enum: sandboxWorkspaceMutationActorKindValues }).notNull(),
3432
+ actorKind: text("actor_kind", {
3433
+ enum: sandboxWorkspaceMutationActorKindValues,
3434
+ }).notNull(),
2723
3435
  actorId: uuid("actor_id").notNull(),
2724
3436
  // Exact turn authority is present only for actor_kind='turn'. Direct HTTP
2725
3437
  // requests and retained processes never invent a turn or quiescence owner.
@@ -2866,7 +3578,9 @@ export const sandboxRetainedProcesses = pgTable(
2866
3578
  sandboxGroupId: uuid("sandbox_group_id").notNull(),
2867
3579
  parentAdmissionId: uuid("parent_admission_id").notNull(),
2868
3580
  holderId: text("holder_id").notNull(),
2869
- ownerActorKind: text("owner_actor_kind", { enum: ["turn", "direct"] }).notNull(),
3581
+ ownerActorKind: text("owner_actor_kind", {
3582
+ enum: ["turn", "direct"],
3583
+ }).notNull(),
2870
3584
  ownerActorId: uuid("owner_actor_id").notNull(),
2871
3585
  ownerTurnId: uuid("owner_turn_id"),
2872
3586
  ownerAttemptId: uuid("owner_attempt_id"),
@@ -2874,6 +3588,11 @@ export const sandboxRetainedProcesses = pgTable(
2874
3588
  leaseEpoch: integer("lease_epoch").notNull(),
2875
3589
  providerBackend: text("provider_backend").notNull(),
2876
3590
  providerInstanceId: text("provider_instance_id").notNull(),
3591
+ // Provider object ids are namespace-scoped. New Modal processes bind the
3592
+ // exact authenticated workspace before execution; legacy rows remain null
3593
+ // until a positive lookup proves which namespace owns the historical box.
3594
+ providerBindingKey: text("provider_binding_key"),
3595
+ providerBinding: jsonb("provider_binding").$type<Record<string, unknown>>(),
2877
3596
  routeKind: text("route_kind", { enum: ["home", "active"] }).notNull(),
2878
3597
  routeTargetId: uuid("route_target_id"),
2879
3598
  routeEpoch: integer("route_epoch").notNull(),
@@ -2889,13 +3608,19 @@ export const sandboxRetainedProcesses = pgTable(
2889
3608
  // never exit/loss proof.
2890
3609
  reconcileAfter: timestamp("reconcile_after", { withTimezone: true }).notNull().defaultNow(),
2891
3610
  reconcileClaimId: uuid("reconcile_claim_id"),
2892
- reconcileClaimedAt: timestamp("reconcile_claimed_at", { withTimezone: true }),
3611
+ reconcileClaimedAt: timestamp("reconcile_claimed_at", {
3612
+ withTimezone: true,
3613
+ }),
2893
3614
  reconcileAttempts: integer("reconcile_attempts").notNull().default(0),
2894
3615
  lastReconcileOutcome: text("last_reconcile_outcome"),
2895
- reconcileProofOutcome: text("reconcile_proof_outcome", { enum: ["exited", "lost"] }),
3616
+ reconcileProofOutcome: text("reconcile_proof_outcome", {
3617
+ enum: ["exited", "lost"],
3618
+ }),
2896
3619
  reconcileProofExitCode: integer("reconcile_proof_exit_code"),
2897
3620
  reconcileProofReason: text("reconcile_proof_reason"),
2898
- reconcileProofObservedAt: timestamp("reconcile_proof_observed_at", { withTimezone: true }),
3621
+ reconcileProofObservedAt: timestamp("reconcile_proof_observed_at", {
3622
+ withTimezone: true,
3623
+ }),
2899
3624
  },
2900
3625
  (table) => ({
2901
3626
  workspaceAccount: foreignKey({
@@ -2990,6 +3715,33 @@ export const sandboxRetainedProcesses = pgTable(
2990
3715
  sql`${table.settlementReason} is null
2991
3716
  or octet_length(${table.settlementReason}) between 1 and 512`,
2992
3717
  ),
3718
+ providerBindingValid: check(
3719
+ "sandbox_retained_processes_provider_binding_check",
3720
+ sql`(
3721
+ ${table.providerBindingKey} is null
3722
+ and ${table.providerBinding} is null
3723
+ ) or (
3724
+ ${table.providerBackend} = 'modal'
3725
+ and octet_length(${table.providerBindingKey}) between 1 and 1024
3726
+ and jsonb_typeof(${table.providerBinding}) = 'object'
3727
+ and ${table.providerBindingKey}::jsonb = ${table.providerBinding}
3728
+ and ${table.providerBindingKey} = format(
3729
+ '{"version":1,"serverUrl":%s,"workspaceName":%s,"environment":%s}',
3730
+ to_jsonb(${table.providerBinding} ->> 'serverUrl')::text,
3731
+ to_jsonb(${table.providerBinding} ->> 'workspaceName')::text,
3732
+ to_jsonb(${table.providerBinding} ->> 'environment')::text
3733
+ )
3734
+ and ${table.providerBinding} = jsonb_build_object(
3735
+ 'version', 1,
3736
+ 'serverUrl', ${table.providerBinding} ->> 'serverUrl',
3737
+ 'workspaceName', ${table.providerBinding} ->> 'workspaceName',
3738
+ 'environment', ${table.providerBinding} ->> 'environment'
3739
+ )
3740
+ and coalesce(octet_length(${table.providerBinding} ->> 'serverUrl'), 0) > 0
3741
+ and coalesce(octet_length(${table.providerBinding} ->> 'workspaceName'), 0) > 0
3742
+ and ${table.providerBinding} ->> 'environment' is not null
3743
+ )`,
3744
+ ),
2993
3745
  reconcileClaimValid: check(
2994
3746
  "sandbox_retained_processes_reconcile_claim_check",
2995
3747
  sql`(${table.reconcileClaimId} is null and ${table.reconcileClaimedAt} is null)
@@ -3020,7 +3772,8 @@ export const sandboxRetainedProcesses = pgTable(
3020
3772
  ${table.reconcileProofOutcome} = 'lost'
3021
3773
  and ${table.reconcileProofExitCode} is null
3022
3774
  and ${table.reconcileProofReason} in (
3023
- 'provider_session_lost_banner', 'provider_instance_not_found'
3775
+ 'provider_session_lost_banner', 'provider_instance_not_found',
3776
+ 'provider_instance_terminated'
3024
3777
  )
3025
3778
  and ${table.reconcileProofObservedAt} is not null
3026
3779
  )`,
@@ -3619,8 +4372,12 @@ export const githubInstallations = pgTable(
3619
4372
  githubActorId: bigint("github_actor_id", { mode: "number" }),
3620
4373
  githubActorLogin: text("github_actor_login"),
3621
4374
  authorityKind: text("authority_kind"),
3622
- authorityCheckedAt: timestamp("authority_checked_at", { withTimezone: true }),
3623
- authorityExpiresAt: timestamp("authority_expires_at", { withTimezone: true }),
4375
+ authorityCheckedAt: timestamp("authority_checked_at", {
4376
+ withTimezone: true,
4377
+ }),
4378
+ authorityExpiresAt: timestamp("authority_expires_at", {
4379
+ withTimezone: true,
4380
+ }),
3624
4381
  authorityNonce: text("authority_nonce"),
3625
4382
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
3626
4383
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -3805,6 +4562,102 @@ export const usageEvents = pgTable(
3805
4562
  }),
3806
4563
  );
3807
4564
 
4565
+ /**
4566
+ * Per model-call Insights facts. Additive observability only — never the billing
4567
+ * ledger. Written after an authoritative `agent.model.usage` emit.
4568
+ */
4569
+ export const modelCallFacts = pgTable(
4570
+ "model_call_facts",
4571
+ {
4572
+ id: uuid("id").primaryKey().defaultRandom(),
4573
+ accountId: uuid("account_id")
4574
+ .notNull()
4575
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
4576
+ workspaceId: uuid("workspace_id")
4577
+ .notNull()
4578
+ .references(() => workspaces.id, { onDelete: "cascade" }),
4579
+ sessionId: uuid("session_id").notNull(),
4580
+ turnId: uuid("turn_id").notNull(),
4581
+ turnAttemptId: uuid("turn_attempt_id"),
4582
+ sourceKey: text("source_key").notNull(),
4583
+ provider: text("provider").notNull(),
4584
+ providerApi: text("provider_api").notNull(),
4585
+ model: text("model").notNull(),
4586
+ billingPath: text("billing_path").notNull(),
4587
+ turnSource: text("turn_source"),
4588
+ initiatorKind: text("initiator_kind"),
4589
+ initiatorSubjectId: text("initiator_subject_id"),
4590
+ scheduledTaskId: uuid("scheduled_task_id"),
4591
+ inputTokens: bigint("input_tokens", { mode: "number" }),
4592
+ outputTokens: bigint("output_tokens", { mode: "number" }),
4593
+ cachedTokens: bigint("cached_tokens", { mode: "number" }),
4594
+ cacheWriteTokens: bigint("cache_write_tokens", { mode: "number" }),
4595
+ reasoningTokens: bigint("reasoning_tokens", { mode: "number" }),
4596
+ totalTokens: bigint("total_tokens", { mode: "number" }),
4597
+ pricedCostMicros: bigint("priced_cost_micros", { mode: "number" }).notNull().default(0),
4598
+ occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
4599
+ recordedAt: timestamp("recorded_at", { withTimezone: true }).notNull().defaultNow(),
4600
+ },
4601
+ (table) => ({
4602
+ workspaceTurnSource: uniqueIndex("model_call_facts_workspace_turn_source_uq").on(
4603
+ table.workspaceId,
4604
+ table.turnId,
4605
+ table.sourceKey,
4606
+ ),
4607
+ workspaceOccurred: index("model_call_facts_workspace_occurred_idx").on(
4608
+ table.workspaceId,
4609
+ table.occurredAt,
4610
+ ),
4611
+ workspaceProviderModelOccurred: index(
4612
+ "model_call_facts_workspace_provider_model_occurred_idx",
4613
+ ).on(table.workspaceId, table.provider, table.model, table.occurredAt),
4614
+ workspaceSessionOccurred: index("model_call_facts_workspace_session_occurred_idx").on(
4615
+ table.workspaceId,
4616
+ table.sessionId,
4617
+ table.occurredAt,
4618
+ ),
4619
+ workspaceScheduledTaskOccurred: index("model_call_facts_workspace_scheduled_task_occurred_idx")
4620
+ .on(table.workspaceId, table.scheduledTaskId, table.occurredAt)
4621
+ .where(sql`${table.scheduledTaskId} is not null`),
4622
+ workspaceAccount: foreignKey({
4623
+ name: "model_call_facts_workspace_account_fk",
4624
+ columns: [table.workspaceId, table.accountId],
4625
+ foreignColumns: [workspaces.id, workspaces.accountId],
4626
+ }).onDelete("cascade"),
4627
+ billingPathValid: check(
4628
+ "model_call_facts_billing_path_check",
4629
+ sql`${table.billingPath} in ('opengeni_credits', 'external')`,
4630
+ ),
4631
+ pricedCostNonNegative: check(
4632
+ "model_call_facts_priced_cost_check",
4633
+ sql`${table.pricedCostMicros} >= 0`,
4634
+ ),
4635
+ initiatorConsistent: check(
4636
+ "model_call_facts_initiator_check",
4637
+ sql`(${table.initiatorKind} is null and ${table.initiatorSubjectId} is null)
4638
+ or (${table.initiatorKind} in ('subject', 'service')
4639
+ and ${table.initiatorSubjectId} is not null
4640
+ and octet_length(${table.initiatorSubjectId}) between 1 and 1024)`,
4641
+ ),
4642
+ sourceKeyBytes: check(
4643
+ "model_call_facts_source_key_bytes_check",
4644
+ sql`octet_length(${table.sourceKey}) between 1 and 1024`,
4645
+ ),
4646
+ providerBytes: check(
4647
+ "model_call_facts_provider_bytes_check",
4648
+ sql`octet_length(${table.provider}) between 1 and 256`,
4649
+ ),
4650
+ providerApiBytes: check(
4651
+ "model_call_facts_provider_api_bytes_check",
4652
+ sql`octet_length(${table.providerApi}) between 1 and 256`,
4653
+ ),
4654
+ modelBytes: check(
4655
+ "model_call_facts_model_bytes_check",
4656
+ sql`octet_length(${table.model}) between 1 and 512`,
4657
+ ),
4658
+ }),
4659
+ );
4660
+
3808
4661
  /** Singleton, migration-installed gate. Standalone defaults keep both off. */
3809
4662
  export const hostExportConfig = pgTable(
3810
4663
  "host_export_config",
@@ -3854,7 +4707,9 @@ export const hostExportOutbox = pgTable(
3854
4707
  payload: jsonb("payload").$type<unknown>().notNull(),
3855
4708
  envelopeBytes: integer("envelope_bytes").notNull(),
3856
4709
  occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
3857
- sourceRecordedAt: timestamp("source_recorded_at", { withTimezone: true }).notNull(),
4710
+ sourceRecordedAt: timestamp("source_recorded_at", {
4711
+ withTimezone: true,
4712
+ }).notNull(),
3858
4713
  enqueuedAt: timestamp("enqueued_at", { withTimezone: true }).notNull(),
3859
4714
  },
3860
4715
  (table) => ({
@@ -4439,3 +5294,4 @@ export const rigChanges = pgTable(
4439
5294
  );
4440
5295
 
4441
5296
  export * from "./workspace-instruction-policies-schema";
5297
+ export * from "./preference-registry-schema";