From 67b2e58fdfa8b8960077c647af93a7582a17d7ec Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 5 Oct 2026 13:58:20 +0800 Subject: [PATCH] =?UTF-8?q?docs(05):=20=E9=94=9A=E7=82=B9=E8=A1=A5?= =?UTF-8?q?=E8=AE=B0=E5=8D=81=E4=B8=80=E2=80=94=E2=80=94W40=20=E6=99=AE?= =?UTF-8?q?=E9=80=9A=E5=8F=91=E9=80=81=E6=9C=AA=E8=BF=9E=E6=8E=A5=E6=97=B6?= =?UTF-8?q?=E8=BF=9B=E9=98=9F=E5=88=97=EF=BC=88=E4=B8=BB=E4=BA=BA=E5=AE=9A?= =?UTF-8?q?=E6=A1=88=E8=90=BD=E5=9C=B0=EF=BC=89=EF=BC=8C=E5=B9=B6=E7=99=BB?= =?UTF-8?q?=E8=AE=B0=20REST=20=E6=9C=AA=E8=A6=86=E7=9B=96=E4=B8=8E?= =?UTF-8?q?=E4=B8=89=E6=9D=A1=E5=BE=85=E5=8A=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 记下这一批的口径与证据,供下一个会话接续: - 分支 feat/W40-send-queue-offline(基线 e60ae7a),代码与测试提交 df9fc85;未合并、未推送。 - 证据:assembleDebug 成功;testDebugUnitTest 1118 / 0 失败 / 0 错误 / 0 跳过(83 套件)。 本批没有真机回归。 - 判据:wsSendOutcome 三档(Dispatched / Queued / Failed);补发触发点是连接状态流变成 Connected 那一刻,无轮询;顺序 = 用户发送先后顺序;只发一次的保证点是队头加出队恰好一次, 第二道是复用同一个 clientMsgId。 - 状态表达:不新增第七态(等连接仍是 ③ 排队中),气泡小标加成「排队中 · 还没连上」, 另有一条柔和的 sendQueueNotice 告知(一轮队列只说一次,Offline 那一档说的是 重新登录 / 检查服务器地址)。 - REST 通道(长文 / 图片 / 附件)本批未覆盖,仍走回滚加既有网络错误文案,理由与影响面写在 补记里。 - 待办里更新了四条:真机回归、REST 要不要也排队(需主人定案)、Offline 立刻告知、 以及那一处刻意未动的失败文案字面量。 --- devdocs/05-开发进度与交接.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/devdocs/05-开发进度与交接.md b/devdocs/05-开发进度与交接.md index 6ee96c7..ff12ead 100644 --- a/devdocs/05-开发进度与交接.md +++ b/devdocs/05-开发进度与交接.md @@ -870,3 +870,31 @@ curl -s -X PATCH "$BASE/api/v1/sessions/$SID" -H "Authorization: Bearer $TOK" \ > 3. `Offline` 立刻告知(不等 3 秒)。 > 4. **W38/W39 的真机回归**:W38 已验(补记九);W39 这三条只在真机上扫一眼即可(触发条件都少见)。 > 5. 旧账:子会话流程(主人搁置)、图片/工具卡实机验证(后端未配工具)、**相册多选→分享**(图片路径仍需真机;App 一个权限都没声明 ⇒ adb 造不出可读 URI,这条**只能**走真机或驱动相册 UI)。 + +> ## ★★ 锚点补记十一(2026-10-05 · W40:普通发送「未连接 ⇒ 进队列」,不再回滚) +> +> ### 状态 +> - worktree 分支 `feat/W40-send-queue-offline`(基线 `e60ae7a`),分支提交 **`df9fc85`**;**未合并、未推送**(主树与 `origin/android` 都没动)。 +> - 本批证据:`assembleDebug` 成功;`testDebugUnitTest` **1118 测试 / 0 失败 / 0 错误 / 0 跳过**(83 套件)。**没有真机回归**(这一批只有单测与编译证据)。 +> - 净变化:W39 加的 `SendFailureMessageTest`(4 条)**删掉**,其断言改成新事实后并入新的 `SendQueueTest`(21 条)⇒ 1101 − 4 + 21 = 1118。 +> +> ### ① 主人的裁决落地:未连接 ⇒ 进队列(上一批的「待办 1」已定案并做完) +> - 新纯函数 `wsSendOutcome(sent, connection)`(`ui/chat/SendQueue.kt`)三档:`Dispatched`(帧交给 socket;**成功路径一个字没动**)/ `Queued`(未就绪四档:Idle / Connecting / Reconnecting / Offline)/ `Failed`(连接就绪却仍发不出去 ⇒ 今天那条 `rollback` + `SEND_FAILED_MESSAGE`)。 +> - `deliver` 的 WS 分支**只改「未就绪」这一支**:不回滚、不进 `error` 横幅,改由 `queueForConnection` 留在待发态(`ChatUiState.queuedForConnection`:条目只有键与并行声明,正文仍从气泡上现取)。 +> - **触发点**:`onConnectionChanged` 里 `connection == WsState.Connected` 那一格(由 `socket.state` 驱动,**无轮询**)+入队后的竞态兜底。 +> - **顺序**:FIFO = 用户发送的先后顺序;补发只看队头。**只发一次**:队头 + 出队恰好一次(`dropQueuedSend`);第二道是补发复用同一个 `clientMsgId`(服务端 `chat_duplicate` 判重)。`flushQueuedSends` 是同步函数(无挂起点),两个触发点不会交错。 +> - ⚠️ **已知边界**:打断声明(`interrupt{scope:"current"}`)不随补发重放(补发时在跑的那一轮早已不是用户按发送时看到的那一个);内容仍只在**进程内存**里,一直连不上又杀进程就丢(既有语义)。 +> +> ### ② 状态表达:③ 排队中 + 小标「还没连上」,**不新增第七态** +> - `phaseOf(待发气泡)` 的 ③ 判据扩为「收到过入队回执 **或** 本端因未连接留住」;气泡小标由新纯函数 `pendingBubbleFooter` 给:`排队中 · 还没连上`(服务端忙时排队仍是 `排队中`)——挂在气泡上而不是只靠告知,因为告知 8 秒就收走,而这是会持续几十秒的状态。 +> - 柔和告知走**新通道** `ChatUiState.sendQueueNotice`(与 `shareNotice` 分开:两条说不同的动作):`SEND_QUEUED_NOTICE = "还没连上,这条排队等着,连上后自动发出"`;`Offline` 那一档换 `SEND_QUEUED_OFFLINE_NOTICE = "现在处于离线,需要重新登录或检查服务器地址;这条还没发出去,已排队不会丢"`(**不提**「连上」「自动发」)。**不刷屏**:一轮「队列从空到空」只说一次。 +> +> ### ③ REST 通道(长文 / 图片 / 附件)**未覆盖**,仍是回滚 + 网络错误文案 +> 理由:它给不出「未连接」这个信号(只有一次网络错误,请求可能已被服务端收到),且补发要重跑图片重编码与附件上传(本地 URI 授权可能已失效)。影响面仅这一条通道。 +> +> ### 待办(更新) +> 1. **W40 的真机回归**:断网发普通消息 ⇒ 应看到「排队中 · 还没连上」+ 柔和告知(**没有**红色横幅、输入栏不退回)⇒ 恢复连接 ⇒ 自动补发且只落库一条。 +> 2. REST 通道(长文 / 图片 / 附件)未连接时要不要也排队——需主人定案(代价见 ③)。 +> 3. `Offline` 立刻告知(不等 3 秒)——W39 遗留,未动。 +> 4. **未纳入新判据的一处字面量**:REST 回执被拒那条路仍是 `rejected.message.ifBlank { "发送失败,请重试" }`,刻意未动。 +> 5. 旧账:子会话流程(主人搁置)、图片/工具卡实机验证(后端未配工具)、**相册多选→分享**(只能走真机或驱动相册 UI)。