Repository navigation
Closed
Labels
ready-for-agent信息完备,agent 可直接开工信息完备,agent 可直接开工
Description
背景
#109 已重审「不新造接缝」并批准一个默认关闭、只在控制线程读一次的设备错误注入点。本票实现 doc/player-state-contract.md §10.4:213 登记的唯一残留判据缺口。
实现范围
sdk/audio/device/AudioDevice.h:加static void setForceOpenFailureForTest(bool enabled),注释写明「仅测试、默认关闭、不进公开 API」。sdk/audio/device/AudioDevice.cpp:文件级std::atomic<bool> g_forceOpenFailure{false}(memory_order_relaxed);AudioDevice::open()(:302)在转m_impl->open()前读一次,命中则return -1,不进Impl::open()、不碰 SDL。sdk/MusicPlayer.cpp播放逻辑零改动。sdk/test/unit/test_player_integration.cpp:在TEST_SUITE("MusicPlayer Error Handling")加一条用例,用带 pid 的TempMediaDir放一首完整music.wav,addMusicDir→ 等getMusicCount()==1与 playlist 回调 →setCurrentIndex(0)→listener.reset()清序列 → RAII guard 打开注入 →play()→waitFor(error_count>0)。- C1:
eventSequence()里firstEvent("error") < firstEvent("state");countEvents(events,"state") == 1(发且仅发一次);last_state == StoppedState;last_error_code == AudioDeviceOpenFailed。 - C5:默认
autoSkipOnError() == true时也不跳轨 ——last_current_index不变、index_change_count == 0(reset 后计数从 0 起)。 - 用例末尾
player.stop();RAII guard 保证REQUIRE抛异常时也恢复开关。
- C1:
doc/player-state-contract.md§8 / §10.3 / §10.4 与doc/observability-contract.md§1 / §7.4:把「缺判据 / 不新造接缝 / 不可推翻前提」的时点措辞同步为「已由 [决策] 重审「不新造接缝」:批准一个默认关闭的设备错误注入点 #109 重审、[实现] C1 / C5 端到端判据:设备错误 error→state 且不跳轨 #110 落地」,保留历史原句作留痕;写明注入点形态、稳定性证据与反悔通道。
硬约束(承接 #109,不可推翻)
- 不改任何既有判据数值 / 容差、不新增
add_test分组、不改 14 个sdk_*目标 / 7 组 TIMEOUT / CI 配置 / BadInput 55 例 396 断言 / 覆盖度 15 行矩阵。 - 不碰
soundbridge::Player公开头与七个void控制入口、三态、回调契约;不新增同步解码入口、不改positionMs归属、不改 10 ms push 节奏。 - 注入开关不得落在解码线程 / 消费主循环 / 判据主循环;后续 effort:L1/L2 观测指标与 drift 的数值阈值拍板 #104「不设任何数值阈值」与 §3.2 第 5 步永久生效不变。
- 新用例不得靠裸 sleep / 绝对时长窗口 / 特定 demuxer 行为;素材缺失走既有
skipCase约定。 - 新用例写文件沿用带 pid 的
TempMediaDir(sdk/test/fixtures/TestProcess.hpp),避免-j4共享路径撞名。
验收判据
- 新增用例在
sdk_interaction_tests目标内稳定可红可绿;本地ctest -j414/14 全绿。 - 稳定性对照:master 基线 ≥10 轮 vs 集成分支 ≥10 轮
ctest -j4;若分支假红率高于基线,按 [决策] 重审「不新造接缝」:批准一个默认关闭的设备错误注入点 #109 闸门撤回全部sdk/改动并裁不落地,留对照表与依据,不改判据 / 不放宽时序窗口。 - 一次两轴
code-review单提交修完;PR 合并后 Linuxsdk-coverage与 Windowssdk-windows双绿(跨平台改动按 AGENTS.md / 规格 §8.4,本地全绿不算完成)。 git diff中sdk/MusicPlayer.cpp、sdk/include/soundbridge/、.github/、sdk/test/CMakeLists.txt零改动。
依赖:原生阻塞于 #109 的条款重审结论。
Metadata
Metadata
Assignees
Labels
ready-for-agent信息完备,agent 可直接开工信息完备,agent 可直接开工
Activity
wt159 commentedon Nov 8, 2026
实现留痕(2026-11-08):本票正文有两处与最终落地不一致,在此更正并留完整证据,票正文不改(执行票是历史决策留痕)。
sdk_interaction_tests目标内」。实测sdk/test/CMakeLists.txt:192-193的SB_TEST_INTERACTION_SUITES只有MusicPlayer Interactive Paths,PublicPlayer Interactive Paths;新用例在TEST_SUITE("MusicPlayer Error Handling"),归sdk_unit_tests(:196-198的-tse排除集不含该 suite)。已用-tse=<排除集> -tc=<用例名>验证该过滤器下 12/12 断言绿;-ltc显示该过滤器共 472 例。不新增add_test分组、不改任何 ctest 目标。last_current_index不变、index_change_count == 0」。实测play()自身就会上报一次当前索引(MusicPlayer.cpp:683),单曲列表下skipToNextPlayable()只会失败、跳轨与否几乎不可观测。最终改为双曲目列表 + 队列稳定窗口,判据是last_current_index == 0与countEvents(events,"error") == 1;若设备错误被误判为可跳轨,会尝试第二首并产生第二次 error / 索引变化。队列屏障用「error/state/index 三个计数连续 4 次 25ms 采样不变」,属稳定后取数、不是绝对时长判据,且两个等待屏障都写成CHECK(非 fatal),保证回归时后续断言也能给出具体红因。变异验证(判据可红可绿):
GetErrorInfo(code).action == ErrorAction::SkipTrack→ 6 条断言红,含sequenceArrived、queueQuiet、状态只发一次、last_current_index == 0、countEvents(error) == 1。onError挪到updatePlayState之后 →errAt < stAt精确红。sdk/MusicPlayer.cpp零改动(变异仅用于验证,未提交)。O1 稳定性闸门:
ctest -j4(cwdsdk/test、三重 PATH)集成分支 10/10 轮全绿 14/14(56.65–59.17 s);master 基线 9/10 轮全绿(第 9 轮sdk_interaction_tests一次既有低概率 flake,LastTestsFailed.log记录为14:sdk_interaction_tests,与本用例无关)。分支假红率不高于基线,闸门通过。跨平台:本地 Windows 全绿不算完成,PR 合并后须等 Linux
sdk-coverage与 Windowssdk-windows双绿。规格回填见doc/player-state-contract.md§8 / §10.3 / §10.4 与doc/observability-contract.md§1 / §7.4。wt159 commentedon Nov 8, 2026
收口决议(2026-11-08):本票已由 PR #111 的
Closes #110自动 CLOSED,合并提交8b364301a。C1 / C5 端到端判据缺口已补齐,这是doc/player-state-contract.md§10.4 登记的唯一残留技术缺口的终态。交付
AudioDevice::setForceOpenFailureForTest():文件级std::atomic<bool>(默认 false,release/acquire),只在AudioDevice::open()包装层短路返回 -1;播放链走生产里真实存在的设备失败分支,sdk/MusicPlayer.cpp播放逻辑零改动。读点只在控制线程,soundbridge::Player公开 API 与七个 void 控制入口一字未动。audio device error reports error before state and does not skip track同时覆盖 C1(error→state 顺序、发且仅发一次状态、Stopped、错误码AudioDeviceOpenFailed)与 C5(默认 autoSkip 开启也不跳到第二首、不触发第二次播放尝试)。归属sdk_unit_tests(票正文误写sdk_interaction_tests,已在 comment6722195681更正)。doc/player-state-contract.md§8 / §10.3 / §10.4 与doc/observability-contract.md§1 / §7.4 已回填终态、证据与反悔通道。证据
SkipTrack检查 → 6 条断言红(含 C5 两条核心);把onError挪到 state 之后 →errAt < stAt精确红;还原后 12/12 绿。ctest -j4稳定性闸门:集成分支 10/10 轮全绿 14/14;master 基线 9/10 轮全绿(第 9 轮sdk_interaction_tests一次既有低概率 flake,与本用例无关)。分支假红率不高于基线,通过 [决策] 重审「不新造接缝」:批准一个默认关闭的设备错误注入点 #109 闸门。逐轮耗时见规格 §10.4。code-review(Standards 0 硬违规)提出的问题在361fc8bf8单提交修完:public钩子注释自相矛盾、relaxed 内存序与线程注释不严谨、文档在 CI 未跑时宣称「终态」、反悔通道与逐轮对照表不全。pull_request阶段 Linuxsdk-coverage42487403007success(14m15s)与 Windowssdk-windows42487403112success(4m34s),均 attempt=1;判定只认gh run view --json status,conclusion,attempt。零改动:
sdk/MusicPlayer.cpp、sdk/include/soundbridge/、.github/、sdk/test/CMakeLists.txt零改动;不新增add_test分组,不改 14 个sdk_*目标 / TIMEOUT / BadInput 55 例 / 覆盖度 15 行矩阵 / 任何既有判据数值;#104「不设数值阈值」与 §3.2 第 5 步永久生效不变。反悔通道:将来若要撤掉注入点,须另开新票并同时处理 C1 / C5 两条判据的归属,不得只删判据留下「契约无门禁」;该条款同时适用于
doc/observability-contract.md§1 / §7.4 的界外例外。docs: C1/C5 缺口收口,回填 CI 双绿终态(#110 / PR #111)
docs: 补记 PR #111 合并后 push run 的偶发 SIGSEGV 与 rerun 取证(#110)
wt159 commentedon Nov 8, 2026
补记(2026-11-08,合并后 push CI 复核):本票 resolution 的「跨平台双绿」准确限定为
pull_request阶段,此处补上合并后 master push run 的完整结果,避免未来读 resolution 时误以为全程无失败。sdk-windowspush run42488656337:success(attempt=1)。sdk-coveragepush run42488656322:attempt 1failure——sdk_interaction_tests的既有seek to middle moves position forward(test_player_integration.cpp:726)偶发SIGSEGV,14 条断言全过、6.27s 进程崩溃;承载本票新增 C1/C5 用例的sdk_unit_testsPassed 16.16 sec。gh run rerun 42488656322 --failed→ attempt 2success:100% tests passed, 0 tests failed out of 14,同目标Passed 12.24 sec,最终conclusion=success。判偶发 flake 依据:merge commit
8b364301a与 PR 分支头361fc8bf8的 tree 同为1caeeae0…(git diff为空),逐字节同代码在 PR run 与 rerun 两次全绿;失败用例属MusicPlayer Interactive Pathssuite,与本票新增用例(归sdk_unit_tests)零交集;AudioDevice::open()包装层默认 false 时行为等价、无新增崩溃路径。「失败目标不在改动文件」这一条本例不成立,已用上述替代证据补齐。未改任何判据 / TIMEOUT / 坏输入 55 例基线 / CI 配置,只做一次 rerun 取证。这是已知低概率 flake 的观测记录,不是待办;若反复出现须另开票重审。完整记录见
doc/player-state-contract.md§10.4(提交cb9aa6ab3)。本票状态不变,票正文不改。docs: 统一「CI 双绿」为 PR 阶段并指向 push run 复核记录(#110)