Repository navigation
Conversation
- AudioStreamDecoder::stop() 在 join 之后清 m_seekRequestMs:cancelRequested() 把「槽内有值」当取消,残留会让停止后该谓词仍为真。start() 本就在 stop() 之后清槽,正常路径行为等价。 - 加两个测试专用读写钩子(#112 批准的第二次限定例外):SDK 内部类型、不进公开 API、setter release / getter acquire、只在控制线程调用、生产路径零调用。 - sdk_unit_tests 新增确定性判据:不启线程、不依赖素材、不命中时序窗口;变异验证可红可绿。 - 不改 :546 与 E 链 #59/#60/#65 时序,不改 MusicPlayer.cpp / 公开 API / 既有判据 / TIMEOUT / 坏输入 55 例基线 / CI 配置。 - 边界:本改动不修复 42488656322 的 SIGSEGV(无复现、无栈、平台不对齐),根因未定位;取证与决议见 #112。
|
补记本地稳定性对照(合并门禁之一)。结论先说:不粉饰成「全绿」,两组各 9/10,且为消除基线歧义正在补跑真实 master 同轮数对照,结论出来前不合并。 分支两组 10 轮
|
| 组 | 结果 | 失败轮次 | SIGSEGV | sdk_unit_tests(含新判据) |
|---|---|---|---|---|
| 第一组(review 修改前代码) | 9/10 全绿 | round 9 | 0 | 10/10 Passed |
| 最终组(review 修改后最终代码) | 9/10 全绿 | round 6 | 0 | 10/10 Passed |
两组失败完全同形态,都是 sdk_interaction_tests 的 test_player_integration.cpp:1408 CHECK( afterMonotonic ) is NOT correct!,耗时 14.28s / 14.32s;失败列表只有 Test #14,sdk_unit_tests 明确 Passed 23.52 sec。这是既有的位置单调性断言(采样撞短窗口类假红),与本次改动零交集:本 PR 的新判据在 AudioStreamDecoder Stop Contract suite,归 sdk_unit_tests,而 sdk_interaction_tests 只跑 MusicPlayer Interactive Paths,PublicPlayer Interactive Paths(sdk/test/CMakeLists.txt:192-196,234-237);生产改动只在 AudioStreamDecoder::stop() 的 join 之后多一次槽清空,而 start() 本就会清槽,对播放期间的位置无因果路径。
为什么还要补跑 master
第十四轮在同 HEAD 96d3213 上跑过 master 10/10 全绿,而 C1/C5 时的 master 对照是 9/10(同源 sdk_interaction_tests 既有 flake)。分支两组各 9/10 落在这两个历史基线之间,单靠引用历史数据消除不了歧义。按 #112 决议里「master 与分支同轮数 ctest -j4 对照,分支假红率高于基线即撤回全部 sdk/ 改动」的闸门,正在实跑 master 10 轮(同一台机器、同一 build 目录、同样 -j4),完成后会在这里补结论。
- 若 master 也出现同形态
afterMonotonicflake 且假红率不低于分支 → 判为基线既有 flake,放行。 - 若 master 10/10 全绿而分支两组各 1 次 → 判为本改动放大假红,撤回全部
sdk/改动并关闭本 PR,不合并、不放宽任何判据或超时。
其余验证状态
判据自检(1 case / 2 assertions / 515 skipped)、变异验证(去清槽精确红 → 字节一致还原 → 绿)、两轴 code-review 及两处意见修复均已完成。Windows sdk-windows 42544814456 已 success(attempt=1);Linux sdk-coverage 42544814467 进行中。
再次重申边界:本 PR 不修复 42488656322 的 SIGSEGV,根因仍未定位(无复现、无栈、CI 在 Linux / 本机 Windows)。
合并门禁最终结论:按事先写死的闸门撤回,不合并补跑的真实 master 同轮数对照已完成,结论:撤回本 PR 的全部 稳定性对照(同一台机器、同一 build 目录、同样
|
| 组 | 轮次 | 全绿 | 失败轮次 | SIGSEGV |
|---|---|---|---|---|
| 分支第一组(review 修改前代码) | 10 | 9/10 | round 9 | 0 |
| 分支最终组(review 修改后最终代码) | 10 | 9/10 | round 6 | 0 |
| master 基线(本次实跑) | 10 | 10/10 | 无 | 0 |
master 逐轮 58–62s、每轮 14/14;sdk_interaction_tests 13.44–14.03s,10 轮全 Passed。分支两组失败完全同形态:test_player_integration.cpp:1408 的 CHECK( afterMonotonic ),14.28s / 14.32s,111 断言 110 通过 1 失败,失败列表只有 Test #14;sdk_unit_tests(含本 PR 新判据)两组 20/20 全 Passed。逐轮日志在 build/seek-stop-final/、build/seek-stop-triage/、build/seek-stop-master-baseline/ 的 round_*.log / summary.txt。
裁决依据
上一条 comment 与 #112 决议 4 事先写死:「master 与分支同轮数 ctest -j4 ≥10 轮对照,分支假红率高于基线即撤回全部 sdk/ 改动」,并明确列出「若 master 10/10 全绿而分支两组各 1 次 → 判为本改动放大假红,撤回全部 sdk/ 改动并关闭本 PR,不合并、不放宽任何判据或超时」。本次结果精确命中该分支。
按此执行:AudioStreamDecoder.cpp / .h / test_stream_decoder.cpp 三文件 +47 行全部不进 master;不放宽任何判据、TIMEOUT、坏输入 55 例 / 396 断言基线、14 个 sdk_* 目标或 CI 配置;也不以「失败用例与改动零交集」为由事后放宽闸门 —— 这正是 AGENTS.md NOTES 反复警告的做法。分支 implement/seek-stop-state-hygiene / ca3543fef 仅作取证留痕,不得合并或 cherry-pick 到后续开发。
统计诚实声明:两次假红都是既有的 afterMonotonic 位置单调性断言(采样撞短窗口类),本 PR 的新判据归 sdk_unit_tests、生产改动只在 stop() 的 join 之后多一次槽清空,没有可解释该失败的因果路径;20 轮对 10 轮的样本也不足以证明「改动导致假红」。闸门约定的是假红率比较而非因果证明,因此本结论是「按事先约定的规则撤回」,不是「已证实本改动放大假红」,更不是「既有 flake 被修复」。
其余门禁(均已完成,但不改变一票否决的结果)
- 判据自检:
1 case / 2 assertions / 515 skipped,SUCCESS。 - 变异验证:去掉
stop()清槽一行 → 新用例精确红;字节一致还原 → 绿。 - 两轴
code-review两条意见(钩子注释内存序不精确、断言超出票范围)已修复并重跑。 - CI:本 PR 阶段 Linux
sdk-coverage42544814467与 Windowssdk-windows42544814456均completed/success、attempt=1(无 rerun)。CI 双绿不替代本地同轮数稳定性对照。
边界重申
本 PR 从未修复 42488656322 attempt 1 的 SIGSEGV:无复现、无崩溃栈、CI 崩溃在 Linux ubuntu-24.04 而本机取证在 Windows / MinGW730,根因仍未定位。H1(seek 槽未消费完就 stop → SIGSEGV)已被 240 次窗口命中 0 崩溃证伪(Windows 侧);H2 未改(E 链 #59/#60/#65 已裁决时序);H3 / H4 未验(需 Linux core dump 或 ASan)。stop() 不清未消费 seek 槽的状态契约违反确实存在,但本轮没能以通过闸门的形态为它建立长期判据。
若日后要重新落地,须另开新票:先解决基线假红放大或拿出 Linux 侧可复现 / ASan 证据,再重走全套闸门;不得把本分支直接合并。
- AGENTS.md:稳定性闸门条补 11-09 反例(分支两组各 9/10 vs master 10/10 → 撤回 PR #114);SIGSEGV「反复出现」门槛条补一次性破例留痕,明确三条门槛不删不放宽、撤回后终态仍是不改生产代码。 - doc/player-state-contract.md §10.4:记录破例边界、H1 证伪与 stop() 状态契约违反取证、全套验证结果、稳定性闸门一票否决与撤回裁决;如实保留「SIGSEGV 根因未定位 / H2 未改 / H3·H4 未验」。 - doc/streaming-playback-spec.md 新增 §12.6:seek 分支 :546 的 H2 判定「不改」及反悔条件、已排除项复核,明确全部为只读取证、没有任何生产代码落地。 - PR #114 已 CLOSED 不合并,#112 / #113 已 CLOSED 留 resolution;三文件 +47 行的 sdk/ 改动不进 master。
这是什么 / 不是什么
承接 #112 / #113。用户 2026-11-09 明确「强制重审」,主动打破
745ba7b固化的「SIGSEGV flake 反复出现」三条门槛。本 PR 不修复
42488656322attempt 1 的 SIGSEGV:没有复现、没有崩溃栈,CI 崩溃在 Linux / 本机取证在 Windows,根因未定位。本 PR 交付的是「消除一个被取证确认为 100% 命中的状态契约违反 + 建立长期判据」。票、规格与代码注释一律不得宣称修复。取证(纠正上一轮取证的效力)
上一轮 100 次单用例定向压力跑的是既有用例
test_player_integration.cpp:726,它在setPosition()后先轮询等到位置到位、再多等 800ms 才stop()—— seek 槽早已被消费完,根本不经过「seek 槽未消费完就 stop」窗口,所以 0/100 对候选①没有证伪力。本轮改用临时诊断 harness(seek 后不轮询、不 sleep、立刻 stop)+ 控制线程侧临时探针(
stop()进入时读m_seekRequestMs,零解码线程写),三组各 80 轮:窗口命中率每轮 2/3 次、160/240,三组完全一致(确定性),但 0 崩溃、0 断言失败、0 非零退出。
→ H1 作为「SIGSEGV 根因」在 Windows 侧证伪:该叠加窗口是 100% 命中的常态,不足以解释一次偶发崩溃。但
AudioStreamDecoder::stop()确实不清理m_seekRequestMs,而cancelRequested()把「槽内有值」当取消 → stop 返回后该谓词仍为真,构成确定的状态契约违反。改动(3 文件 +47 行)
AudioStreamDecoder.cppstop()在 join 之后、置 IDLE 之前补一行m_seekRequestMs.store(-1);另有两个测试专用方法实现AudioStreamDecoder.hsetPendingSeekForTest(int64_t)/pendingSeekMsForTest() const,SDK 内部类型、不进soundbridge::Player公开 API、生产路径零调用test_stream_decoder.cppsdk_unit_tests的确定性判据:不启解码线程、不依赖真实素材、不命中任何时序窗口stop()清槽正常路径行为等价:start()本就在stop()之后清槽,state=IDLE 会让seekToMs()直接返回,解码线程此时已 join。验证
1 case / 2 assertions / 515 skipped(真实命中,非-tc静默 0 匹配假通过);sdk_unit_tests全绿。1 failed,CHECK(pendingSeekMsForTest() == -1) is NOT correct!);cmp字节一致还原 + 重编译 → 绿。证明判据不是摆设。stop()的默认 seq_cst store(原措辞会被读成事实错误),并把判据断言收敛回票 [实现] stop() 清空未消费 seek 槽并锁定状态契约 #113 批准范围(删掉两条锁既有行为、与契约无关的CHECK)。ctest -j410 轮第一组:9/10 全绿、0 次 SIGSEGV;第 9 轮失败为sdk_interaction_tests的既有afterMonotonic(test_player_integration.cpp:1408),与本次改动零交集,含新判据的sdk_unit_tests10/10 全 Passed。该目标是 C1/C5 对照里 master 9/10 同源的既有低概率 flake。最终代码的第二组 10 轮正在运行,结论将补 comment。HEAD 96d3213的第十四轮 10/10 全绿(同机、同日、同代码)。明确不做
:546的m_abortDecode.store(false)及 E 链 [T04] 播放任务所有权与生命周期 prefactor #59/[T05] FLAC 增量垂直切片(MVP) #60/[T10] seek 两档与精度判据套件 #65 已裁决时序(H2:240 次窗口命中未见 join 异常)。_releaseAudio())需 ASan 或 Linux core dump,本机 MinGW 无 ASan,未验、未改,不猜测。MusicPlayer.cpp、公开 API、七个void控制入口、任何既有判据 / TIMEOUT / 坏输入 55 例基线 / 14 个sdk_*目标 / CI 配置;不新增add_test分组,不写固定名字的共享路径。合并门禁
最终组 10 轮对照结论 + PR 阶段 Linux
sdk-coverage与 Windowssdk-windows双绿(只认gh run view <id> --json status,conclusion,attempt)。反悔通道
若日后证明该判据只锁实现细节、无契约价值,须另开新票同时撤掉两个钩子与判据,不得只删判据留下无门禁的改动。