capacity part 4: drop the central global_concurrency table (migration 0037) (#2555)

Final piece of the cross-project cap removal. Enforcement (#2509),
settings/API/UI (#2529) are merged; this removes the storage.

Nothing read the table. `global_max_concurrent` held the deleted
machine-wide cap; `currently_active`/`queued_count` were written only by
`acquireGlobalSlot`/`releaseGlobalSlot`, measured earlier in this
program to have **no production caller**, so those counters were
fiction. Live “N running (all projects)” telemetry comes from
`CentralCore.getLiveRunningAgentCounts` and is unaffected.

Dropped rather than left unread: a lingering table with
plausible-looking counters invites a future reader to trust it — the
same trap as a readable-but-ignored settings key.

## The trap this hit, because the first attempt looked correct

`schema-applier.ts` warns that *“migrations are registered here
explicitly (not auto-discovered from the migrations dir), so a new .sql
file that is not wired through a version constant + bookkeeping check
silently never runs.”*

My first pass added the `.sql`, updated the drizzle model and bumped the
baseline — **and the table was still present in a fresh database**. It
was caught only because the test asserts the table is *gone*
(`to_regclass(...) IS NULL`) rather than merely unreferenced; an
absence-of-reference assertion would have passed while the table
survived.

Now registered properly: `DROP_GLOBAL_CONCURRENCY_VERSION = "0037"`,
explicit path constant, applied-check, bookkeeping insert.

The historical `0000` baseline is deliberately **not** rewritten — a
fresh database CREATEs the table then drops it, converging with upgraded
databases without editing history, which is how every prior migration
here behaves.

Also removed: the drizzle model, the `centralTableNames` entry, and the
`replacesCentralSeed` special case in the SQLite migrator (a legacy
SQLite `globalConcurrency` table now has no destination and is simply
not migrated — correct, since its cap is deleted and its counters were
never written).

## Verification

`pnpm lint` clean · core `tsc` clean · `pnpm test:gate` green (414 + 10
+ 71) · `schema-applier` 75/75 · `sqlite-migrator` 43/43 · full core PG
suite **1044 passed / 3 failed** — the same 3 pre-existing
(`central-archive-secrets` log-prefix,
`workflow-settings-project-identity` legacy fallback ×2).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-07-29 10:15:42 -07:00
committed by GitHub
parent 3da5358b33
commit 969c2cdf1d
7 changed files with 97 additions and 20 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Remove the unused cross-project concurrency table from the central database.
category: internal
dev: Migration 0037 drops `central.global_concurrency`. Nothing read it after the cap was removed: `global_max_concurrent` held the deleted machine-wide limit, and `currently_active`/`queued_count` were maintained only by `acquireGlobalSlot`/`releaseGlobalSlot`, which had no production caller. `SCHEMA_BASELINE_VERSION` advances to 0037 and the migration is explicitly registered in `schema-applier.ts` (migrations are not auto-discovered). The historical 0000 baseline is left untouched, so a fresh database creates the table and then drops it, converging with upgraded databases. Live cross-project telemetry is unaffected — it comes from `CentralCore.getLiveRunningAgentCounts`.

View File

@@ -79,6 +79,7 @@ import {
MILESTONE_ASSERTION_PROVENANCE_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION,
MISSION_LINEAGE_STOP_VERSION, MISSION_LINEAGE_STOP_VERSION,
CHAT_SESSION_TAGS_VERSION, CHAT_SESSION_TAGS_VERSION,
DROP_GLOBAL_CONCURRENCY_VERSION,
} from "../../postgres/schema-applier.js"; } from "../../postgres/schema-applier.js";
import { ProjectPartitionRekeyError, rekeyFallbackProjectPartition } from "../../postgres/migration-stamping.js"; import { ProjectPartitionRekeyError, rekeyFallbackProjectPartition } from "../../postgres/migration-stamping.js";
import type { PluginSchemaInitHook } from "../../postgres/plugin-schema-hook.js"; import type { PluginSchemaInitHook } from "../../postgres/plugin-schema-hook.js";
@@ -681,7 +682,7 @@ pgDescribe("schema-applier: VAL-SCHEMA-001 final-schema parity (table counts)",
ctx = null; ctx = null;
}); });
it("creates all 96 project tables, 18 central tables, 1 archive table", async () => { it("creates all 96 project tables, 17 central tables, 1 archive table", async () => {
ctx = await setupFreshDb(); ctx = await setupFreshDb();
// FNXC:PostgresCutover 2026-07-05-15:55: apply the BASELINE only. // FNXC:PostgresCutover 2026-07-05-15:55: apply the BASELINE only.
// applySchemaBaseline now runs the plugin schema-init hooks by default, // applySchemaBaseline now runs the plugin schema-init hooks by default,
@@ -704,7 +705,13 @@ pgDescribe("schema-applier: VAL-SCHEMA-001 final-schema parity (table counts)",
// + 1 mission_lineage_stops (FNXC:MissionLineageBudget FN-8543 / migration 0035). // + 1 mission_lineage_stops (FNXC:MissionLineageBudget FN-8543 / migration 0035).
// Plugin tables are added separately by the hook. // Plugin tables are added separately by the hook.
expect(bySchema.project).toBe(98); expect(bySchema.project).toBe(98);
expect(bySchema.central).toBe(18); /*
FNXC:CapacityModel 2026-07-29-08:10 (drop the cross-project cap — table half):
17, not 18: `central.global_concurrency` is dropped by migration 0037. A fresh
database still CREATEs it from the historical 0000 baseline and then drops it,
so fresh and upgraded databases converge on the same shape.
*/
expect(bySchema.central).toBe(17);
expect(bySchema.archive).toBe(1); expect(bySchema.archive).toBe(1);
}); });
@@ -1669,6 +1676,7 @@ pgDescribe("schema-applier: automation project-isolation upgrade", () => {
MILESTONE_ASSERTION_PROVENANCE_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION,
MISSION_LINEAGE_STOP_VERSION, MISSION_LINEAGE_STOP_VERSION,
CHAT_SESSION_TAGS_VERSION, CHAT_SESSION_TAGS_VERSION,
DROP_GLOBAL_CONCURRENCY_VERSION,
]); ]);
expect((await applySchemaBaseline(ctx.db, { pluginHooks: [] })).applied).toBe(false); expect((await applySchemaBaseline(ctx.db, { pluginHooks: [] })).applied).toBe(false);
}); });
@@ -1731,6 +1739,7 @@ pgDescribe("schema-applier: automation project-isolation upgrade", () => {
MILESTONE_ASSERTION_PROVENANCE_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION,
MISSION_LINEAGE_STOP_VERSION, MISSION_LINEAGE_STOP_VERSION,
CHAT_SESSION_TAGS_VERSION, CHAT_SESSION_TAGS_VERSION,
DROP_GLOBAL_CONCURRENCY_VERSION,
]); ]);
}); });
@@ -1926,6 +1935,7 @@ pgDescribe("schema-applier: automation project-isolation upgrade", () => {
MILESTONE_ASSERTION_PROVENANCE_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION,
MISSION_LINEAGE_STOP_VERSION, MISSION_LINEAGE_STOP_VERSION,
CHAT_SESSION_TAGS_VERSION, CHAT_SESSION_TAGS_VERSION,
DROP_GLOBAL_CONCURRENCY_VERSION,
]); ]);
}); });
@@ -2002,6 +2012,7 @@ pgDescribe("schema-applier: automation project-isolation upgrade", () => {
MILESTONE_ASSERTION_PROVENANCE_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION,
MISSION_LINEAGE_STOP_VERSION, MISSION_LINEAGE_STOP_VERSION,
CHAT_SESSION_TAGS_VERSION, CHAT_SESSION_TAGS_VERSION,
DROP_GLOBAL_CONCURRENCY_VERSION,
]); ]);
}); });
@@ -2078,6 +2089,7 @@ pgDescribe("schema-applier: automation project-isolation upgrade", () => {
MILESTONE_ASSERTION_PROVENANCE_VERSION, MILESTONE_ASSERTION_PROVENANCE_VERSION,
MISSION_LINEAGE_STOP_VERSION, MISSION_LINEAGE_STOP_VERSION,
CHAT_SESSION_TAGS_VERSION, CHAT_SESSION_TAGS_VERSION,
DROP_GLOBAL_CONCURRENCY_VERSION,
]); ]);
}); });
}); });

View File

@@ -1134,12 +1134,10 @@ pgDescribe("SQLite-to-PostgreSQL migrator", () => {
try { try {
legacy.exec(` legacy.exec(`
CREATE TABLE centralSettings (id INTEGER PRIMARY KEY, defaultProjectId TEXT, updatedAt TEXT NOT NULL); CREATE TABLE centralSettings (id INTEGER PRIMARY KEY, defaultProjectId TEXT, updatedAt TEXT NOT NULL);
CREATE TABLE globalConcurrency (id INTEGER PRIMARY KEY, globalMaxConcurrent INTEGER, currentlyActive INTEGER, queuedCount INTEGER, updatedAt TEXT);
CREATE TABLE plugin_installs (id TEXT PRIMARY KEY, name TEXT NOT NULL, version TEXT NOT NULL, path TEXT NOT NULL, createdAt TEXT NOT NULL, updatedAt TEXT NOT NULL); CREATE TABLE plugin_installs (id TEXT PRIMARY KEY, name TEXT NOT NULL, version TEXT NOT NULL, path TEXT NOT NULL, createdAt TEXT NOT NULL, updatedAt TEXT NOT NULL);
CREATE TABLE project_plugin_states (projectPath TEXT NOT NULL, pluginId TEXT NOT NULL, enabled INTEGER NOT NULL, state TEXT NOT NULL, error TEXT, createdAt TEXT NOT NULL, updatedAt TEXT NOT NULL, PRIMARY KEY (projectPath, pluginId)); CREATE TABLE project_plugin_states (projectPath TEXT NOT NULL, pluginId TEXT NOT NULL, enabled INTEGER NOT NULL, state TEXT NOT NULL, error TEXT, createdAt TEXT NOT NULL, updatedAt TEXT NOT NULL, PRIMARY KEY (projectPath, pluginId));
`); `);
legacy.prepare(`INSERT INTO centralSettings VALUES (?, ?, ?)`).run(1, "project-default", "2026-06-01"); legacy.prepare(`INSERT INTO centralSettings VALUES (?, ?, ?)`).run(1, "project-default", "2026-06-01");
legacy.prepare(`INSERT INTO globalConcurrency VALUES (?, ?, ?, ?, ?)`).run(1, 10, 0, 0, "2026-06-02");
legacy.prepare(`INSERT INTO plugin_installs VALUES (?, ?, ?, ?, ?, ?)`).run("plugin-a", "A", "1.0.0", "/a", "2026-06-01", "2026-06-01"); legacy.prepare(`INSERT INTO plugin_installs VALUES (?, ?, ?, ?, ?, ?)`).run("plugin-a", "A", "1.0.0", "/a", "2026-06-01", "2026-06-01");
legacy.prepare(`INSERT INTO plugin_installs VALUES (?, ?, ?, ?, ?, ?)`).run("plugin-b", "B", "1.0.0", "/b", "2026-06-01", "2026-06-01"); legacy.prepare(`INSERT INTO plugin_installs VALUES (?, ?, ?, ?, ?, ?)`).run("plugin-b", "B", "1.0.0", "/b", "2026-06-01", "2026-06-01");
const insertState = legacy.prepare(`INSERT INTO project_plugin_states VALUES (?, ?, ?, ?, ?, ?, ?)`); const insertState = legacy.prepare(`INSERT INTO project_plugin_states VALUES (?, ?, ?, ?, ?, ?, ?)`);
@@ -1152,17 +1150,26 @@ pgDescribe("SQLite-to-PostgreSQL migrator", () => {
const report = await migrateTest(ctx!.db, [ const report = await migrateTest(ctx!.db, [
{ sqlitePath, pgSchema: "central" as const }, { sqlitePath, pgSchema: "central" as const },
]); ]);
for (const table of ["central_settings", "global_concurrency", "project_plugin_states"]) { /*
FNXC:CapacityModel 2026-07-29-08:10 (drop the cross-project cap — table half):
`global_concurrency` leaves this list with the table itself (migration 0037).
A legacy SQLite `globalConcurrency` table now has no destination and is simply
not migrated, which is the intent: its cap is deleted and its
currently_active/queued_count counters were never written by production code.
*/
for (const table of ["central_settings", "project_plugin_states"]) {
expect(report.tables).toContainEqual(expect.objectContaining({ table, verified: true })); expect(report.tables).toContainEqual(expect.objectContaining({ table, verified: true }));
} }
const settings = await ctx!.db.execute(sql` const settings = await ctx!.db.execute(sql`
SELECT default_project_id, updated_at FROM central.central_settings WHERE id = 1 SELECT default_project_id, updated_at FROM central.central_settings WHERE id = 1
`) as unknown as Array<{ default_project_id: string; updated_at: string }>; `) as unknown as Array<{ default_project_id: string; updated_at: string }>;
expect(settings).toEqual([{ default_project_id: "project-default", updated_at: "2026-06-01" }]); expect(settings).toEqual([{ default_project_id: "project-default", updated_at: "2026-06-01" }]);
const concurrency = await ctx!.db.execute(sql` // The dropped table must be GONE, not merely unread — a lingering table with
SELECT global_max_concurrent, updated_at FROM central.global_concurrency WHERE id = 1 // plausible counters invites a future reader to trust it.
`) as unknown as Array<{ global_max_concurrent: number; updated_at: string }>; const remaining = await ctx!.db.execute(sql`
expect(concurrency).toEqual([{ global_max_concurrent: 10, updated_at: "2026-06-02" }]); SELECT to_regclass('central.global_concurrency') AS present
`) as unknown as Array<{ present: string | null }>;
expect(remaining[0]?.present ?? null).toBeNull();
}); });
/* /*

View File

@@ -0,0 +1,20 @@
-- FNXC:CapacityModel 2026-07-29-08:10 (drop the cross-project cap — table half):
-- Capacity is two numbers PER PROJECT (total agents + max worktrees). The
-- machine-wide cap lived here, in a central singleton row that every runtime
-- subscribed to and periodically re-reconciled against the per-project gates.
--
-- The enforcement and the settings/API/UI halves are already gone. Nothing reads
-- this table: `global_max_concurrent` held the deleted cap, and
-- `currently_active` / `queued_count` were maintained by acquireGlobalSlot /
-- releaseGlobalSlot, which were MEASURED to have no production caller at all —
-- the durable counters were fiction, which is why no operator ever saw the cap
-- bind through them.
--
-- Live "N running (all projects)" telemetry is unaffected: it derives from
-- CentralCore.getLiveRunningAgentCounts via the registered side-effect-safe
-- source, never from this table.
--
-- Dropped rather than left in place: an unread table with plausible-looking
-- counters invites a future reader to trust it, which is the same trap as a
-- readable-but-ignored settings key.
DROP TABLE IF EXISTS central.global_concurrency;

View File

@@ -42,7 +42,7 @@ SCHEMA_BASELINE_VERSION advances to 0031 for durable, single-owner task
continuations at workflow column boundaries. continuations at workflow column boundaries.
FNXC:LegacyAdoption 2026-07-21-17:30: FNXC:LegacyAdoption 2026-07-21-17:30:
SCHEMA_BASELINE_VERSION advances to 0036 for normalized Direct conversation tags; it previously advanced to 0032 for fusion_runtime SELECT + SCHEMA_BASELINE_VERSION advances to 0037 for dropping the cross-project concurrency table; it previously advanced to 0036 for normalized Direct conversation tags; it previously advanced to 0032 for fusion_runtime SELECT +
SECURITY DEFINER write access to the legacy-adoption drained marker. SECURITY DEFINER write access to the legacy-adoption drained marker.
FNXC:TaskWedgeNotifications 2026-10-19-00:00: FNXC:TaskWedgeNotifications 2026-10-19-00:00:
@@ -50,7 +50,7 @@ Advance the PostgreSQL schema ceiling for the durable wedge episode column. The
forward migration must run before TaskStore writes the new field on fresh and forward migration must run before TaskStore writes the new field on fresh and
upgraded databases. upgraded databases.
*/ */
export const SCHEMA_BASELINE_VERSION = "0036"; export const SCHEMA_BASELINE_VERSION = "0037";
/** FNXC:SymbolLock 2026-07-31-10:00: upgrades need durable task declarations before admission resolves symbols. */ /** FNXC:SymbolLock 2026-07-31-10:00: upgrades need durable task declarations before admission resolves symbols. */
export const TASK_DECLARED_SYMBOLS_VERSION = "0028"; export const TASK_DECLARED_SYMBOLS_VERSION = "0028";
const INITIAL_SCHEMA_VERSION = "0000"; const INITIAL_SCHEMA_VERSION = "0000";
@@ -152,6 +152,14 @@ export const MILESTONE_ASSERTION_PROVENANCE_VERSION = "0034";
export const MISSION_LINEAGE_STOP_VERSION = "0035"; export const MISSION_LINEAGE_STOP_VERSION = "0035";
/** FNXC:ChatTags 2026-08-05-10:55: existing clusters need normalized project-scoped Direct conversation tags. */ /** FNXC:ChatTags 2026-08-05-10:55: existing clusters need normalized project-scoped Direct conversation tags. */
export const CHAT_SESSION_TAGS_VERSION = "0036"; export const CHAT_SESSION_TAGS_VERSION = "0036";
/*
FNXC:CapacityModel 2026-07-29-08:10 (drop the cross-project cap — table half):
Drops `central.global_concurrency`. Registered EXPLICITLY, per this file's own
warning that migrations are not auto-discovered and an unwired .sql silently never
runs — which is exactly what happened on the first attempt here: the file existed,
the model was updated, and the table was still present in a fresh database.
*/
export const DROP_GLOBAL_CONCURRENCY_VERSION = "0037";
/** SECURITY DEFINER helper that only inserts LEGACY_ADOPTION_DRAINED_MARKER. */ /** SECURITY DEFINER helper that only inserts LEGACY_ADOPTION_DRAINED_MARKER. */
export const LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION = "fusion_mark_legacy_adoption_drained"; export const LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION = "fusion_mark_legacy_adoption_drained";
@@ -362,6 +370,7 @@ const MILESTONE_ASSERTION_PROVENANCE_MIGRATION_PATH = join(
); );
const MISSION_LINEAGE_STOP_MIGRATION_PATH = join(MIGRATIONS_DIR, "0035_fn_8543_mission_lineage_stop.sql"); const MISSION_LINEAGE_STOP_MIGRATION_PATH = join(MIGRATIONS_DIR, "0035_fn_8543_mission_lineage_stop.sql");
const CHAT_SESSION_TAGS_MIGRATION_PATH = join(MIGRATIONS_DIR, "0036_chat_session_tags.sql"); const CHAT_SESSION_TAGS_MIGRATION_PATH = join(MIGRATIONS_DIR, "0036_chat_session_tags.sql");
const DROP_GLOBAL_CONCURRENCY_MIGRATION_PATH = join(MIGRATIONS_DIR, "0037_drop_global_concurrency.sql");
/** /**
* Ensure the migration bookkeeping table exists. Lives in the public schema so * Ensure the migration bookkeeping table exists. Lives in the public schema so
@@ -468,6 +477,7 @@ export async function applySchemaBaseline(
const milestoneAssertionProvenanceAlreadyApplied = applied.includes(MILESTONE_ASSERTION_PROVENANCE_VERSION); const milestoneAssertionProvenanceAlreadyApplied = applied.includes(MILESTONE_ASSERTION_PROVENANCE_VERSION);
const missionLineageStopAlreadyApplied = applied.includes(MISSION_LINEAGE_STOP_VERSION); const missionLineageStopAlreadyApplied = applied.includes(MISSION_LINEAGE_STOP_VERSION);
const chatSessionTagsAlreadyApplied = applied.includes(CHAT_SESSION_TAGS_VERSION); const chatSessionTagsAlreadyApplied = applied.includes(CHAT_SESSION_TAGS_VERSION);
const dropGlobalConcurrencyAlreadyApplied = applied.includes(DROP_GLOBAL_CONCURRENCY_VERSION);
assertBinaryNotOlderThanDatabase(applied); assertBinaryNotOlderThanDatabase(applied);
let schemaChanged = false; let schemaChanged = false;
@@ -989,6 +999,20 @@ export async function applySchemaBaseline(
schemaChanged = true; schemaChanged = true;
} }
/*
FNXC:CapacityModel 2026-07-29-08:10 (drop the cross-project cap — table half):
Runs after the baseline on BOTH fresh and upgrade databases. A fresh database
still CREATEs the table from 0000_initial (the historical baseline is left
untouched, as every prior migration does) and then drops it here, so both paths
converge on the same shape without rewriting history.
*/
if (!dropGlobalConcurrencyAlreadyApplied) {
const migrationSql = await readFile(DROP_GLOBAL_CONCURRENCY_MIGRATION_PATH, "utf8");
await tx.execute(sql.raw(migrationSql));
await tx.execute(sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${DROP_GLOBAL_CONCURRENCY_VERSION}) ON CONFLICT (version) DO NOTHING`);
schemaChanged = true;
}
return { applied: schemaChanged, pluginHooksRun: pluginHooks.length }; return { applied: schemaChanged, pluginHooksRun: pluginHooks.length };
}); });
} }

View File

@@ -123,13 +123,14 @@ export const centralActivityLog = centralSchema.table("central_activity_log", {
]); ]);
// ── Global concurrency state (single row) ──────────────────────────── // ── Global concurrency state (single row) ────────────────────────────
export const globalConcurrency = centralSchema.table("global_concurrency", { /*
id: integer("id").primaryKey(), FNXC:CapacityModel 2026-07-29-08:10 (drop the cross-project cap — table half):
globalMaxConcurrent: integer("global_max_concurrent").default(4), The `global_concurrency` singleton table is DELETED (migration 0037). It held the
currentlyActive: integer("currently_active").default(0), machine-wide agent cap plus currently_active/queued_count counters whose only
queuedCount: integer("queued_count").default(0), writers — acquireGlobalSlot/releaseGlobalSlot — had no production caller. Capacity
updatedAt: text("updated_at"), is two numbers PER PROJECT; live cross-project telemetry comes from
}, (t) => [check("global_concurrency_id_check", sql`${t.id} = 1`)]); CentralCore.getLiveRunningAgentCounts, never from a persisted counter.
*/
// ── Central settings (single row) ──────────────────────────────────── // ── Central settings (single row) ────────────────────────────────────
export const centralSettings = centralSchema.table("central_settings", { export const centralSettings = centralSchema.table("central_settings", {
@@ -337,7 +338,7 @@ export const centralMeta = centralSchema.table("__meta", {
*/ */
export const centralTableNames = [ export const centralTableNames = [
"projects", "nodes", "project_node_path_mappings", "project_health", "projects", "nodes", "project_node_path_mappings", "project_health",
"central_activity_log", "global_concurrency", "central_settings", "central_activity_log", "central_settings",
"peer_nodes", "settings_sync_state", "managed_docker_nodes", "peer_nodes", "settings_sync_state", "managed_docker_nodes",
"plugin_installs", "project_plugin_states", "mesh_shared_snapshots", "plugin_installs", "project_plugin_states", "mesh_shared_snapshots",
"mesh_write_queue", "secrets_global", "task_claims", "global_routines", "__meta", "mesh_write_queue", "secrets_global", "task_claims", "global_routines", "__meta",

View File

@@ -2022,7 +2022,13 @@ async function insertBatch(
*/ */
const replacesCentralSeed = const replacesCentralSeed =
plan.pgSchema === CENTRAL_SCHEMA && plan.pgSchema === CENTRAL_SCHEMA &&
(plan.pgTable === "central_settings" || plan.pgTable === "global_concurrency"); /*
FNXC:CapacityModel 2026-07-29-08:10 (drop the cross-project cap — table half):
`global_concurrency` is no longer a destination: the table is dropped and its
drizzle model is gone, so no plan targets it. Only `central_settings` still
needs seed-replacing semantics.
*/
plan.pgTable === "central_settings";
const isSharedSingleton = isSharedSingletonTable(plan.pgSchema, plan.pgTable); const isSharedSingleton = isSharedSingletonTable(plan.pgSchema, plan.pgTable);
const conflictClause = replacesCentralSeed const conflictClause = replacesCentralSeed
? sql.raw(`ON CONFLICT (${quoteIdent("id")}) DO UPDATE SET ${cols ? sql.raw(`ON CONFLICT (${quoteIdent("id")}) DO UPDATE SET ${cols