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 fullBackup = source.indexOf('Create and verify the full stable backup');
|
||||||
const persistBackup = source.indexOf('Create and verify the persisted-data 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 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 candidateStart = source.indexOf('Start the passive candidate Portal on 18081');
|
||||||
const deepseekCompatStart = source.indexOf(
|
const deepseekCompatStart = source.indexOf(
|
||||||
'Start the DeepSeek tool-round compatibility proxy on 18036',
|
'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_PROXY_PORT=18082/);
|
||||||
assert.match(source, /CANARY_TUNNEL_REMOTE_PORT=19082/);
|
assert.match(source, /CANARY_TUNNEL_REMOTE_PORT=19082/);
|
||||||
assert.match(source, /DEEPSEEK_COMPAT_PORT=18036/);
|
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, /deepseek-no-think-proxy\.mjs/);
|
||||||
assert.match(source, /run-deepseek-compat-proxy-candidate\.sh/);
|
assert.match(source, /run-deepseek-compat-proxy-candidate\.sh/);
|
||||||
assert.match(source, /MEMIND_CANARY_CANDIDATE_HEALTH_URLS/);
|
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/);
|
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-'));
|
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-canary-runner-'));
|
||||||
t.after(() => fs.rm(tempRoot, { recursive: true, force: true }));
|
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.equal(result.status, 0, result.stderr);
|
||||||
assert.match(result.stdout, new RegExp(`^cwd=${ROOT}$`, 'm'));
|
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(
|
assert.match(
|
||||||
result.stdout,
|
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_disable=1$/m);
|
||||||
assert.match(result.stdout, /^deepseek_port=18036$/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_base=unset$/m);
|
||||||
assert.match(result.stdout, /^deepseek_host=unset$/m);
|
assert.match(result.stdout, /^deepseek_host=unset$/m);
|
||||||
assert.match(result.stdout, /^page_data_review=1$/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
|
stable Portal 127.0.0.1:8081
|
||||||
canary router 127.0.0.1:18082
|
canary router 127.0.0.1:18082
|
||||||
candidate Portal 127.0.0.1:18081
|
candidate Portal 127.0.0.1:18081
|
||||||
candidate goosed 127.0.0.1:18015
|
native goosed 127.0.0.1:18006-18014
|
||||||
DeepSeek compat 0.0.0.0:18036 (host/container only)
|
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
|
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
|
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 "git_branch=${branch}"
|
||||||
echo "artifact_tree=.runtime/portal"
|
echo "artifact_tree=.runtime/portal"
|
||||||
echo "artifact_bundle_sha256=${bundle_sha}"
|
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_usernames=${CANARY_USERNAMES}"
|
||||||
echo "canary_wechat_user_ids=${CANARY_WECHAT_USER_IDS}"
|
echo "canary_wechat_user_ids=${CANARY_WECHAT_USER_IDS}"
|
||||||
echo "canary_wechat_page_data_aider_review_enabled=${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED}"
|
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"'; } \
|
| grep -q '"deepseekThinking":"disabled"'; } \
|
||||||
&& ! lsof -nP -iTCP:18081 -sTCP:LISTEN >/dev/null 2>&1 \
|
&& ! lsof -nP -iTCP:18081 -sTCP:LISTEN >/dev/null 2>&1 \
|
||||||
&& ! lsof -nP -iTCP:18015 -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 \
|
&& test \"\$(df -Pk '${REMOTE_ROOT}' | awk 'NR==2 {print \$4}')\" -gt 10485760 \
|
||||||
&& ssh -o BatchMode=yes -o ConnectTimeout=10 '${EDGE_HOST}' \
|
&& ssh -o BatchMode=yes -o ConnectTimeout=10 '${EDGE_HOST}' \
|
||||||
\"test -f '${EDGE_MOBILE_CONFIG}' \
|
\"test -f '${EDGE_MOBILE_CONFIG}' \
|
||||||
@@ -514,28 +516,10 @@ say "Stop an older canary without touching stable Portal 8081"
|
|||||||
restore_edge_to_stable
|
restore_edge_to_stable
|
||||||
stop_candidate_services
|
stop_candidate_services
|
||||||
|
|
||||||
say "Start an isolated goosed candidate on 18015"
|
say "Use the native goosed pool 18006-18014"
|
||||||
(
|
for _p in 18006 18007 18008 18009 18010 18011 18012 18013 18014; do
|
||||||
cd "${GOOSED_DIR}"
|
[[ "$(curl -skS -m 5 "https://127.0.0.1:${_p}/status" 2>/dev/null || true)" == "ok" ]]
|
||||||
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
|
|
||||||
done
|
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"
|
say "Start the DeepSeek tool-round compatibility proxy on 18036"
|
||||||
if deepseek_compat_healthy; then
|
if deepseek_compat_healthy; then
|
||||||
@@ -570,9 +554,6 @@ for _ in $(seq 1 30); do
|
|||||||
done
|
done
|
||||||
deepseek_compat_healthy
|
deepseek_compat_healthy
|
||||||
fi
|
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"
|
say "Start the passive candidate Portal on 18081"
|
||||||
cat > "${CANDIDATE_PLIST}" <<EOF
|
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_STABLE_ROOT</key><string>${STABLE_DIR}</string>
|
||||||
<key>MEMIND_CANARY_RELEASE_ID</key><string>${RELEASE_ID}</string>
|
<key>MEMIND_CANARY_RELEASE_ID</key><string>${RELEASE_ID}</string>
|
||||||
<key>MEMIND_CANARY_CANDIDATE_PORT</key><string>18081</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_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_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>
|
<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 '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 '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_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}"
|
printf 'deepseek_compat_health=http://127.0.0.1:%s/health\n' "${DEEPSEEK_COMPAT_PORT}"
|
||||||
REMOTE_SCRIPT
|
REMOTE_SCRIPT
|
||||||
|
|
||||||
|
|||||||
@@ -27,17 +27,18 @@ export H5_REMINDER_WORKER_ENABLED=0
|
|||||||
export H5_PORT="${MEMIND_CANARY_CANDIDATE_PORT:-18081}"
|
export H5_PORT="${MEMIND_CANARY_CANDIDATE_PORT:-18081}"
|
||||||
export H5_HOST=127.0.0.1
|
export H5_HOST=127.0.0.1
|
||||||
export H5_PUBLIC_BASE_URL="${H5_PUBLIC_BASE_URL:-https://m.tkmind.cn}"
|
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}"
|
if [[ -n "${MEMIND_CANARY_GOOSED_URL:-}" ]]; then
|
||||||
export TKMIND_API_TARGET="${MEMIND_CANARY_GOOSED_URL:-https://127.0.0.1:18015}"
|
export TKMIND_API_TARGETS="${MEMIND_CANARY_GOOSED_URL}"
|
||||||
# Extensions are spawned inside goosed-canary, where the candidate artifact is
|
export TKMIND_API_TARGET="${MEMIND_CANARY_GOOSED_URL}"
|
||||||
# mounted at /opt/portal. Never inherit host-only MCP paths from the stable .env.
|
# Isolated Docker goosed mounts the candidate artifact at /opt/portal.
|
||||||
export GOOSED_MCP_NODE_PATH=/usr/local/bin/node
|
export GOOSED_MCP_NODE_PATH=/usr/local/bin/node
|
||||||
export GOOSED_MCP_SERVER_PATH=/opt/portal/mindspace-sandbox-mcp.mjs
|
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
|
# DeepSeek V4 tool rounds must use the same compatibility contract exercised
|
||||||
# by the release Gate. Stable .env values cannot disable or redirect it.
|
# by the release Gate. Stable .env values cannot disable or redirect it.
|
||||||
export MEMIND_DEEPSEEK_DISABLE_THINKING=1
|
export MEMIND_DEEPSEEK_DISABLE_THINKING=1
|
||||||
export MEMIND_DEEPSEEK_NO_THINK_PORT="${MEMIND_CANARY_DEEPSEEK_PROXY_PORT:-18036}"
|
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_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 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}"
|
export AIDER_BIN="${MEMIND_CANARY_AIDER_BIN:-/opt/homebrew/bin/aider}"
|
||||||
|
|||||||
Reference in New Issue
Block a user