@opengeni/db 0.14.3 → 0.16.2

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 (63) hide show
  1. package/dist/{chunk-ELMUCYZF.js → chunk-4RUK5CON.js} +183 -42
  2. package/dist/chunk-4RUK5CON.js.map +1 -0
  3. package/dist/chunk-HZD7KVAR.js +4648 -0
  4. package/dist/chunk-HZD7KVAR.js.map +1 -0
  5. package/dist/{chunk-Y5WZZVQK.js → chunk-SK7YYHBI.js} +5 -2
  6. package/dist/chunk-SK7YYHBI.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 +6217 -10
  12. package/dist/index.js +6930 -2708
  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 +23533 -3
  28. package/dist/schema.js +17 -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-instruction-policies-schema.d.ts +735 -0
  34. package/dist/workspace-instruction-policies.d.ts +64 -0
  35. package/drizzle/0136_unified_session_tool_policy.sql +1 -1
  36. package/drizzle/0137_preference_registry.sql +1347 -0
  37. package/drizzle/0138_sandbox_checkpoint_artifacts_and_deadlines.sql +1074 -0
  38. package/drizzle/0139_codex_provider_artifact_invalidations.sql +51 -0
  39. package/drizzle/0140_sandbox_restore_and_reaper_fences.sql +276 -0
  40. package/drizzle/0142_sandbox_archive_capture_gate.sql +80 -0
  41. package/drizzle/0143_session_codex_compaction_mode.sql +20 -0
  42. package/drizzle/0144_sandbox_viewer_force_drain_gate.sql +95 -0
  43. package/drizzle/0145_model_call_facts.sql +96 -0
  44. package/drizzle/0146_slack_bot_delete_idempotency.sql +105 -0
  45. package/drizzle/0147_draft_latency_mode.sql +12 -0
  46. package/drizzle/0148_session_turn_latency_mode.sql +12 -0
  47. package/package.json +6 -6
  48. package/src/index.ts +4995 -421
  49. package/src/insights.ts +837 -0
  50. package/src/migrate.ts +9 -1
  51. package/src/new-session-drafts.ts +4 -0
  52. package/src/preference-registry-schema.ts +170 -0
  53. package/src/preference-registry.ts +1220 -0
  54. package/src/provision-roles.ts +95 -22
  55. package/src/role-relationships.ts +132 -0
  56. package/src/runtime-posture.ts +28 -26
  57. package/src/schema.ts +478 -5
  58. package/src/session-queue-commands.ts +39 -6
  59. package/dist/chunk-DW24CKCT.js +0 -4046
  60. package/dist/chunk-DW24CKCT.js.map +0 -1
  61. package/dist/chunk-ELMUCYZF.js.map +0 -1
  62. package/dist/chunk-Y5WZZVQK.js.map +0 -1
  63. 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,19 @@ 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
+ ),
85
109
  }),
86
110
  );
87
111
 
@@ -599,6 +623,90 @@ export const slackBotPostOperations = pgTable(
599
623
  }),
600
624
  );
601
625
 
626
+ // Durable provider-operation identity for OpenGeni Slack bot deletions. Slack
627
+ // has no client-supplied idempotency key for chat.delete, so an expired
628
+ // provider_started claim becomes outcome_unknown and must be reconciled before
629
+ // another mutation is admitted.
630
+ export const slackBotDeleteOperations = pgTable(
631
+ "slack_bot_delete_operations",
632
+ {
633
+ id: uuid("id").primaryKey().defaultRandom(),
634
+ accountId: uuid("account_id")
635
+ .notNull()
636
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
637
+ workspaceId: uuid("workspace_id")
638
+ .notNull()
639
+ .references(() => workspaces.id, { onDelete: "cascade" }),
640
+ connectionId: uuid("connection_id")
641
+ .notNull()
642
+ .references(() => connections.id, { onDelete: "cascade" }),
643
+ operationId: uuid("operation_id").notNull(),
644
+ principalType: text("principal_type").$type<"subject" | "service">().notNull(),
645
+ principalId: text("principal_id").notNull(),
646
+ toolName: text("tool_name").notNull(),
647
+ channelId: text("channel_id").notNull(),
648
+ messageTimestamp: text("message_timestamp").notNull(),
649
+ requestDigest: text("request_digest").notNull(),
650
+ status: text("status")
651
+ .$type<"pending" | "provider_started" | "outcome_unknown" | "completed">()
652
+ .notNull(),
653
+ claimHolderId: uuid("claim_holder_id"),
654
+ claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
655
+ attemptCount: integer("attempt_count").notNull().default(0),
656
+ lastFailureCode: text("last_failure_code"),
657
+ slackChannelId: text("slack_channel_id"),
658
+ slackMessageTimestamp: text("slack_message_timestamp"),
659
+ completedAt: timestamp("completed_at", { withTimezone: true }),
660
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
661
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
662
+ },
663
+ (table) => ({
664
+ workspaceOperation: uniqueIndex("slack_bot_delete_operations_workspace_operation_uq").on(
665
+ table.workspaceId,
666
+ table.operationId,
667
+ ),
668
+ workspaceStatus: index("slack_bot_delete_operations_workspace_status_idx").on(
669
+ table.workspaceId,
670
+ table.status,
671
+ table.updatedAt,
672
+ ),
673
+ principalValid: check(
674
+ "slack_bot_delete_operations_principal_check",
675
+ sql`${table.principalType} in ('subject', 'service')
676
+ and length(${table.principalId}) between 1 and 512`,
677
+ ),
678
+ identityValid: check(
679
+ "slack_bot_delete_operations_identity_check",
680
+ sql`${table.toolName} = 'slack_bot_delete_message'
681
+ and length(${table.channelId}) between 1 and 64
682
+ and length(${table.messageTimestamp}) between 1 and 64
683
+ and ${table.requestDigest} ~ '^[0-9a-f]{64}$'
684
+ and ${table.attemptCount} > 0
685
+ and ((${table.claimHolderId} is null) = (${table.claimExpiresAt} is null))`,
686
+ ),
687
+ statusValid: check(
688
+ "slack_bot_delete_operations_status_check",
689
+ sql`${table.status} in ('pending', 'provider_started', 'outcome_unknown', 'completed')`,
690
+ ),
691
+ completionValid: check(
692
+ "slack_bot_delete_operations_completion_check",
693
+ sql`(
694
+ ${table.status} <> 'completed'
695
+ and ${table.slackChannelId} is null
696
+ and ${table.slackMessageTimestamp} is null
697
+ and ${table.completedAt} is null
698
+ ) or (
699
+ ${table.status} = 'completed'
700
+ and ${table.claimHolderId} is null
701
+ and ${table.claimExpiresAt} is null
702
+ and ${table.slackChannelId} is not null
703
+ and ${table.slackMessageTimestamp} is not null
704
+ and ${table.completedAt} is not null
705
+ )`,
706
+ ),
707
+ }),
708
+ );
709
+
602
710
  // OAuth client registrations minted through MCP DCR, keyed by authorization
603
711
  // server issuer. This is deployment-wide client identity, not a workspace
604
712
  // credential; per-user/provider tokens still live only in connections.
@@ -916,6 +1024,10 @@ export const sessions = pgTable(
916
1024
  // (manual|policy) lives in the migration; no FK (it describes the pin, not an
917
1025
  // account).
918
1026
  codexPinSource: text("codex_pin_source"),
1027
+ // Frozen at create: remote_v2 (Codex remote compaction + Codex-only models)
1028
+ // or portable (plaintext compaction + free provider switching). Existing
1029
+ // rows backfill to portable. CHECK lives in the migration.
1030
+ codexCompactionMode: text("codex_compaction_mode").notNull().default("portable"),
919
1031
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
920
1032
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
921
1033
  // Assigned by the database trigger whenever canonical updated_at activity
@@ -1473,6 +1585,8 @@ export const sessionTurns = pgTable(
1473
1585
  toolsProvided: boolean("tools_provided").notNull().default(false),
1474
1586
  model: text("model").notNull(),
1475
1587
  reasoningEffort: text("reasoning_effort").notNull(),
1588
+ // Peer of model + reasoning_effort for Fast/priority inheritance.
1589
+ latencyMode: text("latency_mode").notNull().default("standard"),
1476
1590
  sandboxBackend: text("sandbox_backend").notNull(),
1477
1591
  // Per-turn OS override. NULL = inherit the session's sandbox_os. CHECK-
1478
1592
  // constrained to the SandboxOs enum (or NULL) in migration 0018.
@@ -1519,6 +1633,10 @@ export const sessionTurns = pgTable(
1519
1633
  oneCurrentInference: uniqueIndex("session_turns_one_current_inference_uq")
1520
1634
  .on(table.workspaceId, table.sessionId)
1521
1635
  .where(sql`${table.status} in ('running','requires_action','recovering','waiting_capacity')`),
1636
+ latencyModeValid: check(
1637
+ "session_turns_latency_mode_check",
1638
+ sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
1639
+ ),
1522
1640
  }),
1523
1641
  );
1524
1642
 
@@ -1828,6 +1946,7 @@ export const composerDrafts = pgTable(
1828
1946
  toolsProvided: boolean("tools_provided").notNull().default(false),
1829
1947
  model: text("model").notNull(),
1830
1948
  reasoningEffort: text("reasoning_effort").notNull(),
1949
+ latencyMode: text("latency_mode").notNull().default("standard"),
1831
1950
  sourceTurnId: uuid("source_turn_id"),
1832
1951
  sourceTurnVersion: integer("source_turn_version"),
1833
1952
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
@@ -1859,6 +1978,10 @@ export const composerDrafts = pgTable(
1859
1978
  sql`length(btrim(${table.subjectId})) > 0`,
1860
1979
  ),
1861
1980
  revisionValid: check("composer_drafts_revision_check", sql`${table.revision} >= 1`),
1981
+ latencyModeValid: check(
1982
+ "composer_drafts_latency_mode_check",
1983
+ sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
1984
+ ),
1862
1985
  }),
1863
1986
  );
1864
1987
 
@@ -1877,6 +2000,7 @@ export const newSessionDrafts = pgTable(
1877
2000
  tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
1878
2001
  model: text("model").notNull(),
1879
2002
  reasoningEffort: text("reasoning_effort").notNull(),
2003
+ latencyMode: text("latency_mode").notNull().default("standard"),
1880
2004
  sessionOptions: jsonb("session_options").$type<Record<string, unknown>>().notNull().default({}),
1881
2005
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
1882
2006
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -1896,6 +2020,10 @@ export const newSessionDrafts = pgTable(
1896
2020
  sql`length(btrim(${table.subjectId})) > 0`,
1897
2021
  ),
1898
2022
  revisionValid: check("new_session_drafts_revision_check", sql`${table.revision} >= 1`),
2023
+ latencyModeValid: check(
2024
+ "new_session_drafts_latency_mode_check",
2025
+ sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
2026
+ ),
1899
2027
  }),
1900
2028
  );
1901
2029
 
@@ -2322,6 +2450,14 @@ export const agentRunStates = pgTable("agent_run_states", {
2322
2450
  // correct either way). NULL on both sides (non-codex freeze + non-codex
2323
2451
  // resume) is a no-op, so single-account and non-codex sessions are unchanged.
2324
2452
  frozenCodexCredentialId: uuid("frozen_codex_credential_id"),
2453
+ // Exact provider rejection invalidates only the opaque reasoning identity
2454
+ // inside this frozen state. The serialized receipt remains durable and
2455
+ // auditable; the resume path neutralizes its provider-bound identity.
2456
+ providerArtifactInvalidatedAt: timestamp("provider_artifact_invalidated_at", {
2457
+ withTimezone: true,
2458
+ }),
2459
+ providerArtifactInvalidationReason: text("provider_artifact_invalidation_reason"),
2460
+ providerArtifactInvalidatedByAttemptId: uuid("provider_artifact_invalidated_by_attempt_id"),
2325
2461
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2326
2462
  });
2327
2463
 
@@ -2451,6 +2587,16 @@ export const sessionHistoryItems = pgTable(
2451
2587
  // (an ON DELETE SET NULL would erase the tag, and a stale-but-null tag still
2452
2588
  // mismatches a live codex id so the strip stays correct either way).
2453
2589
  producerCodexCredentialId: uuid("producer_codex_credential_id"),
2590
+ // An exact provider 400 can prove that an otherwise same-credential opaque
2591
+ // reasoning artifact is no longer decryptable. Keep the original item and
2592
+ // producer provenance immutable, but record the attempt-fenced rejection so
2593
+ // later model reads omit only the provider-bound identity. No FK: the receipt
2594
+ // must outlive operational attempt retention just like producer provenance.
2595
+ providerArtifactInvalidatedAt: timestamp("provider_artifact_invalidated_at", {
2596
+ withTimezone: true,
2597
+ }),
2598
+ providerArtifactInvalidationReason: text("provider_artifact_invalidation_reason"),
2599
+ providerArtifactInvalidatedByAttemptId: uuid("provider_artifact_invalidated_by_attempt_id"),
2454
2600
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2455
2601
  },
2456
2602
  (table) => ({
@@ -2543,6 +2689,134 @@ export const sandboxSessionEnvelopes = pgTable(
2543
2689
  }),
2544
2690
  );
2545
2691
 
2692
+ export const sandboxCheckpointArtifactStateValues = [
2693
+ "candidate",
2694
+ "current",
2695
+ "previous",
2696
+ "delete_pending",
2697
+ "deleting",
2698
+ "delete_failed",
2699
+ "deleted",
2700
+ ] as const;
2701
+
2702
+ /**
2703
+ * Durable ownership ledger for provider-native workspace checkpoints. These
2704
+ * rows intentionally have no cascading parent FK: a workspace/lease can vanish
2705
+ * before the provider object is deleted, and global GC still needs the exact
2706
+ * non-secret provider binding and object id after that deletion.
2707
+ */
2708
+ export const sandboxCheckpointArtifacts = pgTable(
2709
+ "sandbox_checkpoint_artifacts",
2710
+ {
2711
+ id: uuid("id").primaryKey().defaultRandom(),
2712
+ accountId: uuid("account_id").notNull(),
2713
+ workspaceId: uuid("workspace_id").notNull(),
2714
+ sandboxGroupId: uuid("sandbox_group_id").notNull(),
2715
+ sourceLeaseId: uuid("source_lease_id").notNull(),
2716
+ sourceLeaseEpoch: integer("source_lease_epoch").notNull(),
2717
+ sourceInstanceId: text("source_instance_id"),
2718
+ sourceWorkspaceGeneration: integer("source_workspace_generation"),
2719
+ provenance: text("provenance", {
2720
+ enum: ["native_capture", "legacy_provider_adopted"],
2721
+ }).notNull(),
2722
+ providerBackend: text("provider_backend").notNull(),
2723
+ providerBindingKey: text("provider_binding_key").notNull(),
2724
+ providerBinding: jsonb("provider_binding").$type<Record<string, unknown>>().notNull(),
2725
+ objectKind: text("object_kind", {
2726
+ enum: ["modal_filesystem_snapshot", "modal_directory_snapshot"],
2727
+ }).notNull(),
2728
+ objectId: text("object_id").notNull(),
2729
+ archiveBase64: text("archive_base64").notNull(),
2730
+ archiveSha256: text("archive_sha256").notNull(),
2731
+ archiveBytes: integer("archive_bytes").notNull(),
2732
+ descriptor: jsonb("descriptor").$type<Record<string, unknown>>().notNull(),
2733
+ descriptorRevision: text("descriptor_revision").notNull(),
2734
+ state: text("state", { enum: sandboxCheckpointArtifactStateValues })
2735
+ .notNull()
2736
+ .default("candidate"),
2737
+ deleteAfter: timestamp("delete_after", { withTimezone: true }),
2738
+ deleteAttempts: integer("delete_attempts").notNull().default(0),
2739
+ deleteClaimId: uuid("delete_claim_id"),
2740
+ deleteClaimedAt: timestamp("delete_claimed_at", { withTimezone: true }),
2741
+ lastDeleteError: text("last_delete_error"),
2742
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2743
+ publishedAt: timestamp("published_at", { withTimezone: true }),
2744
+ deletedAt: timestamp("deleted_at", { withTimezone: true }),
2745
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
2746
+ },
2747
+ (table) => ({
2748
+ providerObject: uniqueIndex("sandbox_checkpoint_artifacts_provider_object_uq").on(
2749
+ table.providerBackend,
2750
+ table.providerBindingKey,
2751
+ table.objectId,
2752
+ ),
2753
+ gc: index("sandbox_checkpoint_artifacts_gc_idx")
2754
+ .on(table.deleteAfter, table.createdAt, table.id)
2755
+ .where(
2756
+ sql`${table.state} in (
2757
+ 'candidate', 'current', 'previous',
2758
+ 'delete_pending', 'delete_failed', 'deleting'
2759
+ )`,
2760
+ ),
2761
+ source: index("sandbox_checkpoint_artifacts_source_idx").on(
2762
+ table.workspaceId,
2763
+ table.sandboxGroupId,
2764
+ table.sourceLeaseId,
2765
+ ),
2766
+ sourceValid: check(
2767
+ "sandbox_checkpoint_artifacts_source_check",
2768
+ sql`${table.sourceLeaseEpoch} >= 0
2769
+ and (
2770
+ (
2771
+ ${table.provenance} = 'native_capture'
2772
+ and ${table.sourceWorkspaceGeneration} is not null
2773
+ and ${table.sourceWorkspaceGeneration} >= 0
2774
+ and ${table.sourceInstanceId} is not null
2775
+ and octet_length(${table.sourceInstanceId}) between 1 and 512
2776
+ )
2777
+ or (
2778
+ ${table.provenance} = 'legacy_provider_adopted'
2779
+ and ${table.sourceWorkspaceGeneration} is null
2780
+ and ${table.sourceInstanceId} is null
2781
+ )
2782
+ )`,
2783
+ ),
2784
+ providerValid: check(
2785
+ "sandbox_checkpoint_artifacts_provider_check",
2786
+ sql`${table.providerBackend} = 'modal'
2787
+ and octet_length(${table.providerBindingKey}) between 1 and 1024
2788
+ and jsonb_typeof(${table.providerBinding}) = 'object'
2789
+ and ${table.providerBindingKey}::jsonb = ${table.providerBinding}
2790
+ and ${table.objectKind} in ('modal_filesystem_snapshot', 'modal_directory_snapshot')
2791
+ and octet_length(${table.objectId}) between 1 and 1024`,
2792
+ ),
2793
+ archiveValid: check(
2794
+ "sandbox_checkpoint_artifacts_archive_check",
2795
+ sql`${table.archiveBytes} > 0
2796
+ and octet_length(${table.archiveBase64}) > 0
2797
+ and ${table.archiveSha256} ~ '^[0-9a-f]{64}$'
2798
+ and jsonb_typeof(${table.descriptor}) = 'object'
2799
+ and octet_length(${table.descriptorRevision}) between 1 and 256`,
2800
+ ),
2801
+ stateValid: check(
2802
+ "sandbox_checkpoint_artifacts_state_check",
2803
+ sql`${table.state} in (
2804
+ 'candidate', 'current', 'previous', 'delete_pending',
2805
+ 'deleting', 'delete_failed', 'deleted'
2806
+ )`,
2807
+ ),
2808
+ deleteClaimValid: check(
2809
+ "sandbox_checkpoint_artifacts_delete_claim_check",
2810
+ sql`(${table.state} = 'deleting'
2811
+ and ${table.deleteClaimId} is not null
2812
+ and ${table.deleteClaimedAt} is not null)
2813
+ or (${table.state} <> 'deleting'
2814
+ and ${table.deleteClaimId} is null
2815
+ and ${table.deleteClaimedAt} is null)`,
2816
+ ),
2817
+ }),
2818
+ );
2819
+
2546
2820
  // The 4 liveness states of the singleton lease. Exported so the query layer and
2547
2821
  // the stateless resume-by-id path share one source of truth for the domain.
2548
2822
  export const sandboxLeaseLivenessValues = ["cold", "warming", "warm", "draining"] as const;
@@ -2578,14 +2852,14 @@ export const sandboxLeases = pgTable(
2578
2852
  // The container IMAGE the group box runs (Modal image ref / docker image). A shared
2579
2853
  // box is SHARED STATE: all its sessions run the SAME filesystem, so they must run the
2580
2854
  // 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
2855
+ // whose resolved image DIFFERS is a conflict (B3): a solo holder requests a
2856
+ // capture-and-drain rotation; N-holders are rejected (SandboxImageConflictError). Nullable — a
2583
2857
  // legacy/cold row reads NULL = "image unknown", which never conflicts.
2584
2858
  image: text("image"),
2585
2859
  // The frozen rig version the live box was created under (M3). Like `image`,
2586
2860
  // 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).
2861
+ // so a resume resolving a DIFFERENT rig_version_id conflicts (a solo holder
2862
+ // requests capture-and-drain rotation; N-holders throw SandboxRigConflictError).
2589
2863
  // Nullable — a legacy/cold row or a rig-less session reads NULL = "rig
2590
2864
  // unknown", which never conflicts. No FK (symmetric with sandbox_group_id's
2591
2865
  // bare-uuid rationale: this lease outlives no single rig_versions row's RLS).
@@ -2611,6 +2885,19 @@ export const sandboxLeases = pgTable(
2611
2885
  // the same row update; equality is the only durable completeness proof.
2612
2886
  workspaceGeneration: integer("workspace_generation").notNull().default(0),
2613
2887
  archiveGeneration: integer("archive_generation"),
2888
+ // Provider-native capture may pause the live box. The exact claim is
2889
+ // acquired before provider I/O and cleared only after that capture settles;
2890
+ // new holders and workspace mutations fence on it. The SQL constraint also
2891
+ // requires the claimed generation to remain current, so an unaware writer
2892
+ // cannot advance generation through an active capture.
2893
+ archiveCaptureId: uuid("archive_capture_id"),
2894
+ archiveCaptureGeneration: integer("archive_capture_generation"),
2895
+ archiveCaptureStartedAt: timestamp("archive_capture_started_at", {
2896
+ withTimezone: true,
2897
+ }),
2898
+ archiveCaptureDeadlineAt: timestamp("archive_capture_deadline_at", {
2899
+ withTimezone: true,
2900
+ }),
2614
2901
 
2615
2902
  // The group box-envelope (the "envelope split" Critical): the small recovery
2616
2903
  // descriptor to resume()-by-id the group's box without a per-session join.
@@ -2623,6 +2910,18 @@ export const sandboxLeases = pgTable(
2623
2910
  lastMeterAt: timestamp("last_meter_at", { withTimezone: true }),
2624
2911
  lastMeterTick: integer("last_meter_tick").notNull().default(0),
2625
2912
 
2913
+ providerCreatedAt: timestamp("provider_created_at", { withTimezone: true }),
2914
+ providerDeadlineAt: timestamp("provider_deadline_at", { withTimezone: true }),
2915
+ rotationRequestedAt: timestamp("rotation_requested_at", { withTimezone: true }),
2916
+ rotationReason: text("rotation_reason", {
2917
+ enum: ["provider_deadline", "operator"],
2918
+ }),
2919
+ // The SQL migration owns the two DEFERRABLE foreign keys and deferred
2920
+ // scope/state constraint triggers. Drizzle does not model deferrability, so
2921
+ // these remain bare UUIDs here rather than generating a stricter wrong FK.
2922
+ currentCheckpointArtifactId: uuid("current_checkpoint_artifact_id"),
2923
+ previousCheckpointArtifactId: uuid("previous_checkpoint_artifact_id"),
2924
+
2626
2925
  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
2627
2926
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2628
2927
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -2646,6 +2945,13 @@ export const sandboxLeases = pgTable(
2646
2945
  expiredDrainingInventory: index("sandbox_leases_expired_draining_inventory_idx")
2647
2946
  .on(table.expiresAt, table.backend)
2648
2947
  .where(sql`${table.liveness} = 'draining'`),
2948
+ providerDeadline: index("sandbox_leases_provider_deadline_idx")
2949
+ .on(table.providerDeadlineAt, table.id)
2950
+ .where(
2951
+ sql`${table.backend} = 'modal'
2952
+ and ${table.liveness} in ('warming', 'warm')
2953
+ and ${table.rotationRequestedAt} is null`,
2954
+ ),
2649
2955
  workspaceGenerationValid: check(
2650
2956
  "sandbox_leases_workspace_generation_check",
2651
2957
  sql`${table.workspaceGeneration} >= 0`,
@@ -2656,6 +2962,43 @@ export const sandboxLeases = pgTable(
2656
2962
  or (${table.archiveGeneration} >= 0
2657
2963
  and ${table.archiveGeneration} <= ${table.workspaceGeneration})`,
2658
2964
  ),
2965
+ archiveCaptureValid: check(
2966
+ "sandbox_leases_archive_capture_check",
2967
+ sql`(
2968
+ ${table.archiveCaptureId} is null
2969
+ and ${table.archiveCaptureGeneration} is null
2970
+ and ${table.archiveCaptureStartedAt} is null
2971
+ and ${table.archiveCaptureDeadlineAt} is null
2972
+ ) or (
2973
+ ${table.archiveCaptureId} is not null
2974
+ and ${table.archiveCaptureGeneration} is not null
2975
+ and ${table.archiveCaptureGeneration} = ${table.workspaceGeneration}
2976
+ and ${table.archiveCaptureStartedAt} is not null
2977
+ and ${table.archiveCaptureDeadlineAt} > ${table.archiveCaptureStartedAt}
2978
+ )`,
2979
+ ),
2980
+ archiveCaptureDeadline: index("sandbox_leases_archive_capture_deadline_idx")
2981
+ .on(table.archiveCaptureDeadlineAt, table.id)
2982
+ .where(sql`${table.archiveCaptureId} is not null`),
2983
+ providerDeadlineValid: check(
2984
+ "sandbox_leases_provider_deadline_check",
2985
+ sql`(${table.providerCreatedAt} is null and ${table.providerDeadlineAt} is null)
2986
+ or (${table.providerCreatedAt} is not null
2987
+ and ${table.providerDeadlineAt} is not null
2988
+ and ${table.providerDeadlineAt} > ${table.providerCreatedAt})`,
2989
+ ),
2990
+ rotationValid: check(
2991
+ "sandbox_leases_rotation_check",
2992
+ sql`(${table.rotationRequestedAt} is null and ${table.rotationReason} is null)
2993
+ or (${table.rotationRequestedAt} is not null
2994
+ and ${table.rotationReason} in ('provider_deadline', 'operator'))`,
2995
+ ),
2996
+ checkpointDistinct: check(
2997
+ "sandbox_leases_checkpoint_distinct_check",
2998
+ sql`${table.currentCheckpointArtifactId} is null
2999
+ or ${table.previousCheckpointArtifactId} is null
3000
+ or ${table.currentCheckpointArtifactId} <> ${table.previousCheckpointArtifactId}`,
3001
+ ),
2659
3002
  }),
2660
3003
  );
2661
3004
 
@@ -2874,6 +3217,11 @@ export const sandboxRetainedProcesses = pgTable(
2874
3217
  leaseEpoch: integer("lease_epoch").notNull(),
2875
3218
  providerBackend: text("provider_backend").notNull(),
2876
3219
  providerInstanceId: text("provider_instance_id").notNull(),
3220
+ // Provider object ids are namespace-scoped. New Modal processes bind the
3221
+ // exact authenticated workspace before execution; legacy rows remain null
3222
+ // until a positive lookup proves which namespace owns the historical box.
3223
+ providerBindingKey: text("provider_binding_key"),
3224
+ providerBinding: jsonb("provider_binding").$type<Record<string, unknown>>(),
2877
3225
  routeKind: text("route_kind", { enum: ["home", "active"] }).notNull(),
2878
3226
  routeTargetId: uuid("route_target_id"),
2879
3227
  routeEpoch: integer("route_epoch").notNull(),
@@ -2990,6 +3338,33 @@ export const sandboxRetainedProcesses = pgTable(
2990
3338
  sql`${table.settlementReason} is null
2991
3339
  or octet_length(${table.settlementReason}) between 1 and 512`,
2992
3340
  ),
3341
+ providerBindingValid: check(
3342
+ "sandbox_retained_processes_provider_binding_check",
3343
+ sql`(
3344
+ ${table.providerBindingKey} is null
3345
+ and ${table.providerBinding} is null
3346
+ ) or (
3347
+ ${table.providerBackend} = 'modal'
3348
+ and octet_length(${table.providerBindingKey}) between 1 and 1024
3349
+ and jsonb_typeof(${table.providerBinding}) = 'object'
3350
+ and ${table.providerBindingKey}::jsonb = ${table.providerBinding}
3351
+ and ${table.providerBindingKey} = format(
3352
+ '{"version":1,"serverUrl":%s,"workspaceName":%s,"environment":%s}',
3353
+ to_jsonb(${table.providerBinding} ->> 'serverUrl')::text,
3354
+ to_jsonb(${table.providerBinding} ->> 'workspaceName')::text,
3355
+ to_jsonb(${table.providerBinding} ->> 'environment')::text
3356
+ )
3357
+ and ${table.providerBinding} = jsonb_build_object(
3358
+ 'version', 1,
3359
+ 'serverUrl', ${table.providerBinding} ->> 'serverUrl',
3360
+ 'workspaceName', ${table.providerBinding} ->> 'workspaceName',
3361
+ 'environment', ${table.providerBinding} ->> 'environment'
3362
+ )
3363
+ and coalesce(octet_length(${table.providerBinding} ->> 'serverUrl'), 0) > 0
3364
+ and coalesce(octet_length(${table.providerBinding} ->> 'workspaceName'), 0) > 0
3365
+ and ${table.providerBinding} ->> 'environment' is not null
3366
+ )`,
3367
+ ),
2993
3368
  reconcileClaimValid: check(
2994
3369
  "sandbox_retained_processes_reconcile_claim_check",
2995
3370
  sql`(${table.reconcileClaimId} is null and ${table.reconcileClaimedAt} is null)
@@ -3020,7 +3395,8 @@ export const sandboxRetainedProcesses = pgTable(
3020
3395
  ${table.reconcileProofOutcome} = 'lost'
3021
3396
  and ${table.reconcileProofExitCode} is null
3022
3397
  and ${table.reconcileProofReason} in (
3023
- 'provider_session_lost_banner', 'provider_instance_not_found'
3398
+ 'provider_session_lost_banner', 'provider_instance_not_found',
3399
+ 'provider_instance_terminated'
3024
3400
  )
3025
3401
  and ${table.reconcileProofObservedAt} is not null
3026
3402
  )`,
@@ -3805,6 +4181,102 @@ export const usageEvents = pgTable(
3805
4181
  }),
3806
4182
  );
3807
4183
 
4184
+ /**
4185
+ * Per model-call Insights facts. Additive observability only — never the billing
4186
+ * ledger. Written after an authoritative `agent.model.usage` emit.
4187
+ */
4188
+ export const modelCallFacts = pgTable(
4189
+ "model_call_facts",
4190
+ {
4191
+ id: uuid("id").primaryKey().defaultRandom(),
4192
+ accountId: uuid("account_id")
4193
+ .notNull()
4194
+ .references(() => managedAccounts.id, { onDelete: "cascade" }),
4195
+ workspaceId: uuid("workspace_id")
4196
+ .notNull()
4197
+ .references(() => workspaces.id, { onDelete: "cascade" }),
4198
+ sessionId: uuid("session_id").notNull(),
4199
+ turnId: uuid("turn_id").notNull(),
4200
+ turnAttemptId: uuid("turn_attempt_id"),
4201
+ sourceKey: text("source_key").notNull(),
4202
+ provider: text("provider").notNull(),
4203
+ providerApi: text("provider_api").notNull(),
4204
+ model: text("model").notNull(),
4205
+ billingPath: text("billing_path").notNull(),
4206
+ turnSource: text("turn_source"),
4207
+ initiatorKind: text("initiator_kind"),
4208
+ initiatorSubjectId: text("initiator_subject_id"),
4209
+ scheduledTaskId: uuid("scheduled_task_id"),
4210
+ inputTokens: bigint("input_tokens", { mode: "number" }),
4211
+ outputTokens: bigint("output_tokens", { mode: "number" }),
4212
+ cachedTokens: bigint("cached_tokens", { mode: "number" }),
4213
+ cacheWriteTokens: bigint("cache_write_tokens", { mode: "number" }),
4214
+ reasoningTokens: bigint("reasoning_tokens", { mode: "number" }),
4215
+ totalTokens: bigint("total_tokens", { mode: "number" }),
4216
+ pricedCostMicros: bigint("priced_cost_micros", { mode: "number" }).notNull().default(0),
4217
+ occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
4218
+ recordedAt: timestamp("recorded_at", { withTimezone: true }).notNull().defaultNow(),
4219
+ },
4220
+ (table) => ({
4221
+ workspaceTurnSource: uniqueIndex("model_call_facts_workspace_turn_source_uq").on(
4222
+ table.workspaceId,
4223
+ table.turnId,
4224
+ table.sourceKey,
4225
+ ),
4226
+ workspaceOccurred: index("model_call_facts_workspace_occurred_idx").on(
4227
+ table.workspaceId,
4228
+ table.occurredAt,
4229
+ ),
4230
+ workspaceProviderModelOccurred: index(
4231
+ "model_call_facts_workspace_provider_model_occurred_idx",
4232
+ ).on(table.workspaceId, table.provider, table.model, table.occurredAt),
4233
+ workspaceSessionOccurred: index("model_call_facts_workspace_session_occurred_idx").on(
4234
+ table.workspaceId,
4235
+ table.sessionId,
4236
+ table.occurredAt,
4237
+ ),
4238
+ workspaceScheduledTaskOccurred: index("model_call_facts_workspace_scheduled_task_occurred_idx")
4239
+ .on(table.workspaceId, table.scheduledTaskId, table.occurredAt)
4240
+ .where(sql`${table.scheduledTaskId} is not null`),
4241
+ workspaceAccount: foreignKey({
4242
+ name: "model_call_facts_workspace_account_fk",
4243
+ columns: [table.workspaceId, table.accountId],
4244
+ foreignColumns: [workspaces.id, workspaces.accountId],
4245
+ }).onDelete("cascade"),
4246
+ billingPathValid: check(
4247
+ "model_call_facts_billing_path_check",
4248
+ sql`${table.billingPath} in ('opengeni_credits', 'external')`,
4249
+ ),
4250
+ pricedCostNonNegative: check(
4251
+ "model_call_facts_priced_cost_check",
4252
+ sql`${table.pricedCostMicros} >= 0`,
4253
+ ),
4254
+ initiatorConsistent: check(
4255
+ "model_call_facts_initiator_check",
4256
+ sql`(${table.initiatorKind} is null and ${table.initiatorSubjectId} is null)
4257
+ or (${table.initiatorKind} in ('subject', 'service')
4258
+ and ${table.initiatorSubjectId} is not null
4259
+ and octet_length(${table.initiatorSubjectId}) between 1 and 1024)`,
4260
+ ),
4261
+ sourceKeyBytes: check(
4262
+ "model_call_facts_source_key_bytes_check",
4263
+ sql`octet_length(${table.sourceKey}) between 1 and 1024`,
4264
+ ),
4265
+ providerBytes: check(
4266
+ "model_call_facts_provider_bytes_check",
4267
+ sql`octet_length(${table.provider}) between 1 and 256`,
4268
+ ),
4269
+ providerApiBytes: check(
4270
+ "model_call_facts_provider_api_bytes_check",
4271
+ sql`octet_length(${table.providerApi}) between 1 and 256`,
4272
+ ),
4273
+ modelBytes: check(
4274
+ "model_call_facts_model_bytes_check",
4275
+ sql`octet_length(${table.model}) between 1 and 512`,
4276
+ ),
4277
+ }),
4278
+ );
4279
+
3808
4280
  /** Singleton, migration-installed gate. Standalone defaults keep both off. */
3809
4281
  export const hostExportConfig = pgTable(
3810
4282
  "host_export_config",
@@ -4439,3 +4911,4 @@ export const rigChanges = pgTable(
4439
4911
  );
4440
4912
 
4441
4913
  export * from "./workspace-instruction-policies-schema";
4914
+ export * from "./preference-registry-schema";