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
2 changes: 1 addition & 1 deletion .github/workflows/core-candidate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
- name: Build native measurement
run: cmake --build build --config Release --target core_measure
- name: Build and test candidate C++ adapter
run: cmake --build build --config Release --target candidate_core_test && ctest --test-dir build -C Release -R candidate_core --output-on-failure
run: cmake --build build --config Release --target candidate_core_test workflow_checkpoint_test && ctest --test-dir build -C Release -R "^(candidate_core|workflow_checkpoint)$" --no-tests=error --output-on-failure
- name: Verify resize trace and actual replay input rejection
run: cmake --build build --config Release --target candidate_resize_replay && ctest --test-dir build -C Release -R "^(resize_trace|candidate_resize_replay)$" --no-tests=error --output-on-failure
- name: Build and test candidate shell on Windows
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,13 @@ if(BUILD_TESTING)
add_executable(transport_completion_test experiments/shell/transport_completion_test.cpp)
termforge_warnings(transport_completion_test)
add_test(NAME transport_completion COMMAND transport_completion_test)
add_executable(workflow_checkpoint_test experiments/shell/workflow_checkpoint_test.cpp)
target_link_libraries(workflow_checkpoint_test PRIVATE termforge_core)
termforge_warnings(workflow_checkpoint_test)
if(TERMFORGE_BUILD_CANDIDATE_ADAPTER)
termforge_candidate_shell(workflow_checkpoint_test)
endif()
add_test(NAME workflow_checkpoint COMMAND workflow_checkpoint_test)
add_executable(scenario_tick_gate_test experiments/shell/scenario_tick_gate_test.cpp)
termforge_warnings(scenario_tick_gate_test)
add_test(NAME scenario_tick_gate COMMAND scenario_tick_gate_test)
Expand Down
3 changes: 2 additions & 1 deletion docs/EVIDENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ 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 旧因未闭合。构建重叠结果明确排除。 |
| 窄列命令回显与恢复完成(#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 旧因未闭合(#87 后续见下一行)。构建重叠结果明确排除。 |
| 替换会话完整记录检查点(#87) | [机制、因果与边界](research/workflow-record-checkpoint.md)、[固定源码及原两轮验证](../experiments/shell/results/2026-10-27-workflow-record-checkpoint/validation.json) | 旧判据在真实消费半行时采样而红,同 session 后续字节补齐;被动等待方案因输出结束而红。默认关闭的有界 LF 检查点受控通过,最终 c662011 两轮原八会话及关闭 guard 通过;完整官方 56/57、8 项内部 skip,Vim59 仍红。历史两份 native 后续缺口、诊断 trace 截断及未复现分别保留。 |
| 工作区几何与交互的固定记录 | [#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 @@ -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 两轮及六组原生样本通过;[#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 及完整后端仍开放;旧残尾、超时和组合失败记录保留 |
| 实验分支:`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)的原保存/恢复/钳制分别通过;[#87 完整记录检查点](research/workflow-record-checkpoint.md)有受控旧红/新绿及最终同源码两轮原八会话 data-only。最新官方完整回归 56/57、8 项内部 skip,[Vim #52](https://github.com/JavaZeroo/termforge/issues/52)仍红,#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` 或实验后端联合配置。

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 @@ -44,7 +44,7 @@ flowchart LR

## 下一批的任务边界

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 组合独立验收。各回归可用原冻结输入独立定位,最终修复验收须在联合配置重建;一次未复现不自动构成因果修复。
1. **在已冻结基线上逐项闭合后端回归。** #55 已交付含红的真实基线;接续 #52、#63 的独立失败。#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)的原保存/恢复/钳制限定回归通过;[#87 完整记录检查点](../research/workflow-record-checkpoint.md)已具有受控因果红绿及同源码两轮原八会话 data-only。完整官方回归中的 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 验收。
Expand Down
45 changes: 45 additions & 0 deletions docs/research/workflow-record-checkpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 替换会话的完整记录检查点

原八会话 data-only 工作流的 `cycle-eight` 快照必须在替换会话仍持续输出时取得,并满足既有精确文字、身份及回收断言。[#87](https://github.com/JavaZeroo/termforge/issues/87) 修正的是合成测试的消费与采样协调;正常产品输出默认不启用检查点,Python oracle、生产输入和期限保持不变。

## 失败及因果证据

历史两份失败在 F5 第 127 条记录只得到 12 个点,独立 oracle 要求 35 个点;源已有 16384 B,队列还有 8217 B。原件仍可离线重现 `replacement core payload/role mismatch`。那两次没有保存后续 native 运输,不能追溯宣称已证明其完整性。

原 stage35 只要求 source≥4096 B 和任意编号前缀,而消费者一次最多取 8192 B。实际 READY 前缀 25 B 与两个 4096 B 源块可以合并为 8217 B;重分片回放在 8192 B 处产生相同的第 127 条半行,余下 25 B 补齐它。这证明了机制,不等于重现历史 GUI 调度。最初四次有界活体观察均未捕获半行,这些未复现结果单列保留。

随后用同一诊断 EXE 做受控旧判据/新判据对照:在第一轮 F5 替换输出前保持消费者,源到达 16384 B 后只放行一次真实 8192 B 消费;保存状态,再继续原工作流。没有改生产字节、4096 B 分块、20 ms 间隔、32000 条/2048000 B、五轮替换、精确 oracle 或期限。

- 旧判据在第 117 条中途采样,原 oracle 真红。相同 session 后续实际 39 B 补齐该条,运输前缀保持;独立候选核心回放得到完整原文字。
- 仅被动等待空行的中间方案仍失败:持续消费跳过边界,直到生产结束才采样,原 oracle 报 `replacement output not active`。这不是可接受修复。
- 新检查点在实际 LF 后持有快照,通过原 oracle;该检查点源为 241664 B,小于 2048000 B,`fixture_running=true`、`output_done=false`。同 session 的实际后续 41 B 补齐受控半行。两次运行各有自己的真实运输,未声称它们逐字节相同。

诊断记录上限为 128 KiB/1024 events。新方案的后续 collected 运输超出字节上限,但所需补齐字节在保存的前缀内;held/checkpoint 未溢出。这里只证明该前缀内的补齐,不声称完整后续运输已捕获。受控消费者调度仅用于因果实验,最终原场景回归移除诊断调度和记录。

## 最终机制与边界

`OutputRecordCheckpoint` 仅由 UI 线程显式启用。已有空行边界时立即保持;否则每次取一个真实队列字节并交给原核心,遇 LF 后保持,最多读取 256 B,并受原场景 70 秒总期限约束。两个替换会话各自就绪后才采集同一检查点,随即释放,恢复原 8192 B 消费块及 65536 B/4 ms tick 总预算。底层队列仍有界。

检查点不验证或修补正文:完整的 `BROKEN` 编号行也会就绪,再由原 Python oracle 拒绝。空启动、只有 READY、CR 无 LF、当前半行、只有其他角色等不会被完整记录判据接受。关闭会解除保持,关闭中或无有效 HWND 的对象拒绝重新启用,避免阻碍排空及回收。

`workflow_checkpoint_test` 在实际默认核心和候选 native-viewport 核心验证 8192/8217 分片、后续补齐、保持/释放及边界负例;最初红测试和最终测试保留相同触发用例,最终另增边界与状态用例,不能称整个测试源码相同。`runtime_observation` 用自有非输入 desktop 验证默认关闭、显式启用、关闭解除和关闭后拒绝重新启用。普通 cmd 回显不保证运输中有字面 LF,因此一个依赖此假设的临时关闭测试已排除;最终真实关闭测试只宣称关闭时已 armed,未宣称它必为 held。

## 正式验证与复现

固定源码、EXE/依赖哈希、旧红、新绿、完整回归、内部 skip 和回收结果见[公开白名单记录](../../experiments/shell/results/2026-10-27-workflow-record-checkpoint/validation.json)。原运输、窗口路径和 desktop 身份保留本地。最终原完整八会话测试包含两个新进程、每次五轮替换;它与受控诊断运行分别记录。

最终源码 `c662011`、候选 `.5`/固定官方后端 flags24 的完整 CTest 为 **56/57,402.66 秒**,两轮原八会话均通过,Job active=0、desktop 已回收。唯一失败为 Vim stage59,仍由 #52 定位;8 项内部 skip 逐项列出,不算真实 CF/IME 通过。关闭 guard 的实际新用例先红后绿;红例未独立保留 EXE 哈希,该字段明确为 null,源码、相同测试、构建日志和失败日志仍在。更早 `f89b0ac` 的 57/57 只属于关闭 guard 前版本,不能拼入最终源码,也不能解释 Vim 历史失败。候选 CI 另增加该跨平台核心回归;CI 的 system 后端与本机官方配置分列。

在依赖和全部 helper 已构建的候选/显式官方配置运行:

```powershell
ctest --test-dir build/candidate -C Release -R '^(workflow_checkpoint|runtime_observation)$' --output-on-failure
$env:TERMFORGE_BIN_DIR = "$PWD/build/candidate/bin/Release"
$env:TERMFORGE_EXPECT_CONPTY_BACKEND = 'reviewed-side-by-side-1.25.260930003'
$env:TERMFORGE_TEST_ARTIFACTS = "$PWD/local/workflow-record-check-new"
$env:PYTHONUTF8 = '1'
python -m unittest experiments.shell.test_workflow_sessions.WorkflowSessionsTests.test_two_fresh_owned_eight_session_rounds -v
ctest --test-dir build/candidate -C Release --output-on-failure
```

完整回归还需固定 Vim 在当前进程 PATH 中。官方后端、system 后端、默认核心和候选核心分别记录身份,不能互相借用结论。data-only 通过不代表真实 CF/IME、实际呈现、性能或完整 R2;#52、#63 及 #47 的其他门槛仍独立处理。
39 changes: 39 additions & 0 deletions experiments/shell/output_record_checkpoint.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Explicit synthetic-consumer coordination; disabled during ordinary use.
#pragma once
#include <chrono>
#include <cstddef>
#include <stdexcept>
#include <string_view>

namespace tf_shell_test {
class OutputRecordCheckpoint {
public:
using Clock=std::chrono::steady_clock;
static constexpr size_t byte_limit=256;
private:
bool armed_=false,held_=false;
size_t consumed_=0;
Clock::time_point deadline_{};
public:
void arm(bool at_boundary,Clock::time_point deadline) {
if(armed_) return;
if(deadline<=Clock::now()) throw std::invalid_argument("output checkpoint deadline expired");
deadline_=deadline;armed_=true;held_=at_boundary;consumed_=0;
}
size_t read_budget(size_t normal) const {
if(!armed_) return normal;
if(Clock::now()>=deadline_) throw std::runtime_error("output checkpoint deadline expired");
if(!held_ && consumed_>=byte_limit) throw std::runtime_error("output checkpoint record bound exceeded");
return held_?0:1;
}
void consumed(std::string_view bytes) {
if(!armed_) return;
if(held_ || bytes.size()!=1) throw std::runtime_error("output checkpoint read boundary violated");
if(++consumed_>byte_limit) throw std::runtime_error("output checkpoint record bound exceeded");
if(bytes.front()=='\n') held_=true;
}
bool held() const { return held_; }
bool active() const { return armed_; }
void release() noexcept { armed_=held_=false;consumed_=0; }
};
} // namespace tf_shell_test
Loading