From 798c6ee907e5680a99436cfb912cfd53a96a0e19 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 5 Oct 2026 19:53:16 +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=83=E2=80=94=E2=80=94W45=20=E9=98=B6?= =?UTF-8?q?=E6=A2=AF=E8=AE=BE=E5=A4=87=E9=AA=8C=E8=AF=81=E9=80=9A=E8=BF=87?= =?UTF-8?q?=EF=BC=88route=3DRest=E3=80=81=E4=BB=A3=E7=90=86=E8=A7=81=20200?= =?UTF-8?q?=E3=80=81=E8=90=BD=E5=BA=93=201=20=E6=9D=A1=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E9=99=84=E6=88=91=E8=BF=9E=E7=BB=AD=E4=B8=89=E6=AC=A1=E8=AF=AF?= =?UTF-8?q?=E5=88=A4=E7=9A=84=E5=85=B1=E5=90=8C=E7=82=B9=E4=B8=8E=E4=B8=89?= =?UTF-8?q?=E6=9D=A1=E8=AE=BE=E5=A4=87=E9=AA=8C=E8=AF=81=E7=BA=AA=E5=BE=8B?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=8F=8A=E5=B7=A5=E5=85=B7=E5=8D=A1=E7=BC=BA?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=E6=A0=B9=E5=9B=A0=E4=B8=8E=E7=99=BB=E8=AE=B0?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devdocs/05-开发进度与交接.md | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/devdocs/05-开发进度与交接.md b/devdocs/05-开发进度与交接.md index 194072e..d612850 100644 --- a/devdocs/05-开发进度与交接.md +++ b/devdocs/05-开发进度与交接.md @@ -1165,3 +1165,46 @@ curl -s -X PATCH "$BASE/api/v1/sessions/$SID" -H "Authorization: Bearer $TOK" \ > 2. `devtools/fake-backend` 里的 `GET /api/v1/health` 路由与 README 的说法现在是死的(无害夹具,未清)。 > 3. 待主人过目:静默持续到某次补发成功 vs 每轮结束恢复告知(改一行)。 > 4. 待办:子会话流程跑一遍出清单;W42 多选器真机观感。 + +> ## ★★ 锚点补记十七(2026-10-06 · **W45 那条阶梯验通了**,以及我连续三次的误判) +> +> ### 状态 +> `android` = `origin/android` = **`16699c4`**(W46 合并提交;分支提交 `d546f31`);主树 **1155 测试 / 0 失败 / 0 错误**。W46 worktree 已清。`02` 里另有一笔**已推**的登记(`b8399b5`,工具卡缺数据面,见下)。 +> +> ### ✅ 设备验证:**通过**(判据三条独立) +> 场景:`ws_block_proxy.py` 只掐 `GET /ws/chat`(回 503)+ `adb reverse tcp:10942 tcp:18098`;新包(含 W46 的 `CyreneRoute` 日志);输入栏发一条纯文本。 +> ``` +> CyreneRoute: wsDispatched=false socket=Reconnecting mirror=Reconnecting wsObject=absent route=Rest reason=ConnectionNotReady outcome=Queued fromQueue=false +> 代理日志: PASS POST /api/v1/chat -> 200 +> 库里: 恰好 1 条 +> ``` +> ⇒ **`route=Rest` ⇒ 直接试 REST ⇒ 请求真的发出去(代理看到 200)⇒ 消息落库。** W45「把探测换成直接尝试」**成立**。 +> 顺带把 W41 那个「探测不可用」的缺口**绕过去并消掉了**(那套机制已被删除)。 +> +> ### ⚠️ 我在这一串里连着错了三次(必须记下来) +> 1. 「App 从来没探过 `/health`」——**推不出来**(W44 证明:`Unreachable` 生在连接之前,三种成因在对端同形)。 +> 2. 「零请求 + 进队列 ⇒ 只能是 `Offline` 那一档」——**错**。这次日志给出的真实答案是 `route=Rest`,**REST 确实发出去了**。 +> 3. 前几轮「发送没发生」的结论——**错**,有两次是我点在了 `com.android.settings` 上(前台不是我们的 App),有一次消息其实**进了队列**(我当时只查了网络侧、没看界面)。 +> +> **共同点:我拿「对端日志缺席」当「客户端没做」的证据,而中间还隔着几层我看不见的东西。** +> **纪律(写死)**:① 设备验证**第一步永远是 `dumpsys window | grep mCurrentFocus`** 确认前台是自己的 App;② 要判「客户端做了什么」,**优先看客户端自己的输出**(`CyreneRoute` / `logcat -s OkHttp`),**不要**从代理/后端日志反推;③ 一次只改一个变量。 +> +> ### 一条仍未解释的旧现象(如实留着) +> W45 那次(同一场景)气泡停在「排队中 · 还没连上」、代理没有 POST、库里没有那条。**与本次唯一可见的差别是时机**:那次我在 App 启动后 ~55 秒就发了(正撞上启动期的请求洪峰),这次 App 已稳定运行一分多钟。 +> **最可能的解释**:`route=Rest` 但那次 REST 死在**整通上限 10 秒**(被启动期拥挤的连接/续期吃掉)⇒ `Unsent` ⇒ 进队列。**未经证实**,W46 的日志下一次复现时可以直接读到(看 `route` 与 `reason`,再看 OkHttp 有没有 `--> POST`)。 +> +> ### W46 留下的可观测性(以后常备) +> `ChatViewModel.sendThroughLadder` 一进入就一行 **`Log.d("CyreneRoute", …)`(仅 DEBUG)**: +> `wsDispatched= socket= mirror= wsObject= route= reason= outcome= fromQueue=` +> - `socket` 是**权威值**(`ChatSocket.state.value`),`mirror` 是**顶栏读的那个镜像** —— 一行就能分辨「镜像滞后」。 +> - `reason` 三档:`FrameDispatched`(走 WS)/ `ConnectionOffline`(进队列,一个请求都不发)/ `ConnectionNotReady`(直接试 REST)。 +> - 这是全仓**唯一**一处 `android.util.Log`,引入理由:必须是稳定可 grep 的固定 tag,而 OkHttp 的 BASIC 日志只照得到 REST 侧、照不到这条判据。 +> - `SendFallbackTest` 有「结果 + 原因」的全表测试。 +> - 复核结论:`WsState.Offline` 的写点**只有两处**(`ChatSocket.kt:233` ConfigMissing、`:284` 鉴权失败),**503 到不了 Offline** —— 所以「零请求 + 进队列」在纯函数层面**只有** `ConnectionOffline` 一条,本次实测也确认了不是它。 +> +> ### 另外:主人报的「工具调用记录回合结束后消失」——根因已定,**已登记给后端** +> **数据面缺失**:工具卡的数据只活在**流式路的本地状态**里;助手行落库时客户端把整条路丢掉,而**落库消息 DTO 里没有工具字段**可渲染。 +> **证据是同一段代码里的对比**:思维链有「打捞 + 滞留 10 分钟」的补救(因为 DTO 里有 `thinking`),**工具一个字段都没有**。 +> **不是我方本地状态的 bug**(我方与 `devdocs/03:141`「thinking / tool_call:仅 WS 实时有」逐字一致)。后端**其实已经把工具调用落进 `flow_graphs`**,缺的是「取出来给聊天端」。 +> 已登记进 `02`(`b8399b5`):要可选字段(`omitempty`,缺席=老行为逐字不变)、覆盖面对齐 `turnId`、**归属要明确**、允许开独立端点。 +> 我方接线点:目前 `ToolCard` 在「已落库消息」那条渲染路径上是**不可达代码**(渲染器签名里没有 tools 参数)——字段一到即可接。