@intx/db 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +2 -2
  2. package/dist/approval-store.d.ts +52 -0
  3. package/dist/approval-store.js +79 -0
  4. package/dist/asset-resolution.d.ts +2 -2
  5. package/dist/client.d.ts +10 -0
  6. package/dist/connection.js +11 -8
  7. package/dist/credential-resolution.d.ts +130 -18
  8. package/dist/credential-resolution.js +142 -3
  9. package/dist/grant-store.js +35 -13
  10. package/dist/index.d.ts +13 -4
  11. package/dist/index.js +11 -3
  12. package/dist/model-source-resolution.d.ts +52 -6
  13. package/dist/model-source-resolution.js +145 -19
  14. package/dist/parse-row.d.ts +212 -32
  15. package/dist/parse-row.js +109 -18
  16. package/dist/rekey-credential-secrets.d.ts +13 -0
  17. package/dist/rekey-credential-secrets.js +61 -0
  18. package/dist/schema/approvals.d.ts +245 -0
  19. package/dist/schema/approvals.js +52 -0
  20. package/dist/schema/catalog.d.ts +17 -0
  21. package/dist/schema/catalog.js +7 -1
  22. package/dist/schema/credentials.d.ts +1 -1
  23. package/dist/schema/git-tokens.js +1 -1
  24. package/dist/schema/grants.js +8 -2
  25. package/dist/schema/index.d.ts +8 -4
  26. package/dist/schema/index.js +8 -4
  27. package/dist/schema/messages.d.ts +5 -5
  28. package/dist/schema/messages.js +20 -9
  29. package/dist/schema/offerings.js +8 -2
  30. package/dist/schema/principals.d.ts +2 -2
  31. package/dist/schema/principals.js +7 -5
  32. package/dist/schema/providers.d.ts +17 -0
  33. package/dist/schema/providers.js +5 -0
  34. package/dist/schema/roles.js +6 -2
  35. package/dist/schema/session-assets.d.ts +1 -38
  36. package/dist/schema/session-assets.js +36 -19
  37. package/dist/schema/sessions.js +7 -2
  38. package/dist/schema/sidecar-allocation.d.ts +406 -0
  39. package/dist/schema/sidecar-allocation.js +57 -0
  40. package/dist/schema/sidecar.d.ts +19 -2
  41. package/dist/schema/sidecar.js +13 -3
  42. package/dist/schema/signal-correlations.d.ts +177 -0
  43. package/dist/schema/signal-correlations.js +31 -0
  44. package/dist/schema/wallets.d.ts +3 -3
  45. package/dist/schema/wallets.js +4 -2
  46. package/dist/schema/{agents.d.ts → workflow-definitions.d.ts} +79 -113
  47. package/dist/schema/workflow-definitions.js +97 -0
  48. package/dist/schema/workflow-run-dispatch.d.ts +328 -0
  49. package/dist/schema/workflow-run-dispatch.js +56 -0
  50. package/dist/schema/{workflow-deployments.d.ts → workflow-run-execution.d.ts} +43 -46
  51. package/dist/schema/workflow-run-execution.js +48 -0
  52. package/dist/schema/workflow-run-launch-spec.d.ts +200 -0
  53. package/dist/schema/workflow-run-launch-spec.js +26 -0
  54. package/dist/schema/{instances.d.ts → workflow-run.d.ts} +39 -71
  55. package/dist/schema/workflow-run.js +102 -0
  56. package/dist/sidecar-allocation-store.d.ts +171 -0
  57. package/dist/sidecar-allocation-store.js +512 -0
  58. package/dist/signal-correlation-store.d.ts +36 -0
  59. package/dist/signal-correlation-store.js +63 -0
  60. package/dist/tenant-hierarchy.d.ts +2 -1
  61. package/dist/tenant-hierarchy.js +10 -5
  62. package/dist/workflow-definition-store.d.ts +55 -0
  63. package/dist/workflow-definition-store.js +93 -0
  64. package/dist/workflow-run-dispatch-store.d.ts +80 -0
  65. package/dist/workflow-run-dispatch-store.js +298 -0
  66. package/dist/workflow-run-launch-spec-store.d.ts +13 -0
  67. package/dist/workflow-run-launch-spec-store.js +30 -0
  68. package/dist/workflow-run-store.d.ts +54 -0
  69. package/dist/workflow-run-store.js +85 -0
  70. package/migrations/0037_credential_use_backfill.sql +39 -0
  71. package/migrations/0038_chilly_blacklash.sql +37 -0
  72. package/migrations/0039_quick_carnage.sql +2 -0
  73. package/migrations/0040_reshape_approval_origin.sql +24 -0
  74. package/migrations/0041_make_approval_timeout_at_nullable.sql +1 -0
  75. package/migrations/0042_youthful_mantis.sql +2 -0
  76. package/migrations/0043_signal_correlation_deployment_fk.sql +1 -0
  77. package/migrations/0044_model_offering_quirks.sql +1 -0
  78. package/migrations/0045_create_workflow_run.sql +13 -0
  79. package/migrations/0046_approval_signal_correlation_run_fk.sql +2 -0
  80. package/migrations/0047_create_workflow_definition.sql +30 -0
  81. package/migrations/0048_workflow_definition_origin_agent_id.sql +2 -0
  82. package/migrations/0049_curly_omega_flight.sql +2 -0
  83. package/migrations/0050_late_crystal.sql +10 -0
  84. package/migrations/0051_funny_madelyne_pryor.sql +1 -0
  85. package/migrations/0052_drop_inference_turn_instance_fk.sql +1 -0
  86. package/migrations/0053_session_mail_session_id_index.sql +1 -0
  87. package/migrations/0054_rekey_instance_grants_to_workflow_run.sql +10 -0
  88. package/migrations/0055_backfill_anchor_workflow_runs.sql +69 -0
  89. package/migrations/0056_repoint_deployment_fks_to_anchor_run.sql +32 -0
  90. package/migrations/0057_drop_workflow_deployment_projection.sql +22 -0
  91. package/migrations/0058_repoint_offering_fk_to_definition.sql +41 -0
  92. package/migrations/0059_repoint_transaction_fk_to_run.sql +10 -0
  93. package/migrations/0060_drop_session_mail_instance_fk.sql +6 -0
  94. package/migrations/0061_drop_session_asset_instance_fk.sql +7 -0
  95. package/migrations/0062_drop_agent_asset_table.sql +11 -0
  96. package/migrations/0063_repoint_agent_role_fk_to_definition.sql +39 -0
  97. package/migrations/0064_repoint_agent_session_fk_to_definition.sql +47 -0
  98. package/migrations/0065_add_workflow_definition_model_requirements.sql +37 -0
  99. package/migrations/0066_rekey_agent_definition_principals_to_workflow.sql +27 -0
  100. package/migrations/0067_add_workflow_definition_kind.sql +10 -0
  101. package/migrations/0068_drop_agent_tables_and_origin_agent_id.sql +31 -0
  102. package/migrations/0069_drop_workflow_definition_kind.sql +10 -0
  103. package/migrations/0070_flashy_proteus.sql +13 -0
  104. package/migrations/0072_add_workflow_definition_credential_bindings.sql +1 -0
  105. package/migrations/0073_grant_target_exactly_one_check.sql +13 -0
  106. package/migrations/0074_add_provider_api_base_url.sql +1 -0
  107. package/migrations/0075_workflow_run_launch_spec.sql +17 -0
  108. package/migrations/0076_sidecar_allocation.sql +40 -0
  109. package/migrations/0077_workflow_run_dispatch.sql +29 -0
  110. package/migrations/0078_workflow_run_dispatch_kind.sql +2 -0
  111. package/migrations/0079_rename_workflow_run_deployment_id_to_anchor_run_id.sql +4 -0
  112. package/migrations/0080_rename_correlation_approval_deployment_id_to_anchor_run_id.sql +9 -0
  113. package/migrations/0081_workflow_definition_content_hash_and_approved_wire_hash.sql +4 -0
  114. package/migrations/0082_blue_black_queen.sql +1 -0
  115. package/migrations/0083_replace_launch_spec_snapshot_with_frozen_bundle.sql +3 -0
  116. package/migrations/0084_delete_orphaned_credential_grants.sql +22 -0
  117. package/migrations/meta/0037_snapshot.json +3237 -0
  118. package/migrations/meta/0038_snapshot.json +3470 -0
  119. package/migrations/meta/0039_snapshot.json +3470 -0
  120. package/migrations/meta/0040_snapshot.json +3489 -0
  121. package/migrations/meta/0041_snapshot.json +3489 -0
  122. package/migrations/meta/0042_snapshot.json +3489 -0
  123. package/migrations/meta/0043_snapshot.json +3498 -0
  124. package/migrations/meta/0044_snapshot.json +3504 -0
  125. package/migrations/meta/0045_snapshot.json +3589 -0
  126. package/migrations/meta/0046_snapshot.json +3607 -0
  127. package/migrations/meta/0047_snapshot.json +3832 -0
  128. package/migrations/meta/0048_snapshot.json +3853 -0
  129. package/migrations/meta/0049_snapshot.json +3854 -0
  130. package/migrations/meta/0050_snapshot.json +3924 -0
  131. package/migrations/meta/0051_snapshot.json +3940 -0
  132. package/migrations/meta/0052_snapshot.json +3931 -0
  133. package/migrations/meta/0053_snapshot.json +3952 -0
  134. package/migrations/meta/0054_snapshot.json +3952 -0
  135. package/migrations/meta/0055_snapshot.json +3952 -0
  136. package/migrations/meta/0056_snapshot.json +3952 -0
  137. package/migrations/meta/0057_snapshot.json +3839 -0
  138. package/migrations/meta/0058_snapshot.json +3839 -0
  139. package/migrations/meta/0059_snapshot.json +3839 -0
  140. package/migrations/meta/0060_snapshot.json +3830 -0
  141. package/migrations/meta/0061_snapshot.json +3821 -0
  142. package/migrations/meta/0062_snapshot.json +3723 -0
  143. package/migrations/meta/0063_snapshot.json +3723 -0
  144. package/migrations/meta/0064_snapshot.json +3723 -0
  145. package/migrations/meta/0065_snapshot.json +3729 -0
  146. package/migrations/meta/0066_snapshot.json +3729 -0
  147. package/migrations/meta/0067_snapshot.json +3736 -0
  148. package/migrations/meta/0068_snapshot.json +3347 -0
  149. package/migrations/meta/0069_snapshot.json +3340 -0
  150. package/migrations/meta/0070_snapshot.json +3444 -0
  151. package/migrations/meta/0072_snapshot.json +3450 -0
  152. package/migrations/meta/0073_snapshot.json +3455 -0
  153. package/migrations/meta/0074_snapshot.json +3461 -0
  154. package/migrations/meta/0075_snapshot.json +3567 -0
  155. package/migrations/meta/0076_snapshot.json +3851 -0
  156. package/migrations/meta/0077_snapshot.json +4067 -0
  157. package/migrations/meta/0078_snapshot.json +4078 -0
  158. package/migrations/meta/0079_snapshot.json +4078 -0
  159. package/migrations/meta/0080_snapshot.json +4078 -0
  160. package/migrations/meta/0081_snapshot.json +4096 -0
  161. package/migrations/meta/0082_snapshot.json +4102 -0
  162. package/migrations/meta/0083_snapshot.json +4096 -0
  163. package/migrations/meta/0084_snapshot.json +4096 -0
  164. package/migrations/meta/_journal.json +329 -0
  165. package/package.json +6 -3
  166. package/dist/schema/agent-assets.d.ts +0 -109
  167. package/dist/schema/agent-assets.js +0 -15
  168. package/dist/schema/agents.js +0 -57
  169. package/dist/schema/instances.js +0 -39
  170. package/dist/schema/workflow-deployments.js +0 -37
@@ -0,0 +1,13 @@
1
+ import type { DB, DBExecutor } from "./client.js";
2
+ import { parseWorkflowRunLaunchSpecRow } from "./parse-row.js";
3
+ import { workflowRunLaunchSpec } from "./schema/workflow-run-launch-spec.js";
4
+ type DBHandle = DB["db"];
5
+ type LaunchSpecInsert = typeof workflowRunLaunchSpec.$inferInsert;
6
+ type ParsedLaunchSpec = ReturnType<typeof parseWorkflowRunLaunchSpecRow>;
7
+ /** Store for immutable workflow recovery inputs keyed by anchor run. */
8
+ export declare function createWorkflowRunLaunchSpecStore(db: DBHandle): {
9
+ create(row: LaunchSpecInsert, tx?: DBExecutor): Promise<ParsedLaunchSpec>;
10
+ get(anchorRunId: string, tx?: DBExecutor): Promise<ParsedLaunchSpec | null>;
11
+ };
12
+ export type WorkflowRunLaunchSpecStore = ReturnType<typeof createWorkflowRunLaunchSpecStore>;
13
+ export {};
@@ -0,0 +1,30 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { parseWorkflowRunLaunchSpecRow } from "./parse-row.js";
3
+ import { workflowRunLaunchSpec } from "./schema/workflow-run-launch-spec.js";
4
+ /** Store for immutable workflow recovery inputs keyed by anchor run. */
5
+ export function createWorkflowRunLaunchSpecStore(db) {
6
+ return {
7
+ async create(row, tx) {
8
+ parseWorkflowRunLaunchSpecRow({
9
+ ...row,
10
+ schemaVersion: row.schemaVersion ?? 1,
11
+ toolPackagePins: row.toolPackagePins ?? null,
12
+ createdAt: row.createdAt ?? new Date(),
13
+ });
14
+ const [inserted] = await (tx ?? db)
15
+ .insert(workflowRunLaunchSpec)
16
+ .values(row)
17
+ .returning();
18
+ if (inserted === undefined) {
19
+ throw new Error(`workflowRunLaunchSpecStore.create: insert returned no row for ${row.anchorRunId}`);
20
+ }
21
+ return parseWorkflowRunLaunchSpecRow(inserted);
22
+ },
23
+ async get(anchorRunId, tx) {
24
+ const row = await (tx ?? db).query.workflowRunLaunchSpec.findFirst({
25
+ where: eq(workflowRunLaunchSpec.anchorRunId, anchorRunId),
26
+ });
27
+ return row === undefined ? null : parseWorkflowRunLaunchSpecRow(row);
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,54 @@
1
+ import type { DB, DBExecutor } from "./client.js";
2
+ import { workflowRun } from "./schema/workflow-run.js";
3
+ import { parseWorkflowRunRow } from "./parse-row.js";
4
+ type DBHandle = DB["db"];
5
+ type WorkflowRunInsert = typeof workflowRun.$inferInsert;
6
+ type ParsedWorkflowRun = ReturnType<typeof parseWorkflowRunRow>;
7
+ /**
8
+ * Store for the `workflow_run` table, the per-run authorization subject that
9
+ * approvals and signal correlations anchor to. Each method accepts an optional
10
+ * transaction handle so the run row can be written in the same transaction that
11
+ * co-writes the run's principal or its approval.
12
+ */
13
+ export declare function createWorkflowRunStore(db: DBHandle): {
14
+ create(row: WorkflowRunInsert, tx?: DBExecutor): Promise<ParsedWorkflowRun>;
15
+ /**
16
+ * Idempotent variant of `create`. On an `id` primary-key conflict the
17
+ * insert is a no-op and this returns `null` rather than throwing, so a
18
+ * redelivered createIfAbsent (workflow-log replay, supervisor restart
19
+ * re-emitting) does not fail the run's co-write. Returns the parsed row
20
+ * only when this call performed the insert.
21
+ */
22
+ createIfAbsent(row: WorkflowRunInsert, tx?: DBExecutor): Promise<ParsedWorkflowRun | null>;
23
+ /**
24
+ * Anchor an externally-triggered run onto its deploy-time anchor row. The
25
+ * anchor is created at deploy (born "deployed" with a null principal); the
26
+ * first trigger reconciles it here, attaching `principalId` and flipping
27
+ * "deployed" -> "running" in one UPDATE. The insert is a conflict-tolerant
28
+ * safety net: the anchor provably exists by the time a trigger runs, so it
29
+ * normally no-ops. The three-part guard makes the reconcile single-shot and
30
+ * safe: `principalId IS NULL` never overwrites a principal a concurrent
31
+ * winner already set, and `status = 'deployed'` never resurrects a run a
32
+ * concurrent teardown already settled terminal (the null-principal guard
33
+ * alone would). `principalId` must be non-null: only the externally-
34
+ * triggered path anchors through here, and it always mints one.
35
+ */
36
+ anchorWithPrincipal(row: WorkflowRunInsert & {
37
+ principalId: string;
38
+ }, tx?: DBExecutor): Promise<void>;
39
+ /**
40
+ * Atomically settle a live run into a terminal state. The live-status guard
41
+ * (`status IN ('deployed','running')`) makes the flip single-shot: the first
42
+ * caller stamps the terminal status and `endedAt` and gets the row back; any
43
+ * later caller matches no row and receives null, so the run is not
44
+ * re-terminated and its `endedAt` is not overwritten. Accepting "deployed"
45
+ * settles a deployment torn down before its first trigger. This is a safety
46
+ * property, not a recovery path -- it makes a second call (a manual replay
47
+ * against an already-settled run) a harmless no-op; it does not by itself
48
+ * re-drive a flip that failed. Returns the parsed row only on the winning
49
+ * flip.
50
+ */
51
+ markTerminal(runId: string, status: "completed" | "failed" | "cancelled", endedAt: Date, tx?: DBExecutor): Promise<ParsedWorkflowRun | null>;
52
+ };
53
+ export type WorkflowRunStore = ReturnType<typeof createWorkflowRunStore>;
54
+ export {};
@@ -0,0 +1,85 @@
1
+ import { and, eq, inArray, isNull } from "drizzle-orm";
2
+ import { liveWorkflowRunStatuses, workflowRun } from "./schema/workflow-run.js";
3
+ import { parseWorkflowRunRow } from "./parse-row.js";
4
+ /**
5
+ * Store for the `workflow_run` table, the per-run authorization subject that
6
+ * approvals and signal correlations anchor to. Each method accepts an optional
7
+ * transaction handle so the run row can be written in the same transaction that
8
+ * co-writes the run's principal or its approval.
9
+ */
10
+ export function createWorkflowRunStore(db) {
11
+ return {
12
+ async create(row, tx) {
13
+ const [inserted] = await (tx ?? db)
14
+ .insert(workflowRun)
15
+ .values(row)
16
+ .returning();
17
+ if (inserted === undefined) {
18
+ throw new Error(`workflowRunStore.create: insert returned no row for ${row.id}`);
19
+ }
20
+ return parseWorkflowRunRow(inserted);
21
+ },
22
+ /**
23
+ * Idempotent variant of `create`. On an `id` primary-key conflict the
24
+ * insert is a no-op and this returns `null` rather than throwing, so a
25
+ * redelivered createIfAbsent (workflow-log replay, supervisor restart
26
+ * re-emitting) does not fail the run's co-write. Returns the parsed row
27
+ * only when this call performed the insert.
28
+ */
29
+ async createIfAbsent(row, tx) {
30
+ const [inserted] = await (tx ?? db)
31
+ .insert(workflowRun)
32
+ .values(row)
33
+ .onConflictDoNothing({ target: workflowRun.id })
34
+ .returning();
35
+ return inserted === undefined ? null : parseWorkflowRunRow(inserted);
36
+ },
37
+ /**
38
+ * Anchor an externally-triggered run onto its deploy-time anchor row. The
39
+ * anchor is created at deploy (born "deployed" with a null principal); the
40
+ * first trigger reconciles it here, attaching `principalId` and flipping
41
+ * "deployed" -> "running" in one UPDATE. The insert is a conflict-tolerant
42
+ * safety net: the anchor provably exists by the time a trigger runs, so it
43
+ * normally no-ops. The three-part guard makes the reconcile single-shot and
44
+ * safe: `principalId IS NULL` never overwrites a principal a concurrent
45
+ * winner already set, and `status = 'deployed'` never resurrects a run a
46
+ * concurrent teardown already settled terminal (the null-principal guard
47
+ * alone would). `principalId` must be non-null: only the externally-
48
+ * triggered path anchors through here, and it always mints one.
49
+ */
50
+ async anchorWithPrincipal(row, tx) {
51
+ const executor = tx ?? db;
52
+ const [inserted] = await executor
53
+ .insert(workflowRun)
54
+ .values(row)
55
+ .onConflictDoNothing({ target: workflowRun.id })
56
+ .returning();
57
+ if (inserted !== undefined)
58
+ return;
59
+ await executor
60
+ .update(workflowRun)
61
+ .set({ principalId: row.principalId, status: "running" })
62
+ .where(and(eq(workflowRun.id, row.id), isNull(workflowRun.principalId), eq(workflowRun.status, "deployed")));
63
+ },
64
+ /**
65
+ * Atomically settle a live run into a terminal state. The live-status guard
66
+ * (`status IN ('deployed','running')`) makes the flip single-shot: the first
67
+ * caller stamps the terminal status and `endedAt` and gets the row back; any
68
+ * later caller matches no row and receives null, so the run is not
69
+ * re-terminated and its `endedAt` is not overwritten. Accepting "deployed"
70
+ * settles a deployment torn down before its first trigger. This is a safety
71
+ * property, not a recovery path -- it makes a second call (a manual replay
72
+ * against an already-settled run) a harmless no-op; it does not by itself
73
+ * re-drive a flip that failed. Returns the parsed row only on the winning
74
+ * flip.
75
+ */
76
+ async markTerminal(runId, status, endedAt, tx) {
77
+ const [updated] = await (tx ?? db)
78
+ .update(workflowRun)
79
+ .set({ status, endedAt })
80
+ .where(and(eq(workflowRun.id, runId), inArray(workflowRun.status, [...liveWorkflowRunStatuses])))
81
+ .returning();
82
+ return updated === undefined ? null : parseWorkflowRunRow(updated);
83
+ },
84
+ };
85
+ }
@@ -0,0 +1,39 @@
1
+ -- Backfill `credential:{id}` / `use` grants for the owner of every existing
2
+ -- personal credential (rows where `principal_id` is set) that does not already
3
+ -- have one. This keeps existing personal-credential owners working once
4
+ -- launch enforcement fails closed. Organizational credentials
5
+ -- (`principal_id` IS NULL) are intentionally excluded: they remain gated
6
+ -- behind tenant-owner role inheritance and explicit administrative grants.
7
+ --
8
+ -- Idempotent: the `WHERE NOT EXISTS` guard skips any credential whose owner
9
+ -- already holds a matching grant, so re-application inserts nothing and does
10
+ -- not fail. Grant ids reproduce the app convention (`grt_` prefix followed by
11
+ -- 32 hex characters) via `gen_random_uuid()`.
12
+ INSERT INTO "grant" (
13
+ "id",
14
+ "tenant_id",
15
+ "principal_id",
16
+ "resource",
17
+ "action",
18
+ "effect",
19
+ "origin",
20
+ "expires_at"
21
+ )
22
+ SELECT
23
+ 'grt_' || replace(gen_random_uuid()::text, '-', ''),
24
+ c."tenant_id",
25
+ c."principal_id",
26
+ 'credential:' || c."id",
27
+ 'use',
28
+ 'allow',
29
+ 'creator',
30
+ NULL
31
+ FROM "credential" c
32
+ WHERE c."principal_id" IS NOT NULL
33
+ AND NOT EXISTS (
34
+ SELECT 1
35
+ FROM "grant" g
36
+ WHERE g."principal_id" = c."principal_id"
37
+ AND g."resource" = 'credential:' || c."id"
38
+ AND g."action" = 'use'
39
+ );
@@ -0,0 +1,37 @@
1
+ CREATE TABLE "approval" (
2
+ "id" text PRIMARY KEY NOT NULL,
3
+ "tenant_id" text NOT NULL,
4
+ "instance_id" text NOT NULL,
5
+ "agent_id" text NOT NULL,
6
+ "origin_principal_id" text NOT NULL,
7
+ "correlation_id" text NOT NULL,
8
+ "tool_definition" jsonb NOT NULL,
9
+ "tool_arguments" jsonb NOT NULL,
10
+ "scope" text,
11
+ "status" text DEFAULT 'pending' NOT NULL,
12
+ "origin_kind" text NOT NULL,
13
+ "timeout_at" timestamp NOT NULL,
14
+ "resolved_at" timestamp,
15
+ "created_at" timestamp DEFAULT now() NOT NULL,
16
+ "updated_at" timestamp DEFAULT now() NOT NULL,
17
+ CONSTRAINT "approval_correlation_id_unique" UNIQUE("correlation_id")
18
+ );
19
+ --> statement-breakpoint
20
+ CREATE TABLE "signal_correlation" (
21
+ "correlation_id" text PRIMARY KEY NOT NULL,
22
+ "tenant_id" text NOT NULL,
23
+ "deployment_id" text NOT NULL,
24
+ "agent_address" text NOT NULL,
25
+ "run_id" text NOT NULL,
26
+ "signal_name" text NOT NULL,
27
+ "kind" text NOT NULL,
28
+ "signal_id" text,
29
+ "resolved_at" timestamp,
30
+ "created_at" timestamp DEFAULT now() NOT NULL
31
+ );
32
+ --> statement-breakpoint
33
+ ALTER TABLE "approval" ADD CONSTRAINT "approval_tenant_id_tenant_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenant"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
34
+ ALTER TABLE "approval" ADD CONSTRAINT "approval_instance_id_agent_instance_id_fk" FOREIGN KEY ("instance_id") REFERENCES "public"."agent_instance"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
35
+ ALTER TABLE "approval" ADD CONSTRAINT "approval_agent_id_agent_id_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agent"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
36
+ ALTER TABLE "approval" ADD CONSTRAINT "approval_origin_principal_id_principal_id_fk" FOREIGN KEY ("origin_principal_id") REFERENCES "public"."principal"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
37
+ ALTER TABLE "signal_correlation" ADD CONSTRAINT "signal_correlation_tenant_id_tenant_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenant"("id") ON DELETE cascade ON UPDATE no action;
@@ -0,0 +1,2 @@
1
+ ALTER TABLE "approval" ALTER COLUMN "tool_definition" DROP NOT NULL;--> statement-breakpoint
2
+ ALTER TABLE "approval" ALTER COLUMN "tool_arguments" DROP NOT NULL;
@@ -0,0 +1,24 @@
1
+ -- Reshape `approval` so its origin is the workflow deployment it came from.
2
+ -- The dropped instance/agent/origin-principal FKs had no valid referent: a
3
+ -- workflow deployment has no agent_instance/agent row and its run principal is
4
+ -- a substrate principal, not a `principal`-table row. The three added columns
5
+ -- are NOT NULL with no default and no backfill; like the repo's other such
6
+ -- adds (e.g. 0014, `workflow_deployment.address`), this relies on the table
7
+ -- being empty when the migration runs. The table is unreleased -- the approval
8
+ -- routes are 501 stubs -- so no populated row predates these columns.
9
+ ALTER TABLE "approval" DROP CONSTRAINT "approval_instance_id_agent_instance_id_fk";
10
+ --> statement-breakpoint
11
+ ALTER TABLE "approval" DROP CONSTRAINT "approval_agent_id_agent_id_fk";
12
+ --> statement-breakpoint
13
+ ALTER TABLE "approval" DROP CONSTRAINT "approval_origin_principal_id_principal_id_fk";
14
+ --> statement-breakpoint
15
+ ALTER TABLE "approval" ADD COLUMN "deployment_id" text NOT NULL;--> statement-breakpoint
16
+ ALTER TABLE "approval" ADD COLUMN "run_id" text NOT NULL;--> statement-breakpoint
17
+ ALTER TABLE "approval" ADD COLUMN "agent_address" text NOT NULL;--> statement-breakpoint
18
+ ALTER TABLE "approval" ADD CONSTRAINT "approval_deployment_id_workflow_deployment_id_fk" FOREIGN KEY ("deployment_id") REFERENCES "public"."workflow_deployment"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
19
+ CREATE INDEX "approval_tenant_status_idx" ON "approval" USING btree ("tenant_id","status","created_at");--> statement-breakpoint
20
+ CREATE INDEX "approval_deployment_idx" ON "approval" USING btree ("deployment_id");--> statement-breakpoint
21
+ ALTER TABLE "approval" DROP COLUMN "instance_id";--> statement-breakpoint
22
+ ALTER TABLE "approval" DROP COLUMN "agent_id";--> statement-breakpoint
23
+ ALTER TABLE "approval" DROP COLUMN "origin_principal_id";--> statement-breakpoint
24
+ ALTER TABLE "approval" DROP COLUMN "origin_kind";
@@ -0,0 +1 @@
1
+ ALTER TABLE "approval" ALTER COLUMN "timeout_at" DROP NOT NULL;
@@ -0,0 +1,2 @@
1
+ ALTER TABLE "approval" ALTER COLUMN "tool_definition" SET NOT NULL;--> statement-breakpoint
2
+ ALTER TABLE "approval" ALTER COLUMN "tool_arguments" SET NOT NULL;
@@ -0,0 +1 @@
1
+ ALTER TABLE "signal_correlation" ADD CONSTRAINT "signal_correlation_deployment_id_workflow_deployment_id_fk" FOREIGN KEY ("deployment_id") REFERENCES "public"."workflow_deployment"("id") ON DELETE cascade ON UPDATE no action;
@@ -0,0 +1 @@
1
+ ALTER TABLE "model_offering" ADD COLUMN "quirks" jsonb;
@@ -0,0 +1,13 @@
1
+ CREATE TABLE "workflow_run" (
2
+ "id" text PRIMARY KEY NOT NULL,
3
+ "deployment_id" text NOT NULL,
4
+ "tenant_id" text NOT NULL,
5
+ "principal_id" text,
6
+ "status" text DEFAULT 'running' NOT NULL,
7
+ "created_at" timestamp DEFAULT now() NOT NULL,
8
+ "ended_at" timestamp
9
+ );
10
+ --> statement-breakpoint
11
+ ALTER TABLE "workflow_run" ADD CONSTRAINT "workflow_run_deployment_id_workflow_deployment_id_fk" FOREIGN KEY ("deployment_id") REFERENCES "public"."workflow_deployment"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
12
+ ALTER TABLE "workflow_run" ADD CONSTRAINT "workflow_run_tenant_id_tenant_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenant"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
13
+ ALTER TABLE "workflow_run" ADD CONSTRAINT "workflow_run_principal_id_principal_id_fk" FOREIGN KEY ("principal_id") REFERENCES "public"."principal"("id") ON DELETE set null ON UPDATE no action;
@@ -0,0 +1,2 @@
1
+ ALTER TABLE "approval" ADD CONSTRAINT "approval_run_id_workflow_run_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."workflow_run"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
2
+ ALTER TABLE "signal_correlation" ADD CONSTRAINT "signal_correlation_run_id_workflow_run_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."workflow_run"("id") ON DELETE cascade ON UPDATE no action;
@@ -0,0 +1,30 @@
1
+ CREATE TABLE "workflow_definition" (
2
+ "id" text PRIMARY KEY NOT NULL,
3
+ "tenant_id" text NOT NULL,
4
+ "creator_principal_id" text,
5
+ "asset_id" text,
6
+ "name" text NOT NULL,
7
+ "description" text,
8
+ "grant_requirements" jsonb,
9
+ "current_version" text DEFAULT '1' NOT NULL,
10
+ "status" text DEFAULT 'deployed' NOT NULL,
11
+ "created_at" timestamp DEFAULT now() NOT NULL,
12
+ "updated_at" timestamp DEFAULT now() NOT NULL
13
+ );
14
+ --> statement-breakpoint
15
+ CREATE TABLE "workflow_definition_version" (
16
+ "id" text PRIMARY KEY NOT NULL,
17
+ "definition_id" text NOT NULL,
18
+ "version" text NOT NULL,
19
+ "status" text DEFAULT 'active' NOT NULL,
20
+ "created_at" timestamp DEFAULT now() NOT NULL,
21
+ CONSTRAINT "workflow_definition_version_definition_version" UNIQUE("definition_id","version")
22
+ );
23
+ --> statement-breakpoint
24
+ ALTER TABLE "workflow_definition" ADD CONSTRAINT "workflow_definition_tenant_id_tenant_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenant"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
25
+ ALTER TABLE "workflow_definition" ADD CONSTRAINT "workflow_definition_creator_principal_id_principal_id_fk" FOREIGN KEY ("creator_principal_id") REFERENCES "public"."principal"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
26
+ ALTER TABLE "workflow_definition" ADD CONSTRAINT "workflow_definition_asset_id_asset_id_fk" FOREIGN KEY ("asset_id") REFERENCES "public"."asset"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
27
+ ALTER TABLE "workflow_definition_version" ADD CONSTRAINT "workflow_definition_version_definition_id_workflow_definition_id_fk" FOREIGN KEY ("definition_id") REFERENCES "public"."workflow_definition"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
28
+ CREATE INDEX "workflow_definition_tenant_idx" ON "workflow_definition" USING btree ("tenant_id","created_at");--> statement-breakpoint
29
+ CREATE UNIQUE INDEX "workflow_definition_asset_idx" ON "workflow_definition" USING btree ("asset_id");--> statement-breakpoint
30
+ CREATE INDEX "workflow_definition_version_definition_idx" ON "workflow_definition_version" USING btree ("definition_id");
@@ -0,0 +1,2 @@
1
+ ALTER TABLE "workflow_definition" ADD COLUMN "origin_agent_id" text;--> statement-breakpoint
2
+ CREATE INDEX "workflow_definition_origin_agent_idx" ON "workflow_definition" USING btree ("origin_agent_id");
@@ -0,0 +1,2 @@
1
+ DROP INDEX "workflow_definition_origin_agent_idx";--> statement-breakpoint
2
+ CREATE UNIQUE INDEX "workflow_definition_origin_agent_idx" ON "workflow_definition" USING btree ("origin_agent_id") WHERE "workflow_definition"."origin_agent_id" is not null;
@@ -0,0 +1,10 @@
1
+ ALTER TABLE "workflow_run" ALTER COLUMN "deployment_id" DROP NOT NULL;--> statement-breakpoint
2
+ ALTER TABLE "workflow_run" ADD COLUMN "definition_id" text;--> statement-breakpoint
3
+ ALTER TABLE "workflow_run" ADD COLUMN "address" text;--> statement-breakpoint
4
+ ALTER TABLE "workflow_run" ADD COLUMN "public_key" text;--> statement-breakpoint
5
+ ALTER TABLE "workflow_run" ADD COLUMN "sidecar_id" text;--> statement-breakpoint
6
+ ALTER TABLE "workflow_run" ADD COLUMN "kernel_id" text;--> statement-breakpoint
7
+ ALTER TABLE "workflow_run" ADD COLUMN "model_preferences" jsonb;--> statement-breakpoint
8
+ ALTER TABLE "workflow_run" ADD CONSTRAINT "workflow_run_definition_id_workflow_definition_id_fk" FOREIGN KEY ("definition_id") REFERENCES "public"."workflow_definition"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
9
+ ALTER TABLE "workflow_run" ADD CONSTRAINT "workflow_run_sidecar_id_sidecar_id_fk" FOREIGN KEY ("sidecar_id") REFERENCES "public"."sidecar"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
10
+ CREATE INDEX "workflow_run_definition_idx" ON "workflow_run" USING btree ("definition_id");
@@ -0,0 +1 @@
1
+ CREATE UNIQUE INDEX "workflow_run_address_idx" ON "workflow_run" USING btree ("address") WHERE "workflow_run"."address" is not null;
@@ -0,0 +1 @@
1
+ ALTER TABLE "inference_turn" DROP CONSTRAINT "inference_turn_instance_id_agent_instance_id_fk";
@@ -0,0 +1 @@
1
+ CREATE INDEX "session_mail_session_id_created_at_idx" ON "session_mail" USING btree ("session_id","created_at");
@@ -0,0 +1,10 @@
1
+ -- Re-key run-scoped grants onto the folded workflow-run resource. A folded run
2
+ -- shares the instance id space, so the rewrite is prefix-identity: the id after
3
+ -- the colon is unchanged, only the type name moves instance: -> workflow-run:
4
+ -- (carrying instance:* -> workflow-run:* too). The match is colon-delimited so
5
+ -- it never touches the unrelated agent-state: grants; there is no instance-state
6
+ -- sibling. Idempotent: after this runs no row matches instance:%, so a re-run is
7
+ -- a no-op.
8
+ UPDATE "grant"
9
+ SET resource = 'workflow-run:' || substr(resource, length('instance:') + 1)
10
+ WHERE resource LIKE 'instance:%';
@@ -0,0 +1,69 @@
1
+ -- Reconstruct an anchor workflow_run for every deployment that predates the
2
+ -- runtime anchor insert. A deployment's routing address and reconnect key now
3
+ -- live on its anchor run (the workflow_run whose id equals the deployment id),
4
+ -- which new deploys create at runtime -- but deployments created earlier have a
5
+ -- workflow_deployment row and no anchor run, so the reconnect key lookup finds
6
+ -- no run for their address and their reconnect challenge fails closed. This
7
+ -- copies the deployment's identity onto a fresh anchor run so those deployments
8
+ -- reconnect exactly as ones deployed after the runtime anchor insert do.
9
+ --
10
+ -- A runtime-created anchor run also carries its definition -- deploy resolves
11
+ -- and writes definition_id -- so a reconstructed one must too; an anchor run
12
+ -- without a definition is only half the deployment's first-class stand-in. A
13
+ -- definition_id resolves from the deployment's asset, which the workflow-asset
14
+ -- fold populates. The guard below aborts the migration before it writes
15
+ -- anything if any deployment still needing an anchor run has no folded
16
+ -- definition, so the backfill reconstructs every anchor run completely or
17
+ -- writes nothing and tells the operator to run the fold first. The production
18
+ -- path applies migrations under `drizzle-kit migrate`, which wraps the pending
19
+ -- set in a transaction, and PostgreSQL DDL is transactional, so an aborting
20
+ -- guard rolls the whole set back -- there is no partial commit to re-run from
21
+ -- the top, so the guard is simply a clear up-front precondition.
22
+ DO $$
23
+ BEGIN
24
+ IF EXISTS (
25
+ SELECT 1
26
+ FROM "workflow_deployment" wd
27
+ WHERE NOT EXISTS (
28
+ SELECT 1 FROM "workflow_run" r WHERE r.id = wd.id
29
+ )
30
+ AND NOT EXISTS (
31
+ SELECT 1 FROM "workflow_definition" wdef
32
+ WHERE wdef.asset_id = wd.definition_asset_id
33
+ )
34
+ ) THEN
35
+ RAISE EXCEPTION 'workflow-asset fold has not run: a deployment lacks a folded definition and its anchor run would be definition-less. The fold tooling has been retired; create the missing workflow_definition for the deployment asset by hand before applying this migration (see the agent-fold migration note in DEV.md).';
36
+ END IF;
37
+ END $$;
38
+ --> statement-breakpoint
39
+ -- public_key is copied from the deployment (its old deploy-ack key) so the
40
+ -- reconnect challenge resolves the same key it did before; created_at is copied
41
+ -- so listing order is stable; status is the anchor's live value; definition_id
42
+ -- resolves through the folded definition the guard above proved present. The
43
+ -- remaining columns match a runtime anchor insert: no principal, no runtime
44
+ -- bindings, not ended. NOT EXISTS on the id keeps it idempotent and skips
45
+ -- deployments that already have a runtime-created anchor run.
46
+ INSERT INTO "workflow_run" (
47
+ id,
48
+ tenant_id,
49
+ deployment_id,
50
+ definition_id,
51
+ address,
52
+ public_key,
53
+ status,
54
+ created_at
55
+ )
56
+ SELECT
57
+ wd.id,
58
+ wd.tenant_id,
59
+ wd.id,
60
+ wdef.id,
61
+ wd.address,
62
+ wd.public_key,
63
+ 'running',
64
+ wd.created_at
65
+ FROM "workflow_deployment" wd
66
+ LEFT JOIN "workflow_definition" wdef ON wdef.asset_id = wd.definition_asset_id
67
+ WHERE NOT EXISTS (
68
+ SELECT 1 FROM "workflow_run" r WHERE r.id = wd.id
69
+ );
@@ -0,0 +1,32 @@
1
+ -- Re-point the three deployment_id foreign keys from the workflow_deployment
2
+ -- projection onto the anchor run -- the workflow_run whose id equals the
3
+ -- deployment id -- leaving the projection unreferenced. Every deployment_id
4
+ -- value already equals an anchor run's id (migration 0055 backfilled one per
5
+ -- deployment), so each re-pointed constraint validates on add; a deployment
6
+ -- that somehow lacks its anchor run makes the ADD CONSTRAINT abort, a free
7
+ -- integrity check.
8
+ --
9
+ -- First, fill definition_id on the runs the projection still anchors, so every
10
+ -- run carries its definition -- the run anchors on the definition, not the
11
+ -- deployment. A pre-existing non-anchor run -- a folded or child run created
12
+ -- before this branch added the column -- has a null definition_id that only the
13
+ -- deployment -> asset -> definition join can resolve; migration 0055 fills the
14
+ -- anchor runs it inserts but never touches these existing rows, and
15
+ -- workflow_deployment is the only place their mapping survives. asset_id is
16
+ -- unique per definition, so the join matches at most one definition per run.
17
+ UPDATE "workflow_run" r
18
+ SET definition_id = wdef.id
19
+ FROM "workflow_deployment" wd
20
+ JOIN "workflow_definition" wdef ON wdef.asset_id = wd.definition_asset_id
21
+ WHERE r.deployment_id = wd.id
22
+ AND r.definition_id IS NULL;
23
+ --> statement-breakpoint
24
+ ALTER TABLE "approval" DROP CONSTRAINT "approval_deployment_id_workflow_deployment_id_fk";
25
+ --> statement-breakpoint
26
+ ALTER TABLE "signal_correlation" DROP CONSTRAINT "signal_correlation_deployment_id_workflow_deployment_id_fk";
27
+ --> statement-breakpoint
28
+ ALTER TABLE "workflow_run" DROP CONSTRAINT "workflow_run_deployment_id_workflow_deployment_id_fk";
29
+ --> statement-breakpoint
30
+ ALTER TABLE "approval" ADD CONSTRAINT "approval_deployment_id_workflow_run_id_fk" FOREIGN KEY ("deployment_id") REFERENCES "public"."workflow_run"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
31
+ ALTER TABLE "signal_correlation" ADD CONSTRAINT "signal_correlation_deployment_id_workflow_run_id_fk" FOREIGN KEY ("deployment_id") REFERENCES "public"."workflow_run"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
32
+ ALTER TABLE "workflow_run" ADD CONSTRAINT "workflow_run_deployment_id_workflow_run_id_fk" FOREIGN KEY ("deployment_id") REFERENCES "public"."workflow_run"("id") ON DELETE cascade ON UPDATE no action;
@@ -0,0 +1,22 @@
1
+ -- Drop the workflow_deployment projection. Its routing identity, reconnect key,
2
+ -- and status now live on the anchor run, its foreign keys were re-pointed onto
3
+ -- the anchor run, and nothing reads or writes it. This is irreversible.
4
+ --
5
+ -- Promote workflow_run.definition_id to NOT NULL: every run now carries a
6
+ -- definition (set at birth for new runs, filled by 0056 for the rows the
7
+ -- projection anchored). The guard below aborts before writing anything if any
8
+ -- run is still null -- that means the workflow-asset fold has not run, and
9
+ -- dropping the projection would strand those rows with no way to resolve their
10
+ -- definition. A blunt IS NULL check catches every class, including a run with a
11
+ -- null deployment_id the deployment join could never reach. Abort loudly so the
12
+ -- operator runs the fold and retries.
13
+ DO $$
14
+ BEGIN
15
+ IF EXISTS (SELECT 1 FROM "workflow_run" WHERE definition_id IS NULL) THEN
16
+ RAISE EXCEPTION 'workflow_run rows without a definition remain; run the workflow-asset fold (bin/db-backfill) before applying this migration';
17
+ END IF;
18
+ END $$;
19
+ --> statement-breakpoint
20
+ ALTER TABLE "workflow_run" ALTER COLUMN "definition_id" SET NOT NULL;
21
+ --> statement-breakpoint
22
+ DROP TABLE "workflow_deployment";
@@ -0,0 +1,41 @@
1
+ -- Re-point the offering foreign key off the agent onto the folded workflow
2
+ -- definition. The column keeps its agent_id name -- the offering API exposes
3
+ -- agentId -- but its values become workflow_definition ids: every agent was
4
+ -- folded to exactly one definition, linked by workflow_definition.origin_agent_id
5
+ -- (a partial unique index, so the join matches at most one definition).
6
+ --
7
+ -- The guard runs before any write. The production path applies migrations under
8
+ -- `drizzle-kit migrate`, which wraps the pending set in a transaction, and
9
+ -- PostgreSQL DDL is transactional, so an aborting guard rolls the whole set
10
+ -- back -- there is no partial commit to defend against. It aborts loudly if any
11
+ -- offering's agent has no folded definition, meaning the agent fold has not
12
+ -- run; the total fold makes that impossible in a folded database, so the guard
13
+ -- is a fail-loud assertion.
14
+ DO $$
15
+ BEGIN
16
+ IF EXISTS (
17
+ SELECT 1
18
+ FROM "offering" o
19
+ WHERE NOT EXISTS (
20
+ SELECT 1 FROM "workflow_definition" wd
21
+ WHERE wd.origin_agent_id = o.agent_id
22
+ )
23
+ ) THEN
24
+ RAISE EXCEPTION 'offering(s) reference an agent with no folded definition; run the agent fold (bin/db-backfill) before applying this migration';
25
+ END IF;
26
+ END $$;
27
+ --> statement-breakpoint
28
+ -- Drop the old agent foreign key BEFORE rewriting the values: the rewrite sets
29
+ -- agent_id to a workflow_definition id, which is not an agent id, so it would
30
+ -- violate the still-active agent FK. The offering table was renamed from
31
+ -- `capability` (migration 0004); Postgres does not rename constraints on a
32
+ -- table rename, so its agent FK still carries the original `capability_`-
33
+ -- prefixed name, not the `offering_`-prefixed name drizzle's snapshot infers.
34
+ ALTER TABLE "offering" DROP CONSTRAINT "capability_agent_id_agent_id_fk";
35
+ --> statement-breakpoint
36
+ UPDATE "offering" o
37
+ SET agent_id = wd.id
38
+ FROM "workflow_definition" wd
39
+ WHERE wd.origin_agent_id = o.agent_id;
40
+ --> statement-breakpoint
41
+ ALTER TABLE "offering" ADD CONSTRAINT "offering_agent_id_workflow_definition_id_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."workflow_definition"("id") ON DELETE restrict ON UPDATE no action;
@@ -0,0 +1,10 @@
1
+ -- Re-point the transaction ledger off the agent onto the run that incurs a
2
+ -- charge. The table is unwritten (no producer), so there is no data to migrate
3
+ -- and no contract to preserve: rename agent_id to run_id and reference
4
+ -- workflow_run, keeping the nullable set-null delete so ledger history survives
5
+ -- the deletion of the run it references.
6
+ ALTER TABLE "transaction" RENAME COLUMN "agent_id" TO "run_id";
7
+ --> statement-breakpoint
8
+ ALTER TABLE "transaction" DROP CONSTRAINT "transaction_agent_id_agent_id_fk";
9
+ --> statement-breakpoint
10
+ ALTER TABLE "transaction" ADD CONSTRAINT "transaction_run_id_workflow_run_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."workflow_run"("id") ON DELETE set null ON UPDATE no action;
@@ -0,0 +1,6 @@
1
+ -- Drop session_mail's foreign key to agent_instance. instance_id becomes a
2
+ -- bare polymorphic column -- a legacy agent_instance id, or null for a folded
3
+ -- run -- mirroring inference_turn.instance_id (migration 0052). A folded run's
4
+ -- id comes from a shared id space that agent_instance does not contain, so no
5
+ -- single-table foreign key spans both.
6
+ ALTER TABLE "session_mail" DROP CONSTRAINT "session_mail_instance_id_agent_instance_id_fk";
@@ -0,0 +1,7 @@
1
+ -- Drop session_asset's foreign key to agent_instance. instance_id becomes a
2
+ -- bare polymorphic column -- a legacy agent_instance id or a folded run id --
3
+ -- mirroring inference_turn.instance_id (migration 0052). A folded launch
4
+ -- already writes its workflow_run id here, which the agent_instance FK rejected,
5
+ -- so this also unblocks attaching assets to a folded run. instance_id stays NOT
6
+ -- NULL and part of the (instance_id, mount_path) primary key.
7
+ ALTER TABLE "session_asset" DROP CONSTRAINT "session_asset_instance_id_agent_instance_id_fk";
@@ -0,0 +1,11 @@
1
+ -- Drop the agent_asset table. Manual attach-to-an-agent was never wired,
2
+ -- so the table has no writer and is empty, and the launch-time direct
3
+ -- attachment path that read it is gone. session_asset's agent_asset_id
4
+ -- foreign key and its source column only distinguished direct attachments
5
+ -- from resolver-derived materializations; with the direct path gone every
6
+ -- row is resolver-derived, so both are dead. Drop the two columns first --
7
+ -- dropping agent_asset_id takes its foreign key with it -- so the table
8
+ -- has no remaining dependents when it goes (no CASCADE needed).
9
+ ALTER TABLE "session_asset" DROP COLUMN "agent_asset_id";--> statement-breakpoint
10
+ ALTER TABLE "session_asset" DROP COLUMN "source";--> statement-breakpoint
11
+ DROP TABLE "agent_asset";