@opengeni/db 0.9.3 → 0.12.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.
- package/dist/{chunk-4LG5NBTC.js → chunk-VUKRIBO5.js} +577 -12
- package/dist/chunk-VUKRIBO5.js.map +1 -0
- package/dist/{chunk-KW526IJA.js → chunk-Y5WZZVQK.js} +80 -4
- package/dist/chunk-Y5WZZVQK.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6372 -2189
- package/dist/index.js.map +1 -1
- package/dist/migrate.d.ts +6 -3
- package/dist/migrate.js +1 -1
- package/dist/provision-roles.d.ts +1122 -91
- package/dist/{schema-CdPGTHlD.d.ts → schema-CnpD6BcX.d.ts} +5908 -3626
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +19 -1
- package/drizzle/0053_codex_credential_leases.sql +2 -2
- package/drizzle/0057_durable_queue_control.sql +1 -1
- package/drizzle/0061_session_workflow_wake_outbox.sql +1 -1
- package/drizzle/0062_session_list_snapshot_reaper.sql +1 -1
- package/drizzle/0063_session_control_mega_foundation.sql +1 -1
- package/drizzle/0064_rotation_strategy_sharded_backfill.sql +1 -1
- package/drizzle/0065_codex_subscription_overview.sql +168 -0
- package/drizzle/0065_session_tool_policy.sql +38 -0
- package/drizzle/0067_session_event_payload_bounds.sql +2 -2
- package/drizzle/0068_workspace_control_event_bounds.sql +2 -2
- package/drizzle/0069_session_event_history_backfill.sql +2 -2
- package/drizzle/0074_session_activity_revisions.sql +2 -2
- package/drizzle/0106_session_attempt_mcp_approval_policies.sql +29 -0
- package/drizzle/0107_host_export_lineage_contract.sql +381 -0
- package/drizzle/0108_fence_invalidated_warming_epochs.sql +76 -0
- package/drizzle/0109_nested_agent_depth_expand.sql +42 -0
- package/drizzle/0110_nested_agent_depth_boundary.sql +480 -0
- package/drizzle/0111_nested_agent_depth_backfill.sql +49 -0
- package/drizzle/0112_nested_agent_depth_contract.sql +38 -0
- package/drizzle/0113_nested_agent_depth_validate.sql +13 -0
- package/drizzle/0114_nested_agent_depth_contract.sql +49 -0
- package/drizzle/0115_nested_agent_depth_validate.sql +11 -0
- package/drizzle/0116_nested_agent_depth_index.sql +4 -0
- package/drizzle/0117_sandbox_recovery_generations.sql +699 -0
- package/drizzle/0118_new_session_drafts.sql +59 -0
- package/drizzle/0119_pending_tool_output_policy.sql +5 -0
- package/drizzle/0120_durable_goal_wake.sql +360 -0
- package/drizzle/0121_goal_update_idempotency.sql +11 -0
- package/package.json +5 -4
- package/src/codex-token-resolver.ts +175 -14
- package/src/connection-token-resolver.ts +143 -120
- package/src/event-payload-sanitizer.ts +32 -2
- package/src/index.ts +7734 -1330
- package/src/migrate.ts +131 -2
- package/src/new-session-drafts.ts +144 -0
- package/src/schema.ts +626 -16
- package/src/session-control.ts +44 -18
- package/src/session-queue-commands.ts +94 -21
- package/src/session-tool-call-settlement.ts +6 -1
- package/dist/chunk-4LG5NBTC.js.map +0 -1
- package/dist/chunk-KW526IJA.js.map +0 -1
package/src/schema.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { McpServerConnectionRef } from "@opengeni/contracts";
|
|
1
|
+
import type { McpServerConnectionRef, SessionMcpApprovalPolicy } from "@opengeni/contracts";
|
|
2
2
|
import { sql } from "drizzle-orm";
|
|
3
|
+
import type { SessionToolPolicy } from "@opengeni/contracts";
|
|
3
4
|
import type { HumanInputQuestion, HumanInputResponse } from "@opengeni/contracts";
|
|
4
5
|
import {
|
|
5
6
|
bigint,
|
|
@@ -80,6 +81,34 @@ export const workspaces = pgTable(
|
|
|
80
81
|
}),
|
|
81
82
|
);
|
|
82
83
|
|
|
84
|
+
// One target-schema-local deployment fallback. The migration runner reconciles
|
|
85
|
+
// this singleton from OPENGENI_MAX_NESTED_AGENT_DEPTH; session admission locks
|
|
86
|
+
// and reads it through the SECURITY DEFINER capability installed by the
|
|
87
|
+
// boundary migration so the application role cannot mutate policy authority.
|
|
88
|
+
export const nestedAgentDepthConfiguration = pgTable(
|
|
89
|
+
"nested_agent_depth_configuration",
|
|
90
|
+
{
|
|
91
|
+
singleton: boolean("singleton").primaryKey().notNull().default(true),
|
|
92
|
+
maxNestedAgentDepth: integer("max_nested_agent_depth").notNull(),
|
|
93
|
+
policySource: text("policy_source").$type<"deployment" | "default">().notNull(),
|
|
94
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
95
|
+
},
|
|
96
|
+
(table) => ({
|
|
97
|
+
singletonOnly: check(
|
|
98
|
+
"nested_agent_depth_configuration_singleton_check",
|
|
99
|
+
sql`${table.singleton}`,
|
|
100
|
+
),
|
|
101
|
+
maxValid: check(
|
|
102
|
+
"nested_agent_depth_configuration_max_check",
|
|
103
|
+
sql`${table.maxNestedAgentDepth} >= 0`,
|
|
104
|
+
),
|
|
105
|
+
sourceValid: check(
|
|
106
|
+
"nested_agent_depth_configuration_source_check",
|
|
107
|
+
sql`${table.policySource} in ('deployment', 'default')`,
|
|
108
|
+
),
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
|
|
83
112
|
// One mandatory workspace-wide admission barrier. Every inference-admitting
|
|
84
113
|
// transaction locks this row before it touches a session; Pause/Resume and
|
|
85
114
|
// foreground Send/Steer advance its monotonic revision under FOR UPDATE.
|
|
@@ -320,6 +349,19 @@ export const codexSubscriptionCredentials = pgTable(
|
|
|
320
349
|
// refresh, encrypted material, and already-frozen/in-flight turns are
|
|
321
350
|
// intentionally independent. account eligibility policy owns toggle OCC/audit and product UI.
|
|
322
351
|
allocatorEnabled: boolean("allocator_enabled").notNull().default(true),
|
|
352
|
+
// Independent OCC/audit sequence for the allocator toggle. Token refresh
|
|
353
|
+
// continues to own `version`; quota/cache writes own neither counter.
|
|
354
|
+
allocatorVersion: integer("allocator_version").notNull().default(1),
|
|
355
|
+
allocatorUpdatedBySubjectId: text("allocator_updated_by_subject_id"),
|
|
356
|
+
allocatorUpdatedAt: timestamp("allocator_updated_at", { withTimezone: true }),
|
|
357
|
+
// Authoritative count-only summary cached from /wham/usage. Detailed rows
|
|
358
|
+
// are never persisted as redemption authority; every first POST preflights
|
|
359
|
+
// the provider's fresh detail endpoint.
|
|
360
|
+
resetCreditAvailableCount: integer("reset_credit_available_count"),
|
|
361
|
+
resetCreditsCheckedAt: timestamp("reset_credits_checked_at", { withTimezone: true }),
|
|
362
|
+
// Set only by a direct Better Auth cookie connection/reconnection. Legacy,
|
|
363
|
+
// configured, delegated, API-key, and agent-created rows remain view-only.
|
|
364
|
+
connectedBySubjectId: text("connected_by_subject_id"),
|
|
323
365
|
selectionCount: integer("selection_count").notNull().default(0),
|
|
324
366
|
lastSelectedAt: timestamp("last_selected_at", { withTimezone: true }),
|
|
325
367
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -343,6 +385,82 @@ export const codexSubscriptionCredentials = pgTable(
|
|
|
343
385
|
}),
|
|
344
386
|
);
|
|
345
387
|
|
|
388
|
+
// One durable logical human redemption. `processing` means the fresh provider
|
|
389
|
+
// detail preflight is still owed; `provider_started` means the POST may have
|
|
390
|
+
// reached upstream and every retry must reuse upstreamIdempotencyKey without
|
|
391
|
+
// requiring the credit to remain visible as available.
|
|
392
|
+
export const codexResetRedemptionAttempts = pgTable(
|
|
393
|
+
"codex_reset_redemption_attempts",
|
|
394
|
+
{
|
|
395
|
+
id: uuid("id").primaryKey(),
|
|
396
|
+
accountId: uuid("account_id")
|
|
397
|
+
.notNull()
|
|
398
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
399
|
+
workspaceId: uuid("workspace_id")
|
|
400
|
+
.notNull()
|
|
401
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
402
|
+
credentialId: uuid("credential_id").notNull(),
|
|
403
|
+
subjectId: text("subject_id").notNull(),
|
|
404
|
+
browserSessionHash: text("browser_session_hash").notNull(),
|
|
405
|
+
creditId: text("credit_id").notNull(),
|
|
406
|
+
upstreamIdempotencyKey: uuid("upstream_idempotency_key").notNull().defaultRandom(),
|
|
407
|
+
status: text("status").notNull().default("processing"),
|
|
408
|
+
outcome: text("outcome"),
|
|
409
|
+
claimHolderId: uuid("claim_holder_id"),
|
|
410
|
+
claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
|
|
411
|
+
confirmationExpiresAt: timestamp("confirmation_expires_at", { withTimezone: true }).notNull(),
|
|
412
|
+
providerStartedAt: timestamp("provider_started_at", { withTimezone: true }),
|
|
413
|
+
completedAt: timestamp("completed_at", { withTimezone: true }),
|
|
414
|
+
lastFailureKind: text("last_failure_kind"),
|
|
415
|
+
retryCount: integer("retry_count").notNull().default(0),
|
|
416
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
417
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
418
|
+
},
|
|
419
|
+
(table) => ({
|
|
420
|
+
workspaceAccount: foreignKey({
|
|
421
|
+
name: "codex_reset_redemption_workspace_account_fk",
|
|
422
|
+
columns: [table.workspaceId, table.accountId],
|
|
423
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
424
|
+
}).onDelete("cascade"),
|
|
425
|
+
upstreamKey: uniqueIndex("codex_reset_redemption_upstream_key_idx").on(
|
|
426
|
+
table.upstreamIdempotencyKey,
|
|
427
|
+
),
|
|
428
|
+
credentialCredit: uniqueIndex("codex_reset_redemption_credential_credit_idx")
|
|
429
|
+
.on(table.workspaceId, table.credentialId, table.creditId)
|
|
430
|
+
.where(
|
|
431
|
+
sql`${table.status} <> 'completed' or ${table.outcome} in ('reset', 'alreadyRedeemed')`,
|
|
432
|
+
),
|
|
433
|
+
workspaceCredential: index("codex_reset_redemption_workspace_credential_idx").on(
|
|
434
|
+
table.workspaceId,
|
|
435
|
+
table.credentialId,
|
|
436
|
+
table.createdAt,
|
|
437
|
+
),
|
|
438
|
+
claimExpiry: index("codex_reset_redemption_claim_expiry_idx")
|
|
439
|
+
.on(table.claimExpiresAt)
|
|
440
|
+
.where(sql`${table.status} <> 'completed'`),
|
|
441
|
+
statusValid: check(
|
|
442
|
+
"codex_reset_redemption_status_check",
|
|
443
|
+
sql`${table.status} in ('processing', 'provider_started', 'completed')`,
|
|
444
|
+
),
|
|
445
|
+
outcomeValid: check(
|
|
446
|
+
"codex_reset_redemption_outcome_check",
|
|
447
|
+
sql`${table.outcome} is null or ${table.outcome} in ('reset', 'nothingToReset', 'noCredit', 'alreadyRedeemed')`,
|
|
448
|
+
),
|
|
449
|
+
completionConsistent: check(
|
|
450
|
+
"codex_reset_redemption_completed_check",
|
|
451
|
+
sql`(${table.status} = 'completed') = (${table.outcome} is not null and ${table.completedAt} is not null)`,
|
|
452
|
+
),
|
|
453
|
+
retryCountValid: check(
|
|
454
|
+
"codex_reset_redemption_retry_count_check",
|
|
455
|
+
sql`${table.retryCount} >= 0`,
|
|
456
|
+
),
|
|
457
|
+
humanSubjectValid: check(
|
|
458
|
+
"codex_reset_redemption_human_subject_check",
|
|
459
|
+
sql`${table.subjectId} like 'user:_%'`,
|
|
460
|
+
),
|
|
461
|
+
}),
|
|
462
|
+
);
|
|
463
|
+
|
|
346
464
|
// Generic external-service credential spine. credential_encrypted is the ONLY
|
|
347
465
|
// secret-bearing column; normal API reads use metadata-only helpers below the DB
|
|
348
466
|
// layer. Runtime token material is decrypted only by the broker accessor.
|
|
@@ -634,6 +752,10 @@ export const sessions = pgTable(
|
|
|
634
752
|
// Non-default first-party MCP token permissions (manager-style sessions);
|
|
635
753
|
// null means the fixed worker default set in @opengeni/runtime.
|
|
636
754
|
firstPartyMcpPermissions: jsonb("first_party_mcp_permissions").$type<string[]>(),
|
|
755
|
+
// Durable tool-policy origin. NULL is retained for pre-migration rows;
|
|
756
|
+
// mapSession exposes those rows as `legacy` instead of guessing omitted vs
|
|
757
|
+
// explicit [].
|
|
758
|
+
toolPolicy: jsonb("tool_policy").$type<SessionToolPolicy>(),
|
|
637
759
|
// The manager session that spawned this one via session_create. Set only
|
|
638
760
|
// when the creating grant carried a worker-signed sessionId claim (a session
|
|
639
761
|
// spawning a worker); null for direct API creates and scheduled-task runs.
|
|
@@ -647,6 +769,15 @@ export const sessions = pgTable(
|
|
|
647
769
|
// workspace to a single session row — the dedup that closes the
|
|
648
770
|
// double-submit/double-dispatch stuck-queued bug.
|
|
649
771
|
createIdempotencyKey: text("create_idempotency_key"),
|
|
772
|
+
// Immutable creation-time hierarchy and policy snapshot. These values are
|
|
773
|
+
// populated by the database admission boundary and never re-derived from
|
|
774
|
+
// a live workspace setting for an existing session.
|
|
775
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
776
|
+
nestedAgentDepth: integer("nested_agent_depth").notNull(),
|
|
777
|
+
maxNestedAgentDepthOverride: integer("max_nested_agent_depth_override"),
|
|
778
|
+
effectiveMaxNestedAgentDepth: integer("effective_max_nested_agent_depth").notNull(),
|
|
779
|
+
nestedAgentDepthPolicySource: text("nested_agent_depth_policy_source").notNull(),
|
|
780
|
+
nestedAgentDepthPolicySessionId: uuid("nested_agent_depth_policy_session_id"),
|
|
650
781
|
temporalWorkflowId: text("temporal_workflow_id"),
|
|
651
782
|
activeTurnId: uuid("active_turn_id"),
|
|
652
783
|
// Actual input tokens reported for the last model call of the most recent
|
|
@@ -729,12 +860,64 @@ export const sessions = pgTable(
|
|
|
729
860
|
// point and enumerate all sessions in a group for attribution/disclosure.
|
|
730
861
|
sandboxGroup: index("sessions_sandbox_group_idx").on(table.workspaceId, table.sandboxGroupId),
|
|
731
862
|
// Partial unique index: one session per (workspace, create_idempotency_key)
|
|
732
|
-
// when a key is present.
|
|
733
|
-
//
|
|
734
|
-
// the
|
|
863
|
+
// when a key is present. The boundary trigger reserves the cross-outcome
|
|
864
|
+
// winner before this source row commits; a losing source insert is
|
|
865
|
+
// suppressed and the domain layer replays the durable winner.
|
|
735
866
|
createIdempotency: uniqueIndex("sessions_workspace_create_idempotency_idx")
|
|
736
867
|
.on(table.workspaceId, table.createIdempotencyKey)
|
|
737
868
|
.where(sql`${table.createIdempotencyKey} is not null`),
|
|
869
|
+
rootDepth: index("sessions_workspace_root_depth_idx").on(
|
|
870
|
+
table.workspaceId,
|
|
871
|
+
table.rootSessionId,
|
|
872
|
+
table.nestedAgentDepth,
|
|
873
|
+
),
|
|
874
|
+
}),
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
// A denied session create is durable evidence, not a mutable session/resource
|
|
878
|
+
// artifact. It has its own workspace-scoped idempotency key so retries replay
|
|
879
|
+
// the same denial without creating a session or billing/run rows.
|
|
880
|
+
export const sessionSpawnDenials = pgTable(
|
|
881
|
+
"session_spawn_denials",
|
|
882
|
+
{
|
|
883
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
884
|
+
accountId: uuid("account_id").notNull(),
|
|
885
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
886
|
+
parentSessionId: uuid("parent_session_id"),
|
|
887
|
+
rootSessionId: uuid("root_session_id"),
|
|
888
|
+
currentDepth: integer("current_depth").notNull(),
|
|
889
|
+
attemptedDepth: bigint("attempted_depth", { mode: "number" }).notNull(),
|
|
890
|
+
effectiveMaxNestedAgentDepth: integer("effective_max_nested_agent_depth").notNull(),
|
|
891
|
+
requestedMaxNestedAgentDepthOverride: integer("requested_max_nested_agent_depth_override"),
|
|
892
|
+
policySource: text("policy_source").notNull(),
|
|
893
|
+
policySessionId: uuid("policy_session_id"),
|
|
894
|
+
subjectId: text("subject_id"),
|
|
895
|
+
code: text("code").notNull(),
|
|
896
|
+
idempotencyKey: text("idempotency_key"),
|
|
897
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
898
|
+
},
|
|
899
|
+
(table) => ({
|
|
900
|
+
workspaceIdentity: uniqueIndex("session_spawn_denials_workspace_id_uq").on(
|
|
901
|
+
table.workspaceId,
|
|
902
|
+
table.id,
|
|
903
|
+
),
|
|
904
|
+
workspaceCreated: index("session_spawn_denials_workspace_created_idx").on(
|
|
905
|
+
table.workspaceId,
|
|
906
|
+
table.createdAt,
|
|
907
|
+
),
|
|
908
|
+
parent: index("session_spawn_denials_parent_idx").on(
|
|
909
|
+
table.workspaceId,
|
|
910
|
+
table.parentSessionId,
|
|
911
|
+
table.createdAt,
|
|
912
|
+
),
|
|
913
|
+
idempotency: uniqueIndex("session_spawn_denials_workspace_idempotency_idx")
|
|
914
|
+
.on(table.workspaceId, table.idempotencyKey)
|
|
915
|
+
.where(sql`${table.idempotencyKey} is not null`),
|
|
916
|
+
workspaceAccount: foreignKey({
|
|
917
|
+
name: "session_spawn_denials_workspace_account_fk",
|
|
918
|
+
columns: [table.workspaceId, table.accountId],
|
|
919
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
920
|
+
}).onDelete("cascade"),
|
|
738
921
|
}),
|
|
739
922
|
);
|
|
740
923
|
|
|
@@ -1156,6 +1339,9 @@ export const sessionTurns = pgTable(
|
|
|
1156
1339
|
turnInstructions: text("turn_instructions"),
|
|
1157
1340
|
resources: jsonb("resources").$type<unknown[]>().notNull().default([]),
|
|
1158
1341
|
tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
|
|
1342
|
+
// false = inherit the durable session policy; true = this turn explicitly
|
|
1343
|
+
// replaces it with `tools` after the core subset fence.
|
|
1344
|
+
toolsProvided: boolean("tools_provided").notNull().default(false),
|
|
1159
1345
|
model: text("model").notNull(),
|
|
1160
1346
|
reasoningEffort: text("reasoning_effort").notNull(),
|
|
1161
1347
|
sandboxBackend: text("sandbox_backend").notNull(),
|
|
@@ -1230,6 +1416,10 @@ export const sessionTurnAttempts = pgTable(
|
|
|
1230
1416
|
verifiedControlRevision: bigint("verified_control_revision", {
|
|
1231
1417
|
mode: "number",
|
|
1232
1418
|
}).notNull(),
|
|
1419
|
+
// Immutable policy snapshot captured under the session lock at claim.
|
|
1420
|
+
mcpApprovalPolicies: jsonb("mcp_approval_policies")
|
|
1421
|
+
.$type<Record<string, SessionMcpApprovalPolicy>>()
|
|
1422
|
+
.notNull(),
|
|
1233
1423
|
startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1234
1424
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1235
1425
|
closedAt: timestamp("closed_at", { withTimezone: true }),
|
|
@@ -1363,6 +1553,9 @@ export const sessionCommandReceipts = pgTable(
|
|
|
1363
1553
|
table.targetSessionId,
|
|
1364
1554
|
table.createdAt,
|
|
1365
1555
|
),
|
|
1556
|
+
goalUpdateOperation: uniqueIndex("session_command_receipts_goal_update_operation_uq")
|
|
1557
|
+
.on(table.workspaceId, table.action, table.targetSessionId, table.operationKey)
|
|
1558
|
+
.where(sql`${table.action} = 'goal.update'`),
|
|
1366
1559
|
actorValid: check(
|
|
1367
1560
|
"session_command_receipts_actor_check",
|
|
1368
1561
|
sql`(
|
|
@@ -1502,6 +1695,7 @@ export const composerDrafts = pgTable(
|
|
|
1502
1695
|
text: text("text").notNull().default(""),
|
|
1503
1696
|
resources: jsonb("resources").$type<unknown[]>().notNull().default([]),
|
|
1504
1697
|
tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
|
|
1698
|
+
toolsProvided: boolean("tools_provided").notNull().default(false),
|
|
1505
1699
|
model: text("model").notNull(),
|
|
1506
1700
|
reasoningEffort: text("reasoning_effort").notNull(),
|
|
1507
1701
|
sourceTurnId: uuid("source_turn_id"),
|
|
@@ -1538,6 +1732,43 @@ export const composerDrafts = pgTable(
|
|
|
1538
1732
|
}),
|
|
1539
1733
|
);
|
|
1540
1734
|
|
|
1735
|
+
// Private pre-session composer truth. It is separate from composerDrafts so
|
|
1736
|
+
// the established-session table keeps its mandatory session foreign key.
|
|
1737
|
+
export const newSessionDrafts = pgTable(
|
|
1738
|
+
"new_session_drafts",
|
|
1739
|
+
{
|
|
1740
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1741
|
+
accountId: uuid("account_id").notNull(),
|
|
1742
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
1743
|
+
subjectId: text("subject_id").notNull(),
|
|
1744
|
+
revision: bigint("revision", { mode: "number" }).notNull().default(1),
|
|
1745
|
+
text: text("text").notNull().default(""),
|
|
1746
|
+
resources: jsonb("resources").$type<unknown[]>().notNull().default([]),
|
|
1747
|
+
tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
|
|
1748
|
+
model: text("model").notNull(),
|
|
1749
|
+
reasoningEffort: text("reasoning_effort").notNull(),
|
|
1750
|
+
sessionOptions: jsonb("session_options").$type<Record<string, unknown>>().notNull().default({}),
|
|
1751
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1752
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1753
|
+
},
|
|
1754
|
+
(table) => ({
|
|
1755
|
+
workspaceAccount: foreignKey({
|
|
1756
|
+
name: "new_session_drafts_workspace_account_fk",
|
|
1757
|
+
columns: [table.workspaceId, table.accountId],
|
|
1758
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
1759
|
+
}).onDelete("cascade"),
|
|
1760
|
+
subjectWorkspace: uniqueIndex("new_session_drafts_subject_workspace_uq").on(
|
|
1761
|
+
table.workspaceId,
|
|
1762
|
+
table.subjectId,
|
|
1763
|
+
),
|
|
1764
|
+
subjectValid: check(
|
|
1765
|
+
"new_session_drafts_subject_check",
|
|
1766
|
+
sql`length(btrim(${table.subjectId})) > 0`,
|
|
1767
|
+
),
|
|
1768
|
+
revisionValid: check("new_session_drafts_revision_check", sql`${table.revision} >= 1`),
|
|
1769
|
+
}),
|
|
1770
|
+
);
|
|
1771
|
+
|
|
1541
1772
|
export const sessionSystemUpdates = pgTable(
|
|
1542
1773
|
"session_system_updates",
|
|
1543
1774
|
{
|
|
@@ -1677,6 +1908,10 @@ export const sessionWorkflowWakeOutbox = pgTable(
|
|
|
1677
1908
|
"session_workflow_wake_outbox_revision_check",
|
|
1678
1909
|
sql`${table.wakeRevision} > 0 and ${table.deliveredRevision} >= 0 and ${table.deliveredRevision} <= ${table.wakeRevision}`,
|
|
1679
1910
|
),
|
|
1911
|
+
revisionSafe: check(
|
|
1912
|
+
"session_workflow_wake_outbox_revision_safe_check",
|
|
1913
|
+
sql`${table.wakeRevision} <= 9007199254740991 and ${table.deliveredRevision} <= 9007199254740991`,
|
|
1914
|
+
),
|
|
1680
1915
|
workspaceAccount: foreignKey({
|
|
1681
1916
|
name: "session_workflow_wake_outbox_workspace_account_fk",
|
|
1682
1917
|
columns: [table.workspaceId, table.accountId],
|
|
@@ -1723,6 +1958,18 @@ export const sessionGoals = pgTable(
|
|
|
1723
1958
|
maxAutoContinuations: integer("max_auto_continuations"), // per-goal override; a configured settings cap (if any) remains the hard ceiling
|
|
1724
1959
|
lastContinuationTurnId: uuid("last_continuation_turn_id"),
|
|
1725
1960
|
versionAtLastContinuation: integer("version_at_last_continuation"),
|
|
1961
|
+
// Postgres owns the continuation obligation. Terminal settlement advances
|
|
1962
|
+
// wakeRevision in the same transaction that makes the session idle;
|
|
1963
|
+
// materialization advances observedRevision only alongside the one typed
|
|
1964
|
+
// update, timeline events, usage row, and workflow-wake outbox row.
|
|
1965
|
+
// Temporal signals and workflow history are replaceable nudges over these
|
|
1966
|
+
// monotonic revisions.
|
|
1967
|
+
continuationWakeRevision: bigint("continuation_wake_revision", { mode: "number" })
|
|
1968
|
+
.notNull()
|
|
1969
|
+
.default(0),
|
|
1970
|
+
continuationObservedRevision: bigint("continuation_observed_revision", { mode: "number" })
|
|
1971
|
+
.notNull()
|
|
1972
|
+
.default(0),
|
|
1726
1973
|
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
|
|
1727
1974
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1728
1975
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -1737,6 +1984,10 @@ export const sessionGoals = pgTable(
|
|
|
1737
1984
|
table.sessionId,
|
|
1738
1985
|
),
|
|
1739
1986
|
status: index("session_goals_workspace_status_idx").on(table.workspaceId, table.status),
|
|
1987
|
+
continuationRevisionValid: check(
|
|
1988
|
+
"session_goals_continuation_revision_check",
|
|
1989
|
+
sql`${table.continuationWakeRevision} >= 0 and ${table.continuationObservedRevision} >= 0 and ${table.continuationObservedRevision} <= ${table.continuationWakeRevision} and ${table.continuationWakeRevision} <= 9007199254740991 and ${table.continuationObservedRevision} <= 9007199254740991`,
|
|
1990
|
+
),
|
|
1740
1991
|
}),
|
|
1741
1992
|
);
|
|
1742
1993
|
|
|
@@ -2096,6 +2347,7 @@ export const sessionPendingToolCalls = pgTable(
|
|
|
2096
2347
|
callId: text("call_id").notNull(),
|
|
2097
2348
|
callType: text("call_type").notNull(),
|
|
2098
2349
|
callItem: jsonb("call_item").$type<Record<string, unknown>>().notNull(),
|
|
2350
|
+
modelToolOutputTruncationTokens: integer("model_tool_output_truncation_tokens"),
|
|
2099
2351
|
resultItem: jsonb("result_item").$type<Record<string, unknown>>(),
|
|
2100
2352
|
resultRecordedAt: timestamp("result_recorded_at", { withTimezone: true }),
|
|
2101
2353
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -2208,6 +2460,14 @@ export const sandboxLeases = pgTable(
|
|
|
2208
2460
|
// Epochs never approach 2^31, so the narrower type loses nothing.
|
|
2209
2461
|
leaseEpoch: integer("lease_epoch").notNull().default(0),
|
|
2210
2462
|
|
|
2463
|
+
// Monotonic mutation intent for the live workspace. Every acknowledged
|
|
2464
|
+
// filesystem-writing operation advances this under the exact lease epoch +
|
|
2465
|
+
// provider-instance fence BEFORE it reaches the provider. A verified
|
|
2466
|
+
// archive fold copies the exact captured value into archive_generation in
|
|
2467
|
+
// the same row update; equality is the only durable completeness proof.
|
|
2468
|
+
workspaceGeneration: integer("workspace_generation").notNull().default(0),
|
|
2469
|
+
archiveGeneration: integer("archive_generation"),
|
|
2470
|
+
|
|
2211
2471
|
// The group box-envelope (the "envelope split" Critical): the small recovery
|
|
2212
2472
|
// descriptor to resume()-by-id the group's box without a per-session join.
|
|
2213
2473
|
resumeBackendId: text("resume_backend_id"),
|
|
@@ -2225,9 +2485,30 @@ export const sandboxLeases = pgTable(
|
|
|
2225
2485
|
},
|
|
2226
2486
|
(table) => ({
|
|
2227
2487
|
groupIdx: uniqueIndex("sandbox_leases_group_idx").on(table.workspaceId, table.sandboxGroupId),
|
|
2488
|
+
scopedId: uniqueIndex("sandbox_leases_scoped_id_uq").on(
|
|
2489
|
+
table.accountId,
|
|
2490
|
+
table.workspaceId,
|
|
2491
|
+
table.sandboxGroupId,
|
|
2492
|
+
table.id,
|
|
2493
|
+
),
|
|
2494
|
+
accountWorkspaceId: uniqueIndex("sandbox_leases_account_workspace_id_uq").on(
|
|
2495
|
+
table.accountId,
|
|
2496
|
+
table.workspaceId,
|
|
2497
|
+
table.id,
|
|
2498
|
+
),
|
|
2228
2499
|
reaperIdx: index("sandbox_leases_reaper_idx")
|
|
2229
2500
|
.on(table.expiresAt)
|
|
2230
2501
|
.where(sql`${table.liveness} in ('warming','warm','draining')`),
|
|
2502
|
+
workspaceGenerationValid: check(
|
|
2503
|
+
"sandbox_leases_workspace_generation_check",
|
|
2504
|
+
sql`${table.workspaceGeneration} >= 0`,
|
|
2505
|
+
),
|
|
2506
|
+
archiveGenerationValid: check(
|
|
2507
|
+
"sandbox_leases_archive_generation_check",
|
|
2508
|
+
sql`${table.archiveGeneration} is null
|
|
2509
|
+
or (${table.archiveGeneration} >= 0
|
|
2510
|
+
and ${table.archiveGeneration} <= ${table.workspaceGeneration})`,
|
|
2511
|
+
),
|
|
2231
2512
|
}),
|
|
2232
2513
|
);
|
|
2233
2514
|
|
|
@@ -2246,7 +2527,7 @@ export const sandboxLeaseHolders = pgTable(
|
|
|
2246
2527
|
leaseId: uuid("lease_id")
|
|
2247
2528
|
.notNull()
|
|
2248
2529
|
.references(() => sandboxLeases.id, { onDelete: "cascade" }),
|
|
2249
|
-
kind: text("kind", { enum: ["turn", "viewer"] }).notNull(),
|
|
2530
|
+
kind: text("kind", { enum: ["turn", "viewer", "direct", "process"] }).notNull(),
|
|
2250
2531
|
holderId: text("holder_id").notNull(),
|
|
2251
2532
|
// The attributing session within the (possibly shared) group.
|
|
2252
2533
|
subjectId: uuid("subject_id"),
|
|
@@ -2254,6 +2535,11 @@ export const sandboxLeaseHolders = pgTable(
|
|
|
2254
2535
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2255
2536
|
},
|
|
2256
2537
|
(table) => ({
|
|
2538
|
+
leaseScope: foreignKey({
|
|
2539
|
+
name: "sandbox_lease_holders_lease_scope_fk",
|
|
2540
|
+
columns: [table.accountId, table.workspaceId, table.leaseId],
|
|
2541
|
+
foreignColumns: [sandboxLeases.accountId, sandboxLeases.workspaceId, sandboxLeases.id],
|
|
2542
|
+
}).onDelete("cascade"),
|
|
2257
2543
|
holderIdx: uniqueIndex("sandbox_lease_holders_holder_idx").on(
|
|
2258
2544
|
table.leaseId,
|
|
2259
2545
|
table.kind,
|
|
@@ -2264,6 +2550,283 @@ export const sandboxLeaseHolders = pgTable(
|
|
|
2264
2550
|
}),
|
|
2265
2551
|
);
|
|
2266
2552
|
|
|
2553
|
+
export const sandboxWorkspaceMutationActorKindValues = ["turn", "direct", "process"] as const;
|
|
2554
|
+
export const sandboxWorkspaceMutationHolderKindValues = ["turn", "direct", "process"] as const;
|
|
2555
|
+
|
|
2556
|
+
// Durable admission ledger for every provider operation that may mutate a
|
|
2557
|
+
// persistable /workspace. The row is inserted atomically with the lease's
|
|
2558
|
+
// workspace_generation increment before the provider is invoked, then marked
|
|
2559
|
+
// physically settled after the provider promise resolves OR rejects. Capture
|
|
2560
|
+
// remains blocked by an unsettled direct/process row. A turn row may cease
|
|
2561
|
+
// blocking only after its exact attempt carries the authoritative quiesced_at
|
|
2562
|
+
// receipt. Yielded provider processes remain retained/unsettled until exact
|
|
2563
|
+
// exit or loss proof settles their parent admission.
|
|
2564
|
+
export const sandboxWorkspaceMutationAdmissions = pgTable(
|
|
2565
|
+
"sandbox_workspace_mutation_admissions",
|
|
2566
|
+
{
|
|
2567
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
2568
|
+
accountId: uuid("account_id").notNull(),
|
|
2569
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
2570
|
+
leaseId: uuid("lease_id")
|
|
2571
|
+
.notNull()
|
|
2572
|
+
.references(() => sandboxLeases.id, { onDelete: "cascade" }),
|
|
2573
|
+
sandboxGroupId: uuid("sandbox_group_id").notNull(),
|
|
2574
|
+
sessionId: uuid("session_id").notNull(),
|
|
2575
|
+
actorKind: text("actor_kind", { enum: sandboxWorkspaceMutationActorKindValues }).notNull(),
|
|
2576
|
+
actorId: uuid("actor_id").notNull(),
|
|
2577
|
+
// Exact turn authority is present only for actor_kind='turn'. Direct HTTP
|
|
2578
|
+
// requests and retained processes never invent a turn or quiescence owner.
|
|
2579
|
+
turnId: uuid("turn_id"),
|
|
2580
|
+
attemptId: uuid("attempt_id"),
|
|
2581
|
+
executionGeneration: integer("execution_generation"),
|
|
2582
|
+
holderKind: text("holder_kind", {
|
|
2583
|
+
enum: sandboxWorkspaceMutationHolderKindValues,
|
|
2584
|
+
}).notNull(),
|
|
2585
|
+
holderId: text("holder_id").notNull(),
|
|
2586
|
+
leaseEpoch: integer("lease_epoch").notNull(),
|
|
2587
|
+
providerBackend: text("provider_backend").notNull(),
|
|
2588
|
+
providerInstanceId: text("provider_instance_id").notNull(),
|
|
2589
|
+
routeKind: text("route_kind", { enum: ["home", "active"] }).notNull(),
|
|
2590
|
+
// null route target means the persistable home/group provider. A non-null
|
|
2591
|
+
// target is pinned together with the active pointer epoch observed when the
|
|
2592
|
+
// operation was admitted.
|
|
2593
|
+
routeTargetId: uuid("route_target_id"),
|
|
2594
|
+
routeEpoch: integer("route_epoch").notNull(),
|
|
2595
|
+
workspaceGeneration: integer("workspace_generation").notNull(),
|
|
2596
|
+
operation: text("operation").notNull(),
|
|
2597
|
+
providerOutcome: text("provider_outcome", {
|
|
2598
|
+
enum: ["resolved", "rejected", "retained"],
|
|
2599
|
+
}),
|
|
2600
|
+
admittedAt: timestamp("admitted_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2601
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
2602
|
+
},
|
|
2603
|
+
(table) => ({
|
|
2604
|
+
workspaceAccount: foreignKey({
|
|
2605
|
+
name: "sandbox_workspace_mutation_admissions_workspace_account_fk",
|
|
2606
|
+
columns: [table.workspaceId, table.accountId],
|
|
2607
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
2608
|
+
}).onDelete("cascade"),
|
|
2609
|
+
workspaceSession: foreignKey({
|
|
2610
|
+
name: "sandbox_workspace_mutation_admissions_workspace_session_fk",
|
|
2611
|
+
columns: [table.workspaceId, table.sessionId],
|
|
2612
|
+
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
2613
|
+
}).onDelete("restrict"),
|
|
2614
|
+
workspaceTurn: foreignKey({
|
|
2615
|
+
name: "sandbox_workspace_mutation_admissions_workspace_turn_fk",
|
|
2616
|
+
columns: [table.workspaceId, table.turnId],
|
|
2617
|
+
foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
|
|
2618
|
+
}).onDelete("restrict"),
|
|
2619
|
+
workspaceAttempt: foreignKey({
|
|
2620
|
+
name: "sandbox_workspace_mutation_admissions_workspace_attempt_fk",
|
|
2621
|
+
columns: [table.workspaceId, table.attemptId],
|
|
2622
|
+
foreignColumns: [sessionTurnAttempts.workspaceId, sessionTurnAttempts.id],
|
|
2623
|
+
}).onDelete("restrict"),
|
|
2624
|
+
leaseGeneration: uniqueIndex("sandbox_workspace_mutation_admissions_lease_generation_uq").on(
|
|
2625
|
+
table.leaseId,
|
|
2626
|
+
table.workspaceGeneration,
|
|
2627
|
+
),
|
|
2628
|
+
scopedId: uniqueIndex("sandbox_workspace_mutation_admissions_scoped_id_uq").on(
|
|
2629
|
+
table.accountId,
|
|
2630
|
+
table.workspaceId,
|
|
2631
|
+
table.sessionId,
|
|
2632
|
+
table.leaseId,
|
|
2633
|
+
table.id,
|
|
2634
|
+
),
|
|
2635
|
+
blocking: index("sandbox_workspace_mutation_admissions_blocking_idx")
|
|
2636
|
+
.on(table.leaseId, table.workspaceGeneration)
|
|
2637
|
+
.where(sql`${table.settledAt} is null`),
|
|
2638
|
+
attempt: index("sandbox_workspace_mutation_admissions_attempt_idx").on(
|
|
2639
|
+
table.workspaceId,
|
|
2640
|
+
table.attemptId,
|
|
2641
|
+
),
|
|
2642
|
+
actor: index("sandbox_workspace_mutation_admissions_actor_idx").on(
|
|
2643
|
+
table.workspaceId,
|
|
2644
|
+
table.actorKind,
|
|
2645
|
+
table.actorId,
|
|
2646
|
+
),
|
|
2647
|
+
generationValid: check(
|
|
2648
|
+
"sandbox_workspace_mutation_admissions_generation_check",
|
|
2649
|
+
sql`${table.workspaceGeneration} > 0
|
|
2650
|
+
and ${table.leaseEpoch} >= 0
|
|
2651
|
+
and ${table.routeEpoch} >= 0
|
|
2652
|
+
and (${table.executionGeneration} is null or ${table.executionGeneration} > 0)`,
|
|
2653
|
+
),
|
|
2654
|
+
actorValid: check(
|
|
2655
|
+
"sandbox_workspace_mutation_admissions_actor_check",
|
|
2656
|
+
sql`(
|
|
2657
|
+
${table.actorKind} = 'turn'
|
|
2658
|
+
and ${table.actorId} = ${table.attemptId}
|
|
2659
|
+
and ${table.turnId} is not null
|
|
2660
|
+
and ${table.attemptId} is not null
|
|
2661
|
+
and ${table.executionGeneration} is not null
|
|
2662
|
+
and ${table.holderKind} = 'turn'
|
|
2663
|
+
) or (
|
|
2664
|
+
${table.actorKind} = 'direct'
|
|
2665
|
+
and ${table.turnId} is null
|
|
2666
|
+
and ${table.attemptId} is null
|
|
2667
|
+
and ${table.executionGeneration} is null
|
|
2668
|
+
and ${table.holderKind} = 'direct'
|
|
2669
|
+
) or (
|
|
2670
|
+
${table.actorKind} = 'process'
|
|
2671
|
+
and ${table.turnId} is null
|
|
2672
|
+
and ${table.attemptId} is null
|
|
2673
|
+
and ${table.executionGeneration} is null
|
|
2674
|
+
and ${table.holderKind} = 'process'
|
|
2675
|
+
)`,
|
|
2676
|
+
),
|
|
2677
|
+
routeValid: check(
|
|
2678
|
+
"sandbox_workspace_mutation_admissions_route_check",
|
|
2679
|
+
sql`${table.actorKind} in ('turn', 'direct', 'process')
|
|
2680
|
+
and ${table.holderKind} in ('turn', 'direct', 'process')
|
|
2681
|
+
and octet_length(${table.holderId}) between 1 and 256
|
|
2682
|
+
and octet_length(${table.providerBackend}) between 1 and 64
|
|
2683
|
+
and octet_length(${table.providerInstanceId}) between 1 and 512
|
|
2684
|
+
and ${table.routeKind} in ('home', 'active')
|
|
2685
|
+
and (${table.routeKind} = 'active' or ${table.routeTargetId} is null)`,
|
|
2686
|
+
),
|
|
2687
|
+
operationValid: check(
|
|
2688
|
+
"sandbox_workspace_mutation_admissions_operation_check",
|
|
2689
|
+
sql`octet_length(${table.operation}) between 1 and 128`,
|
|
2690
|
+
),
|
|
2691
|
+
outcomeValid: check(
|
|
2692
|
+
"sandbox_workspace_mutation_admissions_outcome_check",
|
|
2693
|
+
sql`${table.providerOutcome} is null or ${table.providerOutcome} in ('resolved', 'rejected', 'retained')`,
|
|
2694
|
+
),
|
|
2695
|
+
settlementConsistent: check(
|
|
2696
|
+
"sandbox_workspace_mutation_admissions_settlement_check",
|
|
2697
|
+
sql`(${table.providerOutcome} is null and ${table.settledAt} is null)
|
|
2698
|
+
or (${table.providerOutcome} = 'retained' and ${table.settledAt} is null)
|
|
2699
|
+
or (${table.providerOutcome} in ('resolved', 'rejected') and ${table.settledAt} is not null)`,
|
|
2700
|
+
),
|
|
2701
|
+
}),
|
|
2702
|
+
);
|
|
2703
|
+
|
|
2704
|
+
export const sandboxRetainedProcessStateValues = ["active", "exited", "lost"] as const;
|
|
2705
|
+
|
|
2706
|
+
// A yielded exec is not merely a numeric provider session id: it is a durable
|
|
2707
|
+
// continuation of the exact admitted mutation and owns a non-TTL process lease
|
|
2708
|
+
// holder until exit/loss is proven. Every later model-facing stdin write gets a
|
|
2709
|
+
// distinct actor_kind='process' admission tied back to this identity. Control
|
|
2710
|
+
// polling may use the pinned provider route without creating a new generation.
|
|
2711
|
+
export const sandboxRetainedProcesses = pgTable(
|
|
2712
|
+
"sandbox_retained_processes",
|
|
2713
|
+
{
|
|
2714
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
2715
|
+
accountId: uuid("account_id").notNull(),
|
|
2716
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
2717
|
+
sessionId: uuid("session_id").notNull(),
|
|
2718
|
+
leaseId: uuid("lease_id").notNull(),
|
|
2719
|
+
sandboxGroupId: uuid("sandbox_group_id").notNull(),
|
|
2720
|
+
parentAdmissionId: uuid("parent_admission_id").notNull(),
|
|
2721
|
+
holderId: text("holder_id").notNull(),
|
|
2722
|
+
ownerActorKind: text("owner_actor_kind", { enum: ["turn", "direct"] }).notNull(),
|
|
2723
|
+
ownerActorId: uuid("owner_actor_id").notNull(),
|
|
2724
|
+
ownerTurnId: uuid("owner_turn_id"),
|
|
2725
|
+
ownerAttemptId: uuid("owner_attempt_id"),
|
|
2726
|
+
ownerExecutionGeneration: integer("owner_execution_generation"),
|
|
2727
|
+
leaseEpoch: integer("lease_epoch").notNull(),
|
|
2728
|
+
providerBackend: text("provider_backend").notNull(),
|
|
2729
|
+
providerInstanceId: text("provider_instance_id").notNull(),
|
|
2730
|
+
routeKind: text("route_kind", { enum: ["home", "active"] }).notNull(),
|
|
2731
|
+
routeTargetId: uuid("route_target_id"),
|
|
2732
|
+
routeEpoch: integer("route_epoch").notNull(),
|
|
2733
|
+
providerSessionId: integer("provider_session_id").notNull(),
|
|
2734
|
+
state: text("state", { enum: sandboxRetainedProcessStateValues }).notNull().default("active"),
|
|
2735
|
+
exitCode: integer("exit_code"),
|
|
2736
|
+
settlementReason: text("settlement_reason"),
|
|
2737
|
+
startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2738
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
2739
|
+
},
|
|
2740
|
+
(table) => ({
|
|
2741
|
+
workspaceAccount: foreignKey({
|
|
2742
|
+
name: "sandbox_retained_processes_workspace_account_fk",
|
|
2743
|
+
columns: [table.workspaceId, table.accountId],
|
|
2744
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
2745
|
+
}).onDelete("cascade"),
|
|
2746
|
+
workspaceSession: foreignKey({
|
|
2747
|
+
name: "sandbox_retained_processes_workspace_session_fk",
|
|
2748
|
+
columns: [table.workspaceId, table.sessionId],
|
|
2749
|
+
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
2750
|
+
}).onDelete("restrict"),
|
|
2751
|
+
parentAdmissionScope: foreignKey({
|
|
2752
|
+
name: "sandbox_retained_processes_parent_admission_scope_fk",
|
|
2753
|
+
columns: [
|
|
2754
|
+
table.accountId,
|
|
2755
|
+
table.workspaceId,
|
|
2756
|
+
table.sessionId,
|
|
2757
|
+
table.leaseId,
|
|
2758
|
+
table.parentAdmissionId,
|
|
2759
|
+
],
|
|
2760
|
+
foreignColumns: [
|
|
2761
|
+
sandboxWorkspaceMutationAdmissions.accountId,
|
|
2762
|
+
sandboxWorkspaceMutationAdmissions.workspaceId,
|
|
2763
|
+
sandboxWorkspaceMutationAdmissions.sessionId,
|
|
2764
|
+
sandboxWorkspaceMutationAdmissions.leaseId,
|
|
2765
|
+
sandboxWorkspaceMutationAdmissions.id,
|
|
2766
|
+
],
|
|
2767
|
+
}).onDelete("restrict"),
|
|
2768
|
+
scopedId: uniqueIndex("sandbox_retained_processes_scoped_id_uq").on(
|
|
2769
|
+
table.accountId,
|
|
2770
|
+
table.workspaceId,
|
|
2771
|
+
table.sessionId,
|
|
2772
|
+
table.leaseId,
|
|
2773
|
+
table.id,
|
|
2774
|
+
),
|
|
2775
|
+
parentAdmission: uniqueIndex("sandbox_retained_processes_parent_admission_uq").on(
|
|
2776
|
+
table.parentAdmissionId,
|
|
2777
|
+
),
|
|
2778
|
+
liveProviderSession: uniqueIndex("sandbox_retained_processes_live_provider_session_uq")
|
|
2779
|
+
.on(
|
|
2780
|
+
table.leaseId,
|
|
2781
|
+
table.leaseEpoch,
|
|
2782
|
+
table.providerInstanceId,
|
|
2783
|
+
table.routeEpoch,
|
|
2784
|
+
table.providerSessionId,
|
|
2785
|
+
)
|
|
2786
|
+
.where(sql`${table.state} = 'active'`),
|
|
2787
|
+
holder: uniqueIndex("sandbox_retained_processes_holder_uq").on(table.leaseId, table.holderId),
|
|
2788
|
+
active: index("sandbox_retained_processes_active_idx")
|
|
2789
|
+
.on(table.workspaceId, table.sessionId, table.startedAt)
|
|
2790
|
+
.where(sql`${table.state} = 'active'`),
|
|
2791
|
+
identityValid: check(
|
|
2792
|
+
"sandbox_retained_processes_identity_check",
|
|
2793
|
+
sql`${table.leaseEpoch} >= 0
|
|
2794
|
+
and ${table.routeEpoch} >= 0
|
|
2795
|
+
and ${table.providerSessionId} > 0
|
|
2796
|
+
and octet_length(${table.holderId}) between 1 and 256
|
|
2797
|
+
and octet_length(${table.providerBackend}) between 1 and 64
|
|
2798
|
+
and octet_length(${table.providerInstanceId}) between 1 and 512
|
|
2799
|
+
and (${table.routeKind} = 'active' or ${table.routeTargetId} is null)`,
|
|
2800
|
+
),
|
|
2801
|
+
ownerValid: check(
|
|
2802
|
+
"sandbox_retained_processes_owner_check",
|
|
2803
|
+
sql`(
|
|
2804
|
+
${table.ownerActorKind} = 'turn'
|
|
2805
|
+
and ${table.ownerActorId} = ${table.ownerAttemptId}
|
|
2806
|
+
and ${table.ownerTurnId} is not null
|
|
2807
|
+
and ${table.ownerAttemptId} is not null
|
|
2808
|
+
and ${table.ownerExecutionGeneration} > 0
|
|
2809
|
+
) or (
|
|
2810
|
+
${table.ownerActorKind} = 'direct'
|
|
2811
|
+
and ${table.ownerTurnId} is null
|
|
2812
|
+
and ${table.ownerAttemptId} is null
|
|
2813
|
+
and ${table.ownerExecutionGeneration} is null
|
|
2814
|
+
)`,
|
|
2815
|
+
),
|
|
2816
|
+
settlementValid: check(
|
|
2817
|
+
"sandbox_retained_processes_settlement_check",
|
|
2818
|
+
sql`(${table.state} = 'active' and ${table.settledAt} is null and ${table.exitCode} is null)
|
|
2819
|
+
or (${table.state} = 'exited' and ${table.settledAt} is not null)
|
|
2820
|
+
or (${table.state} = 'lost' and ${table.settledAt} is not null and ${table.exitCode} is null)`,
|
|
2821
|
+
),
|
|
2822
|
+
reasonValid: check(
|
|
2823
|
+
"sandbox_retained_processes_reason_check",
|
|
2824
|
+
sql`${table.settlementReason} is null
|
|
2825
|
+
or octet_length(${table.settlementReason}) between 1 and 512`,
|
|
2826
|
+
),
|
|
2827
|
+
}),
|
|
2828
|
+
);
|
|
2829
|
+
|
|
2267
2830
|
// The recording lifecycle states (P4.3). Exported so the activity + the query
|
|
2268
2831
|
// layer share one source of truth for the §3.1 state machine.
|
|
2269
2832
|
export const sessionRecordingStateValues = [
|
|
@@ -2384,14 +2947,12 @@ export const workspaceCaptures = pgTable(
|
|
|
2384
2947
|
}),
|
|
2385
2948
|
);
|
|
2386
2949
|
|
|
2387
|
-
// Interactive PTY sessions.
|
|
2388
|
-
//
|
|
2389
|
-
//
|
|
2390
|
-
//
|
|
2391
|
-
//
|
|
2392
|
-
//
|
|
2393
|
-
// a last_input_at heartbeat so the reaper can kill idle/orphaned PTYs. Mirrors
|
|
2394
|
-
// the account/workspace/session FK chain of sandboxSessionEnvelopes.
|
|
2950
|
+
// Interactive PTY sessions. An OPEN PTY adopts one exact retained process; the
|
|
2951
|
+
// provider's numeric exec-session id is only a copied locator and never authority
|
|
2952
|
+
// on its own. Provider/lease/route/admission identity is copied onto the row so a
|
|
2953
|
+
// stale pointer or box epoch cannot redirect control to a rival process. Legacy
|
|
2954
|
+
// numeric-only rows are closed by the maintenance cutover and may retain null
|
|
2955
|
+
// identity columns only in that terminal state.
|
|
2395
2956
|
export const sandboxPtySessions = pgTable(
|
|
2396
2957
|
"sandbox_pty_sessions",
|
|
2397
2958
|
{
|
|
@@ -2405,10 +2966,18 @@ export const sandboxPtySessions = pgTable(
|
|
|
2405
2966
|
sessionId: uuid("session_id")
|
|
2406
2967
|
.notNull()
|
|
2407
2968
|
.references(() => sessions.id, { onDelete: "cascade" }),
|
|
2408
|
-
|
|
2409
|
-
|
|
2969
|
+
leaseId: uuid("lease_id"),
|
|
2970
|
+
sandboxGroupId: uuid("sandbox_group_id"),
|
|
2971
|
+
retainedProcessId: uuid("retained_process_id"),
|
|
2972
|
+
openAdmissionId: uuid("open_admission_id"),
|
|
2973
|
+
// Copied provider locator for the adopted retained process.
|
|
2410
2974
|
execSessionId: integer("exec_session_id"),
|
|
2411
|
-
leaseEpoch: integer("lease_epoch").notNull(),
|
|
2975
|
+
leaseEpoch: integer("lease_epoch").notNull(),
|
|
2976
|
+
providerBackend: text("provider_backend"),
|
|
2977
|
+
providerInstanceId: text("provider_instance_id"),
|
|
2978
|
+
routeKind: text("route_kind", { enum: ["home", "active"] }),
|
|
2979
|
+
routeTargetId: uuid("route_target_id"),
|
|
2980
|
+
routeEpoch: integer("route_epoch"),
|
|
2412
2981
|
cols: integer("cols").notNull(),
|
|
2413
2982
|
rows: integer("rows").notNull(),
|
|
2414
2983
|
shell: text("shell").notNull(),
|
|
@@ -2422,9 +2991,46 @@ export const sandboxPtySessions = pgTable(
|
|
|
2422
2991
|
closedAt: timestamp("closed_at", { withTimezone: true }),
|
|
2423
2992
|
},
|
|
2424
2993
|
(table) => ({
|
|
2994
|
+
retainedProcessScope: foreignKey({
|
|
2995
|
+
name: "sandbox_pty_sessions_retained_process_scope_fk",
|
|
2996
|
+
columns: [
|
|
2997
|
+
table.accountId,
|
|
2998
|
+
table.workspaceId,
|
|
2999
|
+
table.sessionId,
|
|
3000
|
+
table.leaseId,
|
|
3001
|
+
table.retainedProcessId,
|
|
3002
|
+
],
|
|
3003
|
+
foreignColumns: [
|
|
3004
|
+
sandboxRetainedProcesses.accountId,
|
|
3005
|
+
sandboxRetainedProcesses.workspaceId,
|
|
3006
|
+
sandboxRetainedProcesses.sessionId,
|
|
3007
|
+
sandboxRetainedProcesses.leaseId,
|
|
3008
|
+
sandboxRetainedProcesses.id,
|
|
3009
|
+
],
|
|
3010
|
+
}).onDelete("restrict"),
|
|
2425
3011
|
openIdx: index("sandbox_pty_sessions_session_idx")
|
|
2426
3012
|
.on(table.workspaceId, table.sessionId)
|
|
2427
3013
|
.where(sql`${table.status} = 'open'`),
|
|
3014
|
+
processIdx: uniqueIndex("sandbox_pty_sessions_open_process_uq")
|
|
3015
|
+
.on(table.retainedProcessId)
|
|
3016
|
+
.where(sql`${table.status} = 'open'`),
|
|
3017
|
+
openIdentityValid: check(
|
|
3018
|
+
"sandbox_pty_sessions_open_identity_check",
|
|
3019
|
+
sql`${table.status} <> 'open' or (
|
|
3020
|
+
${table.leaseId} is not null
|
|
3021
|
+
and ${table.sandboxGroupId} is not null
|
|
3022
|
+
and ${table.retainedProcessId} is not null
|
|
3023
|
+
and ${table.openAdmissionId} is not null
|
|
3024
|
+
and ${table.execSessionId} > 0
|
|
3025
|
+
and octet_length(${table.providerBackend}) between 1 and 64
|
|
3026
|
+
and octet_length(${table.providerInstanceId}) between 1 and 512
|
|
3027
|
+
and ${table.routeKind} in ('home', 'active')
|
|
3028
|
+
and (${table.routeKind} = 'active' or ${table.routeTargetId} is null)
|
|
3029
|
+
and ${table.routeEpoch} is not null
|
|
3030
|
+
and ${table.leaseEpoch} >= 0
|
|
3031
|
+
and ${table.routeEpoch} >= 0
|
|
3032
|
+
)`,
|
|
3033
|
+
),
|
|
2428
3034
|
}),
|
|
2429
3035
|
);
|
|
2430
3036
|
|
|
@@ -2999,6 +3605,10 @@ export const hostExportOutbox = pgTable(
|
|
|
2999
3605
|
"host_export_outbox_kind_check",
|
|
3000
3606
|
sql`${table.exportKind} in ('session_event', 'usage_event')`,
|
|
3001
3607
|
),
|
|
3608
|
+
rootSessionCaptured: check(
|
|
3609
|
+
"host_export_outbox_root_session_check",
|
|
3610
|
+
sql`${table.sessionId} is null or ${table.rootSessionId} is not null`,
|
|
3611
|
+
),
|
|
3002
3612
|
sourceUnique: uniqueIndex("host_export_outbox_source_uq").on(table.exportKind, table.sourceId),
|
|
3003
3613
|
cursorUnique: uniqueIndex("host_export_outbox_cursor_uq")
|
|
3004
3614
|
.on(table.exportKind, table.exportCursor)
|