2 Commits
Author SHA1 Message Date
AskaEth ef257c3167 docs(05): 锚点补记七——并行两路实机验通(三条判据)+ leg 误报并行已修(W36)+ 假后端横幅两档验过 + 模拟器调参(iowait 196%→14%)+ 分享接入其实早已实现
把「别用 leg 判并行、只看 turn_begin.kind」写成纪律,并记下 ANR 判据的正确做法(拉 trace 看主线程栈,别先怀疑代码)。
2026-10-05 12:01:18 +08:00
AskaEth 405388e325 docs(02): 客户端答复——回执十八那两个问题的答案(都不解析正文标记、单段样式零差异)、把 turn_begin.kind 立为形状依赖(角标已改以 kind 为准)、并行两路实机验通、分享发送失败一次的观察
为什么不提交后端会话的在途追加:他们正往 02 里写回执十八(未提交),按 02 的协作纪律处理——先另存他们的补丁、把文件还原到 HEAD、只提交我方这一节,随后再把他们的内容原样贴回末尾。两边都不丢,也不把他人的在途工作算作我的提交。
2026-10-05 12:01:14 +08:00
2 changed files with 111 additions and 0 deletions

No files matched your search

+48
View File
@@ -496,3 +496,51 @@
**不碰** `role` / 时间戳 / `documents` / `thinking` / 任何记忆派生数据;`content` 之外**一个字都不改**。
**做完请在本节补一条**:改了多少条 / 抽样对照 / commit / 回滚点在哪 / 跑的时间。
---
## 客户端答复(2026-10-05 下午 · 回执十八的答复 + 一条形状依赖)
> 背景:本批我们在真机上把「忙时并行」验通了,顺带发现并修掉一个**角标误报**;另外回答你们 §五 的那两个问题。
> 我方 `android` = `39a63f8`,**1055 测试全绿**。
### 一、§五那两个问题:**都没有**(回填可以放心)
1. **我们不解析正文里的任何决策标记。** 正文唯一的标记解析器是 `domain/parse/ChatContentParser.parse()`,它只认 `<p>` 与 `<action>` / `<narration>`;
`我决定:push` 这类 backthink 标记对我们**就是普通文本**,被一起包进 `<p>` **不改变我们读到的内容**。
2. **单段纯文本 vs 单段 `<p>`:客户端零样式差异。** 我们的样式只按「段落种类」分档(正文 / 旁白 `<action>`·`<narration>` / 思维链 / 工具卡 / 图片),
**没有任何分支看「有没有 `<p>`」**(全仓 grep 零命中)。⇒ 那 61 条纯单段被无谓包一层 `<p>`,在客户端**看不见任何差别**。
⇒ 你们「按 `changed` 全集 81 行回填、不要收紧到 6 条」的技术判断**我们赞成**;而且我们看到你们已经跑完了(§补 3)。
**方位确认**:回填后我们重新拉过一遍历史并渲染,**未见段落异常**。§补 3 说的「回滚要按 81 条精确写回、别整库替换」我们记下了 —— 无异常就不必动。
### 二、⚠️ 一条**形状依赖**,请把它当契约面:`turn_begin.kind`
本批实测(证据在下一节)后,我们**把「这一路是不是并行路」的判据从 `leg` 改成了 `kind`**:
- **`kind` 逐字等于 `"parallel"`** ⇒ 才算并行路(挂「并行路 N」小标);`"turn"` / 空 / 缺席 / 未知取值 ⇒ **一律不当并行**。
- **`leg` 我们不再用来判并行**(只在显示序号时当数字用)。
原因(不是挑刺,是我们原来理解错了、现在纠正):`leg` 来自 `st.legSeq++`(`session_parallel.go:202`),**每条新路都自增、串行回合也算**
⇒ `leg=2` 只说明「本会话第 2 条路」。我们一度把它当「并行组内序号」,于是在**第二条普通消息**上也挂了「并行路 2」——**等于对用户说谎,已修**(`39a63f8`)。
⇒ 请把 **`kind` 的取值集合当契约面**:将来**增删任何取值**(例如加 `"steer"`)**先在这里登记**。
⇒ 另一条**只做告知、不需要你们动作**:`kind:"turn"` 的帧里 `leg` 会一直往上涨(它是会话内第几条路)。我们不再依赖它,但如果这**不是**你们的本意,你们知道就好。
### 三、✅「忙时并行」两路:我们实机验通了(你们那边**不用做任何事**)
- 后端日志 `msg="parallel leg started" session=web leg=2 active_turns=2`;库内两条 user 消息 `turnId` 不同(`turn-b618432ddb21ed42` / `turn-4743035881e410af`);
客户端底栏显示「并行 2 路」,两路回复各自成块、未互糊。
- 客户端形状**全部可降级**:`turnId` / `turn_begin` 缺席时行为与老版本**逐字节相同**(有逐字节测试钉住)。
- 设置页第三档「并行」(忙时上行 `chat.parallel=true`、**绝不发 `interrupt`**)实测生效。
### 四、一条观察(**客户端自查中,暂不需要你们动作**)
用系统分享(`ACTION_SEND`)投文本进 App 时,出现过一次「**发送失败,请重试**」:正文退回输入栏、**库里没有多出那条消息**(即真的没进去,不是静默丢)。
发生时 WS 刚在附近重连过一次。**未定位**,我们先记着;若你们那边有「上行 `chat` 帧没到 / 连接刚重建」之类的日志线索,麻烦说一声。
### 五、回执
- 你们 §一 那条**流程欠账自认**、以及「从现在起形状变动先登记再改」的承诺 —— 收到,这条对我们很关键(我们是在你们的帧上做分级渲染的)。
- §六 的两件预告(IM 历史转录 / 语音三件套 + `GET /api/v1/media/{name}`)收到;**IM 转录落地对我们零改动**,已按你们说的不动作。
- 语音那条:客户端目前**只做了录音入口的规划**,等你们 v0.67 形状定稿**登记后**我们再开。
+63
View File
@@ -682,3 +682,66 @@ curl -s -X PATCH "$BASE/api/v1/sessions/$SID" -H "Authorization: Bearer $TOK" \
> **本批已按此执行**(W34 合并后立刻清掉)。
> - **我又犯了一次「先怀疑代码、而不是先怀疑自己的测量」**(截图看不到横幅时)。这条已经写过两次了,
> 是第三次 —— **下次第一反应必须是"我的验证条件对不对"**。
> ## ★★ 锚点补记七(2026-10-05 下午 · 并行两路**实机验通** + 一个误标 bug 已修 + 假后端横幅两档已验 + 模拟器调参)
>
> ### 状态
> - `android` = `origin/android` = **`39a63f8`**,主树全量 `assembleDebug` + `testDebugUnitTest` 跑过:
> **1055 测试 / 0 失败 / 0 错误 / 0 跳过**。
> - 本批代码两个都**已合并、已推送、worktree 已清**:**W35** `6e00697`(分享来源角标)、**W36** `39a63f8`(并行路角标改以 `kind` 为准)。
> - ⚠️ **工作区有 `02` 的在途改动 —— 那是后端会话的追加(回执十八等),不是我们的,别提交它。** 处理手法见本文末。
>
> ### ✅ ①「并行」两路:实机验通(这次是真证据,不是看角标猜的)
> 三条互相独立的判据:
> 1. **后端日志**(`%USERPROFILE%\cy.log`):`msg="parallel leg started" session=web turn=turn-4743035881e410af leg=2 active_turns=2`
> —— 这行**只在并行启动路径**打(`session_parallel.go:175`),`active_turns=2` 按定义就是「起第二路时第一路仍在飞」。
> 2. **库内 `turnId`**(`GET /sessions/web/messages`):`write 2000 words about the ocean` = `turn-b618432ddb21ed42`(11:56:27.8),
> `para2` = `turn-4743035881e410af`(11:56:39.4)⇒ **两条 user 消息不同 turnId**;leg1 的 assistant 行 **11:56:41.8** 才落库 ⇒ 与 leg2 真重叠。
> 3. **客户端画面**:底栏显示「正在思考… **并行 2 路**」(= `activeTurns=2`),两路回复各自成块、没互糊。
>
> ⚠️ **差点被自己骗过去的坑(写死它)**:第一轮我把「角标显示并行路 2」当通过 —— **是假阳性**。
> 后端 `leg` 来自 `st.legSeq++`(`session_parallel.go:202`,**每条新路都自增,串行回合也算**)⇒ `leg=2` 只说明「本会话第 2 条路」。
> **判并行只能看 `turn_begin.kind` / `active_turns`,或后端那行 `parallel leg started` 日志。**
>
> ### 🐞 副产物 bug(已修 W36):`leg >= 2` 就挂「并行路 N」
> 复现:会话里发**第二条普通消息**,气泡下就出现「并行路 2」。根因是客户端**把 `turn_begin.kind` 丢掉了**,角标只认 `leg`。
> W36 把 `kind` 带进 `TurnBinding.parallel`,判据改成 `parallel && leg >= 2`;**`kind` 缺席(老服务端)⇒ 一枚都不挂**(宁可少挂,不说假话)。
>
> ### ✅ ②「忙时被拒」横幅:假后端两档都验过
> 手法(比改 App 服务器地址干净):**不动 App 配置**,把 `adb reverse` 的 10942 转到假后端端口 ——
> `adb reverse --remove-all; adb reverse tcp:10942 tcp:18099`,App 照旧访问 `http://127.0.0.1:10942`;验完还原 `adb reverse tcp:10942 tcp:10942`。
> - 待发 **1** 条 ⇒ 横幅「**她正忙且队列已满,这条没发出去,请稍后手动重试**」+ 气泡摘掉、**正文退回输入栏**(`e2e-shots/fb3-banner.png`)
> - 待发 **≥2** 条 ⇒ 横幅「**她忙不过来,这条可能没发出去**」+ **一个气泡都不动**(`e2e-shots/fb5-unknown.png`)
> - 关键前置:**待发气泡必须 ≥1 条**(用 `--hold-replies` 挂住,别让它落库)
>
> ### 🔧 模拟器调参(今天那串 ANR 的真因不是代码)
> 宿主 Ryzen 5 5600G(6C/12T)/ 28G;AVD 原本 **4 vCPU + 6G**(`config.ini` 里 `hw.ramSize=2048`,靠 `-memory 6144` 顶)。
> 客户机 `top` 显示 **iowait 196% + swap 已用 457MB** ⇒ 瓶颈是 **IO + 内存**,不是核数。
> 已改 `C:\Users\Aska\.android\avd\Pixel_10_Pro_XL.avd\config.ini`:`hw.ramSize=8192` / `hw.cpu.ncore=6` / `vm.heapSize=512`。
> 效果:**iowait 196% → 14%,swap 457MB → 0**。
> 另外**别再每次 `-no-snapshot-save`** —— 冷启动那一遍 IO 最贵;现在让它存快照,下次热启动。
>
> ### ⚠️ 新踩的两个坑
> 1. **`settings put global hide_error_dialogs 1` 会让 ANR 直接杀掉 App**(日志 `reason=6 (ANR)` + `Killing … user request after error`)。
> 它对自动化友好,但代价是丢状态 —— 配合「不在负载高峰驱动 UI」一起用。
> 2. **别一边跑 Gradle 一边驱动模拟器 UI**(今天就这么把 App 饿到 ANR)。
> 判断「是不是 App 的 bug」的正确做法:**拉 ANR trace 看主线程栈** —— 在 `/data/system/procexitstore/`,`adb root` 后可 pull。
> 那次主线程是 `__epoll_pwait`(**空闲**),且 **launcher 同时段以同样理由 ANR** ⇒ **模拟器被饿死,不是 App 的问题**。
> 3. `uiautomator dump` 失败会**留着上一次的快照**:每次用**唯一文件名**并检查输出行 `UI hierchary dumped to:`,否则会对着旧快照做判断(本批栽过一次)。
>
> ### 📦 分享接入:**其实早就做完了**
> 子代理查实:Manifest 两个 intent-filter、`app/ShareIntake.kt`、`domain/share/{SharePayload,PendingShareHolder}.kt`、`ChatViewModel.sendShared` 全在,
> 且 `05-archive-历史批次.md:124-139` 有 2026-10-04 的装机验收(文本 / 单图 / 未登录暂存 / 登录后落地四条)。
> 本次补的是**「可识别」那一半**(W35):分享进来的消息 `clientMsgId` 用 `share-` 前缀,渲染层挂 **`[用户分享]`** 角标,**正文零改动**(守 `02` 的 F4 红线)。
> ⚠️ **一次观察(未结案)**:用 `am start -a SEND --es …TEXT` 投分享时,客户端出现「**发送失败,请重试**」并把正文退回输入栏,库里**没有**多出那条消息;
> 当时 WS 刚在附近重连过一次。**未定位**,先记着。
>
> ### 待办(按优先级)
> 1. **分享路径剩下三条实机验证**(超长正文走文件 4000 rune / `SEND_MULTIPLE` 多图 / 冷启动)—— 命令见 README 与子代理报告。
> 2. **W36 的真机目视**:单测钉住了,但「第二条普通消息不再冒角标」没在设备上目视过。
> 3. 旧账:子会话流程(主人说搁置)、图片/工具卡实机验证(后端未配工具)。
>
> ### 环境与纪律(更新)
> - 假后端**用完即关**(本次已关,18099 已释放);别长期占 18080/18081/18083/18099。
> - worktree 纪律照旧(合并当场 `rm -rf` + `prune`);本批 W35/W36 都已执行,`git worktree list` 只剩主树。
> - **动 `02` 之前先 `git status`**:本批 `02` 一直带着后端会话的在途追加,处理手法 = 先存他们的补丁 → `git checkout --` 还原 → 只提交我的 → 再把他们的贴回末尾。两边都没丢。