P0.U-engine-session-snapshots · ADR-12 LeftDock § Engine + Session + Snapshots 三段实施
Worker:ClaudeC · 前端 / 部门:前端 P0-xishell / 预计:2.0d / 优先级:P1 / 状态:ready
🔍 触发与解锁链
- 触发:ADR-12 Phase 3 #10 未派 · 用户拍板方向 3(本 fork + #11 + Recorder 真业务 · 总 5.5d 最激进并行)。LeftDock 框架(
a7df354)已就位 · § Workspace + Measurements 2 段已实装 · 但 § Engine + Session + Snapshots 三段仍是占位。 - 解锁条件:本 fork zombie 后,ADR-12 §6.2 Phase 3 通过条件之一(LeftDock 8 段全部可见)达标 · 整体 ADR-12 进度从 75% → 85%。
任务定义(基于 ADR-AIOS-12 v2.3 §5.3 #10 + §A.7/§A.8/§A.19 + §2.11 全局红线)
LeftDock 8 段(Workspace / Session / Engine / Measurements / Recordings / Snapshots / Validation / Task Flow)中本 fork 实施 3 段:
核心范围: 1. § Engine(对齐 §A.8):Physical Input(Device Select + Gain + Channel Map + Polarity + Delay + Calibration)+ Playback Output(Output Device + Volume + Mute + Solo + Output Routing)+ Generator schema 占位(Sine/Pink/Chirp/MLS/Multitone · UI 留下季度 · §4.3 Non-Goals) 2. § Session(对齐 §A.7):Device Profile + Clock Status + Sample Rate + Buffer Size + Routing + Calibration 状态 + Active Channels(只读视图 · 数据来源 P5 WS Device Status) 3. § Snapshots(对齐 §A.19):Save Snapshot(曲线 + 参数 + Overlay + 结果 + 布局)+ Compare Snapshot A↔B(双曲线模式)+ Golden Snapshot(参考基线)+ Export Snapshot(.json 导出)· 跨 widget 共享
🚨 全局红线对齐(ADR-12 §2.11 第 8+9 项 · 用户拍板 2026-05-30 12:50):
- 响应式横竖屏:LeftDock 三段使用 ResizeObserver 监听容器宽度 · 横屏(宽 ≥ 高)= 完整三段并列展开 / 竖屏(高 > 宽)= 三段折叠为可滚动列表
- 主题色系切换:严禁硬编码 hex · 必须 var(--xs-leftdock-*) design-token · 在 design-tokens.css 新增 token 段
完整 prompt(直接复制粘贴 worker 终端)
[U-thread]: P0.U-engine-session-snapshots
[部门]: 前端 P0-xishell
[Worker CWD]: d:/work/25_claude/workspace/AlgoDepartment/04_development/
[Occupies]: P0.K-shared-meter-dock · P5.K-meter-tap(read)
[优先级]: P1 · 2.0d
[ADR]: docs/08-implementation/40-aios/ADR/ADR-AIOS-12-xitest-realtime-arch.md(v2.3)
[业务行为契约引用]: ADR-12 §5.3 Phase 3 #10 + §A.7/§A.8/§A.19 + §2.11 第 8+9 项全局红线 + v2.3 前后端责任边界
[参考文档]:
- ADR-AIOS-12 §5.3 Phase 3 实施清单 #10(本 fork 主依据)
- ADR-AIOS-12 §A.7 Session(实时会话 · 7 字段)+ §A.8 Engine(I/O 引擎 · 6 子节)+ §A.19 Snapshots(4 操作)
- ADR-AIOS-12 §2.11 第 8+9 项全局红线(响应式横竖屏 + 主题色系切换)
- ADR-AIOS-12 §4.3 Non-Goals(Generator UI 留下季度 · Multi-monitor schema 留 UI 不做 · 本 fork 严守)
- 已就位 LeftDock 框架(a7df354):frontend_vue3/src/stages/xitest/leftDock/(LeftDock.vue + WorkspacePanel.vue + MeasurementsPanel.vue · 8 段路由已留 placeholder)
- 已就位 P5 Device Status WS(48cf0ba · MeterTapService 推送 WASAPI 状态)
- 已就位 8379de2 / 554ddd1:design-token --xs-* 模板 + 横竖屏 e2e 风格
【背景】
ADR-12 LeftDock 框架已就位(`a7df354` Phase 1 闭环)· 8 段路由 placeholder 已留 · 本 fork 实装 § Engine + § Session + § Snapshots 三段。
§ Engine = I/O 设备配置(Physical Input / Playback Output)· 数据来源 P5 WASAPI device list(已就位)· 通道映射 + Calibration 状态 stub(校准算法留下季度)。
§ Session = 当前会话只读视图 · 时钟 / 采样率 / Buffer / XRUN 等 · WS 推送(P5 已就位)· 不写 P5。
§ Snapshots = 跨 widget 测量快照 · 用 Storage Engine localStorage(若 #11 还没就位 · 用临时 in-memory store + commit trailer `[need:storage-engine]`)。
【执行步骤】(7 步)
Step 1 · types schema 扩展(0.2d)
- frontend_vue3/src/types/engine.ts(新增):
interface PhysicalInput { deviceId: string; deviceName: string; gainDb: number; channelMap: ChannelMap; polarity: 'normal' | 'invert'; delayMs: number; calibrated: boolean }
interface PlaybackOutput { deviceId: string; deviceName: string; volumeDb: number; mute: boolean; solo: boolean; routing: ChannelRouting }
interface GeneratorConfig { type: 'sine' | 'pink' | 'white' | 'chirp' | 'sweep' | 'mls' | 'multitone'; params: Record<string, number> } // schema only · UI 留下季度
- frontend_vue3/src/types/session.ts(新增):
interface SessionState { deviceProfile: string; clockStatus: 'locked' | 'unlocked' | 'free'; sampleRate: number; bufferSize: number; routing: string; calibrated: boolean; activeChannels: number[] }
- frontend_vue3/src/types/snapshot.ts(新增):
interface Snapshot { id: string; widgetId: string; type: SnapshotType; data: unknown; params: unknown; capturedAt: number; tag?: 'A' | 'B' | 'golden' }
type SnapshotType = 'fft' | 'rms' | 'transfer' | 'phase' | 'waveform' | 'electrical' | 'spectrogram' | 'impulse'
Step 2 · § Engine UI(0.5d · ADR §A.8)
- 新增 stages/xitest/leftDock/EnginePanel.vue
- 子段 1:Physical Input(下拉 device list + Gain slider + Channel Map 8 通道 + Polarity ± + Delay ms + Calibration 状态 ● / ○)
- 子段 2:Playback Output(下拉 device list + Volume + Mute / Solo · 不实装 Output Routing 详细 UI · 留 stub)
- 子段 3:Generator schema 占位(灰显 · tooltip "UI 留下季度 · §4.3 Non-Goals" · §A.8 子节预留)
- useEngineConfig.ts composable:订阅 P5 device list WS(已就位 toolKind=device-status)· emit on-change 给 P5
Step 3 · § Session UI(0.3d · ADR §A.7)
- 新增 stages/xitest/leftDock/SessionPanel.vue
- 7 字段网格:Device Profile / Clock Status(badge 颜色)/ Sample Rate / Buffer Size / Routing / Calibration 状态 / Active Channels(8 dot)
- useSessionState.ts composable:订阅 P5 Device Status WS · 自动 reactive 更新
- 严禁修改 P5 字段(只读视图)
Step 4 · § Snapshots UI + Storage(0.5d · ADR §A.19)
- 新增 stages/xitest/leftDock/SnapshotsPanel.vue
- 列表渲染所有快照 · 行操作:[A] / [B] / [Golden] / [Compare] / [Export] / [Delete]
- useSnapshots.ts composable:
- if (storageEngine 已就位):用 localStorage / IndexedDB
- else:用 in-memory Map(Pinia store · 本 session 内有效 · #11 zombie 后切换)
- Compare 模式:选中 A + B → 跳转主画布 widget 渲染双曲线对比
- Export:下载 .json(包含 data + params + capturedAt)
- Save:从 currentSelectedWidget 抓 freezeFrame() → 存入 store
Step 5 · 响应式横竖屏(0.2d · 全局红线 #1)
- LeftDock 容器用 ResizeObserver 监听
- aspectRatio ≥ 0.5(宽屏):三段并列垂直展开 · 默认 EnginePanel + SessionPanel 同时可见 · SnapshotsPanel 折叠为可点开
- aspectRatio < 0.5(竖屏 LeftDock 拉窄):三段全折叠为 accordion · 用户点击展开
- widgetLayoutStore.orientation 派生 state 联动(若已存在)
- vitest case × 2(横竖屏渲染验证)
Step 6 · 主题色系 design-token(0.2d · 全局红线 #2)
- 全组件 grep "#[0-9a-fA-F]\{3,8\}" 应 0 命中
- design-tokens.css 新增 token 段:
--xs-leftdock-bg / --xs-leftdock-border / --xs-leftdock-section-title
--xs-engine-input-active / --xs-engine-output-mute / --xs-engine-calibrated-ok / --xs-engine-calibrated-pending
--xs-session-clock-locked / --xs-session-clock-free / --xs-session-channel-active
--xs-snapshot-tag-a / --xs-snapshot-tag-b / --xs-snapshot-tag-golden
- playwright 主题切换 e2e(浅色 / 深色 截图对比 · maxDiffPixels: 100)
Step 7 · 自查 + commit(0.3d)
- npm run typecheck 全绿
- npm run test:unit 不退化(基线 356/3)+ 新增 vitest case 全过(预计 +6)
- npm run test:e2e 不退化(已就位单点)
- grep "#[0-9a-fA-F]\{3,8\}" 在 EnginePanel.vue / SessionPanel.vue / SnapshotsPanel.vue · 应 0 命中
- grep "audio-data\|audio-buffer\|fft\|numpy" 在本 fork 改动文件 · 应 0 命中(沿用 ADR-07 §1.3.4 三层分工 · 前端零数学)
- commit subject: feat(P0.U-engine-session-snapshots): implement LeftDock Engine+Session+Snapshots 3 sections (responsive landscape/portrait + design-token theme · ADR-12 §5.3 #10)
- commit trailer 三元组:[step=7/7] [pid=P0] [uid=U-engine-session-snapshots] [occupies=P0.K-shared-meter-dock+P5.K-meter-tap-read] [files=stages/xitest/leftDock/{Engine,Session,Snapshots}Panel.vue,types/{engine,session,snapshot}.ts,composables/use{EngineConfig,SessionState,Snapshots}.ts,styles/design-tokens.css]
【验收】(stop 前必跑)
形式合规:
☐ npm run typecheck 全绿
☐ npm run test:unit 不退化 + 新增 6 case 全过
☐ npm run test:e2e 不退化(已就位单点)
☐ grep `#[0-9a-fA-F]{3,8}` 在 3 个 Panel.vue 中 0 命中
☐ grep `audio-data|audio-buffer|fft|numpy` 在本 fork 改动文件 0 命中(沿用三层分工铁律)
☐ design-tokens.css 已加 --xs-leftdock-* / --xs-engine-* / --xs-session-* / --xs-snapshot-* token
业务行为契约(端到端真值 · 必跑):
☐ § Engine 切换 device · P5 WS 收到 emit · device list 刷新
☐ § Session 时钟状态 badge 颜色随 P5 推送变化(locked → 绿 / free → 黄 / unlocked → 红)
☐ § Snapshots Save A → 主画布 widget 抓 freezeFrame · 存入 store · 列表显示
☐ § Snapshots Compare A↔B → 主画布 widget 切双曲线模式
☐ 横屏 1920×1080 vs 竖屏 1080×1920 三段布局正确切换(全局红线 #1)
☐ 主题切换浅色 ↔ 深色 · LeftDock 颜色变化(全局红线 #2)
【commit】
- subject + 三元组 trailer 见 Step 7
- 7 天宽限期内三元组缺失仅 warning · 6/2 起 strict mode 硬拒
【禁止】(7 项红线)
1. ❌ 禁止在前端实装 audio 数据处理 / FFT / RMS 计算(沿用 ADR-07 §1.3.4 三层分工 · 数学全交 P7)
2. ❌ 禁止硬编码 hex 色值(必须 var(--xs-*) design-token · 全局红线 #2)
3. ❌ 禁止跳过响应式横竖屏 e2e(必须 viewport 1920×1080 vs 1080×1920 各跑一次 · 全局红线 #1)
4. ❌ 禁止实装 Generator UI(留下季度 · ADR-12 §4.3 Non-Goals · schema 占位即可)
5. ❌ 禁止改 P5 后端任何接口(对齐 ADR-12 §2.11 v2.3 前后端责任边界 · 现有数据契约不变)
6. ❌ 禁止跳过 e2e 真值(必须 6 个断言 + 全局红线 #1#2)
7. ❌ 禁止与并行 fork P0.U-bottom-dock-storage(#11)抢同一文件(本 fork 仅在 stages/xitest/leftDock/ + types/ + composables/ + styles/design-tokens.css)
解锁链(本任务 zombie 后)
- ✅ ADR-12 §6.2 Phase 3 通过条件之一(LeftDock 8 段全部可见)达标
- ✅ § Snapshots 解锁后 ADR-12 §A.19 跨 widget 快照对比可用
- ✅ Storage Engine 切换接口预留(#11 zombie 后切换 localStorage / IndexedDB · 本 fork in-memory fallback 自动失效)
风险评估
| 风险 | 缓解 |
|---|---|
| #11 storage-engine 未就位时本 fork in-memory 失效 | Step 4 useSnapshots 自动 fallback in-memory · #11 zombie 后切换无感 · commit trailer [need:storage-engine] 备案 |
| LeftDock 容器宽度变化(用户调拖)与横竖屏切换冲突 | Step 5 ResizeObserver 防抖 200ms + widgetLayoutStore 联动 |
| design-token 命名空间与 #11 BottomDock 冲突 | Step 6 LeftDock 用 --xs-leftdock- 前缀 · BottomDock 应用 --xs-bottomdock- · 不重叠 |
| § Engine Calibration 真业务依赖 P5 设备校准 API(未实装) | Step 2 Calibration 状态用 stub(占位 ● / ○ · tooltip "校准算法留下季度")· 不阻塞 |
历史
| 时间 | 事件 | hash |
|---|---|---|
| 2026-05-31 14:26 | dispatched · 用户拍板方向 3 三 fork 全派(本 fork + #11 + Recorder 真业务) | — |