feat(gateway): 链路图冷启动快照(v0.71)+ 面板来源说明条 —— 修「轮次结束后打开页面一片空白」
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 断点已证 = **时序层**:graph_update 只走实时帧从不重放、flowGraphs 不持久化、补拉通路此前根本不存在(EndRound 注释承诺过「刷新能重放」,代码里从来没有)
  铁证:15:16:38 页面重载抹掉 15:09 那轮图,而下一轮心跳要等 ~15:24 ⇒ 打开后台思考页时桶必然为空
- 新增只读端点 GET /api/v1/admin/flow/graph?sessionId=(owner|admin;省略=主会话;graph 与 graph_update 帧的 data 逐字同形)
  无图 ⇒ 200 + graph:null(不画假图);图源未接线 ⇒ 500 flow_unavailable(不伪装成「没有图」);不审计、不发布
- loop.FlowPublisher.LastGraph:只读快照(不发布/不改图/不动轮次计数),FlowGraph.Clone 深拷贝避免锁外编码撕裂
- 前端 useFlowSnapshot:只在「本会话还没有图」时补拉(避免每行一个请求);Flow/Agents/Backthink 三处接入 + 来源说明条(明确「最近一轮」与「多轮历史回放尚未实现」)
- 变异实测:LastGraph 恒 nil ⇒ 4 条测试红;白名单去掉 sess-backthink ⇒ 对应测试红(首次变异因未使用 import 编译失败 ⇒ 已作废重做)
- ⚠️ 诚实边界:每会话只回**最近一轮**(多轮回放属 F2);白名单外会话(IM 群聊/陌生人)永远没有图;**后端重启后未跑新轮次前端点如实返 null(图是内存资产,不落库)**—— 主人要的「本地数据」正是 F2 要补的
This commit is contained in:
AskaEth committed 2026-10-05 15:38:53 +08:00
1 parent a3482ed06e
commit 1bf85a955b
23 files changed
+1427 -36

No files matched your search

+21
View File
@@ -21,6 +21,7 @@ import (
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/orchestration"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/task"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
"git.yeij.top/AskaEth/Cyrene_v2/internal/services/automations"
"git.yeij.top/AskaEth/Cyrene_v2/internal/services/backthink"
)
@@ -284,3 +285,23 @@ type ChannelEventStore interface {
// 的表,不含内存里待 flush 的部分(即 §4.3 的「近似值」)。
Counters(ctx context.Context, platform string) ([]events.Counter, error)
}
// FlowGraphSource 是**最近一轮链路图**的只读出口(契约 v0.71 的
// `GET /api/v1/admin/flow/graph`;design/19 §4 的 P3)。生产实现就是
// `*loop.FlowPublisher`(`internal/runtime/loop/flow.go` 的 `LastGraph`),
// 组合根把**同一个**发布器既交给 loop/orchestration(写入面:每帧 span
// 发布 `ws.graph_update`)也交给网关(本查询面)。
//
// 它刻意只声明**一个读方法**:发布、建图、轮次计数与发布会话白名单都留在
// 发布器自己手里,管理查询面拿不到、也不该拿到它们(最小权限)——因此
// 只读查询**不可能**改变任何会话的实时图,也不可能把面板看不见的会话
// 变成可查的(白名单外的会话从未建图,`LastGraph` 自然回 nil)。
//
// 为 nil 时端点诚实作答 500 `flow_unavailable`,绝不回 `graph:null`
// (那会把「图源没接线」伪装成「这一轮确实没有图」——
// 与 `usage_unavailable` / `channel_events_unavailable` 同一口径)。
type FlowGraphSource interface {
// LastGraph 返回 sessionID 最近一轮图的一份只读快照;该会话还没有图
// (从未跑过带 span 的轮次,或本就不在发布会话范围内)时返回 nil。
LastGraph(sessionID string) *trace.FlowGraph
}