← 回工程日志
# #7 修复偶发问题:聊天页字发出去之后仍留在输入框里
归属日期: 2026-10-20
序号: 7
当前状态: 📌 待做(第1次)
被接手次数: 0
该任务出现时间为
2026-10-20-本次第一次
---
## 2026-10-20 登记(登记人:晚风-DeepSeek,仅登记,未排查未修)
### 用户原话(勿改写)
> 「最近老是有偶发性的这种情况 就是我字发出去了,然后字还在聊天框里面」
### 现象定义(接手者按这个判定)
- 点发送(或 Ctrl+回车)后,**消息确实发出去了**:气泡出现、AI 开始回。
- 但**输入框里的字没被清空**,或者被清空之后**又被填回来**。
- **偶发**,不是每次;所以不能靠"试一次没好"下结论。
### 涉及文件(两份,各改一遍,改一份不影响另一份)
| 端 | 页面文件 | 桥 |
|---|---|---|
| 晚风 9000 | `/home/zyf/hermes-webchat/ui-9000.html`(A 机) | `hermes-webchat.service` |
| 幽灵 9001 | `/home/yyl/hermes-webchat/ui-9001.html`(电脑B) | `hermes-webchat-9001.service` |
页面文件是**热读**(按 mtime 现读)→ 改完手机刷新即生效,**不用重启桥**。
### 优先怀疑的代码路径(按可能性排序,均有出处)
1. **`restoreSend()` 误判(最像)**:2026-10-17 为"追加发言吞气泡"加的 `localSent` 机制里,`restoreSend()` 的职责是"把**没发成功**的文字还回输入框"。若它把"已成功但响应慢/超时"的那条也当成失败还原 → 正是"发出去了、字又回来了"。查 `send()` 的 catch 分支与 `_unsend()` 的调用条件。
2. **`send()` 里清空输入框的位置**:若清空动作写在某个 `await`/fetch 之后,前面任何提前 `return` 或异常都会跳过它。
3. **busy 分支**:`#send` 恒为"发送"(2026-10-12 定稿,busy 时也发,内核 `busy_input_mode=interrupt` 原地并入当前轮)。busy 时走 interrupt 那条路径要确认同样清了输入框。
4. **并发流保护 `streamGen` 的 finally 分支**:`if(gen===streamGen)` 只清最新那条流的账,若 gen 不匹配,连带的清理可能被跳过。
### 必须保住、不许改回去的既有定稿(回归红线)
- `#send` 恒为「发送」按钮,busy 时也能发;停止用独立 `#stopb`,**不许让发送键兼作停止键**。
- `sessPoll` 轮询间隔 = **8000**(2000 已被证明会压垮手机链路)。
- 防连点用 350ms 时间戳去抖(`_lastSendAt`),**不许用 busy 拦发送**。
- `streamGen` / `newStream()` 并发流保护必须在。
### 验证要求(改完必须给证据)
1. headless Chrome + CDP 复现路径:发一条 → 断言 `document.querySelector('#inp').value === ''`;连续发 5~10 条(含 busy 时追加发一条),**全部为空**才算过。
2. 人为制造慢响应/断网再恢复,确认 `restoreSend()` 只在**真失败**时还原文字。
3. 两端各验一次(9000 与 9001 是两份文件)。
4. 贴真命令 + 原始输出,禁止只写"已验证"。
### 不做什么
- 不动内核(`hermes_bridge.py`)——此现象是页面层,改桥属于扩大范围。
- 不动 `ui.html` 之外的渲染/流控制逻辑(`streamGen` 有翻车史,见 skill `hermes-phone-chat`)。
### 遗留/卡点
- 尚未复现(偶发),接手者先稳定复现再动手;复现不出来就先加日志埋点(发送时打印"清空前/清空后"的值),等下一次偶发抓现场。
电脑A 10-20 21:29