diff --git a/release-gate/local-stack.mjs b/release-gate/local-stack.mjs index 47aa056..3d00555 100644 --- a/release-gate/local-stack.mjs +++ b/release-gate/local-stack.mjs @@ -283,6 +283,15 @@ export async function createLocalGateStack({ fsp.mkdir(storageRoot, { recursive: true }), fsp.mkdir(publishRoot, { recursive: true }), ]); + // Keep the H5 root writable and isolated so packaged-runtime smoke tests + // cannot materialize MindSpace pages inside the candidate artifact. The + // platform skill catalog still comes from the packaged runtime via a + // read-only symlink. + await fsp.symlink( + path.join(resolvedPortalRoot, 'skills'), + path.join(sandboxRoot, 'skills'), + 'dir', + ); const wechatBundle = path.join(resolvedPortalRoot, 'wechat-mp.bundle.mjs'); if (await fsp.stat(wechatBundle).catch(() => null)) { await fsp.copyFile(wechatBundle, path.join(sandboxRoot, 'wechat-mp.bundle.mjs')); @@ -350,11 +359,9 @@ export async function createLocalGateStack({ baseEnv.MINDSPACE_USERDATA_MCP_PG_URL, pgDatabase, ), - // Keep the packaged runtime root as the code/skill root. Persistent data - // is isolated independently below; pointing H5_ROOT at the empty sandbox - // makes listPlatformSkillCatalog() see no skills and silently removes - // static_publish/page-data tools from ordinary users. - MEMIND_PORTAL_H5_ROOT: resolvedPortalRoot, + // Keep code and packaged skills available while isolating all writable + // H5/MindSpace state from the candidate runtime artifact. + MEMIND_PORTAL_H5_ROOT: sandboxRoot, H5_USERS_ROOT: usersRoot, MINDSPACE_STORAGE_ROOT: storageRoot, MEMIND_SHARED_PUBLISH_ROOT: publishRoot, diff --git a/release-gate/release-script.test.mjs b/release-gate/release-script.test.mjs index d43de39..a7aa5b4 100644 --- a/release-gate/release-script.test.mjs +++ b/release-gate/release-script.test.mjs @@ -47,7 +47,7 @@ test('packaged runtime gate isolates persistent roots and rejects artifact mutat path.join(ROOT, 'release-gate', 'local-stack.mjs'), 'utf8', ); - assert.match(localStackSource, /MEMIND_PORTAL_H5_ROOT: resolvedPortalRoot/); + assert.match(localStackSource, /MEMIND_PORTAL_H5_ROOT: sandboxRoot/); assert.match(localStackSource, /MEMIND_DEEPSEEK_DISABLE_THINKING: '0'/); assert.match(localStackSource, /H5_USERS_ROOT: usersRoot/); assert.match(localStackSource, /MINDSPACE_STORAGE_ROOT: storageRoot/);