# 修复清单与逐条证据(space polish R5,round2) 取证轮结论 → 编号修复 → 验证证据。设计依据全文见 docs/design/04-space-rebuild.md「修订记录 R5」节。 ## F1 刺耳音效重合成(P0) **嫌疑清单(round1 客观数据,research/space-polish/round1/sfx-spectrum-analysis.txt)** | id | 前真峰值 | 前≥3kHz | 前≥5kHz | 前质心 | 暴露频率 | |---|---|---|---|---|---| | alarm | -4.00 | 82.3% | 63.9% | 7580Hz(峰 16kHz) | 每颗陨石 2 遍、全程 4s 间隔 | | dodge | **-2.30** | 63.6% | 50.2% | 6330Hz | 每次闪避 | | shield_block | **-2.60** | 52.2% | 40.2% | 4692Hz | 保护期每 4s(比 alarm 还密) | | boost | **-2.70** | 53.0% | 43.9% | 5637Hz | 每次加速 | | shield | **-2.90** | 1.2% | 0.5% | 499Hz | 峰值超标 | **修复**:`tools/gen_space_syn.py`(新建,参照 gen_cipher_syn.py 先例)程序合成重制 5 件 + 新增 whiff。 低谐波设计:alarm=700/560Hz 电子双音、dodge=500→2100Hz 气声扫频、shield_block=250-2300Hz 电涟、 boost=55-93Hz 低哼+暗频推进、shield=320→980Hz shimmer。one-shot QC 全过(去直流+8ms cos²+ 编码后 ebur128 真峰值 ≤-3dBFS + 解码回读 ≥3kHz 能量)。 **修后数据(round2/sfx-spectrum-after.txt,与修前同口径)** | id | 后真峰值 | 后≥3kHz | 后≥5kHz | 后质心 | |---|---|---|---|---| | alarm | -3.50 | 0.0% | 0.0% | 593Hz(前 7580) | | dodge | -3.90 | 0.0% | 0.0% | 1090Hz(前 6330) | | shield_block | -3.90 | 0.0% | 0.0% | 1271Hz(前 4692) | | boost | -3.60 | 0.0% | 0.0% | 114Hz | | shield | -3.40 | 0.0% | 0.0% | 784Hz | | whiff(新) | -4.80 | 0.0% | 0.0% | 461Hz | 四席人设评审刺耳清单(alarm/dodge/shield_block/boost)全部消除;whoosh_*/crash/hit 修前即干净,未动。 ## F2 保护期结束死亡窗:归因防顶断 replay(P0) **修前证据(round1 live-A transcript 行 261-331,ta 151.13-163.13)**:裸飞期逼近 4.0s=刷怪 4.0s, 撞击与下一颗 spawn 同窗 → `hit_left`/`hit_down` vstart 与 kill 同时间戳(**零毫秒归因**), protect_end 被顶到 0.5-3.5s,8 秒三连撞至死不知方位。TRUNCATED 占比 39%(38/97)。 **修复**(web/space/game.js):呼喊生存优先裁定不变;`hit_`/`protect_end` 起播经 `_defendVoice` 登记,被顶断时登记残留,呼喊播完 onComplete → `_replayDefended` queue 补 replay(hit_last 排其后,先因后果)。 **修后证据(round2 live-A events,live-A-voice-timeline.txt)**:同窗口复现两轮—— - 轮 1(ta 160.3-168.3):hit_left 零毫秒被杀 → 160.79 **replay 完整播 3.5s**; hit_right 零毫秒被杀 → 164.78 **replay 完整播 3.5s**(两轮各自闭环)。 - 轮 2(ta 253.9):hit_right 被杀 → 254.38 replay 播完 257.9。 - protect_end 被顶断 → replay 补播(B 局 ta 64.69 第二轮 vstart)。 - playtest.mjs 新增断言:登记残留→补 replay→replay 播完接 hit_last→4 条全绿(S1 172/172)。 ## F3 保护期 protect_* 七连截断 → 去重 **修前**:6.96s 教学句对 4.0s 刷怪间隔,live-A 保护期 7 连 TRUNCATED(transcript 行 367-473), 每句都截在同一位置、同一句话重复 7 遍。 **修复**:上一句 protect_ 在播时新吸收只发 shield_block 音 + WARNING 震(`_protectSaying` 去重)。 **修后**:live-A' ta 102.3 protect_up **sim=1.0 完整播出**(修前同句 sim 0.33-0.63); 110.3 第二次吸收在播句刚结束时正常起新句。playtest 去重断言 2 条绿。 ## F4 状态盲区:protect_soon 50s 预告 **修前**:保护期结束无任何提前量,P4(反应慢)/P3(打断恢复)最受伤的时刻恰是信息最乱的时刻。 **修复**:开局 50s 播报新句「训练护盾还剩十秒。」(`protect_soon`,queue 不顶句,打断由 _rearmRunTimers 补播)。 **修后**:live-A' ta 149.8 sim=1.0 OK(ASR 完整识别);live-B' ta 53.8 OK。 playtest 断言绿。对局期 status key 维持 00 §5 豁免表裁定(不新增手势,见 04-space-rebuild R5 末条)。 ## F5 动作反馈盲区:加速冷却拒绝 **修前**:冷却中单击全静默(护盾拒绝有回音、加速没有);P1/P2/P4 三席点名。 **修复**:`_deny(now, voiceId)` 共用 4s 去抖(护盾拒绝同路径、原句不变); 新句 `boost_not_ready`「引擎还在冷却,稍等一下。」+ HEARTBEAT 震。 **修后**:playtest 4 条断言绿(拒绝播报/不重置加速/HEARTBEAT/去抖);live-B' 资产实测加载、 护盾侧拒绝 echo 在乱按下反复兑现(feat_shield_done ×6 vstart)。 ## F6 激活确认震动(兑现 04 §5 旧承诺) **修前**:boost/shield 激活(对局期+feature 期)均无 CONFIRM 震,文档 §5 承诺未兑现。 **修复**:4 处激活点补 `vibrate('confirm')`。playtest 断言 2 条绿(delta 计数)。 ## F7 挥空/滑错方向反馈 **修前**:无效手势与成功闪避同静默(dodge 音只在判定时响),玩家怀疑输入失灵。 **修复**:playing 期滑向无悬置陨石方向 → `sfx/whiff` 轻叹(0.55 音量;引擎 swipe 震动已有"收到")。 **修后**:live-B' 乱按中 whiff 实测触发 3+ 次(events 28.9/33.5 等);playtest 断言绿。 ## 验证数字汇总 - web/space/test/playtest.mjs:**172 通过 / 0 失败**(新增 R5 断言 15 条) - web/harness/guide.test.mjs:**122 通过 / 0 失败** - tools/check_all_assets.py:**全项目绿**(space 184 文件/各 61 id,新增 2 句 ×2 性别 ×2 格式) - 回归:其余 14 款游戏 playtest 全绿(abyss/bridge/cipher/detective/dungeon/escape/hunt/keeper/radio/rhythm/rpg/simon/storyline/teahouse) - 刺耳复测:F1 表(全部 ≤-3.4dBFS、≥3kHz 0%) - live 复跑(8141):A' 两轮保护期结束窗归因 replay 全闭环 + protect_soon OK ×2 局; B' 零 console.error,whiff/护盾拒绝/protect 链全部实测触发 ## 遗留清单 1. `voice/shield_block`(格挡确认句)不在防顶断登记内,保护期吸收高峰时仍可能被呼喊顶断—— 有 shield_block 音效+WARNING 震落位,残损可接受;如后续投诉再纳入登记。 2. live 复跑因 harness 手势派发延迟(峰值 46s,listen ASR 竞争)未能实机验证 boost_not_ready 语音出声(资产加载、去抖路径、whiff 均实测;boost 拒绝语义由 playtest 覆盖)。建议真机人耳复测。 3. gd_last_life(向导层"撑住"句)仍可能被后续呼喊顶断(guide.error 无 onComplete 钩子, 引擎不可改);优先级低于归因句,未纳入本轮。 4. `hit`(受击音)≥3kHz 30.7% 未重合成——四席评审均未点名(低频主导的撞击感成立),保留。 5. gen_voice_dual.py --check 对本机缺旧 space staging wav 报「缺 male/female」59 条—— 环境存量问题(旧 wav 未随仓库保留),与本轮无关;新句两性时长健康(2.48/1.52s、3.28/3.04s)。