diff --git a/docs/validation/WxAgent-会话消息同步-P4-build-manifest.json b/docs/validation/WxAgent-会话消息同步-P4-build-manifest.json new file mode 100644 index 0000000..4759728 --- /dev/null +++ b/docs/validation/WxAgent-会话消息同步-P4-build-manifest.json @@ -0,0 +1,41 @@ +{ + "implementation_commit": "e534e46", + "build_commands": [ + "cd control-plane && go build -o ./cmd/wxagent-control-plane", + "dotnet publish node-agent/WxAgent.Tray -c Release -r win-x64 --self-contained true -p:EnableWindowsTargeting=true -p:PublishSingleFile=true -p:PublishTrimmed=false" + ], + "artifacts": { + "control_plane_sha256": "0bd1cd062a87561a6753062696f63a141ca41c89eaf9640e8f299319bf26edc7", + "tray_sha256": "72b4aae3347cc054f9787fb84924101346eceed4acc632cab555a754d7260b71", + "windows_deployed_tray_sha256": "72b4aae3347cc054f9787fb84924101346eceed4acc632cab555a754d7260b71" + }, + "validation_environment": { + "windows_host": "DESKTOP-EGI7QCK", + "windows_build": "10.0.19044.0", + "wechat_version": "4.1.13.65", + "interactive_session": 1, + "deployment_path": "C:\\Users\\Rogee\\wx-agent01", + "verified_accounts_present": 1, + "verified_page_hmac_databases": 20, + "raw_database_or_key_content_committed": false + }, + "automated_validation": { + "web_tests": "4/4", + "core_tests": "173/173", + "service_tests": "25/25", + "go_tests": "go test ./... passed", + "solution_build": "Release with EnableWindowsTargeting passed", + "diff_check": "passed", + "synthetic_isolation": { + "accounts": 8, + "messages": 800, + "reads": 16000, + "result": "passed" + } + }, + "notes": [ + "The implementation commit is the code revision used to build and deploy the hashes above; later evidence-only documentation commits do not change implementation files.", + "This host had one page-1-HMAC-verified account, so the real-device matrix covers every verified account present on the host; multi-account isolation is additionally covered by the synthetic eight-account test.", + "Long-duration endurance, power-loss, production-scale capacity, and multi-control-plane HA remain explicitly outside this single-node P0-P4 acceptance scope." + ] +} diff --git a/docs/validation/WxAgent-会话消息同步-P4-live-evidence.json b/docs/validation/WxAgent-会话消息同步-P4-live-evidence.json index 4179ea3..f44328b 100644 --- a/docs/validation/WxAgent-会话消息同步-P4-live-evidence.json +++ b/docs/validation/WxAgent-会话消息同步-P4-live-evidence.json @@ -1,95 +1,109 @@ { - "captured_at": "2026-09-22T09:40:00+08:00", - "source_revision": "ab9ff38", + "captured_at": "2026-09-22T10:35:00+08:00", + "implementation_commit": "e534e46", + "build_manifest": "docs/validation/WxAgent-会话消息同步-P4-build-manifest.json", "artifacts": { - "control_plane_sha256": "f7695475efcf6742a2c6d8e7355029916093ad03c93fa3127c6e0534d8487fb2", - "tray_sha256": "f649cb55335e668850769e9c13e4bea5add5839e7a4a08179ede4c8895ee2bf7" + "control_plane_sha256": "0bd1cd062a87561a6753062696f63a141ca41c89eaf9640e8f299319bf26edc7", + "tray_sha256": "72b4aae3347cc054f9787fb84924101346eceed4acc632cab555a754d7260b71", + "windows_deployed_tray_sha256": "72b4aae3347cc054f9787fb84924101346eceed4acc632cab555a754d7260b71" }, - "account": { + "account_scope": { "account_id_prefix": "a2e8a1ea", + "verified_accounts_present_on_windows_host": 1, + "verified_page_hmac_databases": 20, "authorized_chat_count": 2, "raw_message_content_included": false, - "database_keys_included": false + "database_keys_included": false, + "synthetic_multi_account_isolation": { + "accounts": 8, + "messages": 800, + "reads": 16000, + "result": "passed" + } }, - "offline_replay": { + "current_live_sync": { + "node_status": "Online", + "capabilities_include": ["db-messages", "db-merged"], + "confirmed_sequence": 4, + "messages": 460, + "conversations": 2, + "coverage": "complete", + "directory_cursor_present": true, + "conversation_source": "session/session.db/SessionTable", + "directory_states": ["visible"], + "nonempty_titles": 2, + "title_equals_chat_id": 0 + }, + "offline_replay_current_binary": { "control_plane_unreachable": true, - "agent_process_session": 1, + "agent_session": 1, "queue_pending_while_unreachable": 1, - "queue_bytes_while_unreachable": 3317, - "control_plane_restarted": true, + "queue_bytes_while_unreachable": 188751, "queue_pending_after_reconnect": 0, "node_status_after_reconnect": "Online", - "messages_before_replay": 458, - "messages_after_replay": 459, - "confirmed_batches_after_replay": 5, + "messages_after_replay": 460, + "confirmed_batches_after_replay": 4, "coverage_after_replay": "complete" }, - "agent_restart_recovery": { - "messages_before": 459, - "batches_before": 5, - "confirmed_sequence_before": 5, + "agent_restart_current_binary": { "tray_stopped_seconds": 15, "tray_restarted_session": 1, "node_status_after_restart": "Online", - "messages_after": 459, - "batches_after": 5, - "confirmed_sequence_after": 5, + "queue_pending_after_restart": 0, + "messages_before": 460, + "messages_after": 460, + "batches_before": 4, + "batches_after": 4, + "confirmed_sequence_before": 4, + "confirmed_sequence_after": 4, "duplicate_batch_observed": false }, - "control_plane_crash_recovery": { + "control_plane_crash_recovery_current_binary": { "termination": "SIGKILL", "integrity_before_restart": "ok", - "messages_before_restart": 460, - "batches_before_restart": 6, - "confirmed_sequence_before_restart": 6, "integrity_after_restart": "ok", "node_status_after_restart": "Online", - "messages_after_restart": 460, - "batches_after_restart": 6, + "messages_before": 460, + "messages_after": 460, + "batches_before": 4, + "batches_after": 4, "coverage_after_restart": "complete" }, - "authorization_revoke": { - "revoke_http_status": 200, + "authorization_revoke_current_binary": { + "web_revoke_http_status": 200, "conversations_http_status_while_revoked": 403, "messages_http_status_while_revoked": 403, "sync_status_http_status_while_revoked": 200, - "authorized_test_send_exit": 0, - "pending_batches_after_revoked_send": 1, - "agent_rejection_http_status": 403, - "agent_rejection_code": "AccountNotAuthorized", - "restored_by_agent_reregistration": true, - "node_status_after_restore": "Online", - "messages_after_restore": 460, - "confirmed_batches_after_restore": 6, - "coverage_after_restore": "complete", + "node_re_registration_restored_authorization": true, "conversations_http_status_after_restore": 200, "messages_http_status_after_restore": 200 }, - "windows": { + "windows_current_binary": { "session": 1, "interactive": true, "doctor_exit": 0, "inspect_ui_exit": 0, "smoke_exit": 0, - "wechat_version": "4.1.13.65", - "windows_build": "10.0.19044.0", - "ui_tree_nodes": 166, - "scope": "File Transfer Assistant and approved test chats only", + "ui_tree_nodes": 163, "stability_smoke": { "exit": 0, - "success": true, "healthy": true, "sample_count": 7, "message_events": 0, "reconnect_events": 0, - "working_set_growth_bytes": 1273856, - "handle_growth": 12, - "thread_growth": 2 - } + "working_set_growth_bytes": 1298432, + "handle_growth": 8, + "thread_growth": 2, + "findings": [] + }, + "wechat_version": "4.1.13.65", + "windows_build": "10.0.19044.0", + "scope": "File Transfer Assistant and approved test chats only" }, "notes": [ - "The offline batch was observed in the durable queue before the control plane was restarted and drained after reconnect.", - "The authorization-revoked message was accepted by the test WeChat UI but remained in the Agent queue; the platform rejected it and did not ACK it until authorization was restored.", - "Long-duration endurance, power-loss, multi-control-plane HA, and production-sized capacity are separate follow-up validation, not represented as passed by this artifact." + "The real-device host had exactly one page-1-HMAC-verified account; the real-device matrix therefore covered every verified account present on that host.", + "Conversation rows were accepted from the actual session database and carried source session/session.db/SessionTable; no conversation title equaled chat_id.", + "No raw WeChat database, database key, message body, contact name, or secret was committed.", + "Long-duration endurance, power-loss, production-scale capacity, and multi-control-plane HA remain explicitly outside this single-node P0-P4 acceptance scope." ] } diff --git a/docs/validation/WxAgent-会话消息同步-P4-验收记录.md b/docs/validation/WxAgent-会话消息同步-P4-验收记录.md index 3ae5e99..7cbd797 100644 --- a/docs/validation/WxAgent-会话消息同步-P4-验收记录.md +++ b/docs/validation/WxAgent-会话消息同步-P4-验收记录.md @@ -1,9 +1,9 @@ # 会话消息同步与分账号存储:P4 验收记录 > 验收日期:2026-09-22(+08:00) -> 源码基线:`ab9ff38`(实现变更已在本地提交) -> 控制面验收二进制:`/tmp/wxagent-control-plane-final5`,SHA-256:`f7695475efcf6742a2c6d8e7355029916093ad03c93fa3127c6e0534d8487fb2` -> Tray 验收二进制:`/tmp/wxagent-tray-publish-final8b/WxAgent.Tray.exe`,SHA-256:`f649cb55335e668850769e9c13e4bea5add5839e7a4a08179ede4c8895ee2bf7` +> 实现源码提交:`e534e46`;构建/部署映射见 [`P4 build manifest`](WxAgent-会话消息同步-P4-build-manifest.json) +> 控制面 SHA-256:`0bd1cd062a87561a6753062696f63a141ca41c89eaf9640e8f299319bf26edc7` +> Tray SHA-256(Linux 构建与 Windows 部署一致):`72b4aae3347cc054f9787fb84924101346eceed4acc632cab555a754d7260b71` ## 1. 自动化回归 @@ -47,20 +47,21 @@ SQLite 运行约束:WAL、`synchronous=FULL`、foreign keys、5 秒 busy timeo - `session_id=1`, `interactive=True` - WeChat `4.1.13.65`,Windows build `10.0.19044.0` - Doctor:`MainView`、`session_list`、`chat_message_page`、`chat_message_list`、`chat_input_field`、`tool_bar_accessible` 全部存在。 -- UI 快照 166 个节点,已脱敏;smoke 发送确认目标为 File Transfer Assistant,未启用 Web 发送。 +- UI 快照 163 个节点,已脱敏;smoke 使用 `--read-only`,未启用 Web 发送。 非交互 SSH Session 0 的失败结果不作为真机验收结果;它只证明 Session 0 必须拒绝 UIA 操作。 -## 4. 真机同步、断线补传、进程重启与授权撤销 +## 4. 真机同步、目录来源、断线补传、进程重启与授权撤销 -完整、脱敏的事件计数见 [`WxAgent-会话消息同步-P4-live-evidence.json`](WxAgent-会话消息同步-P4-live-evidence.json)。关键结果: +完整、脱敏的事件计数见 [`WxAgent-会话消息同步-P4-live-evidence.json`](WxAgent-会话消息同步-P4-live-evidence.json)。二进制构建与部署映射见 [`P4 build manifest`](WxAgent-会话消息同步-P4-build-manifest.json)。关键结果: -- **断线补传**:控制面不可达时 Agent durable queue 观察到 1 个 pending batch(3317 bytes);控制面恢复后队列降为 0,节点回到 `Online`,副本从 458 条消息/4 批次推进到 459 条消息/5 批次,coverage=`complete`。 -- **Agent 进程重启**:停止 Tray 15 秒后以交互 Session 1 重启;重启前后均为 459 条消息、5 批次、confirmed sequence=5,无重复批次,节点重新 `Online`。 -- **授权撤销**:控制面 revoke 返回 200;撤销期间 conversations/messages 均返回 403,sync-status 仍可读。测试消息发送成功但平台拒收,Agent 日志记录 `AccountNotAuthorized/status=403`,队列保留 1 个批次;Tray 重新注册恢复授权后队列清空,副本到 460 条消息/6 批次,查询恢复 200。 -- **控制面崩溃恢复**:对 live 控制面执行 SIGKILL,重启前后 SQLite `integrity_check=ok`,消息/批次保持 460/6,节点重新 `Online`,coverage=`complete`。 -- **短时稳定性**:Windows `stability-smoke` 60 秒、7 次采样通过,healthy=true、messageEvents=0、reconnectEvents=0、无 findings。 -- **副本最终状态**:2 个已授权会话,coverage=`complete`,`idx_conversations_activity`、`idx_messages_chat_time`、`idx_messages_observed_at` 均存在。 +- **真实会话目录**:当前二进制从 `session/session.db/SessionTable` 读取目录后再应用 Reporting scope;副本 2 条会话均带该 source、`directory_state=visible`,标题非空且没有一条标题等于 `chat_id`,不再从 scope 合成 `observed` 会话。 +- **当前能力注册**:节点注册 capability 包含 `db-messages`、`db-merged`;Windows 主机当前仅有 1 个 page-1-HMAC 验证账号、20 个已验证数据库,因此真机矩阵覆盖该主机全部已验证账号;8 账号合成隔离压力另行通过。 +- **断线补传**:使用实现提交 `e534e46` 的 Tray;控制面不可达时 durable queue 观察到 1 个 pending batch(188751 bytes),控制面恢复后队列降为 0,节点回到 `Online`,副本达到 460 条消息/4 批次,coverage=`complete`。 +- **Agent 进程重启**:停止 Tray 15 秒后以交互 Session 1 重启;重启前后均为 460 条消息、4 批次、confirmed sequence=4,无重复批次,节点重新 `Online`。 +- **授权撤销**:使用 Web Bearer session,revoke 返回 200;撤销期间 conversations/messages 返回 403、sync-status 保持 200;Tray 重新注册恢复授权后 conversations/messages 恢复 200。 +- **控制面崩溃恢复**:对当前 live 控制面执行 SIGKILL,重启前后 SQLite `integrity_check=ok`,消息/批次保持 460/4,节点重新 `Online`,coverage=`complete`。 +- **短时稳定性**:当前二进制 Windows `stability-smoke` 60 秒、7 次采样通过,healthy=true、messageEvents=0、reconnectEvents=0、无 findings。 测试机 `service.json` 显式开启 `EnableDataSync` 仅用于本次白名单影子/真机验收(5 秒周期、100 条批次上限);代码默认仍为关闭。Reporting 白名单仍只包含文件传输助手、Hao 豪、吉祥三宝和消息测试专用群组范围。 @@ -83,4 +84,4 @@ SQLite 运行约束:WAL、`synchronous=FULL`、foreign keys、5 秒 busy timeo - 所有微信版本、所有数据库分片布局及 page 1 HMAC 失败样本的真机矩阵。 - 生产备份介质上的异机恢复与定期恢复演练。 -这些项目已列为后续运维/发布专项;本轮已完成授权测试账号的影子同步、断线补传、进程重启恢复、授权撤销和平台读取切换。旧 `/v1/reads/*` 仍保留,其他账号仍保持默认关闭,避免把本轮单账号证据扩大成生产容量承诺。 +这些项目已列为后续运维/发布专项;本轮已完成该 Windows 主机全部已验证账号的影子同步、断线补传、进程重启恢复、授权撤销和平台读取切换。旧 `/v1/reads/*` 仍保留,代码默认同步关闭;不得把单主机账号证据扩大成生产容量承诺。