From de2c64d1111d4f594e658c6dd638814d67380fbf Mon Sep 17 00:00:00 2001 From: Nixevol Date: Wed, 30 Sep 2026 10:45:28 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=A7=A3=E6=95=A3=E7=BE=A4=E4=BD=9C?= =?UTF-8?q?=E5=BA=9F=20scheduled=20=E6=97=B6=E6=B6=88=E6=81=AF=E7=BA=A7?= =?UTF-8?q?=E5=9B=9E=E6=89=A7=E6=94=B9=E7=94=A8=20rejected?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/DEVIATIONS.md | 9 +++++++++ internal/app/group/group_test.go | 10 ++++++++++ internal/app/group/void.go | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/DEVIATIONS.md b/docs/DEVIATIONS.md index 3ebcd47..ecd1ed3 100644 --- a/docs/DEVIATIONS.md +++ b/docs/DEVIATIONS.md @@ -1092,3 +1092,12 @@ - 原因:同一连接上 `group.create`/`group.add` 同步向本连接注入下行时,与 mochi InlineClient 互相等待,`resp` 回不去(`TestUplinkDMOfflineGroupRecall` 在清掉测试客户端 dial deadline 后稳定复现)。 - 备选方案:broker 层对 Inline 发布做无锁队列。 - 影响:`group_event` 可能略晚于 `resp` 到达;业务结果仍以 `resp` 为准。 + +### fix-issue-6 + +1. **解散群时 scheduled 消息级回执 state 改为 rejected** + - 原条款:DEVELOPMENT 6.4 消息级作废写 `endpoint_id` 空、`state=rejected`;7.6 解散群将 `scheduled` 消息改为 `completed`/`group_dissolved` 并写消息级回执。I4 旧实现把回执 state 误写成消息状态 `completed`。 + - 实际做法:`internal/app/group/void.go` 的 `voidGroupAllTx` 插入回执时改用 `rejected`(与 I5.2 / identity lifecycle 一致);消息行仍为 `completed`。 + - 原因:`completed` 不在回执枚举(accepted|recalled|expired|dropped|rejected)内,会误导 SDK/后台。 + - 备选方案:沿用 `completed`(违反协议)。 + - 影响:仅修正解散路径回执字段;不改 emit / PublishDown。 diff --git a/internal/app/group/group_test.go b/internal/app/group/group_test.go index 85eda56..cb18641 100644 --- a/internal/app/group/group_test.go +++ b/internal/app/group/group_test.go @@ -296,6 +296,16 @@ WHERE m.id='gm1' AND d.endpoint_id='bob'`).Scan(&reason) if err != nil || state != "completed" || mreason != "group_dissolved" { t.Fatalf("state=%s reason=%s err=%v", state, mreason, err) } + // 消息级回执 state 须为协议枚举 rejected,不得写成消息状态 completed(issue #6 / DEVELOPMENT 6.4) + var rState, rReason, rEndpoint string + err = db.Read.QueryRow(` +SELECT state, reason, endpoint_id FROM receipts WHERE sender_id='alice' AND msg_id='gm2'`).Scan(&rState, &rReason, &rEndpoint) + if err != nil { + t.Fatalf("receipt for dissolved scheduled: %v", err) + } + if rState != "rejected" || rReason != "group_dissolved" || rEndpoint != "" { + t.Fatalf("receipt state=%q reason=%q endpoint=%q want rejected/group_dissolved/empty", rState, rReason, rEndpoint) + } // 同编号新建群 created2, err := gApp.Create(ctx, "alice", &protocol.GroupCreate{ V: protocol.Version, Type: protocol.TypeGroupCreate, RID: "6", diff --git a/internal/app/group/void.go b/internal/app/group/void.go index 7411ad0..73d30c3 100644 --- a/internal/app/group/void.go +++ b/internal/app/group/void.go @@ -139,10 +139,11 @@ UPDATE messages SET state = 'completed', reason = ? WHERE seq = ? AND state = 's return execErr } if r.receipt != 0 { + // 消息级作废回执:endpoint_id 空,state=rejected(DEVELOPMENT 6.4);消息行仍为 completed if _, execErr := tx.Exec(` INSERT INTO receipts(sender_id, msg_id, endpoint_id, state, reason, created_at, acked) VALUES(?,?,?,?,?,?,0)`, - r.senderID, r.msgID, "", "completed", reasonGroupDissolved, nowMs); execErr != nil { + r.senderID, r.msgID, "", "rejected", reasonGroupDissolved, nowMs); execErr != nil { return execErr } }