Repository navigation
Description
当前接续(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,SHAdbf5618927a80184d5b7e86921adcbf0be0d198ceabef8b0a545e36c956c8306;未据文件存在声称整项或实际呈现通过。 occupied.bin为精确256个B,SHAb0102e3e5f3ced3b4bd1e9d1a08ef35c5fce216b024beea399c4a51b95ece8e7,未出现显式重试载荷;只有这两个文件、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保护,不用增加等待或自动重试掩盖首错;本节记录新样本和诊断缺口,不作为原因修复。
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsTodo
Activity
docs(clipboard): preserve bounded R99 evidence and retire instrumenta…
Merge pull request #193 from JavaZeroo/ci/repeat-shell-coverage
JavaZeroo commentedon Oct 30, 2026
剪贴板
OpenClipboard: 5家族的文本形状盘点(只读源码 +local/repeat*计数)0. 身份与范围
D:\Code\termforge-uia-note,分支feat/qt-reply-wiring,HEAD350c158,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)、0a90489failure_step/state_step分离。1. 产品路径(
clipboard.hpp及其调用面)OpenClipboard: <code>(5=ERROR_ACCESS_DENIED)ClipboardAccess构造Copy failed: OpenClipboard: 5(footer + 标题TermForge — Copy failed: OpenClipboard: 5,shell.cpp:298);粘贴/读取:不出现,UI 固定system clipboard read failed,码只进证据字段win32_errorUnicode text unavailable: 1168system clipboard read failedGetClipboardData: <code>、GlobalLock: <code>(读)、GlobalAlloc: <code>、GlobalLock: <code>(写)、EmptyClipboard: <code>、SetClipboardData: <code>Copy failed:可见;读取:隐藏,只留码clipboard limit exceeds hard bound、copy exceeds clipboard limit、clipboard copy requires an owner window、copy contains embedded NULlength_error在 helper 内映射为 111system 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 failedclipboard_worker.hppshell.cpp:360)Paste failed: <what>shell.cpp:388同步异常兜底要点:读取已异步化到 helper,
OpenClipboard: 5原文不会到达 UI;写仍是同步,所以只有"复制"能显示OpenClipboard: 5原文。2. 夹具路径(
clipboard_scenario_state.hpp)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)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()[TF-CLIPBOARD-OWNER] teardown deadline: step=... win32_error=... worker_error=...,随后_Exit(92)stop()3 s 未回收clipboard case=<occupied|oversize|cancel|close> phase=prepare-owner before-product-paste: <内层>workspace_clipboard_scenario.hpp:67-70OpenClipboard: <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 timeoutwrite_unicode_clipboard、write_oversized_clipboard、require_hosted_clipboard、paste_checkprepare_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: 5Copy failed: OpenClipboard(产品负向契约)prepare-ownerTF-CLIPBOARD-OWNER口径:
local/repeat*下 25,325 个文件(.json/.jsonl/.layout/.txt/.log按 UTF-8、.bin按 UTF-16LE),跳过 5,023 个二进制(绝大多数.bmp,合计约 23.2 GB)。命中数不等于失败事件:copy 证据每 case 固定 7 条(sample.json1 +selection.json4 +selection-interactions.jsonl2),186 个 copy 文件 = 62 case = 31 轮。全部命中里只有 2 个
sample.json属于本家族且非 passed:local/repeat9/shell/run-ivc325fs/clipboard-system-1/sample.jsonui-clipboard-system/test_system_clipboard_product_read_errors_cancel_and_closetimed_out=falseshell probe failed: clipboard case=oversize phase=prepare-owner before-product-paste: OpenClipboard: 5local/repeat13/shell/run-dxct4ssg/copy-system-0/sample.jsonui-copy-system/test_mouse_selection_to_real_system_clipboardtimed_out=falseshell 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 仅夹具准备
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 重试,仍失败才原样抛出。[TF-CLIPBOARD-OWNER] ... ready handshake(repeat13)是夹具自己的 owner 线程;旧版把持续变化的步骤名与首错码拼在一起,23f3399/0a90489后拆成failure_step/state_step。静态观察(新,未运行验证):
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 → 夹具串行化问题;其他进程 → 外部占用超过预算;无打开窗口 → 不是占用而是访问上下文/权限,重试无意义。边界
local/repeat*;未扫描.bmp/.png/.exe/.zip,.bin只按 UTF-16LE 解码,若以 UTF-8 存文本会漏。命中数与失败事件不是一一对应(copy 每 case 7 条)。fd1d6416:50:56、23f33997:58:24),不声称是同一运行。ui-copy-bytes-systemsentinel-write/readback 的根因,也未判断 [R2][回归] 定位 hosted 剪贴板占用反馈后的45秒超时 #99 原 45 秒事件的根因;不声称两者与上述两条夹具失败同因。mode=delayed只出现在代码路径,本地无样本。Merge pull request #226 from JavaZeroo/fix/owner-ready-failure-ub
JavaZeroo commentedon Oct 30, 2026
新的失败字段样本(夹具侧,含 failure_step / state_step 拆分)
PR #233 的 Windows 回归(job 123897375437)在
shell用例里再次命中本族,消息已带 #218/#217 引入的拆分字段:判读:
failure_step=OpenClipboardOpenClipboard(错误码 5)state_step=DestroyWindow-cleanup也就是说:失败发生在 owner 握手的准备阶段,而消息是在清理阶段才被记录的——这正是把两个步骤分开的价值:它们描述的不是同一时刻。
与既有结论的关系
GetOpenClipboardWindow()的持有者类别(夹具自身 / 同进程其他窗口 / 其他进程 / 无窗口),这能把三类原因彻底分开。边界
JavaZeroo commentedon Oct 31, 2026
复核:本项列出的第一项接续工作已经完成
本项正文写:
我核对了当前
main的实现,这两点已经分开记录:failure_stepclipboard_scenario_state.hpp:57secondary_failure_step:52state_step:72单独输出ready_failure()的输出形如:即"原始首错"与"当前步骤"在同一行里并列,不再互相覆盖。
observation()也是先发布error_、再读细节,避免读到半写状态。因此
secondary_*)本项开头那段源码核对结论已经过期,应据当前代码更新;但本项仍不满足关闭条件(原事件未复现)。
边界
JavaZeroo commentedon Nov 1, 2026
[DEBUG-r99] 第二批有界观测(draft PR #300):未复现,本批停止
身份:分支
debug/r99-clip-stage-log,HEAD19fcb6e6dcade30e0f8f11d10f50958564fade95,父为原失败678804ff5201fab4296b133af9457b7120739b68(仅在其上叠加 [DEBUG-r99] 阶段记录 + 首轮 push 启用TERMFORGE_DEBUG_R99=1)。PR #300 为观测 draft,勿合并。CI(首轮 push 的 default 才是目标):
test_system_clipboard_product_read_errors_cancel_and_close均通过。alacritty-headless失败于「Build and test candidate shell on Windows」。这是外部 Alacritty 候选(非 [R2][回归] 定位 hosted 剪贴板占用反馈后的45秒超时 #99 的 default 自研核心),本提交未改候选工作流/候选源码,与 [R2][回归] 定位 hosted 剪贴板占用反馈后的45秒超时 #99 不并入同因。pull_requestrun;gh pr checks 300只回显上述 push 四检查。实测
status=passed、exit_code=0、timed_out=false,clipboard-workflow.json两轮均在(四 case 完整)。原 45 秒 launcher 超时本次未出现。r99-debug.jsonl67 行(≤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全程单调不减。owner_error=1418/1418(ERROR_CLIPBOARD_NOT_OPEN)是 delayed owner 目标关闭后的预期晚渲染结果(expected_requester_gone),不是回归、不是本项 45 秒事件。r1-windows-inputid 13076263249、4327097B,ZIP SHA256efe43d3234af0efe152d3cfb0bd85b3c571d33824ed6a1b7a1742a241061ba4f;两轮记录 SHA256bbc011f6820b50dc8afeac51abda43b1222adaf9c6e120134012346557cbd890/955dd202c8f17bbff111faadff075fb843244265209c9f37223f8d25d4c8dd0e。原件仅本地D:\Code\tf-r99-art。推断
未知(保留)