Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Primary Issue
Closes #58
Target Version
3.0-dev
Scope
修复 WebSocket 送达 ACK 的两处完整性问题:客户端伪造消息/会话水位线可以影响持久游标,以及先删除 Redis unacked、再调用 Message 导致失败后无法重传。
Push 从连接对应的 Redis 持久 payload 恢复可信消息身份;Message 在同一加锁事务内检查有效成员并单调推进
last_ack_seq;只有 RPC 传输与业务响应都成功,Push 才按原 payload 比较删除待确认记录。回调持有 channel 和 Redis 客户端,设置三秒超时、关闭隐式 RPC 重试,失败保留已有重传状态。增加拒绝、失败、收敛计数与真实全栈故障/兼容性测试。Non-goals
本增量不解决全部 #58 验收项,也不是上线候选的完成声明。保留现有 HTTP
update_read_ack路由;内部调用方认证仍由 #61 跟踪。尚未实现最老 pending age、独立 ACK intent worker、Redis 持久性升级、无限期离线收敛、多实例容量或全部崩溃点注入。不修改MarkRead、消息序号分配、数据库 schema、Protobuf wire 格式或附件权限。本分支包含下述明确声明的前置 PR。Architecture Impact
Yes — Push 到 Message 的确认边界改为先提交 MySQL、后清理 Redis;继续由 Message 拥有送达游标,Push 拥有设备投递状态,没有跨库原子事务或新服务。
Core-flow Impact
Yes — 改变 ACK 的可信数据来源、事务内成员校验、成功定义、删除顺序及故障重放;客户端仍需要在现有 TTL 内通过心跳和再次 ACK 参与收敛。
Updated Skills
.agents/skills/chatnow-orienting/references/core-flows.md.agents/skills/chatnow-orienting/references/technology-stack.md.agents/skills/chatnow-testing/references/case-catalog.md.agents/skills/chatnow-testing/references/framework.mdRED Evidence
虚拟机
/home/icepop/issue58-audit保存完整 stdout/stderr;本地证据归档目录为E:/Code/Github_storage/ChatNow/.git/codex-audits/2026-09-14/issue58。以下均在对应生产修复前观察到行为断言失败:tests)go test -tags=func ./func/... -run '^TestFN_WS_DeliveryAckRejectsForgery$' -v -count=1 -timeout=120sseq_id/message_id/conversation_id改变权威投递状态ack-forgery-red.loggo test -tags=reliability ./reliability/... -run '^TestRL_DeliveryAckRetainedDuringMessageOutage$' -v -count=1 -timeout=120sack-outage-red.loggo test -tags=func ./func/... -run '^TestFN_MS_DeliveryAckMembershipRace$' -v -count=1 -timeout=60sack-membership-red.log初版伪造测试还误把省略可选水位线视作非法;核对协议后删除该错误预期,并独立验证兼容省略字段的 ACK。该纠正不替代以上三类真实伪造 RED。初次完整功能回归另发现控制通知 ACK 携带会话上下文被新分支拦截,
functional.log中 194 项通过、1 项失败;保留原测试断言修正生产分支,目标回归已通过。GREEN Evidence
提交:
b9d6bfbf815ee46957f84979a0bda82e87d3ab01。本地虚拟机使用独立源码目录
/home/icepop/ChatNow-ack-58和原有合成 Compose 栈。9 个服务重新编译、打包并部署,running-binaries.json显示运行产物与本轮 native binary 的 SHA-256 全部一致。没有使用真实业务数据。go test -tags=func ./func/... -run '^TestFN_(WS_DeliveryAck|MS_DeliveryAck|CA_UnackedSameUserSeqLatestPayloadAndAck)' -v -count=1 -timeout=120s:exit 0,5 个顶层用例、6 个伪造子用例通过,12.136 秒;完整结果ack-target-unified.log。覆盖成员竞争、可选字段、重复/乱序、业务失败、六类身份伪造及原控制通知兼容回归。独立故障用例已观察到 Message 停机保留状态、Push 重启、相同设备重连、心跳重放及再次 ACK 后 Redis/MySQL 收敛:
ack-outage-final.log,exit 0,25.000 秒。最终统一镜像的完整 Reliability 已失败,不能据此宣布最终门禁通过。首次重连失败ack-outage-green.log也保留,修复的是测试在 Push 重启后等待实际 WebSocket upgrade 的就绪条件。Regression Verification
go test ./pkg/contracts ./pkg/agentpolicy ./cmd/agent-policy ./pkg/client ./pkg/cleanup ./pkg/chaos -count=1,static-unified.log,exit 0。cmake -S /home/icepop/ChatNow-ack-58 -B /home/icepop/ChatNow-ack-58/build -DCMAKE_BUILD_TYPE=Release;cmake --build /home/icepop/ChatNow-ack-58/build --target conversation_server gateway_server identity_server media_server message_server presence_server push_server relationship_server transmite_server --parallel 2,exit 0,configure.log/build-all.log。控制通知修正后 Push 单独重编译 exit 0,build-push-compatibility.log。go vet -tags=func,reliability,perf ./...与test -z "$(gofmt -l .)",exit 0,vet-final.log/fmt-final.log。go test -race ./pkg/client ./pkg/chaos ./pkg/cleanup -count=1,exit 0,race-support.log。make test-bvt,18 项通过,6.560 秒,bvt-unified.log,exit 0。make test-func,195 项通过,279.820 秒,functional-unified.log,exit 0。此前失败轮次完整保留,兼容性修复后重新执行完整层。make test-scenario,12 项通过,37.710 秒,scenario-unified.log,exit 0;这些是 Functional 中的场景子集,另外单独执行。CHATNOW_ACK_BENCH=1 go test -tags=perf ./perf/... -run '^$' -bench '^BenchmarkPF10_DeliveryACK$' -benchtime=100x -count=1 -timeout=180s,exit 0,140.5 ACK/s、562.0 SQL/s、4 SQL/ACK、P95 9678 us、P99 10934 us,ack-perf-unified.log。初次同配置各 100 次样本:旧实现 125.8 ACK/s、754.5 SQL/s、6 SQL/ACK、P95 9717 us、P99 12401 us;初版修复 134.5 ACK/s、537.9 SQL/s、4 SQL/ACK、P95 11177 us、P99 12378 us。完整日志ack-perf-baseline.log/ack-perf-candidate.log;顺序低负载测试,包含查询分辨率与后台 SQL 影响,不是生产 SLO 或容量承诺。make test-reliability,exit 2,141.765 秒,8 个顶层通过、1 个失败。RL-ACK-01 在故障注入前发消息即返回 9002 / brpc E112(无法选择 Transmite endpoint),所以本轮没有进入 ACK 故障断言。控制器采用合成低限流配置,finally已恢复配置并检查服务。完整结果reliability.log/reliability-exits.json。继续按 Diagnose intermittent message RPC unavailability in functional CI #104 调查服务重建后的就绪放行和实际 RPC 可用性差异。source-equivalence-final.json明确记录差异;没有把环境生成文件提交进增量。Security and Compatibility
Security: WS ACK 绑定已认证连接 user/device 和服务端保存的消息 ID、用户投递序号、会话 ID、会话序号;异常路径保留重试状态。SQL 参数由 ODB 绑定。新增日志不输出 token、payload、用户或设备 ID。HTTP/direct RPC 的可信水位线边界尚未闭环,不能声称全部入口已抗伪造。
Compatibility: 保留 ACK 可选水位线、省略字段、控制通知携带会话上下文、重复和乱序处理;三个序号域和已读语义独立。退出成员返回既有 3002,事务不可用返回可重试 9002。旧 Push 仍有提前删除风险,混合版本滚动期间不能承诺新保证。
Migration: 本增量无 schema、Redis key 格式或 Protobuf 迁移。部署使用新 Message 和 Push;完成所有 Push 替换后才可评估新边界。现有 unacked TTL 与 Redis 持久性不变。前置栈的初始化/迁移约束见各前置 PR,本地合成栈证据不覆盖生产升级。
Unverified Items
update_read_ack仍接受客户端水位线,内部调用方认证仍缺失(Authenticate internal RPC callers and protect forwarded auth context #61);WS 修复不能证明全入口可信。/home/icepop/issue104-recovery-audit/full-reliability.log);三次单独恢复通过不能证明根因已修复。Investigate Identity worker crash after account smoke tests #96 历史 Identity 崩溃没有新 core 或明确根因。Rollback Plan
若新增 ACK 拒绝或收敛失败影响正常投递,先保留 MySQL 与 Redis 现场和脱敏诊断,停止推进发布;合成 VM 可恢复已保留的旧运行镜像后验证就绪,不删除数据。旧版本会重新暴露提前清理和不可信水位线风险,生产回滚由人工负责人权衡并批准。本增量不回退数据库水位线、不做数据清空。
Stacked PR Dependencies
Dependency: #89、#98、#100、#103、#106、#107、#109、#111;直接前置
fix/104-message-readiness-diagnostics@e3acfd6f739625e0d7ace8fd441d158fb2db36c7。Final target version: 3.0-dev
Merge order: #89 → #98 → #100 → #103 → #106 → #107 → #109 → #111 → 本 PR。#110 是未包含的独立同级构建候选。
After predecessor merge: 保留公开历史,安全同步已合入的
3.0-dev,重新核对完整 diff、冲突及当前 HEAD 全部适用门禁;目标仍为3.0-dev,由人工合并。Full-diff Self-review
Base and range:
origin/3.0-dev...HEAD,merge-base 为b3f962ef70a0433b4dd4393a0ad98a45efb75898;本增量从e3acfd6f739625e0d7ace8fd441d158fb2db36c7开始。Verdict: Draft / not ready。已核对范围清单、前置提交、生产调用链、初始化/配置、测试断言、生成文件来源及 Skill 同步;本增量仅包含 ACK 与所需测试/参考更新。完整前置 diff 包含既有 TLS、RPC 信任、MQ、迁移和故障恢复缺口,不能把本增量的目标通过解释为整个堆叠已经完成上线评审。已检查本增量全部 17 个暂存文件,未加入凭据或环境生成文件,暂存 diff 检查通过;完整日志和源码指纹保留在上述审计目录。