## Parent [#85](https://github.com/wt159/SoundBridge/issues/85) — [Spec] 播放器状态与公开 API 契约实现计划。 ## What to build 把规格 §8 表格里剩下的三类契约变成判据:曲目切换固定 `onTrackChanged → onDurationChanged → onPositionChanged`、`onDurationChanged` 每曲一次、状态序列无相邻重复;重复 `play/pause/stop` 不重复发状态、被丢弃命令不产生回调也不改查询值;「必须上报清单」各码至少有一条可判定路径,并把 `PlaylistEmpty` / `ResampleInitFailed` / `ResampleFailed` 明确标为「有码不承诺上报」。 - 只扩既有分组与记录器,**不改既有断言数值**;对无法判定的重入 / 所有权 / ABI 不写测试。 - 若发现某条契约在现状下不成立,先修生产链最小改动,再补判据(在同一票内闭环)。 ## Acceptance criteria - [ ] 三类契约都有可红可绿的用例,落在 `sdk_player_tests` / `sdk_unit_tests` / `sdk_interaction_tests` - [ ] 既有四个数值判据与坏输入 / 覆盖度基线原样通过 - [ ] 新增用例不写固定名共享路径,不引入裸 sleep ## Blocked by [#87](https://github.com/wt159/SoundBridge/issues/87), [#88](https://github.com/wt159/SoundBridge/issues/88), [#89](https://github.com/wt159/SoundBridge/issues/89)(GitHub 原生 blocked_by 已连接)。. **必须遵守(来自 spec、ADR 0002/0003/0004 与 `doc/bad-input-spec.md`):** - 七个控制入口保持 `void`;不新增错误码、不改 `onError` 签名、不新增状态机、不扩状态集合(对外仍 `Playing/Paused/Stopped` 三态)。 - 判据**不新造数值**:沿用 `max(1%,150ms)`、`r × good`、5pp、零容差差分、getter 与回调 ≤50ms、状态序列无相邻重复、每曲一次 duration。 - 坏输入 55 例 / 396 断言与覆盖度矩阵 15 行**一字不动**;14 个 `sdk_*` ctest 目标、TIMEOUT、`-j4`、快集 / 全量集划分全部不动。 - 新增用例若写文件必须带 pid(`-j4` 撞名假红的教训);线程契约用 `promise/future` 或轮询验证,不裸 sleep。 - 事实基线见 [#76](https://github.com/wt159/SoundBridge/issues/76) 的 `research/public-api-contract-facts` 分支;术语见 `GLOSSARY.md`。
Activity
test: 回调三连与重复命令幂等的补强判据(#91 / T06)
wt159 commentedon Nov 8, 2026
Resolution(2026-11-08,图外实现 effort #85 / PR #93)
补齐规格 §8 剩下三类判据,只扩既有分组与记录器、不改任何既有断言数值:
onTrackChanged → onDurationChanged → onPositionChanged;duration 计数限定在「首个 position 之前」的窗口(code-review m2 修复),避免稳态播放追加事件让断言失真。play/pause/stop不额外发状态回调:每个重复命令后接一个必定改变状态的哨兵命令作队列屏障(code-review M4 修复,去掉裸 sleep),并给无声卡加skipCase。test_error.cpp的 action 表锁住「必须上报清单」的口径输入。重入 / 所有权 / ABI 仍只写头文件注释与规格,不做最小可测替身。全量 14/14 绿。