fix(flow): graph_update 按路分桶——修真并行两路的图互相覆盖(FV2)
【取证(症状成立,且比登记描述更糟)】两路真并行时两路最终落盘**同一个 turn_id**,
其中一路的图彻底消失,且 A 路的工具被画在 B 路的图上。逐层定位:发布器 graphs 只按
sessionID 建键(后起的路整张顶掉前者)· 帧载荷基线的键集被既有测试精确断言为
{id,nodes,edges,sessionId,startedAt,endedAt}(无任何区分路的键)· 前端每会话单桶 ·
落盘 (session_id,turn_id) 唯一键两路相撞 · 冷启动 LastGraph 只有一张。
该 bug 早已公开登记(design/15 §2.5.10-1「本轮未解决」、契约 §6-19「仍**未修**」)。
【修法】
- 归属桶 {会话}[#{路}](loop.FlowOwnerKey,与 checkpoint 键同字符口径);路只来自
ParallelLegFrom(ctx) ⇒ 单路逐字不变(桶 = 会话 id),既有调用点语义零改动
- 图 id 的第二分量改用**建图序号**(每次 +1、永不复用):同一轮里可以有并行路 +
队首续跑的串行路,用轮次号会让两条串行路撞同一个 web-1
- 轮次号只在上一轮的路全部收尾后推进,并丢掉更早轮次的桶(否则内存随路数无界增长)
- 新增只读出口 LatestLanes ⇒ GET /admin/flow/graph 的 lanes[](最近一轮每一路),
graph 仍是「最新一路」= 向后兼容
- 同源洞一并修:子代理归属原取 AgentSpec.ParentSession(会话、不含路)⇒ 并行路里派的
子代理 span 被静默丢弃;新增 AgentSpec.FlowOwner 承载「会话#路」,ParentSession 继续
只承载会话(总线载荷 subagent_result.sessionId 不受影响)
- 前端:store 增 flowLanes(按 turnId 分格、按轮淘汰、硬上限 4)+ LaneTracks 泳道卡;
单路/未给 lanes 时渲染路径与改前逐字相同
【无迁移】turn_id 是自由文本、每路 id 唯一 ⇒ 0022 的唯一索引天然分两行(0023 仍空着)
【我的验收】① 隔离 worktree(30 文件)build/vet/linux/darwin 全过、69 包全绿 0 FAIL;
② 我亲手打红变异:让 FlowOwnerKey 忽略路 ⇒ TestFlowPublisher_ParallelLegsDoNotOverwriteEachOther
FAIL;③ 前端独立复跑 npx tsc --noEmit + npm run build 通过(4.12s)
⚠️ 契约 v0.77 的登记在紧随其后的 docs(contract) 提交里(同一个工作时段内)。
This commit is contained in:
1 parent
c9144c1096
commit
89434eadef
30 files changed
+2039
-148
No files matched your search
@@ -293,10 +293,10 @@ type ChannelEventStore interface {
|
||||
// 组合根把**同一个**发布器既交给 loop/orchestration(写入面:每帧 span
|
||||
// 发布 `ws.graph_update`)也交给网关(本查询面)。
|
||||
//
|
||||
// 它刻意只声明**一个读方法**:发布、建图、轮次计数与发布会话白名单都留在
|
||||
// 发布器自己手里,管理查询面拿不到、也不该拿到它们(最小权限)——因此
|
||||
// 只读查询**不可能**改变任何会话的实时图,也不可能把面板看不见的会话
|
||||
// 变成可查的(白名单外的会话从未建图,`LastGraph` 自然回 nil)。
|
||||
// 它刻意只声明**两个只读方法**(v0.77 起是两个:`LastGraph` + `LatestLanes`):
|
||||
// 发布、建图、轮次计数与发布会话白名单都留在发布器自己手里,管理查询面拿不到、
|
||||
// 也不该拿到它们(最小权限)——因此只读查询**不可能**改变任何会话的实时图,
|
||||
// 也不可能把面板看不见的会话变成可查的(白名单外的会话从未建图,两者自然回空)。
|
||||
//
|
||||
// 为 nil 时端点诚实作答 500 `flow_unavailable`,绝不回 `graph:null`
|
||||
// (那会把「图源没接线」伪装成「这一轮确实没有图」——
|
||||
@@ -305,6 +305,14 @@ type FlowGraphSource interface {
|
||||
// LastGraph 返回 sessionID 最近一轮图的一份只读快照;该会话还没有图
|
||||
// (从未跑过带 span 的轮次,或本就不在发布会话范围内)时返回 nil。
|
||||
LastGraph(sessionID string) *trace.FlowGraph
|
||||
// LatestLanes 返回 sessionID **最近一轮每一路**的图快照(契约 v0.77 的
|
||||
// `lanes[]`),按路的开始时间升序;没有图时返回空切片。
|
||||
//
|
||||
// 真并行时同一会话同一轮有多条路(design/15 §2.5.5),`LastGraph` 只给出
|
||||
// 其中最新的一条 —— 管理面板要靠本方法才看得全「两路各自的图」,否则
|
||||
// 后起的那一路会把前一路从面板上顶掉(design/15 §2.5.10-1)。它同样是
|
||||
// **只读**的:不发布、不改图、不动轮次计数。
|
||||
LatestLanes(sessionID string) []*trace.FlowGraph
|
||||
}
|
||||
|
||||
// FlowGraphStore 是**已落盘轮次图**的只读出口(契约 v0.73 的
|
||||
|
||||
Reference in new issue
Block a user