From d5d2feee3644cb0b91ec57037e87b10b57bf8aef Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 5 Oct 2026 22:30:08 +0800 Subject: [PATCH] =?UTF-8?q?docs(05):=20=E9=94=9A=E7=82=B9=E8=A1=A5?= =?UTF-8?q?=E8=AE=B0=E4=BA=8C=E5=8D=81=E4=BA=94=E2=80=94=E2=80=94W48?= =?UTF-8?q?=EF=BC=88=E8=B4=A6=E5=8F=B7=E6=8C=87=E7=BA=B9=E8=BF=9B=20VM=20k?= =?UTF-8?q?ey=20=E4=BF=AE=20S1=20+=20=E6=90=9C=E7=B4=A2=20VM=20=E5=90=8C?= =?UTF-8?q?=E7=B1=BB=E7=BC=BA=E9=99=B7=20+=205=20=E5=A4=84=E9=94=99?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=20+=20=E4=BB=A3=E7=90=86=E6=8C=AA=E8=BF=9B?= =?UTF-8?q?=20devtools=EF=BC=89=E4=B8=8E=20W49=EF=BC=88=E9=9D=9E=E6=BF=80?= =?UTF-8?q?=E6=B4=BB=E4=BC=9A=E8=AF=9D=E8=8A=82=E6=B5=81=E9=9D=99=E9=BB=98?= =?UTF-8?q?=E9=87=8D=E6=8B=89=E4=BF=AE=20S6=EF=BC=8C3=20=E7=A7=92=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=20+=20=E7=BB=93=E6=9E=84=E6=80=A7=20trailing=20+=20?= =?UTF-8?q?=E4=B8=80=E5=A4=84=E5=88=BB=E6=84=8F=E5=81=8F=E5=B7=AE=EF=BC=89?= =?UTF-8?q?=E8=90=BD=E5=9C=B0=EF=BC=9B=E5=90=88=E5=B9=B6=E5=90=8E=201177?= =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=E5=85=A8=E7=BB=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devdocs/05-开发进度与交接.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/devdocs/05-开发进度与交接.md b/devdocs/05-开发进度与交接.md index 62cc7f0..188933d 100644 --- a/devdocs/05-开发进度与交接.md +++ b/devdocs/05-开发进度与交接.md @@ -1374,3 +1374,28 @@ curl -s -X PATCH "$BASE/api/v1/sessions/$SID" -H "Authorization: Bearer $TOK" \ > **① P1(我方接):主动消息实时看不到。** 核实结论:`proactive_message` 帧我们**只解了错的 id**(`messageId`,而落库行是另一个 `id`;`ignoreUnknownKeys` 把新 `id` 静默丢弃),且**整帧零消费**(`ChatViewModel.onEvent` 无该分支)⇒ **「显示两次」不会发生,但「实时看不到她主动说的话」是真缺口**(只能等重连/重开/切会话拉历史)。修法位置已定(`WsEvent.ProactiveData` 补 `id`/`createdAt` + `ChatViewModel` 加分支,**按已落库 assistant 行并入 `mergeMessages`**,**必须自己钉死主会话**——该帧壳**不带 `sessionId`**,否则会窜进每个次级会话)。 > **② `tool_execution` 口径:选 (a)**(只认 `.start`/`.end` 按 `id` 关联;**不要他们补 `.update`**)。取舍已明确:**没有 `.update` ⇒ 工具卡的结果区是空的**(`ToolCallState.output` 只由 `.update` 的 delta 追加)⇒ **我们真正要的是他们已认领的「持久化 `toolCalls[]` 回看面」**,并请求把输出/摘要一并带上。 > **③ 移动端推送:暂不接**(等主人自建)。并已告知他们:他们建议的「应用内提示」`message_persisted{proactive:true}` 在我们这边**零实现**(`PersistedData` 只读 `message`;客户端无任何 Notification 代码)⇒ **那条建议目前不产生任何效果**,别当兜底。 + +> ## ★★ 锚点补记二十五(2026-10-06 深夜 · W48 + W49 落地:S1 与 S6 的客户端半边) +> +> ### 状态 +> `android` = `origin/android` = **`5dc6408`**(两个合并提交);主树 **1177 测试 / 0 失败 / 0 错误**;**worktree 全清**(只剩主树),主仓只剩 `02` 那笔后端会话的在途追加。 +> +> ### W48(分支 `4f860aa`,合并 `e589ab3`):修 **S1** + 注释纠错 + 工具归位 +> - **账号指纹进 VM key**:新增顶层纯函数 **`accountFingerprint(baseUrl, username)`**(`core/prefs/SessionPreferences.kt`,**口径就是既有的 `baseUrl|username`,不另造第二套** —— `SessionsViewModel` 的私有实现也改成调它),VM key = `指纹 + "|" + sessionId`(`ui/chat/ChatScreen.kt` 的 `chatViewModelKey`)。 +> - **顺带修了同类缺陷**:**会话内搜索小 VM** 的 key 也加了指纹(它持有的 `hits` 就是消息正文,换环境后在主会话(id 恒为 `web`)重开搜索会把**别的服务器**的消息摆进面板)。 +> - **5 处错注释纠正**(`ChatHomeScreen` ×3、`ChatViewModel` ×2,加上点名的 `ChatScreen:161-164`):原写「key 一变 VM 立刻被销毁」是错的(key 变只销毁**组合**,VM 仍在 Activity store 里收帧)。**行为一字未动**(`onCleared` 仍空)。 +> - **`ws_block_proxy.py` 挪进 `devtools/ws-block-proxy/`** + `README.md`(用途 / 用法 / **「Web 前端不经过 `adb reverse` ⇒ 代理日志每一行都只可能来自 App」**这条关键性质 / `adb reverse tcp:10942 tcp:18098` 的典型用法 / 提醒抹掉日志里的 token 查询串),并**冒烟测过**(503 BLOCKED + 200 PASS)。**一次 `clean` 再也不会把它扫掉了。** +> - ⚠️ **未做设备验收**(禁碰 adb):换账号后屏幕上是否真的不再有旧消息,只由纯函数单测钉住。 +> +> ### W49(分支 `93cf3e3`,合并 `5dc6408`):修 **S6** 的客户端半边 +> - 新增判据层 **`ui/sessions/InactiveSessionPull.kt`**:`silentRefreshStep` 等纯函数 + **3 秒节流窗口**。 +> - `SessionsViewModel`:非激活会话落 `message_persisted` ⇒ **节流地走既有 `refresh(silent = true)`**(**与打开抽屉那次逐字相同**,含 `withReadCursors` 遮罩),让红点在**不开抽屉**时也能亮;登录态变化时**清账本 + 取消补拉任务**。 +> - **3 秒的理由**(写进 KDoc):够快(3 秒还在「就是刚发生」的感知里);够粗(一次静默重拉是**两个**请求,而播出方**按每条消息**推帧,3 秒能把人手连打 5 条收进同一窗口);与 `SHARE_WAIT_NOTICE_MILLIS` 同量级。 +> - **trailing 是结构性保证**:同一时刻**最多一个**补拉任务;窗口内的后续成因只更新账本并返回 `Ignore`;到点**直接拉**并把窗口重开(不回头问判据,避免自锁);边界取 `>=`。 +> - **不拉的三档**:当前打开的会话(那条路「看到即已读」,多拉是白花两个请求)、同一窗口内的后续消息、窗口内且补拉已排上。 +> - **它不是「造数」**:一个数都不编 —— 帧本身只说「某会话有新消息落库」,客户端据此**去问一次服务端**。同理这是「增量到位之前红点唯一能亮的办法」;**后端补上 `unreadCount` 后这条路可退成不必走**。 +> - ⚠️ **一个刻意的偏差**:**`select`(切会话)不接触发** —— 它紧接着发 `POST /read`,而游标还没落地时重拉会**按旧游标算出未读、把刚清掉的角标闪回来**。判据对「切会话」够用,KDoc 写明了理由。**若将来发现「切回来后红点不对」,这里就是第一嫌疑处。** +> - ⚠️ **未做设备验收**:「红点确实在没开抽屉时自己出现」没有实机证据。 +> +> ### 顺带要改的旧引用(我) +> `devdocs/05` 里那条「建议把 `ws_block_proxy.py` 挪进 `devtools/`」的建议**已执行**(`devtools/ws-block-proxy/`);文中提到旧路径(`app/build/e2e-shots/ws_block_proxy.py`)的地方**现在过时**,下次一并更正。