@opengeni/db 0.22.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/{chunk-CYGFLLMN.js → chunk-3UCHDMKG.js} +656 -282
  2. package/dist/chunk-3UCHDMKG.js.map +1 -0
  3. package/dist/{chunk-BNGEN5QZ.js → chunk-L6ADMZHE.js} +24 -2
  4. package/dist/chunk-L6ADMZHE.js.map +1 -0
  5. package/dist/index.d.ts +42 -3
  6. package/dist/index.js +6919 -3760
  7. package/dist/index.js.map +1 -1
  8. package/dist/provision-roles.js +1 -1
  9. package/dist/runtime-posture.d.ts +3 -3
  10. package/dist/schema.d.ts +1416 -92
  11. package/dist/schema.js +11 -1
  12. package/dist/session-control.d.ts +7 -1
  13. package/dist/session-queue-commands.d.ts +8 -0
  14. package/dist/session-realtime-context.d.ts +56 -0
  15. package/dist/session-realtime-ledger.d.ts +188 -0
  16. package/dist/session-realtime-mirror.d.ts +30 -0
  17. package/dist/session-realtime-state.d.ts +2 -0
  18. package/dist/session-realtime-terminal.d.ts +40 -0
  19. package/dist/session-realtime.d.ts +59 -0
  20. package/dist/workspace-instruction-policies-schema.d.ts +239 -0
  21. package/dist/workspace-instruction-policies.d.ts +44 -0
  22. package/drizzle/0156_slack_reaction_trigger.sql +49 -0
  23. package/drizzle/0157_session_policy_role_snapshots.sql +1146 -0
  24. package/drizzle/0158_session_realtime_mode.sql +88 -0
  25. package/drizzle/0159_session_realtime_ledger.sql +198 -0
  26. package/drizzle/0160_session_realtime_delegation_terminal.sql +38 -0
  27. package/drizzle/0161_session_realtime_context_projection.sql +82 -0
  28. package/drizzle/0162_session_realtime_connection_promotion.sql +53 -0
  29. package/drizzle/0163_session_realtime_delegation_progress.sql +35 -0
  30. package/drizzle/0164_session_realtime_models.sql +28 -0
  31. package/package.json +4 -4
  32. package/src/index.ts +670 -79
  33. package/src/preference-registry.ts +11 -6
  34. package/src/provision-roles.ts +12 -0
  35. package/src/runtime-posture.ts +10 -0
  36. package/src/schema.ts +400 -43
  37. package/src/session-control.ts +596 -21
  38. package/src/session-queue-commands.ts +76 -7
  39. package/src/session-realtime-context.ts +393 -0
  40. package/src/session-realtime-ledger.ts +1790 -0
  41. package/src/session-realtime-mirror.ts +160 -0
  42. package/src/session-realtime-state.ts +25 -0
  43. package/src/session-realtime-terminal.ts +306 -0
  44. package/src/session-realtime.ts +611 -0
  45. package/src/workspace-instruction-policies-schema.ts +41 -0
  46. package/src/workspace-instruction-policies.ts +131 -2
  47. package/dist/chunk-BNGEN5QZ.js.map +0 -1
  48. package/dist/chunk-CYGFLLMN.js.map +0 -1
@@ -998,7 +998,10 @@ async function withPreferenceRegistryAttemptAuthority<T>(
998
998
  ), locked_turn AS MATERIALIZED (
999
999
  SELECT turn.id, turn.account_id, turn.workspace_id, turn.session_id,
1000
1000
  turn.active_attempt_id, turn.execution_generation,
1001
- turn.initiator_kind, turn.initiator_subject_id
1001
+ coalesce(
1002
+ turn.initiating_human_subject_id,
1003
+ case when turn.initiator_kind = 'subject' then turn.initiator_subject_id end
1004
+ ) as initiating_human_subject_id
1002
1005
  FROM session_turns turn
1003
1006
  JOIN locked_session session
1004
1007
  ON session.id = turn.session_id
@@ -1008,8 +1011,10 @@ async function withPreferenceRegistryAttemptAuthority<T>(
1008
1011
  AND turn.active_attempt_id = ${input.attemptId}::uuid
1009
1012
  AND turn.execution_generation = ${input.executionGeneration}
1010
1013
  AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
1011
- AND turn.initiator_kind = 'subject'
1012
- AND length(btrim(turn.initiator_subject_id)) BETWEEN 1 AND 1024
1014
+ AND length(btrim(coalesce(
1015
+ turn.initiating_human_subject_id,
1016
+ case when turn.initiator_kind = 'subject' then turn.initiator_subject_id end
1017
+ ))) BETWEEN 1 AND 1024
1013
1018
  FOR SHARE OF turn
1014
1019
  ), locked_attempt AS MATERIALIZED (
1015
1020
  SELECT attempt.id, attempt.account_id, attempt.workspace_id,
@@ -1032,7 +1037,7 @@ async function withPreferenceRegistryAttemptAuthority<T>(
1032
1037
  )
1033
1038
  FOR SHARE OF attempt
1034
1039
  )
1035
- SELECT turn.initiator_subject_id
1040
+ SELECT turn.initiating_human_subject_id
1036
1041
  FROM locked_workspace workspace
1037
1042
  JOIN locked_session session ON true
1038
1043
  JOIN locked_turn turn ON true
@@ -1041,8 +1046,8 @@ async function withPreferenceRegistryAttemptAuthority<T>(
1041
1046
  AND workspace.id = attempt.workspace_id
1042
1047
  AND session.id = attempt.session_id
1043
1048
  AND turn.id = attempt.turn_id
1044
- `)) as unknown as Array<{ initiator_subject_id: string }>;
1045
- const initiatingHumanSubjectId = rows[0]?.initiator_subject_id;
1049
+ `)) as unknown as Array<{ initiating_human_subject_id: string }>;
1050
+ const initiatingHumanSubjectId = rows[0]?.initiating_human_subject_id;
1046
1051
  if (!initiatingHumanSubjectId) {
1047
1052
  throw new PreferenceRegistryInitiatorError(
1048
1053
  "Preference retrieval requires the exact current attempt, generation, and immutable human initiator",
@@ -469,6 +469,18 @@ BEGIN
469
469
  ${literal(role)}
470
470
  );
471
471
  END IF;
472
+ IF to_regprocedure(
473
+ format(
474
+ '%I.workspace_instruction_policy_get_or_create_snapshot(uuid,uuid,uuid,uuid,uuid,integer)',
475
+ ${literal(schema)}
476
+ )
477
+ ) IS NOT NULL THEN
478
+ EXECUTE format(
479
+ 'GRANT EXECUTE ON FUNCTION %I.workspace_instruction_policy_get_or_create_snapshot(uuid, uuid, uuid, uuid, uuid, integer) TO %I',
480
+ ${literal(schema)},
481
+ ${literal(role)}
482
+ );
483
+ END IF;
472
484
  IF to_regprocedure(
473
485
  format(
474
486
  '%I.scoped_knowledge_apply_lifecycle(uuid,text,uuid,text,bigint,text,text,text,text,text,text)',
@@ -95,6 +95,10 @@ export const FORCE_RLS_TABLES = [
95
95
  "session_mcp_servers",
96
96
  "session_pending_tool_calls",
97
97
  "session_pins",
98
+ "session_realtime_connections",
99
+ "session_realtime_context_projections",
100
+ "session_realtime_entries",
101
+ "session_realtime_modes",
98
102
  "session_recordings",
99
103
  "session_spawn_denials",
100
104
  "session_stream_acknowledgments",
@@ -122,6 +126,7 @@ export const FORCE_RLS_TABLES = [
122
126
  "workspace_instruction_policy_activation_events",
123
127
  "workspace_instruction_policy_heads",
124
128
  "workspace_instruction_policy_revisions",
129
+ "workspace_instruction_policy_snapshots",
125
130
  "workspace_model_policies",
126
131
  "workspace_packs",
127
132
  "workspace_session_activity_revisions",
@@ -217,6 +222,10 @@ export const RUNTIME_FULL_DML_TABLES = [
217
222
  "session_mcp_servers",
218
223
  "session_pending_tool_calls",
219
224
  "session_pins",
225
+ "session_realtime_connections",
226
+ "session_realtime_context_projections",
227
+ "session_realtime_entries",
228
+ "session_realtime_modes",
220
229
  "session_recordings",
221
230
  "session_stream_acknowledgments",
222
231
  "session_system_update_outbox",
@@ -257,6 +266,7 @@ export const RUNTIME_READ_ONLY_TABLES = [
257
266
  "nested_agent_depth_configuration",
258
267
  "preference_registry_events",
259
268
  "preference_registry_snapshots",
269
+ "workspace_instruction_policy_snapshots",
260
270
  ] as const;
261
271
 
262
272
  /** Append-only evidence/revision tables are insertable and queryable, never mutable. */
package/src/schema.ts CHANGED
@@ -557,16 +557,12 @@ export const codexSubscriptionCredentials = pgTable(
557
557
  // continues to own `version`; quota/cache writes own neither counter.
558
558
  allocatorVersion: integer("allocator_version").notNull().default(1),
559
559
  allocatorUpdatedBySubjectId: text("allocator_updated_by_subject_id"),
560
- allocatorUpdatedAt: timestamp("allocator_updated_at", {
561
- withTimezone: true,
562
- }),
560
+ allocatorUpdatedAt: timestamp("allocator_updated_at", { withTimezone: true }),
563
561
  // Authoritative count-only summary cached from /wham/usage. Detailed rows
564
562
  // are never persisted as redemption authority; every first POST preflights
565
563
  // the provider's fresh detail endpoint.
566
564
  resetCreditAvailableCount: integer("reset_credit_available_count"),
567
- resetCreditsCheckedAt: timestamp("reset_credits_checked_at", {
568
- withTimezone: true,
569
- }),
565
+ resetCreditsCheckedAt: timestamp("reset_credits_checked_at", { withTimezone: true }),
570
566
  // Set only by a direct Better Auth cookie connection/reconnection. Legacy,
571
567
  // configured, delegated, API-key, and agent-created rows remain view-only.
572
568
  connectedBySubjectId: text("connected_by_subject_id"),
@@ -616,9 +612,7 @@ export const codexResetRedemptionAttempts = pgTable(
616
612
  outcome: text("outcome"),
617
613
  claimHolderId: uuid("claim_holder_id"),
618
614
  claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
619
- confirmationExpiresAt: timestamp("confirmation_expires_at", {
620
- withTimezone: true,
621
- }).notNull(),
615
+ confirmationExpiresAt: timestamp("confirmation_expires_at", { withTimezone: true }).notNull(),
622
616
  providerStartedAt: timestamp("provider_started_at", { withTimezone: true }),
623
617
  completedAt: timestamp("completed_at", { withTimezone: true }),
624
618
  lastFailureKind: text("last_failure_kind"),
@@ -826,7 +820,9 @@ export const slackInteractionInbox = pgTable(
826
820
  slackMessageTs: text("slack_message_ts").notNull(),
827
821
  slackThreadTs: text("slack_thread_ts"),
828
822
  triggerKind: text("trigger_kind")
829
- .$type<"app_mention" | "dm" | "slash_command" | "message_shortcut" | "thread_reply">()
823
+ .$type<
824
+ "app_mention" | "dm" | "reaction" | "slash_command" | "message_shortcut" | "thread_reply"
825
+ >()
830
826
  .notNull(),
831
827
  text: text("text").notNull(),
832
828
  status: text("status")
@@ -838,6 +834,7 @@ export const slackInteractionInbox = pgTable(
838
834
  attemptCount: integer("attempt_count").notNull().default(0),
839
835
  retryAt: timestamp("retry_at", { withTimezone: true }),
840
836
  lastErrorCode: text("last_error_code"),
837
+ reactionContextCheckpoint: jsonb("reaction_context_checkpoint").$type<unknown>(),
841
838
  processedAt: timestamp("processed_at", { withTimezone: true }),
842
839
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
843
840
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -1310,6 +1307,11 @@ export const sessions = pgTable(
1310
1307
  // Composed system-level AFTER the workspace agentInstructions; never emitted
1311
1308
  // as a timeline event.
1312
1309
  instructions: text("instructions"),
1310
+ // Immutable normalized prompt-policy role. This is deliberately separate
1311
+ // from workspace membership roles and memory selectors. Existing rows keep
1312
+ // NULL and use the bounded metadata.role compatibility fallback at the
1313
+ // attempt-snapshot boundary.
1314
+ policyRole: text("policy_role"),
1313
1315
  resources: jsonb("resources").$type<unknown[]>().notNull().default([]),
1314
1316
  skills: jsonb("skills").$type<unknown[]>().notNull().default([]),
1315
1317
  tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
@@ -1517,6 +1519,323 @@ export const sessions = pgTable(
1517
1519
  }),
1518
1520
  );
1519
1521
 
1522
+ // One temporary realtime owner for an ordinary session. Terminal rows remain
1523
+ // as lifecycle evidence; the partial unique index admits only one active owner.
1524
+ export const sessionRealtimeModes = pgTable(
1525
+ "session_realtime_modes",
1526
+ {
1527
+ id: uuid("id").primaryKey().defaultRandom(),
1528
+ accountId: uuid("account_id").notNull(),
1529
+ workspaceId: uuid("workspace_id").notNull(),
1530
+ sessionId: uuid("session_id").notNull(),
1531
+ operationId: uuid("operation_id").notNull(),
1532
+ ownerSubjectId: text("owner_subject_id").notNull(),
1533
+ browserInstanceId: text("browser_instance_id").notNull(),
1534
+ ownerKeyHash: text("owner_key_hash").notNull(),
1535
+ model: text("model").notNull(),
1536
+ state: text("state").notNull().default("active"),
1537
+ version: integer("version").notNull().default(1),
1538
+ connectionEpoch: integer("connection_epoch").notNull().default(1),
1539
+ leaseExpiresAt: timestamp("lease_expires_at", { withTimezone: true }).notNull(),
1540
+ lastHeartbeatAt: timestamp("last_heartbeat_at", { withTimezone: true }).notNull(),
1541
+ startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
1542
+ endedAt: timestamp("ended_at", { withTimezone: true }),
1543
+ endReason: text("end_reason"),
1544
+ // The rolling migration owns this forward reference. End commits at most
1545
+ // one canonical transcript-tail Steer and binds its audit projection here.
1546
+ contextProjectionId: uuid("context_projection_id"),
1547
+ contextProjectedAt: timestamp("context_projected_at", { withTimezone: true }),
1548
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
1549
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
1550
+ },
1551
+ (table) => ({
1552
+ workspaceAccount: foreignKey({
1553
+ name: "session_realtime_modes_workspace_account_fk",
1554
+ columns: [table.workspaceId, table.accountId],
1555
+ foreignColumns: [workspaces.id, workspaces.accountId],
1556
+ }).onDelete("cascade"),
1557
+ workspaceSession: foreignKey({
1558
+ name: "session_realtime_modes_workspace_session_fk",
1559
+ columns: [table.workspaceId, table.sessionId],
1560
+ foreignColumns: [sessions.workspaceId, sessions.id],
1561
+ }).onDelete("cascade"),
1562
+ operation: uniqueIndex("session_realtime_modes_operation_uq").on(
1563
+ table.workspaceId,
1564
+ table.sessionId,
1565
+ table.operationId,
1566
+ ),
1567
+ oneActive: uniqueIndex("session_realtime_modes_one_active_uq")
1568
+ .on(table.workspaceId, table.sessionId)
1569
+ .where(sql`${table.state} = 'active'`),
1570
+ activeLease: index("session_realtime_modes_active_lease_idx")
1571
+ .on(table.leaseExpiresAt, table.workspaceId, table.sessionId)
1572
+ .where(sql`${table.state} = 'active'`),
1573
+ stateValid: check(
1574
+ "session_realtime_modes_state_check",
1575
+ sql`${table.state} in ('active', 'ended')`,
1576
+ ),
1577
+ modelValid: check(
1578
+ "session_realtime_modes_model_check",
1579
+ sql`${table.model} in (
1580
+ 'gpt-live-1-boulder-alpha',
1581
+ 'opengeni-gateway/openai/gpt-realtime-2.1',
1582
+ 'opengeni-gateway/openai/gpt-realtime-mini',
1583
+ 'opengeni-gateway/xai/grok-voice-think-fast-2.0',
1584
+ 'workspace-gateway/openai/gpt-realtime-2.1',
1585
+ 'workspace-gateway/openai/gpt-realtime-mini',
1586
+ 'workspace-gateway/xai/grok-voice-think-fast-2.0'
1587
+ )`,
1588
+ ),
1589
+ endReasonValid: check(
1590
+ "session_realtime_modes_end_reason_check",
1591
+ sql`${table.endReason} is null or ${table.endReason} in ('user_stop', 'browser_unload', 'lease_expired')`,
1592
+ ),
1593
+ versionValid: check("session_realtime_modes_version_check", sql`${table.version} >= 1`),
1594
+ epochValid: check("session_realtime_modes_epoch_check", sql`${table.connectionEpoch} >= 1`),
1595
+ ownerSubjectValid: check(
1596
+ "session_realtime_modes_owner_subject_check",
1597
+ sql`octet_length(${table.ownerSubjectId}) between 1 and 1024`,
1598
+ ),
1599
+ browserInstanceValid: check(
1600
+ "session_realtime_modes_browser_instance_check",
1601
+ sql`octet_length(${table.browserInstanceId}) between 1 and 256`,
1602
+ ),
1603
+ ownerKeyHashValid: check(
1604
+ "session_realtime_modes_owner_key_hash_check",
1605
+ sql`${table.ownerKeyHash} ~ '^[0-9a-f]{64}$'`,
1606
+ ),
1607
+ leaseValid: check(
1608
+ "session_realtime_modes_lease_check",
1609
+ sql`${table.leaseExpiresAt} > ${table.lastHeartbeatAt}`,
1610
+ ),
1611
+ terminalValid: check(
1612
+ "session_realtime_modes_terminal_check",
1613
+ sql`(${table.state} = 'active' and ${table.endedAt} is null and ${table.endReason} is null)
1614
+ or (${table.state} = 'ended' and ${table.endedAt} is not null and ${table.endReason} is not null)`,
1615
+ ),
1616
+ }),
1617
+ );
1618
+
1619
+ export const sessionRealtimeConnections = pgTable(
1620
+ "session_realtime_connections",
1621
+ {
1622
+ id: uuid("id").primaryKey().defaultRandom(),
1623
+ accountId: uuid("account_id").notNull(),
1624
+ workspaceId: uuid("workspace_id").notNull(),
1625
+ sessionId: uuid("session_id").notNull(),
1626
+ realtimeId: uuid("realtime_id")
1627
+ .notNull()
1628
+ .references(() => sessionRealtimeModes.id, { onDelete: "cascade" }),
1629
+ operationId: uuid("operation_id").notNull(),
1630
+ connectionEpoch: integer("connection_epoch").notNull(),
1631
+ startupFenceSequence: integer("startup_fence_sequence").notNull().default(0),
1632
+ promotionMode: text("promotion_mode").notNull().default("legacy"),
1633
+ state: text("state").notNull().default("negotiating"),
1634
+ sdpAnswer: text("sdp_answer"),
1635
+ failureCode: text("failure_code"),
1636
+ providerSessionId: text("provider_session_id"),
1637
+ startupEventId: text("startup_event_id"),
1638
+ startupAcknowledgedAt: timestamp("startup_acknowledged_at", { withTimezone: true }),
1639
+ negotiatedAt: timestamp("negotiated_at", { withTimezone: true }),
1640
+ closedAt: timestamp("closed_at", { withTimezone: true }),
1641
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
1642
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
1643
+ },
1644
+ (table) => ({
1645
+ workspaceAccount: foreignKey({
1646
+ name: "session_realtime_connections_workspace_account_fk",
1647
+ columns: [table.workspaceId, table.accountId],
1648
+ foreignColumns: [workspaces.id, workspaces.accountId],
1649
+ }).onDelete("cascade"),
1650
+ workspaceSession: foreignKey({
1651
+ name: "session_realtime_connections_workspace_session_fk",
1652
+ columns: [table.workspaceId, table.sessionId],
1653
+ foreignColumns: [sessions.workspaceId, sessions.id],
1654
+ }).onDelete("cascade"),
1655
+ operation: uniqueIndex("session_realtime_connections_operation_uq").on(
1656
+ table.realtimeId,
1657
+ table.operationId,
1658
+ ),
1659
+ epoch: uniqueIndex("session_realtime_connections_epoch_uq").on(
1660
+ table.realtimeId,
1661
+ table.connectionEpoch,
1662
+ ),
1663
+ oneActive: uniqueIndex("session_realtime_connections_one_active_uq")
1664
+ .on(table.realtimeId)
1665
+ .where(
1666
+ sql`(${table.promotionMode} = 'legacy' and ${table.state} in ('negotiating', 'ready', 'active'))
1667
+ or (${table.promotionMode} = 'staged' and ${table.state} = 'active')`,
1668
+ ),
1669
+ onePreparing: uniqueIndex("session_realtime_connections_one_preparing_uq")
1670
+ .on(table.realtimeId)
1671
+ .where(
1672
+ sql`(${table.promotionMode} = 'legacy' and ${table.state} in ('negotiating', 'ready', 'active'))
1673
+ or (${table.promotionMode} = 'staged' and ${table.state} in ('negotiating', 'ready'))`,
1674
+ ),
1675
+ epochValid: check(
1676
+ "session_realtime_connections_epoch_check",
1677
+ sql`${table.connectionEpoch} >= 1`,
1678
+ ),
1679
+ startupFenceValid: check(
1680
+ "session_realtime_connections_startup_fence_check",
1681
+ sql`${table.startupFenceSequence} >= 0`,
1682
+ ),
1683
+ promotionModeValid: check(
1684
+ "session_realtime_connections_promotion_mode_check",
1685
+ sql`${table.promotionMode} in ('legacy', 'staged')`,
1686
+ ),
1687
+ stateValid: check(
1688
+ "session_realtime_connections_state_check",
1689
+ sql`${table.state} in ('negotiating', 'ready', 'active', 'failed', 'closed')`,
1690
+ ),
1691
+ sdpValid: check(
1692
+ "session_realtime_connections_sdp_check",
1693
+ sql`${table.sdpAnswer} is null or octet_length(${table.sdpAnswer}) between 1 and 1048576`,
1694
+ ),
1695
+ failureValid: check(
1696
+ "session_realtime_connections_failure_check",
1697
+ sql`${table.failureCode} is null or octet_length(${table.failureCode}) between 1 and 128`,
1698
+ ),
1699
+ providerSessionValid: check(
1700
+ "session_realtime_connections_provider_session_check",
1701
+ sql`${table.providerSessionId} is null or octet_length(${table.providerSessionId}) between 1 and 1024`,
1702
+ ),
1703
+ startupEventValid: check(
1704
+ "session_realtime_connections_startup_event_check",
1705
+ sql`${table.startupEventId} is null or octet_length(${table.startupEventId}) between 1 and 1024`,
1706
+ ),
1707
+ startupAckValid: check(
1708
+ "session_realtime_connections_startup_ack_check",
1709
+ sql`(${table.startupAcknowledgedAt} is null and ${table.providerSessionId} is null and ${table.startupEventId} is null)
1710
+ or (${table.startupAcknowledgedAt} is not null and ${table.providerSessionId} is not null)`,
1711
+ ),
1712
+ terminalValid: check(
1713
+ "session_realtime_connections_terminal_check",
1714
+ sql`(${table.state} = 'negotiating' and ${table.sdpAnswer} is null and ${table.failureCode} is null and ${table.negotiatedAt} is null and ${table.closedAt} is null)
1715
+ or (${table.state} = 'ready' and ${table.sdpAnswer} is not null and ${table.failureCode} is null and ${table.negotiatedAt} is not null and ${table.closedAt} is null)
1716
+ or (${table.state} = 'active' and ${table.sdpAnswer} is not null and ${table.failureCode} is null and ${table.negotiatedAt} is not null and ${table.closedAt} is null)
1717
+ or (${table.state} = 'failed' and ${table.sdpAnswer} is null and ${table.failureCode} is not null and ${table.closedAt} is not null)
1718
+ or (${table.state} = 'closed' and ${table.closedAt} is not null)`,
1719
+ ),
1720
+ }),
1721
+ );
1722
+
1723
+ export const sessionRealtimeEntries = pgTable(
1724
+ "session_realtime_entries",
1725
+ {
1726
+ id: uuid("id").primaryKey().defaultRandom(),
1727
+ accountId: uuid("account_id").notNull(),
1728
+ workspaceId: uuid("workspace_id").notNull(),
1729
+ sessionId: uuid("session_id").notNull(),
1730
+ realtimeId: uuid("realtime_id")
1731
+ .notNull()
1732
+ .references(() => sessionRealtimeModes.id, { onDelete: "cascade" }),
1733
+ operationId: uuid("operation_id").notNull(),
1734
+ connectionEpoch: integer("connection_epoch").notNull(),
1735
+ sequence: integer("sequence").notNull(),
1736
+ direction: text("direction").notNull(),
1737
+ kind: text("kind").notNull(),
1738
+ role: text("role"),
1739
+ providerEventId: text("provider_event_id"),
1740
+ delegationItemId: text("delegation_item_id"),
1741
+ // The referenced tables are declared later in this schema module; the
1742
+ // rolling migration owns all three ON DELETE SET NULL foreign keys.
1743
+ sourceUpdateId: uuid("source_update_id"),
1744
+ historyItemId: uuid("history_item_id"),
1745
+ // The rolling migration owns this ON DELETE SET NULL foreign key because
1746
+ // sessionTurns is declared later in this schema module. A non-null value
1747
+ // links the accepted provider call and its one terminal outbound
1748
+ // result/error to the same ordinary turn. It never denotes a child/fork
1749
+ // session.
1750
+ turnId: uuid("turn_id"),
1751
+ text: text("text"),
1752
+ payload: jsonb("payload").$type<Record<string, unknown>>().notNull().default({}),
1753
+ clientAckedAt: timestamp("client_acked_at", { withTimezone: true }),
1754
+ providerAckedAt: timestamp("provider_acked_at", { withTimezone: true }),
1755
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
1756
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
1757
+ },
1758
+ (table) => ({
1759
+ workspaceAccount: foreignKey({
1760
+ name: "session_realtime_entries_workspace_account_fk",
1761
+ columns: [table.workspaceId, table.accountId],
1762
+ foreignColumns: [workspaces.id, workspaces.accountId],
1763
+ }).onDelete("cascade"),
1764
+ workspaceSession: foreignKey({
1765
+ name: "session_realtime_entries_workspace_session_fk",
1766
+ columns: [table.workspaceId, table.sessionId],
1767
+ foreignColumns: [sessions.workspaceId, sessions.id],
1768
+ }).onDelete("cascade"),
1769
+ operation: uniqueIndex("session_realtime_entries_operation_uq").on(
1770
+ table.realtimeId,
1771
+ table.operationId,
1772
+ ),
1773
+ sequence: uniqueIndex("session_realtime_entries_sequence_uq").on(
1774
+ table.realtimeId,
1775
+ table.sequence,
1776
+ ),
1777
+ sourceUpdate: uniqueIndex("session_realtime_entries_source_update_uq")
1778
+ .on(table.realtimeId, table.sourceUpdateId)
1779
+ .where(sql`${table.sourceUpdateId} is not null`),
1780
+ delegationTurn: uniqueIndex("session_realtime_entries_delegation_turn_uq")
1781
+ .on(table.turnId)
1782
+ .where(sql`${table.kind} = 'delegation_call' and ${table.turnId} is not null`),
1783
+ delegationTerminal: uniqueIndex("session_realtime_entries_delegation_terminal_uq")
1784
+ .on(table.turnId)
1785
+ .where(
1786
+ sql`${table.direction} = 'provider_out' and ${table.kind} in ('delegation_result', 'error') and ${table.turnId} is not null`,
1787
+ ),
1788
+ delegationCall: uniqueIndex("session_realtime_entries_delegation_call_uq")
1789
+ .on(table.realtimeId, table.delegationItemId)
1790
+ .where(sql`${table.kind} = 'delegation_call' and ${table.delegationItemId} is not null`),
1791
+ outboundPending: index("session_realtime_entries_outbound_pending_idx")
1792
+ .on(table.realtimeId, table.sequence)
1793
+ .where(sql`${table.direction} = 'provider_out' and ${table.providerAckedAt} is null`),
1794
+ epochValid: check("session_realtime_entries_epoch_check", sql`${table.connectionEpoch} >= 1`),
1795
+ sequenceValid: check("session_realtime_entries_sequence_check", sql`${table.sequence} >= 1`),
1796
+ directionValid: check(
1797
+ "session_realtime_entries_direction_check",
1798
+ sql`${table.direction} in ('provider_in', 'provider_out')`,
1799
+ ),
1800
+ kindValid: check(
1801
+ "session_realtime_entries_kind_check",
1802
+ sql`${table.kind} in ('user_transcript', 'assistant_transcript', 'delegation_call', 'delegation_progress', 'delegation_result', 'interruption', 'session_update', 'error')`,
1803
+ ),
1804
+ roleValid: check(
1805
+ "session_realtime_entries_role_check",
1806
+ sql`${table.role} is null or ${table.role} in ('user', 'assistant')`,
1807
+ ),
1808
+ providerEventValid: check(
1809
+ "session_realtime_entries_provider_event_check",
1810
+ sql`${table.providerEventId} is null or octet_length(${table.providerEventId}) between 1 and 1024`,
1811
+ ),
1812
+ delegationItemValid: check(
1813
+ "session_realtime_entries_delegation_item_check",
1814
+ sql`${table.delegationItemId} is null or octet_length(${table.delegationItemId}) between 1 and 1024`,
1815
+ ),
1816
+ textValid: check(
1817
+ "session_realtime_entries_text_check",
1818
+ sql`${table.text} is null or octet_length(${table.text}) <= 131072`,
1819
+ ),
1820
+ payloadValid: check(
1821
+ "session_realtime_entries_payload_check",
1822
+ sql`octet_length(${table.payload}::text) <= 131072`,
1823
+ ),
1824
+ turnValid: check(
1825
+ "session_realtime_entries_turn_check",
1826
+ sql`${table.turnId} is null
1827
+ or (${table.kind} = 'delegation_call' and ${table.direction} = 'provider_in')
1828
+ or (${table.kind} in ('delegation_progress', 'delegation_result', 'error') and ${table.direction} = 'provider_out')`,
1829
+ ),
1830
+ transcriptValid: check(
1831
+ "session_realtime_entries_transcript_check",
1832
+ sql`(${table.kind} = 'user_transcript' and ${table.role} = 'user' and ${table.text} is not null)
1833
+ or (${table.kind} = 'assistant_transcript' and ${table.role} = 'assistant' and ${table.text} is not null)
1834
+ or (${table.kind} not in ('user_transcript', 'assistant_transcript') and ${table.role} is null)`,
1835
+ ),
1836
+ }),
1837
+ );
1838
+
1520
1839
  // A denied session create is durable evidence, not a mutable session/resource
1521
1840
  // artifact. It has its own workspace-scoped idempotency key so retries replay
1522
1841
  // the same denial without creating a session or billing/run rows.
@@ -2082,6 +2401,11 @@ export const sessionTurns = pgTable(
2082
2401
  .$type<Record<string, unknown>>()
2083
2402
  .notNull()
2084
2403
  .default({ backfill: true }),
2404
+ // Immutable human authority for exact-attempt governance. Human turns bind
2405
+ // their own subject; trusted continuations/compactions may inherit the
2406
+ // causal turn's value while retaining a service initiator. Null means the
2407
+ // turn has no human preference authority.
2408
+ initiatingHumanSubjectId: text("initiating_human_subject_id"),
2085
2409
  // Immutable exact personal MCP authority for this logical turn. Recovery,
2086
2410
  // approval, retries, and Toolspace reuse this row; no runtime may infer
2087
2411
  // broader authority from the session creator or mutable session state.
@@ -2121,6 +2445,61 @@ export const sessionTurns = pgTable(
2121
2445
  }),
2122
2446
  );
2123
2447
 
2448
+ // One bounded audit/idempotency projection of an ended mode's transcript-tail
2449
+ // wrapper, bound to the exact ordinary Steer turn that durably carries it.
2450
+ export const sessionRealtimeContextProjections = pgTable(
2451
+ "session_realtime_context_projections",
2452
+ {
2453
+ id: uuid("id").primaryKey().defaultRandom(),
2454
+ accountId: uuid("account_id").notNull(),
2455
+ workspaceId: uuid("workspace_id").notNull(),
2456
+ sessionId: uuid("session_id").notNull(),
2457
+ turnId: uuid("turn_id").notNull(),
2458
+ context: text("context"),
2459
+ sourceModeCount: integer("source_mode_count").notNull(),
2460
+ sourceEntryCount: integer("source_entry_count").notNull(),
2461
+ includedEntryCount: integer("included_entry_count").notNull(),
2462
+ omittedEntryCount: integer("omitted_entry_count").notNull(),
2463
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
2464
+ },
2465
+ (table) => ({
2466
+ workspaceAccount: foreignKey({
2467
+ name: "session_realtime_context_projections_workspace_account_fk",
2468
+ columns: [table.workspaceId, table.accountId],
2469
+ foreignColumns: [workspaces.id, workspaces.accountId],
2470
+ }).onDelete("cascade"),
2471
+ workspaceSession: foreignKey({
2472
+ name: "session_realtime_context_projections_workspace_session_fk",
2473
+ columns: [table.workspaceId, table.sessionId],
2474
+ foreignColumns: [sessions.workspaceId, sessions.id],
2475
+ }).onDelete("cascade"),
2476
+ workspaceTurn: foreignKey({
2477
+ name: "session_realtime_context_projections_workspace_turn_fk",
2478
+ columns: [table.workspaceId, table.turnId],
2479
+ foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
2480
+ }).onDelete("cascade"),
2481
+ turn: uniqueIndex("session_realtime_context_projections_turn_uq").on(
2482
+ table.workspaceId,
2483
+ table.sessionId,
2484
+ table.turnId,
2485
+ ),
2486
+ contextValid: check(
2487
+ "session_realtime_context_projections_context_check",
2488
+ sql`${table.context} is null or octet_length(${table.context}) between 1 and 65536`,
2489
+ ),
2490
+ countsValid: check(
2491
+ "session_realtime_context_projections_counts_check",
2492
+ sql`${table.sourceModeCount} >= 1
2493
+ and ${table.sourceEntryCount} >= 0
2494
+ and ${table.includedEntryCount} >= 0
2495
+ and ${table.omittedEntryCount} >= 0
2496
+ and ${table.includedEntryCount} + ${table.omittedEntryCount} = ${table.sourceEntryCount}
2497
+ and ((${table.sourceEntryCount} = 0 and ${table.context} is null)
2498
+ or (${table.sourceEntryCount} > 0 and ${table.context} is not null))`,
2499
+ ),
2500
+ }),
2501
+ );
2502
+
2124
2503
  // First-class ownership for one accepted execution attempt. A workflow may
2125
2504
  // preallocate id, but this row is inserted only by the activity transaction
2126
2505
  // that actually claims the logical turn and registers its exact dispatch.
@@ -2849,14 +3228,10 @@ export const sessionGoals = pgTable(
2849
3228
  // update, timeline events, usage row, and workflow-wake outbox row.
2850
3229
  // Temporal signals and workflow history are replaceable nudges over these
2851
3230
  // monotonic revisions.
2852
- continuationWakeRevision: bigint("continuation_wake_revision", {
2853
- mode: "number",
2854
- })
3231
+ continuationWakeRevision: bigint("continuation_wake_revision", { mode: "number" })
2855
3232
  .notNull()
2856
3233
  .default(0),
2857
- continuationObservedRevision: bigint("continuation_observed_revision", {
2858
- mode: "number",
2859
- })
3234
+ continuationObservedRevision: bigint("continuation_observed_revision", { mode: "number" })
2860
3235
  .notNull()
2861
3236
  .default(0),
2862
3237
  metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
@@ -3640,9 +4015,7 @@ export const sandboxLeaseHolders = pgTable(
3640
4015
  leaseId: uuid("lease_id")
3641
4016
  .notNull()
3642
4017
  .references(() => sandboxLeases.id, { onDelete: "cascade" }),
3643
- kind: text("kind", {
3644
- enum: ["turn", "viewer", "direct", "process"],
3645
- }).notNull(),
4018
+ kind: text("kind", { enum: ["turn", "viewer", "direct", "process"] }).notNull(),
3646
4019
  holderId: text("holder_id").notNull(),
3647
4020
  // The attributing session within the (possibly shared) group.
3648
4021
  subjectId: uuid("subject_id"),
@@ -3687,9 +4060,7 @@ export const sandboxWorkspaceMutationAdmissions = pgTable(
3687
4060
  .references(() => sandboxLeases.id, { onDelete: "cascade" }),
3688
4061
  sandboxGroupId: uuid("sandbox_group_id").notNull(),
3689
4062
  sessionId: uuid("session_id").notNull(),
3690
- actorKind: text("actor_kind", {
3691
- enum: sandboxWorkspaceMutationActorKindValues,
3692
- }).notNull(),
4063
+ actorKind: text("actor_kind", { enum: sandboxWorkspaceMutationActorKindValues }).notNull(),
3693
4064
  actorId: uuid("actor_id").notNull(),
3694
4065
  // Exact turn authority is present only for actor_kind='turn'. Direct HTTP
3695
4066
  // requests and retained processes never invent a turn or quiescence owner.
@@ -3836,9 +4207,7 @@ export const sandboxRetainedProcesses = pgTable(
3836
4207
  sandboxGroupId: uuid("sandbox_group_id").notNull(),
3837
4208
  parentAdmissionId: uuid("parent_admission_id").notNull(),
3838
4209
  holderId: text("holder_id").notNull(),
3839
- ownerActorKind: text("owner_actor_kind", {
3840
- enum: ["turn", "direct"],
3841
- }).notNull(),
4210
+ ownerActorKind: text("owner_actor_kind", { enum: ["turn", "direct"] }).notNull(),
3842
4211
  ownerActorId: uuid("owner_actor_id").notNull(),
3843
4212
  ownerTurnId: uuid("owner_turn_id"),
3844
4213
  ownerAttemptId: uuid("owner_attempt_id"),
@@ -3866,19 +4235,13 @@ export const sandboxRetainedProcesses = pgTable(
3866
4235
  // never exit/loss proof.
3867
4236
  reconcileAfter: timestamp("reconcile_after", { withTimezone: true }).notNull().defaultNow(),
3868
4237
  reconcileClaimId: uuid("reconcile_claim_id"),
3869
- reconcileClaimedAt: timestamp("reconcile_claimed_at", {
3870
- withTimezone: true,
3871
- }),
4238
+ reconcileClaimedAt: timestamp("reconcile_claimed_at", { withTimezone: true }),
3872
4239
  reconcileAttempts: integer("reconcile_attempts").notNull().default(0),
3873
4240
  lastReconcileOutcome: text("last_reconcile_outcome"),
3874
- reconcileProofOutcome: text("reconcile_proof_outcome", {
3875
- enum: ["exited", "lost"],
3876
- }),
4241
+ reconcileProofOutcome: text("reconcile_proof_outcome", { enum: ["exited", "lost"] }),
3877
4242
  reconcileProofExitCode: integer("reconcile_proof_exit_code"),
3878
4243
  reconcileProofReason: text("reconcile_proof_reason"),
3879
- reconcileProofObservedAt: timestamp("reconcile_proof_observed_at", {
3880
- withTimezone: true,
3881
- }),
4244
+ reconcileProofObservedAt: timestamp("reconcile_proof_observed_at", { withTimezone: true }),
3882
4245
  },
3883
4246
  (table) => ({
3884
4247
  workspaceAccount: foreignKey({
@@ -4640,12 +5003,8 @@ export const githubInstallations = pgTable(
4640
5003
  githubActorId: bigint("github_actor_id", { mode: "number" }),
4641
5004
  githubActorLogin: text("github_actor_login"),
4642
5005
  authorityKind: text("authority_kind"),
4643
- authorityCheckedAt: timestamp("authority_checked_at", {
4644
- withTimezone: true,
4645
- }),
4646
- authorityExpiresAt: timestamp("authority_expires_at", {
4647
- withTimezone: true,
4648
- }),
5006
+ authorityCheckedAt: timestamp("authority_checked_at", { withTimezone: true }),
5007
+ authorityExpiresAt: timestamp("authority_expires_at", { withTimezone: true }),
4649
5008
  authorityNonce: text("authority_nonce"),
4650
5009
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4651
5010
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -4975,9 +5334,7 @@ export const hostExportOutbox = pgTable(
4975
5334
  payload: jsonb("payload").$type<unknown>().notNull(),
4976
5335
  envelopeBytes: integer("envelope_bytes").notNull(),
4977
5336
  occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
4978
- sourceRecordedAt: timestamp("source_recorded_at", {
4979
- withTimezone: true,
4980
- }).notNull(),
5337
+ sourceRecordedAt: timestamp("source_recorded_at", { withTimezone: true }).notNull(),
4981
5338
  enqueuedAt: timestamp("enqueued_at", { withTimezone: true }).notNull(),
4982
5339
  },
4983
5340
  (table) => ({