kitt-stt · dev-report · 2026-09-02-switchable-wake-provider

可切換 KWS Method:STT / Manual

Wake arbitration 永遠啟用。Typed kws.method.name 選擇是否以 final transcript 執行 match_wakekws.method.stt_cfgs 保留為已驗證的空設定物件。兩種 method 共用 Web UI/LM control、bypass、exit word、state、timeout 與 EOT。本輪不引入 iGo、DSpotter、VID 或聲學音訊介面。
狀態:Rebase 驗證完成;整套測試非全綠 分支 feat/switchable-wake-provider Offline 906 passed / 8 failed / 1 skipped STT live 56 passed / 28 failed / 4 skipped Manual live 4 passed

🎛️本輪 · KWS method 實作與驗收

結論

kws.method.name=sttWakeBypassMatcher.match_wake 比對 final transcript; kws.method.name=manual 跳過 match_wakestrip_wake_prefix。 Wake arbitration 不再有 Boolean gate;兩種 method 都保留 Web UI Active/Standby、match_bypass、exit word、state、timeout 與 EOT。預設為 stt

906
offline passed · 另有 8 failed / 1 skipped
STT
default method
Manual
Web UI controlled
0
feature-gate branches
4
new SW contracts

ID 對照:歷史測試子項

以下代號只用來保留歷輪測試追溯,不代表本次 KWS cycle 新增的驗收條件。

ID所屬 cycle/意義
A12026-07-29 排程:沒有前次延遲時使用 initial_interval。
A22026-07-29 排程:間隔為延遲 × margin,設地板但不設上限。
A32026-07-29 排程:margin 必須大於 1。
A42026-07-29 排程:最小間隔必須大於 0。
A52026-07-29 排程:初始間隔必須大於 0。
A62026-07-29 排程:環境變數可覆寫 YAML margin。

名詞定義

名詞/ID意義與本報告用途
KWS / STT / ASRKWS 是喚醒詞偵測;本版用 STT(語音轉文字,也稱 ASR)的 final transcript 做文字比對,尚無聲學 KWS。
Active / Standby / manualActive/Standby 是共用喚醒狀態;manual 是略過 match_wake 的 method,不等於 Standby。
VAD / segment / turnVAD 偵測語音起訖;一段 VAD 音訊是 segment,一次送交下游的對話輸入是 turn,可包含多段 segment。VAD stop 不一定結束 turn。
EOT / TurnSenseEOT 是 turn 結束判定;TurnSense 提供語尾評分,EotController 結合 wake、強制停止與等待規則選擇 commit/wait/cancel。
HR / ITN / s2tHR 是同音替換,配置於 recognizer;ITN 將口語數字正規化,包含 OpenCC s2t(簡轉繁)。interim 只做 s2t,final 做完整 ITN。
fbank / LFR / CMVN聲學前處理的濾波器組特徵/低幀率堆疊/均值變異數正規化。stream 沿用的是特徵,不是沿用 interim 文字。
RTF / CER / WER處理時間與音訊時長之比/字元錯誤率/詞錯誤率。累積測試含效能與辨識檢查,但本報告不把舊量測當作 rebase 後的效能比較。
SNR / FP32 / bf16訊噪比與浮點精度格式。出現在累積訓練/模型測試;本次 live 使用 CUDA、FP32,不代表其他格式已做 live 驗證。
TensorRT / execution provider / sm89模型執行後端與 GPU 架構;RTX 4090 為 sm89,TensorRT engine 受 GPU/版本相容性限制。model.provider 與 kws.method.name 是不同設定。
MatMulInteger / MatMulNBits / QDQ量化矩陣乘法算子與量化/反量化節點;累積測試保留部署相容性檢查,不代表本次執行量化模型。
SW_id / PRD F_id / UXSW_id 是 SW 規格的穩定需求編號;PRD F_id 是產品功能分組;UX 條款補充互動要求。附錄 B 行為欄描述要求,結果欄描述驗證,兩者不等同。
歷史驗收 ID附錄 B 的 A1–A6 是 2026-07-29 排程驗收;B1/B2 是 interim/final ITN 拆分;B14-R1、B14-R2、B19-R1、B19-R2、B19-R3 是既有併發測試子項,不是本次 KWS 的新需求。

Plan 與範圍

設計與施工依據: 2026-09-02-switchable-wake-provider-design.md2026-09-02-switchable-wake-provider.md。 本輪只交付 stt / manual;未來 iGo / DSpotter acoustic authority、generation/sample clock 與 One-shot 音訊裁切仍屬後續 cycle。

kws.method.nameRuntime 行為
stt(預設)執行 match_wake;命中時執行 strip_wake_prefix
manual跳過 match_wakestrip_wake_prefix;保留 Web UI/LM control、match_bypass、exit word、state、timeout 與 EOT

Architecture 與 frame flow

KWS method Speech path KittSttService 收到 ASR final 後,stt 執行 wake-word matching 並在命中後移除 wake prefix,manual 跳過兩者;兩條路徑匯入共用的 bypass、exit word、final 輸出判斷與 EOT 流程。 Speech path KittSttService · kws.method.name 決定 wake-word matching stt manual SenseVoice ASR final final transcript kws.method.name? STT wake-word match match_wake 命中後 strip_wake_prefix Skip wake-word match 跳過 match_wake 不呼叫 strip_wake_prefix Shared final processing match_bypass · exit word _should_emit_final · EotController.apply 菱形:method 選擇 圓點:兩條路徑匯合,共用後續處理
圖 1 · Speech path:kws.method.name 只決定是否呼叫 match_wake;兩條路徑之後使用相同的 final processing。
架構圖解
Frame / input方向觸發條件動作Owner
InterruptionFrame(agent_active)Web UI → STTstt / manualroom-wide Active,啟動 shared timeoutKittSttService.process_frame
InterruptionFrame(agent_standby)Web UI / LM → STTstt / manualroom-wide Standby,丟棄 pending turnKittSttService.process_frame
ASR final transcriptinternalsttmatch_wake;命中時執行 strip_wake_prefix_finalize_utterance_impl
ASR final transcriptinternalmanual跳過 match_wakematch_bypass 仍執行_finalize_utterance_impl

本輪 acceptance 與 Feature-first traceability

PRD FeatureSW_idBehaviourExecutable evidenceResult
STT_EXTRASW-W-19stt / manual 切換是否執行 match_waketest_kws_method_policy.py · test_kws_method_manual.py✓ PASS
STT_EXTRASW-B-12manual 跳過 match_wake;保留 final 路徑的 match_bypass(已驗證 exact/prefix)test_kws_method_policy.py · test_kws_method_manual.py部分覆蓋
STT_EXTRASW-UI-07Web UI/LM Active/Standby control 對兩種 method 共用test_kws_method_policy.py · test_btn_control.py✓ PASS
STT_EXTRASW-CFG-03kws.method.name 只接受 stt / manual;舊設定鍵會回報 validation errortest_kws_method_config.py · test_status_page_settings.py✓ PASS
GateCommand / environmentResult
Targeted offline.venv/bin/python -m pytest -q tests/test_kws_method_config.py tests/test_kws_method_policy.py tests/test_status_page_settings.py tests/test_eot_state.py tests/test_turn_arbitration.py48 passed
Offline fullUV_NO_SYNC=1 ASR_PORT=65534 ./tests/test.sh -q(live 另以隔離容器執行)906 passed, 8 failed, 1 skipped
Default STT liveUV_NO_SYNC=1 HOST_PORT=19342 IMAGE=kitt-stt:rebase-20260905 ./tests/docker-test.sh --build · RTX 4090 / CUDA56 passed, 28 failed, 4 skipped · 57m56s
Manual liveUV_NO_SYNC=1 HOST_PORT=19343 IMAGE=kitt-stt:rebase-20260905 KWS_METHOD=manual LIVE_TEST_TARGET=tests/functional/live/test_kws_method_manual.py ./tests/docker-test.sh --build4 passed · 17.26s
490ms 單項重測UV_NO_SYNC=1 HOST_PORT=19344 IMAGE=kitt-stt:rebase-20260905 LIVE_TEST_TARGET='tests/functional/live/test_remaining_ux_gaps.py::test_command_wait_timeout_boundary[490ms-one-turn]' ./tests/docker-test.sh --build -s · CUDA1 failed · 7.02s · 已包含在全套 28 個失敗中,不重複計數
StaticBranch runtime/config 與 KWS 測試 Ruff;method/config/policy 測試 scoped Pyright;bash -n、git diff --check範圍內 0 errors;全樹 Ruff 29 項,與 main 相同
2026-09-05 驗證基準

本次基底為 main@4ee1821。離線 8 個失敗均在乾淨 main 重現:test_ai_agent_ux_spec.py 的退出詞清單/英文大小寫、500ms command wait timeout 與拒識門檻。KWS focused tests 為 48 passed;整套測試不宣稱全綠。

STT live 的 4 個 skipped 是 manual 專用測試,另以 kws.method.name=manual 執行。28 個 live 失敗包含斷句、問候抑制/第二次問候、中英混用、prefix 跨段、退出詞、拒識與延遲門檻;本次未重跑乾淨 main 的 live suite,因此不將它們全部判定為既有失敗或 rebase 迴歸。

490ms 斷句:FAIL,暫不修復
STT live 失敗明細(28 項;檔案皆位於 tests/functional/live/)

🏗️附錄 A · STT SW Stack 架構與資料流

STT SW stack · KWS method branch(2026-09-05) kitt-core FrameProcessorServer msgpack / WebSocket KittSttService(src/kitt_stt_service.py) per-connection processor · per-user UserSession(src/session/) interim 路徑(偽串流) 反應式排程決定「何時重解」 持續 stream 只餵新增音訊 後處理只做 s2t final 路徑(權威) 整段重新解碼 沿用 interim 的 stream,只補尾巴 HR(recognizer)→ ITN(詞庫) 已抽好的 fbank BatchASRManager(src/asr/batch_asr_manager.py) 一個 recognizer + 一把鎖 · SherpaOnnxModelCache 單例(preload) 喚醒與 turn 控制 KWSStreamManager · EotController offline SenseVoice(sherpa-onnx,CUDA) sherpa-onnx-sense-voice-kitt-wake-lora-v1 · FP32 kws.method.name stt | manual
圖 A1 · STT SW stack。interim 與 final 共用 recognizer;final 可沿用 interim 特徵 stream,只補未餵入的尾端音訊。KWSStreamManager 管理共用喚醒狀態,不載入聲學模型;EotController 管理 turn 結束。這些是既有機制,本 cycle 新增的是 KWS method 選擇。

ASR final 的分支見上方 Speech path。完整 Frame 契約如下;Web UI 控制不屬於 method hierarchy。ITN 已承接 main 的詞庫實作,未把舊 cycle 的延遲量測當作本次數據。

Frame方向觸發 case動作/條件位置
StartFrameINpipeline 啟動初始化設定與模型;session manager 由 service 建構時建立。src/kitt_stt_service.py:314
AudioRawFrameIN音訊到達依 utterance 狀態加入 segment buffer 或 preroll;符合 _should_emit_interim 才排程 interim。src/kitt_stt_service.py:893
VADUserStartedSpeakingFrameINVAD 開始建立/延續 turn,重置 segment 狀態;延續等待中的 turn 時取消等待。src/kitt_stt_service.py:672
VADUserStoppedSpeakingFrameINVAD 停止快照音訊、交棒 stream,執行 final ASR 與 TurnSense;VAD stop 不等於 EOT commit。src/kitt_stt_service.py:774
UserStarted/StoppedSpeakingFrameIN上游 speaking 邊界交由 kitt-core 基底處理;本服務的 per-user ASR 路徑由 VAD frame 驅動。src/kitt_stt_service.py:877
BotStarted/StoppedSpeakingFrameINTTS 播放起訖更新播放狀態與共用 idle timeout。src/kitt_stt_service.py:907
InterruptionFrameINreason=agent_active / agent_standbyWeb UI/LM 改變 room-wide 狀態;standby 丟棄 pending turn。src/kitt_stt_service.py:992
STTUpdateSettingsFrameIN更新設定透過基底的設定更新路徑套用 delta。src/kitt_stt_service.py:1177
EndFrameIN連線結束收尾並清理 session;不讓未完成 turn 留到下一連線。src/kitt_stt_service.py:1033
ASRMetadataFrameOUT啟動/final 座位量測回報模型資訊或座位負載量測;不是權威文字載體。src/kitt_stt_service.py:314 / src/kitt_stt_service.py:1217
InterimTranscriptionFrameOUTinterim 有新文字/清除顯示一般 interim 只做 s2t;無可送 final 時可能送空 interim 清除畫面。src/kitt_stt_service.py:1278
TranscriptionFrameOUT非空 final 且 _should_emit_final 通過權威文字;segment 的 eot.model 隨文字傳遞,僅 commit carrier 帶 eot.decision。src/kitt_stt_service.py:1681
ZonalUserStoppedSpeakingFrameOUTtimeout/wake-only/ASR error 等無 final 的 commitexplicit stop 承載 eot.decision;不是每個 final 都另送 stop。src/eot.py:155
InterruptionFrameOUT喚醒成功/退出詞/無匹配/idle timeoutreason=agent_active 或 agent_standby;通知下游狀態。src/kitt_stt_service.py:583 / src/kitt_stt_service.py:471
TTSSpeakFrameOUTStandby 的純喚醒詞符合 wake-only 條件時送招呼語,再以 explicit stop 關閉該控制 turn。src/kitt_stt_service.py:1801

附錄 B · 測試(累積)

驗證基準:2026-09-05 · main@4ee1821 + KWS method branch

Feature 總覽

下表計算需求列,不是 pytest case 數;同一需求可能跨 Feature,同一測試也可涵蓋多個需求,因此各組不能相加當成測試總數。執行命令見本輪驗證表

PRD F_idFeature有 STT SW_id?需求列數2026-09-05 驗證狀態
F_2One-shot(喚醒詞 + 指令連說)有;見分組細表12 個需求列PASS 10 / FAIL 2
F_3聆聽等待 / 智慧斷句 / 解除喚醒時機有;見分組細表26 個需求列PASS 18 / FAIL 6 / PARTIAL 2
F_4.3語音打斷 Barge-in / 解除喚醒詞有;見分組細表3 個需求列FAIL 1 / PASS 2
UX 專有PRD 無對應 F_id有;見分組細表3 個需求列FAIL 2 / PASS 1
STT_EXTRAPRD 未描述、STT 已具備有;見分組細表65 個需求列PASS 53 / PARTIAL 1 / — 9 / FAIL 1 / SKIP 1
F_1多音區識別/控制下游/OUT_OF_SCOPE未執行下游驗收
F_4.1背景併行下游/OUT_OF_SCOPE未執行下游驗收
F_4.2後令壓前令下游/OUT_OF_SCOPE未執行下游驗收
F_5連續指令下游/OUT_OF_SCOPE未執行下游驗收
F_6上下文理解下游/OUT_OF_SCOPE未執行下游驗收
F_2 · One-shot(喚醒詞 + 指令連說)
SW_id行為(規格)測試結果
SW-W-03Standby→Active(喚醒詞在句首):喚醒詞+指令連說,辨識其後之指令;喚醒詞不得出現在 final,且不得因前期聽歪而誤顯示喚醒詞test_wake.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-04喚醒詞 <停頓> 指令 亦能喚醒,final 無喚醒詞test_wake.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-05喚醒詞不在句首不觸發test_standby.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-08Active 期間:喚醒後任何話都辨識並往後送;句首喚醒詞於 final 過濾、非句首喚醒詞保留;interim 出現喚醒詞可接受test_active.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_active.py::test_active_wake_filter
SW-W-09Active 句首喚醒詞 + smart-turn,仍不顯示喚醒詞test_active.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_active.py::test_active_smart_turn_wake_head
SW-W-13Standby 第一句未命中 → turn 關閉,故第二句句首的喚醒詞是新 turn 的句首正常觸發喚醒test_smart_turn_wake.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-14英文出廠喚醒詞 Hi Foxtron 須觸發(大小寫無關),且喚醒詞不得留在 finaltest_wake_factory_words.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
SW-W-15第一次主動問候的時機UX§1.3.2):喚醒成立後須送出問候的 TTSSpeakFrame,STT 側上界 500mstest_active_greeting.py · test_wake_latency.py✗ FAIL
2026-09-05 STT live:1 passed / 1 failed。
test_active_greeting.py::test_ux_1_3_2_first_greeting_is_sent_within_500ms
test_wake_latency.py::test_wake_only_greeting_fits_the_response_budget
SW-W-16喚醒成立後 <550ms 內有人說話 → 不觸發第一次主動問候。窗的起點是 InterruptionFrame(agent_active) 送出的那一刻——下游能觀測到的「喚醒成功」就是這個 frametest_active_greeting.py✗ FAIL
2026-09-05 STT live:0 passed / 4 failed。
test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[50ms]
test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[200ms]
test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[350ms]
test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[500ms]
SW-W-17喚醒詞+指令連說須觸發喚醒:連讀成一句時同樣要送出 InterruptionFrame(agent_active),不因喚醒詞未單獨成句而不通知下游test_active_greeting.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_active_greeting.py::test_ux_1_3_one_shot_wake_emits_active_like_a_bare_wake
SW-W-18喚醒詞+指令連說不得出現問候語:使用者在喚醒當下就把指令說完了,等同已在抑制窗內說過話test_active_greeting.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_active_greeting.py::test_ux_1_3_2_one_shot_wake_suppresses_the_first_greeting
SW-WM-01喚醒詞比對與剝除:latin 大小寫無關、分隔字元先剝除、喚醒詞後可直接接指令剝除喚醒詞後指令完整保留tests/test_wake_matcher.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
F_3 · 聆聽等待 / 智慧斷句 / 解除喚醒時機
SW_id行為(規格)測試結果
SW-W-01非喚醒(Standby):說喚醒詞以外任何句子,STT 不出任何文字、不往後送;相似音喚醒詞不得觸發test_standby.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-02非喚醒下說無關長語音,需立即 smart-turn stoptest_standby.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-07smart-turn 斷句不因 VAD 誤判過度斷句test_smart_turn_wake.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-09Active 句首喚醒詞 + smart-turn,仍不顯示喚醒詞test_active.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_active.py::test_active_smart_turn_wake_head
SW-W-10Active 期間 smart-turn 功能正常(跨段黏合)test_active.py✗ FAIL
2026-09-05 STT live:0 passed / 1 failed。
test_active.py::test_active_smart_turn
SW-W-11Active 第二句開頭喚醒詞不過濾(正常顯示)test_smart_turn_wake.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-W-12斷句前後不得因雜音產生語助詞(嗯/啊/喔)test_active.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_active.py::test_active_wake_filter
SW-W-13Standby 第一句未命中 → turn 關閉,故第二句句首的喚醒詞是新 turn 的句首正常觸發喚醒test_smart_turn_wake.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-WM-02alias 只能買回實測誤聽,不得擴大誤觸發:全中文 alias 與 canonical 距離 ≤1 字;普通語句不得誤觸發tests/test_wake_matcher.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-B-03Prefix + smart-turn 正常合併test_bypass_prefix.py✗ FAIL
2026-09-05 STT live:0 passed / 1 failed。
test_bypass_prefix.py::test_prefix_smart_turn
SW-B-08特定指令於 smart-turn 第一句句首觸發,只傳「關閉空調」test_bypass_cmd.py✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-B-10Standby 第一句未命中 → turn 關閉,故第二句句首的 Prefix 是新 turn 的句首正常觸發test_smart_turn_bypass.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-B-11同上,第二句句首的特定指令正常觸發test_smart_turn_bypass.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-X-01Timeout 15s:TTS 說完起算,15s 無人說話 → 回 Standbytest_timeout.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-X-02重新喚醒後 timeout 重新計時test_timeout.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-X-05第二次主動問候的時機UX§1.3.3):喚醒起算 =10秒 任何座位都沒說話 → 播「你好,需要我為你做什麼呢?」test_active_greeting.py · test_remaining_ux_gaps.py✗ FAIL
2026-09-05 STT live:0 passed / 2 failed。
test_active_greeting.py::test_ux_1_3_3_second_greeting_fires_at_10s_when_nobody_speaks
test_remaining_ux_gaps.py::test_ten_second_prompt_stage_exists_end_to_end
SW-X-0610 秒內有人說話 → 不觸發第二次主動問候test_active_greeting.py部分覆蓋
2026-09-05 STT live:1 passed / 0 failed。
test_active_greeting.py::test_ux_1_3_3_speaking_within_10s_suppresses_the_second_greeting測項 PASS,但未驗證第二次問候確實發生;SW-X-05 為 FAIL,不能據此宣稱完整 UX 時序成立。
SW-X-07退出聆聽路徑一UX§1.3.4):第二次問候播完後=5秒 無人說話 → 回 Standbytest_active_greeting.py部分覆蓋
2026-09-05 STT live:1 passed / 0 failed。
test_active_greeting.py::test_ux_1_3_4_exits_5s_after_the_second_greeting測項 PASS,但未驗證第二次問候確實發生;SW-X-05 為 FAIL,不能據此宣稱完整 UX 時序成立。
SW-TURN-01一個 turn 內只有第一個 VAD segment 是 turn head;其餘為續段,不跑喚醒/免喚醒偵測tests/test_turn_arbitration.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-TURN-02續段的送出權依 bypass 種類授權:prefix 授予(SW-B-03 需要),exact 不授予SW-B-07 的語意)tests/test_turn_arbitration.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-TURN-03新 turn head 清除上一個 turn 的指令送出權,續段則保留tests/test_turn_arbitration.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-EOT-01STT 是唯一 EOT authority:每個 VAD stop 以語尾模型評分 turn tail(跨 segment,最後 8 秒),COMPLETE 立即結束 turn,INCOMPLETEINVALID 等固定秒數,上限 500msUX§3.1command_wait_timeout;可由狀態頁調整,見 SW-OPS-04);等待內有新語音則延續同一 turn。立即完成且有非空 final 時,文字與 eot.decisionaction=commit + reason)必須由同一個 TranscriptionFrame 原子傳遞;timeout 或無 final 時才以 UserStoppedSpeakingFrame 承載同一 commit contracttests/test_eot_state.pytests/turnsense/test_policy.pytests/test_eot_kws_precedence.pytests/test_ai_agent_ux_spec.py · livetest_remaining_ux_gaps.py✗ FAIL
2026-09-05 STT live:1 passed / 1 failed。
test_remaining_ux_gaps.py::test_command_wait_timeout_boundary[490ms-one-turn]
test_remaining_ux_gaps.py::test_command_wait_timeout_boundary[510ms-two-turns]離線 500ms 設定檢查亦 FAIL;490ms 預期 1 個 final、實際 2 個,510ms PASS。
SW-EOT-02KWS 事件(standby 無匹配/離開詞/agent_standby/連線結束)一律丟棄 turn,優先於強制停止與模型判定;被丟棄的 turn 永不進 LLM。ASR final 失敗不屬 KWS cancel:該段不送 transcription,改以 asr_error 結束 turn離線:tests/test_eot_kws_precedence.py · live(wire contract)test_forced_stop.py✓ PASS
2026-09-05 STT live:3 passed / 0 failed。
SW-EOT-05拒識門檻一:連續語音 >15 秒 → 不得往下游送test_rejection_thresholds.py✗ FAIL
2026-09-05 STT live:0 passed / 1 failed。
test_rejection_thresholds.py::test_ux_8_2_speech_longer_than_15s_is_not_forwarded
SW-EOT-06拒識門檻二:連續語音 >50 字 → 不得往下游送test_rejection_thresholds.py✗ FAIL
2026-09-05 STT live:0 passed / 1 failed。
test_rejection_thresholds.py::test_ux_8_2_speech_longer_than_50_chars_is_not_forwarded
SW-EOT-07兩門檻皆未越過者必須照常送出(拒識的反向對照)test_rejection_thresholds.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_rejection_thresholds.py::test_ux_8_2_speech_under_both_thresholds_is_forwarded_normally
F_4.3 · 語音打斷 Barge-in / 解除喚醒詞
SW_id行為(規格)測試結果
SW-X-04說解除喚醒詞 → 切 StandbyUX§2.1 指定 13 個:謝謝/再見/退出/退下/滾蛋/滾/Thank you/Thanks/Goodbye/ByeBye/Dismiss/Quiet/Shut up)livetest_exit_words.py · test_btn_control.py · 離線比對層:tests/test_exit_word.pytests/test_ai_agent_ux_spec.py✗ FAIL
2026-09-05 STT live:1 passed / 12 failed。
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u8b1d\u8b1d]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u518d\u898b]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u9000\u51fa]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u9000\u4e0b]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u6efe\u86cb]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u6efe]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Thank you]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Thanks]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Goodbye]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[ByeBye]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Quiet]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Shut up]
test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Dismiss]離線退出詞清單/英文大小寫檢查亦 FAIL。
SW-WM-03退出詞 alias 必須錨定到已設定的退出詞:alias 群組的 canonical 不在 exit_words 內則整組忽略tests/test_wake_matcher.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-EOT-02KWS 事件(standby 無匹配/離開詞/agent_standby/連線結束)一律丟棄 turn,優先於強制停止與模型判定;被丟棄的 turn 永不進 LLM。ASR final 失敗不屬 KWS cancel:該段不送 transcription,改以 asr_error 結束 turn離線:tests/test_eot_kws_precedence.py · live(wire contract)test_forced_stop.py✓ PASS
2026-09-05 STT live:3 passed / 0 failed。
UX 專有 · PRD 無對應 F_id
SW_id行為(規格)測試結果
SW-X-08拒識之後必須維持聆聽UX§10.2):越過 UX§8.2 門檻的語句丟棄不往下送,但不得因此離開 Active——拒識是「裝沒聽到」,不是「結束這一輪」test_rejection_thresholds.py✗ FAIL
2026-09-05 STT live:0 passed / 2 failed。
test_rejection_thresholds.py::test_ux_10_2_rejection_keeps_the_room_listening[over-15s]
test_rejection_thresholds.py::test_ux_10_2_rejection_keeps_the_room_listening[over-50-chars]
SW-LANG-01整句英文指令須被辨識,且不需切換任何語言設定test_bilingual.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_bilingual.py::test_english_command_after_chinese_wake_word
SW-LANG-02同一句內中英夾雜時兩種文字都要保留:辨識器須在句中換文字系統,不是為整句選一種語言test_bilingual.py✗ FAIL
2026-09-05 STT live:0 passed / 1 failed。
test_bilingual.py::test_code_switching_within_one_command
STT_EXTRA · PRD 未描述、STT 已具備
SW_id行為(規格)測試結果
SW-W-19kws.method.name=stt 執行 transcript 喚醒;manual 跳過 match_wakestrip_wake_prefixtest_kws_method_policy.py · test_kws_method_manual.py✓ PASS
2026-09-05 focused offline 與 manual live 4 passed。
SW-B-12manual 保留 match_bypass;已驗證 current-segment exact/prefix,非句首與跨段尚未完整覆蓋test_kws_method_policy.py · test_kws_method_manual.py部分覆蓋
2026-09-05 focused offline 與 manual live 4 passed。僅 current-segment exact/prefix;非句首與跨段未完整覆蓋。
SW-UI-07stt / manual 共用 InterruptionFrame(agent_active/agent_standby) 控制test_kws_method_policy.py · test_kws_method_manual.py✓ PASS
2026-09-05 focused offline 與 manual live 4 passed。
SW-CFG-03kws.method.name 預設 stt、只接受 stt / manual;舊設定鍵拒絕啟動test_kws_method_config.py · test_status_page_settings.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-B-01Prefix(default「冷氣溫度*」「導航到*」):非喚醒下前綴符合即整句往後送test_bypass_prefix.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_bypass_prefix.py::test_prefix_trigger
SW-B-02Prefix 不在句首不觸發test_bypass_prefix.py✓ PASS
2026-09-05 STT live:1 passed / 0 failed。
test_bypass_prefix.py::test_prefix_not_at_start
SW-B-05特定指令(exact,default「關閉空調」):非喚醒下整句相符即往後送test_bypass_cmd.py✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-B-06特定指令 不在句首不觸發test_bypass_cmd.py✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-B-07特定指令句中夾雜其他話不觸發test_bypass_cmd.py✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-X-03按 WebUI 綠色 active 按鈕 → 回 Standbytest_btn_control.py✓ PASS
2026-09-05 STT live:6 passed / 0 failed。
SW-UI-01WebUI Standby 按鈕可啟動喚醒(灰→綠),之後任何話都辨識往後送test_btn_control.py✓ PASS
2026-09-05 STT live:6 passed / 0 failed。
SW-UI-02每次 connect 後狀態不壞:Connect→喚醒→disconnect ×5 都正常test_btn_control.py✓ PASS
2026-09-05 STT live:6 passed / 0 failed。
SW-UI-03頻繁切換穩定:連點喚醒按鈕 ≥10 次後,切換仍正常test_btn_control.py✓ PASS
2026-09-05 STT live:6 passed / 0 failed。
SW-UI-04連點後於 Standby 說「嗨鴻華」仍能觸發test_btn_control.py✓ PASS
2026-09-05 STT live:6 passed / 0 failed。
SW-UI-05講話中瞬間切 Standby,WebUI 不得有灰字卡住test_btn_control.py✓ PASS
2026-09-05 STT live:6 passed / 0 failed。
SW-UI-06講話中瞬間切靜音(mic),WebUI 不得卡住STT_EXTRA
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-01同車多 user 喚醒狀態同步(按鈕同開同關)—(歸屬:web-ui)
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-02多 user 按鈕/語音喚醒穩定度(交互點擊 ≥5 次仍正常)—(歸屬:web-ui)
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-03UserA 講話中(final 未送),UserB 切 standby → STT 立即停聽、WebUI 無卡字—(歸屬:web-ui + STT)
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-04新 connect 的 user 同步當前喚醒狀態—(歸屬:web-ui)
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-05開關 mic 不影響喚醒狀態同步—(歸屬:web-ui)
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-06多 user timeout 穩定:長句期間不得誤切 standby—(歸屬:web-ui + STT)
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-07自定義喚醒詞在多 user 間同步(含刪除同步)—(歸屬:web-ui)
無 STT 自動化驗證;下游行為不由本表判定。
SW-MU-08多車隔離:Car1 喚醒/自定義詞不影響 Car2—(歸屬:web-ui(STT 以 ?car= 分段))
無 STT 自動化驗證;下游行為不由本表判定。
SW-CFG-01可經 WebUI 客製化喚醒詞/免喚醒詞,行為與原廠一致test_stt_config.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-CFG-02刪除客製化詞後不再觸發test_stt_config.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-PERF-01連續長句(≥90 秒)講話期間,interim 重新解碼排程不得因緩衝區持續變長而失控卡住test_audio_stress.py✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-PERF-02反應式 interim 重解碼排程的設定解析:間隔由上一次解碼延遲 × 安全係數決定,並受下限約束tests/test_audio_cfg.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-PERF-03整車多人同時講話(1 條連線、4 個座位帶不同 user_id):interim 重新解碼排程不得因共用辨識器的鎖爭用而卡住每個座位都必須拿到自己的 final,且不得有非本車座位的 user_id(不串話)tests/functional/live/test_multiuser_concurrency.py(5 條)|離線機制測試 tests/test_interim_concurrency.py(13 條)、tests/test_itn_off_frame_path.py(3 條)✓ PASS
2026-09-05 STT live:5 passed / 0 failed。
SW-PERF-04喚醒通知須在 200ms 內送出UX§1.3.1):UI 動效由此 frame 觸發test_wake_latency.py✗ FAIL
2026-09-05 STT live:0 passed / 2 failed。
SW-PERF-05喚醒率回歸下限 ≥90%UX§1.1test_wake_rate.py✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-EOT-03語尾模型的音訊前處理必須與訓練時逐位元相同(fbank 80 → LFR 7/6 → CMVN,裁到最後 8 秒),否則三分類機率不成立tests/turnsense/test_frontend.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-EOT-04語尾模型只在 CUDA 上執行(與 SW-OPS-06 同一原則,見 kitt-stt-sw-spec.md §10):provider 未生效時伺服器拒絕啟動而非降級到 CPU;行程內單例、推論序列化且不佔用 event looptests/turnsense/test_runtime.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-01final 的 ITN:中文數字正規化 + 繁簡轉換tests/test_text_converter.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-02interim 與 final 的 ITN 刻意不同:interim 只做 s2t(),final 做完整 itn();故兩者在數字上可以不同,這是設計不是 bugtests/test_batch_asr_manager_itn_split.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-03 2026-09-04「這個數字字元是不是數字」由詞庫決定而非執行期斷詞器;緊鄰受保護詞的真數字仍必須轉換;執行期不得持有斷詞器(jieba 不在 runtime 依賴內)tests/test_itn_lexicon.py(43,offline)✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-04 2026-09-04整數與小數(含正負號)轉阿拉伯數字:1負十-10負三點一四一六九九九九九-3.141699999test_text_converter.py::test_allpytest -k "G1- or G2- or G12-"✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-05 2026-09-04百分比(含正負號)轉阿拉伯數字:百分之一1%百分之負零點五-0.5%test_text_converter.py::test_allpytest -k G3-✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-06 2026-09-04分數(含正負號)轉阿拉伯數字:二分之一1/2負三分之一-1/3test_text_converter.py::test_allpytest -k G4-✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-07 2026-09-04日期/時間:數字轉阿拉伯數字,單位詞維持中文一月五號1月5號十一點五十九分五十九秒11點59分59秒test_text_converter.py::test_allpytest -k "G5- or G8-"✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-08 2026-09-04程度副詞維持全中文、不得數字化:一點點一些十分滿意 等 40+ 慣用語test_text_converter.py::test_allpytest -k G7-✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-ITN-09 2026-09-04完整車內出貨指令語料 495 列、29 個產品功能分類,逐句 100% 正確;分類本身不得靜默缺漏test_itn_lexicon.py::test_every_incar_command_normalises_as_adjudicatedtest_every_product_category_is_represented✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-OPS-01模型解析:get_local_model_path 維持純函式(不觸發下載);ensure_local_model_path 只在 bundle 真的缺失時 pull、且只 pull 自己那個 .dvc;失敗訊息必須指名該跑的指令tests/test_model_manager.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-OPS-02出貨模型的五處必須一致config-basic.yamlmodel.keyutils/model_manager.py 註冊表、三個 Dockerfile*COPYdeploy.shMODEL_DVC_FILES.dockerignore 的 build context 白名單tests/test_augment.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-OPS-03Per-turn debug log 檢索端點GET /debug/logs,2026-08-20):features.enable_debug_log_endpoint 關閉時回 404;開啟時可依 trace_id(來自 WS 握手 ?trace_id=,經 logger.contextualize 標記,比照既有 ?car= 機制)與時間窗(since_ms/until_ms/minutes)篩選 in-memory ring buffer(debug.debug_log_buffer_lines 筆數上限);零筆符合回 200 而非錯誤tests/test_debug_log_buffer.pytests/test_debug_log_config.pytests/test_debug_log_endpoint.pytests/functional/live/test_debug_logs.py✓ PASS
2026-09-05 STT live:2 passed / 0 failed。
SW-OPS-04狀態頁設定介面:EOT 等待秒數以滑桿呈現,其上下界與步進即 clamp() 實際夾制的範圍;整頁只有一個儲存動作,任一欄位驗證失敗則全部不送出。上界必須低於 kitt-core 的 user_turn_stop_timeout,否則該 fallback 會搶在語尾判定之前結束 turntests/test_status_page_settings.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-OPS-05live 測試 harness 不得產生 false passtests/docker-test.sh 重用映像的新鮮度檢查,必須涵蓋 Dockerfile 所有 COPY 進映像的路徑。清單以 Dockerfile 為來源推導驗證,不得手工維護——漏一個路徑就會讓套件對著不是受測版本的程式碼跑出綠燈tests/test_augment.py::test_docker_test_rebuilds_when_any_baked_in_path_changes✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-OPS-06provider=trt 不得靜默降級成 CUDA(與 SW-EOT-04 是同一原則的兩個實例:指定的 provider 沒生效就拒絕啟動),兩層:① 註冊層——TensorRT EP 註冊失敗時(onnxruntime build 沒有 TRT、libnvinfer 不在載入路徑、ORT 退回選項),vendored sherpa-onnx 中止行程而非 fallback;② 執行層——recognizer 建好之後,若 model.provider 要的是 trt 而 libnvinfer 未常駐於本行程,服務啟動必須失敗。①擋不到②:engine 因 sm 或 TRT 版本不符而無法反序列化時 EP 仍註冊成功,ORT 可以把節點丟回 CUDA。兩者的共同理由是該降級在執行期不可見——服務照常啟動、答案正確,只是慢數倍,該輪就因此量到一組標著 TensorRT 卻跑在 CUDA 的數字tests/test_trt_provider_guard.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-FT-01訓練語料建構:目標詞以 config-basic.yaml 為單一事實來源;句型展開不污染標籤;音色池與配額可重現;AISHELL-3 全程只當評估、永不進訓練tests/test_finetune_corpus.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-FT-02量測與判定:MODEL/PRODUCT 雙軸(別名不計入模型能力)、三軸判定須同時成立、checkpoint 選擇規則(一般 ASR 品質門檻未通過者不得被選中、全 NO-GO 時不得回傳贏家)tests/test_finetune_eval.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-FT-03LoRA 接線:不可達目標必須拋錯而非靜默不啟用;可訓練集合非空且只含 lora;merge 後鍵集合=base 且權重確實改變tests/test_finetune_lora.pySKIP
2026-09-05 offline:模組需要 funasr,未執行;不沿用舊 PASS。
SW-FT-04波形增強:SNR 精度、訓練/評估池不相交、確定性、不削波;預設 AUG_RATIO=0(乾淨語料)tests/test_augment.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-FT-05論文基準計分不得與一般 ASR 品質驗收計分共用程式碼;中英文正規化分流、論文目標值釘住;精度以 --model-file 選擇(預設 model.onnx,歷史呼叫方式不變),且寫進 report JSON 讓每個數字帶著它的精度來源tests/test_paper_bench.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-FT-06模型量化匯出:sherpa-onnx 的 metadata_propsmodel_type / lfr_window_size / neg_mean / inv_stddev / lang_* / with_itn …)在 INT8 與 FP16 轉換後必須逐鍵存活——少一個,sherpa-onnx 就載不起來;FP16 圖必須保持 fp32 的 graph I/Okeep_io_types),否則餵 fp32 waveform 會型別不符;INT8 的量化參數(op_types_to_quantize / weight_type只允許存在一份,exporter 與獨立量化工具共用同一個函式,不得各寫一份而漂移tests/test_quantize_bundle.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-FT-07量測後端可換為 ONNX--onnx-dir(sherpa-onnx)與 --init-param(PyTorch)互斥,避免報告出現一個不知道用哪個後端量的數字;--require-cache 時,付費 TTS 語料只要有一個 clip 不在快取裡就在發出任何 TTS 請求之前失敗(Google TTS 按字計費,一次誤觸就是真實支出)tests/test_eval_onnx_backend.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-FT-08運算子的裝置可攜性:量化會把 MatMul 換成 MatMulIntegerMatMulNBits 等運算子,而目標裝置的 execution provider 未必實作它們——未實作時 ORT 會靜默指派回 CPU,模型照跑、文字照樣正確,只是速度不是部署時假設的那個。工具須:①列出圖中所有運算子;②列出某個量化方案新增/移除了哪些運算子;③以 ORT profiler 的實際節點指派回答「哪些落在目標 provider、哪些退回 CPU」;④把「provider 根本沒載入」與「部分運算子退回」分開報告(前者是環境問題,後者才是運算子支援問題)。輸入由圖的簽章合成,所以在沒有語料的邊緣裝置上也能重跑tests/test_op_support.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-01新增測試檔必須在本規格留下紀錄:掛在某個 SW_id 之下,或明示「刻意不給 ID」與理由。反向亦然——本規格不得引用已不存在的測試檔(重新命名或刪除後留下的空指向,比未覆蓋更危險,因為它看起來有覆蓋)。§8/§9 兩區與其 ID 前綴不得被靜默移除tests/test_spec_traceability.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-02cycle 報告的累積 ledger 只增不減:最新一份報告必須涵蓋歷輪聯集的所有 SW_id(不只是對前一輪比對——那會讓某個 ID 消失一輪後就永遠消失,因為下一次比的是兩份都已缺它的報告)。報告檔名須與 docs/dev-specs/ 的 cycle stem 對應tests/test_report_integrity.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-03報告要定義自己用的技術名詞CLAUDE.md Rule 5):凡讀者需要查才看得懂、且結論依賴其意義的名詞(sm89RTFMatMulIntegerCMVN…),必須在報告的名詞定義節裡說明「是什麼」與「該輪為何重要」。⚠️ 機械檢查的範圍是「有名詞表的報告,其涵蓋必須完整」;「報告有沒有名詞表」判不了誰是該輪的 cycle,故列入 close-out checklisttests/test_report_glossary.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-04報告的圖表要能被讀懂CLAUDE.md §6 item 4b):每張圖需有 aria-label;每張數據圖需有 caption,且 caption 要寫出結論而非重複標題(架構/流程圖屬 item 4,豁免)。⚠️ 規則不追溯——報告以「至少有一張帶 caption 的圖」表示採用此慣例,之後其圖才受檢;該輪之前無任何報告為圖加 captiontests/test_report_charts.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-05報告的章節交叉引用必須指得到CLAUDE.md §6 item 7e):報告是獨立閱讀的文件,§N 是讀者從結論走到證據的唯一途徑;重新編號章節時,引用它的文字必須同步改。⚠️ 檢查只驗指得到,無法判斷「§9 其實該寫 §10」。既有 4 份報告的 12 個懸空引用列成 KNOWN_DANGLING 明帳,只能減不能加tests/test_report_crossrefs.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-06報告的 ID 對照表要逐項定義CLAUDE.md Rule 3):報告引用的每一個 ADEFR 都要在表裡有自己一列——只定義「家族」與範圍不算數,那回答的是「A 是什麼」不是「其中某一個 id 是什麼」。⚠️ 規則不追溯:以報告是否含「ID 對照」章節判定是否受檢;既有 2 份報告的 18 個未定義 ID 列成 KNOWN_UNDEFINED 明帳,只能減不能加tests/test_report_ids.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-07報告的小節要掛在自己的章節底下CLAUDE.md §6 item 7f):不得有 <h3> 排在本節 <h2> 之前;編號 N.M 的小節必須位於編號 N<section> 內;站內連結必須指得到錨點。該輪發生兩次——插入時以「下一個 h2」定位,內容落進下一節,而 HTML 解析/標籤平衡/錨點檢查全部看不出來tests/test_report_structure.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-08報告引用的測試檔必須存在CLAUDE.md §3 懸空引用原則):ledger 是審閱者判斷「這個需求有沒有人守」的依據,指向不存在的檔案讀起來和有覆蓋一模一樣,比空白更糟——空白至少會促使人去查。SW-DOC-01 守的是規格↔測試,這條守的是報告↔測試,而後者才是審閱者實際會讀的。⚠️ 只驗檔名;函式是否存在、結果是否與實跑相符,仍是收尾檢查表的工作tests/test_report_test_refs.py✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
SW-DOC-09 2026-09-04累積 ledger 裡「該需求所屬 cycle新增」的高亮必須跟著換手:沒被該需求所屬 cycle新增的列要清掉 class="hl",只有該需求所屬 cycle自己新增的列能保留,且要帶明確日期(CLAUDE.md §6 rule 7g)。原編號 SW-DOC-08,rebase 到 2026-09-04-ai-agent-ux-alignment 時撞號而改號test_report_highlighting.py(1)✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
已廢止 / 已移除(保留以滿足累積 ledger 只增不減,SW-DOC-02;不代表仍有覆蓋)
SW_id行為(規格)測試結果
SW-W-06smart-turn 第二句開頭說喚醒詞不觸發喚醒 · 2026-08-17 廢止,與 SW-W-02 互斥,見 SW 規格的廢止紀錄。由 SW-W-13 取代
已廢止/移除,保留歷史 ID,不列入通過數。
SW-B-04Prefix 出現在 smart-turn 第二句句首不觸發 · 2026-08-17 廢止,與 SW-W-02 互斥,見 SW 規格的廢止紀錄。由 SW-B-10 取代
已廢止/移除,保留歷史 ID,不列入通過數。
SW-B-09特定指令於 smart-turn 第二句句首不觸發 · 2026-08-17 廢止,與 SW-W-02 互斥,見 SW 規格的廢止紀錄。由 SW-B-11 取代
已廢止/移除,保留歷史 ID,不列入通過數。
SW-PERF-06跨座位批次解碼——2026-08-31 一輪判定不採用(機制正確但只在鎖爭用時才形成,對 10 秒以內的音訊是負收益),程式碼與其 5 條測試已隨定案從樹上移除。列在這裡是因為那一輪的報告引用了它( Rule 4)—(已移除)
已廢止/移除,保留歷史 ID,不列入通過數。
STT_EXTRA · 反應式 Interim 排程(沿用,離線)
驗收 ID行為測試(file::test)結果
A1第一次 interim 無前次延遲 → 用 initial_intervaltest_audio_cfg::test_next_interval_uses_initial_when_no_prior_latency✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
A2間隔 = max(延遲×margin, 地板),無上限test_audio_cfg::test_next_interval_is_latency_times_margin_above_the_floor / test_next_interval_has_no_upper_ceiling✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
延遲很小時被地板夾住test_audio_cfg::test_next_interval_clamped_to_floor_for_small_latency✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
A3–A5margin≤1 / 地板≤0 / 初始值≤0 → ValidationErrortest_audio_cfg::test_safety_margin_must_be_greater_than_one / test_min_interval_must_be_positive / test_initial_interval_must_be_positive✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
A6ASR_INTERIM_SAFETY_MARGIN 覆寫 / 未設時吃 YAMLtest_audio_cfg::test_env_var_overrides_margin / test_no_env_var_keeps_yaml_default✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
STT_EXTRA · SW-PERF-01:永久 live 回歸測試(沿用,live)
驗收 ID行為測試(file::test)結果
SW-PERF-01連線無錯誤test_audio_stress::test_audio_stress_no_errors✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-PERF-0190 秒連續長句仍收到 finaltest_audio_stress::test_audio_stress_final_received✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-PERF-01time to final 有界test_audio_stress::test_audio_stress_time_to_final_bounded✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
SW-PERF-01相鄰 interim 最大間隔有界test_audio_stress::test_audio_stress_interim_gap_bounded✓ PASS
2026-09-05 STT live:4 passed / 0 failed。
STT_EXTRA · interim/final ITN 拆分(沿用,離線)
驗收 ID行為測試(file::test)結果
B1interim 只套用 s2t(),不做數字正規化test_batch_asr_manager_itn_split::test_interim_inference_only_applies_s2t_not_numeral_normalization✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
B2final 仍套用完整 itn()(s2t + 數字),不受影響test_batch_asr_manager_itn_split::test_offline_inference_still_applies_full_itn✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
STT_EXTRA · 併發排程(沿用,離線 13 條,單一檔 tests/test_interim_concurrency.py
驗收 ID行為測試(file::test)結果
B14-R1RTF 只計 decode_stream() 的時間,不含鎖等待test_interim_concurrency::test_decode_ms_and_latency_ms_agree_with_no_contention / test_decode_ms_excludes_lock_queueing_but_latency_ms_includes_it✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
B14-R2每個 session 有獨立buffer_lock,與 inference_lock 分開,且真的序列化併發存取test_interim_concurrency::test_buffer_lock_is_per_session_and_separate_from_inference_lock / test_buffer_lock_serializes_append_against_read✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
B19-R1_interim_redecode_body 不得被 inline await;恰有一次背景派發,且必須是 self.create_tasktest_interim_concurrency::test_interim_redecode_is_dispatched_never_awaited✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
B19-R2×人數 不得偷渡回來:呼叫端只能帶 1 個位置引數,函式簽名不得有人數參數test_interim_concurrency::test_the_schedule_is_never_given_a_speaker_count✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
B19-R3三個已移除的旗標保持移除FeaturesCfg 無欄位、config-basic.yaml 無鍵,舊 override 檔仍可載入且為惰性test_interim_concurrency::test_the_removed_knobs_stay_removed✓ PASS
2026-09-05 offline 全套:此列所列測項通過(8 個失敗均在 test_ai_agent_ux_spec.py)。
下游 / OOS(無 STT SW_id / 測試 — 歸屬 NLU · DM · TTS · web-ui,沿用)
F_id / SW_idFeature / 行為歸屬
F_1多音區識別/控制(權限·AreaID·多區並行)下游 + STT per-user_id hook
F_4.1語音打斷_背景併行處理下游 DM/TTS
F_4.2語音打斷_後令壓前令下游 DM 仲裁
F_5連續指令下游 NLU 拆解(UX§4.2.1 拆解成功率同歸此列)
F_6上下文理解下游 DM 快取(UX§5 保留輪數同歸此列)
F_3.4c最大錄音時限自動停止kitt-web-ui——✓ 已實作,設定 20s(2026-09-04 UX cycle 記錄的使用者確認;2026-09-05 未驗證 Web UI)
SW-UI-06講話中切 mic 靜音、WebUI 不卡字web-ui(無 STT 測試)
SW-MU-01..08多使用者/多車喚醒同步、隔離web-ui(STT 提供 per-user_id / ?car= hook)
UX§1.3.1UX§7UX§9UX§10(除 11.3)問候語 UI/Guardrail/回復策略/顯示策略下游 UI/LLM/TTS
STT_EXTRA · 2026-08-31 特徵增量化測試(無 SW_id,保留原列)
SW_id行為測試結果

刻意不掛 SW_id
interim 重解碼的特徵抽取增量化:增量餵入與一次性餵入產生的特徵必須逐 bit 相同; 持續 stream 不得跨 utterance 復用;該句的 final 沿用同一個 stream 只補未餵的尾巴; 餵入失敗必須可見且可復原(拋 IncrementalFeedError、游標只在成功後推進、 半餵的 stream 丟棄重建);交棒不得在 interim 餵入中途發生(否則 final 重複餵同一段音訊) tests/test_offline_stream_incremental.py(8)
tests/test_batch_asr_manager_incremental_prep.py(8)
tests/test_interim_incremental_wiring.py(6)
tests/test_final_stream_reuse.py(9)
31/31 PASS · 2026-09-05 offline
2026-09-05 STT live 逐項結果(88 cases)
測項結果
tests/functional/live/test_active.py::test_active_wake_filterPASSED
tests/functional/live/test_active.py::test_active_smart_turn_wake_headPASSED
tests/functional/live/test_active.py::test_active_smart_turnFAILED
tests/functional/live/test_active_greeting.py::test_ux_1_3_2_first_greeting_is_sent_within_500msPASSED
tests/functional/live/test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[50ms]FAILED
tests/functional/live/test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[200ms]FAILED
tests/functional/live/test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[350ms]FAILED
tests/functional/live/test_active_greeting.py::test_ux_1_3_2_speaking_inside_the_window_suppresses_the_first_greeting[500ms]FAILED
tests/functional/live/test_active_greeting.py::test_ux_1_3_one_shot_wake_emits_active_like_a_bare_wakePASSED
tests/functional/live/test_active_greeting.py::test_ux_1_3_2_one_shot_wake_suppresses_the_first_greetingPASSED
tests/functional/live/test_active_greeting.py::test_ux_1_3_3_second_greeting_fires_at_10s_when_nobody_speaksFAILED
tests/functional/live/test_active_greeting.py::test_ux_1_3_3_speaking_within_10s_suppresses_the_second_greetingPASSED
tests/functional/live/test_active_greeting.py::test_ux_1_3_4_exits_5s_after_the_second_greetingPASSED
tests/functional/live/test_audio_stress.py::test_audio_stress_no_errorsPASSED
tests/functional/live/test_audio_stress.py::test_audio_stress_final_receivedPASSED
tests/functional/live/test_audio_stress.py::test_audio_stress_time_to_final_boundedPASSED
tests/functional/live/test_audio_stress.py::test_audio_stress_interim_gap_boundedPASSED
tests/functional/live/test_bilingual.py::test_code_switching_within_one_commandFAILED
tests/functional/live/test_bilingual.py::test_english_command_after_chinese_wake_wordPASSED
tests/functional/live/test_btn_control.py::test_btn_activatePASSED
tests/functional/live/test_btn_control.py::test_btn_rapid_toggle_activePASSED
tests/functional/live/test_btn_control.py::test_btn_rapid_toggle_wakePASSED
tests/functional/live/test_btn_control.py::test_btn_deactivatePASSED
tests/functional/live/test_btn_control.py::test_btn_standby_voicePASSED
tests/functional/live/test_btn_control.py::test_btn_standby_midPASSED
tests/functional/live/test_bypass_cmd.py::test_cmd_triggerPASSED
tests/functional/live/test_bypass_cmd.py::test_cmd_not_at_startPASSED
tests/functional/live/test_bypass_cmd.py::test_cmd_extra_wordsPASSED
tests/functional/live/test_bypass_cmd.py::test_standby_cmd_smart_turnPASSED
tests/functional/live/test_bypass_prefix.py::test_prefix_triggerPASSED
tests/functional/live/test_bypass_prefix.py::test_prefix_not_at_startPASSED
tests/functional/live/test_bypass_prefix.py::test_prefix_smart_turnFAILED
tests/functional/live/test_debug_logs.py::test_trace_id_scopes_retrieved_logs_to_its_own_connectionPASSED
tests/functional/live/test_debug_logs.py::test_missing_trace_id_query_param_returns_a_404_when_the_route_itself_is_missingPASSED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u8b1d\u8b1d]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u518d\u898b]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u9000\u51fa]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u9000\u4e0b]PASSED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u6efe\u86cb]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[\u6efe]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Thank you]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Thanks]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Goodbye]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[ByeBye]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Quiet]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Shut up]FAILED
tests/functional/live/test_exit_words.py::test_ux_2_1_tier1_exit_word_returns_to_standby[Dismiss]FAILED
tests/functional/live/test_forced_stop.py::test_forced_vad_stop_commits_immediately[max_duration]PASSED
tests/functional/live/test_forced_stop.py::test_forced_vad_stop_commits_immediately[mic_off]PASSED
tests/functional/live/test_forced_stop.py::test_forced_vad_stop_commits_immediately[audio_stall]PASSED
tests/functional/live/test_kws_method_manual.py::test_wake_transcript_does_not_activate_manual_modeSKIPPED
tests/functional/live/test_kws_method_manual.py::test_web_ui_active_allows_speech_without_wake_strippingSKIPPED
tests/functional/live/test_kws_method_manual.py::test_web_ui_standby_blocks_speech_againSKIPPED
tests/functional/live/test_kws_method_manual.py::test_bypass_still_emits_in_manual_standbySKIPPED
tests/functional/live/test_multiuser_concurrency.py::test_multiuser_no_errorsPASSED
tests/functional/live/test_multiuser_concurrency.py::test_multiuser_no_stray_user_idsPASSED
tests/functional/live/test_multiuser_concurrency.py::test_multiuser_every_seat_gets_a_finalPASSED
tests/functional/live/test_multiuser_concurrency.py::test_multiuser_time_to_final_boundedPASSED
tests/functional/live/test_multiuser_concurrency.py::test_multiuser_interim_gap_boundedPASSED
tests/functional/live/test_rejection_thresholds.py::test_ux_8_2_speech_longer_than_15s_is_not_forwardedFAILED
tests/functional/live/test_rejection_thresholds.py::test_ux_8_2_speech_longer_than_50_chars_is_not_forwardedFAILED
tests/functional/live/test_rejection_thresholds.py::test_ux_8_2_speech_under_both_thresholds_is_forwarded_normallyPASSED
tests/functional/live/test_rejection_thresholds.py::test_ux_10_2_rejection_keeps_the_room_listening[over-15s]FAILED
tests/functional/live/test_rejection_thresholds.py::test_ux_10_2_rejection_keeps_the_room_listening[over-50-chars]FAILED
tests/functional/live/test_remaining_ux_gaps.py::test_non_wake_speech_never_activates[multiuser-10s.wav]PASSED
tests/functional/live/test_remaining_ux_gaps.py::test_non_wake_speech_never_activates[stress-90s.wav]PASSED
tests/functional/live/test_remaining_ux_gaps.py::test_ten_second_prompt_stage_exists_end_to_endFAILED
tests/functional/live/test_remaining_ux_gaps.py::test_command_wait_timeout_boundary[490ms-one-turn]FAILED
tests/functional/live/test_remaining_ux_gaps.py::test_command_wait_timeout_boundary[510ms-two-turns]PASSED
tests/functional/live/test_smart_turn_bypass.py::test_standby_smart_turn_prefix_2ndPASSED
tests/functional/live/test_smart_turn_bypass.py::test_standby_smart_turn_cmd_2ndPASSED
tests/functional/live/test_smart_turn_wake.py::test_standby_smart_turn_wake_2ndPASSED
tests/functional/live/test_smart_turn_wake.py::test_active_smart_turn_wake_2ndPASSED
tests/functional/live/test_standby.py::test_standby_rejectionPASSED
tests/functional/live/test_standby.py::test_standby_wake_not_at_startPASSED
tests/functional/live/test_stt_config.py::test_custom_stt_config_activePASSED
tests/functional/live/test_stt_config.py::test_custom_stt_config_deletedPASSED
tests/functional/live/test_timeout.py::test_timeout_deactivatePASSED
tests/functional/live/test_timeout.py::test_timeout_resetPASSED
tests/functional/live/test_wake.py::test_wake_immediatePASSED
tests/functional/live/test_wake.py::test_wake_pausePASSED
tests/functional/live/test_wake_factory_words.py::test_wake_hi_foxtronPASSED
tests/functional/live/test_wake_latency.py::test_wake_to_agent_active_fits_the_ui_budgetFAILED
tests/functional/live/test_wake_latency.py::test_wake_only_greeting_fits_the_response_budgetFAILED
tests/functional/live/test_wake_rate.py::test_ux_1_1_wake_rate_meets_the_90_percent_floor[\u55e8\u9d3b\u83ef]PASSED
tests/functional/live/test_wake_rate.py::test_ux_1_1_wake_rate_meets_the_90_percent_floor[Hi Foxtron]PASSED
tests/functional/live/test_wake_rate.py::test_ux_1_1_false_wake_floor_is_zero_over_repeated_replays[multiuser-10s]PASSED
tests/functional/live/test_wake_rate.py::test_ux_1_1_false_wake_floor_is_zero_over_repeated_replays[say-wake-midsentence]PASSED

量測紀錄位置

以下是本機紀錄,不是雲端下載連結;表格已列出審閱所需結果。

範圍本機紀錄
Offline/tmp/kitt-stt-rebase-20260905-offline-closeout.log
STT live/tmp/kitt-stt-rebase-20260905-live-rerun.log
Manual live/tmp/kitt-stt-rebase-20260905-manual.log
490ms 重測/tmp/kitt-stt-490ms-retest-u10L7Z.log

本次文件驗證:report/traceability 測試 61 passed / 1 skipped;skip 是本報告沒有數字編號章節,另以瀏覽器確認所有頁內錨點有效。此報告也另行核對歷輪聯集,110 個 SW ID 全數保留。這次只改文件,未重新執行 runtime suite;上述 runtime 結果來自 2026-09-05 rebase 後的紀錄。

附錄 C · 未覆蓋範圍與後續工作

Cycle:2026-09-02-switchable-wake-provider · runtime 驗證:2026-09-05 · 基底 main@4ee1821。整套測試非全綠;需求結果與驗證範圍見附錄 B。