跳转至

本 R1 不废弃整个 ADR-25(§1+§2+§3.1+§5+§6 主体保留)· 仅修订 §3.2 + §3.3 + §4 二 fork。 supersede:F2 bff2fc2(SubgraphsDock 第 6 项整体方向错) 保留:F1 d9a2e1c(useChainMiniNodes + 📦 视觉)· 但单击行为需 F1.1 hotfix 修不响应 abort:F3 子图详情进入路径(嵌套 mini-bar + 面包屑设计错)· 由 F3-R1 doc tabs 多 tab 路由替代 起 3 R1 hotfix:F1.1(单击不响应 hotfix 0.2d)+ F2-R1(FlowReadonlyDock 子图示意图 1.0d)+ F3-R1(doc tabs 多 tab 路由 1.5d) tags: [aios, adr, p3-xitune, flow-readonly-dock, doc-tabs, subgraph-display, hotfix-r1, supersede-fork] level: l2 related_adr: - ADR-AIOS-25 (父 ADR · 本 R1 修订 §3.2+§3.3) - ADR-AIOS-23 (supersede · ADR-25 supersede 起源 · 本 R1 教训承接 ADR-23→25→25-R1) - ADR-AIOS-08-R1 (子图定义 + dirty 标记 · 本 R1 §3.3-R1 复用 dirty) - ADR-AIOS-16 (SubgraphRuntime · 本 R1 不动)


ADR-AIOS-25-R1 · FlowReadonlyDock 显示子图示意图 + xitune doc tabs 多 tab 路由

状态:✅ v0.1 accepted · 2026-06-15 16:45(用户 16:45 拍板 accept · 31 分钟内通过 · 同时启用 .clinerules v3.0 终极极简) 修订对象:ADR-25 §3.2 + §3.3 + §4 实施清单 F2/F3 二 fork 保留对象:ADR-25 §1 §2 §3.1 §5 §6 决议主体不动 + F1 d9a2e1c(useChainMiniNodes + 📦 视觉)部分保留 + 单击行为需 F1.1 hotfix


§0 修订记录(Revision History)

时间 版本 事件
2026-06-15 12:12 ADR-25 v0.1 proposed supersedes ADR-23(范围迁移 xilink→xitune)
2026-06-15 13:42 ADR-25 v0.1 accepted 4 fork ready · F1+F2 双连可起手
2026-06-15 13:50 F1+F2 双连 dispatched DASHBOARD v5.1.8 · ClaudeA
2026-06-15 15:48 F2 zombie bff2fc2 SubgraphsDock 落地
2026-06-15 15:53 F1 zombie d9a2e1c useChainMiniNodes 落地
2026-06-15 16:06 ⛔ 用户反馈范围方向错 见 §1.1 verbatim
2026-06-15 16:08~16:13 4 路真值核查 git show F1+F2 + read FlowReadonlyDock(402 行)+ grep DocTab(已存在 buildDocTabs/setDocTabs 框架)+ list xitune drawers
2026-06-15 16:14 R1 v0.1 proposed 3 R1 hotfix(F1.1+F2-R1+F3-R1)

§1 修订触发与用户原话

§1.1 6/15 用户纠错原话(verbatim · 16:06)

xilink 定义了子图,又是没有理解我的需求定义。。。。 我需要你再 xitune 中的原来 link,第二个 dock 中已经实现了只读 link 的显示,只不过不能显示子图模块;所以我需要你去完善他做到能显示子图示意图,并且双击可以打开一个主页的 tab,新的 tab 中 mini-node 中可以显示当前子图的所有模块,剩下的逻辑和主链路的 tab 一致,单击主界面是当前调音窗口双击悬浮窗; 在主页面的 mini-node 中双击子图模块可以打开或者跳转到子图 tab 主页,主链路中单击子图主页面不变化

§1.2 verbatim 三段拆解(关键定位)

# 用户原话片段 真意定位 ADR-25 v0.1 错误方向
1 "xitune 中的原来 link · 第二个 dock 中已经实现了只读 link 的显示 · 只不过不能显示子图模块 · 我需要你去完善他" 完善 xitune/drawers/FlowReadonlyDock.vue(LEFT_DOCK 第 2 项 xt-flow 🔗 链路流图 · v5 自绘 SVG mini-map · 402 行)使 SVG 中显示子图示意图 ❌ ADR-25 v0.1 §3.2 新建 SubgraphsDock 第 6 项(F2 bff2fc2 落地 · 整体方向错)
2 "双击可以打开一个主页的 tab · 新的 tab 中 mini-node 中可以显示当前子图的所有模块 · 剩下的逻辑和主链路的 tab 一致 · 单击主界面是当前调音窗口双击悬浮窗" xitune 已有 buildDocTabs() + shellSlots.setDocTabs() 框架(L220-231)· R1 扩展为多 tab 路由(主 tab + 子图 tab N 个)· 子图 tab 主页 = 复用 chain-mini-bar 但 modules 源切到 subgraphDefs[defId].nodes · 单击/双击行为与 Main tab 一致 ❌ ADR-25 v0.1 §3.3 currentSubgraphId state + 面包屑 Main > [子图名] + 嵌套 mini-bar 设计(F3 设计错 · 应改重设计)
3 "在主页面的 mini-node 中双击子图模块可以打开或者跳转到子图 tab 主页 · 主链路中单击子图主页面不变化" F1 双击 stub 升级为 openSubgraphTab(defId) · F1 单击行为需改:子图节点单击不响应(主页面不变化) ⚠️ F1 d9a2e1c 双击 stub 占位行为对 · 但单击行为目前仍是默认 onMiniNodeClickWithDelay 切 activeInstanceId(用户明确说不变化 · 需 F1.1 hotfix)

§1.3 误读分析(ADR-25 v0.1 起草病根)

ADR-25 v0.1 起草时(6/15 12:12)Cline-AIOS 起草 §3.2 SubgraphsDock 第 6 项时未对照 xitune 现有 12 drawer 体系中已存在的 xt-flow FlowReadonlyDock.vue(只读 SVG 流图 · 402 行 · 用户原意中"原来 link 第二个 dock"明确指此)· 同时起草 §3.3 时未发现 xitune 已有 buildDocTabs/setDocTabs/DocTab 框架(L220-231)· 凭"嵌套 mini-bar + 面包屑"自创 · 与项目既有 doc tab 约定背离 · 6/15 用户实测后纠错。

§1.4 4 路真值核查关键证据

证据 结论
E1 git show bff2fc2 stat F2 落地 5 文件 +523/-15 · 含新建 SubgraphsDock(183 行)+ SubgraphListItem(109 行)+ useSubgraphList(43 行)+ test(127 行)+ 修 xitune/index.vue 76 行(LEFT_DOCK 第 6 项 + drawer 注册 + F1 模板 CSS 携带)
E2 read FlowReadonlyDock.vue 全文 402 行 · v5 自绘 SVG mini-map · L54-83 模块节点 <g><rect> + <text> 渲染 · L123-132 getModuleBg(moduleId) 颜色映射 · L153-157 onModuleDblClick = floating.openDialog · 完全无子图识别 → R1 完善的真扩展点(用户原意中"完善他")
E3 grep "tab|Tab" xitune/index.vue L117 activeDocTabLabel 显示当前文档 / L220-231 buildDocTabs() 单 tab 工程名 · 已有 shellSlots.setDocTabs(tabs, 'main') API · L227 单 tab 实现 · L220 注释明确"无子图则不显示多 tab"(预留扩展位)→ R1 多 tab 路由现成基础
E4 F1 d9a2e1c diff useChainMiniNodes composable 派生 isSubgraph + subgraphMeta · 模板 mini-node--subgraph class + 📦 emoji + tooltip + 双击 stub 占位 · ✅ 视觉部分可保留 · ❌ 单击行为未改(@click="onMiniNodeClickWithDelay(...)" 默认切 activeInstanceId) → 需 F1.1 hotfix

§2 修订决议(Decision Revision)

§2.1 三个核心修订点

修订点 原 ADR-25 v0.1 R1 修订后
§3.2 子图入口 新建 SubgraphsDock.vue 左 dock 第 6 项 + 列表 + 单击切 active + 双击 emit 完善 FlowReadonlyDock.vue SVG 流图(LEFT_DOCK 第 2 项 xt-flow)· SVG 中子图节点显示子图示意图(嵌套小矩形 + 不同色 + 📦 标记)· 双击 → openSubgraphTab
§3.3 双击行为 currentSubgraphId state + 面包屑 Main > [子图名] + chain-mini-bar 嵌套渲染 xitune doc tabs 多 tab 路由(扩展现有 buildDocTabs() + shellSlots.setDocTabs())· 主 tab + 子图 tab N · 关闭按钮 · dirty 复用 ADR-08-R1 · 子图 tab 主页 chain-mini-bar 复用主链路结构 + modules 源切到 subgraphDefs[defId].nodes
§3.1 单击行为(F1 d9a2e1c 已落地需 hotfix) 单击切 activeInstanceId(默认行为) 子图节点单击不响应(主页面不变化 · 用户 verbatim "主链路中单击子图主页面不变化")

§2.2 F1 d9a2e1c 资产保留矩阵

F1 落地资产 R1 处置 理由
useChainMiniNodes.ts composable 完全保留 派生 isSubgraph + subgraphMeta 是子图节点视觉识别的真值源 · F2-R1 FlowReadonlyDock 也复用
xitune/index.vue 模板 mini-node--subgraph class ✅ 保留 子图节点 📦 emoji + 副字 + 高亮边框视觉对
xitune/index.vue CSS .mini-node--subgraph + .mn-subgraph-count ✅ 保留 视觉样式对
xitune/index.vue onMiniNodeDblclick 子图分支(console.log stub) ✅ 保留 → R1 升级 F3-R1 实施时把 console.log 替换为 useSubgraphTabs.openSubgraphTab(node.subgraphMeta.defId)
xitune/index.vue onMiniNodeClickWithDelay 子图节点行为 需 F1.1 hotfix 当前默认切 activeInstanceId · 用户明确说"主链路中单击子图主页面不变化" · F1.1 加 isSubgraph 分支提早 return
useChainMiniNodes.spec.ts 5 case ✅ 保留 单元测试覆盖派生逻辑正确

§2.3 F2 bff2fc2 资产废弃矩阵

F2 落地资产 R1 处置 理由
SubgraphsDock.vue(183 行) 删除 整体方向错 · 用户要的是完善 FlowReadonlyDock 不是新建 dock
SubgraphListItem.vue(109 行) 删除 SubgraphsDock 子组件 · 一并废弃
useSubgraphList.ts(43 行) 删除 SubgraphsDock 数据源 · 一并废弃(R1 用 useChainMiniNodes 派生 isSubgraph 即可识别子图)
useSubgraphList.spec.ts(127 行) 删除 测试 useSubgraphList 一并废弃
xitune/index.vue LEFT_DOCK 第 6 项 { key: 'xt-subgraph', icon: '📦', tip: '子图列表...' } 删除 用户不需要新建 dock 项
xitune/index.vue shellSlots.registerDrawerComponent('xt-subgraph', ...) 一行 删除 drawer 注册一并删
xitune/index.vue 注释 "(LEFT 6 + RIGHT 7 = 13 项)" 改回 "(LEFT 5 + RIGHT 7 = 12 项)" 数量恢复

§2.4 F3 子图详情(嵌套 mini-bar + 面包屑)整体废弃

ADR-25 v0.1 §3.3 设计的 currentSubgraphId state + 面包屑 Main > [子图名] + chain-mini-bar 嵌套渲染 整体废弃 · 由 F3-R1 doc tabs 多 tab 路由(扩展现有 buildDocTabs() + shellSlots.setDocTabs())替代 · F3 active prompt 撤销(从未派发 · 文件未落地不需 abort)。


§3 业务行为契约修订

§3.1-R1 chain-mini-bar 单击行为修订(superseding ADR-25 §3.1 单击部分)

① 输入/输出契约(F1 d9a2e1c 已落地视觉部分保留)

// 复用 F1 useChainMiniNodes composable 派生(L389-401 chainMiniNodes computed)
// onMiniNodeClickWithDelay 加 isSubgraph 分支
function onMiniNodeClickWithDelay(instanceId: string, _moduleId: string) {
  // R1 §3.1 ① — 子图节点单击不响应(主页面不变化)
  const node = chainMiniNodes.value.find(n => n.instanceId === instanceId)
  if (node?.isSubgraph) {
    // 子图节点单击不响应:不切 activeInstanceId · 主页面不变化
    return
  }
  // 普通节点 / IO 端点保持原行为(切 activeInstanceId 等)
  // ... 现有逻辑 ...
}

② 收敛/成功判据

判据 阈值 含义
子图节点单击响应 0 副作用(主页面不变化) activeInstanceId 不变 / 主区不刷新 / floating 不弹
子图节点 hover tooltip ✅ 保留(F1 d9a2e1c) 子图 ${name} · 含 ${moduleCount} module · 双击查看内部
子图节点高亮边框 ✅ 保留(F1 d9a2e1c CSS) 蓝紫色 1px solid + box-shadow
子图节点双击 触发 openSubgraphTab(F3-R1 接管) 占位 console.log → openSubgraphTab(defId)
普通 module 单击 默认行为不变 保持 onMiniNodeClickWithDelay 切 activeInstanceId

③ 失败回退路径(5 类)

失败 触发 UI 表现 恢复路径
useChainMiniNodes 没找到 instanceId 数据竞态 不响应(同子图节点) reactive 重 emit
isSubgraph 字段缺失 F1 d9a2e1c 回滚 退化为默认行为 F1.1 hotfix 后恢复
子图节点 hover 时 tooltip 加载失败 reactive 异步 显示 fallback "子图(加载中)" watcher 完成后正确
子图节点高亮边框未渲染 CSS 加载顺序 同普通 module scoped style 已 import 应自动
用户连续单击切换 多次 click race 始终不响应(idempotent) 无 race(早 return)

④ 用户操作流(端到端 5 步)

  1. 用户在 xitune 主链路 chain-mini-bar 看到子图节点 📦 EQ_A(3个)
  2. 单击 📦 EQ_A → 主页面不变化(activeInstanceId 不切 / 主区不刷新)
  3. hover 📦 EQ_A → tooltip "子图 EQ_A · 含 3 module · 双击查看内部"
  4. 双击 📦 EQ_A → 触发 F3-R1 openSubgraphTab(defId)(子图 tab 主页打开 / 跳转)
  5. 普通 module 节点单击行为不变(切 activeInstanceId 等)

⑤ 端到端真值 e2e

test('R1 §3.1 · 子图节点单击不响应主页面不变化', async ({ page }) => {
  await loadFixture('subgraph-eq-a-with-3-modules.xitune')
  await page.goto('/xitune')
  // 选定一个普通 module 作 baseline
  await page.click('.mini-node[data-module-id="gain_v1"]')
  const baselineActiveId = await page.locator('.tuning-main').getAttribute('data-active-instance-id')
  // 单击子图节点
  await page.click('.mini-node--subgraph[data-instance-id="eq-a-001"]')
  // 断言:主页面 activeInstanceId 不变(主页面不变化)
  const afterClickActiveId = await page.locator('.tuning-main').getAttribute('data-active-instance-id')
  expect(afterClickActiveId).toBe(baselineActiveId)
})

§3.2-R1 FlowReadonlyDock 子图示意图(superseding ADR-25 §3.2 SubgraphsDock 整体废弃)

① 输入/输出契约

// 复用 useChainMiniNodes 派生 isSubgraph(R1 重构 FlowReadonlyDock 使用此 composable 替代直接读 linkStore.modules)
// 或新增 useSubgraphFlowNodes composable(从 linkStore.modules + linkStore.subgraphDefs 派生 FlowSubgraphNode)

interface FlowSubgraphNode extends ModuleInstance {
  isSubgraph: true
  subgraphMeta: {
    defId: string
    name: string
    moduleCount: number
    nestedNodes: ModuleInstance[]  // 子图内部 module 数组(用于 SVG 嵌套渲染)
  }
}

// FlowReadonlyDock SVG 渲染分支(L54-83 模块节点 `<g>` 加 isSubgraph 分支)
// - 普通 module:`<rect>` + `<text>` 单层(现有)
// - 子图 module:`<rect>` 外框(同尺寸 200×80 · 蓝紫色 fill rgba(157,78,221,0.15))+
//   内部 `<rect>` × N(每个子模块 30×16 · 网格布局 max 5 列)+ `<text>` 顶部 📦 EQ_A (3个)

② 收敛/成功判据

判据 阈值 含义
子图示意图渲染 200×80 主框 + N 个 30×16 嵌套小矩形(网格 max 5 列) 每个子模块 1 个小矩形 · 不重叠
子图节点视觉区分 蓝紫色 fill rgba(157,78,221,0.15) + 📦 emoji 顶部 与普通 module 颜色映射(getModuleBg)对比明显
子图节点单击 highlightId 高亮(同普通 module · L148) eventBus emit xitune:active-module
子图节点双击 openSubgraphTab(defId)(F3-R1 接管 · 不再调 floating.openDialog) 跳转子图 tab
渲染性能 50 modules 中 5 子图各含 5 module · 渲染 ≤ 50ms SVG 直绘 · 无虚拟列表开销

③ 失败回退路径(5 类)

失败 触发 UI 表现 恢复路径
subgraphDefs[defId] 不存在 xilink 工程导出后 def 删 主框 + ⚠️ 红字"def 缺失" 用户重新导入 xilink 工程
子图内 module 数 = 0 空子图 主框 + 📦 EQ_A (0个) · 无嵌套小矩形 等用户在 xilink 添加 module
子图内 module 数 > 25 超 5×5 网格 显示前 24 个 + 第 25 格 "..." 省略号 双击进入子图 tab 看完整
嵌套子图 子图内含子图(ADR-16 支持) 内层小矩形仍是普通子图(<rect> 30×16 · 不递归) F3-R1 子图 tab 内可再嵌套(进 N 层)
SVG 渲染异常 浏览器兼容 退化为单层 module 渲染(同 v5 现有) 浏览器升级或刷新

④ 用户操作流(端到端 5 步)

  1. 用户在 xitune 切到 LEFT_DOCK 第 2 项 xt-flow 🔗 链路流图(只读)
  2. SVG 流图显示主链路:🎵 source → 📦 EQ_A(嵌套小矩形 × 3:peq + gain + delay)→ 📤 sink
  3. 单击 📦 EQ_A 主框 → 高亮(stroke 黄色 D4A574)+ eventBus emit
  4. 双击 📦 EQ_A 主框 → openSubgraphTab(eq-a-def) → xitune 顶部 doc tabs 加 "EQ_A.subgraph" tab + 自动切到该 tab
  5. 进入子图 tab 主页 → chain-mini-bar 显示子图内部:🎚 peq → 🔊 gain → ⏱ delay(单击调音 / 双击悬浮窗与 Main tab 一致)

⑤ 端到端真值 e2e

test('R1 §3.2 · FlowReadonlyDock 子图示意图 SVG 渲染', async ({ page }) => {
  await loadFixture('subgraph-eq-a-with-3-modules.xitune')
  await page.goto('/xitune')
  await page.click('[data-dock-key="xt-flow"]')

  // 子图主框
  const subgraphRect = page.locator('.flow-node[data-is-subgraph="true"][data-def-id="eq-a-def"] rect.flow-subgraph-main')
  await expect(subgraphRect).toBeVisible()
  await expect(subgraphRect).toHaveAttribute('fill', /rgba\(157,78,221/)

  // 嵌套小矩形 × 3
  const nestedRects = page.locator('.flow-node[data-is-subgraph="true"] rect.flow-subgraph-nested')
  await expect(nestedRects).toHaveCount(3)

  // 顶部 📦 EQ_A (3个)
  await expect(page.locator('.flow-node[data-is-subgraph="true"] text.flow-subgraph-label')).toContainText('📦 EQ_A')

  // 双击进入子图 tab
  await page.dblclick('.flow-node[data-is-subgraph="true"]')
  await expect(page.locator('.doc-tab[data-tab-key^="subgraph-eq-a-def"]')).toBeVisible()
})

§3.3-R1 xitune doc tabs 多 tab 路由(superseding ADR-25 §3.3 嵌套 mini-bar 整体废弃)

① 输入/输出契约

// 扩展现有 buildDocTabs()(L221-228)+ 新增 useSubgraphTabs composable
// xitune/composables/useSubgraphTabs.ts(R1 新建)
interface SubgraphTab {
  key: string                  // `subgraph-${defId}`
  defId: string
  name: string
  icon: '📦'
  dirty: boolean               // 复用 ADR-08-R1 R1.5 dirty 标记
  closeable: true              // 主 tab key='main' closeable=false
}

interface UseSubgraphTabsReturn {
  openSubgraphTab(defId: string): void           // 已开则切 active · 未开则新建并切 active
  closeSubgraphTab(defId: string): void          // 关闭 + 切回 'main'
  activeTabId: Ref<string>                       // 当前 active tab key
  subgraphTabs: ComputedRef<SubgraphTab[]>       // 已打开的子图 tab 数组
}

// 扩展 buildDocTabs()
function buildDocTabs(): DocTab[] {
  const main = { key: 'main', label: name + '.xitune', icon: '🎚', dirty: false }
  const subgraphs = subgraphTabs.value.map(t => ({
    key: t.key,
    label: t.name + '.subgraph',
    icon: t.icon,
    dirty: t.dirty,
    closeable: t.closeable,
  }))
  return [main, ...subgraphs]  // 主 tab 永居首位
}

// 子图 tab 主页 modules 源切换
const currentTabModules = computed(() => {
  if (shellSlots.activeDocTab === 'main') {
    return linkStore.modules  // 主链路(现有)
  }
  // 子图 tab:从 subgraphDefs 取 nodes
  const tab = subgraphTabs.value.find(t => t.key === shellSlots.activeDocTab)
  if (!tab) return linkStore.modules  // fallback
  return linkStore.subgraphDefs[tab.defId]?.nodes ?? []
})

// 子图 tab 主页 chain-mini-bar 复用结构(useChainMiniNodes 接收 currentTabModules 而非 orderedModules)
const { chainMiniNodes } = useChainMiniNodes(currentTabModules)

② 收敛/成功判据

判据 阈值 含义
openSubgraphTab 切换延迟 ≤ 100ms shellSlots.setDocTabs + activeDocTab 切
主 tab 永居首位 buildDocTabs 永远 main 在 [0]
子图 tab 关闭按钮 ✅(closeable=true) shell 默认关闭按钮支持
dirty 标记 复用 ADR-08-R1 R1.5 子图内调音未保存时 dirty=true · 红点显示
子图 tab 主页 chain-mini-bar 显示子图内部 modules 单击调音 / 双击悬浮窗与 Main tab 一致
嵌套深度 任意层(子图 tab 内再双击子图开新 tab) tabs 平铺 · 不嵌套
已开则跳转(不重开) openSubgraphTab(defId) 检查 subgraphTabs.find(t => t.defId === defId) idempotent

③ 失败回退路径(5 类)

失败 触发 UI 表现 恢复路径
进入不存在的 defId def 被删但实例还在 toast "子图定义已不存在" + 不开 tab + 保持当前 tab 用户去 xilink 修复
同 defId 多次 openSubgraphTab idempotent 检查 已开则切 active · 不重开 (已避免)
子图 tab 关闭时该 tab 是 active 切回 'main' shellSlots.setDocTabs activeKey='main' 自动
主 tab key='main' 被错误关闭 shell bug 拒绝关闭(closeable=false) shell 已支持
浏览器刷新丢失打开的子图 tabs F5 仅保留主 tab(状态不持久化) 用户重新双击进入

④ 用户操作流(端到端 6 步)

  1. 用户在 xitune chain-mini-bar 主链路双击 📦 EQ_A → openSubgraphTab('eq-a-def')
  2. xitune 顶部 doc tabs 出现 [🎚 工程名.xitune] [📦 EQ_A.subgraph(可关闭)] · 自动切到 EQ_A tab
  3. EQ_A tab 主页 chain-mini-bar 显示:🎚 peq → 🔊 gain → ⏱ delay(单击调音 / 双击悬浮窗 · 与 Main tab 一致)
  4. 用户单击 🎚 peq → 主区右侧加载 GEQTuningDialog inline 调音(activeInstanceId 切到子图内 peq instanceId)
  5. 用户调完关闭 EQ_A tab(点 ×)→ 切回 [🎚 工程名.xitune] 主 tab · activeInstanceId 自动恢复主 tab 之前选择
  6. 主 tab 内单击普通 gain module 切换调音(默认行为不变)· 单击子图节点不响应(§3.1-R1)

⑤ 端到端真值 e2e

test('R1 §3.3 · doc tabs 多 tab 路由 + 子图 tab 主页 chain-mini-bar 复用', async ({ page }) => {
  await loadFixture('subgraph-eq-a-with-3-modules.xitune')
  await page.goto('/xitune')

  // 双击进入子图 tab
  await page.dblclick('.mini-node--subgraph[data-instance-id="eq-a-001"]')

  // 主 tab + 子图 tab
  await expect(page.locator('.doc-tab')).toHaveCount(2)
  await expect(page.locator('.doc-tab').nth(0)).toContainText('.xitune')
  await expect(page.locator('.doc-tab').nth(1)).toContainText('EQ_A.subgraph')
  await expect(page.locator('.doc-tab').nth(1)).toHaveClass(/active/)

  // 子图 tab 主页 chain-mini-bar 显示内部 modules
  await expect(page.locator('.mini-node[data-module-id^="peq"]')).toBeVisible()
  await expect(page.locator('.mini-node[data-module-id^="gain"]')).toBeVisible()
  await expect(page.locator('.mini-node[data-module-id^="delay"]')).toBeVisible()

  // 单击 peq 调音(与 Main tab 一致)
  await page.click('.mini-node[data-module-id^="peq"]')
  await expect(page.locator('.tuning-dialog-peq')).toBeVisible()

  // 关闭子图 tab
  await page.click('.doc-tab[data-tab-key^="subgraph-eq-a"] .doc-tab-close')
  await expect(page.locator('.doc-tab')).toHaveCount(1)
  await expect(page.locator('.doc-tab').nth(0)).toHaveClass(/active/)
})

§3.4-R1 e2e 真值验证(整合 §3.1-R1 + §3.2-R1 + §3.3-R1)

复合 R1 三 fork 端到端场景 · 已在 §3.1/§3.2/§3.3 ⑤ 中分别给出 · F4-R1 整合为 1 个 spec 文件 · 含上述 4 test + fixture 创建 + DSP 注入断言(若需要)。

// frontend_vue3/e2e/scenarios/xitune-subgraph-r1/integration.spec.ts
test.describe('ADR-25-R1 xitune 子图 R1(FlowReadonlyDock 示意图 + doc tabs 多 tab + 单击不响应)', () => {
  test('§3.1-R1 主链路单击子图节点不响应', ...)              // §3.1 ⑤
  test('§3.2-R1 FlowReadonlyDock 子图示意图 SVG', ...)       // §3.2 ⑤
  test('§3.3-R1 doc tabs 多 tab 路由 + chain-mini-bar 复用', ...)  // §3.3 ⑤
  test('真值断言:子图 tab 内 peq 调音影响实际 audio 输出', async ({ page }) => {
    // 注入 1kHz @ -10dBFS · 进入 EQ_A 子图 tab · 调 peq +6dB @ 1kHz · 断言 sink 输出 -4dBFS ± 0.5dB
  })
})

§4-R1 实施清单(superseding ADR-25 §4)

§4.1 supersede 矩阵

原 fork 状态 R1 处理
F1 P3.A25.F1-xitune-mini-bar-subgraph-icon d9a2e1c zombie 部分保留(useChainMiniNodes + 📦 视觉)+ ❌ 单击行为 supersede by F1.1-R1 hotfix
F2 P3.A25.F2-xitune-subgraphs-dock bff2fc2 zombie 整体 supersede by F2-R1(SubgraphsDock 错向 · 4 文件需删 + LEFT_DOCK 第 6 项需删)
F3 P3.A25.F3-xitune-subgraph-detail-view 未派发 整体废弃(嵌套 mini-bar + 面包屑设计错 · 由 F3-R1 doc tabs 多 tab 替代)
F4 P_e2e.A25.F4-xitune-subgraph-e2e 未派发 重设计为 F4-R1(e2e spec 全新写 · 整合 §3.1-R1 + §3.2-R1 + §3.3-R1 真值断言)

§4.2 R1 hotfix fork 表

F# UID 部门 Worker 工作量 描述 blocked-by
F1.1-R1 P3.UA25R1.F1-mini-bar-click-no-response-on-subgraph 前端 P3-xitune ClaudeA 0.2d xitune/index.vue onMiniNodeClickWithDelay 加 isSubgraph 分支提早 return + vitest +2 case + revert F2 4 文件删除 + LEFT_DOCK 第 6 项删除 + drawer 注册删除 + 数量注释改回(LEFT 5 + RIGHT 7 = 12 项) 无(ready · F2 删除合并在此 hotfix)
F2-R1 P3.UA25R1.F2-flow-readonly-dock-subgraph-display 前端 P3-xitune ClaudeA 1.0d 完善 FlowReadonlyDock.vue SVG 流图(L54-83)子图节点显示子图示意图(嵌套小矩形 max 5×5 + 蓝紫色 + 📦 emoji 顶部)+ 双击行为改 openSubgraphTab(defId)+ vitest +6 case F1.1-R1(可与 F3-R1 文件正交并行)
F3-R1 P3.UA25R1.F3-doc-tabs-multi-tab-routing 前端 P3-xitune ClaudeA 1.5d 新建 useSubgraphTabs composable + 扩展 buildDocTabs 派生子图 tab + 子图 tab 主页 chain-mini-bar modules 源切换(currentTabModules computed)+ openSubgraphTab/closeSubgraphTab API + dirty 复用 ADR-08-R1 R1.5 + vitest +8 case F1.1-R1(可与 F2-R1 文件正交并行)
F4-R1(后续) P_e2e.A25R1.F4-truth-e2e-subgraph-r1 🏆 测试编排 P_e2e ClaudeC 0.5d playwright integration spec 4 test(§3.1-R1 + §3.2-R1 + §3.3-R1 + DSP 真值断言)+ subgraph-eq-a-with-3-modules.xitune fixture 创建 + 1kHz @ -10dBFS peq+6dB 断言 F1.1-R1 + F2-R1 + F3-R1 全 zombie
合计 2.7d 3 hotfix + 0.5d e2e = 3.2d 3 R1 hotfix(全前端 P3-xitune · ClaudeA)+ 1 e2e(ClaudeC)

关键路径:F1.1-R1 → (F2-R1 || F3-R1 文件正交并行)→ F4-R1 e2e

isolation:全部 file isolation(同 worktree 同 branch · 04_development/frontend_vue3/ · F2-R1 改 FlowReadonlyDock.vue · F3-R1 改 xitune/index.vue + 新建 useSubgraphTabs.ts · 文件正交)

§4.3 F1.1-R1 必含工作清单(combo hotfix · 单独说明)

F1.1-R1 是组合 hotfix(单击行为 + F2 文件清理)· 必含 6 件事: 1. ✏️ 修改 xitune/index.vue onMiniNodeClickWithDelay 加 isSubgraph 提早 return 分支 2. 🗑️ 删除 xitune/drawers/SubgraphsDock.vue(183 行) 3. 🗑️ 删除 xitune/drawers/SubgraphListItem.vue(109 行) 4. 🗑️ 删除 xitune/composables/useSubgraphList.ts(43 行) 5. 🗑️ 删除 xitune/composables/__tests__/useSubgraphList.spec.ts(127 行) 6. ✏️ 修改 xitune/index.vue LEFT_DOCK 数组删第 6 项 + drawer 注册删 'xt-subgraph' 一行 + 注释 "(LEFT 6 + RIGHT 7 = 13 项)" 改回 "(LEFT 5 + RIGHT 7 = 12 项)" 7. ✅ vitest +2 case(子图节点单击不响应 · 普通节点单击切 active) 8. ✅ vue-tsc + build + 全测试基线零回归


§5 风险与缓解

风险 缓解
F1.1-R1 删 4 文件 + 改 xitune/index.vue 同 commit · 风险一次过多 拆 2 commit:① 删 SubgraphsDock 4 文件 + LEFT_DOCK ② onMiniNodeClickWithDelay isSubgraph 分支 + 测试
F2-R1 改 FlowReadonlyDock SVG 嵌套小矩形性能(50 modules × 5 子模块 = 250 nodes) SVG 直绘单层 transform · 现有 v5 已支持 50+ modules 流畅 · R1 增 5×5 嵌套小矩形开销 < 5ms · 性能基线达标
F3-R1 buildDocTabs 多 tab 切换 race condition(快速双击多个子图节点) useSubgraphTabs idempotent 检查(同 defId 不重开)+ shellSlots.setDocTabs 原子操作
F3-R1 子图 tab 内 chain-mini-bar 渲染依赖 useChainMiniNodes 接收 currentTabModules · 与 F1 d9a2e1c 现有用法(orderedModules)冲突 修改 useChainMiniNodes 签名:接收 ref(子图 tab 时传 currentTabModules · 主 tab 时传 orderedModules)· 现有调用点改一处
F1 d9a2e1c onMiniNodeClickWithDelay 依赖 chainMiniNodes.value.find(...) 性能 O(N) 查找 · N ≤ 50 · 单击事件低频 · 性能可忽略
dirty 标记复用 ADR-08-R1 R1.5 但 R1.5 实现细节未深入 read F3-R1 prompt Step 0 强制 read ADR-08-R1 R1.5 + linkStore.subgraphDefs dirty 字段真签名 · 不猜
F4-R1 e2e fixture 子图工程 .xitune 文件需手动创建 F4-R1 prompt 含 fixture 创建步骤 + 路径明确(e2e/fixtures/subgraph-eq-a-with-3-modules.xitune)
ClaudeA 排队膨胀(F8 ADR-15 + F1.1-R1 + F2-R1 + F3-R1 + F4-R1 ClaudeC + 后续 ADR-21-R1 4 hotfix 共 7+ 任务) F1.1-R1 极短(0.2d)优先抢占 · F2-R1+F3-R1 文件正交并行 · 实际 ClaudeA 串行 0.2 + max(1.0,1.5) = 1.7d

§6 决议者签名

  • proposed by:Cline-AIOS(2026-06-15 16:14)
  • revision trigger:user(2026-06-15 16:06 verbatim 三段拆解)
  • review by:user(待 accept)
  • accepted by:(待用户 accept ADR-AIOS-25-R1)

§7 状态流转

时间 事件 备注
2026-06-15 16:14 R1 v0.1 proposed 3 R1 hotfix(F1.1+F2-R1+F3-R1)+ F4-R1 e2e
(待) R1 v0.1 accepted 等用户 accept 派发 F1.1-R1
(待) F1.1-R1 zombie 单击不响应 + F2 文件清理
(待) F2-R1 / F3-R1 双并行 zombie FlowReadonlyDock 子图示意图 + doc tabs 多 tab 路由
(待) F4-R1 e2e zombie 整合 §3.1-R1 + §3.2-R1 + §3.3-R1 真值断言
(待) R1 fulfilled 🏆 ADR-25 整体闭环(含 R1 · 用户三件套盲区在 xitune 真闭环)

§8 关联文档

  • ADR-AIOS-25(父 ADR · 本 R1 修订 §3.2+§3.3)
  • ADR-AIOS-23(supersede 起源 · ADR-25 supersede ADR-23 · 本 R1 教训承接 ADR-23→25→25-R1)
  • ADR-AIOS-08-R1(子图定义 + dirty 标记 · 本 R1 §3.3-R1 复用 dirty)
  • ADR-AIOS-16(SubgraphRuntime · 本 R1 不动)
  • F1 commit:d9a2e1c(useChainMiniNodes + 📦 视觉 · 部分保留)
  • F2 commit:bff2fc2(SubgraphsDock 整体 supersede · F1.1-R1 删除)
  • FlowReadonlyDock.vue:402 行 v5 自绘 SVG mini-map(F2-R1 完善目标)
  • xitune/index.vue L220-231:buildDocTabs() + setDocTabs() 已存在框架(F3-R1 扩展基础)

§9 教训沉淀(R1 修订专属 · ADR-23→25→25-R1 三连教训)

§9.1 ADR 起草未对照目标 stage 现有 dock/tab 框架的二次教训

ADR-25 v0.1 起草时(6/15 12:12)Cline-AIOS 虽然吸取了 ADR-23 教训(grep 目标 stage 现状)· 但 read xitune 现状时只 read 了 xitune/index.vue line 7-58 chain-mini-bar 模板(确认现有 chain-mini-bar 实现)· read 完整 drawer 12 项 / grep "DocTab|setDocTabs|buildDocTabs" 确认已有 doc tab 框架 · 凭"新建 SubgraphsDock 第 6 项" + "嵌套 mini-bar + 面包屑"自创 · 与项目既有约定背离 · 6/15 用户实测后再次纠错。

沉淀(高于 ADR-25 §9.1 的二次铁律 · 写入 .clinerules): - 起 ADR 前不仅要 grep 目标 stage 现状 · 还需对照"用户原话中提及的现有组件"逐一找到具体文件: - 用户说"原来 link · 第二个 dock" → 必须找到 LEFT_DOCK 第 2 项的实际 drawer 文件(本例 = FlowReadonlyDock.vue) - 用户说"打开一个主页的 tab" → 必须找到目标 stage 是否已有 tab bar / DocTab 框架(本例 = buildDocTabs/setDocTabs 已存在) - 用户原话中"完善他"/"主页的 tab"等指代词必须解析为具体文件 / API · 不能凭"新建 dock"/"嵌套 mini-bar"自创

§9.2 F1+F2 双连派发的资产保留教训

ADR-25 v0.1 F1+F2 双连派发后 · F1(d9a2e1c)落地视觉部分对(useChainMiniNodes + 📦 + tooltip + 高亮)· F2(bff2fc2)落地整体方向错(SubgraphsDock)· R1 修订时精细评估 F1 部分保留 + F2 整体废弃(见 §2.2 + §2.3 矩阵)· 而非简单 git revert(过度回滚 · 会丢 F1 视觉资产)。

沉淀:R1 修订时不能盲目 git revert 错向 fork commit · 必须 git show diff 评估每文件每段落是 F1/F2 哪部分 · 部分保留 + 部分删除(combo hotfix 处置)。

§9.3 ADR-23→25→25-R1 三连 supersede 链教训

阶段 错误 修订
ADR-23(6/13) 范围错(误改 xilink 应改 xitune) ADR-25(6/15 12:12 supersede · 范围迁移)
ADR-25 v0.1(6/15 12:12) 设计错(SubgraphsDock 第 6 项 + 嵌套 mini-bar + 面包屑) ADR-25-R1(6/15 16:14 supersede §3.2+§3.3 · 改 FlowReadonlyDock 完善 + doc tabs 多 tab)
ADR-25-R1(6/15 16:14) TBD(等用户 accept 后实施核查) TBD

沉淀:同一业务问题在 4 小时内连续 2 次 supersede(ADR-23→25→25-R1)· 反映 Cline-AIOS Plan 模式起 ADR 时对用户 verbatim 原话的解析深度不足 · 倾向"自创新方案" 而非"对齐现有组件" · 写入 .clinerules Plan 模式硬约束: - 用户 verbatim 原话每个名词(dock/tab/mini-node/popup 等)必须在 grep 后找到具体文件 + 行号 · 写入 ADR §1 触发证据 - 起草 ADR §3 业务契约前 · 必须列出"用户原话提及的现有组件清单"(N 个文件 + N 个 API)+ "本 ADR 是完善还是新建"(完善优先 · 新建必须明确背离理由)


下一步:proposed 2026-06-15 16:14 → 等用户 accept ADR-AIOS-25-R1 → Cline-AIOS 同步 DASHBOARD v5.1.8→v5.1.9(F2 supersede + F3 废弃 + 3 R1 hotfix ready 入 §📋)→ 用户 start P3.UA25R1.F1-mini-bar-click-no-response-on-subgraph 派发(ClaudeA 0.2d combo hotfix)