diff --git a/devdocs/02-前后端协同事项.md b/devdocs/02-前后端协同事项.md index 6c5ccb0..765fbf6 100644 --- a/devdocs/02-前后端协同事项.md +++ b/devdocs/02-前后端协同事项.md @@ -544,3 +544,48 @@ - 你们 §一 那条**流程欠账自认**、以及「从现在起形状变动先登记再改」的承诺 —— 收到,这条对我们很关键(我们是在你们的帧上做分级渲染的)。 - §六 的两件预告(IM 历史转录 / 语音三件套 + `GET /api/v1/media/{name}`)收到;**IM 转录落地对我们零改动**,已按你们说的不动作。 - 语音那条:客户端目前**只做了录音入口的规划**,等你们 v0.67 形状定稿**登记后**我们再开。 + +--- + +### 客户端答复(2026-10-05 晚 · 回执十九的答复:§四 那两个信息 + `kind`/`leg` 与 v0.67 确认) + +#### 一、§四 你们要的两个信息 + +**1. 时间点**:**2026-10-05 11:56**(本机 `+08:00`,与你们日志同时区)。精确锚点: +**`GET /ws/chat status=200` 记在 `11:56:08.077`**(你们那行「握手成功那一刻」的中间件日志)⇒ 界面上的失败横幅 + 正文退回输入栏出现在**其后约 10 秒内**; +随后我用**界面按钮**把**同一段文本**发出去并成功,落库 **`11:56:27.8`**(`turn-b618432ddb21ed42`)。**这 20 秒窗口可以把那次失败夹住。** + +**2. socket 状态 + 是否收到 `error` 帧**: + +- **没有收到任何 `error` 帧。** 证据是**横幅文案本身**:那条「发送失败,请重试」在客户端**只有一处**产生点(`ChatViewModel.kt:1283`),条件是 `socket.sendChat(...)` 返回 `false`; + 服务端定向 `error` 帧走**另一条**通道(会把你们给的原文当横幅显示),**不是这句**。⇒ **帧在客户端就没发出去**,与你们「符合『帧根本没到达我们』」的判断一致。 +- **为什么会发不出去**:那条路径是**分享**(`ACTION_SEND`)而不是按钮。分享的消费点有一道「等连接」的门(`ChatScreen.kt:338-343`),但它**把 `withTimeoutOrNull` 的返回值丢掉了** + ⇒ **超时与成功走同一条下游**:照样 `sendShared` → `deliver` → WS 发送。于是「等 3 秒没等到」在用户眼里**等于**「发送失败」。 + 而**按钮那条路完全不等**(`ChatViewModel.kt:1029-1036`)—— 人是看着「已连接」按的,所以它总能成。 +- ⚠️ **诚实边界**:客户端**全项目没有一行 `android.util.Log`**(项目现状),所以「投递那一刻 `WsState` 究竟是 `Connecting` 还是 `Reconnecting`」我们**没有直接日志**,只能由上两条推断。 + 我们界面副标题显示的是 `ws.state` 的**主线程镜像**(`ChatViewModel.kt:797` / `813-825`),写方在 IO 线程 ⇒ 它**可以滞后**,所以我们**不拿「界面显示已连接」当证据**。 + +#### 二、你们的建议:**采纳**,我们这侧已有具体落点 + +「把『允许发送』绑在**握手完成**之后,而不是绑在 socket 对象已创建上」——同意,这正是我们查出的那处缺陷。修法方向(**不需要你们做任何事**): + +1. 让「等到连接」的结果**参与决策**:超时就不再当成「发送失败」,而是**如实告知「还没连上」**,且**不把内容丢掉**(现在是内容被取走 → 发失败 → 只剩输入栏那一份,holder 里的重试资格没了)。 +2. 同源缺陷一并修:分享内容**一条都没读进来时是完全静默的**(用户点了分享、什么都没发生)—— **已修**(`6cdf111`)。 + +#### 三、`kind` / `leg`:确认收到,感谢把「取值集合」立为契约面 + +- 结论已写进 `05`:**判并行只看 `kind`,`leg` 只当序号**;`kind:"turn"` 的帧里 `leg` 一直涨是**本意**(我们之前误读成「并行组内序号」,已在 `39a63f8` 修正)。 +- 「增删 `kind` 取值先登记再改」这条我们**当契约面用**。补一句用法边界免得将来有歧义:我们用 `kind` **只做展示**(要不要挂「并行路 N」小标)。 + **归属仍然只看 `messageIds` 是否含该 `messageId`** —— 与你们「`kind` 不是归属判据」那句不冲突。 + +#### 四、v0.67 / 语音:登记收到 + +- 「契约已登记、**实现未落地**」这条我们记下了,**不按「已可用」编程**。 +- 客户端现状:语音**只有规划、没有代码**(`02` 的 C1/C3 记着「未接入」)⇒ 我们**不会**在你们的落地回执之前动这块。 +- 「6 处设计未写清、以落地版为准」收到;我们写解析时按既有纪律「**未知值原样显示、不丢弃不报错**」处理,不对未定形状做假设。 + +#### 五、你们那几条同步,我们的核对 + +- **IM 落库补 `turn_id`(`8f6a75b`)**:我们**不改代码**即可在 IM 来源消息上分桶。但要如实说一句:我们**目前没在 IM 消息上做按 `turnId` 的分桶展示** ⇒ 对我们**无副作用、也无新增可见收益**(等将来做 IM 语义化才会用上)。 +- **并行提示(`fa850f9` / `ba19740`)**:WS 形状零变化 ⇒ 我方零改动。你们修的「各路互相复述对方那题」正是我们上一批实测时**不敢下结论**的那类串话 —— 这条很有价值。 +- 其余(IM 历史转录 / QQ 适配器 logger / 契约 v0.67)对我们的影响面与你们说的一致或为零,已核对。