Files
memind/docs/goose-v149-103-cutover-runbook.md
T
john 570ecbd1b0 feat(wechat): add WX gate evidence and v1.49 103 cutover runbook
Prioritize scheduled-task intent over page.generate for automation phrases, add run-wechat-gate-evidence.mjs for WX-01..13, and document 103 maintenance-window steps for Goose v1.49.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 15:01:32 +08:00

429 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Goose v1.49 · 103 生产切换 Runbook
> **状态:** 草案(本地 v1.49 证据已齐;**未授权**在 103/105 执行任何操作)
>
> **适用范围:** 103(`58.38.22.103` / Mac Studio arm64)将 goosed 运行时从 **1.41 native** 升级到 **v1.49 TKMind 补丁树**
>
> **不包含:** Portal runtime 整包发版(见 [portal-release skill](../.claude/skills/portal-release/SKILL.md))、105 nginx 灰度(见 [release-canary-103.md](./release-canary-103.md))、Memory owner 切换(见 [TKMIND_V1_49_MIGRATION.md](../TKMIND_V1_49_MIGRATION.md))
---
## 1. 目标与边界
### 1.1 要达成什么
| 目标 | 说明 |
|------|------|
| 9 实例 goosed 升级到 v1.49 | 仍监听 **`18006`–`18014`**,与现网 `TKMIND_API_TARGETS` / `h5_user_sessions.goosed_target` 兼容 |
| 保留 TKMind 定制 | `tkmind_compat` REST、PG Session 共享、sandbox-fs MCP、harness、计费 relay、微信/页面 fail-closed |
| 用户数据零丢失 | RDS、PG `memind_sessions`、MindSpace 磁盘、Redis 路由键不删库 |
| 可回滚 | 15 分钟内回到 1.41 native 或 Docker standby |
### 1.2 明确不做(除非单独批准)
- 修改 RDS schema / 跑未审批 migration
- 切换 Memory 写入 owner 到 upstream v1.49
- 拆除 `:18036` DeepSeek no-think 代理
- 在本 runbook 内顺带发 Portal runtime(可同维护窗,但须独立 Gate + 脚本)
- 从本机 Mac 直接 `rsync` 二进制到 103(须在 **103 上** clone + vendor + 编译,或交付已审计的 release tar)
### 1.3 与 native 1.41 迁移的关系
2026-07-30 已完成 [goosed-native-103-migration-plan.md](./goosed-native-103-migration-plan.md)(Docker → native **1.41**)。
本 runbook 是 **第二次运行时升级**:native 1.41 → native **v1.49**。目录可沿用 `/Users/john/Project/tkmind_go-native` 的 launchd 模式,但二进制与启动命令改为 `goose serve`(见 [goose-v149-local-phase0-manifest.md](./goose-v149-local-phase0-manifest.md))。
---
## 2. 准入闸门(全部满足才申请维护窗)
### 2.1 Memind 仓库
| # | 项 | 命令 / 标准 |
|---|-----|-------------|
| 1 | v1.49 补丁已 review | `tkmind_go-v149` · 分支 `upgrade/v1.49-tkmind` · commit 记录在 Phase 3 清单 |
| 2 | Memind 侧脚本/文档已进 `main` | `check-release-ready.sh`、canary 脚本、WX gate 脚本 |
| 3 | Phase 3 本地证据 | `node scripts/run-goosed-v149-phase3-offline.mjs` → `GOOSE_V149_PHASE3_OFFLINE_OK` |
| 4 | 完整 LLM smoke(可选但推荐) | `GOOSE_V149_ALLOW_REAL_LLM=1` + `run-goosed-v149-phase3.mjs` → `GOOSE_V149_PHASE3_OK` |
| 5 | Memory manifest 无 drift | `node scripts/compare-goose-v149-memory-manifest.mjs` |
| 6 | WX 单测 + 本地 webhook | `node scripts/run-wechat-gate-evidence.mjs`;`run-wechat-scenario-test.mjs` poem-page |
| 7 | **用户明确批准** | 合并 `main`、103 维护窗、本 runbook 执行 |
### 2.2 103 只读基线(维护前 24h 内采集)
在 **103 上只读**执行,保存到本机 `test/_103_baselines/pre-v149-YYYYMMDD/`:
```bash
ssh john@58.38.22.103 '
date -u +%Y-%m-%dT%H:%M:%SZ
cat /Users/john/Project/Memind/.release-manifest.txt
grep -E "^(TKMIND_API_TARGETS|GOOSED_RUNTIME|GOOSED_MCP_|GOOSE_SESSION|MEMIND_DEEPSEEK)" /Users/john/Project/Memind/.env | sed "s/=.*/=***/"
/Users/john/Project/tkmind_go-native/goosed --version 2>/dev/null || ls /Users/john/Project/tkmind_go-native/releases/
for p in $(seq 18006 18014); do
printf "goosed_%s=" "$p"
curl -kfsS --connect-timeout 3 "https://127.0.0.1:${p}/status" || echo FAIL
done
curl -fsS http://127.0.0.1:8081/api/status
curl -fsS http://127.0.0.1:8082/mindspace/v1/contract | head -c 400
'
```
记录:`release_id`、`GOOSED_TAG`(Docker standby)、九个 launchd label 状态、Portal `git_head`。
---
## 3. 103 资产清单(不能遗漏)
### 3.1 目录与仓库
| 路径 | 用途 | v1.49 动作 |
|------|------|------------|
| `/Users/john/Project/Memind` | Portal live + MCP 脚本 | **不删**;确认 `mindspace-sandbox-mcp.mjs` 与 runtime manifest 一致 |
| `/Users/john/Project/tkmind_go-native` | 当前 1.41 native 池 | 备份后部署 v1.49 binary;保留旧 `releases/goosed-*` 回滚 |
| `/Users/john/Project/tkmind_go-v149` | v1.49 源码(**103 上需 clone**) | 见 §4 |
| `/Users/john/Project/tkmind_go-v141-prod-prep/.hermit/...` | Rust git vendor 缓存 | 见 §4.2;或从本机 tar 传到 103 |
| `/Users/john/Project/goosed-prod` | Docker standby | **保留**停机的 compose + 原 `GOOSED_TAG` |
| `/Users/john/MindSpace` | MindSpace 服务 | **不动** |
| `~/Library/LaunchAgents/cn.tkmind.goosed-native-1800*.plist` | 9 实例 | 更新 `ProgramArguments` 指向 v1.49 |
| `~/Library/LaunchAgents/cn.tkmind.memind-deepseek-no-think.plist` | `:18036` | **必须保持运行** |
### 3.2 持久化(备份,禁止覆盖)
与 `release-portal-runtime-prod.sh` manifest 一致,**额外**:
| 资产 | 备份 |
|------|------|
| 阿里云 RDS `goose` | 控制台快照 |
| PG `memind_sessions` @ `:5432` | `pg_dump` |
| PG `mindspace_userdata_prod` @ `:5433` | `pg_dump` |
| `tkmind_go-native/` 整目录 | `tar.gz` |
| `tkmind_go-v149/`(首次 clone 前无) | 首次 build 后备份 `target/release/goose` |
| Portal `.env` | 单独拷贝(含 secret,不进 Git) |
| 105 nginx `m.tkmind.cn` / `wechat.m.tkmind.cn` | 发布脚本同款备份 |
### 3.3 服务依赖(切换后仍须全绿)
| 组件 | 端口 | 说明 |
|------|------|------|
| Portal | 8081 | `cn.tkmind.memind-portal` |
| MindSpace | 8082 | 独立服务 |
| memind_adm | 8085 | 智趣/Cursor **后台白名单**在此配置,非 `.env` |
| DeepSeek no-think | 18036 | native goosed 自定义 provider 指向 |
| PostgreSQL | 5432 / 5433 | Session + userdata |
| Redis | 6379 | worker 路由(可重建,但切换前记录) |
| imgproxy | launchd | 页面缩略图 |
---
## 4. 103 上从零拉齐 GitHub / 离线依赖
> 本机 Mac 已有缓存 **不等于** 103 已有。以下在 **103 SSH 会话**内执行(或维护窗预演)。
### 4.1 Goose 源码
```bash
# 在 103 上
cd /Users/john/Project
# upstream 基线 tag(对照用)
# https://github.com/aaif-goose/goose/releases/tag/v1.49.0
# TKMind 补丁树(与本地一致的分支/commit)
git clone git@git.tkmind.cn:tkmind/tkmind_go.git tkmind_go-v149 # 或已有 remote 的实际 URL
cd tkmind_go-v149
git fetch origin upgrade/v1.49-tkmind
git checkout upgrade/v1.49-tkmind
git rev-parse HEAD # 必须与 Phase 3 记录的 commit 一致
```
若使用 worktree,路径固定为 `/Users/john/Project/tkmind_go-v149`(与 `GOOSE_V149_ROOT` 默认一致)。
### 4.2 Rust / cargo vendor(GitHub 不稳定时)
| 依赖 | 来源 | 103 命令 |
|------|------|----------|
| **rust-sdk** | hermit 缓存 | `bash /Users/john/Project/Memind/scripts/ensure-goose-v149-vendor.sh` |
| **cudaforge** | hermit 缓存 | 同上 |
| **rusty_v8** | GitHub release | `bash /Users/john/Project/Memind/scripts/ensure-goose-v149-v8.sh` |
Hermit 根目录默认:`/Users/john/Project/tkmind_go-v141-prod-prep/.hermit/rust/git/checkouts/`。
若 103 无 hermit 树,从本机传输(维护窗前):
```bash
# 本机
tar -czf /tmp/goose-v149-hermit-vendor.tgz -C /Users/john/Project/tkmind_go-v141-prod-prep .hermit
scp /tmp/goose-v149-hermit-vendor.tgz john@58.38.22.103:/tmp/
# 103
mkdir -p /Users/john/Project/tkmind_go-v141-prod-prep
tar -xzf /tmp/goose-v149-hermit-vendor.tgz -C /Users/john/Project/tkmind_go-v141-prod-prep
```
v8 直链见 [goose-v149-offline-downloads.md](./goose-v149-offline-downloads.md)。
### 4.3 工具链
```bash
# 103 上确认
uname -m # arm64
rustup show # 需 1.96.1
/opt/homebrew/opt/node@24/bin/node --version
/opt/homebrew/opt/postgresql@17/bin/pg_isready -h 127.0.0.1 -p 5432
```
### 4.4 编译 v1.49(103 本机)
```bash
cd /Users/john/Project/Memind
export GOOSE_V149_ROOT=/Users/john/Project/tkmind_go-v149
bash scripts/ensure-goose-v149-vendor.sh
bash scripts/ensure-goose-v149-v8.sh
GOOSE_V149_BUILD_MODE=codemode bash scripts/build-goosed-v149-local.sh
# 日志:/tmp/goosed-v149-build.log
/Users/john/Project/tkmind_go-v149/target/release/goose --version # 期望 goose 1.49.x
strings .../goose | grep -q platform_extensions::code_execution && echo code-mode OK
```
**禁止**使用 `GOOSE_V149_BUILD_MODE=minimal` 上生产。
### 4.5 安装 release 二进制(推荐)
```bash
STAMP=$(date +%Y%m%d-v149-m1)
install -m 755 /Users/john/Project/tkmind_go-v149/target/release/goose \
/Users/john/Project/tkmind_go-native/releases/goose-${STAMP}
# 更新 run-goosed-native.sh 或各 .env.1800N 中的 GOOSE_BIN 指向该 release
```
保留上一版 `releases/goosed-20260729-v141-m1`(或当前 live)用于回滚。
---
## 5. 推荐切换策略
### 5.1 两阶段(推荐)
| 阶段 | 范围 | 端口 | 目的 |
|------|------|------|------|
| **A. Canary goosed** | 单实例 | `:18015` | 与 [release-canary-103.md](./release-canary-103.md) 候选 goosed 对齐;Portal 灰度用户(如唐 `wx_ul610et8`) |
| **B. 全池切换** | 9 实例 | `:18006`–`:18014` | 维护窗内替换全部 launchd |
阶段 A 可在 **不** 替换 18006–18014 的情况下验证 v1.49 + sandbox-fs + DeepSeek + 微信。
### 5.2 全池切换(维护窗)
参考 [goosed-native-103-migration-plan.md](./goosed-native-103-migration-plan.md) Phase 1–2,替换为 v1.49 启动参数。
---
## 6. 单实例配置模板(v1.49)
以 **18006** 为例;18007–18014 复制并改 `GOOSE_PORT` / launchd label。
### 6.1 环境变量(`.env.18006` 或 launchd `EnvironmentVariables`)
```bash
GOOSE_PORT=18006
GOOSE_HOST=127.0.0.1
GOOSE_TLS=true
GOOSE_SERVER__SECRET_KEY=<与 Portal TKMIND_SERVER__SECRET_KEY 同步>
GOOSE_DISABLE_KEYRING=1
# 生产 Session PG(不是本地 goose_sessions_v149_dev)
GOOSE_SESSION_DB_URL=postgresql://<user>@127.0.0.1:5432/memind_sessions
# MCP — 宿主机路径,必须与 Portal .env 一致
GOOSED_MCP_NODE_PATH=/opt/homebrew/opt/node@24/bin/node
GOOSED_MCP_SERVER_PATH=/Users/john/Project/Memind/mindspace-sandbox-mcp.mjs
PORTAL_RUNTIME_DIR=/Users/john/Project/Memind
MINDSPACE_STORAGE_ROOT=/Users/john/MindSpace/data/mindspace
# Memory — 强制 legacy owner(禁止 upstream 写 MySQL)
MEMORY_BACKEND=legacy
MEMORY_VECTOR_ENABLED=0
MEMORY_AGENT_INJECTION_MODE=off
MEMORY_LIFECYCLE_ENABLED=0
MEMORY_CANDIDATE_ENABLED=0
# XDG 每实例隔离(避免 9 实例争用同一 state)
XDG_CONFIG_HOME=/Users/john/Project/tkmind_go-native/state/18006/config
XDG_DATA_HOME=/Users/john/Project/tkmind_go-native/state/18006/data
XDG_STATE_HOME=/Users/john/Project/tkmind_go-native/state/18006/state
XDG_CACHE_HOME=/Users/john/Project/tkmind_go-native/state/18006/cache
```
### 6.2 启动命令
v1.49 **不再**使用 `goosed agent`,改为:
```bash
exec /Users/john/Project/tkmind_go-native/releases/goose-<STAMP> serve \
--host 127.0.0.1 --port 18006 --tls
```
legacy REST(`/agent/start`、`/sessions/{id}/reply`)由 **`tkmind_compat`** 在 v1.49 内提供;切换后必须跑:
```bash
node /Users/john/Project/Memind/scripts/check-goosed-v149-all.mjs # 在 103 上针对 localhost:18006 预演
```
### 6.3 Portal `.env` 核对项
| 变量 | 要求 |
|------|------|
| `TKMIND_API_TARGETS` | 九个 `https://127.0.0.1:18006` … `18014` URL |
| `GOOSED_RUNTIME` | `native` |
| `GOOSED_MCP_*` | 宿主机绝对路径,且文件存在 |
| `MEMIND_DEEPSEEK_DISABLE_THINKING` | `1` |
| DeepSeek provider URL | `http://127.0.0.1:18036/v1`(非 `host.docker.internal`) |
| Memory 开关 | **不** 因 v1.49 默认开启 upstream Memory |
---
## 7. 维护窗执行清单
**建议窗口:** ≥ 45 分钟(9 实例 + provider 同步 + P0 回归)
### Phase 0 — 备份(可先执行)
- [ ] RDS 快照
- [ ] `pg_dump memind_sessions`、`mindspace_userdata_prod`
- [ ] Portal persist tar + `tkmind_go-native` tar
- [ ] 记录当前 `releases/goosed-*` 文件名
### Phase 1 — 切流量
- [ ] 105 维护页或阻止新会话(见 native 迁移计划 drain)
- [ ] 可选 soft drain Redis `memind:runtime:worker:goosed-N:drain`
- [ ] 超时后停 `cn.tkmind.memind-portal`(或仅 block 新 session,视 drain)
### Phase 2 — 替换 goosed 二进制与 launchd
- [ ] 确认 `:18036` DeepSeek 代理仍 `active`
- [ ] `launchctl bootout` 九个 `cn.tkmind.goosed-native-1800N`
- [ ] 部署 v1.49 `goose` release + 更新 run 脚本
- [ ] `launchctl bootstrap` 九个实例
- [ ] 九个 `/status` 返回 `ok`
```bash
for p in $(seq 18006 18014); do
echo -n "$p: "
curl -kfsS --connect-timeout 3 "https://127.0.0.1:$p/status" || echo FAIL
done
```
- [ ] **Provider 同步到全部 9 个 target**(Admin 模型中心 / 103 既有流程)
- [ ] sandbox-fs 冒烟:`node scripts/check-goosed-v149-sandbox-fs.mjs`(指向 18006)
### Phase 3 — Portal
**若无 Portal 代码变更:**
- [ ] 重启 `cn.tkmind.memind-portal`(读 `.env`)
- [ ] **跳过** Docker remount
**若同窗发 Portal runtime:**
- [ ] `bash scripts/check-release-ready.sh`
- [ ] Gate report 绑定 commit + artifact SHA
- [ ] `bash scripts/release-portal-runtime-prod.sh --yes`(或 canary 流程)
### Phase 4 — P0 回归(103 localhost + 105 外网)
| 优先级 | 场景 | 验证 |
|--------|------|------|
| P0 | Portal `/api/status` | 200 |
| P0 | `/auth/login` 错误密码 | 401 + 正确文案 |
| P0 | 新建 H5 对话 | `goosed_target` 落在 18006–18014 |
| P0 | **旧 session 续聊** | 维护前存在的 session `/reply` 成功 |
| P0 | sandbox-fs 落盘 | page.generate → `public/*.html` 200 |
| P1 | 微信真实回调 | WX-01~13;非仅 health |
| P1 | DeepSeek 工具轮次 | 无 `reasoning_content` 裸奔错误 |
| P1 | imgproxy / MindSearch | 生产 URL |
Gate:维护窗 commit 须绑定 **Core + Impact Gate report**([production-release-guardian.md](./production-release-guardian.md))。
### Phase 5 — 恢复流量
- [ ] 105 nginx → `58.38.22.103:8081`(或灰度 `19082` 路径)
- [ ] 外网 `https://m.tkmind.cn/api/status`
### Phase 6 — 观察 24–72h
- [ ] `GOOSED_RUNTIME=native node scripts/runtime-worker-metrics.mjs sample`
- [ ] `monitor-goosed-fds.mjs` 覆盖 18006–18014
- [ ] 续聊 / 页面 / 微信投诉
---
## 8. 回滚
**触发:** 九 target 非全绿、旧 session 批量续聊失败、P0 回归失败、FD 泄漏
**目标:** < 15 分钟
| 步骤 | 操作 |
|------|------|
| 1 | 105 保持维护 |
| 2 | `launchctl bootout` 九个 v1.49 native 实例 |
| 3 | 恢复 launchd 指向 **1.41** `releases/goosed-*` |
| 4 | 或紧急:`cd goosed-prod && docker compose up -d`(原 `GOOSED_TAG`,仅 18006 standby) |
| 5 | Portal `.env` 恢复备份 |
| 6 | 若 Portal 已发新版:按 `archived_source` / backup `release_id` 回滚 |
| 7 | 九路 `/status` + `/auth/login` + 旧 session 续聊抽样 |
**回滚不需要:** 恢复 RDS / PG(若切换中未改库)。
本地 canary 回滚(仅开发机):`bash scripts/switch-goose-v149-canary.sh rollback`
---
## 9. 与 Portal 发版的关系
| 动作 | 独立? | 说明 |
|------|--------|------|
| Goose v1.49 全池 | 是 | 本 runbook |
| Portal runtime | 是 | `release-portal-runtime-prod.sh`;artifact 含 `mindspace-sandbox-mcp.mjs` |
| 105 灰度 | 可组合 | 先 canary goosed `:18015` + 灰度 Portal |
| Memory owner | **禁止**绑在 v1.49 包内 | 单独审批 |
**推荐顺序:** Memind 合并 `main` → 103 上 build v1.49 → canary(18015 + 唐)→ 全池维护窗 →(可选)Portal Gate 发版。
---
## 10. 证据附件(维护窗结束后归档)
保存到 `test/_103_baselines/post-v149-YYYYMMDD/`:
| 文件 | 内容 |
|------|------|
| `goose-version.txt` | `goose --version` × 9 |
| `status-loop.txt` | 18006–18014 `/status` |
| `portal-manifest.txt` | `.release-manifest.txt` |
| `gate-report.json` | Core + Impact,绑定 commit |
| `phase3-offline.log` | 本机 `GOOSE_V149_PHASE3_OFFLINE_OK` |
| `wechat-smoke.log` | 本地 `run-wechat-scenario-test`(103 真实 WX 另补) |
| `rollback-pointer.txt` | 1.41 release 文件名 + Docker `GOOSED_TAG` |
---
## 11. 相关文档
| 文档 | 用途 |
|------|------|
| [TKMIND_V1_49_MIGRATION.md](../TKMIND_V1_49_MIGRATION.md) | 决策表、Memory 闸门 |
| [goose-v149-phase3-closeout.md](./goose-v149-phase3-closeout.md) | 本地证据与合并前闸门 |
| [goose-v149-offline-downloads.md](./goose-v149-offline-downloads.md) | v8 / vendor 直链 |
| [103-runtime-topology.md](./103-runtime-topology.md) | 端口与服务拓扑 |
| [goosed-native-103-migration-plan.md](./goosed-native-103-migration-plan.md) | 1.41 native 迁移(已执行) |
| [production-release-guardian.md](./production-release-guardian.md) | Gate 场景 |
| [发包必看.md](./发包必看.md) | Portal 发版强制项 |
---
## 12. 变更记录
| 日期 | 说明 |
|------|------|
| 2026-09-10 | 初稿:103 clone/vendor/build/9 实例/回滚清单;本地 Phase 3 证据已齐,待用户批准执行 |