ADR-AIOS-12 · XiTest Realtime Widget Workspace 架构与业务行为契约决议
v2.0 · Cline-AIOS 深化版 · 2026-05-29
基于用户起稿(§附录 A · 912 行 · 22 节功能清单)+ Demo HTML(
04_development/frontend_vue3/docs/superpowers/specs/xitest-realtime-ui-demo.html· 1225 行单 widget 4 tab 示意)+ ADR-07 §1.3.4 三层分工铁律,深化为可派发决议。核心收获:本 ADR 是 Cline-AIOS 调度内核回应用户 2026-05-28 "业务深度系统性缺失" 诊断的第一份"业务行为契约必填段"标杆示范。后续所有 ADR 必须按本 ADR §3 模板填 5 项契约,不再写"壳子框架"。
1. 上下文(Context)
1.1 触发事件
2026-05-29 11:38 用户在 06_docs/site-build/ Cline-AIOS 长会话中,基于前序 P4.U3-perf-visual-stub-upgrade(commit ceecccf)zombie 后的"业务深度核查",给出新指令:
用户原话(2026-05-29 11:38): "new ADR Xitest · 针对 xitest 的 realtime 以及右 dock 的 rms 频响 相位 scope 显示我们需要先完成,你在 07 号 adr 中只是初步的一个壳子框架。接下来我们针对这个功能做具体功能的详细设计。对标产品:1. Audio Precision APx500 2. Smaart suite 3. Ocenaudio。我让智能体初步实现了一个 demo,只是参考功能,具体的设计我会列出大体方向 D:/work/25_claude/workspace/AlgoDepartment/04_development/frontend_vue3/docs/superpowers/specs/xitest-realtime-ui-demo.html。实时/realtime 功能详细定义以及页面布局参考 ADR-AIOS-XiTest-RealTime-Arch.md。"
2026-05-29 12:00 用户进一步纠偏 Cline-AIOS 第一轮跑偏方案:
用户原话(2026-05-29 12:00): "现在哪里有 tab,哪个 html 文件只是一个示意图,具体的布局已经在给你的 md 文件中有了啊,所有的测量都以类似控件的 widget 的方式拖入主界面,主界面的布局等规划也都给出来了 4.* 2 1 等显示格局配置,你是完全没读 md 么。realtime 的这些功能我都要,你可以先实施 realtime 的显示,后续的 sequence 实施但是不能不提这个需求。"
1.2 用户起稿(§附录 A · 912 行)真实需求图谱
| 段 | 真实规范 | Cline-AIOS v1 误读(已纠正) |
|---|---|---|
| §三 整体结构 | Top Toolbar + Left Dock + Realtime Dashboard(Widget-based) + Right Dock(Inspector)+ Bottom Dock | 误读为 4 tab 切换 |
| §六 Workspace Preset | 4 套预设(Tuning / Electrical / Recording / Multi-channel)+ 用户自定义 | 误读为"任选 1 套" |
| §九-§十六 Measurement 库 | 完整 7 大类(Time Domain / Frequency / Transfer / Electrical / Recording / Validation / Utility) | 误读为 4 tab 内嵌组件 |
| §十六 Task Flow | 5 类 Flow Node(Source / Measurement / Validation / Logic / Export)· 流程编排 | 误判为方向 B 砍掉 |
| §十七 Dashboard | Widget 拖拽 / Resize / Dock / Float / Split / Fullscreen / Save Layout / Multi-monitor · Main Widget + Mini Widget | 误读为 fixed 4 tab |
| §十八 Right Dock Inspector | 6 段通用结构(Source/Measurement/Display/Validation/Automation/Storage) + 每 widget 独立 Inspector | 误读为左 sidebar 6 段固定 |
| §十九 Snapshots | 保存曲线/参数/Overlay/结果/布局 · Save/Compare/Golden/Export | 仅识别为 A/B 快照(漏 Golden / 布局快照) |
| §二十一 Bottom Dock | Console / Device Status / XRUN / Measurement Log / Task Queue / Validation Result | 完全漏读 |
| §二十二 统一工程核心 | 5 引擎(Measurement / Validation / Task / Storage / Visualization) | 完全漏读 |
1.3 Demo HTML 真实定位(纠正)
xitest-realtime-ui-demo.html(1225 行)= 单个 Main Widget 全屏化呈现(等价于 Workspace = 1 widget × 4 个 tab 形态切换)· 不是整体布局蓝本。Cline-AIOS v1 把它当 MVP 蓝本,导致砍掉 Widget Workspace + 7 类 Measurement + Sequence。
Demo HTML 真实价值:展示了单个 widget 内部业务深度切片(FFT/平均/倍频/范围/曲线 6 段控件 + 频响双图 + Peak Hold 衰减 + A/B 快照 + 8 通道 RMS 网格)· 这些细节作为本 ADR §3 业务行为契约的实证素材写入(每契约段引用 Demo 哪部分 line range)。
1.4 真值核查发现(已知前置就位)
前端 P4-xitest 现状(P4.U3 zombie · ceecccf): - ✅ TestMode 5 联合(unit/integration/e2e/regression/realtime)+ stage chip - ✅ realtime mode = SpectrumChart + WaveformChart 2 stub(physical-input tap) - ✅ regression mode = RMSMeter + FreqResponseChart + PhaseChart 3 stub(sink-pre tap) - ✅ MeterNodeSelector + useMeterWs composable - ❌ Widget Workspace 框架完全缺失(无拖拽/Resize/Dock/Float/Split/Save Layout/Multi-monitor) - ❌ MeasurementNode 统一抽象完全缺失(每个 stub 是独立 vue · 无统一 input/processing/measurement/validation/visualization/automation/storage 7 子能力) - ❌ 4 套 Workspace Preset 完全缺失 - ❌ Right Dock Inspector 6 段通用结构完全缺失 - ❌ Sequence(Task Flow)schema + UI 入口完全缺失 - ❌ Bottom Dock 状态栏(Console / XRUN / Measurement Log / Task Queue / Validation Result)完全缺失
后端 P5-backend-csharp 现状(P5.U-meter-source-tap zombie · 4adda88): - ✅ MeterTapService 30fps WS + WASAPI 设备枚举 + sink-pre tap - ✅ PysidecarMeterBridge HTTP 桥接 P7 - ❌ 多 toolKind 路由完全缺失(当前只支持 RMS/FreqResp/Phase 3 类 · 不支持 Transfer/Spectrogram/Waveform/Electrical/Recorder) - ❌ WS 帧 schema 单一(无 toolKind 字段区分) - ❌ 限流策略缺失(当前所有客户端共享同一帧率)
P7-pysidecar 现状:
- ✅ 19 个 REST 端点已实装(/analyze/freq_response / /analyze/rms / /analyze/phase / /analyze/coherence / /analyze/octave_band / /analyze/waterfall / ...)
- ❌ 缺端点:/analyze/transfer_function(双通道传递函数 · Smaart 核心)//analyze/group_delay(群延迟)//analyze/peak_hold(P7 端 Peak Hold 状态机)//analyze/snapshot_diff(Golden 对比)//analyze/thd(THD/THD+N/SINAD)
契约 P_contracts: - ✅ protocol-v1 frozen(K1 sleeping-permanent) - ⚠️ ADR-07 §2.1.3 已记录 meter-source 扩展为 v2 候选 · 但 v2 未启动 - ⚠️ 本 ADR 触发 K2-protocol-v2 启动条件之一(与 ADR-08 / ADR-09 / ADR-10 共享 v2 命名空间)
2. 决议(Decision)
2.1 主决议 · Dockable+Workspace+Widget+Scene 混合架构(对齐 ADR-XiTune-AutoTune-layout §2)
核心理念(用户起稿 §三 + ADR-XiTune-AutoTune-layout §2 共享):
整体 UI 布局(用户起稿 §三 锁定):
┌─────────────────────────────────────────────────────────┐
│ Top Toolbar │
├──────────────┬───────────────────────────────┬──────────┤
│ Left Dock │ Realtime Dashboard │ Right │
│ Project Res │ Widget-based Workspace │ Inspector│
│ - Workspace │ ┌─────┬─────┐ │ Source │
│ - Session │ │ FFT │ RMS │ │ Measure │
│ - Engine │ ├─────┼─────┤ │ Display │
│ - Measurement│ │ Tx │ Wav │ │ Validate │
│ - Recordings │ └─────┴─────┘ │ Automate │
│ - Snapshots │ │ Storage │
│ - Validation │ │ │
│ - Task Flow │ │ │
├──────────────┴───────────────────────────────┴──────────┤
│ Bottom Dock │
│ Console | Device | XRUN | Measure Log | Task | Validate │
└─────────────────────────────────────────────────────────┘
2.2 子决议 · 5 引擎统一抽象(用户起稿 §二.2 + §二十二 锁定)
| Engine | 职责 | 本 ADR 实施范围 |
|---|---|---|
| Measurement Engine | 7 类 MeasurementNode 注册表 + 实时数据流 | ✅ 本期完整实施(7 类) |
| Validation Engine | Pass/Fail 判据 + Threshold/Mask/Tolerance/Golden | ⏳ 本期 schema + UI 入口 · 判据算法留下季度 |
| Task Engine | 5 类 Flow Node(Source/Measurement/Validation/Logic/Export)· 流程编排 | ⏳ 本期 schema + UI 入口 · 执行引擎留下季度 |
| Storage Engine | Snapshot / Recording / Workspace Layout 持久化 | ✅ 本期实施 Snapshot + Layout · Recording 留下季度 |
| Visualization Engine | Widget 容器 + 拖拽 + Resize + Save Layout + Multi-monitor | ✅ 本期完整实施 |
2.3 子决议 · MeasurementNode 统一抽象(本 ADR 核心契约)
用户起稿 §三.3 锁定的 7 子能力(每个 MeasurementNode 必含):
// types/measurement-node.ts(本 ADR v2.0 落盘 · ≤ 60 行)
export type MeasurementKind =
| 'time-domain' // §十(Waveform Scope / RMS Meter / Oscilloscope)
| 'frequency' // §十一(FFT Analyzer / RTA / Spectrogram)
| 'transfer' // §十二(Transfer Function · Smaart 核心)
| 'electrical' // §十三(Electrical Meter / Sweep Analyzer · APx500 核心)
| 'recording' // §十四(Recorder)
| 'validation' // §十五(Pass/Fail Compare)
| 'utility' // §九 Utility(Generator / Marker / Cursor 等)
export interface MeasurementNode {
id: string
kind: MeasurementKind
type: string // 具体子类型(如 'rms-meter' / 'fft-analyzer' / 'transfer-fn')
// §九 7 子能力(每个 node 必含 · 本 ADR 锁定)
input: NodeInput // §2.4 Input(节点选择 + 通道映射)
processing: ProcessingConfig // 预处理(window/filter/gating)
measurement: MeasurementConfig // 测量参数(fft-size/avg-type/threshold)
validation?: ValidationRule // 验证规则(threshold/mask/tolerance/golden)
visualization: VizConfig // 显示(scale/color/overlay/legend/dB-range)
automation?: AutomationHook // 自动化钩子(供 Task Flow 调用)
storage: StorageConfig // 持久化(snapshot/recording-buffer/golden-ref)
}
// 详细字段定义 · 见 §3 各 MeasurementNode 5 项业务行为契约
2.4 子决议 · NodeInput 节点选择(继承 ADR-07 §1.3.1 + 本 ADR 扩展)
ADR-07 已锁定 2 节点 · 本 ADR 不变更:
- sink-pre:PC 模式 · 进入物理 sink 前的算法链路最终输出 · 后端 P5 sink-pre tap
- physical-input:振声声卡 / mic · 后端 P5 WASAPI 采集
本 ADR 新增 NodeInput.channelMap(用户起稿 §八.1 Channel Map · 8 通道):
export interface NodeInput {
node: 'sink-pre' | 'physical-input' | 'recording-replay' // 第 3 类:回放录音(对接 §十四 Recorder)
channels: number[] // 选通道(如 [0,1] L+R · [0,1,2,3,4,5,6,7] 8 声道)
channelLabels?: string[] // 用户标签(L/R/Ls/Rs/C/LFE/Lss/Rss)
refChannel?: number // Transfer Function 用(参考通道)
measureChannel?: number // Transfer Function 用(测量通道)
}
2.5 子决议 · Widget 容器与 Workspace(用户起稿 §十七 锁定)
// types/dashboard-widget.ts(本 ADR v2.0 落盘 · ≤ 50 行)
export type WidgetState = 'docked' | 'floating' | 'fullscreen' | 'split-h' | 'split-v'
export type GridLayout = '2x2' | '4-row' | '2x1' | '1-full' | '4x1' | 'free'
export interface DashboardWidget {
id: string
measurementNodeId: string // 关联 MeasurementNode
layout: { x: number; y: number; w: number; h: number; zIndex: number }
state: WidgetState
monitor?: number // 多屏 0/1/2(Multi-monitor 用)
title?: string // 用户自定义标题(覆盖 MeasurementNode.type 默认)
collapsed?: boolean // 折叠为 Mini Widget
}
export interface Workspace {
id: string
name: string // 4 套预设 + 用户自定义
preset: 'tuning' | 'electrical' | 'recording' | 'multi-channel' | 'custom'
widgets: DashboardWidget[]
gridLayout: GridLayout
measurementNodes: MeasurementNode[] // 本 workspace 拥有的 node
createdAt: number
modifiedAt: number
}
§十七 8 大功能本 ADR 实施范围:
| 功能 | 本 ADR 实施 | 留下季度 |
|---|---|---|
| Drag(拖拽) | ✅ Phase 1 · vue-grid-layout 或自研 | — |
| Resize(缩放) | ✅ Phase 1 | — |
| Dock(停靠) | ✅ Phase 1 | — |
| Float(浮动) | ✅ Phase 1 · element-plus dialog 浮窗 | — |
| Split(分屏) | ✅ Phase 1 · Split-h / Split-v | — |
| Fullscreen(全屏) | ✅ Phase 1 · 单 widget 占满 Dashboard | — |
| Save Layout(保存布局) | ✅ Phase 3 · Workspace.widgets[] 持久化到 Storage Engine | — |
| Multi-monitor(多屏) | ⏳ schema 留 monitor 字段 · UI 实施留下季度 | 🔜 |
2.6 子决议 · 4 套 Workspace Preset(用户起稿 §六 锁定)
| Preset | 用途 | 默认 Widget 组合 | gridLayout |
|---|---|---|---|
| Tuning | 调音(对标 Smaart) | Transfer / FFT / Phase / RMS | 2x2 |
| Electrical | AP 类电信号(对标 APx500) | THD / SINAD / Scope / Generator | 2x2 |
| Recording | 录音分析(对标 Ocenaudio) | Waveform / Spectrogram / Markers | 2x1 |
| Multi-channel | 车载多通道 | RMS Matrix / Delay Matrix / Phase Matrix | 4-row |
2.7 子决议 · Right Dock Inspector 6 段通用结构(用户起稿 §十八 锁定)
当前选中 Widget → Inspector 显示 6 段(每段对应 MeasurementNode 的 1 个子能力):
┌─ Right Dock(Inspector · 当前 Widget=FFT) ─┐
│ § Source │
│ - Node: [physical-input ▼] │
│ - Channels: [☑L ☑R ☐Ls ...] │
├─────────────────────────────────────────────┤
│ § Measurement │
│ - FFT Size: [4096 ▼] │
│ - Window: [Hanning ▼] │
│ - Average: [指数 8 次] │
├─────────────────────────────────────────────┤
│ § Display │
│ - Scale: [对数 ▼] │
│ - dB Range: [80 dB] │
│ - Overlay: [☑ Peak Hold ☐ Golden] │
├─────────────────────────────────────────────┤
│ § Validation │
│ - [+ 添加 Pass/Fail 规则] │
├─────────────────────────────────────────────┤
│ § Automation │
│ - [☐ 加入 Task Flow] │
├─────────────────────────────────────────────┤
│ § Storage │
│ - [💾 Save Snapshot] [📁 Load Golden] │
│ - [⏺ Start Recording] │
└─────────────────────────────────────────────┘
Inspector 复用机制:6 段是通用容器 · 每段内具体控件由 MeasurementNode.kind/type 决定(参考用户起稿 §十八 FFT Inspector / Transfer Inspector / Recorder Inspector 表格)。Phase 1 实施容器 + FFT/RMS/Transfer/Phase/Waveform 5 个 Inspector · 其他 Inspector(Spectrogram/THD/Sweep/Recorder)留 Phase 2-3。
2.8 子决议 · Bottom Dock 状态栏(用户起稿 §二十一 锁定)
┌─ Bottom Dock(高度 ~22-32px) ────────────────────────────────────┐
│ Console▾ │ Device Status │ XRUN: 0 │ Measure Log▾ │ Tasks: 0 │ ✓ │
└────────────────────────────────────────────────────────────────┘
| 段 | 内容 | 实施范围 |
|---|---|---|
| Console | INFO/WARNING/ERROR/DEVICE/SCRIPT 5 级日志 · 可折叠 | ✅ Phase 1 |
| Device Status | Clock Lock / Sample Rate / Buffer / XRUN / CPU | ✅ Phase 1(WS 推送) |
| XRUN 计数器 | 红色 badge · 累计 XRUN 次数 | ✅ Phase 1 |
| Measurement Log | 最近 N 次测量结果(可点击跳回 widget) | ✅ Phase 2 |
| Task Queue | 当前运行/排队的 Task Flow / Recording / Export | ⏳ Phase 4 占位 |
| Validation Result | 最新一次 Pass/Fail 结果 + 链接 | ⏳ Phase 4 占位 |
2.9 子决议 · Sequence(Task Flow)占位(用户起稿 §十六 + 用户原话"后续实施但不能不提")
本 ADR 锁定 schema + UI 入口 · 不实施执行引擎:
// types/task-flow.ts(本 ADR v2.0 落盘 · ≤ 50 行)
export type FlowNodeKind = 'source' | 'measurement' | 'validation' | 'logic' | 'export'
export interface FlowNode {
id: string
kind: FlowNodeKind
type: string // 具体类型(如 source 下:'playback-sweep' / 'playback-pink-noise')
config: Record<string, unknown>
inputs: string[] // 上游 FlowNode id
outputs: string[] // 下游 FlowNode id
// 占位字段 · Phase 4 不实施执行
status?: 'pending' | 'running' | 'pass' | 'fail' | 'skip'
result?: unknown
startedAt?: number
completedAt?: number
}
export interface TaskFlow {
id: string
name: string
nodes: FlowNode[]
trigger: 'manual' | 'scheduled' | 'on-event'
// 执行引擎相关字段 · 留下季度
}
5 类 Flow Node 抽象(用户起稿 §十六):
| Kind | 子类型示例 | 用途 |
|---|---|---|
| Source | playback-sweep / playback-pink / playback-mls / record-input | 信号产生/输入 |
| Measurement | fft-snapshot / rms-1s / transfer-fn / thd-meter | 触发测量 + 抓数据 |
| Validation | threshold-compare / golden-compare / mask-test | Pass/Fail 判据 |
| Logic | if-condition / wait-ms / loop-n | 流程控制 |
| Export | report-pdf / csv-dump / image-snapshot | 结果导出 |
Phase 4 实施范围: - ✅ types/task-flow.ts schema 落盘 - ✅ Left Dock § Task Flow 段 UI 入口(列表 + "新建 Flow"按钮) - ✅ Bottom Dock § Task Queue 占位段 - ❌ 执行引擎不实施(无 FlowNode 真跑 · 用户期望后续季度做) - ❌ 5 类 Flow Node 具体子类型不实施(仅 schema)
2.10 子决议 · 三层分工铁律(继承 ADR-07 §1.3.4)
| 层 | 进程 | 本 ADR v2.0 新增职责 |
|---|---|---|
| L1 I/O | P5-backend-csharp | ① MeterTapService 扩展 toolKind 路由(7 类 MeasurementNode 各路由 P7 端点)② WS 帧 schema 加 toolKind 字段 ③ 限流 30fps/tool/client ④ Bottom Dock Device Status 推送(WASAPI 状态 + XRUN 计数 + CPU 占用) |
| L2 数学 | P7-pysidecar | ① 新增 5 端点:/analyze/transfer_function / /analyze/group_delay / /analyze/peak_hold / /analyze/snapshot_diff / /analyze/thd ② 现有 19 端点 schema 升级(返回值加物理元信息字段:resolution / noiseFloorDb / averagedCount) |
| L3 显示 | 前端 | ① Widget Workspace 框架 ② 7 类 MeasurementNode 实施 ③ Right Dock Inspector 6 段 ④ 4 套 Workspace Preset ⑤ Bottom Dock 状态栏 ⑥ Sequence schema + UI 入口 · 零数学 |
2.11 边界铁律(强制约束)
- Widget 容器内禁止业务逻辑:Widget = 容器 + Measurement 引用 · 业务逻辑必须封装在 MeasurementNode 内
- MeasurementNode 7 子能力不可拆:任何新 MeasurementNode 实施必须填齐 7 子能力(input/processing/measurement/validation/visualization/automation/storage)· 缺任一 = 派发拒绝
- 5 项业务行为契约必填:任何新 MeasurementNode 派发前必须填齐 §3 5 段(MeterDataFrame schema + 收敛判据 + 失败回退 + 用户操作流 + 端到端真值 e2e)
- 三层分工铁律不可破:前端零数学 · P5 零数学 · P7 全部数学(继承 ADR-07 §1.3.4)
- Sequence 执行引擎本期禁止实施:仅 schema + UI 入口 · 任何"顺手做执行"提议拒绝 · 必须新起 ADR 修订
- Workspace Preset 4 套不可减:Tuning/Electrical/Recording/Multi-channel 是用户锁定的 · 任何减项需新起 ADR
- Multi-monitor schema 留 · UI 不做:DashboardWidget.monitor 字段必须保留 · 但 UI 实施留下季度
- 响应式适配横竖屏(v2.2 新增 · 用户拍板 2026-05-30 12:50):所有 xitest Widget(主界面)+ 右 dock(Inspector)+ 底栏(Bottom Dock)必须支持横竖屏切换 · 横屏(宽 ≥ 高)布局 vs 竖屏(高 > 宽)布局两套响应式断点 · 实施侧:用 ResizeObserver 监听容器尺寸 + CSS @container query / aspect-ratio 媒体查询 + Pinia widgetLayoutStore 暴露
orientation: 'landscape' | 'portrait'派生状态 · 后续 xitest fork prompt 必须含此约束 · 验收必须包含横竖屏 e2e(playwright 改 viewport 1920×1080 vs 1080×1920 各跑一次) - 主题色系切换(v2.2 新增 · 用户拍板 2026-05-30 12:50):所有色系搭配必须满足主题切换(浅色 / 深色 / 自定义)· 严禁硬编码 hex 色值(
#fff/#000/rgba(...)在 .vue / .css 中均禁)· 必须用 design-token / CSS variable(如var(--xs-color-primary)/var(--xs-bg-elevated-1))· 实施侧:对齐主仓frontend_vue3/src/styles/design-tokens.css现有 token 体系 · 新增 token 必须先在 design-tokens.css 中声明 · 后续 xitest fork prompt 必须含此约束 · 验收必须 grep 证明本 fork 改动文件无硬编码 hex(允许在 design-tokens.css 内定义)
§2.11 第 8+9 项作为后续 xitest 任务全局红线(适用范围:ADR-12 Phase 3+ 所有 MeasurementNode fork / ADR-08 §2.1 议题⑤ DrawerXiTest 后续迭代 / ADR-11 v1.3 fork 1-v3 4 Tab Widget · 等)。已 zombie 的 ADR-12 #5/#6/#7 不追溯 · 但下一轮迭代必须补齐。本红线已于 2026-05-30 13:00 直接内联到 P0.U-measurement-thd-snr + P0.U-measurement-impulse-spectrogram 两 prompt(避免 ADR 回写延迟阻塞派发)。
§2.11 第 8+9 项前后端责任边界(v2.3 新增 · 用户 2026-05-31 11:49 洞察:"刚刚添加的内容好像都是前端 · 后端是否需要接口对应的变化"):
明确边界:第 8+9 项纯前端 UI 渲染范畴 · P5/P7 后端无需适配 · 现有数据契约不变。
§2.11 第 8 项响应式横竖屏: - ✅ 前端责任(L3 显示):ResizeObserver / CSS @container query / widgetLayoutStore.orientation 派生 state / playwright viewport e2e - ❌ P5 不参与:WS 帧 schema 不带 widget 像素尺寸 · 30fps 推送频率与 widget 大小完全无关(前端按容器尺寸独立渲染) - ❌ P7 不参与:numpy/scipy 计算颗粒度由 fftSize/sampleRate 决定 · 与 widget 像素数完全无关(前端可任意缩放数据点)
§2.11 第 9 项主题色系切换: - ✅ 前端责任(L3 显示):design-token / CSS variable / 浅色/深色/自定义主题 / playwright 截图对比 e2e - ❌ P5 不参与:WS 帧 schema 仅推数值数据(rmsDb / magsDb / phaseDeg 等)· 不推任何颜色/样式信息 - ❌ P7 不参与:即使 spectrogram colormap 也是 P7 推 magDb 矩阵 + 前端 Canvas 用 design-token 渲染 · P7 端无需感知配色
历史任务后端适配核查(回应用户 2026-05-31 11:49 提问): - ADR-12 Phase 1 #1+#8(P0.U-meter-types-v3
9fc31c4+ P5.U-meter-tap-multi-tool48cf0ba):后端只扩 toolKind 路由 + WS 帧 schema · 不涉及响应式/主题 · 无需补 - ADR-12 Phase 2 #5/#6/#7(8379de2+600f0fc+729327c):全前端组件 · 后端复用 Phase 1 已就位的 toolKind 路由 · 不涉及响应式/主题 · 无需补 - ADR-09 后端 fork(P5.UA9-plugin-registry-service / P6.UA9-plugin-abi-v1):plugin 架构 · 不涉及响应式/主题 · 无需补 - ADR-08 后端三 fork(8238c4d+41ad8d9+b43c35a):error-channel / perf-service / runtime-mode-refactor · 不涉及响应式/主题 · 无需补 - ADR-11 v1.3 fork 1b-v2(P5.U-autotune-vehicle-config-extend · 1.0d ClaudeB · dispatched 中):VehicleConfig schema + IR 持久化 · 不涉及响应式/主题 · 无需补结论:全栈所有历史任务无需为响应式 + 主题切换做后端适配 · 现有数据契约保持不变。后续若发现确有跨栈联动场景(如"P7 端口推送 widget 尺寸建议"等创新需求)· 必须新起 ADR-AIOS-12-RX 修订本边界。
3. 业务行为契约(Business Behavior Contract · 本 ADR 核心 · 7 类 MeasurementNode × 5 项契约)
本节是 Cline-AIOS 调度内核回应用户 2026-05-28 "业务深度系统性缺失"诊断的核心交付物。每类 MeasurementNode 必须填齐 5 项契约,任何派发缺契约 = 立即拒绝。
5 项契约必填段: 1. 输入/输出契约(MeterDataFrame schema 物理意义 · 字段单位 · 采样率 · 通道映射) 2. 收敛/成功判据(测量稳定阈值 · 信号存在判据 · 帧率达标) 3. 失败回退路径(5 类失败场景 + UI 表现 + 恢复路径) 4. 用户操作流(端到端 5 步 · 鼠标轨迹 · 关键交互) 5. 端到端真值 e2e(用户场景必跑通 · 不只是 typecheck/build/test 形式合规)
3.1 RMS Meter Node(time-domain · type='rms-meter' · §十.2)
① 输入/输出契约
export interface MeterFrame_RMS {
kind: 'rms-meter'
node: 'sink-pre' | 'physical-input' | 'recording-replay'
timestamp: number // P5 采集时间戳(ms · 单调时钟)
sampleRate: 48000 | 44100 | 96000
channels: number // 通道数(默认 8)
channelLabels: string[] // ['L','R','Ls','Rs','C','LFE','Lss','Rss']
// 8 通道并行数据
rmsDb: number[] // 各通道 RMS(dBFS · 0=满量程 · -∞=静音 · 长度=channels)
peakDb: number[] // 各通道瞬时 Peak(dBFS)
peakHoldDb: number[] // 各通道 Peak Hold(dBFS · P7 端衰减系数 0.998/帧)
// 可选附加(用户在 Inspector 启用)
lufsIntegrated?: number[] // 响度(LUFS · ITU-R BS.1770)
crestFactor?: number[] // 峰均比(dB · peakDb - rmsDb)
// 时间常数
averagingType: 'fast' | 'slow' | 'instant' // fast=125ms · slow=1s · instant=10ms
// 物理元信息
noiseFloorDb: number // 当前估计噪声地板
}
② 收敛/成功判据
| 判据 | 阈值 | 含义 |
|---|---|---|
| 通道映射已锁定 | channelLabels.length === channels | 用户在 Engine.Channel Map 配过通道顺序 |
| 帧率达标 | 前端实测 FPS ≥ 25(目标 30) | UX 可接受 |
| 静音判定 | rmsDb[i] < noiseFloorDb + 3dB → 该通道 bar 灰显 | 区分"无信号"与"低信号" |
| 过载判定 | peakDb[i] > -1dBFS 持续 100ms → bar 红闪 | 提示用户降增益 |
③ 失败回退路径
| 失败 | 触发 | UI 表现 | 恢复路径 |
|---|---|---|---|
| WS 断开 | P5 WS heartbeat 超时 5s | 全 8 bar 灰显 + 顶栏红点 + "已断开 · 重连中…" | 自动重连 ½/4/8/16/30s 指数退避 |
| 单通道断开 | P5 WASAPI 报告 channel[i] 故障 | 该通道 bar 灰显 + 标签红框 | 不影响其他通道 · 用户检查物理接线 |
| P7 sidecar 崩溃 | P5 收到 HTTP 502 from :8001 | 全 bar 灰显 + "分析后端不可用" | P5 自动重启 P7 + health-check |
| 通道映射不一致 | channelLabels.length ≠ channels | 顶栏黄警 + "通道映射未锁定 · 请配 Channel Map" | 用户跳到 Left Dock § Engine 配置 |
| 数据帧倒序 | timestamp 倒退 > 100ms | 静默丢弃 + 计数器 +1 · 累计 ≥ 10 帧/s 上报 dev-tools | 通常是 P5/P7 时钟漂移 |
④ 用户操作流
Step 1 · 拖入 Widget
Left Dock § Measurements → 拖 'RMS Meter' 到 Dashboard
→ 自动创建 MeasurementNode(kind=time-domain · type=rms-meter)+ Widget(2x1 默认)
Step 2 · 选源(Right Inspector § Source)
Node: [physical-input ▼] · Channels: [☑L ☑R ☑Ls ☑Rs ☑C ☑LFE ☑Lss ☑Rss]
→ 实时下发 P5 · 切换时清空 Peak Hold
Step 3 · 配置(Right Inspector § Measurement)
Averaging Type: [Fast ▼] / [Slow] / [Instant]
☑ Peak Hold(衰减时间:3s)
☑ Show Crest Factor
Step 4 · 观察
8 bar 实时刷新(30fps)· 数值显示在 bar 下方 · Peak Hold 红线衰减
bar 颜色梯度:< -20dB 青绿 · -20 to -3dB 黄 · > -3dB 红
右键单通道 bar → "聚焦此通道"(联动 FFT widget filter)
Step 5 · 快照(Right Inspector § Storage)
[💾 Save Snapshot] → 保存当前 8 通道 RMS 值 + 时间戳到 Workspace.snapshots
[📁 Compare with Golden] → 加载 Golden RMS 值 · bar 旁显示 ΔdB
⑤ 端到端真值 e2e
// e2e/rms-meter-truth.spec.ts(Phase 4 · ClaudeC 写)
test('RMS Meter · 8 通道注入 -20dBFS 粉噪 · 8 bar 应都在 -20±1dB', async ({ page }) => {
// 前置:测试夹具向声卡 8 通道注入 -20dBFS 粉噪 · sample-accurate
await page.goto('/xitest?mode=realtime')
await dragMeasurementToCanvas(page, 'rms-meter')
await selectNode(page, 'physical-input')
await selectChannels(page, [0,1,2,3,4,5,6,7])
// 等稳定 8 帧
await page.waitForFunction(() => window.__xitestDebug.getRmsAveragedCount() >= 8, { timeout: 5000 })
// 真值断言:8 通道 RMS 都应在 -20±1dB
for (let i = 0; i < 8; i++) {
const rms = await page.evaluate((idx) => window.__xitestDebug.getRmsDb(idx), i)
expect(rms).toBeGreaterThan(-21)
expect(rms).toBeLessThan(-19)
}
})
test('RMS Meter · 单通道 -3dBFS 1kHz 正弦 · Peak Hold 应稳定在 -3dB', async ({ page }) => {
await injectChannel(0, '1kHz sine -3dBFS')
// 等 Peak Hold 锁定
await page.waitForFunction(() => window.__xitestDebug.getPeakHoldDb(0) > -4, { timeout: 3000 })
const peakHold = await page.evaluate(() => window.__xitestDebug.getPeakHoldDb(0))
expect(peakHold).toBeGreaterThan(-3.5)
expect(peakHold).toBeLessThan(-2.5)
})
3.2 FFT Analyzer Node(frequency · type='fft-analyzer' · §十一.1)
① 输入/输出契约
export interface MeterFrame_FFT {
kind: 'fft-analyzer'
node: 'sink-pre' | 'physical-input' | 'recording-replay'
timestamp: number
sampleRate: 48000 | 44100 | 96000
fftSize: 1024 | 4096 | 8192 | 16384 | 32768
window: 'hanning' | 'hamming' | 'blackman' | 'flat-top' | 'rect'
overlap: 0 | 0.5 | 0.75 | 0.875
// bins 数据(物理意义明确)
freqs: Float32Array // bin 中心频率(Hz · 长度=fftSize/2+1)
magsDb: Float32Array // 幅度(dBFS · 长度同 freqs)
// 平均状态(P7 端维护)
averagedCount: number // 当前已平均帧数
averagingType: 'linear' | 'exponential' | 'peak'
averagingTarget: number // 目标平均次数(8/16/32/64/128)
// 倍频程(用户起稿 §十一.2 RTA)
octaveBand?: 'off' | '1/1' | '1/3' | '1/6' | '1/12' | '1/24'
octaveData?: Float32Array // 倍频程数据(若 octaveBand !== 'off')
// Peak Hold(P7 端状态机)
peakHoldDb?: Float32Array // 同 magsDb 长度 · 衰减 0.995/帧
// 物理元信息
resolution: number // Hz/bin = sampleRate/fftSize
noiseFloorDb: number
}
② 收敛/成功判据
| 判据 | 阈值 | 含义 |
|---|---|---|
| 测量稳定 | averagedCount ≥ averagingTarget AND std(magsDb[100~10kHz]) < 0.5dB | 频谱稳定可读 |
| 信号存在 | mean(magsDb[20~20kHz]) > noiseFloorDb + 6dB | 不是纯噪声 |
| 帧率达标 | 前端实测 FPS ≥ 25 | UX 可接受 |
| 分辨率达标 | resolution = sampleRate/fftSize · 用户在 Inspector 看到状态栏更新 | 物理意义可解释 |
③ 失败回退路径
| 失败 | 触发 | UI 表现 | 恢复路径 |
|---|---|---|---|
| WS 断开 | 同 §3.1 | 图灰显 + "已断开" | 同 §3.1 |
| FFT 配置不合法 | overlap=0.875 + fftSize=32768 + sampleRate=44100 → P7 计算超时 | 顶栏红警 + "配置过载 · 已自动降级" | P7 自动降到 overlap=0.75 |
| 信号过弱 | mean(magsDb) < noiseFloorDb + 3dB | 顶栏黄警 + "信号过弱 ⚠️" | 用户增大输入增益 |
| 频谱泄漏严重 | 单频信号 → 邻 bin 衰减 < 6dB(窗函数选错) | Inspector § Measurement 提示 "建议选 Flat Top 窗" | 用户切窗函数 |
| 过载/clipping | magsDb 任一 bin > -1dBFS 持续 100ms | 该频段红色闪烁 | 用户调输入增益 |
④ 用户操作流
Step 1 · 拖入 Widget
Left Dock § Measurements → 'FFT Analyzer' → 拖到 Dashboard
Step 2 · 选源(Inspector § Source)
Node: [physical-input ▼] · Channels: [☑ L]
Step 3 · 配 FFT(Inspector § Measurement)
FFT Size: [4096 ▼](状态栏立即显示分辨率 = 11.7 Hz/bin)
Window: [Hanning ▼]
Overlap: [75% ▼]
Averaging: [指数 8 次] · ☑ Peak Hold(3s 衰减)
Step 4 · 配显示(Inspector § Display)
Scale: [对数 ▼]
dB Range: [80dB] · Reference: [0dB]
☑ 1/3 Oct Smoothing
Step 5 · 观察 + 测量
鼠标 hover → 十字游标 + "1.2 kHz · -23.4 dB"
右键 → "标记此点"(添加 Cursor)
双击空白 → 回到默认视图
[💾 Snapshot A] → [💾 Snapshot B] → 切 [双曲线模式] 对比
⑤ 端到端真值 e2e
test('FFT · physical-input 注入 1kHz -10dBFS 正弦 · 应在 1kHz 处出现 -10±1dB 峰', async ({ page }) => {
await injectChannel(0, '1kHz sine -10dBFS')
await dragMeasurementToCanvas(page, 'fft-analyzer')
await configFFT(page, { size: 4096, window: 'hanning', overlap: 0.75 })
await page.waitForFunction(() => window.__xitestDebug.getFftAveragedCount() >= 8)
const peakBin = await page.evaluate(() => window.__xitestDebug.getFftPeakBinFreq())
expect(peakBin).toBeGreaterThan(950)
expect(peakBin).toBeLessThan(1050)
const peakDb = await page.evaluate(() => window.__xitestDebug.getFftPeakDb())
expect(peakDb).toBeGreaterThan(-11)
expect(peakDb).toBeLessThan(-9)
})
test('FFT · sink-pre 加载 PEQ +6dB@1kHz Q=2 · 1kHz 比 100Hz/10kHz 高 5~7dB', async ({ page }) => {
await loadPreset(page, 'peq-plus-6db-at-1khz-q2')
await injectChannel(0, 'pink-noise -20dBFS')
await selectNode(page, 'sink-pre')
await page.waitForFunction(() => window.__xitestDebug.getFftAveragedCount() >= 16)
const ref = await page.evaluate(() =>
(window.__xitestDebug.getFftDbAt(100) + window.__xitestDebug.getFftDbAt(10000)) / 2
)
const peak = await page.evaluate(() => window.__xitestDebug.getFftDbAt(1000))
expect(peak - ref).toBeGreaterThan(5)
expect(peak - ref).toBeLessThan(7)
})
3.3 Transfer Function Node(transfer · type='transfer-fn' · §十二 · Smaart 核心)
① 输入/输出契约
export interface MeterFrame_Transfer {
kind: 'transfer-fn'
node: 'physical-input' // 仅 physical-input 双通道(ref + measure)
timestamp: number
sampleRate: number
fftSize: number
refChannel: number // 参考通道(发声端 · 已知信号)
measureChannel: number // 测量通道(mic · 实测响应)
// 双通道传递函数核心数据
freqs: Float32Array // bin 频率
magnitudeDb: Float32Array // 幅频响应(dB · 测量/参考)
phaseWrapped: Float32Array // 相位 wrapped(°· ±180)
phaseUnwrapped?: Float32Array // 相位 unwrapped(°· 连续)
groupDelay?: Float32Array // 群延迟(ms · -dφ/dω)
coherence: Float32Array // 相干性(0~1 · 测量可信度)
// 延时查找(Smaart Delay Finder)
delayFinderMs?: number // 检测到的最佳延时(ms)· null=未锁定
delayLocked: boolean // 延时已锁定
averagedCount: number
coherenceThreshold: number // 用户设定阈值(默认 0.7)
// 物理元信息
resolution: number
}
② 收敛/成功判据
| 判据 | 阈值 | 含义 |
|---|---|---|
| 延时已锁定 | delayLocked === true · 跨 averagedCount ≥ 16 帧不变 | Smaart 双通道核心条件 |
| 相干性达标 | mean(coherence[100~10kHz]) > coherenceThreshold(默认 0.7) | 测量可信度高 |
| 测量稳定 | std(magnitudeDb[100~10kHz]) < 0.5dB(连续 8 帧) | 频响曲线稳定 |
| 信号在两通道都存在 | refChannel rms > -40dBFS AND measureChannel rms > -40dBFS | 双通道都有声 |
③ 失败回退路径
| 失败 | 触发 | UI 表现 | 恢复路径 |
|---|---|---|---|
| 延时未锁定 | delayFinderMs 跨 5s 仍 null | "Delay Finder 未锁定 · 检查参考信号" | 用户检查 ref 通道是否有信号 |
| 相干性过低 | mean(coherence) < 0.3 | 全图灰显 + "相干性过低 · 增大信号 / 减少噪声" | 用户增大发声音量 |
| 单通道断开 | ref 或 measure 通道无信号 | 顶栏红警 + 标识哪个通道断 | 检查物理接线 |
| 相位环绕异常 | unwrapped 相位跨 360° 跳变 | "相位环绕异常 · 切 Wrapped 模式" | 用户切显示模式 |
| 通道选择错误 | refChannel === measureChannel | 派发拒绝(Validation Engine 拦截)+ 红警 | 用户重选不同通道 |
④ 用户操作流
Step 1 · 准备(场景:扩声系统调音)
舞台 console → 调音台 → DSP → 功放 → 扬声器 → 麦克风 → 声卡(2 通道:ch0=参考 ch1=mic)
Step 2 · 拖入 Widget · 选 Tuning Workspace Preset
Left Dock § Workspace → "Tuning"(自动加载 Transfer/FFT/Phase/RMS 4 widget · 2x2)
Step 3 · 配 Transfer(Inspector § Source/Measurement)
Ref Channel: [ch0 ▼] · Measure Channel: [ch1 ▼]
Delay Tracking: [☑ 自动]
Coherence Threshold: [0.7]
Step 4 · 启动测量
Top Toolbar [▶ Run] → 播放粉噪 / 扫频 → 等延时锁定(3-5s)
状态栏显示 "Delay Locked: 4.2 ms · Coherence: 0.85"
Step 5 · 阅读 + 优化
Magnitude 曲线 → 看哪些频段超出目标 ± 3dB
Phase 曲线 → 看分频点是否对齐
右键 → "导出当前测量到 Snapshot" → Tuning Workspace 保存
Right Inspector § Validation → 加 Mask 规则(如 ±3dB tolerance) → Pass/Fail
⑤ 端到端真值 e2e
test('Transfer · 已知 4ms 延时 · Delay Finder 应锁定 4±0.5ms', async ({ page }) => {
// 前置:测试夹具 ch0=参考粉噪 · ch1=参考粉噪延迟 4ms 后注入
await injectStereo('pink-ref', 'pink-delayed-4ms')
await loadWorkspace(page, 'tuning')
await configTransfer(page, { ref: 0, measure: 1 })
await page.waitForFunction(() => window.__xitestDebug.isTransferDelayLocked(), { timeout: 8000 })
const delay = await page.evaluate(() => window.__xitestDebug.getTransferDelayMs())
expect(delay).toBeGreaterThan(3.5)
expect(delay).toBeLessThan(4.5)
})
test('Transfer · 在 ch1 加 PEQ -3dB@1kHz · transfer 曲线应在 1kHz 显示 -3±0.5dB', async ({ page }) => {
await loadPreset(page, 'peq-minus-3db-at-1khz')
await injectStereo('pink-ref', 'pink-via-peq')
await page.waitForFunction(() => window.__xitestDebug.getTransferAveragedCount() >= 16)
const mag1k = await page.evaluate(() => window.__xitestDebug.getTransferMagDb(1000))
expect(mag1k).toBeGreaterThan(-3.5)
expect(mag1k).toBeLessThan(-2.5)
})
3.4 Phase Meter Node(frequency · type='phase-meter' · §十一/§十八 共享)
① 输入/输出契约
export interface MeterFrame_Phase {
kind: 'phase-meter'
node: 'sink-pre' | 'physical-input'
timestamp: number
sampleRate: number
fftSize: number
freqs: Float32Array
phaseWrapped: Float32Array // ±180°
phaseUnwrapped?: Float32Array // 用户在 Inspector 启用
groupDelay?: Float32Array // ms · 用户在 Inspector 启用
averagedCount: number
// 物理元信息
resolution: number
}
② 收敛/成功判据
| 判据 | 阈值 | 含义 |
|---|---|---|
| 测量稳定 | std(phaseWrapped[100~10kHz]) < 5°(连续 8 帧) | 相位曲线稳定 |
| 群延迟可读 | groupDelay 全段无 NaN/Inf | 数值合法 |
③ 失败回退路径(同 FFT · 略)
④ 用户操作流(简版)
⑤ 端到端真值 e2e
test('Phase · 注入纯 1kHz 正弦 · 1kHz 处相位应稳定(std < 5°)', async ({ page }) => {
await injectChannel(0, '1kHz sine -10dBFS')
await dragMeasurementToCanvas(page, 'phase-meter')
await page.waitForFunction(() => window.__xitestDebug.getPhaseAveragedCount() >= 16)
const phaseStd = await page.evaluate(() => window.__xitestDebug.getPhaseStdAt(1000))
expect(phaseStd).toBeLessThan(5)
})
3.5 Waveform Scope Node(time-domain · type='waveform-scope' · §十.1)
① 输入/输出契约
export interface MeterFrame_Waveform {
kind: 'waveform-scope'
node: 'sink-pre' | 'physical-input' | 'recording-replay'
timestamp: number
sampleRate: number
channels: number
bufferSize: number // 抓取长度(samples · 100ms-5s)
samples: Float32Array[] // 各通道波形(长度=channels × bufferSize)
// 触发(用户起稿 §十.1)
triggered: boolean
triggerLevel?: number // dBFS(-60 ~ 0)
triggerEdge?: 'rising' | 'falling'
preRollPercent?: number // 0-100% · 预触发长度
// 冻结
frozen: boolean // 用户按 Freeze 后停止刷新
}
② 收敛/成功判据
| 判据 | 阈值 | 含义 |
|---|---|---|
| 触发已捕获 | triggered === true(若启用 trigger) | 抓到目标波形 |
| 缓冲已填满 | samples.length === bufferSize | 完整一段波形 |
③ 失败回退路径(简版)
| 失败 | 触发 | UI 表现 |
|---|---|---|
| 触发等待超时 | 60s 未触发 | "等待触发超时 · 降低 trigger level" |
| 数据丢帧 | 后端 P5 报告 buffer underrun | 顶栏红警 + XRUN 计数 +1 |
④ 用户操作流(简版 · 对应 Demo HTML 时域抓取 tab)
拖 'Waveform Scope' → 选源 → 配触发(level / edge / preroll)→ [⏺ Record] →
触发后停止 → [💾 Snapshot A] → 重新触发 → [💾 Snapshot B] → 切 Overlay 对比
⑤ 端到端真值 e2e
test('Waveform · 注入 1kHz 方波 · trigger 锁后 buffer 应包含完整周期', async ({ page }) => {
await injectChannel(0, '1kHz square -6dBFS')
await dragMeasurementToCanvas(page, 'waveform-scope')
await configWaveform(page, { triggerLevel: -10, edge: 'rising', preroll: 20 })
await page.waitForFunction(() => window.__xitestDebug.isWaveformTriggered(), { timeout: 5000 })
// 真值:1ms 内应有完整方波周期(1kHz period = 1ms)
const periodSamples = await page.evaluate(() => window.__xitestDebug.getWaveformPeriodSamples())
expect(periodSamples).toBeGreaterThan(46) // 48000Hz · 1kHz · 48 samples
expect(periodSamples).toBeLessThan(50)
})
3.6 Electrical Meter Node(electrical · type='electrical-meter' · §十三 · APx500 核心)
本期 Phase 2 仅实施 schema + 显示 stub · THD/SINAD/SNR 算法实施需 P7 新增
/analyze/thd端点。
① 输入/输出契约
export interface MeterFrame_Electrical {
kind: 'electrical-meter'
node: 'physical-input'
timestamp: number
// 用户起稿 §十三 全字段
vrms: number[] // 电压(V · 各通道)
dbu: number[] // 电平(dBu · 0.775V=0dBu)
frequency: number[] // 主频率(Hz)
thd: number[] // 谐波失真(%)
thdN: number[] // THD+N(%)
sinad: number[] // SINAD(dB)
snr: number[] // 信噪比(dB)
// 校准状态
calibrated: boolean // 用户在 Engine § Calibration 配过校准
calibrationDate?: number
}
②-⑤ 略(本期 Phase 2 实施 stub · Phase 4 真值 e2e 需 AP 测试夹具配合)
3.7 Recorder Node(recording · type='recorder' · §十四)
本期 Phase 3 仅实施 schema + UI 入口 + 内存 ring buffer · 文件持久化(.wav 多轨)留下季度。
① 输入/输出契约
export interface RecordingSession {
id: string
startedAt: number
stoppedAt?: number
durationMs: number
channels: number
sampleRate: number
bufferMode: 'ring' | 'continuous' // ring=固定长度循环 · continuous=持续到 stop
bufferSizeMs: number // ring buffer 长度
markers: Array<{ at: number; label: string }>
preRollMs: number
triggerConfig?: TriggerConfig
}
②-⑤ 略
4. 后果(Consequences)
4.1 正面后果
✅ 业务行为契约必填段:7 类 MeasurementNode × 5 项契约示范 · 后续所有 ADR 模板对齐 · 杜绝"壳子框架" ✅ Widget Workspace 解锁专业 UX:对标 Smaart/APx500/Ocenaudio 的工程师交互(拖拽/Resize/Save Layout/Multi-monitor schema) ✅ MeasurementNode 统一抽象:7 类 × 7 子能力 · 任何新 Measurement(STIPA/RT60 等)按模板派生 · 不重复造轮子 ✅ 4 套 Workspace Preset:Tuning(Smaart)/Electrical(APx500)/Recording(Ocenaudio)/Multi-channel(车载) · 用户一键切场景 ✅ Sequence 占位不丢需求:Task Flow schema + UI 入口本期落 · 执行引擎留下季度 · 回应用户"不能不提" ✅ 三层分工铁律延续:前端零数学 · P5 仅 I/O · P7 全部数学 · 继承 ADR-07 §1.3.4 ✅ 三 ADR 平行推进:本 ADR + ADR-XiTune-AutoTune + ADR-XiTune-AutoTune-layout 共享 Dockable+Workspace+Widget+Scene 架构
4.2 负面后果与缓解
| 后果 | 影响 | 缓解 |
|---|---|---|
| ⚠️ Widget Workspace 框架工作量大 | Phase 1 需 5d · 阻塞后续 Phase | 选成熟方案 vue-grid-layout · 不自研 |
| ⚠️ 7 类 MeasurementNode 全实施 | Phase 2 需 8d · ClaudeA/D 并行高强度 | 拆 7 个独立 U-thread · 各 1.0-1.5d · 并行 |
| ⚠️ Inspector 6 段 × 7 类组合 | 每组合需独立子组件 · 工作量 ×N | Inspector 容器抽象 · 子段按 MeasurementNode.type 路由 · DRY |
| ⚠️ Sequence schema 落但执行不实 | 用户可能误以为可用 | Top Toolbar [▶ Run Sequence] 按钮灰显 + tooltip "Phase 4 占位 · 执行引擎下季度" |
| ⚠️ Multi-monitor schema 留 UI 不做 | 用户在 Inspector 可能看到 monitor 选项但不生效 | Inspector 不显示 monitor 选项 · schema 仅为未来兼容 |
| ⚠️ P7 新增 5 端点工作量 | Phase 2-3 后端阻塞 | ClaudeB 主导 · 与前端并行(端点 mock 优先 · 算法后跟) |
| ⚠️ 业务行为契约 5 段写起来重 | 每 MeasurementNode 派发都需填 5 段 · 派发慢 | .clinerules v1.8 加自查清单 · prompt 模板带 5 段骨架(空 stub) |
4.3 关键非目标(Non-Goals)
- ❌ 不实施 Sequence(Task Flow)执行引擎(留下季度)
- ❌ 不实施 Validation Engine 算法(threshold/mask/golden compare 仅 schema · Phase 4 占位)
- ❌ 不实施 Recording 文件持久化(.wav 多轨 · ring buffer 仅内存 · 留下季度)
- ❌ 不实施 Multi-monitor UI(schema 留 monitor 字段)
- ❌ 不实施 Snapshot 跨 Workspace 共享(同 Workspace 内可对比)
- ❌ 不实施 Spectrogram 瀑布图(Phase 2 schema 占位 · UI 实施留下季度)
- ❌ 不实施 Generator 信号源(Sine/Pink/Chirp/MLS/Multitone · schema 留 · UI 留下季度)
- ❌ 不实施 LUFS 响度算法(P7 端 · 留下季度)
- ❌ 不修改 contract-v1.0(已 frozen · meter-source 扩展统一并入 v2)
- ❌ 不与 ADR-10 SignalSink 联动(留下季度 · HMI 触发测试 sequence)
5. 实施清单(Implementation · Phase 1-4 · 12 U-thread · 总 20d)
5.1 Phase 1 · Widget Workspace 框架(5d · 优先级 P1)
| # | U-thread | CPU | 工时 | 业务深度核心 |
|---|---|---|---|---|
| 1 | P0.U-meter-types-v3 | ClaudeA | 1.0d | types/measurement-node.ts + types/dashboard-widget.ts + types/workspace.ts + types/task-flow.ts(占位)+ types/meter-frame-{rms,fft,transfer,phase,waveform,electrical,recording}.ts · 7 类 MeterFrame schema · workspaceStore Pinia 骨架 |
| 2 | P0.U-widget-workspace-framework | ClaudeA | 2.5d | DashboardCanvas.vue(vue-grid-layout 集成)· Widget 容器(Drag/Resize/Dock/Float/Split/Fullscreen/Save Layout)· 4 套 Workspace Preset 切换 · gridLayout 6 种 |
| 3 | P0.U-measurement-node-registry | ClaudeA | 1.0d | MeasurementNodeRegistry.ts(Map |
| 4 | P0.U-right-inspector-framework | ClaudeD | 0.5d | RightInspector.vue 6 段通用容器 · 子段按 selectedWidget.measurementNode.type 路由 · stub Source/Measurement/Display/Validation/Automation/Storage 6 子组件 |
5.2 Phase 2 · 7 类 MeasurementNode 实施(8d · 优先级 P1)
| # | U-thread | CPU | 工时 | 范围 |
|---|---|---|---|---|
| 5 | P0.U-measurement-rms-fft-phase | ClaudeA | 2.0d | RMSMeterNode + FFTAnalyzerNode + PhaseMeterNode 完整实施(组件 + Inspector + 5 项业务行为契约 §3.⅓.⅔.4) |
| 6 | P0.U-measurement-transfer-waveform | ClaudeD | 2.0d | TransferFunctionNode + WaveformScopeNode 完整实施(§3.3/3.5) |
| 7 | P0.U-measurement-electrical-recorder-stub | ClaudeD | 1.5d | ElectricalMeterNode + RecorderNode 实施(§3.6/3.7 schema + UI · 算法依赖 P7 端点 · stub) |
| 8 | P5.U-meter-tap-multi-tool | ClaudeB | 1.5d | MeterTapService 扩展 toolKind 路由(7 类)· WS 帧 schema 升级带 toolKind · 限流 30fps/tool/client · Bottom Dock Device Status 推送 |
| 9 | P7.U-analyze-extensions | ClaudeB | 1.0d | pysidecar 新增 5 端点:/analyze/transfer_function / /analyze/group_delay / /analyze/peak_hold / /analyze/snapshot_diff / /analyze/thd |
5.3 Phase 3 · Engine + Session + Storage + Bottom Dock(4d · 优先级 P2)
| # | U-thread | CPU | 工时 | 范围 |
|---|---|---|---|---|
| 10 | P0.U-engine-session-snapshots | ClaudeA | 2.0d | LeftDock § Engine(Physical Input/Playback Output 设备配置)+ § Session(时钟/路由/校准状态)+ § Snapshots(Save/Compare/Golden/Export) |
| 11 | P0.U-bottom-dock + storage-engine | ClaudeD | 2.0d | BottomDock.vue(Console 5 级日志 + Device Status WS 推送 + XRUN 计数 + Measurement Log)· Storage Engine 实施(Workspace.widgets[] 持久化 · localStorage / IndexedDB) |
5.4 Phase 4 · Sequence 占位 + 端到端真值 e2e(3d · 优先级 P2)
| # | U-thread | CPU | 工时 | 范围 |
|---|---|---|---|---|
| 12 | P0.U-task-flow-stub + e2e-truth | ClaudeC | 3.0d | LeftDock § Task Flow UI 入口(列表 + "新建 Flow"按钮 · stub 不可执行)+ BottomDock § Task Queue 占位 + 端到端真值 e2e 5 场景脚本(粉噪/1kHz 正弦/EQ +6dB/PEQ -3dB/触发抓波形)· 替代当前形式合规测试 |
5.5 派发顺序(K-thread 占用约束)
Phase 1 #1 → 解锁 #2 #3 #4(并行)
Phase 2 #5 #6 #7(并行 ClaudeA/D)+ #8 #9(并行 ClaudeB)
Phase 3 #10 #11(并行 ClaudeA/D)
Phase 4 #12(ClaudeC)
总工作量 20d × 4 CPU 并行 ≈ 5 周(对齐用户起稿广度 · 不缩水)
6. 验收(Acceptance)
6.1 文档验收
- ADR-AIOS-12-xitest-realtime-arch.md v2.0 落盘(本文件)· status: proposed
- processes/P_arch/ADR-XiTest-RealTime/ 子进程 PCB 创建
- processes/P_arch/PROCESS.md 加 ADR-XiTest-RealTime 子事件 user_thread
- processes/P4-xitest/PROCESS.md state release-candidate-final → planning-v2 + 加 4 fork
- processes/P0-xishell/PROCESS.md 加 4 fork(meter-types-v3 / widget-workspace-framework / measurement-node-registry / engine-session-snapshots / bottom-dock-storage / measurement-* / task-flow-stub-e2e-truth · 共 7 fork 给 P0)
- processes/P5-backend-csharp/PROCESS.md 加 1 fork(meter-tap-multi-tool)
- DASHBOARD.md v2.7.29 → v2.7.30 同步
- .clinerules/aios-orchestration.md v1.7 → v1.8 加 §"业务行为契约必填段"
6.2 实施验收(Phase 1-4 落地后)
| Phase | 通过条件 |
|---|---|
| Phase 1 | Widget 可拖拽/Resize/Save Layout · 4 套 Preset 一键切换 · LeftDock § Measurements 7 类节点可拖入 · RightInspector 6 段框架可见 |
| Phase 2 | 7 类 MeasurementNode 全部可拖入 + Inspector 配置 + 实时数据流 · §3 中 §3.⅓.⅔.3/3.4/3.5 五类 e2e 真值脚本全部跑通 |
| Phase 3 | LeftDock 8 段(Workspace/Session/Engine/Measurements/Recordings/Snapshots/Validation/Task Flow)全部可见 · BottomDock 6 段(Console/Device/XRUN/Measure Log/Task Queue 占位/Validation Result 占位)全部可见 · Workspace 布局可保存/加载 |
| Phase 4 | LeftDock § Task Flow 可见 + "新建"按钮(不可执行 + tooltip)· 端到端真值 e2e 5 场景在 CI 中绿 |
6.3 边界铁律验收(长期)
- 任何"在 Widget 内塞业务逻辑"提议 → 拒绝(§2.11 #1)
- 任何"派发 MeasurementNode 缺 5 项契约"提议 → 拒绝(§2.11 #3)
- 任何"前端做 FFT/RMS/相位计算"提议 → 拒绝(§2.11 #4 三层分工铁律)
- 任何"实施 Sequence 执行引擎"提议 → 必须新起 ADR-AIOS-12-RX(§2.11 #5)
- 任何"减 Workspace Preset 1 套"提议 → 必须新起 ADR(§2.11 #6)
7. 替代方案(Alternatives Considered)
7.1 替代方案 A(已废弃 · 对应 v1 误读)· 4 tab 切换
- 描述:不做 Widget Workspace · 全 stage 用 fixed 4 tab(频响/相位/时域/RMS)
- 废弃理由:
- 与用户起稿 §十七 Dashboard widget-based 直接冲突
- 与对标产品(Smaart/APx500/Ocenaudio)专业 UX 不一致
- 用户原话"所有的测量都以类似控件的 widget 的方式拖入主界面"明确否决
- 失去 Multi-monitor / Save Layout / 自定义场景能力
- 本 ADR 选择:严格 Widget Workspace + 4 套 Preset
7.2 替代方案 B(已废弃)· APx500 优先(测试自动化)
- 描述:realtime 弱化 · 主菜单 Sequence/Step/Result/Report 4 视图
- 废弃理由:用户原话"先实施 realtime 的显示 · 后续的 sequence 实施"明确顺序
7.3 替代方案 C(已废弃)· 三家融合全实施(含 Sequence 执行引擎)
- 描述:realtime + Sequence 执行引擎 + Recording 文件持久化全做
- 废弃理由:工作量 35d+ · 风险再次"广度泛滥业务浅" · 用户已说"sequence 后续实施"
- 本 ADR 选择:realtime 完整 + Sequence 占位 schema · 执行引擎下季度
7.4 替代方案 D(已废弃)· 用户起稿原文直接落 ADR
- 描述:不深化 · 把用户起稿 22 节直接当 ADR
- 废弃理由:无业务行为契约 5 段 · 不可派发 · 等于"壳子框架"
- 本 ADR 选择:保留用户起稿为 §附录 A · 主体写 5 项契约 + 实施清单
8. 状态流转(Status History)
| 日期 | 状态 | 操作 | 说明 |
|---|---|---|---|
| 2026-05-29 11:38 | 起草触发 | 用户给出"new ADR Xitest"指令 + 对标 3 产品 + demo 路径 + 起稿路径 | 用户起稿 912 行已就位 |
| 2026-05-29 11:48 | 信息收集 | Cline-AIOS read 4 输入文件(用户起稿 + ADR-10 + Demo HTML + ADR-07) | 全景图谱锁定 |
| 2026-05-29 11:50 | Plan v1 | Cline-AIOS plan_mode_respond 给方向 A/B/C(❌ 跑偏 · 把 Demo 当蓝本 · 砍 Sequence) | 已纠正 |
| 2026-05-29 12:00 | 用户纠偏 | 用户原话"哪里有 tab" + "realtime 这些功能我都要" + "sequence 后续实施但不能不提" | 强力纠偏 |
| 2026-05-29 12:04 | Plan v2 | Cline-AIOS 重读 md §十六-§二十二 + 对齐 ADR-XiTune-AutoTune-layout | 真实需求图谱锁定 |
| 2026-05-29 12:06 | 用户拍板 | 默认推荐(1A + 2是 + 3按MeasurementNode展开 · 1500行特批) | 进入 ACT 落盘 |
| 2026-05-29 12:10 | 用户拍板处置 | 方案 1 · 原路径覆写 + 起稿 §附录 A | 决定本文件结构 |
| 2026-05-29 12:15 | proposed v2.0(本版) | ADR v2.0 落盘 · 等用户 accept ADR-AIOS-12 |
12 U-thread fork ready |
| 2026-05-29 13:45 | 编号标准化 | git mv ADR-AIOS-XiTest-RealTime-Arch.md → ADR-AIOS-12-xitest-realtime-arch.md · 对齐 ADR-01~11 编号体系 |
用户拍板方案 A(简单顺位编号) |
| 2026-05-29 14:18 | accepted v2.1 | status proposed → accepted · 用户原话"方案 1 · accept ADR-AIOS-12 + start 3 fork" · 同时 dispatched Phase 1 起手 3 fork(P0.U-meter-types-v3 + P5.U-meter-tap-multi-tool + P7.U-analyze-extensions · 全部文件隔离 · 不绑定 CPU) | 与 aios-cpu1 ADR-11 实施并行 · 子目录隔离不冲突 |
| 2026-05-30 12:50 | 用户拍板 2 全局红线 | 用户原话"下一个 xitest 相关任务的 prompt 中加 · 适当的适配主界面 widget 窗口大小以及右侧 dock 横竖屏 · 所有的色系搭配要满足主题色系切换" · 同时 stop ADR-12 Phase 2 #6+#7(600f0fc + 729327c)· Phase 2 全闭环 |
红线先内联到 P0.U-measurement-thd-snr + impulse-spectrogram 两 prompt · 避免 ADR 回写延迟阻塞 |
| 2026-05-30 15:53 | v2.2 修订 | §2.11 边界铁律 7 项 → 9 项(加第 8+9 项 响应式横竖屏 + 主题色系切换 design-token)· frontmatter version v2.1 → v2.2 | 用户拍板 13:50 "ADR-12 §2.6 第 7+8 项铁律回写 v2.1→v2.2 · 把全局红线正式写入 ADR" · 实际写入 §2.11(铁律真位置) |
| 2026-05-31 11:50 | v2.3 修订 | §2.11 第 8+9 项后追加"前后端责任边界"说明 · 明确纯前端 UI 渲染范畴 · P5/P7 后端无需适配 · 现有数据契约保持不变 · 历史 5 类后端任务核查全部确认无需补 · frontmatter v2.2 → v2.3 | 用户 2026-05-31 11:49 洞察:"刚刚添加的内容都是前端 · 后端是否需要接口对应的变化 · 历史任务中做了后端适配么" · 杜绝未来误解前后端责任 |
9. 关键术语表(Glossary)
| 术语 | 定义 |
|---|---|
| Widget | Dashboard 内的可拖拽容器 · 持有 1 个 MeasurementNode 引用 |
| MeasurementNode | 测量节点统一抽象 · 7 子能力(input/processing/measurement/validation/visualization/automation/storage) |
| Workspace | 一组 Widget × 布局 × MeasurementNode × Engine 的工程文件 |
| Workspace Preset | 4 套预设(Tuning/Electrical/Recording/Multi-channel)+ 用户自定义 |
| 5 引擎 | Measurement / Validation / Task / Storage / Visualization 共享引擎 · §二十二 锁定 |
| 5 项业务行为契约 | 输入输出 schema + 收敛判据 + 失败回退 + 用户操作流 + 端到端真值 e2e · §3 必填 |
| Inspector 6 段 | Source/Measurement/Display/Validation/Automation/Storage · 通用容器 |
| Flow Node 5 类 | Source/Measurement/Validation/Logic/Export · §十六 Task Flow 锁定 |
| Dockable+Workspace+Widget+Scene | 与 ADR-XiTune-AutoTune-layout §2 共享的混合架构理念 |
| Smaart 风格 | 实时声学测量 · Transfer Function 双通道 · Live IR · Workspace=Tuning |
| APx500 风格 | 测试自动化 · THD/SINAD/Sweep · Workspace=Electrical |
| Ocenaudio 风格 | 多通道波形编辑 · 快照对比 · Workspace=Recording |
10. 相关决议与文档
10.1 相关 ADR
- ADR-AIOS-07 P3-xitune/P4-xitest 业务边界:本 ADR 继承 §1.3.4 三层分工铁律 + §1.3.1 节点选择契约 + §2.1.4 mode 命名(perf→regression / visual→realtime)
- ADR-AIOS-11(平行 · xitune-autotune):P3 自动调音 MVP · 本 ADR 仅引用(P3 调音 measure phase 可复用 §3.3 Transfer Function)
- ADR-AIOS-XiTune-AutoTune-layout(已归档至
ref/· 用户手动移动):P3 调音工作区布局思路文档 · 与本 ADR 共享 Dockable+Workspace+Widget+Scene 架构理念 - ADR-AIOS-04 XiForge 架构:Module UID 规范 · 本 ADR 不直接关联
- ADR-AIOS-05 XiStudio Workspace · LEGACY_*_MAP:本 ADR Workspace 持久化沿用 LEGACY_LINK_FILE_MAP 协议
- ADR-AIOS-06 OS 化任务调度:本 ADR 全程使用其调度协议
- ADR-AIOS-08/09/10(平行):XiLink stage 议题 · 共享 K2-protocol-v2 启动 · 正交无冲突
- ADR-AIOS-10 SignalSink 抽象:本 ADR 未来扩展(HMI 触发测试 sequence · 留下季度)
10.2 相关 PROCESS.md
processes/P4-xitest/PROCESS.md(本 ADR 主战场 · 4 fork U-thread · state planning-v2)processes/P0-xishell/PROCESS.md(本 ADR 共享栈 · 7 fork U-thread)processes/P5-backend-csharp/PROCESS.md(后端 · 1 fork)processes/P_arch/PROCESS.md(本 ADR 子事件)processes/P_arch/ADR-XiTest-RealTime/PROCESS.md(子进程 PCB · 本 ADR 派生)
10.3 关联契约
contracts/protocol-v1.md(frozen · 不修改)contracts/protocol-v2.md(候选启动 · 本 ADR 贡献:§meter-tool-routing(toolKind 路由 schema)+§measurement-node(7 类 MeasurementNode schema))
10.4 关联输入文件
- 用户起稿:本文件 §附录 A(原路径 912 行 · v1 完整保留)
- Demo HTML:
d:/work/25_claude/workspace/AlgoDepartment/04_development/frontend_vue3/docs/superpowers/specs/xitest-realtime-ui-demo.html(1225 行 · 单 widget 4 tab 示意) - 现有实装:
04_development/frontend_vue3/src/stages/xitest/**(P4.U3 zombie · ceecccf · realtime+regression mode 2+3 stub) - 后端基础:
04_development/backend_csharp/Routes/MeterDevApiRoutes.cs+Services/Meter/*(P5.U-meter-source-tap zombie · 4adda88)
11. 决议者签名(Approvers)
- 拍板:用户(2026-05-29 12:06 默认推荐 · 1A + 2是 + 3按MeasurementNode展开 · 1500 行特批 · 12:10 处置方案 1)
- 起草:Cline-AIOS · cwd=
d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/ - 真值核查:Cline-AIOS read 4 输入文件全文(用户起稿 912 行 + Demo HTML 1225 行 + ADR-10 + ADR-07 §1-§3)
- 后续修订:任何修改本 ADR 必须先 fork ADR-AIOS-12-RX(R = Revision)子进程
本 ADR 落地 = AIOS v7 OS 化模型下"业务行为契约必填段"标杆示范 · 回应用户 2026-05-28 "业务深度系统性缺失"诊断 · 后续所有 ADR 模板对齐本 ADR §3 5 项契约 · 杜绝"壳子框架"。
附录 A · 用户起稿(2026-05-29 · 912 行 · 22 节功能清单)
以下为用户 2026-05-29 上午起草的原始文档全文,保留作为本 ADR 决议的设计依据。Cline-AIOS v2.0 决议(§1-§11)基于本附录提炼,并补充 Demo HTML(MVP 单 widget 切片)+ ADR-07 三层分工铁律 + 业务行为契约必填段。
A.1 产品定位
XiTest / Realtime:
不是单纯频谱工具。
不是单纯录音工具。
不是单纯示波器。
其本质定位:
"实时音频测量与工程化验证工作台"
需要同时满足:
| 场景 | 目标 |
|---|---|
| 实时调音 | 实时频响 / 相位 / RMS |
| 台架验证 | THD / Delay / FR |
| 多通道验证 | Matrix / Overlay |
| 工程回归 | Golden Compare |
| E2E测试 | 流程化验证 |
| Integration测试 | 多模块协同 |
| 录音分析 | Waveform / Spectrogram |
| 自动化测试 | Task Flow |
因此:
XiTest 中所有测量组件必须统一为:
Realtime 只是:
Measurement Node 的实时可视化工作区
A.2 整体架构
A.2.1 XiTest 架构
XiTest
├── Realtime
├── Integration
├── E2E
├── Regression
├── Automation
├── Report
└── Measurement Engine
A.2.2 核心统一引擎
所有模块共享:
A.2.3 Measurement Node(核心抽象)
所有测量能力:FFT / RMS / THD / Transfer / Spectrogram / Frequency Response
统一抽象:Measurement Node
统一结构:
Measurement Node
├── Input
├── Processing
├── Measurement
├── Validation
├── Visualization
├── Automation
└── Storage
A.3 Realtime UI 总体结构
┌────────────────────────────────────────────────────────────┐
│ Top Toolbar │
├──────────────┬───────────────────────────────┬────────────┤
│ Left Dock │ Realtime Dashboard │ Right Dock │
│ Workspace │ │ Inspector │
│ Resources │ Widget-based Measurement │ Parameters │
│ Measurements │ Workspace │ │
├──────────────┴───────────────────────────────┴────────────┤
│ Bottom Dock │
│ Console | Device Status | XRUN | Measurement Log | Tasks │
└────────────────────────────────────────────────────────────┘
A.4 Top Toolbar(顶部工具栏)
只保留全局状态与全局操作 · 不放复杂配置 · 复杂参数统一放入 Left Dock / Right Inspector。
| 功能 | 说明 |
|---|---|
| Current Project | 当前工程 |
| Current Workspace | 当前工作区 |
| Realtime Status | 实时运行状态 |
| Record | 开始录制 |
| Pause | 暂停 |
| Snapshot | 当前测量快照 |
| Overlay | 曲线叠加 |
| Sync | 同步刷新 |
| Layout | 工作区布局 |
| Fullscreen | 全屏分析 |
A.5 Left Dock(左侧工作区)
工程资源中心 · 不是工具栏 · 而是 Workspace + Resource + Measurement 管理中心。
LEFT DOCK
├── Workspace
├── Session
├── Engine
├── Measurements
├── Recordings
├── Snapshots
├── Validation
└── Task Flow
A.6 Workspace(工作区)
Workspace 是最重要的概念之一,定义:窗口布局 + 测量组件 + 参数状态 + Overlay状态 + 通道状态。即 Workspace = 一整套实时分析环境。
Workspace 功能定义
| 功能 | 说明 |
|---|---|
| Save Workspace | 保存布局 |
| Load Workspace | 加载布局 |
| Export Workspace | 导出 |
| Share Workspace | 分享 |
| Clone Workspace | 克隆 |
| Lock Workspace | 锁定布局 |
Workspace Preset(系统预设)
1. Tuning Workspace:用于调音 · 布局 = Transfer + FFT + Phase + RMS
2. Electrical Workspace:用于 AP 类电信号分析 · 布局 = THD + SINAD + Scope + Generator
3. Recording Workspace:用于录音分析 · 布局 = Waveform + Spectrogram + Markers
4. Multi-channel Workspace:用于车载多通道 · 布局 = RMS Matrix + Delay Matrix + Phase Matrix
A.7 Session(实时会话)
代表当前实时工程环境。
| 功能 | 说明 |
|---|---|
| Device Profile | 当前设备 |
| Clock Status | 时钟状态 |
| Sample Rate | 采样率 |
| Buffer Size | Buffer |
| Routing | 通道路由 |
| Calibration | 校准 |
| Active Channels | 激活通道 |
A.8 Engine(输入输出引擎)
ENGINE
├── Physical Input
├── Playback Output
├── Generator
├── Virtual Loopback
├── CAN / RPM
└── Trigger
Physical Input:Device Select / Gain / Channel Map / Polarity / Delay / Calibration
Playback Output:Output Device / Volume / Mute / Solo / Output Routing
Generator:Sine / Pink Noise / White Noise / Chirp / Sweep / MLS / Multitone
A.9 Measurements(测量组件库)
所有测量组件都是 Measurement Node · 支持拖拽 / 复用 / 流程化 / 自动化 / Pass-Fail。
MEASUREMENTS
├── Time Domain
├── Frequency
├── Transfer
├── Electrical
├── Recording
├── Validation
└── Utility
A.10 Time Domain(时域组件)
Waveform Scope:Live Waveform / Trigger / Freeze / Buffer Replay / Zoom / Cursor
RMS Meter:实时 RMS(per-channel)/ Peak / LUFS / Crest Factor / Fast/Slow / Hold / Max/Min
Oscilloscope:XY Mode / Phase Scope / Lissajous / Trigger
A.11 Frequency(频域组件)
FFT Analyzer:FFT Size / Window / Average / Smoothing / Peak Hold / Overlay / Trace Store / Frequency Cursor
RTA:Octave / SPL Weighting / Average / Real-time Overlay
Spectrogram:Waterfall / Colormap / Time Scroll / Frequency Zoom
A.12 Transfer(Smaart 核心)
Transfer Function:Magnitude / Phase / Coherence / Delay Finder / Overlay / Golden Compare
A.13 Electrical(AP 核心)
Electrical Meter:Vrms / dBu / Frequency / THD / THD+N / SINAD / SNR
Sweep Analyzer:Log Sweep / Step Sweep / Chirp / MLS
A.14 Recording(录音组件)
Recorder:Multi-track / Loop / Marker / AB Compare / Snapshot / Buffer Cache
A.15 Validation(工程化验证)
所有组件必须支持 Pass / Fail。
| 功能 | 说明 |
|---|---|
| Threshold | 阈值 |
| Mask | 掩码 |
| Tolerance | 容差 |
| Golden Compare | Golden对比 |
| Delta Compare | 差异对比 |
| Result Export | 结果导出 |
A.16 Task Flow(工程核心)
XiTest 必须支持 流程化测试编排。
Test Flow 示例:Playback → RMS → THD → FR Compare → Pass/Fail
Flow Node 分类:
| 类型 | 说明 |
|---|---|
| Source Node | 输入/播放 |
| Measurement Node | FFT/THD |
| Validation Node | Compare |
| Logic Node | IF/WAIT |
| Export Node | Report |
A.17 Realtime Dashboard(中央区域)
中央区域 = Widget-based Workspace。
| 功能 | 说明 |
|---|---|
| Drag | 拖拽 |
| Resize | 缩放 |
| Dock | 停靠 |
| Float | 浮动 |
| Split | 分屏 |
| Fullscreen | 全屏 |
| Save Layout | 保存布局 |
| Multi-monitor | 多屏 |
Main Widget:FFT / Transfer / Waveform / THD / Spectrogram
Mini Widget:RMS / Peak / Clock / THD Numeric / Latency / CPU / XRUN
A.18 Right Dock(Inspector)
右侧 = 当前 Widget 参数面板。
Inspector 通用结构:Source / Measurement / Display / Validation / Automation / Storage
FFT Inspector:FFT Size / Window / Average / Overlap / Smoothing / Scale / dB Range / Overlay
Transfer Inspector:Ref Channel / Measure Channel / Delay Tracking / Coherence / Phase Wrap
Recorder Inspector:Buffer / Trigger / Pre-roll / Auto Save / File Format
A.19 Snapshots(测量快照)
Snapshot 保存:曲线 + 参数 + Overlay + 结果 + 布局
| 功能 | 说明 |
|---|---|
| Save Snapshot | 保存 |
| Compare Snapshot | 对比 |
| Golden Snapshot | Golden |
| Export Snapshot | 导出 |
A.20 Recordings(工程文件)
所有录音属于工程资源 · 支持回放 / 分析 / Overlay / Compare / Offline FFT。
A.21 Bottom Dock(底部状态栏)
Console:INFO / WARNING / ERROR / DEVICE / SCRIPT
Device Status:Clock Lock / Sample Rate / Buffer / XRUN / CPU
Task Queue:Recording / Export / Sweep / Regression
A.22 统一工程核心(最终核心)
XiTest 所有模块(Realtime / Integration / E2E / Regression / Automation)必须共享 5 引擎(Measurement / Validation / Task / Storage / Visualization)。
Realtime 只是 "工程化测量节点的实时观测模式"。
附录 A 结束 · 用户起稿(2026-05-29 上午 · 912 行)完整保留 · 是本 ADR 决议依据。