跳转至

P_e2e.U-phase4-truth · ADR-12 Phase 4 端到端真值 e2e 5 场景脚本(7 类 MeasurementNode 全验收)

Worker:ClaudeC · 测试编排 / 部门:前端 + 测试 / 预计:3.0d / 优先级:P1 / 状态:ready

🔍 触发与解锁链

  • 触发:ADR-12 Phase 3 主战场全闭环(#5/#6/#7/#10/#11 五 fork 全 zombie · 真业务组件就位)· §5.4 Phase 4 e2e 真值脚本可纳入 7 类 MeasurementNode 全验收。
  • 解锁条件:本 fork zombie 后 · ADR-12 §6.2 Phase 4 通过条件全部达标 · CI 环境 e2e 真值 5 场景全绿 · 替代历史形式合规测试。

任务定义(基于 ADR-AIOS-12 v2.3 §5.4 + §3 + §6.2)

ADR-12 §5.4 原范围 P0.U-task-flow-stub + e2e-truth 已被用户拆为 2 个独立 fork: - ✅ 本 fork(P_e2e.U-phase4-truth):聚焦 5 场景端到端真值 e2e 脚本编排(本 fork 主体 · 3.0d) - 🔮 候选:P0.U-task-flow-stub(LeftDock § Task Flow UI 入口 + BottomDock § Task Queue 占位 · 留独立 fork · 1.0d · 不阻塞本 fork)

核心范围(对齐 ADR-12 §3.1-§3.7 ⑤ 端到端真值段):

场景 信号注入 期望验证 涉及 MeasurementNode
Scene 1 · 8 通道粉噪 -20dBFS 同时向 8 通道注入 -20dBFS 粉噪(sample-accurate) 8 bar RMS 都在 -20±1dB RMS Meter(§3.1)
Scene 2 · 1kHz 正弦 -10dBFS physical-input ch0 注入 1kHz -10dBFS 正弦 FFT 1000Hz 峰值 ± 50Hz · ± 1dB / Phase 1kHz std < 5° / Electrical THD < 0.05% / SINAD > 60dB FFT(§3.2)+ Phase(§3.4)+ Electrical(§3.6)
Scene 3 · sink-pre PEQ +6dB@1kHz Q=2 加载 PEQ preset · 注入粉噪 -20dBFS · 选 sink-pre tap 1kHz 比 100Hz/10kHz 高 5~7dB FFT(§3.2)
Scene 4 · Transfer ch1 PEQ -3dB@1kHz ch0=参考粉噪 · ch1=PEQ -3dB 滤波后 Transfer mag 1kHz 显示 -3 ± 0.5dB · Delay Finder 锁定 Transfer Function(§3.3)
Scene 5 · 1kHz 方波 -6dBFS 触发 注入 1kHz 方波 + Trigger level=-10dBFS rising edge + preroll=20% Waveform buffer 含完整周期 · 46-50 samples @ 48kHz / Spectrogram 1kHz 全程 > -10dB Waveform Scope(§3.5)+ Spectrogram(§3.x)

🚨 全局红线对齐(ADR-12 §2.11 第 8+9 项 + 前后端责任边界 v2.3): - ✅ Scene 5 含响应式横竖屏 e2e(viewport 1920×1080 vs 1080×1920 各跑一次 · 全局红线 #1) - ✅ 各 Scene 含主题切换 e2e(浅色/深色 · 截图对比无颜色泄漏 · 全局红线 #2) - ✅ 后端无需新增任何接口适配(对齐 v2.3 前后端责任边界)

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

[U-thread]: P_e2e.U-phase4-truth
[部门]: 前端 + 测试编排
[Worker CWD]: d:/work/25_claude/workspace/AlgoDepartment/04_development/
[Occupies]: P0.K-shared-meter-dock(read)+ P5.K-meter-tap(read)+ P7.K-endpoints(read)
[优先级]: P1 · 3.0d
[ADR]: docs/08-implementation/40-aios/ADR/ADR-AIOS-12-xitest-realtime-arch.md(v2.3)
[业务行为契约引用]: ADR-12 §5.4 Phase 4 e2e 真值脚本 + §3.1-§3.7 7 类 MeasurementNode ⑤ 端到端真值段 + §6.2 Phase 4 验收 + §2.11 第 8+9 项全局红线 + v2.3 前后端责任边界
[参考文档]:
  - ADR-AIOS-12 §5.4 Phase 4 实施清单 + §3 业务行为契约 7 类 ⑤ 段(本 fork 主依据)
  - ADR-AIOS-12 §6.2 Phase 4 通过条件:e2e 真值 5 场景在 CI 中绿
  - 已就位标杆 zombie(对照仿写 e2e 风格):
    · 8379de2 · P0.U-measurement-rms-fft-phase(§3.1/3.2/3.4 三组件 + e2e 首落地标杆)
    · 600f0fc · P0.U-measurement-transfer-waveform(§3.3/3.5 真业务)
    · 729327c · P0.U-measurement-electrical-recorder-stub(§3.6/3.7 ① schema 占位)
    · 554ddd1 · P0.U-measurement-thd-snr(§3.6 Electrical APx500 真业务 + 全局 2 红线 e2e 标杆)
    · af945e2 · P0.U-measurement-impulse-spectrogram(§3.x IR + Spectrogram + 横竖屏 e2e)
  - 已就位测试基础:frontend_vue3/playwright.config.ts + e2e/ 目录(各 fork 已落 *-truth.spec.ts)
  - 已就位 P5/P7:48cf0ba(MeterTapService 7 toolKind 路由)+ 153a109(P7 5 端点)+ 4adda88(WASAPI sink-pre tap)

【背景】
ADR-12 Phase 3 主战场全闭环 · 7 类 MeasurementNode 中 5 类已落真业务(RMS/FFT/Phase/Transfer/Waveform/Electrical/IR/Spectrogram)+ 2 类 Recorder/Sweep stub。各 fork 已写自己的 e2e *-truth.spec.ts(单点验证)· 但缺乏**集成场景** e2e(用户真实工程化测试场景)。

本 fork 不写新 MeasurementNode · 仅编排 5 集成场景 e2e 脚本 · 同时验证多个 MeasurementNode 协同 + 全局红线 #1#2 · 替代历史形式合规测试(typecheck/build/test 仅 stub 数据)。

【执行步骤】(8 步)

Step 1 · 测试夹具基础设施(0.5d)
  - 路径:frontend_vue3/e2e/fixtures/(新增)
  - injectChannel(channel: number, signal: SignalSpec): Promise<void>
    支持的 SignalSpec:
    - { type: 'pink-noise', dbFs: number }
    - { type: 'sine', frequency: number, dbFs: number }
    - { type: 'square', frequency: number, dbFs: number }
    - { type: 'sweep', startHz: number, endHz: number, duration: number, dbFs: number }
  - injectStereo(refSpec, measureSpec): 双通道注入(Transfer 用)
  - loadPreset(presetName: string): 加载已就位 preset(peq-plus-6db-at-1khz-q2 · peq-minus-3db-at-1khz)
  - selectNode(node: 'sink-pre' | 'physical-input' | 'recording-replay'): 切 P5 tap 节点
  - selectChannels(channels: number[]): UI 触发通道选择
  - dragMeasurementToCanvas(type: MeasurementKind): 从 LeftDock 拖入对应 widget
  - 实现细节:dispatch DOM events + window.__xitestDebug 全局对象暴露 hook · 不碰真实 P7 数学

Step 2 · Scene 1 · 8 通道粉噪 RMS(0.4d · §3.1 ⑤)
  - 文件:e2e/scenarios/scene-1-rms-8ch-pink.spec.ts
  - 步骤:goto('/xitest?mode=realtime') → dragMeasurementToCanvas('rms-meter') → selectNode('physical-input') → selectChannels(0..7) → injectChannel(0..7, pink-noise -20dBFS)
  - 等稳定 8 帧:waitForFunction(() => getRmsAveragedCount() >= 8, timeout: 5000)
  - 真值断言:8 通道 rmsDb[i] 都在 [-21, -19] dB
  - 失败回退断言:WS 断 → bar 灰显 + 顶栏红点

Step 3 · Scene 2 · 1kHz 正弦多组件协同(0.5d · §3.1+§3.2+§3.4+§3.6)
  - 文件:e2e/scenarios/scene-2-1khz-sine.spec.ts
  - 步骤:载入 4 widget(RMS + FFT + Phase + Electrical)→ injectChannel(0, sine 1kHz -10dBFS)
  - FFT 真值:peakBinFreq ∈ [950, 1050] · peakDb ∈ [-11, -9]
  - Phase 真值:phase 1kHz std < 5° (跨 16 averaged)
  - Electrical 真值:frequency ≈ 1000 ± 5 · thd < 0.05% · sinad > 60dB
  - RMS 真值:peakHoldDb 稳定在 -10 ± 1dB

Step 4 · Scene 3 · sink-pre PEQ FFT(0.4d · §3.2 ⑤)
  - 文件:e2e/scenarios/scene-3-sink-pre-peq.spec.ts
  - 步骤:loadPreset('peq-plus-6db-at-1khz-q2') → injectChannel(0, pink-noise -20dBFS) → selectNode('sink-pre')
  - 等稳定 16 averaged
  - 真值:fftDbAt(1000) - (fftDbAt(100) + fftDbAt(10000)) / 2 ∈ [5, 7] dB
  - 边界:测量分辨率 resolution ≈ sampleRate / fftSize · Inspector 状态栏显示正确

Step 5 · Scene 4 · Transfer Function 双通道(0.5d · §3.3 ⑤)
  - 文件:e2e/scenarios/scene-4-transfer-peq.spec.ts
  - 步骤:loadWorkspace('tuning')(自动 4 widget 2x2)→ loadPreset('peq-minus-3db-at-1khz') → injectStereo(pink-ref, pink-via-peq) → configTransfer({ ref: 0, measure: 1 })
  - 等延时锁定:waitForFunction(() => isTransferDelayLocked(), timeout: 8000)
  - 真值:transferMagDb(1000) ∈ [-3.5, -2.5] dB · coherence(100~10kHz) > 0.7 · delayLocked === true
  - 失败回退:相干性过低(< 0.3)灰显 banner

Step 6 · Scene 5 · 方波触发 + 横竖屏 + 主题切换(0.6d · §3.5/§3.x + 全局红线 #1#2)
  - 文件:e2e/scenarios/scene-5-square-trigger-responsive.spec.ts
  - Step 5.1 触发抓波形:injectChannel(0, square 1kHz -6dBFS) → configWaveform({ triggerLevel: -10, edge: 'rising', preroll: 20 }) → 等触发 → 真值 periodSamples ∈ [46, 50] @ 48kHz
  - Step 5.2 Spectrogram:同时启 spectrogram widget · 真值 spectrogram[any timeFrame][bin@1000Hz] > -10dB · 持续 5s
  - Step 5.3 横竖屏(全局红线 #1):page.setViewportSize({ width: 1920, height: 1080 })→ 截图 → page.setViewportSize({ width: 1080, height: 1920 })→ 截图 · 断言两张截图布局合理(orientation 派生 state 切换)
  - Step 5.4 主题切换(全局红线 #2):toggle theme 'light' → 截图 → toggle 'dark' → 截图 · 断言截图色值差异(grep design-token 证明无硬编码)

Step 7 · CI 集成 + 性能基线(0.4d)
  - 在 frontend_vue3/playwright.config.ts 加 e2e:scenarios projects 配置
  - 加 npm script:`"test:e2e:scenarios": "playwright test e2e/scenarios"`
  - 运行所有 5 场景 · 总耗时 < 5min(单场景 < 1min · 包含夹具初始化)
  - GitHub Actions / 本地 CI 配置 README 更新(docs 在 04_development · 不动 06_docs)

Step 8 · 自查 + commit(0.2d)
  - npm run typecheck 全绿
  - npm run test:unit 不退化(基线 356/3)
  - npm run test:e2e 不退化(已就位 *-truth.spec.ts 全过)
  - npm run test:e2e:scenarios 5 场景全绿(总耗时记录在 commit body)
  - 验证已就位 5 fork zombie 的 *-truth.spec.ts 仍然全过(不破坏单点 e2e)
  - commit subject: feat(P_e2e.U-phase4-truth): add Phase 4 end-to-end truth scenarios (5 scenarios · 7 MeasurementNode coverage · global redline #1#2 viewport+theme · ADR-12 v2.3)
  - commit trailer 三元组:[step=8/8] [pid=P_e2e] [uid=U-phase4-truth] [occupies=P0.K-shared-meter-dock-read+P5.K-meter-tap-read+P7.K-endpoints-read] [files=e2e/fixtures/...,e2e/scenarios/scene-{1..5}-*.spec.ts,playwright.config.ts,package.json]

【验收】(stop 前必跑)

形式合规:
  ☐ npm run typecheck 全绿
  ☐ npm run test:unit 不退化(基线 356/3)
  ☐ npm run test:e2e(已就位单点)不退化
  ☐ npm run test:e2e:scenarios 5 场景全绿
  ☐ 总 e2e 耗时 < 5min
  ☐ playwright.config.ts 已加 scenarios projects 配置

业务行为契约(端到端真值 · 必跑 5 场景):
  ☐ Scene 1 · 8 通道粉噪 -20dBFS · 8 bar RMS ∈ [-21, -19] dB
  ☐ Scene 2 · 1kHz 正弦 · FFT/Phase/Electrical 4 真值断言全过
  ☐ Scene 3 · sink-pre PEQ +6dB@1kHz · FFT 1kHz 比 100Hz/10kHz 高 5~7dB
  ☐ Scene 4 · Transfer ch1 PEQ -3dB · transferMag(1kHz) ∈ [-3.5, -2.5] · 延时锁定
  ☐ Scene 5.1 · 方波触发 · period ∈ [46, 50] samples
  ☐ Scene 5.2 · Spectrogram 1kHz 全程 > -10dB
  ☐ Scene 5.3 · 横竖屏 viewport 1920×1080 vs 1080×1920 切换布局合理(全局红线 #1)
  ☐ Scene 5.4 · 主题切换浅色 ↔ 深色 · 截图色值变化(全局红线 #2)

【commit】
- subject + 三元组 trailer 见 Step 8
- 7 天宽限期内三元组缺失仅 warning · 6/2 起 strict mode 硬拒

【禁止】(7 项红线)
1. ❌ 禁止改任何已就位 MeasurementNode 真业务组件(本 fork 仅消费 + 编排 e2e · 不动 RMSMeter/SpectrumChart/PhaseChart/TransferChart/WaveformChart/ElectricalMeter/ImpulseResponse/Spectrogram 内部实现)
2. ❌ 禁止改 P5/P7 后端任何接口(对齐 ADR-12 §2.11 v2.3 前后端责任边界 · 现有数据契约不变)
3. ❌ 禁止跳过 5 场景任一(必须全跑 · 8 个真值断言全过)
4. ❌ 禁止跳过全局红线 #1#2 e2e(横竖屏 viewport + 主题切换截图必须包含)
5. ❌ 禁止用 stub mock 数据替代真实信号注入(必须用 injectChannel/injectStereo 真夹具 · 否则违反"e2e 真值替代形式合规"原则)
6. ❌ 禁止越界引入 stages/ 子目录代码(本 fork 仅在 e2e/fixtures/ + e2e/scenarios/ + playwright.config.ts + package.json)
7. ❌ 禁止实施 §5.4 task-flow-stub UI(LeftDock § Task Flow + BottomDock § Task Queue · 留独立小 fork)

解锁链(本任务 zombie 后)

  • ✅ ADR-12 §6.2 Phase 4 通过条件全部达标 · CI e2e 真值 5 场景全绿
  • ✅ 后续 ADR-12 R1 修订(若发生)新加 MeasurementNode 必须先在本 e2e/scenarios/ 加新场景或扩展现有场景
  • ✅ ADR-08 hotfix 4 fork zombie 后用户验收清单可纳入本 e2e 5 场景作为回归测试

风险评估

风险 缓解
injectChannel 测试夹具实现复杂度(需操作真实 audio device) Step 1 用 window.__xitestDebug 全局 hook 注入虚拟信号 + AudioWorkletNode mock · 不依赖真硬件 · 与已就位 8379de2 fixture 风格一致
5 场景总耗时超过 5min(playwright 启动慢) Step 7 配置 workers: 2 + projects 复用 browser context · 优化夹具初始化(共享 page 实例)
横竖屏 e2e viewport 切换闪烁(全局红线 #1) Step 6.5.3 加 page.waitForTimeout(500) 让 ResizeObserver 重新计算 · 截图前等 widgetLayoutStore.orientation 派生 state 稳定
主题切换 design-token 截图对比误差(全局红线 #2) Step 6.5.4 用 toMatchSnapshot 容差(maxDiffPixels: 100)· 不要求像素完全一致 · 仅断言主体色块差异
已就位 5 fork *-truth.spec.ts 与本 5 场景集成场景断言冲突 Step 8 验证已就位单点 e2e 仍全过 · 若有冲突则在 e2e/scenarios/ 加 .skip 跳过冲突场景 + commit trailer [need:fork-coordination]

历史

时间 事件 hash
2026-05-31 13:58 dispatched · ADR-12 Phase 3 全闭环后立即派发 · 用户拍板 start