OpenProgram / WebUI reliability / implementation handoff

WebSocket 命令与交互等待生命周期

基线:c1f10273。本页限定单条 WebSocket 命令失败、连接断开和 legacy ask_user 等待的所有权与可观察行为;实现状态与验证证据见第 07 节。

确定方案。 单条命令异常在 receive loop 内隔离并返回稳定的 action_error;dispatcher 不清理 action 自己取得的 reservation,避免误删另一连接的 owner。连接断开时,仅当该 session 没有其他聚焦连接,才向 legacy follow-up queue 投递进程内 sentinel;等待者收到 sentinel 后返回 None,不能把断连解释为空字符串答案。

01 · 当前实现与已验证缺口

入口当前行为缺口
server._websocket_handlerreceive loop 只捕获 JSON 解析异常;handler 异常由外层连接级捕获。一条坏命令结束整条连接,后续有效命令无法处理。
server._handle_ws_command未知 action 返回 action_error;已注册 handler 的异常直接传播。错误协议不一致,并可能泄漏为连接级 traceback。
server._web_follow_up使用 session queue 等待 300 秒;timeout 返回空字符串。最后一个可回答页面断开后仍等待,且断连/超时与用户回答空字符串无法区分。
stop/delete已有路径向 queue 投递取消对象或移除 queue。行为未在 WebSocket 断连入口复用;取消对象仍可能被当作答案。

02 · 参考机制与取舍

Starlette WebSocket

transport 断开通过 WebSocketDisconnect 结束连接。采用连接级清理放在 finally,命令级应用异常留在 receive loop 内处理。

QuestionRegistry

新 runtime question 已有 session-scoped、claim-once 的 cancel_session()。legacy follow-up 不迁移协议,只采用相同的“取消不是答案”语义。

现有 run reservation

_release_run_reservation(session_id,msg_id) 已按 owner 清理。dispatcher 缺少 owner token,因此拒绝在通用异常分支按 session 清理。

采用:命令级错误帧、最后观察者断连 sentinel、owner-scoped action cleanup。修改:legacy queue 的返回类型允许 None拒绝:任何 tab 断开都取消、dispatcher 按 session 删除 reservation、异常后关闭连接、把 sentinel 传给业务函数。

03 · 目标数据流

1
收到文本;非法 JSON 记录低敏诊断并继续 receive。
2
解析为 object 后执行 action handler;未知 action 沿用现有 action_error
3
handler 异常写结构化日志,仅包含 action/session/type;向同一 socket 返回 code=handler_error,然后继续接收下一条命令。
4
transport 断开后先从连接集合移除当前 socket,再检查其 focused session 是否仍有其他连接。
5
若没有其他聚焦连接且存在 legacy follow-up queue,投递唯一 sentinel;queue 仍由 _web_follow_up 的 finally 删除。
6
等待者把 sentinel 转为 None;真实空字符串仍保持空字符串,因此两者可区分。

04 · 信任边界、失败与兼容

05 · 明确排除

06 · 验收矩阵

公共入口场景可观察断言
_websocket_handler第一条已注册 action 抛 KeyError,第二条为 ping同一连接先收到低敏 action_error,再收到 pong;连接未因第一条关闭。
_websocket_handler非法 JSON忽略该帧并继续处理下一条;不回显原文本。
_web_follow_up + disconnect唯一聚焦连接断开等待线程在测试时限内返回 None,不等待 300 秒;queue 最终删除。
disconnect同 session 仍有另一聚焦连接不投 sentinel,等待保持;另一连接提交正常答案后返回该答案。
follow_up_answer用户提交空字符串返回 "",不得转换为断连。

07 · 实现文件与证据

文件职责
openprogram/webui/server.py命令级异常边界、低敏错误帧、连接观察者清理、follow-up sentinel 解释。
tests/unit/test_websocket_command_lifecycle.py真实 receive-loop、断连和等待线程的公共入口回归。

已实现并完成独立审查。 实现提交:4bc76c83be307d4b781de2b1。最终定向验证:67 passed;Ruff 通过;文档构建 457 页;链接检查 0 broken links。