@opengeni/db 1.0.1 → 3.2.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-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
- package/dist/chunk-2EH4WRHL.js.map +1 -0
- package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
- package/dist/chunk-6HMM2R5T.js +390 -0
- package/dist/chunk-6HMM2R5T.js.map +1 -0
- package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
- package/dist/chunk-AZHW7R5V.js.map +1 -0
- package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
- package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
- package/dist/chunk-KRLPEMLH.js.map +1 -0
- package/dist/chunk-NAB6FKFN.js +516 -0
- package/dist/chunk-NAB6FKFN.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-UZNXG44K.js +4508 -0
- package/dist/chunk-UZNXG44K.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 +85 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +23 -4
- package/dist/editable-artifact-durable-export.js +2 -2
- 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 +1606 -81
- package/dist/index.js +21898 -8147
- 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/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 +29 -8
- package/dist/schema.d.ts +24914 -13703
- package/dist/schema.js +99 -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 +43 -4
- package/dist/session-realtime-ledger.d.ts +2 -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 +268 -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 +28 -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/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -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/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
- package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
- package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
- package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
- package/drizzle/0346_document_migration_audit_surface.sql +454 -0
- package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -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 +167 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +87 -2
- 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 +11676 -1550
- 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/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 +995 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +905 -6
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1317 -72
- package/src/schema.ts +3316 -428
- 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 +441 -85
- package/src/session-realtime-context.ts +4 -6
- package/src/session-realtime-ledger.ts +28 -14
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +410 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +867 -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 +138 -11
- 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-4SR4HKKA.js.map +0 -1
- package/dist/chunk-6ZYKCRFO.js.map +0 -1
- package/dist/chunk-NXAFLCQX.js +0 -2468
- package/dist/chunk-NXAFLCQX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-WD5ROSLL.js +0 -117
- package/dist/chunk-WD5ROSLL.js.map +0 -1
- package/dist/chunk-ZWREYEWA.js.map +0 -1
- /package/dist/{chunk-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
- /package/dist/{chunk-LTG3S6ZY.js.map → chunk-E6CLMKEE.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
|
-
|
|
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
|
+
],
|
|
921
|
+
}),
|
|
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
|
+
],
|
|
970
|
+
}),
|
|
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 }),
|
|
1047
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1048
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1049
|
+
},
|
|
1050
|
+
(table) => ({
|
|
1051
|
+
accountIdentity: uniqueIndex("organization_user_resource_authorities_id_account_idx").on(
|
|
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 }),
|
|
732
1253
|
status: text("status").notNull().default("active"), // active | needs_relogin | error
|
|
733
1254
|
lastError: text("last_error"),
|
|
734
1255
|
version: integer("version").notNull().default(1),
|
|
735
|
-
label: text("label"), // user-chosen nickname; null ⇒ derive from email/plan/account
|
|
736
|
-
accountEmail: text("account_email"), // email from the id_token (user's own email; non-secret)
|
|
737
|
-
// P2 usage cache (plaintext metadata; NEVER a token). Snapshotted from
|
|
738
|
-
// GET /wham/usage; drives the quota bars + the cache TTL. primary = 5h window
|
|
739
|
-
// (limit_window_seconds 18000), secondary = weekly (604800).
|
|
740
|
-
primaryUsedPercent: integer("primary_used_percent"),
|
|
741
|
-
primaryResetAt: timestamp("primary_reset_at", { withTimezone: true }),
|
|
742
|
-
secondaryUsedPercent: integer("secondary_used_percent"),
|
|
743
|
-
secondaryResetAt: timestamp("secondary_reset_at", { withTimezone: true }),
|
|
744
|
-
usageCheckedAt: timestamp("usage_checked_at", { withTimezone: true }), // snapshot freshness → cache TTL clock
|
|
745
|
-
// P3 rotation cooldown (plaintext metadata; NEVER a token). Set when this account hit its
|
|
746
|
-
// usage cap on a rotation turn; the rotation engine treats `exhausted_until > now()` as
|
|
747
|
-
// capped/skip so it isn't immediately re-picked. Self-clears via the now() comparison.
|
|
748
|
-
exhaustedUntil: timestamp("exhausted_until", { withTimezone: true }),
|
|
749
|
-
// Workspace-local, server-held fairness cursor. Provider usage headers are
|
|
750
|
-
// capacity hints, never the sole allocator: live lease count is ranked first
|
|
751
|
-
// and this cursor deterministically breaks equal-load/equal-capacity ties.
|
|
752
|
-
// This flag controls NEW automatic allocations only. Credential health,
|
|
753
|
-
// refresh, encrypted material, and an already-leased in-flight turn are
|
|
754
|
-
// intentionally independent. account eligibility policy owns toggle OCC/audit and product UI.
|
|
755
|
-
allocatorEnabled: boolean("allocator_enabled").notNull().default(true),
|
|
756
|
-
// Independent OCC/audit sequence for the allocator toggle. Token refresh
|
|
757
|
-
// continues to own `version`; quota/cache writes own neither counter.
|
|
758
|
-
allocatorVersion: integer("allocator_version").notNull().default(1),
|
|
759
|
-
allocatorUpdatedBySubjectId: text("allocator_updated_by_subject_id"),
|
|
760
|
-
allocatorUpdatedAt: timestamp("allocator_updated_at", {
|
|
761
|
-
withTimezone: true,
|
|
762
|
-
}),
|
|
763
|
-
// Authoritative count-only summary cached from /wham/usage. Detailed rows
|
|
764
|
-
// are never persisted as redemption authority; every first POST preflights
|
|
765
|
-
// the provider's fresh detail endpoint.
|
|
766
|
-
resetCreditAvailableCount: integer("reset_credit_available_count"),
|
|
767
|
-
resetCreditsCheckedAt: timestamp("reset_credits_checked_at", {
|
|
768
|
-
withTimezone: true,
|
|
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],
|
|
769
1712
|
}),
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
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"),
|
|
775
1799
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
776
1800
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
777
1801
|
},
|
|
778
1802
|
(table) => ({
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
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(
|
|
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(
|
|
790
1808
|
table.workspaceId,
|
|
791
|
-
table.
|
|
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)`,
|
|
792
1825
|
),
|
|
793
|
-
|
|
794
|
-
"
|
|
795
|
-
|
|
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')`,
|
|
1833
|
+
),
|
|
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,120 @@ 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
|
+
// One live card per person per conversation. The existing uniques are keyed
|
|
2064
|
+
// to the originating event, so they stop Slack's retries of ONE event from
|
|
2065
|
+
// posting twice but not two different messages. `slackUserId` is in the key
|
|
2066
|
+
// on purpose: a shared channel has many people in it, and asking one of them
|
|
2067
|
+
// must not swallow another's request. A direct message is already one
|
|
2068
|
+
// channel per person, so the same index covers both surfaces.
|
|
2069
|
+
//
|
|
2070
|
+
// Expiry is not in the predicate because `now()` is not immutable. A
|
|
2071
|
+
// timed-out row is settled `expired` by the writer before it opens a new
|
|
2072
|
+
// prompt.
|
|
2073
|
+
pendingConversation: uniqueIndex("slack_route_prompts_pending_conversation_uq")
|
|
2074
|
+
.on(table.connectionId, table.slackChannelId, table.slackUserId)
|
|
2075
|
+
.where(sql`${table.status} = 'pending'`),
|
|
2076
|
+
statusValid: check(
|
|
2077
|
+
"slack_route_prompts_status_check",
|
|
2078
|
+
sql`${table.status} in ('pending', 'answered', 'expired', 'cancelled')`,
|
|
2079
|
+
),
|
|
2080
|
+
triggerValid: check(
|
|
2081
|
+
"slack_route_prompts_trigger_check",
|
|
2082
|
+
sql`${table.triggerKind} in (
|
|
2083
|
+
'app_mention', 'dm', 'reaction', 'slash_command',
|
|
2084
|
+
'message_shortcut', 'thread_reply', 'block_action'
|
|
2085
|
+
)`,
|
|
2086
|
+
),
|
|
2087
|
+
answerConsistent: check(
|
|
2088
|
+
"slack_route_prompts_answer_check",
|
|
2089
|
+
sql`(${table.status} = 'answered') = (${table.answeredTargetWorkspaceId} is not null)
|
|
2090
|
+
and (${table.answeredTargetAccountId} is null) = (${table.answeredTargetWorkspaceId} is null)
|
|
2091
|
+
and (${table.answeredTargetAccountId} is null
|
|
2092
|
+
or ${table.answeredTargetAccountId} = ${table.accountId})
|
|
2093
|
+
and (${table.answeredTargetWorkspaceId} is null) = (${table.answeredAt} is null)`,
|
|
2094
|
+
),
|
|
2095
|
+
bounded: check(
|
|
2096
|
+
"slack_route_prompts_bounds_check",
|
|
2097
|
+
sql`octet_length(${table.slackTeamId}) between 1 and 64
|
|
2098
|
+
and octet_length(${table.slackUserId}) between 1 and 64
|
|
2099
|
+
and octet_length(${table.slackChannelId}) between 1 and 64
|
|
2100
|
+
and octet_length(${table.slackMessageTs}) between 1 and 64
|
|
2101
|
+
and octet_length(${table.providerEventId}) between 1 and 256
|
|
2102
|
+
and octet_length(${table.requestText}) between 1 and 12000
|
|
2103
|
+
and (${table.slackThreadTs} is null
|
|
2104
|
+
or octet_length(${table.slackThreadTs}) between 1 and 64)
|
|
2105
|
+
and (${table.answeredBySubjectId} is null
|
|
2106
|
+
or octet_length(${table.answeredBySubjectId}) between 1 and 1024)`,
|
|
973
2107
|
),
|
|
974
2108
|
}),
|
|
975
2109
|
);
|
|
976
2110
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
2111
|
+
/**
|
|
2112
|
+
* One row per workspace offered by a {@link slackRoutePrompts} card. The row id
|
|
2113
|
+
* is the Slack button `value`, so it must be a UUID: the block-action normalizer
|
|
2114
|
+
* already requires that shape, which is why the picker uses buttons rather than
|
|
2115
|
+
* a `static_select` (whose `selected_option.value` the normalizer never reads).
|
|
2116
|
+
*
|
|
2117
|
+
* These rows are a snapshot taken at prompt time and are NEVER authority. The
|
|
2118
|
+
* answer path re-authorizes the chosen workspace live.
|
|
2119
|
+
*/
|
|
2120
|
+
export const slackRoutePromptOptions = pgTable(
|
|
2121
|
+
"slack_route_prompt_options",
|
|
983
2122
|
{
|
|
984
2123
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
985
2124
|
accountId: uuid("account_id")
|
|
@@ -988,55 +2127,54 @@ export const slackInstallationBindings = pgTable(
|
|
|
988
2127
|
workspaceId: uuid("workspace_id")
|
|
989
2128
|
.notNull()
|
|
990
2129
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
991
|
-
|
|
2130
|
+
promptId: uuid("prompt_id").notNull(),
|
|
2131
|
+
candidateAccountId: uuid("candidate_account_id")
|
|
992
2132
|
.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"),
|
|
2133
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
2134
|
+
candidateWorkspaceId: uuid("candidate_workspace_id")
|
|
2135
|
+
.notNull()
|
|
2136
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
2137
|
+
candidateLabel: text("candidate_label").notNull(),
|
|
2138
|
+
position: integer("position").notNull(),
|
|
1004
2139
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1005
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1006
2140
|
},
|
|
1007
2141
|
(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
2142
|
workspaceAccount: foreignKey({
|
|
1018
|
-
name: "
|
|
2143
|
+
name: "slack_route_prompt_options_workspace_account_fk",
|
|
1019
2144
|
columns: [table.workspaceId, table.accountId],
|
|
1020
2145
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
1021
2146
|
}).onDelete("cascade"),
|
|
1022
|
-
|
|
1023
|
-
"
|
|
1024
|
-
|
|
2147
|
+
promptIdentity: foreignKey({
|
|
2148
|
+
name: "slack_route_prompt_options_prompt_fk",
|
|
2149
|
+
columns: [table.accountId, table.workspaceId, table.promptId],
|
|
2150
|
+
foreignColumns: [
|
|
2151
|
+
slackRoutePrompts.accountId,
|
|
2152
|
+
slackRoutePrompts.workspaceId,
|
|
2153
|
+
slackRoutePrompts.id,
|
|
2154
|
+
],
|
|
2155
|
+
}).onDelete("cascade"),
|
|
2156
|
+
candidateWorkspaceAccount: foreignKey({
|
|
2157
|
+
name: "slack_route_prompt_options_candidate_workspace_account_fk",
|
|
2158
|
+
columns: [table.candidateWorkspaceId, table.candidateAccountId],
|
|
2159
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
2160
|
+
}).onDelete("cascade"),
|
|
2161
|
+
promptWorkspace: unique("slack_route_prompt_options_prompt_workspace_uq").on(
|
|
2162
|
+
table.promptId,
|
|
2163
|
+
table.candidateWorkspaceId,
|
|
1025
2164
|
),
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
or (${table.state} = 'quarantined' and length(btrim(${table.quarantineReason})) > 0)`,
|
|
2165
|
+
promptPosition: unique("slack_route_prompt_options_prompt_position_uq").on(
|
|
2166
|
+
table.promptId,
|
|
2167
|
+
table.position,
|
|
1030
2168
|
),
|
|
1031
|
-
|
|
1032
|
-
"
|
|
1033
|
-
sql
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
2169
|
+
sameAccount: check(
|
|
2170
|
+
"slack_route_prompt_options_same_account_check",
|
|
2171
|
+
sql`${table.candidateAccountId} = ${table.accountId}`,
|
|
2172
|
+
),
|
|
2173
|
+
bounded: check(
|
|
2174
|
+
"slack_route_prompt_options_bounds_check",
|
|
2175
|
+
sql`octet_length(${table.candidateLabel}) between 1 and 128
|
|
2176
|
+
and ${table.position} >= 0`,
|
|
1038
2177
|
),
|
|
1039
|
-
versionPositive: check("slack_installation_bindings_version_check", sql`${table.version} > 0`),
|
|
1040
2178
|
}),
|
|
1041
2179
|
);
|
|
1042
2180
|
|
|
@@ -1143,6 +2281,9 @@ export const slackBotUserLinks = pgTable(
|
|
|
1143
2281
|
slackUserId: text("slack_user_id").notNull(),
|
|
1144
2282
|
subjectId: text("subject_id").notNull(),
|
|
1145
2283
|
linkedBySubjectId: text("linked_by_subject_id").notNull(),
|
|
2284
|
+
// The exact interaction id that won this identity's one-time onboarding
|
|
2285
|
+
// hint. NULL means the hint has not been shown yet.
|
|
2286
|
+
firstTaskHintInteractionId: uuid("first_task_hint_interaction_id"),
|
|
1146
2287
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1147
2288
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1148
2289
|
},
|
|
@@ -1368,6 +2509,21 @@ export const slackInteractionInbox = pgTable(
|
|
|
1368
2509
|
retryAt: timestamp("retry_at", { withTimezone: true }),
|
|
1369
2510
|
lastErrorCode: text("last_error_code"),
|
|
1370
2511
|
reactionContextCheckpoint: jsonb("reaction_context_checkpoint").$type<unknown>(),
|
|
2512
|
+
// Workspace routing decision, persisted on the claimed row so a retry after
|
|
2513
|
+
// a crash re-uses the same decision rather than re-asking. `accountId` and
|
|
2514
|
+
// `workspaceId` above stay HOME (the installation's credential tenancy) and
|
|
2515
|
+
// stay NOT NULL: `workspace_rls_visible` is strict equality, so a NULL
|
|
2516
|
+
// workspace would make an un-routed row invisible to every tenant including
|
|
2517
|
+
// its own. NULL `routeState` means "legacy / never routed" and is exactly
|
|
2518
|
+
// pre-routing behaviour.
|
|
2519
|
+
routeState: text("route_state").$type<"resolved" | "awaiting_choice" | "denied">(),
|
|
2520
|
+
// Deliberately no foreign key: an inbox row is short-lived and
|
|
2521
|
+
// definer-claimed, so a runtime re-check degrades to "ask again" while an FK
|
|
2522
|
+
// would hard-fail on a workspace deleted mid-flight.
|
|
2523
|
+
targetAccountId: uuid("target_account_id"),
|
|
2524
|
+
targetWorkspaceId: uuid("target_workspace_id"),
|
|
2525
|
+
routePromptId: uuid("route_prompt_id"),
|
|
2526
|
+
routePromptExpiresAt: timestamp("route_prompt_expires_at", { withTimezone: true }),
|
|
1371
2527
|
processedAt: timestamp("processed_at", { withTimezone: true }),
|
|
1372
2528
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1373
2529
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -1390,6 +2546,73 @@ export const slackInteractionInbox = pgTable(
|
|
|
1390
2546
|
}),
|
|
1391
2547
|
);
|
|
1392
2548
|
|
|
2549
|
+
// Coalesced private App Home refresh authority. One row per installed Slack
|
|
2550
|
+
// connection/user serializes provider replacement calls while allowing event
|
|
2551
|
+
// retries and newer opens to converge on the latest requested revision.
|
|
2552
|
+
export const slackAppHomeRefreshes = pgTable(
|
|
2553
|
+
"slack_app_home_refreshes",
|
|
2554
|
+
{
|
|
2555
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
2556
|
+
accountId: uuid("account_id")
|
|
2557
|
+
.notNull()
|
|
2558
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
2559
|
+
workspaceId: uuid("workspace_id")
|
|
2560
|
+
.notNull()
|
|
2561
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
2562
|
+
connectionId: uuid("connection_id")
|
|
2563
|
+
.notNull()
|
|
2564
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
2565
|
+
slackTeamId: text("slack_team_id").notNull(),
|
|
2566
|
+
slackUserId: text("slack_user_id").notNull(),
|
|
2567
|
+
providerEventId: text("provider_event_id").notNull(),
|
|
2568
|
+
providerViewHash: text("provider_view_hash"),
|
|
2569
|
+
desiredRevision: integer("desired_revision").notNull().default(1),
|
|
2570
|
+
processedRevision: integer("processed_revision").notNull().default(0),
|
|
2571
|
+
claimHolderId: uuid("claim_holder_id"),
|
|
2572
|
+
claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
|
|
2573
|
+
attemptCount: integer("attempt_count").notNull().default(0),
|
|
2574
|
+
retryAt: timestamp("retry_at", { withTimezone: true }),
|
|
2575
|
+
lastErrorCode: text("last_error_code"),
|
|
2576
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2577
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2578
|
+
},
|
|
2579
|
+
(table) => ({
|
|
2580
|
+
connectionUser: uniqueIndex("slack_app_home_refreshes_connection_user_uq").on(
|
|
2581
|
+
table.connectionId,
|
|
2582
|
+
table.slackUserId,
|
|
2583
|
+
),
|
|
2584
|
+
pending: index("slack_app_home_refreshes_pending_idx")
|
|
2585
|
+
.on(table.retryAt, table.updatedAt, table.id)
|
|
2586
|
+
.where(sql`${table.processedRevision} < ${table.desiredRevision}`),
|
|
2587
|
+
workspaceAccount: foreignKey({
|
|
2588
|
+
name: "slack_app_home_refreshes_workspace_account_fk",
|
|
2589
|
+
columns: [table.workspaceId, table.accountId],
|
|
2590
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
2591
|
+
}).onDelete("cascade"),
|
|
2592
|
+
bounds: check(
|
|
2593
|
+
"slack_app_home_refreshes_bounds_check",
|
|
2594
|
+
sql`octet_length(${table.slackTeamId}) between 1 and 64
|
|
2595
|
+
and octet_length(${table.slackUserId}) between 1 and 64
|
|
2596
|
+
and octet_length(${table.providerEventId}) between 1 and 256
|
|
2597
|
+
and (${table.providerViewHash} is null
|
|
2598
|
+
or octet_length(${table.providerViewHash}) between 1 and 256)
|
|
2599
|
+
and (${table.lastErrorCode} is null
|
|
2600
|
+
or octet_length(${table.lastErrorCode}) between 1 and 128)`,
|
|
2601
|
+
),
|
|
2602
|
+
revisions: check(
|
|
2603
|
+
"slack_app_home_refreshes_revisions_check",
|
|
2604
|
+
sql`${table.desiredRevision} > 0
|
|
2605
|
+
and ${table.processedRevision} >= 0
|
|
2606
|
+
and ${table.processedRevision} <= ${table.desiredRevision}
|
|
2607
|
+
and ${table.attemptCount} >= 0`,
|
|
2608
|
+
),
|
|
2609
|
+
claim: check(
|
|
2610
|
+
"slack_app_home_refreshes_claim_check",
|
|
2611
|
+
sql`(${table.claimHolderId} is null) = (${table.claimExpiresAt} is null)`,
|
|
2612
|
+
),
|
|
2613
|
+
}),
|
|
2614
|
+
);
|
|
2615
|
+
|
|
1393
2616
|
export const slackInteractions = pgTable(
|
|
1394
2617
|
"slack_interactions",
|
|
1395
2618
|
{
|
|
@@ -1426,6 +2649,15 @@ export const slackInteractions = pgTable(
|
|
|
1426
2649
|
deliveryRetryAt: timestamp("delivery_retry_at", { withTimezone: true }),
|
|
1427
2650
|
deliveryLastErrorCode: text("delivery_last_error_code"),
|
|
1428
2651
|
ackSlackMessageTs: text("ack_slack_message_ts"),
|
|
2652
|
+
// Frozen once: whether this interaction's acknowledgement renders the
|
|
2653
|
+
// one-time onboarding hint. NULL means the decision has not been resolved.
|
|
2654
|
+
firstTaskHint: boolean("first_task_hint"),
|
|
2655
|
+
// The routed workspace's display name, frozen when the interaction binds.
|
|
2656
|
+
// A live lookup at post time would be wrong: a workspace rename between the
|
|
2657
|
+
// original post and a reconciliation makes `reconcilePostMessage`'s
|
|
2658
|
+
// byte-compare raise `post_reconciliation_mismatch`. NULL means no
|
|
2659
|
+
// per-message workspace line.
|
|
2660
|
+
routedWorkspaceLabel: text("routed_workspace_label"),
|
|
1429
2661
|
progressCount: integer("progress_count").notNull().default(0),
|
|
1430
2662
|
terminalDeliveryState: text("terminal_delivery_state")
|
|
1431
2663
|
.$type<"open" | "completed" | "failed" | "cancelled" | "blocked">()
|
|
@@ -2440,6 +3672,9 @@ export const channels = pgTable(
|
|
|
2440
3672
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
2441
3673
|
name: text("name").notNull(),
|
|
2442
3674
|
description: text("description"),
|
|
3675
|
+
pinned: boolean("pinned").notNull().default(false),
|
|
3676
|
+
// Explicit user order within the pinned and unpinned project groups.
|
|
3677
|
+
sortOrder: integer("sort_order").notNull().default(0),
|
|
2443
3678
|
// Attribution string: 'user:<subject>' | 'session:<id>' | 'system'.
|
|
2444
3679
|
createdBy: text("created_by"),
|
|
2445
3680
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -2500,6 +3735,9 @@ export const sessions = pgTable(
|
|
|
2500
3735
|
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
2501
3736
|
ownerSubjectId: text("owner_subject_id"),
|
|
2502
3737
|
visibility: text("visibility").notNull().default("workspace_shared"),
|
|
3738
|
+
createRequestedVisibility: text("create_requested_visibility")
|
|
3739
|
+
.notNull()
|
|
3740
|
+
.default("workspace_shared"),
|
|
2503
3741
|
authorityEpoch: integer("authority_epoch").notNull().default(1),
|
|
2504
3742
|
// Independent-copy provenance. A destination may use either visibility and
|
|
2505
3743
|
// may live in another workspace in the same organization; no live process,
|
|
@@ -2510,6 +3748,10 @@ export const sessions = pgTable(
|
|
|
2510
3748
|
forkedAt: timestamp("forked_at", { withTimezone: true }),
|
|
2511
3749
|
forkedByOrganizationMembershipId: uuid("forked_by_organization_membership_id"),
|
|
2512
3750
|
model: text("model").notNull(),
|
|
3751
|
+
// Immutable session-default execution policy. Follow-up composer drafts and
|
|
3752
|
+
// accepted turns are separate authorities and never mutate these columns.
|
|
3753
|
+
reasoningEffort: text("reasoning_effort").notNull(),
|
|
3754
|
+
latencyMode: text("latency_mode").notNull(),
|
|
2513
3755
|
sandboxBackend: text("sandbox_backend").notNull(),
|
|
2514
3756
|
// The OS this session's box runs. Defaults to 'linux' (today's only OS, so
|
|
2515
3757
|
// every existing + new row is a behavior-preserving no-op). CHECK-constrained
|
|
@@ -2539,13 +3781,10 @@ export const sessions = pgTable(
|
|
|
2539
3781
|
// sandbox. integer (NOT bigint) — the lease-epoch spike: int8 reads back as a
|
|
2540
3782
|
// JS string and breaks the strict fence; int4 returns a number.
|
|
2541
3783
|
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).
|
|
3784
|
+
// The session's effective absolute Connected Machine root. New attaches
|
|
3785
|
+
// resolve an optional relative request against the persisted Hello root and
|
|
3786
|
+
// write the result through the epoch-fenced setActiveSandbox CAS. Legacy
|
|
3787
|
+
// rows may still be null/relative and are resolved at establishment.
|
|
2549
3788
|
workingDir: text("working_dir"),
|
|
2550
3789
|
variableSetId: uuid("variable_set_id").references(() => workspaceVariableSets.id, {
|
|
2551
3790
|
onDelete: "set null",
|
|
@@ -2577,6 +3816,12 @@ export const sessions = pgTable(
|
|
|
2577
3816
|
.$type<McpPersonalConnectionDelegation[]>()
|
|
2578
3817
|
.notNull()
|
|
2579
3818
|
.default([]),
|
|
3819
|
+
// Initial accepted-work staging only. The initializer consumes this inside
|
|
3820
|
+
// the same transaction that inserts the first logical turn and grant
|
|
3821
|
+
// snapshots; runtime never authorizes from the session field.
|
|
3822
|
+
initialPersonalResourceAttachmentIntent: jsonb(
|
|
3823
|
+
"initial_personal_resource_attachment_intent",
|
|
3824
|
+
).$type<PersonalResourceAttachmentIntent>(),
|
|
2580
3825
|
initialXaiProviderAccountAuthoritySnapshot: jsonb(
|
|
2581
3826
|
"initial_xai_provider_account_authority_snapshot",
|
|
2582
3827
|
)
|
|
@@ -2593,8 +3838,8 @@ export const sessions = pgTable(
|
|
|
2593
3838
|
// spawning a worker); null for direct API creates and scheduled-task runs.
|
|
2594
3839
|
// When set, this worker's terminal-for-now transitions wake the parent so a
|
|
2595
3840
|
// manager can orchestrate workers without busy-polling. The migration-owned
|
|
2596
|
-
// self-reference uses ON DELETE
|
|
2597
|
-
//
|
|
3841
|
+
// self-reference uses ON DELETE CASCADE so the explicit quiescent root-tree
|
|
3842
|
+
// deletion lifecycle removes the complete hierarchy atomically.
|
|
2598
3843
|
parentSessionId: uuid("parent_session_id"),
|
|
2599
3844
|
// Exact parent turn whose worker-signed attempt created this child. This is
|
|
2600
3845
|
// private immutable authority lineage: child completion copies personal MCP
|
|
@@ -2676,6 +3921,14 @@ export const sessions = pgTable(
|
|
|
2676
3921
|
}),
|
|
2677
3922
|
},
|
|
2678
3923
|
(table) => ({
|
|
3924
|
+
reasoningEffortValid: check(
|
|
3925
|
+
"sessions_reasoning_effort_check",
|
|
3926
|
+
sql`${table.reasoningEffort} in ('none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max')`,
|
|
3927
|
+
),
|
|
3928
|
+
latencyModeValid: check(
|
|
3929
|
+
"sessions_latency_mode_check",
|
|
3930
|
+
sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
|
|
3931
|
+
),
|
|
2679
3932
|
accountIdentity: uniqueIndex("sessions_id_account_idx").on(table.id, table.accountId),
|
|
2680
3933
|
workspaceIdentity: uniqueIndex("sessions_workspace_id_idx").on(table.workspaceId, table.id),
|
|
2681
3934
|
workspaceCreated: index("sessions_workspace_created_idx").on(
|
|
@@ -2802,6 +4055,18 @@ export const organizationUserResourceGrants = pgTable(
|
|
|
2802
4055
|
table.workspaceId,
|
|
2803
4056
|
table.status,
|
|
2804
4057
|
),
|
|
4058
|
+
activeIdentity: uniqueIndex("organization_user_resource_grants_active_identity_uq")
|
|
4059
|
+
.on(
|
|
4060
|
+
table.accountId,
|
|
4061
|
+
table.authorityId,
|
|
4062
|
+
table.workspaceId,
|
|
4063
|
+
table.action,
|
|
4064
|
+
table.mode,
|
|
4065
|
+
table.context,
|
|
4066
|
+
sql`coalesce(${table.sessionId}, '00000000-0000-0000-0000-000000000000'::uuid)`,
|
|
4067
|
+
sql`coalesce(${table.authorityEpoch}, 0)`,
|
|
4068
|
+
)
|
|
4069
|
+
.where(sql`${table.status} = 'active'`),
|
|
2805
4070
|
authority: foreignKey({
|
|
2806
4071
|
name: "organization_user_resource_grants_authority_fk",
|
|
2807
4072
|
columns: [table.authorityId, table.accountId],
|
|
@@ -2954,7 +4219,7 @@ export const sessionRealtimeModes = pgTable(
|
|
|
2954
4219
|
),
|
|
2955
4220
|
endReasonValid: check(
|
|
2956
4221
|
"session_realtime_modes_end_reason_check",
|
|
2957
|
-
sql`${table.endReason} is null or ${table.endReason} in ('user_stop', 'browser_unload', 'lease_expired')`,
|
|
4222
|
+
sql`${table.endReason} is null or ${table.endReason} in ('user_stop', 'browser_unload', 'lease_expired', 'authority_revoked')`,
|
|
2958
4223
|
),
|
|
2959
4224
|
versionValid: check("session_realtime_modes_version_check", sql`${table.version} >= 1`),
|
|
2960
4225
|
epochValid: check("session_realtime_modes_epoch_check", sql`${table.connectionEpoch} >= 1`),
|
|
@@ -3257,10 +4522,11 @@ export const sessionSpawnDenials = pgTable(
|
|
|
3257
4522
|
}),
|
|
3258
4523
|
);
|
|
3259
4524
|
|
|
3260
|
-
// Per-authenticated-subject session organization. This is
|
|
3261
|
-
// relation instead of
|
|
3262
|
-
//
|
|
3263
|
-
// must remain agent/runtime truth.
|
|
4525
|
+
// Per-authenticated-subject session organization and follow-up state. This is
|
|
4526
|
+
// deliberately a relation instead of session columns: one member's pin,
|
|
4527
|
+
// acknowledgment, or actively-working label must never affect another member,
|
|
4528
|
+
// and a session's own activity timestamps must remain agent/runtime truth.
|
|
4529
|
+
// `subjectId` is the trusted AccessGrant
|
|
3264
4530
|
// subject, which is text because configured/delegated principals are not always
|
|
3265
4531
|
// UUIDs. The account/workspace pair carries the standard forced-RLS boundary.
|
|
3266
4532
|
export const sessionPins = pgTable(
|
|
@@ -3284,13 +4550,38 @@ export const sessionPins = pgTable(
|
|
|
3284
4550
|
pinned: boolean("pinned").notNull().default(true),
|
|
3285
4551
|
pinnedAt: timestamp("pinned_at", { withTimezone: true }).defaultNow(),
|
|
3286
4552
|
version: integer("version").notNull().default(1),
|
|
4553
|
+
// A session is unread for this subject whenever its durable event sequence
|
|
4554
|
+
// has advanced beyond this explicit acknowledgment fence. Merely opening a
|
|
4555
|
+
// route never changes the fence.
|
|
4556
|
+
acknowledgedSequence: integer("acknowledged_sequence").notNull().default(0),
|
|
4557
|
+
activelyWorking: boolean("actively_working").notNull().default(false),
|
|
4558
|
+
attentionVersion: integer("attention_version").notNull().default(0),
|
|
4559
|
+
archived: boolean("archived").notNull().default(false),
|
|
4560
|
+
archivedAt: timestamp("archived_at", { withTimezone: true }),
|
|
4561
|
+
archiveVersion: integer("archive_version").notNull().default(0),
|
|
3287
4562
|
},
|
|
3288
4563
|
(table) => ({
|
|
3289
4564
|
subjectNonempty: check(
|
|
3290
4565
|
"session_pins_subject_nonempty",
|
|
3291
4566
|
sql`length(btrim(${table.subjectId})) > 0`,
|
|
3292
4567
|
),
|
|
3293
|
-
|
|
4568
|
+
versionNonnegative: check("session_pins_version_nonnegative", sql`${table.version} >= 0`),
|
|
4569
|
+
acknowledgedSequenceFloor: check(
|
|
4570
|
+
"session_pins_acknowledged_sequence_floor",
|
|
4571
|
+
sql`${table.acknowledgedSequence} >= -1`,
|
|
4572
|
+
),
|
|
4573
|
+
attentionVersionNonnegative: check(
|
|
4574
|
+
"session_pins_attention_version_nonnegative",
|
|
4575
|
+
sql`${table.attentionVersion} >= 0`,
|
|
4576
|
+
),
|
|
4577
|
+
archiveVersionNonnegative: check(
|
|
4578
|
+
"session_pins_archive_version_nonnegative",
|
|
4579
|
+
sql`${table.archiveVersion} >= 0`,
|
|
4580
|
+
),
|
|
4581
|
+
archiveStateConsistent: check(
|
|
4582
|
+
"session_pins_archive_state_consistent",
|
|
4583
|
+
sql`((${table.archived}) and (${table.archivedAt}) is not null) or ((not ${table.archived}) and (${table.archivedAt}) is null)`,
|
|
4584
|
+
),
|
|
3294
4585
|
stateConsistent: check(
|
|
3295
4586
|
"session_pins_state_consistent",
|
|
3296
4587
|
sql`((${table.pinned}) and (${table.pinnedAt}) is not null) or ((not ${table.pinned}) and (${table.pinnedAt}) is null)`,
|
|
@@ -3317,15 +4608,22 @@ export const sessionPins = pgTable(
|
|
|
3317
4608
|
table.pinnedAt.desc(),
|
|
3318
4609
|
table.sessionId.desc(),
|
|
3319
4610
|
),
|
|
4611
|
+
subjectArchived: index("session_pins_workspace_subject_archived_idx").on(
|
|
4612
|
+
table.workspaceId,
|
|
4613
|
+
table.subjectId,
|
|
4614
|
+
table.archived,
|
|
4615
|
+
table.archivedAt.desc(),
|
|
4616
|
+
table.sessionId.desc(),
|
|
4617
|
+
),
|
|
3320
4618
|
}),
|
|
3321
4619
|
);
|
|
3322
4620
|
|
|
3323
|
-
//
|
|
3324
|
-
//
|
|
3325
|
-
//
|
|
3326
|
-
//
|
|
3327
|
-
//
|
|
3328
|
-
//
|
|
4621
|
+
// Rolling-compatibility storage for pre-keyset session-list cursors. New page
|
|
4622
|
+
// one reads freeze the committed workspace activity revision in an opaque
|
|
4623
|
+
// updated_at/id keyset and create no row here. Old API replicas and cursors may
|
|
4624
|
+
// retain an already-ordered id array for its short TTL, so current replicas keep
|
|
4625
|
+
// reading, visibility-stripping, member-cleaning, and reaping those rows until
|
|
4626
|
+
// the compatibility table is retired by a later migration.
|
|
3329
4627
|
export const sessionListSnapshots = pgTable(
|
|
3330
4628
|
"session_list_snapshots",
|
|
3331
4629
|
{
|
|
@@ -3335,6 +4633,7 @@ export const sessionListSnapshots = pgTable(
|
|
|
3335
4633
|
subjectId: text("subject_id").notNull(),
|
|
3336
4634
|
parentSessionFilter: text("parent_session_filter").notNull().default("all"),
|
|
3337
4635
|
search: text("search"),
|
|
4636
|
+
archiveMode: text("archive_mode").$type<"active" | "archived">().notNull().default("active"),
|
|
3338
4637
|
ordinarySessionIds: uuid("ordinary_session_ids")
|
|
3339
4638
|
.array()
|
|
3340
4639
|
.notNull()
|
|
@@ -3360,6 +4659,10 @@ export const sessionListSnapshots = pgTable(
|
|
|
3360
4659
|
"session_list_snapshots_search_length",
|
|
3361
4660
|
sql`${table.search} is null or length(${table.search}) <= 200`,
|
|
3362
4661
|
),
|
|
4662
|
+
archiveModeValid: check(
|
|
4663
|
+
"session_list_snapshots_archive_mode_valid",
|
|
4664
|
+
sql`${table.archiveMode} in ('active', 'archived')`,
|
|
4665
|
+
),
|
|
3363
4666
|
workspaceExpiry: index("session_list_snapshots_workspace_expiry_idx").on(
|
|
3364
4667
|
table.workspaceId,
|
|
3365
4668
|
table.subjectId,
|
|
@@ -4233,6 +5536,12 @@ export const documents = pgTable(
|
|
|
4233
5536
|
authorityKind: text("authority_kind").notNull().default("workspace"),
|
|
4234
5537
|
authorityWorkspaceId: uuid("authority_workspace_id"),
|
|
4235
5538
|
authoritySubjectId: text("authority_subject_id"),
|
|
5539
|
+
// Activated personal documents follow their organization membership across
|
|
5540
|
+
// workspaces. Legacy personal rows retain a null authority id and their
|
|
5541
|
+
// original workspace anchor; originWorkspaceId is provenance only.
|
|
5542
|
+
authorityId: uuid("authority_id"),
|
|
5543
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
5544
|
+
originWorkspaceId: uuid("origin_workspace_id").notNull(),
|
|
4236
5545
|
// Per-document access controls. visibility 'private' restricts human reads to
|
|
4237
5546
|
// created_by (a grant subject id, not a uuid); agent_access=false hides the
|
|
4238
5547
|
// document from agent retrieval surfaces (docs MCP) while humans keep REST.
|
|
@@ -4291,16 +5600,29 @@ export const documents = pgTable(
|
|
|
4291
5600
|
columns: [table.authorityWorkspaceId, table.accountId],
|
|
4292
5601
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
4293
5602
|
}).onDelete("restrict"),
|
|
5603
|
+
userAuthority: foreignKey({
|
|
5604
|
+
name: "documents_user_authority_fk",
|
|
5605
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
5606
|
+
foreignColumns: [
|
|
5607
|
+
organizationUserResourceAuthorities.id,
|
|
5608
|
+
organizationUserResourceAuthorities.accountId,
|
|
5609
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
5610
|
+
],
|
|
5611
|
+
}).onDelete("restrict"),
|
|
4294
5612
|
authorityState: check(
|
|
4295
5613
|
"documents_authority_chk",
|
|
4296
|
-
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null)
|
|
4297
|
-
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null)
|
|
4298
|
-
or (${table.authorityKind} = 'personal' and
|
|
5614
|
+
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5615
|
+
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5616
|
+
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)))`,
|
|
4299
5617
|
),
|
|
4300
5618
|
authorityVisibility: check(
|
|
4301
5619
|
"documents_authority_visibility_chk",
|
|
4302
5620
|
sql`(${table.authorityKind} = 'personal') = (${table.visibility} = 'private')`,
|
|
4303
5621
|
),
|
|
5622
|
+
originWorkspace: check(
|
|
5623
|
+
"documents_origin_workspace_chk",
|
|
5624
|
+
sql`${table.originWorkspaceId} = ${table.workspaceId}`,
|
|
5625
|
+
),
|
|
4304
5626
|
visibilityState: check(
|
|
4305
5627
|
"documents_visibility_chk",
|
|
4306
5628
|
sql`${table.visibility} in ('workspace', 'private')`,
|
|
@@ -4355,6 +5677,8 @@ export const documentChunks = pgTable(
|
|
|
4355
5677
|
authorityKind: text("authority_kind").notNull().default("workspace"),
|
|
4356
5678
|
authorityWorkspaceId: uuid("authority_workspace_id"),
|
|
4357
5679
|
authoritySubjectId: text("authority_subject_id"),
|
|
5680
|
+
authorityId: uuid("authority_id"),
|
|
5681
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
4358
5682
|
embedding: vector("embedding").notNull(),
|
|
4359
5683
|
embeddingModel: text("embedding_model").notNull(),
|
|
4360
5684
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -4377,11 +5701,20 @@ export const documentChunks = pgTable(
|
|
|
4377
5701
|
columns: [table.authorityWorkspaceId, table.accountId],
|
|
4378
5702
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
4379
5703
|
}).onDelete("restrict"),
|
|
5704
|
+
userAuthority: foreignKey({
|
|
5705
|
+
name: "document_chunks_user_authority_fk",
|
|
5706
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
5707
|
+
foreignColumns: [
|
|
5708
|
+
organizationUserResourceAuthorities.id,
|
|
5709
|
+
organizationUserResourceAuthorities.accountId,
|
|
5710
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
5711
|
+
],
|
|
5712
|
+
}).onDelete("restrict"),
|
|
4380
5713
|
authorityState: check(
|
|
4381
5714
|
"document_chunks_authority_chk",
|
|
4382
|
-
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null)
|
|
4383
|
-
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null)
|
|
4384
|
-
or (${table.authorityKind} = 'personal' and
|
|
5715
|
+
sql`(${table.authorityKind} = 'organization' and ${table.authorityWorkspaceId} is null and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5716
|
+
or (${table.authorityKind} = 'workspace' and ${table.authorityWorkspaceId} = ${table.workspaceId} and ${table.authoritySubjectId} is null and ${table.authorityId} is null and ${table.ownerOrganizationMembershipId} is null)
|
|
5717
|
+
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)))`,
|
|
4385
5718
|
),
|
|
4386
5719
|
}),
|
|
4387
5720
|
);
|
|
@@ -4510,6 +5843,12 @@ export const sessionTurns = pgTable(
|
|
|
4510
5843
|
temporalWorkflowId: text("temporal_workflow_id").notNull(),
|
|
4511
5844
|
status: text("status").notNull(),
|
|
4512
5845
|
source: text("source").notNull().default("user"),
|
|
5846
|
+
// Immutable user-facing admission intent. Physical execution still uses
|
|
5847
|
+
// status=queued until a worker claims the row; this field keeps that
|
|
5848
|
+
// implementation queue distinct from prompts genuinely waiting behind
|
|
5849
|
+
// other work. Null is reserved for rolling/legacy writers and non-human
|
|
5850
|
+
// turns, and is projected conservatively as visible queue work.
|
|
5851
|
+
promptRouting: text("prompt_routing"),
|
|
4513
5852
|
position: bigint("position", { mode: "number" }).notNull(),
|
|
4514
5853
|
prompt: losslessText("prompt").notNull(),
|
|
4515
5854
|
promptCodecVersion: losslessCodecVersion("prompt_codec_version"),
|
|
@@ -4564,15 +5903,28 @@ export const sessionTurns = pgTable(
|
|
|
4564
5903
|
.$type<McpPersonalConnectionDelegation[]>()
|
|
4565
5904
|
.notNull()
|
|
4566
5905
|
.default([]),
|
|
5906
|
+
// Credential-free public summary of a turn-bound personal Variable
|
|
5907
|
+
// Set/Rig attachment. Exact resource and grant identity lives only in the
|
|
5908
|
+
// immutable accepted-work snapshot tables.
|
|
5909
|
+
personalResourceAttachmentSummary: jsonb(
|
|
5910
|
+
"personal_resource_attachment_summary",
|
|
5911
|
+
).$type<PersonalResourceAttachmentSummary>(),
|
|
5912
|
+
// 0 = legacy attempt-selected authority; 1 = immutable logical-turn
|
|
5913
|
+
// snapshots. Drained migration 0306 makes every new atomic attachment v1.
|
|
5914
|
+
personalResourceProtocolVersion: integer("personal_resource_protocol_version")
|
|
5915
|
+
.notNull()
|
|
5916
|
+
.default(0),
|
|
5917
|
+
// Immutable scheduled occurrence that accepted this logical turn. Null for
|
|
5918
|
+
// ordinary human, goal, child, and unrelated internal work.
|
|
5919
|
+
scheduledTaskRunId: uuid("scheduled_task_run_id"),
|
|
4567
5920
|
xaiProviderAccountAuthoritySnapshot: jsonb("xai_provider_account_authority_snapshot")
|
|
4568
5921
|
.$type<XaiProviderAccountAuthoritySnapshotV1>()
|
|
4569
5922
|
.notNull()
|
|
4570
5923
|
.default(WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1),
|
|
4571
5924
|
cancelledBy: text("cancelled_by"),
|
|
4572
5925
|
cancelReason: text("cancel_reason"),
|
|
4573
|
-
//
|
|
4574
|
-
//
|
|
4575
|
-
// concurrent reservations so exactly `codemodeMaxCallsPerTurn` succeed.
|
|
5926
|
+
// Leftover unused counter from the removed per-turn Codemode call cap
|
|
5927
|
+
// (migrations 0043/0205). New writers do not increment it; do not enforce.
|
|
4576
5928
|
codemodeCallCount: integer("codemode_call_count").notNull().default(0),
|
|
4577
5929
|
startedAt: timestamp("started_at", { withTimezone: true }),
|
|
4578
5930
|
finishedAt: timestamp("finished_at", { withTimezone: true }),
|
|
@@ -4593,6 +5945,11 @@ export const sessionTurns = pgTable(
|
|
|
4593
5945
|
oneCurrentInference: uniqueIndex("session_turns_one_current_inference_uq")
|
|
4594
5946
|
.on(table.workspaceId, table.sessionId)
|
|
4595
5947
|
.where(sql`${table.status} in ('running','requires_action','recovering','waiting_capacity')`),
|
|
5948
|
+
// Agent-monitoring "was this prompt's turn ever claimed" probe
|
|
5949
|
+
// (`excludeUnclaimedHumanPromptEventFilter`), migration 0322.
|
|
5950
|
+
unclaimedPromptTrigger: index("session_turns_unclaimed_prompt_trigger_idx")
|
|
5951
|
+
.on(table.workspaceId, table.sessionId, table.triggerEventId)
|
|
5952
|
+
.where(sql`${table.startedAt} is null`),
|
|
4596
5953
|
latencyModeValid: check(
|
|
4597
5954
|
"session_turns_latency_mode_check",
|
|
4598
5955
|
sql`${table.latencyMode} in ('standard', 'priority', 'fast')`,
|
|
@@ -4605,6 +5962,148 @@ export const sessionTurns = pgTable(
|
|
|
4605
5962
|
}),
|
|
4606
5963
|
);
|
|
4607
5964
|
|
|
5965
|
+
/** Immutable logical-turn receipt for atomic personal-resource issuance. */
|
|
5966
|
+
export const turnPersonalResourceAttachmentReceipts = pgTable(
|
|
5967
|
+
"turn_personal_resource_attachment_receipts",
|
|
5968
|
+
{
|
|
5969
|
+
turnId: uuid("turn_id")
|
|
5970
|
+
.primaryKey()
|
|
5971
|
+
.references(() => sessionTurns.id, { onDelete: "cascade" }),
|
|
5972
|
+
accountId: uuid("account_id").notNull(),
|
|
5973
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
5974
|
+
sessionId: uuid("session_id").notNull(),
|
|
5975
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id").notNull(),
|
|
5976
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id").notNull(),
|
|
5977
|
+
membershipAuthorizationRevision: bigint("membership_authorization_revision", {
|
|
5978
|
+
mode: "number",
|
|
5979
|
+
}).notNull(),
|
|
5980
|
+
sessionVisibility: text("session_visibility").notNull(),
|
|
5981
|
+
sessionAuthorityEpoch: integer("session_authority_epoch").notNull(),
|
|
5982
|
+
grantMode: text("grant_mode").notNull(),
|
|
5983
|
+
sharedOutputWarningVersion: integer("shared_output_warning_version").notNull(),
|
|
5984
|
+
sharedOutputAcknowledged: boolean("shared_output_acknowledged").notNull(),
|
|
5985
|
+
requestDigest: bytea("request_digest").notNull(),
|
|
5986
|
+
resourceCount: integer("resource_count").notNull(),
|
|
5987
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5988
|
+
},
|
|
5989
|
+
(table) => ({
|
|
5990
|
+
workspaceTurn: foreignKey({
|
|
5991
|
+
name: "turn_personal_resource_attachment_receipts_workspace_turn_fk",
|
|
5992
|
+
columns: [table.workspaceId, table.turnId],
|
|
5993
|
+
foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
|
|
5994
|
+
}).onDelete("cascade"),
|
|
5995
|
+
identity: check(
|
|
5996
|
+
"turn_personal_resource_attachment_receipts_identity_chk",
|
|
5997
|
+
sql`${table.sessionAuthorityEpoch} > 0
|
|
5998
|
+
and octet_length(${table.initiatingHumanSubjectId}) between 1 and 512
|
|
5999
|
+
and ${table.membershipAuthorizationRevision} > 0
|
|
6000
|
+
and ${table.resourceCount} between 1 and 28
|
|
6001
|
+
and ${table.grantMode} in ('once', 'session', 'always')
|
|
6002
|
+
and ${table.sessionVisibility} in ('user_private', 'workspace_shared')
|
|
6003
|
+
and ${table.sharedOutputWarningVersion} = 1
|
|
6004
|
+
and (${table.sessionVisibility} <> 'workspace_shared'
|
|
6005
|
+
or ${table.sharedOutputAcknowledged})`,
|
|
6006
|
+
),
|
|
6007
|
+
}),
|
|
6008
|
+
);
|
|
6009
|
+
|
|
6010
|
+
/** Exact resource/grant authority frozen on one accepted logical turn. */
|
|
6011
|
+
export const turnPersonalResourceSnapshots = pgTable(
|
|
6012
|
+
"turn_personal_resource_snapshots",
|
|
6013
|
+
{
|
|
6014
|
+
turnId: uuid("turn_id").notNull(),
|
|
6015
|
+
accountId: uuid("account_id").notNull(),
|
|
6016
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6017
|
+
sessionId: uuid("session_id").notNull(),
|
|
6018
|
+
resourceKind: text("resource_kind").notNull(),
|
|
6019
|
+
resourceId: uuid("resource_id").notNull(),
|
|
6020
|
+
resourceVersionId: uuid("resource_version_id"),
|
|
6021
|
+
selectionSources: text("selection_sources").array().notNull(),
|
|
6022
|
+
action: text("action").notNull(),
|
|
6023
|
+
originWorkspaceId: uuid("origin_workspace_id").notNull(),
|
|
6024
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id").notNull(),
|
|
6025
|
+
membershipAuthorizationRevision: bigint("membership_authorization_revision", {
|
|
6026
|
+
mode: "number",
|
|
6027
|
+
}).notNull(),
|
|
6028
|
+
authorityId: uuid("authority_id").notNull(),
|
|
6029
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }).notNull(),
|
|
6030
|
+
grantId: uuid("grant_id").notNull(),
|
|
6031
|
+
grantGeneration: bigint("grant_generation", { mode: "number" }).notNull(),
|
|
6032
|
+
grantMode: text("grant_mode").notNull(),
|
|
6033
|
+
grantContext: text("grant_context").notNull(),
|
|
6034
|
+
grantSessionId: uuid("grant_session_id"),
|
|
6035
|
+
grantAuthorityEpoch: integer("grant_authority_epoch"),
|
|
6036
|
+
canonicalDelegation: jsonb("canonical_delegation").$type<UserResourceDelegation>().notNull(),
|
|
6037
|
+
snapshotDigest: bytea("snapshot_digest").notNull(),
|
|
6038
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6039
|
+
},
|
|
6040
|
+
(table) => ({
|
|
6041
|
+
pk: primaryKey({ columns: [table.turnId, table.resourceKind, table.resourceId] }),
|
|
6042
|
+
receipt: foreignKey({
|
|
6043
|
+
name: "turn_personal_resource_snapshots_receipt_fk",
|
|
6044
|
+
columns: [table.turnId],
|
|
6045
|
+
foreignColumns: [turnPersonalResourceAttachmentReceipts.turnId],
|
|
6046
|
+
}).onDelete("cascade"),
|
|
6047
|
+
authority: index("turn_personal_resource_snapshots_authority_idx").on(table.authorityId),
|
|
6048
|
+
grant: index("turn_personal_resource_snapshots_grant_idx").on(table.grantId),
|
|
6049
|
+
kind: check(
|
|
6050
|
+
"turn_personal_resource_snapshots_kind_chk",
|
|
6051
|
+
sql`(${table.resourceKind} = 'variable_set'
|
|
6052
|
+
and ${table.action} = 'variable_set.use'
|
|
6053
|
+
and ${table.resourceVersionId} is null)
|
|
6054
|
+
or (${table.resourceKind} = 'rig'
|
|
6055
|
+
and ${table.action} = 'rig.use'
|
|
6056
|
+
and ${table.resourceVersionId} is not null)
|
|
6057
|
+
or (${table.resourceKind} = 'connected_machine'
|
|
6058
|
+
and ${table.action} = 'connected_machine.use'
|
|
6059
|
+
and ${table.resourceVersionId} is null)`,
|
|
6060
|
+
),
|
|
6061
|
+
generations: check(
|
|
6062
|
+
"turn_personal_resource_snapshots_generation_chk",
|
|
6063
|
+
sql`${table.membershipAuthorizationRevision} > 0
|
|
6064
|
+
and ${table.authorityGeneration} > 0
|
|
6065
|
+
and ${table.grantGeneration} > 0
|
|
6066
|
+
and cardinality(${table.selectionSources}) between 1 and 26`,
|
|
6067
|
+
),
|
|
6068
|
+
grantShape: check(
|
|
6069
|
+
"turn_personal_resource_snapshots_grant_chk",
|
|
6070
|
+
sql`${table.grantMode} in ('once', 'session', 'always')
|
|
6071
|
+
and ${table.grantContext} in ('user_private', 'workspace_shared')
|
|
6072
|
+
and ((${table.grantMode} = 'always'
|
|
6073
|
+
and ${table.grantSessionId} is null
|
|
6074
|
+
and ${table.grantAuthorityEpoch} is null)
|
|
6075
|
+
or (${table.grantMode} in ('once', 'session')
|
|
6076
|
+
and ${table.grantSessionId} = ${table.sessionId}
|
|
6077
|
+
and ${table.grantAuthorityEpoch} > 0))`,
|
|
6078
|
+
),
|
|
6079
|
+
}),
|
|
6080
|
+
);
|
|
6081
|
+
|
|
6082
|
+
/** One once grant may belong to one accepted logical turn only. */
|
|
6083
|
+
export const turnPersonalResourceOnceReceipts = pgTable(
|
|
6084
|
+
"turn_personal_resource_once_receipts",
|
|
6085
|
+
{
|
|
6086
|
+
grantId: uuid("grant_id").primaryKey(),
|
|
6087
|
+
turnId: uuid("turn_id").notNull(),
|
|
6088
|
+
accountId: uuid("account_id").notNull(),
|
|
6089
|
+
authorityId: uuid("authority_id").notNull(),
|
|
6090
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }).notNull(),
|
|
6091
|
+
grantGeneration: bigint("grant_generation", { mode: "number" }).notNull(),
|
|
6092
|
+
consumedAt: timestamp("consumed_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6093
|
+
},
|
|
6094
|
+
(table) => ({
|
|
6095
|
+
receipt: foreignKey({
|
|
6096
|
+
name: "turn_personal_resource_once_receipts_turn_fk",
|
|
6097
|
+
columns: [table.turnId],
|
|
6098
|
+
foreignColumns: [turnPersonalResourceAttachmentReceipts.turnId],
|
|
6099
|
+
}).onDelete("cascade"),
|
|
6100
|
+
generations: check(
|
|
6101
|
+
"turn_personal_resource_once_receipts_generation_chk",
|
|
6102
|
+
sql`${table.authorityGeneration} > 0 and ${table.grantGeneration} > 0`,
|
|
6103
|
+
),
|
|
6104
|
+
}),
|
|
6105
|
+
);
|
|
6106
|
+
|
|
4608
6107
|
// One bounded audit/idempotency projection of an ended mode's transcript-tail
|
|
4609
6108
|
// wrapper, bound to the exact ordinary Steer turn that durably carries it.
|
|
4610
6109
|
export const sessionRealtimeContextProjections = pgTable(
|
|
@@ -4693,6 +6192,9 @@ export const sessionTurnAttempts = pgTable(
|
|
|
4693
6192
|
authorityEpoch: integer("authority_epoch").notNull(),
|
|
4694
6193
|
authorityVisibility: text("authority_visibility").notNull(),
|
|
4695
6194
|
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6195
|
+
personalResourceProtocolVersion: integer("personal_resource_protocol_version")
|
|
6196
|
+
.notNull()
|
|
6197
|
+
.default(0),
|
|
4696
6198
|
// Immutable policy snapshot captured under the session lock at claim.
|
|
4697
6199
|
mcpApprovalPolicies: jsonb("mcp_approval_policies")
|
|
4698
6200
|
.$type<Record<string, SessionMcpApprovalPolicy>>()
|
|
@@ -4721,7 +6223,7 @@ export const sessionTurnAttempts = pgTable(
|
|
|
4721
6223
|
name: "session_turn_attempts_workspace_session_fk",
|
|
4722
6224
|
columns: [table.workspaceId, table.sessionId],
|
|
4723
6225
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
4724
|
-
}).onDelete("
|
|
6226
|
+
}).onDelete("cascade"),
|
|
4725
6227
|
workspaceTurn: foreignKey({
|
|
4726
6228
|
name: "session_turn_attempts_workspace_turn_fk",
|
|
4727
6229
|
columns: [table.workspaceId, table.turnId],
|
|
@@ -4805,6 +6307,202 @@ export const sessionTurnAttempts = pgTable(
|
|
|
4805
6307
|
}),
|
|
4806
6308
|
);
|
|
4807
6309
|
|
|
6310
|
+
// Per-turn startup SLO checkpoint ledger (migration 0318). One row per
|
|
6311
|
+
// (turn, milestone, outcome); the transaction whose
|
|
6312
|
+
// `insert ... on conflict do nothing returning` returns the row is the
|
|
6313
|
+
// canonical inserter and the sole metric receipt, so recovery and replay
|
|
6314
|
+
// conflict without re-reading the turn's session_events. `pre_ledger_history`
|
|
6315
|
+
// rows seal a turn whose startup predates the ledger.
|
|
6316
|
+
export const sessionTurnStartupMilestones = pgTable(
|
|
6317
|
+
"session_turn_startup_milestones",
|
|
6318
|
+
{
|
|
6319
|
+
accountId: uuid("account_id").notNull(),
|
|
6320
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6321
|
+
sessionId: uuid("session_id").notNull(),
|
|
6322
|
+
turnId: uuid("turn_id").notNull(),
|
|
6323
|
+
milestone: text("milestone").notNull(),
|
|
6324
|
+
outcome: text("outcome").notNull(),
|
|
6325
|
+
canonicalSource: text("canonical_source").notNull(),
|
|
6326
|
+
eventId: uuid("event_id"),
|
|
6327
|
+
occurredAt: timestamp("occurred_at", { withTimezone: true }),
|
|
6328
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6329
|
+
},
|
|
6330
|
+
(table) => ({
|
|
6331
|
+
pk: primaryKey({
|
|
6332
|
+
name: "session_turn_startup_milestones_pkey",
|
|
6333
|
+
columns: [table.workspaceId, table.turnId, table.milestone, table.outcome],
|
|
6334
|
+
}),
|
|
6335
|
+
workspaceAccount: foreignKey({
|
|
6336
|
+
name: "session_turn_startup_milestones_workspace_account_fk",
|
|
6337
|
+
columns: [table.workspaceId, table.accountId],
|
|
6338
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
6339
|
+
}).onDelete("cascade"),
|
|
6340
|
+
workspaceSession: foreignKey({
|
|
6341
|
+
name: "session_turn_startup_milestones_workspace_session_fk",
|
|
6342
|
+
columns: [table.workspaceId, table.sessionId],
|
|
6343
|
+
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
6344
|
+
}).onDelete("cascade"),
|
|
6345
|
+
workspaceTurn: foreignKey({
|
|
6346
|
+
name: "session_turn_startup_milestones_workspace_turn_fk",
|
|
6347
|
+
columns: [table.workspaceId, table.turnId],
|
|
6348
|
+
foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
|
|
6349
|
+
}).onDelete("cascade"),
|
|
6350
|
+
workspaceSessionIndex: index("session_turn_startup_milestones_workspace_session_idx").on(
|
|
6351
|
+
table.workspaceId,
|
|
6352
|
+
table.sessionId,
|
|
6353
|
+
),
|
|
6354
|
+
milestoneCheck: check(
|
|
6355
|
+
"session_turn_startup_milestones_milestone_chk",
|
|
6356
|
+
sql`${table.milestone} in ('queue', 'provider_dispatch', 'first_byte')`,
|
|
6357
|
+
),
|
|
6358
|
+
outcomeCheck: check(
|
|
6359
|
+
"session_turn_startup_milestones_outcome_chk",
|
|
6360
|
+
sql`${table.outcome} in ('completed', 'failed')`,
|
|
6361
|
+
),
|
|
6362
|
+
checkpointCheck: check(
|
|
6363
|
+
"session_turn_startup_milestones_checkpoint_chk",
|
|
6364
|
+
sql`${table.outcome} = 'completed' or ${table.milestone} = 'first_byte'`,
|
|
6365
|
+
),
|
|
6366
|
+
canonicalSourceCheck: check(
|
|
6367
|
+
"session_turn_startup_milestones_canonical_source_chk",
|
|
6368
|
+
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)`,
|
|
6369
|
+
),
|
|
6370
|
+
}),
|
|
6371
|
+
);
|
|
6372
|
+
|
|
6373
|
+
// Credential-free authority captured with the accepted logical turn. Runtime
|
|
6374
|
+
// credential resolution loads this canonical row by exact turn + tool surface;
|
|
6375
|
+
// a caller-provided snapshot is never authority.
|
|
6376
|
+
export const turnConnectionAuthoritySnapshots = pgTable(
|
|
6377
|
+
"turn_connection_authority_snapshots",
|
|
6378
|
+
{
|
|
6379
|
+
accountId: uuid("account_id").notNull(),
|
|
6380
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6381
|
+
sessionId: uuid("session_id").notNull(),
|
|
6382
|
+
turnId: uuid("turn_id").notNull(),
|
|
6383
|
+
serverId: text("server_id").notNull(),
|
|
6384
|
+
connectionId: uuid("connection_id").notNull(),
|
|
6385
|
+
connectionGeneration: bigint("connection_generation", { mode: "number" }).notNull(),
|
|
6386
|
+
originWorkspaceId: uuid("origin_workspace_id").notNull(),
|
|
6387
|
+
providerDomain: text("provider_domain").notNull(),
|
|
6388
|
+
connectionKind: text("connection_kind").notNull(),
|
|
6389
|
+
authorityScope: text("authority_scope").notNull(),
|
|
6390
|
+
authoritySource: text("authority_source").notNull(),
|
|
6391
|
+
ownerSubjectId: text("owner_subject_id"),
|
|
6392
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
6393
|
+
membershipAuthorizationRevision: bigint("membership_authorization_revision", {
|
|
6394
|
+
mode: "number",
|
|
6395
|
+
}),
|
|
6396
|
+
authorityId: uuid("authority_id"),
|
|
6397
|
+
authorityGeneration: bigint("authority_generation", { mode: "number" }),
|
|
6398
|
+
grantId: uuid("grant_id"),
|
|
6399
|
+
grantGeneration: bigint("grant_generation", { mode: "number" }),
|
|
6400
|
+
grantMode: text("grant_mode"),
|
|
6401
|
+
grantContext: text("grant_context"),
|
|
6402
|
+
grantSessionId: uuid("grant_session_id"),
|
|
6403
|
+
grantAuthorityEpoch: integer("grant_authority_epoch"),
|
|
6404
|
+
sessionVisibility: text("session_visibility").notNull(),
|
|
6405
|
+
sessionAuthorityEpoch: integer("session_authority_epoch").notNull(),
|
|
6406
|
+
canonicalSnapshot: jsonb("canonical_snapshot").$type<Record<string, unknown>>().notNull(),
|
|
6407
|
+
snapshotDigest: bytea("snapshot_digest").notNull(),
|
|
6408
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6409
|
+
},
|
|
6410
|
+
(table) => ({
|
|
6411
|
+
identity: primaryKey({ columns: [table.turnId, table.serverId] }),
|
|
6412
|
+
turn: foreignKey({
|
|
6413
|
+
name: "turn_connection_authority_turn_fk",
|
|
6414
|
+
columns: [table.workspaceId, table.turnId],
|
|
6415
|
+
foreignColumns: [sessionTurns.workspaceId, sessionTurns.id],
|
|
6416
|
+
}).onDelete("cascade"),
|
|
6417
|
+
connection: foreignKey({
|
|
6418
|
+
name: "turn_connection_authority_connection_fk",
|
|
6419
|
+
columns: [table.connectionId],
|
|
6420
|
+
foreignColumns: [connections.id],
|
|
6421
|
+
}).onDelete("restrict"),
|
|
6422
|
+
membership: foreignKey({
|
|
6423
|
+
name: "turn_connection_authority_membership_fk",
|
|
6424
|
+
columns: [table.ownerOrganizationMembershipId, table.accountId],
|
|
6425
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
6426
|
+
}).onDelete("restrict"),
|
|
6427
|
+
authority: foreignKey({
|
|
6428
|
+
name: "turn_connection_authority_authority_fk",
|
|
6429
|
+
columns: [table.authorityId, table.accountId],
|
|
6430
|
+
foreignColumns: [
|
|
6431
|
+
organizationUserResourceAuthorities.id,
|
|
6432
|
+
organizationUserResourceAuthorities.accountId,
|
|
6433
|
+
],
|
|
6434
|
+
}).onDelete("restrict"),
|
|
6435
|
+
grant: foreignKey({
|
|
6436
|
+
name: "turn_connection_authority_grant_fk",
|
|
6437
|
+
columns: [table.grantId, table.accountId],
|
|
6438
|
+
foreignColumns: [organizationUserResourceGrants.id, organizationUserResourceGrants.accountId],
|
|
6439
|
+
}).onDelete("restrict"),
|
|
6440
|
+
connectionLookup: index("turn_connection_authority_connection_idx").on(
|
|
6441
|
+
table.accountId,
|
|
6442
|
+
table.connectionId,
|
|
6443
|
+
table.turnId,
|
|
6444
|
+
table.serverId,
|
|
6445
|
+
),
|
|
6446
|
+
serverValid: check(
|
|
6447
|
+
"turn_connection_authority_server_check",
|
|
6448
|
+
sql`octet_length(${table.serverId}) between 1 and 256`,
|
|
6449
|
+
),
|
|
6450
|
+
generationValid: check(
|
|
6451
|
+
"turn_connection_authority_generation_check",
|
|
6452
|
+
sql`${table.connectionGeneration} > 0 and ${table.sessionAuthorityEpoch} > 0`,
|
|
6453
|
+
),
|
|
6454
|
+
}),
|
|
6455
|
+
);
|
|
6456
|
+
|
|
6457
|
+
// One metadata-only authorization fact per caller-preallocated physical
|
|
6458
|
+
// provider request. No credential, header, body, provider response, or content
|
|
6459
|
+
// is retained in this table.
|
|
6460
|
+
export const connectionUseAuditFacts = pgTable(
|
|
6461
|
+
"connection_use_audit_facts",
|
|
6462
|
+
{
|
|
6463
|
+
physicalRequestId: uuid("physical_request_id").primaryKey(),
|
|
6464
|
+
usePhase: text("use_phase").notNull(),
|
|
6465
|
+
requestDigest: bytea("request_digest").notNull(),
|
|
6466
|
+
accountId: uuid("account_id").notNull(),
|
|
6467
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
6468
|
+
sessionId: uuid("session_id").notNull(),
|
|
6469
|
+
turnId: uuid("turn_id").notNull(),
|
|
6470
|
+
attemptId: uuid("attempt_id").notNull(),
|
|
6471
|
+
executionGeneration: integer("execution_generation").notNull(),
|
|
6472
|
+
serverId: text("server_id").notNull(),
|
|
6473
|
+
connectionId: uuid("connection_id"),
|
|
6474
|
+
connectionGeneration: bigint("connection_generation", { mode: "number" }),
|
|
6475
|
+
authorityScope: text("authority_scope"),
|
|
6476
|
+
ownerSubjectId: text("owner_subject_id"),
|
|
6477
|
+
authorityId: uuid("authority_id"),
|
|
6478
|
+
grantId: uuid("grant_id"),
|
|
6479
|
+
initiatorKind: text("initiator_kind"),
|
|
6480
|
+
initiatorSubjectId: text("initiator_subject_id"),
|
|
6481
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id"),
|
|
6482
|
+
authorityEpoch: integer("authority_epoch"),
|
|
6483
|
+
authorityVisibility: text("authority_visibility"),
|
|
6484
|
+
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6485
|
+
outcome: text("outcome").notNull(),
|
|
6486
|
+
denialReason: text("denial_reason"),
|
|
6487
|
+
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6488
|
+
},
|
|
6489
|
+
(table) => ({
|
|
6490
|
+
attempt: index("connection_use_audit_attempt_idx").on(
|
|
6491
|
+
table.workspaceId,
|
|
6492
|
+
table.attemptId,
|
|
6493
|
+
table.occurredAt,
|
|
6494
|
+
),
|
|
6495
|
+
shapeValid: check(
|
|
6496
|
+
"connection_use_audit_shape_check",
|
|
6497
|
+
sql`octet_length(${table.serverId}) between 1 and 256
|
|
6498
|
+
and octet_length(${table.requestDigest}) = 32
|
|
6499
|
+
and ${table.executionGeneration} > 0
|
|
6500
|
+
and ${table.usePhase} in ('credential_resolution', 'provider_request')
|
|
6501
|
+
and ${table.outcome} in ('authorized', 'denied')`,
|
|
6502
|
+
),
|
|
6503
|
+
}),
|
|
6504
|
+
);
|
|
6505
|
+
|
|
4808
6506
|
// Immutable executable tool universe admitted to one exact attempt. Model MCP
|
|
4809
6507
|
// and sandbox Codemode use the same digest and opaque identities from this row.
|
|
4810
6508
|
export const sessionAttemptToolCatalogs = pgTable(
|
|
@@ -5208,7 +6906,7 @@ export const sessionCommandReceipts = pgTable(
|
|
|
5208
6906
|
name: "session_command_receipts_target_session_fk",
|
|
5209
6907
|
columns: [table.workspaceId, table.targetSessionId],
|
|
5210
6908
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
5211
|
-
}).onDelete("
|
|
6909
|
+
}).onDelete("cascade"),
|
|
5212
6910
|
targetTurn: foreignKey({
|
|
5213
6911
|
name: "session_command_receipts_target_turn_fk",
|
|
5214
6912
|
columns: [table.workspaceId, table.targetTurnId],
|
|
@@ -5274,7 +6972,7 @@ export const workspaceControlEvents = pgTable(
|
|
|
5274
6972
|
name: "workspace_control_events_root_session_fk",
|
|
5275
6973
|
columns: [table.workspaceId, table.rootSessionId],
|
|
5276
6974
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
5277
|
-
}).onDelete("
|
|
6975
|
+
}).onDelete("cascade"),
|
|
5278
6976
|
workspaceRevision: uniqueIndex("workspace_control_events_workspace_revision_uq").on(
|
|
5279
6977
|
table.workspaceId,
|
|
5280
6978
|
table.revision,
|
|
@@ -5322,7 +7020,7 @@ export const sessionAttemptInterruptions = pgTable(
|
|
|
5322
7020
|
name: "session_attempt_interruptions_workspace_session_fk",
|
|
5323
7021
|
columns: [table.workspaceId, table.sessionId],
|
|
5324
7022
|
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
5325
|
-
}).onDelete("
|
|
7023
|
+
}).onDelete("cascade"),
|
|
5326
7024
|
operation: foreignKey({
|
|
5327
7025
|
name: "session_attempt_interruptions_operation_fk",
|
|
5328
7026
|
columns: [table.workspaceId, table.operationId],
|
|
@@ -5342,7 +7040,7 @@ export const sessionAttemptInterruptions = pgTable(
|
|
|
5342
7040
|
.where(sql`${table.state} in ('pending', 'delivered', 'acknowledged')`),
|
|
5343
7041
|
kindValid: check(
|
|
5344
7042
|
"session_attempt_interruptions_kind_check",
|
|
5345
|
-
sql`${table.kind} in ('session_pause', 'workspace_pause', 'steer', 'maintenance')`,
|
|
7043
|
+
sql`${table.kind} in ('session_pause', 'workspace_pause', 'steer', 'maintenance', 'authority_change', 'organization_membership_revoked')`,
|
|
5346
7044
|
),
|
|
5347
7045
|
stateValid: check(
|
|
5348
7046
|
"session_attempt_interruptions_state_check",
|
|
@@ -5482,6 +7180,9 @@ export const sessionSystemUpdates = pgTable(
|
|
|
5482
7180
|
.$type<XaiProviderAccountAuthoritySnapshotV1>()
|
|
5483
7181
|
.notNull()
|
|
5484
7182
|
.default(WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1),
|
|
7183
|
+
// Private scheduled-occurrence authority linkage. Public update/event
|
|
7184
|
+
// projections intentionally omit this producer identifier.
|
|
7185
|
+
scheduledTaskRunId: uuid("scheduled_task_run_id"),
|
|
5485
7186
|
// pending is visible queue truth; delivered means its exact model-memory
|
|
5486
7187
|
// batch was durably claimed. Terminal cancellation/supersession is explicit.
|
|
5487
7188
|
state: text("state").notNull().default("pending"),
|
|
@@ -5497,7 +7198,7 @@ export const sessionSystemUpdates = pgTable(
|
|
|
5497
7198
|
(table) => ({
|
|
5498
7199
|
kindValid: check(
|
|
5499
7200
|
"system_updates_kind_check",
|
|
5500
|
-
sql`${table.kind} in ('scheduled_occurrence', 'goal_continuation', 'agent_message', 'agent_steer_instruction', 'child_terminal_result', 'media_generation_result')`,
|
|
7201
|
+
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')`,
|
|
5501
7202
|
),
|
|
5502
7203
|
payloadKindValid: check(
|
|
5503
7204
|
"system_updates_payload_kind_check",
|
|
@@ -5518,6 +7219,11 @@ export const sessionSystemUpdates = pgTable(
|
|
|
5518
7219
|
table.state,
|
|
5519
7220
|
table.createdAt,
|
|
5520
7221
|
),
|
|
7222
|
+
// Producer-side supersession / resolution of one child's pending notices
|
|
7223
|
+
// of one kind on the parent (migration 0325).
|
|
7224
|
+
pendingKindSource: index("session_system_updates_pending_kind_source_idx")
|
|
7225
|
+
.on(table.workspaceId, table.sessionId, table.kind, table.sourceId)
|
|
7226
|
+
.where(sql`${table.state} = 'pending'`),
|
|
5521
7227
|
onePendingSteer: uniqueIndex("session_system_updates_one_pending_steer_idx")
|
|
5522
7228
|
.on(table.workspaceId, table.sessionId)
|
|
5523
7229
|
.where(sql`${table.kind} = 'agent_steer_instruction' and ${table.state} = 'pending'`),
|
|
@@ -5584,11 +7290,11 @@ export const sessionSystemUpdateOutbox = pgTable(
|
|
|
5584
7290
|
(table) => ({
|
|
5585
7291
|
kindValid: check(
|
|
5586
7292
|
"system_update_outbox_kind_check",
|
|
5587
|
-
sql`${table.kind}
|
|
7293
|
+
sql`${table.kind} in ('child_terminal_result', 'child_requires_action', 'child_requires_action_resolved', 'child_paused', 'child_waiting_capacity', 'child_progress')`,
|
|
5588
7294
|
),
|
|
5589
7295
|
payloadKindValid: check(
|
|
5590
7296
|
"system_update_outbox_payload_kind_check",
|
|
5591
|
-
sql`${table.payload} ->> 'type' =
|
|
7297
|
+
sql`${table.payload} ->> 'type' = ${table.kind}`,
|
|
5592
7298
|
),
|
|
5593
7299
|
dedupe: uniqueIndex("session_system_update_outbox_dedupe_uq").on(
|
|
5594
7300
|
table.workspaceId,
|
|
@@ -5670,6 +7376,7 @@ export const sessionGoals = pgTable(
|
|
|
5670
7376
|
status: text("status").notNull().default("active"), // active | paused | completed
|
|
5671
7377
|
text: text("text").notNull(),
|
|
5672
7378
|
successCriteria: text("success_criteria"),
|
|
7379
|
+
rootConstraints: jsonb("root_constraints").$type<string[]>().notNull().default([]),
|
|
5673
7380
|
evidence: text("evidence"), // set by goal_complete
|
|
5674
7381
|
rationale: text("rationale"), // set by goal_pause
|
|
5675
7382
|
pausedReason: text("paused_reason"), // agent | user_pause | api | no_progress | max_auto_continuations | limits
|
|
@@ -5703,6 +7410,15 @@ export const sessionGoals = pgTable(
|
|
|
5703
7410
|
})
|
|
5704
7411
|
.notNull()
|
|
5705
7412
|
.default(0),
|
|
7413
|
+
// Agent-declared continuation hold (`goal_wait`, migration 0317). Honored
|
|
7414
|
+
// only while `continuationHoldTurnId` is still the latest finished turn and
|
|
7415
|
+
// the deadline has not passed; it never consumes the wake/observed ledger.
|
|
7416
|
+
// Any newer finished turn, a passed deadline, or a goal mutation clears all
|
|
7417
|
+
// four columns together.
|
|
7418
|
+
continuationHoldTurnId: uuid("continuation_hold_turn_id"),
|
|
7419
|
+
continuationHoldUntil: timestamp("continuation_hold_until", { withTimezone: true }),
|
|
7420
|
+
continuationHoldReason: text("continuation_hold_reason"),
|
|
7421
|
+
continuationHoldSetAt: timestamp("continuation_hold_set_at", { withTimezone: true }),
|
|
5706
7422
|
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
|
|
5707
7423
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5708
7424
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -5721,6 +7437,10 @@ export const sessionGoals = pgTable(
|
|
|
5721
7437
|
"session_goals_continuation_revision_check",
|
|
5722
7438
|
sql`${table.continuationWakeRevision} >= 0 and ${table.continuationObservedRevision} >= 0 and ${table.continuationObservedRevision} <= ${table.continuationWakeRevision} and ${table.continuationWakeRevision} <= 9007199254740991 and ${table.continuationObservedRevision} <= 9007199254740991`,
|
|
5723
7439
|
),
|
|
7440
|
+
continuationHoldValid: check(
|
|
7441
|
+
"session_goals_continuation_hold_check",
|
|
7442
|
+
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))`,
|
|
7443
|
+
),
|
|
5724
7444
|
}),
|
|
5725
7445
|
);
|
|
5726
7446
|
|
|
@@ -5743,12 +7463,14 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5743
7463
|
resultObjectiveRevision: integer("result_objective_revision"),
|
|
5744
7464
|
text: text("text").notNull(),
|
|
5745
7465
|
successCriteria: text("success_criteria"),
|
|
7466
|
+
rootConstraints: jsonb("root_constraints").$type<string[]>().notNull().default([]),
|
|
5746
7467
|
mutationPolicy: text("mutation_policy").$type<SessionGoalMutationPolicy>().notNull(),
|
|
5747
7468
|
rationale: text("rationale").notNull(),
|
|
5748
7469
|
actor: text("actor").$type<"agent" | "api" | "scheduled_task">().notNull(),
|
|
5749
7470
|
actorTurnId: uuid("actor_turn_id"),
|
|
5750
7471
|
actorAttemptId: uuid("actor_attempt_id"),
|
|
5751
7472
|
proposalId: uuid("proposal_id"),
|
|
7473
|
+
rollbackOfRevisionId: uuid("rollback_of_revision_id"),
|
|
5752
7474
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5753
7475
|
},
|
|
5754
7476
|
(table) => ({
|
|
@@ -5777,6 +7499,11 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5777
7499
|
columns: [table.workspaceId, table.proposalId],
|
|
5778
7500
|
foreignColumns: [table.workspaceId, table.id],
|
|
5779
7501
|
}).onDelete("restrict"),
|
|
7502
|
+
rollbackOfRevision: foreignKey({
|
|
7503
|
+
name: "session_goal_revisions_rollback_of_revision_fk",
|
|
7504
|
+
columns: [table.workspaceId, table.rollbackOfRevisionId],
|
|
7505
|
+
foreignColumns: [table.workspaceId, table.id],
|
|
7506
|
+
}).onDelete("restrict"),
|
|
5780
7507
|
appliedRevision: uniqueIndex("session_goal_revisions_applied_revision_uq")
|
|
5781
7508
|
.on(table.workspaceId, table.goalId, table.resultObjectiveRevision)
|
|
5782
7509
|
.where(sql`${table.disposition} = 'applied'`),
|
|
@@ -5786,6 +7513,14 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5786
7513
|
table.createdAt,
|
|
5787
7514
|
table.id,
|
|
5788
7515
|
),
|
|
7516
|
+
proposalDecision: uniqueIndex("session_goal_revisions_proposal_decision_uq")
|
|
7517
|
+
.on(table.workspaceId, table.proposalId)
|
|
7518
|
+
.where(
|
|
7519
|
+
sql`${table.proposalId} is not null and ${table.disposition} in ('applied', 'rejected')`,
|
|
7520
|
+
),
|
|
7521
|
+
rollbackRequest: uniqueIndex("session_goal_revisions_rollback_request_uq")
|
|
7522
|
+
.on(table.workspaceId, table.goalId, table.rollbackOfRevisionId, table.baseObjectiveRevision)
|
|
7523
|
+
.where(sql`${table.disposition} = 'applied' and ${table.rollbackOfRevisionId} is not null`),
|
|
5789
7524
|
dispositionValid: check(
|
|
5790
7525
|
"session_goal_revisions_disposition_chk",
|
|
5791
7526
|
sql`${table.disposition} in ('applied', 'proposed', 'rejected')`,
|
|
@@ -5803,6 +7538,12 @@ export const sessionGoalRevisions = pgTable(
|
|
|
5803
7538
|
sql`(${table.disposition} = 'applied' and ${table.resultObjectiveRevision} = ${table.baseObjectiveRevision} + 1)
|
|
5804
7539
|
or (${table.disposition} in ('proposed', 'rejected') and ${table.resultObjectiveRevision} is null)`,
|
|
5805
7540
|
),
|
|
7541
|
+
lineageShape: check(
|
|
7542
|
+
"session_goal_revisions_lineage_shape_chk",
|
|
7543
|
+
sql`(${table.disposition} = 'proposed' and ${table.proposalId} is null and ${table.rollbackOfRevisionId} is null)
|
|
7544
|
+
or (${table.disposition} = 'rejected' and ${table.proposalId} is not null and ${table.rollbackOfRevisionId} is null)
|
|
7545
|
+
or (${table.disposition} = 'applied' and not (${table.proposalId} is not null and ${table.rollbackOfRevisionId} is not null))`,
|
|
7546
|
+
),
|
|
5806
7547
|
}),
|
|
5807
7548
|
);
|
|
5808
7549
|
|
|
@@ -6279,6 +8020,12 @@ export const sessionPendingToolCalls = pgTable(
|
|
|
6279
8020
|
callType: text("call_type").notNull(),
|
|
6280
8021
|
callItem: losslessJsonb("call_item").$type<Record<string, unknown>>().notNull(),
|
|
6281
8022
|
callItemCodecVersion: losslessCodecVersion("call_item_codec_version"),
|
|
8023
|
+
interruptionKind: text("interruption_kind"),
|
|
8024
|
+
tiedReasoningItems: losslessJsonb("tied_reasoning_items")
|
|
8025
|
+
.$type<Array<Record<string, unknown>>>()
|
|
8026
|
+
.notNull()
|
|
8027
|
+
.default([]),
|
|
8028
|
+
tiedReasoningItemsCodecVersion: losslessCodecVersion("tied_reasoning_items_codec_version"),
|
|
6282
8029
|
modelToolOutputTruncationTokens: integer("model_tool_output_truncation_tokens"),
|
|
6283
8030
|
resultItem: losslessJsonb("result_item").$type<Record<string, unknown>>(),
|
|
6284
8031
|
resultItemCodecVersion: losslessCodecVersion("result_item_codec_version"),
|
|
@@ -6303,6 +8050,14 @@ export const sessionPendingToolCalls = pgTable(
|
|
|
6303
8050
|
table.sessionId,
|
|
6304
8051
|
table.turnId,
|
|
6305
8052
|
),
|
|
8053
|
+
interruptionKindValid: check(
|
|
8054
|
+
"session_pending_tool_calls_interruption_kind_chk",
|
|
8055
|
+
sql`${table.interruptionKind} is null or ${table.interruptionKind} in ('human_input', 'approval', 'interaction_intervention')`,
|
|
8056
|
+
),
|
|
8057
|
+
tiedReasoningItemsArray: check(
|
|
8058
|
+
"session_pending_tool_calls_tied_reasoning_items_chk",
|
|
8059
|
+
sql`jsonb_typeof(${table.tiedReasoningItems}) = 'array'`,
|
|
8060
|
+
),
|
|
6306
8061
|
}),
|
|
6307
8062
|
);
|
|
6308
8063
|
|
|
@@ -6741,6 +8496,11 @@ export const sandboxLeaseHolders = pgTable(
|
|
|
6741
8496
|
holderId: text("holder_id").notNull(),
|
|
6742
8497
|
// The attributing session within the (possibly shared) group.
|
|
6743
8498
|
subjectId: uuid("subject_id"),
|
|
8499
|
+
// Viewer holders only (0281): the authenticated viewer subject and the
|
|
8500
|
+
// session authority epoch observed at attach - identities and epochs
|
|
8501
|
+
// only, mirrored into the scoped stream token's claims.
|
|
8502
|
+
viewerSubjectId: text("viewer_subject_id"),
|
|
8503
|
+
viewerAuthorityEpoch: integer("viewer_authority_epoch"),
|
|
6744
8504
|
lastHeartbeatAt: timestamp("last_heartbeat_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6745
8505
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
6746
8506
|
},
|
|
@@ -6762,6 +8522,14 @@ export const sandboxLeaseHolders = pgTable(
|
|
|
6762
8522
|
|
|
6763
8523
|
export const sandboxWorkspaceMutationActorKindValues = ["turn", "direct", "process"] as const;
|
|
6764
8524
|
export const sandboxWorkspaceMutationHolderKindValues = ["turn", "direct", "process"] as const;
|
|
8525
|
+
// The causal principal behind an admitted workspace writer. `subject`/`service`
|
|
8526
|
+
// are the canonical `session_turns` initiator vocabulary; `legacy_unattributed`
|
|
8527
|
+
// exists only for rows written before migration 0277 recorded any authority.
|
|
8528
|
+
export const sandboxWorkspaceMutationInitiatorKindValues = [
|
|
8529
|
+
"subject",
|
|
8530
|
+
"service",
|
|
8531
|
+
"legacy_unattributed",
|
|
8532
|
+
] as const;
|
|
6765
8533
|
|
|
6766
8534
|
// Durable admission ledger for every provider operation that may mutate a
|
|
6767
8535
|
// persistable /workspace. The row is inserted atomically with the lease's
|
|
@@ -6806,6 +8574,29 @@ export const sandboxWorkspaceMutationAdmissions = pgTable(
|
|
|
6806
8574
|
routeEpoch: integer("route_epoch").notNull(),
|
|
6807
8575
|
workspaceGeneration: integer("workspace_generation").notNull(),
|
|
6808
8576
|
operation: text("operation").notNull(),
|
|
8577
|
+
// Exact authority admitted with this operation (migration 0277). Identities
|
|
8578
|
+
// and epochs only, never a secret value. `legacy_unattributed` marks a
|
|
8579
|
+
// pre-0277 `direct`/`process` row whose authority was never recorded; a
|
|
8580
|
+
// post-0277 writer never produces it and new admission refuses it.
|
|
8581
|
+
initiatorKind: text("initiator_kind", {
|
|
8582
|
+
enum: sandboxWorkspaceMutationInitiatorKindValues,
|
|
8583
|
+
})
|
|
8584
|
+
.notNull()
|
|
8585
|
+
.default("legacy_unattributed"),
|
|
8586
|
+
initiatorSubjectId: text("initiator_subject_id").notNull().default("unattributed-legacy"),
|
|
8587
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id"),
|
|
8588
|
+
// The grant identity that authorized the causal human, plus the
|
|
8589
|
+
// authorization revision observed at admission. The revision is audit
|
|
8590
|
+
// evidence: a role change is not a revocation and must not fence a writer.
|
|
8591
|
+
initiatorOrganizationMembershipId: uuid("initiator_organization_membership_id"),
|
|
8592
|
+
initiatorAuthorizationRevision: bigint("initiator_authorization_revision", { mode: "number" }),
|
|
8593
|
+
// Session tenancy authority observed when the operation was admitted; the
|
|
8594
|
+
// same triple `session_turn_attempts` freezes for a turn.
|
|
8595
|
+
authorityEpoch: integer("authority_epoch"),
|
|
8596
|
+
authorityVisibility: text("authority_visibility", {
|
|
8597
|
+
enum: ["user_private", "workspace_shared"],
|
|
8598
|
+
}),
|
|
8599
|
+
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6809
8600
|
providerOutcome: text("provider_outcome", {
|
|
6810
8601
|
enum: ["resolved", "rejected", "retained"],
|
|
6811
8602
|
}),
|
|
@@ -6856,6 +8647,65 @@ export const sandboxWorkspaceMutationAdmissions = pgTable(
|
|
|
6856
8647
|
table.actorKind,
|
|
6857
8648
|
table.actorId,
|
|
6858
8649
|
),
|
|
8650
|
+
initiatorMembership: foreignKey({
|
|
8651
|
+
name: "sandbox_workspace_mutation_admissions_initiator_membership_fk",
|
|
8652
|
+
columns: [table.initiatorOrganizationMembershipId, table.accountId],
|
|
8653
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8654
|
+
}).onDelete("restrict"),
|
|
8655
|
+
authorityOwnerMembership: foreignKey({
|
|
8656
|
+
name: "sandbox_workspace_mutation_admissions_authority_owner_fk",
|
|
8657
|
+
columns: [table.authorityOwnerOrganizationMembershipId, table.accountId],
|
|
8658
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8659
|
+
}).onDelete("restrict"),
|
|
8660
|
+
initiator: index("sandbox_workspace_mutation_admissions_initiator_idx")
|
|
8661
|
+
.on(table.accountId, table.initiatorOrganizationMembershipId)
|
|
8662
|
+
.where(sql`${table.settledAt} is null`),
|
|
8663
|
+
initiatorValid: check(
|
|
8664
|
+
"sandbox_workspace_mutation_admissions_initiator_check",
|
|
8665
|
+
sql`(
|
|
8666
|
+
${table.initiatorKind} = 'legacy_unattributed'
|
|
8667
|
+
and ${table.initiatorSubjectId} = 'unattributed-legacy'
|
|
8668
|
+
and ${table.initiatingHumanSubjectId} is null
|
|
8669
|
+
and ${table.initiatorOrganizationMembershipId} is null
|
|
8670
|
+
and ${table.initiatorAuthorizationRevision} is null
|
|
8671
|
+
) or (
|
|
8672
|
+
${table.initiatorKind} in ('subject', 'service')
|
|
8673
|
+
and length(btrim(${table.initiatorSubjectId})) between 1 and 1024
|
|
8674
|
+
and ${table.initiatorSubjectId} <> 'unattributed-legacy'
|
|
8675
|
+
and (
|
|
8676
|
+
${table.initiatingHumanSubjectId} is null
|
|
8677
|
+
or length(btrim(${table.initiatingHumanSubjectId})) between 1 and 1024
|
|
8678
|
+
)
|
|
8679
|
+
and (
|
|
8680
|
+
${table.initiatorOrganizationMembershipId} is null
|
|
8681
|
+
or ${table.initiatingHumanSubjectId} is not null
|
|
8682
|
+
)
|
|
8683
|
+
and (
|
|
8684
|
+
${table.initiatorAuthorizationRevision} is null
|
|
8685
|
+
or (
|
|
8686
|
+
${table.initiatorAuthorizationRevision} > 0
|
|
8687
|
+
and ${table.initiatorOrganizationMembershipId} is not null
|
|
8688
|
+
)
|
|
8689
|
+
)
|
|
8690
|
+
)`,
|
|
8691
|
+
),
|
|
8692
|
+
tenancyValid: check(
|
|
8693
|
+
"sandbox_workspace_mutation_admissions_tenancy_check",
|
|
8694
|
+
sql`(
|
|
8695
|
+
${table.authorityEpoch} is null
|
|
8696
|
+
and ${table.authorityVisibility} is null
|
|
8697
|
+
and ${table.authorityOwnerOrganizationMembershipId} is null
|
|
8698
|
+
) or (
|
|
8699
|
+
${table.authorityEpoch} is not null
|
|
8700
|
+
and ${table.authorityVisibility} is not null
|
|
8701
|
+
and ${table.authorityEpoch} > 0
|
|
8702
|
+
and ${table.authorityVisibility} in ('user_private', 'workspace_shared')
|
|
8703
|
+
and (
|
|
8704
|
+
${table.authorityVisibility} <> 'user_private'
|
|
8705
|
+
or ${table.authorityOwnerOrganizationMembershipId} is not null
|
|
8706
|
+
)
|
|
8707
|
+
)`,
|
|
8708
|
+
),
|
|
6859
8709
|
generationValid: check(
|
|
6860
8710
|
"sandbox_workspace_mutation_admissions_generation_check",
|
|
6861
8711
|
sql`${table.workspaceGeneration} > 0
|
|
@@ -6950,6 +8800,23 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
6950
8800
|
routeTargetId: uuid("route_target_id"),
|
|
6951
8801
|
routeEpoch: integer("route_epoch").notNull(),
|
|
6952
8802
|
providerSessionId: integer("provider_session_id").notNull(),
|
|
8803
|
+
// Authority frozen when the process was retained (migration 0277). A
|
|
8804
|
+
// `legacy_unattributed` process keeps running; only its next workspace
|
|
8805
|
+
// mutation is refused, because nothing may invent an owner for it.
|
|
8806
|
+
initiatorKind: text("initiator_kind", {
|
|
8807
|
+
enum: sandboxWorkspaceMutationInitiatorKindValues,
|
|
8808
|
+
})
|
|
8809
|
+
.notNull()
|
|
8810
|
+
.default("legacy_unattributed"),
|
|
8811
|
+
initiatorSubjectId: text("initiator_subject_id").notNull().default("unattributed-legacy"),
|
|
8812
|
+
initiatingHumanSubjectId: text("initiating_human_subject_id"),
|
|
8813
|
+
initiatorOrganizationMembershipId: uuid("initiator_organization_membership_id"),
|
|
8814
|
+
initiatorAuthorizationRevision: bigint("initiator_authorization_revision", { mode: "number" }),
|
|
8815
|
+
authorityEpoch: integer("authority_epoch"),
|
|
8816
|
+
authorityVisibility: text("authority_visibility", {
|
|
8817
|
+
enum: ["user_private", "workspace_shared"],
|
|
8818
|
+
}),
|
|
8819
|
+
authorityOwnerOrganizationMembershipId: uuid("authority_owner_organization_membership_id"),
|
|
6953
8820
|
state: text("state", { enum: sandboxRetainedProcessStateValues }).notNull().default("active"),
|
|
6954
8821
|
exitCode: integer("exit_code"),
|
|
6955
8822
|
settlementReason: text("settlement_reason"),
|
|
@@ -7032,6 +8899,68 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
7032
8899
|
activeInventory: index("sandbox_retained_processes_active_inventory_idx")
|
|
7033
8900
|
.on(table.ownerActorKind, table.workspaceId, table.ownerTurnId, table.ownerAttemptId)
|
|
7034
8901
|
.where(sql`${table.state} = 'active'`),
|
|
8902
|
+
initiatorMembership: foreignKey({
|
|
8903
|
+
name: "sandbox_retained_processes_initiator_membership_fk",
|
|
8904
|
+
columns: [table.initiatorOrganizationMembershipId, table.accountId],
|
|
8905
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8906
|
+
}).onDelete("restrict"),
|
|
8907
|
+
authorityOwnerMembership: foreignKey({
|
|
8908
|
+
name: "sandbox_retained_processes_authority_owner_fk",
|
|
8909
|
+
columns: [table.authorityOwnerOrganizationMembershipId, table.accountId],
|
|
8910
|
+
foreignColumns: [organizationMemberships.id, organizationMemberships.accountId],
|
|
8911
|
+
}).onDelete("restrict"),
|
|
8912
|
+
initiator: index("sandbox_retained_processes_initiator_idx")
|
|
8913
|
+
.on(table.accountId, table.initiatorOrganizationMembershipId)
|
|
8914
|
+
.where(sql`${table.state} = 'active'`),
|
|
8915
|
+
initiatingHuman: index("sandbox_retained_processes_initiating_human_idx")
|
|
8916
|
+
.on(table.accountId, table.initiatingHumanSubjectId)
|
|
8917
|
+
.where(sql`${table.state} = 'active'`),
|
|
8918
|
+
initiatorValid: check(
|
|
8919
|
+
"sandbox_retained_processes_initiator_check",
|
|
8920
|
+
sql`(
|
|
8921
|
+
${table.initiatorKind} = 'legacy_unattributed'
|
|
8922
|
+
and ${table.initiatorSubjectId} = 'unattributed-legacy'
|
|
8923
|
+
and ${table.initiatingHumanSubjectId} is null
|
|
8924
|
+
and ${table.initiatorOrganizationMembershipId} is null
|
|
8925
|
+
and ${table.initiatorAuthorizationRevision} is null
|
|
8926
|
+
) or (
|
|
8927
|
+
${table.initiatorKind} in ('subject', 'service')
|
|
8928
|
+
and length(btrim(${table.initiatorSubjectId})) between 1 and 1024
|
|
8929
|
+
and ${table.initiatorSubjectId} <> 'unattributed-legacy'
|
|
8930
|
+
and (
|
|
8931
|
+
${table.initiatingHumanSubjectId} is null
|
|
8932
|
+
or length(btrim(${table.initiatingHumanSubjectId})) between 1 and 1024
|
|
8933
|
+
)
|
|
8934
|
+
and (
|
|
8935
|
+
${table.initiatorOrganizationMembershipId} is null
|
|
8936
|
+
or ${table.initiatingHumanSubjectId} is not null
|
|
8937
|
+
)
|
|
8938
|
+
and (
|
|
8939
|
+
${table.initiatorAuthorizationRevision} is null
|
|
8940
|
+
or (
|
|
8941
|
+
${table.initiatorAuthorizationRevision} > 0
|
|
8942
|
+
and ${table.initiatorOrganizationMembershipId} is not null
|
|
8943
|
+
)
|
|
8944
|
+
)
|
|
8945
|
+
)`,
|
|
8946
|
+
),
|
|
8947
|
+
tenancyValid: check(
|
|
8948
|
+
"sandbox_retained_processes_tenancy_check",
|
|
8949
|
+
sql`(
|
|
8950
|
+
${table.authorityEpoch} is null
|
|
8951
|
+
and ${table.authorityVisibility} is null
|
|
8952
|
+
and ${table.authorityOwnerOrganizationMembershipId} is null
|
|
8953
|
+
) or (
|
|
8954
|
+
${table.authorityEpoch} is not null
|
|
8955
|
+
and ${table.authorityVisibility} is not null
|
|
8956
|
+
and ${table.authorityEpoch} > 0
|
|
8957
|
+
and ${table.authorityVisibility} in ('user_private', 'workspace_shared')
|
|
8958
|
+
and (
|
|
8959
|
+
${table.authorityVisibility} <> 'user_private'
|
|
8960
|
+
or ${table.authorityOwnerOrganizationMembershipId} is not null
|
|
8961
|
+
)
|
|
8962
|
+
)`,
|
|
8963
|
+
),
|
|
7035
8964
|
identityValid: check(
|
|
7036
8965
|
"sandbox_retained_processes_identity_check",
|
|
7037
8966
|
sql`${table.leaseEpoch} >= 0
|
|
@@ -7134,6 +9063,166 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
7134
9063
|
}),
|
|
7135
9064
|
);
|
|
7136
9065
|
|
|
9066
|
+
export const sessionBackgroundCommands = pgTable(
|
|
9067
|
+
"session_background_commands",
|
|
9068
|
+
{
|
|
9069
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
9070
|
+
accountId: uuid("account_id").notNull(),
|
|
9071
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
9072
|
+
sessionId: uuid("session_id").notNull(),
|
|
9073
|
+
provider: text("provider", { enum: ["managed", "connected_machine"] }).notNull(),
|
|
9074
|
+
state: text("state", { enum: ["running", "stopping", "exited", "lost"] })
|
|
9075
|
+
.notNull()
|
|
9076
|
+
.default("running"),
|
|
9077
|
+
retainedProcessId: uuid("retained_process_id"),
|
|
9078
|
+
controlWorkspaceId: uuid("control_workspace_id"),
|
|
9079
|
+
enrollmentId: uuid("enrollment_id"),
|
|
9080
|
+
connectionInstanceId: text("connection_instance_id"),
|
|
9081
|
+
opId: text("op_id"),
|
|
9082
|
+
commandPreview: text("command_preview").notNull().default(""),
|
|
9083
|
+
cancelRequestedAt: timestamp("cancel_requested_at", { withTimezone: true }),
|
|
9084
|
+
cancelRequestedBy: text("cancel_requested_by"),
|
|
9085
|
+
exitCode: integer("exit_code"),
|
|
9086
|
+
settlementReason: text("settlement_reason"),
|
|
9087
|
+
startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9088
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
9089
|
+
reconcileAfter: timestamp("reconcile_after", { withTimezone: true }).notNull().defaultNow(),
|
|
9090
|
+
reconcileClaimId: uuid("reconcile_claim_id"),
|
|
9091
|
+
reconcileClaimedAt: timestamp("reconcile_claimed_at", { withTimezone: true }),
|
|
9092
|
+
reconcileAttempts: integer("reconcile_attempts").notNull().default(0),
|
|
9093
|
+
lastReconcileOutcome: text("last_reconcile_outcome"),
|
|
9094
|
+
reconcileProofOutcome: text("reconcile_proof_outcome", { enum: ["exited", "lost"] }),
|
|
9095
|
+
reconcileProofExitCode: integer("reconcile_proof_exit_code"),
|
|
9096
|
+
reconcileProofReason: text("reconcile_proof_reason"),
|
|
9097
|
+
reconcileProofObservedAt: timestamp("reconcile_proof_observed_at", { withTimezone: true }),
|
|
9098
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9099
|
+
},
|
|
9100
|
+
(table) => ({
|
|
9101
|
+
workspaceAccount: foreignKey({
|
|
9102
|
+
name: "session_background_commands_workspace_fk",
|
|
9103
|
+
columns: [table.workspaceId, table.accountId],
|
|
9104
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
9105
|
+
}).onDelete("cascade"),
|
|
9106
|
+
workspaceSession: foreignKey({
|
|
9107
|
+
name: "session_background_commands_session_fk",
|
|
9108
|
+
columns: [table.workspaceId, table.sessionId],
|
|
9109
|
+
foreignColumns: [sessions.workspaceId, sessions.id],
|
|
9110
|
+
}).onDelete("cascade"),
|
|
9111
|
+
controlWorkspaceAccount: foreignKey({
|
|
9112
|
+
name: "session_background_commands_control_workspace_fk",
|
|
9113
|
+
columns: [table.controlWorkspaceId, table.accountId],
|
|
9114
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
9115
|
+
}).onDelete("restrict"),
|
|
9116
|
+
retainedProcess: foreignKey({
|
|
9117
|
+
name: "session_background_commands_process_fk",
|
|
9118
|
+
columns: [table.retainedProcessId],
|
|
9119
|
+
foreignColumns: [sandboxRetainedProcesses.id],
|
|
9120
|
+
}).onDelete("restrict"),
|
|
9121
|
+
managedProcess: uniqueIndex("session_background_commands_process_uq")
|
|
9122
|
+
.on(table.retainedProcessId)
|
|
9123
|
+
.where(sql`${table.retainedProcessId} is not null`),
|
|
9124
|
+
connectedOp: uniqueIndex("session_background_commands_connected_op_uq")
|
|
9125
|
+
.on(table.controlWorkspaceId, table.enrollmentId, table.connectionInstanceId, table.opId)
|
|
9126
|
+
.where(sql`${table.provider} = 'connected_machine'`),
|
|
9127
|
+
activeSession: index("session_background_commands_active_session_idx")
|
|
9128
|
+
.on(table.workspaceId, table.sessionId, table.state, table.startedAt, table.id)
|
|
9129
|
+
.where(sql`${table.state} in ('running', 'stopping')`),
|
|
9130
|
+
stopping: index("session_background_commands_stopping_idx")
|
|
9131
|
+
.on(table.reconcileAfter, table.cancelRequestedAt, table.id)
|
|
9132
|
+
.where(sql`${table.state} in ('running', 'stopping')`),
|
|
9133
|
+
providerValid: check(
|
|
9134
|
+
"session_background_commands_provider_check",
|
|
9135
|
+
sql`${table.provider} in ('managed', 'connected_machine')`,
|
|
9136
|
+
),
|
|
9137
|
+
stateValid: check(
|
|
9138
|
+
"session_background_commands_state_check",
|
|
9139
|
+
sql`${table.state} in ('running', 'stopping', 'exited', 'lost')`,
|
|
9140
|
+
),
|
|
9141
|
+
providerIdentityValid: check(
|
|
9142
|
+
"session_background_commands_provider_identity_check",
|
|
9143
|
+
sql`(
|
|
9144
|
+
${table.provider} = 'managed'
|
|
9145
|
+
and ${table.retainedProcessId} is not null
|
|
9146
|
+
and ${table.controlWorkspaceId} is null
|
|
9147
|
+
and ${table.enrollmentId} is null
|
|
9148
|
+
and ${table.connectionInstanceId} is null
|
|
9149
|
+
and ${table.opId} is null
|
|
9150
|
+
) or (
|
|
9151
|
+
${table.provider} = 'connected_machine'
|
|
9152
|
+
and ${table.retainedProcessId} is null
|
|
9153
|
+
and ${table.controlWorkspaceId} is not null
|
|
9154
|
+
and ${table.enrollmentId} is not null
|
|
9155
|
+
and ${table.connectionInstanceId} is not null
|
|
9156
|
+
and octet_length(${table.connectionInstanceId}) between 1 and 128
|
|
9157
|
+
and ${table.opId} is not null
|
|
9158
|
+
and octet_length(${table.opId}) between 1 and 256
|
|
9159
|
+
)`,
|
|
9160
|
+
),
|
|
9161
|
+
lifecycleValid: check(
|
|
9162
|
+
"session_background_commands_lifecycle_check",
|
|
9163
|
+
sql`(
|
|
9164
|
+
${table.state} = 'running'
|
|
9165
|
+
and ${table.cancelRequestedAt} is null
|
|
9166
|
+
and ${table.cancelRequestedBy} is null
|
|
9167
|
+
and ${table.exitCode} is null
|
|
9168
|
+
and ${table.settlementReason} is null
|
|
9169
|
+
and ${table.settledAt} is null
|
|
9170
|
+
) or (
|
|
9171
|
+
${table.state} = 'stopping'
|
|
9172
|
+
and ${table.cancelRequestedAt} is not null
|
|
9173
|
+
and ${table.cancelRequestedBy} is not null
|
|
9174
|
+
and octet_length(btrim(${table.cancelRequestedBy})) between 1 and 1024
|
|
9175
|
+
and ${table.exitCode} is null
|
|
9176
|
+
and ${table.settlementReason} is null
|
|
9177
|
+
and ${table.settledAt} is null
|
|
9178
|
+
) or (
|
|
9179
|
+
${table.state} = 'exited'
|
|
9180
|
+
and ${table.settledAt} is not null
|
|
9181
|
+
and octet_length(btrim(${table.settlementReason})) between 1 and 512
|
|
9182
|
+
) or (
|
|
9183
|
+
${table.state} = 'lost'
|
|
9184
|
+
and ${table.exitCode} is null
|
|
9185
|
+
and ${table.settledAt} is not null
|
|
9186
|
+
and octet_length(btrim(${table.settlementReason})) between 1 and 512
|
|
9187
|
+
)`,
|
|
9188
|
+
),
|
|
9189
|
+
previewValid: check(
|
|
9190
|
+
"session_background_commands_preview_check",
|
|
9191
|
+
sql`octet_length(${table.commandPreview}) <= 2048`,
|
|
9192
|
+
),
|
|
9193
|
+
reconcileValid: check(
|
|
9194
|
+
"session_background_commands_reconcile_check",
|
|
9195
|
+
sql`${table.reconcileAttempts} >= 0
|
|
9196
|
+
and (
|
|
9197
|
+
(${table.reconcileClaimId} is null and ${table.reconcileClaimedAt} is null)
|
|
9198
|
+
or (${table.reconcileClaimId} is not null and ${table.reconcileClaimedAt} is not null)
|
|
9199
|
+
)
|
|
9200
|
+
and (
|
|
9201
|
+
${table.lastReconcileOutcome} is null
|
|
9202
|
+
or octet_length(${table.lastReconcileOutcome}) between 1 and 64
|
|
9203
|
+
)
|
|
9204
|
+
and (
|
|
9205
|
+
(
|
|
9206
|
+
${table.reconcileProofOutcome} is null
|
|
9207
|
+
and ${table.reconcileProofExitCode} is null
|
|
9208
|
+
and ${table.reconcileProofReason} is null
|
|
9209
|
+
and ${table.reconcileProofObservedAt} is null
|
|
9210
|
+
) or (
|
|
9211
|
+
${table.reconcileProofOutcome} = 'exited'
|
|
9212
|
+
and ${table.reconcileProofExitCode} is not null
|
|
9213
|
+
and octet_length(btrim(${table.reconcileProofReason})) between 1 and 512
|
|
9214
|
+
and ${table.reconcileProofObservedAt} is not null
|
|
9215
|
+
) or (
|
|
9216
|
+
${table.reconcileProofOutcome} = 'lost'
|
|
9217
|
+
and ${table.reconcileProofExitCode} is null
|
|
9218
|
+
and octet_length(btrim(${table.reconcileProofReason})) between 1 and 512
|
|
9219
|
+
and ${table.reconcileProofObservedAt} is not null
|
|
9220
|
+
)
|
|
9221
|
+
)`,
|
|
9222
|
+
),
|
|
9223
|
+
}),
|
|
9224
|
+
);
|
|
9225
|
+
|
|
7137
9226
|
// The recording lifecycle states (P4.3). Exported so the activity + the query
|
|
7138
9227
|
// layer share one source of truth for the §3.1 state machine.
|
|
7139
9228
|
export const sessionRecordingStateValues = [
|
|
@@ -7354,6 +9443,17 @@ export const enrollmentExposureValues = ["whole-machine"] as const;
|
|
|
7354
9443
|
export const enrollmentStatusValues = ["active", "revoked"] as const;
|
|
7355
9444
|
export const enrollmentOsValues = ["linux", "macos", "windows"] as const;
|
|
7356
9445
|
export const sandboxKindValues = ["modal", "selfhosted"] as const;
|
|
9446
|
+
export const agentUpdateStatusValues = [
|
|
9447
|
+
"requested",
|
|
9448
|
+
"accepted",
|
|
9449
|
+
"waiting_for_idle",
|
|
9450
|
+
"downloading",
|
|
9451
|
+
"verifying",
|
|
9452
|
+
"applying",
|
|
9453
|
+
"restarting",
|
|
9454
|
+
"succeeded",
|
|
9455
|
+
"failed",
|
|
9456
|
+
] as const;
|
|
7357
9457
|
|
|
7358
9458
|
// One row per registered machine. The agent's ed25519 PUBLIC key IS the machine
|
|
7359
9459
|
// identity (the NATS control-plane subject the agent subscribes to maps to it).
|
|
@@ -7371,6 +9471,11 @@ export const enrollments = pgTable(
|
|
|
7371
9471
|
workspaceId: uuid("workspace_id")
|
|
7372
9472
|
.notNull()
|
|
7373
9473
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
9474
|
+
authorityScope: text("authority_scope").notNull().default("workspace"),
|
|
9475
|
+
authorityId: uuid("authority_id"),
|
|
9476
|
+
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
9477
|
+
originWorkspaceId: uuid("origin_workspace_id"),
|
|
9478
|
+
generation: bigint("generation", { mode: "number" }).notNull().default(1),
|
|
7374
9479
|
// The agent's ed25519 public key (the machine identity).
|
|
7375
9480
|
pubkey: text("pubkey").notNull(),
|
|
7376
9481
|
exposure: text("exposure", { enum: enrollmentExposureValues })
|
|
@@ -7389,13 +9494,49 @@ export const enrollments = pgTable(
|
|
|
7389
9494
|
// from every connect Hello alongside has_display.
|
|
7390
9495
|
desktopUnavailableReason: text("desktop_unavailable_reason"),
|
|
7391
9496
|
allowScreenControl: boolean("allow_screen_control").notNull().default(false),
|
|
9497
|
+
// Optional per-connection command policy. NULL is the unrestricted default.
|
|
9498
|
+
// Values remain within JavaScript's exact-integer wire range; local runner and
|
|
9499
|
+
// ancestor host policy may only tighten them at execution.
|
|
9500
|
+
operationMemoryMaxBytes: bigint("operation_memory_max_bytes", {
|
|
9501
|
+
mode: "number",
|
|
9502
|
+
}),
|
|
9503
|
+
operationMemoryHighBytes: bigint("operation_memory_high_bytes", {
|
|
9504
|
+
mode: "number",
|
|
9505
|
+
}),
|
|
9506
|
+
operationCpuMaxMillicores: bigint("operation_cpu_max_millicores", {
|
|
9507
|
+
mode: "number",
|
|
9508
|
+
}),
|
|
9509
|
+
operationPolicyRevision: integer("operation_policy_revision").notNull().default(0),
|
|
9510
|
+
operationPolicyUpdatedAt: timestamp("operation_policy_updated_at", {
|
|
9511
|
+
withTimezone: true,
|
|
9512
|
+
}),
|
|
7392
9513
|
status: text("status", { enum: enrollmentStatusValues }).notNull().default("active"),
|
|
7393
9514
|
// Credential-family fence. Existing rows/migration-era bearers are generation
|
|
7394
9515
|
// 1; every successful re-enrollment increments this atomically before a new
|
|
7395
9516
|
// bearer is signed. Auth and self-revoke require an exact row/claim match.
|
|
7396
9517
|
credentialGeneration: integer("credential_generation").notNull().default(1),
|
|
9518
|
+
// One live runner instance owns this enrollment's data-plane address at a
|
|
9519
|
+
// time. Auth-callout claims/renews the lease before NATS grants a connection;
|
|
9520
|
+
// every operational subject includes the instance id, so an older still-open
|
|
9521
|
+
// socket cannot receive work after a successor claims authority.
|
|
9522
|
+
connectionInstanceId: text("connection_instance_id"),
|
|
9523
|
+
connectionGeneration: integer("connection_generation").notNull().default(0),
|
|
9524
|
+
connectionLeaseExpiresAt: timestamp("connection_lease_expires_at", {
|
|
9525
|
+
withTimezone: true,
|
|
9526
|
+
}),
|
|
9527
|
+
// Durable diagnostics for valid cloned credentials / duplicate daemons that
|
|
9528
|
+
// were blocked while another process held the live authority lease.
|
|
9529
|
+
connectionDuplicateDeniedCount: integer("connection_duplicate_denied_count")
|
|
9530
|
+
.notNull()
|
|
9531
|
+
.default(0),
|
|
9532
|
+
connectionDuplicateDeniedAt: timestamp("connection_duplicate_denied_at", {
|
|
9533
|
+
withTimezone: true,
|
|
9534
|
+
}),
|
|
7397
9535
|
os: text("os", { enum: enrollmentOsValues }).notNull().default("linux"),
|
|
7398
9536
|
arch: text("arch").notNull().default("x86_64"),
|
|
9537
|
+
// Exact absolute launch root reported by the authoritative runner Hello.
|
|
9538
|
+
// Null means no current runner has supplied a usable root yet.
|
|
9539
|
+
workspaceRoot: text("workspace_root"),
|
|
7399
9540
|
// Heartbeat liveness cursor. Null until the first connect.
|
|
7400
9541
|
lastSeenAt: timestamp("last_seen_at", { withTimezone: true }),
|
|
7401
9542
|
// Clean going-offline marker (migration 0049). Set when the machine announces a
|
|
@@ -7406,18 +9547,154 @@ export const enrollments = pgTable(
|
|
|
7406
9547
|
// (the default) ⇒ no goodbye pending — today's last_seen-aging behavior.
|
|
7407
9548
|
wentOfflineAt: timestamp("went_offline_at", { withTimezone: true }),
|
|
7408
9549
|
wentOfflineReason: text("went_offline_reason"),
|
|
9550
|
+
// Exact running build + negotiated capability truth, refreshed from the
|
|
9551
|
+
// authoritative process Hello. Null means an older agent has not reported it.
|
|
9552
|
+
agentVersion: text("agent_version"),
|
|
9553
|
+
agentBinarySha256: text("agent_binary_sha256"),
|
|
9554
|
+
agentUpdateChannel: text("agent_update_channel", {
|
|
9555
|
+
enum: ["stable", "beta"] as const,
|
|
9556
|
+
}),
|
|
9557
|
+
agentCapabilities: jsonb("agent_capabilities")
|
|
9558
|
+
.$type<Record<string, boolean>>()
|
|
9559
|
+
.notNull()
|
|
9560
|
+
.default({}),
|
|
9561
|
+
// One current/most-recent self-update. The accepting connection coordinates
|
|
9562
|
+
// fence every progress write; a successor Hello is the only success signal.
|
|
9563
|
+
agentUpdateOperationId: uuid("agent_update_operation_id"),
|
|
9564
|
+
agentUpdateStatus: text("agent_update_status", {
|
|
9565
|
+
enum: agentUpdateStatusValues,
|
|
9566
|
+
}),
|
|
9567
|
+
agentUpdateTargetVersion: text("agent_update_target_version"),
|
|
9568
|
+
agentUpdateExpectedBinarySha256: text("agent_update_expected_binary_sha256"),
|
|
9569
|
+
agentUpdateErrorCode: text("agent_update_error_code"),
|
|
9570
|
+
agentUpdateRetryable: boolean("agent_update_retryable").notNull().default(false),
|
|
9571
|
+
agentUpdateRolledBack: boolean("agent_update_rolled_back").notNull().default(false),
|
|
9572
|
+
agentUpdateConnectionInstanceId: text("agent_update_connection_instance_id"),
|
|
9573
|
+
agentUpdateConnectionGeneration: integer("agent_update_connection_generation"),
|
|
9574
|
+
agentUpdateRequestedAt: timestamp("agent_update_requested_at", {
|
|
9575
|
+
withTimezone: true,
|
|
9576
|
+
}),
|
|
9577
|
+
agentUpdateUpdatedAt: timestamp("agent_update_updated_at", {
|
|
9578
|
+
withTimezone: true,
|
|
9579
|
+
}),
|
|
9580
|
+
agentUpdateCompletedAt: timestamp("agent_update_completed_at", {
|
|
9581
|
+
withTimezone: true,
|
|
9582
|
+
}),
|
|
7409
9583
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7410
9584
|
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
7411
9585
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7412
9586
|
},
|
|
7413
9587
|
(table) => ({
|
|
7414
|
-
// One enrollment per
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
table.pubkey
|
|
7418
|
-
|
|
9588
|
+
// One enrollment identity per authority boundary and pubkey. Revocation keeps
|
|
9589
|
+
// the identity so a re-enroll can reactivate the same durable row.
|
|
9590
|
+
workspacePubkey: uniqueIndex("enrollments_workspace_pubkey_idx")
|
|
9591
|
+
.on(table.workspaceId, table.pubkey)
|
|
9592
|
+
.where(sql`${table.authorityScope} = 'workspace'`),
|
|
9593
|
+
organizationPubkey: uniqueIndex("enrollments_organization_pubkey_idx")
|
|
9594
|
+
.on(table.accountId, table.pubkey)
|
|
9595
|
+
.where(sql`${table.authorityScope} = 'organization'`),
|
|
9596
|
+
userPubkey: uniqueIndex("enrollments_user_pubkey_idx")
|
|
9597
|
+
.on(table.accountId, table.ownerOrganizationMembershipId, table.pubkey)
|
|
9598
|
+
.where(sql`${table.authorityScope} = 'user'`),
|
|
7419
9599
|
// List a workspace's ACTIVE machines without scanning revoked rows.
|
|
7420
9600
|
workspaceStatus: index("enrollments_workspace_status_idx").on(table.workspaceId, table.status),
|
|
9601
|
+
authorityShape: check(
|
|
9602
|
+
"enrollments_authority_shape_check",
|
|
9603
|
+
sql`(
|
|
9604
|
+
${table.authorityScope} in ('organization', 'workspace')
|
|
9605
|
+
and ${table.authorityId} is null
|
|
9606
|
+
and ${table.ownerOrganizationMembershipId} is null
|
|
9607
|
+
) or (
|
|
9608
|
+
${table.authorityScope} = 'user'
|
|
9609
|
+
and ${table.authorityId} is not null
|
|
9610
|
+
and ${table.ownerOrganizationMembershipId} is not null
|
|
9611
|
+
)`,
|
|
9612
|
+
),
|
|
9613
|
+
authorityScopeValid: check(
|
|
9614
|
+
"enrollments_authority_scope_check",
|
|
9615
|
+
sql`${table.authorityScope} in ('organization', 'workspace', 'user')`,
|
|
9616
|
+
),
|
|
9617
|
+
generationPositive: check("enrollments_generation_check", sql`${table.generation} > 0`),
|
|
9618
|
+
authority: foreignKey({
|
|
9619
|
+
name: "enrollments_authority_fk",
|
|
9620
|
+
columns: [table.authorityId, table.accountId, table.ownerOrganizationMembershipId],
|
|
9621
|
+
foreignColumns: [
|
|
9622
|
+
organizationUserResourceAuthorities.id,
|
|
9623
|
+
organizationUserResourceAuthorities.accountId,
|
|
9624
|
+
organizationUserResourceAuthorities.organizationMembershipId,
|
|
9625
|
+
],
|
|
9626
|
+
}).onDelete("restrict"),
|
|
9627
|
+
connectionAuthorityShape: check(
|
|
9628
|
+
"enrollments_connection_authority_shape_chk",
|
|
9629
|
+
sql`(${table.connectionInstanceId} is null and ${table.connectionLeaseExpiresAt} is null)
|
|
9630
|
+
or (${table.connectionInstanceId} is not null
|
|
9631
|
+
and length(${table.connectionInstanceId}) between 1 and 128
|
|
9632
|
+
and ${table.connectionLeaseExpiresAt} is not null)`,
|
|
9633
|
+
),
|
|
9634
|
+
connectionGenerationNonnegative: check(
|
|
9635
|
+
"enrollments_connection_generation_chk",
|
|
9636
|
+
sql`${table.connectionGeneration} >= 0`,
|
|
9637
|
+
),
|
|
9638
|
+
operationMemoryMaxShape: check(
|
|
9639
|
+
"enrollments_operation_memory_max_shape_chk",
|
|
9640
|
+
sql`${table.operationMemoryMaxBytes} is null or (${table.operationMemoryMaxBytes} > 0 and ${table.operationMemoryMaxBytes} <= 9007199254740991)`,
|
|
9641
|
+
),
|
|
9642
|
+
operationMemoryHighShape: check(
|
|
9643
|
+
"enrollments_operation_memory_high_shape_chk",
|
|
9644
|
+
sql`${table.operationMemoryHighBytes} is null or (${table.operationMemoryHighBytes} > 0 and ${table.operationMemoryHighBytes} <= 9007199254740991)`,
|
|
9645
|
+
),
|
|
9646
|
+
operationMemoryOrder: check(
|
|
9647
|
+
"enrollments_operation_memory_order_chk",
|
|
9648
|
+
sql`${table.operationMemoryMaxBytes} is null or ${table.operationMemoryHighBytes} is null or ${table.operationMemoryHighBytes} <= ${table.operationMemoryMaxBytes}`,
|
|
9649
|
+
),
|
|
9650
|
+
operationCpuShape: check(
|
|
9651
|
+
"enrollments_operation_cpu_shape_chk",
|
|
9652
|
+
sql`${table.operationCpuMaxMillicores} is null or ${table.operationCpuMaxMillicores} between 1 and 4294967295`,
|
|
9653
|
+
),
|
|
9654
|
+
operationPolicyRevisionNonnegative: check(
|
|
9655
|
+
"enrollments_operation_policy_revision_chk",
|
|
9656
|
+
sql`${table.operationPolicyRevision} >= 0`,
|
|
9657
|
+
),
|
|
9658
|
+
agentBinarySha256Shape: check(
|
|
9659
|
+
"enrollments_agent_binary_sha256_chk",
|
|
9660
|
+
sql`${table.agentBinarySha256} is null or ${table.agentBinarySha256} ~ '^[0-9a-f]{64}$'`,
|
|
9661
|
+
),
|
|
9662
|
+
agentUpdateChannelShape: check(
|
|
9663
|
+
"enrollments_agent_update_channel_chk",
|
|
9664
|
+
sql`${table.agentUpdateChannel} is null or ${table.agentUpdateChannel} in ('stable', 'beta')`,
|
|
9665
|
+
),
|
|
9666
|
+
agentUpdateExpectedBinarySha256Shape: check(
|
|
9667
|
+
"enrollments_agent_update_expected_binary_sha256_chk",
|
|
9668
|
+
sql`${table.agentUpdateExpectedBinarySha256} is null or ${table.agentUpdateExpectedBinarySha256} ~ '^[0-9a-f]{64}$'`,
|
|
9669
|
+
),
|
|
9670
|
+
agentUpdateStateShape: check(
|
|
9671
|
+
"enrollments_agent_update_state_shape_chk",
|
|
9672
|
+
sql`(
|
|
9673
|
+
(${table.agentUpdateOperationId} is null
|
|
9674
|
+
and ${table.agentUpdateStatus} is null
|
|
9675
|
+
and ${table.agentUpdateTargetVersion} is null
|
|
9676
|
+
and ${table.agentUpdateConnectionInstanceId} is null
|
|
9677
|
+
and ${table.agentUpdateConnectionGeneration} is null
|
|
9678
|
+
and ${table.agentUpdateRequestedAt} is null
|
|
9679
|
+
and ${table.agentUpdateUpdatedAt} is null)
|
|
9680
|
+
or
|
|
9681
|
+
(${table.agentUpdateOperationId} is not null
|
|
9682
|
+
and ${table.agentUpdateStatus} in (
|
|
9683
|
+
'requested', 'accepted', 'waiting_for_idle', 'downloading', 'verifying',
|
|
9684
|
+
'applying', 'restarting', 'succeeded', 'failed'
|
|
9685
|
+
)
|
|
9686
|
+
and ${table.agentUpdateTargetVersion} is not null
|
|
9687
|
+
and ${table.agentUpdateConnectionInstanceId} is not null
|
|
9688
|
+
and ${table.agentUpdateConnectionGeneration} is not null
|
|
9689
|
+
and ${table.agentUpdateConnectionGeneration} >= 0
|
|
9690
|
+
and ${table.agentUpdateRequestedAt} is not null
|
|
9691
|
+
and ${table.agentUpdateUpdatedAt} is not null)
|
|
9692
|
+
)`,
|
|
9693
|
+
),
|
|
9694
|
+
connectionDuplicateDeniedCountNonnegative: check(
|
|
9695
|
+
"enrollments_connection_duplicate_denied_count_chk",
|
|
9696
|
+
sql`${table.connectionDuplicateDeniedCount} >= 0`,
|
|
9697
|
+
),
|
|
7421
9698
|
}),
|
|
7422
9699
|
);
|
|
7423
9700
|
|
|
@@ -7719,6 +9996,12 @@ export const scheduledTasks = pgTable(
|
|
|
7719
9996
|
.$type<XaiProviderAccountAuthoritySnapshotV1>()
|
|
7720
9997
|
.notNull()
|
|
7721
9998
|
.default(WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1),
|
|
9999
|
+
authorityRevision: bigint("authority_revision", { mode: "number" }).notNull().default(1),
|
|
10000
|
+
// The migration-owned BEFORE INSERT/UPDATE trigger replaces this client
|
|
10001
|
+
// placeholder with the canonical whole-row execution digest.
|
|
10002
|
+
executionDigest: text("execution_digest")
|
|
10003
|
+
.notNull()
|
|
10004
|
+
.$defaultFn(() => ""),
|
|
7722
10005
|
reusableSessionId: uuid("reusable_session_id").references(() => sessions.id, {
|
|
7723
10006
|
onDelete: "set null",
|
|
7724
10007
|
}),
|
|
@@ -7730,6 +10013,7 @@ export const scheduledTasks = pgTable(
|
|
|
7730
10013
|
// in migration 0047 (forward-reference pattern). Consumed in M3.
|
|
7731
10014
|
rigId: uuid("rig_id"),
|
|
7732
10015
|
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
|
|
10016
|
+
deletedAt: timestamp("deleted_at", { withTimezone: true }),
|
|
7733
10017
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7734
10018
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7735
10019
|
},
|
|
@@ -7761,6 +10045,12 @@ export const temporalScheduleCleanupOutbox = pgTable(
|
|
|
7761
10045
|
accountId: uuid("account_id").notNull(),
|
|
7762
10046
|
workspaceId: uuid("workspace_id").notNull(),
|
|
7763
10047
|
temporalScheduleId: text("temporal_schedule_id").notNull(),
|
|
10048
|
+
scheduledTaskId: uuid("scheduled_task_id"),
|
|
10049
|
+
connectorCleanupSubjectId: text("connector_cleanup_subject_id"),
|
|
10050
|
+
connectorCleanupSnapshot: jsonb("connector_cleanup_snapshot"),
|
|
10051
|
+
connectorCleanupCompletedAt: timestamp("connector_cleanup_completed_at", {
|
|
10052
|
+
withTimezone: true,
|
|
10053
|
+
}),
|
|
7764
10054
|
claimId: uuid("claim_id"),
|
|
7765
10055
|
claimUntil: timestamp("claim_until", { withTimezone: true }),
|
|
7766
10056
|
attemptCount: integer("attempt_count").notNull().default(0),
|
|
@@ -7784,6 +10074,58 @@ export const temporalScheduleCleanupOutbox = pgTable(
|
|
|
7784
10074
|
and ${table.attemptCount} >= 0
|
|
7785
10075
|
and ((${table.claimId} is null and ${table.claimUntil} is null)
|
|
7786
10076
|
or (${table.claimId} is not null and ${table.claimUntil} is not null))
|
|
10077
|
+
and ((${table.scheduledTaskId} is null and ${table.connectorCleanupSubjectId} is null
|
|
10078
|
+
and ${table.connectorCleanupSnapshot} is null)
|
|
10079
|
+
or (${table.scheduledTaskId} is not null and ${table.connectorCleanupSubjectId} is not null
|
|
10080
|
+
and ${table.connectorCleanupSnapshot} is not null))
|
|
10081
|
+
and (${table.connectorCleanupSnapshot} is not null
|
|
10082
|
+
or ${table.connectorCleanupCompletedAt} is null)
|
|
10083
|
+
and (${table.connectorCleanupSubjectId} is null
|
|
10084
|
+
or octet_length(${table.connectorCleanupSubjectId}) between 1 and 4096)
|
|
10085
|
+
and (${table.connectorCleanupSnapshot} is null or (
|
|
10086
|
+
jsonb_typeof(${table.connectorCleanupSnapshot}) = 'object'
|
|
10087
|
+
and ${table.connectorCleanupSnapshot} ?& array[
|
|
10088
|
+
'version','taskId','accountId','workspaceId','connectorKind','connectionId',
|
|
10089
|
+
'connectionVersion','sourceId','sourceLifecycleGeneration',
|
|
10090
|
+
'sourceConfigGeneration','externalSourceId','subjectId'
|
|
10091
|
+
]
|
|
10092
|
+
and ${table.connectorCleanupSnapshot} - array[
|
|
10093
|
+
'version','taskId','accountId','workspaceId','connectorKind','connectionId',
|
|
10094
|
+
'connectionVersion','sourceId','sourceLifecycleGeneration',
|
|
10095
|
+
'sourceConfigGeneration','externalSourceId','subjectId'
|
|
10096
|
+
]::text[] = '{}'::jsonb
|
|
10097
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'version') = 'number'
|
|
10098
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'taskId') = 'string'
|
|
10099
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'accountId') = 'string'
|
|
10100
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'workspaceId') = 'string'
|
|
10101
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'connectorKind') = 'string'
|
|
10102
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'connectionId') = 'string'
|
|
10103
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'connectionVersion') = 'number'
|
|
10104
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'sourceId') = 'string'
|
|
10105
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'sourceLifecycleGeneration') = 'number'
|
|
10106
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'sourceConfigGeneration') = 'number'
|
|
10107
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'externalSourceId') = 'string'
|
|
10108
|
+
and jsonb_typeof(${table.connectorCleanupSnapshot}->'subjectId') = 'string'
|
|
10109
|
+
and ${table.connectorCleanupSnapshot}->>'version' = '1'
|
|
10110
|
+
and ${table.connectorCleanupSnapshot}->>'connectorKind' in ('google_drive','atlassian')
|
|
10111
|
+
and ${table.connectorCleanupSnapshot}->>'subjectId' = ${table.connectorCleanupSubjectId}
|
|
10112
|
+
and ${table.connectorCleanupSnapshot}->>'taskId' = ${table.scheduledTaskId}::text
|
|
10113
|
+
and ${table.connectorCleanupSnapshot}->>'accountId' = ${table.accountId}::text
|
|
10114
|
+
and ${table.connectorCleanupSnapshot}->>'workspaceId' = ${table.workspaceId}::text
|
|
10115
|
+
and octet_length(${table.connectorCleanupSnapshot}->>'externalSourceId') between 1 and 2048
|
|
10116
|
+
and octet_length(${table.connectorCleanupSnapshot}->>'subjectId') between 1 and 4096
|
|
10117
|
+
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}$'
|
|
10118
|
+
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}$'
|
|
10119
|
+
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}$'
|
|
10120
|
+
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}$'
|
|
10121
|
+
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}$'
|
|
10122
|
+
and ${table.connectorCleanupSnapshot}->>'connectionVersion' ~ '^[1-9][0-9]*$'
|
|
10123
|
+
and ${table.connectorCleanupSnapshot}->>'sourceLifecycleGeneration' ~ '^[1-9][0-9]*$'
|
|
10124
|
+
and ${table.connectorCleanupSnapshot}->>'sourceConfigGeneration' ~ '^[1-9][0-9]*$'
|
|
10125
|
+
and (${table.connectorCleanupSnapshot}->>'connectionVersion')::numeric <= 9007199254740991
|
|
10126
|
+
and (${table.connectorCleanupSnapshot}->>'sourceLifecycleGeneration')::numeric <= 9007199254740991
|
|
10127
|
+
and (${table.connectorCleanupSnapshot}->>'sourceConfigGeneration')::numeric <= 9007199254740991
|
|
10128
|
+
))
|
|
7787
10129
|
and (${table.lastError} is null or length(${table.lastError}) <= 2000)`,
|
|
7788
10130
|
),
|
|
7789
10131
|
}),
|
|
@@ -7801,14 +10143,16 @@ export const scheduledTaskRuns = pgTable(
|
|
|
7801
10143
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
7802
10144
|
taskId: uuid("task_id")
|
|
7803
10145
|
.notNull()
|
|
7804
|
-
.references(() => scheduledTasks.id
|
|
10146
|
+
.references(() => scheduledTasks.id),
|
|
10147
|
+
taskAuthorityRevision: bigint("task_authority_revision", {
|
|
10148
|
+
mode: "number",
|
|
10149
|
+
}),
|
|
10150
|
+
taskExecutionDigest: text("task_execution_digest"),
|
|
7805
10151
|
status: text("status").notNull().default("queued"),
|
|
7806
10152
|
triggerType: text("trigger_type").notNull(),
|
|
7807
10153
|
scheduledAt: timestamp("scheduled_at", { withTimezone: true }),
|
|
7808
10154
|
firedAt: timestamp("fired_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7809
|
-
sessionId: uuid("session_id").references(() => sessions.id,
|
|
7810
|
-
onDelete: "set null",
|
|
7811
|
-
}),
|
|
10155
|
+
sessionId: uuid("session_id").references(() => sessions.id),
|
|
7812
10156
|
triggerEventId: uuid("trigger_event_id"),
|
|
7813
10157
|
actionKind: text("action_kind").notNull().default("agent_turn"),
|
|
7814
10158
|
knowledgeSyncRunId: uuid("knowledge_sync_run_id"),
|
|
@@ -7817,6 +10161,10 @@ export const scheduledTaskRuns = pgTable(
|
|
|
7817
10161
|
// Stable Temporal producer identity. Activity replay/re-dispatch returns
|
|
7818
10162
|
// the exact run instead of allocating a second schedule source row.
|
|
7819
10163
|
producerKey: text("producer_key"),
|
|
10164
|
+
// Complete credential-free accepted execution truth. It is private worker
|
|
10165
|
+
// authority and never appears in public scheduled-run projections.
|
|
10166
|
+
acceptedExecutionSnapshot: jsonb("accepted_execution_snapshot").$type<unknown>(),
|
|
10167
|
+
acceptedExecutionDigest: text("accepted_execution_digest"),
|
|
7820
10168
|
error: text("error"),
|
|
7821
10169
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7822
10170
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -7923,45 +10271,186 @@ export const githubInstallations = pgTable(
|
|
|
7923
10271
|
)
|
|
7924
10272
|
`,
|
|
7925
10273
|
),
|
|
7926
|
-
authorityNonce: uniqueIndex("github_installations_authority_nonce_uq")
|
|
7927
|
-
.on(table.authorityNonce)
|
|
7928
|
-
.where(sql`${table.authorityNonce} is not null`),
|
|
10274
|
+
authorityNonce: uniqueIndex("github_installations_authority_nonce_uq")
|
|
10275
|
+
.on(table.authorityNonce)
|
|
10276
|
+
.where(sql`${table.authorityNonce} is not null`),
|
|
10277
|
+
}),
|
|
10278
|
+
);
|
|
10279
|
+
|
|
10280
|
+
export const githubInstallationRepositories = pgTable(
|
|
10281
|
+
"github_installation_repositories",
|
|
10282
|
+
{
|
|
10283
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
10284
|
+
accountId: uuid("account_id")
|
|
10285
|
+
.notNull()
|
|
10286
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
10287
|
+
workspaceId: uuid("workspace_id")
|
|
10288
|
+
.notNull()
|
|
10289
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
10290
|
+
installationId: integer("installation_id").notNull(),
|
|
10291
|
+
repositoryId: bigint("repository_id", { mode: "number" }).notNull(),
|
|
10292
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10293
|
+
},
|
|
10294
|
+
(table) => ({
|
|
10295
|
+
installationRepository: uniqueIndex("github_install_repo_workspace_installation_repo_idx").on(
|
|
10296
|
+
table.workspaceId,
|
|
10297
|
+
table.installationId,
|
|
10298
|
+
table.repositoryId,
|
|
10299
|
+
),
|
|
10300
|
+
workspaceInstallation: index("github_install_repo_workspace_installation_idx").on(
|
|
10301
|
+
table.workspaceId,
|
|
10302
|
+
table.installationId,
|
|
10303
|
+
),
|
|
10304
|
+
workspaceAccount: foreignKey({
|
|
10305
|
+
columns: [table.workspaceId, table.accountId],
|
|
10306
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
10307
|
+
name: "github_installation_repositories_workspace_account_fk",
|
|
10308
|
+
}).onDelete("cascade"),
|
|
10309
|
+
installationBinding: foreignKey({
|
|
10310
|
+
columns: [table.workspaceId, table.installationId],
|
|
10311
|
+
foreignColumns: [githubInstallations.workspaceId, githubInstallations.installationId],
|
|
10312
|
+
name: "github_installation_repositories_installation_fk",
|
|
10313
|
+
}).onDelete("cascade"),
|
|
10314
|
+
}),
|
|
10315
|
+
);
|
|
10316
|
+
|
|
10317
|
+
export const prReviewAppRegistrations = pgTable(
|
|
10318
|
+
"pr_review_app_registrations",
|
|
10319
|
+
{
|
|
10320
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
10321
|
+
sourceId: uuid("source_id").notNull(),
|
|
10322
|
+
accountId: uuid("account_id")
|
|
10323
|
+
.notNull()
|
|
10324
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
10325
|
+
workspaceId: uuid("workspace_id")
|
|
10326
|
+
.notNull()
|
|
10327
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
10328
|
+
name: text("name").notNull(),
|
|
10329
|
+
provider: text("provider").notNull(),
|
|
10330
|
+
providerBaseUrl: text("provider_base_url").notNull(),
|
|
10331
|
+
appId: text("app_id"),
|
|
10332
|
+
credentialKind: text("credential_kind").notNull(),
|
|
10333
|
+
credentialEncrypted: text("credential_encrypted"),
|
|
10334
|
+
accessTokenExpiresAt: timestamp("access_token_expires_at", { withTimezone: true }),
|
|
10335
|
+
webhookAuthKind: text("webhook_auth_kind").notNull(),
|
|
10336
|
+
webhookUsername: text("webhook_username"),
|
|
10337
|
+
status: text("status").notNull().default("active"),
|
|
10338
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
10339
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10340
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10341
|
+
},
|
|
10342
|
+
(table) => ({
|
|
10343
|
+
workspaceRegistration: uniqueIndex("pr_review_app_registrations_workspace_id_uq").on(
|
|
10344
|
+
table.workspaceId,
|
|
10345
|
+
table.id,
|
|
10346
|
+
),
|
|
10347
|
+
workspaceRegistrationProvider: uniqueIndex(
|
|
10348
|
+
"pr_review_app_registrations_workspace_id_provider_uq",
|
|
10349
|
+
).on(table.workspaceId, table.id, table.provider),
|
|
10350
|
+
workspaceProviderName: uniqueIndex("pr_review_app_registrations_workspace_provider_name_uq").on(
|
|
10351
|
+
table.workspaceId,
|
|
10352
|
+
table.provider,
|
|
10353
|
+
table.name,
|
|
10354
|
+
),
|
|
10355
|
+
workspaceStatus: index("pr_review_app_registrations_workspace_status_idx").on(
|
|
10356
|
+
table.workspaceId,
|
|
10357
|
+
table.status,
|
|
10358
|
+
),
|
|
10359
|
+
providerCheck: check(
|
|
10360
|
+
"pr_review_app_registrations_provider_chk",
|
|
10361
|
+
sql`${table.provider} in ('github', 'gitlab', 'azure_devops')`,
|
|
10362
|
+
),
|
|
10363
|
+
credentialCheck: check(
|
|
10364
|
+
"pr_review_app_registrations_credential_chk",
|
|
10365
|
+
sql`(
|
|
10366
|
+
(${table.provider} = 'github' and ${table.credentialKind} = 'github_app' and ${table.credentialEncrypted} is not null and ${table.appId} is not null)
|
|
10367
|
+
or
|
|
10368
|
+
(${table.provider} in ('gitlab', 'azure_devops') and ${table.credentialKind} = 'provider_token' and ${table.credentialEncrypted} is not null)
|
|
10369
|
+
)`,
|
|
10370
|
+
),
|
|
10371
|
+
webhookAuthCheck: check(
|
|
10372
|
+
"pr_review_app_registrations_webhook_auth_chk",
|
|
10373
|
+
sql`(
|
|
10374
|
+
(${table.provider} = 'github' and ${table.webhookAuthKind} = 'hmac_sha256')
|
|
10375
|
+
or (${table.provider} = 'gitlab' and ${table.webhookAuthKind} = 'shared_token')
|
|
10376
|
+
or (${table.provider} = 'azure_devops' and ${table.webhookAuthKind} = 'basic' and ${table.webhookUsername} is not null)
|
|
10377
|
+
)`,
|
|
10378
|
+
),
|
|
10379
|
+
statusCheck: check(
|
|
10380
|
+
"pr_review_app_registrations_status_chk",
|
|
10381
|
+
sql`${table.status} in ('active', 'disabled')`,
|
|
10382
|
+
),
|
|
10383
|
+
workspaceAccount: foreignKey({
|
|
10384
|
+
columns: [table.workspaceId, table.accountId],
|
|
10385
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
10386
|
+
name: "pr_review_app_registrations_workspace_account_fk",
|
|
10387
|
+
}).onDelete("cascade"),
|
|
7929
10388
|
}),
|
|
7930
10389
|
);
|
|
7931
10390
|
|
|
7932
|
-
export const
|
|
7933
|
-
"
|
|
10391
|
+
export const prReviewRepositoryBindings = pgTable(
|
|
10392
|
+
"pr_review_repository_bindings",
|
|
7934
10393
|
{
|
|
7935
10394
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
10395
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
7936
10396
|
accountId: uuid("account_id")
|
|
7937
10397
|
.notNull()
|
|
7938
10398
|
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
7939
10399
|
workspaceId: uuid("workspace_id")
|
|
7940
10400
|
.notNull()
|
|
7941
10401
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
7942
|
-
|
|
7943
|
-
|
|
10402
|
+
registrationId: uuid("registration_id").notNull(),
|
|
10403
|
+
provider: text("provider").notNull(),
|
|
10404
|
+
repositoryUri: text("repository_uri").notNull(),
|
|
10405
|
+
repositoryFullName: text("repository_full_name").notNull(),
|
|
10406
|
+
providerRepositoryId: text("provider_repository_id").notNull(),
|
|
10407
|
+
installationId: text("installation_id"),
|
|
10408
|
+
projectId: text("project_id"),
|
|
10409
|
+
model: text("model"),
|
|
10410
|
+
additionalInstructions: text("additional_instructions"),
|
|
10411
|
+
status: text("status").notNull().default("active"),
|
|
10412
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
7944
10413
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10414
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
7945
10415
|
},
|
|
7946
10416
|
(table) => ({
|
|
7947
|
-
|
|
10417
|
+
workspaceBinding: uniqueIndex("pr_review_repository_bindings_workspace_id_uq").on(
|
|
7948
10418
|
table.workspaceId,
|
|
7949
|
-
table.
|
|
7950
|
-
table.repositoryId,
|
|
10419
|
+
table.id,
|
|
7951
10420
|
),
|
|
7952
|
-
|
|
10421
|
+
workspaceBindingRegistrationProvider: uniqueIndex(
|
|
10422
|
+
"pr_review_repo_workspace_registration_provider_uq",
|
|
10423
|
+
).on(table.workspaceId, table.id, table.registrationId, table.provider),
|
|
10424
|
+
registrationRepository: uniqueIndex("pr_review_repository_bindings_registration_repo_uq").on(
|
|
10425
|
+
table.registrationId,
|
|
10426
|
+
table.providerRepositoryId,
|
|
10427
|
+
),
|
|
10428
|
+
triggerIdentity: uniqueIndex("pr_review_repository_bindings_trigger_uq").on(table.triggerId),
|
|
10429
|
+
workspaceStatus: index("pr_review_repository_bindings_workspace_status_idx").on(
|
|
7953
10430
|
table.workspaceId,
|
|
7954
|
-
table.
|
|
10431
|
+
table.status,
|
|
10432
|
+
),
|
|
10433
|
+
providerCheck: check(
|
|
10434
|
+
"pr_review_repository_bindings_provider_chk",
|
|
10435
|
+
sql`${table.provider} in ('github', 'gitlab', 'azure_devops')`,
|
|
10436
|
+
),
|
|
10437
|
+
statusCheck: check(
|
|
10438
|
+
"pr_review_repository_bindings_status_chk",
|
|
10439
|
+
sql`${table.status} in ('active', 'disabled')`,
|
|
7955
10440
|
),
|
|
7956
10441
|
workspaceAccount: foreignKey({
|
|
7957
10442
|
columns: [table.workspaceId, table.accountId],
|
|
7958
10443
|
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
7959
|
-
name: "
|
|
10444
|
+
name: "pr_review_repository_bindings_workspace_account_fk",
|
|
7960
10445
|
}).onDelete("cascade"),
|
|
7961
|
-
|
|
7962
|
-
columns: [table.workspaceId, table.
|
|
7963
|
-
foreignColumns: [
|
|
7964
|
-
|
|
10446
|
+
registration: foreignKey({
|
|
10447
|
+
columns: [table.workspaceId, table.registrationId, table.provider],
|
|
10448
|
+
foreignColumns: [
|
|
10449
|
+
prReviewAppRegistrations.workspaceId,
|
|
10450
|
+
prReviewAppRegistrations.id,
|
|
10451
|
+
prReviewAppRegistrations.provider,
|
|
10452
|
+
],
|
|
10453
|
+
name: "pr_review_repository_bindings_registration_fk",
|
|
7965
10454
|
}).onDelete("cascade"),
|
|
7966
10455
|
}),
|
|
7967
10456
|
);
|
|
@@ -8083,6 +10572,8 @@ export const modelCallFacts = pgTable(
|
|
|
8083
10572
|
mode: "number",
|
|
8084
10573
|
}),
|
|
8085
10574
|
pricingSource: text("pricing_source"),
|
|
10575
|
+
contextContributions:
|
|
10576
|
+
jsonb("context_contributions").$type<readonly ModelContextContributionSummary[]>(),
|
|
8086
10577
|
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
8087
10578
|
recordedAt: timestamp("recorded_at", { withTimezone: true }).notNull().defaultNow(),
|
|
8088
10579
|
},
|
|
@@ -8153,6 +10644,10 @@ export const modelCallFacts = pgTable(
|
|
|
8153
10644
|
"model_call_facts_model_bytes_check",
|
|
8154
10645
|
sql`octet_length(${table.model}) between 1 and 512`,
|
|
8155
10646
|
),
|
|
10647
|
+
contextContributionsValid: check(
|
|
10648
|
+
"model_call_facts_context_contributions_check",
|
|
10649
|
+
sql`opengeni_private.model_context_contributions_valid(${table.contextContributions})`,
|
|
10650
|
+
),
|
|
8156
10651
|
}),
|
|
8157
10652
|
);
|
|
8158
10653
|
|
|
@@ -8456,6 +10951,10 @@ export const packInstallations = pgTable(
|
|
|
8456
10951
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
8457
10952
|
},
|
|
8458
10953
|
(table) => ({
|
|
10954
|
+
workspaceIdentity: uniqueIndex("pack_installations_workspace_id_uq").on(
|
|
10955
|
+
table.workspaceId,
|
|
10956
|
+
table.id,
|
|
10957
|
+
),
|
|
8459
10958
|
workspacePack: uniqueIndex("pack_installations_workspace_pack_idx").on(
|
|
8460
10959
|
table.workspaceId,
|
|
8461
10960
|
table.packId,
|
|
@@ -8502,6 +11001,376 @@ export const packInstallationComponents = pgTable(
|
|
|
8502
11001
|
}),
|
|
8503
11002
|
);
|
|
8504
11003
|
|
|
11004
|
+
export const automationSources = pgTable(
|
|
11005
|
+
"automation_sources",
|
|
11006
|
+
{
|
|
11007
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11008
|
+
endpointId: uuid("endpoint_id").notNull().defaultRandom(),
|
|
11009
|
+
accountId: uuid("account_id")
|
|
11010
|
+
.notNull()
|
|
11011
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
11012
|
+
workspaceId: uuid("workspace_id")
|
|
11013
|
+
.notNull()
|
|
11014
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
11015
|
+
name: text("name").notNull(),
|
|
11016
|
+
adapterId: text("adapter_id").notNull(),
|
|
11017
|
+
configuration: jsonb("configuration").$type<Record<string, unknown>>().notNull().default({}),
|
|
11018
|
+
webhookSecretEncrypted: text("webhook_secret_encrypted").notNull(),
|
|
11019
|
+
status: text("status").notNull().default("active"),
|
|
11020
|
+
version: integer("version").notNull().default(1),
|
|
11021
|
+
packInstallationId: uuid("pack_installation_id"),
|
|
11022
|
+
packConnectorId: text("pack_connector_id"),
|
|
11023
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
11024
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11025
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11026
|
+
},
|
|
11027
|
+
(table) => ({
|
|
11028
|
+
endpoint: uniqueIndex("automation_sources_endpoint_uq").on(table.endpointId),
|
|
11029
|
+
workspaceIdentity: uniqueIndex("automation_sources_workspace_id_uq").on(
|
|
11030
|
+
table.workspaceId,
|
|
11031
|
+
table.id,
|
|
11032
|
+
),
|
|
11033
|
+
workspaceStatus: index("automation_sources_workspace_status_idx").on(
|
|
11034
|
+
table.workspaceId,
|
|
11035
|
+
table.status,
|
|
11036
|
+
),
|
|
11037
|
+
shape: check(
|
|
11038
|
+
"automation_sources_shape_chk",
|
|
11039
|
+
sql`${table.status} in ('active', 'disabled')
|
|
11040
|
+
and ${table.version} > 0
|
|
11041
|
+
and octet_length(${table.name}) between 1 and 512
|
|
11042
|
+
and octet_length(${table.adapterId}) between 1 and 128
|
|
11043
|
+
and octet_length(${table.createdBySubjectId}) between 1 and 4096
|
|
11044
|
+
and jsonb_typeof(${table.configuration}) = 'object'
|
|
11045
|
+
and ((${table.packInstallationId} is null and ${table.packConnectorId} is null)
|
|
11046
|
+
or (${table.packInstallationId} is not null
|
|
11047
|
+
and octet_length(${table.packConnectorId}) between 1 and 128))`,
|
|
11048
|
+
),
|
|
11049
|
+
workspaceAccount: foreignKey({
|
|
11050
|
+
columns: [table.workspaceId, table.accountId],
|
|
11051
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11052
|
+
name: "automation_sources_workspace_account_fk",
|
|
11053
|
+
}).onDelete("cascade"),
|
|
11054
|
+
packInstallation: foreignKey({
|
|
11055
|
+
columns: [table.workspaceId, table.packInstallationId],
|
|
11056
|
+
foreignColumns: [packInstallations.workspaceId, packInstallations.id],
|
|
11057
|
+
name: "automation_sources_pack_installation_fk",
|
|
11058
|
+
}).onDelete("cascade"),
|
|
11059
|
+
}),
|
|
11060
|
+
);
|
|
11061
|
+
|
|
11062
|
+
/** Credential-free global webhook routing. Possession of the opaque endpoint
|
|
11063
|
+
* UUID locates the tenant; authentication still requires the encrypted secret
|
|
11064
|
+
* on the FORCE-RLS source row before any payload is parsed or accepted. */
|
|
11065
|
+
export const automationWebhookEndpoints = pgTable(
|
|
11066
|
+
"automation_webhook_endpoints",
|
|
11067
|
+
{
|
|
11068
|
+
endpointId: uuid("endpoint_id").primaryKey(),
|
|
11069
|
+
accountId: uuid("account_id")
|
|
11070
|
+
.notNull()
|
|
11071
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
11072
|
+
workspaceId: uuid("workspace_id")
|
|
11073
|
+
.notNull()
|
|
11074
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
11075
|
+
sourceId: uuid("source_id")
|
|
11076
|
+
.notNull()
|
|
11077
|
+
.references(() => automationSources.id, { onDelete: "cascade" }),
|
|
11078
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11079
|
+
},
|
|
11080
|
+
(table) => ({
|
|
11081
|
+
source: uniqueIndex("automation_webhook_endpoints_source_uq").on(table.sourceId),
|
|
11082
|
+
workspaceAccount: foreignKey({
|
|
11083
|
+
columns: [table.workspaceId, table.accountId],
|
|
11084
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11085
|
+
name: "automation_webhook_endpoints_workspace_account_fk",
|
|
11086
|
+
}).onDelete("cascade"),
|
|
11087
|
+
}),
|
|
11088
|
+
);
|
|
11089
|
+
|
|
11090
|
+
export const automationTriggers = pgTable(
|
|
11091
|
+
"automation_triggers",
|
|
11092
|
+
{
|
|
11093
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11094
|
+
accountId: uuid("account_id")
|
|
11095
|
+
.notNull()
|
|
11096
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
11097
|
+
workspaceId: uuid("workspace_id")
|
|
11098
|
+
.notNull()
|
|
11099
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
11100
|
+
sourceId: uuid("source_id").notNull(),
|
|
11101
|
+
name: text("name").notNull(),
|
|
11102
|
+
status: text("status").notNull().default("active"),
|
|
11103
|
+
currentRevision: integer("current_revision").notNull().default(1),
|
|
11104
|
+
packInstallationId: uuid("pack_installation_id"),
|
|
11105
|
+
packTemplateId: text("pack_template_id"),
|
|
11106
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
11107
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11108
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11109
|
+
},
|
|
11110
|
+
(table) => ({
|
|
11111
|
+
workspaceIdentity: uniqueIndex("automation_triggers_workspace_id_uq").on(
|
|
11112
|
+
table.workspaceId,
|
|
11113
|
+
table.id,
|
|
11114
|
+
),
|
|
11115
|
+
workspaceSourceIdentity: uniqueIndex("automation_triggers_workspace_source_id_uq").on(
|
|
11116
|
+
table.workspaceId,
|
|
11117
|
+
table.id,
|
|
11118
|
+
table.sourceId,
|
|
11119
|
+
),
|
|
11120
|
+
workspaceStatus: index("automation_triggers_workspace_status_idx").on(
|
|
11121
|
+
table.workspaceId,
|
|
11122
|
+
table.status,
|
|
11123
|
+
),
|
|
11124
|
+
source: foreignKey({
|
|
11125
|
+
columns: [table.workspaceId, table.sourceId],
|
|
11126
|
+
foreignColumns: [automationSources.workspaceId, automationSources.id],
|
|
11127
|
+
name: "automation_triggers_source_fk",
|
|
11128
|
+
}).onDelete("cascade"),
|
|
11129
|
+
packInstallation: foreignKey({
|
|
11130
|
+
columns: [table.workspaceId, table.packInstallationId],
|
|
11131
|
+
foreignColumns: [packInstallations.workspaceId, packInstallations.id],
|
|
11132
|
+
name: "automation_triggers_pack_installation_fk",
|
|
11133
|
+
}).onDelete("cascade"),
|
|
11134
|
+
workspaceAccount: foreignKey({
|
|
11135
|
+
columns: [table.workspaceId, table.accountId],
|
|
11136
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11137
|
+
name: "automation_triggers_workspace_account_fk",
|
|
11138
|
+
}).onDelete("cascade"),
|
|
11139
|
+
shape: check(
|
|
11140
|
+
"automation_triggers_shape_chk",
|
|
11141
|
+
sql`${table.status} in ('active', 'paused', 'disabled')
|
|
11142
|
+
and ${table.currentRevision} > 0
|
|
11143
|
+
and octet_length(${table.name}) between 1 and 512
|
|
11144
|
+
and octet_length(${table.createdBySubjectId}) between 1 and 4096
|
|
11145
|
+
and ((${table.packInstallationId} is null and ${table.packTemplateId} is null)
|
|
11146
|
+
or (${table.packInstallationId} is not null and octet_length(${table.packTemplateId}) between 1 and 128))`,
|
|
11147
|
+
),
|
|
11148
|
+
}),
|
|
11149
|
+
);
|
|
11150
|
+
|
|
11151
|
+
export const automationTriggerRevisions = pgTable(
|
|
11152
|
+
"automation_trigger_revisions",
|
|
11153
|
+
{
|
|
11154
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
11155
|
+
revision: integer("revision").notNull(),
|
|
11156
|
+
accountId: uuid("account_id").notNull(),
|
|
11157
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11158
|
+
adapterId: text("adapter_id").notNull(),
|
|
11159
|
+
eventTypes: jsonb("event_types").$type<string[]>().notNull(),
|
|
11160
|
+
configuration: jsonb("configuration").$type<Record<string, unknown>>().notNull().default({}),
|
|
11161
|
+
parameters: jsonb("parameters").$type<Record<string, unknown>>().notNull().default({}),
|
|
11162
|
+
sessionTemplate: jsonb("session_template").$type<AutomationSessionTemplate>().notNull(),
|
|
11163
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
11164
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11165
|
+
},
|
|
11166
|
+
(table) => ({
|
|
11167
|
+
identity: primaryKey({ columns: [table.triggerId, table.revision] }),
|
|
11168
|
+
trigger: foreignKey({
|
|
11169
|
+
columns: [table.workspaceId, table.triggerId],
|
|
11170
|
+
foreignColumns: [automationTriggers.workspaceId, automationTriggers.id],
|
|
11171
|
+
name: "automation_trigger_revisions_trigger_fk",
|
|
11172
|
+
}).onDelete("cascade"),
|
|
11173
|
+
workspaceAccount: foreignKey({
|
|
11174
|
+
columns: [table.workspaceId, table.accountId],
|
|
11175
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11176
|
+
name: "automation_trigger_revisions_workspace_account_fk",
|
|
11177
|
+
}).onDelete("cascade"),
|
|
11178
|
+
shape: check(
|
|
11179
|
+
"automation_trigger_revisions_shape_chk",
|
|
11180
|
+
sql`${table.revision} > 0
|
|
11181
|
+
and octet_length(${table.adapterId}) between 1 and 128
|
|
11182
|
+
and jsonb_typeof(${table.eventTypes}) = 'array'
|
|
11183
|
+
and jsonb_array_length(${table.eventTypes}) between 1 and 64
|
|
11184
|
+
and jsonb_typeof(${table.configuration}) = 'object'
|
|
11185
|
+
and jsonb_typeof(${table.parameters}) = 'object'
|
|
11186
|
+
and jsonb_typeof(${table.sessionTemplate}) = 'object'`,
|
|
11187
|
+
),
|
|
11188
|
+
}),
|
|
11189
|
+
);
|
|
11190
|
+
|
|
11191
|
+
export const automationTriggerEvents = pgTable(
|
|
11192
|
+
"automation_trigger_events",
|
|
11193
|
+
{
|
|
11194
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11195
|
+
accountId: uuid("account_id").notNull(),
|
|
11196
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11197
|
+
sourceId: uuid("source_id").notNull(),
|
|
11198
|
+
sourceVersion: integer("source_version").notNull(),
|
|
11199
|
+
sourceConfiguration: jsonb("source_configuration").$type<Record<string, unknown>>().notNull(),
|
|
11200
|
+
matchedTriggerRevisions: jsonb("matched_trigger_revisions")
|
|
11201
|
+
.$type<Array<{ triggerId: string; revision: number }>>()
|
|
11202
|
+
.notNull(),
|
|
11203
|
+
deliveryKey: text("delivery_key").notNull(),
|
|
11204
|
+
requestDigest: text("request_digest").notNull(),
|
|
11205
|
+
adapterId: text("adapter_id").notNull(),
|
|
11206
|
+
eventType: text("event_type").notNull(),
|
|
11207
|
+
occurrenceKey: text("occurrence_key").notNull(),
|
|
11208
|
+
normalizedEvent: jsonb("normalized_event").$type<Record<string, unknown>>().notNull(),
|
|
11209
|
+
status: text("status").notNull().default("accepted"),
|
|
11210
|
+
ignoredReason: text("ignored_reason"),
|
|
11211
|
+
errorCode: text("error_code"),
|
|
11212
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11213
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11214
|
+
},
|
|
11215
|
+
(table) => ({
|
|
11216
|
+
sourceDelivery: uniqueIndex("automation_trigger_events_source_delivery_uq").on(
|
|
11217
|
+
table.sourceId,
|
|
11218
|
+
table.deliveryKey,
|
|
11219
|
+
),
|
|
11220
|
+
workspaceCreated: index("automation_trigger_events_workspace_created_idx").on(
|
|
11221
|
+
table.workspaceId,
|
|
11222
|
+
table.createdAt,
|
|
11223
|
+
),
|
|
11224
|
+
workspaceSourceIdentity: uniqueIndex("automation_trigger_events_workspace_source_id_uq").on(
|
|
11225
|
+
table.workspaceId,
|
|
11226
|
+
table.sourceId,
|
|
11227
|
+
table.id,
|
|
11228
|
+
),
|
|
11229
|
+
source: foreignKey({
|
|
11230
|
+
columns: [table.workspaceId, table.sourceId],
|
|
11231
|
+
foreignColumns: [automationSources.workspaceId, automationSources.id],
|
|
11232
|
+
name: "automation_trigger_events_source_fk",
|
|
11233
|
+
}).onDelete("cascade"),
|
|
11234
|
+
workspaceAccount: foreignKey({
|
|
11235
|
+
columns: [table.workspaceId, table.accountId],
|
|
11236
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11237
|
+
name: "automation_trigger_events_workspace_account_fk",
|
|
11238
|
+
}).onDelete("cascade"),
|
|
11239
|
+
shape: check(
|
|
11240
|
+
"automation_trigger_events_shape_chk",
|
|
11241
|
+
sql`${table.status} in ('accepted', 'ignored', 'failed')
|
|
11242
|
+
and ${table.sourceVersion} > 0
|
|
11243
|
+
and jsonb_typeof(${table.sourceConfiguration}) = 'object'
|
|
11244
|
+
and jsonb_typeof(${table.matchedTriggerRevisions}) = 'array'
|
|
11245
|
+
and jsonb_array_length(${table.matchedTriggerRevisions}) <= 32
|
|
11246
|
+
and ${table.requestDigest} ~ '^[0-9a-f]{64}$'
|
|
11247
|
+
and octet_length(${table.deliveryKey}) between 1 and 1024
|
|
11248
|
+
and octet_length(${table.eventType}) between 1 and 256
|
|
11249
|
+
and octet_length(${table.occurrenceKey}) between 1 and 1024
|
|
11250
|
+
and jsonb_typeof(${table.normalizedEvent}) = 'object'`,
|
|
11251
|
+
),
|
|
11252
|
+
}),
|
|
11253
|
+
);
|
|
11254
|
+
|
|
11255
|
+
export const automationRuns = pgTable(
|
|
11256
|
+
"automation_runs",
|
|
11257
|
+
{
|
|
11258
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11259
|
+
accountId: uuid("account_id").notNull(),
|
|
11260
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11261
|
+
sourceId: uuid("source_id").notNull(),
|
|
11262
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
11263
|
+
triggerRevision: integer("trigger_revision").notNull(),
|
|
11264
|
+
eventId: uuid("event_id").notNull(),
|
|
11265
|
+
occurrenceKey: text("occurrence_key").notNull(),
|
|
11266
|
+
acceptedExecution: jsonb("accepted_execution").$type<AutomationAcceptedExecution>().notNull(),
|
|
11267
|
+
status: text("status").notNull().default("queued"),
|
|
11268
|
+
sessionId: uuid("session_id").references(() => sessions.id, { onDelete: "set null" }),
|
|
11269
|
+
errorCode: text("error_code"),
|
|
11270
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11271
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11272
|
+
},
|
|
11273
|
+
(table) => ({
|
|
11274
|
+
triggerOccurrence: uniqueIndex("automation_runs_trigger_occurrence_uq").on(
|
|
11275
|
+
table.triggerId,
|
|
11276
|
+
table.occurrenceKey,
|
|
11277
|
+
),
|
|
11278
|
+
workspaceStatus: index("automation_runs_workspace_status_idx").on(
|
|
11279
|
+
table.workspaceId,
|
|
11280
|
+
table.status,
|
|
11281
|
+
table.createdAt,
|
|
11282
|
+
),
|
|
11283
|
+
workspaceTriggerIdentity: uniqueIndex("automation_runs_workspace_trigger_id_uq").on(
|
|
11284
|
+
table.workspaceId,
|
|
11285
|
+
table.triggerId,
|
|
11286
|
+
table.id,
|
|
11287
|
+
),
|
|
11288
|
+
source: foreignKey({
|
|
11289
|
+
columns: [table.workspaceId, table.sourceId],
|
|
11290
|
+
foreignColumns: [automationSources.workspaceId, automationSources.id],
|
|
11291
|
+
name: "automation_runs_source_fk",
|
|
11292
|
+
}).onDelete("restrict"),
|
|
11293
|
+
triggerSource: foreignKey({
|
|
11294
|
+
columns: [table.workspaceId, table.triggerId, table.sourceId],
|
|
11295
|
+
foreignColumns: [
|
|
11296
|
+
automationTriggers.workspaceId,
|
|
11297
|
+
automationTriggers.id,
|
|
11298
|
+
automationTriggers.sourceId,
|
|
11299
|
+
],
|
|
11300
|
+
name: "automation_runs_trigger_source_fk",
|
|
11301
|
+
}).onDelete("restrict"),
|
|
11302
|
+
triggerRevisionFk: foreignKey({
|
|
11303
|
+
columns: [table.triggerId, table.triggerRevision],
|
|
11304
|
+
foreignColumns: [automationTriggerRevisions.triggerId, automationTriggerRevisions.revision],
|
|
11305
|
+
name: "automation_runs_trigger_revision_fk",
|
|
11306
|
+
}).onDelete("restrict"),
|
|
11307
|
+
event: foreignKey({
|
|
11308
|
+
columns: [table.workspaceId, table.sourceId, table.eventId],
|
|
11309
|
+
foreignColumns: [
|
|
11310
|
+
automationTriggerEvents.workspaceId,
|
|
11311
|
+
automationTriggerEvents.sourceId,
|
|
11312
|
+
automationTriggerEvents.id,
|
|
11313
|
+
],
|
|
11314
|
+
name: "automation_runs_event_fk",
|
|
11315
|
+
}).onDelete("restrict"),
|
|
11316
|
+
workspaceAccount: foreignKey({
|
|
11317
|
+
columns: [table.workspaceId, table.accountId],
|
|
11318
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11319
|
+
name: "automation_runs_workspace_account_fk",
|
|
11320
|
+
}).onDelete("cascade"),
|
|
11321
|
+
shape: check(
|
|
11322
|
+
"automation_runs_shape_chk",
|
|
11323
|
+
sql`${table.triggerRevision} > 0
|
|
11324
|
+
and ${table.status} in ('queued', 'dispatching', 'dispatched', 'skipped', 'failed')
|
|
11325
|
+
and octet_length(${table.occurrenceKey}) between 1 and 1024
|
|
11326
|
+
and jsonb_typeof(${table.acceptedExecution}) = 'object'`,
|
|
11327
|
+
),
|
|
11328
|
+
}),
|
|
11329
|
+
);
|
|
11330
|
+
|
|
11331
|
+
export const automationRunEventLinks = pgTable(
|
|
11332
|
+
"automation_run_event_links",
|
|
11333
|
+
{
|
|
11334
|
+
runId: uuid("run_id")
|
|
11335
|
+
.notNull()
|
|
11336
|
+
.references(() => automationRuns.id, { onDelete: "cascade" }),
|
|
11337
|
+
eventId: uuid("event_id")
|
|
11338
|
+
.notNull()
|
|
11339
|
+
.references(() => automationTriggerEvents.id, { onDelete: "cascade" }),
|
|
11340
|
+
accountId: uuid("account_id").notNull(),
|
|
11341
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
11342
|
+
sourceId: uuid("source_id").notNull(),
|
|
11343
|
+
triggerId: uuid("trigger_id").notNull(),
|
|
11344
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
11345
|
+
},
|
|
11346
|
+
(table) => ({
|
|
11347
|
+
identity: primaryKey({ columns: [table.runId, table.eventId] }),
|
|
11348
|
+
eventTrigger: uniqueIndex("automation_run_event_links_event_trigger_uq").on(
|
|
11349
|
+
table.eventId,
|
|
11350
|
+
table.triggerId,
|
|
11351
|
+
),
|
|
11352
|
+
run: foreignKey({
|
|
11353
|
+
columns: [table.workspaceId, table.triggerId, table.runId],
|
|
11354
|
+
foreignColumns: [automationRuns.workspaceId, automationRuns.triggerId, automationRuns.id],
|
|
11355
|
+
name: "automation_run_event_links_run_fk",
|
|
11356
|
+
}).onDelete("cascade"),
|
|
11357
|
+
event: foreignKey({
|
|
11358
|
+
columns: [table.workspaceId, table.sourceId, table.eventId],
|
|
11359
|
+
foreignColumns: [
|
|
11360
|
+
automationTriggerEvents.workspaceId,
|
|
11361
|
+
automationTriggerEvents.sourceId,
|
|
11362
|
+
automationTriggerEvents.id,
|
|
11363
|
+
],
|
|
11364
|
+
name: "automation_run_event_links_event_fk",
|
|
11365
|
+
}).onDelete("cascade"),
|
|
11366
|
+
workspaceAccount: foreignKey({
|
|
11367
|
+
columns: [table.workspaceId, table.accountId],
|
|
11368
|
+
foreignColumns: [workspaces.id, workspaces.accountId],
|
|
11369
|
+
name: "automation_run_event_links_workspace_account_fk",
|
|
11370
|
+
}).onDelete("cascade"),
|
|
11371
|
+
}),
|
|
11372
|
+
);
|
|
11373
|
+
|
|
8505
11374
|
export const workspacePacks = pgTable(
|
|
8506
11375
|
"workspace_packs",
|
|
8507
11376
|
{
|
|
@@ -9246,22 +12115,31 @@ export const rigs = pgTable(
|
|
|
9246
12115
|
description: text("description"),
|
|
9247
12116
|
// Attribution string: 'user:<subject>' | 'session:<id>' | 'system'.
|
|
9248
12117
|
createdBy: text("created_by"),
|
|
9249
|
-
// Inert migration-0230 identity foundation. Existing DAO/API/runtime paths
|
|
9250
|
-
// omit these fields and keep their historical workspace authority.
|
|
9251
12118
|
authorityScope: text("authority_scope").notNull().default("workspace"),
|
|
9252
12119
|
authorityId: uuid("authority_id"),
|
|
9253
12120
|
ownerOrganizationMembershipId: uuid("owner_organization_membership_id"),
|
|
9254
12121
|
originWorkspaceId: uuid("origin_workspace_id"),
|
|
12122
|
+
generation: bigint("generation", { mode: "number" }).notNull().default(1),
|
|
12123
|
+
status: text("status").notNull().default("active"),
|
|
12124
|
+
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
9255
12125
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9256
12126
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
9257
12127
|
},
|
|
9258
12128
|
(table) => ({
|
|
9259
|
-
workspaceName: uniqueIndex("
|
|
12129
|
+
workspaceName: uniqueIndex("rigs_workspace_name_active_idx")
|
|
12130
|
+
.on(table.workspaceId, table.name)
|
|
12131
|
+
.where(sql`${table.authorityScope} = 'workspace' and ${table.status} = 'active'`),
|
|
12132
|
+
organizationName: uniqueIndex("rigs_organization_name_active_idx")
|
|
12133
|
+
.on(table.accountId, table.name)
|
|
12134
|
+
.where(sql`${table.authorityScope} = 'organization' and ${table.status} = 'active'`),
|
|
12135
|
+
userName: uniqueIndex("rigs_user_name_active_idx")
|
|
12136
|
+
.on(table.accountId, table.ownerOrganizationMembershipId, table.name)
|
|
12137
|
+
.where(sql`${table.authorityScope} = 'user' and ${table.status} = 'active'`),
|
|
9260
12138
|
workspaceCreated: index("rigs_workspace_created_idx").on(table.workspaceId, table.createdAt),
|
|
9261
12139
|
authorityShape: check(
|
|
9262
12140
|
"rigs_authority_shape_check",
|
|
9263
12141
|
sql`(
|
|
9264
|
-
${table.authorityScope}
|
|
12142
|
+
${table.authorityScope} in ('organization', 'workspace')
|
|
9265
12143
|
and ${table.authorityId} is null
|
|
9266
12144
|
and ${table.ownerOrganizationMembershipId} is null
|
|
9267
12145
|
) or (
|
|
@@ -9272,7 +12150,14 @@ export const rigs = pgTable(
|
|
|
9272
12150
|
),
|
|
9273
12151
|
authorityScopeValid: check(
|
|
9274
12152
|
"rigs_authority_scope_check",
|
|
9275
|
-
sql`${table.authorityScope} in ('workspace', 'user')`,
|
|
12153
|
+
sql`${table.authorityScope} in ('organization', 'workspace', 'user')`,
|
|
12154
|
+
),
|
|
12155
|
+
generationPositive: check("rigs_generation_check", sql`${table.generation} > 0`),
|
|
12156
|
+
statusValid: check("rigs_status_check", sql`${table.status} in ('active', 'revoked')`),
|
|
12157
|
+
revocationShape: check(
|
|
12158
|
+
"rigs_revocation_check",
|
|
12159
|
+
sql`(${table.status} = 'active' and ${table.revokedAt} is null)
|
|
12160
|
+
or (${table.status} = 'revoked' and ${table.revokedAt} is not null)`,
|
|
9276
12161
|
),
|
|
9277
12162
|
authority: foreignKey({
|
|
9278
12163
|
name: "rigs_authority_fk",
|
|
@@ -9390,6 +12275,9 @@ export * from "./preference-registry-schema";
|
|
|
9390
12275
|
export * from "./memory-governance-schema";
|
|
9391
12276
|
export * from "./scoped-knowledge-schema";
|
|
9392
12277
|
export * from "./task-notes-schema";
|
|
12278
|
+
export * from "./company-brain-context-selection-schema";
|
|
12279
|
+
export * from "./governed-learning-evaluator-schema";
|
|
12280
|
+
export * from "./governed-learning-activation-schema";
|
|
9393
12281
|
export * from "./knowledge-source-sync-schema";
|
|
9394
12282
|
export * from "./transcription-recordings-schema";
|
|
9395
12283
|
export * from "./interaction-schema";
|