Skip to content

[R2][回归] 定位 hosted 剪贴板占用反馈后的45秒超时 #99

Open

Description

@JavaZeroo

当前接续(2026-11-01)

首错failure_step、当前state_step和独立清理secondary字段已经分列,原“先补ready握手字段”的实施步骤已完成。第二批观测在原失败谱系的Draft #300上完成两个默认配置场景,未复现45秒事件;该PR只作诊断,不算产品修复。

剩余是原失败瞬间stage/owner/helper/UI泵的因果定位。有同类失败或新假设再做有界批次,保留45秒期限,不能用新绿色结果回填旧根因。本项继续开放,归#38汇总。以下原合同与原件身份保留。


真实失败与范围

PR98 push default run 40453238227,Windows job 122020560138,checkout/HEAD 678804ff5201fab4296b133af9457b7120739b68,默认自研核心 + system ConPTY。完整 CTest 51/52,300.54s;唯一失败组 shell 40项中38通过、1error、1skip,113.401s。

失败是 ShellTests.test_system_clipboard_product_read_errors_cancel_and_close 第一轮 ui-clipboard-system。外部原60秒未超时;内部 launcher 原45秒到期,exit124,stderr=test launcher child exceeded 45 seconds。同HEAD PR默认52/52(260.27s)及两条candidate成功不能覆盖该push失败;没有重跑取绿。

原件审计与已知阶段

r1-windows-input artifact 12711093376,4242073B,ZIP SHA 2dde2aa91b24b7afb59a8c4536d89b586846fc4815d008d7a5a44bbe939890f9 与GitHub digest一致。完整ZIP与该例四个文件保存于私有 local/r56-native-runtime/r98-clipboard-timeout 及相邻ZIP,未修改原件。

  • sample SHA 085acdd3acdde2052fa8b8569f838efbc4c54147bc4c32510e69f06c29a544b3:timed_out=false、launcher exit124、stdout为空;回收后Job active0/total14/terminated0,desktop_gone=true。回收不代表自然退出。
  • 已产生 occupied-error.bmp,2745846B,SHA dbf5618927a80184d5b7e86921adcbf0be0d198ceabef8b0a545e36c956c8306;未据文件存在声称整项或实际呈现通过。
  • occupied.bin 为精确256个 B,SHA b0102e3e5f3ced3b4bd1e9d1a08ef35c5fce216b024beea399c4a51b95ece8e7,未出现显式重试载荷;只有这两个文件、sample与workspace.layout,没有最终 clipboard-workflow.json、后续case文件或第二轮。
  • 固定源码中该错误图在 occupied 场景 stage4 的产品错误状态检查后生成;后面依次包含 helper/忙状态回收、owner释放/finish、另一会话标记及显式重试。失败瞬间的确切stage、owner线程、helper、UI泵、重试与EOF未知,不能从文件缺失或Job计数推出死锁位置。
  • sample未记录逐运行EXE哈希;此处保留CI构建/checkout身份,不补造逐运行绑定。

与已有失败分列

本例是产品Paste读取占用反馈后的launcher超时,不是 #85 已观察的选择复制夹具 OpenClipboard5,也不同于 #73 首条选择记录缺失或 #97 candidate-scroll 20秒退出超时;尚无同因证据。PR98没有修改剪贴板场景/worker文件,但这不能代替根因分析。原产品占用反馈、显式重试、取消/关闭合同保持。

有界后续与验收

  • 保持原两轮、occupied/oversized/cancel/target-close四case、256B基线、精确重试字节及原45/60秒期限;不增加sleep、跳过或延长等待取绿。
  • 从现有失败原件开始,固定最小阶段记录与样本/停止条件;区分错误反馈之后的helper回收、owner release/finish、UI泵、会话标记与显式重试等待。原异常、强制结束和Job/desktop结果分别保留。
  • 仅在已有一次性hosted VM验证真实系统剪贴板;不伪造hosted标记、不操作个人Windows剪贴板。受控错误路径不冒充原超时因果复现。
  • 获得同类失败后最小修复和必要反例;最终同源码原方法与完整声明配置通过。若未复现,保留原失败和未知,继续独立工作。

父项 #38,本项阻塞 #38;关联 #13 的既有剪贴板产品合同。此项可独立开始,不阻塞无关源码margin实验,但继续阻塞完整R2可靠性验收。

下一次有界观测(执行前固定)

以原失败源码 678804ff5201fab4296b133af9457b7120739b68 建独立诊断分支。仅在该分支的首轮 push/default Windows hosted CI 开启 [DEBUG-r99] 阶段记录;保留原完整回归上下文和该方法的两轮四case、256B基线及45/60秒期限。普通PR/candidate检查不启用记录,结果分列;不增加重试、sleep或修改个人剪贴板环境。

记录只包含stage/case索引、单调时长/回调计数、helper的零等待状态、paste busy、owner的固定步骤名/释放事件/错误数字,以及owner release/finish、会话标记发送、显式retry调用前后的固定事件。每次阶段/事件变化及至多每秒一个heartbeat,最多256行;不保存剪贴板内容、终端文字、路径、PID/HWND或凭据。记录是改善失败定位的临时诊断,不作为性能/呈现证据;文件I/O可能影响时序。若原失败未复现,本批只报告未复现及实际阶段覆盖,保留#99开放,不循环取绿。临时观测不并入产品。

首批阶段观测结果:未复现,停止本批

Draft PR101,观测源码 b9789543a792b0a0b96139377ea43f4dfab46626,tree bb8d6ce8464ec8b50ff86000dfb1f0b39b3b9888。本地构建通过、原非hosted守卫3/3,Standards/Spec分别0 findings;真实CF只在下面的hosted运行。临时观测不是原因修复。

首轮 push/default Windows 40459936505 / job122041868650 的原方法两轮均完成四case;独立离线重新验证270/270/268/256 B接收、owner释放/退出、helper回收及最终结果。两轮均exit0、未超时、Job active0/total27/terminated0、desktop gone,stderr空。每轮72条记录、45次callback,阶段/事件顺序、单调字段、字段白名单及256条上限均核验;未截断。最后记录分别为1614/1527ms的complete-before-close,这是诊断阶段时长,不是端到端性能或自然退出时刻。原#99的45秒事件没有复现,原因仍未知,不循环再跑此批。

原始r1-windows-input artifact12714865514为4269771B,ZIP SHA 4b597e169d36624c87a6a9859e0fc3b2a37846569bca3eaca4c51322ec7d2791与GitHub digest一致。私有local/r99保存完整ZIP、原两轮和离线审计;首次下载的1572864B不完整文件保留并排除。CI clean-build清单记录四个固定EXE SHA及checkout;这是构建身份,未归档二进制不声称被本地重新哈希。trace SHA分别为13bb8dc1fa4167b5baafaba6e999cd5fccdb25ac79a53b9b0a8012bdabfd27c4、a4838fac461364dce95f0f68e7a3c927ed4f264c88f6629fc2b2bafc607205b4。

完整CI仍失败,不能写成联合验收通过:push Windows50/52、280.05s;PR Windows51/52、276.72s;两条Linux均32/33,12.67s/12.95s。四者均暴露诊断新增清单路径导致的既有workflow路径计数断言2!=1;push Windows另有原ui-copy-system第二轮OpenClipboard5,另记#85的新入口,不与#99合并根因。PR实际checkout b58c029fc0f861c2e7d251d125b18ec70e80dda9且trace关闭。两条External candidate各自通过,不能抵消default失败。临时C++记录与CI启用步骤现已全部撤回;最终PR101相对父#98只保留审核过的证据与限制说明。收尾源码33129ce5a6fdaddc5d7a623b7997d9915ee88f4c、tree47e57b97bc9f9251382e9f5c259aca1e4cba2cb8;三处恢复文件与父678804f一致,原ActionOracleTest7/7(0.487s),Standards硬规则0/异味0、Spec0。收尾源码 33129ce5a6fdaddc5d7a623b7997d9915ee88f4c 的四条CI均成功,未重跑:PR default 40463504513 Windows52/52、271.41s,Linux33/33、12.69s;push default 40463501535 Windows52/52、271.55s,Linux成功;PR/push candidate 40463504537/40463501543分别成功。PR实际checkout 8f4ac81396cd957c7c86970cb4db1891d9203cc0,tree与审查一致。诊断已关闭;这些是撤回后的独立回归,原观测批的两项失败和#99未知原因保留。报告和公开白名单见PR101;没有追加诊断批次。

PR108 的另一阶段失败:delayed owner 准备(与原45秒事件分列)

push/default Windows run40521519113 / job122249591319,HEAD 678a7f41df8323e550b2804f664f2a3d7510d0a4,默认自研核心/system。完整CTest 45/46、266.40s;shell组39项中1error、1skip。PR默认及两条候选CI分别成功,不能覆盖此失败;没有重跑。

失败仍在原方法 test_system_clipboard_product_read_errors_cancel_and_close,但本次是第一轮 cancel case、stage3、prepare-owner / before-product-paste,不是原占用反馈后的45秒超时。stderr为 mode=delayed step=DestroyWindow-cleanup win32_error=5 worker_error=5 registration_last_error=0 wait_status=0。exit2、timed_out=false;Job收尾前后active0/total20/terminated0,desktop_gone=true。

r1-windows-input artifact12741568178 为4283054B,ZIP SHA256 e6083dcd130cf306f44fe9e3c2e0809a47e7b1747ba86f241a4c66f17e4d0334 已下载并与GitHub digest核对,原件仅保留私有local/r29-replay-boundaries。occupied.bin与oversize.bin各270B;cancel.bin为精确256个B(SHA256 b0102e3e5f3ced3b4bd1e9d1a08ef35c5fce216b024beea399c4a51b95ece8e7)。没有最终clipboard-workflow.json、target-close文件或第二轮。文件存在与长度不单独代表前两case完整验收。

源码核对:ClipboardScenarioOwner::record_failure 保存首个错误及failure_step,但 ready_failure 输出的是持续变化的 step_;catch清理会将该字段改为DestroyWindow-cleanup。因此日志可能把清理步骤名与更早保存的错误5组合,不能据此认定DestroyWindow是原始失败API或根因。本次尚未确定原生首错调用、占用/权限上下文,也未与#85或本项原45秒事件建立同因关系。

接续时先让ready握手错误保留原始failure_step和独立清理错误,再按原两轮四case及3秒ready/45秒launcher/60秒外层期限作有界验证。保持一次性hosted保护,不用增加等待或自动重试掩盖首错;本节记录新样本和诊断缺口,不作为原因修复。

Activity

  1. self-assigned this
    on Oct 27, 2026
  2. added
    ready-for-agent范围明确且真实阻塞已解除,可开始实施
    research有明确问题与出口的证据调查
    on Oct 27, 2026
  3. added a commit that references this issue on Oct 29, 2026
  4. JavaZeroo commented on Oct 30, 2026

    @JavaZeroo
    OwnerAuthor

    剪贴板 OpenClipboard: 5 家族的文本形状盘点(只读源码 + local/repeat* 计数)

    0. 身份与范围

    • 源码:worktree D:\Code\termforge-uia-note,分支 feat/qt-reply-wiring,HEAD 350c158,git status 干净。仅静态阅读。
    • 读取的文件:clipboard.hpp、clipboard_scenario_state.hpp、clipboard_worker.cpp、clipboard_worker.hpp、workspace_clipboard_scenario.hpp、shell.cpp、text_interactions.hpp、run.py、test_shell.py。
    • 相关提交(git log 实读):4a69077 读重试、3fe57d6 写重试、fd1d641 夹具准备重试、23f3399 清理前 SetLastError(0)、0a90489 failure_step/state_step 分离。
    • 未构建、未运行测试/CI、未调用系统剪贴板。

    1. 产品路径(clipboard.hpp 及其调用面)

    # 文本形状 产生点 重试/界(代码实读) 落到 UI 的方式
    P1 OpenClipboard: <code>(5=ERROR_ACCESS_DENIED) ClipboardAccess 构造 读 5 次尝试,Sleep 20/40/60/80 ms(合计 200 ms);写 3 次尝试,Sleep 10/20 ms(合计 30 ms,源码注释给的界是 ≤60 ms) 复制:Copy failed: OpenClipboard: 5(footer + 标题 TermForge — Copy failed: OpenClipboard: 5,shell.cpp:298);粘贴/读取:不出现,UI 固定 system clipboard read failed,码只进证据字段 win32_error
    P2 Unicode text unavailable: 1168 读路径 打开成功后判定,无重试 读取:被 helper 收成 system clipboard read failed
    P3 GetClipboardData: <code>、GlobalLock: <code>(读)、GlobalAlloc: <code>、GlobalLock: <code>(写)、EmptyClipboard: <code>、SetClipboardData: <code> 读/写路径 同 P1 的重试窗口 复制:前缀 Copy failed: 可见;读取:隐藏,只留码
    P4 非 code 形:clipboard limit exceeds hard bound、copy exceeds clipboard limit、clipboard copy requires an owner window、copy contains embedded NUL 上限/参数校验 无 复制可见;读取的 length_error 在 helper 内映射为 111
    P5 固定文案:system clipboard read failed、clipboard read cancelled、clipboard read timed out、clipboard helper exited with an incomplete frame、invalid clipboard protocol header、clipboard pipe read failed、clipboard pipe inspection failed、clipboard frame exceeds limit、trailing clipboard data、clipboard helper termination failed、clipboard Job inspection failed clipboard_worker.hpp helper 期限 50..10000 ms(当前 5000) 直接作为 footer 状态(shell.cpp:360)
    P6 Paste failed: <what> shell.cpp:388 同步异常兜底 — 仅同步阶段异常(helper 创建/启动失败等)

    要点:读取已异步化到 helper,OpenClipboard: 5 原文不会到达 UI;写仍是同步,所以只有"复制"能显示 OpenClipboard: 5 原文。

    2. 夹具路径(clipboard_scenario_state.hpp)

    # 文本形状 产生点 关键字段
    F1 clipboard owner failed its bounded ready handshake: mode=<occupied|delayed> failure_step=<step> state_step=<step> win32_error=<n> worker_error=<n> registration_last_error=<n> wait_status=<n>(stderr 带 [TF-CLIPBOARD-OWNER] 前缀) ready_failure():3 s ready 等待后 ready_status!=WAIT_OBJECT_0 || error_ failure_step 保存首个失败调用;state_step 是记录时刻的当前步骤(catch 清理后通常是 DestroyWindow-cleanup)
    F2 clipboard owner worker failed: mode=... step=<failure_step|当前step> win32_error=... worker_error=... secondary_step=<step|none> secondary_native_error=... secondary_worker_error=... released()/finish() 的 reject_worker() 次级错误独立成字段
    F3 [TF-CLIPBOARD-OWNER] teardown deadline: step=... win32_error=... worker_error=...,随后 _Exit(92) stop() 3 s 未回收 不抛文本,进程退出码 92
    F4 clipboard case=<occupied|oversize|cancel|close> phase=prepare-owner before-product-paste: <内层> workspace_clipboard_scenario.hpp:67-70 内层可为 F1 或 F5
    F5 准备写入内层:OpenClipboard: <code>、GlobalAlloc/GlobalLock/EmptyClipboard/SetClipboardData: <code>、oversize fixture allocation failed、oversize fixture lock failed、oversize fixture publish failed、system clipboard scenario requires a disposable GitHub-hosted VM、clipboard fixture events failed、clipboard contention release timeout write_unicode_clipboard、write_oversized_clipboard、require_hosted_clipboard、paste_check prepare_clipboard 重试 4 次、Sleep 50/100/150 ms,仍失败则原样抛出最后一次 what()

    record_failure 在 native_error==0 时用 ERROR_GEN_FAILURE(31) 兜底,所以 win32_error=0 worker_error=31 也是合法形状。

    固定步骤名(step() 实取 23 个,另 2 个只作 failure_step 出现):

    thread-not-started、SetThreadDesktop、RegisterClassW、CreateWindowExW、OpenClipboard、EmptyClipboard、SetClipboardData-delayed、IsClipboardFormatAvailable、CloseClipboard-ready、GetOpenClipboardWindow、SetEvent-ready、Wait-release、CloseClipboard-release、GetMessageW、CloseClipboard-cleanup、DestroyWindow-cleanup、SetEvent-render-entered、WaitForSingleObject-render-release、GlobalAlloc-render、GlobalLock-render、GlobalUnlock-render、SetClipboardData-render、SetEvent-render-released、DestroyWindow-close;另有 WaitForSingleObject-render-release-timeout、WaitForSingleObject-render-release-failed。

    3. local/repeat* 命中计数

    文件夹 OpenClipboard: 5 其中 Copy failed: OpenClipboard(产品负向契约) prepare-owner TF-CLIPBOARD-OWNER 命中文件数
    repeat2 / repeat3 / repeat-evidence 0 0 0 0 0
    repeat4 28 28 0 0 12
    repeat5 14 14 0 0 6
    repeat6 14 14 0 0 6
    repeat7 28 28 0 0 12
    repeat8 14 14 0 0 6
    repeat9 30 28 2 0 13
    repeat10 14 14 0 0 6
    repeat11 28 28 0 0 12
    repeat12 56 56 0 0 24
    repeat13 56 56 0 2 24(+1 个 owner 文件)
    repeat14 70 70 0 0 30
    repeat15 14 14 0 0 6
    repeat16 70 70 0 0 30
    合计 436 434 2 2 187(+1)

    口径:local/repeat* 下 25,325 个文件(.json/.jsonl/.layout/.txt/.log 按 UTF-8、.bin 按 UTF-16LE),跳过 5,023 个二进制(绝大多数 .bmp,合计约 23.2 GB)。命中数不等于失败事件:copy 证据每 case 固定 7 条(sample.json 1 + selection.json 4 + selection-interactions.jsonl 2),186 个 copy 文件 = 62 case = 31 轮。

    全部命中里只有 2 个 sample.json 属于本家族且非 passed:

    产物 模式 / 测试 状态 error 原文
    local/repeat9/shell/run-ivc325fs/clipboard-system-1/sample.json ui-clipboard-system / test_system_clipboard_product_read_errors_cancel_and_close failed,exit 2,timed_out=false shell probe failed: clipboard case=oversize phase=prepare-owner before-product-paste: OpenClipboard: 5
    local/repeat13/shell/run-dxct4ssg/copy-system-0/sample.json ui-copy-system / test_mouse_selection_to_real_system_clipboard failed,exit 2,timed_out=false shell probe failed: [TF-CLIPBOARD-OWNER] clipboard owner failed its bounded ready handshake: mode=occupied step=DestroyWindow-cleanup win32_error=5 worker_error=5 registration_last_error=0 wait_status=0

    两者都是旧文案(step= 而非 failure_step=/state_step=),形状与 #85 第 2、3 条评论一致;本地没有 mode=delayed 的同类样本。

    4. 结论:产品可见 vs 仅夹具准备

    • 产品可见且在契约内:434 条 Copy failed: OpenClipboard: 5 全部落在 status=passed 的 copy-system 产物里(31 轮 × 2 case),由夹具故意长期持有剪贴板触发,test_selection_bytes.py:202 与 validate_selection 仍要求该文案。这批是负向契约证据,不是缺陷信号。
    • 产品可见但不含码:粘贴/读取失败只显示 system clipboard read failed;OpenClipboard: 5 不会以原文出现在粘贴路径,码 5 只存在于证据字段。
    • 仅夹具准备:prepare-owner ... OpenClipboard: 5(repeat9)是夹具在 stage3 写"占用"场景时被别人占着;fd1d641 已有 4 次/50/100/150 ms 重试,仍失败才原样抛出。
    • 仅夹具 owner:[TF-CLIPBOARD-OWNER] ... ready handshake(repeat13)是夹具自己的 owner 线程;旧版把持续变化的步骤名与首错码拼在一起,23f3399/0a90489 后拆成 failure_step/state_step。
    • 两条失败样本都没有触及产品读/写的失败判定,不能据此推断产品路径根因,也不与 [R2][回归] 定位 hosted 剪贴板占用反馈后的45秒超时 #99 原 45 秒事件建立同因关系。

    静态观察(新,未运行验证):ready_failure() 直接拼 failure_step_.load(),而该原子初值是 nullptr;若握手是超时(wait_status=WAIT_TIMEOUT 且 error_==0),这里会把 nullptr 拼进 std::string(UB)。也就是说"ready 握手超时"这一形状当前无法安全输出;worker_failure() 对 nullptr 有保护,两处不一致。下一次握手超时会直接影响取证。

    5. 单一"下一次观测"

    只加一个观测:失败瞬间的剪贴板持有者类别。在最后一次 OpenClipboard 失败处取 GetOpenClipboardWindow(),归类为 ①等于夹具 window_ ②同进程其他窗口 ③其他进程窗口 ④无打开窗口,并记录该次发生在 product 读 / product 写 / fixture prepare 写 / fixture owner 的哪一处(只记类别,不记 HWND/PID/标题/内容)。

    一条就够的原因:两条失败样本都不含持有者身份,#85 正文已把"打开者/所有者是谁"列为未知;selection-bytes 的 stage6/7 已有同类分类(docs/research/selection-clipboard-boundaries.md),但 prepare-owner 写与 owner ready 两处没有。三类结果直接分开三种原因:自己/上一 case → 夹具串行化问题;其他进程 → 外部占用超过预算;无打开窗口 → 不是占用而是访问上下文/权限,重试无意义。

    边界

    • 只做了静态代码阅读 + 对本地已下载产物做文本扫描;未构建、未运行任何测试/CI、未调用真实系统剪贴板、未修改产品/夹具代码。
    • 计数范围仅 local/repeat*;未扫描 .bmp/.png/.exe/.zip,.bin 只按 UTF-16LE 解码,若以 UTF-8 存文本会漏。命中数与失败事件不是一一对应(copy 每 case 7 条)。
    • 未核对 repeat 产物与具体 CI run/artifact 的 SHA。与 [R2][回归] 定位 hosted 选择复制夹具的 OpenClipboard 5 #85 第 2、3 条评论的对应仅依据文本形状、模式名和目录时间戳(repeat9 6:49:48、repeat13 7:57:37,对应提交 fd1d641 6:50:56、23f3399 7:58:24),不声称是同一运行。
    • 未判断 [R2][回归] 定位 hosted 选择复制夹具的 OpenClipboard 5 #85 最初 ui-copy-bytes-system sentinel-write/readback 的根因,也未判断 [R2][回归] 定位 hosted 剪贴板占用反馈后的45秒超时 #99 原 45 秒事件的根因;不声称两者与上述两条夹具失败同因。
    • 第 4 节的 nullptr/UB 判断是静态推断,没有构造运行证据;mode=delayed 只出现在代码路径,本地无样本。
  5. added a commit that references this issue on Oct 30, 2026
  6. JavaZeroo commented on Oct 30, 2026

    @JavaZeroo
    OwnerAuthor

    新的失败字段样本(夹具侧,含 failure_step / state_step 拆分)

    PR #233 的 Windows 回归(job 123897375437)在 shell 用例里再次命中本族,消息已带 #218/#217 引入的拆分字段:

    [TF-CLIPBOARD-OWNER] clipboard owner failed its bounded ready handshake:
    mode=occupied failure_step=OpenClipboard state_step=DestroyWindow-cleanup
    win32_error=5 worker_error=...
    

    判读:

    字段 含义
    failure_step=OpenClipboard 首个失败发生在 worker 内的 OpenClipboard(错误码 5)
    state_step=DestroyWindow-cleanup 消息生成时夹具已推进到销毁窗口的清理阶段

    也就是说:失败发生在 owner 握手的准备阶段,而消息是在清理阶段才被记录的——这正是把两个步骤分开的价值:它们描述的不是同一时刻。

    与既有结论的关系

    • 夹具侧已加有界重试(4 次,50/100/150 ms),仍未覆盖该次;
    • 仍缺的观测:失败瞬间 GetOpenClipboardWindow() 的持有者类别(夹具自身 / 同进程其他窗口 / 其他进程 / 无窗口),这能把三类原因彻底分开。

    边界

    • 单次样本,未复现;
    • 产品读写路径未被触发(失败在夹具准备阶段)。
  7. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    复核:本项列出的第一项接续工作已经完成

    本项正文写:

    源码核对:ClipboardScenarioOwner::record_failure 保存首个错误及 failure_step,但 ready_failure 输出的是持续变化的 step_;catch 清理会将该字段改为 DestroyWindow-cleanup。因此日志可能把清理步骤名与更早保存的错误 5 组合……

    接续时先让 ready 握手错误保留原始 failure_step 和独立清理错误……

    我核对了当前 main 的实现,这两点已经分开记录:

    字段 含义 代码位置
    failure_step 首次失败时的步骤(写入后不再改变) clipboard_scenario_state.hpp:57
    secondary_failure_step 后续(含清理)错误,独立保存 :52
    state_step 当前步骤(会变) :72 单独输出

    ready_failure() 的输出形如:

    … failure_step=<首次失败步骤> state_step=<当前步骤> win32_error=… worker_error=…
    

    即"原始首错"与"当前步骤"在同一行里并列,不再互相覆盖。observation() 也是先发布 error_、再读细节,避免读到半写状态。

    因此

    项 状态
    保留原始 failure_step ✅ 已有
    独立记录清理错误 ✅ 已有(secondary_*)
    原 45 秒事件 仍未复现,因果未知

    本项开头那段源码核对结论已经过期,应据当前代码更新;但本项仍不满足关闭条件(原事件未复现)。

    边界

    • 我只做了源码核对,未运行 hosted 剪贴板用例;
    • 若你认为该段描述仍成立,请指出具体版本,我再核对。
  8. JavaZeroo commented on Nov 1, 2026

    @JavaZeroo
    OwnerAuthor

    [DEBUG-r99] 第二批有界观测(draft PR #300):未复现,本批停止

    身份:分支 debug/r99-clip-stage-log,HEAD 19fcb6e6dcade30e0f8f11d10f50958564fade95,父为原失败 678804ff5201fab4296b133af9457b7120739b68(仅在其上叠加 [DEBUG-r99] 阶段记录 + 首轮 push 启用 TERMFORGE_DEBUG_R99=1)。PR #300 为观测 draft,勿合并。

    CI(首轮 push 的 default 才是目标):

    实测

    • 结论未复现:两轮均 status=passed、exit_code=0、timed_out=false,clipboard-workflow.json 两轮均在(四 case 完整)。原 45 秒 launcher 超时本次未出现。
    • [DEBUG-r99] 记录每轮 r99-debug.jsonl 67 行(≤256),字段只有 tag/event/case_index/stage/elapsed_ms/callbacks/helper_zero_wait/paste_busy/owner_step/owner_released/owner_error/owner_native_error;无 PID/HWND/路径/终端文字/剪贴板内容/凭据。elapsed_ms、callbacks 全程单调不减。
    • 四 case 阶段覆盖:occupied 0–9、oversize 2–9、cancel 2–9、close 2–7(target_gone 路径结束于 stage7)。全程 ~1694ms(第二轮 ~1388ms);这是诊断时长,不是端到端性能/自然退出时刻。
    • 首轮 occupied(原失败 case)顺序实测(ms):product-read-started 304 → marker-during 307 → helper 回收 378(helper_zero_wait=true,paste_busy 仍 true)→ busy 清除 409 → error-feedback 410 → owner release 442(owner_step=Wait-release,released=false)→ owner released 473(owner_step=GetMessageW,released=true)→ owner finish 474(owner_error=0/0)→ marker-after 477 → 显式 retry 511(paste_busy 复真)→ case-complete 631。各阶段间约 30–50ms(≈30ms 定时器),无停顿/无 heartbeat 堆积;若 45 秒事件再发,记录会停在某 stage 的每秒 heartbeat 上,可直接定位。
    • close case(index 3)owner_error=1418/1418(ERROR_CLIPBOARD_NOT_OPEN)是 delayed owner 目标关闭后的预期晚渲染结果(expected_requester_gone),不是回归、不是本项 45 秒事件。
    • 哈希:artifact r1-windows-input id 13076263249、4327097B,ZIP SHA256 efe43d3234af0efe152d3cfb0bd85b3c571d33824ed6a1b7a1742a241061ba4f;两轮记录 SHA256 bbc011f6820b50dc8afeac51abda43b1222adaf9c6e120134012346557cbd890 / 955dd202c8f17bbff111faadff075fb843244265209c9f37223f8d25d4c8dd0e。原件仅本地 D:\Code\tf-r99-art。

    推断

    • default 自研核心 + system ConPTY 的 45 秒事件本批未触发,与首批(PR docs(clipboard): preserve the bounded hosted timeout observation #101)一致;临时文件 I/O 未在本批改变可观察时序到复现程度,但无法据此排除 I/O 对原时序的扰动。
    • 候选 windows 失败来自 678804f 研究谱系/候选自身,与本次诊断提交(仅默认流程 env + 剪贴板场景仪表)无因果关系。

    未知(保留)

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

Metadata

Metadata

Assignees

Labels

ready-for-agent范围明确且真实阻塞已解除,可开始实施research有明确问题与出口的证据调查

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions