承接 [#112](https://github.com/wt159/SoundBridge/issues/112) 的决议。**本票不修复 SIGSEGV**:`42488656322` attempt 1 的崩溃根因仍未定位(Linux CI / 无 core / 无 ASan),本票只消除被取证确认为 100% 命中的状态契约违反,并为它建立长期判据。 ## 改动清单(严格最小化) 1. `sdk/audio/decode/AudioStreamDecoder.cpp` — `stop()` 在 `m_thread.join()` 之后、`m_state.store(IDLE)` 之前补一行 `m_seekRequestMs.store(-1);`。 - 依据:`cancelRequested()`(`:451-457`)把「槽内有值」当取消;`start()` 本就在 `stop()` 之后清槽(`:174`),`seekToMs()` 在 IDLE 时直接返回,解码线程此时已 join —— 正常路径行为等价。 2. `sdk/audio/decode/AudioStreamDecoder.h` / `.cpp` — 两个**测试专用**方法(SDK 内部类型,不进 `soundbridge::Player` 公开 API,生产路径零调用): - `void setPendingSeekForTest(int64_t targetMs)`:`m_seekRequestMs.store(targetMs, std::memory_order_release)` - `int64_t pendingSeekMsForTest() const`:`m_seekRequestMs.load(std::memory_order_acquire)` - 只在控制线程调用;`m_seekRequestMs` 已有的解码线程 store 用默认 seq_cst,与 acquire 兼容。 3. `sdk/test/unit/test_stream_decoder.cpp`(归属 `sdk_unit_tests`,与 C1/C5 判据同目标)— 新用例: ``` decoder.setPendingSeekForTest(5000); decoder.stop(); CHECK(decoder.pendingSeekMsForTest() == -1); ``` 不启解码线程、不依赖真实素材、不命中任何时序窗口 → **确定性、毫秒级、可红可绿**。这是 #112 批准的第二次限定例子的全部范围。 ## 明确不做 - 不改 `AudioStreamDecoder.cpp:546` 的 `m_abortDecode.store(false)` 及 E 链 #59/#60/#65 时序(H2:240 次窗口命中未见 join 异常)。 - 不改 `MusicPlayer.cpp`、不改公开 API、不改七个 `void` 控制入口。 - 不改任何既有判据、TIMEOUT、坏输入 55 例 / 396 断言基线、14 个 `sdk_*` ctest 目标、CI 配置。 - 不新增 `add_test` 分组,不写固定名字的共享路径(`-j4` 稳定性)。 ## 验收 - **变异验证**:去掉 `stop()` 的清槽一行 → 新用例红;还原 → 绿。证明判据不是摆设。 - **稳定性闸门**:分支与 master 各 ≥10 轮 `ctest -j4` 同轮数对照,分支假红率不得高于基线;钩子不得落解码线程 / 判据主循环;两轴 `code-review`。 - **跨平台**:PR 阶段 Linux `sdk-coverage` + Windows `sdk-windows` 双绿(只认 `gh run view <id> --json status,conclusion,attempt`)。 - 文档回填:`doc/player-state-contract.md` §10.4 或 `AGENTS.md` NOTES 记录破例、取证数据、`H2/H3/H4` 未改或未验的如实状态;`745ba7b` 门槛条不删,只补「11-09 用户强制重审」破例留痕。 ## 反悔通道 若日后证明该判据只锁实现细节、无契约价值,须另开新票**同时**撤掉两个钩子与该用例,不得只删判据留下无门禁的改动。
Activity
wt159 commentedon Nov 9, 2026
Resolution:实现完成但稳定性闸门未过,全部撤回、未进 master
master中不存在stop()清槽、setPendingSeekForTest/pendingSeekMsForTest钩子或AudioStreamDecoder Stop Contract用例。完整依据见 PR #114 结论 comment 与 #112 resolution。实际做到的(取证有效,但不足以放行)
:546/MusicPlayer.cpp/ 公开 API / 七个void入口 / 任何既有判据 / TIMEOUT / 坏输入 55 例 / 14 目标 / CI 配置stop()的m_seekRequestMs.store(-1)→ 新用例精确红;字节一致还原 → 绿(1 case / 2 assertions / 515 skipped)state()/canDecode()两条无关 CHECK[DEBUG-seekstop]探针与诊断用例已git checkout HEAD --还原,零残留42544814467、Windows42544814456均completed/successattempt=1ctest -j4各 9/10(两次同形态afterMonotonic),真实 master 同轮数 10/10 全绿、0 SIGSEGV撤回动作
按 #112 决议 4 与 PR #114 事先写死的规则「分支假红率高于基线即撤回全部
sdk/改动」:PR #114 已 CLOSED、不合并;AudioStreamDecoder.cpp/.h/test_stream_decoder.cpp三文件不进 master;不放宽判据 / TIMEOUT / 基线 / CI 配置,也不以「失败用例与改动零交集」为由事后放宽闸门。分支implement/seek-stop-state-hygiene(ca3543fef) 仅作取证留痕。统计诚实:20 轮对 10 轮、失败用例与本改动零交集,不能证明因果;这是「按事先约定规则撤回」,不是「已证实改动放大假红」。
反悔通道的落实
正文「反悔通道」要求撤钩子与判据必须同时、不得只删判据留下无门禁的改动。本次是整体撤回:钩子、生产一行、判据三者都不在 master,天然满足该条款,无「无门禁的改动」遗留。
doc/player-state-contract.md§10.4 与AGENTS.mdNOTES 已记录破例、取证数据、撤回结论,以及 H2 未改 / H3·H4 未验 / 根因未定位的如实状态;745ba7b门槛条不删,只补 11-09 破例留痕。后续
本票不重开。要重新落地须另开新票:先解决基线假红放大或取得 Linux 侧复现 / ASan 证据,再重走全套闸门;不得直接合并或 cherry-pick
ca3543fef。SIGSEGV 根因仍未定位,本 effort 从未声称修复它。wt159 commentedon Nov 9, 2026
实现完成但稳定性闸门未过,全部撤回、未进 master;完整 resolution 见上方 comment。
docs: 回填「强制重审」破例与撤回结论,门槛条不删不放宽