本 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 步)
- 用户在 xitune 主链路 chain-mini-bar 看到子图节点 📦 EQ_A(3个)
- 单击 📦 EQ_A → 主页面不变化(activeInstanceId 不切 / 主区不刷新)
- hover 📦 EQ_A → tooltip "子图 EQ_A · 含 3 module · 双击查看内部"
- 双击 📦 EQ_A → 触发 F3-R1 openSubgraphTab(defId)(子图 tab 主页打开 / 跳转)
- 普通 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 步)
- 用户在 xitune 切到 LEFT_DOCK 第 2 项
xt-flow 🔗 链路流图(只读)
- SVG 流图显示主链路:🎵 source → 📦 EQ_A(嵌套小矩形 × 3:peq + gain + delay)→ 📤 sink
- 单击 📦 EQ_A 主框 → 高亮(stroke 黄色 D4A574)+ eventBus emit
- 双击 📦 EQ_A 主框 → openSubgraphTab(
eq-a-def) → xitune 顶部 doc tabs 加 "EQ_A.subgraph" tab + 自动切到该 tab
- 进入子图 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 步)
- 用户在 xitune chain-mini-bar 主链路双击 📦 EQ_A → openSubgraphTab('eq-a-def')
- xitune 顶部 doc tabs 出现 [🎚 工程名.xitune] [📦 EQ_A.subgraph(可关闭)] · 自动切到 EQ_A tab
- EQ_A tab 主页 chain-mini-bar 显示:🎚 peq → 🔊 gain → ⏱ delay(单击调音 / 双击悬浮窗 · 与 Main tab 一致)
- 用户单击 🎚 peq → 主区右侧加载 GEQTuningDialog inline 调音(activeInstanceId 切到子图内 peq instanceId)
- 用户调完关闭 EQ_A tab(点 ×)→ 切回 [🎚 工程名.xitune] 主 tab · activeInstanceId 自动恢复主 tab 之前选择
- 主 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)