/**
 * Mosaic Native Kanban — frozen Drizzle schema contract v1.
 *
 * This is the canonical target/compatibility declaration for integration into
 * the ONE current-main packages/db/src/schema.ts. It MUST NOT be imported as a
 * competing schema module. KBN-100 applies the field-by-field expand/backfill/
 * switch/contract map in SHARED-CONTRACT.md; legacy fields marked below remain
 * declared throughout the expand and N-1 window.
 *
 * Existing Better Auth users.id is the identity parent. User references require
 * active workspace membership checks in the same authoritative transaction.
 */

import { sql } from 'drizzle-orm';
import {
  bigint,
  boolean,
  check,
  foreignKey,
  index,
  integer,
  jsonb,
  numeric,
  pgEnum,
  pgTable,
  primaryKey,
  text,
  timestamp,
  uniqueIndex,
  uuid,
} from 'drizzle-orm/pg-core';

// ─── Frozen vocabularies ─────────────────────────────────────────────────────

export const workspaceLifecycleEnum = pgEnum('workspace_lifecycle', [
  'active',
  'suspended',
  'archived',
]);
export const workspaceMemberRoleEnum = pgEnum('workspace_member_role', [
  'owner',
  'admin',
  'member',
  'auditor',
  'service',
]);
export const teamMemberRoleEnum = pgEnum('team_member_role', ['manager', 'member']);
export const agentLifecycleEnum = pgEnum('agent_lifecycle', ['enabled', 'disabled']);
export const agentSessionStateEnum = pgEnum('agent_session_state', [
  'starting',
  'available',
  'busy',
  'degraded',
  'offline',
  'ended',
]);
export const projectStatusEnum = pgEnum('project_status_v1', [
  'planning',
  'active',
  'paused',
  'completed',
  'archived',
]);
export const missionStatusEnum = pgEnum('mission_status_v1', [
  'draft',
  'awaiting_approval',
  'active',
  'paused',
  'certifying',
  'completed',
  'failed',
  'cancelled',
]);
export const milestoneStatusEnum = pgEnum('milestone_status_v1', [
  'planned',
  'active',
  'at_risk',
  'completed',
  'cancelled',
]);
export const taskStatusEnum = pgEnum('task_status_v1', [
  'backlog',
  'ready',
  'in_progress',
  'blocked',
  'in_review',
  'done',
  'cancelled',
]);
export const priorityEnum = pgEnum('work_priority_v1', ['critical', 'high', 'medium', 'low']);
export const specialistRoleEnum = pgEnum('specialist_role_v1', [
  'planning',
  'enhance',
  'coder',
  'review',
  'security-review',
  'pr-monitor',
  'certifier',
]);
export const dependencyTypeEnum = pgEnum('task_dependency_type', [
  'blocks',
  'review_gate',
  'certification_gate',
]);
/** Must match assignmentStates in mechanical-coordinator.v1.ts exactly. */
export const assignmentStateEnum = pgEnum('task_assignment_state_v1', [
  'awaiting_approval',
  'policy_pre_authorized',
  'approved',
  'rejected',
  'leased',
  'released',
  'expired',
  'superseded',
]);
export const leaseStateEnum = pgEnum('task_lease_state', [
  'pending_ack',
  'active',
  'released',
  'expired',
  'revoked',
]);
export const actorKindEnum = pgEnum('actor_kind_v1', [
  'user',
  'agent',
  'session',
  'service',
  'policy',
  'system',
]);
export const approvalDecisionEnum = pgEnum('approval_decision_v1', [
  'requested',
  'approved',
  'rejected',
  'escalated',
]);
export const executionDispositionEnum = pgEnum('task_execution_disposition_v1', [
  'available',
  'retry_delayed',
  'quarantined',
  'exhausted',
]);
export const changeProposalStateEnum = pgEnum('change_proposal_state_v1', [
  'pending',
  'accepted',
  'rejected',
]);
export const outboxStateEnum = pgEnum('outbox_state_v1', [
  'pending',
  'publishing',
  'published',
  'failed',
]);

// ─── Tenant and identity ─────────────────────────────────────────────────────

export const workspacesV1 = pgTable(
  'workspaces',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    name: text('name').notNull(),
    slug: text('slug').notNull(),
    settings: jsonb('settings').notNull().$type<Record<string, unknown>>().default({}),
    lifecycle: workspaceLifecycleEnum('lifecycle').notNull().default('active'),
    ownerId: text('owner_id').notNull(), // FK to existing users.id at integration
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    uniqueIndex('workspaces_slug_uidx').on(t.slug),
    check('workspaces_version_positive_chk', sql`${t.version} > 0`),
  ],
);

export const workspaceMembersV1 = pgTable(
  'workspace_members',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    userId: text('user_id').notNull(), // FK to existing users.id at integration
    role: workspaceMemberRoleEnum('role').notNull().default('member'),
    active: boolean('active').notNull().default(true),
    joinedAt: timestamp('joined_at', { withTimezone: true }).notNull().defaultNow(),
    revokedAt: timestamp('revoked_at', { withTimezone: true }),
  },
  (t) => [
    uniqueIndex('workspace_members_workspace_user_uidx').on(t.workspaceId, t.userId),
    index('workspace_members_user_active_idx').on(t.userId, t.active),
  ],
);

export const teamsV1 = pgTable(
  'teams',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    name: text('name').notNull(),
    slug: text('slug').notNull(),
    ownerId: text('owner_id').notNull(), // legacy/current users.id field retained
    managerId: text('manager_id').notNull(), // legacy/current users.id field retained
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    uniqueIndex('teams_workspace_slug_uidx').on(t.workspaceId, t.slug),
    uniqueIndex('teams_workspace_id_uidx').on(t.workspaceId, t.id),
  ],
);

export const teamMembersV1 = pgTable(
  'team_members',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    teamId: uuid('team_id').notNull(),
    userId: text('user_id').notNull(),
    role: teamMemberRoleEnum('role').notNull().default('member'),
    invitedBy: text('invited_by'),
    joinedAt: timestamp('joined_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'team_members_workspace_team_fk',
      columns: [t.workspaceId, t.teamId],
      foreignColumns: [teamsV1.workspaceId, teamsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('team_members_workspace_team_user_uidx').on(t.workspaceId, t.teamId, t.userId),
  ],
);

export const agentsV1 = pgTable(
  'agents',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    name: text('name').notNull(),
    provider: text('provider').notNull(), // legacy retained
    model: text('model').notNull(), // legacy retained
    legacyStatus: text('status', {
      enum: ['idle', 'active', 'error', 'offline'],
    })
      .notNull()
      .default('idle'),
    projectId: uuid('project_id'), // legacy retained through N-1
    ownerId: text('owner_id'), // legacy retained; active membership required
    systemPrompt: text('system_prompt'), // legacy retained
    allowedTools: jsonb('allowed_tools').$type<string[]>(), // legacy retained
    skills: jsonb('skills').$type<string[]>(), // legacy retained
    isSystem: boolean('is_system').notNull().default(false), // legacy retained
    config: jsonb('config'), // legacy retained
    runtime: text('runtime').notNull(),
    roles: jsonb('roles').notNull().$type<string[]>().default([]),
    capabilities: jsonb('capabilities').notNull().$type<string[]>().default([]),
    lifecycle: agentLifecycleEnum('lifecycle').notNull().default('enabled'),
    metadata: jsonb('metadata').notNull().$type<Record<string, unknown>>().default({}),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    uniqueIndex('agents_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('agents_workspace_name_uidx').on(t.workspaceId, t.name),
    index('agents_workspace_lifecycle_idx').on(t.workspaceId, t.lifecycle),
    check('agents_version_positive_chk', sql`${t.version} > 0`),
  ],
);

export const agentSessionsV1 = pgTable(
  'agent_sessions',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    agentId: uuid('agent_id').notNull(),
    harnessSessionKey: text('harness_session_key').notNull(),
    host: text('host').notNull(),
    state: agentSessionStateEnum('state').notNull().default('starting'),
    declaredRoles: specialistRoleEnum('declared_primary_role'),
    roleSet: jsonb('role_set').notNull().$type<string[]>().default([]),
    capabilities: jsonb('capabilities').notNull().$type<string[]>().default([]),
    capacity: integer('capacity').notNull().default(1),
    contextUsagePercent: integer('context_usage_percent'),
    startedAt: timestamp('started_at', { withTimezone: true }).notNull().defaultNow(),
    lastHeartbeatAt: timestamp('last_heartbeat_at', { withTimezone: true }),
    endedAt: timestamp('ended_at', { withTimezone: true }),
    metadata: jsonb('metadata').notNull().$type<Record<string, unknown>>().default({}),
  },
  (t) => [
    foreignKey({
      name: 'agent_sessions_workspace_agent_fk',
      columns: [t.workspaceId, t.agentId],
      foreignColumns: [agentsV1.workspaceId, agentsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('agent_sessions_workspace_harness_key_uidx').on(t.workspaceId, t.harnessSessionKey),
    uniqueIndex('agent_sessions_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('agent_sessions_workspace_agent_id_uidx').on(t.workspaceId, t.agentId, t.id),
    index('agent_sessions_workspace_state_heartbeat_idx').on(
      t.workspaceId,
      t.state,
      t.lastHeartbeatAt,
    ),
    check('agent_sessions_capacity_positive_chk', sql`${t.capacity} > 0`),
    check(
      'agent_sessions_context_percent_chk',
      sql`${t.contextUsagePercent} is null or (${t.contextUsagePercent} >= 0 and ${t.contextUsagePercent} <= 100)`,
    ),
  ],
);

// ─── Planning hierarchy ──────────────────────────────────────────────────────

export const projectsV1 = pgTable(
  'projects',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    name: text('name').notNull(),
    description: text('description'),
    /** Legacy status remains declared/readable through the N-1 window. */
    legacyStatus: text('status', {
      enum: ['active', 'paused', 'completed', 'archived'],
    })
      .notNull()
      .default('active'),
    canonicalStatus: projectStatusEnum('canonical_status').notNull().default('planning'),
    /** Legacy ownership fields retained until contract release. */
    legacyOwnerId: text('owner_id'),
    legacyTeamId: uuid('team_id'),
    legacyOwnerType: text('owner_type', { enum: ['user', 'team'] })
      .notNull()
      .default('user'),
    accountableUserId: text('accountable_user_id'),
    accountableTeamId: uuid('accountable_team_id'),
    priority: priorityEnum('priority').notNull().default('medium'),
    repositoryUrl: text('repository_url'),
    repositoryProvider: text('repository_provider'),
    defaultBranch: text('default_branch'),
    domain: text('domain'),
    startDate: timestamp('start_date', { withTimezone: true }),
    targetDate: timestamp('target_date', { withTimezone: true }),
    blockerSummary: text('blocker_summary'),
    progressPolicy: jsonb('progress_policy').notNull().$type<Record<string, unknown>>().default({}),
    metadata: jsonb('metadata').notNull().$type<Record<string, unknown>>().default({}),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'projects_workspace_accountable_user_fk',
      columns: [t.workspaceId, t.accountableUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
    foreignKey({
      name: 'projects_workspace_accountable_team_fk',
      columns: [t.workspaceId, t.accountableTeamId],
      foreignColumns: [teamsV1.workspaceId, teamsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('projects_workspace_id_uidx').on(t.workspaceId, t.id),
    index('projects_workspace_status_idx').on(t.workspaceId, t.canonicalStatus),
    check(
      'projects_exactly_one_accountable_owner_chk',
      sql`num_nonnulls(${t.accountableUserId}, ${t.accountableTeamId}) = 1`,
    ),
    check('projects_version_positive_chk', sql`${t.version} > 0`),
  ],
);

export const milestonesV1 = pgTable(
  'milestones',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    projectId: uuid('project_id').notNull(),
    name: text('name').notNull(),
    description: text('description'),
    status: milestoneStatusEnum('status').notNull().default('planned'),
    sequence: integer('sequence').notNull(),
    targetDate: timestamp('target_date', { withTimezone: true }),
    completedAt: timestamp('completed_at', { withTimezone: true }),
    providerMilestoneRef: text('provider_milestone_ref'),
    acceptanceSummary: text('acceptance_summary'),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'milestones_workspace_project_fk',
      columns: [t.workspaceId, t.projectId],
      foreignColumns: [projectsV1.workspaceId, projectsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('milestones_workspace_project_id_uidx').on(t.workspaceId, t.projectId, t.id),
    uniqueIndex('milestones_project_sequence_uidx').on(t.workspaceId, t.projectId, t.sequence),
    index('milestones_workspace_project_status_idx').on(t.workspaceId, t.projectId, t.status),
    check('milestones_sequence_positive_chk', sql`${t.sequence} > 0`),
    check('milestones_version_positive_chk', sql`${t.version} > 0`),
  ],
);

/** Avoids an unsafe circular projects.current_milestone FK during expand. */
export const projectCurrentMilestonesV1 = pgTable(
  'project_current_milestones',
  {
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    projectId: uuid('project_id').notNull(),
    milestoneId: uuid('milestone_id').notNull(),
    setByUserId: text('set_by_user_id').notNull(),
    setAt: timestamp('set_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    primaryKey({ name: 'project_current_milestones_pk', columns: [t.workspaceId, t.projectId] }),
    foreignKey({
      name: 'project_current_milestones_project_fk',
      columns: [t.workspaceId, t.projectId],
      foreignColumns: [projectsV1.workspaceId, projectsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'project_current_milestones_milestone_fk',
      columns: [t.workspaceId, t.projectId, t.milestoneId],
      foreignColumns: [milestonesV1.workspaceId, milestonesV1.projectId, milestonesV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'project_current_milestones_set_by_user_fk',
      columns: [t.workspaceId, t.setByUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
  ],
);

export const missionsV1 = pgTable(
  'missions',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    projectId: uuid('project_id').notNull(),
    name: text('name').notNull(),
    /** Legacy fields remain through N-1 and are mapped, never dropped on expand. */
    legacyDescription: text('description'),
    legacyStatus: text('status', {
      enum: ['planning', 'active', 'paused', 'completed', 'failed'],
    })
      .notNull()
      .default('planning'),
    legacyUserId: text('user_id'),
    legacyMilestones: jsonb('milestones').$type<Record<string, unknown>[]>(),
    legacyConfig: jsonb('config'),
    objective: text('objective').notNull(),
    canonicalStatus: missionStatusEnum('canonical_status').notNull().default('draft'),
    phase: text('phase'),
    prdArtifactUri: text('prd_artifact_uri'),
    prdRevision: text('prd_revision'),
    portfolioOrchestratorId: text('portfolio_orchestrator_id'),
    projectSubOrchestratorId: text('project_sub_orchestrator_id'),
    approvalPolicy: jsonb('approval_policy').notNull().$type<Record<string, unknown>>().default({}),
    startedAt: timestamp('started_at', { withTimezone: true }),
    completedAt: timestamp('completed_at', { withTimezone: true }),
    metadata: jsonb('metadata').notNull().$type<Record<string, unknown>>().default({}),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'missions_workspace_project_fk',
      columns: [t.workspaceId, t.projectId],
      foreignColumns: [projectsV1.workspaceId, projectsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('missions_workspace_project_id_uidx').on(t.workspaceId, t.projectId, t.id),
    uniqueIndex('missions_workspace_id_uidx').on(t.workspaceId, t.id),
    index('missions_workspace_project_status_idx').on(
      t.workspaceId,
      t.projectId,
      t.canonicalStatus,
    ),
    check('missions_version_positive_chk', sql`${t.version} > 0`),
  ],
);

export const missionMilestonesV1 = pgTable(
  'mission_milestones',
  {
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    projectId: uuid('project_id').notNull(),
    missionId: uuid('mission_id').notNull(),
    milestoneId: uuid('milestone_id').notNull(),
    ordering: integer('ordering').notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    primaryKey({
      name: 'mission_milestones_pk',
      columns: [t.workspaceId, t.projectId, t.missionId, t.milestoneId],
    }),
    foreignKey({
      name: 'mission_milestones_project_mission_fk',
      columns: [t.workspaceId, t.projectId, t.missionId],
      foreignColumns: [missionsV1.workspaceId, missionsV1.projectId, missionsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'mission_milestones_project_milestone_fk',
      columns: [t.workspaceId, t.projectId, t.milestoneId],
      foreignColumns: [milestonesV1.workspaceId, milestonesV1.projectId, milestonesV1.id],
    }).onDelete('restrict'),
    uniqueIndex('mission_milestones_order_uidx').on(
      t.workspaceId,
      t.projectId,
      t.missionId,
      t.ordering,
    ),
    check('mission_milestones_order_positive_chk', sql`${t.ordering} > 0`),
  ],
);

// ─── Tasks, tags, dependencies ───────────────────────────────────────────────

export const tasksV1 = pgTable(
  'tasks',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    projectId: uuid('project_id').notNull(),
    missionId: uuid('mission_id'),
    milestoneId: uuid('milestone_id'),
    parentTaskId: uuid('parent_task_id'),
    title: text('title').notNull(),
    description: text('description'),
    /** Legacy/current-main fields retained throughout expand/N-1. */
    legacyStatus: text('status', {
      enum: ['not-started', 'in-progress', 'blocked', 'done', 'cancelled'],
    })
      .notNull()
      .default('not-started'),
    legacyAssignee: text('assignee'),
    legacyTags: jsonb('tags').$type<string[]>(),
    legacyDueDate: timestamp('due_date', { withTimezone: true }),
    acceptanceCriteria: jsonb('acceptance_criteria')
      .notNull()
      .$type<Record<string, unknown> | string[]>()
      .default([]),
    canonicalStatus: taskStatusEnum('canonical_status').notNull().default('backlog'),
    priority: priorityEnum('priority').notNull().default('medium'),
    boardRank: numeric('board_rank', { precision: 30, scale: 15 }).notNull().default('1000'),
    accountableUserId: text('accountable_user_id'),
    accountableTeamId: uuid('accountable_team_id'),
    assignedSpecialistRole: specialistRoleEnum('assigned_specialist_role'),
    dueAt: timestamp('due_at', { withTimezone: true }),
    notBeforeAt: timestamp('not_before_at', { withTimezone: true }),
    estimateMinutes: integer('estimate_minutes'),
    progressPercent: integer('progress_percent').notNull().default(0),
    blocker: text('blocker'),
    retryPolicy: jsonb('retry_policy').notNull().$type<Record<string, unknown>>().default({}),
    /** Atomically incremented under this task row lock for every new lease. */
    fencingCounter: bigint('fencing_counter', { mode: 'bigint' })
      .notNull()
      .default(sql`0`),
    archivedAt: timestamp('archived_at', { withTimezone: true }),
    archivedByUserId: text('archived_by_user_id'),
    archiveReason: text('archive_reason'),
    metadata: jsonb('metadata').notNull().$type<Record<string, unknown>>().default({}),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
    completedAt: timestamp('completed_at', { withTimezone: true }),
  },
  (t) => [
    foreignKey({
      name: 'tasks_workspace_project_fk',
      columns: [t.workspaceId, t.projectId],
      foreignColumns: [projectsV1.workspaceId, projectsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'tasks_project_mission_fk',
      columns: [t.workspaceId, t.projectId, t.missionId],
      foreignColumns: [missionsV1.workspaceId, missionsV1.projectId, missionsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'tasks_project_milestone_fk',
      columns: [t.workspaceId, t.projectId, t.milestoneId],
      foreignColumns: [milestonesV1.workspaceId, milestonesV1.projectId, milestonesV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'tasks_project_parent_fk',
      columns: [t.workspaceId, t.projectId, t.parentTaskId],
      foreignColumns: [t.workspaceId, t.projectId, t.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'tasks_workspace_accountable_user_fk',
      columns: [t.workspaceId, t.accountableUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
    foreignKey({
      name: 'tasks_workspace_archived_by_user_fk',
      columns: [t.workspaceId, t.archivedByUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
    foreignKey({
      name: 'tasks_workspace_accountable_team_fk',
      columns: [t.workspaceId, t.accountableTeamId],
      foreignColumns: [teamsV1.workspaceId, teamsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('tasks_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('tasks_workspace_project_id_uidx').on(t.workspaceId, t.projectId, t.id),
    index('tasks_workspace_project_status_rank_idx').on(
      t.workspaceId,
      t.projectId,
      t.canonicalStatus,
      t.boardRank,
    ),
    index('tasks_workspace_due_idx').on(t.workspaceId, t.dueAt),
    check(
      'tasks_exactly_one_accountable_owner_chk',
      sql`num_nonnulls(${t.accountableUserId}, ${t.accountableTeamId}) = 1`,
    ),
    check('tasks_version_positive_chk', sql`${t.version} > 0`),
    check('tasks_fencing_counter_nonnegative_chk', sql`${t.fencingCounter} >= 0`),
    check(
      'tasks_progress_percent_chk',
      sql`${t.progressPercent} >= 0 and ${t.progressPercent} <= 100`,
    ),
    check(
      'tasks_archive_fields_chk',
      sql`(${t.archivedAt} is null and ${t.archivedByUserId} is null and ${t.archiveReason} is null) or (${t.archivedAt} is not null and ${t.archivedByUserId} is not null and ${t.archiveReason} is not null)`,
    ),
  ],
);

export const tagsV1 = pgTable(
  'tags',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    name: text('name').notNull(),
    normalizedName: text('normalized_name').notNull(),
    color: text('color'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    uniqueIndex('tags_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('tags_workspace_normalized_name_uidx').on(t.workspaceId, t.normalizedName),
  ],
);

export const taskTagsV1 = pgTable(
  'task_tags',
  {
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id').notNull(),
    tagId: uuid('tag_id').notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    primaryKey({ name: 'task_tags_pk', columns: [t.workspaceId, t.taskId, t.tagId] }),
    foreignKey({
      name: 'task_tags_workspace_task_fk',
      columns: [t.workspaceId, t.taskId],
      foreignColumns: [tasksV1.workspaceId, tasksV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_tags_workspace_tag_fk',
      columns: [t.workspaceId, t.tagId],
      foreignColumns: [tagsV1.workspaceId, tagsV1.id],
    }).onDelete('restrict'),
  ],
);

export const taskDependenciesV1 = pgTable(
  'task_dependencies',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    predecessorTaskId: uuid('predecessor_task_id').notNull(),
    successorTaskId: uuid('successor_task_id').notNull(),
    dependencyType: dependencyTypeEnum('dependency_type').notNull().default('blocks'),
    completionCondition: jsonb('completion_condition').$type<Record<string, unknown>>(),
    createdByActorKind: actorKindEnum('created_by_actor_kind').notNull(),
    createdByActorId: text('created_by_actor_id').notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'task_dependencies_predecessor_fk',
      columns: [t.workspaceId, t.predecessorTaskId],
      foreignColumns: [tasksV1.workspaceId, tasksV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_dependencies_successor_fk',
      columns: [t.workspaceId, t.successorTaskId],
      foreignColumns: [tasksV1.workspaceId, tasksV1.id],
    }).onDelete('restrict'),
    /** One directed pair only; dependency type is an attribute, not a second edge. */
    uniqueIndex('task_dependencies_directed_edge_uidx').on(
      t.workspaceId,
      t.predecessorTaskId,
      t.successorTaskId,
    ),
    index('task_dependencies_successor_idx').on(t.workspaceId, t.successorTaskId),
    check(
      'task_dependencies_no_self_edge_chk',
      sql`${t.predecessorTaskId} <> ${t.successorTaskId}`,
    ),
  ],
);

// ─── Links, immutable artifacts, audit events, outage proposals ──────────────

export const externalLinksV1 = pgTable(
  'external_links',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    entityType: text('entity_type', {
      enum: ['project', 'mission', 'milestone', 'task'],
    }).notNull(),
    entityId: uuid('entity_id').notNull(),
    provider: text('provider').notNull(),
    linkType: text('link_type', {
      enum: ['issue', 'pr', 'ci', 'document', 'release', 'deployment'],
    }).notNull(),
    externalId: text('external_id').notNull(),
    url: text('url').notNull(),
    repository: text('repository'),
    syncMetadata: jsonb('sync_metadata').notNull().$type<Record<string, unknown>>().default({}),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    uniqueIndex('external_links_entity_provider_type_external_uidx').on(
      t.workspaceId,
      t.entityType,
      t.entityId,
      t.provider,
      t.linkType,
      t.externalId,
    ),
    index('external_links_entity_idx').on(t.workspaceId, t.entityType, t.entityId),
  ],
);

export const artifactsV1 = pgTable(
  'artifacts',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id'),
    missionId: uuid('mission_id'),
    type: text('type').notNull(),
    uri: text('uri').notNull(),
    immutableRevision: text('immutable_revision').notNull(),
    digest: text('digest').notNull(),
    producerActorKind: actorKindEnum('producer_actor_kind').notNull(),
    producerActorId: text('producer_actor_id').notNull(),
    evidenceClassification: text('evidence_classification').notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'artifacts_workspace_task_fk',
      columns: [t.workspaceId, t.taskId],
      foreignColumns: [tasksV1.workspaceId, tasksV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'artifacts_workspace_mission_fk',
      columns: [t.workspaceId, t.missionId],
      foreignColumns: [missionsV1.workspaceId, missionsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('artifacts_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('artifacts_workspace_digest_uidx').on(t.workspaceId, t.digest),
    check('artifacts_exactly_one_owner_chk', sql`num_nonnulls(${t.taskId}, ${t.missionId}) = 1`),
  ],
);

export const taskEventsV1 = pgTable(
  'task_events',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    aggregateType: text('aggregate_type', {
      enum: [
        'workspace',
        'project',
        'mission',
        'milestone',
        'task',
        'assignment',
        'lease',
        'change_proposal',
      ],
    }).notNull(),
    aggregateId: uuid('aggregate_id').notNull(),
    eventType: text('event_type').notNull(),
    actorKind: actorKindEnum('actor_kind').notNull(),
    actorId: text('actor_id').notNull(),
    correlationId: uuid('correlation_id').notNull(),
    causationId: uuid('causation_id'),
    idempotencyKey: text('idempotency_key').notNull(),
    previousVersion: integer('previous_version'),
    newVersion: integer('new_version'),
    payload: jsonb('payload').notNull().$type<Record<string, unknown>>().default({}),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    uniqueIndex('task_events_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('task_events_workspace_idempotency_uidx').on(t.workspaceId, t.idempotencyKey),
    index('task_events_aggregate_created_idx').on(
      t.workspaceId,
      t.aggregateType,
      t.aggregateId,
      t.createdAt,
    ),
  ],
);

export const changeProposalsV1 = pgTable(
  'change_proposals',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    proposerUserId: text('proposer_user_id').notNull(),
    sourceNoteDigest: text('source_note_digest').notNull(),
    targetAggregateType: text('target_aggregate_type', {
      enum: ['project', 'mission', 'milestone', 'task'],
    }).notNull(),
    targetAggregateId: uuid('target_aggregate_id').notNull(),
    expectedAggregateVersion: integer('expected_aggregate_version').notNull(),
    proposedCommand: text('proposed_command').notNull(),
    proposedPayload: jsonb('proposed_payload').notNull().$type<Record<string, unknown>>(),
    state: changeProposalStateEnum('state').notNull().default('pending'),
    idempotencyKey: text('idempotency_key').notNull(),
    submittedAuditEventId: uuid('submitted_audit_event_id').notNull(),
    decisionActorUserId: text('decision_actor_user_id'),
    decisionReason: text('decision_reason'),
    decidedAt: timestamp('decided_at', { withTimezone: true }),
    acceptedCommandAuditEventId: uuid('accepted_command_audit_event_id'),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'change_proposals_workspace_proposer_user_fk',
      columns: [t.workspaceId, t.proposerUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
    foreignKey({
      name: 'change_proposals_workspace_decision_actor_user_fk',
      columns: [t.workspaceId, t.decisionActorUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
    foreignKey({
      name: 'change_proposals_workspace_submitted_event_fk',
      columns: [t.workspaceId, t.submittedAuditEventId],
      foreignColumns: [taskEventsV1.workspaceId, taskEventsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'change_proposals_workspace_accepted_command_event_fk',
      columns: [t.workspaceId, t.acceptedCommandAuditEventId],
      foreignColumns: [taskEventsV1.workspaceId, taskEventsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('change_proposals_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('change_proposals_workspace_idempotency_uidx').on(t.workspaceId, t.idempotencyKey),
    index('change_proposals_workspace_target_state_idx').on(
      t.workspaceId,
      t.targetAggregateType,
      t.targetAggregateId,
      t.state,
    ),
    check('change_proposals_expected_version_positive_chk', sql`${t.expectedAggregateVersion} > 0`),
    check('change_proposals_version_positive_chk', sql`${t.version} > 0`),
    check(
      'change_proposals_decision_fields_chk',
      sql`(${t.state} = 'pending' and ${t.decisionActorUserId} is null and ${t.decisionReason} is null and ${t.decidedAt} is null and ${t.acceptedCommandAuditEventId} is null) or (${t.state} = 'rejected' and ${t.decisionActorUserId} is not null and ${t.decisionReason} is not null and ${t.decidedAt} is not null and ${t.acceptedCommandAuditEventId} is null) or (${t.state} = 'accepted' and ${t.decisionActorUserId} is not null and ${t.decisionReason} is not null and ${t.decidedAt} is not null and ${t.acceptedCommandAuditEventId} is not null)`,
    ),
  ],
);

// ─── Assignments, execution, fencing, checkpoints ────────────────────────────

export const taskAssignmentsV1 = pgTable(
  'task_assignments',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id').notNull(),
    taskVersion: integer('task_version').notNull(),
    targetUserId: text('target_user_id'),
    targetTeamId: uuid('target_team_id'),
    targetAgentId: uuid('target_agent_id'),
    targetSessionId: uuid('target_session_id'),
    specialistRole: specialistRoleEnum('specialist_role').notNull(),
    state: assignmentStateEnum('state').notNull().default('awaiting_approval'),
    policyRevision: text('policy_revision').notNull(),
    proposedByUserId: text('proposed_by_user_id'),
    proposedByAgentId: uuid('proposed_by_agent_id'),
    reason: text('reason').notNull(),
    proposedAt: timestamp('proposed_at', { withTimezone: true }).notNull().defaultNow(),
    expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
    approvedAt: timestamp('approved_at', { withTimezone: true }),
    endedAt: timestamp('ended_at', { withTimezone: true }),
  },
  (t) => [
    foreignKey({
      name: 'task_assignments_workspace_task_fk',
      columns: [t.workspaceId, t.taskId],
      foreignColumns: [tasksV1.workspaceId, tasksV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_assignments_workspace_user_fk',
      columns: [t.workspaceId, t.targetUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_assignments_workspace_proposer_user_fk',
      columns: [t.workspaceId, t.proposedByUserId],
      foreignColumns: [workspaceMembersV1.workspaceId, workspaceMembersV1.userId],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_assignments_workspace_proposer_agent_fk',
      columns: [t.workspaceId, t.proposedByAgentId],
      foreignColumns: [agentsV1.workspaceId, agentsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_assignments_workspace_team_fk',
      columns: [t.workspaceId, t.targetTeamId],
      foreignColumns: [teamsV1.workspaceId, teamsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_assignments_workspace_agent_fk',
      columns: [t.workspaceId, t.targetAgentId],
      foreignColumns: [agentsV1.workspaceId, agentsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_assignments_workspace_agent_session_fk',
      columns: [t.workspaceId, t.targetAgentId, t.targetSessionId],
      foreignColumns: [agentSessionsV1.workspaceId, agentSessionsV1.agentId, agentSessionsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('task_assignments_workspace_id_uidx').on(t.workspaceId, t.id),
    uniqueIndex('task_assignments_exact_target_uidx').on(
      t.workspaceId,
      t.taskId,
      t.id,
      t.targetAgentId,
      t.targetSessionId,
    ),
    index('task_assignments_workspace_task_state_idx').on(t.workspaceId, t.taskId, t.state),
    check(
      'task_assignments_exactly_one_principal_chk',
      sql`num_nonnulls(${t.targetUserId}, ${t.targetTeamId}, ${t.targetAgentId}) = 1`,
    ),
    check(
      'task_assignments_exactly_one_proposer_chk',
      sql`num_nonnulls(${t.proposedByUserId}, ${t.proposedByAgentId}) = 1`,
    ),
    check(
      'task_assignments_agent_session_pair_chk',
      sql`(${t.targetAgentId} is null and ${t.targetSessionId} is null) or (${t.targetAgentId} is not null and ${t.targetSessionId} is not null)`,
    ),
    check('task_assignments_task_version_positive_chk', sql`${t.taskVersion} > 0`),
  ],
);

export const taskExecutionStatesV1 = pgTable(
  'task_execution_states',
  {
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id').notNull(),
    disposition: executionDispositionEnum('disposition').notNull().default('available'),
    attemptCount: integer('attempt_count').notNull().default(0),
    maxAttempts: integer('max_attempts').notNull(),
    nextEligibleAt: timestamp('next_eligible_at', { withTimezone: true }),
    terminalReason: text('terminal_reason'),
    updatedByActorKind: actorKindEnum('updated_by_actor_kind').notNull(),
    updatedByActorId: text('updated_by_actor_id').notNull(),
    policyRevision: text('policy_revision').notNull(),
    version: integer('version').notNull().default(1),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    primaryKey({ name: 'task_execution_states_pk', columns: [t.workspaceId, t.taskId] }),
    foreignKey({
      name: 'task_execution_states_workspace_task_fk',
      columns: [t.workspaceId, t.taskId],
      foreignColumns: [tasksV1.workspaceId, tasksV1.id],
    }).onDelete('restrict'),
    index('task_execution_states_disposition_next_idx').on(
      t.workspaceId,
      t.disposition,
      t.nextEligibleAt,
    ),
    check('task_execution_states_attempt_nonnegative_chk', sql`${t.attemptCount} >= 0`),
    check('task_execution_states_max_positive_chk', sql`${t.maxAttempts} > 0`),
    check('task_execution_states_attempt_bound_chk', sql`${t.attemptCount} <= ${t.maxAttempts}`),
    check('task_execution_states_version_positive_chk', sql`${t.version} > 0`),
  ],
);

export const taskLeasesV1 = pgTable(
  'task_leases',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id').notNull(),
    assignmentId: uuid('assignment_id').notNull(),
    agentId: uuid('agent_id').notNull(),
    agentSessionId: uuid('agent_session_id').notNull(),
    state: leaseStateEnum('state').notNull().default('pending_ack'),
    acquiredAt: timestamp('acquired_at', { withTimezone: true }).notNull().defaultNow(),
    acknowledgedAt: timestamp('acknowledged_at', { withTimezone: true }),
    acknowledgeBy: timestamp('acknowledge_by', { withTimezone: true }).notNull(),
    lastHeartbeatAt: timestamp('last_heartbeat_at', { withTimezone: true }),
    expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
    /** Exact value atomically returned from tasks.fencing_counter. */
    fencingToken: bigint('fencing_token', { mode: 'bigint' }).notNull(),
    attemptNumber: integer('attempt_number').notNull(),
    releaseReason: text('release_reason'),
    releasedAt: timestamp('released_at', { withTimezone: true }),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'task_leases_exact_assignment_target_fk',
      columns: [t.workspaceId, t.taskId, t.assignmentId, t.agentId, t.agentSessionId],
      foreignColumns: [
        taskAssignmentsV1.workspaceId,
        taskAssignmentsV1.taskId,
        taskAssignmentsV1.id,
        taskAssignmentsV1.targetAgentId,
        taskAssignmentsV1.targetSessionId,
      ],
    }).onDelete('restrict'),
    uniqueIndex('task_leases_active_task_uidx')
      .on(t.workspaceId, t.taskId)
      .where(sql`${t.state} in ('pending_ack', 'active')`),
    uniqueIndex('task_leases_exact_fence_uidx').on(t.workspaceId, t.taskId, t.id, t.fencingToken),
    uniqueIndex('task_leases_task_fence_uidx').on(t.workspaceId, t.taskId, t.fencingToken),
    index('task_leases_workspace_state_expiry_idx').on(t.workspaceId, t.state, t.expiresAt),
    check('task_leases_fence_positive_chk', sql`${t.fencingToken} > 0`),
    check('task_leases_attempt_positive_chk', sql`${t.attemptNumber} > 0`),
  ],
);

export const taskCheckpointsV1 = pgTable(
  'task_checkpoints',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id').notNull(),
    leaseId: uuid('lease_id').notNull(),
    fencingToken: bigint('fencing_token', { mode: 'bigint' }).notNull(),
    sequence: integer('sequence').notNull(),
    resumableSummary: text('resumable_summary').notNull(),
    contextUsagePercent: integer('context_usage_percent'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    foreignKey({
      name: 'task_checkpoints_exact_lease_fence_fk',
      columns: [t.workspaceId, t.taskId, t.leaseId, t.fencingToken],
      foreignColumns: [
        taskLeasesV1.workspaceId,
        taskLeasesV1.taskId,
        taskLeasesV1.id,
        taskLeasesV1.fencingToken,
      ],
    }).onDelete('restrict'),
    uniqueIndex('task_checkpoints_workspace_task_id_uidx').on(t.workspaceId, t.taskId, t.id),
    uniqueIndex('task_checkpoints_lease_sequence_uidx').on(t.workspaceId, t.leaseId, t.sequence),
    index('task_checkpoints_task_created_idx').on(t.workspaceId, t.taskId, t.createdAt),
    check('task_checkpoints_sequence_positive_chk', sql`${t.sequence} > 0`),
    check('task_checkpoints_fence_positive_chk', sql`${t.fencingToken} > 0`),
    check(
      'task_checkpoints_context_percent_chk',
      sql`${t.contextUsagePercent} is null or (${t.contextUsagePercent} >= 0 and ${t.contextUsagePercent} <= 100)`,
    ),
  ],
);

export const checkpointArtifactsV1 = pgTable(
  'task_checkpoint_artifacts',
  {
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id').notNull(),
    checkpointId: uuid('checkpoint_id').notNull(),
    artifactId: uuid('artifact_id').notNull(),
  },
  (t) => [
    primaryKey({
      name: 'task_checkpoint_artifacts_pk',
      columns: [t.workspaceId, t.checkpointId, t.artifactId],
    }),
    foreignKey({
      name: 'task_checkpoint_artifacts_checkpoint_fk',
      columns: [t.workspaceId, t.taskId, t.checkpointId],
      foreignColumns: [
        taskCheckpointsV1.workspaceId,
        taskCheckpointsV1.taskId,
        taskCheckpointsV1.id,
      ],
    }).onDelete('restrict'),
    foreignKey({
      name: 'task_checkpoint_artifacts_artifact_fk',
      columns: [t.workspaceId, t.artifactId],
      foreignColumns: [artifactsV1.workspaceId, artifactsV1.id],
    }).onDelete('restrict'),
  ],
);

// ─── Approvals, evidence, outbox ─────────────────────────────────────────────

export const approvalDecisionsV1 = pgTable(
  'approval_decisions',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    taskId: uuid('task_id'),
    missionId: uuid('mission_id'),
    assignmentId: uuid('assignment_id'),
    gateType: text('gate_type').notNull(),
    requestedFromRole: specialistRoleEnum('requested_from_role'),
    decision: approvalDecisionEnum('decision').notNull().default('requested'),
    conditions: jsonb('conditions').notNull().$type<Record<string, unknown>>().default({}),
    actorKind: actorKindEnum('actor_kind'),
    actorId: text('actor_id'),
    policyRevision: text('policy_revision').notNull(),
    reason: text('reason'),
    requestedAt: timestamp('requested_at', { withTimezone: true }).notNull().defaultNow(),
    decidedAt: timestamp('decided_at', { withTimezone: true }),
  },
  (t) => [
    foreignKey({
      name: 'approval_decisions_workspace_task_fk',
      columns: [t.workspaceId, t.taskId],
      foreignColumns: [tasksV1.workspaceId, tasksV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'approval_decisions_workspace_mission_fk',
      columns: [t.workspaceId, t.missionId],
      foreignColumns: [missionsV1.workspaceId, missionsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'approval_decisions_workspace_assignment_fk',
      columns: [t.workspaceId, t.assignmentId],
      foreignColumns: [taskAssignmentsV1.workspaceId, taskAssignmentsV1.id],
    }).onDelete('restrict'),
    uniqueIndex('approval_decisions_workspace_id_uidx').on(t.workspaceId, t.id),
    index('approval_decisions_assignment_idx').on(t.workspaceId, t.assignmentId, t.decision),
    check(
      'approval_decisions_one_target_chk',
      sql`num_nonnulls(${t.taskId}, ${t.missionId}, ${t.assignmentId}) = 1`,
    ),
  ],
);

export const approvalDecisionArtifactsV1 = pgTable(
  'approval_decision_artifacts',
  {
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    approvalDecisionId: uuid('approval_decision_id').notNull(),
    artifactId: uuid('artifact_id').notNull(),
  },
  (t) => [
    primaryKey({
      name: 'approval_decision_artifacts_pk',
      columns: [t.workspaceId, t.approvalDecisionId, t.artifactId],
    }),
    foreignKey({
      name: 'approval_decision_artifacts_decision_fk',
      columns: [t.workspaceId, t.approvalDecisionId],
      foreignColumns: [approvalDecisionsV1.workspaceId, approvalDecisionsV1.id],
    }).onDelete('restrict'),
    foreignKey({
      name: 'approval_decision_artifacts_artifact_fk',
      columns: [t.workspaceId, t.artifactId],
      foreignColumns: [artifactsV1.workspaceId, artifactsV1.id],
    }).onDelete('restrict'),
  ],
);

export const outboxEventsV1 = pgTable(
  'outbox_events',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    workspaceId: uuid('workspace_id')
      .notNull()
      .references(() => workspacesV1.id, { onDelete: 'restrict' }),
    aggregateType: text('aggregate_type').notNull(),
    aggregateId: uuid('aggregate_id').notNull(),
    aggregateRevision: integer('aggregate_revision').notNull(),
    eventType: text('event_type').notNull(),
    payload: jsonb('payload').notNull().$type<Record<string, unknown>>(),
    state: outboxStateEnum('state').notNull().default('pending'),
    attempts: integer('attempts').notNull().default(0),
    nextAttemptAt: timestamp('next_attempt_at', { withTimezone: true }),
    publishedAt: timestamp('published_at', { withTimezone: true }),
    lastError: text('last_error'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    uniqueIndex('outbox_events_aggregate_revision_type_uidx').on(
      t.workspaceId,
      t.aggregateType,
      t.aggregateId,
      t.aggregateRevision,
      t.eventType,
    ),
    index('outbox_events_state_next_attempt_idx').on(t.state, t.nextAttemptAt),
    check('outbox_events_revision_positive_chk', sql`${t.aggregateRevision} > 0`),
    check('outbox_events_attempts_nonnegative_chk', sql`${t.attempts} >= 0`),
  ],
);

/**
 * Mandatory transaction/privilege rules frozen with this schema:
 *
 * 1. Every user principal/owner/proposer/decision actor must have ACTIVE
 *    workspace_members membership; denials expose no foreign-ID existence.
 * 2. roleSet/roles JSON values are validated against specialist_role_v1 until
 *    normalized role joins are introduced; the primary/assigned role is enum.
 * 3. Dependency cycles are rejected under a serialized recursive check.
 * 4. task_events is declared before change_proposals so migration DDL creates
 *    task_events_workspace_id_uidx before both workspace-aware proposal event
 *    FKs. Submission preallocates the proposal ID and, in one transaction,
 *    inserts `change_proposal.submitted` with aggregate_type=change_proposal,
 *    aggregate_id=proposal.id, previous_version=NULL, new_version=1, then the
 *    proposal referencing that event. Missing or foreign-workspace events fail.
 * 5. change_proposals never mutate targets directly. Acceptance locks proposal
 *    and target, proves fresh PG write health, checks expected version, invokes
 *    the NORMAL typed command, and in that same transaction binds its emitted
 *    event. The event workspace/aggregate type/aggregate ID must equal the
 *    proposal workspace/target, causation_id must equal submittedAuditEventId,
 *    and payload.changeProposalId must equal proposal.id; unrelated events fail.
 * 6. Lease acquisition locks task+assignment+approval+session, increments
 *    tasks.fencing_counter atomically, and uses RETURNING bigint as the token.
 * 7. task_events, task_checkpoints, checkpoint/artifact evidence, approval
 *    evidence, and immutable artifacts grant application roles INSERT/SELECT
 *    only. Canonical parents are archived, not hard-deleted; all parent FKs use
 *    RESTRICT. Purge requires an audited retention/break-glass procedure.
 * 8. Polymorphic external_links and change_proposals targets are validated in a
 *    workspace-scoped transaction before insert; no existence oracle.
 * 9. Legacy fields remain in the unified Drizzle declaration throughout expand
 *    and N-1. New Gateway commands never accept mission_tasks.status as a write
 *    source; its concrete retirement is specified in SHARED-CONTRACT.md.
 */
