docs(05): 落 W8–W10 批次状态、模拟器与该轮自动化的坑、契约 v0.59、附件预览欠账

This commit is contained in:
AskaEth committed 2026-10-04 19:09:10 +08:00
1 parent ca5596a732
commit e59ef08cf9
1 file changed
+40
+40
View File
@@ -454,3 +454,43 @@ APK = 主树 `a6b4bae` 的产物(`app/build/outputs/apk/debug/app-debug.apk`
- **附件与正文各自独立存在**:用户自己打的字照发,附件随 `chat.documents` 一起发(服务端两种都支持,**纯附件回合也合法**)。**绝不把正文搬进附件**,所以也就没有「转文件后正文还发不发」这个问题。
- 接线时必须如实告知:`document_unreadable`(400) 客户端**基本触发不到**(那要显式索取正文,而 `document-read` 是服务端工具);客户端实际能看到的信号是 DTO 里的 `status:"unreadable"`。`truncated` 只表示**注入被预算截断**,**不是**「读不到」——两个信号不许互相顶替。
- 附件上行载荷:`"documents":[{"name":"<32hex>.<ext>"}]`,**≤5 条、只给服务端存储名**;带附件一律走 REST(客户端策略)。**`name` 是唯一上行字段**。
## W8–W10 批次 + 芯片修复(2026-10-04 深夜 → 2026-10-05 凌晨)
**四个模块全部合并、已推 `origin/android`,主树每一轮都跑 `assembleDebug` + `testDebugUnitTest --rerun-tasks`**(不是 FROM-CACHE),逐轮测试数我自己读 JUnit XML 求和:
| 模块 | 内容 | 测试 | 提交 |
|---|---|---|---|
| W8 | 设置页「版本」行可点 → **关于页**(应用名 / 版本取自 `BuildConfig` / 简介 / 作者 `AskaEth`) | 485 → 487 | `3ed2377` → `f24877d` |
| W10 | 接上**可观测性三帧**(`observability_metrics/trace/log`),概览页实时刷新 + 「最近日志」区块 | 487 → 516 | `b5e6f78` → `93941cd` |
| W9 | **文档附件全链路接线**:选文件入口(SAF)/ 待发芯片 / 上传 → `chat.documents` / 气泡芯片 / 分享进来的**文件**走文档通道 | 516 → 567 | `30180ab` → `ab76798` |
| — | 契约 v0.59 已发布 → 更正 W6 那批「未发布」注释(纯注释) | 567 | `2973391` |
| — | `devdocs/` **纳入版本库**(`.gitignore` 移除该条) | — | `2369dd2` |
| — | **附件芯片改换行排布**(修主人发现的「多附件被裁到屏幕外」) | 567 | `ca5596a` |
**已实机验证**:关于页(点版本进 → 返回一次到设置、再一次到聊天,层级正确);附件芯片换行(主会话那条**三附件**消息现在渲染成三行、三枚芯片与各自的状态行全部可见)。
### 踩到的坑(重要,别再重复)
- **模拟器「未响应」弹窗的根因是 AVD 内存配小了**:`hw.ramSize=2048` / `vm.heapSize=256`,而镜像是 **API 37 / 16k page / 1344×2992@480dpi**。冷启 2 分钟后 guest `load average` 冲到 **52.96**,`system_server` / `SystemUI` 被反复挤压 → 不停弹 `isn't responding`。**修法(不动 AVD 配置)**:启动时加 `-memory 6144`;另把闲置的 Gradle daemon 停掉(`gradlew --stop`,两个 daemon 白占 4 GB)→ 宿主空闲内存 5 GB → 13.9 GB,6 GB 后 guest 负载降到 ~20、**ANR 归零**。若要固化,改 `config.ini` 的 `hw.ramSize`(那文件在项目外,需主人点头)。
- **在跑构建时 `adb reboot` 会把模拟器卡死在开机中途**:`sys.boot_completed` 永远空、`dev.bootcomplete` 空、logcat 里 init 反复报 `Could not find 'aidl/activity' for ctl.interface_start`(= `system_server` 没起来),此时 `adb install` 会**永远挂住**。**修法:`adb emu kill` 后冷启**,别指望它自己好。
- **`uiautomator dump` 会静默失败并留下旧文件** → 每次用唯一文件名;**`am start` 的 extra 值不能带空格**(远端 shell 会再拆一次);sharesheet 的 **Direct Share 卡片点不动 `input tap`**,点普通应用行或用 `-n` 直投。
- **双击坐标复用会点错**:本轮「记住了」的坐标在两次会话里分别落到了「添加文件附件」(意外开了 DocumentsUI,反而算半个正面证据)和「与昔涟」顶栏标题上。**每次都从新 dump 取 bounds**,并按 x/y 区间消歧(抽屉行 vs 顶栏标题同名)。
- **提交信息里别用反引号**:`git commit -m "…`文件名`…"` 在双引号里会被 bash 当命令替换执行,信息被吃掉一段(本轮真踩了,已用 `-F 消息文件` amend 修回)。**含反引号的提交信息一律走 `-F`。**
### 契约侧(已登记 `02`)
- **`api-client.md` 已发布 v0.59**(§1.2 文档存储与摄取契约 + 端点表 16/17)。我们实现的形状**逐条一致**(`file` 部件名、201/200+`deduped`、20 MiB、≤5、只收 `name`、相对 `url`、嗅探基类型、`documents` 数组含 `chars`/`truncated`/`status`、0 个附件时该键省略、4 个错误码);白名单在契约里也已更正为 **22 项**。
- 新登记的 `02` 项:`F7`(上传产物无删除端点 ⇒ 客户端无法清理孤儿)、可观测性订阅**会被「没有在线 WS 连接」剪掉**(客户端必须持连接)、日志**没有历史引导**(本端还没接 `GET /admin/observability/logs`,所以「最近日志」只显示进页面之后产生的)。
- **`G5` 已由后端落地**(`pending_full` 带 `clientMsgId`)⇒ 队列满时客户端从此能**精确定位是哪条气泡被丢**;本端还没接(现状仍会让那条气泡永远挂「发送中…」)——**这是下一批的候选**。
### 主人给了一个调试用 `X-API-Key`(**owner 级**,值不写进任何文件)
`GET /api/v1/sessions`、`/api/v1/admin/observability/{metrics,logs}` 全部 200 —— 联调可以**不再用口令登录**(更省事也更干净)。用法:`curl -H "X-API-Key: <值>"`。
### 新欠账(按优先级)
1. **附件预览 / 打开**(主人 2026-10-05 问的):`DocumentRepository.download(name)` 在 W6 就写好了、**零调用方**;消息 DTO 只带引用与统计(契约刻意),所以预览要**按需拉**。要做三件:① `FileProvider`(**manifest 现在没有任何 provider**,`file://` 交给别的 App 会抛 `FileUriExposedException`)② 下载到 `cacheDir/documents/<name>`(名字是内容寻址 + 服务端 `immutable` ⇒ 缓存永不失效)③ 预览要**截断并如实说明**(20 MiB 文本不能一把塞进 `Text`)。**两个决定待主人拍**:点芯片的默认动作(App 内预览 / 交给别的 App / 两者都给)与截断阈值。⚠️ `/documents/{name}` **要 Bearer**,所以**不能**照图片那样让 Coil 直接啃(Coil 用的不是挂了 `AuthInterceptor` 的那个 client)。
2. **`pending_full` 的 `clientMsgId` 接线**(后端已就绪,见上)。
3. **`GET /admin/observability/logs` 接线**(给「最近日志」补历史引导)。
4. 搜索 / 编辑删除 / `after` 仍未动;可观测性 `observability_audit` 后端仍未做(审计仍是 REST)。