Skip to content

[R2][回归] 定位 hosted 选择场景首记录前超时 #73

Closed as not planned

Description

@JavaZeroo

固定观察与范围

实验分支源码 af563ba15aa5abf90a09ca55eb9c177ac873ecf0 的 push CI 40313695853 真实失败;同次 checkout 为该 SHA。注意该 Windows regression job 仍以 cmake -S . -B build -DCMAKE_BUILD_TYPE=Release 构建默认自研核心/system,不是显式官方后端验收。

ShellTests.test_selection_autoscroll_with_short_and_tall_workspace 的 client_height=681 子项在 ui-selection 返回2,报原 selection scenario exceeded its bounded deadline。原内部30秒、外层40秒未超时;外层 Job active=0、terminated=0,desktop 删除。原目录只有 sample 与 workspace.layout:没有 selection-base.jsonl、selection-interactions.jsonl 或最终 selection.json,不能把测试方法名当成已经进入 autoscroll 的证据。

本次有界原件审计

  • Windows Server 2025 Datacenter 10.0.26100;runner 2.338.0,image windows-2025-vs2026 / 20261021.278.1。
  • failure artifact 12646521226,4709004B,ZIP SHA-256 b1a22a58edd44278bd16aa0b5bb76d2908f81dded0a11900c6db8109a5c9f2cc,与 GitHub digest 同,下载一次。
  • 原件/布局保存在忽略目录 local/ci-2026-10-26-postmerge;仅提取目标失败、小日志和身份,共318382B,未重跑 UI 或 CI。
  • 样本未逐运行哈希 EXE。同 job text-actions / 两份 workflow 身份一致:shell SHA-256 c167582dc096767eeae73de34b4d4e80924e397fbf59e4f47b7698f67c97d5c8;不补造逐运行或 source-to-binary 证明。
  • 此样本没有失败时 stage/两会话 ready/settled/marker/grid/generation/capture 观测。准确 stage、原生状态、reader EOF、自然退出/强制取消均 unknown。现有源码最早的 record("empty") 位于 stage2,缺文件仅表明没有保留下首个完成记录,不足以从 Job 数量推断状态。

与已知任务的边界

这不是 #66 已闭合的 styled selection-bytes / reverse 双会话tick门槛;入口、动作与缺失阶段不同。也不是 #61 save/restore oracle、#63 workspace stage52 或 #40/#44/#57 的已证明同因。保留旧 #43 短客户区锚点修正,不凭相同“681”判定已覆盖或重新打开它。PR #50 同树另一批绿不能覆盖本次红。

下一批交付与验收

  • 固定原源码/布局/原期限及真实失败,先加有界、白名单的最后stage、会话ready/settled、必要marker布尔、实际网格/resize generation及capture观测;原异常与Job/desktop结果保留,原运输/文字只留私有。
  • 限定一批样本和停止条件,先区分首次输出前的stage0/1/2等待与真正autoscroll阶段;无复现就保留未知,不能无限刷绿。
  • 可证伪首假设:某一会话ready/settled或首批marker等待没有推进,尚未产生第一个record。用同次阶段/布尔证据证伪,不先增加sleep或扩大30/40秒。
  • 有同类red后再做单变量修复,保留负例;原681与860、选区文字/颜色/anchor、真实鼠标/滚动、每tick一行/释放后停止、焦点/capture、完整重绘、字节隔离及Job/desktop断言均不降。
  • 最终默认及声明候选配置各自完成原完整方法与回归,真实CF仍单列;同步 [R2][回归] 收敛 Windows 可靠性与历史未闭合失败 #38/[R2-12][交付] 构建并验收 Windows R2 基础开发包 #35 与 FEATURES/EVIDENCE。

父项 #38;本项阻塞 #38。ready,无未解除前置;实际呈现、性能及完整R2不由本次审计推断。

PR93 的同类首记录缺失样本(独立入口)

PR93 Build 首次 Windows 作业,HEAD ba9e7bd10596347c20dbbbc4d2c5e7cca600a0b3、实际 checkout 5cd12da8c4cbded082e7686a2b8db91c7b9e9f2f,默认自研核心/system;Windows Server2025 10.0.26100。完整CTest51/52、294.89s,仅shell失败;shell40项中38通过、1error、1skip,102.653s。

test_mouse_selection_to_real_system_clipboard 的 ui-copy-system 第一轮完成原12份基础快照和28份交互、真实复制/占用反馈/释放重试;原离线validator再次通过。第二轮返回2、原30秒内层deadline,40秒外层未超时;原目录仅sample和workspace.layout,没有首条selection-base、interactions或最终selection.json。Job active0/total9/terminated0,desktopgone;布局保存为1008×681。失败时准确stage、两会话ready/settled/marker及原生输入仍未知。布局文件不是失败瞬间几何观测,Job总数也不能推断阶段。

artifact12698350461,4257181B,ZIP SHA256 d0a26fd0b79d548b11ada117bac238d18b8113c9041e91151b7b090ae8ddcdd9 与GitHub digest一致,原ZIP、目标文件、完整job日志和审计保存在忽略目录local/ci-pr93-attempt1。逐运行sample没有EXE哈希;同job text-actions身份记录shell SHA256 f5f9974beaa68546bac8928bc7f39f9bee333a80df58fe68c34fda7d43e8f9e9,不补造逐运行身份。

该入口与原681 ui-selection共用初始等待与错误条件,因此纳入本项调查,但不认定两者同因。此次不是OpenClipboard异常,不归为#85已观察调用;也不是#63工作区stage52。保留两个入口各自的原负载/期限/断言,下一批增加共同初始边界的安全观察以区分原因。

为核对仅改文档/证据的PR93集成门槛,预先限定一次同HEAD失败job重跑;原源码、输入、期限和断言不变,若再红停止重试。即使通过也只是另一份未复现结果,本项保持开放,不将重跑当作原因修复。

限定复查已完成:同checkout Windows作业12192242410252/52、269.94s。artifact12699216921、4326500B、SHA256 d0150af666d84b2fb26648fd978b18d2f85de657a50c72644db32785bc0ca2c7;两轮各12基础阶段/28交互、真实CF/占用恢复及原离线validator通过,exit0、非超时、Job active0/terminated0、desktopgone。同job shell身份284756a7ef4638d8a961409648f298679f181eec32ed588f16d9538da7a79214,与首次重建哈希分列。没有继续重跑;本项原原因仍未知、保持开放,两个初始等待入口继续按上述有界观测计划定位。

Activity

  1. added
    bugSomething isn't working
    ready-for-agent范围明确且真实阻塞已解除,可开始实施
    compatibility平台、协议或行为兼容问题
    on Oct 26, 2026
  2. changed the title [-][R2][回归] 定位 hosted 681 高度选择场景首记录前超时[/-] [+][R2][回归] 定位 hosted 选择场景首记录前超时[/+] on Oct 26, 2026
  3. JavaZeroo commented on Oct 28, 2026

    @JavaZeroo
    OwnerAuthor

    新增独立样本:PR154 push/default run40769220998/job123101546682,HEAD/checkout58fee280…,完整56/59、332.37s。test_selection_autoscroll_with_short_and_tall_workspace(client_height=860) 返回2、内层 selection scenario exceeded its bounded deadline,非外层timeout;681子项有完整记录,此860目录仅sample/workspace.layout,无首条selection-base/interactions/final。自有Job0/9/0、desktop_gone=true,自然child退出/失败时准确stage仍unknown。artifact12851572745(4722483B)SHAea38ca1099f6f52420d77bee16796d04e986eab02c8912a692e013bf4d12282a;LastTest162003B SHA6ec38d3f098ade5f683f7c1fa0368843c642eb068aabb0cfa76ff8e0e7fe4a22。原件私有保留,未重跑。该入口同类早期无记录现象,不据此认定与旧681/Copy同因;同run的Node和动作几何失选分别#144/#156。

  4. JavaZeroo commented on Oct 29, 2026

    @JavaZeroo
    OwnerAuthor

    新增独立未修复负例:PR165 push 默认 Windows job123188586384,source/checkout 0deb19bf4da73a1cc0e82f398925c540da7edb55,默认 C++/system 配置,CTest60/61、322.08s;shell39项中1error、1skip、108.717s。

    test_mouse_selection_to_real_system_clipboard 第二轮 ui-copy-system 返回2,原内部selection deadline;外层未超时,Job0/9/0、desktopgone。失败目录仅 sample537B/SHA256 3ea453fd3305450af73052bd372583a28d8cd4a436a149bce12e97664f8ffef0 与workspace.layout395B,没有首条 selection-base/interactions/最终selection。准确stage与等待原因仍unknown,不凭相同错误认定与旧样本同因。

    artifact12863976333,4726763B/SHA256 288e37b03d151e9e29629671c0fb247dae102419bb23c3a3d84ea56566b4c9f1,一次下载且与GitHub digest吻合,私有 local/ci-pr165-push-0 保留原ZIP、LastTest与准确路径的两成员。目录中的 shell-failure-sample.json 是初次筛选循环留下的另一条预期注入失败,不得当作本失败原件;本次正确原件为 copy-system-1-sample.json。

    同HEAD PR默认检查、Qt6项检查成功是独立样本,不覆盖此负例;没有重跑失败job。本项继续按现有有界初始stage观测方案处理。

  5. JavaZeroo commented on Oct 29, 2026

    @JavaZeroo
    OwnerAuthor

    用扩展后的复现作业(text_actions|selection_context|shell,run 40918682003)再次命中"首记录前超时"形状,这次保留了完整输出与消费轨迹。

    失败样本

    • 失败用例:test_selection_autoscroll_with_short_and_tall_workspace → shell probe failed: selection scenario exceeded its bounded deadline;
    • 对应产物目录:shell/run-9u41hr4s/selection-height-681/(没有 selection*.jsonl 交互记录,只有 535 B 的 sample.json,符合"首记录前超时");
    • 对比:同轮的 selection-height-860 产物齐全(sample 2839 B、interactions 33 KB、selection.json 42 KB)。

    消费轨迹(output-trace.jsonl)

    terminal1 383437  offset0   bytes153  cols82 rows5
    terminal1 383437  offset153 bytes76   cols82 rows5
    terminal1 383453  offset229 bytes56   cols82 rows5
    terminal2 383500  offset0   bytes95   cols54 rows12
    terminal2 383562  offset262 bytes141  cols54 rows12
    terminal1 383562  offset285 bytes348  cols82 rows5
    terminal1 383578  offset633 bytes4    cols82 rows5
    terminal2 413437  offset507 bytes16   cols54 rows12   <-- 30 秒空档后的最后一小块
    terminal1 413437  offset637 bytes16   cols82 rows5
    

    即:约 30 秒内两个终端都没有消费任何输出,最后各收到 16 字节,随后到期限。

    输出内容(output.bin,1176 B)

    终端正常起了 cmd、跑了 chcp 65001/cls,出现 TF> 提示符,执行了 echo ALPHA tail&echo BETA 中文 é&echo TF_SELECT_READY 并打印了 TF_SELECT_READY;随后坏在下一批输入:

    ESC[?25l ESC[2;1H "TF>echo OTHER  text&echo TF_SELECT_OTHE" ...(截断)
    

    即第二条命令只打出了前缀、没有完成,之后 30 秒无输出。

    含义

    这不是"终端没起来"或"选择逻辑超时",而是输入注入后子进程没有再产生输出:

    • 要么按键/输入没有被子进程收到(输入队列或 ConPTY 写入端阻塞);
    • 要么子进程收到但输出没被消费(读取端阻塞)。

    下一步(有界):在输入侧也加同样的轨迹(每次 WriteFile/输入块的时间、字节数、结果),与输出轨迹放在同一条时间线上,就能判定卡在写入端还是读取端。

    本条只增加证据,不改变测试期限或产品行为。

  6. added 3 commits that reference this issue on Oct 29, 2026
  7. 8 remaining items

  8. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    前提更正:那条失败转储不在 ui-selection 路径上;「输入是否到达队列」现有记录已能给出一半答案

    1. 上一轮评论(2026-10-30)的两处引用需要更正

    上一轮说法 实际(我逐行核对 origin/main 8c7b1ed)
    选择场景以 --mode ui-selection 运行,见 run.py:531 run.py:531 是 record["unicode_output"] = validate_unicode_output(out),与选择场景无关;ui-* 由 execute() 用 shell_test_launcher.exe <desktop> <mode> <frame.bmp> 起动(run.py:470-471)
    ShellWindow 失败转储覆盖选择场景(shell.cpp:1438 起,mode_ 非空即打印) 转储在 ShellWindow::collect() 内(origin/main:1420-1453,input_high_water 在 :1448),而 ui-selection 在 origin/main:1493-1495 被派发给 Workspace:Workspace window(image,mode); return window.run();。Workspace 的失败只保留文本(workspace.hpp:646 failure_=error.what(); discard_and_close() → :728 require(failure_.empty(),…));tab 侧 collect_child 确实会调 child->collect()(workspace_interactions.hpp:96),但转储条件是该 tab 自己的 failure_ 非空,选择场景的 deadline 是 workspace 级异常,不会设置它

    产物核对:我下载并 grep 了三份 failure artifact(run 41005229351、41187698074、41187449435,artifact 名 failure-windows-2025),没有任何文件出现 input_high_water=;10-30 那份 shells-0/sample.json 的 stderr 只有一行 workspace shells scenario timeout at stage 5。也就是说,该转储至今没有在产物里出现过(限定在我核对的这三份)。

    2. 「输入是否到达队列」现在能回答到什么程度

    层 现有读数 已知两个本机样本(local/repeat10 selection-1、local/repeat12 selection-height-681) 结论
    入队 termforge-input-trace-v1 的 enqueue 记录带真实 accepted(queues.hpp:141) 各 200 条(enqueue 100 + write 100),105 B/相,accepted 全 true,拒绝 0 输入确实进了队列
    写出 write 记录在 Session::send 返回后才落盘,accepted 是常量 true(queues.hpp:108) 与 enqueue 同毫秒成对 已写入 ConPTY 输入管道,但不等于 conhost 把最后一个 CR 交给 cmd
    队列计数 input_.high_water / rejected 只在 ShellWindow 转储里输出 无 ui-selection 无此读数

    → 所以本条真正缺的不是「到达队列」,而是「进队列之后」。上一轮想用 input_high_water 回答的也正是「队列侧有没有拒绝」,而这一点现有 input-trace 已经给出否定(0 拒绝)。旁证:10-30 的 ui-shells 样本同目录 1518 条输入记录同样 0 拒绝。

    3. 关闭判据与下一步

    原文(本项正文):

    → 当前不可关闭:机制仍未单变量证实,且没有任何一次带阶段/布尔读数的 red。

    单一观测(一次即可):把同一行转储放到 Workspace 的失败路径,字段取 stage_、两会话 settled() 与两个 marker 的 contains_line 布尔、每个 tab 的 InputQueue::snapshot()(queues.hpp:62-82 已有 high_water/rejected)、session.output_bytes/read_error,再加现有 screen dump。下一次 ui-selection 命中就能同时给出「stage」与「队列侧」读数,取代现在靠 output.bin 反推 stage 2 的做法。

    边界

    • 只读:origin/main 8c7b1ed 的 shell.cpp、workspace.hpp、workspace_interactions.hpp、queues.hpp、run.py;三份 CI artifact(下载到本机 TEMP,未写入仓库);本树 local/repeat10 与 local/repeat12 两份旧样本的 output-trace。
    • 「转储从未出现」只针对我下载核对的三份 artifact,不代表全部历史产物;未重跑、未 dispatch、未改代码/断言/期限。
    • 105 B 的口径:enqueue 与 write 各 100 条记录,按记录求和为 210 B(两相各 105 B)。
    • 本评论只更正证据归属,不改变本项开放状态;未把本项与 [R2][回归] 定位 hosted 四 shell 退出 stage6 超时 #80 的 stage5 oracle 问题归为同因。
  9. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    更正:我 10-30 那条「转储已覆盖选择场景」的结论是错的

    经代码核对与三份 artifact 复核,先前的判断不成立:

    我先前的说法 实际情况
    选择场景失败会打印 stage=/input_high_water= 等转储 该转储位于 ShellWindow::collect()(origin/main:1420-1453),而 ui-selection 被派发到 Workspace(shell.hpp:1493-1495),其失败路径只保留文本(workspace.hpp:646 → :728)
    run.py:531 是选择场景入口 那是 validate_unicode_output,与选择场景无关

    证据:三份失败 artifact(41005229351 / 41187698074 / 41187449435)grep 无任何 input_high_water=;shells-0 的 stderr 只有一行。

    已被证实与仍未知

    问题 结论
    输入是否到达队列 已证实到达:两个本机样本各 200 条记录、accepted 全 true、0 拒绝
    到达之后卡在哪 仍未知(conhost/cmd 侧)

    为此做的改动

    已在 Workspace 的失败路径补一行标识:

    workspace-failure mode=<test_mode> what=<message>
    

    这样选择/动作/shells 三类 Workspace 场景失败时,产物里至少能读到是哪个场景、什么错误(此前只剩 run.py 抛出的单行 ValueError)。

    边界

    • 该行只加场景身份与错误文本,不含 InputQueue::snapshot()、output_bytes/read_error 与整屏;这些需要下一片(涉及 Workspace 到 Shell 的访问器);
    • 不改变任何期限与判定。
  10. added 3 commits that reference this issue on Oct 31, 2026
  11. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    命中:新的 Workspace 转储给出了决定性读数

    run 41190293290(job 124505531143,shell 用例 98.15 s)首次带上了本轮新增的 Workspace 转储:

    workspace-failure mode=ui-selection what=selection scenario exceeded its bounded deadline
      tab bottom:0 input_high_water=3  input_rejected=0 output_bytes=637 read_error=0 consumed=637 stage=0 closing=false child_signaled=false exit_code=259
      tab main:0   input_high_water=1  input_rejected=0 output_bytes=505 read_error=0 consumed=505 stage=0 closing=false child_signaled=false exit_code=259
    

    判读

    读数 含义
    input_rejected=0(两个会话) 输入没有任何被拒绝
    input_high_water 只有 3 / 1 字节 队列基本是空的,不是"积压写不进去"
    output_bytes == consumed(637/637、505/505) 读到的字节已全部消费,读取侧没有堆积
    read_error=0 读取无错误
    child_signaled=false、exit_code=259 两个子进程在期限瞬间仍然活着(259 = STILL_ACTIVE)

    合起来:输入都进去了、输出都被消费完了、子进程还活着但不再产出 —— 未知被收窄到"子进程没有再输出"这一侧,而不是队列、读取或回收。

    一处需要记录的局限

    stage=0:选择场景由 Workspace 驱动,ShellWindow 自己的 stage_ 不参与,因此这个字段在该模式下恒为 0,不能用来判断场景进度。真正的阶段只在 Workspace 的场景状态里,尚未导出。

    与既有结论的一致性

    这与 #36 的结论同型(写入成功 → 子进程随后停止产出),说明两个问题可能共享同一类"宿主侧输出停滞",但本项仍不据此合并根因。

    下一步(单一观测)

    把 Workspace 场景的 stage_(选择/动作脚本的阶段变量)导出到同一条转储里,即可判定是"卡在等某个标记"还是"卡在发下一条命令"。

  12. added a commit that references this issue on Oct 31, 2026
  13. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    第三个不同模式的样本,形态一致

    run 41194082923,shell 用例 100.86 s:

    workspace-failure mode=ui-copy-system what=selection scenario exceeded its bounded deadline
      tab bottom:0 input_high_water=26 input_rejected=0 output_bytes=688 read_error=0 consumed=688 stage=0 closing=false child_signaled=false exit_code=259
      tab main:0   input_high_water=2  input_rejected=0 output_bytes=577 read_error=0 consumed=577 stage=0 closing=false child_signaled=false exit_code=259
    

    与前面两个样本的对比

    样本 模式 input_high_water output vs consumed 子进程
    10-31 A ui-selection 3 / 1 637/637、505/505 存活(259)
    10-31 B ui-actions 1 / 1 4267/4267、4971/4971 存活(259)
    本样本 ui-copy-system 26 / 2 688/688、577/577 存活(259)

    三个不同模式、不同字节量的样本,形状完全一致:输入无拒绝、输出读完即消费完、子进程仍存活。

    这意味着什么

    边界

    • 三份样本都不含 selection-discard.jsonl(需 TERMFORGE_SELECTION_DIAG);
    • stage=0 仍属 Workspace 场景的已知局限;
    • 不据此改变修法方向,仍需要你选定其一。
  14. added 3 commits that reference this issue on Oct 31, 2026
  15. JavaZeroo commented on Nov 1, 2026

    @JavaZeroo
    OwnerAuthor

    按「不死磕」原则关闭:hosted 选择场景首记录前超时

    关闭理由

    用户明确「可以接受不完美、不需要一直死磕一个问题」。本项属于批次内不可复现、诊断已就位的一类,因此按此原则关闭。

    本项已有的证据

    三个不同模式的样本(ui-selection、ui-actions、ui-copy-system)形状一致:input_rejected=0、output_bytes == consumed、子进程存活(259)。另统计 80 条丢弃记录:40 条 row-text-changed 中0 条为部分重绘,40 条 anchor-missing-or-shrunk 的字节与列数均为 0。

    已就位的诊断(再次命中时可立即判读)

    观测 位置
    场景身份与场景阶段 失败行 workspace-failure mode=… stage=…
    每标签页计数器 失败行下的 tab <group>:<index> …
    丢弃原因与差异文本 selection-discard.jsonl 的 reason/saved_text/current_text

    关闭时的真实状态

    本项不是根因修复。原始失败记录仍保留,未被新批次覆盖。

    重开条件

    若同类失败再次出现,凭上述诊断字段可直接判读,恢复本项即可,无需重做本轮探索。

  16. removed
    ready-for-agent范围明确且真实阻塞已解除,可开始实施
    on Nov 1, 2026
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

    bugSomething isn't workingcompatibility平台、协议或行为兼容问题

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions