docs(05): 存档本轮装机验收的设备证据(W18/W15/W19 通过、W16 确认不可用、四条新坑)

This commit is contained in:
AskaEth committed 2026-10-04 21:41:45 +08:00
1 parent e8c6389fde
commit c67aa2da48
1 file changed
+64
+64
View File
@@ -597,3 +597,67 @@ APK = 主树 `a6b4bae` 的产物(`app/build/outputs/apk/debug/app-debug.apk`
### 新登记(见 `02`)
W16 报上来六条**契约没写透**的口径,其中两条值得扫一眼:**`before` 是含还是不含游标**(契约只对 `after` 明说)、**`q` 匹配的是含标记的原始 `content`**(搜 `action` 会命中、但我们**不画高亮**,不假装命中)。
## 装机验收轮(2026-10-05 上午 · 设备证据存档)
主人要求「每项都要**设备证据**,不能只看编译过了」。设备:模拟器 `Pixel_10_Pro_XL`(`-memory 6144`),App 的服务器地址 `http://127.0.0.1:10942`,`adb reverse tcp:10942 tcp:10942`。
### ② W18 `.pdf` 非文本拒收 —— ✅ 通过
用 API 造了一份**带文本层的真 PDF**(自拼对象 + 正确 xref,563 字节,文本 `Cyrene PDF e2e: meow-314`)→ `POST /documents` → `POST /chat` 挂进会话 `E2E-PDF`。落库形状:
`documents: [{"name":"0efe0a2a….pdf","mime":"application/pdf","size":563,"chars":24,"status":"extracted"}]`
(**`chars:24` 正好等于那份 PDF 里那句文本的长度** ⇒ 文本层真被抽取;也顺带证明我拼的 PDF 是合法的。)
设备上点那枚芯片,弹层显示:
```
附件预览
0efe0a2a13c2583568904105946f91a6.pdf
PDF · 563 B · 24 字 · 已读入
这是 PDF,App 内不预览这类内容,请用「用其它应用打开」或「保存到下载目录」
用其它应用打开 / 保存到下载目录 / 关闭
服务端只保留了内容寻址的存储名…原始文件名不会返回给客户端
```
⇒ **正文区是那句人话,不是一屏二进制** —— 洞堵住了。截图 `app/build/e2e-shots/w18-pdf-preview.png`。
(同时印证了登记进 `02` 的那条「措辞别扭」:芯片说**已读入**、弹层说**不预览**,两句都真。)
### ③ W15 重试复用幂等键 —— ✅ **可验部分**通过(另半边由单测背书)
会话 `E2E-RETRY`:
| 步骤 | 结果 |
|---|---|
| **硬断开**(`adb kill-server` 掐断 reverse 上的在途连接)→ 点发送 | **失败回滚**:正文 `W15-retry-2` **被还回输入框**,没有变成卡死的「发送中…」气泡 |
| 恢复隧道 → 等 WS 重连 → **原样重发** | 服务端**只有 1 条**该内容的消息(**不重复**) |
| 落库 | `clientMsgId: local-7c99433b-…` —— 幂等键确实在链路上 |
⚠️ **如实标明边界**:「复用**同一个** id」那半边在本机**证不出来** —— 那次失败根本没到服务端,所以 id 从未被服务端见过,重试是「铸新键 + 正常收下」,结果同样是**一条**。那半边的证据只有单测(W15 的 13+10、W17 的 16、W21 的 +7,其中一条专门钉住「失败记键 → 重发复用 → duplicate → 屏幕上只剩一条」)。**不许把它说成「设备上验过了」。**
### ④ W19 消息编辑删除 —— ✅ 通过
| 环节 | 证据 |
|---|---|
| 角色门 | 同一条 `⋯`(`content-desc="消息操作"`):**user** 消息 → 「编辑 + 删除」;**assistant** 消息 → **只有「删除」** |
| 编辑弹层 | 标题「编辑这条消息」、内容框里是**原始 content**、右下角**码点计数 `11 / 4000`** |
| 编辑执行 | logcat **`PATCH /api/v1/messages/696cdf76…`(32 字节)→ `200`**,恰好一次;服务端同一条 id 内容变成 `W15-retry-2-EDITED`(**原位改、无第二条气泡**) |
| 二次确认 | 「删除这条消息?」/「它会从所有端移除,且不可恢复。」 |
| 删除执行 | logcat **`DELETE /api/v1/messages/f9c53d22…` → `200`**(56 字节);服务端那条 assistant **已消失**、界面气泡消失 |
### ① W16 会话内搜索 —— ❌ **设备上不可用**(真 bug,修复中)
点顶栏入口 `content-desc="搜索会话里的消息"`(`[1206,204][1266,264]`)**界面毫无变化**:无面板、无「输入关键词…」、无标题。但 dump 里**多出**一个 `android.widget.EditText` 位于 **`[36,339][1176,509]`**(顶部、宽约 1140px;聊天页自己的输入框在 `[300,1736][1086,1906]`)⇒ **面板的输入框出来了、面板其余部分没出来或尺寸塌了**。
- 第一次修复的代理(W20)**零输出挂死 14 分钟、worktree 里零改动**(停掉后核对:停在旧提交、无残留)。
- 已重派(W22),并在任务书里加了**反挂死三条**:不许它自己跑 `git merge`(分支由主代理对齐好)、**任何命令 3 分钟无输出就换做法/报告**、**只跑一轮构建**。
### 本轮新增的坑(客户端侧方法论,值得单独记)
1. **`adb reverse --remove tcp:10942` 断不开已经建立的连接**(reverse 规则只影响**新建**连接)⇒ 拿它造「发送失败」是**无效**的(那次发送照样成功落库)。要真断得用 `adb kill-server` / `start-server`。
2. **两个子代理同时跑 Gradle 会抢 `~/.gradle/caches` 的文件锁**,表现就是**零输出挂死**(本次 W20 静默 14 分钟就是它)。⇒ 给子代理加「**某条命令 3 分钟无输出就报告**」的约束;也别让它们跑多轮 `--rerun-tasks`。
3. **「文件还在」≠「消息还在」**(后端已确认:他们现在有 GC,未引用且超 7 天的文档会被删;`GET /api/v1/files/<name>` 只证明字节在)。⇒ 别拿它当存活证据。
4. **`mysql`/`uiautomator dump` 在转场期会静默失败并留下旧文件** ⇒ 唯一文件名 + 重试 3 次 + 检查非空(这条早就记过,本轮又踩到一次)。
### 验收用的会话(**都留着,未清理**)
`E2E-DOC`(纯附件回合没助手消息的现场)、`E2E-PDF`(带 PDF 附件、回合正常)、`E2E-RETRY`(含一条**被编辑过**的消息 `W15-retry-2-EDITED`)。主人说清再清。