@opengeni/db 0.36.1 → 3.1.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attached-browser-devices.d.ts +7 -0
- package/dist/automations.d.ts +154 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-integrations.d.ts +13 -0
- package/dist/child-lifecycle-notices.d.ts +68 -0
- package/dist/{chunk-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
- package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
- package/dist/{chunk-HSOWSYOX.js → chunk-NMUBV7Z5.js} +19 -11
- package/dist/chunk-NMUBV7Z5.js.map +1 -0
- package/dist/chunk-OF5OBB76.js +4457 -0
- package/dist/chunk-OF5OBB76.js.map +1 -0
- package/dist/{chunk-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
- package/dist/chunk-PR2WMLOQ.js.map +1 -0
- package/dist/{chunk-Z7VYMNPZ.js → chunk-SCPUJS53.js} +41 -4
- package/dist/chunk-SCPUJS53.js.map +1 -0
- package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
- package/dist/chunk-SIBYBA2D.js.map +1 -0
- package/dist/chunk-TIKF3KTI.js +383 -0
- package/dist/chunk-TIKF3KTI.js.map +1 -0
- package/dist/chunk-ZZ5LJEFX.js +516 -0
- package/dist/chunk-ZZ5LJEFX.js.map +1 -0
- package/dist/codemode-operations.d.ts +1 -6
- package/dist/company-brain-context-selection-schema.d.ts +705 -0
- package/dist/company-brain-context-selection.d.ts +94 -0
- package/dist/company-brain-governed-writes.d.ts +24 -0
- package/dist/company-brain.d.ts +55 -0
- package/dist/company-profile-agent-admin.d.ts +15 -0
- package/dist/company-profile-schema.d.ts +619 -2
- package/dist/company-profile.d.ts +9 -4
- package/dist/connection-authority.d.ts +95 -0
- package/dist/connection-scopes.d.ts +8 -0
- package/dist/connection-tenancy-backfill.d.ts +41 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +19 -0
- package/dist/editable-artifact-durable-export.d.ts +10 -0
- package/dist/editable-artifact-durable-export.js +18 -3
- package/dist/editable-artifact-durable-export.js.map +1 -1
- package/dist/editable-artifacts.d.ts +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation-schema.d.ts +984 -0
- package/dist/governed-learning-activation.d.ts +98 -0
- package/dist/governed-learning-evaluator-schema.d.ts +633 -0
- package/dist/governed-learning-evaluator.d.ts +28 -0
- package/dist/index.d.ts +1633 -87
- package/dist/index.js +22004 -8109
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +18 -0
- package/dist/integration-bindings.d.ts +1 -0
- package/dist/integration-facets.d.ts +30 -0
- package/dist/interaction-placement-loss.d.ts +22 -0
- package/dist/knowledge-source-sync-schema.d.ts +730 -0
- package/dist/knowledge-source-sync.d.ts +60 -0
- package/dist/managed-human-provisioning.d.ts +25 -0
- package/dist/memory-domain.d.ts +3 -3
- package/dist/migrate.d.ts +11 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +43 -5
- package/dist/organization-membership-backfill.d.ts +174 -0
- package/dist/organization-membership-lifecycle.d.ts +162 -0
- package/dist/pr-review.d.ts +107 -0
- package/dist/preference-registry-schema.d.ts +2 -0
- package/dist/preference-registry.d.ts +2 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +23 -9
- package/dist/schema.d.ts +24925 -13697
- package/dist/schema.js +103 -1
- package/dist/scoped-knowledge-schema.d.ts +52 -1
- package/dist/session-background-commands.d.ts +125 -0
- package/dist/session-background-commands.js +34 -0
- package/dist/session-background-commands.js.map +1 -0
- package/dist/session-control.d.ts +156 -3
- package/dist/session-goal-pacing.d.ts +68 -0
- package/dist/session-queue-commands.d.ts +42 -5
- package/dist/session-realtime-ledger.d.ts +3 -0
- package/dist/session-tenancy.d.ts +71 -1
- package/dist/session-tenancy.js +25 -3
- package/dist/session-tool-call-settlement.d.ts +9 -4
- package/dist/slack-routing-personal-workspace.d.ts +23 -0
- package/dist/slack-routing.d.ts +153 -0
- package/dist/slack-task-policy-schema.d.ts +34 -0
- package/dist/slack-task-policy.d.ts +8 -0
- package/dist/slack-user-link-access.d.ts +1 -0
- package/dist/task-notes-schema.d.ts +594 -0
- package/dist/task-notes.d.ts +39 -0
- package/dist/turn-initiator.d.ts +2 -0
- package/dist/user-resource-authority.d.ts +109 -0
- package/dist/video-generation.js +3 -3
- package/dist/workspace-authority.d.ts +81 -0
- package/dist/workspace-instruction-policies-schema.d.ts +279 -0
- package/dist/workspace-instruction-policies.d.ts +62 -0
- package/dist/workspace-learning-policy.d.ts +1 -0
- package/dist/workspace-membership-permissions.d.ts +2 -0
- package/drizzle/0240_enrollment_connection_authority.sql +39 -0
- package/drizzle/0240_model_context_user_messages.sql +204 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
- package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
- package/drizzle/0245_model_context_contribution_facts.sql +88 -0
- package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
- package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
- package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
- package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
- package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
- package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
- package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
- package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
- package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
- package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
- package/drizzle/0256_connection_authority_delegation.sql +703 -0
- package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
- package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
- package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
- package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
- package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
- package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
- package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
- package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
- package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
- package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
- package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
- package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
- package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
- package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
- package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
- package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
- package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
- package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
- package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
- package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
- package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
- package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
- package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
- package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
- package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
- package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
- package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
- package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
- package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
- package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
- package/drizzle/0289_session_composer_policy_authority.sql +597 -0
- package/drizzle/0290_organization_membership_backfill.sql +268 -0
- package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
- package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
- package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
- package/drizzle/0294_preference_activation_authority.sql +237 -0
- package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
- package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
- package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
- package/drizzle/0298_organization_tenancy_parity.sql +609 -0
- package/drizzle/0299_organization_membership_lock_order.sql +291 -0
- package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
- package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
- package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
- package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
- package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
- package/drizzle/0305_personal_resource_grant_management.sql +584 -0
- package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
- package/drizzle/0307_session_attention_state.sql +51 -0
- package/drizzle/0308_session_archives.sql +35 -0
- package/drizzle/0309_channel_project_pins.sql +6 -0
- package/drizzle/0310_channel_project_order.sql +27 -0
- package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
- package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
- package/drizzle/0313_private_child_session_authority.sql +365 -0
- package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
- package/drizzle/0315_personal_github_repository_selection.sql +624 -0
- package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
- package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
- package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
- package/drizzle/0319_event_triggered_automations.sql +254 -0
- package/drizzle/0320_pr_review_pack.sql +113 -0
- package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
- package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
- package/drizzle/0323_organization_private_session_enablement.sql +489 -0
- package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
- package/drizzle/0325_child_lifecycle_notices.sql +44 -0
- package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
- package/drizzle/0327_slack_first_task_hint.sql +29 -0
- package/drizzle/0328_session_background_commands.sql +590 -0
- package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
- package/drizzle/0330_api_key_descriptions.sql +20 -0
- package/drizzle/0331_managed_organization_creation.sql +163 -0
- package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
- package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
- package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
- package/drizzle/0335_slack_workspace_routing.sql +460 -0
- package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
- package/drizzle/0337_slack_routed_action_handles.sql +189 -0
- package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
- package/drizzle/0339_document_authority_reclassification.sql +1153 -0
- package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
- package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
- package/package.json +10 -6
- package/src/attached-browser-devices.ts +233 -5
- package/src/automations.ts +911 -0
- package/src/browser-sessions.ts +10 -0
- package/src/capability-integrations.ts +175 -1
- package/src/child-lifecycle-notices.ts +241 -0
- package/src/codemode-operations.ts +1 -35
- package/src/company-brain-context-selection-schema.ts +100 -0
- package/src/company-brain-context-selection.ts +359 -0
- package/src/company-brain-governed-writes.ts +1170 -0
- package/src/company-brain.ts +309 -0
- package/src/company-profile-agent-admin.ts +225 -0
- package/src/company-profile-schema.ts +121 -1
- package/src/company-profile.ts +21 -0
- package/src/computer-sessions.ts +10 -1
- package/src/connection-authority.ts +290 -0
- package/src/connection-scopes.ts +20 -0
- package/src/connection-tenancy-backfill.ts +81 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +75 -2
- package/src/editable-artifact-durable-export.ts +27 -0
- package/src/editable-artifacts-schema.ts +10 -5
- package/src/editable-artifacts.ts +21 -11
- package/src/governed-learning-activation-schema.ts +121 -0
- package/src/governed-learning-activation.ts +588 -0
- package/src/governed-learning-evaluator-schema.ts +72 -0
- package/src/governed-learning-evaluator.ts +217 -0
- package/src/index.ts +12001 -1699
- package/src/insights.ts +107 -0
- package/src/integration-bindings.ts +88 -6
- package/src/integration-facets.ts +287 -84
- package/src/interaction-placement-loss.ts +234 -0
- package/src/knowledge-source-sync-schema.ts +83 -0
- package/src/knowledge-source-sync.ts +530 -0
- package/src/managed-human-provisioning.ts +116 -0
- package/src/memory-domain.ts +27 -32
- package/src/migrate.ts +77 -1
- package/src/new-session-drafts.ts +229 -35
- package/src/organization-membership-backfill.ts +735 -0
- package/src/organization-membership-lifecycle.ts +985 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +931 -24
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1315 -52
- package/src/schema.ts +3336 -438
- package/src/scoped-knowledge-schema.ts +16 -8
- package/src/scoped-knowledge.ts +1 -1
- package/src/session-background-commands.ts +759 -0
- package/src/session-control.ts +640 -74
- package/src/session-goal-pacing.ts +126 -0
- package/src/session-queue-commands.ts +450 -98
- package/src/session-realtime-context.ts +19 -3
- package/src/session-realtime-ledger.ts +75 -12
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +403 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +469 -0
- package/src/slack-task-policy-schema.ts +5 -0
- package/src/slack-task-policy.ts +18 -0
- package/src/slack-user-link-access.ts +17 -1
- package/src/task-notes-schema.ts +74 -0
- package/src/task-notes.ts +124 -2
- package/src/turn-initiator.ts +8 -0
- package/src/user-resource-authority.ts +377 -0
- package/src/workspace-authority.ts +160 -0
- package/src/workspace-instruction-policies-schema.ts +53 -1
- package/src/workspace-instruction-policies.ts +528 -77
- package/src/workspace-learning-policy.ts +21 -5
- package/src/workspace-membership-permissions.ts +9 -0
- package/dist/chunk-5KTIEDX7.js.map +0 -1
- package/dist/chunk-FPVAD4CO.js +0 -117
- package/dist/chunk-FPVAD4CO.js.map +0 -1
- package/dist/chunk-HSOWSYOX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-VKLB2ZGI.js +0 -2389
- package/dist/chunk-VKLB2ZGI.js.map +0 -1
- package/dist/chunk-Z7VYMNPZ.js.map +0 -1
- /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
- /package/dist/{chunk-VTPRIXKG.js.map → chunk-NJVZPWXY.js.map} +0 -0
package/src/schema.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
AutomationAcceptedExecution,
|
|
3
|
+
AutomationSessionTemplate,
|
|
2
4
|
AttemptToolCatalog,
|
|
3
5
|
AttemptToolResult,
|
|
4
6
|
DraftTimelineAnnotation,
|
|
5
7
|
FirstPartyMcpToolName,
|
|
6
8
|
McpPersonalConnectionDelegation,
|
|
9
|
+
PersonalResourceAttachmentIntent,
|
|
10
|
+
PersonalResourceAttachmentSummary,
|
|
7
11
|
McpServerConnectionRef,
|
|
12
|
+
ModelContextContributionSummary,
|
|
8
13
|
RigProviderImages,
|
|
9
14
|
SessionMcpApprovalPolicy,
|
|
10
15
|
SessionGoalChangeKind,
|
|
@@ -12,6 +17,7 @@ import type {
|
|
|
12
17
|
SessionGoalSnapshot,
|
|
13
18
|
SlackUserLinkAccessRequest,
|
|
14
19
|
TimelineAnnotation,
|
|
20
|
+
UserResourceDelegation,
|
|
15
21
|
XaiProviderAccountAuthoritySnapshotV1,
|
|
16
22
|
} from "@opengeni/contracts";
|
|
17
23
|
import { WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1 } from "@opengeni/contracts";
|
|
@@ -49,6 +55,12 @@ const vector = customType<{ data: number[]; driverData: string }>({
|
|
|
49
55
|
},
|
|
50
56
|
});
|
|
51
57
|
|
|
58
|
+
const bytea = customType<{ data: Uint8Array; driverData: Uint8Array }>({
|
|
59
|
+
dataType() {
|
|
60
|
+
return "bytea";
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
52
64
|
export type ConnectorActionPolicyDecision = "allow" | "ask" | "block";
|
|
53
65
|
|
|
54
66
|
export type ConnectorActionPolicySnapshotEntry = {
|
|
@@ -436,6 +448,7 @@ export const organizationMemberships = pgTable(
|
|
|
436
448
|
.notNull()
|
|
437
449
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
438
450
|
subjectId: text("subject_id").notNull(),
|
|
451
|
+
role: text("role").notNull().default("member"),
|
|
439
452
|
status: text("status").notNull().default("provisioning"),
|
|
440
453
|
personalWorkspaceId: uuid("personal_workspace_id"),
|
|
441
454
|
authorizationRevision: bigint("authorization_revision", { mode: "number" })
|
|
@@ -460,6 +473,9 @@ export const organizationMemberships = pgTable(
|
|
|
460
473
|
personalWorkspace: uniqueIndex("organization_memberships_personal_workspace_idx")
|
|
461
474
|
.on(table.accountId, table.personalWorkspaceId)
|
|
462
475
|
.where(sql`${table.personalWorkspaceId} is not null`),
|
|
476
|
+
retentionDue: index("organization_memberships_retention_due_idx")
|
|
477
|
+
.on(table.accountId, table.personalRetentionUntil, table.id)
|
|
478
|
+
.where(sql`${table.status} = 'revoked' and ${table.personalRetentionUntil} is not null`),
|
|
463
479
|
personalWorkspaceAccount: foreignKey({
|
|
464
480
|
name: "organization_memberships_personal_workspace_account_fk",
|
|
465
481
|
columns: [table.personalWorkspaceId, table.accountId],
|
|
@@ -469,6 +485,10 @@ export const organizationMemberships = pgTable(
|
|
|
469
485
|
"organization_memberships_status_check",
|
|
470
486
|
sql`${table.status} in ('provisioning', 'active', 'suspended', 'revoked')`,
|
|
471
487
|
),
|
|
488
|
+
roleValid: check(
|
|
489
|
+
"organization_memberships_role_check",
|
|
490
|
+
sql`${table.role} in ('owner', 'admin', 'member')`,
|
|
491
|
+
),
|
|
472
492
|
activePersonalWorkspace: check(
|
|
473
493
|
"organization_memberships_active_personal_workspace_check",
|
|
474
494
|
sql`${table.status} <> 'active' or ${table.personalWorkspaceId} is not null`,
|
|
@@ -489,6 +509,122 @@ export const organizationMemberships = pgTable(
|
|
|
489
509
|
}),
|
|
490
510
|
);
|
|
491
511
|
|
|
512
|
+
export const organizationProfileEvents = pgTable(
|
|
513
|
+
"organization_profile_events",
|
|
514
|
+
{
|
|
515
|
+
id: uuid("id").primaryKey(),
|
|
516
|
+
accountId: uuid("account_id")
|
|
517
|
+
.notNull()
|
|
518
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
519
|
+
actorMembershipId: uuid("actor_membership_id").notNull(),
|
|
520
|
+
previousName: text("previous_name").notNull(),
|
|
521
|
+
requestedName: text("requested_name").notNull(),
|
|
522
|
+
expectedUpdatedAt: timestamp("expected_updated_at", { withTimezone: true }).notNull(),
|
|
523
|
+
resultUpdatedAt: timestamp("result_updated_at", { withTimezone: true }).notNull(),
|
|
524
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
525
|
+
},
|
|
526
|
+
(table) => ({
|
|
527
|
+
actorMembership: foreignKey({
|
|
528
|
+
name: "organization_profile_events_actor_fk",
|
|
529
|
+
columns: [table.actorMembershipId, table.accountId],
|
|
530
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
531
|
+
}).onDelete("restrict"),
|
|
532
|
+
}),
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
// Forward-only organization-scoped activation receipt for the product session-
|
|
536
|
+
// tenancy surface. Runtime may observe this marker, but only the drained
|
|
537
|
+
// migration-owner activation seam may insert it.
|
|
538
|
+
export const sessionTenancyActivations = pgTable(
|
|
539
|
+
"session_tenancy_activations",
|
|
540
|
+
{
|
|
541
|
+
accountId: uuid("account_id")
|
|
542
|
+
.primaryKey()
|
|
543
|
+
.references(() => managedAccounts.id, { onDelete: "restrict" }),
|
|
544
|
+
activationVersion: integer("activation_version").notNull(),
|
|
545
|
+
inventoryDigest: text("inventory_digest").notNull(),
|
|
546
|
+
parityDigest: text("parity_digest").notNull(),
|
|
547
|
+
activatedBy: text("activated_by").notNull(),
|
|
548
|
+
backfillReceiptIds: uuid("backfill_receipt_ids")
|
|
549
|
+
.array()
|
|
550
|
+
.notNull()
|
|
551
|
+
.default(sql`'{}'::uuid[]`),
|
|
552
|
+
activatedAt: timestamp("activated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
553
|
+
},
|
|
554
|
+
(table) => ({
|
|
555
|
+
versionValid: check(
|
|
556
|
+
"session_tenancy_activations_version_check",
|
|
557
|
+
sql`${table.activationVersion} = 1`,
|
|
558
|
+
),
|
|
559
|
+
digestsValid: check(
|
|
560
|
+
"session_tenancy_activations_digests_check",
|
|
561
|
+
sql`${table.inventoryDigest} ~ '^[0-9a-f]{64}$'
|
|
562
|
+
and ${table.parityDigest} ~ '^[0-9a-f]{64}$'`,
|
|
563
|
+
),
|
|
564
|
+
actorValid: check(
|
|
565
|
+
"session_tenancy_activations_actor_check",
|
|
566
|
+
sql`octet_length(${table.activatedBy}) between 1 and 256`,
|
|
567
|
+
),
|
|
568
|
+
backfillReceiptsValid: check(
|
|
569
|
+
"session_tenancy_activation_backfill_receipts_check",
|
|
570
|
+
sql`cardinality(${table.backfillReceiptIds}) in (0, 5, 6)`,
|
|
571
|
+
),
|
|
572
|
+
}),
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
export const organizationPrivateSessionSettings = pgTable(
|
|
576
|
+
"organization_private_session_settings",
|
|
577
|
+
{
|
|
578
|
+
accountId: uuid("account_id")
|
|
579
|
+
.primaryKey()
|
|
580
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
581
|
+
enabled: boolean("enabled").notNull().default(false),
|
|
582
|
+
version: bigint("version", { mode: "number" }).notNull().default(1),
|
|
583
|
+
updatedByMembershipId: uuid("updated_by_membership_id"),
|
|
584
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
585
|
+
},
|
|
586
|
+
(table) => ({
|
|
587
|
+
updater: foreignKey({
|
|
588
|
+
name: "organization_private_session_settings_updater_fk",
|
|
589
|
+
columns: [table.updatedByMembershipId, table.accountId],
|
|
590
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
591
|
+
}).onDelete("restrict"),
|
|
592
|
+
versionValid: check(
|
|
593
|
+
"organization_private_session_settings_version_check",
|
|
594
|
+
sql`${table.version} > 0`,
|
|
595
|
+
),
|
|
596
|
+
}),
|
|
597
|
+
);
|
|
598
|
+
|
|
599
|
+
export const organizationPrivateSessionSettingEvents = pgTable(
|
|
600
|
+
"organization_private_session_setting_events",
|
|
601
|
+
{
|
|
602
|
+
id: uuid("id").primaryKey(),
|
|
603
|
+
accountId: uuid("account_id")
|
|
604
|
+
.notNull()
|
|
605
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
606
|
+
actorMembershipId: uuid("actor_membership_id").notNull(),
|
|
607
|
+
requestedEnabled: boolean("requested_enabled").notNull(),
|
|
608
|
+
expectedVersion: bigint("expected_version", { mode: "number" }).notNull(),
|
|
609
|
+
resultEnabled: boolean("result_enabled").notNull(),
|
|
610
|
+
resultVersion: bigint("result_version", { mode: "number" }).notNull(),
|
|
611
|
+
resultUpdatedAt: timestamp("result_updated_at", { withTimezone: true }).notNull(),
|
|
612
|
+
changed: boolean("changed").notNull(),
|
|
613
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
614
|
+
},
|
|
615
|
+
(table) => ({
|
|
616
|
+
actor: foreignKey({
|
|
617
|
+
name: "organization_private_session_setting_events_actor_fk",
|
|
618
|
+
columns: [table.actorMembershipId, table.accountId],
|
|
619
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
620
|
+
}).onDelete("restrict"),
|
|
621
|
+
versionsValid: check(
|
|
622
|
+
"organization_private_session_setting_events_versions_check",
|
|
623
|
+
sql`${table.expectedVersion} >= 0 and ${table.resultVersion} > 0`,
|
|
624
|
+
),
|
|
625
|
+
}),
|
|
626
|
+
);
|
|
627
|
+
|
|
492
628
|
export const organizationUserRetentionPolicies = pgTable(
|
|
493
629
|
"organization_user_retention_policies",
|
|
494
630
|
{
|
|
@@ -517,7 +653,7 @@ export const organizationUserRetentionPolicies = pgTable(
|
|
|
517
653
|
or (
|
|
518
654
|
${table.mode} = 'delete_after'
|
|
519
655
|
and ${table.retentionDays} is not null
|
|
520
|
-
and ${table.retentionDays} between
|
|
656
|
+
and ${table.retentionDays} between 30 and 90
|
|
521
657
|
)`,
|
|
522
658
|
),
|
|
523
659
|
versionValid: check(
|
|
@@ -527,280 +663,1193 @@ export const organizationUserRetentionPolicies = pgTable(
|
|
|
527
663
|
}),
|
|
528
664
|
);
|
|
529
665
|
|
|
530
|
-
export const
|
|
531
|
-
"
|
|
666
|
+
export const organizationMembershipInvitations = pgTable(
|
|
667
|
+
"organization_membership_invitations",
|
|
532
668
|
{
|
|
533
669
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
534
670
|
accountId: uuid("account_id")
|
|
535
671
|
.notNull()
|
|
536
672
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
673
|
+
targetSubjectId: text("target_subject_id"),
|
|
674
|
+
targetEmail: text("target_email").notNull(),
|
|
675
|
+
targetName: text("target_name"),
|
|
676
|
+
initialWorkspaceIds: uuid("initial_workspace_ids")
|
|
677
|
+
.array()
|
|
678
|
+
.notNull()
|
|
679
|
+
.default(sql`'{}'::uuid[]`),
|
|
680
|
+
role: text("role").notNull().default("member"),
|
|
681
|
+
status: text("status").notNull().default("pending"),
|
|
682
|
+
revision: bigint("revision", { mode: "number" }).notNull().default(1),
|
|
683
|
+
createdByMembershipId: uuid("created_by_membership_id").notNull(),
|
|
684
|
+
acceptedMembershipId: uuid("accepted_membership_id"),
|
|
685
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
|
546
686
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
547
687
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
548
688
|
},
|
|
549
689
|
(table) => ({
|
|
550
|
-
accountIdentity: uniqueIndex("
|
|
690
|
+
accountIdentity: uniqueIndex("organization_membership_invitations_id_account_idx").on(
|
|
551
691
|
table.id,
|
|
552
692
|
table.accountId,
|
|
553
693
|
),
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
694
|
+
pendingTarget: uniqueIndex("organization_membership_invitations_pending_target_uq")
|
|
695
|
+
.on(table.accountId, table.targetSubjectId)
|
|
696
|
+
.where(sql`${table.status} = 'pending' AND ${table.targetSubjectId} IS NOT NULL`),
|
|
697
|
+
pendingEmail: uniqueIndex("organization_membership_invitations_pending_email_uq")
|
|
698
|
+
.on(table.accountId, table.targetEmail)
|
|
699
|
+
.where(sql`${table.status} = 'pending'`),
|
|
700
|
+
accountCreated: index("organization_membership_invitations_account_created_idx").on(
|
|
701
|
+
table.accountId,
|
|
702
|
+
table.createdAt.desc(),
|
|
703
|
+
table.id.desc(),
|
|
704
|
+
),
|
|
705
|
+
subjectCreated: index("organization_membership_invitations_subject_created_idx").on(
|
|
706
|
+
table.targetSubjectId,
|
|
707
|
+
table.createdAt.desc(),
|
|
708
|
+
table.id.desc(),
|
|
709
|
+
),
|
|
710
|
+
creator: foreignKey({
|
|
711
|
+
name: "organization_membership_invitations_creator_fk",
|
|
712
|
+
columns: [table.createdByMembershipId, table.accountId],
|
|
563
713
|
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
564
714
|
}).onDelete("restrict"),
|
|
565
|
-
|
|
566
|
-
"
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
sql`${table.generation} > 0`,
|
|
715
|
+
acceptedMembership: foreignKey({
|
|
716
|
+
name: "organization_membership_invitations_accepted_membership_fk",
|
|
717
|
+
columns: [table.acceptedMembershipId, table.accountId],
|
|
718
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
719
|
+
}).onDelete("restrict"),
|
|
720
|
+
roleValid: check(
|
|
721
|
+
"organization_membership_invitations_role_check",
|
|
722
|
+
sql`${table.role} in ('owner', 'admin', 'member')`,
|
|
574
723
|
),
|
|
575
724
|
statusValid: check(
|
|
576
|
-
"
|
|
577
|
-
sql`${table.status} in ('
|
|
725
|
+
"organization_membership_invitations_status_check",
|
|
726
|
+
sql`${table.status} in ('pending', 'accepted', 'revoked', 'expired')`,
|
|
578
727
|
),
|
|
579
|
-
|
|
580
|
-
"
|
|
581
|
-
sql
|
|
582
|
-
|
|
728
|
+
revisionValid: check(
|
|
729
|
+
"organization_membership_invitations_revision_check",
|
|
730
|
+
sql`${table.revision} > 0`,
|
|
731
|
+
),
|
|
732
|
+
acceptanceValid: check(
|
|
733
|
+
"organization_membership_invitations_acceptance_check",
|
|
734
|
+
sql`(${table.status} = 'accepted' and ${table.acceptedMembershipId} is not null)
|
|
735
|
+
or (${table.status} <> 'accepted' and ${table.acceptedMembershipId} is null)`,
|
|
583
736
|
),
|
|
584
737
|
}),
|
|
585
738
|
);
|
|
586
739
|
|
|
587
|
-
export const
|
|
588
|
-
"
|
|
740
|
+
export const organizationInvitationBindingEvents = pgTable(
|
|
741
|
+
"organization_invitation_binding_events",
|
|
589
742
|
{
|
|
590
743
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
591
744
|
accountId: uuid("account_id")
|
|
592
745
|
.notNull()
|
|
593
746
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}),
|
|
597
|
-
|
|
598
|
-
prefix: text("prefix").notNull(),
|
|
599
|
-
keyHash: text("key_hash").notNull(),
|
|
600
|
-
permissions: jsonb("permissions").$type<string[]>().notNull().default([]),
|
|
601
|
-
expiresAt: timestamp("expires_at", { withTimezone: true }),
|
|
602
|
-
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
603
|
-
lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
|
|
604
|
-
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
605
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
747
|
+
invitationId: uuid("invitation_id").notNull(),
|
|
748
|
+
targetSubjectId: text("target_subject_id").notNull(),
|
|
749
|
+
resultingRevision: bigint("resulting_revision", { mode: "number" }).notNull(),
|
|
750
|
+
boundAt: timestamp("bound_at", { withTimezone: true }).notNull().defaultNow(),
|
|
606
751
|
},
|
|
607
752
|
(table) => ({
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
753
|
+
invitation: foreignKey({
|
|
754
|
+
name: "organization_invitation_binding_events_invitation_fk",
|
|
755
|
+
columns: [table.invitationId, table.accountId],
|
|
756
|
+
foreignColumns: [
|
|
757
|
+
organizationMembershipInvitations.id,
|
|
758
|
+
organizationMembershipInvitations.accountId,
|
|
759
|
+
],
|
|
760
|
+
}).onDelete("restrict"),
|
|
761
|
+
invitationIdentity: uniqueIndex("organization_invitation_binding_events_invitation_uq").on(
|
|
762
|
+
table.accountId,
|
|
763
|
+
table.invitationId,
|
|
764
|
+
),
|
|
765
|
+
subjectValid: check(
|
|
766
|
+
"organization_invitation_binding_events_subject_check",
|
|
767
|
+
sql`${table.targetSubjectId} = btrim(${table.targetSubjectId})
|
|
768
|
+
and ${table.targetSubjectId} like 'user:%'
|
|
769
|
+
and octet_length(convert_to(${table.targetSubjectId}, 'UTF8')) between 6 and 1024`,
|
|
770
|
+
),
|
|
771
|
+
revisionValid: check(
|
|
772
|
+
"organization_invitation_binding_events_revision_check",
|
|
773
|
+
sql`${table.resultingRevision} > 1`,
|
|
774
|
+
),
|
|
612
775
|
}),
|
|
613
776
|
);
|
|
614
777
|
|
|
615
|
-
export const
|
|
616
|
-
"
|
|
778
|
+
export const organizationMembershipOperationReceipts = pgTable(
|
|
779
|
+
"organization_membership_operation_receipts",
|
|
617
780
|
{
|
|
618
|
-
id: uuid("id").primaryKey().defaultRandom(),
|
|
619
781
|
accountId: uuid("account_id")
|
|
620
782
|
.notNull()
|
|
621
783
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
description: text("description"),
|
|
627
|
-
// Migration 0230 is schema-only: all shipped CRUD continues to omit these
|
|
628
|
-
// fields and therefore remains workspace-scoped. A later activation slice
|
|
629
|
-
// must provide the complete owner authority and runtime protocol.
|
|
630
|
-
authorityScope: text("authority_scope").notNull().default("workspace"),
|
|
631
|
-
authorityId: uuid("authority_id"),
|
|
632
|
-
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
633
|
-
originWorkspaceId: uuid("origin_workspace_id"),
|
|
784
|
+
operationId: uuid("operation_id").notNull(),
|
|
785
|
+
action: text("action").notNull(),
|
|
786
|
+
inputHash: text("input_hash").notNull(),
|
|
787
|
+
result: jsonb("result").$type<Record<string, unknown>>().notNull(),
|
|
634
788
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
635
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
636
789
|
},
|
|
637
790
|
(table) => ({
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
workspaceCreated: index("workspace_variable_sets_workspace_created_idx").on(
|
|
643
|
-
table.workspaceId,
|
|
644
|
-
table.createdAt,
|
|
645
|
-
),
|
|
646
|
-
authorityShape: check(
|
|
647
|
-
"workspace_variable_sets_authority_shape_check",
|
|
648
|
-
sql`(
|
|
649
|
-
${table.authorityScope} = 'workspace'
|
|
650
|
-
and ${table.authorityId} is null
|
|
651
|
-
and ${table.ownerOrganizationMembershipId} is null
|
|
652
|
-
) or (
|
|
653
|
-
${table.authorityScope} = 'user'
|
|
654
|
-
and ${table.authorityId} is not null
|
|
655
|
-
and ${table.ownerOrganizationMembershipId} is not null
|
|
656
|
-
)`,
|
|
791
|
+
identity: primaryKey({ columns: [table.accountId, table.operationId] }),
|
|
792
|
+
actionValid: check(
|
|
793
|
+
"organization_membership_operation_receipts_action_check",
|
|
794
|
+
sql`${table.action} in ('invite', 'accept', 'revoke_invitation', 'change_role', 'suspend', 'reactivate', 'offboard', 'retention', 'create_workspace')`,
|
|
657
795
|
),
|
|
658
|
-
|
|
659
|
-
"
|
|
660
|
-
sql`${table.
|
|
796
|
+
inputHashValid: check(
|
|
797
|
+
"organization_membership_operation_receipts_input_hash_check",
|
|
798
|
+
sql`${table.inputHash} ~ '^[0-9a-f]{64}$'`,
|
|
661
799
|
),
|
|
662
|
-
authority: foreignKey({
|
|
663
|
-
name: "workspace_variable_sets_authority_fk",
|
|
664
|
-
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
665
|
-
foreignColumns: [
|
|
666
|
-
organizationUserResourceAuthorities.id,
|
|
667
|
-
organizationUserResourceAuthorities.accountId,
|
|
668
|
-
organizationUserResourceAuthorities.organizationMembershipId,
|
|
669
|
-
],
|
|
670
|
-
}).onDelete("restrict"),
|
|
671
|
-
// PostgreSQL's column-subset SET NULL action preserves account_id; Drizzle
|
|
672
|
-
// cannot represent that action, so migration 0230 owns the origin FK.
|
|
673
800
|
}),
|
|
674
801
|
);
|
|
675
802
|
|
|
676
|
-
export const
|
|
677
|
-
"
|
|
803
|
+
export const organizationMembershipLifecycleEvents = pgTable(
|
|
804
|
+
"organization_membership_lifecycle_events",
|
|
678
805
|
{
|
|
679
806
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
680
807
|
accountId: uuid("account_id")
|
|
681
808
|
.notNull()
|
|
682
809
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
810
|
+
operationId: uuid("operation_id").notNull(),
|
|
811
|
+
actorMembershipId: uuid("actor_membership_id").notNull(),
|
|
812
|
+
targetMembershipId: uuid("target_membership_id"),
|
|
813
|
+
kind: text("kind").notNull(),
|
|
814
|
+
priorAuthorizationRevision: bigint("prior_authorization_revision", {
|
|
815
|
+
mode: "number",
|
|
816
|
+
}),
|
|
817
|
+
resultingAuthorizationRevision: bigint("resulting_authorization_revision", {
|
|
818
|
+
mode: "number",
|
|
819
|
+
}),
|
|
820
|
+
reason: text("reason"),
|
|
693
821
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
694
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
695
822
|
},
|
|
696
823
|
(table) => ({
|
|
697
|
-
|
|
698
|
-
table.
|
|
699
|
-
table.
|
|
700
|
-
table.name,
|
|
824
|
+
operation: uniqueIndex("organization_membership_lifecycle_events_operation_uq").on(
|
|
825
|
+
table.accountId,
|
|
826
|
+
table.operationId,
|
|
701
827
|
),
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
table.
|
|
828
|
+
actor: foreignKey({
|
|
829
|
+
name: "organization_membership_lifecycle_events_actor_fk",
|
|
830
|
+
columns: [table.actorMembershipId, table.accountId],
|
|
831
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
832
|
+
}).onDelete("restrict"),
|
|
833
|
+
target: foreignKey({
|
|
834
|
+
name: "organization_membership_lifecycle_events_target_fk",
|
|
835
|
+
columns: [table.targetMembershipId, table.accountId],
|
|
836
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
837
|
+
}).onDelete("restrict"),
|
|
838
|
+
kindValid: check(
|
|
839
|
+
"organization_membership_lifecycle_events_kind_check",
|
|
840
|
+
sql`${table.kind} in ('invite', 'accept', 'revoke_invitation', 'change_role', 'suspend', 'reactivate', 'offboard', 'retention')`,
|
|
705
841
|
),
|
|
706
842
|
}),
|
|
707
843
|
);
|
|
708
844
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
// access/refresh/id tokens live INSIDE credential_encrypted (v1 AES-256-GCM,
|
|
712
|
-
// same envelope as workspace_variable_set_variables); the other columns are
|
|
713
|
-
// plaintext metadata (header value + UI). RLS-isolated per workspace.
|
|
714
|
-
export const codexSubscriptionCredentials = pgTable(
|
|
715
|
-
"codex_subscription_credentials",
|
|
845
|
+
export const organizationUserRetentionDeletions = pgTable(
|
|
846
|
+
"organization_user_retention_deletions",
|
|
716
847
|
{
|
|
717
|
-
id: uuid("id").primaryKey().defaultRandom(),
|
|
718
848
|
accountId: uuid("account_id")
|
|
719
849
|
.notNull()
|
|
720
850
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
851
|
+
membershipId: uuid("membership_id").notNull(),
|
|
852
|
+
retentionUntil: timestamp("retention_until", { withTimezone: true }).notNull(),
|
|
853
|
+
state: text("state").notNull().default("claimed"),
|
|
854
|
+
claimOperationId: uuid("claim_operation_id").notNull(),
|
|
855
|
+
claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }).notNull(),
|
|
856
|
+
attemptCount: integer("attempt_count").notNull().default(1),
|
|
857
|
+
databaseResult: jsonb("database_result").$type<Record<string, unknown>>(),
|
|
858
|
+
databaseFinalizedAt: timestamp("database_finalized_at", { withTimezone: true }),
|
|
859
|
+
result: jsonb("result").$type<Record<string, unknown>>(),
|
|
860
|
+
completedAt: timestamp("completed_at", { withTimezone: true }),
|
|
861
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
862
|
+
},
|
|
863
|
+
(table) => ({
|
|
864
|
+
identity: primaryKey({ columns: [table.accountId, table.membershipId] }),
|
|
865
|
+
operation: uniqueIndex("organization_user_retention_deletions_operation_uq").on(
|
|
866
|
+
table.claimOperationId,
|
|
867
|
+
),
|
|
868
|
+
claim: index("organization_user_retention_deletions_claim_idx").on(
|
|
869
|
+
table.accountId,
|
|
870
|
+
table.state,
|
|
871
|
+
table.claimExpiresAt,
|
|
872
|
+
),
|
|
873
|
+
membership: foreignKey({
|
|
874
|
+
name: "organization_user_retention_deletions_membership_fk",
|
|
875
|
+
columns: [table.membershipId, table.accountId],
|
|
876
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
877
|
+
}).onDelete("restrict"),
|
|
878
|
+
stateValid: check(
|
|
879
|
+
"organization_user_retention_deletions_state_check",
|
|
880
|
+
sql`${table.state} in ('claimed', 'failed', 'completed')`,
|
|
881
|
+
),
|
|
882
|
+
attemptValid: check(
|
|
883
|
+
"organization_user_retention_deletions_attempt_check",
|
|
884
|
+
sql`${table.attemptCount} > 0`,
|
|
885
|
+
),
|
|
886
|
+
completionValid: check(
|
|
887
|
+
"organization_user_retention_deletions_completion_check",
|
|
888
|
+
sql`(${table.state} = 'completed' and ${table.completedAt} is not null and ${table.result} is not null)
|
|
889
|
+
or (${table.state} <> 'completed' and ${table.completedAt} is null and ${table.result} is null)`,
|
|
890
|
+
),
|
|
891
|
+
databaseFinalizationValid: check(
|
|
892
|
+
"organization_retention_deletions_db_finalized_chk",
|
|
893
|
+
sql`(${table.databaseFinalizedAt} is null and ${table.databaseResult} is null)
|
|
894
|
+
or (${table.databaseFinalizedAt} is not null and ${table.databaseResult} is not null)`,
|
|
895
|
+
),
|
|
896
|
+
}),
|
|
897
|
+
);
|
|
898
|
+
|
|
899
|
+
export const organizationUserRetentionObjectObligations = pgTable(
|
|
900
|
+
"organization_user_retention_object_obligations",
|
|
901
|
+
{
|
|
902
|
+
accountId: uuid("account_id").notNull(),
|
|
903
|
+
membershipId: uuid("membership_id").notNull(),
|
|
904
|
+
objectKind: text("object_kind").notNull(),
|
|
905
|
+
sourceId: text("source_id").notNull(),
|
|
906
|
+
objectBucket: text("object_bucket").notNull(),
|
|
907
|
+
objectKey: text("object_key").notNull(),
|
|
908
|
+
preparedOperationId: uuid("prepared_operation_id").notNull(),
|
|
909
|
+
objectKeyHash: text("object_key_hash").notNull(),
|
|
910
|
+
preparedAt: timestamp("prepared_at", { withTimezone: true }).notNull().defaultNow(),
|
|
911
|
+
},
|
|
912
|
+
(table) => ({
|
|
913
|
+
identity: primaryKey({
|
|
914
|
+
columns: [
|
|
915
|
+
table.accountId,
|
|
916
|
+
table.membershipId,
|
|
917
|
+
table.objectKind,
|
|
918
|
+
table.sourceId,
|
|
919
|
+
table.objectBucket,
|
|
920
|
+
],
|
|
762
921
|
}),
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
922
|
+
deletion: foreignKey({
|
|
923
|
+
name: "organization_retention_object_obligations_deletion_fk",
|
|
924
|
+
columns: [table.accountId, table.membershipId],
|
|
925
|
+
foreignColumns: [
|
|
926
|
+
organizationUserRetentionDeletions.accountId,
|
|
927
|
+
organizationUserRetentionDeletions.membershipId,
|
|
928
|
+
],
|
|
929
|
+
}).onDelete("restrict"),
|
|
930
|
+
hashValid: check(
|
|
931
|
+
"organization_user_retention_object_obligations_hash_check",
|
|
932
|
+
sql`${table.objectKeyHash} ~ '^[0-9a-f]{64}$'`,
|
|
933
|
+
),
|
|
934
|
+
shapeValid: check(
|
|
935
|
+
"organization_user_retention_object_obligations_shape_check",
|
|
936
|
+
sql`${table.objectKind} in (
|
|
937
|
+
'file', 'session_recording', 'browser_state_artifact', 'browser_state_upload',
|
|
938
|
+
'transcription_recording_object', 'video_staging_reference',
|
|
939
|
+
'workspace_artifact_version', 'editable_artifact_blob',
|
|
940
|
+
'workspace_capture_manifest', 'workspace_capture_tree_index',
|
|
941
|
+
'workspace_capture_blob'
|
|
942
|
+
)
|
|
943
|
+
and octet_length(${table.sourceId}) between 1 and 2048
|
|
944
|
+
and octet_length(${table.objectBucket}) between 1 and 1024
|
|
945
|
+
and octet_length(${table.objectKey}) between 1 and 4096`,
|
|
946
|
+
),
|
|
947
|
+
}),
|
|
948
|
+
);
|
|
949
|
+
|
|
950
|
+
export const organizationUserRetentionObjectDeletionReceipts = pgTable(
|
|
951
|
+
"organization_user_retention_object_deletion_receipts",
|
|
952
|
+
{
|
|
953
|
+
accountId: uuid("account_id").notNull(),
|
|
954
|
+
membershipId: uuid("membership_id").notNull(),
|
|
955
|
+
objectKind: text("object_kind").notNull(),
|
|
956
|
+
sourceId: text("source_id").notNull(),
|
|
957
|
+
objectBucket: text("object_bucket").notNull(),
|
|
958
|
+
operationId: uuid("operation_id").notNull(),
|
|
959
|
+
deletedAt: timestamp("deleted_at", { withTimezone: true }).notNull().defaultNow(),
|
|
960
|
+
},
|
|
961
|
+
(table) => ({
|
|
962
|
+
identity: primaryKey({
|
|
963
|
+
columns: [
|
|
964
|
+
table.accountId,
|
|
965
|
+
table.membershipId,
|
|
966
|
+
table.objectKind,
|
|
967
|
+
table.sourceId,
|
|
968
|
+
table.objectBucket,
|
|
969
|
+
],
|
|
769
970
|
}),
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
971
|
+
obligation: foreignKey({
|
|
972
|
+
name: "organization_retention_object_deletions_obligation_fk",
|
|
973
|
+
columns: [
|
|
974
|
+
table.accountId,
|
|
975
|
+
table.membershipId,
|
|
976
|
+
table.objectKind,
|
|
977
|
+
table.sourceId,
|
|
978
|
+
table.objectBucket,
|
|
979
|
+
],
|
|
980
|
+
foreignColumns: [
|
|
981
|
+
organizationUserRetentionObjectObligations.accountId,
|
|
982
|
+
organizationUserRetentionObjectObligations.membershipId,
|
|
983
|
+
organizationUserRetentionObjectObligations.objectKind,
|
|
984
|
+
organizationUserRetentionObjectObligations.sourceId,
|
|
985
|
+
organizationUserRetentionObjectObligations.objectBucket,
|
|
986
|
+
],
|
|
987
|
+
}).onDelete("restrict"),
|
|
988
|
+
}),
|
|
989
|
+
);
|
|
990
|
+
|
|
991
|
+
export const organizationUserRetentionDeletionEvents = pgTable(
|
|
992
|
+
"organization_user_retention_deletion_events",
|
|
993
|
+
{
|
|
994
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
995
|
+
accountId: uuid("account_id").notNull(),
|
|
996
|
+
membershipId: uuid("membership_id").notNull(),
|
|
997
|
+
operationId: uuid("operation_id").notNull(),
|
|
998
|
+
kind: text("kind").notNull(),
|
|
999
|
+
reasonCode: text("reason_code"),
|
|
1000
|
+
result: jsonb("result").$type<Record<string, unknown>>().notNull(),
|
|
1001
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1002
|
+
},
|
|
1003
|
+
(table) => ({
|
|
1004
|
+
operationKind: uniqueIndex("organization_user_retention_deletion_events_operation_kind_uq").on(
|
|
1005
|
+
table.accountId,
|
|
1006
|
+
table.operationId,
|
|
1007
|
+
table.kind,
|
|
1008
|
+
),
|
|
1009
|
+
membershipCreated: index("organization_retention_events_member_created_idx").on(
|
|
1010
|
+
table.accountId,
|
|
1011
|
+
table.membershipId,
|
|
1012
|
+
table.createdAt,
|
|
1013
|
+
table.id,
|
|
1014
|
+
),
|
|
1015
|
+
membership: foreignKey({
|
|
1016
|
+
name: "organization_user_retention_deletion_events_membership_fk",
|
|
1017
|
+
columns: [table.membershipId, table.accountId],
|
|
1018
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
1019
|
+
}).onDelete("restrict"),
|
|
1020
|
+
kindValid: check(
|
|
1021
|
+
"organization_user_retention_deletion_events_kind_check",
|
|
1022
|
+
sql`${table.kind} in ('claimed', 'failed', 'completed')`,
|
|
1023
|
+
),
|
|
1024
|
+
reasonValid: check(
|
|
1025
|
+
"organization_user_retention_deletion_events_reason_check",
|
|
1026
|
+
sql`${table.reasonCode} is null or ${table.reasonCode} ~ '^[a-z0-9_]{1,64}$'`,
|
|
1027
|
+
),
|
|
1028
|
+
}),
|
|
1029
|
+
);
|
|
1030
|
+
|
|
1031
|
+
export const organizationUserResourceAuthorities = pgTable(
|
|
1032
|
+
"organization_user_resource_authorities",
|
|
1033
|
+
{
|
|
1034
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1035
|
+
accountId: uuid("account_id")
|
|
1036
|
+
.notNull()
|
|
1037
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1038
|
+
organizationMembershipId: uuid("organization_membership_id").notNull(),
|
|
1039
|
+
resourceKind: text("resource_kind").notNull(),
|
|
1040
|
+
resourceId: uuid("resource_id").notNull(),
|
|
1041
|
+
// Provenance only. The migration owns a composite same-organization FK
|
|
1042
|
+
// whose delete action clears only this column, never account_id.
|
|
1043
|
+
originWorkspaceId: uuid("origin_workspace_id"),
|
|
1044
|
+
generation: bigint("generation", { mode: "number" }).notNull().default(1),
|
|
1045
|
+
status: text("status").notNull().default("active"),
|
|
1046
|
+
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
775
1047
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
776
1048
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
777
1049
|
},
|
|
778
1050
|
(table) => ({
|
|
779
|
-
|
|
780
|
-
// One row per (workspace, ChatGPT account). Partial WHERE chatgpt_account_id IS NOT NULL
|
|
781
|
-
// so degenerate null-account rows can't collide; the device-grant connect path always
|
|
782
|
-
// populates chatgpt_account_id.
|
|
783
|
-
wsAccount: uniqueIndex("codex_subscription_credentials_ws_account_idx")
|
|
784
|
-
.on(table.workspaceId, table.chatgptAccountId)
|
|
785
|
-
.where(sql`${table.chatgptAccountId} is not null`),
|
|
786
|
-
workspace: index("codex_subscription_credentials_workspace_lookup_idx").on(table.workspaceId),
|
|
787
|
-
// Composite identity is the defense-in-depth FK target for workspace-local
|
|
788
|
-
// lease references in migration 0053.
|
|
789
|
-
workspaceIdentity: uniqueIndex("codex_subscription_credentials_workspace_id_idx").on(
|
|
790
|
-
table.workspaceId,
|
|
1051
|
+
accountIdentity: uniqueIndex("organization_user_resource_authorities_id_account_idx").on(
|
|
791
1052
|
table.id,
|
|
1053
|
+
table.accountId,
|
|
1054
|
+
),
|
|
1055
|
+
accountMembershipIdentity: uniqueIndex(
|
|
1056
|
+
"organization_user_resource_authorities_id_account_membership_idx",
|
|
1057
|
+
).on(table.id, table.accountId, table.organizationMembershipId),
|
|
1058
|
+
resourceIdentity: uniqueIndex(
|
|
1059
|
+
"organization_user_resource_authorities_resource_identity_idx",
|
|
1060
|
+
).on(table.accountId, table.organizationMembershipId, table.resourceKind, table.resourceId),
|
|
1061
|
+
membership: foreignKey({
|
|
1062
|
+
name: "organization_user_resource_authorities_membership_fk",
|
|
1063
|
+
columns: [table.organizationMembershipId, table.accountId],
|
|
1064
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
1065
|
+
}).onDelete("restrict"),
|
|
1066
|
+
resourceKindValid: check(
|
|
1067
|
+
"organization_user_resource_authorities_kind_check",
|
|
1068
|
+
sql`${table.resourceKind} = lower(btrim(${table.resourceKind}))
|
|
1069
|
+
and length(${table.resourceKind}) between 1 and 64
|
|
1070
|
+
and ${table.resourceKind} ~ '^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$'`,
|
|
1071
|
+
),
|
|
1072
|
+
generationValid: check(
|
|
1073
|
+
"organization_user_resource_authorities_generation_check",
|
|
1074
|
+
sql`${table.generation} > 0`,
|
|
1075
|
+
),
|
|
1076
|
+
statusValid: check(
|
|
1077
|
+
"organization_user_resource_authorities_status_check",
|
|
1078
|
+
sql`${table.status} in ('active', 'retained', 'revoked')`,
|
|
1079
|
+
),
|
|
1080
|
+
revocationValid: check(
|
|
1081
|
+
"organization_user_resource_authorities_revocation_check",
|
|
1082
|
+
sql`(${table.status} = 'revoked' and ${table.revokedAt} is not null)
|
|
1083
|
+
or (${table.status} <> 'revoked' and ${table.revokedAt} is null)`,
|
|
1084
|
+
),
|
|
1085
|
+
}),
|
|
1086
|
+
);
|
|
1087
|
+
|
|
1088
|
+
export const apiKeys = pgTable(
|
|
1089
|
+
"api_keys",
|
|
1090
|
+
{
|
|
1091
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1092
|
+
accountId: uuid("account_id")
|
|
1093
|
+
.notNull()
|
|
1094
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1095
|
+
workspaceId: uuid("workspace_id").references(() => workspaces.id, {
|
|
1096
|
+
onDelete: "cascade",
|
|
1097
|
+
}),
|
|
1098
|
+
name: text("name").notNull(),
|
|
1099
|
+
description: text("description"),
|
|
1100
|
+
prefix: text("prefix").notNull(),
|
|
1101
|
+
keyHash: text("key_hash").notNull(),
|
|
1102
|
+
permissions: jsonb("permissions").$type<string[]>().notNull().default([]),
|
|
1103
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }),
|
|
1104
|
+
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
1105
|
+
lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
|
|
1106
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1107
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1108
|
+
},
|
|
1109
|
+
(table) => ({
|
|
1110
|
+
prefix: index("api_keys_prefix_idx").on(table.prefix),
|
|
1111
|
+
hash: uniqueIndex("api_keys_key_hash_idx").on(table.keyHash),
|
|
1112
|
+
account: index("api_keys_account_idx").on(table.accountId),
|
|
1113
|
+
workspace: index("api_keys_workspace_idx").on(table.workspaceId),
|
|
1114
|
+
descriptionValid: check(
|
|
1115
|
+
"api_keys_description_check",
|
|
1116
|
+
sql`${table.description} is null or length(${table.description}) between 1 and 500`,
|
|
1117
|
+
),
|
|
1118
|
+
}),
|
|
1119
|
+
);
|
|
1120
|
+
|
|
1121
|
+
export const workspaceVariableSets = pgTable(
|
|
1122
|
+
"workspace_variable_sets",
|
|
1123
|
+
{
|
|
1124
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1125
|
+
accountId: uuid("account_id")
|
|
1126
|
+
.notNull()
|
|
1127
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1128
|
+
workspaceId: uuid("workspace_id")
|
|
1129
|
+
.notNull()
|
|
1130
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1131
|
+
name: text("name").notNull(),
|
|
1132
|
+
description: text("description"),
|
|
1133
|
+
// Omitted creation remains workspace-owned. User ownership is anchored to
|
|
1134
|
+
// the common organization-user resource authority; organization ownership
|
|
1135
|
+
// has no member owner and is administered through account authority.
|
|
1136
|
+
authorityScope: text("authority_scope").notNull().default("workspace"),
|
|
1137
|
+
authorityId: uuid("authority_id"),
|
|
1138
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
1139
|
+
originWorkspaceId: uuid("origin_workspace_id"),
|
|
1140
|
+
generation: bigint("generation", { mode: "number" }).notNull().default(1),
|
|
1141
|
+
status: text("status").notNull().default("active"),
|
|
1142
|
+
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
1143
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1144
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1145
|
+
},
|
|
1146
|
+
(table) => ({
|
|
1147
|
+
workspaceName: uniqueIndex("workspace_variable_sets_workspace_name_active_idx")
|
|
1148
|
+
.on(table.workspaceId, table.name)
|
|
1149
|
+
.where(sql`${table.authorityScope} = 'workspace' and ${table.status} = 'active'`),
|
|
1150
|
+
workspaceCreated: index("workspace_variable_sets_workspace_created_idx").on(
|
|
1151
|
+
table.workspaceId,
|
|
1152
|
+
table.createdAt,
|
|
1153
|
+
),
|
|
1154
|
+
authorityShape: check(
|
|
1155
|
+
"workspace_variable_sets_authority_shape_check",
|
|
1156
|
+
sql`(
|
|
1157
|
+
${table.authorityScope} in ('organization', 'workspace')
|
|
1158
|
+
and ${table.authorityId} is null
|
|
1159
|
+
and ${table.ownerOrganizationMembershipId} is null
|
|
1160
|
+
) or (
|
|
1161
|
+
${table.authorityScope} = 'user'
|
|
1162
|
+
and ${table.authorityId} is not null
|
|
1163
|
+
and ${table.ownerOrganizationMembershipId} is not null
|
|
1164
|
+
)`,
|
|
1165
|
+
),
|
|
1166
|
+
authorityScopeValid: check(
|
|
1167
|
+
"workspace_variable_sets_authority_scope_check",
|
|
1168
|
+
sql`${table.authorityScope} in ('organization', 'workspace', 'user')`,
|
|
1169
|
+
),
|
|
1170
|
+
generationValid: check(
|
|
1171
|
+
"workspace_variable_sets_generation_check",
|
|
1172
|
+
sql`${table.generation} > 0`,
|
|
1173
|
+
),
|
|
1174
|
+
statusValid: check(
|
|
1175
|
+
"workspace_variable_sets_status_check",
|
|
1176
|
+
sql`${table.status} in ('active', 'revoked')`,
|
|
1177
|
+
),
|
|
1178
|
+
revocationValid: check(
|
|
1179
|
+
"workspace_variable_sets_revocation_check",
|
|
1180
|
+
sql`(${table.status} = 'revoked' and ${table.revokedAt} is not null)
|
|
1181
|
+
or (${table.status} = 'active' and ${table.revokedAt} is null)`,
|
|
1182
|
+
),
|
|
1183
|
+
authority: foreignKey({
|
|
1184
|
+
name: "workspace_variable_sets_authority_fk",
|
|
1185
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
1186
|
+
foreignColumns: [
|
|
1187
|
+
organizationUserResourceAuthorities.id,
|
|
1188
|
+
organizationUserResourceAuthorities.accountId,
|
|
1189
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
1190
|
+
],
|
|
1191
|
+
}).onDelete("restrict"),
|
|
1192
|
+
// PostgreSQL's column-subset SET NULL action preserves account_id; Drizzle
|
|
1193
|
+
// cannot represent that action, so migration 0230 owns the origin FK.
|
|
1194
|
+
}),
|
|
1195
|
+
);
|
|
1196
|
+
|
|
1197
|
+
export const workspaceVariableSetVariables = pgTable(
|
|
1198
|
+
"workspace_variable_set_variables",
|
|
1199
|
+
{
|
|
1200
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1201
|
+
accountId: uuid("account_id")
|
|
1202
|
+
.notNull()
|
|
1203
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1204
|
+
workspaceId: uuid("workspace_id")
|
|
1205
|
+
.notNull()
|
|
1206
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1207
|
+
variableSetId: uuid("variable_set_id")
|
|
1208
|
+
.notNull()
|
|
1209
|
+
.references(() => workspaceVariableSets.id, { onDelete: "cascade" }),
|
|
1210
|
+
name: text("name").notNull(),
|
|
1211
|
+
// Format: v1:<base64 iv>:<base64 ciphertext||gcm-tag>. Never returned by any API.
|
|
1212
|
+
valueEncrypted: text("value_encrypted").notNull(),
|
|
1213
|
+
version: integer("version").notNull().default(1),
|
|
1214
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1215
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1216
|
+
},
|
|
1217
|
+
(table) => ({
|
|
1218
|
+
variableSetName: uniqueIndex("workspace_variable_set_variables_env_name_idx").on(
|
|
1219
|
+
table.workspaceId,
|
|
1220
|
+
table.variableSetId,
|
|
1221
|
+
table.name,
|
|
1222
|
+
),
|
|
1223
|
+
variableSet: index("workspace_variable_set_variables_workspace_env_idx").on(
|
|
1224
|
+
table.workspaceId,
|
|
1225
|
+
table.variableSetId,
|
|
1226
|
+
),
|
|
1227
|
+
}),
|
|
1228
|
+
);
|
|
1229
|
+
|
|
1230
|
+
// Per-workspace ChatGPT/Codex subscription credential. One row per connected
|
|
1231
|
+
// ChatGPT account within a workspace.
|
|
1232
|
+
// access/refresh/id tokens live INSIDE credential_encrypted (v1 AES-256-GCM,
|
|
1233
|
+
// same envelope as workspace_variable_set_variables); the other columns are
|
|
1234
|
+
// plaintext metadata (header value + UI). RLS-isolated per workspace.
|
|
1235
|
+
export const codexSubscriptionCredentials = pgTable(
|
|
1236
|
+
"codex_subscription_credentials",
|
|
1237
|
+
{
|
|
1238
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1239
|
+
accountId: uuid("account_id")
|
|
1240
|
+
.notNull()
|
|
1241
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1242
|
+
workspaceId: uuid("workspace_id")
|
|
1243
|
+
.notNull()
|
|
1244
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1245
|
+
// Format: v1:<base64 iv>:<base64 ciphertext||gcm-tag>. JSON {access_token, refresh_token, id_token}. Never returned by any API.
|
|
1246
|
+
credentialEncrypted: text("credential_encrypted").notNull(),
|
|
1247
|
+
chatgptAccountId: text("chatgpt_account_id"), // plaintext ChatGPT-Account-ID header value (non-secret)
|
|
1248
|
+
scopes: text("scopes"), // space-delimited, as granted
|
|
1249
|
+
planType: text("plan_type"),
|
|
1250
|
+
isFedramp: boolean("is_fedramp").notNull().default(false),
|
|
1251
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }), // derived from access-token JWT exp
|
|
1252
|
+
lastRefreshAt: timestamp("last_refresh_at", { withTimezone: true }),
|
|
1253
|
+
status: text("status").notNull().default("active"), // active | needs_relogin | error
|
|
1254
|
+
lastError: text("last_error"),
|
|
1255
|
+
version: integer("version").notNull().default(1),
|
|
1256
|
+
label: text("label"), // user-chosen nickname; null ⇒ derive from email/plan/account
|
|
1257
|
+
accountEmail: text("account_email"), // email from the id_token (user's own email; non-secret)
|
|
1258
|
+
// P2 usage cache (plaintext metadata; NEVER a token). Snapshotted from
|
|
1259
|
+
// GET /wham/usage; drives the quota bars + the cache TTL. primary = 5h window
|
|
1260
|
+
// (limit_window_seconds 18000), secondary = weekly (604800).
|
|
1261
|
+
primaryUsedPercent: integer("primary_used_percent"),
|
|
1262
|
+
primaryResetAt: timestamp("primary_reset_at", { withTimezone: true }),
|
|
1263
|
+
secondaryUsedPercent: integer("secondary_used_percent"),
|
|
1264
|
+
secondaryResetAt: timestamp("secondary_reset_at", { withTimezone: true }),
|
|
1265
|
+
usageCheckedAt: timestamp("usage_checked_at", { withTimezone: true }), // snapshot freshness → cache TTL clock
|
|
1266
|
+
// P3 rotation cooldown (plaintext metadata; NEVER a token). Set when this account hit its
|
|
1267
|
+
// usage cap on a rotation turn; the rotation engine treats `exhausted_until > now()` as
|
|
1268
|
+
// capped/skip so it isn't immediately re-picked. Self-clears via the now() comparison.
|
|
1269
|
+
exhaustedUntil: timestamp("exhausted_until", { withTimezone: true }),
|
|
1270
|
+
// Workspace-local, server-held fairness cursor. Provider usage headers are
|
|
1271
|
+
// capacity hints, never the sole allocator: live lease count is ranked first
|
|
1272
|
+
// and this cursor deterministically breaks equal-load/equal-capacity ties.
|
|
1273
|
+
// This flag controls NEW automatic allocations only. Credential health,
|
|
1274
|
+
// refresh, encrypted material, and an already-leased in-flight turn are
|
|
1275
|
+
// intentionally independent. account eligibility policy owns toggle OCC/audit and product UI.
|
|
1276
|
+
allocatorEnabled: boolean("allocator_enabled").notNull().default(true),
|
|
1277
|
+
// Independent OCC/audit sequence for the allocator toggle. Token refresh
|
|
1278
|
+
// continues to own `version`; quota/cache writes own neither counter.
|
|
1279
|
+
allocatorVersion: integer("allocator_version").notNull().default(1),
|
|
1280
|
+
allocatorUpdatedBySubjectId: text("allocator_updated_by_subject_id"),
|
|
1281
|
+
allocatorUpdatedAt: timestamp("allocator_updated_at", {
|
|
1282
|
+
withTimezone: true,
|
|
1283
|
+
}),
|
|
1284
|
+
// Authoritative count-only summary cached from /wham/usage. Detailed rows
|
|
1285
|
+
// are never persisted as redemption authority; every first POST preflights
|
|
1286
|
+
// the provider's fresh detail endpoint.
|
|
1287
|
+
resetCreditAvailableCount: integer("reset_credit_available_count"),
|
|
1288
|
+
resetCreditsCheckedAt: timestamp("reset_credits_checked_at", {
|
|
1289
|
+
withTimezone: true,
|
|
1290
|
+
}),
|
|
1291
|
+
// Set only by a direct Better Auth cookie connection/reconnection. Legacy,
|
|
1292
|
+
// configured, delegated, API-key, and agent-created rows remain view-only.
|
|
1293
|
+
connectedBySubjectId: text("connected_by_subject_id"),
|
|
1294
|
+
selectionCount: integer("selection_count").notNull().default(0),
|
|
1295
|
+
lastSelectedAt: timestamp("last_selected_at", { withTimezone: true }),
|
|
1296
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1297
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1298
|
+
},
|
|
1299
|
+
(table) => ({
|
|
1300
|
+
// REPLACES codex_subscription_credentials_workspace_idx (the one-per-workspace cap).
|
|
1301
|
+
// One row per (workspace, ChatGPT account). Partial WHERE chatgpt_account_id IS NOT NULL
|
|
1302
|
+
// so degenerate null-account rows can't collide; the device-grant connect path always
|
|
1303
|
+
// populates chatgpt_account_id.
|
|
1304
|
+
wsAccount: uniqueIndex("codex_subscription_credentials_ws_account_idx")
|
|
1305
|
+
.on(table.workspaceId, table.chatgptAccountId)
|
|
1306
|
+
.where(sql`${table.chatgptAccountId} is not null`),
|
|
1307
|
+
workspace: index("codex_subscription_credentials_workspace_lookup_idx").on(table.workspaceId),
|
|
1308
|
+
// Composite identity is the defense-in-depth FK target for workspace-local
|
|
1309
|
+
// lease references in migration 0053.
|
|
1310
|
+
workspaceIdentity: uniqueIndex("codex_subscription_credentials_workspace_id_idx").on(
|
|
1311
|
+
table.workspaceId,
|
|
1312
|
+
table.id,
|
|
1313
|
+
),
|
|
1314
|
+
workspaceAccountIdentity: uniqueIndex(
|
|
1315
|
+
"codex_subscription_credentials_workspace_account_id_idx",
|
|
1316
|
+
).on(table.workspaceId, table.accountId, table.id),
|
|
1317
|
+
}),
|
|
1318
|
+
);
|
|
1319
|
+
|
|
1320
|
+
// Optional workspace-level credential used only for ChatGPT connected Apps.
|
|
1321
|
+
// Inference selection, usage, cooldown, allocator, pins, and leases never read
|
|
1322
|
+
// this row. A durable null row retains the OCC sequence after designation clear.
|
|
1323
|
+
export const codexAppsSettings = pgTable(
|
|
1324
|
+
"codex_apps_settings",
|
|
1325
|
+
{
|
|
1326
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1327
|
+
accountId: uuid("account_id")
|
|
1328
|
+
.notNull()
|
|
1329
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1330
|
+
workspaceId: uuid("workspace_id")
|
|
1331
|
+
.notNull()
|
|
1332
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1333
|
+
credentialId: uuid("credential_id"),
|
|
1334
|
+
version: integer("version").notNull().default(1),
|
|
1335
|
+
designatedAt: timestamp("designated_at", { withTimezone: true }),
|
|
1336
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1337
|
+
},
|
|
1338
|
+
(table) => ({
|
|
1339
|
+
workspaceAccount: foreignKey({
|
|
1340
|
+
name: "codex_apps_settings_workspace_account_fk",
|
|
1341
|
+
columns: [table.workspaceId, table.accountId],
|
|
1342
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
1343
|
+
}).onDelete("cascade"),
|
|
1344
|
+
credentialScope: foreignKey({
|
|
1345
|
+
name: "codex_apps_settings_credential_scope_fk",
|
|
1346
|
+
columns: [table.workspaceId, table.accountId, table.credentialId],
|
|
1347
|
+
foreignColumns: [
|
|
1348
|
+
codexSubscriptionCredentials.workspaceId,
|
|
1349
|
+
codexSubscriptionCredentials.accountId,
|
|
1350
|
+
codexSubscriptionCredentials.id,
|
|
1351
|
+
],
|
|
1352
|
+
}).onDelete("cascade"),
|
|
1353
|
+
workspace: uniqueIndex("codex_apps_settings_workspace_idx").on(table.workspaceId),
|
|
1354
|
+
designationShape: check(
|
|
1355
|
+
"codex_apps_settings_designation_shape_chk",
|
|
1356
|
+
sql`${table.version} > 0 and (
|
|
1357
|
+
(${table.credentialId} is null and ${table.designatedAt} is null)
|
|
1358
|
+
or
|
|
1359
|
+
(${table.credentialId} is not null and ${table.designatedAt} is not null)
|
|
1360
|
+
)`,
|
|
1361
|
+
),
|
|
1362
|
+
}),
|
|
1363
|
+
);
|
|
1364
|
+
|
|
1365
|
+
// One durable logical human redemption. `processing` means the fresh provider
|
|
1366
|
+
// detail preflight is still owed; `provider_started` means the POST may have
|
|
1367
|
+
// reached upstream and every retry must reuse upstreamIdempotencyKey without
|
|
1368
|
+
// requiring the credit to remain visible as available.
|
|
1369
|
+
export const codexResetRedemptionAttempts = pgTable(
|
|
1370
|
+
"codex_reset_redemption_attempts",
|
|
1371
|
+
{
|
|
1372
|
+
id: uuid("id").primaryKey(),
|
|
1373
|
+
accountId: uuid("account_id")
|
|
1374
|
+
.notNull()
|
|
1375
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1376
|
+
workspaceId: uuid("workspace_id")
|
|
1377
|
+
.notNull()
|
|
1378
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1379
|
+
credentialId: uuid("credential_id").notNull(),
|
|
1380
|
+
subjectId: text("subject_id").notNull(),
|
|
1381
|
+
browserSessionHash: text("browser_session_hash").notNull(),
|
|
1382
|
+
creditId: text("credit_id").notNull(),
|
|
1383
|
+
upstreamIdempotencyKey: uuid("upstream_idempotency_key").notNull().defaultRandom(),
|
|
1384
|
+
status: text("status").notNull().default("processing"),
|
|
1385
|
+
outcome: text("outcome"),
|
|
1386
|
+
claimHolderId: uuid("claim_holder_id"),
|
|
1387
|
+
claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
|
|
1388
|
+
confirmationExpiresAt: timestamp("confirmation_expires_at", {
|
|
1389
|
+
withTimezone: true,
|
|
1390
|
+
}).notNull(),
|
|
1391
|
+
providerStartedAt: timestamp("provider_started_at", { withTimezone: true }),
|
|
1392
|
+
completedAt: timestamp("completed_at", { withTimezone: true }),
|
|
1393
|
+
lastFailureKind: text("last_failure_kind"),
|
|
1394
|
+
retryCount: integer("retry_count").notNull().default(0),
|
|
1395
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1396
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1397
|
+
},
|
|
1398
|
+
(table) => ({
|
|
1399
|
+
workspaceAccount: foreignKey({
|
|
1400
|
+
name: "codex_reset_redemption_workspace_account_fk",
|
|
1401
|
+
columns: [table.workspaceId, table.accountId],
|
|
1402
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
1403
|
+
}).onDelete("cascade"),
|
|
1404
|
+
upstreamKey: uniqueIndex("codex_reset_redemption_upstream_key_idx").on(
|
|
1405
|
+
table.upstreamIdempotencyKey,
|
|
1406
|
+
),
|
|
1407
|
+
credentialCredit: uniqueIndex("codex_reset_redemption_credential_credit_idx")
|
|
1408
|
+
.on(table.workspaceId, table.credentialId, table.creditId)
|
|
1409
|
+
.where(
|
|
1410
|
+
sql`${table.status} <> 'completed' or ${table.outcome} in ('reset', 'alreadyRedeemed')`,
|
|
1411
|
+
),
|
|
1412
|
+
workspaceCredential: index("codex_reset_redemption_workspace_credential_idx").on(
|
|
1413
|
+
table.workspaceId,
|
|
1414
|
+
table.credentialId,
|
|
1415
|
+
table.createdAt,
|
|
1416
|
+
),
|
|
1417
|
+
claimExpiry: index("codex_reset_redemption_claim_expiry_idx")
|
|
1418
|
+
.on(table.claimExpiresAt)
|
|
1419
|
+
.where(sql`${table.status} <> 'completed'`),
|
|
1420
|
+
statusValid: check(
|
|
1421
|
+
"codex_reset_redemption_status_check",
|
|
1422
|
+
sql`${table.status} in ('processing', 'provider_started', 'completed')`,
|
|
1423
|
+
),
|
|
1424
|
+
outcomeValid: check(
|
|
1425
|
+
"codex_reset_redemption_outcome_check",
|
|
1426
|
+
sql`${table.outcome} is null or ${table.outcome} in ('reset', 'nothingToReset', 'noCredit', 'alreadyRedeemed')`,
|
|
1427
|
+
),
|
|
1428
|
+
completionConsistent: check(
|
|
1429
|
+
"codex_reset_redemption_completed_check",
|
|
1430
|
+
sql`(${table.status} = 'completed') = (${table.outcome} is not null and ${table.completedAt} is not null)`,
|
|
1431
|
+
),
|
|
1432
|
+
retryCountValid: check(
|
|
1433
|
+
"codex_reset_redemption_retry_count_check",
|
|
1434
|
+
sql`${table.retryCount} >= 0`,
|
|
1435
|
+
),
|
|
1436
|
+
humanSubjectValid: check(
|
|
1437
|
+
"codex_reset_redemption_human_subject_check",
|
|
1438
|
+
sql`${table.subjectId} like 'user:_%'`,
|
|
1439
|
+
),
|
|
1440
|
+
}),
|
|
1441
|
+
);
|
|
1442
|
+
|
|
1443
|
+
// Generic external-service credential spine. credential_encrypted is the ONLY
|
|
1444
|
+
// secret-bearing column; normal API reads use metadata-only helpers below the DB
|
|
1445
|
+
// layer. Runtime token material is decrypted only by the broker accessor.
|
|
1446
|
+
export const connections = pgTable(
|
|
1447
|
+
"connections",
|
|
1448
|
+
{
|
|
1449
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1450
|
+
accountId: uuid("account_id")
|
|
1451
|
+
.notNull()
|
|
1452
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1453
|
+
workspaceId: uuid("workspace_id")
|
|
1454
|
+
.notNull()
|
|
1455
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1456
|
+
subjectId: text("subject_id"),
|
|
1457
|
+
providerDomain: text("provider_domain").notNull(),
|
|
1458
|
+
kind: text("kind").notNull(),
|
|
1459
|
+
status: text("status").notNull().default("active"),
|
|
1460
|
+
credentialEncrypted: text("credential_encrypted").notNull(),
|
|
1461
|
+
grantedScopes: jsonb("granted_scopes").$type<string[]>().notNull().default([]),
|
|
1462
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }),
|
|
1463
|
+
lastRefreshAt: timestamp("last_refresh_at", { withTimezone: true }),
|
|
1464
|
+
lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
|
|
1465
|
+
lastError: text("last_error"),
|
|
1466
|
+
version: integer("version").notNull().default(1),
|
|
1467
|
+
// Server-owned proof that the dedicated install route verified the exact
|
|
1468
|
+
// credential at this connection version. Generic/legacy writers cannot set
|
|
1469
|
+
// these columns, and migration 0131 clears them when protected fields change
|
|
1470
|
+
// without a fresh verification in the same statement.
|
|
1471
|
+
verifiedInstallAt: timestamp("verified_install_at", { withTimezone: true }),
|
|
1472
|
+
verifiedInstallVersion: integer("verified_install_version"),
|
|
1473
|
+
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
|
|
1474
|
+
createdBySubjectId: text("created_by_subject_id"),
|
|
1475
|
+
updatedBySubjectId: text("updated_by_subject_id"),
|
|
1476
|
+
// Explicit execution authority. Workspace rows have no member authority;
|
|
1477
|
+
// user rows bind one immutable organization membership and common resource
|
|
1478
|
+
// authority. `legacy_user` preserves pre-tenancy personal rows without
|
|
1479
|
+
// inventing an owner membership; it is ineligible for delegated use until
|
|
1480
|
+
// the migration cutover binds it. Public metadata projects only the opaque
|
|
1481
|
+
// authority id to the exact subject owner; membership, scope, origin, and
|
|
1482
|
+
// generation remain internal.
|
|
1483
|
+
authorityScope: text("authority_scope").notNull().default("workspace"),
|
|
1484
|
+
authorityId: uuid("authority_id"),
|
|
1485
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
1486
|
+
originWorkspaceId: uuid("origin_workspace_id"),
|
|
1487
|
+
// Separate from credential version: refresh may rotate token material
|
|
1488
|
+
// without invalidating already accepted work, while reconnect/disconnect
|
|
1489
|
+
// and identity/status transitions advance this generation.
|
|
1490
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }).notNull().default(1),
|
|
1491
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1492
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1493
|
+
},
|
|
1494
|
+
(table) => ({
|
|
1495
|
+
workspaceProviderStatus: index("connections_workspace_provider_status_idx").on(
|
|
1496
|
+
table.workspaceId,
|
|
1497
|
+
table.providerDomain,
|
|
1498
|
+
table.status,
|
|
1499
|
+
),
|
|
1500
|
+
workspaceSubjectProvider: index("connections_workspace_subject_provider_idx").on(
|
|
1501
|
+
table.workspaceId,
|
|
1502
|
+
table.subjectId,
|
|
1503
|
+
table.providerDomain,
|
|
1504
|
+
),
|
|
1505
|
+
workspaceKind: index("connections_workspace_kind_idx").on(table.workspaceId, table.kind),
|
|
1506
|
+
workspaceExpires: index("connections_workspace_expires_idx").on(
|
|
1507
|
+
table.workspaceId,
|
|
1508
|
+
table.expiresAt,
|
|
1509
|
+
),
|
|
1510
|
+
authorityIdentity: uniqueIndex("connections_authority_identity_uq")
|
|
1511
|
+
.on(table.accountId, table.authorityId)
|
|
1512
|
+
.where(sql`${table.authorityId} is not null`),
|
|
1513
|
+
ownerAuthority: index("connections_owner_authority_idx")
|
|
1514
|
+
.on(
|
|
1515
|
+
table.accountId,
|
|
1516
|
+
table.ownerOrganizationMembershipId,
|
|
1517
|
+
table.status,
|
|
1518
|
+
table.updatedAt,
|
|
1519
|
+
table.id,
|
|
1520
|
+
)
|
|
1521
|
+
.where(sql`${table.authorityScope} = 'user'`),
|
|
1522
|
+
authorityScopeValid: check(
|
|
1523
|
+
"connections_authority_scope_check",
|
|
1524
|
+
sql`${table.authorityScope} in ('workspace', 'user', 'legacy_user')`,
|
|
1525
|
+
),
|
|
1526
|
+
authorityShapeValid: check(
|
|
1527
|
+
"connections_authority_shape_check",
|
|
1528
|
+
sql`(
|
|
1529
|
+
${table.authorityScope} = 'workspace'
|
|
1530
|
+
and ${table.subjectId} is null
|
|
1531
|
+
and ${table.authorityId} is null
|
|
1532
|
+
and ${table.ownerOrganizationMembershipId} is null
|
|
1533
|
+
and ${table.originWorkspaceId} = ${table.workspaceId}
|
|
1534
|
+
) or (
|
|
1535
|
+
${table.authorityScope} = 'user'
|
|
1536
|
+
and ${table.subjectId} is not null
|
|
1537
|
+
and ${table.authorityId} is not null
|
|
1538
|
+
and ${table.ownerOrganizationMembershipId} is not null
|
|
1539
|
+
and ${table.originWorkspaceId} is not null
|
|
1540
|
+
) or (
|
|
1541
|
+
${table.authorityScope} = 'legacy_user'
|
|
1542
|
+
and ${table.subjectId} is not null
|
|
1543
|
+
and ${table.authorityId} is null
|
|
1544
|
+
and ${table.ownerOrganizationMembershipId} is null
|
|
1545
|
+
and ${table.originWorkspaceId} is not null
|
|
1546
|
+
)`,
|
|
1547
|
+
),
|
|
1548
|
+
authorityGenerationValid: check(
|
|
1549
|
+
"connections_authority_generation_check",
|
|
1550
|
+
sql`${table.authorityGeneration} > 0`,
|
|
1551
|
+
),
|
|
1552
|
+
authority: foreignKey({
|
|
1553
|
+
name: "connections_authority_fk",
|
|
1554
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
1555
|
+
foreignColumns: [
|
|
1556
|
+
organizationUserResourceAuthorities.id,
|
|
1557
|
+
organizationUserResourceAuthorities.accountId,
|
|
1558
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
1559
|
+
],
|
|
1560
|
+
}).onDelete("restrict"),
|
|
1561
|
+
// Migration 0255 owns the same-organization origin FK because Drizzle
|
|
1562
|
+
// cannot express PostgreSQL's column-subset SET NULL action.
|
|
1563
|
+
}),
|
|
1564
|
+
);
|
|
1565
|
+
|
|
1566
|
+
/**
|
|
1567
|
+
* Monotonic authority head for one personal GitHub connection's selected
|
|
1568
|
+
* repository set. The head is separate from the selected rows so replacing
|
|
1569
|
+
* the set with an empty array still advances durable authority.
|
|
1570
|
+
*/
|
|
1571
|
+
export const personalGitHubRepositorySelectionHeads = pgTable(
|
|
1572
|
+
"personal_github_repository_selection_heads",
|
|
1573
|
+
{
|
|
1574
|
+
connectionId: uuid("connection_id")
|
|
1575
|
+
.primaryKey()
|
|
1576
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
1577
|
+
accountId: uuid("account_id")
|
|
1578
|
+
.notNull()
|
|
1579
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1580
|
+
originWorkspaceId: uuid("origin_workspace_id")
|
|
1581
|
+
.notNull()
|
|
1582
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1583
|
+
ownerSubjectId: text("owner_subject_id").notNull(),
|
|
1584
|
+
providerPrincipalId: text("provider_principal_id").notNull(),
|
|
1585
|
+
credentialBindingId: uuid("credential_binding_id").notNull(),
|
|
1586
|
+
connectionAuthorityGeneration: bigint("connection_authority_generation", {
|
|
1587
|
+
mode: "number",
|
|
1588
|
+
}).notNull(),
|
|
1589
|
+
generation: bigint("generation", { mode: "number" }).notNull().default(1),
|
|
1590
|
+
updatedBySubjectId: text("updated_by_subject_id").notNull(),
|
|
1591
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1592
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1593
|
+
},
|
|
1594
|
+
(table) => ({
|
|
1595
|
+
tenantConnection: uniqueIndex("personal_github_repository_selection_heads_tenant_uq").on(
|
|
1596
|
+
table.accountId,
|
|
1597
|
+
table.originWorkspaceId,
|
|
1598
|
+
table.ownerSubjectId,
|
|
1599
|
+
table.connectionId,
|
|
1600
|
+
),
|
|
1601
|
+
owner: index("personal_github_repository_selection_heads_owner_idx").on(
|
|
1602
|
+
table.accountId,
|
|
1603
|
+
table.ownerSubjectId,
|
|
1604
|
+
table.connectionId,
|
|
1605
|
+
),
|
|
1606
|
+
generationValid: check(
|
|
1607
|
+
"personal_github_repository_selection_heads_generation_chk",
|
|
1608
|
+
sql`${table.connectionAuthorityGeneration} > 0 and ${table.generation} > 0`,
|
|
1609
|
+
),
|
|
1610
|
+
}),
|
|
1611
|
+
);
|
|
1612
|
+
|
|
1613
|
+
/** Only explicitly selected repositories are persisted; discovery stays live. */
|
|
1614
|
+
export const personalGitHubRepositorySelections = pgTable(
|
|
1615
|
+
"personal_github_repository_selections",
|
|
1616
|
+
{
|
|
1617
|
+
connectionId: uuid("connection_id").notNull(),
|
|
1618
|
+
repositoryId: bigint("repository_id", { mode: "bigint" }).notNull(),
|
|
1619
|
+
accountId: uuid("account_id")
|
|
1620
|
+
.notNull()
|
|
1621
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1622
|
+
originWorkspaceId: uuid("origin_workspace_id")
|
|
1623
|
+
.notNull()
|
|
1624
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1625
|
+
ownerSubjectId: text("owner_subject_id").notNull(),
|
|
1626
|
+
canonicalFullName: text("canonical_full_name").notNull(),
|
|
1627
|
+
canonicalHttpsUri: text("canonical_https_uri").notNull(),
|
|
1628
|
+
defaultBranch: text("default_branch").notNull(),
|
|
1629
|
+
visibility: text("visibility").notNull(),
|
|
1630
|
+
private: boolean("private").notNull(),
|
|
1631
|
+
archived: boolean("archived").notNull(),
|
|
1632
|
+
disabled: boolean("disabled").notNull(),
|
|
1633
|
+
permissions: jsonb("permissions").$type<Record<string, boolean>>().notNull(),
|
|
1634
|
+
selectedAccess: text("selected_access").notNull(),
|
|
1635
|
+
selectionGeneration: bigint("selection_generation", {
|
|
1636
|
+
mode: "number",
|
|
1637
|
+
}).notNull(),
|
|
1638
|
+
selectedBySubjectId: text("selected_by_subject_id").notNull(),
|
|
1639
|
+
selectedAt: timestamp("selected_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1640
|
+
verifiedAt: timestamp("verified_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1641
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1642
|
+
},
|
|
1643
|
+
(table) => ({
|
|
1644
|
+
identity: primaryKey({ columns: [table.connectionId, table.repositoryId] }),
|
|
1645
|
+
head: foreignKey({
|
|
1646
|
+
name: "personal_github_repository_selections_head_fk",
|
|
1647
|
+
columns: [table.accountId, table.originWorkspaceId, table.ownerSubjectId, table.connectionId],
|
|
1648
|
+
foreignColumns: [
|
|
1649
|
+
personalGitHubRepositorySelectionHeads.accountId,
|
|
1650
|
+
personalGitHubRepositorySelectionHeads.originWorkspaceId,
|
|
1651
|
+
personalGitHubRepositorySelectionHeads.ownerSubjectId,
|
|
1652
|
+
personalGitHubRepositorySelectionHeads.connectionId,
|
|
1653
|
+
],
|
|
1654
|
+
}).onDelete("cascade"),
|
|
1655
|
+
tenant: index("personal_github_repository_selections_tenant_idx").on(
|
|
1656
|
+
table.accountId,
|
|
1657
|
+
table.originWorkspaceId,
|
|
1658
|
+
table.connectionId,
|
|
1659
|
+
),
|
|
1660
|
+
shapeValid: check(
|
|
1661
|
+
"personal_github_repository_selections_shape_chk",
|
|
1662
|
+
sql`${table.repositoryId} > 0
|
|
1663
|
+
and ${table.selectionGeneration} > 0
|
|
1664
|
+
and ${table.selectedAccess} in ('read', 'write')
|
|
1665
|
+
and ${table.visibility} in ('public', 'private', 'internal')
|
|
1666
|
+
and ${table.private} = (${table.visibility} = 'private')
|
|
1667
|
+
and jsonb_typeof(${table.permissions}) = 'object'
|
|
1668
|
+
and ${table.permissions} ?& array['pull','push','admin','maintain','triage']
|
|
1669
|
+
and ${table.permissions} - array['pull','push','admin','maintain','triage']::text[] = '{}'::jsonb
|
|
1670
|
+
and jsonb_typeof(${table.permissions}->'pull') = 'boolean'
|
|
1671
|
+
and jsonb_typeof(${table.permissions}->'push') = 'boolean'
|
|
1672
|
+
and jsonb_typeof(${table.permissions}->'admin') = 'boolean'
|
|
1673
|
+
and jsonb_typeof(${table.permissions}->'maintain') = 'boolean'
|
|
1674
|
+
and jsonb_typeof(${table.permissions}->'triage') = 'boolean'
|
|
1675
|
+
and (${table.permissions}->'pull' = 'true'::jsonb
|
|
1676
|
+
or ${table.permissions}->'push' = 'true'::jsonb
|
|
1677
|
+
or ${table.permissions}->'admin' = 'true'::jsonb
|
|
1678
|
+
or ${table.permissions}->'maintain' = 'true'::jsonb
|
|
1679
|
+
or ${table.permissions}->'triage' = 'true'::jsonb)
|
|
1680
|
+
and (${table.selectedAccess} <> 'write' or (
|
|
1681
|
+
not ${table.archived} and not ${table.disabled}
|
|
1682
|
+
and (${table.permissions}->'push' = 'true'::jsonb
|
|
1683
|
+
or ${table.permissions}->'admin' = 'true'::jsonb
|
|
1684
|
+
or ${table.permissions}->'maintain' = 'true'::jsonb)
|
|
1685
|
+
))
|
|
1686
|
+
and octet_length(${table.ownerSubjectId}) between 1 and 512
|
|
1687
|
+
and ${table.canonicalFullName} ~ '^[A-Za-z0-9][A-Za-z0-9-]{0,38}/[A-Za-z0-9_.-]{1,100}$'
|
|
1688
|
+
and octet_length(${table.canonicalFullName}) between 3 and 140
|
|
1689
|
+
and octet_length(${table.defaultBranch}) between 1 and 255`,
|
|
1690
|
+
),
|
|
1691
|
+
}),
|
|
1692
|
+
);
|
|
1693
|
+
|
|
1694
|
+
/** Bounded idempotency receipt for an owner-issued full selection replacement. */
|
|
1695
|
+
export const personalGitHubRepositorySelectionOperations = pgTable(
|
|
1696
|
+
"personal_github_repository_selection_operations",
|
|
1697
|
+
{
|
|
1698
|
+
connectionId: uuid("connection_id").notNull(),
|
|
1699
|
+
idempotencyKey: text("idempotency_key").notNull(),
|
|
1700
|
+
accountId: uuid("account_id").notNull(),
|
|
1701
|
+
originWorkspaceId: uuid("origin_workspace_id").notNull(),
|
|
1702
|
+
ownerSubjectId: text("owner_subject_id").notNull(),
|
|
1703
|
+
requestDigest: bytea("request_digest").notNull(),
|
|
1704
|
+
resultingGeneration: bigint("resulting_generation", {
|
|
1705
|
+
mode: "number",
|
|
1706
|
+
}).notNull(),
|
|
1707
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1708
|
+
},
|
|
1709
|
+
(table) => ({
|
|
1710
|
+
identity: primaryKey({
|
|
1711
|
+
columns: [table.connectionId, table.idempotencyKey],
|
|
1712
|
+
}),
|
|
1713
|
+
head: foreignKey({
|
|
1714
|
+
name: "personal_github_repository_selection_operations_head_fk",
|
|
1715
|
+
columns: [table.accountId, table.originWorkspaceId, table.ownerSubjectId, table.connectionId],
|
|
1716
|
+
foreignColumns: [
|
|
1717
|
+
personalGitHubRepositorySelectionHeads.accountId,
|
|
1718
|
+
personalGitHubRepositorySelectionHeads.originWorkspaceId,
|
|
1719
|
+
personalGitHubRepositorySelectionHeads.ownerSubjectId,
|
|
1720
|
+
personalGitHubRepositorySelectionHeads.connectionId,
|
|
1721
|
+
],
|
|
1722
|
+
}).onDelete("cascade"),
|
|
1723
|
+
shapeValid: check(
|
|
1724
|
+
"personal_github_repository_selection_operations_shape_chk",
|
|
1725
|
+
sql`${table.resultingGeneration} > 0
|
|
1726
|
+
and octet_length(${table.idempotencyKey}) between 1 and 200
|
|
1727
|
+
and octet_length(${table.ownerSubjectId}) between 1 and 512
|
|
1728
|
+
and octet_length(${table.requestDigest}) = 32`,
|
|
1729
|
+
),
|
|
1730
|
+
}),
|
|
1731
|
+
);
|
|
1732
|
+
|
|
1733
|
+
export const connectionUseOnceConsumptionReceipts = pgTable(
|
|
1734
|
+
"connection_use_once_consumption_receipts",
|
|
1735
|
+
{
|
|
1736
|
+
grantId: uuid("grant_id").primaryKey(),
|
|
1737
|
+
accountId: uuid("account_id")
|
|
1738
|
+
.notNull()
|
|
1739
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1740
|
+
authorityId: uuid("authority_id").notNull(),
|
|
1741
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }).notNull(),
|
|
1742
|
+
grantGeneration: bigint("grant_generation", { mode: "number" }).notNull(),
|
|
1743
|
+
acceptedWorkKind: text("accepted_work_kind").notNull(),
|
|
1744
|
+
acceptedWorkId: uuid("accepted_work_id").notNull(),
|
|
1745
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1746
|
+
},
|
|
1747
|
+
(table) => ({
|
|
1748
|
+
authority: foreignKey({
|
|
1749
|
+
name: "connection_once_receipts_authority_fk",
|
|
1750
|
+
columns: [table.authorityId, table.accountId],
|
|
1751
|
+
foreignColumns: [
|
|
1752
|
+
organizationUserResourceAuthorities.id,
|
|
1753
|
+
organizationUserResourceAuthorities.accountId,
|
|
1754
|
+
],
|
|
1755
|
+
}).onDelete("cascade"),
|
|
1756
|
+
grant: foreignKey({
|
|
1757
|
+
name: "connection_once_receipts_grant_fk",
|
|
1758
|
+
columns: [table.grantId, table.accountId],
|
|
1759
|
+
foreignColumns: [organizationUserResourceGrants.id, organizationUserResourceGrants.accountId],
|
|
1760
|
+
}).onDelete("cascade"),
|
|
1761
|
+
generationValid: check(
|
|
1762
|
+
"connection_once_receipts_generation_check",
|
|
1763
|
+
sql`${table.authorityGeneration} > 0 and ${table.grantGeneration} > 0`,
|
|
1764
|
+
),
|
|
1765
|
+
acceptedWorkKindValid: check(
|
|
1766
|
+
"connection_once_receipts_work_kind_check",
|
|
1767
|
+
sql`${table.acceptedWorkKind} in ('turn', 'scheduled_task')`,
|
|
1768
|
+
),
|
|
1769
|
+
}),
|
|
1770
|
+
);
|
|
1771
|
+
|
|
1772
|
+
// One durable routing authority per installed Slack team. The active partial
|
|
1773
|
+
// unique index is the database fence that prevents a team from being routed to
|
|
1774
|
+
// two OpenGeni workspaces. Legacy ambiguous rows are retained as quarantined
|
|
1775
|
+
// evidence instead of deleting credentials or guessing a winner.
|
|
1776
|
+
export const slackInstallationBindings = pgTable(
|
|
1777
|
+
"slack_installation_bindings",
|
|
1778
|
+
{
|
|
1779
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1780
|
+
accountId: uuid("account_id")
|
|
1781
|
+
.notNull()
|
|
1782
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1783
|
+
workspaceId: uuid("workspace_id")
|
|
1784
|
+
.notNull()
|
|
1785
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1786
|
+
connectionId: uuid("connection_id")
|
|
1787
|
+
.notNull()
|
|
1788
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
1789
|
+
slackTeamId: text("slack_team_id").notNull(),
|
|
1790
|
+
slackTeamName: text("slack_team_name").notNull(),
|
|
1791
|
+
botId: text("bot_id").notNull(),
|
|
1792
|
+
botUserId: text("bot_user_id").notNull(),
|
|
1793
|
+
botDisplayName: text("bot_display_name").notNull(),
|
|
1794
|
+
state: text("state").$type<"active" | "quarantined">().notNull(),
|
|
1795
|
+
quarantineReason: text("quarantine_reason"),
|
|
1796
|
+
version: integer("version").notNull().default(1),
|
|
1797
|
+
createdBySubjectId: text("created_by_subject_id"),
|
|
1798
|
+
updatedBySubjectId: text("updated_by_subject_id"),
|
|
1799
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1800
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1801
|
+
},
|
|
1802
|
+
(table) => ({
|
|
1803
|
+
connection: uniqueIndex("slack_installation_bindings_connection_uq").on(table.connectionId),
|
|
1804
|
+
activeTeam: uniqueIndex("slack_installation_bindings_active_team_uq")
|
|
1805
|
+
.on(table.slackTeamId)
|
|
1806
|
+
.where(sql`${table.state} = 'active'`),
|
|
1807
|
+
workspaceState: index("slack_installation_bindings_workspace_state_idx").on(
|
|
1808
|
+
table.workspaceId,
|
|
1809
|
+
table.state,
|
|
1810
|
+
table.updatedAt,
|
|
1811
|
+
),
|
|
1812
|
+
workspaceAccount: foreignKey({
|
|
1813
|
+
name: "slack_installation_bindings_workspace_account_fk",
|
|
1814
|
+
columns: [table.workspaceId, table.accountId],
|
|
1815
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
1816
|
+
}).onDelete("cascade"),
|
|
1817
|
+
stateValid: check(
|
|
1818
|
+
"slack_installation_bindings_state_check",
|
|
1819
|
+
sql`${table.state} in ('active', 'quarantined')`,
|
|
1820
|
+
),
|
|
1821
|
+
quarantineConsistent: check(
|
|
1822
|
+
"slack_installation_bindings_quarantine_check",
|
|
1823
|
+
sql`(${table.state} = 'active' and ${table.quarantineReason} is null)
|
|
1824
|
+
or (${table.state} = 'quarantined' and length(btrim(${table.quarantineReason})) > 0)`,
|
|
1825
|
+
),
|
|
1826
|
+
identityBounded: check(
|
|
1827
|
+
"slack_installation_bindings_identity_check",
|
|
1828
|
+
sql`octet_length(${table.slackTeamId}) between 1 and 64
|
|
1829
|
+
and octet_length(${table.slackTeamName}) between 1 and 256
|
|
1830
|
+
and octet_length(${table.botId}) between 1 and 64
|
|
1831
|
+
and octet_length(${table.botUserId}) between 1 and 64
|
|
1832
|
+
and ${table.botDisplayName} in ('OpenGeni', 'OpenGeni Staging')`,
|
|
792
1833
|
),
|
|
793
|
-
|
|
794
|
-
"codex_subscription_credentials_workspace_account_id_idx",
|
|
795
|
-
).on(table.workspaceId, table.accountId, table.id),
|
|
1834
|
+
versionPositive: check("slack_installation_bindings_version_check", sql`${table.version} > 0`),
|
|
796
1835
|
}),
|
|
797
1836
|
);
|
|
798
1837
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
1838
|
+
/**
|
|
1839
|
+
* Per-channel Slack workspace routing within one organization.
|
|
1840
|
+
*
|
|
1841
|
+
* HOME tenancy (`accountId`/`workspaceId`) is the installation binding's own
|
|
1842
|
+
* workspace: it owns the bot credential every provider call is fenced on. The
|
|
1843
|
+
* TARGET (`targetAccountId`/`targetWorkspaceId`) is where the session, its
|
|
1844
|
+
* grant, and its events live. `slack_channel_routes_same_account_check` keeps
|
|
1845
|
+
* both sides in one organization; cross-organization routing is out of scope.
|
|
1846
|
+
*
|
|
1847
|
+
* The row is the durable ask-once memory: once a human picks in the Slack
|
|
1848
|
+
* picker, or an admin sets it in the web sheet, later messages in that channel
|
|
1849
|
+
* never ask again.
|
|
1850
|
+
*/
|
|
1851
|
+
export const slackChannelRoutes = pgTable(
|
|
1852
|
+
"slack_channel_routes",
|
|
804
1853
|
{
|
|
805
1854
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
806
1855
|
accountId: uuid("account_id")
|
|
@@ -809,121 +1858,145 @@ export const codexAppsSettings = pgTable(
|
|
|
809
1858
|
workspaceId: uuid("workspace_id")
|
|
810
1859
|
.notNull()
|
|
811
1860
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
812
|
-
|
|
1861
|
+
connectionId: uuid("connection_id")
|
|
1862
|
+
.notNull()
|
|
1863
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
1864
|
+
slackTeamId: text("slack_team_id").notNull(),
|
|
1865
|
+
slackChannelId: text("slack_channel_id").notNull(),
|
|
1866
|
+
targetAccountId: uuid("target_account_id")
|
|
1867
|
+
.notNull()
|
|
1868
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1869
|
+
targetWorkspaceId: uuid("target_workspace_id")
|
|
1870
|
+
.notNull()
|
|
1871
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1872
|
+
decidedBySubjectId: text("decided_by_subject_id").notNull(),
|
|
1873
|
+
decidedBySlackUserId: text("decided_by_slack_user_id").notNull(),
|
|
1874
|
+
source: text("source").$type<"picker" | "admin">().notNull(),
|
|
813
1875
|
version: integer("version").notNull().default(1),
|
|
814
|
-
|
|
1876
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
815
1877
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
816
1878
|
},
|
|
817
1879
|
(table) => ({
|
|
1880
|
+
channel: unique("slack_channel_routes_channel_uq").on(table.connectionId, table.slackChannelId),
|
|
818
1881
|
workspaceAccount: foreignKey({
|
|
819
|
-
name: "
|
|
1882
|
+
name: "slack_channel_routes_workspace_account_fk",
|
|
820
1883
|
columns: [table.workspaceId, table.accountId],
|
|
821
1884
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
822
1885
|
}).onDelete("cascade"),
|
|
823
|
-
|
|
824
|
-
name: "
|
|
825
|
-
columns: [table.
|
|
826
|
-
foreignColumns: [
|
|
827
|
-
codexSubscriptionCredentials.workspaceId,
|
|
828
|
-
codexSubscriptionCredentials.accountId,
|
|
829
|
-
codexSubscriptionCredentials.id,
|
|
830
|
-
],
|
|
1886
|
+
targetWorkspaceAccount: foreignKey({
|
|
1887
|
+
name: "slack_channel_routes_target_workspace_account_fk",
|
|
1888
|
+
columns: [table.targetWorkspaceId, table.targetAccountId],
|
|
1889
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
831
1890
|
}).onDelete("cascade"),
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
"
|
|
835
|
-
sql`${table.
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
)
|
|
1891
|
+
target: index("slack_channel_routes_target_idx").on(table.targetWorkspaceId, table.slackTeamId),
|
|
1892
|
+
sameAccount: check(
|
|
1893
|
+
"slack_channel_routes_same_account_check",
|
|
1894
|
+
sql`${table.targetAccountId} = ${table.accountId}`,
|
|
1895
|
+
),
|
|
1896
|
+
bounded: check(
|
|
1897
|
+
"slack_channel_routes_bounds_check",
|
|
1898
|
+
sql`octet_length(${table.slackTeamId}) between 1 and 64
|
|
1899
|
+
and octet_length(${table.slackChannelId}) between 1 and 64
|
|
1900
|
+
and octet_length(${table.decidedBySubjectId}) between 1 and 1024
|
|
1901
|
+
and octet_length(${table.decidedBySlackUserId}) between 1 and 64
|
|
1902
|
+
and ${table.source} in ('picker', 'admin')
|
|
1903
|
+
and ${table.version} > 0`,
|
|
840
1904
|
),
|
|
841
1905
|
}),
|
|
842
1906
|
);
|
|
843
1907
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1908
|
+
/**
|
|
1909
|
+
* Per-Slack-human direct-message workspace routing, same HOME/TARGET split as
|
|
1910
|
+
* {@link slackChannelRoutes}. Absent a row, a DM derives that human's own
|
|
1911
|
+
* personal workspace from their active organization membership pointer; the
|
|
1912
|
+
* workspace id is never accepted from a Slack payload or from this table.
|
|
1913
|
+
*/
|
|
1914
|
+
export const slackUserDmRoutes = pgTable(
|
|
1915
|
+
"slack_user_dm_routes",
|
|
850
1916
|
{
|
|
851
|
-
id: uuid("id").primaryKey(),
|
|
1917
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
852
1918
|
accountId: uuid("account_id")
|
|
853
1919
|
.notNull()
|
|
854
1920
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
855
1921
|
workspaceId: uuid("workspace_id")
|
|
856
1922
|
.notNull()
|
|
857
1923
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
retryCount: integer("retry_count").notNull().default(0),
|
|
1924
|
+
connectionId: uuid("connection_id")
|
|
1925
|
+
.notNull()
|
|
1926
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
1927
|
+
slackTeamId: text("slack_team_id").notNull(),
|
|
1928
|
+
slackUserId: text("slack_user_id").notNull(),
|
|
1929
|
+
targetAccountId: uuid("target_account_id")
|
|
1930
|
+
.notNull()
|
|
1931
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
1932
|
+
targetWorkspaceId: uuid("target_workspace_id")
|
|
1933
|
+
.notNull()
|
|
1934
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
1935
|
+
decidedBySubjectId: text("decided_by_subject_id").notNull(),
|
|
1936
|
+
decidedBySlackUserId: text("decided_by_slack_user_id").notNull(),
|
|
1937
|
+
source: text("source").$type<"picker" | "admin">().notNull(),
|
|
1938
|
+
version: integer("version").notNull().default(1),
|
|
874
1939
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
875
1940
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
876
1941
|
},
|
|
877
1942
|
(table) => ({
|
|
1943
|
+
user: unique("slack_user_dm_routes_user_uq").on(table.connectionId, table.slackUserId),
|
|
878
1944
|
workspaceAccount: foreignKey({
|
|
879
|
-
name: "
|
|
1945
|
+
name: "slack_user_dm_routes_workspace_account_fk",
|
|
880
1946
|
columns: [table.workspaceId, table.accountId],
|
|
881
1947
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
882
1948
|
}).onDelete("cascade"),
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
table.workspaceId,
|
|
893
|
-
table.credentialId,
|
|
894
|
-
table.createdAt,
|
|
895
|
-
),
|
|
896
|
-
claimExpiry: index("codex_reset_redemption_claim_expiry_idx")
|
|
897
|
-
.on(table.claimExpiresAt)
|
|
898
|
-
.where(sql`${table.status} <> 'completed'`),
|
|
899
|
-
statusValid: check(
|
|
900
|
-
"codex_reset_redemption_status_check",
|
|
901
|
-
sql`${table.status} in ('processing', 'provider_started', 'completed')`,
|
|
902
|
-
),
|
|
903
|
-
outcomeValid: check(
|
|
904
|
-
"codex_reset_redemption_outcome_check",
|
|
905
|
-
sql`${table.outcome} is null or ${table.outcome} in ('reset', 'nothingToReset', 'noCredit', 'alreadyRedeemed')`,
|
|
906
|
-
),
|
|
907
|
-
completionConsistent: check(
|
|
908
|
-
"codex_reset_redemption_completed_check",
|
|
909
|
-
sql`(${table.status} = 'completed') = (${table.outcome} is not null and ${table.completedAt} is not null)`,
|
|
910
|
-
),
|
|
911
|
-
retryCountValid: check(
|
|
912
|
-
"codex_reset_redemption_retry_count_check",
|
|
913
|
-
sql`${table.retryCount} >= 0`,
|
|
1949
|
+
targetWorkspaceAccount: foreignKey({
|
|
1950
|
+
name: "slack_user_dm_routes_target_workspace_account_fk",
|
|
1951
|
+
columns: [table.targetWorkspaceId, table.targetAccountId],
|
|
1952
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
1953
|
+
}).onDelete("cascade"),
|
|
1954
|
+
target: index("slack_user_dm_routes_target_idx").on(table.targetWorkspaceId, table.slackTeamId),
|
|
1955
|
+
sameAccount: check(
|
|
1956
|
+
"slack_user_dm_routes_same_account_check",
|
|
1957
|
+
sql`${table.targetAccountId} = ${table.accountId}`,
|
|
914
1958
|
),
|
|
915
|
-
|
|
916
|
-
"
|
|
917
|
-
sql
|
|
1959
|
+
bounded: check(
|
|
1960
|
+
"slack_user_dm_routes_bounds_check",
|
|
1961
|
+
sql`octet_length(${table.slackTeamId}) between 1 and 64
|
|
1962
|
+
and octet_length(${table.slackUserId}) between 1 and 64
|
|
1963
|
+
and octet_length(${table.decidedBySubjectId}) between 1 and 1024
|
|
1964
|
+
and octet_length(${table.decidedBySlackUserId}) between 1 and 64
|
|
1965
|
+
and ${table.source} in ('picker', 'admin')
|
|
1966
|
+
and ${table.version} > 0`,
|
|
918
1967
|
),
|
|
919
1968
|
}),
|
|
920
1969
|
);
|
|
921
1970
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1971
|
+
/**
|
|
1972
|
+
* The pending first-use Slack workspace picker.
|
|
1973
|
+
*
|
|
1974
|
+
* `slack_interaction_action_handles` cannot carry it: that table's `sessionId`
|
|
1975
|
+
* is NOT NULL and composite-FK'd to an existing `slack_interactions` row, while
|
|
1976
|
+
* a picker exists BEFORE any session.
|
|
1977
|
+
*
|
|
1978
|
+
* `inboxId` deliberately carries no foreign key. The `awaiting_choice` inbox row
|
|
1979
|
+
* is settled `processed` before the human answers - the answer arrives as its
|
|
1980
|
+
* own `block_action` inbox row - so this column is provenance, not a live edge.
|
|
1981
|
+
*
|
|
1982
|
+
* `requestText` mirrors the inbox's exact 12000 byte bound so a prompt can
|
|
1983
|
+
* always carry the originating row's text losslessly.
|
|
1984
|
+
*
|
|
1985
|
+
* `providerEventId` is the ORIGINAL event, and it is PROVENANCE, not the id the
|
|
1986
|
+
* answer re-materializes under. Migration 0335's comment claims the answer can
|
|
1987
|
+
* re-insert the original event id under the inbox's own
|
|
1988
|
+
* `(connection_id, provider_event_id)` dedupe unique; that is wrong, and the
|
|
1989
|
+
* migration's bytes are frozen so the claim is corrected here instead. The
|
|
1990
|
+
* original inbox row still exists and is settled `processed`, so re-inserting
|
|
1991
|
+
* its id conflicts and does nothing, and the chosen workspace would never start
|
|
1992
|
+
* any work at all. The answer must enqueue a DERIVED id -
|
|
1993
|
+
* `<originalProviderEventId>:route:<promptId>` - which is unique per prompt and
|
|
1994
|
+
* still idempotent, so a double-click cannot create two sessions. The
|
|
1995
|
+
* `(connection_id, provider_event_id)` unique on this table is what makes
|
|
1996
|
+
* Slack's retries of the same event unable to post a second picker.
|
|
1997
|
+
*/
|
|
1998
|
+
export const slackRoutePrompts = pgTable(
|
|
1999
|
+
"slack_route_prompts",
|
|
927
2000
|
{
|
|
928
2001
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
929
2002
|
accountId: uuid("account_id")
|
|
@@ -932,54 +2005,107 @@ export const connections = pgTable(
|
|
|
932
2005
|
workspaceId: uuid("workspace_id")
|
|
933
2006
|
.notNull()
|
|
934
2007
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
2008
|
+
connectionId: uuid("connection_id")
|
|
2009
|
+
.notNull()
|
|
2010
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
2011
|
+
inboxId: uuid("inbox_id").notNull(),
|
|
2012
|
+
slackTeamId: text("slack_team_id").notNull(),
|
|
2013
|
+
slackUserId: text("slack_user_id").notNull(),
|
|
2014
|
+
slackChannelId: text("slack_channel_id").notNull(),
|
|
2015
|
+
slackMessageTs: text("slack_message_ts").notNull(),
|
|
2016
|
+
providerEventId: text("provider_event_id").notNull(),
|
|
2017
|
+
triggerKind: text("trigger_kind")
|
|
2018
|
+
.$type<
|
|
2019
|
+
| "app_mention"
|
|
2020
|
+
| "dm"
|
|
2021
|
+
| "reaction"
|
|
2022
|
+
| "slash_command"
|
|
2023
|
+
| "message_shortcut"
|
|
2024
|
+
| "thread_reply"
|
|
2025
|
+
| "block_action"
|
|
2026
|
+
>()
|
|
2027
|
+
.notNull(),
|
|
2028
|
+
requestText: text("request_text").notNull(),
|
|
2029
|
+
hasFiles: boolean("has_files").notNull().default(false),
|
|
2030
|
+
slackThreadTs: text("slack_thread_ts"),
|
|
2031
|
+
messageOperationId: uuid("message_operation_id").notNull(),
|
|
2032
|
+
status: text("status")
|
|
2033
|
+
.$type<"pending" | "answered" | "expired" | "cancelled">()
|
|
2034
|
+
.notNull()
|
|
2035
|
+
.default("pending"),
|
|
2036
|
+
answeredTargetAccountId: uuid("answered_target_account_id"),
|
|
2037
|
+
answeredTargetWorkspaceId: uuid("answered_target_workspace_id"),
|
|
2038
|
+
answeredBySubjectId: text("answered_by_subject_id"),
|
|
2039
|
+
answeredAt: timestamp("answered_at", { withTimezone: true }),
|
|
2040
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
|
955
2041
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
956
2042
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
957
2043
|
},
|
|
958
2044
|
(table) => ({
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
table.
|
|
962
|
-
table.
|
|
2045
|
+
inbox: unique("slack_route_prompts_inbox_uq").on(table.connectionId, table.inboxId),
|
|
2046
|
+
providerEvent: unique("slack_route_prompts_event_uq").on(
|
|
2047
|
+
table.connectionId,
|
|
2048
|
+
table.providerEventId,
|
|
963
2049
|
),
|
|
964
|
-
|
|
2050
|
+
tenantIdentity: unique("slack_route_prompts_identity_uq").on(
|
|
2051
|
+
table.accountId,
|
|
965
2052
|
table.workspaceId,
|
|
966
|
-
table.
|
|
967
|
-
table.providerDomain,
|
|
2053
|
+
table.id,
|
|
968
2054
|
),
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
table.workspaceId,
|
|
972
|
-
|
|
2055
|
+
workspaceAccount: foreignKey({
|
|
2056
|
+
name: "slack_route_prompts_workspace_account_fk",
|
|
2057
|
+
columns: [table.workspaceId, table.accountId],
|
|
2058
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
2059
|
+
}).onDelete("cascade"),
|
|
2060
|
+
pending: index("slack_route_prompts_pending_idx")
|
|
2061
|
+
.on(table.expiresAt, table.id)
|
|
2062
|
+
.where(sql`${table.status} = 'pending'`),
|
|
2063
|
+
statusValid: check(
|
|
2064
|
+
"slack_route_prompts_status_check",
|
|
2065
|
+
sql`${table.status} in ('pending', 'answered', 'expired', 'cancelled')`,
|
|
2066
|
+
),
|
|
2067
|
+
triggerValid: check(
|
|
2068
|
+
"slack_route_prompts_trigger_check",
|
|
2069
|
+
sql`${table.triggerKind} in (
|
|
2070
|
+
'app_mention', 'dm', 'reaction', 'slash_command',
|
|
2071
|
+
'message_shortcut', 'thread_reply', 'block_action'
|
|
2072
|
+
)`,
|
|
2073
|
+
),
|
|
2074
|
+
answerConsistent: check(
|
|
2075
|
+
"slack_route_prompts_answer_check",
|
|
2076
|
+
sql`(${table.status} = 'answered') = (${table.answeredTargetWorkspaceId} is not null)
|
|
2077
|
+
and (${table.answeredTargetAccountId} is null) = (${table.answeredTargetWorkspaceId} is null)
|
|
2078
|
+
and (${table.answeredTargetAccountId} is null
|
|
2079
|
+
or ${table.answeredTargetAccountId} = ${table.accountId})
|
|
2080
|
+
and (${table.answeredTargetWorkspaceId} is null) = (${table.answeredAt} is null)`,
|
|
2081
|
+
),
|
|
2082
|
+
bounded: check(
|
|
2083
|
+
"slack_route_prompts_bounds_check",
|
|
2084
|
+
sql`octet_length(${table.slackTeamId}) between 1 and 64
|
|
2085
|
+
and octet_length(${table.slackUserId}) between 1 and 64
|
|
2086
|
+
and octet_length(${table.slackChannelId}) between 1 and 64
|
|
2087
|
+
and octet_length(${table.slackMessageTs}) between 1 and 64
|
|
2088
|
+
and octet_length(${table.providerEventId}) between 1 and 256
|
|
2089
|
+
and octet_length(${table.requestText}) between 1 and 12000
|
|
2090
|
+
and (${table.slackThreadTs} is null
|
|
2091
|
+
or octet_length(${table.slackThreadTs}) between 1 and 64)
|
|
2092
|
+
and (${table.answeredBySubjectId} is null
|
|
2093
|
+
or octet_length(${table.answeredBySubjectId}) between 1 and 1024)`,
|
|
973
2094
|
),
|
|
974
2095
|
}),
|
|
975
2096
|
);
|
|
976
2097
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
2098
|
+
/**
|
|
2099
|
+
* One row per workspace offered by a {@link slackRoutePrompts} card. The row id
|
|
2100
|
+
* is the Slack button `value`, so it must be a UUID: the block-action normalizer
|
|
2101
|
+
* already requires that shape, which is why the picker uses buttons rather than
|
|
2102
|
+
* a `static_select` (whose `selected_option.value` the normalizer never reads).
|
|
2103
|
+
*
|
|
2104
|
+
* These rows are a snapshot taken at prompt time and are NEVER authority. The
|
|
2105
|
+
* answer path re-authorizes the chosen workspace live.
|
|
2106
|
+
*/
|
|
2107
|
+
export const slackRoutePromptOptions = pgTable(
|
|
2108
|
+
"slack_route_prompt_options",
|
|
983
2109
|
{
|
|
984
2110
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
985
2111
|
accountId: uuid("account_id")
|
|
@@ -988,55 +2114,54 @@ export const slackInstallationBindings = pgTable(
|
|
|
988
2114
|
workspaceId: uuid("workspace_id")
|
|
989
2115
|
.notNull()
|
|
990
2116
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
991
|
-
|
|
2117
|
+
promptId: uuid("prompt_id").notNull(),
|
|
2118
|
+
candidateAccountId: uuid("candidate_account_id")
|
|
992
2119
|
.notNull()
|
|
993
|
-
.references(() =>
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
state: text("state").$type<"active" | "quarantined">().notNull(),
|
|
1000
|
-
quarantineReason: text("quarantine_reason"),
|
|
1001
|
-
version: integer("version").notNull().default(1),
|
|
1002
|
-
createdBySubjectId: text("created_by_subject_id"),
|
|
1003
|
-
updatedBySubjectId: text("updated_by_subject_id"),
|
|
2120
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
2121
|
+
candidateWorkspaceId: uuid("candidate_workspace_id")
|
|
2122
|
+
.notNull()
|
|
2123
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
2124
|
+
candidateLabel: text("candidate_label").notNull(),
|
|
2125
|
+
position: integer("position").notNull(),
|
|
1004
2126
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1005
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1006
2127
|
},
|
|
1007
2128
|
(table) => ({
|
|
1008
|
-
connection: uniqueIndex("slack_installation_bindings_connection_uq").on(table.connectionId),
|
|
1009
|
-
activeTeam: uniqueIndex("slack_installation_bindings_active_team_uq")
|
|
1010
|
-
.on(table.slackTeamId)
|
|
1011
|
-
.where(sql`${table.state} = 'active'`),
|
|
1012
|
-
workspaceState: index("slack_installation_bindings_workspace_state_idx").on(
|
|
1013
|
-
table.workspaceId,
|
|
1014
|
-
table.state,
|
|
1015
|
-
table.updatedAt,
|
|
1016
|
-
),
|
|
1017
2129
|
workspaceAccount: foreignKey({
|
|
1018
|
-
name: "
|
|
2130
|
+
name: "slack_route_prompt_options_workspace_account_fk",
|
|
1019
2131
|
columns: [table.workspaceId, table.accountId],
|
|
1020
2132
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
1021
2133
|
}).onDelete("cascade"),
|
|
1022
|
-
|
|
1023
|
-
"
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
2134
|
+
promptIdentity: foreignKey({
|
|
2135
|
+
name: "slack_route_prompt_options_prompt_fk",
|
|
2136
|
+
columns: [table.accountId, table.workspaceId, table.promptId],
|
|
2137
|
+
foreignColumns: [
|
|
2138
|
+
slackRoutePrompts.accountId,
|
|
2139
|
+
slackRoutePrompts.workspaceId,
|
|
2140
|
+
slackRoutePrompts.id,
|
|
2141
|
+
],
|
|
2142
|
+
}).onDelete("cascade"),
|
|
2143
|
+
candidateWorkspaceAccount: foreignKey({
|
|
2144
|
+
name: "slack_route_prompt_options_candidate_workspace_account_fk",
|
|
2145
|
+
columns: [table.candidateWorkspaceId, table.candidateAccountId],
|
|
2146
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
2147
|
+
}).onDelete("cascade"),
|
|
2148
|
+
promptWorkspace: unique("slack_route_prompt_options_prompt_workspace_uq").on(
|
|
2149
|
+
table.promptId,
|
|
2150
|
+
table.candidateWorkspaceId,
|
|
1030
2151
|
),
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
2152
|
+
promptPosition: unique("slack_route_prompt_options_prompt_position_uq").on(
|
|
2153
|
+
table.promptId,
|
|
2154
|
+
table.position,
|
|
2155
|
+
),
|
|
2156
|
+
sameAccount: check(
|
|
2157
|
+
"slack_route_prompt_options_same_account_check",
|
|
2158
|
+
sql`${table.candidateAccountId} = ${table.accountId}`,
|
|
2159
|
+
),
|
|
2160
|
+
bounded: check(
|
|
2161
|
+
"slack_route_prompt_options_bounds_check",
|
|
2162
|
+
sql`octet_length(${table.candidateLabel}) between 1 and 128
|
|
2163
|
+
and ${table.position} >= 0`,
|
|
1038
2164
|
),
|
|
1039
|
-
versionPositive: check("slack_installation_bindings_version_check", sql`${table.version} > 0`),
|
|
1040
2165
|
}),
|
|
1041
2166
|
);
|
|
1042
2167
|
|
|
@@ -1143,6 +2268,9 @@ export const slackBotUserLinks = pgTable(
|
|
|
1143
2268
|
slackUserId: text("slack_user_id").notNull(),
|
|
1144
2269
|
subjectId: text("subject_id").notNull(),
|
|
1145
2270
|
linkedBySubjectId: text("linked_by_subject_id").notNull(),
|
|
2271
|
+
// The exact interaction id that won this identity's one-time onboarding
|
|
2272
|
+
// hint. NULL means the hint has not been shown yet.
|
|
2273
|
+
firstTaskHintInteractionId: uuid("first_task_hint_interaction_id"),
|
|
1146
2274
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1147
2275
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1148
2276
|
},
|
|
@@ -1368,6 +2496,21 @@ export const slackInteractionInbox = pgTable(
|
|
|
1368
2496
|
retryAt: timestamp("retry_at", { withTimezone: true }),
|
|
1369
2497
|
lastErrorCode: text("last_error_code"),
|
|
1370
2498
|
reactionContextCheckpoint: jsonb("reaction_context_checkpoint").$type<unknown>(),
|
|
2499
|
+
// Workspace routing decision, persisted on the claimed row so a retry after
|
|
2500
|
+
// a crash re-uses the same decision rather than re-asking. `accountId` and
|
|
2501
|
+
// `workspaceId` above stay HOME (the installation's credential tenancy) and
|
|
2502
|
+
// stay NOT NULL: `workspace_rls_visible` is strict equality, so a NULL
|
|
2503
|
+
// workspace would make an un-routed row invisible to every tenant including
|
|
2504
|
+
// its own. NULL `routeState` means "legacy / never routed" and is exactly
|
|
2505
|
+
// pre-routing behaviour.
|
|
2506
|
+
routeState: text("route_state").$type<"resolved" | "awaiting_choice" | "denied">(),
|
|
2507
|
+
// Deliberately no foreign key: an inbox row is short-lived and
|
|
2508
|
+
// definer-claimed, so a runtime re-check degrades to "ask again" while an FK
|
|
2509
|
+
// would hard-fail on a workspace deleted mid-flight.
|
|
2510
|
+
targetAccountId: uuid("target_account_id"),
|
|
2511
|
+
targetWorkspaceId: uuid("target_workspace_id"),
|
|
2512
|
+
routePromptId: uuid("route_prompt_id"),
|
|
2513
|
+
routePromptExpiresAt: timestamp("route_prompt_expires_at", { withTimezone: true }),
|
|
1371
2514
|
processedAt: timestamp("processed_at", { withTimezone: true }),
|
|
1372
2515
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1373
2516
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -1390,6 +2533,73 @@ export const slackInteractionInbox = pgTable(
|
|
|
1390
2533
|
}),
|
|
1391
2534
|
);
|
|
1392
2535
|
|
|
2536
|
+
// Coalesced private App Home refresh authority. One row per installed Slack
|
|
2537
|
+
// connection/user serializes provider replacement calls while allowing event
|
|
2538
|
+
// retries and newer opens to converge on the latest requested revision.
|
|
2539
|
+
export const slackAppHomeRefreshes = pgTable(
|
|
2540
|
+
"slack_app_home_refreshes",
|
|
2541
|
+
{
|
|
2542
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
2543
|
+
accountId: uuid("account_id")
|
|
2544
|
+
.notNull()
|
|
2545
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
2546
|
+
workspaceId: uuid("workspace_id")
|
|
2547
|
+
.notNull()
|
|
2548
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
2549
|
+
connectionId: uuid("connection_id")
|
|
2550
|
+
.notNull()
|
|
2551
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
2552
|
+
slackTeamId: text("slack_team_id").notNull(),
|
|
2553
|
+
slackUserId: text("slack_user_id").notNull(),
|
|
2554
|
+
providerEventId: text("provider_event_id").notNull(),
|
|
2555
|
+
providerViewHash: text("provider_view_hash"),
|
|
2556
|
+
desiredRevision: integer("desired_revision").notNull().default(1),
|
|
2557
|
+
processedRevision: integer("processed_revision").notNull().default(0),
|
|
2558
|
+
claimHolderId: uuid("claim_holder_id"),
|
|
2559
|
+
claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
|
|
2560
|
+
attemptCount: integer("attempt_count").notNull().default(0),
|
|
2561
|
+
retryAt: timestamp("retry_at", { withTimezone: true }),
|
|
2562
|
+
lastErrorCode: text("last_error_code"),
|
|
2563
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2564
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2565
|
+
},
|
|
2566
|
+
(table) => ({
|
|
2567
|
+
connectionUser: uniqueIndex("slack_app_home_refreshes_connection_user_uq").on(
|
|
2568
|
+
table.connectionId,
|
|
2569
|
+
table.slackUserId,
|
|
2570
|
+
),
|
|
2571
|
+
pending: index("slack_app_home_refreshes_pending_idx")
|
|
2572
|
+
.on(table.retryAt, table.updatedAt, table.id)
|
|
2573
|
+
.where(sql`${table.processedRevision} < ${table.desiredRevision}`),
|
|
2574
|
+
workspaceAccount: foreignKey({
|
|
2575
|
+
name: "slack_app_home_refreshes_workspace_account_fk",
|
|
2576
|
+
columns: [table.workspaceId, table.accountId],
|
|
2577
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
2578
|
+
}).onDelete("cascade"),
|
|
2579
|
+
bounds: check(
|
|
2580
|
+
"slack_app_home_refreshes_bounds_check",
|
|
2581
|
+
sql`octet_length(${table.slackTeamId}) between 1 and 64
|
|
2582
|
+
and octet_length(${table.slackUserId}) between 1 and 64
|
|
2583
|
+
and octet_length(${table.providerEventId}) between 1 and 256
|
|
2584
|
+
and (${table.providerViewHash} is null
|
|
2585
|
+
or octet_length(${table.providerViewHash}) between 1 and 256)
|
|
2586
|
+
and (${table.lastErrorCode} is null
|
|
2587
|
+
or octet_length(${table.lastErrorCode}) between 1 and 128)`,
|
|
2588
|
+
),
|
|
2589
|
+
revisions: check(
|
|
2590
|
+
"slack_app_home_refreshes_revisions_check",
|
|
2591
|
+
sql`${table.desiredRevision} > 0
|
|
2592
|
+
and ${table.processedRevision} >= 0
|
|
2593
|
+
and ${table.processedRevision} <= ${table.desiredRevision}
|
|
2594
|
+
and ${table.attemptCount} >= 0`,
|
|
2595
|
+
),
|
|
2596
|
+
claim: check(
|
|
2597
|
+
"slack_app_home_refreshes_claim_check",
|
|
2598
|
+
sql`(${table.claimHolderId} is null) = (${table.claimExpiresAt} is null)`,
|
|
2599
|
+
),
|
|
2600
|
+
}),
|
|
2601
|
+
);
|
|
2602
|
+
|
|
1393
2603
|
export const slackInteractions = pgTable(
|
|
1394
2604
|
"slack_interactions",
|
|
1395
2605
|
{
|
|
@@ -1426,6 +2636,15 @@ export const slackInteractions = pgTable(
|
|
|
1426
2636
|
deliveryRetryAt: timestamp("delivery_retry_at", { withTimezone: true }),
|
|
1427
2637
|
deliveryLastErrorCode: text("delivery_last_error_code"),
|
|
1428
2638
|
ackSlackMessageTs: text("ack_slack_message_ts"),
|
|
2639
|
+
// Frozen once: whether this interaction's acknowledgement renders the
|
|
2640
|
+
// one-time onboarding hint. NULL means the decision has not been resolved.
|
|
2641
|
+
firstTaskHint: boolean("first_task_hint"),
|
|
2642
|
+
// The routed workspace's display name, frozen when the interaction binds.
|
|
2643
|
+
// A live lookup at post time would be wrong: a workspace rename between the
|
|
2644
|
+
// original post and a reconciliation makes `reconcilePostMessage`'s
|
|
2645
|
+
// byte-compare raise `post_reconciliation_mismatch`. NULL means no
|
|
2646
|
+
// per-message workspace line.
|
|
2647
|
+
routedWorkspaceLabel: text("routed_workspace_label"),
|
|
1429
2648
|
progressCount: integer("progress_count").notNull().default(0),
|
|
1430
2649
|
terminalDeliveryState: text("terminal_delivery_state")
|
|
1431
2650
|
.$type<"open" | "completed" | "failed" | "cancelled" | "blocked">()
|
|
@@ -2440,6 +3659,9 @@ export const channels = pgTable(
|
|
|
2440
3659
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
2441
3660
|
name: text("name").notNull(),
|
|
2442
3661
|
description: text("description"),
|
|
3662
|
+
pinned: boolean("pinned").notNull().default(false),
|
|
3663
|
+
// Explicit user order within the pinned and unpinned project groups.
|
|
3664
|
+
sortOrder: integer("sort_order").notNull().default(0),
|
|
2443
3665
|
// Attribution string: 'user:<subject>' | 'session:<id>' | 'system'.
|
|
2444
3666
|
createdBy: text("created_by"),
|
|
2445
3667
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -2464,10 +3686,10 @@ export const sessions = pgTable(
|
|
|
2464
3686
|
status: text("status").notNull().default("queued"),
|
|
2465
3687
|
initialMessage: losslessText("initial_message").notNull(),
|
|
2466
3688
|
initialMessageCodecVersion: losslessCodecVersion("initial_message_codec_version"),
|
|
2467
|
-
//
|
|
2468
|
-
// initial turn copies
|
|
2469
|
-
// retrying caller's different
|
|
2470
|
-
|
|
3689
|
+
// Model-visible application context frozen with the winning create. The
|
|
3690
|
+
// initial turn copies it into the canonical user message so an idempotent
|
|
3691
|
+
// repair cannot adopt a retrying caller's different message context.
|
|
3692
|
+
initialModelContext: text("initial_model_context"),
|
|
2471
3693
|
title: text("title"),
|
|
2472
3694
|
titleSource: text("title_source"),
|
|
2473
3695
|
// Per-session agent persona/system instructions supplied at create (the
|
|
@@ -2500,6 +3722,9 @@ export const sessions = pgTable(
|
|
|
2500
3722
|
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
2501
3723
|
ownerSubjectId: text("owner_subject_id"),
|
|
2502
3724
|
visibility: text("visibility").notNull().default("workspace_shared"),
|
|
3725
|
+
createRequestedVisibility: text("create_requested_visibility")
|
|
3726
|
+
.notNull()
|
|
3727
|
+
.default("workspace_shared"),
|
|
2503
3728
|
authorityEpoch: integer("authority_epoch").notNull().default(1),
|
|
2504
3729
|
// Independent-copy provenance. A destination may use either visibility and
|
|
2505
3730
|
// may live in another workspace in the same organization; no live process,
|
|
@@ -2510,6 +3735,10 @@ export const sessions = pgTable(
|
|
|
2510
3735
|
forkedAt: timestamp("forked_at", { withTimezone: true }),
|
|
2511
3736
|
forkedByOrganizationMembershipId: uuid("forked_by_organization_membership_id"),
|
|
2512
3737
|
model: text("model").notNull(),
|
|
3738
|
+
// Immutable session-default execution policy. Follow-up composer drafts and
|
|
3739
|
+
// accepted turns are separate authorities and never mutate these columns.
|
|
3740
|
+
reasoningEffort: text("reasoning_effort").notNull(),
|
|
3741
|
+
latencyMode: text("latency_mode").notNull(),
|
|
2513
3742
|
sandboxBackend: text("sandbox_backend").notNull(),
|
|
2514
3743
|
// The OS this session's box runs. Defaults to 'linux' (today's only OS, so
|
|
2515
3744
|
// every existing + new row is a behavior-preserving no-op). CHECK-constrained
|
|
@@ -2539,13 +3768,10 @@ export const sessions = pgTable(
|
|
|
2539
3768
|
// sandbox. integer (NOT bigint) — the lease-epoch spike: int8 reads back as a
|
|
2540
3769
|
// JS string and breaks the strict fence; int4 returns a number.
|
|
2541
3770
|
activeEpoch: integer("active_epoch").notNull().default(0),
|
|
2542
|
-
// The session's
|
|
2543
|
-
//
|
|
2544
|
-
//
|
|
2545
|
-
//
|
|
2546
|
-
// setActiveSandbox CAS, NOT the row INSERT. NULL (the default) ⇒ today's
|
|
2547
|
-
// behavior exactly — the agent substitutes its workspace_root for an empty cwd,
|
|
2548
|
-
// so an unset working_dir is a byte-identical no-op. Create-time only (Stage A).
|
|
3771
|
+
// The session's effective absolute Connected Machine root. New attaches
|
|
3772
|
+
// resolve an optional relative request against the persisted Hello root and
|
|
3773
|
+
// write the result through the epoch-fenced setActiveSandbox CAS. Legacy
|
|
3774
|
+
// rows may still be null/relative and are resolved at establishment.
|
|
2549
3775
|
workingDir: text("working_dir"),
|
|
2550
3776
|
variableSetId: uuid("variable_set_id").references(() => workspaceVariableSets.id, {
|
|
2551
3777
|
onDelete: "set null",
|
|
@@ -2577,6 +3803,12 @@ export const sessions = pgTable(
|
|
|
2577
3803
|
.$type<McpPersonalConnectionDelegation[]>()
|
|
2578
3804
|
.notNull()
|
|
2579
3805
|
.default([]),
|
|
3806
|
+
// Initial accepted-work staging only. The initializer consumes this inside
|
|
3807
|
+
// the same transaction that inserts the first logical turn and grant
|
|
3808
|
+
// snapshots; runtime never authorizes from the session field.
|
|
3809
|
+
initialPersonalResourceAttachmentIntent: jsonb(
|
|
3810
|
+
"initial_personal_resource_attachment_intent",
|
|
3811
|
+
).$type<PersonalResourceAttachmentIntent>(),
|
|
2580
3812
|
initialXaiProviderAccountAuthoritySnapshot: jsonb(
|
|
2581
3813
|
"initial_xai_provider_account_authority_snapshot",
|
|
2582
3814
|
)
|
|
@@ -2593,8 +3825,8 @@ export const sessions = pgTable(
|
|
|
2593
3825
|
// spawning a worker); null for direct API creates and scheduled-task runs.
|
|
2594
3826
|
// When set, this worker's terminal-for-now transitions wake the parent so a
|
|
2595
3827
|
// manager can orchestrate workers without busy-polling. The migration-owned
|
|
2596
|
-
// self-reference uses ON DELETE
|
|
2597
|
-
//
|
|
3828
|
+
// self-reference uses ON DELETE CASCADE so the explicit quiescent root-tree
|
|
3829
|
+
// deletion lifecycle removes the complete hierarchy atomically.
|
|
2598
3830
|
parentSessionId: uuid("parent_session_id"),
|
|
2599
3831
|
// Exact parent turn whose worker-signed attempt created this child. This is
|
|
2600
3832
|
// private immutable authority lineage: child completion copies personal MCP
|
|
@@ -2676,6 +3908,14 @@ export const sessions = pgTable(
|
|
|
2676
3908
|
}),
|
|
2677
3909
|
},
|
|
2678
3910
|
(table) => ({
|
|
3911
|
+
reasoningEffortValid: check(
|
|
3912
|
+
"sessions_reasoning_effort_check",
|
|
3913
|
+
sql`${table.reasoningEffort} in ('none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max')`,
|
|
3914
|
+
),
|
|
3915
|
+
latencyModeValid: check(
|
|
3916
|
+
"sessions_latency_mode_check",
|
|
3917
|
+
sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
|
|
3918
|
+
),
|
|
2679
3919
|
accountIdentity: uniqueIndex("sessions_id_account_idx").on(table.id, table.accountId),
|
|
2680
3920
|
workspaceIdentity: uniqueIndex("sessions_workspace_id_idx").on(table.workspaceId, table.id),
|
|
2681
3921
|
workspaceCreated: index("sessions_workspace_created_idx").on(
|
|
@@ -2762,6 +4002,11 @@ export const sessions = pgTable(
|
|
|
2762
4002
|
table.rootSessionId,
|
|
2763
4003
|
table.nestedAgentDepth,
|
|
2764
4004
|
),
|
|
4005
|
+
initialModelContextValid: check(
|
|
4006
|
+
"sessions_initial_model_context_check",
|
|
4007
|
+
sql`${table.initialModelContext} is null
|
|
4008
|
+
or opengeni_private.model_context_value_valid(${table.initialModelContext})`,
|
|
4009
|
+
),
|
|
2765
4010
|
}),
|
|
2766
4011
|
);
|
|
2767
4012
|
|
|
@@ -2797,6 +4042,18 @@ export const organizationUserResourceGrants = pgTable(
|
|
|
2797
4042
|
table.workspaceId,
|
|
2798
4043
|
table.status,
|
|
2799
4044
|
),
|
|
4045
|
+
activeIdentity: uniqueIndex("organization_user_resource_grants_active_identity_uq")
|
|
4046
|
+
.on(
|
|
4047
|
+
table.accountId,
|
|
4048
|
+
table.authorityId,
|
|
4049
|
+
table.workspaceId,
|
|
4050
|
+
table.action,
|
|
4051
|
+
table.mode,
|
|
4052
|
+
table.context,
|
|
4053
|
+
sql`coalesce(${table.sessionId}, '00000000-0000-0000-0000-000000000000'::uuid)`,
|
|
4054
|
+
sql`coalesce(${table.authorityEpoch}, 0)`,
|
|
4055
|
+
)
|
|
4056
|
+
.where(sql`${table.status} = 'active'`),
|
|
2800
4057
|
authority: foreignKey({
|
|
2801
4058
|
name: "organization_user_resource_grants_authority_fk",
|
|
2802
4059
|
columns: [table.authorityId, table.accountId],
|
|
@@ -2949,7 +4206,7 @@ export const sessionRealtimeModes = pgTable(
|
|
|
2949
4206
|
),
|
|
2950
4207
|
endReasonValid: check(
|
|
2951
4208
|
"session_realtime_modes_end_reason_check",
|
|
2952
|
-
sql`${table.endReason} is null or ${table.endReason} in ('user_stop', 'browser_unload', 'lease_expired')`,
|
|
4209
|
+
sql`${table.endReason} is null or ${table.endReason} in ('user_stop', 'browser_unload', 'lease_expired', 'authority_revoked')`,
|
|
2953
4210
|
),
|
|
2954
4211
|
versionValid: check("session_realtime_modes_version_check", sql`${table.version} >= 1`),
|
|
2955
4212
|
epochValid: check("session_realtime_modes_epoch_check", sql`${table.connectionEpoch} >= 1`),
|
|
@@ -3115,6 +4372,9 @@ export const sessionRealtimeEntries = pgTable(
|
|
|
3115
4372
|
textCodecVersion: losslessCodecVersion("text_codec_version"),
|
|
3116
4373
|
payload: losslessJsonb("payload").$type<Record<string, unknown>>().notNull().default({}),
|
|
3117
4374
|
payloadCodecVersion: losslessCodecVersion("payload_codec_version"),
|
|
4375
|
+
// Application context for an exact provider-in delegation or finalized
|
|
4376
|
+
// transcript. It is materialized as ordinary user-role message content.
|
|
4377
|
+
modelContext: text("model_context"),
|
|
3118
4378
|
clientAckedAt: timestamp("client_acked_at", { withTimezone: true }),
|
|
3119
4379
|
providerAckedAt: timestamp("provider_acked_at", { withTimezone: true }),
|
|
3120
4380
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -3190,6 +4450,15 @@ export const sessionRealtimeEntries = pgTable(
|
|
|
3190
4450
|
or (${table.kind} = 'assistant_transcript' and ${table.role} = 'assistant' and ${table.text} is not null)
|
|
3191
4451
|
or (${table.kind} not in ('user_transcript', 'assistant_transcript') and ${table.role} is null)`,
|
|
3192
4452
|
),
|
|
4453
|
+
modelContextValid: check(
|
|
4454
|
+
"session_realtime_entries_model_context_check",
|
|
4455
|
+
sql`${table.modelContext} is null
|
|
4456
|
+
or (
|
|
4457
|
+
${table.direction} = 'provider_in'
|
|
4458
|
+
and ${table.kind} in ('delegation_call', 'user_transcript', 'assistant_transcript')
|
|
4459
|
+
and opengeni_private.model_context_value_valid(${table.modelContext})
|
|
4460
|
+
)`,
|
|
4461
|
+
),
|
|
3193
4462
|
}),
|
|
3194
4463
|
);
|
|
3195
4464
|
|
|
@@ -3240,10 +4509,11 @@ export const sessionSpawnDenials = pgTable(
|
|
|
3240
4509
|
}),
|
|
3241
4510
|
);
|
|
3242
4511
|
|
|
3243
|
-
// Per-authenticated-subject session organization. This is
|
|
3244
|
-
// relation instead of
|
|
3245
|
-
//
|
|
3246
|
-
// must remain agent/runtime truth.
|
|
4512
|
+
// Per-authenticated-subject session organization and follow-up state. This is
|
|
4513
|
+
// deliberately a relation instead of session columns: one member's pin,
|
|
4514
|
+
// acknowledgment, or actively-working label must never affect another member,
|
|
4515
|
+
// and a session's own activity timestamps must remain agent/runtime truth.
|
|
4516
|
+
// `subjectId` is the trusted AccessGrant
|
|
3247
4517
|
// subject, which is text because configured/delegated principals are not always
|
|
3248
4518
|
// UUIDs. The account/workspace pair carries the standard forced-RLS boundary.
|
|
3249
4519
|
export const sessionPins = pgTable(
|
|
@@ -3267,13 +4537,38 @@ export const sessionPins = pgTable(
|
|
|
3267
4537
|
pinned: boolean("pinned").notNull().default(true),
|
|
3268
4538
|
pinnedAt: timestamp("pinned_at", { withTimezone: true }).defaultNow(),
|
|
3269
4539
|
version: integer("version").notNull().default(1),
|
|
4540
|
+
// A session is unread for this subject whenever its durable event sequence
|
|
4541
|
+
// has advanced beyond this explicit acknowledgment fence. Merely opening a
|
|
4542
|
+
// route never changes the fence.
|
|
4543
|
+
acknowledgedSequence: integer("acknowledged_sequence").notNull().default(0),
|
|
4544
|
+
activelyWorking: boolean("actively_working").notNull().default(false),
|
|
4545
|
+
attentionVersion: integer("attention_version").notNull().default(0),
|
|
4546
|
+
archived: boolean("archived").notNull().default(false),
|
|
4547
|
+
archivedAt: timestamp("archived_at", { withTimezone: true }),
|
|
4548
|
+
archiveVersion: integer("archive_version").notNull().default(0),
|
|
3270
4549
|
},
|
|
3271
4550
|
(table) => ({
|
|
3272
4551
|
subjectNonempty: check(
|
|
3273
4552
|
"session_pins_subject_nonempty",
|
|
3274
4553
|
sql`length(btrim(${table.subjectId})) > 0`,
|
|
3275
4554
|
),
|
|
3276
|
-
|
|
4555
|
+
versionNonnegative: check("session_pins_version_nonnegative", sql`${table.version} >= 0`),
|
|
4556
|
+
acknowledgedSequenceFloor: check(
|
|
4557
|
+
"session_pins_acknowledged_sequence_floor",
|
|
4558
|
+
sql`${table.acknowledgedSequence} >= -1`,
|
|
4559
|
+
),
|
|
4560
|
+
attentionVersionNonnegative: check(
|
|
4561
|
+
"session_pins_attention_version_nonnegative",
|
|
4562
|
+
sql`${table.attentionVersion} >= 0`,
|
|
4563
|
+
),
|
|
4564
|
+
archiveVersionNonnegative: check(
|
|
4565
|
+
"session_pins_archive_version_nonnegative",
|
|
4566
|
+
sql`${table.archiveVersion} >= 0`,
|
|
4567
|
+
),
|
|
4568
|
+
archiveStateConsistent: check(
|
|
4569
|
+
"session_pins_archive_state_consistent",
|
|
4570
|
+
sql`((${table.archived}) and (${table.archivedAt}) is not null) or ((not ${table.archived}) and (${table.archivedAt}) is null)`,
|
|
4571
|
+
),
|
|
3277
4572
|
stateConsistent: check(
|
|
3278
4573
|
"session_pins_state_consistent",
|
|
3279
4574
|
sql`((${table.pinned}) and (${table.pinnedAt}) is not null) or ((not ${table.pinned}) and (${table.pinnedAt}) is null)`,
|
|
@@ -3300,15 +4595,22 @@ export const sessionPins = pgTable(
|
|
|
3300
4595
|
table.pinnedAt.desc(),
|
|
3301
4596
|
table.sessionId.desc(),
|
|
3302
4597
|
),
|
|
4598
|
+
subjectArchived: index("session_pins_workspace_subject_archived_idx").on(
|
|
4599
|
+
table.workspaceId,
|
|
4600
|
+
table.subjectId,
|
|
4601
|
+
table.archived,
|
|
4602
|
+
table.archivedAt.desc(),
|
|
4603
|
+
table.sessionId.desc(),
|
|
4604
|
+
),
|
|
3303
4605
|
}),
|
|
3304
4606
|
);
|
|
3305
4607
|
|
|
3306
|
-
//
|
|
3307
|
-
//
|
|
3308
|
-
//
|
|
3309
|
-
//
|
|
3310
|
-
//
|
|
3311
|
-
//
|
|
4608
|
+
// Rolling-compatibility storage for pre-keyset session-list cursors. New page
|
|
4609
|
+
// one reads freeze the committed workspace activity revision in an opaque
|
|
4610
|
+
// updated_at/id keyset and create no row here. Old API replicas and cursors may
|
|
4611
|
+
// retain an already-ordered id array for its short TTL, so current replicas keep
|
|
4612
|
+
// reading, visibility-stripping, member-cleaning, and reaping those rows until
|
|
4613
|
+
// the compatibility table is retired by a later migration.
|
|
3312
4614
|
export const sessionListSnapshots = pgTable(
|
|
3313
4615
|
"session_list_snapshots",
|
|
3314
4616
|
{
|
|
@@ -3318,6 +4620,7 @@ export const sessionListSnapshots = pgTable(
|
|
|
3318
4620
|
subjectId: text("subject_id").notNull(),
|
|
3319
4621
|
parentSessionFilter: text("parent_session_filter").notNull().default("all"),
|
|
3320
4622
|
search: text("search"),
|
|
4623
|
+
archiveMode: text("archive_mode").$type<"active" | "archived">().notNull().default("active"),
|
|
3321
4624
|
ordinarySessionIds: uuid("ordinary_session_ids")
|
|
3322
4625
|
.array()
|
|
3323
4626
|
.notNull()
|
|
@@ -3343,6 +4646,10 @@ export const sessionListSnapshots = pgTable(
|
|
|
3343
4646
|
"session_list_snapshots_search_length",
|
|
3344
4647
|
sql`${table.search} is null or length(${table.search}) <= 200`,
|
|
3345
4648
|
),
|
|
4649
|
+
archiveModeValid: check(
|
|
4650
|
+
"session_list_snapshots_archive_mode_valid",
|
|
4651
|
+
sql`${table.archiveMode} in ('active', 'archived')`,
|
|
4652
|
+
),
|
|
3346
4653
|
workspaceExpiry: index("session_list_snapshots_workspace_expiry_idx").on(
|
|
3347
4654
|
table.workspaceId,
|
|
3348
4655
|
table.subjectId,
|
|
@@ -4216,6 +5523,12 @@ export const documents = pgTable(
|
|
|
4216
5523
|
authorityKind: text("authority_kind").notNull().default("workspace"),
|
|
4217
5524
|
authorityWorkspaceId: uuid("authority_workspace_id"),
|
|
4218
5525
|
authoritySubjectId: text("authority_subject_id"),
|
|
5526
|
+
// Activated personal documents follow their organization membership across
|
|
5527
|
+
// workspaces. Legacy personal rows retain a null authority id and their
|
|
5528
|
+
// original workspace anchor; originWorkspaceId is provenance only.
|
|
5529
|
+
authorityId: uuid("authority_id"),
|
|
5530
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
5531
|
+
originWorkspaceId: uuid("origin_workspace_id").notNull(),
|
|
4219
5532
|
// Per-document access controls. visibility 'private' restricts human reads to
|
|
4220
5533
|
// created_by (a grant subject id, not a uuid); agent_access=false hides the
|
|
4221
5534
|
// document from agent retrieval surfaces (docs MCP) while humans keep REST.
|
|
@@ -4274,16 +5587,29 @@ export const documents = pgTable(
|
|
|
4274
5587
|
columns: [table.authorityWorkspaceId, table.accountId],
|
|
4275
5588
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
4276
5589
|
}).onDelete("restrict"),
|
|
5590
|
+
userAuthority: foreignKey({
|
|
5591
|
+
name: "documents_user_authority_fk",
|
|
5592
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
5593
|
+
foreignColumns: [
|
|
5594
|
+
organizationUserResourceAuthorities.id,
|
|
5595
|
+
organizationUserResourceAuthorities.accountId,
|
|
5596
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
5597
|
+
],
|
|
5598
|
+
}).onDelete("restrict"),
|
|
4277
5599
|
authorityState: check(
|
|
4278
5600
|
"documents_authority_chk",
|
|
4279
|
-
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null)
|
|
4280
|
-
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null)
|
|
4281
|
-
or (${table.authorityKind} = 'personal' and
|
|
5601
|
+
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5602
|
+
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5603
|
+
or (${table.authorityKind} = 'personal' and nullif(btrim(${table.authoritySubjectId}), '') is not null and octet_length(convert_to(${table.authoritySubjectId}, 'UTF8')) <= 1024 and ${table.authoritySubjectId} = ${table.createdBy} and ((${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null) or (${table.authorityWorkspaceId} is null and ${table.authorityId} is not null and ${table.ownerOrganizationMembershipId} is not null)))`,
|
|
4282
5604
|
),
|
|
4283
5605
|
authorityVisibility: check(
|
|
4284
5606
|
"documents_authority_visibility_chk",
|
|
4285
5607
|
sql`(${table.authorityKind} = 'personal') = (${table.visibility} = 'private')`,
|
|
4286
5608
|
),
|
|
5609
|
+
originWorkspace: check(
|
|
5610
|
+
"documents_origin_workspace_chk",
|
|
5611
|
+
sql`${table.originWorkspaceId} = ${table.workspaceId}`,
|
|
5612
|
+
),
|
|
4287
5613
|
visibilityState: check(
|
|
4288
5614
|
"documents_visibility_chk",
|
|
4289
5615
|
sql`${table.visibility} in ('workspace', 'private')`,
|
|
@@ -4338,6 +5664,8 @@ export const documentChunks = pgTable(
|
|
|
4338
5664
|
authorityKind: text("authority_kind").notNull().default("workspace"),
|
|
4339
5665
|
authorityWorkspaceId: uuid("authority_workspace_id"),
|
|
4340
5666
|
authoritySubjectId: text("authority_subject_id"),
|
|
5667
|
+
authorityId: uuid("authority_id"),
|
|
5668
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
4341
5669
|
embedding: vector("embedding").notNull(),
|
|
4342
5670
|
embeddingModel: text("embedding_model").notNull(),
|
|
4343
5671
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -4360,11 +5688,20 @@ export const documentChunks = pgTable(
|
|
|
4360
5688
|
columns: [table.authorityWorkspaceId, table.accountId],
|
|
4361
5689
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
4362
5690
|
}).onDelete("restrict"),
|
|
5691
|
+
userAuthority: foreignKey({
|
|
5692
|
+
name: "document_chunks_user_authority_fk",
|
|
5693
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
5694
|
+
foreignColumns: [
|
|
5695
|
+
organizationUserResourceAuthorities.id,
|
|
5696
|
+
organizationUserResourceAuthorities.accountId,
|
|
5697
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
5698
|
+
],
|
|
5699
|
+
}).onDelete("restrict"),
|
|
4363
5700
|
authorityState: check(
|
|
4364
5701
|
"document_chunks_authority_chk",
|
|
4365
|
-
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null)
|
|
4366
|
-
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null)
|
|
4367
|
-
or (${table.authorityKind} = 'personal' and
|
|
5702
|
+
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5703
|
+
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5704
|
+
or (${table.authorityKind} = 'personal' and nullif(btrim(${table.authoritySubjectId}), '') is not null and octet_length(convert_to(${table.authoritySubjectId}, 'UTF8')) <= 1024 and ((${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null) or (${table.authorityWorkspaceId} is null and ${table.authorityId} is not null and ${table.ownerOrganizationMembershipId} is not null)))`,
|
|
4368
5705
|
),
|
|
4369
5706
|
}),
|
|
4370
5707
|
);
|
|
@@ -4493,13 +5830,20 @@ export const sessionTurns = pgTable(
|
|
|
4493
5830
|
temporalWorkflowId: text("temporal_workflow_id").notNull(),
|
|
4494
5831
|
status: text("status").notNull(),
|
|
4495
5832
|
source: text("source").notNull().default("user"),
|
|
5833
|
+
// Immutable user-facing admission intent. Physical execution still uses
|
|
5834
|
+
// status=queued until a worker claims the row; this field keeps that
|
|
5835
|
+
// implementation queue distinct from prompts genuinely waiting behind
|
|
5836
|
+
// other work. Null is reserved for rolling/legacy writers and non-human
|
|
5837
|
+
// turns, and is projected conservatively as visible queue work.
|
|
5838
|
+
promptRouting: text("prompt_routing"),
|
|
4496
5839
|
position: bigint("position", { mode: "number" }).notNull(),
|
|
4497
5840
|
prompt: losslessText("prompt").notNull(),
|
|
4498
5841
|
promptCodecVersion: losslessCodecVersion("prompt_codec_version"),
|
|
4499
5842
|
annotations: jsonb("annotations").$type<TimelineAnnotation[]>().notNull().default([]),
|
|
4500
|
-
//
|
|
4501
|
-
//
|
|
4502
|
-
|
|
5843
|
+
// Application context for this exact user message. It is copied into the
|
|
5844
|
+
// canonical user-role history item at claim and omitted from public queue
|
|
5845
|
+
// projections; full event/audit data retains it.
|
|
5846
|
+
modelContext: text("model_context"),
|
|
4503
5847
|
resources: jsonb("resources").$type<unknown[]>().notNull().default([]),
|
|
4504
5848
|
tools: jsonb("tools").$type<unknown[]>().notNull().default([]),
|
|
4505
5849
|
// false = inherit the durable session policy; true = this turn explicitly
|
|
@@ -4546,15 +5890,28 @@ export const sessionTurns = pgTable(
|
|
|
4546
5890
|
.$type<McpPersonalConnectionDelegation[]>()
|
|
4547
5891
|
.notNull()
|
|
4548
5892
|
.default([]),
|
|
5893
|
+
// Credential-free public summary of a turn-bound personal Variable
|
|
5894
|
+
// Set/Rig attachment. Exact resource and grant identity lives only in the
|
|
5895
|
+
// immutable accepted-work snapshot tables.
|
|
5896
|
+
personalResourceAttachmentSummary: jsonb(
|
|
5897
|
+
"personal_resource_attachment_summary",
|
|
5898
|
+
).$type<PersonalResourceAttachmentSummary>(),
|
|
5899
|
+
// 0 = legacy attempt-selected authority; 1 = immutable logical-turn
|
|
5900
|
+
// snapshots. Drained migration 0306 makes every new atomic attachment v1.
|
|
5901
|
+
personalResourceProtocolVersion: integer("personal_resource_protocol_version")
|
|
5902
|
+
.notNull()
|
|
5903
|
+
.default(0),
|
|
5904
|
+
// Immutable scheduled occurrence that accepted this logical turn. Null for
|
|
5905
|
+
// ordinary human, goal, child, and unrelated internal work.
|
|
5906
|
+
scheduledTaskRunId: uuid("scheduled_task_run_id"),
|
|
4549
5907
|
xaiProviderAccountAuthoritySnapshot: jsonb("xai_provider_account_authority_snapshot")
|
|
4550
5908
|
.$type<XaiProviderAccountAuthoritySnapshotV1>()
|
|
4551
5909
|
.notNull()
|
|
4552
5910
|
.default(WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1),
|
|
4553
5911
|
cancelledBy: text("cancelled_by"),
|
|
4554
5912
|
cancelReason: text("cancel_reason"),
|
|
4555
|
-
//
|
|
4556
|
-
//
|
|
4557
|
-
// concurrent reservations so exactly `codemodeMaxCallsPerTurn` succeed.
|
|
5913
|
+
// Leftover unused counter from the removed per-turn Codemode call cap
|
|
5914
|
+
// (migrations 0043/0205). New writers do not increment it; do not enforce.
|
|
4558
5915
|
codemodeCallCount: integer("codemode_call_count").notNull().default(0),
|
|
4559
5916
|
startedAt: timestamp("started_at", { withTimezone: true }),
|
|
4560
5917
|
finishedAt: timestamp("finished_at", { withTimezone: true }),
|
|
@@ -4575,10 +5932,162 @@ export const sessionTurns = pgTable(
|
|
|
4575
5932
|
oneCurrentInference: uniqueIndex("session_turns_one_current_inference_uq")
|
|
4576
5933
|
.on(table.workspaceId, table.sessionId)
|
|
4577
5934
|
.where(sql`${table.status} in ('running','requires_action','recovering','waiting_capacity')`),
|
|
5935
|
+
// Agent-monitoring "was this prompt's turn ever claimed" probe
|
|
5936
|
+
// (`excludeUnclaimedHumanPromptEventFilter`), migration 0322.
|
|
5937
|
+
unclaimedPromptTrigger: index("session_turns_unclaimed_prompt_trigger_idx")
|
|
5938
|
+
.on(table.workspaceId, table.sessionId, table.triggerEventId)
|
|
5939
|
+
.where(sql`${table.startedAt} is null`),
|
|
4578
5940
|
latencyModeValid: check(
|
|
4579
5941
|
"session_turns_latency_mode_check",
|
|
4580
5942
|
sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
|
|
4581
5943
|
),
|
|
5944
|
+
modelContextValid: check(
|
|
5945
|
+
"session_turns_model_context_check",
|
|
5946
|
+
sql`${table.modelContext} is null
|
|
5947
|
+
or opengeni_private.model_context_value_valid(${table.modelContext})`,
|
|
5948
|
+
),
|
|
5949
|
+
}),
|
|
5950
|
+
);
|
|
5951
|
+
|
|
5952
|
+
/** Immutable logical-turn receipt for atomic personal-resource issuance. */
|
|
5953
|
+
export const turnPersonalResourceAttachmentReceipts = pgTable(
|
|
5954
|
+
"turn_personal_resource_attachment_receipts",
|
|
5955
|
+
{
|
|
5956
|
+
turnId: uuid("turn_id")
|
|
5957
|
+
.primaryKey()
|
|
5958
|
+
.references(() => sessionTurns.id, { onDelete: "cascade" }),
|
|
5959
|
+
accountId: uuid("account_id").notNull(),
|
|
5960
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
5961
|
+
sessionId: uuid("session_id").notNull(),
|
|
5962
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id").notNull(),
|
|
5963
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id").notNull(),
|
|
5964
|
+
membershipAuthorizationRevision: bigint("membership_authorization_revision", {
|
|
5965
|
+
mode: "number",
|
|
5966
|
+
}).notNull(),
|
|
5967
|
+
sessionVisibility: text("session_visibility").notNull(),
|
|
5968
|
+
sessionAuthorityEpoch: integer("session_authority_epoch").notNull(),
|
|
5969
|
+
grantMode: text("grant_mode").notNull(),
|
|
5970
|
+
sharedOutputWarningVersion: integer("shared_output_warning_version").notNull(),
|
|
5971
|
+
sharedOutputAcknowledged: boolean("shared_output_acknowledged").notNull(),
|
|
5972
|
+
requestDigest: bytea("request_digest").notNull(),
|
|
5973
|
+
resourceCount: integer("resource_count").notNull(),
|
|
5974
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5975
|
+
},
|
|
5976
|
+
(table) => ({
|
|
5977
|
+
workspaceTurn: foreignKey({
|
|
5978
|
+
name: "turn_personal_resource_attachment_receipts_workspace_turn_fk",
|
|
5979
|
+
columns: [table.workspaceId, table.turnId],
|
|
5980
|
+
foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
|
|
5981
|
+
}).onDelete("cascade"),
|
|
5982
|
+
identity: check(
|
|
5983
|
+
"turn_personal_resource_attachment_receipts_identity_chk",
|
|
5984
|
+
sql`${table.sessionAuthorityEpoch} > 0
|
|
5985
|
+
and octet_length(${table.initiatingHumanSubjectId}) between 1 and 512
|
|
5986
|
+
and ${table.membershipAuthorizationRevision} > 0
|
|
5987
|
+
and ${table.resourceCount} between 1 and 28
|
|
5988
|
+
and ${table.grantMode} in ('once', 'session', 'always')
|
|
5989
|
+
and ${table.sessionVisibility} in ('user_private', 'workspace_shared')
|
|
5990
|
+
and ${table.sharedOutputWarningVersion} = 1
|
|
5991
|
+
and (${table.sessionVisibility} <> 'workspace_shared'
|
|
5992
|
+
or ${table.sharedOutputAcknowledged})`,
|
|
5993
|
+
),
|
|
5994
|
+
}),
|
|
5995
|
+
);
|
|
5996
|
+
|
|
5997
|
+
/** Exact resource/grant authority frozen on one accepted logical turn. */
|
|
5998
|
+
export const turnPersonalResourceSnapshots = pgTable(
|
|
5999
|
+
"turn_personal_resource_snapshots",
|
|
6000
|
+
{
|
|
6001
|
+
turnId: uuid("turn_id").notNull(),
|
|
6002
|
+
accountId: uuid("account_id").notNull(),
|
|
6003
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6004
|
+
sessionId: uuid("session_id").notNull(),
|
|
6005
|
+
resourceKind: text("resource_kind").notNull(),
|
|
6006
|
+
resourceId: uuid("resource_id").notNull(),
|
|
6007
|
+
resourceVersionId: uuid("resource_version_id"),
|
|
6008
|
+
selectionSources: text("selection_sources").array().notNull(),
|
|
6009
|
+
action: text("action").notNull(),
|
|
6010
|
+
originWorkspaceId: uuid("origin_workspace_id").notNull(),
|
|
6011
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id").notNull(),
|
|
6012
|
+
membershipAuthorizationRevision: bigint("membership_authorization_revision", {
|
|
6013
|
+
mode: "number",
|
|
6014
|
+
}).notNull(),
|
|
6015
|
+
authorityId: uuid("authority_id").notNull(),
|
|
6016
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }).notNull(),
|
|
6017
|
+
grantId: uuid("grant_id").notNull(),
|
|
6018
|
+
grantGeneration: bigint("grant_generation", { mode: "number" }).notNull(),
|
|
6019
|
+
grantMode: text("grant_mode").notNull(),
|
|
6020
|
+
grantContext: text("grant_context").notNull(),
|
|
6021
|
+
grantSessionId: uuid("grant_session_id"),
|
|
6022
|
+
grantAuthorityEpoch: integer("grant_authority_epoch"),
|
|
6023
|
+
canonicalDelegation: jsonb("canonical_delegation").$type<UserResourceDelegation>().notNull(),
|
|
6024
|
+
snapshotDigest: bytea("snapshot_digest").notNull(),
|
|
6025
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6026
|
+
},
|
|
6027
|
+
(table) => ({
|
|
6028
|
+
pk: primaryKey({ columns: [table.turnId, table.resourceKind, table.resourceId] }),
|
|
6029
|
+
receipt: foreignKey({
|
|
6030
|
+
name: "turn_personal_resource_snapshots_receipt_fk",
|
|
6031
|
+
columns: [table.turnId],
|
|
6032
|
+
foreignColumns: [turnPersonalResourceAttachmentReceipts.turnId],
|
|
6033
|
+
}).onDelete("cascade"),
|
|
6034
|
+
authority: index("turn_personal_resource_snapshots_authority_idx").on(table.authorityId),
|
|
6035
|
+
grant: index("turn_personal_resource_snapshots_grant_idx").on(table.grantId),
|
|
6036
|
+
kind: check(
|
|
6037
|
+
"turn_personal_resource_snapshots_kind_chk",
|
|
6038
|
+
sql`(${table.resourceKind} = 'variable_set'
|
|
6039
|
+
and ${table.action} = 'variable_set.use'
|
|
6040
|
+
and ${table.resourceVersionId} is null)
|
|
6041
|
+
or (${table.resourceKind} = 'rig'
|
|
6042
|
+
and ${table.action} = 'rig.use'
|
|
6043
|
+
and ${table.resourceVersionId} is not null)
|
|
6044
|
+
or (${table.resourceKind} = 'connected_machine'
|
|
6045
|
+
and ${table.action} = 'connected_machine.use'
|
|
6046
|
+
and ${table.resourceVersionId} is null)`,
|
|
6047
|
+
),
|
|
6048
|
+
generations: check(
|
|
6049
|
+
"turn_personal_resource_snapshots_generation_chk",
|
|
6050
|
+
sql`${table.membershipAuthorizationRevision} > 0
|
|
6051
|
+
and ${table.authorityGeneration} > 0
|
|
6052
|
+
and ${table.grantGeneration} > 0
|
|
6053
|
+
and cardinality(${table.selectionSources}) between 1 and 26`,
|
|
6054
|
+
),
|
|
6055
|
+
grantShape: check(
|
|
6056
|
+
"turn_personal_resource_snapshots_grant_chk",
|
|
6057
|
+
sql`${table.grantMode} in ('once', 'session', 'always')
|
|
6058
|
+
and ${table.grantContext} in ('user_private', 'workspace_shared')
|
|
6059
|
+
and ((${table.grantMode} = 'always'
|
|
6060
|
+
and ${table.grantSessionId} is null
|
|
6061
|
+
and ${table.grantAuthorityEpoch} is null)
|
|
6062
|
+
or (${table.grantMode} in ('once', 'session')
|
|
6063
|
+
and ${table.grantSessionId} = ${table.sessionId}
|
|
6064
|
+
and ${table.grantAuthorityEpoch} > 0))`,
|
|
6065
|
+
),
|
|
6066
|
+
}),
|
|
6067
|
+
);
|
|
6068
|
+
|
|
6069
|
+
/** One once grant may belong to one accepted logical turn only. */
|
|
6070
|
+
export const turnPersonalResourceOnceReceipts = pgTable(
|
|
6071
|
+
"turn_personal_resource_once_receipts",
|
|
6072
|
+
{
|
|
6073
|
+
grantId: uuid("grant_id").primaryKey(),
|
|
6074
|
+
turnId: uuid("turn_id").notNull(),
|
|
6075
|
+
accountId: uuid("account_id").notNull(),
|
|
6076
|
+
authorityId: uuid("authority_id").notNull(),
|
|
6077
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }).notNull(),
|
|
6078
|
+
grantGeneration: bigint("grant_generation", { mode: "number" }).notNull(),
|
|
6079
|
+
consumedAt: timestamp("consumed_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6080
|
+
},
|
|
6081
|
+
(table) => ({
|
|
6082
|
+
receipt: foreignKey({
|
|
6083
|
+
name: "turn_personal_resource_once_receipts_turn_fk",
|
|
6084
|
+
columns: [table.turnId],
|
|
6085
|
+
foreignColumns: [turnPersonalResourceAttachmentReceipts.turnId],
|
|
6086
|
+
}).onDelete("cascade"),
|
|
6087
|
+
generations: check(
|
|
6088
|
+
"turn_personal_resource_once_receipts_generation_chk",
|
|
6089
|
+
sql`${table.authorityGeneration} > 0 and ${table.grantGeneration} > 0`,
|
|
6090
|
+
),
|
|
4582
6091
|
}),
|
|
4583
6092
|
);
|
|
4584
6093
|
|
|
@@ -4670,6 +6179,9 @@ export const sessionTurnAttempts = pgTable(
|
|
|
4670
6179
|
authorityEpoch: integer("authority_epoch").notNull(),
|
|
4671
6180
|
authorityVisibility: text("authority_visibility").notNull(),
|
|
4672
6181
|
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6182
|
+
personalResourceProtocolVersion: integer("personal_resource_protocol_version")
|
|
6183
|
+
.notNull()
|
|
6184
|
+
.default(0),
|
|
4673
6185
|
// Immutable policy snapshot captured under the session lock at claim.
|
|
4674
6186
|
mcpApprovalPolicies: jsonb("mcp_approval_policies")
|
|
4675
6187
|
.$type<Record<string, SessionMcpApprovalPolicy>>()
|
|
@@ -4698,7 +6210,7 @@ export const sessionTurnAttempts = pgTable(
|
|
|
4698
6210
|
name: "session_turn_attempts_workspace_session_fk",
|
|
4699
6211
|
columns: [table.workspaceId, table.sessionId],
|
|
4700
6212
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
4701
|
-
}).onDelete("
|
|
6213
|
+
}).onDelete("cascade"),
|
|
4702
6214
|
workspaceTurn: foreignKey({
|
|
4703
6215
|
name: "session_turn_attempts_workspace_turn_fk",
|
|
4704
6216
|
columns: [table.workspaceId, table.turnId],
|
|
@@ -4782,6 +6294,202 @@ export const sessionTurnAttempts = pgTable(
|
|
|
4782
6294
|
}),
|
|
4783
6295
|
);
|
|
4784
6296
|
|
|
6297
|
+
// Per-turn startup SLO checkpoint ledger (migration 0318). One row per
|
|
6298
|
+
// (turn, milestone, outcome); the transaction whose
|
|
6299
|
+
// `insert ... on conflict do nothing returning` returns the row is the
|
|
6300
|
+
// canonical inserter and the sole metric receipt, so recovery and replay
|
|
6301
|
+
// conflict without re-reading the turn's session_events. `pre_ledger_history`
|
|
6302
|
+
// rows seal a turn whose startup predates the ledger.
|
|
6303
|
+
export const sessionTurnStartupMilestones = pgTable(
|
|
6304
|
+
"session_turn_startup_milestones",
|
|
6305
|
+
{
|
|
6306
|
+
accountId: uuid("account_id").notNull(),
|
|
6307
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6308
|
+
sessionId: uuid("session_id").notNull(),
|
|
6309
|
+
turnId: uuid("turn_id").notNull(),
|
|
6310
|
+
milestone: text("milestone").notNull(),
|
|
6311
|
+
outcome: text("outcome").notNull(),
|
|
6312
|
+
canonicalSource: text("canonical_source").notNull(),
|
|
6313
|
+
eventId: uuid("event_id"),
|
|
6314
|
+
occurredAt: timestamp("occurred_at", { withTimezone: true }),
|
|
6315
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6316
|
+
},
|
|
6317
|
+
(table) => ({
|
|
6318
|
+
pk: primaryKey({
|
|
6319
|
+
name: "session_turn_startup_milestones_pkey",
|
|
6320
|
+
columns: [table.workspaceId, table.turnId, table.milestone, table.outcome],
|
|
6321
|
+
}),
|
|
6322
|
+
workspaceAccount: foreignKey({
|
|
6323
|
+
name: "session_turn_startup_milestones_workspace_account_fk",
|
|
6324
|
+
columns: [table.workspaceId, table.accountId],
|
|
6325
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
6326
|
+
}).onDelete("cascade"),
|
|
6327
|
+
workspaceSession: foreignKey({
|
|
6328
|
+
name: "session_turn_startup_milestones_workspace_session_fk",
|
|
6329
|
+
columns: [table.workspaceId, table.sessionId],
|
|
6330
|
+
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
6331
|
+
}).onDelete("cascade"),
|
|
6332
|
+
workspaceTurn: foreignKey({
|
|
6333
|
+
name: "session_turn_startup_milestones_workspace_turn_fk",
|
|
6334
|
+
columns: [table.workspaceId, table.turnId],
|
|
6335
|
+
foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
|
|
6336
|
+
}).onDelete("cascade"),
|
|
6337
|
+
workspaceSessionIndex: index("session_turn_startup_milestones_workspace_session_idx").on(
|
|
6338
|
+
table.workspaceId,
|
|
6339
|
+
table.sessionId,
|
|
6340
|
+
),
|
|
6341
|
+
milestoneCheck: check(
|
|
6342
|
+
"session_turn_startup_milestones_milestone_chk",
|
|
6343
|
+
sql`${table.milestone} in ('queue', 'provider_dispatch', 'first_byte')`,
|
|
6344
|
+
),
|
|
6345
|
+
outcomeCheck: check(
|
|
6346
|
+
"session_turn_startup_milestones_outcome_chk",
|
|
6347
|
+
sql`${table.outcome} in ('completed', 'failed')`,
|
|
6348
|
+
),
|
|
6349
|
+
checkpointCheck: check(
|
|
6350
|
+
"session_turn_startup_milestones_checkpoint_chk",
|
|
6351
|
+
sql`${table.outcome} = 'completed' or ${table.milestone} = 'first_byte'`,
|
|
6352
|
+
),
|
|
6353
|
+
canonicalSourceCheck: check(
|
|
6354
|
+
"session_turn_startup_milestones_canonical_source_chk",
|
|
6355
|
+
sql`(${table.canonicalSource} = 'inserted_event' and ${table.eventId} is not null and ${table.occurredAt} is not null) or (${table.canonicalSource} = 'pre_ledger_history' and ${table.outcome} = 'completed' and ${table.eventId} is null and ${table.occurredAt} is null)`,
|
|
6356
|
+
),
|
|
6357
|
+
}),
|
|
6358
|
+
);
|
|
6359
|
+
|
|
6360
|
+
// Credential-free authority captured with the accepted logical turn. Runtime
|
|
6361
|
+
// credential resolution loads this canonical row by exact turn + tool surface;
|
|
6362
|
+
// a caller-provided snapshot is never authority.
|
|
6363
|
+
export const turnConnectionAuthoritySnapshots = pgTable(
|
|
6364
|
+
"turn_connection_authority_snapshots",
|
|
6365
|
+
{
|
|
6366
|
+
accountId: uuid("account_id").notNull(),
|
|
6367
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6368
|
+
sessionId: uuid("session_id").notNull(),
|
|
6369
|
+
turnId: uuid("turn_id").notNull(),
|
|
6370
|
+
serverId: text("server_id").notNull(),
|
|
6371
|
+
connectionId: uuid("connection_id").notNull(),
|
|
6372
|
+
connectionGeneration: bigint("connection_generation", { mode: "number" }).notNull(),
|
|
6373
|
+
originWorkspaceId: uuid("origin_workspace_id").notNull(),
|
|
6374
|
+
providerDomain: text("provider_domain").notNull(),
|
|
6375
|
+
connectionKind: text("connection_kind").notNull(),
|
|
6376
|
+
authorityScope: text("authority_scope").notNull(),
|
|
6377
|
+
authoritySource: text("authority_source").notNull(),
|
|
6378
|
+
ownerSubjectId: text("owner_subject_id"),
|
|
6379
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
6380
|
+
membershipAuthorizationRevision: bigint("membership_authorization_revision", {
|
|
6381
|
+
mode: "number",
|
|
6382
|
+
}),
|
|
6383
|
+
authorityId: uuid("authority_id"),
|
|
6384
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }),
|
|
6385
|
+
grantId: uuid("grant_id"),
|
|
6386
|
+
grantGeneration: bigint("grant_generation", { mode: "number" }),
|
|
6387
|
+
grantMode: text("grant_mode"),
|
|
6388
|
+
grantContext: text("grant_context"),
|
|
6389
|
+
grantSessionId: uuid("grant_session_id"),
|
|
6390
|
+
grantAuthorityEpoch: integer("grant_authority_epoch"),
|
|
6391
|
+
sessionVisibility: text("session_visibility").notNull(),
|
|
6392
|
+
sessionAuthorityEpoch: integer("session_authority_epoch").notNull(),
|
|
6393
|
+
canonicalSnapshot: jsonb("canonical_snapshot").$type<Record<string, unknown>>().notNull(),
|
|
6394
|
+
snapshotDigest: bytea("snapshot_digest").notNull(),
|
|
6395
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6396
|
+
},
|
|
6397
|
+
(table) => ({
|
|
6398
|
+
identity: primaryKey({ columns: [table.turnId, table.serverId] }),
|
|
6399
|
+
turn: foreignKey({
|
|
6400
|
+
name: "turn_connection_authority_turn_fk",
|
|
6401
|
+
columns: [table.workspaceId, table.turnId],
|
|
6402
|
+
foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
|
|
6403
|
+
}).onDelete("cascade"),
|
|
6404
|
+
connection: foreignKey({
|
|
6405
|
+
name: "turn_connection_authority_connection_fk",
|
|
6406
|
+
columns: [table.connectionId],
|
|
6407
|
+
foreignColumns: [connections.id],
|
|
6408
|
+
}).onDelete("restrict"),
|
|
6409
|
+
membership: foreignKey({
|
|
6410
|
+
name: "turn_connection_authority_membership_fk",
|
|
6411
|
+
columns: [table.ownerOrganizationMembershipId, table.accountId],
|
|
6412
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
6413
|
+
}).onDelete("restrict"),
|
|
6414
|
+
authority: foreignKey({
|
|
6415
|
+
name: "turn_connection_authority_authority_fk",
|
|
6416
|
+
columns: [table.authorityId, table.accountId],
|
|
6417
|
+
foreignColumns: [
|
|
6418
|
+
organizationUserResourceAuthorities.id,
|
|
6419
|
+
organizationUserResourceAuthorities.accountId,
|
|
6420
|
+
],
|
|
6421
|
+
}).onDelete("restrict"),
|
|
6422
|
+
grant: foreignKey({
|
|
6423
|
+
name: "turn_connection_authority_grant_fk",
|
|
6424
|
+
columns: [table.grantId, table.accountId],
|
|
6425
|
+
foreignColumns: [organizationUserResourceGrants.id, organizationUserResourceGrants.accountId],
|
|
6426
|
+
}).onDelete("restrict"),
|
|
6427
|
+
connectionLookup: index("turn_connection_authority_connection_idx").on(
|
|
6428
|
+
table.accountId,
|
|
6429
|
+
table.connectionId,
|
|
6430
|
+
table.turnId,
|
|
6431
|
+
table.serverId,
|
|
6432
|
+
),
|
|
6433
|
+
serverValid: check(
|
|
6434
|
+
"turn_connection_authority_server_check",
|
|
6435
|
+
sql`octet_length(${table.serverId}) between 1 and 256`,
|
|
6436
|
+
),
|
|
6437
|
+
generationValid: check(
|
|
6438
|
+
"turn_connection_authority_generation_check",
|
|
6439
|
+
sql`${table.connectionGeneration} > 0 and ${table.sessionAuthorityEpoch} > 0`,
|
|
6440
|
+
),
|
|
6441
|
+
}),
|
|
6442
|
+
);
|
|
6443
|
+
|
|
6444
|
+
// One metadata-only authorization fact per caller-preallocated physical
|
|
6445
|
+
// provider request. No credential, header, body, provider response, or content
|
|
6446
|
+
// is retained in this table.
|
|
6447
|
+
export const connectionUseAuditFacts = pgTable(
|
|
6448
|
+
"connection_use_audit_facts",
|
|
6449
|
+
{
|
|
6450
|
+
physicalRequestId: uuid("physical_request_id").primaryKey(),
|
|
6451
|
+
usePhase: text("use_phase").notNull(),
|
|
6452
|
+
requestDigest: bytea("request_digest").notNull(),
|
|
6453
|
+
accountId: uuid("account_id").notNull(),
|
|
6454
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6455
|
+
sessionId: uuid("session_id").notNull(),
|
|
6456
|
+
turnId: uuid("turn_id").notNull(),
|
|
6457
|
+
attemptId: uuid("attempt_id").notNull(),
|
|
6458
|
+
executionGeneration: integer("execution_generation").notNull(),
|
|
6459
|
+
serverId: text("server_id").notNull(),
|
|
6460
|
+
connectionId: uuid("connection_id"),
|
|
6461
|
+
connectionGeneration: bigint("connection_generation", { mode: "number" }),
|
|
6462
|
+
authorityScope: text("authority_scope"),
|
|
6463
|
+
ownerSubjectId: text("owner_subject_id"),
|
|
6464
|
+
authorityId: uuid("authority_id"),
|
|
6465
|
+
grantId: uuid("grant_id"),
|
|
6466
|
+
initiatorKind: text("initiator_kind"),
|
|
6467
|
+
initiatorSubjectId: text("initiator_subject_id"),
|
|
6468
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id"),
|
|
6469
|
+
authorityEpoch: integer("authority_epoch"),
|
|
6470
|
+
authorityVisibility: text("authority_visibility"),
|
|
6471
|
+
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6472
|
+
outcome: text("outcome").notNull(),
|
|
6473
|
+
denialReason: text("denial_reason"),
|
|
6474
|
+
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6475
|
+
},
|
|
6476
|
+
(table) => ({
|
|
6477
|
+
attempt: index("connection_use_audit_attempt_idx").on(
|
|
6478
|
+
table.workspaceId,
|
|
6479
|
+
table.attemptId,
|
|
6480
|
+
table.occurredAt,
|
|
6481
|
+
),
|
|
6482
|
+
shapeValid: check(
|
|
6483
|
+
"connection_use_audit_shape_check",
|
|
6484
|
+
sql`octet_length(${table.serverId}) between 1 and 256
|
|
6485
|
+
and octet_length(${table.requestDigest}) = 32
|
|
6486
|
+
and ${table.executionGeneration} > 0
|
|
6487
|
+
and ${table.usePhase} in ('credential_resolution', 'provider_request')
|
|
6488
|
+
and ${table.outcome} in ('authorized', 'denied')`,
|
|
6489
|
+
),
|
|
6490
|
+
}),
|
|
6491
|
+
);
|
|
6492
|
+
|
|
4785
6493
|
// Immutable executable tool universe admitted to one exact attempt. Model MCP
|
|
4786
6494
|
// and sandbox Codemode use the same digest and opaque identities from this row.
|
|
4787
6495
|
export const sessionAttemptToolCatalogs = pgTable(
|
|
@@ -5185,7 +6893,7 @@ export const sessionCommandReceipts = pgTable(
|
|
|
5185
6893
|
name: "session_command_receipts_target_session_fk",
|
|
5186
6894
|
columns: [table.workspaceId, table.targetSessionId],
|
|
5187
6895
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
5188
|
-
}).onDelete("
|
|
6896
|
+
}).onDelete("cascade"),
|
|
5189
6897
|
targetTurn: foreignKey({
|
|
5190
6898
|
name: "session_command_receipts_target_turn_fk",
|
|
5191
6899
|
columns: [table.workspaceId, table.targetTurnId],
|
|
@@ -5251,7 +6959,7 @@ export const workspaceControlEvents = pgTable(
|
|
|
5251
6959
|
name: "workspace_control_events_root_session_fk",
|
|
5252
6960
|
columns: [table.workspaceId, table.rootSessionId],
|
|
5253
6961
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
5254
|
-
}).onDelete("
|
|
6962
|
+
}).onDelete("cascade"),
|
|
5255
6963
|
workspaceRevision: uniqueIndex("workspace_control_events_workspace_revision_uq").on(
|
|
5256
6964
|
table.workspaceId,
|
|
5257
6965
|
table.revision,
|
|
@@ -5299,7 +7007,7 @@ export const sessionAttemptInterruptions = pgTable(
|
|
|
5299
7007
|
name: "session_attempt_interruptions_workspace_session_fk",
|
|
5300
7008
|
columns: [table.workspaceId, table.sessionId],
|
|
5301
7009
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
5302
|
-
}).onDelete("
|
|
7010
|
+
}).onDelete("cascade"),
|
|
5303
7011
|
operation: foreignKey({
|
|
5304
7012
|
name: "session_attempt_interruptions_operation_fk",
|
|
5305
7013
|
columns: [table.workspaceId, table.operationId],
|
|
@@ -5319,7 +7027,7 @@ export const sessionAttemptInterruptions = pgTable(
|
|
|
5319
7027
|
.where(sql`${table.state} in ('pending', 'delivered', 'acknowledged')`),
|
|
5320
7028
|
kindValid: check(
|
|
5321
7029
|
"session_attempt_interruptions_kind_check",
|
|
5322
|
-
sql`${table.kind} in ('session_pause', 'workspace_pause', 'steer', 'maintenance')`,
|
|
7030
|
+
sql`${table.kind} in ('session_pause', 'workspace_pause', 'steer', 'maintenance', 'authority_change', 'organization_membership_revoked')`,
|
|
5323
7031
|
),
|
|
5324
7032
|
stateValid: check(
|
|
5325
7033
|
"session_attempt_interruptions_state_check",
|
|
@@ -5459,6 +7167,9 @@ export const sessionSystemUpdates = pgTable(
|
|
|
5459
7167
|
.$type<XaiProviderAccountAuthoritySnapshotV1>()
|
|
5460
7168
|
.notNull()
|
|
5461
7169
|
.default(WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1),
|
|
7170
|
+
// Private scheduled-occurrence authority linkage. Public update/event
|
|
7171
|
+
// projections intentionally omit this producer identifier.
|
|
7172
|
+
scheduledTaskRunId: uuid("scheduled_task_run_id"),
|
|
5462
7173
|
// pending is visible queue truth; delivered means its exact model-memory
|
|
5463
7174
|
// batch was durably claimed. Terminal cancellation/supersession is explicit.
|
|
5464
7175
|
state: text("state").notNull().default("pending"),
|
|
@@ -5474,7 +7185,7 @@ export const sessionSystemUpdates = pgTable(
|
|
|
5474
7185
|
(table) => ({
|
|
5475
7186
|
kindValid: check(
|
|
5476
7187
|
"system_updates_kind_check",
|
|
5477
|
-
sql`${table.kind} in ('scheduled_occurrence', 'goal_continuation', 'agent_message', 'agent_steer_instruction', 'child_terminal_result', 'media_generation_result')`,
|
|
7188
|
+
sql`${table.kind} in ('scheduled_occurrence', 'goal_continuation', 'agent_message', 'agent_steer_instruction', 'child_terminal_result', 'media_generation_result', 'child_requires_action', 'child_requires_action_resolved', 'child_paused', 'child_waiting_capacity', 'child_progress')`,
|
|
5478
7189
|
),
|
|
5479
7190
|
payloadKindValid: check(
|
|
5480
7191
|
"system_updates_payload_kind_check",
|
|
@@ -5495,6 +7206,11 @@ export const sessionSystemUpdates = pgTable(
|
|
|
5495
7206
|
table.state,
|
|
5496
7207
|
table.createdAt,
|
|
5497
7208
|
),
|
|
7209
|
+
// Producer-side supersession / resolution of one child's pending notices
|
|
7210
|
+
// of one kind on the parent (migration 0325).
|
|
7211
|
+
pendingKindSource: index("session_system_updates_pending_kind_source_idx")
|
|
7212
|
+
.on(table.workspaceId, table.sessionId, table.kind, table.sourceId)
|
|
7213
|
+
.where(sql`${table.state} = 'pending'`),
|
|
5498
7214
|
onePendingSteer: uniqueIndex("session_system_updates_one_pending_steer_idx")
|
|
5499
7215
|
.on(table.workspaceId, table.sessionId)
|
|
5500
7216
|
.where(sql`${table.kind} = 'agent_steer_instruction' and ${table.state} = 'pending'`),
|
|
@@ -5561,11 +7277,11 @@ export const sessionSystemUpdateOutbox = pgTable(
|
|
|
5561
7277
|
(table) => ({
|
|
5562
7278
|
kindValid: check(
|
|
5563
7279
|
"system_update_outbox_kind_check",
|
|
5564
|
-
sql`${table.kind}
|
|
7280
|
+
sql`${table.kind} in ('child_terminal_result', 'child_requires_action', 'child_requires_action_resolved', 'child_paused', 'child_waiting_capacity', 'child_progress')`,
|
|
5565
7281
|
),
|
|
5566
7282
|
payloadKindValid: check(
|
|
5567
7283
|
"system_update_outbox_payload_kind_check",
|
|
5568
|
-
sql`${table.payload} ->> 'type' =
|
|
7284
|
+
sql`${table.payload} ->> 'type' = ${table.kind}`,
|
|
5569
7285
|
),
|
|
5570
7286
|
dedupe: uniqueIndex("session_system_update_outbox_dedupe_uq").on(
|
|
5571
7287
|
table.workspaceId,
|
|
@@ -5647,6 +7363,7 @@ export const sessionGoals = pgTable(
|
|
|
5647
7363
|
status: text("status").notNull().default("active"), // active | paused | completed
|
|
5648
7364
|
text: text("text").notNull(),
|
|
5649
7365
|
successCriteria: text("success_criteria"),
|
|
7366
|
+
rootConstraints: jsonb("root_constraints").$type<string[]>().notNull().default([]),
|
|
5650
7367
|
evidence: text("evidence"), // set by goal_complete
|
|
5651
7368
|
rationale: text("rationale"), // set by goal_pause
|
|
5652
7369
|
pausedReason: text("paused_reason"), // agent | user_pause | api | no_progress | max_auto_continuations | limits
|
|
@@ -5680,6 +7397,15 @@ export const sessionGoals = pgTable(
|
|
|
5680
7397
|
})
|
|
5681
7398
|
.notNull()
|
|
5682
7399
|
.default(0),
|
|
7400
|
+
// Agent-declared continuation hold (`goal_wait`, migration 0317). Honored
|
|
7401
|
+
// only while `continuationHoldTurnId` is still the latest finished turn and
|
|
7402
|
+
// the deadline has not passed; it never consumes the wake/observed ledger.
|
|
7403
|
+
// Any newer finished turn, a passed deadline, or a goal mutation clears all
|
|
7404
|
+
// four columns together.
|
|
7405
|
+
continuationHoldTurnId: uuid("continuation_hold_turn_id"),
|
|
7406
|
+
continuationHoldUntil: timestamp("continuation_hold_until", { withTimezone: true }),
|
|
7407
|
+
continuationHoldReason: text("continuation_hold_reason"),
|
|
7408
|
+
continuationHoldSetAt: timestamp("continuation_hold_set_at", { withTimezone: true }),
|
|
5683
7409
|
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
|
|
5684
7410
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5685
7411
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -5698,6 +7424,10 @@ export const sessionGoals = pgTable(
|
|
|
5698
7424
|
"session_goals_continuation_revision_check",
|
|
5699
7425
|
sql`${table.continuationWakeRevision} >= 0 and ${table.continuationObservedRevision} >= 0 and ${table.continuationObservedRevision} <= ${table.continuationWakeRevision} and ${table.continuationWakeRevision} <= 9007199254740991 and ${table.continuationObservedRevision} <= 9007199254740991`,
|
|
5700
7426
|
),
|
|
7427
|
+
continuationHoldValid: check(
|
|
7428
|
+
"session_goals_continuation_hold_check",
|
|
7429
|
+
sql`(${table.continuationHoldTurnId} is null and ${table.continuationHoldUntil} is null and ${table.continuationHoldReason} is null and ${table.continuationHoldSetAt} is null) or (${table.continuationHoldTurnId} is not null and ${table.continuationHoldUntil} is not null and ${table.continuationHoldSetAt} is not null and (${table.continuationHoldReason} is null or octet_length(${table.continuationHoldReason}) <= 2048))`,
|
|
7430
|
+
),
|
|
5701
7431
|
}),
|
|
5702
7432
|
);
|
|
5703
7433
|
|
|
@@ -5720,12 +7450,14 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5720
7450
|
resultObjectiveRevision: integer("result_objective_revision"),
|
|
5721
7451
|
text: text("text").notNull(),
|
|
5722
7452
|
successCriteria: text("success_criteria"),
|
|
7453
|
+
rootConstraints: jsonb("root_constraints").$type<string[]>().notNull().default([]),
|
|
5723
7454
|
mutationPolicy: text("mutation_policy").$type<SessionGoalMutationPolicy>().notNull(),
|
|
5724
7455
|
rationale: text("rationale").notNull(),
|
|
5725
7456
|
actor: text("actor").$type<"agent" | "api" | "scheduled_task">().notNull(),
|
|
5726
7457
|
actorTurnId: uuid("actor_turn_id"),
|
|
5727
7458
|
actorAttemptId: uuid("actor_attempt_id"),
|
|
5728
7459
|
proposalId: uuid("proposal_id"),
|
|
7460
|
+
rollbackOfRevisionId: uuid("rollback_of_revision_id"),
|
|
5729
7461
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5730
7462
|
},
|
|
5731
7463
|
(table) => ({
|
|
@@ -5754,6 +7486,11 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5754
7486
|
columns: [table.workspaceId, table.proposalId],
|
|
5755
7487
|
foreignColumns: [table.workspaceId, table.id],
|
|
5756
7488
|
}).onDelete("restrict"),
|
|
7489
|
+
rollbackOfRevision: foreignKey({
|
|
7490
|
+
name: "session_goal_revisions_rollback_of_revision_fk",
|
|
7491
|
+
columns: [table.workspaceId, table.rollbackOfRevisionId],
|
|
7492
|
+
foreignColumns: [table.workspaceId, table.id],
|
|
7493
|
+
}).onDelete("restrict"),
|
|
5757
7494
|
appliedRevision: uniqueIndex("session_goal_revisions_applied_revision_uq")
|
|
5758
7495
|
.on(table.workspaceId, table.goalId, table.resultObjectiveRevision)
|
|
5759
7496
|
.where(sql`${table.disposition} = 'applied'`),
|
|
@@ -5763,6 +7500,14 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5763
7500
|
table.createdAt,
|
|
5764
7501
|
table.id,
|
|
5765
7502
|
),
|
|
7503
|
+
proposalDecision: uniqueIndex("session_goal_revisions_proposal_decision_uq")
|
|
7504
|
+
.on(table.workspaceId, table.proposalId)
|
|
7505
|
+
.where(
|
|
7506
|
+
sql`${table.proposalId} is not null and ${table.disposition} in ('applied', 'rejected')`,
|
|
7507
|
+
),
|
|
7508
|
+
rollbackRequest: uniqueIndex("session_goal_revisions_rollback_request_uq")
|
|
7509
|
+
.on(table.workspaceId, table.goalId, table.rollbackOfRevisionId, table.baseObjectiveRevision)
|
|
7510
|
+
.where(sql`${table.disposition} = 'applied' and ${table.rollbackOfRevisionId} is not null`),
|
|
5766
7511
|
dispositionValid: check(
|
|
5767
7512
|
"session_goal_revisions_disposition_chk",
|
|
5768
7513
|
sql`${table.disposition} in ('applied', 'proposed', 'rejected')`,
|
|
@@ -5780,6 +7525,12 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5780
7525
|
sql`(${table.disposition} = 'applied' and ${table.resultObjectiveRevision} = ${table.baseObjectiveRevision} + 1)
|
|
5781
7526
|
or (${table.disposition} in ('proposed', 'rejected') and ${table.resultObjectiveRevision} is null)`,
|
|
5782
7527
|
),
|
|
7528
|
+
lineageShape: check(
|
|
7529
|
+
"session_goal_revisions_lineage_shape_chk",
|
|
7530
|
+
sql`(${table.disposition} = 'proposed' and ${table.proposalId} is null and ${table.rollbackOfRevisionId} is null)
|
|
7531
|
+
or (${table.disposition} = 'rejected' and ${table.proposalId} is not null and ${table.rollbackOfRevisionId} is null)
|
|
7532
|
+
or (${table.disposition} = 'applied' and not (${table.proposalId} is not null and ${table.rollbackOfRevisionId} is not null))`,
|
|
7533
|
+
),
|
|
5783
7534
|
}),
|
|
5784
7535
|
);
|
|
5785
7536
|
|
|
@@ -6256,6 +8007,12 @@ export const sessionPendingToolCalls = pgTable(
|
|
|
6256
8007
|
callType: text("call_type").notNull(),
|
|
6257
8008
|
callItem: losslessJsonb("call_item").$type<Record<string, unknown>>().notNull(),
|
|
6258
8009
|
callItemCodecVersion: losslessCodecVersion("call_item_codec_version"),
|
|
8010
|
+
interruptionKind: text("interruption_kind"),
|
|
8011
|
+
tiedReasoningItems: losslessJsonb("tied_reasoning_items")
|
|
8012
|
+
.$type<Array<Record<string, unknown>>>()
|
|
8013
|
+
.notNull()
|
|
8014
|
+
.default([]),
|
|
8015
|
+
tiedReasoningItemsCodecVersion: losslessCodecVersion("tied_reasoning_items_codec_version"),
|
|
6259
8016
|
modelToolOutputTruncationTokens: integer("model_tool_output_truncation_tokens"),
|
|
6260
8017
|
resultItem: losslessJsonb("result_item").$type<Record<string, unknown>>(),
|
|
6261
8018
|
resultItemCodecVersion: losslessCodecVersion("result_item_codec_version"),
|
|
@@ -6280,6 +8037,14 @@ export const sessionPendingToolCalls = pgTable(
|
|
|
6280
8037
|
table.sessionId,
|
|
6281
8038
|
table.turnId,
|
|
6282
8039
|
),
|
|
8040
|
+
interruptionKindValid: check(
|
|
8041
|
+
"session_pending_tool_calls_interruption_kind_chk",
|
|
8042
|
+
sql`${table.interruptionKind} is null or ${table.interruptionKind} in ('human_input', 'approval', 'interaction_intervention')`,
|
|
8043
|
+
),
|
|
8044
|
+
tiedReasoningItemsArray: check(
|
|
8045
|
+
"session_pending_tool_calls_tied_reasoning_items_chk",
|
|
8046
|
+
sql`jsonb_typeof(${table.tiedReasoningItems}) = 'array'`,
|
|
8047
|
+
),
|
|
6283
8048
|
}),
|
|
6284
8049
|
);
|
|
6285
8050
|
|
|
@@ -6718,6 +8483,11 @@ export const sandboxLeaseHolders = pgTable(
|
|
|
6718
8483
|
holderId: text("holder_id").notNull(),
|
|
6719
8484
|
// The attributing session within the (possibly shared) group.
|
|
6720
8485
|
subjectId: uuid("subject_id"),
|
|
8486
|
+
// Viewer holders only (0281): the authenticated viewer subject and the
|
|
8487
|
+
// session authority epoch observed at attach - identities and epochs
|
|
8488
|
+
// only, mirrored into the scoped stream token's claims.
|
|
8489
|
+
viewerSubjectId: text("viewer_subject_id"),
|
|
8490
|
+
viewerAuthorityEpoch: integer("viewer_authority_epoch"),
|
|
6721
8491
|
lastHeartbeatAt: timestamp("last_heartbeat_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6722
8492
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6723
8493
|
},
|
|
@@ -6739,6 +8509,14 @@ export const sandboxLeaseHolders = pgTable(
|
|
|
6739
8509
|
|
|
6740
8510
|
export const sandboxWorkspaceMutationActorKindValues = ["turn", "direct", "process"] as const;
|
|
6741
8511
|
export const sandboxWorkspaceMutationHolderKindValues = ["turn", "direct", "process"] as const;
|
|
8512
|
+
// The causal principal behind an admitted workspace writer. `subject`/`service`
|
|
8513
|
+
// are the canonical `session_turns` initiator vocabulary; `legacy_unattributed`
|
|
8514
|
+
// exists only for rows written before migration 0277 recorded any authority.
|
|
8515
|
+
export const sandboxWorkspaceMutationInitiatorKindValues = [
|
|
8516
|
+
"subject",
|
|
8517
|
+
"service",
|
|
8518
|
+
"legacy_unattributed",
|
|
8519
|
+
] as const;
|
|
6742
8520
|
|
|
6743
8521
|
// Durable admission ledger for every provider operation that may mutate a
|
|
6744
8522
|
// persistable /workspace. The row is inserted atomically with the lease's
|
|
@@ -6783,6 +8561,29 @@ export const sandboxWorkspaceMutationAdmissions = pgTable(
|
|
|
6783
8561
|
routeEpoch: integer("route_epoch").notNull(),
|
|
6784
8562
|
workspaceGeneration: integer("workspace_generation").notNull(),
|
|
6785
8563
|
operation: text("operation").notNull(),
|
|
8564
|
+
// Exact authority admitted with this operation (migration 0277). Identities
|
|
8565
|
+
// and epochs only, never a secret value. `legacy_unattributed` marks a
|
|
8566
|
+
// pre-0277 `direct`/`process` row whose authority was never recorded; a
|
|
8567
|
+
// post-0277 writer never produces it and new admission refuses it.
|
|
8568
|
+
initiatorKind: text("initiator_kind", {
|
|
8569
|
+
enum: sandboxWorkspaceMutationInitiatorKindValues,
|
|
8570
|
+
})
|
|
8571
|
+
.notNull()
|
|
8572
|
+
.default("legacy_unattributed"),
|
|
8573
|
+
initiatorSubjectId: text("initiator_subject_id").notNull().default("unattributed-legacy"),
|
|
8574
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id"),
|
|
8575
|
+
// The grant identity that authorized the causal human, plus the
|
|
8576
|
+
// authorization revision observed at admission. The revision is audit
|
|
8577
|
+
// evidence: a role change is not a revocation and must not fence a writer.
|
|
8578
|
+
initiatorOrganizationMembershipId: uuid("initiator_organization_membership_id"),
|
|
8579
|
+
initiatorAuthorizationRevision: bigint("initiator_authorization_revision", { mode: "number" }),
|
|
8580
|
+
// Session tenancy authority observed when the operation was admitted; the
|
|
8581
|
+
// same triple `session_turn_attempts` freezes for a turn.
|
|
8582
|
+
authorityEpoch: integer("authority_epoch"),
|
|
8583
|
+
authorityVisibility: text("authority_visibility", {
|
|
8584
|
+
enum: ["user_private", "workspace_shared"],
|
|
8585
|
+
}),
|
|
8586
|
+
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6786
8587
|
providerOutcome: text("provider_outcome", {
|
|
6787
8588
|
enum: ["resolved", "rejected", "retained"],
|
|
6788
8589
|
}),
|
|
@@ -6833,6 +8634,65 @@ export const sandboxWorkspaceMutationAdmissions = pgTable(
|
|
|
6833
8634
|
table.actorKind,
|
|
6834
8635
|
table.actorId,
|
|
6835
8636
|
),
|
|
8637
|
+
initiatorMembership: foreignKey({
|
|
8638
|
+
name: "sandbox_workspace_mutation_admissions_initiator_membership_fk",
|
|
8639
|
+
columns: [table.initiatorOrganizationMembershipId, table.accountId],
|
|
8640
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8641
|
+
}).onDelete("restrict"),
|
|
8642
|
+
authorityOwnerMembership: foreignKey({
|
|
8643
|
+
name: "sandbox_workspace_mutation_admissions_authority_owner_fk",
|
|
8644
|
+
columns: [table.authorityOwnerOrganizationMembershipId, table.accountId],
|
|
8645
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8646
|
+
}).onDelete("restrict"),
|
|
8647
|
+
initiator: index("sandbox_workspace_mutation_admissions_initiator_idx")
|
|
8648
|
+
.on(table.accountId, table.initiatorOrganizationMembershipId)
|
|
8649
|
+
.where(sql`${table.settledAt} is null`),
|
|
8650
|
+
initiatorValid: check(
|
|
8651
|
+
"sandbox_workspace_mutation_admissions_initiator_check",
|
|
8652
|
+
sql`(
|
|
8653
|
+
${table.initiatorKind} = 'legacy_unattributed'
|
|
8654
|
+
and ${table.initiatorSubjectId} = 'unattributed-legacy'
|
|
8655
|
+
and ${table.initiatingHumanSubjectId} is null
|
|
8656
|
+
and ${table.initiatorOrganizationMembershipId} is null
|
|
8657
|
+
and ${table.initiatorAuthorizationRevision} is null
|
|
8658
|
+
) or (
|
|
8659
|
+
${table.initiatorKind} in ('subject', 'service')
|
|
8660
|
+
and length(btrim(${table.initiatorSubjectId})) between 1 and 1024
|
|
8661
|
+
and ${table.initiatorSubjectId} <> 'unattributed-legacy'
|
|
8662
|
+
and (
|
|
8663
|
+
${table.initiatingHumanSubjectId} is null
|
|
8664
|
+
or length(btrim(${table.initiatingHumanSubjectId})) between 1 and 1024
|
|
8665
|
+
)
|
|
8666
|
+
and (
|
|
8667
|
+
${table.initiatorOrganizationMembershipId} is null
|
|
8668
|
+
or ${table.initiatingHumanSubjectId} is not null
|
|
8669
|
+
)
|
|
8670
|
+
and (
|
|
8671
|
+
${table.initiatorAuthorizationRevision} is null
|
|
8672
|
+
or (
|
|
8673
|
+
${table.initiatorAuthorizationRevision} > 0
|
|
8674
|
+
and ${table.initiatorOrganizationMembershipId} is not null
|
|
8675
|
+
)
|
|
8676
|
+
)
|
|
8677
|
+
)`,
|
|
8678
|
+
),
|
|
8679
|
+
tenancyValid: check(
|
|
8680
|
+
"sandbox_workspace_mutation_admissions_tenancy_check",
|
|
8681
|
+
sql`(
|
|
8682
|
+
${table.authorityEpoch} is null
|
|
8683
|
+
and ${table.authorityVisibility} is null
|
|
8684
|
+
and ${table.authorityOwnerOrganizationMembershipId} is null
|
|
8685
|
+
) or (
|
|
8686
|
+
${table.authorityEpoch} is not null
|
|
8687
|
+
and ${table.authorityVisibility} is not null
|
|
8688
|
+
and ${table.authorityEpoch} > 0
|
|
8689
|
+
and ${table.authorityVisibility} in ('user_private', 'workspace_shared')
|
|
8690
|
+
and (
|
|
8691
|
+
${table.authorityVisibility} <> 'user_private'
|
|
8692
|
+
or ${table.authorityOwnerOrganizationMembershipId} is not null
|
|
8693
|
+
)
|
|
8694
|
+
)`,
|
|
8695
|
+
),
|
|
6836
8696
|
generationValid: check(
|
|
6837
8697
|
"sandbox_workspace_mutation_admissions_generation_check",
|
|
6838
8698
|
sql`${table.workspaceGeneration} > 0
|
|
@@ -6927,6 +8787,23 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
6927
8787
|
routeTargetId: uuid("route_target_id"),
|
|
6928
8788
|
routeEpoch: integer("route_epoch").notNull(),
|
|
6929
8789
|
providerSessionId: integer("provider_session_id").notNull(),
|
|
8790
|
+
// Authority frozen when the process was retained (migration 0277). A
|
|
8791
|
+
// `legacy_unattributed` process keeps running; only its next workspace
|
|
8792
|
+
// mutation is refused, because nothing may invent an owner for it.
|
|
8793
|
+
initiatorKind: text("initiator_kind", {
|
|
8794
|
+
enum: sandboxWorkspaceMutationInitiatorKindValues,
|
|
8795
|
+
})
|
|
8796
|
+
.notNull()
|
|
8797
|
+
.default("legacy_unattributed"),
|
|
8798
|
+
initiatorSubjectId: text("initiator_subject_id").notNull().default("unattributed-legacy"),
|
|
8799
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id"),
|
|
8800
|
+
initiatorOrganizationMembershipId: uuid("initiator_organization_membership_id"),
|
|
8801
|
+
initiatorAuthorizationRevision: bigint("initiator_authorization_revision", { mode: "number" }),
|
|
8802
|
+
authorityEpoch: integer("authority_epoch"),
|
|
8803
|
+
authorityVisibility: text("authority_visibility", {
|
|
8804
|
+
enum: ["user_private", "workspace_shared"],
|
|
8805
|
+
}),
|
|
8806
|
+
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6930
8807
|
state: text("state", { enum: sandboxRetainedProcessStateValues }).notNull().default("active"),
|
|
6931
8808
|
exitCode: integer("exit_code"),
|
|
6932
8809
|
settlementReason: text("settlement_reason"),
|
|
@@ -7009,6 +8886,68 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
7009
8886
|
activeInventory: index("sandbox_retained_processes_active_inventory_idx")
|
|
7010
8887
|
.on(table.ownerActorKind, table.workspaceId, table.ownerTurnId, table.ownerAttemptId)
|
|
7011
8888
|
.where(sql`${table.state} = 'active'`),
|
|
8889
|
+
initiatorMembership: foreignKey({
|
|
8890
|
+
name: "sandbox_retained_processes_initiator_membership_fk",
|
|
8891
|
+
columns: [table.initiatorOrganizationMembershipId, table.accountId],
|
|
8892
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8893
|
+
}).onDelete("restrict"),
|
|
8894
|
+
authorityOwnerMembership: foreignKey({
|
|
8895
|
+
name: "sandbox_retained_processes_authority_owner_fk",
|
|
8896
|
+
columns: [table.authorityOwnerOrganizationMembershipId, table.accountId],
|
|
8897
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8898
|
+
}).onDelete("restrict"),
|
|
8899
|
+
initiator: index("sandbox_retained_processes_initiator_idx")
|
|
8900
|
+
.on(table.accountId, table.initiatorOrganizationMembershipId)
|
|
8901
|
+
.where(sql`${table.state} = 'active'`),
|
|
8902
|
+
initiatingHuman: index("sandbox_retained_processes_initiating_human_idx")
|
|
8903
|
+
.on(table.accountId, table.initiatingHumanSubjectId)
|
|
8904
|
+
.where(sql`${table.state} = 'active'`),
|
|
8905
|
+
initiatorValid: check(
|
|
8906
|
+
"sandbox_retained_processes_initiator_check",
|
|
8907
|
+
sql`(
|
|
8908
|
+
${table.initiatorKind} = 'legacy_unattributed'
|
|
8909
|
+
and ${table.initiatorSubjectId} = 'unattributed-legacy'
|
|
8910
|
+
and ${table.initiatingHumanSubjectId} is null
|
|
8911
|
+
and ${table.initiatorOrganizationMembershipId} is null
|
|
8912
|
+
and ${table.initiatorAuthorizationRevision} is null
|
|
8913
|
+
) or (
|
|
8914
|
+
${table.initiatorKind} in ('subject', 'service')
|
|
8915
|
+
and length(btrim(${table.initiatorSubjectId})) between 1 and 1024
|
|
8916
|
+
and ${table.initiatorSubjectId} <> 'unattributed-legacy'
|
|
8917
|
+
and (
|
|
8918
|
+
${table.initiatingHumanSubjectId} is null
|
|
8919
|
+
or length(btrim(${table.initiatingHumanSubjectId})) between 1 and 1024
|
|
8920
|
+
)
|
|
8921
|
+
and (
|
|
8922
|
+
${table.initiatorOrganizationMembershipId} is null
|
|
8923
|
+
or ${table.initiatingHumanSubjectId} is not null
|
|
8924
|
+
)
|
|
8925
|
+
and (
|
|
8926
|
+
${table.initiatorAuthorizationRevision} is null
|
|
8927
|
+
or (
|
|
8928
|
+
${table.initiatorAuthorizationRevision} > 0
|
|
8929
|
+
and ${table.initiatorOrganizationMembershipId} is not null
|
|
8930
|
+
)
|
|
8931
|
+
)
|
|
8932
|
+
)`,
|
|
8933
|
+
),
|
|
8934
|
+
tenancyValid: check(
|
|
8935
|
+
"sandbox_retained_processes_tenancy_check",
|
|
8936
|
+
sql`(
|
|
8937
|
+
${table.authorityEpoch} is null
|
|
8938
|
+
and ${table.authorityVisibility} is null
|
|
8939
|
+
and ${table.authorityOwnerOrganizationMembershipId} is null
|
|
8940
|
+
) or (
|
|
8941
|
+
${table.authorityEpoch} is not null
|
|
8942
|
+
and ${table.authorityVisibility} is not null
|
|
8943
|
+
and ${table.authorityEpoch} > 0
|
|
8944
|
+
and ${table.authorityVisibility} in ('user_private', 'workspace_shared')
|
|
8945
|
+
and (
|
|
8946
|
+
${table.authorityVisibility} <> 'user_private'
|
|
8947
|
+
or ${table.authorityOwnerOrganizationMembershipId} is not null
|
|
8948
|
+
)
|
|
8949
|
+
)`,
|
|
8950
|
+
),
|
|
7012
8951
|
identityValid: check(
|
|
7013
8952
|
"sandbox_retained_processes_identity_check",
|
|
7014
8953
|
sql`${table.leaseEpoch} >= 0
|
|
@@ -7111,6 +9050,166 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
7111
9050
|
}),
|
|
7112
9051
|
);
|
|
7113
9052
|
|
|
9053
|
+
export const sessionBackgroundCommands = pgTable(
|
|
9054
|
+
"session_background_commands",
|
|
9055
|
+
{
|
|
9056
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
9057
|
+
accountId: uuid("account_id").notNull(),
|
|
9058
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
9059
|
+
sessionId: uuid("session_id").notNull(),
|
|
9060
|
+
provider: text("provider", { enum: ["managed", "connected_machine"] }).notNull(),
|
|
9061
|
+
state: text("state", { enum: ["running", "stopping", "exited", "lost"] })
|
|
9062
|
+
.notNull()
|
|
9063
|
+
.default("running"),
|
|
9064
|
+
retainedProcessId: uuid("retained_process_id"),
|
|
9065
|
+
controlWorkspaceId: uuid("control_workspace_id"),
|
|
9066
|
+
enrollmentId: uuid("enrollment_id"),
|
|
9067
|
+
connectionInstanceId: text("connection_instance_id"),
|
|
9068
|
+
opId: text("op_id"),
|
|
9069
|
+
commandPreview: text("command_preview").notNull().default(""),
|
|
9070
|
+
cancelRequestedAt: timestamp("cancel_requested_at", { withTimezone: true }),
|
|
9071
|
+
cancelRequestedBy: text("cancel_requested_by"),
|
|
9072
|
+
exitCode: integer("exit_code"),
|
|
9073
|
+
settlementReason: text("settlement_reason"),
|
|
9074
|
+
startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9075
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
9076
|
+
reconcileAfter: timestamp("reconcile_after", { withTimezone: true }).notNull().defaultNow(),
|
|
9077
|
+
reconcileClaimId: uuid("reconcile_claim_id"),
|
|
9078
|
+
reconcileClaimedAt: timestamp("reconcile_claimed_at", { withTimezone: true }),
|
|
9079
|
+
reconcileAttempts: integer("reconcile_attempts").notNull().default(0),
|
|
9080
|
+
lastReconcileOutcome: text("last_reconcile_outcome"),
|
|
9081
|
+
reconcileProofOutcome: text("reconcile_proof_outcome", { enum: ["exited", "lost"] }),
|
|
9082
|
+
reconcileProofExitCode: integer("reconcile_proof_exit_code"),
|
|
9083
|
+
reconcileProofReason: text("reconcile_proof_reason"),
|
|
9084
|
+
reconcileProofObservedAt: timestamp("reconcile_proof_observed_at", { withTimezone: true }),
|
|
9085
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9086
|
+
},
|
|
9087
|
+
(table) => ({
|
|
9088
|
+
workspaceAccount: foreignKey({
|
|
9089
|
+
name: "session_background_commands_workspace_fk",
|
|
9090
|
+
columns: [table.workspaceId, table.accountId],
|
|
9091
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
9092
|
+
}).onDelete("cascade"),
|
|
9093
|
+
workspaceSession: foreignKey({
|
|
9094
|
+
name: "session_background_commands_session_fk",
|
|
9095
|
+
columns: [table.workspaceId, table.sessionId],
|
|
9096
|
+
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
9097
|
+
}).onDelete("cascade"),
|
|
9098
|
+
controlWorkspaceAccount: foreignKey({
|
|
9099
|
+
name: "session_background_commands_control_workspace_fk",
|
|
9100
|
+
columns: [table.controlWorkspaceId, table.accountId],
|
|
9101
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
9102
|
+
}).onDelete("restrict"),
|
|
9103
|
+
retainedProcess: foreignKey({
|
|
9104
|
+
name: "session_background_commands_process_fk",
|
|
9105
|
+
columns: [table.retainedProcessId],
|
|
9106
|
+
foreignColumns: [sandboxRetainedProcesses.id],
|
|
9107
|
+
}).onDelete("restrict"),
|
|
9108
|
+
managedProcess: uniqueIndex("session_background_commands_process_uq")
|
|
9109
|
+
.on(table.retainedProcessId)
|
|
9110
|
+
.where(sql`${table.retainedProcessId} is not null`),
|
|
9111
|
+
connectedOp: uniqueIndex("session_background_commands_connected_op_uq")
|
|
9112
|
+
.on(table.controlWorkspaceId, table.enrollmentId, table.connectionInstanceId, table.opId)
|
|
9113
|
+
.where(sql`${table.provider} = 'connected_machine'`),
|
|
9114
|
+
activeSession: index("session_background_commands_active_session_idx")
|
|
9115
|
+
.on(table.workspaceId, table.sessionId, table.state, table.startedAt, table.id)
|
|
9116
|
+
.where(sql`${table.state} in ('running', 'stopping')`),
|
|
9117
|
+
stopping: index("session_background_commands_stopping_idx")
|
|
9118
|
+
.on(table.reconcileAfter, table.cancelRequestedAt, table.id)
|
|
9119
|
+
.where(sql`${table.state} in ('running', 'stopping')`),
|
|
9120
|
+
providerValid: check(
|
|
9121
|
+
"session_background_commands_provider_check",
|
|
9122
|
+
sql`${table.provider} in ('managed', 'connected_machine')`,
|
|
9123
|
+
),
|
|
9124
|
+
stateValid: check(
|
|
9125
|
+
"session_background_commands_state_check",
|
|
9126
|
+
sql`${table.state} in ('running', 'stopping', 'exited', 'lost')`,
|
|
9127
|
+
),
|
|
9128
|
+
providerIdentityValid: check(
|
|
9129
|
+
"session_background_commands_provider_identity_check",
|
|
9130
|
+
sql`(
|
|
9131
|
+
${table.provider} = 'managed'
|
|
9132
|
+
and ${table.retainedProcessId} is not null
|
|
9133
|
+
and ${table.controlWorkspaceId} is null
|
|
9134
|
+
and ${table.enrollmentId} is null
|
|
9135
|
+
and ${table.connectionInstanceId} is null
|
|
9136
|
+
and ${table.opId} is null
|
|
9137
|
+
) or (
|
|
9138
|
+
${table.provider} = 'connected_machine'
|
|
9139
|
+
and ${table.retainedProcessId} is null
|
|
9140
|
+
and ${table.controlWorkspaceId} is not null
|
|
9141
|
+
and ${table.enrollmentId} is not null
|
|
9142
|
+
and ${table.connectionInstanceId} is not null
|
|
9143
|
+
and octet_length(${table.connectionInstanceId}) between 1 and 128
|
|
9144
|
+
and ${table.opId} is not null
|
|
9145
|
+
and octet_length(${table.opId}) between 1 and 256
|
|
9146
|
+
)`,
|
|
9147
|
+
),
|
|
9148
|
+
lifecycleValid: check(
|
|
9149
|
+
"session_background_commands_lifecycle_check",
|
|
9150
|
+
sql`(
|
|
9151
|
+
${table.state} = 'running'
|
|
9152
|
+
and ${table.cancelRequestedAt} is null
|
|
9153
|
+
and ${table.cancelRequestedBy} is null
|
|
9154
|
+
and ${table.exitCode} is null
|
|
9155
|
+
and ${table.settlementReason} is null
|
|
9156
|
+
and ${table.settledAt} is null
|
|
9157
|
+
) or (
|
|
9158
|
+
${table.state} = 'stopping'
|
|
9159
|
+
and ${table.cancelRequestedAt} is not null
|
|
9160
|
+
and ${table.cancelRequestedBy} is not null
|
|
9161
|
+
and octet_length(btrim(${table.cancelRequestedBy})) between 1 and 1024
|
|
9162
|
+
and ${table.exitCode} is null
|
|
9163
|
+
and ${table.settlementReason} is null
|
|
9164
|
+
and ${table.settledAt} is null
|
|
9165
|
+
) or (
|
|
9166
|
+
${table.state} = 'exited'
|
|
9167
|
+
and ${table.settledAt} is not null
|
|
9168
|
+
and octet_length(btrim(${table.settlementReason})) between 1 and 512
|
|
9169
|
+
) or (
|
|
9170
|
+
${table.state} = 'lost'
|
|
9171
|
+
and ${table.exitCode} is null
|
|
9172
|
+
and ${table.settledAt} is not null
|
|
9173
|
+
and octet_length(btrim(${table.settlementReason})) between 1 and 512
|
|
9174
|
+
)`,
|
|
9175
|
+
),
|
|
9176
|
+
previewValid: check(
|
|
9177
|
+
"session_background_commands_preview_check",
|
|
9178
|
+
sql`octet_length(${table.commandPreview}) <= 2048`,
|
|
9179
|
+
),
|
|
9180
|
+
reconcileValid: check(
|
|
9181
|
+
"session_background_commands_reconcile_check",
|
|
9182
|
+
sql`${table.reconcileAttempts} >= 0
|
|
9183
|
+
and (
|
|
9184
|
+
(${table.reconcileClaimId} is null and ${table.reconcileClaimedAt} is null)
|
|
9185
|
+
or (${table.reconcileClaimId} is not null and ${table.reconcileClaimedAt} is not null)
|
|
9186
|
+
)
|
|
9187
|
+
and (
|
|
9188
|
+
${table.lastReconcileOutcome} is null
|
|
9189
|
+
or octet_length(${table.lastReconcileOutcome}) between 1 and 64
|
|
9190
|
+
)
|
|
9191
|
+
and (
|
|
9192
|
+
(
|
|
9193
|
+
${table.reconcileProofOutcome} is null
|
|
9194
|
+
and ${table.reconcileProofExitCode} is null
|
|
9195
|
+
and ${table.reconcileProofReason} is null
|
|
9196
|
+
and ${table.reconcileProofObservedAt} is null
|
|
9197
|
+
) or (
|
|
9198
|
+
${table.reconcileProofOutcome} = 'exited'
|
|
9199
|
+
and ${table.reconcileProofExitCode} is not null
|
|
9200
|
+
and octet_length(btrim(${table.reconcileProofReason})) between 1 and 512
|
|
9201
|
+
and ${table.reconcileProofObservedAt} is not null
|
|
9202
|
+
) or (
|
|
9203
|
+
${table.reconcileProofOutcome} = 'lost'
|
|
9204
|
+
and ${table.reconcileProofExitCode} is null
|
|
9205
|
+
and octet_length(btrim(${table.reconcileProofReason})) between 1 and 512
|
|
9206
|
+
and ${table.reconcileProofObservedAt} is not null
|
|
9207
|
+
)
|
|
9208
|
+
)`,
|
|
9209
|
+
),
|
|
9210
|
+
}),
|
|
9211
|
+
);
|
|
9212
|
+
|
|
7114
9213
|
// The recording lifecycle states (P4.3). Exported so the activity + the query
|
|
7115
9214
|
// layer share one source of truth for the §3.1 state machine.
|
|
7116
9215
|
export const sessionRecordingStateValues = [
|
|
@@ -7331,6 +9430,17 @@ export const enrollmentExposureValues = ["whole-machine"] as const;
|
|
|
7331
9430
|
export const enrollmentStatusValues = ["active", "revoked"] as const;
|
|
7332
9431
|
export const enrollmentOsValues = ["linux", "macos", "windows"] as const;
|
|
7333
9432
|
export const sandboxKindValues = ["modal", "selfhosted"] as const;
|
|
9433
|
+
export const agentUpdateStatusValues = [
|
|
9434
|
+
"requested",
|
|
9435
|
+
"accepted",
|
|
9436
|
+
"waiting_for_idle",
|
|
9437
|
+
"downloading",
|
|
9438
|
+
"verifying",
|
|
9439
|
+
"applying",
|
|
9440
|
+
"restarting",
|
|
9441
|
+
"succeeded",
|
|
9442
|
+
"failed",
|
|
9443
|
+
] as const;
|
|
7334
9444
|
|
|
7335
9445
|
// One row per registered machine. The agent's ed25519 PUBLIC key IS the machine
|
|
7336
9446
|
// identity (the NATS control-plane subject the agent subscribes to maps to it).
|
|
@@ -7348,6 +9458,11 @@ export const enrollments = pgTable(
|
|
|
7348
9458
|
workspaceId: uuid("workspace_id")
|
|
7349
9459
|
.notNull()
|
|
7350
9460
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
9461
|
+
authorityScope: text("authority_scope").notNull().default("workspace"),
|
|
9462
|
+
authorityId: uuid("authority_id"),
|
|
9463
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
9464
|
+
originWorkspaceId: uuid("origin_workspace_id"),
|
|
9465
|
+
generation: bigint("generation", { mode: "number" }).notNull().default(1),
|
|
7351
9466
|
// The agent's ed25519 public key (the machine identity).
|
|
7352
9467
|
pubkey: text("pubkey").notNull(),
|
|
7353
9468
|
exposure: text("exposure", { enum: enrollmentExposureValues })
|
|
@@ -7366,13 +9481,49 @@ export const enrollments = pgTable(
|
|
|
7366
9481
|
// from every connect Hello alongside has_display.
|
|
7367
9482
|
desktopUnavailableReason: text("desktop_unavailable_reason"),
|
|
7368
9483
|
allowScreenControl: boolean("allow_screen_control").notNull().default(false),
|
|
9484
|
+
// Optional per-connection command policy. NULL is the unrestricted default.
|
|
9485
|
+
// Values remain within JavaScript's exact-integer wire range; local runner and
|
|
9486
|
+
// ancestor host policy may only tighten them at execution.
|
|
9487
|
+
operationMemoryMaxBytes: bigint("operation_memory_max_bytes", {
|
|
9488
|
+
mode: "number",
|
|
9489
|
+
}),
|
|
9490
|
+
operationMemoryHighBytes: bigint("operation_memory_high_bytes", {
|
|
9491
|
+
mode: "number",
|
|
9492
|
+
}),
|
|
9493
|
+
operationCpuMaxMillicores: bigint("operation_cpu_max_millicores", {
|
|
9494
|
+
mode: "number",
|
|
9495
|
+
}),
|
|
9496
|
+
operationPolicyRevision: integer("operation_policy_revision").notNull().default(0),
|
|
9497
|
+
operationPolicyUpdatedAt: timestamp("operation_policy_updated_at", {
|
|
9498
|
+
withTimezone: true,
|
|
9499
|
+
}),
|
|
7369
9500
|
status: text("status", { enum: enrollmentStatusValues }).notNull().default("active"),
|
|
7370
9501
|
// Credential-family fence. Existing rows/migration-era bearers are generation
|
|
7371
9502
|
// 1; every successful re-enrollment increments this atomically before a new
|
|
7372
9503
|
// bearer is signed. Auth and self-revoke require an exact row/claim match.
|
|
7373
9504
|
credentialGeneration: integer("credential_generation").notNull().default(1),
|
|
9505
|
+
// One live runner instance owns this enrollment's data-plane address at a
|
|
9506
|
+
// time. Auth-callout claims/renews the lease before NATS grants a connection;
|
|
9507
|
+
// every operational subject includes the instance id, so an older still-open
|
|
9508
|
+
// socket cannot receive work after a successor claims authority.
|
|
9509
|
+
connectionInstanceId: text("connection_instance_id"),
|
|
9510
|
+
connectionGeneration: integer("connection_generation").notNull().default(0),
|
|
9511
|
+
connectionLeaseExpiresAt: timestamp("connection_lease_expires_at", {
|
|
9512
|
+
withTimezone: true,
|
|
9513
|
+
}),
|
|
9514
|
+
// Durable diagnostics for valid cloned credentials / duplicate daemons that
|
|
9515
|
+
// were blocked while another process held the live authority lease.
|
|
9516
|
+
connectionDuplicateDeniedCount: integer("connection_duplicate_denied_count")
|
|
9517
|
+
.notNull()
|
|
9518
|
+
.default(0),
|
|
9519
|
+
connectionDuplicateDeniedAt: timestamp("connection_duplicate_denied_at", {
|
|
9520
|
+
withTimezone: true,
|
|
9521
|
+
}),
|
|
7374
9522
|
os: text("os", { enum: enrollmentOsValues }).notNull().default("linux"),
|
|
7375
9523
|
arch: text("arch").notNull().default("x86_64"),
|
|
9524
|
+
// Exact absolute launch root reported by the authoritative runner Hello.
|
|
9525
|
+
// Null means no current runner has supplied a usable root yet.
|
|
9526
|
+
workspaceRoot: text("workspace_root"),
|
|
7376
9527
|
// Heartbeat liveness cursor. Null until the first connect.
|
|
7377
9528
|
lastSeenAt: timestamp("last_seen_at", { withTimezone: true }),
|
|
7378
9529
|
// Clean going-offline marker (migration 0049). Set when the machine announces a
|
|
@@ -7383,18 +9534,154 @@ export const enrollments = pgTable(
|
|
|
7383
9534
|
// (the default) ⇒ no goodbye pending — today's last_seen-aging behavior.
|
|
7384
9535
|
wentOfflineAt: timestamp("went_offline_at", { withTimezone: true }),
|
|
7385
9536
|
wentOfflineReason: text("went_offline_reason"),
|
|
9537
|
+
// Exact running build + negotiated capability truth, refreshed from the
|
|
9538
|
+
// authoritative process Hello. Null means an older agent has not reported it.
|
|
9539
|
+
agentVersion: text("agent_version"),
|
|
9540
|
+
agentBinarySha256: text("agent_binary_sha256"),
|
|
9541
|
+
agentUpdateChannel: text("agent_update_channel", {
|
|
9542
|
+
enum: ["stable", "beta"] as const,
|
|
9543
|
+
}),
|
|
9544
|
+
agentCapabilities: jsonb("agent_capabilities")
|
|
9545
|
+
.$type<Record<string, boolean>>()
|
|
9546
|
+
.notNull()
|
|
9547
|
+
.default({}),
|
|
9548
|
+
// One current/most-recent self-update. The accepting connection coordinates
|
|
9549
|
+
// fence every progress write; a successor Hello is the only success signal.
|
|
9550
|
+
agentUpdateOperationId: uuid("agent_update_operation_id"),
|
|
9551
|
+
agentUpdateStatus: text("agent_update_status", {
|
|
9552
|
+
enum: agentUpdateStatusValues,
|
|
9553
|
+
}),
|
|
9554
|
+
agentUpdateTargetVersion: text("agent_update_target_version"),
|
|
9555
|
+
agentUpdateExpectedBinarySha256: text("agent_update_expected_binary_sha256"),
|
|
9556
|
+
agentUpdateErrorCode: text("agent_update_error_code"),
|
|
9557
|
+
agentUpdateRetryable: boolean("agent_update_retryable").notNull().default(false),
|
|
9558
|
+
agentUpdateRolledBack: boolean("agent_update_rolled_back").notNull().default(false),
|
|
9559
|
+
agentUpdateConnectionInstanceId: text("agent_update_connection_instance_id"),
|
|
9560
|
+
agentUpdateConnectionGeneration: integer("agent_update_connection_generation"),
|
|
9561
|
+
agentUpdateRequestedAt: timestamp("agent_update_requested_at", {
|
|
9562
|
+
withTimezone: true,
|
|
9563
|
+
}),
|
|
9564
|
+
agentUpdateUpdatedAt: timestamp("agent_update_updated_at", {
|
|
9565
|
+
withTimezone: true,
|
|
9566
|
+
}),
|
|
9567
|
+
agentUpdateCompletedAt: timestamp("agent_update_completed_at", {
|
|
9568
|
+
withTimezone: true,
|
|
9569
|
+
}),
|
|
7386
9570
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7387
9571
|
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
7388
9572
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7389
9573
|
},
|
|
7390
9574
|
(table) => ({
|
|
7391
|
-
// One enrollment per
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
table.pubkey
|
|
7395
|
-
|
|
9575
|
+
// One enrollment identity per authority boundary and pubkey. Revocation keeps
|
|
9576
|
+
// the identity so a re-enroll can reactivate the same durable row.
|
|
9577
|
+
workspacePubkey: uniqueIndex("enrollments_workspace_pubkey_idx")
|
|
9578
|
+
.on(table.workspaceId, table.pubkey)
|
|
9579
|
+
.where(sql`${table.authorityScope} = 'workspace'`),
|
|
9580
|
+
organizationPubkey: uniqueIndex("enrollments_organization_pubkey_idx")
|
|
9581
|
+
.on(table.accountId, table.pubkey)
|
|
9582
|
+
.where(sql`${table.authorityScope} = 'organization'`),
|
|
9583
|
+
userPubkey: uniqueIndex("enrollments_user_pubkey_idx")
|
|
9584
|
+
.on(table.accountId, table.ownerOrganizationMembershipId, table.pubkey)
|
|
9585
|
+
.where(sql`${table.authorityScope} = 'user'`),
|
|
7396
9586
|
// List a workspace's ACTIVE machines without scanning revoked rows.
|
|
7397
9587
|
workspaceStatus: index("enrollments_workspace_status_idx").on(table.workspaceId, table.status),
|
|
9588
|
+
authorityShape: check(
|
|
9589
|
+
"enrollments_authority_shape_check",
|
|
9590
|
+
sql`(
|
|
9591
|
+
${table.authorityScope} in ('organization', 'workspace')
|
|
9592
|
+
and ${table.authorityId} is null
|
|
9593
|
+
and ${table.ownerOrganizationMembershipId} is null
|
|
9594
|
+
) or (
|
|
9595
|
+
${table.authorityScope} = 'user'
|
|
9596
|
+
and ${table.authorityId} is not null
|
|
9597
|
+
and ${table.ownerOrganizationMembershipId} is not null
|
|
9598
|
+
)`,
|
|
9599
|
+
),
|
|
9600
|
+
authorityScopeValid: check(
|
|
9601
|
+
"enrollments_authority_scope_check",
|
|
9602
|
+
sql`${table.authorityScope} in ('organization', 'workspace', 'user')`,
|
|
9603
|
+
),
|
|
9604
|
+
generationPositive: check("enrollments_generation_check", sql`${table.generation} > 0`),
|
|
9605
|
+
authority: foreignKey({
|
|
9606
|
+
name: "enrollments_authority_fk",
|
|
9607
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
9608
|
+
foreignColumns: [
|
|
9609
|
+
organizationUserResourceAuthorities.id,
|
|
9610
|
+
organizationUserResourceAuthorities.accountId,
|
|
9611
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
9612
|
+
],
|
|
9613
|
+
}).onDelete("restrict"),
|
|
9614
|
+
connectionAuthorityShape: check(
|
|
9615
|
+
"enrollments_connection_authority_shape_chk",
|
|
9616
|
+
sql`(${table.connectionInstanceId} is null and ${table.connectionLeaseExpiresAt} is null)
|
|
9617
|
+
or (${table.connectionInstanceId} is not null
|
|
9618
|
+
and length(${table.connectionInstanceId}) between 1 and 128
|
|
9619
|
+
and ${table.connectionLeaseExpiresAt} is not null)`,
|
|
9620
|
+
),
|
|
9621
|
+
connectionGenerationNonnegative: check(
|
|
9622
|
+
"enrollments_connection_generation_chk",
|
|
9623
|
+
sql`${table.connectionGeneration} >= 0`,
|
|
9624
|
+
),
|
|
9625
|
+
operationMemoryMaxShape: check(
|
|
9626
|
+
"enrollments_operation_memory_max_shape_chk",
|
|
9627
|
+
sql`${table.operationMemoryMaxBytes} is null or (${table.operationMemoryMaxBytes} > 0 and ${table.operationMemoryMaxBytes} <= 9007199254740991)`,
|
|
9628
|
+
),
|
|
9629
|
+
operationMemoryHighShape: check(
|
|
9630
|
+
"enrollments_operation_memory_high_shape_chk",
|
|
9631
|
+
sql`${table.operationMemoryHighBytes} is null or (${table.operationMemoryHighBytes} > 0 and ${table.operationMemoryHighBytes} <= 9007199254740991)`,
|
|
9632
|
+
),
|
|
9633
|
+
operationMemoryOrder: check(
|
|
9634
|
+
"enrollments_operation_memory_order_chk",
|
|
9635
|
+
sql`${table.operationMemoryMaxBytes} is null or ${table.operationMemoryHighBytes} is null or ${table.operationMemoryHighBytes} <= ${table.operationMemoryMaxBytes}`,
|
|
9636
|
+
),
|
|
9637
|
+
operationCpuShape: check(
|
|
9638
|
+
"enrollments_operation_cpu_shape_chk",
|
|
9639
|
+
sql`${table.operationCpuMaxMillicores} is null or ${table.operationCpuMaxMillicores} between 1 and 4294967295`,
|
|
9640
|
+
),
|
|
9641
|
+
operationPolicyRevisionNonnegative: check(
|
|
9642
|
+
"enrollments_operation_policy_revision_chk",
|
|
9643
|
+
sql`${table.operationPolicyRevision} >= 0`,
|
|
9644
|
+
),
|
|
9645
|
+
agentBinarySha256Shape: check(
|
|
9646
|
+
"enrollments_agent_binary_sha256_chk",
|
|
9647
|
+
sql`${table.agentBinarySha256} is null or ${table.agentBinarySha256} ~ '^[0-9a-f]{64}$'`,
|
|
9648
|
+
),
|
|
9649
|
+
agentUpdateChannelShape: check(
|
|
9650
|
+
"enrollments_agent_update_channel_chk",
|
|
9651
|
+
sql`${table.agentUpdateChannel} is null or ${table.agentUpdateChannel} in ('stable', 'beta')`,
|
|
9652
|
+
),
|
|
9653
|
+
agentUpdateExpectedBinarySha256Shape: check(
|
|
9654
|
+
"enrollments_agent_update_expected_binary_sha256_chk",
|
|
9655
|
+
sql`${table.agentUpdateExpectedBinarySha256} is null or ${table.agentUpdateExpectedBinarySha256} ~ '^[0-9a-f]{64}$'`,
|
|
9656
|
+
),
|
|
9657
|
+
agentUpdateStateShape: check(
|
|
9658
|
+
"enrollments_agent_update_state_shape_chk",
|
|
9659
|
+
sql`(
|
|
9660
|
+
(${table.agentUpdateOperationId} is null
|
|
9661
|
+
and ${table.agentUpdateStatus} is null
|
|
9662
|
+
and ${table.agentUpdateTargetVersion} is null
|
|
9663
|
+
and ${table.agentUpdateConnectionInstanceId} is null
|
|
9664
|
+
and ${table.agentUpdateConnectionGeneration} is null
|
|
9665
|
+
and ${table.agentUpdateRequestedAt} is null
|
|
9666
|
+
and ${table.agentUpdateUpdatedAt} is null)
|
|
9667
|
+
or
|
|
9668
|
+
(${table.agentUpdateOperationId} is not null
|
|
9669
|
+
and ${table.agentUpdateStatus} in (
|
|
9670
|
+
'requested', 'accepted', 'waiting_for_idle', 'downloading', 'verifying',
|
|
9671
|
+
'applying', 'restarting', 'succeeded', 'failed'
|
|
9672
|
+
)
|
|
9673
|
+
and ${table.agentUpdateTargetVersion} is not null
|
|
9674
|
+
and ${table.agentUpdateConnectionInstanceId} is not null
|
|
9675
|
+
and ${table.agentUpdateConnectionGeneration} is not null
|
|
9676
|
+
and ${table.agentUpdateConnectionGeneration} >= 0
|
|
9677
|
+
and ${table.agentUpdateRequestedAt} is not null
|
|
9678
|
+
and ${table.agentUpdateUpdatedAt} is not null)
|
|
9679
|
+
)`,
|
|
9680
|
+
),
|
|
9681
|
+
connectionDuplicateDeniedCountNonnegative: check(
|
|
9682
|
+
"enrollments_connection_duplicate_denied_count_chk",
|
|
9683
|
+
sql`${table.connectionDuplicateDeniedCount} >= 0`,
|
|
9684
|
+
),
|
|
7398
9685
|
}),
|
|
7399
9686
|
);
|
|
7400
9687
|
|
|
@@ -7696,6 +9983,12 @@ export const scheduledTasks = pgTable(
|
|
|
7696
9983
|
.$type<XaiProviderAccountAuthoritySnapshotV1>()
|
|
7697
9984
|
.notNull()
|
|
7698
9985
|
.default(WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1),
|
|
9986
|
+
authorityRevision: bigint("authority_revision", { mode: "number" }).notNull().default(1),
|
|
9987
|
+
// The migration-owned BEFORE INSERT/UPDATE trigger replaces this client
|
|
9988
|
+
// placeholder with the canonical whole-row execution digest.
|
|
9989
|
+
executionDigest: text("execution_digest")
|
|
9990
|
+
.notNull()
|
|
9991
|
+
.$defaultFn(() => ""),
|
|
7699
9992
|
reusableSessionId: uuid("reusable_session_id").references(() => sessions.id, {
|
|
7700
9993
|
onDelete: "set null",
|
|
7701
9994
|
}),
|
|
@@ -7707,6 +10000,7 @@ export const scheduledTasks = pgTable(
|
|
|
7707
10000
|
// in migration 0047 (forward-reference pattern). Consumed in M3.
|
|
7708
10001
|
rigId: uuid("rig_id"),
|
|
7709
10002
|
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
|
|
10003
|
+
deletedAt: timestamp("deleted_at", { withTimezone: true }),
|
|
7710
10004
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7711
10005
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7712
10006
|
},
|
|
@@ -7738,6 +10032,12 @@ export const temporalScheduleCleanupOutbox = pgTable(
|
|
|
7738
10032
|
accountId: uuid("account_id").notNull(),
|
|
7739
10033
|
workspaceId: uuid("workspace_id").notNull(),
|
|
7740
10034
|
temporalScheduleId: text("temporal_schedule_id").notNull(),
|
|
10035
|
+
scheduledTaskId: uuid("scheduled_task_id"),
|
|
10036
|
+
connectorCleanupSubjectId: text("connector_cleanup_subject_id"),
|
|
10037
|
+
connectorCleanupSnapshot: jsonb("connector_cleanup_snapshot"),
|
|
10038
|
+
connectorCleanupCompletedAt: timestamp("connector_cleanup_completed_at", {
|
|
10039
|
+
withTimezone: true,
|
|
10040
|
+
}),
|
|
7741
10041
|
claimId: uuid("claim_id"),
|
|
7742
10042
|
claimUntil: timestamp("claim_until", { withTimezone: true }),
|
|
7743
10043
|
attemptCount: integer("attempt_count").notNull().default(0),
|
|
@@ -7761,6 +10061,58 @@ export const temporalScheduleCleanupOutbox = pgTable(
|
|
|
7761
10061
|
and ${table.attemptCount} >= 0
|
|
7762
10062
|
and ((${table.claimId} is null and ${table.claimUntil} is null)
|
|
7763
10063
|
or (${table.claimId} is not null and ${table.claimUntil} is not null))
|
|
10064
|
+
and ((${table.scheduledTaskId} is null and ${table.connectorCleanupSubjectId} is null
|
|
10065
|
+
and ${table.connectorCleanupSnapshot} is null)
|
|
10066
|
+
or (${table.scheduledTaskId} is not null and ${table.connectorCleanupSubjectId} is not null
|
|
10067
|
+
and ${table.connectorCleanupSnapshot} is not null))
|
|
10068
|
+
and (${table.connectorCleanupSnapshot} is not null
|
|
10069
|
+
or ${table.connectorCleanupCompletedAt} is null)
|
|
10070
|
+
and (${table.connectorCleanupSubjectId} is null
|
|
10071
|
+
or octet_length(${table.connectorCleanupSubjectId}) between 1 and 4096)
|
|
10072
|
+
and (${table.connectorCleanupSnapshot} is null or (
|
|
10073
|
+
jsonb_typeof(${table.connectorCleanupSnapshot}) = 'object'
|
|
10074
|
+
and ${table.connectorCleanupSnapshot} ?& array[
|
|
10075
|
+
'version','taskId','accountId','workspaceId','connectorKind','connectionId',
|
|
10076
|
+
'connectionVersion','sourceId','sourceLifecycleGeneration',
|
|
10077
|
+
'sourceConfigGeneration','externalSourceId','subjectId'
|
|
10078
|
+
]
|
|
10079
|
+
and ${table.connectorCleanupSnapshot} - array[
|
|
10080
|
+
'version','taskId','accountId','workspaceId','connectorKind','connectionId',
|
|
10081
|
+
'connectionVersion','sourceId','sourceLifecycleGeneration',
|
|
10082
|
+
'sourceConfigGeneration','externalSourceId','subjectId'
|
|
10083
|
+
]::text[] = '{}'::jsonb
|
|
10084
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'version') = 'number'
|
|
10085
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'taskId') = 'string'
|
|
10086
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'accountId') = 'string'
|
|
10087
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'workspaceId') = 'string'
|
|
10088
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'connectorKind') = 'string'
|
|
10089
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'connectionId') = 'string'
|
|
10090
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'connectionVersion') = 'number'
|
|
10091
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'sourceId') = 'string'
|
|
10092
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'sourceLifecycleGeneration') = 'number'
|
|
10093
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'sourceConfigGeneration') = 'number'
|
|
10094
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'externalSourceId') = 'string'
|
|
10095
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'subjectId') = 'string'
|
|
10096
|
+
and ${table.connectorCleanupSnapshot}->>'version' = '1'
|
|
10097
|
+
and ${table.connectorCleanupSnapshot}->>'connectorKind' in ('google_drive','atlassian')
|
|
10098
|
+
and ${table.connectorCleanupSnapshot}->>'subjectId' = ${table.connectorCleanupSubjectId}
|
|
10099
|
+
and ${table.connectorCleanupSnapshot}->>'taskId' = ${table.scheduledTaskId}::text
|
|
10100
|
+
and ${table.connectorCleanupSnapshot}->>'accountId' = ${table.accountId}::text
|
|
10101
|
+
and ${table.connectorCleanupSnapshot}->>'workspaceId' = ${table.workspaceId}::text
|
|
10102
|
+
and octet_length(${table.connectorCleanupSnapshot}->>'externalSourceId') between 1 and 2048
|
|
10103
|
+
and octet_length(${table.connectorCleanupSnapshot}->>'subjectId') between 1 and 4096
|
|
10104
|
+
and ${table.connectorCleanupSnapshot}->>'taskId' ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
|
10105
|
+
and ${table.connectorCleanupSnapshot}->>'accountId' ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
|
10106
|
+
and ${table.connectorCleanupSnapshot}->>'workspaceId' ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
|
10107
|
+
and ${table.connectorCleanupSnapshot}->>'connectionId' ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
|
10108
|
+
and ${table.connectorCleanupSnapshot}->>'sourceId' ~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
|
10109
|
+
and ${table.connectorCleanupSnapshot}->>'connectionVersion' ~ '^[1-9][0-9]*$'
|
|
10110
|
+
and ${table.connectorCleanupSnapshot}->>'sourceLifecycleGeneration' ~ '^[1-9][0-9]*$'
|
|
10111
|
+
and ${table.connectorCleanupSnapshot}->>'sourceConfigGeneration' ~ '^[1-9][0-9]*$'
|
|
10112
|
+
and (${table.connectorCleanupSnapshot}->>'connectionVersion')::numeric <= 9007199254740991
|
|
10113
|
+
and (${table.connectorCleanupSnapshot}->>'sourceLifecycleGeneration')::numeric <= 9007199254740991
|
|
10114
|
+
and (${table.connectorCleanupSnapshot}->>'sourceConfigGeneration')::numeric <= 9007199254740991
|
|
10115
|
+
))
|
|
7764
10116
|
and (${table.lastError} is null or length(${table.lastError}) <= 2000)`,
|
|
7765
10117
|
),
|
|
7766
10118
|
}),
|
|
@@ -7778,14 +10130,16 @@ export const scheduledTaskRuns = pgTable(
|
|
|
7778
10130
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
7779
10131
|
taskId: uuid("task_id")
|
|
7780
10132
|
.notNull()
|
|
7781
|
-
.references(() => scheduledTasks.id
|
|
10133
|
+
.references(() => scheduledTasks.id),
|
|
10134
|
+
taskAuthorityRevision: bigint("task_authority_revision", {
|
|
10135
|
+
mode: "number",
|
|
10136
|
+
}),
|
|
10137
|
+
taskExecutionDigest: text("task_execution_digest"),
|
|
7782
10138
|
status: text("status").notNull().default("queued"),
|
|
7783
10139
|
triggerType: text("trigger_type").notNull(),
|
|
7784
10140
|
scheduledAt: timestamp("scheduled_at", { withTimezone: true }),
|
|
7785
10141
|
firedAt: timestamp("fired_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7786
|
-
sessionId: uuid("session_id").references(() => sessions.id,
|
|
7787
|
-
onDelete: "set null",
|
|
7788
|
-
}),
|
|
10142
|
+
sessionId: uuid("session_id").references(() => sessions.id),
|
|
7789
10143
|
triggerEventId: uuid("trigger_event_id"),
|
|
7790
10144
|
actionKind: text("action_kind").notNull().default("agent_turn"),
|
|
7791
10145
|
knowledgeSyncRunId: uuid("knowledge_sync_run_id"),
|
|
@@ -7794,6 +10148,10 @@ export const scheduledTaskRuns = pgTable(
|
|
|
7794
10148
|
// Stable Temporal producer identity. Activity replay/re-dispatch returns
|
|
7795
10149
|
// the exact run instead of allocating a second schedule source row.
|
|
7796
10150
|
producerKey: text("producer_key"),
|
|
10151
|
+
// Complete credential-free accepted execution truth. It is private worker
|
|
10152
|
+
// authority and never appears in public scheduled-run projections.
|
|
10153
|
+
acceptedExecutionSnapshot: jsonb("accepted_execution_snapshot").$type<unknown>(),
|
|
10154
|
+
acceptedExecutionDigest: text("accepted_execution_digest"),
|
|
7797
10155
|
error: text("error"),
|
|
7798
10156
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7799
10157
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -7900,45 +10258,186 @@ export const githubInstallations = pgTable(
|
|
|
7900
10258
|
)
|
|
7901
10259
|
`,
|
|
7902
10260
|
),
|
|
7903
|
-
authorityNonce: uniqueIndex("github_installations_authority_nonce_uq")
|
|
7904
|
-
.on(table.authorityNonce)
|
|
7905
|
-
.where(sql`${table.authorityNonce} is not null`),
|
|
10261
|
+
authorityNonce: uniqueIndex("github_installations_authority_nonce_uq")
|
|
10262
|
+
.on(table.authorityNonce)
|
|
10263
|
+
.where(sql`${table.authorityNonce} is not null`),
|
|
10264
|
+
}),
|
|
10265
|
+
);
|
|
10266
|
+
|
|
10267
|
+
export const githubInstallationRepositories = pgTable(
|
|
10268
|
+
"github_installation_repositories",
|
|
10269
|
+
{
|
|
10270
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
10271
|
+
accountId: uuid("account_id")
|
|
10272
|
+
.notNull()
|
|
10273
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
10274
|
+
workspaceId: uuid("workspace_id")
|
|
10275
|
+
.notNull()
|
|
10276
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
10277
|
+
installationId: integer("installation_id").notNull(),
|
|
10278
|
+
repositoryId: bigint("repository_id", { mode: "number" }).notNull(),
|
|
10279
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10280
|
+
},
|
|
10281
|
+
(table) => ({
|
|
10282
|
+
installationRepository: uniqueIndex("github_install_repo_workspace_installation_repo_idx").on(
|
|
10283
|
+
table.workspaceId,
|
|
10284
|
+
table.installationId,
|
|
10285
|
+
table.repositoryId,
|
|
10286
|
+
),
|
|
10287
|
+
workspaceInstallation: index("github_install_repo_workspace_installation_idx").on(
|
|
10288
|
+
table.workspaceId,
|
|
10289
|
+
table.installationId,
|
|
10290
|
+
),
|
|
10291
|
+
workspaceAccount: foreignKey({
|
|
10292
|
+
columns: [table.workspaceId, table.accountId],
|
|
10293
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
10294
|
+
name: "github_installation_repositories_workspace_account_fk",
|
|
10295
|
+
}).onDelete("cascade"),
|
|
10296
|
+
installationBinding: foreignKey({
|
|
10297
|
+
columns: [table.workspaceId, table.installationId],
|
|
10298
|
+
foreignColumns: [githubInstallations.workspaceId, githubInstallations.installationId],
|
|
10299
|
+
name: "github_installation_repositories_installation_fk",
|
|
10300
|
+
}).onDelete("cascade"),
|
|
10301
|
+
}),
|
|
10302
|
+
);
|
|
10303
|
+
|
|
10304
|
+
export const prReviewAppRegistrations = pgTable(
|
|
10305
|
+
"pr_review_app_registrations",
|
|
10306
|
+
{
|
|
10307
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
10308
|
+
sourceId: uuid("source_id").notNull(),
|
|
10309
|
+
accountId: uuid("account_id")
|
|
10310
|
+
.notNull()
|
|
10311
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
10312
|
+
workspaceId: uuid("workspace_id")
|
|
10313
|
+
.notNull()
|
|
10314
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
10315
|
+
name: text("name").notNull(),
|
|
10316
|
+
provider: text("provider").notNull(),
|
|
10317
|
+
providerBaseUrl: text("provider_base_url").notNull(),
|
|
10318
|
+
appId: text("app_id"),
|
|
10319
|
+
credentialKind: text("credential_kind").notNull(),
|
|
10320
|
+
credentialEncrypted: text("credential_encrypted"),
|
|
10321
|
+
accessTokenExpiresAt: timestamp("access_token_expires_at", { withTimezone: true }),
|
|
10322
|
+
webhookAuthKind: text("webhook_auth_kind").notNull(),
|
|
10323
|
+
webhookUsername: text("webhook_username"),
|
|
10324
|
+
status: text("status").notNull().default("active"),
|
|
10325
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
10326
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10327
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10328
|
+
},
|
|
10329
|
+
(table) => ({
|
|
10330
|
+
workspaceRegistration: uniqueIndex("pr_review_app_registrations_workspace_id_uq").on(
|
|
10331
|
+
table.workspaceId,
|
|
10332
|
+
table.id,
|
|
10333
|
+
),
|
|
10334
|
+
workspaceRegistrationProvider: uniqueIndex(
|
|
10335
|
+
"pr_review_app_registrations_workspace_id_provider_uq",
|
|
10336
|
+
).on(table.workspaceId, table.id, table.provider),
|
|
10337
|
+
workspaceProviderName: uniqueIndex("pr_review_app_registrations_workspace_provider_name_uq").on(
|
|
10338
|
+
table.workspaceId,
|
|
10339
|
+
table.provider,
|
|
10340
|
+
table.name,
|
|
10341
|
+
),
|
|
10342
|
+
workspaceStatus: index("pr_review_app_registrations_workspace_status_idx").on(
|
|
10343
|
+
table.workspaceId,
|
|
10344
|
+
table.status,
|
|
10345
|
+
),
|
|
10346
|
+
providerCheck: check(
|
|
10347
|
+
"pr_review_app_registrations_provider_chk",
|
|
10348
|
+
sql`${table.provider} in ('github', 'gitlab', 'azure_devops')`,
|
|
10349
|
+
),
|
|
10350
|
+
credentialCheck: check(
|
|
10351
|
+
"pr_review_app_registrations_credential_chk",
|
|
10352
|
+
sql`(
|
|
10353
|
+
(${table.provider} = 'github' and ${table.credentialKind} = 'github_app' and ${table.credentialEncrypted} is not null and ${table.appId} is not null)
|
|
10354
|
+
or
|
|
10355
|
+
(${table.provider} in ('gitlab', 'azure_devops') and ${table.credentialKind} = 'provider_token' and ${table.credentialEncrypted} is not null)
|
|
10356
|
+
)`,
|
|
10357
|
+
),
|
|
10358
|
+
webhookAuthCheck: check(
|
|
10359
|
+
"pr_review_app_registrations_webhook_auth_chk",
|
|
10360
|
+
sql`(
|
|
10361
|
+
(${table.provider} = 'github' and ${table.webhookAuthKind} = 'hmac_sha256')
|
|
10362
|
+
or (${table.provider} = 'gitlab' and ${table.webhookAuthKind} = 'shared_token')
|
|
10363
|
+
or (${table.provider} = 'azure_devops' and ${table.webhookAuthKind} = 'basic' and ${table.webhookUsername} is not null)
|
|
10364
|
+
)`,
|
|
10365
|
+
),
|
|
10366
|
+
statusCheck: check(
|
|
10367
|
+
"pr_review_app_registrations_status_chk",
|
|
10368
|
+
sql`${table.status} in ('active', 'disabled')`,
|
|
10369
|
+
),
|
|
10370
|
+
workspaceAccount: foreignKey({
|
|
10371
|
+
columns: [table.workspaceId, table.accountId],
|
|
10372
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
10373
|
+
name: "pr_review_app_registrations_workspace_account_fk",
|
|
10374
|
+
}).onDelete("cascade"),
|
|
7906
10375
|
}),
|
|
7907
10376
|
);
|
|
7908
10377
|
|
|
7909
|
-
export const
|
|
7910
|
-
"
|
|
10378
|
+
export const prReviewRepositoryBindings = pgTable(
|
|
10379
|
+
"pr_review_repository_bindings",
|
|
7911
10380
|
{
|
|
7912
10381
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
10382
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
7913
10383
|
accountId: uuid("account_id")
|
|
7914
10384
|
.notNull()
|
|
7915
10385
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
7916
10386
|
workspaceId: uuid("workspace_id")
|
|
7917
10387
|
.notNull()
|
|
7918
10388
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
7919
|
-
|
|
7920
|
-
|
|
10389
|
+
registrationId: uuid("registration_id").notNull(),
|
|
10390
|
+
provider: text("provider").notNull(),
|
|
10391
|
+
repositoryUri: text("repository_uri").notNull(),
|
|
10392
|
+
repositoryFullName: text("repository_full_name").notNull(),
|
|
10393
|
+
providerRepositoryId: text("provider_repository_id").notNull(),
|
|
10394
|
+
installationId: text("installation_id"),
|
|
10395
|
+
projectId: text("project_id"),
|
|
10396
|
+
model: text("model"),
|
|
10397
|
+
additionalInstructions: text("additional_instructions"),
|
|
10398
|
+
status: text("status").notNull().default("active"),
|
|
10399
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
7921
10400
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10401
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7922
10402
|
},
|
|
7923
10403
|
(table) => ({
|
|
7924
|
-
|
|
10404
|
+
workspaceBinding: uniqueIndex("pr_review_repository_bindings_workspace_id_uq").on(
|
|
7925
10405
|
table.workspaceId,
|
|
7926
|
-
table.
|
|
7927
|
-
table.repositoryId,
|
|
10406
|
+
table.id,
|
|
7928
10407
|
),
|
|
7929
|
-
|
|
10408
|
+
workspaceBindingRegistrationProvider: uniqueIndex(
|
|
10409
|
+
"pr_review_repo_workspace_registration_provider_uq",
|
|
10410
|
+
).on(table.workspaceId, table.id, table.registrationId, table.provider),
|
|
10411
|
+
registrationRepository: uniqueIndex("pr_review_repository_bindings_registration_repo_uq").on(
|
|
10412
|
+
table.registrationId,
|
|
10413
|
+
table.providerRepositoryId,
|
|
10414
|
+
),
|
|
10415
|
+
triggerIdentity: uniqueIndex("pr_review_repository_bindings_trigger_uq").on(table.triggerId),
|
|
10416
|
+
workspaceStatus: index("pr_review_repository_bindings_workspace_status_idx").on(
|
|
7930
10417
|
table.workspaceId,
|
|
7931
|
-
table.
|
|
10418
|
+
table.status,
|
|
10419
|
+
),
|
|
10420
|
+
providerCheck: check(
|
|
10421
|
+
"pr_review_repository_bindings_provider_chk",
|
|
10422
|
+
sql`${table.provider} in ('github', 'gitlab', 'azure_devops')`,
|
|
10423
|
+
),
|
|
10424
|
+
statusCheck: check(
|
|
10425
|
+
"pr_review_repository_bindings_status_chk",
|
|
10426
|
+
sql`${table.status} in ('active', 'disabled')`,
|
|
7932
10427
|
),
|
|
7933
10428
|
workspaceAccount: foreignKey({
|
|
7934
10429
|
columns: [table.workspaceId, table.accountId],
|
|
7935
10430
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
7936
|
-
name: "
|
|
10431
|
+
name: "pr_review_repository_bindings_workspace_account_fk",
|
|
7937
10432
|
}).onDelete("cascade"),
|
|
7938
|
-
|
|
7939
|
-
columns: [table.workspaceId, table.
|
|
7940
|
-
foreignColumns: [
|
|
7941
|
-
|
|
10433
|
+
registration: foreignKey({
|
|
10434
|
+
columns: [table.workspaceId, table.registrationId, table.provider],
|
|
10435
|
+
foreignColumns: [
|
|
10436
|
+
prReviewAppRegistrations.workspaceId,
|
|
10437
|
+
prReviewAppRegistrations.id,
|
|
10438
|
+
prReviewAppRegistrations.provider,
|
|
10439
|
+
],
|
|
10440
|
+
name: "pr_review_repository_bindings_registration_fk",
|
|
7942
10441
|
}).onDelete("cascade"),
|
|
7943
10442
|
}),
|
|
7944
10443
|
);
|
|
@@ -8060,6 +10559,8 @@ export const modelCallFacts = pgTable(
|
|
|
8060
10559
|
mode: "number",
|
|
8061
10560
|
}),
|
|
8062
10561
|
pricingSource: text("pricing_source"),
|
|
10562
|
+
contextContributions:
|
|
10563
|
+
jsonb("context_contributions").$type<readonly ModelContextContributionSummary[]>(),
|
|
8063
10564
|
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
8064
10565
|
recordedAt: timestamp("recorded_at", { withTimezone: true }).notNull().defaultNow(),
|
|
8065
10566
|
},
|
|
@@ -8130,6 +10631,10 @@ export const modelCallFacts = pgTable(
|
|
|
8130
10631
|
"model_call_facts_model_bytes_check",
|
|
8131
10632
|
sql`octet_length(${table.model}) between 1 and 512`,
|
|
8132
10633
|
),
|
|
10634
|
+
contextContributionsValid: check(
|
|
10635
|
+
"model_call_facts_context_contributions_check",
|
|
10636
|
+
sql`opengeni_private.model_context_contributions_valid(${table.contextContributions})`,
|
|
10637
|
+
),
|
|
8133
10638
|
}),
|
|
8134
10639
|
);
|
|
8135
10640
|
|
|
@@ -8433,6 +10938,10 @@ export const packInstallations = pgTable(
|
|
|
8433
10938
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
8434
10939
|
},
|
|
8435
10940
|
(table) => ({
|
|
10941
|
+
workspaceIdentity: uniqueIndex("pack_installations_workspace_id_uq").on(
|
|
10942
|
+
table.workspaceId,
|
|
10943
|
+
table.id,
|
|
10944
|
+
),
|
|
8436
10945
|
workspacePack: uniqueIndex("pack_installations_workspace_pack_idx").on(
|
|
8437
10946
|
table.workspaceId,
|
|
8438
10947
|
table.packId,
|
|
@@ -8479,6 +10988,376 @@ export const packInstallationComponents = pgTable(
|
|
|
8479
10988
|
}),
|
|
8480
10989
|
);
|
|
8481
10990
|
|
|
10991
|
+
export const automationSources = pgTable(
|
|
10992
|
+
"automation_sources",
|
|
10993
|
+
{
|
|
10994
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
10995
|
+
endpointId: uuid("endpoint_id").notNull().defaultRandom(),
|
|
10996
|
+
accountId: uuid("account_id")
|
|
10997
|
+
.notNull()
|
|
10998
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
10999
|
+
workspaceId: uuid("workspace_id")
|
|
11000
|
+
.notNull()
|
|
11001
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
11002
|
+
name: text("name").notNull(),
|
|
11003
|
+
adapterId: text("adapter_id").notNull(),
|
|
11004
|
+
configuration: jsonb("configuration").$type<Record<string, unknown>>().notNull().default({}),
|
|
11005
|
+
webhookSecretEncrypted: text("webhook_secret_encrypted").notNull(),
|
|
11006
|
+
status: text("status").notNull().default("active"),
|
|
11007
|
+
version: integer("version").notNull().default(1),
|
|
11008
|
+
packInstallationId: uuid("pack_installation_id"),
|
|
11009
|
+
packConnectorId: text("pack_connector_id"),
|
|
11010
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
11011
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11012
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11013
|
+
},
|
|
11014
|
+
(table) => ({
|
|
11015
|
+
endpoint: uniqueIndex("automation_sources_endpoint_uq").on(table.endpointId),
|
|
11016
|
+
workspaceIdentity: uniqueIndex("automation_sources_workspace_id_uq").on(
|
|
11017
|
+
table.workspaceId,
|
|
11018
|
+
table.id,
|
|
11019
|
+
),
|
|
11020
|
+
workspaceStatus: index("automation_sources_workspace_status_idx").on(
|
|
11021
|
+
table.workspaceId,
|
|
11022
|
+
table.status,
|
|
11023
|
+
),
|
|
11024
|
+
shape: check(
|
|
11025
|
+
"automation_sources_shape_chk",
|
|
11026
|
+
sql`${table.status} in ('active', 'disabled')
|
|
11027
|
+
and ${table.version} > 0
|
|
11028
|
+
and octet_length(${table.name}) between 1 and 512
|
|
11029
|
+
and octet_length(${table.adapterId}) between 1 and 128
|
|
11030
|
+
and octet_length(${table.createdBySubjectId}) between 1 and 4096
|
|
11031
|
+
and jsonb_typeof(${table.configuration}) = 'object'
|
|
11032
|
+
and ((${table.packInstallationId} is null and ${table.packConnectorId} is null)
|
|
11033
|
+
or (${table.packInstallationId} is not null
|
|
11034
|
+
and octet_length(${table.packConnectorId}) between 1 and 128))`,
|
|
11035
|
+
),
|
|
11036
|
+
workspaceAccount: foreignKey({
|
|
11037
|
+
columns: [table.workspaceId, table.accountId],
|
|
11038
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11039
|
+
name: "automation_sources_workspace_account_fk",
|
|
11040
|
+
}).onDelete("cascade"),
|
|
11041
|
+
packInstallation: foreignKey({
|
|
11042
|
+
columns: [table.workspaceId, table.packInstallationId],
|
|
11043
|
+
foreignColumns: [packInstallations.workspaceId, packInstallations.id],
|
|
11044
|
+
name: "automation_sources_pack_installation_fk",
|
|
11045
|
+
}).onDelete("cascade"),
|
|
11046
|
+
}),
|
|
11047
|
+
);
|
|
11048
|
+
|
|
11049
|
+
/** Credential-free global webhook routing. Possession of the opaque endpoint
|
|
11050
|
+
* UUID locates the tenant; authentication still requires the encrypted secret
|
|
11051
|
+
* on the FORCE-RLS source row before any payload is parsed or accepted. */
|
|
11052
|
+
export const automationWebhookEndpoints = pgTable(
|
|
11053
|
+
"automation_webhook_endpoints",
|
|
11054
|
+
{
|
|
11055
|
+
endpointId: uuid("endpoint_id").primaryKey(),
|
|
11056
|
+
accountId: uuid("account_id")
|
|
11057
|
+
.notNull()
|
|
11058
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
11059
|
+
workspaceId: uuid("workspace_id")
|
|
11060
|
+
.notNull()
|
|
11061
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
11062
|
+
sourceId: uuid("source_id")
|
|
11063
|
+
.notNull()
|
|
11064
|
+
.references(() => automationSources.id, { onDelete: "cascade" }),
|
|
11065
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11066
|
+
},
|
|
11067
|
+
(table) => ({
|
|
11068
|
+
source: uniqueIndex("automation_webhook_endpoints_source_uq").on(table.sourceId),
|
|
11069
|
+
workspaceAccount: foreignKey({
|
|
11070
|
+
columns: [table.workspaceId, table.accountId],
|
|
11071
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11072
|
+
name: "automation_webhook_endpoints_workspace_account_fk",
|
|
11073
|
+
}).onDelete("cascade"),
|
|
11074
|
+
}),
|
|
11075
|
+
);
|
|
11076
|
+
|
|
11077
|
+
export const automationTriggers = pgTable(
|
|
11078
|
+
"automation_triggers",
|
|
11079
|
+
{
|
|
11080
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11081
|
+
accountId: uuid("account_id")
|
|
11082
|
+
.notNull()
|
|
11083
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
11084
|
+
workspaceId: uuid("workspace_id")
|
|
11085
|
+
.notNull()
|
|
11086
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
11087
|
+
sourceId: uuid("source_id").notNull(),
|
|
11088
|
+
name: text("name").notNull(),
|
|
11089
|
+
status: text("status").notNull().default("active"),
|
|
11090
|
+
currentRevision: integer("current_revision").notNull().default(1),
|
|
11091
|
+
packInstallationId: uuid("pack_installation_id"),
|
|
11092
|
+
packTemplateId: text("pack_template_id"),
|
|
11093
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
11094
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11095
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11096
|
+
},
|
|
11097
|
+
(table) => ({
|
|
11098
|
+
workspaceIdentity: uniqueIndex("automation_triggers_workspace_id_uq").on(
|
|
11099
|
+
table.workspaceId,
|
|
11100
|
+
table.id,
|
|
11101
|
+
),
|
|
11102
|
+
workspaceSourceIdentity: uniqueIndex("automation_triggers_workspace_source_id_uq").on(
|
|
11103
|
+
table.workspaceId,
|
|
11104
|
+
table.id,
|
|
11105
|
+
table.sourceId,
|
|
11106
|
+
),
|
|
11107
|
+
workspaceStatus: index("automation_triggers_workspace_status_idx").on(
|
|
11108
|
+
table.workspaceId,
|
|
11109
|
+
table.status,
|
|
11110
|
+
),
|
|
11111
|
+
source: foreignKey({
|
|
11112
|
+
columns: [table.workspaceId, table.sourceId],
|
|
11113
|
+
foreignColumns: [automationSources.workspaceId, automationSources.id],
|
|
11114
|
+
name: "automation_triggers_source_fk",
|
|
11115
|
+
}).onDelete("cascade"),
|
|
11116
|
+
packInstallation: foreignKey({
|
|
11117
|
+
columns: [table.workspaceId, table.packInstallationId],
|
|
11118
|
+
foreignColumns: [packInstallations.workspaceId, packInstallations.id],
|
|
11119
|
+
name: "automation_triggers_pack_installation_fk",
|
|
11120
|
+
}).onDelete("cascade"),
|
|
11121
|
+
workspaceAccount: foreignKey({
|
|
11122
|
+
columns: [table.workspaceId, table.accountId],
|
|
11123
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11124
|
+
name: "automation_triggers_workspace_account_fk",
|
|
11125
|
+
}).onDelete("cascade"),
|
|
11126
|
+
shape: check(
|
|
11127
|
+
"automation_triggers_shape_chk",
|
|
11128
|
+
sql`${table.status} in ('active', 'paused', 'disabled')
|
|
11129
|
+
and ${table.currentRevision} > 0
|
|
11130
|
+
and octet_length(${table.name}) between 1 and 512
|
|
11131
|
+
and octet_length(${table.createdBySubjectId}) between 1 and 4096
|
|
11132
|
+
and ((${table.packInstallationId} is null and ${table.packTemplateId} is null)
|
|
11133
|
+
or (${table.packInstallationId} is not null and octet_length(${table.packTemplateId}) between 1 and 128))`,
|
|
11134
|
+
),
|
|
11135
|
+
}),
|
|
11136
|
+
);
|
|
11137
|
+
|
|
11138
|
+
export const automationTriggerRevisions = pgTable(
|
|
11139
|
+
"automation_trigger_revisions",
|
|
11140
|
+
{
|
|
11141
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
11142
|
+
revision: integer("revision").notNull(),
|
|
11143
|
+
accountId: uuid("account_id").notNull(),
|
|
11144
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11145
|
+
adapterId: text("adapter_id").notNull(),
|
|
11146
|
+
eventTypes: jsonb("event_types").$type<string[]>().notNull(),
|
|
11147
|
+
configuration: jsonb("configuration").$type<Record<string, unknown>>().notNull().default({}),
|
|
11148
|
+
parameters: jsonb("parameters").$type<Record<string, unknown>>().notNull().default({}),
|
|
11149
|
+
sessionTemplate: jsonb("session_template").$type<AutomationSessionTemplate>().notNull(),
|
|
11150
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
11151
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11152
|
+
},
|
|
11153
|
+
(table) => ({
|
|
11154
|
+
identity: primaryKey({ columns: [table.triggerId, table.revision] }),
|
|
11155
|
+
trigger: foreignKey({
|
|
11156
|
+
columns: [table.workspaceId, table.triggerId],
|
|
11157
|
+
foreignColumns: [automationTriggers.workspaceId, automationTriggers.id],
|
|
11158
|
+
name: "automation_trigger_revisions_trigger_fk",
|
|
11159
|
+
}).onDelete("cascade"),
|
|
11160
|
+
workspaceAccount: foreignKey({
|
|
11161
|
+
columns: [table.workspaceId, table.accountId],
|
|
11162
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11163
|
+
name: "automation_trigger_revisions_workspace_account_fk",
|
|
11164
|
+
}).onDelete("cascade"),
|
|
11165
|
+
shape: check(
|
|
11166
|
+
"automation_trigger_revisions_shape_chk",
|
|
11167
|
+
sql`${table.revision} > 0
|
|
11168
|
+
and octet_length(${table.adapterId}) between 1 and 128
|
|
11169
|
+
and jsonb_typeof(${table.eventTypes}) = 'array'
|
|
11170
|
+
and jsonb_array_length(${table.eventTypes}) between 1 and 64
|
|
11171
|
+
and jsonb_typeof(${table.configuration}) = 'object'
|
|
11172
|
+
and jsonb_typeof(${table.parameters}) = 'object'
|
|
11173
|
+
and jsonb_typeof(${table.sessionTemplate}) = 'object'`,
|
|
11174
|
+
),
|
|
11175
|
+
}),
|
|
11176
|
+
);
|
|
11177
|
+
|
|
11178
|
+
export const automationTriggerEvents = pgTable(
|
|
11179
|
+
"automation_trigger_events",
|
|
11180
|
+
{
|
|
11181
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11182
|
+
accountId: uuid("account_id").notNull(),
|
|
11183
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11184
|
+
sourceId: uuid("source_id").notNull(),
|
|
11185
|
+
sourceVersion: integer("source_version").notNull(),
|
|
11186
|
+
sourceConfiguration: jsonb("source_configuration").$type<Record<string, unknown>>().notNull(),
|
|
11187
|
+
matchedTriggerRevisions: jsonb("matched_trigger_revisions")
|
|
11188
|
+
.$type<Array<{ triggerId: string; revision: number }>>()
|
|
11189
|
+
.notNull(),
|
|
11190
|
+
deliveryKey: text("delivery_key").notNull(),
|
|
11191
|
+
requestDigest: text("request_digest").notNull(),
|
|
11192
|
+
adapterId: text("adapter_id").notNull(),
|
|
11193
|
+
eventType: text("event_type").notNull(),
|
|
11194
|
+
occurrenceKey: text("occurrence_key").notNull(),
|
|
11195
|
+
normalizedEvent: jsonb("normalized_event").$type<Record<string, unknown>>().notNull(),
|
|
11196
|
+
status: text("status").notNull().default("accepted"),
|
|
11197
|
+
ignoredReason: text("ignored_reason"),
|
|
11198
|
+
errorCode: text("error_code"),
|
|
11199
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11200
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11201
|
+
},
|
|
11202
|
+
(table) => ({
|
|
11203
|
+
sourceDelivery: uniqueIndex("automation_trigger_events_source_delivery_uq").on(
|
|
11204
|
+
table.sourceId,
|
|
11205
|
+
table.deliveryKey,
|
|
11206
|
+
),
|
|
11207
|
+
workspaceCreated: index("automation_trigger_events_workspace_created_idx").on(
|
|
11208
|
+
table.workspaceId,
|
|
11209
|
+
table.createdAt,
|
|
11210
|
+
),
|
|
11211
|
+
workspaceSourceIdentity: uniqueIndex("automation_trigger_events_workspace_source_id_uq").on(
|
|
11212
|
+
table.workspaceId,
|
|
11213
|
+
table.sourceId,
|
|
11214
|
+
table.id,
|
|
11215
|
+
),
|
|
11216
|
+
source: foreignKey({
|
|
11217
|
+
columns: [table.workspaceId, table.sourceId],
|
|
11218
|
+
foreignColumns: [automationSources.workspaceId, automationSources.id],
|
|
11219
|
+
name: "automation_trigger_events_source_fk",
|
|
11220
|
+
}).onDelete("cascade"),
|
|
11221
|
+
workspaceAccount: foreignKey({
|
|
11222
|
+
columns: [table.workspaceId, table.accountId],
|
|
11223
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11224
|
+
name: "automation_trigger_events_workspace_account_fk",
|
|
11225
|
+
}).onDelete("cascade"),
|
|
11226
|
+
shape: check(
|
|
11227
|
+
"automation_trigger_events_shape_chk",
|
|
11228
|
+
sql`${table.status} in ('accepted', 'ignored', 'failed')
|
|
11229
|
+
and ${table.sourceVersion} > 0
|
|
11230
|
+
and jsonb_typeof(${table.sourceConfiguration}) = 'object'
|
|
11231
|
+
and jsonb_typeof(${table.matchedTriggerRevisions}) = 'array'
|
|
11232
|
+
and jsonb_array_length(${table.matchedTriggerRevisions}) <= 32
|
|
11233
|
+
and ${table.requestDigest} ~ '^[0-9a-f]{64}$'
|
|
11234
|
+
and octet_length(${table.deliveryKey}) between 1 and 1024
|
|
11235
|
+
and octet_length(${table.eventType}) between 1 and 256
|
|
11236
|
+
and octet_length(${table.occurrenceKey}) between 1 and 1024
|
|
11237
|
+
and jsonb_typeof(${table.normalizedEvent}) = 'object'`,
|
|
11238
|
+
),
|
|
11239
|
+
}),
|
|
11240
|
+
);
|
|
11241
|
+
|
|
11242
|
+
export const automationRuns = pgTable(
|
|
11243
|
+
"automation_runs",
|
|
11244
|
+
{
|
|
11245
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11246
|
+
accountId: uuid("account_id").notNull(),
|
|
11247
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11248
|
+
sourceId: uuid("source_id").notNull(),
|
|
11249
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
11250
|
+
triggerRevision: integer("trigger_revision").notNull(),
|
|
11251
|
+
eventId: uuid("event_id").notNull(),
|
|
11252
|
+
occurrenceKey: text("occurrence_key").notNull(),
|
|
11253
|
+
acceptedExecution: jsonb("accepted_execution").$type<AutomationAcceptedExecution>().notNull(),
|
|
11254
|
+
status: text("status").notNull().default("queued"),
|
|
11255
|
+
sessionId: uuid("session_id").references(() => sessions.id, { onDelete: "set null" }),
|
|
11256
|
+
errorCode: text("error_code"),
|
|
11257
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11258
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11259
|
+
},
|
|
11260
|
+
(table) => ({
|
|
11261
|
+
triggerOccurrence: uniqueIndex("automation_runs_trigger_occurrence_uq").on(
|
|
11262
|
+
table.triggerId,
|
|
11263
|
+
table.occurrenceKey,
|
|
11264
|
+
),
|
|
11265
|
+
workspaceStatus: index("automation_runs_workspace_status_idx").on(
|
|
11266
|
+
table.workspaceId,
|
|
11267
|
+
table.status,
|
|
11268
|
+
table.createdAt,
|
|
11269
|
+
),
|
|
11270
|
+
workspaceTriggerIdentity: uniqueIndex("automation_runs_workspace_trigger_id_uq").on(
|
|
11271
|
+
table.workspaceId,
|
|
11272
|
+
table.triggerId,
|
|
11273
|
+
table.id,
|
|
11274
|
+
),
|
|
11275
|
+
source: foreignKey({
|
|
11276
|
+
columns: [table.workspaceId, table.sourceId],
|
|
11277
|
+
foreignColumns: [automationSources.workspaceId, automationSources.id],
|
|
11278
|
+
name: "automation_runs_source_fk",
|
|
11279
|
+
}).onDelete("restrict"),
|
|
11280
|
+
triggerSource: foreignKey({
|
|
11281
|
+
columns: [table.workspaceId, table.triggerId, table.sourceId],
|
|
11282
|
+
foreignColumns: [
|
|
11283
|
+
automationTriggers.workspaceId,
|
|
11284
|
+
automationTriggers.id,
|
|
11285
|
+
automationTriggers.sourceId,
|
|
11286
|
+
],
|
|
11287
|
+
name: "automation_runs_trigger_source_fk",
|
|
11288
|
+
}).onDelete("restrict"),
|
|
11289
|
+
triggerRevisionFk: foreignKey({
|
|
11290
|
+
columns: [table.triggerId, table.triggerRevision],
|
|
11291
|
+
foreignColumns: [automationTriggerRevisions.triggerId, automationTriggerRevisions.revision],
|
|
11292
|
+
name: "automation_runs_trigger_revision_fk",
|
|
11293
|
+
}).onDelete("restrict"),
|
|
11294
|
+
event: foreignKey({
|
|
11295
|
+
columns: [table.workspaceId, table.sourceId, table.eventId],
|
|
11296
|
+
foreignColumns: [
|
|
11297
|
+
automationTriggerEvents.workspaceId,
|
|
11298
|
+
automationTriggerEvents.sourceId,
|
|
11299
|
+
automationTriggerEvents.id,
|
|
11300
|
+
],
|
|
11301
|
+
name: "automation_runs_event_fk",
|
|
11302
|
+
}).onDelete("restrict"),
|
|
11303
|
+
workspaceAccount: foreignKey({
|
|
11304
|
+
columns: [table.workspaceId, table.accountId],
|
|
11305
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11306
|
+
name: "automation_runs_workspace_account_fk",
|
|
11307
|
+
}).onDelete("cascade"),
|
|
11308
|
+
shape: check(
|
|
11309
|
+
"automation_runs_shape_chk",
|
|
11310
|
+
sql`${table.triggerRevision} > 0
|
|
11311
|
+
and ${table.status} in ('queued', 'dispatching', 'dispatched', 'skipped', 'failed')
|
|
11312
|
+
and octet_length(${table.occurrenceKey}) between 1 and 1024
|
|
11313
|
+
and jsonb_typeof(${table.acceptedExecution}) = 'object'`,
|
|
11314
|
+
),
|
|
11315
|
+
}),
|
|
11316
|
+
);
|
|
11317
|
+
|
|
11318
|
+
export const automationRunEventLinks = pgTable(
|
|
11319
|
+
"automation_run_event_links",
|
|
11320
|
+
{
|
|
11321
|
+
runId: uuid("run_id")
|
|
11322
|
+
.notNull()
|
|
11323
|
+
.references(() => automationRuns.id, { onDelete: "cascade" }),
|
|
11324
|
+
eventId: uuid("event_id")
|
|
11325
|
+
.notNull()
|
|
11326
|
+
.references(() => automationTriggerEvents.id, { onDelete: "cascade" }),
|
|
11327
|
+
accountId: uuid("account_id").notNull(),
|
|
11328
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11329
|
+
sourceId: uuid("source_id").notNull(),
|
|
11330
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
11331
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11332
|
+
},
|
|
11333
|
+
(table) => ({
|
|
11334
|
+
identity: primaryKey({ columns: [table.runId, table.eventId] }),
|
|
11335
|
+
eventTrigger: uniqueIndex("automation_run_event_links_event_trigger_uq").on(
|
|
11336
|
+
table.eventId,
|
|
11337
|
+
table.triggerId,
|
|
11338
|
+
),
|
|
11339
|
+
run: foreignKey({
|
|
11340
|
+
columns: [table.workspaceId, table.triggerId, table.runId],
|
|
11341
|
+
foreignColumns: [automationRuns.workspaceId, automationRuns.triggerId, automationRuns.id],
|
|
11342
|
+
name: "automation_run_event_links_run_fk",
|
|
11343
|
+
}).onDelete("cascade"),
|
|
11344
|
+
event: foreignKey({
|
|
11345
|
+
columns: [table.workspaceId, table.sourceId, table.eventId],
|
|
11346
|
+
foreignColumns: [
|
|
11347
|
+
automationTriggerEvents.workspaceId,
|
|
11348
|
+
automationTriggerEvents.sourceId,
|
|
11349
|
+
automationTriggerEvents.id,
|
|
11350
|
+
],
|
|
11351
|
+
name: "automation_run_event_links_event_fk",
|
|
11352
|
+
}).onDelete("cascade"),
|
|
11353
|
+
workspaceAccount: foreignKey({
|
|
11354
|
+
columns: [table.workspaceId, table.accountId],
|
|
11355
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11356
|
+
name: "automation_run_event_links_workspace_account_fk",
|
|
11357
|
+
}).onDelete("cascade"),
|
|
11358
|
+
}),
|
|
11359
|
+
);
|
|
11360
|
+
|
|
8482
11361
|
export const workspacePacks = pgTable(
|
|
8483
11362
|
"workspace_packs",
|
|
8484
11363
|
{
|
|
@@ -9223,22 +12102,31 @@ export const rigs = pgTable(
|
|
|
9223
12102
|
description: text("description"),
|
|
9224
12103
|
// Attribution string: 'user:<subject>' | 'session:<id>' | 'system'.
|
|
9225
12104
|
createdBy: text("created_by"),
|
|
9226
|
-
// Inert migration-0230 identity foundation. Existing DAO/API/runtime paths
|
|
9227
|
-
// omit these fields and keep their historical workspace authority.
|
|
9228
12105
|
authorityScope: text("authority_scope").notNull().default("workspace"),
|
|
9229
12106
|
authorityId: uuid("authority_id"),
|
|
9230
12107
|
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
9231
12108
|
originWorkspaceId: uuid("origin_workspace_id"),
|
|
12109
|
+
generation: bigint("generation", { mode: "number" }).notNull().default(1),
|
|
12110
|
+
status: text("status").notNull().default("active"),
|
|
12111
|
+
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
9232
12112
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9233
12113
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9234
12114
|
},
|
|
9235
12115
|
(table) => ({
|
|
9236
|
-
workspaceName: uniqueIndex("
|
|
12116
|
+
workspaceName: uniqueIndex("rigs_workspace_name_active_idx")
|
|
12117
|
+
.on(table.workspaceId, table.name)
|
|
12118
|
+
.where(sql`${table.authorityScope} = 'workspace' and ${table.status} = 'active'`),
|
|
12119
|
+
organizationName: uniqueIndex("rigs_organization_name_active_idx")
|
|
12120
|
+
.on(table.accountId, table.name)
|
|
12121
|
+
.where(sql`${table.authorityScope} = 'organization' and ${table.status} = 'active'`),
|
|
12122
|
+
userName: uniqueIndex("rigs_user_name_active_idx")
|
|
12123
|
+
.on(table.accountId, table.ownerOrganizationMembershipId, table.name)
|
|
12124
|
+
.where(sql`${table.authorityScope} = 'user' and ${table.status} = 'active'`),
|
|
9237
12125
|
workspaceCreated: index("rigs_workspace_created_idx").on(table.workspaceId, table.createdAt),
|
|
9238
12126
|
authorityShape: check(
|
|
9239
12127
|
"rigs_authority_shape_check",
|
|
9240
12128
|
sql`(
|
|
9241
|
-
${table.authorityScope}
|
|
12129
|
+
${table.authorityScope} in ('organization', 'workspace')
|
|
9242
12130
|
and ${table.authorityId} is null
|
|
9243
12131
|
and ${table.ownerOrganizationMembershipId} is null
|
|
9244
12132
|
) or (
|
|
@@ -9249,7 +12137,14 @@ export const rigs = pgTable(
|
|
|
9249
12137
|
),
|
|
9250
12138
|
authorityScopeValid: check(
|
|
9251
12139
|
"rigs_authority_scope_check",
|
|
9252
|
-
sql`${table.authorityScope} in ('workspace', 'user')`,
|
|
12140
|
+
sql`${table.authorityScope} in ('organization', 'workspace', 'user')`,
|
|
12141
|
+
),
|
|
12142
|
+
generationPositive: check("rigs_generation_check", sql`${table.generation} > 0`),
|
|
12143
|
+
statusValid: check("rigs_status_check", sql`${table.status} in ('active', 'revoked')`),
|
|
12144
|
+
revocationShape: check(
|
|
12145
|
+
"rigs_revocation_check",
|
|
12146
|
+
sql`(${table.status} = 'active' and ${table.revokedAt} is null)
|
|
12147
|
+
or (${table.status} = 'revoked' and ${table.revokedAt} is not null)`,
|
|
9253
12148
|
),
|
|
9254
12149
|
authority: foreignKey({
|
|
9255
12150
|
name: "rigs_authority_fk",
|
|
@@ -9367,6 +12262,9 @@ export * from "./preference-registry-schema";
|
|
|
9367
12262
|
export * from "./memory-governance-schema";
|
|
9368
12263
|
export * from "./scoped-knowledge-schema";
|
|
9369
12264
|
export * from "./task-notes-schema";
|
|
12265
|
+
export * from "./company-brain-context-selection-schema";
|
|
12266
|
+
export * from "./governed-learning-evaluator-schema";
|
|
12267
|
+
export * from "./governed-learning-activation-schema";
|
|
9370
12268
|
export * from "./knowledge-source-sync-schema";
|
|
9371
12269
|
export * from "./transcription-recordings-schema";
|
|
9372
12270
|
export * from "./interaction-schema";
|