From 162c3b1df6ade1fd454e5126bf614de596f756c4 Mon Sep 17 00:00:00 2001 From: Franz Rolfsvaag Date: Wed, 22 Jul 2026 10:26:20 +0200 Subject: [PATCH] Promote 0.2.25 to stable --- CHANGELOG.md | 4 ++-- docs/branch-deployments.md | 17 +++++++---------- release-index.json | 30 ++++++++++++++++++++++++++++++ scripts/verify-release-metadata.js | 16 +++++++++------- scripts/verify-update-system.js | 6 +++--- update-manifest.json | 4 ++-- 6 files changed, 53 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e009b21..4a57641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,8 @@ ## 0.2.25 - Added verified, snapshot-backed production deployment switching between `main` and exact `experimental-*` branches, including bundled plugin code, preserved plugin data, automatic failed-apply restoration, and graceful wrapper restarts. -- Added a guarded one-time bootstrap that completes bundled-plugin synchronization after an older stable updater installs this experimental core; metadata checks alone cannot trigger deployment. -- Completed the experimental DesignMotionHQ UX foundation and representative settings, navigation, theme, command, updates, resources, and OBS overlay workflows with a five-viewport browser/accessibility matrix. +- Added a guarded compatibility bootstrap that completes bundled-plugin synchronization if stable `0.2.24` installs an experimental branch directly; metadata checks alone cannot trigger deployment. +- Completed the DesignMotionHQ UX foundation and representative settings, navigation, theme, command, updates, resources, and OBS overlay workflows with a five-viewport browser/accessibility matrix. - Fixed overlay editor scrolling and viewport containment, interactive pop-out preview editing, and persistent resource storage-limit saves with immediate page reconciliation. ## 0.2.24 diff --git a/docs/branch-deployments.md b/docs/branch-deployments.md index 424b2a2..bf1e833 100644 --- a/docs/branch-deployments.md +++ b/docs/branch-deployments.md @@ -29,16 +29,13 @@ new branch. ## Test an experimental branch -To enter from stable `0.2.24`, open **Admin > Settings**, select -**Experimental** as the update branch, save, and use **Update from repository**. -The older updater installs experimental core `0.2.25`; on its first startup the -new guarded bootstrap confirms that an actual core update completed, snapshots -the installation, synchronizes bundled plugin code, and restarts a second time. -Merely checking metadata cannot trigger this bootstrap. Stable `0.2.24` predates -the exact-branch picker, so it selects the newest published `experimental-*` -branch. The same guarded entry path is available again after a return to stable. -While experimental code is running, use the exact branch controls below to move -between `main` and any published experimental branch. +First update production on `main` to stable `0.2.25` through the existing +**Update from repository** action. This installs the exact-branch controls on +stable, so future switches in either direction use the same verified workflow. +If a `0.2.24` host enters Experimental before taking the stable update, the +guarded compatibility bootstrap completes bundled-plugin synchronization after +the older updater installs the newest `experimental-*` branch; expect a second +restart. Merely checking metadata cannot trigger that bootstrap. 1. Open **Admin > Updates** and find **Running code branch**. 2. Confirm the page reports the expected running branch and commit. diff --git a/release-index.json b/release-index.json index 2cbed77..91a822a 100644 --- a/release-index.json +++ b/release-index.json @@ -2,6 +2,36 @@ "schema_version": 1, "channel": "stable", "releases": [ + { + "version": "0.2.25", + "ref": "refs/tags/v0.2.25", + "released_at": "2026-07-22", + "installable": true, + "rollback_safe": true, + "replaces_versions": [ + "1.2.0" + ], + "data_policy": "preserve", + "dependency_policy": "sync_on_restart", + "migration_notes": "Adds the shared DesignMotionHQ UX foundation, repaired overlay and resource-library workflows, and verified snapshot-backed switching between main and exact experimental branches. Existing content, settings, tokens, overlays, databases, uploads, models, feedback, secrets, plugin data, and local-only plugins are preserved.", + "plugins": { + "auto-vc": "0.1.6", + "birthday": "0.1.3", + "economy-framework": "0.2.10", + "economy-games": "0.1.7", + "expression-interaction": "0.2.1", + "lumi_ai": "0.8.5", + "moderation": "0.1.5", + "okf": "0.1.2", + "quotes": "0.1.2", + "sample-plugin": "0.1.0", + "throne_wishlist": "0.1.2", + "welcome_messages": "0.1.1" + }, + "tools": { + "lumi_ai_web_search": "0.1.1" + } + }, { "version": "0.2.24", "ref": "refs/tags/v0.2.24", diff --git a/scripts/verify-release-metadata.js b/scripts/verify-release-metadata.js index e09bf1b..71b1869 100644 --- a/scripts/verify-release-metadata.js +++ b/scripts/verify-release-metadata.js @@ -5,8 +5,8 @@ const { findSafeTarget } = require("../src/services/versioning"); const root = path.join(__dirname, ".."); const releaseVersion = "0.2.25"; -const stableReleaseVersion = "0.2.24"; -const previousStableVersion = "0.2.23"; +const previousStableVersion = "0.2.24"; +const priorStableVersion = "0.2.23"; const earliestCompatibleCoreVersion = "0.1.9"; const changedPlugins = { "auto-vc": { from: "0.1.5", to: "0.1.6", knowledge: "auto-vc" }, @@ -45,19 +45,21 @@ assert.equal(packageJson.version, releaseVersion); assert.equal(packageLock.version, releaseVersion); assert.equal(packageLock.packages?.[""]?.version, releaseVersion); assert.equal(coreManifest.version, releaseVersion); -assert.equal(coreManifest.channel, "experimental"); +assert.equal(coreManifest.channel, "stable"); assert.equal(coreManifest.compatible_from, earliestCompatibleCoreVersion); assert.equal(coreManifest.rollback_safe, true); assert.deepEqual(coreManifest.replaces_versions, ["1.2.0"]); -assert.equal(releaseIndex.releases[0].version, stableReleaseVersion); -assert.equal(releaseIndex.releases[0].ref, `refs/tags/v${stableReleaseVersion}`); +assert.equal(releaseIndex.releases[0].version, releaseVersion); +assert.equal(releaseIndex.releases[0].ref, `refs/tags/v${releaseVersion}`); assert.equal(releaseIndex.releases[1].version, previousStableVersion); assert.equal(releaseIndex.releases[1].ref, `refs/tags/v${previousStableVersion}`); +assert.equal(releaseIndex.releases[2].version, priorStableVersion); +assert.equal(releaseIndex.releases[2].ref, `refs/tags/v${priorStableVersion}`); assert.equal(releaseIndex.releases.at(-1).version, earliestCompatibleCoreVersion); assert.equal(hasVersionHeading(readText("CHANGELOG.md"), releaseVersion), true); assert.match(readText("knowledge/core/lumi-core.md"), new RegExp(`^Version: ${escapeRegex(releaseVersion)}$`, "m")); -const safeCoreTarget = findSafeTarget(stableReleaseVersion, [ +const safeCoreTarget = findSafeTarget(previousStableVersion, [ ...(Array.isArray(coreManifest.versions) ? coreManifest.versions : []), coreManifest ]); @@ -88,4 +90,4 @@ assert.equal(webSearch.minimum_lumi_version, "0.2.0"); assert.equal(webSearch.minimum_lumi_ai_version, "0.8.2"); assert.equal(hasVersionHeading(readText("plugins/lumi_ai_web_search/CHANGELOG.md"), webSearch.version), true); -console.log("Release metadata verification passed: experimental core 0.2.25 over stable 0.2.24, Lumi AI 0.8.5, and synchronized package metadata."); +console.log("Release metadata verification passed: stable core 0.2.25 after 0.2.24, Lumi AI 0.8.5, and synchronized package metadata."); diff --git a/scripts/verify-update-system.js b/scripts/verify-update-system.js index 23c25f6..7fc830a 100644 --- a/scripts/verify-update-system.js +++ b/scripts/verify-update-system.js @@ -21,7 +21,7 @@ function readJson(relativePath) { const releaseIndex = readJson("release-index.json"); const releaseVersions = releaseIndex.releases.map((release) => release.version); -assert.deepEqual(releaseVersions, ["0.2.24", "0.2.23", "0.2.22", "0.2.21", "0.2.20", "0.2.19", "0.2.18", "0.2.17", "0.2.16", "0.2.15", "0.2.14", "0.2.13", "0.2.12", "0.2.11", "0.2.10", "0.2.9", "0.2.8", "0.2.7", "0.2.6", "0.2.5", "0.2.4", "0.2.3", "0.2.2", "0.2.1", "0.2.0", "0.1.9"]); +assert.deepEqual(releaseVersions, ["0.2.25", "0.2.24", "0.2.23", "0.2.22", "0.2.21", "0.2.20", "0.2.19", "0.2.18", "0.2.17", "0.2.16", "0.2.15", "0.2.14", "0.2.13", "0.2.12", "0.2.11", "0.2.10", "0.2.9", "0.2.8", "0.2.7", "0.2.6", "0.2.5", "0.2.4", "0.2.3", "0.2.2", "0.2.1", "0.2.0", "0.1.9"]); assert.equal(new Set(releaseVersions).size, releaseVersions.length, "release versions must be unique"); for (const release of releaseIndex.releases) { assert.equal(normalizeRepositoryRef(release.ref), release.ref); @@ -33,9 +33,9 @@ const currentRelease = releaseIndex.releases[0]; const packageVersion = readJson("package.json").version; const coreManifest = readJson("update-manifest.json"); assert.equal(packageVersion, coreManifest.version); -assert.equal(coreManifest.channel, "experimental"); +assert.equal(coreManifest.channel, "stable"); assert.equal(packageVersion, "0.2.25"); -assert.equal(currentRelease.version, "0.2.24"); +assert.equal(currentRelease.version, "0.2.25"); assert.deepEqual(currentRelease.replaces_versions, ["1.2.0"]); for (const [pluginId, version] of Object.entries(currentRelease.plugins)) { assert.equal(readJson(`plugins/${pluginId}/plugin.json`).version, version, `${pluginId} release catalog version`); diff --git a/update-manifest.json b/update-manifest.json index aa20f8c..6a56f8a 100644 --- a/update-manifest.json +++ b/update-manifest.json @@ -1,14 +1,14 @@ { "name": "Lumi Core", "version": "0.2.25", - "channel": "experimental", + "channel": "stable", "released_at": "2026-07-22", "compatible_from": "0.1.9", "migration_kind": "patch", "replaces_versions": [ "1.2.0" ], - "migration_notes": "Experimental DesignMotionHQ UX checkpoint plus safe production branch deployment controls. Existing content, settings, tokens, overlays, databases, uploads, models, feedback, secrets, plugin data, and local-only plugins are preserved. Bundled plugin code follows the selected branch.", + "migration_notes": "DesignMotionHQ UX checkpoint plus safe production branch deployment controls. Existing content, settings, tokens, overlays, databases, uploads, models, feedback, secrets, plugin data, and local-only plugins are preserved. Bundled plugin code follows the selected branch.", "rollback_safe": true, "requirements": [ "Node.js 18 or newer"