跳转至
ACCEPTED

ADR-AIOS-22 · XiTest Realtime UX 大重构 + I/O 架构重定 + 5 Widget 算法接入

拍板时间:2026-06-13 13:00 proposed · 2026-06-13 15:46 accepted · status:accepted v0.1 · 拍板人:用户 范围:supersede ADR-AIOS-17(主版 fulfilled 部分保留作历史)+ supersede ADR-AIOS-17-R1(包括 v0.2 R2 5 fork on-hold)· I/O 架构 / 5 widget 算法接入 / 8 块 UX 新需求 全部并入本 ADR


1. Context · 背景

xitest realtime stage(实时模式)在 ADR-12(架构)+ ADR-13(双模式数据链路)+ ADR-15(workspace 持久化)+ ADR-17(I/O v2)+ ADR-17-R1(5 widget 占位 → R2 算法接入)的多次叠加下,已交付如下能力:

  • ✅ Workspace + Widget Dashboard + Top Toolbar + Left/Right/Bottom Dock 主框架
  • ✅ 模式 A 真硬件 / 模式 B loopback 双数据链路
  • ✅ Workspace 持久化(profile/preset)8 fork 收尾中
  • ✅ 5 widget 占位(phase / transfer / waveform / spectrogram / electrical),其中 waveform 已 zombie · 其余 4 个 R2 5 fork on-hold

用户 2026-06-13 12:43 提出 8 块 UX 大重构需求(见原始任务):

  1. preset 拆分:曲线 preset 与窗口布局 preset 合并在同一处太乱 → 单独左 dock 管 layout preset(系统默认不可删 / 用户自建可删 + 增删改另存)
  2. 曲线右键菜单缺失:实时窗口中曲线缺少 12+ 项操作(信息显示弹窗 / 改名 / 注释 / 颜色 / offset / 权重 / 线宽 / 平均 / 重新抓取 / copyAscii / 另存 / 新建目录归档 / 打开文件位置 / 随机色 / 删除)
  3. workspace capture 存储:右 dock 已 capture 的曲线缺按测量模块分组 + 双击加载 · 后端 xitest/realtime/<measurement-module>/ 持久化
  4. 测量组件视觉:主窗口测量组件方块过大 + 命名英文 → 缩小到当前内方块尺寸 + 中文化 + 预留 i18n
  5. 三段式属性 dock:右侧第 1 dock 当前是 6 段通用容器(ADR-12 §A 决议),用户重新分类为 3 段:① 通用(线粗/刻度/范围/权重)② 图形显示(bar/line/peakHold/peakTrack)③ 算法本身(window/fftSize/...)
  6. 左 dock I/O 设备配置重做:支持多 device 多通道勾选(ASIO 几十通道选 5 输入 + 10 输出)+ 全局持久化 + xistudio loopback 双向联动(任一选 loopback 另一自动跳)
  7. 新增左 dock · Smaart 风格通道测量:基于 5 选中通道集合新建测量(单通道:fft/rms · 双通道:thd/transfer · 平均:多通道)+ 苹果风格列表 + 启停按钮 + 与主界面通道映射
  8. 新增左 dock · Generator + 输出矩阵 mixer:loopback / 直接输出 · 信号源足够全(类比 fireface UFx)+ 矩阵勾选输出通道(对接 xiCal 硬件声卡)
  9. 右侧曲线显示 dock 删除:realtime stage 不需要,但 xilink/xitune/xiforge 仍需 → 条件渲染(同一组件 v-if stage==='realtime')

2. Problem · 问题陈述

ADR-12/13/15/17/17-R1 已搭好底盘,但 UX 与运行时模型存在 8 块结构性缺口:preset 单一概念混合两种语义(layout vs curve)、曲线无右键交互、capture 存储无业务分组、属性 dock 6 段过于平铺、I/O 配置不支持多通道选择 + loopback 联动断裂、缺少 Smaart 风格通道测量编排层、缺少 Generator/Mixer 输出层、右侧曲线 dock 在 realtime 中冗余。

这些缺口必须以 1 份 ADR 整体重构,不能拆 fork 因为它们共享同一份 store/契约/持久化目录结构。


3. Constraints · 硬约束

契约与 frozen 清单

  • ❌ 不动 contracts/v1/ frozen 文件(ADR-08 §3 铁律 · MeterFrame_* / ChainBuilder schema 等)
  • ❌ 不动 contracts/v2/ 已 frozen 段(若 K2-protocol-v2 已起,需协调 P_contracts 侧)
  • ✅ 可新增 contracts/v1/realtime/ 子目录定义 layout-preset / curve-preset / device-config / channel-config / generator-config / capture-group 6 个新 schema(版本 v1.0 起步)
  • ✅ Workspace 持久化磁盘格式遵循 ADR-15 已 fulfilled 协议(profile + preset + 副作用切除)

Stage 边界

  • ✅ 改动仅限 xitest realtime stage(stages/xitest/ + stages/realtime/ + 相关 store/composable/router)
  • ❌ xilink / xitune / xiforge / case-study 4 stage 严格不动(条件渲染右侧曲线 dock 通过 stage prop 判断)
  • ✅ ADR-21 xilink 7 fork 同期推进 · 文件正交 · 不冲突

测试基线(必须保留)

  • 前端 356/3 · 后端 217+12+8=237/0 · DSP 502 passed/6 pre-existing · sidecar 78/0
  • 新增 e2e case 必须为正向叠加,不允许降低任何模块覆盖

Ximind 大模型兼容性 5 项铁律(.clinerules v1.3 §ADR 设计基本要求 要求 1)

  • 状态可读:layout preset / curve preset / device config / channel selection / generator state / mixer matrix / capture group 全部 JSON 结构化 + 自描述字段 + 暴露 GET API
  • 操作可写:save/load preset / select channel / start/stop measurement / load capture into widget 全部语义化 POST 端点 + 自然语言 description 字段
  • 意图可解释:每个测量组件三段式属性带 description: string · curve 右键 12 项操作每项含 human_readable_action · loopback 联动跳变带 reason_code
  • 路径可追溯:WS /ws/realtime/state 推送所有运行时变化 + 持久化审计日志 data/xitest/realtime/audit.jsonl
  • 错误可恢复:所有用户级操作返回 {ok, code, message, recovery_hints[]}(eg. "device not found · 建议重连或选其他 device")

Ximind 兼容性详细落地见 §11


4. Options · 方向

方向 A:1 份大 ADR 整体重构(✅ 用户拍板 2026-06-13 13:00)

  • 优点:8 块需求共享 store/契约/dock 框架,合并落盘契约 + frontend 重构 + backend API 一次过 · 用户决策成本最低
  • 缺点:fork 数量较多(预计 12-14 fork),关键路径较长(~25-30 工作日)
  • 适合时机:用户对路线已有共识 + ADR-15 收尾在即 + ADR-21 同期推进可错峰

方向 B:拆 3 份并行(已 reject)

  • ADR-22(preset/属性/曲线菜单)+ ADR-23(I/O + Smaart 通道 + Generator)+ ADR-24(workspace capture 分组)
  • 缺点:3 份 ADR 共享 RealtimeStore + persistence schema,跨 ADR 协调成本高
  • 用户原话:"都放在 ADR22 中实现"

方向 C:拆 ADR-22 + ADR-17 R2 修订(已 reject)

  • 用户原话:"ADR17 废弃 · 都以刚刚的提示词为准放在 ADR22 中进行"
  • ADR-17 已 fulfilled 主版 + R1 v0.2 R2 全部以 supersede 方式归历史(本 ADR §10 References)

5. Decision · 决议

采纳方向 A:1 份 ADR-AIOS-22 整体重构 · supersede ADR-17 + ADR-17-R1 · 8 块需求 + I/O 架构重定 + 5 widget 算法接入(继承 ADR-17-R1 R2 设计)合并为 14 fork U-thread 实施。

关键决议点:

# 决议 来源
D1 preset 拆 2 类:LayoutPreset(窗口/widget 摆位)+ CurvePreset(曲线集合)· 两 dock 独立 · 系统默认不可删 + 用户自建可删 + 增删改另存 用户需求 1
D2 曲线右键菜单 12 项:信息弹窗 / 改名 / 注释 / 颜色 / offset / 权重 / 线宽 / 平均 / 重新抓取 / copyAscii / 另存 / 新建归档目录 / 打开文件位置 / 随机色 / 删除 用户需求 1
D3 workspace capture 按测量模块分组:data/xitest/realtime/<measurement-module>/<capture-id>.json · 双击加载到对应 widget 用户需求 2
D4 测量组件缩小到内方块尺寸:命名中文 + 预留 i18n key 用户需求 3
D5 属性 dock 三段式:① 通用(common)② 图形显示(display)③ 算法(algorithm)· 替代 ADR-12 §A 6 段平铺 用户需求 4
D6 I/O 设备配置 dock 重做:多 device 多通道勾选 + 全局持久化 + loopback 双向联动 用户需求 5
D7 新增 Smaart 风格通道测量 dock:基于选中通道集合新建测量(单/双/平均)· 苹果风格 · 启停按钮 · 主界面映射 用户需求 6
D8 新增 Generator + 输出矩阵 dock:信号源全集 + 矩阵勾选输出通道 + xiCal 兼容 用户需求 7
D9 右侧曲线 dock 条件渲染:v-if="stage==='realtime'" 隐藏(realtime 不需要)· 其他 stage 保留 用户需求 8
D10 5 widget 算法接入(继承 ADR-17-R1 R2):phase / transfer / spectrogram / electrical / waveform(已 zombie 保留) ADR-17-R1 R2 supersede
D11 I/O 架构 supersede ADR-17 主版:重新规定数据链路 + sidecar /analyze/* 路由 + WasapiCapture 接口(保留 ADR-17 已落地代码 · 仅在 ADR-22 内重新声明所有权) 用户需求 拍板 b

6. Consequences · 影响面

正面

  • ✅ realtime stage UX 一次性对齐用户预期 · 后续不再有"preset 概念混乱"等结构性问题
  • ✅ Ximind 大模型可全量解析 realtime 状态 + 调用所有用户级操作(为 P_ximind 未来落地铺路)
  • ✅ I/O 架构归属清晰(ADR-22 接管 · ADR-17 历史保留)
  • ✅ 5 widget 算法接入与 8 块 UX 同步 · 避免双轨

负面 / 风险

  • ⚠️ fork 数量大(14 fork · 25-30 工作日 + e2e)· 需分 4 Phase 串行 + 每 Phase 内并行
  • ⚠️ 跨栈影响:contracts/v1/realtime/ 新增 6 schema(P_contracts 侧需评审)+ backend Routes/Realtime + frontend stages/xitest/+ DSP 4 widget 算法
  • ⚠️ 测试基线压力:e2e 必须新增 ~25-30 case 真值断言 · ClaudeC 工作量上升
  • ⚠️ ADR-17-R1 R2 5 fork 工作量回收:R2 设计稿(phase/transfer/spectrogram/electrical/e2e)迁移到 ADR-22 §7 Phase 2 + 3 · 不重做但需重新归类

跨进程影响

  • P_arch:本 ADR 子进程目录 + 与 ADR-12/13/15/17/17-R1/21 关系标注
  • P_contracts:新增 v1/realtime/ 6 schema · 1.0d 评审
  • P0-frontend(stages/xitest):主战场 · 8 fork
  • P_dsp:4 widget 算法(phase/transfer/spectrogram/electrical)· 4 fork
  • P5-backend:Routes/Realtime + IO + Generator + Mixer · 3 fork
  • P7-sidecar:/analyze/* 端点扩展(若需)
  • ADR-21:xilink 侧 7 fork 文件正交 · 不冲突 · 可同期跑

7. Implementation · 实施(14 fork · 4 Phase)

Phase 1 · 契约 + 持久化基础(并行 2 fork · 1.5d 关键路径)

F1 · 契约扩展(P_contracts)

uid: P_contracts.A22.F1-realtime-contracts-extension
isolation: file
isolation_files:
  - contracts/v1/realtime/layout-preset.schema.json
  - contracts/v1/realtime/curve-preset.schema.json
  - contracts/v1/realtime/device-config.schema.json
  - contracts/v1/realtime/channel-selection.schema.json
  - contracts/v1/realtime/generator-config.schema.json
  - contracts/v1/realtime/capture-group.schema.json
worker: ClaudeB
estimated: 1.5d
unblocks: [F2, F3, F4, F5, F6, F7]
ximind_compat: ✅ 每个 schema 必含 description + human_readable_label 字段
- 新建 6 schema · 每个含 v1.0 frontmatter · 字段含 description/title/examples - 测试:backend_csharp/tests/Contracts/RealtimeContractsTests.cs 6 case(schema 加载 + validation + Ximind 必填字段检查)

F2 · 持久化目录与 IO 服务(P5-backend)

uid: P5.A22.F2-realtime-persistence-and-io-service
isolation: file
isolation_files:
  - backend_csharp/Services/Realtime/RealtimePresetService.cs
  - backend_csharp/Services/Realtime/RealtimeDeviceService.cs
  - backend_csharp/Services/Realtime/RealtimeCaptureGroupService.cs
  - backend_csharp/Routes/Realtime/RealtimePresetRoutes.cs
  - backend_csharp/Routes/Realtime/RealtimeDeviceRoutes.cs
  - backend_csharp/Routes/Realtime/RealtimeCaptureGroupRoutes.cs
  - data/xitest/realtime/_presets/layout/system/  (系统默认 layout preset 种子)
  - data/xitest/realtime/_presets/curve/system/   (系统默认 curve preset 种子)
worker: ClaudeB
estimated: 2.0d
blocked_by: [F1]
unblocks: [F8, F9, F10, F11]
ximind_compat: ✅ 所有 POST 端点含 description · 所有 GET 端点 JSON 自描述
- 端点清单: - GET/POST/PUT/DELETE /api/realtime/preset/layout(系统默认禁删 · 用户自建可删) - GET/POST/PUT/DELETE /api/realtime/preset/curve - GET/POST/PUT /api/realtime/device/config(多 device 多通道勾选 + loopback 联动逻辑) - GET/POST/PUT /api/realtime/channel/selection - GET /api/realtime/capture-group?module=<name> + POST /api/realtime/capture-group/save + GET /api/realtime/capture-group/load/<id> - loopback 联动逻辑:PUT /api/realtime/device/config 内部检测 input.kind === 'xistudio-loopback' → 自动 force output.kind = 'xistudio-loopback' · 反之同 · 返回带 reason_code: "loopback-bidirectional-coupling" - 测试:backend_csharp/tests/Realtime/RealtimePresetServiceTests.cs + RealtimeDeviceServiceTests.cs ≥ 12 case

Phase 2 · 5 Widget 算法接入(并行 4 fork · 8.0d 关键路径 · 继承 ADR-17-R1 R2)

F3 · phase widget 算法(P_dsp)

uid: P_dsp.A22.F3-phase-widget-algorithm
isolation: task
worktree: AlgoDepartment/04_development_branch_adr22-phase/
branch: feature/adr22-phase
isolation_files:
  - dsp_algo/modules/phase_widget/  (FFT + atan2 + numpy.unwrap + groupDelay)
worker: ClaudeB(沿用 ADR-17-R1 R2 F1 设计稿)
estimated: 1.5d
blocked_by: [F1]
ximind_compat: ✅ MeterFrame_Phase 字段含 description
- 输出 MeterFrame_Phase · ≥ 6 单测 case

F4 · transfer widget 算法(P_dsp)

uid: P_dsp.A22.F4-transfer-widget-algorithm
isolation: task
worktree: AlgoDepartment/04_development_branch_adr22-transfer/
branch: feature/adr22-transfer
isolation_files:
  - dsp_algo/modules/transfer_widget/  (GCC-PHAT + coherence + mag/phase)
worker: ClaudeB(沿用 ADR-17-R1 R2 F2 + ADR-21 F5 复用)
estimated: 2.5d
blocked_by: [F1]
ximind_compat: 
- 与 ADR-21 F5(xilink transfer-module)算法仓共用 · 不重做 · 但 widget 包装层独立

F5 · spectrogram widget 算法(P_dsp)

uid: P_dsp.A22.F5-spectrogram-widget-algorithm
isolation: task
worktree: AlgoDepartment/04_development_branch_adr22-spectrogram/
branch: feature/adr22-spectrogram
isolation_files:
  - dsp_algo/modules/spectrogram_widget/  (STFT + colormap + scrolling)
worker: ClaudeB(沿用 ADR-17-R1 R2 F4 设计稿)
estimated: 2.0d
blocked_by: [F1]
ximind_compat: 

F6 · electrical widget 算法(P_dsp)

uid: P_dsp.A22.F6-electrical-widget-algorithm
isolation: task
worktree: AlgoDepartment/04_development_branch_adr22-electrical/
branch: feature/adr22-electrical
isolation_files:
  - dsp_algo/modules/electrical_widget/  (LUFS + THD + crest factor)
worker: ClaudeB(沿用 ADR-17-R1 R2 F5 设计稿)
estimated: 2.0d
blocked_by: [F1]
ximind_compat: 

Phase 3 · 8 块 UX 重构 frontend(串行 + 并行混合 · ~12.5d 关键路径)

F7 · LayoutPresetDock + CurvePresetDock 拆分(前端)

uid: P0.A22.F7-preset-docks-split
isolation: file
isolation_files:
  - frontend_vue3/src/stages/xitest/leftDock/LeftDock.vue
  - frontend_vue3/src/stages/xitest/leftDock/LayoutPresetDock.vue
  - frontend_vue3/src/stages/xitest/leftDock/CurvePresetDock.vue
  - frontend_vue3/src/stores/realtime/useLayoutPresetStore.ts
  - frontend_vue3/src/stores/realtime/useCurvePresetStore.ts
worker: ClaudeA
estimated: 1.5d
blocked_by: [F2]
ximind_compat: ✅ store state 字段命名语义化
- 系统默认 preset 不可删(禁用按钮)+ 用户自建可删 + 增删改另存 - 5 e2e case:加载默认 / 创建用户 / 改名 / 另存 / 删除自建

F8 · 曲线右键菜单 12 项操作(前端)

uid: P0.A22.F8-curve-context-menu
isolation: file
isolation_files:
  - frontend_vue3/src/stages/xitest/dashboard/CurveContextMenu.vue
  - frontend_vue3/src/stages/xitest/dashboard/CurveInfoDialog.vue
worker: ClaudeA
estimated: 2.0d
blocked_by: [F2]
ximind_compat: ✅ 12 项每项 human_readable_action
- 12 项:信息弹窗 / 改名 / 注释 / 颜色 / offset / 权重 / 线宽 / 平均 / 重新抓取 / copyAscii / 另存 / 新建归档目录 / 打开文件位置 / 随机色 / 删除 - 6 e2e case 覆盖关键操作

F9 · workspace capture 按测量模块分组 dock(前端)

uid: P0.A22.F9-workspace-capture-grouped
isolation: file
isolation_files:
  - frontend_vue3/src/stages/xitest/leftDock/LeftDock.vue
  - frontend_vue3/src/stages/xitest/leftDock/WorkspaceCaptureDock.vue
  - frontend_vue3/src/stores/realtime/useCaptureGroupStore.ts
worker: ClaudeA
estimated: 1.5d
blocked_by: [F2]
ximind_compat: 
- 树形:测量模块 → capture 列表 · 双击加载到对应 widget · 4 e2e case

F10 · 测量组件缩小 + 中文化(前端)

uid: P0.A22.F10-widget-shrink-i18n
isolation: file
isolation_files:
  - frontend_vue3/src/stages/xitest/dashboard/DashboardCanvas.vue
  - frontend_vue3/src/stages/xitest/dashboard/widgets/fft/FftWidget.vue
  - frontend_vue3/src/stages/xitest/dashboard/widgets/rms/RmsWidget.vue
  - frontend_vue3/src/stages/xitest/dashboard/widgets/transfer/TransferWidget.vue
  - frontend_vue3/src/stages/xitest/dashboard/widgets/spectrogram/SpectrogramWidget.vue
  - frontend_vue3/src/stages/xitest/dashboard/widgets/electrical/ElectricalWidget.vue
  - frontend_vue3/src/stages/xitest/dashboard/widgets/waveform/WaveformWidget.vue
  - frontend_vue3/src/stages/xitest/dashboard/widgets/widgetLabels.ts
worker: ClaudeA
estimated: 1.0d
blocked_by: []
ximind_compat: ✅ widgetLabels.ts 各 key 含 description
- ⚠ 方��高度由 DashboardCanvas.vue 的 grid-auto-rows 控制(不改 widget 内部尺寸) - ⚠ 项目未安装 vue-i18n,改用纯 TS 常量文件 widgetLabels.ts - 7 widget 中文化 + 方块尺寸缩小到 160px 高

F11 · 三段式属性 dock(前端)

uid: P0.A22.F11-property-dock-three-segments
isolation: file
isolation_files:
  - frontend_vue3/src/stages/xitest/inspector/RightInspector.vue (改造现有 6 段→3 段)
  - frontend_vue3/src/stages/xitest/inspector/inspectorRouter.ts
  - frontend_vue3/src/stages/xitest/inspector/sections/CommonSegment.vue
  - frontend_vue3/src/stages/xitest/inspector/sections/DisplaySegment.vue
  - frontend_vue3/src/stages/xitest/inspector/sections/AlgorithmSegment.vue
  - frontend_vue3/src/config/widget-properties/fft.ts
  - frontend_vue3/src/config/widget-properties/rms.ts
  - frontend_vue3/src/config/widget-properties/transfer.ts
  - frontend_vue3/src/config/widget-properties/spectrogram.ts
  - frontend_vue3/src/config/widget-properties/electrical.ts
  - frontend_vue3/src/config/widget-properties/waveform.ts
worker: ClaudeA
estimated: 2.5d
blocked_by: [F2]
ximind_compat: ✅ 每个属性字段含 description + human_readable_label
- ⚠ 右侧面板入口是 inspector/RightInspector.vue(非新建 rightDock/) - 替代 ADR-12 §A 6 段平铺 · 6 widget(fft/rms/thd/transfer/spectrogram/electrical)逐一映射

F12 · I/O 设备配置 dock 重做 + Smaart 风格通道测量 dock(前端)

uid: P0.A22.F12-io-and-smaart-channel-docks
isolation: file
isolation_files:
  - frontend_vue3/src/stages/xitest/leftDock/LeftDock.vue
  - frontend_vue3/src/stages/xitest/leftDock/IODeviceConfigDock.vue (重写)
  - frontend_vue3/src/stages/xitest/leftDock/SmaartChannelDock.vue (新增)
  - frontend_vue3/src/stores/realtime/useDeviceConfigStore.ts
  - frontend_vue3/src/stores/realtime/useSmaartChannelStore.ts
worker: ClaudeA
estimated: 2.5d
blocked_by: [F2]
ximind_compat: ✅ loopback 联动跳变带 reason_code 提示
- ⚠ useDeviceConfigStore 仅管多通道选择状态,不重复存储 realtimeRunStore 已有 deviceId - I/O dock:多 device 多通道勾选 + loopback 双向联动(用户选 input loopback → 弹 toast "已自动切换 output 为 loopback · reason: bidirectional-coupling") - Smaart dock:新建测量(单通道 fft/rms · 双通道 thd/transfer · 平均多通道)+ 苹果风格列表 + 启停按钮 - 8 e2e case

F13 · Generator + 输出矩阵 mixer dock(前端 + 后端)

uid: P0.A22.F13-generator-and-mixer-dock
isolation: file
isolation_files:
  - frontend_vue3/src/stages/xitest/leftDock/LeftDock.vue
  - frontend_vue3/src/stages/xitest/leftDock/GeneratorMixerDock.vue
  - frontend_vue3/src/stores/realtime/useGeneratorStore.ts
  - backend_csharp/Services/Realtime/RealtimeGeneratorService.cs
  - backend_csharp/Routes/Realtime/RealtimeGeneratorRoutes.cs
worker: ClaudeA + ClaudeB(协作)
estimated: 2.0d
blocked_by: [F2]
ximind_compat: 
- 信号源全集:sine / sweep / pinkNoise / whiteNoise / chirp / multitone / loopWav · 每种含 description - 矩阵勾选:M 信号源 × N 输出通道 · 苹果风格矩阵 - 5 e2e case · xiCal 兼容性预留 hook

F14 · 右侧曲线 dock 条件渲染(前端 · 跨 stage 影响最小)

uid: P0.A22.F14-right-curve-dock-conditional-render
isolation: file
isolation_files:
  - frontend_vue3/src/components/dock/CurveDisplayDock.vue (新建,通过 shellSlots.activityRight 注册)
  - frontend_vue3/src/stages/xitest/index.vue (realtime 不注册即不显示)
  - frontend_vue3/src/stages/xilink/index.vue (注册到 activityRight · 不影响)
worker: ClaudeA
estimated: 1.0d
blocked_by: []
ximind_compat: 
- ⚠ CurveDisplayDock.vue 当前不存在,本 fork 新建 - 条件渲染通过各 stage 的 shellSlots.activityRight 注册/不注册实现(非 v-if prop) - 不破坏其他 stage

Phase 4 · 端到端验收(1 fork · 3.0d)

F15 · e2e 真值验收(测试编排)

uid: P_e2e.A22.F15-truth-e2e-realtime-overhaul
isolation: file
isolation_files:
  - frontend_vue3/e2e/realtime/preset-docks.spec.ts
  - frontend_vue3/e2e/realtime/curve-context-menu.spec.ts
  - frontend_vue3/e2e/realtime/capture-group.spec.ts
  - frontend_vue3/e2e/realtime/property-dock-three-segments.spec.ts
  - frontend_vue3/e2e/realtime/io-device-and-loopback.spec.ts
  - frontend_vue3/e2e/realtime/smaart-channel.spec.ts
  - frontend_vue3/e2e/realtime/generator-mixer.spec.ts
  - frontend_vue3/e2e/realtime/widgets-shrink-i18n.spec.ts
  - frontend_vue3/e2e/realtime/right-curve-dock-conditional.spec.ts
worker: ClaudeC
estimated: 3.0d
blocked_by: [F7, F8, F9, F10, F11, F12, F13, F14]
ximind_compat: ✅ 每个 case 真值断言含 reason
- ⚠ e2e 测试根目录为 e2e/(非 tests/e2e/),新建 e2e/realtime/ 与现有 e2e/realtime-stage/ 同级 - ≥ 30 case 真值断言 · 解锁 ADR-22 fulfilled 🏆

关键路径与并行度

Phase 1 (1.5d 关键)  F1(1.5d) → F2(2.0d 解锁绝大部分)
Phase 2 (8.0d 关键)  F3+F4+F5+F6 并行 🚀task 4 worktree(最长 F4 2.5d)
Phase 3 (12.5d 关键) F7/F8/F9/F11/F12/F13 并行(单 ClaudeA 串行 ~12.5d · F10/F14 0.5-1.0d 插空)
Phase 4 (3.0d)       F15 e2e

总计:~25d 关键路径(ClaudeA 主战场 · ClaudeB Phase 2 并行 + Phase 1 F2 + Phase 3 F13 协作 · ClaudeC F15)

8. Migration · 迁移与兼容

ADR-17 主版 supersede 处理

  • ADR-17 frontmatter:status: fulfilledstatus: superseded + superseded_by: ADR-AIOS-22 + superseded_at: 2026-06-13T13:00+08:00
  • ADR-17 主体内容永久保留作历史(已 fulfilled 真值不删)
  • I/O 数据链路代码不动 · 仅在 ADR-22 内重新声明所有权 · 后续 I/O 改动归 ADR-22

9. 审计记录 (2026-06-24)

9.1 Store 去重

ADR-22 实现过程中发现三处 Store 职责重叠,已修复:

重叠 修复措施 提交
captureStore vs useCaptureGroupStore 删除 System B (后端 CaptureGroup API + store),统一使用 ADR-13 captureStore (IndexedDB) 6bce336
xiTestDeviceStore.signal* vs useGeneratorStore xiTestDeviceStore 移除 signal 字段,DeviceConfigPanel 改用 useGeneratorStore 本次提交
xiTestDeviceStore vs useDeviceStore (realtime/) 添加角色注释明确边界:前者=运行时状态(Widget 读),后者=持久化配置(LeftDock 用) 本次提交
xiTestWorkspaceStore vs useLayoutPresetStore 添加角色注释:前者=当前活布局,后者=Preset CRUD 本次提交

9.2 Store 角色边界(最终状态)

┌─────────────────────────────────────────────────────────┐
│ 设备状态                                                  │
│  xiTestDeviceStore (运行时·Widget 读取)                    │
│  useDeviceStore    (持久化·LeftDock CRUD)                 │
│  同步点: index.vue onApply                               │
├─────────────────────────────────────────────────────────┤
│ 信号配置 → useGeneratorStore (唯一数据源)                  │
├─────────────────────────────────────────────────────────┤
│ Capture → captureStore → 后端 API                        │
│           POST /api/realtime/captures/{projectId}         │
│           存储: data/xitest/realtime/captures/            │
├─────────────────────────────────────────────────────────┤
│ TestProject → 后端 API                                   │
│           POST /api/realtime/projects                    │
│           存储: data/xitest/realtime/projects/            │
├─────────────────────────────────────────────────────────┤
│ Workspace → 后端 API                                     │
│           PUT /api/realtime/workspace/{name}              │
│           存储: data/xitest/realtime/workspaces/          │
├─────────────────────────────────────────────────────────┤
│ Snapshot → 后端 API                                      │
│           PUT /api/realtime/snapshot/{id}                 │
│           存储: data/xitest/realtime/snapshots/           │
├─────────────────────────────────────────────────────────┤
│ 布局                                                      │
│  xiTestWorkspaceStore  (当前活布局·网格+节点)              │
│  useLayoutPresetStore  (Preset CRUD·系统/用户)            │
└─────────────────────────────────────────────────────────┘

9.3 规则

  • 同一领域实体不得有两个 Store 持有权威状态
  • 新增 Store 前先检查是否已有 Store 覆盖该领域
  • 跨 Store 同步通过明确的同步点(如 onApply),不互相写入
  • 所有存储/落盘在后端实现,前端通过 REST API 操作(2026-06-24 架构决策)

9.4 Phase 1 存储后端化 (2026-06-24)

远端架构决策:所有涉及存储或落盘的功能统一在后端实现,前端仅通过 REST API 操作。

迁移项 原存储 新后端 API 提交
Capture + TestProject IndexedDB captureStore RealtimeCaptureService + /api/realtime/projects|captures 5cce2af
Snapshot localStorage/IndexedDB snapshotStore RealtimeWorkspaceService + /api/realtime/snapshots 5cce2af
Workspace 布局 localStorage xiTestWorkspaceStore RealtimeWorkspaceService + /api/realtime/workspace 5cce2af
设备配置 独立 localStorage key 嵌入 workspace JSON (deviceConfig 字段) 5cce2af

后端新增文件: - Services/Realtime/RealtimeCaptureService.cs — TestProject + CaptureRecord CRUD - Services/Realtime/RealtimeWorkspaceService.cs — Workspace + Snapshot 持久化 - Routes/Realtime/RealtimeCaptureRoutes.cs — 6 个 REST 端点 - Routes/Realtime/RealtimeWorkspaceRoutes.cs — 6 个 REST 端点

数据目录结构:

data/xitest/realtime/
├── projects/       ← TestProject JSON ({id}.json)
├── captures/       ← CaptureRecord JSON ({projectId}/{captureId}.json)
├── workspaces/     ← Workspace JSON ({name}.json)
├── snapshots/      ← Snapshot JSON ({id}.json)
├── _presets/       ← ADR-22 F2 预设 (已有)
└── ...

UI 偏好(theme/stage/panel 尺寸)保持 localStorage Pinia persist,不纳入后端存储。

9.6 信号配置统一 (2026-06-24)

解决 ADR-13 DeviceConfigPanel 与 ADR-22 GeneratorMixerDock 两套信号配置并存问题。

变更: - index.vue realtime-run 处理器: signalConfig 改用 buildSignalConfig() → 优先读取 useGeneratorStore.config.sources[0],无信号源时回退 realtimeRunStore.signalConfig - GeneratorMixerDock.vue handleSave(): 保存 Generator 配置时同步写入 realtimeRunStore.signalConfig - 引擎启动 ▶ 和 Generator 保存的配置同源

提交: 本次提交

9.5 Snapshot 创建功能 (2026-06-24)

快照创建入口从 Widget 工具栏补充,解决之前有 captureFromWidget 实现但无 UI 入口的问题:

图表 Widget ID 快照类型 数据内容
SpectrumChart (FFT) fft-chart fft freqs + magsDb + averagedCount
FreqResponseChart (Transfer) transfer-chart transfer freqs + magnitudeDb + phaseDeg + coherence + delayMs
PhaseChart phase-chart phase freqs + phaseDeg + mode

每个图表工具栏新增 📸 按钮,点击后调用 useSnapshots().captureFromWidget(),经 snapshotStore.saveSnapshot()PUT /api/realtime/snapshot/{id} 落盘。

SnapshotsPanel.vue 补充 onMounted → loadSnapshots() 初始化加载已有快照。

提交: b0777fe (loadSnapshots) + 本次提交 (快照按钮)

ADR-17-R1 supersede 处理

  • ADR-17-R1 frontmatter:status: accepted-on-holdstatus: superseded
  • 5 fork on-hold 状态:
  • F1 phase / F2 transfer / F4 spectrogram / F5 electrical / F6 e2e → abort + 标 "由 ADR-22 F3/F4/F5/F6/F15 接管"
  • prompt 文件不存在(R2 仅 ADR 内列表)· DASHBOARD §📋 移除这 5 行
  • F3 waveform 已 zombie · 不动

Workspace 持久化兼容

  • 旧 preset 数据(ADR-12/15 期 · 单一 preset 概念混合 layout+curve)→ 启动时迁移脚本拆分:
  • 提取 widgets[] 摆位 → LayoutPreset
  • 提取 curves[] 集合 → CurvePreset
  • 旧 preset 加 legacy: true tag · 7 天宽限期后由用户手动删除
  • 后端启动时检测 data/xitest/realtime/_presets/legacy/ 自动迁移 · 写审计日志

contracts/v1/realtime/ 6 schema 与已有契约关系

  • 不冲突 · 全部新增子目录
  • ADR-21 xilink 侧 transfer-module schema 与本 ADR transfer widget schema 共享 MeterFrame_Transfer · 由 ADR-21 F5 主导定义 · 本 ADR F4 复用

9. Validation · 验收

测试基线(必须保持或上升)

  • 前端 356/3 → 预计 ≥ 380/3(F15 新增 ~30 case)
  • 后端 217+12+8=237/0 → 预计 ≥ 260/0(F2 新增 ~20 case + F13 新增 ~5 case)
  • DSP 502/6 → 预计 ≥ 520/6(F3-F6 各 ≥ 6 case)
  • sidecar 78/0 不变(本 ADR 不动 sidecar)

端到端验收门禁(F15 9 spec 真值断言)

  1. preset-docks.spec.ts:加载系统默认 layout / curve preset · 创建用户 preset · 删除用户 · 拒绝删除系统(button disabled)
  2. curve-context-menu.spec.ts:12 项操作每项至少 1 case · 含信息弹窗显示完整字段 + 改名持久化
  3. capture-group.spec.ts:capture 按测量模块分组显示 + 双击加载到对应 widget
  4. property-dock-three-segments.spec.ts:6 widget × 3 段属性显示 · 修改持久化
  5. io-device-and-loopback.spec.ts:多 device 多通道勾选持久化 + loopback 双向联动 toast 显示
  6. smaart-channel.spec.ts:新建单/双/平均测量 + 启停按钮 + 与主界面通道映射
  7. generator-mixer.spec.ts:7 信号源 + 矩阵勾选 + xiCal hook 占位
  8. widgets-shrink-i18n.spec.ts:测量组件尺寸 ≤ X px + 中英文切换
  9. right-curve-dock-conditional.spec.ts:realtime stage 不渲染右侧曲线 dock + 其他 stage 渲染

Ximind 兼容性验收(每 fork 必含)

  • 每新增 schema 字段含 description
  • 每新增 POST 端点 request body 含 description / human_readable_action
  • 每新增 error 返回 {code, message, recovery_hints[]}
  • WS /ws/realtime/state 推送覆盖所有运行时变更

10. References · 关联

直接 supersede

  • ADR-AIOS-17(xistudio-realtime-io-arch-v2)· fulfilled → superseded(主体保留作历史)
  • ADR-AIOS-17-R1(realtime-widgets-algorithm-impl v0.2 R2)· accepted-on-hold → superseded(5 fork abort + 由 ADR-22 F3/F4/F5/F6/F15 接管)

强相关(不动 · 共存)

  • ADR-AIOS-12(xitest-realtime-arch v2.3 fulfilled 🏆)· 提供 Workspace + Widget Dashboard + Top Toolbar + Dock 主框架基础 · 本 ADR 在其 §A.6 Save/Load Workspace 之上拆分 layout vs curve preset
  • ADR-AIOS-13(xitest-realtime-dual-mode v1.0 fulfilled 🏆)· 提供模式 A 真硬件 / 模式 B loopback 双数据链路 · 本 ADR 在 F2 内重做 device 配置时尊重该决议
  • ADR-AIOS-15(workspace-persistence-overhaul · F8+F6 收尾中)· 提供 profile/preset 持久化协议 · 本 ADR 6 新 schema 遵守
  • ADR-AIOS-16(subgraph-unified-architecture fulfilled 🏆)· 算法接入边界
  • ADR-AIOS-18(plugin-protocol fulfilled 🏆)· 5 widget 算法接入走 plugin 协议
  • ADR-AIOS-21(xilink-dock-and-analysis-modules accepted v0.1)· F5 transfer-module 算法仓与本 ADR F4 共享

用户原始需求

  • 用户 2026-06-13 12:43 任务原文(8 块 UX + I/O + Smaart + Generator + 右侧 dock 条件渲染)· 详见 processes/P_arch/ADR-AIOS-22-xitest-realtime-ux-overhaul/PROCESS.md §0 用户原话存档

.clinerules 引用

  • .clinerules/aios-orchestration.md v1.4 §ADR 设计基本要求(Ximind 兼容性 5 项)
  • .clinerules/aios-orchestration.md v1.4 §UID 命名规范(本 ADR fork 用 A22 M 段)
  • .clinerules/aios-orchestration.md v1.4 §任务隔离类型(F3-F6 用 🚀 task · 其余 🧵 file)

11. Ximind Compatibility · 大模型兼容性(.clinerules v1.3 铁律)

铁律来源:.clinerules/aios-orchestration.md v1.3 §ADR 设计基本要求 要求 1 本 ADR 落地策略:14 fork 每个交付前必跑 Ximind 兼容性自查清单(见 §9 Validation)

11.1 Ximind 大模型可读状态(GET API + WS)

# 状态 端点 JSON 字段示例
1 layout preset 当前 + 列表 GET /api/realtime/preset/layout {id, name, description, type:"system|user", widgets:[{kind, position, size, description}]}
2 curve preset 当前 + 列表 GET /api/realtime/preset/curve {id, name, description, curves:[{id, name, color, source_widget, description}]}
3 I/O 设备配置 GET /api/realtime/device/config {input:{kind, devices:[{id, name, channels:[{id, label, selected}]}]}, output:{...}, loopback_coupled:bool}
4 通道测量列表(Smaart 风格) GET /api/realtime/channel/measurements [{id, name, type:"single|dual|average", channels:[...], description, running:bool}]
5 Generator 状态 GET /api/realtime/generator/state {sources:[{id, kind, params, description}], mixer_matrix:{rows, cols, gains[][]}}
6 capture group(分组列表) GET /api/realtime/capture-group?module=fft [{id, module, timestamp, curves[], description}]
7 运行时全状态 WS WS /ws/realtime/state 推送上述任意状态变更 + {action, reason_code, human_readable_message, timestamp}

11.2 Ximind 大模型可写操作(POST/PUT/DELETE)

# 操作 端点 request body 必含字段
1 保存 layout preset POST /api/realtime/preset/layout {name, description, widgets[], intent:"自然语言意图"}
2 删除 layout preset DELETE /api/realtime/preset/layout/:id (系统默认拒绝 + 返回 recovery_hints:["请另存为用户 preset 后再删除"])
3 修改曲线属性 PUT /api/realtime/curve/:id {name?, comment?, color?, offset?, weight?, lineWidth?, description}
4 曲线右键 12 项操作 POST /api/realtime/curve/:id/action {action:"info|rename|...|delete", params, human_readable_action}
5 I/O 设备配置 PUT /api/realtime/device/config {input:{...}, output:{...}, intent}(loopback 联动自动校正)
6 新建 Smaart 测量 POST /api/realtime/channel/measurement {name, type, channels[], description}
7 启停测量 POST /api/realtime/channel/measurement/:id/start|stop {intent}
8 加载 capture 到 widget POST /api/realtime/capture-group/:id/load-to-widget {widget_id, intent}
9 Generator 信号源 + 矩阵 PUT /api/realtime/generator/config {sources[], mixer_matrix, intent}

11.3 自然语言描述字段铁律

  • 每个 schema 字段 ≥ 1 个 description(中文优先 · 英文 fallback)
  • 每个 POST 端点 request body 含 intent 字段(用户/AI 操作意图描述)
  • 每个 measurement 的属性三段(common/display/algorithm)每个属性含 description + human_readable_label

11.4 审计日志路径

  • WS:/ws/realtime/state 实时推送
  • 持久化:data/xitest/realtime/audit.jsonl(每行 1 个 JSON event:{timestamp, action, target, params, reason_code, ai_caller?})
  • 大模型可回放历史:GET /api/realtime/audit?since=<ts>&action=<filter>

11.5 Error 结构

所有用户级操作失败必返回:

{
  "ok": false,
  "code": "DEVICE_NOT_FOUND" | "PRESET_LOCKED" | "LOOPBACK_BIDIRECTIONAL_FORCED" | ...,
  "message": "中文用户级消息",
  "recovery_hints": [
    "建议 1:重连 ASIO 驱动",
    "建议 2:选择其他 device",
    "建议 3:切换到 loopback 模式"
  ],
  "ai_actionable": true
}

11.6 fork 责任归属(哪些直接服务 Ximind)

  • F1 契约扩展:100% 服务 Ximind(6 schema 字段 description 是 Ximind 解析基础)
  • F2 后端 IO 服务:100% 服务 Ximind(端点 description + intent + recovery_hints)
  • F11 三段式属性 dock:70% 服务 Ximind(每属性 description + human_readable_label)
  • F12 I/O dock + Smaart dock:80% 服务 Ximind(loopback 联动 reason_code · Smaart 测量 intent)
  • F13 Generator + Mixer:60% 服务 Ximind(信号源 description + 矩阵 intent)
  • F7/F8/F9/F10/F14:40% 服务 Ximind(audit 日志 + WS 推送)
  • F3/F4/F5/F6 算法:30% 服务 Ximind(MeterFrame_* 字段 description)
  • F15 e2e:100% 服务 Ximind(每 case 真值断言含 reason · 大模型可基于 spec 自查)

拍板回执:本 ADR 起草于 2026-06-13 13:00 · 用户拍板方向 A(全并入 ADR-22)+ supersede ADR-17 + ADR-17-R1 + 条件渲染右侧 dock · 14 fork · ~25d 关键路径

status: proposed → 等用户 accept ADR-AIOS-22 后切换 accepted · F1+F10+F14 ready 优先派(F10/F14 不依赖 F1)· F2 等 F1 zombie 解锁 · F3-F6 与 F2 并行 🚀task