1. 桥写放大:旧代码每 ~50ms 轮询都无条件重写 state 和帧 文件(约 40 次原子 temp+replace/s 走 runsc gofer, 泵持久返回同一帧、updated_at 每轮都变,字节其实不变)。 现帧字节不变不写;state 只在 url/title/started/holder/ streaming 变化时写,或 0.5s 心跳一次(判死阈值 30s, 绰绰有余);静态页写量从 ~40次/s 降到 ~2次/s。 2. MCP 主循环 stdin 优先:旧循环先 drain 再读 stdin, 每次工具调用都先付一轮文件 IO。现 pending 请求先处理, 空闲轮询 drain,忙时 200ms 保底 drain 一次防饿死。 3. stream 轮询 200ms → 50ms,画面延迟下限随之下降。 附回归测试:无变化轮询不重写、帧变化立即写、holder 变化绕过节流立即写。
根因(2026-10-30 活体实证):#181 的 .browser-remote.sock 假设 宿主能连容器内 socket,但生产 Docker 任务走 runsc/gVisor, 其 gofer 挂载下容器内建的 socket 只在容器内可见,宿主目录 里只有普通文件(browser-live.png 一直能透传)。后果:server 代理对真实任务一律 503,会话根本没活过。 修法:传输层改四个普通文件(worktree 内,原子写 + 追加日志): - .browser-remote-state.json:MCP 每轮重写,mtime 即存活信号, server 判 30 秒无心跳为会话死亡(503); - .browser-remote-frame.jpg:最新 screencast 帧(base64 文本); - .browser-remote-input.jsonl:server 追加,MCP 按偏移量消费 完整行,执行时再判 holder,半行等下一轮; - .browser-remote-control.json:{holder, seq},MCP 首轮即应用, 接管可先于浏览器启动。 - holder 竞态:control 写下后 state 文件约 50ms 才刷新,server 的 input/stream 改判 effective_holder(控制文件 mtime 新者胜), 否则接管后立刻点会误 409。 - 线程契约与控制权模型不变;MCP 主循环仍是唯一触页线程。 - 播种刷新(#181)让老租户自动拿到新版脚本。 测试:socket 测试改文件桥测试(桥轮询/偏移量/半行/陈旧态/ effective_holder + server 代理全链),全量 1357 项通过(skipped 4)。