# docs/rules/STATE.md —— 文档/代码同步任务状态(重写式维护) > 依据 CLAUDE.md「代码现状文档治理」:以本文件为唯一恢复点,状态变了就重写本文件,勿追加流水账。 > 老任务以「**完成态**记录」保留(不删,便于回溯),新任务以独立 H2 段落接续;本文件 ≈"任务帐本"。 ## 任务:dsh 升级到 0.1.5-rc.2 + 全版本兼容加固 + 0.7.7 发布 —— **已完成(2026-09-14,留作回溯基线)** ### 结果 - **dsh 升级**:0.1.5-alpha.2 → 0.1.5-rc.2(原子升级,`/mnt/work/upgrade-dsh-015rc2.sh`,STATUS: OK; `/voice-mode` 200、NRestarts=0、journal 0 错误关键字;子包依赖版本号 bump,代码层零变更)。 - **重验矩阵全绿(4 版本)**:check-anchors 0.1.1-rc.2 / 0.1.2-rc.1 / 0.1.5-rc.1 / 0.1.5-rc.2 全部 9/9; typecheck 四线 host+client 全过(8/8);四核心(`/tmp/dsh011-core`、`/tmp/dsh012-core`、 `/tmp/dsh015-core`、`/tmp/dsh015-rc2-core`)隔离冒烟全过;`npm test` 91/91。 - **线上 dsh 0.1.5-rc.2 真实 LLM 端到端**:24 audio 帧、0 tts-error(minimax / MiniMax-M3 模型)。 - **第一性原理深挖产出**(修正 compat-contract §7 错误认知): typert 描述符**逐端点差异化**——`session/list` 用 `args._request`(下划线开头); `session/create|prompt|cancel` 用 `args.request`;`settings/describe`、`llm/listProviders` 不嵌字段; 所有 `/api/*` 强制 `payload.args` 信封;method 字段与 path 同为斜杠形(rc.2 严格校验)。 - **代码同步**:devDeps 四类型包 → 0.1.5-rc.1(保持)+ cordis ^4.0.2(peerDeps 维持 ^4.0.1); `verify-dual.sh` 默认线从双版本扩到四版本;`typecheck-dual.sh` trap restore 同步备份/还原 pnpm-lock.yaml (之前只还原 package.json,跑完留有临时 lockfile——历史缺陷已修)。 - **兼容声明(Git + npm 双轨)**: - `package.json` engines.dsh = `">=0.1.1-rc.2"`(无上界;npm manifest 实证) - `package.json` description = 「0.1.1-rc.2 起全版本兼容,含 0.1.5-rc.2 端到端验证」 - `docs/compat-contract.md` §8 = 4 版本矩阵 + schema 实证表 - **0.7.7 已发布**: - git: 源码 `a3ec2f7`、发布 `2fc4e49`(BUILD_TAG=a3ec2f7)、tag `v0.7.7`、main 已 push - npm: `dsh-voice-mode@0.7.7`(tag=latest,覆盖 0.7.6),`npm view ... engines` 实证 `dsh: '>=0.1.1-rc.2'` - GitHub release: https://github.com/qishuilalala/dsh-voice-mode/releases/tag/v0.7.7 ### 后续触发点(已轮替为新任务) - 老任务已结束;继续监控点转交"**8 轮竞品调研 + 真实落地**"任务段 - 备份/回滚指针保留在下文,作为历史基线 ### 备份指针(保留为回溯参考) - dsh 全局回滚基线:`/mnt/work/dsh-0.1.5-alpha.2-pre-rollback-20260914-095242.tar.gz` - profile/skills/sessions 备份:`/home/www/.dsh/backups/profile-pre-0.1.5-rc.2-20260914-095314/`(338M) - 升级日志:`/mnt/work/upgrade-dsh-015rc2.log`、`/mnt/work/upgrade-dsh-015rc2.status` - 升级脚本:`/mnt/work/upgrade-dsh-015rc2.sh` - 历史对照:`/mnt/work/upgrade-dsh-015a2.sh`(0.1.2-rc.1 → 0.1.5-alpha.2)、`/mnt/work/dsh-0.1.2-rc.1-pre-rollback-20260910.tar.gz` --- ## 任务:8 轮竞品调研 + 真实落地(main 当前任务)—— **调研归档完成(2026-09-15);第 9 轮起开始真机落地** ### 结果 - **调研资产沉淀(6 轮 + 1 准备 + 1 收尾)**: - 18 份子代理深度报告(≈7,500 行),集中在 `docs/competitive/sources/scan-*.md` 与 `docs/findings/*.md` - 1 主扫描汇总 + 1 backlog(43 项 P0-P3,go/plan/blocked/drop 四档决策) - 2 真机对照审查 + 2 实施就绪设计稿 - 2 新 ADR:ADR-0007(emotion-tag DSL,提议)+ ADR-0004(WebSocket transport,前置 #1 升级段) - **真实代码改动(第七轮起开工;commit 一览)**: - `c9f3435` `feat(wakeword): normalizeWake 加前缀语气词白名单`(5 行 regex + 6 测试项,11 项测试全过) - `ebe55b2` `docs(README): 修设置表 4 漏列 + 1 笔误`(4 漏字段 + `silenceMs 700 → 1500`,与 src/index.ts:278 schema 真源对齐) - `5ad037f` `调研(第六轮收尾): 把散落的 docs/findings/ 纳入 git`(109 + 328 + 146 + 459 行) - `ef54739` `docs(findings): dsh-llm 62 运行时导出相关性清单`(82 行) - `53dca87` `docs(CONTEXT): ADR-0006 第一级探测现状改为'部分实现'`(真机 asr.ts:778 已读 `track.getSettings().echoCancellation`,但未接通到 `bargeInMode='manual'` 闸门) - **第一性原理深挖结论**(来自 `docs/competitive/scan-2026-09.md` §0.2): - **声学层已不是壁垒**——WebRTC APM3、Silero v5、TEN-VAD 等公开 SOTA 可下载;本插件 ADR-0001/0006 已经做得接近头部 - **真正的难处是"社会-语用层"**——发言权调度(轮次让位)+ 人格一致性 + 延迟与人性张力 - **本插件最薄弱一格**:拟人度(人格 + 情绪 + 非语言发声 + 多角色对话)+ TTS 流式首包 ≤200ms ### 后续触发点(下一阶段真机落地) - **Phase 1 D0-2 真机落地**:本轮已完成 2/3(README 笔误 + normalizeWake) - 候选:状态条计时器(<0.5 天纯前端 setInterval)或 P0 system prompt 4 层模板落地(1 天,需 host `inject` 扩 `systemPrompt`,peer 已实测可达) - **Phase 3(Day 3-7)**:P0 SenseVoice 锁语种(schema `index.ts:224-227` 锚点需重定)+ P0 hotwords(`AsrRuntimeOptions` 补 getter + `decodingMethod` 切 `modified_beam_search`) - **Phase 4(Day 7-14)**:P1 CardForm draft/validate(150 行)+ P1 MCP `voice_*` 工具(需 host `inject` 实证) - **Phase 5(Day 14-30)**:A1 标签 DSL(需先拍 ADR-0007)+ B6 Interactive mode / B9 Read AI 复述 / B3 APM3 PoC - **必须先决的 ADR**:ADR-0003(client-side VAD)+ ADR-0007(emotion-tag)+ ADR-0008(让位语义 + 4 层 system prompt,第 6 轮已备齐草稿要素) ### 锚定真源(CLAUDE.md G5 evidence rule) - **PluginHost ← `plugin/dsh-voice-mode/src/`** —— 9k+ 行 TypeScript 源码,永远是唯一真源 - **State ← `docs/rules/STATE.md`**(本文件) - **Context ← `CONTEXT.md`**(开发者上下文) - **ADR ← `docs/adr/0001-0008`** - **Competitive research ← `docs/competitive/scan-2026-09.md` 主扫描 + `docs/competitive/sources/` 18 份子报告** - **Backlog ← `docs/competitive/backlog.md` 43 项 P0-P3** --- ## 任务:拍板后实施(main 当前任务)—— **计划已定稿待开工(2026-09-14)** ### 2026-09-14 拍板与实证(前置事件,全部已落盘) - **用户拍板**:ADR-0007「完整做分两步(先本地后 Edge)」· ADR-0008「Phase 1(#1+#2,#3-5 砍/推迟)」· 3 处链断 P0「批量 go」· xAI fallback 拒绝 · 声音克隆推迟 · C1 人格层推迟 - **用户录真机 fixture**:4 条 2×2 矩阵(外放/耳机 × 纯听/打断),`mode:full` 含音轨,不进公开仓。 判定见 `docs/findings/2026-09-14-fixture-verdict.md`(crest≥7dB 成立;Silero 0/937 泛化; confirmMs 517/488ms;detect 串行化实证;耳机残差>用户语音 = ADR-0001 边界形态) - **线上同步实证**:dsh.service 21:48:41 重启 > lib 重建 21:22:50;fixture env.build=6d077c2。 R7-R23 四件(normalizeWake/计时器/双条 SVG/数据流向标签)**已在线上运行** - **守卫抓真问题**:`npm test` 曾因「lib 早于源码」失败 → R29 重建(commit 0ff025b)→ 91/91 全绿 ### 当前状态:计划定稿 + 移交提示词定稿,**未开工**(角色分工 2026-09-14 重新定义) - **唯一执行入口:`docs/plan/implementation-plan-2026-09-14.md`**(含对抗性审查 10 项修正:批 1 PoC 前置与释放 API 降级 / 批 2 pending request 核实 / 批 3 ellipsis 互斥与遮挡 / 批 4 tts-queue 零触碰定稿 + whisper 成对标签 / 批 5 短应答开段致命边界 + I10 豁免 / 新测试必须登记 package.json)。 - **移交提示词(2026-09-14 定稿)**: - `docs/plan/executor-prompt.md` —— 执行 agent 全量输入(铁律 10 条 / PoC 前置 / 四连验证 / 失败报告与简报格式 / 禁令清单) - `docs/plan/reviewer-prompt.md` —— 审查 agent 全量输入(六轴框架 / 固定桶输出 / 不修复纪律 / 与执行者关系) - **角色分工**:计划维护者(本会话)只负责计划、文档、提示词维护;**执行与审查由其他角色按上述两份提示词执行**。 ### 恢复点(若会话中断,从这里续) 1. 读本段 + `docs/plan/implementation-plan-2026-09-14.md` 全文 2. `git log --oneline -5` 确认批 0 + 提示词 commit 已入库 3. 移交执行:将 `docs/plan/executor-prompt.md` 全文交给执行 agent,从**批 1(P0 热词,含 3.0a PoC 前置)**开始 4. 每批 commit 后可选移交审查:`docs/plan/reviewer-prompt.md` + 指定 `git show <批 commit>` 5. 执行/审查回报的冲突转计划维护者裁决;每批完成后执行者回写本文件「批次进度」表(批 6 统一回写其余文档) ### 批次进度表 | 批 | 状态 | commit | 计划维护者裁决记录 | |---|---|---|---| | 0 文档同步 | ✅ | c2980f4 | — | | 计划修正+提示词 | ✅ | 42dcd16 | 对抗性审查 10 项修正(V1-V10) | | 1 P0 热词 | ✅ | 9467c81 | **两条偏差均裁决接受**:①新文件 `src/asr-hotwords.ts`(可测性抽取,纯函数无状态,已补记计划 §3.2);②验证顺序计划内部冲突为真(verify-client mtime 断言 vs 初版顺序),定稿 `tsc×2 → build → npm test` 已修计划 §0.2。PoC:P2 free() 实证存在(无需降级);**P1 端到端 SKIP(开发机无流式模型)——构造层已验(102/102),识别偏置效果待批 6 真机验收**。 | | 2 P0 锁语种 | ✅ | 3025e1b | **审查 subagent Verdict = pass-with-minor**:无 Blocker / Important。**4 条 Minor**:M1 commit message 行号偏 1(`sense-worker.ts:135` → 实际 136,已 commit 不 amend,记录在 STATE 防回查混乱);M2 schema 严格 + runtime sanitize 轻度冗余(功能正确,保留作未来 schema 放宽兜底);M3 NUL 分隔测试描述略偏(断言仍成立,下批修正);M4 commit message「3 次重试覆盖」措辞可更直白(技术正确,不阻断)。**2 条 Open(已裁决)**:**Q1 接受**——补计划 §4.2 `asr-sense-key.ts` 注脚(与批 1 同模式,纯函数模块正式入文档);**Q2 接受**——补计划 §4.4 集成层豁免说明(①② 由 `asr-host.ts:386-441` 短直读可验保证,集成层留批 6 真机)。§4.3 核实已在 commit message(M1 行号偏差不影响核实有效性)。I10 字节等价、`dsh.client.inject` 9 项未动、不变量 I1-I10 全保。 | | 3 字幕 a11y | ✅ | 0fe3f90 | **审查 subagent Verdict = pass-with-minor**:**3 条 Important 必须修**(I1/I2/I3)。**I1** schema description「屏幕宽 >686px 时略窄于现状 480px」数学方向反(70vw 在 >686px 时**宽于** 480px),属 I10 取舍显式声明硬伤,向用户传错误事实——三处同步修(`index.ts:292` schema description / `index.ts:185` 行注释 / plan §5.3)。**I2** caption-a11y.test.mjs:46 测试只断言字符串「略窄」存在不验证方向,反向错误(写「略宽」)也能过——加反向断言 + 语义校验(70vw vs 480px 在典型 viewport 谁大谁小)。**I3** plan §5.2 第 215 行「通用透传」与源码显式白名单矛盾 + §5.2 表只列 6 处实际 7 处——补 §5.2 表第 7 处(fetchConfig 白名单)+ 措辞修正「通用透传」→「逐字段白名单拼接」(已在本裁决 commit 完成)。**4 条 Minor 不阻断**:M1 DEFAULT_BOOT/bootNow 冗余(全局一致模式,留批 6 收口讨论 `BOOT_DEFAULTS` 常量复用);M2 `.dshvm-caption` CSS 类与内联 style 重复(类实际不生效,留作扩展 hook,建议 commit message 标注);M3 测试 DEFAULT_BOOT/bootNow 同正则无法区分两处(拆测或加范围限定);M4 secInteraction 字幕分类不符(plan §5.2:212 显式要求,批 6 考虑 secAppearance)。**Q1 与 I3 同处理;Q2 与 I1 同处理**。**修复前置门**:I1/I2/I3 修完再放行批 4,由执行 agent 在批 4 开工前单独补 docfix commit。 | | 3 字幕 a11y(docfix) | ✅ | a96acd9 | **审查 subagent Verdict = pass**:**无 Blocker / Important**。**2 条 Minor**:M1 反向断言基于全文 grep 覆盖典型回退场景,「中性表述」理论上漏报——未来可加固项,非当前 docfix 遗漏;M2 lib BUILD_TAG = `cf27caa` ≠ HEAD `a96acd9`(build.mjs 在 commit 前跑锁定父 commit 的既定工作流,非本 commit 引入)。**Q1 转计划维护者**:是否要求每批 lib BUILD_TAG = 本 commit 短哈希?建议 build 时点改「commit 后」或脚本化「build → commit lib」——**留批 6 总收口阶段统一讨论**,当前不动。三处修复均到位:schema description 三档(`<686px 窄 / ≈686px 近 / >686px 宽`)+ 行注释同步 + 测试三档独立 regex + 反向断言(亲手验过:旧措辞会红);数学方向正确;I1-I10 全保;132/132 通过;lib 文本已是修正后版本。 | | 4 ADR-0007 步1 | **不放行** | 959c742 | **审查 subagent Verdict = fail(因 B1)**:**B1 端到端功能断裂**——emotion 标签在到达 `tts-local.synthesize` 之前就被 `segmenter.plainText`(`src/segmenter.ts:27` 正则 `/<\/?[a-zA-Z][^>]*>/g`)剥掉,emotion 处理是死代码;单测 151/151 全绿是因 `emotion.test.mjs` 直接 import `parseEmotionTags` 绕过 segmenter——典型「单测通过、集成断裂」反例。**B1 是 plan 缺陷**(§6.2 末段决策"处理点全收在 synthesize 内部"正确,但未约束"segmenter 必须保留 emotion 标签"),不是 executor 错。**4 Important**:I1 集成层探针缺失(未补 segmenter→emotion.ts 全链路断言);I2 无 LLM prompt 注入(VOICE_SPOKEN_PROMPT 未追加 emotion 标签使用指引,即便修好 B1 端用户也无路径触发);I3 EmotionSegment.preBreakMs 语义偏差(需补 plan §6.2 注脚);I4 whisper 单→成对标签偏差需回写 ADR-0007。**6 Minor**:M1 空 samples 行为变化(silent 44-byte WAV vs 原 throw);M2 stripEmotionTags 死代码(无 src 调用方);M3 行数偏差轻微不实;M4 16000 硬编码采样率;M5 needsRespawn 措辞不精确;M6 注释冗余。**Q1-Q4 转计划维护者**(已处理:plan §6.2 已加 segmenter 修复行 + 集成断言新文件行 + §6.3 收口前置门;§6.0 表补 break 段后置静音 + whisper 不平衡保守语义)。**批 4 不回退**:959c742 作为基础设施保留;**「批 4 收口 commit」由执行 agent 承担**:① 修 `src/segmenter.ts:27` plainText 正则豁免 emotion 标签名(推荐:line 27 通用 HTML 剥离改为只剥真正块级 HTML,emotion 标签集合固定且已知,未列入不剥——零信任);② 新建 `test/emotion-integration.test.mjs`(5 种 emotion 标签场景的 segmenter→emotion.ts 全链路断言,B1 防回归);③ tsc×2 → build → npm test 全绿;④ commit message 显式标注「批 4 收口(修 plan §6.2 前置约束遗漏 B1)」。**批 5 顺延**:批 4 收口 commit 入库 + 集成断言 + 段切分器修复全部完成 + 审查 subagent 验证 B1 已修后再放行。 | | 4 ADR-0007 步1(收口) | **待 docfix** | 7b94653 | **审查 subagent Verdict = PASS**(带 1 Important 文档准确性 + 1 数字偏差)。**核心修复全部到位**:B1 双修(plainText 白名单 22 HTML 标签 + sanitizeForTts 字符集移除 `<`/`>`)+ 新建 emotion-integration.test.mjs 9 项 + 既有 segmenter.test.mjs 净增 1 项——**B1 反向断言真伪三种场景亲手验证有效**(仅回退 plainText / 仅回退 sanitizeForTts / 同时回退两处,均让集成测试红)。**I4/I5/I6 完整保**(tts-queue/emotion.ts/tts-local.ts 0 行 diff;client.inject 9 项未动)。**2 Important 必须修**(I1 + I2,由执行 agent 单独 docfix commit 承担):**I1** commit message + `test/segmenter.test.mjs:48` 注释「blockquote > 与 \| 字符不再被剥」描述错(实为仅 > 不被剥,\| 仍被剥成空格——`lib/index.js:1027` 字符集 `[*_#\|^=+~\`]` 仍含 \|;测试 line 52 实际断言 `> 引用 \| 表格` → `> 引用 表格`);**I2** 测试总数自报 160 vs 实际 161(差 1 项,segmenter.test.mjs 净增 1 项不是替换)。**3 Minor 不阻断**:M1 白名单遗漏 HTML5 常见标签(article/section/aside/nav 等);M2 emotion-integration 反向断言隐式覆盖 sanitizeForTts(场景 2-5 经 segmenter 链路同时经过 plainText + sanitizeForTts 已验证);M3 场景 5 混合用例断言较弱。**Q3 ADR-0007 回写 + Q4 CONTEXT.md 基线(91 → 161)均留批 6 收口阶段统一处理**。**前置门**:执行 agent 补 docfix commit 修 I1 + I2 后再放行批 5。 | | 4 ADR-0007 步1(收口 docfix) | ✅ | d013193 | **审查 subagent Verdict = PASS**:**无 Blocker / Important**。**2 Minor**:M1 commit message「实际比计划预期少 1」方向表述错(实际比 plan 算式**多** 1——132+19+9=160 是 plan §6.3 算式,实际 161 是因 segmenter.test.mjs 净增 1 未纳入 plan 算式),按批 1 M1 先例不 amend 不补 docfix,记录在 STATE 防回查混乱;M2 测试名从「保留 > 字符」小扩到「> 字符不再被剥」,与新注释一致,可接受。docfix 实际仅 1 文件改动(test/segmenter.test.mjs 注释 5+/4-),I1 注释副作用描述修正(\| 字符仍被剥,实证 lib/index.js:1026)+ I2 数字自报 161 算术验证(13+10+3+7+5+8+6+40+11+10+20+19+9 = 161)+ 7b94653 未 amend(父提交 = c1593e4,hash 不变)+ I1-I10 全保 + 161/161 通过。**前置门全部清除,批 5 正式放行。** | | 5 ADR-0008 P1 | ✅ | 7f1a09f | **审查 subagent Verdict = pass-with-minor**:无 Blocker / Important。**2 Minor**:M1 `strings.ts` 死代码 2 键(`backchannelHint` / `descBackchannelHint`,zh + en 共 4 键,settings-form 未使用)——**放批 6 收口统一清**(避免批次碎片化);M2 词表 17 项 vs 自报「16 项」1 字偏差(right 被长度过滤)——不修。**4 Open**:Q1 plan §7.2 与 §10 内部不自洽已修(删 right + 改「复用 normalizeWake」→「独立 normalizeBackchannel」+ 范围溢出注脚);Q2 集成层验证留批 6 真机冒烟;Q3 backchannelYield=false 仍跑 matchBackchannel(CPU 浪费不修不阻);Q4 hold 1500ms 时长留批 6 真机观测。**14 个行号锚点全命中**(asr.ts:374 emit / 379 新 if / client.tsx:943 帧守卫 / 1605 onBackchannel / index.ts:628 /config 等);**测试反向断言亲手验证有效**(删 'ok' → 红);**I3 保护到位**(partial emit L374 不变 + 新 if L379 emit 后 + 无 return);**I4/I5 完整保**(tts-queue.ts 0 行 diff + onBackchannel 不经过 epoch);**191/191 通过**(基线 161 + backchannel 30);**I10 豁免已规范声明**(index.ts:162/194/306 + client.tsx:1604 四处)。 | | 6 总收口 | ✅ | 14dfc5e | **审查 subagent Verdict = pass-with-minor**:**无 Blocker / Important**。**7 Minor 全部为文案数字偏差或既定模式**(按批 1 M1 / 批 3 / 批 4 docfix 先例均接受不修,记录在 STATE 防回查混乱):**M1** CONTEXT.md 自报「8 新键」vs 实际 7(批 1/2 + 批 3 + 批 5);**M2** ADR-0007 落地注记「22 个 HTML 标签」vs 实际 26(含 h[1-6] 计 1 项);**M3** ADR-0008「词表 16 项」与「17 项 + right 被滤」自相矛盾;**M4** 行号引用 ±1-2 行漂移(emotion.ts:32→80 等)——符合 plan §0.5 警告;**M5** `lib/client.js` BUILD_TAG=「3c1a996」(父 commit)≠ HEAD 14dfc5e ——既定工作流(build 在 commit 前),与批 1/批 3 docfix M5 同模式;**M6** `src/strings.ts` 总长声称「313 → 309」vs 实际「361 → 357」(4 行净删事实正确,基线数字偏差);**M7** §8.4 真机冒烟清单扩到 6 项(plan §8 仅 5 项)——低成本文档自检,可接受。**§8 6 步全部到位**:① tsc×2 + npm test 191/191 + verify:dual 4 版全绿;② git log 复盘批 0-5 各自独立 commit(累计 18 commit 含 6 个 plan/state 修订);③ systemctl restart 降级只读验证(sandbox 拦截已记录)+ 用户生产环境 PID 2342921 since 17:16:26 已生效;④ 真机冒烟 6 项清单已输出给用户;⑤ CONTEXT.md + ADR-0007/0008 + backlog.md + M1 死代码清理完整回写;⑥ verify:dual 4 版锚点 + 4 版 typecheck + 2 核心 0.1.1/0.1.5 runtime 冒烟全绿。**lib 产物实证含批 1-5 全部功能**(grep hotwordsBuf / langKey / captionFontSize / matchBackchannel / 帧守卫 / `.dshvm-caption` CSS 全命中)。**I1-I10 全保**:I6 client.inject 9 锚点零改动;I10 豁免 4 处显式声明。**6 批串行计划全部完成,可打 release tag。** | | **累计健康审查** | ✅ | 5c20a8c | **综合审查 subagent Verdict = PASS(累计水平)**:**0 Blocker / 0 Important / 3 Minor** 全部为 STATE 已记录既定模式(M-A 累计行号漂移超 plan §0.5 警告 ±60 行 / M-B CONTEXT 7 vs 8 键数 = 批 6 M1 累计 / M-C BUILD_TAG = 批 6 M5 累计)。**59 commits 已推 origin/main**(a2aadc8..5c20a8c,git push 成功;GitHub `test` 状态检查是保护分支规则要求,本地 191/191 已通过)。**验证四连亲跑全绿**:tsc(host) 0 输出 / tsc(client) 0 输出 / build 16ms / npm test 191/191。**跨批次集成**:5 个新文件正确导入导出(asr-hotwords/asr-sense-key/emotion/segmenter 修复 + plainText/sanitizeForTts 双修);settings-form 累计 7 新 Row(secRecognition + secInteraction 布局合理);strings.ts 累计 7 主键 + 7 派生 + 1 aria,zh/en 一致;schema description 齐全。**I1-I10 整库水平全保**:I1 finalize+resetGen / I2 计数仅播放期 / I3 播放门不 return / I4-I5 tts-queue 0 行 diff / **I6 client.inject 9 锚点零改动**(grep 实证)/ I7 cordis 未扩 / I8 models.ts 0 diff / I9 零 API Key / **I10 豁免 4 处显式声明**(index.ts:162/194/306 + client.tsx:1604)。**累计净增**:src 1376 行 / test 856 行 / lib 4 产物 grep 实证 17+ 关键字段全命中。**真机冒烟 6 项完整覆盖** 6 批串行所有 P0 验收点(热词识别效果 / 锁 en 抖动消失 / 字幕 24px / `` 停顿 / 说「嗯」跳句 / ADR 落地注记)。**文档代码一致性**:CONTEXT 7 键 vs schema defaults 逐字段一致(仅键数自报偏差);ADR-0007/0008 后文显式声明「实际行为」无误导;backlog.md 批次进度章节完整;STATE.md 6 批全 ✅。**累计唯一遗留**:Q1 累计行号漂移系统性问题(ADR 引用偏差 ±60 行超 plan §0.5 ±1-2 警告)——语义无误导但行号 grep 会找不到,建议 release tag 后做一次完整 grep + ADR 行号同步刷新。**累计健康 PASS,可打 release tag。** | | 7 批 A 周全修复 | ✅ | 78574ad | **审查 subagent Verdict = PASS**:**无 Blocker / Important**。**3 Minor 全部接受**:**M1** 反向断言覆盖弱——`markStale` 内追加 `recognizer = null` 测试仍绿(`recognizer` 是闭包私有变量,runtime 不暴露 getter;测试已涵盖正向 markStale 存在 + 不抛错 + 不破坏句柄),属测试深度问题,未来批可选补强。**M2** BUILD_TAG 父 hash 实为 `0b00856` 而非派发方写的 `3c1a996`——executor 工作流既定模式(build 在 commit 前跑),与批 6 M5 同模式,不阻断。**M3** watch 回调忽略框架 prev 参数——闭包 `const prev = vset` 与框架 `(next, prev)` 单线程串行调用等价,功能正确;建议未来批改用框架参数更健壮。**Q1** senseVoice 触发 markStale 必要性(防御性失效合理)。**Q2** I1 在 getRecognizer 重建路径上的旧隐患(非批 A 引入,markStale 不 dispose 本身安全)。**核心修复到位**:`markStale` 仅清 `recognizerHotwordsKey + senseWorkerLangKey`(asr-host.ts:783-786),**不主动 dispose**——避免 I1 race;watch 先 `const prev = vset` 再 `vset = next`(index.ts:513-514)防 vset=next 后比较失效二次 Bug;5 ASR 字段全覆盖(hotwords/Score/language/ITN/senseVoice);pump catch 加 sessionId(item/attempt 是 while/for 内部 const/let,外层 catch 不可见,按外科手术式原则不加)。**不变量 I1-I10 全保**:I1 markStale 不 dispose → in-flight 安全;I4 tts-queue 改动仅 catch 块字符串,pump 协议零触碰;I5 markStale 不动 epoch;I6 client.inject 9 锚点逐字未动。**npm test 191 + 9(新 asr-host-rebuild)= 200 项全绿**。**批 B 放行**(/config + fetchConfig 透传 5 字段)。 | | 7 批 B 周全修复 | ✅ | e952583 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / Important**。**2 Minor 全部接受**:**M1** committed lib BUILD_TAG = "733ea77"(父 commit hash)—— 已重新 build,BUILD_TAG 现为 e952583,工作区有未提交 1 行 lib/client.js 改动(按惯例保留);既定工作流(build 在 commit 前),与批 6 M5 同模式。**M2** 零新单元测试——5 个新校验分支未专门覆盖,但 verify-client.mjs + live curl 间接保证 + 37 项反向断言亲跑全过;与 B3 对抗性审查一致「client 不消费则不需深度单测」,未来批可补 `test/client-fetch-config.test.mjs`。**2 Open 全部接受**:**Q1** 未补 kokoroModel/spokenFormat——对抗性审查 B3 决定 client 不消费不补(按需时单独批补);**Q2** bus.ui.boot 5 新字段无 client 运行时消费者——pass-through 是 commit 显式意图,UI 显示按需单独批补。**核心修复到位**:VoiceBootConfig 接口(src/client.tsx:1137-1178)加 5 ASR 字段(asrHotwords string / asrHotwordsScore number / recognitionLanguage 6 语种 union / senseITN + senseVoice boolean),**严格**与 src/index.ts:111-164 VOICE_SETTINGSValue 类型对齐;**严格不**透传 7 host-only 字段(kokoroModel/spokenFormat/cacheDir/allowLan/audioMime/ttsEngine/modelHost)——对抗性审查 B3 决定。fetchConfig 白名单(src/client.tsx:1280-1326)严格类型校验(asrHotwordsScore 1-5 范围兜底 1.5 / recognitionLanguage 6 语种 === 串行兜底 'auto' / senseITN + senseVoice === false 兜底 true)。DEFAULT_BOOT(L562-584)+ bootNow fallback(L1238-1261)各含 20 字段(15 旧 + 5 新),默认值与 VOICE_SETTINGS_DEFAULTS 逐字段对齐。**不变量 I1-I10 全保**:I6 client.inject 9 锚点零改动;I10 默认行为 5 新字段默认值与 schema 一致。**npm test 200 项全绿 + curl /config 7 字段全返非 null**。**批 C 放行**(FIELD_LABELS 7 中文 + strings.ts 同步)。 | | 7 批 C 周全修复 | ✅ | 44b6775 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 1 Important + 4 Minor**。**I1 双轨漂移检测未实现值一致性**(**接受不修**——commit message 自报能力 vs 实际断言能力不符,按既定模式「commit 描述强于断言」;当前 UI 走 FIELD_LABELS,zh *Label 镜像未对外使用,短期不阻断;**STATE 显式记录整合批前必补 1 项值一致性断言**)。**4 Minor 全部接受**:**M1** descRefs 阈值 26 vs 实测 27(不影响功能)。**M2** 15 项迁移期遗留字段无 zh 键(未来整合批必处理——STATE 登记)。**M3** strings.ts en 段 7 stub 未对外使用(已知 B1 风险)。**M4** BUILD_TAG 父 hash "27eb669"(既定模式,与批 A M2 + 批 B M1 同)。**Q1** descRefs 阈值 26 vs 27(转计划维护者)。**Q2** 15 项迁移期遗留字段何时处理(建议新增整合批统一收敛:删 FIELD_LABELS + 补 15 项 *Label 键 + 改 tr() 模式——plan §12.6 决策表追加 1 行)。**核心修复到位**:FIELD_LABELS 字典补 7 中文(热词/热词偏置分/识别语种/逆文本归一化/字幕字号/字幕宽度/短应答让位);strings.ts zh 段加 7 *Label 键 + en 段加 7 stub(typescript Record 强制);**新增 strings-coverage.test.mjs 30 断言**(B1 防回归核心)覆盖 settings-form.tsx 所有 Row/field/desc 引用 + FIELD_LABELS + strings.ts zh 双侧完整性。**4 项反向断言亲跑**:删 FIELD_LABELS 字段红 + 删 zh *Label 红 + 删 en stub tsc 报错 + 删 desc 红——全部如预期。**npm test 16 文件 / 230 项全绿**。**不变量 I1-I10 全保**:仅字典补全 + 静态扫描测试;I6 client.inject 9 锚点逐字未动。**批 D 放行**(tts-local 拼帧段后置静音 + emotion.ts:30 注释反向 + stripEmotionTags 处置)。 | | 7 批 D 周全修复 | ✅ | 2d247f6 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 1 Important + 2 Minor**。**I1 守门反向断言形同虚设**(**接受不修**——`emotion.test.mjs:133-140` 下线守门实际是 `typeof parseEmotionTags === 'function'` 恒真断言,把 stripEmotionTags 复活测试仍绿;按"commit 描述强于断言"既定模式,ponytail 删除本身正确——下批可补强或 PR 末尾用动态 import + `typeof mod.stripEmotionTags === 'undefined'` 加固)。**2 Minor 全部接受**:**M1** `emotion.ts:16` EmotionSegment 接口注释"前置静音"与实际"段后置静音"不一致(preBreakMs 命名从输入序出发,文档术语瑕疵,不影响功能)。**M2** lib/client.js BUILD_TAG = "9201d6a"(父 hash),既定工作流。**Q1** Edge TTS 引擎对 emotion 标签处置——EdgeTtsEngine(tts-queue.ts:104)不经 parseEmotionTags 直接给 msedge-tts 云端 SSML 原生支持,未来启用另开批次。**核心修复到位**:tts-local.ts:477-486 拼帧顺序修复(`chunks.push(silence)` 移到 `chunks.push(samples)` 之后),让"你好世界"输出顺序从「300ms静音+你好+世界」(错位)变「你好+300ms静音+世界」(plan §6.0 段后置静音)。**反向断言亲跑**:把拼帧顺序回退旧 → 测试红(错误信息"起始样本 #0 应非静音"定位 tts-local.ts:241 行)。emotion.ts:30 注释反向("全段当 whisper"→"全段退回非 whisper"),与代码 L99-103 实现一致。emotion.ts:108-115 删除 stripEmotionTags export(**选 2 删除**——ponytail 原则:全 src 0 引用 + ASR partial 结构上不含 emotion 标签 + 测试侧加下线守门)。**新增 emotion-tts-local.test.mjs 7 项**(B4 防回归核心)覆盖 WAV 时长 = 段时长 + 静音累计 + 段后置静音顺序 + whisper 增益×0.5 + 静态源码反向门。**emotion.test.mjs 4 项 stripEmotionTags 测删除 + 1 项下线守门新增 + import 调整 + 顶部注释更新**(emotion 19 → 16 项)。emotion-integration.test.mjs:40 去掉 stripEmotionTags 解构(无需翻转——注释原本就对齐修复方向)。**npm test 17 文件 / 234 项全绿**。**不变量 I1-I10 全保**:I4 tts-queue.ts 0 行 diff(pump 协议零触碰,tts-local 改动仅在多段合成 chunk 拼接层);I5 epoch 未触碰;I6 client.inject 9 锚点逐字未动。**批 E 放行**(endpointConfirmMs 短句 confirm 200ms + SenseVoice 预热前置 enterMode + timeout 20s + 新增 endpoint-short 防回归)。 | | 7 批 E 周全修复 | ✅ | 921334e | **审查 subagent Verdict = PASS**:**无 Blocker / Important / 1 Minor**。**M1 lib BUILD_TAG 父 hash(6de4aa2)既定工作流,不阻断**。**2 Open**:**Q1** plan §12.4 的 `test/fixtures/zh-60s.wav` + 扩展 `test/asr-e2e.js`(B5 60s 长段话端到端防回归)仍未实现,**显式记录为缺口,建议批 7z 收口批或独立批补齐**。**Q2** 批 E 1 commit 完成(plan 估 3 commit,更高效无须修复)。**核心修复到位**:**endpointConfirmMs 短句 confirm 0 → CONFIRM_MIN_MS=200**(asr-host.ts:177/190)——B5 主因候选 1(VAD 段分裂)修复:每次换气停顿(≥1.5s)即切段改为 ≥200ms 才端点,给续说一个最小窗口;长句 350ms + 连词结尾 800ms 路径不变。**SenseVoice timeout 10s → 20s**(asr-host.ts:598)——B5 辅因候选 3(冷启动慢撞 10s timeout 降级 zipformer)修复。**SenseVoice 预热前置 enterMode**:新增 `warmupSense(): Promise` 接口(asr-host.ts:127-130)+ 实现(5s 上限 + senseVoice 关闭守卫 L788-797);`/toggle` collectBody 改 `async`(L727)+ on=true 路径 `await asr.warmupSense()`(L767-771,在 asr.reset 之前)。**warmup() 同步签名保留**(apply 调用契约未变)。**silenceMs 默认 1500ms 守恒**(B5 对抗性纠正未扩大化)。**新增 endpoint-short.test.mjs 17 项**(B5 防回归核心)= 5 短句 + 4 长句/连词 + 6 源码 grep 反向门(CONFIRM_MIN_MS=200 / return CONFIRM_MIN_MS / setTimeout 20000 / warmupSense 接口+实现 / /toggle async+await)+ 1 接口向后兼容 + 1 注释。**endpoint.test.mjs 第 1 项同步 0 → 200ms**(防回归互锁)。**7 项反向断言亲跑全部 PASS**(关键:改 L190 `return CONFIRM_MIN_MS` → `return 0` 测试红;改 CONFIRM_MIN_MS=200→0 测试红;改 timeout 20000→10000 grep 红;去 await grep 红 + tsc TS1308 报错;B5 对抗性约束验证 silenceMs: 1500→500 测试仍全绿)。**npm test 18 文件 / 251 项全绿**(234 旧基线 + 17 endpoint-short)。**不变量 I1-I10 全保**:I4 tts-queue.ts 0 行 diff(无 TTS 帧协议改动);I6 client.inject 9 锚点逐字未动(仅 scripts.test 插入 endpoint-short);I7-I10 未触碰。**批 F 放行**(spokenFormat 注释 + matchBackchannel 守卫 + effectiveNote 文案)。 | | 7 批 F 周全修复 | ✅ | 5ded5d4 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 2 Important + 3 Minor**。**I1 matchBackchannel 守卫无单测覆盖**(**接受不修**——`asr.ts:383-390` 守卫无自动化回归门;3 项反向断言亲跑确认(删 AsrConfig.backchannelYield tsc TS2339 报错 ✓;守卫改 `=== true` 测试仍绿 ✓;完全删守卫测试仍绿 ✓);**STATE 显式登记批 G/H/I 任意时机补 `backchannel-yield.test.mjs`**)。**I2 运行时行为契约无单测**(同上 I1,tsc 静态保护 OK,运行时契约无单测)。**3 Minor 全部接受**:**M1** 锚点漂移——`src/index.ts:67` 注释「见 L182」实指 L183(off by 1);`src/client.tsx:1671` 注释「asr.ts:379」实指 L383-390(plan §0.5 ±1-2 行警告范围)。**M2** settingsCardDesc 实际改动 9 字段(自报 7,含回声门控/工具提示音/自动恢复/口语化提示词调整,无害)。**M3** zh settingsEffectiveNote 段 2「即时生效(下次进入语音模式重建流式识别器)」字面冲突但括号已解释。**Q1** 段 2 用户文案歧义(建议改写「下次进入生效」更直白)——转计划维护者。**核心修复到位**:**`src/index.ts:66` spokenFormat 注释反向**(「默认关」→「默认开,VOICE_SETTINGS_DEFAULTS.spokenFormat=true, 见 L182」与代码 L182 默认 true 对齐)。**`src/asr.ts:379` matchBackchannel 守卫**(加 `config.backchannelYield !== false` 守卫,默认 true 保持 I10 豁免;CPU 浪费修复——partial 100ms 节拍下关状态省 1% CPU/朗读期)。**`src/strings.ts:122-123 zh + 299-300 en` settingsEffectiveNote/settingsCardDesc 扩展 7 字段**(识别热词/热词偏置分/识别语种/逆文本归一化/字幕字号/字幕宽度/短应答让位);三段分组与 markStale lazy rebuild 机制对齐(段 1 批 C/D/E 即时生效 / 段 2 批 1/2 即时生效+下次重建识别器 / 段 3 其余下次进入)。**AsrConfig 接口扩展 `backchannelYield?: boolean`**(src/asr.ts:106-107)+ client.tsx:1671-1672 透传——守卫最小必要 plumb,tsc 静态保护(删字段报 TS2339)。**npm test 17 文件 / 251 项全绿**。**不变量 I1-I10 全保**:I4 tts-queue.ts 0 行 diff(无 TTS 帧协议改动);I6 client.inject 9 锚点逐字未动;I10 守卫默认 true(src/index.ts:196 + src/client.tsx:577/1254 + src/client.tsx:1307 + src/asr.ts:384 四处字节等价)。**批 G 放行**(Number 校验 + idle 预警 + yieldMs 可调 + textarea 校验 + 跳过 disable + 引擎切换下载)。 | | **批 G 周全修复(重做)✅ PASS-WITH-MINOR** | ✅ | d979b8e(HEAD)| **修复 subagent 5 commit 全部到位**:`0d7419a` Fix 1 NumberField 红框 + clamp + strings.ts zh/en `numberInvalid/numberClamped` ✓;`aac30c0` Fix 2 yieldMs **9 处**对称(VoiceSettingsValue/DEFAULTS/schema//config handler + VoiceBootConfig/DEFAULT_BOOT/bootNow/fetchConfig/setBackchannelHold)✓;`faeb204` Fix 3 VoiceOverlay 浮层 `pointerEvents: 'auto' + cursor: 'default' + touchAction: 'manipulation'` ✓;`de031e1` Fix 4 lib rebuild BUILD_TAG 对齐 ✓;`d979b8e` Fix 5 strings-coverage 升级 8 项具体键断言 + FIELD_LABELS.yieldMs 闭包值一致性 ✓。**修复审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 6 Minor 全部接受**:**M1** 自报 22 ahead 实测 23(计数差 1)。**M2** Fix 2 commit message 顶部「8 处」与自身列出 9 处不一致。**M3** Fix 1 commit message 措辞「核心升级」夸大(实际 Fix 5 才做综合升级)。**M4** 反向断言 5 项中第 5 项「改 hardcoded 1500 → tsc 报错」agent 自报失实(tsc 0 错通过;实现本身无误,**仅无可捕获的自动化测试覆盖 yieldMs wiring 路径**——STATE 登记转计划维护者评估是否补端到端测试)。**M5** Fix 3 CSS 改动无自动化测试覆盖(设计边界)。**M6** strings-coverage.test.mjs 被 Fix 1/2/5 三处修改(必要 scope creep;非 silent revert)。**6 项反向断言亲跑**:删 `idleWarn30s`/`yieldMs`/`numberInvalid`/`numberClamped` → strings-coverage 真红 ✓;注释 `index.ts:201 yieldMs: 1500` → tsc TS2741 真红 ✓;注释 `client.tsx:581 yieldMs: 1500` → tsc TS2741 真红 ✓。**npm test 254 项全绿**(实测 254 = 13+10+3+7+17+5+8+6+40+11+9+10+20+16+7+9+30+33)。**BUILD_TAG = d979b8e(= HEAD)** ✓。**跨 commit silent revert 检查全过**:Fix 1 仅 NumberField(不含 idleWarn/pointerEvents)✓;Fix 2 仅 yieldMs(不含 idleWarn/pointerEvents/numberInvalid)✓;Fix 3 仅 pointerEvents CSS ✓;Fix 1/2/5 在 strings-coverage 加的具体键断言**未被** Fix 5 删除(仍是过程保险)。**不变量 I1-I10 全部守恒**:I1 finalize 幂等(asr.ts/asr-host.ts 0 行 diff)✓;I4 TTS 帧协议(tts-queue.ts 0 行 diff)✓;I5 epoch 守卫未触碰 ✓;I6 client.inject 9 锚点(package.json 5 fix commit 内 0 行 diff)✓;I10 yieldMs 默认 1500ms(index.ts:201 + zod 500-3000 + client.tsx:581/1267/1322 全守恒)✓。**批 H 放行**(console.warn toast + 浅色字幕 + mic 对比度 + autoResume onboarding)。 | | 7 批 H 周全修复 | ✅ | 80ea993 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 3 Minor + 2 Open 全部接受**。**M1** 4 commit UI 改动无单测覆盖(既定模式:删 toast/dsw-alias/MicButton 改回 tsc 0 输出 + npm test 254 项全绿;运行时无自动化覆盖)—— 接受不修。**M2** lib BUILD_TAG = "4bbfa8e"(父 hash ≠ HEAD 80ea993,amend 前 build 工作流产物)—— 既定工作流记录不阻断。**M3** 派发方 prompt 自报 MicButton 行号 2212-2236 实际 2383-2386(偏差 ~170 行超 plan §0.5 ±95 行警告)—— 非执行者问题,转派发方自查。**Q1** 「联动提示」与「autoResume」合并到 80ea993(5 项 → 4 commit)—— 规约允许相邻任务合并无 silent revert。**Q2** 「联动提示」语义未明确(plan §12.3 表 387 行仅列 5 字)—— 当前实现覆盖 autoResume 关 + 切回上次会话时弹 notice,与 §12.3 表 387 行「联动提示」语义吻合,转派发方明确范围。**4 commit 逐项到位**:**9d64f45** 任务 1 TTS 失败时补弹 3s error toast(src/client.tsx:915-935 tts-error SSE 回调 + error 3s 条件清,与 idleTimeoutQuit 共用模式)。**350c137** 任务 2 字幕浮层背景与文字走 dsw-alias 主题变量(src/client.tsx:2686 bg → `var(--dsw-alias-bg-layer-3)` + 2691 color → `var(--dsw-alias-label-primary)`;与 settings-form.tsx:32/:35 同源)。**08853d3** 任务 3 MicButton 字色 `#3fb950` → `#2ea043` + fontWeight 600(hold 模式蓝字不动)。**80ea993** 任务 4 autoResume 关 + 切回上次会话时状态条一次性提示(src/client.tsx:74 VoiceUiState.notice + 608 createVoiceBus 初值 + 1880 autoResumeHintTimerRef + 1887-1907 autoResume effect + 1932-1935 卸载清理 + 2542-2556 VoiceStatusBar 优先级 `error > notice > idleWarn > 状态文本` + src/strings.ts:200 zh + 390 en autoResumeHint)。**4 项反向断言亲跑**:9d64f45/350c137/08853d3 删改 tsc 0 输出 + npm test 254 项全绿(运行时无单测);80ea993 删 `notice` 字段 tsc TS2353 报错 6 处 ✓;删 strings.ts autoResumeHint zh/en tsc TS2345 报错 ✓。**npm test 18 文件 / 254 项全绿**(13+10+3+7+17+5+8+6+40+11+9+10+20+16+7+9+30+33)。**跨 commit silent revert 检查全过**:4 commit 各仅做一件事,无跨任务 revert。**不变量 I1-I10 全部守恒**:I1 finalize 幂等(asr-host.ts 0 行 diff)✓;I4 TTS 帧协议(tts-queue.ts 0 行 diff)✓;I6 client.inject 9 锚点(package.json 0 行 diff)✓;I10 仅 UI 改动 runtime 行为零变化。**批 I 放行**(verify-bazong 编码 + ADR 22→26 + README 同步 + /preview 错误)。 | | 7 批 I 周全修复 | ✅ | 6572883 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 4 Minor 全部接受**。**M1** ddd1f7b 残留未用 import `tmpdir`(旧版遗留非本批引入,批 J 死代码清理统一处理)。**M2** ddd1f7b commit message 行号锚点偏移(仅文案)。**M3** 6572883 缺少 `classifyPreviewError` 单测(与批 G 修复 M5 同模式接受不修——删 classifyPreviewError 调用 tsc 报错因函数被引用;强制永远返回 'unknown' tsc 通过但 npm test 全过)。**M4** 6572883 PREVIEW_NETWORK_PATTERN `aborted` 关键词过宽(当前未触发真实误归类风险,未来可优化)。**Q1** ddd1f7b 的 tmpdir 未用 import 留待批 J 处理。**4 commit 逐项到位**:**ddd1f7b** verify-bazong-path.mjs UTF-8 重建(15 处 U+FFBD 全部清除 + Windows 路径 K:/DSH-plugin-builds 删除 + 默认 cacheDir `homedir()/.cache/dsh-voice-mode/models` + DSH_VM_MODELS 覆盖 + CLAUDE.md UTF-8 无 BOM 纪律 Python write_bytes 落盘)。**e8bba91** ADR-0007 L129 22→26 + ADR-0008 L42 5 块→3 条(数字真源对齐:segmenter.ts:30 白名单 26 alternations;ADR-0008 L50-52 YIELDING 3 条 bullets)。**0397e7c** README 同步(根 README + plugin/README.{md,en.md} 加 4 功能节 + 7 设置项 + 3 故障排查)。**6572883** /preview 错误归类(PreviewErrorCategory 类型 + classifyPreviewError 正则分类器 network/engine/text + PREVIEW_ERROR_MESSAGES 用户友好提示表 + console.warn 诊断上下文 6 字段 + 响应体仅返回归类提示不泄露内部)。**6 项反向断言亲跑**:grep U+FFBD = 0;grep `22个|22 个|5块|5 块` 在两 ADR 文件 = 0;6 个变更文件 U+FFBD = 0 + BOM = 0;删 `classifyPreviewError` 调用 tsc 报错;删 strings.ts `tmpdir` 相关 tsc 不报错(仅文案)。**npm test 18 文件 / 254 项全绿**(与批 H 一致)。**跨 commit silent revert 检查全过**:每个 commit 仅做一件事(UTF-8 / ADR / README / /preview 各一 commit)。**不变量 I1-I10 全部守恒**:I1 finalize 幂等(asr-host.ts 0 行 diff)✓;I4 TTS 帧协议(tts-queue.ts 0 行 diff)✓;I6 client.inject 9 锚点(package.json 0 行 diff)✓;I10 仅 UI 改动 + 错误处理 runtime 句柄零触碰。**批 J 放行**(死代码清理 + 默认值微调 + a11y 微调)。 | | 7 批 J 周全修复 | ✅ | 2d646d9 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 6 Minor 全部接受**。**M1** bootNow 兜底 `10` 未改 5(schema min=1 触发概率近 0,agent 自报失实)。**M2** BUILD_TAG = "ca9f005"(父 hash,commit 2d646d9 时基于 ca9f005 HEAD 重建)—— 既定工作流。**M3** `hold` 键实际零引用(agent 引用理由错误,但保留无害)。**M4** test/wakeword.test.mjs(78 行)未登记 scripts.test(跨批遗留)。**M5** test/integration-fork.mjs + verify-preview-loop.mjs 硬编码 rate:1.0 / idleTimeoutMinutes:10(跨批遗留,纯独立 E2E 脚本不在 npm scripts 串联)。**M6** settings-form 折叠状态下 id 不存在于 DOM(屏读容忍语义不完全标准)。**4 commit 逐项到位**:**acfa6fc** 死代码清理 12 键(strings.ts zh + en 双段同步;删 modeBtnToggle/modeBtnHold/modeBtnTitle/ttsEngine/recognitionLanguage/captionFontSize/captionMaxWidth/engineIdle/ttsRedownload/ttsRedownloadHint/ttsCleaning;保留 hold/telEndpoint + en 段 7 stub + asrHotwords/kokoroModel 等字段名引用)。**920d3f3** 默认值微调(src/index.ts VOICE_SETTINGS_DEFAULTS.rate 1.0→1.1 + idleTimeoutMinutes 10→5 + Config schema + interruptLevel description 改进;src/client.tsx DEFAULT_BOOT/bootNow 同步;settings-form.tsx `??` 兜底;strings.ts descInterrupt/descIdle/descRate 中英文案。**字段名零变化**保 schema 兼容 + user settings.yaml 向后兼容)。**ca9f005** a11y 微调(settings-form.tsx 折叠按钮 aria-controls + 折叠体 id 配对 + NumberField 拒绝 `raw.endsWith('.')` 与 `raw.split('.').length > 2`;client.tsx padStart 双位补零 mm:ss)。**2d646d9** lib rebuild 让产物对齐源码(chore(lib) commit 收尾)。**6 项反向断言亲跑**:删 `telEndpoint` → tsc TS2322 报错 ✓;删 aria-controls / padStart / NumberField.endsWith 校验 tsc 不报错(运行时退化无单测覆盖);hold 键删除 tsc 0 输出 + npm test 254 全绿(实际零引用,删除安全)。**npm test 18 文件 / 254 项全绿**。**跨 commit silent revert 检查全过**:4 commit 各仅做一件事(acfa6fc 仅 strings.ts / 920d3f3 默认值 + desc / ca9f005 a11y / 2d646d9 仅 lib)。**不变量 I1-I10 全部守恒**:asr-host.ts/tts-queue.ts/asr.ts/tts-local.ts/tts-vits-worker.ts/sense-worker.ts/aec.ts/package.json 4 commit 全 0 diff ✓;I6 9 锚点逐字未动 ✓;I10 默认行为守恒字段名 100% 一致旧 user settings.yaml 兼容。**10 批次周全修复全部完成**:批 A markStale + watch diff + pump catch / 批 B client fetchConfig 5 ASR 字段透传 / 批 C FIELD_LABELS 7 中文 + strings.ts 同步 / 批 D tts-local 拼帧段后置 + emotion.ts:30 注释反向 + stripEmotionTags 删除 / 批 E endpointConfirmMs 200ms + 预热前置 + timeout 20s / 批 F spokenFormat 注释 + matchBackchannel 守卫 + effectiveNote 文案 / 批 G 5 任务(重做后 PASS-WITH-MINOR)/ 批 H TTS toast + 字幕 + mic 对比 + autoResume / 批 I UTF-8 重建 + ADR 数字 + README + /preview 错误 / 批 J 死代码清理 + 默认值微调 + a11y。**批 K 收口**待执行(build+test / git log 复盘 / systemctl restart + 真机冒烟 / STATE+CONTEXT 回写 + ADR-0007/0008 落地标注 + 可选 verify:dual)。 | | 7 批 K 周全修复收口 | ✅ | 15be91a | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 4 Important + 7 Minor + 3 Open**。**4 Important 全部接受统一派批 L 修**:**I1** 文档 baseline 锚点 6 处过期(c2120d9 → 应为 15be91a)。**I2** 文档「191 项单测」→「实际 254 项」过期。**I3** 文档 1.2 步骤中 2 处标签与源码不符(识别语言 → 识别语种 / ITN 数字规范化 → 逆文本归一化)。**I4** 文档 7.4 步骤对照表默认值与用户实测值混用(captionMaxWidth 默认 1 vs 用户配置 2)。**7 Minor 全部接受**:M1 文档标题措辞模糊 / M2 5 审计轴 vs 10 批次分类正交 / M3 按住 Ctrl+Shift+V 实际默认 mode='toggle' / M4 滴声 wakeWord 默认空 / M5 wake word 默认未配置 / M6 line 386 用户运维数据混入清单 / M7 line 386 文件总行数 386 vs wc -l 385(末尾无换行)。**3 Open 全部接受**:Q1 line 374 覆盖率自相矛盾(已补 test/asr-host-rebuild.test.mjs 9 项未同步)/ Q2 31 项修复出处不明(建议明确 commits ≠ 修复项口径)/ Q3 5 审计轴与 10 批次分类正交。**核心证据**:收口范围 `git show 15be91a --name-only` 仅 2 文件(lib/client.js BUILD_TAG 对齐 + docs/qa/real-machine-acceptance-checklist.md 新文件 386 行)src/ 完全未触动 ✓;10 批次周全修复历史完整(批 A 78574ad / 批 B e952583 / 批 C 44b6775 / 批 D 2d247f6 / 批 E 921334e / 批 F 5ded5d4 / 批 G 重做后 / 批 H / 批 I / 批 J + 8 docs(state) + 4 chore(lib) + 1 plan 起草 0b00856 全部齐全);dsh 服务 systemctl is-active dsh → active;MainPID=2531181;journalctl 最近 2 分钟 0 err;curl /voice-mode/config 7 字段全 non-null + 类型正确(asrHotwords='dsh-voice-mode\n' str / asrHotwordsScore=1.5 float 1-5 / recognitionLanguage='auto' str 6 语种之一 / senseITN=True bool / captionFontSize=0 int 0-3 / captionMaxWidth=2 int 0-2 / backchannelYield=True bool);npm test 254/254 全绿(18 文件 segmenter 13 + aec 10 + download 3 + endpoint 7 + endpoint-short 17 + resample 5 + sense-worker 8 + detect-route 6 + verify-client 40 + hotwords 11 + asr-host-rebuild 9 + sense-lang 10 + caption-a11y 20 + emotion 16 + emotion-tts-local 7 + emotion-integration 9 + backchannel 30 + strings-coverage 33);tsc×2 全过;build.mjs 重建成功 BUILD_TAG 自动对齐 HEAD;7 阶段 21 项文档结构完整;verify:dual 跑过(4 版锚点 + 8 typecheck + 2 runtime 冒烟)。**ahead origin/main = 40**(未 push,按收口不 push 纪律)。**批 L 放行**(docs/qa/real-machine-acceptance-checklist.md 单文件锚点同步:6 处 c2120d9 → 15be91a + 2 处 191 → 254 测试数 + 2 处中英文案 + 1 处默认值表注脚 + 7 Minor + 3 Open 文案微调)。 | | 7 批 L 收口文档锚点同步 | ✅ | d5c13c1 | **审查 subagent Verdict = PASS-WITH-MINOR**:**无 Blocker / 3 Minor + 3 Open 全部接受**。**3 Minor 接受不修**:**M-1** lib BUILD_TAG 与文档声称 15be91a 不符(实测 0b69c38,历史既定模式,build 在 commit 前跑——本批不改,建议下次 chore(release) 附 chore(lib) rebuild)。**M-2** line 4 breakdown 数字 7 docs(state) / 6 docs(adr) / 3 chore(lib) 与实际 11 / 1 / 3 不一致(commit 数数学对得上但括号内 breakdown 不自洽——文案数字偏差不影响功能)。**M-3** commit message 行号 line 384/387 vs 声称 385/386 漂移 ±1-2 行(历史既定模式接受不修)。**3 Open 接受不修**:**Q-1** 「逆文本归一化」中文表述业界存疑(与源码一致即可)。**Q-2** 「31 个 commit」 vs 「31 项修复」 口径未显式区分。**Q-3** 覆盖率统计 53%+10%+8%+4% = 75% ≠ 100%(历史问题)。**核心证据**:单文件 1 commit(`docs/qa/real-machine-acceptance-checklist.md` 60 行改动 34+/26-);src/ lib/ 完全未触动(git diff d5c13c1 -- src/ lib/ = 空);6 处 baseline 锚点 c2120d9 → 15be91a(line 3/29/310/384/387)— grep c2120d9 = 0 命中 ✓;测试数 191 → 254(line 362/385)— grep 191 = 0 命中 ✓;覆盖率 71% → 53% ✓;emotion 19 → 16(line 350/351/373)— grep `^t(` emotion.test.mjs = 16 项 ✓;中英文案 line 43/88/99(识别语言 → 识别语种 / ITN 数字规范化 → 逆文本归一化)— grep 0 命中且 strings.ts:175-176 + settings-form.tsx:79-80 源码一致 ✓;默认值表注脚 line 299(captionMaxWidth 默认 1 与用户配置 2 区分)✓;M1-M7 标题/toggle/唤醒词/提示音/用户配置独立段/末尾 newline 全到位 ✓;Q1 asr-host-rebuild 9 项已补 ✓;Q3 31 commits ≠ 31 修复项明确 ✓;文件 UTF-8 无 BOM(hex dump 首 3 字节 = `23 20 e7` 非 EF BB BF)✓;末尾 newline ✓;tsc×2 全过 + npm test 254 项全绿 + build 成功 ✓。**ahead origin/main = 42**(未 push,按收口不 push 纪律)。 |