From 0fe5e745ff98c37000e88e4cdc1fb0c745bd0fd0 Mon Sep 17 00:00:00 2001 From: Guillermo Casanova Date: Tue, 15 Sep 2026 16:04:10 -0300 Subject: [PATCH] fix(server): block updates under legacy service launchers --- apps/server/src/cloud/servicePreflight.test.ts | 13 ++++++++++--- apps/server/src/cloud/serviceProtocol.ts | 5 +++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/server/src/cloud/servicePreflight.test.ts b/apps/server/src/cloud/servicePreflight.test.ts index 2eb2e02015d0..1b9cf8e46c41 100644 --- a/apps/server/src/cloud/servicePreflight.test.ts +++ b/apps/server/src/cloud/servicePreflight.test.ts @@ -3,15 +3,22 @@ import { expect, it } from "@effect/vitest"; import { runServicePreflight } from "./servicePreflight.ts"; import { SERVICE_LAUNCHER_PROTOCOL } from "./serviceProtocol.ts"; -it("requires the database-snapshot launcher protocol", () => { +it.each([1, 2])("blocks legacy launcher protocol %i", (launcherProtocol) => { expect( runServicePreflight({ databasePath: "/missing/state.sqlite", - launcherProtocol: SERVICE_LAUNCHER_PROTOCOL - 1, + launcherProtocol, version: "1.2.3", }), - ).toMatchObject({ status: "blocked", version: "1.2.3" }); + ).toEqual({ + status: "blocked", + version: "1.2.3", + reason: + "This release requires a newer T3 Code service launcher. Update it on the server machine.", + }); +}); +it("accepts the current launcher protocol", () => { expect( runServicePreflight({ databasePath: "/missing/state.sqlite", diff --git a/apps/server/src/cloud/serviceProtocol.ts b/apps/server/src/cloud/serviceProtocol.ts index a008cbc2030b..2d32a996ee2c 100644 --- a/apps/server/src/cloud/serviceProtocol.ts +++ b/apps/server/src/cloud/serviceProtocol.ts @@ -1,7 +1,8 @@ import type { ServerSelfUpdateOutcome } from "@t3tools/contracts"; -/** Protocol 2 snapshots SQLite before trials so migrations can be rolled back safely. */ -export const SERVICE_LAUNCHER_PROTOCOL = 2 as const; +// Protocol 3 requires the standalone executable layout. Bump when runtimePaths +// or the installed runtime tree changes incompatibly; launchers survive self-updates. +export const SERVICE_LAUNCHER_PROTOCOL = 3 as const; export const SERVICE_LAUNCHER_CONTEXT_ENV = "T3_SERVICE_LAUNCHER_CONTEXT"; export const SERVICE_STATE_FILE = "service-state.json"; /** Written by the launcher just before an explicit stop kills its child, so