History

Rename integration.tools_revised_at → config_revised_at

Tools are materialized per connection (the tool rows are keyed by owner/integration/connection); an integration has no tools, it has the config that derives them. So the integration-side staleness marker is about the config that changed, not the tools — name it for the cause. The connection keeps tools_synced_at, which is accurate (connections do have tools). The comparison now reads tools_synced_at < config_revised_at: 'this connection's tools predate the current config'. Pre-release column, so the cloud migration + snapshot are edited in place; the libSQL/D1 hosts pick up the new name via boot schema-ensure.

Rhys Sullivan committed 4 months ago

Commit c03bdb11 parent 4803f0c8 files · +15 −15Browse files

Unified · Split

8 files
  1. apps/cloud/drizzle/0003_warm_jimmy_woo.sql +1 −1
  2. apps/cloud/drizzle/meta/0003_snapshot.json +2 −2
  3. apps/cloud/src/db/executor-schema.ts +1 −1
  4. e2e/cloud/spec-update-convergence.test.ts +1 −1
  5. packages/core/fumadb/src/adapters/drizzle/runtime-ensure.test.ts +3 −3
  6. packages/core/sdk/src/core-schema.ts +2 −2
  7. packages/core/sdk/src/executor.ts +4 −4
  8. vendor/emulate +1 −1
apps/cloud/drizzle/0003_warm_jimmy_woo.sql+1−1
@@ -1,4 +1,4 @@
11 ALTER TABLE "connection" ADD COLUMN "description" text;--> statement-breakpoint
22 ALTER TABLE "connection" ADD COLUMN "tools_synced_at" bigint;--> statement-breakpoint
33 ALTER TABLE "integration" ADD COLUMN "name" text;--> statement-breakpoint
4−ALTER TABLE "integration" ADD COLUMN "tools_revised_at" bigint;
4+ALTER TABLE "integration" ADD COLUMN "config_revised_at" bigint;
apps/cloud/drizzle/meta/0003_snapshot.json+2−2
@@ -497,8 +497,8 @@ · 496 unmodified lines
497497 "primaryKey": false,
498498 "notNull": true
499499 },
500− "tools_revised_at": {
501− "name": "tools_revised_at",
500+ "config_revised_at": {
501+ "name": "config_revised_at",
502502 "type": "bigint",
503503 "primaryKey": false,
504504 "notNull": false
apps/cloud/src/db/executor-schema.ts+1−1
@@ -17,7 +17,7 @@ export const integration = pgTable( · 16 unmodified lines
1717 plugin_id: text("plugin_id").notNull(),
1818 name: text("name"),
1919 description: text("description").notNull(),
20− tools_revised_at: bigint("tools_revised_at", { mode: "bigint" }),
20+ config_revised_at: bigint("config_revised_at", { mode: "bigint" }),
2121 config: json("config"),
2222 can_remove: boolean("can_remove").notNull().default(true),
2323 can_refresh: boolean("can_refresh").notNull().default(false),
e2e/cloud/spec-update-convergence.test.ts+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
33 // the new tool catalog on that member's next read — not just the editor's.
44 //
55 // This is the lazy-convergence design. Tools are stored per connection. The
6−// editor stamps the integration's `tools_revised_at`, but the owner policy lets
6+// editor stamps the integration's `config_revised_at`, but the owner policy lets
77 // them rebuild catalogs only in their own partition — they cannot write a
88 // co-worker's personal connection rows. So each member's connection carries a
99 // `tools_synced_at` and rebuilds itself the next time THAT member lists tools.
packages/core/fumadb/src/adapters/drizzle/runtime-ensure.test.ts+3−3
@@ -23,13 +23,13 @@ const v1Tables = { · 22 unmodified lines
2323 };
2424
2525 // The running schema adds two nullable columns the old file predates — the
26−// shape of the integration-descriptions feature (name + tools_revised_at).
26+// shape of the integration-descriptions feature (name + config_revised_at).
2727 const v2Tables = {
2828 integration: table("integration", {
2929 id: idColumn("id", "varchar(255)"),
3030 slug: column("slug", "varchar(255)"),
3131 name: column("name", "string").nullable(),
32− tools_revised_at: column("tools_revised_at", "bigint").nullable(),
32+ config_revised_at: column("config_revised_at", "bigint").nullable(),
3333 }),
3434 };
3535
@@ -69,7 +69,7 @@ test("ensure evolves an existing table with the schema's new nullable columns", · 33 unmodified lines
6969 });
7070 const evolved = await columnNames(client);
7171 expect(evolved).toContain("name");
72− expect(evolved).toContain("tools_revised_at");
72+ expect(evolved).toContain("config_revised_at");
7373
7474 // Idempotent: a second boot tolerates the now-duplicate columns.
7575 await ensureDrizzleRuntimeSchemaFromTables(db, {
packages/core/sdk/src/core-schema.ts+2−2
@@ -129,7 +129,7 @@ export const coreTables = defineTables({ · 128 unmodified lines
129129 // template edit). Compared against each connection's `tools_synced_at`
130130 // so OTHER subjects' connections — whose tool rows the updater cannot
131131 // write under the owner policy — lazily rebuild on their next read.
132− tools_revised_at: nullableBigintColumn("tools_revised_at"),
132+ config_revised_at: nullableBigintColumn("config_revised_at"),
133133 can_remove: boolColumn("can_remove", true),
134134 can_refresh: boolColumn("can_refresh", false),
135135 created_at: dateColumn("created_at"),
@@ -156,7 +156,7 @@ export const coreTables = defineTables({ · 20 unmodified lines
156156 // create, editable after; never reset by OAuth re-mints.
157157 description: nullableTextColumn("description"),
158158 // Epoch ms of the last tool (re)production for this connection. Stale
159− // vs the integration's `tools_revised_at` → re-produced on next read.
159+ // vs the integration's `config_revised_at` → re-produced on next read.
160160 tools_synced_at: nullableBigintColumn("tools_synced_at"),
161161 oauth_client: nullableTextColumn("oauth_client"),
162162 // The OWNER of `oauth_client` (a Personal connection may be minted through
packages/core/sdk/src/executor.ts+4−4
@@ -1759,7 +1759,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea · 1758 unmodified lines
17591759 // rebuild catalogs in its own partition (owner policy), so revise
17601760 // the integration: other subjects' connections compare this stamp
17611761 // against their `tools_synced_at` and lazily rebuild on next read.
1762− set.tools_revised_at = now.getTime();
1762+ set.config_revised_at = now.getTime();
17631763 }
17641764 yield* core.updateMany("integration", {
17651765 where: (b: AnyCb) => b("slug", "=", String(slug)),
@@ -1837,7 +1837,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea · 71 unmodified lines
18371837 b("connection", "=", String(ref.name)),
18381838 );
18391839 // Every exit stamps the sync time — including the cleanup paths that
1840− // produce zero tools — so the stale-catalog check (`tools_revised_at`
1840+ // produce zero tools — so the stale-catalog check (`config_revised_at`
18411841 // vs `tools_synced_at`) doesn't re-attempt this connection per read.
18421842 const stampSynced = core.updateMany("connection", {
18431843 where: (b: AnyCb) =>
@@ -2403,11 +2403,11 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea · 559 unmodified lines
24032403 // catalog in place and retries on the next read.
24042404 const syncStaleConnectionTools = Effect.gen(function* () {
24052405 const revised = yield* core.findMany("integration", {
2406− where: (b: AnyCb) => b.isNotNull("tools_revised_at"),
2406+ where: (b: AnyCb) => b.isNotNull("config_revised_at"),
24072407 });
24082408 if (revised.length === 0) return;
24092409 const revisedAt = new Map(
2410− revised.map((row) => [row.slug, Number(row.tools_revised_at)] as const),
2410+ revised.map((row) => [row.slug, Number(row.config_revised_at)] as const),
24112411 );
24122412 const connections = yield* core.findMany("connection", {
24132413 where: (b: AnyCb) => b.or(...revised.map((row) => b("integration", "=", row.slug))),
vendor/emulate+1−1
@@ -1 +1 @@
1−Subproject commit 894206f09681d77f1d9d708a8d49f1c7dc72fa1f
1+Subproject commit 36638da8c104e92cb3522e0dca336618cdfd8205