Skip to content

[R2][回归] 定位 hosted 四 shell 退出 stage6 超时 #80

Open

Description

@JavaZeroo

当前接续(2026-11-01)

最新有界批次本机7/7、当前源码hosted69/69通过;原hosted stage6/30秒事件未复现。stage5 WSL观察窗口已有修正与证据,不能替代stage6旧事件的同因证明。

后续调查须针对原事件谱系/明确假设,保留readiness、传输、退出与Job证据,不再反复跑当前绿色版本。本项继续开放,归#38汇总;下方保留原合同和证据。


真实触发与固定证据

PR #79 的 Windows CI,HEAD c820691(main163d8b8加#72限定oracle修正),实际合并checkout 9b62087;默认自研核心/system配置。完整CTest45/46、294.98s,shell唯一错误是 test_local_shell_launch_working_directory_and_cleanup 的第一轮 ui-shells stage6,原30秒耗尽,外层40秒未超时。#72的原两轮保存/普通恢复/钳制恢复全部通过,不能把本失败算作#72重现。

artifact12669796699,4710638B,SHA256 caa86b6a6d376977f28fa6e1301518ac56cfaa835c08968777a5ed0f46ae1574 与GitHub一致;下载一次,只提取26个相关文件、2893470B。本地原件 local/r79-ci-failure,包含sample、progress、layout、shells、固定测试帧及LastTest日志。

已观察与未知

  • cmd、Windows PowerShell、pwsh、WSL-Ubuntu均已核对工作目录;源码stage5检查四者真实尺寸标记并向当前WSL发送exit,随后等待collected=1/session_count=3。
  • 30秒失败帧上WSL已有TF_SIZE_54x12及TF>,没有可见exit回显;这不能单独证明输入未发送或丢失。底部pwsh也已返回TF>。
  • sample return2、Job active0/total34/terminated0、desktopgone;progress中四会话的exit91发生于失败清理,不能当作自然退出成功或自然退出故障原因。
  • 当前只有到stage6的观测,缺WM_CHAR/队列/实际WriteFile、WSL接收、native size helper退出与shell返回的时序及自然退出端点。shells.json的normal_exit=true在stage5提前写入,不能覆盖最终失败。
  • 与#44的controller graceful、#73的选择首记录缺失没有同因证据;不得合并根因或重跑取绿。

有界交付与验收

  • 固定原输入/源码/后端/环境与原失败,建立同症状红例。先区分UI/队列未发送、Windows子进程→WSL转换时输入丢失、WSL已收exit但生命周期未回收三个假设。
  • 使用有上限的实际字节与阶段观测或事件握手;需要控制调度时采用明确夹具协议,不加固定sleep、扩大30/40秒或跳过WSL。
  • 同一原触发的修前/修后及必要负例;真实目录/子尺寸、四shell顺次正常退出、失败清理与Job/desktop分别留证。
  • 原两轮完整四shell方法和声明配置完整回归通过;更新[R2][回归] 收敛 Windows 可靠性与历史未闭合失败 #38/#35和FEATURES/EVIDENCE,不借另一次CI绿覆盖原原因。

父项#38,本项独立阻塞其可靠性出口;ready,无需等待父项或#72结项。限定修正已随 PR79 合入 main;原 hosted 事件因果仍待定位。

当前因果实验

原源码 c820691 的本机 Win11/system 四 shell 原场景有界运行6次,全部通过;按上限停止,不用于解释原 hosted 失败。

受控改变仅使 WSL 启动的 native size helper 在输出原 TF_SIZE 标记后,PeekConsoleInputW 观察到完整 exit\r 才退出,且不消费该输入。一次运行实际复现 stage6/30s 超时,helper 记录字节657869740d;WSL随后显示新TF>但未退出。Job active0/total20/terminated0、desktopgone。证明尺寸输出不是 shell 输入就绪端点;此诊断改变了调度,原hosted样本没有该边界记录,尚不能据此证明原样本一定同因。原件与源码/二进制/补丁身份保存在local/r80-held-child。

已将该边界变成实际ui-shells事件握手回归:WSL native helper在尺寸输出后等待宿主release;在四个真实尺寸标记齐全时,实际退出条件必须仍阻止下一命令,随后释放并验四shell顺次退出。保留旧条件的回归在4.795s明确失败:size output was mistaken for shell input readiness,local/r80-red保留源码补丁、原始样本及二进制。最终新条件只限WSL:必须观察同次尺寸输出之后的独立新提示符;原30/40s不变,normal_exit证据移到四会话实际回收后写入。

限定修正已验证,原事件仍开放

实现2b85fef48149f022b50d9d8878f62539e02c92ba:最终事件握手与原两轮共3场景通过(两方法10.872s),四会话顺次stage6/7/8/9、exit0、Job0/desktopgone。中间全shell提示符方案的cmd重绘stage5失败保留,最终未放宽共享oracle,仅约束已复现的WSL交接。

同源码默认/system完整CTest46/46,283.89s;shell39方法81.664s、3skip,全套12内部skip(候选依赖/真实应用依赖、hosted CF、opt-in参考注入、私有窗口站OpenClipboard拒绝)完整分列。原held红、旧gate红及中间stage5红都有独立源码/二进制/原件哈希;Standards/Spec代码审查无实现发现。文档与公开白名单记录已整合;PR82 合入 PR79 后,PR79 已以 af63a27 合入 main。Build 40374618725 与 Candidate 40374618675 均通过;Windows 默认/system 46/46、268.68s,实际 checkout539557997b6eca198e46065443faff2c8d8147dd。

原hosted stage6是否同因仍未知;本项保持开放,不用限定修正或新CI成功替换旧失败的因果证据。#81另追踪PR76环境准备超时,产品测试未运行。

Activity

  1. added
    bugSomething isn't working
    ready-for-agent范围明确且真实阻塞已解除,可开始实施
    compatibility平台、协议或行为兼容问题
    on Oct 26, 2026
  2. added 2 commits that reference this issue on Oct 26, 2026
  3. JavaZeroo commented on Oct 28, 2026

    @JavaZeroo
    OwnerAuthor

    新增独立相关样本(不认定与原stage6同因):纯文档PR142 headcafd632016d9daa48e7bc13dadde7013e2ff11b4的默认PR工作流40742782507/Windows123008512465,attempt1,CTest53/54、282.45s;同一四shell方法首轮ui-shells明确workspace shells scenario timeout at stage 5,原有源未改。当前只有stage5超时堆栈,尚未检查具体shell/native helper/提示符阶段,不据此称WSL或输入丢失。failure artifact12841470214 SHAf6a61c08024417cb6700365eefffb9382517026b2286388b0e14c3d74b2fd229;LastTest146975B SHAa524cf936c0336034a071334d4c4fdb297b17f3066647ae8faa7a8b1439cd603,本地原件保全。该head天然push默认成功,不能覆盖本次PR失败;未重跑。与原stage6及中间本机stage5调度红分列,准确因果未知。

  4. JavaZeroo commented on Oct 28, 2026

    @JavaZeroo
    OwnerAuthor

    第二个stage5独立样本:PR140 headb3ae687fc2b9a60532a8c5edaa0db43a80d13d45 push/default40744486195/Windows123014523153,attempt1,CTest53/54、283.78s。本次第二轮shells-1失败(shells-0与held-size-helper通过),原30秒stage5/外40秒未超时,exit2、Job0/total34/terminated0、desktopgone。四者cwd-verified都已记录;失败清理的exit91不当自然退出。失败帧可见WSL的TF_SIZE_54x12及新TF>、pwsh TF_SIZE_82x5与TF>,隐藏cmd/PS5.1条件以及是哪一个size/settled/transport gate未满足仍未知;不以可见两会话推断四者通过。与PR142第一轮stage5、原stage6各自分列,不预先归同因。

    artifact12841541325 SHA7a2a1fc74b706eb208dadfaf0f8691cb71f51e343470736723195c1eaed389d0;LastTest145516B SHA42a8dbf6b9de77eb8ad9128d4171b05ce57fe7d2e22412b68419a501d059d308;均本地保全。原PR140运行自然成功不覆盖本push失败,无同HEAD重试。

  5. JavaZeroo commented on Oct 29, 2026

    @JavaZeroo
    OwnerAuthor

    新样本(PR #202,只新增一个只读分析脚本,不改产品/测试):

    • run 40942366808、job 123688775148;
    • shell 95.55s 失败:test_local_shell_launch_working_directory_and_cleanup → workspace shells scenario timeout at stage 5;

    同一 job 里还出现了一次准备阶段的瞬态失败:

    {"schema":"termforge-hosted-shell-preparation-v1","status":"failed","failure_code":"preparation_guard"}
    {"schema":"termforge-hosted-shell-preparation-v1","status":"passed","failure_code":"none"}

    即准备步骤失败一次后重试通过(该步骤自带一次重试),与本项 stage5/6 的退出超时同属托管环境低频形状。保留红例、不重跑取绿。

  6. JavaZeroo commented on Oct 29, 2026

    @JavaZeroo
    OwnerAuthor

    新样本:四个 shell 都已启动并验证 cwd,卡在 stage 5 退出/确认

    run 40966552246(5 次重复版)的 shell 测试失败:

    shells-0:workspace shells scenario timeout at stage 5,exit_code 2,Job 回收后 active 0/total 34,desktop_gone=true。

    shells-progress.jsonl 的完整阶段

    事件 role stage exit_code tail_bytes
    started / cwd-verified cmd 0→1 — 0
    started / cwd-verified powershell 1→2 — 0
    started / cwd-verified pwsh 2→3 — 0
    started / cwd-verified wsl 3→4 — 0
    exited wsl 5 91 201
    exited pwsh 5 91 248
    exited cmd 5 91 266
    exited powershell 5 91 —

    判读

    与既有记录的关系

    本项此前记录的 stage6 失败(PR79)与本次 stage5 相邻;本次提供了逐 role 的阶段与 tail 字节,可直接对照"退出顺序/确认条件"。

    下一步(仍属本项):在同合同下把 stage 5 的"等待条件"(四个 session 关闭计数、Job 成员归零、desktop 释放)分别记录,以判断是哪个条件未满足。

  7. added a commit that references this issue on Oct 29, 2026
  8. 5 remaining items

  9. added a commit that references this issue on Oct 30, 2026
  10. JavaZeroo commented on Oct 30, 2026

    @JavaZeroo
    OwnerAuthor

    又一次 stage 5 超时(PR #234 的 Windows 回归)

    job 123898511789:workspace shells scenario timeout at stage 5。

    与既有结论一致:stage 5 等待四个会话的尺寸就绪(settled() + TF_SIZE_<cols>x<rows>,WSL 还要求 transport 完成),超时分支会写出 shells-size-readiness.jsonl 与 WSL 的 shells-transport-probe.jsonl。

    本次未下载 artifact 复核那两份诊断文件,因此不追加新判据;仅记录该形状在 IL/DL 变更(与本路径无关)的回归里再次出现。

    边界

  11. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    stage-5 的卡点已由产物直接定位:WSL 尺寸标记没有独立字节记录,不是输入丢失也不是回收挂起

    1. 本次核对的原件(我自己下载并逐字节读过)

    • run 41005229351 / job 123898511789(2026-10-30T04:51:54Z→04:59:08Z,head_sha bccf7a1),artifact failure-windows-2025(12955492292,6555298 B),下载后复核。
    • 失败目录 test-artifacts/shell/run-x8hs3wwb/shells-0/:sample.json 526 B、shells-progress.jsonl 3036 B、shells-size-readiness.jsonl 751 B、shells-transport-probe.jsonl 169 B、output.bin 2365 B、output-trace.jsonl 215950 B。
    • sample.json:mode=ui-shells、exit_code=2、stderr="workspace shells scenario timeout at stage 5"、job_after 0/34/0、desktop_gone=true。

    2. 逐会话事实(readiness 原文)

    role grid settled marker_present transport_completed tail_bytes
    cmd 82x5 true true true* 250
    pwsh 82x5 true true true* 251
    powershell 54x12 true true true* 233
    wsl 54x12 true true false 185

    * 非 WSL 的 transport 列是代码短路常量:workspace_shells_scenario.hpp:23-24 「kind != L"wsl" || transport_output_completed(...)」。所以该列只有 wsl 一行有信息量,不能用三行 true 推断「三个会话的 transport 都过了」。

    同目录的 transport probe(原文):
    {"role":"wsl","marker":"TF_SIZE_54x12","output_seen":false,"prompt_seen":false,"malformed":false,"last_line":"TF> "}

    即:标记在屏幕上(marker_present=true,由 contains_line 在渲染后网格上判),但字节级 oracle 从未把任何一条「记录」判等为 TF_SIZE_54x12(output_seen=false);prompt_seen 因为以 output_seen 为前置,必然同为 false。

    3. 为什么 output_seen=false(可复算的字节级重建)

    • output-trace.jsonl 的 26 条 termforge-output-trace-v1 记录 bytes 之和 等于 output.bin 的 2365 B,因此可按记录顺序把四会话语流逐 chunk 切开:t1 608 / t2 660 / t3 624 / t4 473 B;t4 含 /mnt/d/... → WSL。
    • begin_output_observation() 会先清空缓冲(shell.cpp:1360),所以 readiness 的 tail_bytes 就是该会话观测窗口的长度。WSL(t4)最后 185 B 窗口原文:
    mnt/d/a/termforge/.../shell_size_client.exe"<ESC>[10;1HTF_SIZE_54x12<CR><LF>
    TF> <ESC>]0;D:\a\...<ESC>[?25h<ESC>[?9001l<ESC>[?1004l
    
    • 我按 transport_completion.hpp:19-97 逐字节复算这 185 B:得到 output_seen=false, prompt_seen=false, last_line="TF> ",与产物 probe 逐字段一致。同一复算对 82x5 两个会话窗口给出 output_seen=true(它们的标记独占一条 CRLF 终结记录);54x12 的 powershell 复算同样 false,只是它不受该门控。
    • 机制:进入窗口时记录里已经累积了命令回显残片(...shell_size_client.exe"),随后 ESC[10;1H 是 CUP;transport_completion.hpp:62-66 明确「不跨 CUP 拼接回显」,于是该记录被标为非 literal,紧接的 TF_SIZE_54x12 追加到同一记录也不能置位 → 永远 false。把窗口起点挪到 CUP 之后(或标记前有 LF)即可通过,这正是 82x5 两个会话的形状。

    4. 对本项三个假设的处置

    假设(正文原话) 本样本
    「UI/队列未发送」 否。同目录 input-trace 1518 条记录(enqueue/write 成对,t1 176、t2 185、t3 184、t4 214 B),accepted 全 true,拒绝 0
    「Windows 子进程→WSL 转换时输入丢失」 本样本不成立;原 hosted 样本没有这两份诊断,仍未证伪
    「WSL 已收 exit 但生命周期未回收」 本样本不成立:超时发生在等待尺寸就绪;progress 的四条 exited(exit91、stage=5)属失败清理,不是自然退出

    原 PR79 的 stage6 事件仍未知;本样本只解释 stage5 等待条件,不能替代原因果。

    5. 关闭判据与下一步

    原文判据:「原两轮完整四shell方法和声明配置完整回归通过;更新#38/#35和FEATURES/EVIDENCE,不借另一次CI绿覆盖原原因。」
    → 当前不可关闭:stage5 的等待条件机制已定位,但还没有「改窗口起点 / 改 oracle 契约」的单变量修前修后对照,也没有原 stage6 的因果。
    单一下一步观测(不改 30/40 秒、不扩样):同一次 ui-shells 超时,把 WSL 的 185 B 观测窗口原文(现在只落 tail_bytes)以及 marker 所在记录的累积文本(probe 现在只落 last_line)写进产物;这样就可以在产物内直接复算 transport_output_completed,把「窗口起点落在回显中间」从重建变成记录,并据此二选一:改窗口起点(不动契约),或改 oracle 契约(transport_completion.hpp:6-17 明写其语义,放宽需用户确认)。

    边界

    • 只读:上述 artifact 与本机下载目录、workspace_shells_scenario.hpp、local_shell_diagnostics.hpp、transport_completion.hpp、shell.cpp、queues.hpp 的当前 main 版本(origin/main 8c7b1ed)。未改代码/断言/期限,未重跑、未 dispatch。
    • 第 3 节的窗口归属与 oracle 复算是重建:依据是同目录 output.bin 与 output-trace.jsonl 的 chunk 切分(求和相等已校验)以及本地端口化的 oracle;产物本身只记录 readiness/probe 的布尔与 last_line。为免越界,未把重建当作产物读数陈述。
    • 只核对了这一份 stage5 样本;未验证「窗口起点为何落在回显中间」的调度原因(check_size() 与输入回显的先后),属未知。
    • 未把本样本与原 PR79 stage6 或 [R2][Regression] controller B graceful 的 cmd 正常退出观测缺口 #44/[R2][回归] 定位 hosted 选择场景首记录前超时 #73 归为同因。
  12. added a commit that references this issue on Oct 31, 2026
  13. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    又一次 stage 5 命中,这次带上了每标签页计数器

    run 41190299715(job 124505550311):

    workspace-failure mode=ui-shells what=workspace shells scenario timeout at stage 5
      tab bottom:0 input_high_water=2  input_rejected=0 output_bytes=592 read_error=0 consumed=592 stage=0 closing=false child_signaled=false exit_code=259
      tab bottom:1 input_high_water=1  input_rejected=0 output_bytes=634 read_error=0 consumed=634 stage=0 closing=false child_signaled=false exit_code=259
      tab main:0   input_high_water=19 input_rejected=0 output_bytes=537 read_error=0 consumed=537 stage=0 closing=false child_signaled=false exit_code=259
      tab main:1   input_high_water=5  input_rejected=0 output_bytes=457 read_error=0 consumed=457 stage=0 closing=false child_signaled=false exit_code=259
    

    判读

    读数 含义
    四个会话 input_rejected=0 输入没有被拒绝
    input_high_water 2/1/19/5 队列几乎没有积压(最大 19 字节)
    四个会话 output_bytes == consumed(592/592、634/634、537/537、457/457) 读到的字节已全部消费,读取侧无堆积
    read_error=0 读取无错误
    child_signaled=false、exit_code=259 四个子进程都还活着

    即:这不是输入/读取/回收侧的停滞,而是四个会话都没有推进到 stage 5 要求的就绪条件——与上一轮"WSL 的 185B 观察窗口起点落在回显中间,标记与回显同一条记录、oracle 不跨 CUP 拼接"的解释一致:transport_completed=false 是判据匹配问题,不是数据没到。

    因此本项的状态

    • 机制已定位(观察窗口起点);
    • 本样本进一步排除了"输入/读取积压"与"子进程已退出"两类解释;
    • 仍不可关闭:缺"改窗口起点 vs 改 oracle 契约"的单变量修前/修后对照。

    边界

    • 本样本未附带 shells-size-readiness.jsonl 与 probe 行(那是失败分支写出的独立文件,需从 artifact 取);
    • stage=0 属选择/工作区场景的已知局限(ShellWindow::stage_ 不参与这些模式)。
  14. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    首次拿到带 stage 与自动判读的失败样本

    PR #289 的 Windows 回归(job 124536048854)命中本项形态:

    workspace-failure mode=ui-shells stage=5 what=workspace shells scenario timeout at stage 5
      tab bottom:0 input_high_water=1 input_rejected=0 output_bytes=592 consumed=592 child_signaled=false exit_code=259
      tab bottom:1 input_high_water=4 input_rejected=0 output_bytes=602 consumed=602 child_signaled=false exit_code=259
      tab main:0   input_high_water=1 input_rejected=0 output_bytes=657 consumed=657 child_signaled=false exit_code=259
      tab main:1   input_high_water=1 input_rejected=0 output_bytes=457 consumed=457 child_signaled=false exit_code=259
    判读: bottom:0 rejected=0 drained=yes child=259; bottom:1 rejected=0 drained=yes child=259; main:0 rejected=0 drained=yes child=259; main:1 rejected=0 drained=yes child=259
    

    新增的两点信息

    项 含义
    stage=5(Workspace 自己的阶段) 卡在四会话尺寸就绪验证这一步
    自动判读四行 drained=yes 四个会话都读完即消费完、输入无拒绝、子进程存活(259)、未进入收尾

    与既有结论的关系

    此前复现的机制是:WSL 会话的 185B 观察窗口起点落在命令回显中间,TF_SIZE_54x12 与回显同属一条记录、中间只有 ESC[10;1H,而 transport_completion.hpp:62-66 不跨 CUP 拼接 → output_seen 永远 false。

    本样本与之一致:数据都到了、也都消费了(drained=yes),只是判据没匹配上。

    修法方向(待你确认)

    方案 内容 代价
    A. 改窗口起点 观察窗口从行首开始或按行切分 局部改动;改变"窗口"语义
    B. 改 oracle 契约 允许跨 CUP 拼接 影响其他用例判定严格度
    C. 保持现状 视作测试基础设施已知限制 本项无法关闭

    边界

    • 单一样本,来自 PR 分支而非 main;
    • 未取该 job 的 shells-size-readiness.jsonl 与 probe 行,窗口字段实测值仍未拿到。
  15. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    拿到窗口原文了,并且验证了修法方向

    从 run 41200805448 的 failure-windows-2025 artifact 取到 wsl 探针行:

    {"role":"wsl","marker":"TF_SIZE_54x12","window_bytes":185,
     "window_hex":"221b5b3f31303034h 1b5b3f32356c /mnt/d/a/termforge/.../shell_size_client.exe\" 1b5b31303b3148 54465f53495a455f35347831320d0a 54463e20…"}

    解码后的结构:

    "  ESC[?1004h ESC[?25l /mnt/d/a/termforge/.../shell_size_client.exe"   ← 命令回显
    ESC[10;1H                                                          ← CUP
    TF_SIZE_54x12 CRLF                                                 ← 标记
    TF>                                                                ← 提示符
    

    readiness 四行也印证:cmd/pwsh/powershell 的 transport_completed=true,只有 wsl 为 false(observed_output_tail_bytes=185)。

    我试了「B 方案:改 oracle 跨 CUP 拼接」,被既有合同测试否决

    在 transport_completion.hpp 里把 CUP 当作记录边界后,transport_completion_test 立刻失败:

    CUP cannot discard an echo prefix to invent marker output
    

    这个测试的存在意义正是防止我把回显前缀"洗掉"从而凭空认定标记已输出。 所以 B 方案不可行——不是实现困难,而是它违反既有合同。改动已回退(transport completion checks passed 重新通过)。

    因此方向确定为 A:改观察窗口起点

    正确做法是让观察窗口从命令回显之后开始,而不是让 oracle 去猜。具体位置:

    位置 说明
    workspace_shells_scenario.hpp:73 附近 调用 begin_output_observation() 的时机
    现有窗口 185 B 起点落在回显中间,需在回显结束后再开窗

    边界

    • 本样本来自 PR ci(conpty): 支持只跑单个作业的定向采样 #289 分支的作业,非 main;
    • 窗口长度 185 B 与 readiness 的 observed_output_tail_bytes 一致,可交叉核对;
    • 改窗口起点需要明确"回显结束"的判据(提示符?CRLF?),这属于实现细节,我会在下一轮给出具体方案。
  16. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    A 方案的可行落点(读完调用链后)

    观察窗口的起点在这里:

    // workspace_shells_scenario.hpp:53-56
    for (const auto group : {Group::bottom, Group::main}) for (auto& tab : group_tabs(group)) {
        tab.shell->begin_output_observation();   // ← 窗口从这里开始
        tab.shell->check_size(tab.launch && tab.launch->kind==L"wsl" ? shell_size_event_ : L"");
    }

    窗口从发命令之前就开了,所以 WSL 的输入回显(/mnt/.../shell_size_client.exe\")必然落进窗口,后面才是 ESC[10;1H + 标记。

    三个可选实现

    方案 做法 代价
    A1 让 size helper 在标记前先输出 \r\n,使标记自成一条记录 改动最小、oracle 不动;需确认 helper 输出受控
    A2 在调用点对窗口做裁剪(丢掉最后一个 CUP 之前的内容)再交给 oracle oracle 不动,语义仍在"窗口"层;但要证明裁剪不会把真实错误洗掉
    A3 WSL 专用:detach 后重新 begin_output_observation(),即等回显结束再开窗 最干净;但要有可靠的"回显结束"判据

    我倾向 A1

    因为:

    • oracle 与既有合同(CUP cannot discard an echo prefix…)都不动;
    • 窗口内容变短,判定更直接;
    • 改动局限在测试 helper 与场景,不触及产品路径。

    需要先确认的一件事

    A1 要求 size helper 能控制自己在标记前的输出。我要先读 shell_size_client 的实现确认这一点;若它只输出标记本身,那实际可行的最小改动是 A2。

    边界

    • 本条只给方案,未改代码;
    • 三个方案都只影响测试基础设施(experiments/shell),不改变产品行为。
  17. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    排除 A1:helper 已经输出换行,是 conhost 把它变成了 CUP

    experiments/shell/size_client.cpp:16:

    const auto text = "\r\nTF_SIZE_" + std::to_string(info.dwSize.X) + "x" + std::to_string(info.dwSize.Y) + "\r\n";

    helper 本来就先输出 \r\n。但窗口十六进制里看到的是:

    …shell_size_client.exe" 1b5b31303b3148 54465f53495a455f3534783132
                            ↑ ESC[10;1H        ↑ TF_SIZE_54x12
    

    即那个 \r\n 被 conhost 在 VT 输出模式下翻译成了 ESC[10;1H(绝对定位到第 10 行第 1 列),不是字面 CRLF。

    排除 B:既有合同明确禁止把 CUP 当记录边界

    transport_completion_test.cpp 里有三条直接相关的用例,且用的都是第 1 列的 CUP:

    check(!transport_output_completed("echo \x1b[6;1H"+marker+"\x1b[7;1HTF>", marker),
          "CUP cannot discard an echo prefix to invent marker output");
    check(!transport_output_completed("TF>echo \x1b[6;1H"+marker+"\x1b[7;1HTF>", marker),
          "CUP cannot discard a prompt and echo prefix");
    check(!transport_output_completed("echo "+marker+"\x1b[6;1HTF>", marker),
          "CUP does not turn command echo into output");
    

    也就是说,"列 1 的 CUP"也不允许被当作换行——设计上就是要防止把回显前缀洗掉后凭空认定输出。

    所以只剩场景层:A3

    可行判据很具体:回显是我们自己发的命令文本。WSL 场景知道它要执行的 helper 路径,所以可以:

    1. check_size() 发出命令;
    2. 后续 tick 中,一旦 observed_output() 里出现该 helper 路径(说明回显已完成),重新 begin_output_observation() 开一个新窗口;
    3. 新窗口只含 ESC[10;1H + 标记 + 提示符,oracle 就能正常匹配。

    风险:重开窗口会丢掉此前内容,若标记恰好在重开前到达就会漏掉。因此需要用"窗口里已含标记但 transport 未完成"作为触发条件,而不是无条件重开。

    边界

    • A3 只在 WSL 分支生效,不影响 cmd/pwsh/powershell 三条已通过的路径;
    • 仍属测试基础设施改动,不动产品代码与 oracle 合同。
  18. added a commit that references this issue on Oct 31, 2026
  19. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    修前/修后对照:同一提交内容,结果从红转绿

    版本 内容 Windows 回归
    修前(ci/focus-input 原始版本,430…) 只加 only 输入,不含窗口修复 红:workspace-failure mode=ui-shells stage=5
    修后(rebase 到含 #290 的 main) 同一份 only 输入改动 + WSL 窗口修复 绿(全部检查通过,已合并为 #289)

    修复内容(#290,已合并)

    // workspace_shells_scenario.hpp 的 sizes_ready()
    const auto observed = tab.shell->observed_output();
    if (observed.find("shell_size_client") != std::string::npos &&
        observed.find(marker) == std::string::npos) {
        tab.shell->begin_output_observation();   // 丢掉回显,重开窗口
        return false;
    }

    为什么这是有效的证据

    • 两次运行的差异只有一处:是否包含窗口重开逻辑;
    • 修前那次的失败点正是本项的 stage 5(transport_completed=false),不是别的偶发;
    • 修后同一套 ui-shells 场景通过,说明 WSL 的 transport_output_completed 现在能匹配上。

    仍未证明的部分

    • 只覆盖 cmd/pwsh/powershell/wsl 四会话 + 固定尺寸这一配置;
    • 未验证 shells-size-readiness.jsonl 里 wsl 的 transport_completed 是否已变为 true(需要该次运行的 artifact,我可以下一轮取);
    • 不能据此说"四 shell 场景已稳定",只能说这一形态的成因与修法已被对照证实。

    边界

    • 修复位于测试基础设施(experiments/shell),不改产品行为;
    • oracle 的三条 CUP 合同未被放宽。
  20. JavaZeroo commented on Oct 31, 2026

    @JavaZeroo
    OwnerAuthor

    修后证据的边界(对照本项自己的验收文字)

    本轮去取修后那次运行的 artifact,想确认 wsl 行的 transport_completed 是否变为 true。结果:

    尝试 结果
    下载 41200844601 的 actions-repeat-evidence 成功,3665 个文件
    在其中找 shells-size-readiness.jsonl 没有

    原因:ui-shells 场景属于 shell 套件,跑在 regression 作业里;actions-repeat 只跑 actions/selection 系列。而 regression 通过时不保留 readiness 文件(该文件只在失败产物里)。

    因此可以断言什么

    • sizes_ready() 只有在 transport_output_completed(observed, marker) 为真时才会放行;
    • 修后 regression (windows-2025) 全绿,说明 ui-shells 走完了 stage 5 之后的流程;
    • 结合修前同一作业红在 stage=5,这一形态的成因与修法已被单变量对照证实。

    但本项仍不满足关闭条件

    本项正文明确写着:

    原hosted stage6是否同因仍未知;本项保持开放,不用限定修正或新CI成功替换旧失败的因果证据。

    即:本次修的是 stage 5 的观察窗口(成因已字节级确认),而本项要的是原 hosted stage 6 事件的因果证据。两者不能互相替换。

    因此保持开放,并记录本次净收益

    项 状态
    stage 5 WSL 窗口成因 已确认(185B 窗口 + CUP + 标记同记录)
    对应修法 已实现并合并(#290),修前红/修后绿
    原 hosted stage 6 仍未复现,因果未知
    本项 保持开放
  21. added a commit that references this issue on Oct 31, 2026
  22. JavaZeroo commented on Nov 1, 2026

    @JavaZeroo
    OwnerAuthor

    本批(diagnose/shell-stage6-hosted):hosted 未复现,原事件保持未知

    当前形态确认(实测,main HEAD c3e825e)

    • 2b85fef 事件握手已合入并在当前形态:experiments/shell/workspace_shells_scenario.hpp:46-95 的 check_size/sizes_ready 与 stage5 释放门(wsl 记录 size-helper-held→sizes-ready);experiments/shell/size_client.cpp:4-22 的 --wait-event 事件与 15s 等待;experiments/shell/transport_completion.hpp:19-97 的 transport_output_completed(须观察同次尺寸输出之后的独立新提示符)。
    • readiness/instrumentation:experiments/shell/local_shell_diagnostics.hpp:34-47(shells-size-readiness.jsonl:settled/marker_present/transport_completed/observed_output_tail_bytes)与 :51-125(shells-transport-probe.jsonl:output_seen/prompt_seen/malformed/last_line/window_hex),仅在 30s 超时路径写出,成功路径不产生这两份。

    本机有界多次(实测,上限 7 次)

    • 原方法 ui-shells:plain 6 次 + fence 1 次,7/7 通过。plain 用时 16.938 / 4.359 / 3.359 / 2.875 / 2.860 / 2.890 秒(首轮含冷 WSL 启动),fence 2.891 秒。原 30/40 秒期限、两轮四 shell 方法、真实目录/子尺寸、Job/desktop 留证均未改动。汇总 local/r80-shells-local-report.json;逐轮 shells-progress.jsonl 显示 wsl/pwsh/powershell/cmd 顺次 stage6/7/8/9 exit 0,fence 轮含 size-helper-held→sizes-ready 顺序。

    首轮 default Windows hosted CI(实测)

    • 推 diagnose/shell-stage6-hosted(无新提交,等于 origin/main c3e825e)触发 build.yml。Build 41295616231:windows-2025 regression 成功,65/69 Test #65: shell ... Passed 66.61 sec,100% tests passed out of 69,Total 271.01 sec。
    • 下载 artifact r1-windows-input(ID 13079371385)逐轮核对:shells-0/​shells-1 两轮 shells.json 均 normal_exit=true、main_sessions:2/bottom_sessions:2,四 shell 顺次 stage6/7/8/9 exit 0;shells-held-size-helper 轮含 size-helper-held→sizes-ready→顺次退出。三个场景均未写出 shells-size-readiness.jsonl/​shells-transport-probe.jsonl(印证成功路径)。

    结论

    • 本批 未复现 hosted stage6/30s:当前 main(含 2b85fef)在 default Windows hosted(windows-2025)上 ui-shells 首轮即通过,未出现原 30 秒耗尽。
    • 原 hosted 事件(HEAD c820691 / 合并 checkout 9b62087)的因果身份仍 未知:本批只证明当前形态在 hosted 通过,不构成旧失败与新条件的因果等价证据;按上限停止,不循环重跑取绿。

    下一步

    • 需定位原 hosted 事件时,应在原提交 c820691(修前)或其加 readiness 诊断的中间提交上触发 hosted,让 30s 超时写出 shells-size-readiness/​shells-transport-probe,才能在三假设(UI/队列未发送、Windows 子进程→WSL 输入丢失、WSL 已收 exit 但生命周期未回收)间取舍;本批当前 main 已绿,不重复取绿。
  23. JavaZeroo commented on Nov 1, 2026

    @JavaZeroo
    OwnerAuthor

    修前 hosted 批次(diagnose/shell-stage6-prefix)未复现

    结论:原 hosted stage6/30s 事件本轮未复现,保留未知,不循环重跑;三假设无新证,继续开放。

    实测

    • 分支 diagnose/shell-stage6-prefix,commit 7eb9b10(仅移植超时路径仪表到修前形态)。
    • 默认 Windows hosted CI(Build and synthetic regression)run 41326818928 全绿:windows-2025 job 124908389782 的 Test 步骤成功,失败证据步骤被跳过。
    • 两轮 ui-shells 均正常退出:shells.json normal_exit=true、四 shell(cmd/powershell/pwsh/wsl-Ubuntu)、main_sessions=2/bottom_sessions=2;shells-progress.jsonl 显示 wsl 在 stage6 exited(exit_code 0、cleanup_complete=true、observed_output_tail_bytes 464),随后 pwsh/powershell/cmd 顺序退出;sample.json shells_verified=4、sessions_closed=4、active_children_after=0、Job active0/total34/terminated0、desktop_gone=true、timed_out=false。
    • 两轮均未写 shells-size-readiness.jsonl 与 shells-transport-probe.jsonl,30 秒超时分支未命中,确认阶段超时未发生。

    推断

    • 超时仪表已对照 main 逐字移植,只加不改行为(本地 termforge_shell 编译通过):experiments/shell/local_shell_diagnostics.hpp:35-48 与 49-126 分别写出 shells-size-readiness.jsonl、shells-transport-probe.jsonl;experiments/shell/workspace_shells_scenario.hpp:3、14-36 只在其 30 秒超时分支调用,不改阶段逻辑。
    • 若事件下次再现,这两份 jsonl 记录四 shell 的 settled/marker_present/transport_completed/observed_bytes 与 WSL 的 output_seen/prompt_seen/malformed/last_line/window_hex,可直接取舍三假设。

    未知

    • 原一次性 stage6/30s 事件根因仍未定位;三假设(UI/队列未发送、Windows 子进程到 WSL 输入丢失、WSL 已收 exit 但生命周期未回收)本轮无新证取舍,与本机 6/6、当前源码 hosted 69/69 一致。

    artifact:r1-windows-input,id 13091369066,4305855 B,SHA256 ef93a2b8924bcfda2c6ad1381cb317be576eaab0707603322b77ea4ca9970192。下载一次,shell 两轮证据与全量保留于 tf-r80b local/r80-prefix-batch。

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平台、协议或行为兼容问题ready-for-agent范围明确且真实阻塞已解除,可开始实施

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions