From 2466dc81da914b82804ca45f39c43c5db66fb122 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Thu, 22 Oct 2026 18:21:08 -0400 Subject: [PATCH 1/2] [Fix] Resume tasks whose snapshot baked an older worker release (#3567) A restored task snapshot keeps the image the task started on, so its baked worker release trails the deployment after every upgrade. install-worker.sh treated that drift as fatal, so follow-ups on any task that slept before an upgrade failed during worker install. Task snapshots hold the task's files and cannot boot fresh, so warn and continue; the worker must still match the application release. Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com> --- .docker/sandbox/install-worker.sh | 8 ++++++ deploy/ci/worker-tls-runtime.test.mjs | 40 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/.docker/sandbox/install-worker.sh b/.docker/sandbox/install-worker.sh index d8e0f64c9..66aa1575b 100644 --- a/.docker/sandbox/install-worker.sh +++ b/.docker/sandbox/install-worker.sh @@ -185,6 +185,14 @@ validate_worker_compatibility() { fi if [ "$worker_compatibility_version" != "$expected_compatibility_version" ]; then + # A restored task snapshot keeps the image it started on, so its baked + # release trails the deployment after every upgrade. The task's files + # live in that snapshot and cannot boot fresh, so report the drift and + # keep going. The application release must still match the worker. + if [ "$expected_name" = "baked_worker_product_version" ]; then + echo "Warning: worker release $worker_version differs from $expected_name $expected_version. Continuing; rebuild the worker image or environment snapshot to pick up the current release." >&2 + continue + fi echo "Error: worker release $worker_version is incompatible with $expected_name $expected_version" >&2 return 1 fi diff --git a/deploy/ci/worker-tls-runtime.test.mjs b/deploy/ci/worker-tls-runtime.test.mjs index 9b40595ed..a85f5c121 100644 --- a/deploy/ci/worker-tls-runtime.test.mjs +++ b/deploy/ci/worker-tls-runtime.test.mjs @@ -72,3 +72,43 @@ test('worker bootstrap warns about outdated restored runtimes without stopping', rmSync(directory, { recursive: true, force: true }); } }); + +test('worker bootstrap warns when a restored snapshot baked an older release', () => { + const directory = mkdtempSync(join(tmpdir(), 'worker-compat-')); + try { + writeFileSync(join(directory, 'VERSION'), 'v1.19.0\n'); + const definitions = source.slice( + 0, + source.indexOf('# Fail fast per phase:'), + ); + assert.ok(definitions.includes('validate_worker_compatibility()')); + const run = (variables) => + spawnSync('bash', [], { + input: `${definitions}\nWORKER_DIR=${JSON.stringify(directory)}\n${variables}\nvalidate_worker_compatibility\n`, + encoding: 'utf8', + env: { ...process.env, ROOMOTE_APPLICATION_PRODUCT_VERSION: '' }, + }); + + // Task snapshots cannot boot fresh, so an older baked release only warns. + const stale = run( + 'APPLICATION_PRODUCT_VERSION=1.19.0\nBAKED_WORKER_PRODUCT_VERSION=1.18.0', + ); + assert.equal(stale.status, 0, stale.stderr); + assert.match( + stale.stderr, + /Warning: worker release v1\.19\.0 differs from baked_worker_product_version 1\.18\.0/, + ); + + // The worker must still match the application release it serves. + const mismatched = run( + 'APPLICATION_PRODUCT_VERSION=1.18.2\nBAKED_WORKER_PRODUCT_VERSION=1.19.0', + ); + assert.equal(mismatched.status, 1); + assert.match( + mismatched.stderr, + /Error: worker release v1\.19\.0 is incompatible with application_product_version 1\.18\.2/, + ); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); From 59aea4a107bdf29e26d86ddfbf24741d48622041 Mon Sep 17 00:00:00 2001 From: "roomote-roomote[bot]" <301996811+roomote-roomote[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2026 18:32:11 -0400 Subject: [PATCH 2/2] chore: prepare Roomote 1.19.2 release (#3568) Co-authored-by: @mrubens <2600+mrubens@users.noreply.github.com> --- CHANGELOG.md | 12 ++++++++++++ apps/docs/self-hosting/operations.mdx | 5 ++++- package.json | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e463c445..15fe3840e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ This file tracks product releases for Roomote (single monorepo version). Automated release entries are prepended by `pnpm run version`. +## 1.19.2 (2026-10-22) + +Roomote 1.19.2 lets you continue tasks saved before an upgrade without losing access to their saved work. + +### Highlights + +- Resume saved tasks after an upgrade instead of encountering a worker installation failure caused by an older snapshot image. + +### Patch changes + +- Follow-ups can now resume tasks saved before a Roomote upgrade instead of failing during worker installation because the task snapshot was created with an older release. Worker startup warns about the older snapshot image and continues while still requiring the installed worker to match the application release. + ## 1.19.1 (2026-10-22) Roomote 1.19.1 keeps tasks starting after an upgrade by skipping outdated environment snapshots and rebuilding them automatically. diff --git a/apps/docs/self-hosting/operations.mdx b/apps/docs/self-hosting/operations.mdx index 6693bac93..4de75ee2a 100644 --- a/apps/docs/self-hosting/operations.mdx +++ b/apps/docs/self-hosting/operations.mdx @@ -120,7 +120,10 @@ five minutes and queues replacements from the current image, with rebuilds paced across environments; the daily refresh remains in place too. Rebuild custom worker images yourself, and migrate or update saved task snapshots you intend to keep using. The fresh-start fallback applies to environment snapshots, not saved -task snapshots. +task snapshots. Starting with Roomote 1.19.2, follow-ups can resume saved task +snapshots created with an older release: worker startup warns about the older +image and continues, preserving the task's files. The installed worker must still +match the application release. This does not update tools inside the snapshot. An application upgrade does not replace tools or certificate bundles inside an existing snapshot. Update its OS certificates, Python environments and independent diff --git a/package.json b/package.json index 4f02a7315..7a50903af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "roomote", - "version": "1.19.1", + "version": "1.19.2", "license": "FCL-1.0-ALv2", "packageManager": "pnpm@10.29.3", "engines": {