Skip to content

[决策] 消除 afterMonotonic 基线假红,重建 -j4 稳定对照基线 #115

Closed

Description

@wt159

背景:为什么现在开这张票

2026-11-09「强制重审」effort(#112 / #113 / PR #114)按事先写死的稳定性闸门撤回:分支两组 ctest -j4 各 9/10、真实 master 同轮数 10/10 全绿,两次失败完全同形态 —— sdk_interaction_tests / PublicPlayer Interactive Paths / test_player_integration.cpp:1408 的 CHECK(afterMonotonic),14.28s / 14.32s、111 断言 110 通过 1 失败、0 SIGSEGV;PR 阶段 Linux 42544814467 与 Windows 42544814456 均 success attempt=1。

撤回决议写明的重做前置条件是「先解决基线假红放大,或拿到 Linux 侧复现 / ASan 证据」。本票落实前者:把这条既有的低概率假红从根上修掉,让 -j4 同轮数对照有干净、可判定的基线,不再出现「分支假红率高于基线」这种无法归因的争议。

历史同源观测:2026-11-08 C1/C5 稳定性对照时 master 9/10 的第 9 轮也报过 sdk_interaction_tests 一次既有 flake(doc/player-state-contract.md §10.4)。基线本身并非无假红,本票要消掉的正是它。

根因假设 H_A(静态可辨,列为待实证;不先断言已定位)

position callbacks stay monotonic and a legal seek still rewinds(test_player_integration.cpp:1333-1409)的判据结构:

  1. first = callbacks.positionValues() 快照 → beforeCount = first.size()、before = first.back()。
  2. player.seek(100) → MusicPlayer::Impl::setPosition() 经 m_workQueue.asyncRunTask 异步执行 _setPosition(),后者才 seekToMs() + bumpPositionSession() + reportPosition(100, resetFloor=true)(合法回退)。
  3. waitFor(rewound, 3000) 轮询「beforeCount 之后存在 < before 的值」,stepMs=20(Windows 上 sleep_for 退到约 15.6ms 粒度)。
  4. after = callbacks.positionValues();afterMonotonic 从 beforeCount + 1 起逐对检查 after[i] < after[i-1]。

第 4 步隐含假设「after[beforeCount] 就是 seek 引起的那个回退值,其后全是新会话」。但 first 快照到 seek 异步任务生效之间,旧会话的消费循环仍在经 asyncRunTask 回投 position(带旧 epoch的任务会在 reportPosition 被丢弃,但已在快照后、seek 生效前已经上报的旧会话值不会被撤回)。只要这段窗口里追加了 ≥1 个旧值,after 就是 ... before, old+Δ, [回退值 100], 新会话...,回退点落在 beforeCount + k (k≥1) 而非 beforeCount,afterMonotonic 便把合法回退误判为「新会话内回退」。

与已知事实吻合:rewound 恒真而只有 afterMonotonic 单独红;失败耗时稳定(是断言失败不是超时);-j4 并发负载拉宽该窗口后命中率上升;与 AGENTS.md NOTES 登记的「断言依赖采样撞上短窗口必假红」「SEEKING 窗口固定 12ms、主循环 5ms 采样在 Windows 退到 15.6ms 粒度」同源。

备选 H_B(必须实证排除):若抓到的失败序列显示真回退发生在「回退值之后」(例如 100 → 更小值),则可能是 reportPosition 的 resetFloor=true 分支(sdk/MusicPlayer.cpp:781-786)在 seek 后被二次触发(换曲路径 putMusicPlayListCurBuf:684-688 也会 bumpPositionSession() + resetFloor),属生产契约问题,须另开新票,本票不越界改生产代码。

决议(AI 推荐,沿用既有一次性批量授权,无需再拍板)

批准一次「改既有判据表达方式」的限定 effort,口径写死如下:

  1. 修复 = 按实际会话边界切分,不是放宽判据。把「新会话起点」从固定 beforeCount 改为在 after 中定位实际回退点索引 rewindAt(第一个 < before 的位置),只检查 rewindAt 之后的新会话序列单调性;同时保留「合法回退必须发生」与「新会话内单调不回退」两条契约。
  2. 不放宽的硬定义:不删任何 CHECK / REQUIRE;不改任何数值容差、waitFor 超时(3000ms)、stepMs、seek 目标值、采样门槛;不新增 skipCase 条件;不改 TIMEOUT / 快集·全量集划分 / 14 个 sdk_* 目标 / 坏输入 55 例 · 396 断言基线 / CI 配置;不改任何生产代码(sdk/MusicPlayer.cpp、AudioStreamDecoder.* 等一律不动);不新增测试专用钩子(避免再引入 C1/C5 与 [实现] stop() 清空未消费 seek 槽并锁定状态契约 #113 的钩子稳定性闸门)。
  3. 可红可绿是放行前提:人为在新会话内注入一次真回退(变异验证),判据必须红;还原后绿。证明新判据没有把契约判松。
  4. 实证先行:实现票第一阶段必须抓到失败序列本身(临时诊断输出,取证后零残留),确认是 H_A 还是 H_B;不得跳过实证直接改判据。这是 [决策] 强制重审 seek 竞态:批准第二次限定例外与状态契约加固 #112 踩过的坑(上一轮 100 次单用例压力根本没经过候选窗口,0/100 却被当成证伪证据)。
  5. 稳定性闸门沿用 [决策] 强制重审 seek 竞态:批准第二次限定例外与状态契约加固 #112 决议 4:分支与 master 同轮数 ctest -j4 ≥10 轮对照(同机、同 build 目录、同样 -j4),分支假红率不得高于基线,且本用例在分支上 0 假红;两轴 code-review;Linux sdk-coverage + Windows sdk-windows 双绿(只认 gh run view <id> --json status,conclusion,attempt)。分支假红率高于基线即撤回全部改动并关闭 PR,不合并、不放宽任何判据 / 超时 / 基线。
  6. 反悔通道:若日后证明新判据只锁实现细节、削弱了契约覆盖,须另开新票同时恢复判据与文档,不得只改判据留下无门禁的状态。

边界(写死,不得扩大)

验收

  • 实证抓到失败序列,确认 H_A / 排除 H_B;诊断代码零残留。
  • 新判据在变异注入真回退时精确红、还原后绿。
  • 分支与 master 各 ≥10 轮同轮数 ctest -j4 对照,分支假红率不高于基线且本用例 0 假红。
  • 两轴 code-review 通过;PR 阶段 Linux + Windows CI 双绿。
  • 文档回填:AGENTS.md NOTES(假红根因与「固定索引切会话」反模式)、doc/player-state-contract.md §10.4、当日日志与长期记忆;如实保留「SIGSEGV 根因仍未定位」。

Activity

  1. added a commit that references this issue on Nov 9, 2026
  2. wt159 commented on Nov 9, 2026

    @wt159
    OwnerAuthor

    Resolution:决议 1–6 全部执行完毕,稳定性闸门通过,放行合并

    结果:PR #117 以 merge commit b482b900e 合入 master;本票与 #116 由 PR body 的 Closes 自动 CLOSED。OPEN 票 0 / OPEN PR 0。票正文未改,完整依据留在本 comment 与 PR #117 的两条结论 comment(6738312007 进度、6738722031 最终判定)。

    决议逐条落地

    1. 修复 = 按实际会话边界切分,不是放宽判据 ✅ 落地文件唯一:sdk/test/unit/test_player_integration.cpp,把「新会话起点」从固定 beforeCount+1 改为在 after 中定位实际回退点 rewindAt(首个 < before),只检查 rewindAt+1 之后的相邻对。两条契约(合法回退必须发生、新会话内单调不回退)与断言条数(该 suite 111)不变。
    2. 不放宽的硬定义 ✅ 未删任何 CHECK / REQUIRE(merger 复核 CHECK(40/40、CHECK_MESSAGE(97/97、REQUIRE(9/9);未改 3000ms / stepMs=20 / seek(100) / 采样门槛 / TIMEOUT / 14 个 sdk_* 目标 / 坏输入 55 例 / CI 配置;未改任何生产代码(git diff 全程仅 AGENTS.md + 测试文件);未新增测试专用钩子;未新增 skipCase。
    3. 可红可绿 ✅ 见 [实现] 按实际会话边界切分 afterMonotonic 判据,消除 -j4 基线假红 #116 resolution 阶段 2:注入新会话内真回退 → CHECK(afterMonotonic) 精确红(rc=1);字节一致还原 → 单用例 6/6 绿 + 全套 14/14 绿。
    4. 实证先行 ✅ 临时诊断(只写 stdout、失败时才打印、取证后零残留)全套 -j4 第 7 轮抓到失败序列 beforeCount=24 / before=535 / v[24]=558 / v[25]=100 / v[26]=123:H_A 成立(旧会话在快照后追加 k=1 个值,合法回退落到 beforeCount+1,被误判),H_B 排除(无二次回退、回退后 123 递增,无 resetFloor 二次上报迹象)。诊断 git checkout HEAD -- 还原,merger 复核 FLAKE-DIAG grep=0。
    5. 稳定性闸门(决议 4 口径) ✅ 同机、同 build 目录、同样 -j4、每轮全套 14 目标:分支 10/10 全绿、0 假红(60,59,58,60,59,56,58,59,60,58 s);master 915c2bc40 9/10,第 5 轮 sdk_interaction_tests 13.73s 失败,日志 :1408 CHECK( afterMonotonic )、111 断言 110 通过 1 失败 —— 与 fix: stop() 清空未消费 seek 槽并锁定状态契约(#112 / #113) #114 撤回时两次失败、阶段 1 复现完全同形态。分支 0/10 ≤ 基线 1/10 且本用例 0 假红 → 放行,不触发撤回分支。两轴 code-review:Standards 无硬性违规(1 处 Duplicated Code 判断项被仓库约束抑制),Spec 无范围蔓延、代码与票定伪码逐字一致;一条非硬缺陷提示(rewindAt 取首个 < before 依赖 H_A 实证前提,方向为更严假红而非漏判)如实留痕、不改码。PR 阶段 Linux 42603640630 / Windows 42603640466 均 completed/success attempt=1,headSha 2097825,无 rerun;合并后 push run 42607915236 / 42607915147 另行复核。
    6. 反悔通道 ✅ 若日后证明新判据削弱契约覆盖,须另开新票同时恢复判据与 AGENTS.md / 规格文档,不得只改判据。

    如实的证据边界

    10 轮对 10 轮样本很小,不宣称统计显著;放行依据不是频率差,而是「阶段 1 确定性 H_A 失败序列 + 阶段 2 红/绿变异验证 + 修复版 0 假红且 master 同轮数自然复现同一假红」这一组方向性证据,且严格按事先写死的闸门执行。

    边界(不变)

    • 本 effort 只解决 -j4 基线假红,为后续同轮数对照提供干净基线。
    • 不修 42488656322 attempt 1 的 SIGSEGV:无复现、无崩溃栈,CI 在 Linux ubuntu-24.04 / 本机取证在 Windows MinGW730,根因仍未定位;H1 已在 Windows 侧证伪、H2 未改、H3/H4 未验。
    • 不重做 [实现] stop() 清空未消费 seek 槽并锁定状态契约 #113、不重启「强制重审」、不合并或 cherry-pick ca3543fef;后续重做仍须另开新票并重走全套闸门。
    • AGENTS.md 的「反复出现」三条门槛不删、不放宽;11-09 破例是一次性留痕,不构成先例。
    • 文档回填:AGENTS.md NOTES 反模式条、本规格 §10.4、当日日志与长期记忆(合并后的纯文档提交,按 workflow paths 过滤不触发 CI 属预期)。
  3. added a commit that references this issue on Nov 9, 2026
  4. wt159 commented on Nov 9, 2026

    @wt159
    OwnerAuthor

    补充(不改 resolution):PR #117 合并后的 sdk-coverage push run 42607915236 attempt 1 曾 failure(sdk_unit_tests :256 断言 + sdk_interaction_tests :726 同形态 SIGSEGV,是不同 headSha 的第 2 次),rerun --failed attempt 2 全绿。判 flake 四证据齐全,且「反复出现」条件 ① 的「rerun 不能稳定消解」未满足 → 三条门槛仍未命中,维持观测、不另开票、不改生产代码。完整取证与口径见 PR #117 的结论 comment 及 AGENTS.md 门槛条 / doc/player-state-contract.md §10.4;本票放行结论与边界不变。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agent信息完备,agent 可直接开工

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions