import assert from 'node:assert/strict'; import fs from 'node:fs'; import test from 'node:test'; const releaseScript = fs.readFileSync( new URL('../scripts/release-portal-runtime-prod.sh', import.meta.url), 'utf8', ); test('REL-08 all nine goosed runtimes are remounted and health/identity checked after live swap', () => { assert.match(releaseScript, /containers\[@\].*!= 9/); assert.match(releaseScript, /seq 18006 18014/); assert.match(releaseScript, /up -d --force-recreate/); assert.match(releaseScript, /\/opt\/portal\/mindspace-sandbox-mcp\.mjs/); assert.match(releaseScript, /remount_goosed_after_live_swap/); assert.match(releaseScript, /ensure_portal_tunnel/); const swap = releaseScript.indexOf('mv "${RUNTIME_DIR}" "${APP_DIR}"'); const remount = releaseScript.indexOf('remount_goosed_after_live_swap', swap); const portalStart = releaseScript.indexOf('say "启动新的 Portal runtime"', remount); assert.ok(swap >= 0 && remount > swap && portalStart > remount); }); test('REL-09 release script has an error trap and old-runtime restart primitives', () => { assert.match(releaseScript, /trap 'rollback' ERR/); assert.match(releaseScript, /health check failed: portal=/); assert.match(releaseScript, /launchctl kickstart -k/); assert.match(releaseScript, /run-memind-portal-prod\.sh/); }); test('REL-10 validates upload before switch and snapshots live plus persistent data first', () => { const checksum = releaseScript.indexOf('shasum -a 256 -c'); const fullBackup = releaseScript.indexOf('say "备份当前 live 全目录"'); const persistBackup = releaseScript.indexOf('say "单独备份持久目录"'); const stopOld = releaseScript.indexOf('say "停止旧 Portal 服务"'); const swap = releaseScript.indexOf('mv "${APP_DIR}" "${OLD_LIVE_DIR}"'); assert.ok(checksum >= 0); assert.ok(fullBackup > checksum); assert.ok(persistBackup > fullBackup); assert.ok(stopOld > persistBackup); assert.ok(swap > stopOld); assert.match(releaseScript, /set -euo pipefail/); assert.match(releaseScript, /trap 'rollback' ERR/); });