Repository navigation
Closed
Labels
ready-for-agent信息完备,agent 可直接开工信息完备,agent 可直接开工
Description
承接
#115 决策票的决议已按既有一次性批量授权采用 AI 推荐,本票是其实现票(GitHub 原生 blocked_by 已连接)。本票只解决 -j4 基线假红,不修 SIGSEGV、不重做 #113。
目标:消除 sdk_interaction_tests / PublicPlayer Interactive Paths / test_player_integration.cpp:1408 的 CHECK(afterMonotonic) 低概率假红,让 ctest -j4 同轮数对照有干净基线。
改动清单(严格最小化)
唯一落地文件:sdk/test/unit/test_player_integration.cpp(用例 position callbacks stay monotonic and a legal seek still rewinds,:1333-1409)。
把「新会话起点」从固定快照索引 beforeCount 改为实际回退点:
const std::vector<uint64_t> after = callbacks.positionValues();
// seek 是异步 WorkQueue 任务;first 快照到 seek 生效之间旧会话仍会追加 position。
// 回退点不一定落在 beforeCount,必须按序列内容定位,不能按快照下标猜。
size_t rewindAt = after.size();
for (size_t i = beforeCount; i < after.size(); ++i) {
if (after[i] < before) { rewindAt = i; break; }
}
bool afterMonotonic = true;
for (size_t i = rewindAt + 1; i < after.size(); ++i) {
if (after[i] < after[i - 1]) {
afterMonotonic = false;
}
}rewound 的 waitFor 已保证序列中存在 < before 的值,且 positionValues() 只增不减,故 rewindAt < after.size() 成立;REQUIRE(rewound) 语义不动。
为什么这不是放宽判据:原判据把「after[beforeCount] 之后所有相邻对」都当新会话,于是旧会话尾部 before+Δ → 合法回退值 100 被误判成回退;新判据只把回退点之后当新会话,仍逐对检查单调。若真回退发生在新会话内部(H_B:100 → 更小值),rewindAt 之后那对仍会被抓到 —— 检测力不降反清晰。两条契约(合法回退必须发生、新会话内单调不回退)与断言条数均不变。
阶段 1:实证(必须先做,不得跳过)
- 在用例里临时加诊断输出(打印
beforeCount/before/ 完整after序列 / 实际回退点下标),只写 stdout(ctest捕获),不写任何固定名字的共享文件(-j4撞名假红的教训)。 - 用
ctest --test-dir build/sdk/test -j4 --output-on-failure反复跑全套直到复现一次(历史命中率约 1/10 轮,每轮约 58–62s;单用例串行复现率低,因为并发负载才拉宽窗口)。 - 依据抓到的序列判定:
- H_A 成立:失败序列形如
... before, before+Δ1, before+Δ2, 100, 100+δ ...,回退点在beforeCount + k (k≥1)→ 按上面的改动清单修复。 - H_B 成立:出现「回退值之后还有更小值」或多次回退 → 属生产
reportPosition/resetFloor路径问题,本票停下并另开新票,不改生产代码。
- H_A 成立:失败序列形如
- 诊断代码
git checkout HEAD -- <file>还原,零残留。
阶段 2:变异验证(可红可绿)
- 构造「新会话内真回退」输入:临时让 seek 之后再触发一次
resetFloor上报(例如_setPosition()后追加一次reportPosition(较小值, ..., true, ...)),新判据必须红;或直接在判据侧注入一条含真回退的after序列验证循环能抓到。 - 字节一致还原生产文件后必须绿。取证期间对生产文件的临时改动允许,但还原后
git diff必须为空。 - 记录红/绿两条命令与输出,作为「未放宽判据」的证据。
阶段 3:稳定性闸门(沿用 #112 决议 4,一票否决)
- 分支与 master 同轮数
ctest -j4≥10 轮,同机、同 build 目录、同样-j4;分支假红率不得高于基线,且本用例在分支上 0 假红。 - 切 master 对照前先
git checkout master并重编译UnitTests;切回分支同样重编译,避免拿错二进制。 - 分支假红率高于基线即撤回全部改动并关闭 PR,不合并、不放宽任何判据 / 超时 / 基线 —— 与 PR fix: stop() 清空未消费 seek 槽并锁定状态契约(#112 / #113) #114 的处理完全一致。
- 两轴
code-review;PR 阶段 Linuxsdk-coverage+ Windowssdk-windows双绿(只认gh run view <id> --json status,conclusion,attempt)。
明确不做
- 不改任何生产代码作为落地改动(
sdk/MusicPlayer.cpp、AudioStreamDecoder.*、公开 API、七个void控制入口)。 - 不新增测试专用钩子 / 注入点(避免再引入 [实现] stop() 清空未消费 seek 槽并锁定状态契约 #113 的钩子闸门);不新增
add_test分组。 - 不删任何
CHECK/REQUIRE,不新增skipCase条件;不改任何数值容差、waitFor3000ms、stepMs=20、seek 目标、采样门槛、TIMEOUT、快集 / 全量集划分、14 个sdk_*目标、坏输入 55 例 / 396 断言基线、CI 配置。 - 不改
afterMonotonic的断言条数(该 suite 目前 111 断言 / 19 用例)。 - 不修
42488656322的 SIGSEGV(根因仍未定位:无复现、无栈、CI=Linux / 本机=Windows 不可外推);H2 未改、H3/H4 未验。 - 不重做 [实现] stop() 清空未消费 seek 槽并锁定状态契约 #113、不合并或 cherry-pick
ca3543fef;重做须另开新票重走全套闸门。 AGENTS.md的「反复出现」三条门槛不删、不放宽。
验收
- 阶段 1 抓到失败序列并判定 H_A / 排除 H_B;诊断代码零残留。
- 阶段 2 变异验证精确红 → 字节一致还原 → 绿;生产文件
git diff为空。 - 阶段 3 分支与 master 各 ≥10 轮同轮数
-j4,分支假红率不高于基线且本用例 0 假红。 - 两轴
code-review通过;PR 阶段双平台 CI 双绿。 - 文档回填:
AGENTS.mdNOTES(「按固定快照索引切会话」反模式 + 本假红根因)、doc/player-state-contract.md§10.4、当日日志与长期记忆;如实保留「SIGSEGV 根因仍未定位」以及「本 effort 只解决基线假红」。 - 票正文不改,resolution 留完整依据(实证序列、变异验证命令、逐轮对照数据、撤回或放行的判定)。
Metadata
Metadata
Assignees
Labels
ready-for-agent信息完备,agent 可直接开工信息完备,agent 可直接开工
Activity
merge: #116 afterMonotonic 按实际回退点切分会话(merger)
Merge pull request #117 from wt159/implement/flake-baseline-after-mon…
wt159 commentedon Nov 9, 2026
Resolution:实现完成、全部验收通过,随 PR #117 合入 master
结果:PR #117 merge commit
b482b900e。实现提交a07d19f3d(implementer worktree)→209782555(merger--no-ff合入集成分支)。唯一落地代码文件sdk/test/unit/test_player_integration.cpp,7 insertions / 1 deletion;另有AGENTS.md+1 行的 #115 决议档。票正文未改。阶段 1 实证(H_A 成立 / H_B 排除)
诊断版本在
afterMonotonic为 false 时才printf到 stdout(不写任何固定名字共享文件),全套ctest --test-dir build/sdk/test -j4 --output-on-failure第 7 轮复现,日志build/flake-diag/round_7.log:rewindAt搜索从beforeCount起,v[19..22]虽< before但在快照范围内,不会被误定位。sdk_interaction_tests12.51s 失败、test cases: 19 / 18 passed / 1 failed、assertions: 111 / 110 passed / 1 failed,失败点:1408(诊断版因插入 16 行显示为:1424)CHECK( afterMonotonic )。H_A 精确成立;H_B 排除(只有一次回退,回退后 123 单调递增,没有「回退值之后还有更小值」或多次回退,无resetFloor二次上报迹象)→ 不需另开生产票。诊断git checkout HEAD --还原,merger 复核FLAKE-DIAGgrep=0。阶段 2 变异验证(可红可绿)
cd sdk/test && UnitTests.exe -tc="position callbacks stay monotonic and a legal seek still rewinds"test cases: 1 / 1 passed,assertions: 6 / 6 passed,Status: SUCCESS!,rc=0after改为非 const 并after.push_back(50)(新会话123 → 50)后重编译:1415 ERROR: CHECK( afterMonotonic ) is NOT correct!,assertions: 6 / 5 passed / 1 failed,Status: FAILURE!,rc=1git checkout HEAD -- sdk/test/unit/test_player_integration.cppgit diff为空;重编译后单用例6/6 SUCCESSrc=0;全套ctest -j414/14 全绿 59.38s生产文件全程未改(
sdk/MusicPlayer.cpp等git diff恒为空)。证明新判据仍能抓到新会话内真回退,检测力未降。阶段 3 稳定性闸门(放行)
同机、同 build 目录、同样
-j4,每轮全套 14 目标,脚本build/flake_gate.sh:afterMonotonic假红,逐轮 60,59,58,60,59,56,58,59,60,58 s。915c2bc40(旧判据)9/10,第 5 轮sdk_interaction_tests13.73s 失败,逐轮 58,59,58,57,58,55,58,57,57,59 s;失败日志build/flake-gate/master_round_5.log::1408 CHECK( afterMonotonic ) is NOT correct!、111 断言 110 通过 1 失败,与阶段 1 及 fix: stop() 清空未消费 seek 槽并锁定状态契约(#112 / #113) #114 两次失败完全同形态。6/6 SUCCESS、源码工作区无改动。判定:分支 0/10 ≤ 基线 1/10 且本用例 0 假红 → 放行,不撤回、不放宽任何判据 / 超时 / 基线。10 对 10 样本小,不宣称统计显著;证据强度来自确定性失败序列 + 红绿变异 + 同轮数 master 自然复现。
两轴
code-reviewrewindAt只读本地快照未落判据主循环额外写、无钩子、断言与数值未动、诊断零残留)。1 处Duplicated Code判断项(定位循环与waitForlambda 同形)被「就地判据、不新增 helper/钩子、断言条数不变」的仓库约束抑制,不改。beforeCount、rewindAt=after.size()、命中即 break、rewindAt+1检查),无范围蔓延;rewindAt边界安全(找不到时rewindAt=size、二循环不执行,但CHECK(rewound)会红,不静默通过);两条契约保留。一条非硬缺陷提示留痕:rewindAt取首个< before,正确性系于 H_A 实证前提「快照后旧会话追加值恒>= before」;若该段出现< before的旧值会提前定位、把合法回退重判为回退 —— 方向是更严的假红而非漏判,且monotonicCHECK 原本就不覆盖该追加段。不改代码以免偏离票定伪码与「不放宽」口径。验收清单
-j4,分支 0 假红。42603640630+ Windows42603640466双绿 attempt=1(只认gh run view --json status,conclusion,attempt)。AGENTS.mdNOTES 反模式条 + 补「只解决基线假红 / SIGSEGV 根因仍未定位」、doc/player-state-contract.md§10.4、当日日志与长期记忆。add_test/ 不删 CHECK / 不改数值与 TIMEOUT / 不修 SIGSEGV / 不重做 [实现] stop() 清空未消费 seek 槽并锁定状态契约 #113 / 不合并ca3543fef/ 门槛不删不放宽)。docs: 回填 #115/#116 基线假红 effort 的放行结论与全套证据
wt159 commentedon Nov 9, 2026
补充(不改 resolution):合并后 push run
42607915236attempt 1 的两个失败目标都在test_player_integration.cpp,故「失败目标不在改动文件」不成立,按AGENTS.md登记的替代取证处理:tree 对比209782555vsb482b900e为空、doctest suite 过滤器确认与本次改动用例零交集、同代码 PR run42603640630已绿、一次rerun --failed全绿。未放宽任何判据 / 超时 / 基线;详细数据见 PR #117 结论 comment。本票验收结论不变。