docs(05/07): 锚点补记二十八 —— W48/W49 设备验收通过(换环境串味 / 抽屉未读角标)

改了什么:
- 05 新增锚点补记二十八:W48 的判别法(先清空服务端主会话再换账号,否则两账号同一份历史看不出串味)与结果
  (A 的本地气泡与持久行在 B 账号下都 0 次、抽屉残留 0 次);W49 的机制证据(抽屉关着时客户端自己在
  消息到达后 60ms 发出 GET /api/v1/sessions)与可见结果(次级会话行 未读 1、正在看的主会话无角标);
  并更正一处认知:红点是抽屉内会话行的未读角标,菜单图标上没有点。
- 07 的坑清单补两条:① 登录页地址栏留空时 App 会回落到上次记住的地址(我因此白追一小时「请求怎么打到
  真后端」);②「登出」是设置页最底部的图标按钮(图标是 MiuixIcons.Back、只有 contentDescription),
  截图上像「返回」很难找。

为什么:这批验收原来只有单测覆盖,结清后 05 的待办里不再挂着它;两条坑都是这次真实花掉时间的,
写下来避免下次重演。
This commit is contained in:
AskaEth committed 2026-10-06 08:24:00 +08:00
1 parent c905a47d6f
commit b23948bed0
2 files changed
+42 -2

No files matched your search

+33
View File
@@ -1509,3 +1509,36 @@ curl -s -X PATCH "$BASE/api/v1/sessions/$SID" -H "Authorization: Bearer $TOK" \
- 上面第 3 项「W48/W49 设备验收」**环境已就绪**(模拟器已 root、reverse 指向真后端)⇒ 现在是**可做**状态。
- W50 留了一条**窄尾巴**(只在「落库失败」档可达:降级气泡长按可删 ⇒ 会用本地 id 打服务端报错);收口做法见 `07` §5。
- 已更正「代理旧路径」那条陈旧项(见 `5520d60`)。
---
## ★★ 锚点补记二十八 · W48/W49 **设备验收也通过**(换环境串味 / 抽屉未读角标)
> 环境:模拟器 `emulator-5554` + 假后端 `python devtools/fake-backend/fake_backend.py --port 18090`
> (App 地址栏填 `localhost`,配 `adb reverse tcp:80 tcp:18090`)。操作细节与全部坑见 `07-W50-主动消息-验收与避坑.md`。
### 1. W48(账号指纹进 VM key,修 S1)——**已验**
判别法是关键:**先把服务端主会话清空**(`POST /__control/clear?session=web`)再换账号,否则两个账号拿到同一份历史、看不出串味。
- 账号 A(`e2ea`)的主会话里造两条:一条**只活在 A 的 VM 内存里的本地气泡**(`--without-id` 注入)+ 一条持久行;
- 换到账号 B(`e2eb`;同 baseUrl、不同用户名 ⇒ 指纹不同);
- 结果:**「A账号的消息」0 次、「A账号的持久消息」0 次**,聊天页「还没有消息」,抽屉里 A 的残留 **0 次**
⇒ **VM 没被复用、快照也没串味**。反证很硬:那条本地气泡服务端**根本不存在**,它若还在屏幕上就只能是旧 VM。
- 假后端流水证明这是全新一轮(`08:22:35` 起一整串 `login / enums / sessions / messages`)。
### 2. W49(非激活会话落新消息 ⇒ 节流静默重拉,修 S6)——**已验**
- 场景:App 停在**主会话**、抽屉**关着**;往次级会话 `web:5eed…0001` 灌一条(`POST /__control/reply`)。
- **机制证据(客户端自己发的请求)**:`08:20:03.018` 服务端广播 `message_persisted` ⇒ **`08:20:03.079` 客户端自己发出 `GET /api/v1/sessions`**(60ms 后,抽屉全程关着)——这正是 W49 那条节流静默重拉。
- **可见结果**:打开抽屉,次级会话行上是 `未读 1`(`[232,573][276,617]`),而**正在看的主会话没有角标**。
- ⚠️ **更正一处认知**:这里的「红点」是**抽屉里会话行上的未读角标**(`SessionDrawerContent.kt:403`);
菜单图标本身**没有点**(`ChatScreen.kt:468` 是纯 `Icon`)——以后别再对着菜单图标找点。
### 3. 本次新踩的坑(已补进 `07` §2 第 9、10 条)
1. **登录页地址栏留空 ⇒ App 回落到上一次记住的地址**(我为此白追一小时「请求怎么打到真后端去了」);
2. **「登出」是设置页最底部的图标按钮**(`ui/settings/SettingsScreen.kt:160`,图标是 `MiuixIcons.Back`、
只有 `content-desc="登出"`)——截图上看着像「返回」,很难找。**这是观感问题,等主人拍板**要不要换成带文字的危险行条目。
### 4. 待办变化
- ✅「W48/W49 设备验收」这条**结清**(原来标注「都只有单测」)。
- 还在等/待决策的:**等后端** `toolCalls[]` 回看面(要带输出)+ `unreadCount` 增量;
**待主人**:登出条目观感、移除键位置观感、相册多选分享真机、推送(等自建);
**待主人拍板**:S1 第二步(回收旧 VM)、S5(切会话打断/停止入口)、W50 那条窄尾巴(降级气泡按 `proactive-local:` 前缀屏蔽删除入口)。
@@ -42,8 +42,15 @@
文字/坐标判据一律优先用 dump(`bounds | text`),截图只在需要看观感时用。
8. **滑动手势会被系统返回手势吃掉**:从屏幕底部附近起滑会直接回桌面。真要滚动就避开底部区域
(例如 `input swipe 540 1500 540 800 300`),别用 `1900 → 700`。
9. 验收结束时的状态:`adb root` 仍是开的;reverse 为 `tcp:80 → tcp:10942` 与 `tcp:10942 → tcp:10942`
(都是真后端);App 拿的是假后端签发的 token ⇒ 会在真后端的 401 上登出,登录页地址栏留着 `localhost`。
9. **登录页的「服务器地址」留空时,App 会回落到上一次记住的地址**(不是报错、也不是用界面上那句示例 `http://192.168.1.10:8080`)。
我为此白追了一个小时「请求怎么打到真后端去了」:那一次地址栏恰好是空的(我清过),而当时的 reverse 指向真后端。
**教训**:凡是要换后端,先 `uiautomator dump` 确认地址栏里**真有值**(`http://localhost/`),别信「刚才填过」。
10. **「登出」是设置页最底部的一个图标按钮**(`ui/settings/SettingsScreen.kt:160`,图标用的是 `MiuixIcons.Back`、
只有 `contentDescription = "登出"`,红字):截图上它看起来像「返回」,非常难找。找法:dump 里搜 `content-desc="登出"`
(位置在「关于 → 版本」下面 32dp,约 `y≈2109` 处),或先把设置页滑到底。
⚠️ 这条同时是个**观感问题**(主人可能根本不知道它在哪),要不要换成带文字的危险行条目属于产品决定。
11. 验收结束时的状态:`adb root` 仍是开的;reverse 为 `tcp:80 → tcp:10942` 与 `tcp:10942 → tcp:10942`
(都是真后端);App 拿的是假后端签发的 token ⇒ 会在真后端的 401 上登出,登录页地址栏留着 `localhost`、用户名留着上一次填的。
## 3. 复现整套验收的最短路径