fix(canary): share the native 103 goosed pool instead of Docker
Memind CI / Test, build, and release guards (push) Failing after 2m40s
Memind CI / Test, build, and release guards (push) Failing after 2m40s
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 <cursoragent@cursor.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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}" <<EOF
|
||||
@@ -588,7 +569,6 @@ cat > "${CANDIDATE_PLIST}" <<EOF
|
||||
<key>MEMIND_CANARY_STABLE_ROOT</key><string>${STABLE_DIR}</string>
|
||||
<key>MEMIND_CANARY_RELEASE_ID</key><string>${RELEASE_ID}</string>
|
||||
<key>MEMIND_CANARY_CANDIDATE_PORT</key><string>18081</string>
|
||||
<key>MEMIND_CANARY_GOOSED_URL</key><string>https://127.0.0.1:18015</string>
|
||||
<key>MEMIND_CANARY_DEEPSEEK_PROXY_PORT</key><string>${DEEPSEEK_COMPAT_PORT}</string>
|
||||
<key>MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED</key><string>${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED}</string>
|
||||
<key>MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS</key><string>${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS}</string>
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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}"
|
||||
|
||||
Reference in New Issue
Block a user