diff --git a/docs/EVIDENCE.md b/docs/EVIDENCE.md index fefbba94..095561a3 100644 --- a/docs/EVIDENCE.md +++ b/docs/EVIDENCE.md @@ -56,6 +56,7 @@ R1 固定总出口的源码为 `ce9b24d`,早期 `2dc8d6d` / `9b16acc` 仍分 | 实验 UI 未完成粘贴(#53) | [机制与边界](research/ui-paste-fence.md)、[旧固定记录](../experiments/shell/results/2026-10-26-ui-paste-fence/validation.json)、[组合修复](research/resize-replay-cost.md)、[最终同源码记录](../experiments/shell/results/2026-10-26-replay-cost-and-close/validation.json) | `eae4b6a` 单窗口两轮、真实EOF/无GO负例及两轮原八会话data-only通过;行键复用及关闭期间不回复分别有诊断/因果回归,原completed/stage45/退出错误保留。完整CTest54/56仍有Vim59、resize43、main7/ui52与shell180秒期限;未计真实CF/IME、完整后端或性能通过。 | | Native Vim 捕获目录隔离 | [原因与复验](research/vim-fixture-isolation.md)、[固定原件审计](../experiments/conpty/results/2026-10-26-vim-fixture-isolation/validation.json) | 实验分支同旧 EXE 的兄弟运行一绿一红;修正新目录隔离后完整模块9/9。仅闭合 #52 native 夹具原因;GUI stage59 仍开放,未知与受扰动探针分列。 | | 原生 viewport resize 与默认策略隔离(#51) | [原因与复现](research/native-viewport-resize.md)、[固定验证及六组合成原件](../experiments/conpty/results/2026-10-27-native-viewport-resize/validation.json) | 原 `.4` GUI stage43 与独立 native/replay 红;`.5` 原 resize/Unicode、历史/空格复制、六组 native 对照通过。默认策略填充误判经实际红绿修复;最终完整回归 54/56、12 项内部 skip,#52/#88 及此前 #87 的失败独立保留,不计完整后端或 WindTerm 等价。 | +| 窄列命令回显与恢复完成(#88) | [独立判据合同](research/workspace-restore-transport-oracle.md)、[原件哈希/红绿/正式两轮验证](../experiments/shell/results/2026-10-27-workspace-echo-cr/validation.json) | 原 262 B cmd 运输中的回显裸 CR 使完成判据提前拒绝;修正仅使该记录保持不可信至真实 LF。原两轮保存/普通恢复/钳制及完整 shell 通过;官方完整回归 55/56、8 项内部 skip,#52 仍红,#63/#87 旧因未闭合。构建重叠结果明确排除。 | | 工作区几何与交互的固定记录 | [#38](https://github.com/JavaZeroo/termforge/issues/38)、[工作区几何与输出验证](../experiments/shell/results/2026-10-26-workspace-geometry/validation.json)、[resize 限定证据](../experiments/core/results/2026-10-26-resize-replay/validation.json) | 固定 27f376d 的客户区/布局/输出、默认/候选恢复及窄屏记录;其完整回归仍有 #36/#38 红项,不代表当前所有配置或 R2 通过。 | | 短窗口选区夹具与 hosted 四 shell 前置(#38) | [固定锚点回归](../experiments/shell/test_shell.py)、[准备入口](../tools/prepare_hosted_shells.py)、[夹具收尾合同](research/hosted-wsl-fixture-cleanup.md)、[云端结果与剩余阻塞](https://github.com/JavaZeroo/termforge/issues/38) | 短窗口保留相同选择断言;仅指定一次性 hosted VM 准备固定 Ubuntu。夹具强制收尾与产品自然退出分列,未知归属/回收仍失败。 | | 工作区恢复的运输完成端点(#38 夹具修正) | [限定合同](research/workspace-restore-transport-oracle.md)、[原失败及默认/候选验证](../experiments/shell/results/2026-10-26-workspace-transport-oracle/validation.json) | OSC 标题中的重复标记与 column-one CUP 误导旧端点;新判定保留完整 UTF-8、期限、负载及恢复断言。仅修夹具,不宣称修复产品恢复。 | diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 5724f5eb..3cc69710 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -14,7 +14,7 @@ |---|---|---| | 默认 main:自研核心 + 系统 ConPTY | 默认构建与已发布 Alpha 的基础路线,不需要 Rust | 已有 R1 限定验收;VT/Unicode 能力仍为有限子集,不能引用候选核心的字素或 TUI 结果 | | 显式候选 main:`termforge.4` + 系统 ConPTY | `TERMFORGE_BUILD_CANDIDATE_ADAPTER=ON`;按 [ADR-0003](adr/0003-core-reference-and-reuse.md)保留为可评估实验,正式核心选型待用户确认 | [固定来源](../experiments/candidates/alacritty/PROVENANCE.md)、[适配边界](../experiments/core/CANDIDATE.md)与 [#39 字素合同](research/streaming-graphemes.md);候选正确性通过不关闭系统 ConPTY 或 R2 父项 | -| 实验分支:`termforge.5` + 固定官方 ConPTY | [PR #50(Draft)](https://github.com/JavaZeroo/termforge/pull/50),`.4` 联合源码 `3e5b96d` 的[真实基线](research/joint-conpty-baseline.md)保留,尚未合并 main 或通过产品整体验收 | [#51 原生 viewport 修复](research/native-viewport-resize.md)保留历史并对齐宿主坐标,原 resize/Unicode 两轮及六组原生样本通过;最终完整回归 54/56,保留 [Vim #52](https://github.com/JavaZeroo/termforge/issues/52)、[恢复 stage1 #88](https://github.com/JavaZeroo/termforge/issues/88)和此前[八会话半行 #87](https://github.com/JavaZeroo/termforge/issues/87),同源码记录见该证据。[#53 UI fence](research/ui-paste-fence.md)与[行键复用/关闭回复](research/resize-replay-cost.md)、[#62 worker 夹具](research/sender-fence.md)各自限定通过。终端 margin 与原生状态分列,#47/#63 及完整后端仍开放;旧残尾、超时和组合失败记录保留 | +| 实验分支:`termforge.5` + 固定官方 ConPTY | [PR #50(Draft)](https://github.com/JavaZeroo/termforge/pull/50),`.4` 联合源码 `3e5b96d` 的[真实基线](research/joint-conpty-baseline.md)保留,尚未合并 main 或通过产品整体验收 | [#51 原生 viewport 修复](research/native-viewport-resize.md)保留历史并对齐宿主坐标,原 resize/Unicode 两轮及六组原生样本通过;[#88 回显完成判据](research/workspace-restore-transport-oracle.md)的原两轮保存/恢复/钳制及完整 shell 通过,最终官方完整回归 55/56、8 项内部 skip。[Vim #52](https://github.com/JavaZeroo/termforge/issues/52)仍红,此前[八会话半行 #87](https://github.com/JavaZeroo/termforge/issues/87)和 #63 旧工作区失败原因未闭合。[#53 UI fence](research/ui-paste-fence.md)与[行键复用/关闭回复](research/resize-replay-cost.md)、[#62 worker 夹具](research/sender-fence.md)各自限定通过。终端 margin 与原生状态分列,#47 及完整后端仍开放;旧残尾、超时和组合失败记录保留 | 以下能力默认指已合并实现;某个配置的通过结果不能转用于另一个配置。R1 的真实系统 CF/拼音验收属于固定自研核心配置,不外推到候选 `.4` 或实验后端联合配置。 diff --git a/docs/milestones/R2-local-terminal.md b/docs/milestones/R2-local-terminal.md index f4f47f93..9d13791d 100644 --- a/docs/milestones/R2-local-terminal.md +++ b/docs/milestones/R2-local-terminal.md @@ -44,7 +44,7 @@ flowchart LR ## 下一批的任务边界 -1. **在已冻结基线上逐项闭合后端回归。** #55 已交付含红的真实基线;接续 #51–#53、#63、[#87 八会话半行观测](https://github.com/JavaZeroo/termforge/issues/87)与 [#88 恢复 stage1](https://github.com/JavaZeroo/termforge/issues/88)的独立失败。#62 的[真实 writer 持块、取消与停止夹具](../research/sender-fence.md)不降低原 4MiB/16KiB/期限,#53 已接入默认关闭的 fence,[单窗口 UI/3MB/768B 与控制故障切片](../research/ui-paste-fence.md)及[同源码两轮原八会话data-only](../research/resize-replay-cost.md)已通过;[#51 原生 viewport 修复](../research/native-viewport-resize.md)的原 resize 与 Unicode 限定回归通过,完整官方回归中的 Vim/#88、此前 #87、历史工作区失败及聚合期限证据分别保留,真实 CF/IME 组合独立验收。#51–#53 可以用原冻结输入独立定位,最终修复验收须在联合配置重建;一次未复现不自动构成因果修复。 +1. **在已冻结基线上逐项闭合后端回归。** #55 已交付含红的真实基线;接续 #52、#63 和 [#87 八会话半行观测](https://github.com/JavaZeroo/termforge/issues/87)的独立失败。#62 的[真实 writer 持块、取消与停止夹具](../research/sender-fence.md)不降低原 4MiB/16KiB/期限,#53 已接入默认关闭的 fence,[单窗口 UI/3MB/768B 与控制故障切片](../research/ui-paste-fence.md)及[同源码两轮原八会话data-only](../research/resize-replay-cost.md)已通过;[#51 原生 viewport 修复](../research/native-viewport-resize.md)的原 resize 与 Unicode、[#88 回显完成判据](../research/workspace-restore-transport-oracle.md)的原保存/恢复/钳制限定回归通过。完整官方回归中的 Vim、此前 #87、历史工作区失败及聚合期限证据分别保留,真实 CF/IME 组合独立验收。各回归可用原冻结输入独立定位,最终修复验收须在联合配置重建;一次未复现不自动构成因果修复。 2. **并行处理原版对照、平台语义与性能。** [原生语义处理路径 #56](https://github.com/JavaZeroo/termforge/issues/56)先明确 #41 原合同需要什么、哪些路径可支持;保留必要的上游或独立实现工作,不用“平台不同”豁免缺口。#3/#4 优先建立原版 Windows 本地终端基线;#54 现在冻结重复方法与完成端点并定位吞吐成本,数值预算作为提案交用户确认,不等到 #34 才补性能。 3. **在主线推进独立行为合同。** #29 核对极窄/极短、软硬行、历史/淘汰、选择/Find、连续 resize 和 child ack;#30 核对 IME 组合/提交/取消与输出/resize/切换、应用键盘/粘贴接收、实际复制及同次八会话。已验收的 #39 只提供首批字素基础,最终配置的交叉验收仍需执行。 4. **补终端模式和应用矩阵。** #27 明确 DECOM/DECAWM、pending-wrap、保存恢复、异常序列与 margin×resize;#28 先固定应用版本/入口/动作及协议字节预期,再逐应用完成进入、操作、resize、退出、主屏恢复。Vim 的一个修复不替代完整 TUI 验收。 diff --git a/docs/research/workspace-restore-transport-oracle.md b/docs/research/workspace-restore-transport-oracle.md index 7d8a17b2..a06aafc9 100644 --- a/docs/research/workspace-restore-transport-oracle.md +++ b/docs/research/workspace-restore-transport-oracle.md @@ -16,15 +16,17 @@ ## 限定 oracle 合同 +[#88](https://github.com/JavaZeroo/termforge/issues/88) 的官方后端第二轮普通恢复 stage1 原件中,主 cmd 的 262 B 运输包含命令回显的裸 CR/CUP,随后已有独立目录输出和新提示符。相同 helper 重放四个谓词,仅主 cmd 为 false;只移除该回显 CR 后为 true,再去掉真实输出行仍为 false。修正将这种已存在文字的回显记录保持为不可信,等待真实 LF 后重新验证独立输出;不模拟 CR/CUP,也不删除或拼接回显文字。原完整回归失败保留在 [#51 固定记录](../../experiments/conpty/results/2026-10-27-native-viewport-resize/validation.json)。[修正验证](../../experiments/shell/results/2026-10-27-workspace-echo-cr/validation.json)保留相同触发断言的红绿、最终补充的四个用例,以及构建完成后正式执行的原两轮保存/恢复/钳制;六次运行和完整 shell 方法通过。最终官方配置 CTest 55/56、398.08 秒,Vim stage59 仍归 #52;新构建的 trace 使四项可选差分检查实际执行,剩余 8 项内部 skip 单列。构建重叠的早期运行已排除,旧 #63/#87 失败未因本轮未复现而关闭。 + - 独立扫描 7-bit ESC 形式的完整 OSC(BEL 或 ST 终止)和 CSI。OSC 内容不参与正文匹配,UTF-8 的所有高位正文 bytes 原样保留,包括 `目` 中的 `0x9b`。 - 标记必须匹配完整正文记录,前后不可附加命令、其它正文或任意子串。LF 结束记录;显式正行号、第 1 列 CUP/HVP 仅可结束完整标记或提示符,不能清除命令前缀或拼接分散的标记片段。其它非空内容遇 CUP 保持未知,直到真实 LF;SGR 和其它 CSI 不会凭空结束标记。 - 在首次匹配输出之前,命令编辑中的 BS 只会污染当前记录;CUP 不能解除该污染,也不把退格两侧文字拼起来。真实 LF 后可验证新的完整记录。已经匹配输出后的 BS 仍拒绝,不能借编辑过的提示符证明命令完成。 -- CRLF 的 CR 不改变正文。裸 CR 仅在已观察到记录边界、当前记录为空且未受 BS 污染、尚未匹配输出时允许经过;它不清除文字、不结束记录,也不替代之后的完整标记和新提示符。初始裸 CR、非空或受编辑污染记录中的裸 CR、已匹配输出后的裸 CR,以及其它裸控制字符仍拒绝。 +- CRLF 的 CR 不改变正文。在首次匹配输出之前,非空或已被编辑的记录遇裸 CR 会保持不可信,直到真实 LF;CUP 不能解除该状态或将其中的标记算作输出。已观察到记录边界、当前为空且未受编辑的记录可以保持为空。裸 CR 不清除文字、不结束记录,也不替代之后的完整标记和新提示符;初始空记录和已匹配输出后的裸 CR,以及其它未知裸控制字符仍拒绝。 - 该记录之后必须出现独立的 `TF>` 或 `TF> ` 记录,才证明 shell 返回;输入命令回显、标题内标记、旧提示符和输出行前缀都不满足条件。 - 完整 CSI 仅按语法封装剥离,不解释或验收其执行语义;其中受限 column-one CUP 的记录边界另按上条处理。不完整或格式错误的封装、未知 ESC 引导形式、DCS 等其它控制字符串保持未证明状态。这只覆盖固定持久化命令已输出和返回提示符的运输证据,不扩展为第二个通用 VT 核心;产品屏幕及恢复断言仍独立保留。 - 保留原有 8192-byte 观测上限、30 秒总期限、真实目录/版本、返回提示符、恢复成员/标题/缩放/分屏/几何及尺寸检查和真实 Job/desktop 回收断言。 -`transport_completion_test` 独立覆盖标题重复遮蔽、BEL/ST、SGR、CUP、UTF-8、命令编辑前缀 BS、空记录裸 CR,以及命令回显、CR/BS 拼接或提示符编辑、OSC/DCS payload、不完整控制、缺失或旧提示符等反例。它修正的是测试 oracle,不构成产品恢复故障修复或完整 R2 验收。 +`transport_completion_test` 独立覆盖标题重复遮蔽、BEL/ST、SGR、CUP、UTF-8、命令编辑前缀 BS、空记录裸 CR、窄列回显裸 CR,以及命令回显、CR/BS 拼接或提示符编辑、OSC/DCS payload、不完整控制、缺失或旧提示符等反例。它修正的是测试 oracle,不构成产品恢复故障修复或完整 R2 验收。 ```powershell ctest --test-dir build/default -C Release -R '^transport_completion$' --output-on-failure diff --git a/experiments/shell/results/2026-10-27-workspace-echo-cr/validation.json b/experiments/shell/results/2026-10-27-workspace-echo-cr/validation.json new file mode 100644 index 00000000..0fbc810e --- /dev/null +++ b/experiments/shell/results/2026-10-27-workspace-echo-cr/validation.json @@ -0,0 +1,1009 @@ +{ + "schema": 1, + "issue": 88, + "source_commit": "c93db58ede50ad1288ceeeb937403fa8db43b459", + "implementation_commit": "341b4c22e36ffb5a47c7c1d0ccd70b46402e93b6", + "base_commit": "259e03667f361fd00c6e678f3e86f6ee2dfdca1b", + "configuration": "candidate termforge.5 / explicit official ConPTY 1.25.260930003 / flags24", + "identity": { + "source_commit": "c93db58ede50ad1288ceeeb937403fa8db43b459", + "after_successful_build_utc": "2026-10-26T21:18:00.803994+00:00", + "files_sha256": { + "experiments/shell/transport_completion.hpp": "39dfeb0845e572ec842b7da09dc2b822ba221caa1414a6a386f066214eb4da15", + "experiments/shell/transport_completion_test.cpp": "3761c858c97e5975d51a5c552104ba8457a5183070b12c0f635a7da42647e80d", + "experiments/shell/workspace_persistence_scenario.hpp": "7f70d755549718d0fddb94b43cce12f3955727fcc51599a8bb124bf3e59ec263", + "experiments/shell/test_shell.py": "a6b63c1754b0e0dc1cc01863891f4c7c9d989f818d351838a8cfe295edaf811c", + "experiments/shell/run.py": "45976b828eecb316881d698dedaef09ad304f72d991dfa360f1c552bbcbe9f1d", + "experiments/candidates/alacritty/test_candidate.py": "80b19e6fcd9416d4a34c43a5e50525857e6504f1a485827045f209d4dae4f106", + "build/candidate/bin/Release/termforge_shell.exe": "6adcb6091cbe937f398eace55499042eebcd5c900bd0f36c6eef480a6eac0eb4", + "build/candidate/bin/Release/transport_completion_test.exe": "6952438843e8a7605bb6cf0eb7add56dd8574f4e5edfbc3a534f795030a3fcc8", + "experiments/candidates/alacritty/target/release/termforge-alacritty-trace.exe": "5941d4569d0ae146eb005f12ecfb15014bc06c18ee48d1c9460824ab65df93d3" + } + }, + "baseline": { + "source_commit": "ab360c7aebeb8e9afb5e61d386081abd8e3e8278", + "product_commit": "92eac12d5cd2868b469e8b9a10e68f5e20ee2cb0", + "files_sha256": { + "termforge_shell.exe": "15a149a3d7d47efaf866226559d4b60bbf83e0ff6004a85df41edcb5415ad206", + "transport_completion.hpp": "535ff47bfbdd1038dca22820b467d1ee0d1839a29be38cd750e4de49439b602f", + "transport_completion_test.cpp": "c9bb02bd739f916e78530590ee0f3b29bc952c58e445d31bc047ee69d301dcee", + "transport_completion_test.exe": "ecb414aa56e45cb6026154d2c5bf4c3e2c173c038d4f2641debfa452749b0233" + } + }, + "original_failure": { + "source_commit": "92eac12d5cd2868b469e8b9a10e68f5e20ee2cb0", + "mode": "ui-workspace-restore", + "stage": 1, + "repeat": 1, + "files_sha256": { + "persistence-failure.json": "7ccb0a90b526462a929cbebce42debccfd97b54676e54e0935fbf292826b5e5b", + "restore-geometry.json": "5cc777f65d580599f8bda2d3e7e3d246b63aba19dba55a27e65d358709402638", + "sample.json": "5e546fb36ec65e2d2eb20e9d1047216be33dc8b17eaaa611d995686a1be7d620", + "workspace.layout": "660f3a4064006db91261100c6fb1e1d2fb82f73210575910a29880489dd0cdda" + }, + "result": { + "exit_code": 2, + "timed_out": false, + "job_after": { + "active": 0, + "total": 11, + "terminated": 0 + }, + "desktop_gone": true, + "job_after_cleanup": { + "active": 0, + "total": 11, + "terminated": 0 + } + }, + "native_exit_code": null, + "reader_eof": null, + "native_forced_cleanup": null + }, + "original_replay": { + "product_source": "92eac12d5cd2868b469e8b9a10e68f5e20ee2cb0", + "failure_sha256": "7ccb0a90b526462a929cbebce42debccfd97b54676e54e0935fbf292826b5e5b", + "helper_sha256": "535ff47bfbdd1038dca22820b467d1ee0d1839a29be38cd750e4de49439b602f", + "probe_sha256": "eca81870a7f8228bab14f5d35900d27fc7a207a07c2a1e5b2e49c9faf0189698", + "cases": [ + { + "tab": 0, + "kind": "cmd", + "variant": "original", + "bytes": 230, + "sha256": "68fadc3fc45b9fbaab78b7e1a55987f5fdc11e9a2abdbe39fc65135556703017", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + }, + { + "tab": 1, + "kind": "cmd", + "variant": "original", + "bytes": 262, + "sha256": "8db2595d8d8546bbb7bb7a6facf79ab72e8f88ee4ce6ec9cf255dbac8528013e", + "exit_code": 1, + "stdout": "incomplete", + "stderr": "" + }, + { + "tab": 1, + "kind": "cmd", + "variant": "remove-one-bare-cr", + "bytes": 261, + "sha256": "e2e797ab3c6434bb462b109f08f16e4966cf71df74558cc5ecf6c3906e4cf8ff", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + }, + { + "tab": 1, + "kind": "cmd", + "variant": "independent-output-removed", + "bytes": 230, + "sha256": "e7e16d6f14705c58c00f64d0f4183cfd6efa3a0c1a0e104c4242a4de75ce0b6a", + "exit_code": 1, + "stdout": "incomplete", + "stderr": "" + }, + { + "tab": 2, + "kind": "powershell", + "variant": "original", + "bytes": 4373, + "sha256": "06d376c5709d01185a5696726e5ed2a412184b5e1df886ac948c1ac64b349f4c", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + }, + { + "tab": 3, + "kind": "powershell", + "variant": "original", + "bytes": 4373, + "sha256": "06d376c5709d01185a5696726e5ed2a412184b5e1df886ac948c1ac64b349f4c", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + } + ] + }, + "fixed_replay": { + "product_source": "92eac12d5cd2868b469e8b9a10e68f5e20ee2cb0", + "failure_sha256": "7ccb0a90b526462a929cbebce42debccfd97b54676e54e0935fbf292826b5e5b", + "helper_sha256": "39dfeb0845e572ec842b7da09dc2b822ba221caa1414a6a386f066214eb4da15", + "probe_sha256": "e8f1f3d93d9af701244792e4dfda6ac2813ac9a65299a3a56cb230d6fed503e3", + "cases": [ + { + "tab": 0, + "kind": "cmd", + "variant": "original", + "bytes": 230, + "sha256": "68fadc3fc45b9fbaab78b7e1a55987f5fdc11e9a2abdbe39fc65135556703017", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + }, + { + "tab": 1, + "kind": "cmd", + "variant": "original", + "bytes": 262, + "sha256": "8db2595d8d8546bbb7bb7a6facf79ab72e8f88ee4ce6ec9cf255dbac8528013e", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + }, + { + "tab": 1, + "kind": "cmd", + "variant": "remove-one-bare-cr", + "bytes": 261, + "sha256": "e2e797ab3c6434bb462b109f08f16e4966cf71df74558cc5ecf6c3906e4cf8ff", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + }, + { + "tab": 1, + "kind": "cmd", + "variant": "independent-output-removed", + "bytes": 230, + "sha256": "e7e16d6f14705c58c00f64d0f4183cfd6efa3a0c1a0e104c4242a4de75ce0b6a", + "exit_code": 1, + "stdout": "incomplete", + "stderr": "" + }, + { + "tab": 2, + "kind": "powershell", + "variant": "original", + "bytes": 4373, + "sha256": "06d376c5709d01185a5696726e5ed2a412184b5e1df886ac948c1ac64b349f4c", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + }, + { + "tab": 3, + "kind": "powershell", + "variant": "original", + "bytes": 4373, + "sha256": "06d376c5709d01185a5696726e5ed2a412184b5e1df886ac948c1ac64b349f4c", + "exit_code": 0, + "stdout": "complete", + "stderr": "" + } + ] + }, + "regression": { + "red": { + "base_commit": "ab360c7aebeb8e9afb5e61d386081abd8e3e8278", + "helper_changed": false, + "tests_changed": true, + "files_sha256": { + "experiments/shell/transport_completion.hpp": "535ff47bfbdd1038dca22820b467d1ee0d1839a29be38cd750e4de49439b602f", + "experiments/shell/transport_completion_test.cpp": "1df5bbaddc0bdf1d063bd94708939688d7c2f32a9ca23cb7979b5709002dde3c", + "build/candidate/bin/Release/transport_completion_test.exe": "4ebcad595f55474a3602f33a0720550aba4de10aed512875a437324ce2ae9352", + "local/r88-restore-oracle/red-test.log": "724e968e4f09d21069d2fa3b5ec9bfc79eed48ed561ff947f9f9d67e9bcb2482" + } + }, + "red_exit_code": 1, + "red_error": "wrapped command echo must not hide later independent output and prompt", + "final_test_source_sha256": "3761c858c97e5975d51a5c552104ba8457a5183070b12c0f635a7da42647e80d", + "green_log_sha256": "2cbd854c42e58401a37020b1dd40d4a3f06cd63668c3d942a61da4498c38fce9", + "green_passed": true, + "note": "Red and green retain the exact wrapped_cmd trigger and single-CR control. Final tests additionally include one fresh-LF positive and three negative cases; complete test sources are not identical." + }, + "targeted": { + "method": "ShellTests.test_workspace_v2_multiple_shells_split_and_geometry_restore", + "passed": true, + "seconds": 10.901, + "log_sha256": "c9a30d2427e825ca926fd9cf2f3ac30732f375c89c707f96acf30a776a07ce27", + "cases": [ + { + "repeat": 0, + "mode": "save", + "sample_sha256": "704a24d77efe914364b1942fd416e839a4f5cdd6788585d272ca1ec72584e293", + "geometry_sha256": "5cc777f65d580599f8bda2d3e7e3d246b63aba19dba55a27e65d358709402638", + "layout_sha256": "7dca24d3d78fbbdf53784c68f808add4ca4c976db31cf3d5b85f4b95a1564440", + "result": { + "exit_code": 0, + "timed_out": false, + "job_after": { + "active": 0, + "total": 14, + "terminated": 0 + }, + "desktop_gone": true, + "job_after_cleanup": { + "active": 0, + "total": 14, + "terminated": 0 + } + } + }, + { + "repeat": 0, + "mode": "restore", + "sample_sha256": "c7edac02b5de9f0945766ae59cc20688b07f500556e697e11a4fbcbc163f7c55", + "geometry_sha256": "5cc777f65d580599f8bda2d3e7e3d246b63aba19dba55a27e65d358709402638", + "layout_sha256": "7dca24d3d78fbbdf53784c68f808add4ca4c976db31cf3d5b85f4b95a1564440", + "result": { + "exit_code": 0, + "timed_out": false, + "job_after": { + "active": 0, + "total": 14, + "terminated": 0 + }, + "desktop_gone": true, + "job_after_cleanup": { + "active": 0, + "total": 14, + "terminated": 0 + } + } + }, + { + "repeat": 0, + "mode": "clamped", + "sample_sha256": "19744ab851d4905387d37d639fa6406d50d2d4929f805a5e63a8df896d889ff5", + "geometry_sha256": "e1b9fdfa4c0be1cf1901dfc4678c2952f5be23b95ca1d2a434c92b17f5069ce0", + "layout_sha256": "e3ac37c9350b6b0158f9b95c199fb2e1683663d5c89e1b2c70e9a11e70e6efd3", + "result": { + "exit_code": 0, + "timed_out": false, + "job_after": { + "active": 0, + "total": 14, + "terminated": 0 + }, + "desktop_gone": true, + "job_after_cleanup": { + "active": 0, + "total": 14, + "terminated": 0 + } + } + }, + { + "repeat": 1, + "mode": "save", + "sample_sha256": "231e67a9e06720c61da7f82a56794192d6a5124cc80d645d59b27e2bd80c007e", + "geometry_sha256": "5cc777f65d580599f8bda2d3e7e3d246b63aba19dba55a27e65d358709402638", + "layout_sha256": "5364bdd865f1b515f64b040d88d1e576a54116929472718fa0a43a6c31db5021", + "result": { + "exit_code": 0, + "timed_out": false, + "job_after": { + "active": 0, + "total": 14, + "terminated": 0 + }, + "desktop_gone": true, + "job_after_cleanup": { + "active": 0, + "total": 14, + "terminated": 0 + } + } + }, + { + "repeat": 1, + "mode": "restore", + "sample_sha256": "c834a7430334cce1714c6df8a916e745bba8031762cd7711de3b9e99e08be04d", + "geometry_sha256": "5cc777f65d580599f8bda2d3e7e3d246b63aba19dba55a27e65d358709402638", + "layout_sha256": "5364bdd865f1b515f64b040d88d1e576a54116929472718fa0a43a6c31db5021", + "result": { + "exit_code": 0, + "timed_out": false, + "job_after": { + "active": 0, + "total": 14, + "terminated": 0 + }, + "desktop_gone": true, + "job_after_cleanup": { + "active": 0, + "total": 14, + "terminated": 0 + } + } + }, + { + "repeat": 1, + "mode": "clamped", + "sample_sha256": "a3c5d95d9167cf40185cd6214b6f16a6e5a5d384a69d42d36d706d61df85b230", + "geometry_sha256": "e1b9fdfa4c0be1cf1901dfc4678c2952f5be23b95ca1d2a434c92b17f5069ce0", + "layout_sha256": "815480efcb4523f66552fc0afcc8724f075ff1f3db1214d2cb9a2e2d380593ae", + "result": { + "exit_code": 0, + "timed_out": false, + "job_after": { + "active": 0, + "total": 14, + "terminated": 0 + }, + "desktop_gone": true, + "job_after_cleanup": { + "active": 0, + "total": 14, + "terminated": 0 + } + } + } + ], + "contract": "Original two rounds of save, ordinary restore, clamped restore; exact directories/version/membership/title/zoom/split/geometry/child dimensions and Job/desktop checks; original 30/40 second deadlines." + }, + "final_full_ctest": { + "log_sha256": "8fe637e73b7dbbc0aa5025ad8620933626ac80c42b09e715cd840bdff6a691fc", + "tests": [ + { + "name": "shell_launch", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "candidate_title", + "result": "passed", + "seconds": 0.7 + }, + { + "name": "candidate_reply_close", + "result": "passed", + "seconds": 0.35 + }, + { + "name": "runtime_observation", + "result": "passed", + "seconds": 1.52 + }, + { + "name": "ime_input_expectation", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "sent_message_wait", + "result": "passed", + "seconds": 0.27 + }, + { + "name": "find_bar", + "result": "passed", + "seconds": 0.36 + }, + { + "name": "renderer_metrics", + "result": "passed", + "seconds": 0.86 + }, + { + "name": "ime_context", + "result": "passed", + "seconds": 0.37 + }, + { + "name": "layout_state", + "result": "passed", + "seconds": 0.16 + }, + { + "name": "workspace_state", + "result": "passed", + "seconds": 0.36 + }, + { + "name": "transport_completion", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "scenario_tick_gate", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "candidate_core", + "result": "passed", + "seconds": 1.22 + }, + { + "name": "resize_core", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "history_core", + "result": "passed", + "seconds": 0.02 + }, + { + "name": "selection_core", + "result": "passed", + "seconds": 0.09 + }, + { + "name": "search_core", + "result": "passed", + "seconds": 0.13 + }, + { + "name": "paste", + "result": "passed", + "seconds": 0.02 + }, + { + "name": "sender_fence", + "result": "passed", + "seconds": 1.03 + }, + { + "name": "sender_fence_pipe", + "result": "passed", + "seconds": 0.38 + }, + { + "name": "clipboard_policy", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "keyboard", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "text_action_policy", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "candidate_resize_replay", + "result": "passed", + "seconds": 0.67 + }, + { + "name": "candidate_shell_tui", + "result": "failed", + "seconds": 31.3 + }, + { + "name": "core", + "result": "passed", + "seconds": 6.1 + }, + { + "name": "recovery", + "result": "passed", + "seconds": 9.92 + }, + { + "name": "measure", + "result": "passed", + "seconds": 3.93 + }, + { + "name": "binary_paths", + "result": "passed", + "seconds": 0.18 + }, + { + "name": "conpty_margin_contract", + "result": "passed", + "seconds": 0.28 + }, + { + "name": "benchmark_tools", + "result": "passed", + "seconds": 5.35 + }, + { + "name": "differential", + "result": "passed", + "seconds": 19.61 + }, + { + "name": "ime_inventory", + "result": "passed", + "seconds": 49.71 + }, + { + "name": "text_actions", + "result": "passed", + "seconds": 5.51 + }, + { + "name": "workflow_fixture", + "result": "passed", + "seconds": 22.78 + }, + { + "name": "workflow_sessions", + "result": "passed", + "seconds": 80.64 + }, + { + "name": "workflow_resources", + "result": "passed", + "seconds": 0.58 + }, + { + "name": "workflow_resource_phases", + "result": "passed", + "seconds": 4.34 + }, + { + "name": "workflow_system_content", + "result": "passed", + "seconds": 0.16 + }, + { + "name": "workflow_system_runner", + "result": "passed", + "seconds": 0.64 + }, + { + "name": "copy_error_frame", + "result": "passed", + "seconds": 0.14 + }, + { + "name": "paste_fence_evidence", + "result": "passed", + "seconds": 0.1 + }, + { + "name": "resize_trace", + "result": "passed", + "seconds": 0.11 + }, + { + "name": "research_guards", + "result": "passed", + "seconds": 5.01 + }, + { + "name": "receive", + "result": "passed", + "seconds": 0.22 + }, + { + "name": "conpty", + "result": "passed", + "seconds": 22.88 + }, + { + "name": "conpty_ctrl_c", + "result": "passed", + "seconds": 4.33 + }, + { + "name": "conpty_margin", + "result": "passed", + "seconds": 0.4 + }, + { + "name": "conpty_backend", + "result": "passed", + "seconds": 1.29 + }, + { + "name": "presentation", + "result": "passed", + "seconds": 4.11 + }, + { + "name": "shell", + "result": "passed", + "seconds": 93.71 + }, + { + "name": "selection_bytes", + "result": "passed", + "seconds": 3.66 + }, + { + "name": "selection_context", + "result": "passed", + "seconds": 3.76 + }, + { + "name": "raw_console_receiver", + "result": "passed", + "seconds": 0.38 + }, + { + "name": "paste_system", + "result": "passed", + "seconds": 8.31 + } + ], + "total": 56, + "passed": 55, + "failed": [ + "candidate_shell_tui" + ], + "seconds": 398.08, + "failure_stages": [ + 59 + ], + "full_acceptance": false, + "last_test_log_sha256": "35d684a3b3ec9d593cccc3243ea8a8d2e39a76fc0746c137e942f2d65ff2d75b", + "internal_skips": [ + { + "test": "test_actual_system_copy_paste_and_shortcuts_twice (experiments.shell.test_actions.ActionWindowTest.test_actual_system_copy_paste_and_shortcuts_twice)", + "reason": "actual system Copy/Paste requires a disposable hosted VM" + }, + { + "test": "test_suspended_target_is_reclaimed_if_job_assignment_fails (test_ui_r1.EvidenceBoundaryTests.test_suspended_target_is_reclaimed_if_job_assignment_fails)", + "reason": "opt-in pinned reference failure injection" + }, + { + "test": "test_mouse_selection_to_real_system_clipboard (experiments.shell.test_shell.ShellTests.test_mouse_selection_to_real_system_clipboard)", + "reason": "system copy UI gate requires a disposable hosted VM" + }, + { + "test": "test_system_clipboard_product_read_errors_cancel_and_close (experiments.shell.test_shell.ShellTests.test_system_clipboard_product_read_errors_cancel_and_close)", + "reason": "product clipboard read gate requires a disposable hosted VM" + }, + { + "test": "test_system_clipboard_shortcut_to_window_confirmation_and_receiver (experiments.shell.test_shell.ShellTests.test_system_clipboard_shortcut_to_window_confirmation_and_receiver)", + "reason": "real system clipboard UI gate requires a disposable hosted VM" + }, + { + "test": "test_real_system_copy_shortcuts_for_styled_fixture_twice (experiments.shell.test_selection_bytes.SelectionBytesWindowTest.test_real_system_copy_shortcuts_for_styled_fixture_twice)", + "reason": "system CF requires a disposable hosted VM" + }, + { + "test": "test_real_system_copy_and_edit_context_twice (experiments.shell.test_selection_context.SelectionContextWindowTest.test_real_system_copy_and_edit_context_twice)", + "reason": "real CF/EDIT Copy requires a disposable hosted VM" + }, + { + "test": "test_real_system_clipboard (experiments.shell.test_paste.PasteTests.test_real_system_clipboard)", + "reason": "Private window station OpenClipboard denied (5); system API gate remains unverified." + } + ], + "log_encoding_note": "Localized CTest date header is not UTF-8; only ASCII skip fields are extracted.", + "shell_unittest": { + "run": 40, + "passed": 37, + "errors": 0, + "skipped": 3, + "seconds": 93.494 + }, + "optional_trace_note": "The .5 trace executable is now built; four previously skipped differential classes executed. Eight remaining internal skips are listed separately." + }, + "excluded_overlapping_build": { + "reason": "Targeted method started before the changed shell finished linking. Full CTest also started before overall build completion; retain both only as diagnostics and repeat after completed build.", + "targeted_log_sha256": "410952fb9bc506d798b53102a9c96c97e50f79fe10a8baaebf4bf524537bb8fb", + "diagnostic_full_ctest": { + "log_sha256": "7f5b1cd6692cd76112c71f7bb906684d25a495d24b3252c1481c07b9eba454c4", + "tests": [ + { + "name": "shell_launch", + "result": "passed", + "seconds": 0.06 + }, + { + "name": "candidate_title", + "result": "passed", + "seconds": 1.03 + }, + { + "name": "candidate_reply_close", + "result": "passed", + "seconds": 0.37 + }, + { + "name": "runtime_observation", + "result": "passed", + "seconds": 1.54 + }, + { + "name": "ime_input_expectation", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "sent_message_wait", + "result": "passed", + "seconds": 0.29 + }, + { + "name": "find_bar", + "result": "passed", + "seconds": 0.41 + }, + { + "name": "renderer_metrics", + "result": "passed", + "seconds": 1.24 + }, + { + "name": "ime_context", + "result": "passed", + "seconds": 0.33 + }, + { + "name": "layout_state", + "result": "passed", + "seconds": 0.15 + }, + { + "name": "workspace_state", + "result": "passed", + "seconds": 0.43 + }, + { + "name": "transport_completion", + "result": "passed", + "seconds": 0.02 + }, + { + "name": "scenario_tick_gate", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "candidate_core", + "result": "passed", + "seconds": 1.21 + }, + { + "name": "resize_core", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "history_core", + "result": "passed", + "seconds": 0.02 + }, + { + "name": "selection_core", + "result": "passed", + "seconds": 0.09 + }, + { + "name": "search_core", + "result": "passed", + "seconds": 0.13 + }, + { + "name": "paste", + "result": "passed", + "seconds": 0.02 + }, + { + "name": "sender_fence", + "result": "passed", + "seconds": 1.03 + }, + { + "name": "sender_fence_pipe", + "result": "passed", + "seconds": 0.36 + }, + { + "name": "clipboard_policy", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "keyboard", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "text_action_policy", + "result": "passed", + "seconds": 0.01 + }, + { + "name": "candidate_resize_replay", + "result": "passed", + "seconds": 0.79 + }, + { + "name": "candidate_shell_tui", + "result": "failed", + "seconds": 30.49 + }, + { + "name": "core", + "result": "passed", + "seconds": 6.25 + }, + { + "name": "recovery", + "result": "passed", + "seconds": 9.96 + }, + { + "name": "measure", + "result": "passed", + "seconds": 4.3 + }, + { + "name": "binary_paths", + "result": "passed", + "seconds": 0.2 + }, + { + "name": "conpty_margin_contract", + "result": "passed", + "seconds": 0.28 + }, + { + "name": "benchmark_tools", + "result": "passed", + "seconds": 5.33 + }, + { + "name": "differential", + "result": "passed", + "seconds": 3.35 + }, + { + "name": "ime_inventory", + "result": "passed", + "seconds": 51.23 + }, + { + "name": "text_actions", + "result": "passed", + "seconds": 5.57 + }, + { + "name": "workflow_fixture", + "result": "passed", + "seconds": 22.66 + }, + { + "name": "workflow_sessions", + "result": "passed", + "seconds": 82.77 + }, + { + "name": "workflow_resources", + "result": "passed", + "seconds": 0.53 + }, + { + "name": "workflow_resource_phases", + "result": "passed", + "seconds": 4.31 + }, + { + "name": "workflow_system_content", + "result": "passed", + "seconds": 0.16 + }, + { + "name": "workflow_system_runner", + "result": "passed", + "seconds": 0.64 + }, + { + "name": "copy_error_frame", + "result": "passed", + "seconds": 0.14 + }, + { + "name": "paste_fence_evidence", + "result": "passed", + "seconds": 0.11 + }, + { + "name": "resize_trace", + "result": "passed", + "seconds": 0.12 + }, + { + "name": "research_guards", + "result": "passed", + "seconds": 4.97 + }, + { + "name": "receive", + "result": "passed", + "seconds": 0.21 + }, + { + "name": "conpty", + "result": "passed", + "seconds": 23.52 + }, + { + "name": "conpty_ctrl_c", + "result": "passed", + "seconds": 4.36 + }, + { + "name": "conpty_margin", + "result": "passed", + "seconds": 0.4 + }, + { + "name": "conpty_backend", + "result": "passed", + "seconds": 1.23 + }, + { + "name": "presentation", + "result": "passed", + "seconds": 4.08 + }, + { + "name": "shell", + "result": "passed", + "seconds": 94.42 + }, + { + "name": "selection_bytes", + "result": "passed", + "seconds": 3.59 + }, + { + "name": "selection_context", + "result": "passed", + "seconds": 3.86 + }, + { + "name": "raw_console_receiver", + "result": "passed", + "seconds": 0.42 + }, + { + "name": "paste_system", + "result": "passed", + "seconds": 10.02 + } + ], + "total": 56, + "passed": 55, + "failed": [ + "candidate_shell_tui" + ], + "seconds": 389.17, + "failure_stages": [ + 59 + ], + "full_acceptance": false, + "usable_for_acceptance": false + }, + "usable_for_acceptance": false + }, + "limits": [ + "Raw original transports and workspace files remain local; public regression source contains only fixed synthetic commands and no machine path.", + "This corrects a test completion oracle, not a demonstrated product output-loss defect.", + "Separate configuration results and unresolved #52/#63/#87 remain independent; later green runs do not explain earlier failures.", + "Real CF/IME, actual presentation, performance, WindTerm equivalence and full R2 acceptance are not supplied by this fix." + ], + "presented_done": null, + "performance_acceptance": false, + "windterm_runtime_equivalence": false, + "full_r2_verified": false +} diff --git a/experiments/shell/transport_completion.hpp b/experiments/shell/transport_completion.hpp index e038584c..170d2f9e 100644 --- a/experiments/shell/transport_completion.hpp +++ b/experiments/shell/transport_completion.hpp @@ -10,10 +10,11 @@ namespace tf_shell_test { // column-one CUP. This is a record boundary, without assuming the initial cursor // row or claiming that the marker still occupies a separate visible screen row. // Complete CSI envelopes are omitted without interpreting their semantics. -// A command-editor BS before output invalidates that record until a real LF; +// A command-editor BS or nonempty-record CR before output invalidates that +// record until a real LF; // it cannot erase an echo prefix or splice a marker. Unknown ESC forms, // malformed/incomplete envelopes and other controls remain unproven. -// A bare CR is harmless only in an empty, unedited record after an observed +// A bare CR leaves an empty, unedited record unchanged after an observed // boundary and before marker output. It cannot discard text or end a record. // ShellWindow retains its independent 8192-byte observation cap. inline bool transport_output_completed(std::string_view raw, std::string_view marker) { @@ -75,10 +76,13 @@ inline bool transport_output_completed(std::string_view raw, std::string_view ma if(!terminated) return false; } else return false; } else if(byte=='\r') { - // Only CRLF completes literal text. An empty redraw before the - // marker leaves the record empty and still needs fresh output. + // Only CRLF completes literal text. A wrapped command echo may use + // bare CR/CUP, but that edited record cannot supply marker output. + // Only a later real LF permits a fresh independent output record. if(i==raw.size() || raw[i]!='\n') { - if(!record_boundary || !line.empty() || !literal_line || output_seen) return false; + if(output_seen) return false; + if(!line.empty() || !literal_line) literal_line=false; + else if(!record_boundary) return false; } } else if(byte=='\n') { end_line(); diff --git a/experiments/shell/transport_completion_test.cpp b/experiments/shell/transport_completion_test.cpp index 70a412af..3179ccb6 100644 --- a/experiments/shell/transport_completion_test.cpp +++ b/experiments/shell/transport_completion_test.cpp @@ -31,6 +31,23 @@ int main() { line+"TF>",marker),"command redraw BS before a fresh literal output line does not poison later records"); check(transport_output_completed("echo old\b\r\n"+line+"TF_PS_MAJOR=5\r\nTF> ",marker), "fresh output remains independent of a prior edited command record"); + const std::string wrapped_cmd="\x1b[2;4Hf\x1b[2;5H\x1b[2;5Hor %I in (\"%CD%\") do @echo T \r" + "\x1b[3;1H\x1b[3;1HF_CMD_DIR=%~nxI\x1b[3;16H\x1b[3;16H\r\n"+ + title+"\x1b\\"+line+"\x1b]0;cmd.exe\x1b\\\r\nTF>"; + auto no_echo_cr=wrapped_cmd; + no_echo_cr.erase(no_echo_cr.find("\r\x1b[3;1H"),1); + check(transport_output_completed(no_echo_cr,marker), + "removing only the wrapped command echo CR isolates its rejection"); + check(transport_output_completed(wrapped_cmd,marker), + "wrapped command echo must not hide later independent output and prompt"); + check(transport_output_completed("echo old\rredraw\r\n"+line+"TF> ",marker), + "real LF separates an edited echo from new literal output"); + check(!transport_output_completed("echo \r\x1b[3;1H"+marker+"\x1b[4;1HTF>\r\nTF>",marker), + "CUP cannot recover a CR-edited record to invent output"); + check(!transport_output_completed("echo \r\x1b[3;1H"+marker+"\r\nTF>",marker), + "LF cannot retroactively turn a CR-edited echo into output"); + check(!transport_output_completed("echo \r\x1b[3;1Htail\r\n"+line,marker), + "a discarded wrapped echo still requires a fresh prompt"); const std::string save="\x1b[?25l\x1b[1;3H> \x1b[93mWrite-Output \x1b[36m" "'TF_SAVE_PS' \x1b[m\r\n" "\x1b[63X\x1b[63C\r\x1b[?25hTF_SAVE_PS\r\nTF> ";