Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ termforge_warnings(search_test)

add_executable(paste_test experiments/shell/paste_test.cpp)
termforge_warnings(paste_test)
add_executable(sender_fence_test experiments/shell/sender_fence_test.cpp)
termforge_warnings(sender_fence_test)
find_package(Threads REQUIRED)
target_link_libraries(sender_fence_test PRIVATE Threads::Threads)
add_executable(clipboard_policy_test experiments/shell/clipboard_policy_test.cpp)
termforge_warnings(clipboard_policy_test)
add_executable(keyboard_test experiments/shell/keyboard_test.cpp)
Expand Down Expand Up @@ -293,6 +297,8 @@ if(BUILD_TESTING)
add_test(NAME selection_core COMMAND selection_test)
add_test(NAME search_core COMMAND search_test)
add_test(NAME paste COMMAND paste_test)
add_test(NAME sender_fence COMMAND sender_fence_test)
set_tests_properties(sender_fence PROPERTIES TIMEOUT 10)
add_test(NAME clipboard_policy COMMAND clipboard_policy_test)
add_test(NAME keyboard COMMAND keyboard_test)
add_test(NAME text_action_policy COMMAND text_action_policy_test)
Expand Down
1 change: 1 addition & 0 deletions docs/EVIDENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ R1 固定总出口的源码为 `ce9b24d`,早期 `2dc8d6d` / `9b16acc` 仍分
| 纯 AST 夹具的生命周期记录 | [#40](https://github.com/JavaZeroo/termforge/issues/40)、[计时、进度与回收验证](../research/ime/results/2026-10-26-inventory-lifecycle/validation.json)、[专用 CI 40253727745](https://github.com/JavaZeroo/termforge/actions/runs/40253727745) | 旧 10 秒 AST 夹具及专用 CI 记录启动、AST 和 Job0;原超时根因未确定。诊断增强见 #40 阶段保留,不由一次 CI 成功结项。 |
| 原生 margin 逐字段合同与修复候选(#56 仍开放) | [合同、源码与路径](research/conpty-native-margin-path.md)、[独立 oracle](../experiments/conpty/margin_contract.py)、[固定运行](../experiments/conpty/results/2026-10-26-native-margin-path/validation.json) | 四阶段文字/格属性/光标独立判据;系统与官方原生 final 仍红,官方80列两次原5秒生命周期失败保留。共享单 margin 源码支持小 MIT fork 候选;patch 仅可应用,未编译、未运行、不计修复。 |
| ConPTY 系统/固定官方后端的同源 margin A/B(#41、#47 未关闭) | [合同与第一方来源](research/conpty-margin-backends.md)、[固定 175B 与 16 case 结果](../experiments/conpty/results/2026-10-26-margin-backends/validation.json) | 相同 175B、两网格/两 mode/两 fresh:系统末端 margin 错,固定官方后端的末端正确;CHAR_INFO 仍错。禁用 VT 由窄屏反例拒绝;仅诊断可行性,不证明 PR #50 或 main 联合整合通过。 |
| 实验输入 worker 持块与停止(#62) | [sender fence 合同](research/sender-fence.md)、[固定源码与实际字段](../experiments/shell/results/2026-10-26-sender-fence/validation.json) | `519a3f3` 的系统/官方各两进程、每次 stop/cancel/竞争,共 12 条实际 worker 记录,均 join/Job0;另有各一次原 focus 单测和各 2/2 纯 CTest。明确修正旧 never-read/output-first 不能保证 16KiB 的夹具假设,同 EXE 旧顺序仍红。实现仅在 PR #50 实验整合,main 未包含;probe 未链接候选 VT,纯 EOF 为模拟,#53 UI/3MB/768B/八会话及完整官方矩阵未验收。 |
| 工作区几何与交互的固定记录 | [#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、期限、负载及恢复断言。仅修夹具,不宣称修复产品恢复。 |
Expand Down
2 changes: 1 addition & 1 deletion docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,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)推进 R2 新终端能力 | [固定来源](../experiments/candidates/alacritty/PROVENANCE.md)、[适配边界](../experiments/core/CANDIDATE.md)与 [#39 字素合同](research/streaming-graphemes.md);候选正确性通过不关闭系统 ConPTY 或 R2 父项 |
| 实验分支:`termforge.4` + 固定官方 ConPTY | [PR #50(Draft)](https://github.com/JavaZeroo/termforge/pull/50),联合源码 `3e5b96d` 已重建并[冻结真实基线](research/joint-conpty-baseline.md),尚未合并或通过产品整体验收 | [#47](https://github.com/JavaZeroo/termforge/issues/47) 跟踪后端整合;终端 margin 与原生状态分列。[resize 残尾 #51](https://github.com/JavaZeroo/termforge/issues/51)、[Console-width Vim #52](https://github.com/JavaZeroo/termforge/issues/52)、[未完成粘贴的确定性取消夹具 #53](https://github.com/JavaZeroo/termforge/issues/53)仍开放,现有 completed 观察不能证明部分发送取消通过或产品 Cancel 故障;另有 worker gate [#62](https://github.com/JavaZeroo/termforge/issues/62) 和工作区 [#63](https://github.com/JavaZeroo/termforge/issues/63) 回归 |
| 实验分支:`termforge.4` + 固定官方 ConPTY | [PR #50(Draft)](https://github.com/JavaZeroo/termforge/pull/50),联合源码 `3e5b96d` 已重建并[冻结真实基线](research/joint-conpty-baseline.md),尚未合并或通过产品整体验收 | [#47](https://github.com/JavaZeroo/termforge/issues/47) 跟踪后端整合;终端 margin 与原生状态分列。[resize 残尾 #51](https://github.com/JavaZeroo/termforge/issues/51)、[Console-width Vim #52](https://github.com/JavaZeroo/termforge/issues/52)、[未完成粘贴的确定性取消夹具 #53](https://github.com/JavaZeroo/termforge/issues/53)仍开放,现有 completed 观察不能证明部分发送取消通过或产品 Cancel 故障;worker gate [#62](https://github.com/JavaZeroo/termforge/issues/62) 已有[独立夹具修正与双后端实际 worker 验证](research/sender-fence.md),默认产品路径不启用 fence,也不替代 #53 的 UI 取消/关闭;工作区 [#63](https://github.com/JavaZeroo/termforge/issues/63) 回归仍开放 |

以下能力默认指已合并实现;某个配置的通过结果不能转用于另一个配置。R1 的真实系统 CF/拼音验收属于固定自研核心配置,不外推到候选 `.4` 或实验后端联合配置。

Expand Down
2 changes: 1 addition & 1 deletion docs/milestones/R2-local-terminal.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ flowchart LR

## 下一批的任务边界

1. **优先完成联合基线。** 从主线与 Draft 的明确身份整合,不在旧配置上连续堆修补丁。#51–#53 可以用原冻结输入独立定位,但最终修复验收必须回到联合基线;不会因一次未复现自动获得“已修复”的因果结论。
1. **在已冻结基线上逐项闭合后端回归。** #55 已交付含红的真实基线;接续 #51–#53 与 #63 的独立失败。#62 的[真实 writer 持块、取消与停止夹具](../research/sender-fence.md)不降低原 4MiB/16KiB/期限,下一步把默认关闭的 fence 接到 #53 原 UI/3MB/八会话入口;这不代表这些 UI 路径已通过。#51–#53 可以用原冻结输入独立定位,最终修复验收须在联合配置重建;一次未复现不自动构成因果修复。
2. **并行处理平台语义与性能。** [原生语义处理路径 #56](https://github.com/JavaZeroo/termforge/issues/56)先明确 #41 原合同需要什么、哪些路径可支持;保留必要的上游或独立实现工作,不用“平台不同”豁免缺口。#54 现在就冻结重复方法、完成端点和预算决定程序,再定位吞吐成本;不等到 #34 才补性能。
3. **在主线推进独立行为合同。** #29 核对极窄/极短、软硬行、历史/淘汰、选择/Find、连续 resize 和 child ack;#30 核对 IME 组合/提交/取消与输出/resize/切换、应用键盘/粘贴接收、实际复制及同次八会话。已验收的 #39 只提供首批字素基础,最终配置的交叉验收仍需执行。
4. **补终端模式和应用矩阵。** #27 明确 DECOM/DECAWM、pending-wrap、保存恢复、异常序列与 margin×resize;#28 先固定应用版本/入口/动作及协议字节预期,再逐应用完成进入、操作、resize、退出、主屏恢复。Vim 的一个修复不替代完整 TUI 验收。
Expand Down
63 changes: 63 additions & 0 deletions docs/research/sender-fence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 实际输入 worker 的持块合同与 sender fence

本合同对应 [#62](https://github.com/JavaZeroo/termforge/issues/62),为 [#53](https://github.com/JavaZeroo/termforge/issues/53)提供可复用的协调机制。**实现属于 `fix/conpty-backend-r47` / [Draft #50](https://github.com/JavaZeroo/termforge/pull/50) 的实验整合,尚未进入 main。** 固定运行源码为 `519a3f37d52983062cd99b7efd805f183961fa4d`;完整 source/tree/blob、实际 EXE、官方后端文件对、原始日志 SHA 和逐字段结果见[验证记录](../../experiments/shell/results/2026-10-26-sender-fence/validation.json)。这是实际 `InputQueue` / `PasteTransfer` / ConPTY worker 的限定验证,不是 UI、VT 或操作系统背压验收。

## 修正的夹具假设

旧夹具先启动输出洪流并将 reader 持在 gate,再向完全不读输入的 child 发送 4MiB ASCII。它要求观察到 writer 已提交至少 16KiB,但固定官方后端的一次实际拒绝状态是 `sent=5120 / accepted=6144 / in_flight=1024`,未达到原门槛。不能假设所有宿主都能在 child 不读且输出被持住时预接收 16KiB;本批没有测定内核或宿主缓冲容量,也没有证明其是唯一影响因素。

原 `af563ba` 的 focus 单测真实失败及只有 EXE 身份的 `2ac023b…` 诊断保留;最终同一 EXE 的 `--ungated-writer-observation` 仍按旧顺序返回 2,并再次给出上述低 sent 状态。**没有把旧顺序改写为已通过。** 首次 Python 准备缺少 `termforge_shell.exe`、运行零项测试,单独归为构建前置失败,不计产品失败。缺少固定源码绑定的早期 WIP 绿色不计最终验证。

## 新的明确顺序

4MiB 请求、真实 1024B 分块、16KiB 已发送门槛、reader/output gate、resize 与回收检查保留。夹具明确改变交错顺序:

1. child 用实际控制台读取核对恰好 16KiB `a`,之后不再读输入;只在核对完成后设置独立 primed event。
2. 原 writer 经真实 `take_chunk()` 领取第 17 块,在 queue 发布 `in_flight=1024` 并解锁后,由 sender fence 持住。此时真实计数为 `sent=16384 / accepted=17408 / total=4194304`。
3. parent 同时确认 held 状态和 child primed event,再开启原 flood phase、使 reader 进入原输出 gate。
4. 执行真实 stop、cancel 或 cancel/stop 竞争;继续原 resize generation、child 实际尺寸 102×42、自然退出及自有 Session Job0 检查。

sender fence 只能固定达到门槛后的观察,不能使原来在门槛之前阻塞的 OS 写入自行前进。held 表示 writer 拥有一块真实 payload,不表示 `WriteFile` 已进入或被系统阻塞。输出 gate 的记录来自 reader callback 进入;本批没有独立 flood 字节计数或实际呈现端点。

## 生命周期与接口

`SenderFence` 是绑定单次 transfer 的测试控制面,普通产品 `InputQueue::begin_paste(transfer)` 默认不启用;队列探针显式传入 fence。构造时固定 transfer 身份、非零 generation 和绝对 deadline,`begin_paste(transfer, fence)` 在通知 writer 前完成单次 admission。绑定不同 transfer、重复 admission、错误 ticket、未 held 就 release、重复 release 和过期 release 均被拒绝。

- `snapshot(ticket)` 按值读取 held 状态及真实 progress;不读取或复制输入正文。
- `release(ticket)` 只允许匹配的 held ticket 在 deadline 前继续发送,不生成写确认。
- `InputQueue::cancel_paste()` 先调用真实 `PasteTransfer::cancel()`,再通知 fence;已领取块继续原 `Session::send → WriteFile → acknowledge_written → finish_chunk`,最终取消保持 `sent==accepted`。
- `InputQueue::stop()` 先发布 stopping 并唤醒 fence,再沿原取消同步 I/O 与 join 路径退出。writer 醒来后重新检查 stopping;尚未提交的持块由原 writer failure 清理,不能伪造 ack 或直接当作已发送。
- `abort(ticket, control_eof)` 将控制面中止表现为失败;本批 EOF 仅是纯协议中的方法调用模拟,没有执行实际 IPC EOF。

等待 fence 时不持 queue mutex;cancel/stop 在释放 queue mutex 后通知 fence,防止与 join 形成锁环。`CancelSynchronousIo` 本身不能唤醒 condition-variable wait。fence 强持有绑定 transfer,writer 和 queue 持有 fence 到等待/退出结束。

达到持块、child primed、reader gate 及取消完成的观察共同使用原 3 秒绝对期限;没有每阶段重新延长该观察期限。其他既有 ready、resize、child 尺寸及退出等待分别保留 3 秒,原 Python probe 进程外层仍为 10 秒。纯协议缺 GO 使用 1 秒绝对 deadline,单独证明有限等待;这些带同步的运行不是性能样本。

## 固定结果与计数

最终原始批次有**两种后端各两次 probe 进程运行,每次实际执行三个 worker 动作,共 12 条逐字段审计记录**。原始 launcher 标签 `held-stop-0/1` 不表示只运行 stop。另有两种配置各一次原 focus Python 单测通过,单独记录,不重复并入上述 12 条矩阵。两种配置的 `paste` / `sender_fence` CTest 各 2/2。

| 动作 | 动作前 sent / accepted / in_flight | 动作后 sent / accepted / in_flight | 实际状态与回收 |
|---|---|---|---|
| stop | 16384 / 17408 / 1024 | 16384 / 17408 / 0 | failed,retained capacity 15,Job0 |
| cancel | 16384 / 17408 / 1024 | 17408 / 17408 / 0 | cancelled,retained capacity 15,Job0 |
| cancel/stop 竞争 | 16384 / 17408 / 1024 | 本批为 16384 / 17408 / 0 | 本批均由 stop 获胜、failed、Job0;不能宣称两个交错都被实际观测 |

所有正例保持 input join、resize working/pending/completed generation 1/3/3 和 child 102×42;这些 generation 字段属于 **resize worker**,不是 sender ticket 的独立运行日志。官方配置的构建定义及固定包选择 Console flags24,系统配置 flags0;worker JSON 没有独立输出 flags,证据来源在验证记录中分列。

`shell_queue_probe` 没有链接候选 VT 核心。构建目录叫 `candidate` / `candidate-system`,以及适配开关为 ON,均不能把该结果扩大为候选 VT、Unicode 或 TUI 验收。

## 复验与剩余边界

在已经明确配置并按贡献指南完成构建的目录运行:

```powershell
cmake --build build/candidate --config Release --target shell_queue_probe paste_test sender_fence_test
ctest --test-dir build/candidate -C Release -R '^(paste|sender_fence)$' --no-tests=error --output-on-failure
$env:TERMFORGE_BIN_DIR = (Resolve-Path build/candidate/bin/Release).Path
python -m unittest experiments.shell.test_shell.ShellTests.test_queues_apply_bounded_backpressure_and_reject_input -v
```

系统配置单独使用对应构建目录,不能复用另一 EXE 的身份。旧顺序诊断使用 `shell_queue_probe --ungated-writer-observation`,由 10 秒 subprocess 监督,保留预期 return2 与具体进度;不能将它作为需要重跑取绿的产品测试。

#53 的真实 UI cancel/close、原 3,000,000B 汉字负载、768B receiver checkpoint、真实 flood、完整输入前缀及同次八会话尚未由本批验收。后续必须在发送前预绑定 fence,并让真实 UI 取消进入 queue 的取消通知入口;不能把本夹具额外读取 16KiB 的 priming 原样移到必须保持 768B checkpoint 的 #53。完整官方回归、长期资源、呈现、平台和 WindTerm 性能差距继续独立处理。
1 change: 1 addition & 0 deletions experiments/shell/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ R1 的 [#12–#17 限定合同](../../docs/milestones/R1-local-text.md)和 [#18
- ConPTY 输出线程将最多 64 KiB 的读取块放入 256 KiB 队列;满时等待窗口消费,正常运行不丢弃字节。
- UI 每个 16 ms 定时消息以 8 KiB 小块消费,最多 64 KiB;块间检查 4 ms 预算,随后发布一次快照。单次 feed、快照和绘制仍可能超过预算,它不是硬实时保证。解析和快照发布同属 UI 线程;dirty 范围包含内容与旧/新光标行,多次失效可合并为一次 WM_PAINT。
- 输入写线程独立服务至多 16 KiB 的队列,每条消息不超过 1 KiB。UI 不等待 WriteFile;容量满时拒绝该次输入并发出提示,不宣称输入已成功。关闭期间停止接收新输入。
- PR #50 实验分支的原生 worker 测试可显式预绑定 [sender fence](../../docs/research/sender-fence.md),main 尚未包含:仅在真实已提交至少 16KiB、领取下一块并发布 in-flight 后持住 writer,cancel/stop 使用独立唤醒路径。普通产品默认关闭。队列探针先让 child 核验恰好 16KiB 后停止读,再启动原 flood/output gate;这是对宿主预接收容量假设的明确夹具修正,旧顺序可用 `--ungated-writer-observation` 保留。两种后端实际 stop/cancel/竞争与纯协议结果见[固定验证](results/2026-10-26-sender-fence/validation.json),不代表 OS 写阻塞、候选 VT 或 #53 的 UI/3MB/768B 工作流通过。
- resize 由独立 worker 执行,最多一个在途和一个合并请求;UI 先更新核心与快照并继续消费字节。关闭在回收 ConPTY 之前 join 此 worker。字节流没有 resize 世代边界,不保证所有中间帧及历史与 ConPTY 自身重排完全一致。
- 关闭工作在后台执行,UI 继续消费尾部输出;停止输入写入并反复取消该线程的同步 I/O,终止本会话 Job,关闭 ConPTY,等待读取线程退出。队列排空后执行 `finish()`、提交最终画面并销毁窗口。只终止自有 Job 内的进程,包括 shell 留下的后代。
- 正常 `exit 37` 保留实际退出码 37;关闭正在输出的会话通过 Job 取消。外部自动监督器另建拥有范围明确的 Job:宿主收到 `GO` 前不创建 shell,超时后回收整个自有树。
Expand Down
Loading
Loading