fix: restore existing WeChat instance and add M6 validation tools

This commit is contained in:
2026-09-05 22:49:18 +08:00
parent 1bd0344e8b
commit 1e8e894dba
23 changed files with 1357 additions and 48 deletions
@@ -0,0 +1,58 @@
# M6 稳定性与兼容性——进行中
**M6 尚未完成。** 短时测试不能替代开发计划 §11.3 的 8/24/72 小时测试,也不能替代 Windows 11 和不同 DPI 的真机验收。每项未验证内容继续保留,不按“接口存在/编译通过”结项。
## 已实现并验证
- `recover-ui`:恢复原有微信实例,不启动 `Weixin.exe`、不模拟登录。
- 优先使用 FlaUI UIA3 的通知区域按钮。
- Windows 10 通知区域未通过 UIA3 暴露图标时,使用公开 MSAA 接口定位,再按真实图标边界双击。不读写 Explorer 内存、不猜测托盘回调消息。
- 不再使用 `ShowWindow` 显示灰色 Qt 外壳;不对主窗口盲按 Esc(这会再次隐藏到托盘)。
- 最小化、正常关闭到托盘两种状态均验证了:状态实际发生、恢复同一 HWND 和 PID、`MainView/session_list/chat_message_list` 存在。
- 共享窗口绑定采用以上恢复路径,供普通业务调用与监听复用。
- 监听在统一命令队列内校验目标会话,再获取快照;避免将其他会话内容标成文件传输助手消息。
- `listener-smoke`:仅向文件传输助手发送一条唯一测试消息;收到一次事件,加载 checkpoint 重启监听后不重复上报。
- UI 树遍历有深度、节点数和 runtime ID 去重保护。截断/重复节点会明确失败,保存部分快照而非栈溢出或假报完整。
- `diagnose --output <dir> --baseline <ui-tree.json>`:脱敏快照、操作系统/微信版本、会话、DPI/窗口边界、进程资源、必需控件及基线差异、关联 ID。
- `endurance`:JSONL 持续落盘;统计微信及 Agent 的内存/句柄/线程、消息事件、重连事件、最近有效快照。记录请求/实测时长;未跑满、监听提前退出、快照停滞、最终错误均不算健康。输出目录禁止覆盖。
## 当前已取得的证据
环境:`DESKTOP-EGI7QCK`,Windows 10 build 19044,微信 4.1.13.63,Session 1,窗口 DPI 96(100%)。
- Linux Core:49/49 通过;Release 全量构建 0 警告、0 错误;Windows self-contained 发布通过。
- Windows 8 个命令均 exit 0:recover、doctor、inspect、smoke、recovery-smoke、listener-smoke、30 秒 stability-smoke、diagnose。
- listener:MatchingEvents=1、EventsAfterRestart=0、Snapshots=5、CheckpointSaved=true。
- 基线对比:Added/Removed/MissingRequiredControls 均为空。
- 30 秒短测:ObservedSeconds=30.0794228、CompletedDuration=true、7 个样本、有效监听快照持续更新、Findings 为空。
- 这仅证明上述 **30 秒** 样本,不证明长时间无泄漏。
本次发布包 SHA-256:`5899FD7A07E85B9C20679E06012CB0ED494F96916A8C58F81ACFC533286CA009`。
脱敏摘要见 `evidence/M6-20260905/`;完整本地证据位于 `artifacts/m6-final-validation/m6-validation-20260905T143832/`。历史失败证据不作为通过依据。
## 尚待完成的验收
- [ ] 8/24/72 小时真实监听及长时资源趋势。
- [ ] 网络中断/恢复、20 次微信重启后的恢复(不能绕过登录或锁屏)。
- [ ] 常见弹窗、会话切换的专门恢复回归。
- [ ] 多会话/多子窗口消息归属与去重、长列表滚动场景。
- [ ] 重新核对 M2 连续 500 条发送无重复与 M3 8 小时监听证据;未找到对应证据前仍未验收。
- [ ] Windows 10 多 DPI 与 Windows 11 兼容矩阵。目前仅证明 Windows 10 / 96 DPI。
- [ ] 汇总此前阶段尚未真机覆盖的回归项;M4/M5 中仅编译/门禁验证的写操作不冒充端到端验收。
- [ ] 全部要求通过后更新阶段结论,并提交、PUSH 阶段验收记录。
用户明确跳过无麦克风环境下的 SendAudio;不扩展该豁免到其他功能。
## 重复执行
在已登录且未锁定、微信所在的用户会话执行;不要在 Session 0 运行。
```powershell
.\Invoke-M6Validation.ps1 -Executable .\WxAgent.Host.exe -OutputDirectory C:\Users\Rogee\wx-agent\validation-new
.\Invoke-Endurance.ps1 -Executable .\WxAgent.Host.exe -OutputDirectory C:\Users\Rogee\wx-agent\endurance-new -Hours 72 -SampleSeconds 60
```
脚本位于 `scripts/windows/`。每次使用新输出目录并保留 BinarySha256、请求/实测时长、退出码及全部样本。72 小时运行会在经过 8/24 小时时保存阶段快照,最终 `metrics/report.json` 才是最终结果。
所有早期调试用 `WxAgent*` 一次性定时任务已禁用,防止它们在 23:59 自动重发测试消息;后续任务仅手动触发,不配置未来重复触发器。
@@ -0,0 +1,7 @@
{
"Sent": true,
"MatchingEvents": 1,
"EventsAfterRestart": 0,
"Snapshots": 5,
"CheckpointSaved": true
}
@@ -0,0 +1,18 @@
[
{
"State": "minimized",
"TransitionObserved": true,
"SameInstance": true,
"MainViewFound": true,
"SessionsFound": true,
"MessagesFound": true
},
{
"State": "tray-hidden",
"TransitionObserved": true,
"SameInstance": true,
"MainViewFound": true,
"SessionsFound": true,
"MessagesFound": true
}
]
@@ -0,0 +1,121 @@
{
"StartedAt": "2026-09-05T14:39:32.0610704+00:00",
"FinishedAt": "2026-09-05T14:40:02.1378009+00:00",
"Samples": [
{
"Timestamp": "2026-09-05T14:39:32.2343907+00:00",
"ProcessCount": 5,
"WorkingSetBytes": 153997312,
"HandleCount": 3535,
"ThreadCount": 183,
"WindowFound": true,
"Errors": [],
"MessageEvents": 0,
"ReconnectEvents": 0,
"AgentWorkingSetBytes": 43053056,
"AgentHandleCount": 389,
"AgentThreadCount": 20,
"LastSnapshotAt": null
},
{
"Timestamp": "2026-09-05T14:39:37.4016222+00:00",
"ProcessCount": 5,
"WorkingSetBytes": 153575424,
"HandleCount": 3535,
"ThreadCount": 183,
"WindowFound": true,
"Errors": [],
"MessageEvents": 0,
"ReconnectEvents": 0,
"AgentWorkingSetBytes": 51077120,
"AgentHandleCount": 437,
"AgentThreadCount": 25,
"LastSnapshotAt": "2026-09-05T14:39:36.5158013+00:00"
},
{
"Timestamp": "2026-09-05T14:39:42.4826756+00:00",
"ProcessCount": 5,
"WorkingSetBytes": 153645056,
"HandleCount": 3535,
"ThreadCount": 183,
"WindowFound": true,
"Errors": [],
"MessageEvents": 0,
"ReconnectEvents": 0,
"AgentWorkingSetBytes": 49594368,
"AgentHandleCount": 439,
"AgentThreadCount": 25,
"LastSnapshotAt": "2026-09-05T14:39:40.6950674+00:00"
},
{
"Timestamp": "2026-09-05T14:39:47.5679204+00:00",
"ProcessCount": 5,
"WorkingSetBytes": 153632768,
"HandleCount": 3535,
"ThreadCount": 184,
"WindowFound": true,
"Errors": [],
"MessageEvents": 0,
"ReconnectEvents": 0,
"AgentWorkingSetBytes": 50147328,
"AgentHandleCount": 439,
"AgentThreadCount": 25,
"LastSnapshotAt": "2026-09-05T14:39:46.9856634+00:00"
},
{
"Timestamp": "2026-09-05T14:39:52.6503147+00:00",
"ProcessCount": 5,
"WorkingSetBytes": 153395200,
"HandleCount": 3537,
"ThreadCount": 184,
"WindowFound": true,
"Errors": [],
"MessageEvents": 0,
"ReconnectEvents": 0,
"AgentWorkingSetBytes": 51089408,
"AgentHandleCount": 439,
"AgentThreadCount": 23,
"LastSnapshotAt": "2026-09-05T14:39:51.1846333+00:00"
},
{
"Timestamp": "2026-09-05T14:39:57.7230086+00:00",
"ProcessCount": 5,
"WorkingSetBytes": 152985600,
"HandleCount": 3537,
"ThreadCount": 184,
"WindowFound": true,
"Errors": [],
"MessageEvents": 0,
"ReconnectEvents": 0,
"AgentWorkingSetBytes": 51859456,
"AgentHandleCount": 439,
"AgentThreadCount": 23,
"LastSnapshotAt": "2026-09-05T14:39:57.4318646+00:00"
},
{
"Timestamp": "2026-09-05T14:40:02.1355012+00:00",
"ProcessCount": 5,
"WorkingSetBytes": 152502272,
"HandleCount": 3537,
"ThreadCount": 184,
"WindowFound": true,
"Errors": [],
"MessageEvents": 0,
"ReconnectEvents": 0,
"AgentWorkingSetBytes": 52297728,
"AgentHandleCount": 442,
"AgentThreadCount": 23,
"LastSnapshotAt": "2026-09-05T14:40:01.6026352+00:00"
}
],
"MessageEvents": 0,
"ReconnectEvents": 0,
"WorkingSetGrowthBytes": -1495040,
"HandleGrowth": 2,
"ThreadGrowth": 1,
"Healthy": true,
"Findings": [],
"RequestedSeconds": 30,
"ObservedSeconds": 30.0794228,
"CompletedDuration": true
}
@@ -0,0 +1,56 @@
{
"BinarySha256": "5899FD7A07E85B9C20679E06012CB0ED494F96916A8C58F81ACFC533286CA009",
"Passed": true,
"OperatingSystem": "Microsoft Windows NT 10.0.19044.0",
"Results": [
{
"ExitCode": 0,
"Name": "recover",
"StartedAt": "\/Date(1788619114443)\/",
"FinishedAt": "\/Date(1788619157247)\/"
},
{
"ExitCode": 0,
"Name": "doctor",
"StartedAt": "\/Date(1788619157248)\/",
"FinishedAt": "\/Date(1788619157696)\/"
},
{
"ExitCode": 0,
"Name": "inspect",
"StartedAt": "\/Date(1788619157696)\/",
"FinishedAt": "\/Date(1788619158434)\/"
},
{
"ExitCode": 0,
"Name": "smoke",
"StartedAt": "\/Date(1788619158434)\/",
"FinishedAt": "\/Date(1788619160226)\/"
},
{
"ExitCode": 0,
"Name": "recovery",
"StartedAt": "\/Date(1788619160226)\/",
"FinishedAt": "\/Date(1788619162163)\/"
},
{
"ExitCode": 0,
"Name": "listener",
"StartedAt": "\/Date(1788619162163)\/",
"FinishedAt": "\/Date(1788619171785)\/"
},
{
"ExitCode": 0,
"Name": "stability",
"StartedAt": "\/Date(1788619171785)\/",
"FinishedAt": "\/Date(1788619202188)\/"
},
{
"ExitCode": 0,
"Name": "diagnose",
"StartedAt": "\/Date(1788619202188)\/",
"FinishedAt": "\/Date(1788619203080)\/"
}
],
"SessionId": 1
}