GPU_GUARD_MONOREPO/docs/superpowers/followups/2026-05-12-weixin-db-e2e-report.md
2026-05-20 21:39:12 +08:00

175 lines
9.6 KiB
Markdown

# weixin-db E2E 验证报告(架构 C, 2026-05-12)
> 执行方式:subagent-driven-development。
> 本文档记录 plan `docs/superpowers/plans/2026-05-12-weixin-db-channel.md` 的完成情况、自动化验证结果、剩余手工 E2E 清单。
## 完成状态总览
| 阶段 | Tasks | 状态 |
|---|---|---|
| Phase C-0 · session.db schema PoC | C0-1 | ✅ DONE |
| Phase C-1 · 清理作废代码 | Task 1-5 | ✅ DONE |
| Phase C-2 · runtime/weixin_db/ 纯函数模块 | Task 6-15 | ✅ DONE |
| Phase C-3 · weixin_db.ts 主服务装配 | Task 16 | ✅ DONE |
| Phase C-4 · agent_channel 集成 | Task 17, 18 | ✅ DONE |
| Phase C-5 · agent_channel_group 改用户主动添加 | Task 19, 20 | ✅ DONE |
| Phase C-6 · 前端 UX | Task 21, 22, 23 | ✅ DONE |
| Phase C-7 · 安装包 + Tray | Task 24, 25, 26 | ✅ DONE |
| Phase C-8 · 端到端手工验证 | Task 27 | ⏳ 待用户跑 |
| Phase C-9 · 回复路径 5.7 | 占位 | ❌ (独立 spec) |
## 自动化验证结果
### 1. session.db / contact.db schema RE (Phase C-0)
脚本: `packages/backend/poc/weixin-4x/poc-13-session-schema.mjs` + `poc-14-contact-schema.mjs`
结果文档: `packages/backend/poc/weixin-4x/README-session-schema.md`
关键发现:
- **Msg 表名算法确认**: `tableName = 'Msg_' + md5(username)` (100/100 命中)
- **session.db 主表**: `SessionTable.username`(列出所有会话)
- **群显示名来源**: contact.db 的 `contact` 表 (`remark > nick_name > username`)
- 依此真实 schema **回填**了 `room_resolver.ts`(Task 12),不再是假设。
### 2. key 抽取 PowerShell 脚本冒烟(Task 10)
```bash
powershell.exe -ExecutionPolicy Bypass -NoProfile -File packages/backend/tools/win32/extract-weixin-key.ps1
```
实际输出(2026-05-12 测试):
```json
{"seedDir":"C:\\Users\\lixin\\Documents\\xwechat_files\\shin_seed_7861",
"wxid":"shin","wechatVersion":"4.1.8.107","pid":39916,
"dbKeys":{"message_0.db":"374c4e1a...","session.db":"e43bd85c...","contact.db":"bd93ce66...",...}}
```
✅ 17 个 DB 的 key 全部成功抽取。
### 3. 后端单测 (与 weixin-db 相关的 suite)
```
pnpm --filter @neta/backend test -- netaclaw/runtime/weixin_db netaclaw/service/weixin_db netaclaw/service/agent_channel netaclaw/service/agent_channel_group
Test Suites: 13 passed, 13 total
Tests: 92 passed, 92 total
Time: 7.954 s
```
覆盖:
- `runtime/weixin_db/` 全部模块(wcdb_codec / zstd_decode / db_paths / key_extractor / message_repo / room_resolver / wal_watcher / build_pseudo) — 均 TDD 通过
- `service/weixin_db.ts` — 5 个 case (`replyToGroup` 占位 throw、`bindChannel` 在/非 Windows、`refreshWhitelist``unbindChannel` 幂等)
- `service/agent_channel.ts` — 含 17+9+6 测试:page enrichment 切换为 weixin-db、group 路由经 findByKey + replyToGroup、delete 走 unbindChannel、toggle 刷新 whitelist
- `service/agent_channel_group.ts` — 27 个测试:addByName 新语义、toggle 不再接受 -1、updatePolicy 拒绝 prefix 等
### 4. Tray .NET 单测(Task 26)
```
dotnet test packages/windows-tray/Neta.Tray.Tests
已通过! - 失败: 0,通过: 5,已跳过: 0,总计: 5
```
删除 `BridgeProcessManager` / `BridgeHealthPoller` / `BridgeProcessManagerTests.cs` 后,Neta.Tray 仅管理 backend.exe,5 个剩余测试全通。
### 5. Installer 脚本(Task 24, 25)
- `build-windows-installer.js`: 删 bridge dotnet publish 步骤,加 `tools/win32/*.ps1` 拷贝步骤
- `setup.iss`: 删 `bridge-output\*` / bridge.exe uninstall taskkill;加 `tools-output\win32\*``{app}\tools\win32`
语法检查通过,实际 `iscc` 构建需在 Inno Setup 环境下执行,未包含在本次自动化验证中。
## 手工 E2E Checklist (Task 27)
以下需用户在真实 Windows + PC 微信环境手工跑:
- [ ] **E2E-1**: 前端新建 channel type=`微信本地代理(群聊)`,填 wxid `shin` → 保存成功
- [ ] **E2E-2**: backend 启动时看日志 `[weixin-db] channel X bound, wxid=shin ver=4.1.8.107 pid=XXXXX`,无 error
- [ ] **E2E-3**: 前端"群聊管理"打开,显示"已添加监管 0 个群" → 点 "+ 添加群" → 输入测试群完整名 → 提交
- [ ] **E2E-4**: backend 日志 `addByName created=true`;`netaclaw_agent_channel_group` 多一行 status=1
- [ ] **E2E-5**: 测试群里发"hello"(触发策略 at_mention) → backend 看到 `[weixin-db] incremental read` 但 agent 不回(at_mention 未命中)
- [ ] **E2E-6**: 群里发 `@机器人 你好` → routeInboundMessage 走 handleInboundMessage group 路径 → agentExecutor 执行 → replyToGroup throw 占位 → 日志 `weixin-db reply 暂未实现, cid=X room=测试群 skipped`
- [ ] **E2E-7**: 切到"所有消息"策略 → **未加白名单的群**发消息 → backend 完全没反应(白名单过滤生效)
- [ ] **E2E-8**: 白名单群发消息 → backend 看到处理
- [ ] **E2E-9**: 前端删除该群白名单 → DB row 消失 → 再发消息 backend 无反应
- [ ] **E2E-10**: 关 Weixin → wal 不变,backend 平静;重开 Weixin → 健康探针触发 → 自动 rebind(60s 内)
## 关键技术决策记录
1. **架构 C**: 纯 Node + PowerShell(无独立 .NET bridge 进程)。ps1 脚本 spawn 一次抽 key,后续 Node 本进程处理。
2. **零被动发现**: 群必须用户主动添加,白名单在 DB 解密阶段即过滤,bot **物理上读不到**非白名单群消息(隐私保护)。
3. **回复路径占位**: `replyToGroup` 当前 throw NotImplementedError,`agent_channel.handleDbInbound` try/catch 跳过,不阻塞读链路。spec 5.7 独立 plan 实施。
4. **跨平台兜底**: 非 Windows `loginStatus='unsupported_platform'`,不 spawn powershell 不 crash。
5. **重连机制**: WeixinDbService 60s 健康探针,基于 `process.kill(pid, 0)` + `fs.accessSync` 判断 Weixin 进程 + DB 可读。
## 遗留 Follow-up
1. **Task 27 E2E**: 待用户跑,目前仅自动化部分已验证。
2. **Phase C-9**: replyToGroup 真实实现(5.7)需独立 spec(剪贴板/UIA/WCF 等方案待 brainstorm)。
3. **bigint 字面量**: `tsconfig.target=es2018` 不支持 `999n` 字面量,实现处用 `BigInt(...)` 构造(已注意)。
4. **zstd API**: `@mongodb-js/zstd` v2 只有 async,tryDecompressToString 已 async(plan Task 8.1 兜底方案)。
5. **better-sqlite3 + zstd native bindings**: root `package.json` `pnpm.onlyBuiltDependencies` 已包含两者,`prebuild-install` 会在 pnpm install 时正确执行。
## 文件清单
### 新增
**后端 runtime**:
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/wcdb_codec.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/zstd_decode.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/db_paths.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/key_extractor.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/message_repo.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/room_resolver.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/wal_watcher.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/incremental_reader.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/types.ts`
- `packages/backend/src/modules/netaclaw/runtime/weixin_db/build_pseudo.ts`
- `packages/backend/src/modules/netaclaw/service/weixin_db.ts`
**后端测试**: 上述所有模块对应的 `.test.ts`,以及 `test/modules/netaclaw/service/agent_channel.weixin_db.test.ts`
**工具脚本**: `packages/backend/tools/win32/extract-weixin-key.ps1`
**PoC**:
- `packages/backend/poc/weixin-4x/poc-13-session-schema.mjs`
- `packages/backend/poc/weixin-4x/poc-14-contact-schema.mjs`
- `packages/backend/poc/weixin-4x/README-session-schema.md`
- `packages/backend/poc/weixin-4x/session-schema-output.log`
- `packages/backend/poc/weixin-4x/contact-schema-output.log` (若写了)
### 修改
**后端**:
- `packages/backend/src/modules/netaclaw/service/agent_channel.ts`(weixin-uia → weixin-db 全替换,-147 行净删)
- `packages/backend/src/modules/netaclaw/service/agent_channel_group.ts`(upsertOnInbound → addByName)
- `packages/backend/src/modules/netaclaw/controller/admin/agent_channel_group.ts`(加 /add)
- `packages/backend/src/comm/path.ts`(删 pWechatUploadsPath)
- `packages/backend/src/config/config.default.ts`(删 wechatUploads 静态映射)
- `packages/backend/scripts/build-windows-installer.js`(删 bridge publish,加 tools/win32 拷贝)
- `packages/backend/installer/setup.iss`(删 bridge 项,加 tools 项)
- `packages/backend/package.json`(加 @mongodb-js/zstd)
**前端**:
- `packages/frontend/src/modules/agent/types/index.d.ts`(类型切换)
- `packages/frontend/src/modules/agent/views/channel-management.vue`(文案+字段)
- `packages/frontend/src/modules/agent/components/channel-group-panel.vue`(大改 UX,用户主动添加)
- `packages/frontend/src/modules/agent/composables/useDbChannelValidation.ts`(改名 from useUiaChannelValidation.ts)
**根**:
- `package.json`(加 pnpm.onlyBuiltDependencies)
**Tray**:
- `packages/windows-tray/Neta.Tray/TrayApplicationContext.cs`(删 bridge 拉起逻辑,316→169 行)
### 删除
- `packages/backend/src/modules/netaclaw/service/weixin_uia.ts` + `wechat_archive.ts`
- `packages/backend/src/modules/netaclaw/controller/open/weixin_uia.ts` + `admin/wechat_archive.ts`
- `packages/backend/src/modules/netaclaw/runtime/wechat_uia_routing.ts` + `wechat_archive_schema.ts`
- 对应 test 文件 6 个
- `packages/windows-tray/Neta.WeChatBridge/` + `Neta.WeChatBridge.Tests/` 整个目录
- `packages/windows-tray/Neta.Tray/BridgeProcessManager.cs` + `BridgeHealthPoller.cs`
- `packages/windows-tray/Neta.Tray.Tests/BridgeProcessManagerTests.cs`
- `packages/frontend/src/modules/agent/components/wechat-archive-panel.vue`
- `packages/frontend/src/modules/agent/composables/useUiaChannelValidation.ts`(被 useDbChannelValidation.ts 替代)