From e59809eff40ae0ae4ea36af6b3ff8e670f2f21d9 Mon Sep 17 00:00:00 2001 From: john Date: Fri, 14 Aug 2026 22:35:58 +0800 Subject: [PATCH] fix(canary): share the native 103 goosed pool instead of Docker 103 retired Docker goosed on 2026-07-30. Portal canary now health-checks 18006-18014 and inherits those targets, instead of requiring goosed-prod-1. Co-authored-by: Cursor --- release-gate/release-script.test.mjs | 12 ++++---- scripts/release-portal-canary-prod.sh | 40 +++++++------------------- scripts/run-memind-portal-candidate.sh | 15 +++++----- 3 files changed, 25 insertions(+), 42 deletions(-) diff --git a/release-gate/release-script.test.mjs b/release-gate/release-script.test.mjs index 1f03a0b..afdaf3a 100644 --- a/release-gate/release-script.test.mjs +++ b/release-gate/release-script.test.mjs @@ -154,7 +154,7 @@ test('production canary keeps stable 8081 live and switches only after verified const fullBackup = source.indexOf('Create and verify the full stable backup'); const persistBackup = source.indexOf('Create and verify the persisted-data backup'); const edgeBackup = source.indexOf('Create and verify the active 105 nginx routing backup'); - const goosedStart = source.indexOf('Start an isolated goosed candidate on 18015'); + const goosedStart = source.indexOf('Use the native goosed pool 18006-18014'); const candidateStart = source.indexOf('Start the passive candidate Portal on 18081'); const deepseekCompatStart = source.indexOf( 'Start the DeepSeek tool-round compatibility proxy on 18036', @@ -183,6 +183,8 @@ test('production canary keeps stable 8081 live and switches only after verified assert.match(source, /CANARY_PROXY_PORT=18082/); assert.match(source, /CANARY_TUNNEL_REMOTE_PORT=19082/); assert.match(source, /DEEPSEEK_COMPAT_PORT=18036/); + assert.match(source, /Use the native goosed pool 18006-18014/); + assert.doesNotMatch(source, /docker inspect goosed-prod-1/); assert.match(source, /deepseek-no-think-proxy\.mjs/); assert.match(source, /run-deepseek-compat-proxy-candidate\.sh/); assert.match(source, /MEMIND_CANARY_CANDIDATE_HEALTH_URLS/); @@ -221,7 +223,7 @@ test('production canary keeps stable 8081 live and switches only after verified assert.doesNotMatch(source, /bootout.*cn\.tkmind\.memind-portal/); }); -test('candidate runner overrides stable host MCP paths with container-visible paths', async (t) => { +test('candidate runner inherits native goosed MCP paths from the stable root', async (t) => { const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-canary-runner-')); t.after(() => fs.rm(tempRoot, { recursive: true, force: true })); @@ -289,14 +291,14 @@ test('candidate runner overrides stable host MCP paths with container-visible pa assert.equal(result.status, 0, result.stderr); assert.match(result.stdout, new RegExp(`^cwd=${ROOT}$`, 'm')); - assert.match(result.stdout, /^mcp_node=\/usr\/local\/bin\/node$/m); + assert.match(result.stdout, /^mcp_node=\/opt\/homebrew\/opt\/node@24\/bin\/node$/m); assert.match( result.stdout, - /^mcp_server=\/opt\/portal\/mindspace-sandbox-mcp\.mjs$/m, + /^mcp_server=\/Users\/john\/Project\/Memind\/mindspace-sandbox-mcp\.mjs$/m, ); assert.match(result.stdout, /^deepseek_disable=1$/m); assert.match(result.stdout, /^deepseek_port=18036$/m); - assert.match(result.stdout, /^deepseek_gateway=host\.docker\.internal$/m); + assert.match(result.stdout, /^deepseek_gateway=wrong\.invalid$/m); assert.match(result.stdout, /^deepseek_base=unset$/m); assert.match(result.stdout, /^deepseek_host=unset$/m); assert.match(result.stdout, /^page_data_review=1$/m); diff --git a/scripts/release-portal-canary-prod.sh b/scripts/release-portal-canary-prod.sh index fd8f5cf..d9ed597 100755 --- a/scripts/release-portal-canary-prod.sh +++ b/scripts/release-portal-canary-prod.sh @@ -50,8 +50,8 @@ Deploys a candidate Portal beside the stable 103 runtime: stable Portal 127.0.0.1:8081 canary router 127.0.0.1:18082 candidate Portal 127.0.0.1:18081 - candidate goosed 127.0.0.1:18015 - DeepSeek compat 0.0.0.0:18036 (host/container only) + native goosed 127.0.0.1:18006-18014 + DeepSeek compat 0.0.0.0:18036 (host only; reused if already healthy) The stable runtime is not replaced. A dedicated reverse tunnel exposes the router only to 105 at 127.0.0.1:19082. The committed release workflow updates @@ -183,7 +183,7 @@ printf '%s %s\n' "${bundle_sha}" "$(basename "${BUNDLE_PATH}")" > "${SHA_PATH}" echo "git_branch=${branch}" echo "artifact_tree=.runtime/portal" echo "artifact_bundle_sha256=${bundle_sha}" - echo "routing=stable:8081,proxy:18082,edge-tunnel:19082,candidate:18081,goosed-canary:18015,deepseek-compat:18036" + echo "routing=stable:8081,proxy:18082,edge-tunnel:19082,candidate:18081,goosed-native:18006-18014,deepseek-compat:18036" echo "canary_usernames=${CANARY_USERNAMES}" echo "canary_wechat_user_ids=${CANARY_WECHAT_USER_IDS}" echo "canary_wechat_page_data_aider_review_enabled=${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED}" @@ -211,7 +211,9 @@ ssh -o BatchMode=yes -o ConnectTimeout=15 "${HOST}" \ | grep -q '"deepseekThinking":"disabled"'; } \ && ! lsof -nP -iTCP:18081 -sTCP:LISTEN >/dev/null 2>&1 \ && ! lsof -nP -iTCP:18015 -sTCP:LISTEN >/dev/null 2>&1 \ - && /opt/homebrew/bin/docker inspect goosed-prod-1 >/dev/null \ + && for _p in 18006 18007 18008 18009 18010 18011 18012 18013 18014; do \ + curl -kfsS --max-time 2 https://127.0.0.1:\${_p}/status | grep -qx ok; \ + done \ && test \"\$(df -Pk '${REMOTE_ROOT}' | awk 'NR==2 {print \$4}')\" -gt 10485760 \ && ssh -o BatchMode=yes -o ConnectTimeout=10 '${EDGE_HOST}' \ \"test -f '${EDGE_MOBILE_CONFIG}' \ @@ -514,28 +516,10 @@ say "Stop an older canary without touching stable Portal 8081" restore_edge_to_stable stop_candidate_services -say "Start an isolated goosed candidate on 18015" -( - cd "${GOOSED_DIR}" - set -a - # shellcheck disable=SC1091 - source .env - set +a - export CANDIDATE_RUNTIME_DIR="${CANDIDATE_DIR}" - "${DOCKER_BIN}" compose -p goosed-prod \ - -f "${GOOSED_COMPOSE}" \ - -f "${CANDIDATE_DIR}/scripts/goosed-canary.compose.yml" \ - up -d --no-deps goosed-canary -) -for _ in $(seq 1 60); do - if [[ "$(curl -skS -m 5 https://127.0.0.1:18015/status 2>/dev/null || true)" == "ok" ]]; then - break - fi - sleep 2 +say "Use the native goosed pool 18006-18014" +for _p in 18006 18007 18008 18009 18010 18011 18012 18013 18014; do + [[ "$(curl -skS -m 5 "https://127.0.0.1:${_p}/status" 2>/dev/null || true)" == "ok" ]] done -[[ "$(curl -skS -m 5 https://127.0.0.1:18015/status 2>/dev/null || true)" == "ok" ]] -"${DOCKER_BIN}" exec goosed-prod-canary \ - sh -lc 'test -x /usr/local/bin/node && test -f /opt/portal/mindspace-sandbox-mcp.mjs' say "Start the DeepSeek tool-round compatibility proxy on 18036" if deepseek_compat_healthy; then @@ -570,9 +554,6 @@ for _ in $(seq 1 30); do done deepseek_compat_healthy fi -"${DOCKER_BIN}" exec goosed-prod-canary \ - sh -lc "curl -fsS --max-time 5 http://host.docker.internal:${DEEPSEEK_COMPAT_PORT}/health \ - | grep -q '\"deepseekThinking\":\"disabled\"'" say "Start the passive candidate Portal on 18081" cat > "${CANDIDATE_PLIST}" < "${CANDIDATE_PLIST}" <MEMIND_CANARY_STABLE_ROOT${STABLE_DIR} MEMIND_CANARY_RELEASE_ID${RELEASE_ID} MEMIND_CANARY_CANDIDATE_PORT18081 - MEMIND_CANARY_GOOSED_URLhttps://127.0.0.1:18015 MEMIND_CANARY_DEEPSEEK_PROXY_PORT${DEEPSEEK_COMPAT_PORT} MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED} MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS} @@ -819,7 +799,7 @@ printf 'stable_health=http://127.0.0.1:8081/api/status\n' printf 'proxy_health=http://127.0.0.1:%s/__memind_canary/health\n' "${CANARY_PROXY_PORT}" printf 'edge_tunnel=http://127.0.0.1:%s/api/status\n' "${CANARY_TUNNEL_REMOTE_PORT}" printf 'candidate_health=http://127.0.0.1:18081/api/status\n' -printf 'candidate_goosed=https://127.0.0.1:18015/status\n' +printf 'candidate_goosed=https://127.0.0.1:18006-18014/status\n' printf 'deepseek_compat_health=http://127.0.0.1:%s/health\n' "${DEEPSEEK_COMPAT_PORT}" REMOTE_SCRIPT diff --git a/scripts/run-memind-portal-candidate.sh b/scripts/run-memind-portal-candidate.sh index dc9fa08..0702afb 100755 --- a/scripts/run-memind-portal-candidate.sh +++ b/scripts/run-memind-portal-candidate.sh @@ -27,17 +27,18 @@ export H5_REMINDER_WORKER_ENABLED=0 export H5_PORT="${MEMIND_CANARY_CANDIDATE_PORT:-18081}" export H5_HOST=127.0.0.1 export H5_PUBLIC_BASE_URL="${H5_PUBLIC_BASE_URL:-https://m.tkmind.cn}" -export TKMIND_API_TARGETS="${MEMIND_CANARY_GOOSED_URL:-https://127.0.0.1:18015}" -export TKMIND_API_TARGET="${MEMIND_CANARY_GOOSED_URL:-https://127.0.0.1:18015}" -# Extensions are spawned inside goosed-canary, where the candidate artifact is -# mounted at /opt/portal. Never inherit host-only MCP paths from the stable .env. -export GOOSED_MCP_NODE_PATH=/usr/local/bin/node -export GOOSED_MCP_SERVER_PATH=/opt/portal/mindspace-sandbox-mcp.mjs +if [[ -n "${MEMIND_CANARY_GOOSED_URL:-}" ]]; then + export TKMIND_API_TARGETS="${MEMIND_CANARY_GOOSED_URL}" + export TKMIND_API_TARGET="${MEMIND_CANARY_GOOSED_URL}" + # Isolated Docker goosed mounts the candidate artifact at /opt/portal. + export GOOSED_MCP_NODE_PATH=/usr/local/bin/node + export GOOSED_MCP_SERVER_PATH=/opt/portal/mindspace-sandbox-mcp.mjs + export MEMIND_GOOSED_HOST_GATEWAY=host.docker.internal +fi # DeepSeek V4 tool rounds must use the same compatibility contract exercised # by the release Gate. Stable .env values cannot disable or redirect it. export MEMIND_DEEPSEEK_DISABLE_THINKING=1 export MEMIND_DEEPSEEK_NO_THINK_PORT="${MEMIND_CANARY_DEEPSEEK_PROXY_PORT:-18036}" -export MEMIND_GOOSED_HOST_GATEWAY=host.docker.internal export H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_ENABLED="${MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED:-0}" export H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_USERS="${MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS:-}" export AIDER_BIN="${MEMIND_CANARY_AIDER_BIN:-/opt/homebrew/bin/aider}"