跳转至

P1.A21.F1-dock-host-generalize · XiLink 右 Dock Host 通用化(节点切换 + 通道自适应 + 刻度缩放)

Worker:ClaudeA · 部门:前端 P1-xilink · 预计:2.0d · 优先级:P0 关键路径起点 · 状态:dispatched · isolation:🧵 file(同 worktree 同 branch · 与 F3 dsp_algo / F5 dsp_algo 文件正交并行)

🔍 触发与解锁链

触发:用户 2026-06-13 09:55 提 5 点新需求 #1(右 dock meterdrawer 通用化)· 12:51 拍板 accept ADR-21 · 14:15 拍板 start F1+F3+F5 三连。

用户原话(verbatim · ADR-21 §1.1):

"1. 右侧 dock 接入的 meterdrawer · 在可以显示信号的基础之上需要能够识别当前链路中的节点,并且进行切换,比如所有的 source · sink · 还有就是 log_module_v1;选择链路固定的节点后,可以正确显示该节点的通道数量,做到可以切换;关于界面设计横纵坐标的需要有可以放大缩小的刻度操作;"

架构契约(ADR-21 §3.1 ① 输入/输出契约 · 业务契约 5 必填段全填): - DockHost 接收 ChainNodeRef metadata(nodeId / nodeKind / channelCount / sampleRate / position) - 节点切换 selector 复用 ADR-17 F6 widget endpoint 4 类(physical-input / sink-pre / log-module / xitune-module)+ 加 xilink-module 第 5 类(本 ADR 新增) - channelMask boolean[] 长度 === selectedNode.channelCount(动态) - scaleX/scaleY 单位由 module 决定(fft = Hz/dBFS · scope = ms/V · phase = Hz/° · transfer = Hz/dBFS)

解锁链(本任务 zombie 后): - F2 fft/scope 控件增强 ready(blocked-by-F1) - F4 phase-module 前端 ready(blocked-by-F1+F3) - F6 transfer-module 前端 ready(blocked-by-F1+F5)

任务定义(基于 ADR-21 §3.1)

子任务 ① · DockHost.vue 通用化(0.6d)

Step 1.1:NEW(或重构现有)frontend_vue3/src/stages/xilink/dock/DockHost.vue: - props:{ moduleId: string; supportedNodeKinds: NodeKind[]; defaultNodeId?: string } - 顶部插槽:DockNodeSelector(节点切换下拉)+ DockChannelToggle(通道开关)+ DockScaleControl(刻度滚轮 hint) - 中部插槽:<slot name="canvas" :input="dockModuleInput" />(module 自渲染 canvas) - 底部插槽:<slot name="controls" />(module 自定义控件如 fft displayMode) - 严守 ADR-21 §3.1 ② 性能基线:节点切换 < 150ms · FPS ≥ 30(scope/fft)/ ≥ 60(meter)· 多 module 并存 ≥ 3 不降帧

Step 1.2:DockHost 内部 reactive state: - selectedNodeId: Ref<string> · 默认 defaultNodeId || 'sink-pre' - channelMask: Ref<boolean[]>(长度 = selectedNode.channelCount · 默认全 true) - scaleX/scaleY: Reactive<{min, max}>(单位由 module 决定 · 通过 props.unit 注入) - 5 类失败回退(ADR-21 §3.1 ③):节点不存在 fallback 到 sink-pre / channelMask 全关显示提示 / 刻度越界 swap / 渲染异常红 X / channelCount 突变重置 mask

子任务 ② · DockNodeSelector.vue 节点切换(0.4d)

Step 2.1:NEW frontend_vue3/src/stages/xilink/dock/DockNodeSelector.vue: - 复用 ADR-17 F6 widget endpoint selector(78dc17c · 4 类)+ 加 xilink-module 第 5 类 - props:{ supportedNodeKinds: NodeKind[]; modelValue: string }(v-model) - emit:update:modelValue - 内部:el-select 下拉 · option 按 nodeKind 分组(source / sink / log_module_v1 / xitune-module / xilink-module) - 数据源:从 chainStore 查所有 ChainNodeRef · 过滤 supportedNodeKinds - ADR-21 §3.1 ④ 用户操作流 Step 2-3:default 'sink-pre' · 切到 log_module_v1 自动显示 channelCount

Step 2.2:useChainNodeMetadata.ts composable(NEW): - 接口:useChainNodeMetadata(nodeId: Ref<string>) → 返回 reactive ChainNodeRef - 从 chainStore.nodes 查 + watch nodeId 变化重查 - 暴露 channelCount / sampleRate / position 字段供 DockHost 用

子任务 ③ · useDockScale.ts 刻度缩放(0.4d)

Step 3.1:NEW frontend_vue3/src/stages/xilink/dock/useDockScale.ts: - 接口:useDockScale(canvasRef, { initialScaleX, initialScaleY, axisUnit: 'Hz'|'ms'|'sample' }) - 滚轮事件:1 刻度 = 10% zoom(中心点保持)· clamp 上下限 - ResizeObserver 监听 canvas 容器 · debounce 100ms 触发 redraw 信号 - 返回 reactive { scaleX, scaleY, onWheel, onResize, redrawKey }

Step 3.2:scaleY swap fallback(ADR-21 §3.1 ③):若 scaleY.min > scaleY.max 自动 swap(无感恢复)

子任务 ④ · useDockChannelMask.ts 通道开关(0.3d)

Step 4.1:NEW frontend_vue3/src/stages/xilink/dock/useDockChannelMask.ts: - 接口:useDockChannelMask(channelCount: Ref<number>) → reactive { mask: boolean[], toggle(idx), allOn(), allOff() } - watch channelCount 变化:若新长度 ≠ 旧长度 → 重置全 true(ADR-21 §3.1 ③ "channelCount 突变重置 channelMask") - channelMask all false 时 emit 'no-channel-selected' 信号给 DockHost(显示 "No channel selected" 提示)

子任务 ⑤ · 现有 fft/scope/rms module 接入回归(0.2d)

Step 5.1:read 现有 ADR-18 F5 落地的 4 popup(RMSMeterModulePopup / ScopeModulePopup / FftModulePopup / LogModulePollingPanel · 769405a)+ ADR-18 F7 DSP 算法层(c099772 · 输出 ChainNodeRef + frame)· 改造接入 DockHost 插槽(<slot name="canvas"> + <slot name="controls">不破坏现有渲染逻辑

Step 5.2:vitest 回归 ADR-18 F5 + F7 落地基线(152 case)零回归

子任务 ⑥ · 测试(0.1d)

Step 6.1:vitest 加 ≥ 6 case(ADR-21 §3.1 ⑤ playwright e2e 模板对齐): - DockHost props.supportedNodeKinds 渲染 selector 正确 5 类 - DockNodeSelector 切换 source → log_module_v1 · channelCount 从 2 切到 4 · channelMask 重置全 true - useDockScale 滚轮 zoom 中心点保持 + clamp 上下限 - useDockChannelMask 通道开关 toggle / allOn / allOff - channelCount 突变 → channelMask 重置(ADR-21 §3.1 ③) - 节点不存在 fallback 到 sink-pre + 提示文案

Step 6.2:F8 ADR-15(ClaudeA 排队中 · 0.5d 估近 zombie)+ ADR-18 F5 + ADR-17 F6 基线零回归

完整 prompt(直接复制粘贴 ClaudeA 终端)

[U-thread] P1.A21.F1-dock-host-generalize · ADR-21 §3.1 DockHost 通用化(关键路径起点)
[部门] 前端 P1-xilink
[Worker CWD] d:/work/25_claude/workspace/AlgoDepartment/04_development/
[Occupies] P1.K-shared-xilink-dock + P0.K-shared-types
[优先级] P0(2.0d · 关键路径起点 · 解锁 F2/F4/F6 全部前端 fork)
[ADR] docs/08-implementation/40-aios/ADR/ADR-AIOS-21-xilink-dock-and-analysis-modules.md(必读 §3.1 + §1.4 边界铁律)
[isolation] file(同 worktree 同 branch · 与 F3 dsp_algo / F5 dsp_algo 文件正交并行)

[参考文档绝对路径]
  - 业务契约:ADR-21 §3.1 完整 5 必填段(① ChainNodeRef + DockModuleInput 接口 / ② 性能阈值 / ③ 5 类失败回退 / ④ 5 步操作流 / ⑤ playwright e2e 模板)
  - 用户 2026-06-13 09:55 拍板原话(ADR-21 §1.1):节点切换 source/sink/log_module_v1 + 通道数自适应 + 横纵刻度缩放
  - 范式 commits(worker 必读):
    * 78dc17c P0.A17.F6 widget endpoint selector 4 类(本任务复用 + 加 xilink-module 第 5 类)
    * 769405a P0.A18.F5 IP 库 + 4 popup(本任务 host 接入这些 popup)
    * c099772 P_dsp.A18.F7 DSP 算法层 dspalgo_dll(本任务 host 渲染其输出 frame)
  - 现状参考:
    * frontend_vue3/src/stages/xilink/dock/(现有 dock 基础 host · 本任务通用化升级)
    * frontend_vue3/src/components/popups/{RMSMeter,Scope,Fft}ModulePopup.vue(F5 现有 popup · 本任务接入插槽)
    * frontend_vue3/src/stores/chainStore.ts(节点 metadata 真值源 · ChainNodeRef 字段查询)
    * frontend_vue3/src/composables/useWidgetEndpointSelector.ts(F6 78dc17c · 复用 selector 模型)
  - 三层分工:ADR-07 §1.3.4(L3 前端零数学 · 本任务纯 UI 渲染 + 滚轮事件 · 不做 DSP 计算)

[文件正交策略](.clinerules §任务隔离类型分配准则 v1.4):
  isolation: file · 同 worktree 同 branch · 与 F3 / F5 并行 push 拉合并
  本任务文件:frontend_vue3/src/stages/xilink/dock/{DockHost.vue + DockNodeSelector.vue + useDockScale.ts + useDockChannelMask.ts} + composables/useChainNodeMetadata.ts
  F3 文件:dsp_algo/modules/phase_module/* + dspalgo_dll.c 加 phase export(完全正交)
  F5 文件:dsp_algo/modules/transfer_module/* + dspalgo_dll.c 加 transfer export(完全正交)
  完全正交 · 不冲突

【背景】
  用户 2026-06-13 09:55 提 5 点新需求中 #1:右 dock meterdrawer 通用化 + 节点切换 + 通道数自适应 + 横纵刻度缩放。
  ADR-21 accepted 2026-06-13 12:51 · 7 fork 13d · 本任务 F1 是关键路径起点(解锁 F2/F4/F6 全部前端 fork)。
  ADR-18 已落地 rms/scope/fft 三个 module + log_module(F5 769405a)+ DSP 算法层(F7 c099772)· 但 dock host 仅基础接入 · 没做"节点 selector + 通道适配 + 刻度缩放"通用化。
  本任务升级 host · **不破坏现有 module 渲染逻辑** · 通过插槽机制接入 fft/scope/rms/log/phase/transfer 6 类 module。

【架构关键约束】
  ⚡ 节点切换 5 类:source / sink / log_module_v1 / xitune-module / xilink-module(第 5 类是本 ADR 新增 · 复用 ADR-17 F6 4 类 + 扩 1)
  🎨 通道数自适应:从 ChainNodeRef.channelCount 动态读 · 切节点时 channelMask 重置全 true · UI 通道开关数量动态
  📋 横纵刻度缩放:滚轮 1 刻度 = 10% zoom(中心点保持)+ ResizeObserver 触发 redraw + 单位由 module 决定(unit prop 注入)
  📋 三层分工:L3 前端零数学(本任务纯 UI 渲染 + 滚轮事件 · 不做 FFT/RMS/STFT 计算)
  📋 F1 范围与下游 fork 边界:本 F1 仅做 host 通用化 + 现有 module 接入回归 · **不实装 phase/transfer module 本体**(那是 F4/F6 范围 · 等 F3/F5 算法 zombie)
  ⚡ ADR-21 §1.4 铁律:phase/transfer 计算在 dsp_algo(L1 算法库)· 本任务前端仅消费 frame schema 渲染

【执行步骤】
  Step 0 · 文件注入真值核查(强制门槛 · F2 教训承接)
    - grep -r "DockHost" frontend_vue3/src/stages/xilink/dock/ · 确认现有 host 真签名
    - read frontend_vue3/src/composables/useWidgetEndpointSelector.ts(F6 78dc17c · 复用基础)
    - read frontend_vue3/src/components/popups/RMSMeterModulePopup.vue + ScopeModulePopup.vue + FftModulePopup.vue(F5 769405a · 接入目标)
    - grep "channelCount" frontend_vue3/src/stores/chainStore.ts · 确认节点 metadata 字段
    - 留 commit log:Step 0 三层核查记录

  Step 1 · DockHost.vue 通用化 0.6d(子任务 ①)
    - 重构现有 host(若存在)· 否则 NEW · 加 supportedNodeKinds props + 3 插槽(canvas / controls / selector)
    - 5 类失败回退(ADR-21 §3.1 ③ 全覆盖)
    - 性能基线:节点切换 < 150ms · FPS ≥ 30 / ≥ 60

  Step 2 · DockNodeSelector.vue + useChainNodeMetadata.ts 0.4d(子任务 ②)
    - selector 5 类 + chainStore 节点查询 + 切换响应
    - useChainNodeMetadata watch nodeId 变化重查

  Step 3 · useDockScale.ts 刻度缩放 0.4d(子任务 ③)
    - 滚轮 zoom 中心点保持 + clamp + ResizeObserver
    - axisUnit 注入(Hz/ms/sample · module 自定义)

  Step 4 · useDockChannelMask.ts 通道开关 0.3d(子任务 ④)
    - watch channelCount 变化重置 mask
    - allOn / allOff / toggle API

  Step 5 · 现有 module 接入回归 0.2d(子任务 ⑤)
    - 改造 RMSMeterModulePopup / ScopeModulePopup / FftModulePopup 接入 DockHost 插槽
    - **不破坏现有渲染逻辑** · 仅 wrap 一层 host
    - vitest 回归 ADR-18 F5 + F7 + ADR-17 F6 基线 152 case 零回归

  Step 6 · 测试 + 类型/构建/测试全绿 0.1d(子任务 ⑥)
    - vitest 加 ≥ 6 case
    - vue-tsc --noEmit 0 errors
    - npm run build 0 errors
    - npm run test 全过(基线 + 6 新增)

  Step 7 · 浏览器实测 + commit
    - 启动 backend(dotnet run)+ frontend(npm run dev)
    - 验收点(ADR-21 §3.1 ④ 用户操作流):
      ☐ 进入 xilink stage · 右 dock 点 "+ fft-module"
      ☐ Module 顶部 selector 默认 sink-pre · 显示 2 通道开关
      ☐ 切换到 log_module_v1 · 自动显示该 module channelCount(若 4)+ 4 通道开关
      ☐ 滚轮缩放横轴 0-22kHz → 100Hz-10kHz · canvas 即时重绘
      ☐ 拖拽 dock 高度 · ResizeObserver 触发重绘 · 30fps 保持
      ☐ 切换到不存在节点 · fallback 到 sink-pre + 提示文案
    - git add . && git commit -m "feat(xilink/dock): P1.A21.F1 DockHost 通用化(节点切换 5 类 + 通道自适应 + 刻度缩放)

      用户 2026-06-13 09:55 提 5 点新需求 #1 · 12:51 accept ADR-21 · 14:15 拍板 start F1+F3+F5 三连。
      F1 本任务(ADR-21 §3.1):
      ① DockHost.vue 通用化(supportedNodeKinds props + 3 插槽 + 5 类失败回退)
      ② DockNodeSelector.vue 节点切换 5 类(复用 ADR-17 F6 + 加 xilink-module)+ useChainNodeMetadata composable
      ③ useDockScale.ts 滚轮缩放 + ResizeObserver(中心点保持 + clamp + axisUnit 注入)
      ④ useDockChannelMask.ts 通道开关(watch channelCount 重置 + toggle/allOn/allOff)
      ⑤ 现有 RMS/Scope/Fft popup 接入 DockHost 插槽(零回归 152 case)
      ⑥ vitest +6 case · vue-tsc + build 全绿
      解锁 F2 控件增强 + F4 phase-module 前端 + F6 transfer-module 前端

      [step=7/7] [pid=P1] [uid=P1.A21.F1-dock-host-generalize] [type=fork] [isolation=file]
      [occupies=P1.K-shared-xilink-dock+P0.K-shared-types] [files=5] [ipc=rest+ws-ready]
      [adr=ADR-AIOS-21 §3.1 DockHost 通用化(#1 节点切换+通道自适应+刻度缩放)]"

【验收】
  ☐ Step 0 文件注入真值核查通过(grep + read 4 个标本 + chainStore channelCount 字段确认)
  ☐ Step 1 DockHost.vue 通用化 · 5 类失败回退全覆盖 · 性能基线达标(< 150ms / ≥ 30fps)
  ☐ Step 2 DockNodeSelector 5 类切换 · useChainNodeMetadata watch 重查正确
  ☐ Step 3 useDockScale 滚轮 zoom 中心点保持 + clamp + ResizeObserver redraw
  ☐ Step 4 useDockChannelMask channelCount 突变重置 + 全关提示信号
  ☐ Step 5 现有 RMS/Scope/Fft popup 接入插槽 · ADR-18 F5+F7 + ADR-17 F6 基线 152 case 零回归
  ☐ Step 6 vitest +6 case 全过 · vue-tsc + build 0 errors
  ☐ Step 7 浏览器实测 6 验收点全过(ADR-21 §3.1 ④ 操作流端到端)
  ☐ commit message 含 7 元组 trailer + ADR §3.1 引用

【禁止】
  ❌ 禁止跳过 Step 0 文件注入核查(F2 教训:派发前必须 grep + read 4 标本 + chainStore 字段确认)
  ❌ 禁止在前端做 DSP 数学(三层分工 · phase/transfer 计算在 F3/F5 dsp_algo · 本任务仅 UI 渲染)
  ❌ 禁止把 DockHost 设计成"破坏式重构"(必须保留现有 RMS/Scope/Fft popup 渲染逻辑 · 仅 wrap 一层插槽)
  ❌ 禁止超前实施 phase-module / transfer-module 本体(那是 F4/F6 范围 · 本 F1 仅做 host)
  ❌ 禁止破坏 ADR-18 F5 + F7 + ADR-17 F6 已锁 152 case 基线(零回归是硬门槛)
  ❌ 禁止跳过 vitest +6 case(验收硬门槛)
  ❌ 禁止 commit 缺三元组 trailer(.clinerules v1.6 铁律)
  ❌ 禁止嵌入完整 SFC > 60 行 / TS interface > 5 行(.clinerules v1.6)· 拆 child component 或 v-if 渲染分支

解锁链(本任务 zombie 后)

  • ✅ DockHost 通用化完成 · 5 类节点切换 + 通道自适应 + 刻度缩放 UX 上线
  • ✅ ADR-18 现有 4 popup 接入新 host(零回归)
  • ✅ F2 fft/scope 控件增强 ready(ClaudeA 1.5d · 接 displayMode/peakHold/peakTrack)
  • ✅ F4 phase-module 前端 ready(blocked-by-F1+F3 · 等 F3 zombie 后 ClaudeA 1.5d)
  • ✅ F6 transfer-module 前端 ready(blocked-by-F1+F5 · 等 F5 zombie 后 ClaudeA 2.0d)

风险评估

风险 缓解
现有 dock host 重构破坏 ADR-18 F5 已落地 popup 渲染 Step 0 强制 grep + read 4 popup 真签名 + Step 5 vitest 回归 152 case 零回归 + 插槽机制保持渲染逻辑不变
ChainNodeRef metadata 字段在 chainStore 不齐(channelCount 缺失) Step 0 grep "channelCount" 确认 · 若缺则 fork 内补丁(append-only · 不破坏现有字段)+ ADR-21 §3.1 ① 锁定 schema
滚轮 zoom 中心点保持算法易错 Step 3 用 canvas pointer event clientX/Y → 数据坐标变换 · 仿现有 SpectrumChart 做法 · 单测 zoom 1.5x 后 hover 点不变
ResizeObserver debounce 100ms 与 30fps 冲突 RAF 节流 + ResizeObserver debounce 串联 · 测试 5 instance 同 stage 不掉帧
5 类节点切换 selector 与 ADR-17 F6 4 类冲突 复用 useWidgetEndpointSelector composable · 加第 5 类 xilink-module 用 prop 注入(向后兼容)
ClaudeA 排队膨胀(F8 0.5d ADR-15 + 本 F1 2.0d + 后续 F2/F4/F6 共 5.5d 串行) F8 估近 zombie · 本 F1 是关键路径起点不可让 · 后续 F2 与 F3 dsp_algo 文件正交可并行
F3/F5 dsp_algo 输出 frame schema 与本任务 host 数据流契约不一致 ADR-21 §3.3/§3.4 ① 已锁定 frame schema(MeterFrame_Phase / MeterFrame_Transfer · 复用 ADR-12 §3.4/§3.3)· 跨栈一致

历史

时间 事件 hash
2026-06-13 14:16 dispatched(用户 14:15 拍板 start F1+F3+F5 三连 · ClaudeA 关键路径起点 2.0d)