# 3-16 [done][bug] tree realtime WS 主链口径与前端 SSE 实现不一致 v1

> 发现时间：2026-05-17
>
> 状态：`[done]`
>
> 关联主线：`03-rust-web`

## 1. 问题定义

当前架构口径已描述 `/api/realtime/ws` 是树实时 push 主链，`/api/tree/events` 是 SSE fallback。但前端真实代码仍只发现 `EventSource('/api/tree/events')` 消费链路，没有发现 `/api/realtime/ws` 或 `new WebSocket` 主 consumer。

## 2. 证据

- [routes/mod.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/mod.rs:170) 注册 `/api/tree/events`。
- [routes/mod.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/mod.rs:172) 注册 `/api/realtime/ws`。
- [use-sidebar-tree-stream.ts](/mnt/Data1T/mnote/wolai-frontend/src/lib/tree-stream/use-sidebar-tree-stream.ts:137) 实际创建 `EventSource`。
- [protocol.ts](/mnt/Data1T/mnote/wolai-frontend/src/lib/tree-stream/protocol.ts:72) 固定构造 `/api/tree/events`。

## 3. 影响

- 架构文档与前端运行路径不一致。
- live cache 收口时无法判断真实主链。
- 回归测试如果只检查后端 WS route 存在，会误判前端已切换完成。

## 4. 建议修复

- 明确当前阶段：要么更新架构口径为“前端仍 SSE，WS route 已准备”，要么实现前端 WS consumer。
- 增加浏览器 smoke，断言网络中实际使用的是 WS 主链还是 SSE fallback。
- 文档与测试必须以真实前端消费路径为准。

## 5. 修复

已修复 / 已收口：

- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:7127) Rust SSR 主壳内置 `startWithWebSocket`，实际创建 `/api/realtime/ws` WebSocket consumer。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:7176) WebSocket 断开后调用 `startWithSseFallback`，`/api/tree/events` 明确成为 fallback。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:7301) SSR tree live bootstrap 默认 `transport` 已是 `convex-command-log-ws`，不再默认走 SSE。
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:7593) 增强回归测试，断言 controller 同时包含 WS 主链与 SSE fallback。

## 6. 验证

```bash
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_live_controller_marks_transport_and_closes_source_on_pagehide -- --nocapture
```

结果：1 个测试通过。
