## 当前方向与确认边界(2026-10-26) 公开 VT、原生 API、transport 与末端状态继续分别验证;补固定原版的实际行为对照,未知不算匹配。当前合同的重要变化、原版缺陷修正和产品后端取舍需用户确认,原失败和阻塞保留。 依据:[已确认方向与决策权限](https://github.com/JavaZeroo/termforge/blob/cdcaee2ddc062bfdc757290dc7dc03db2e6df163/docs/adr/0006-confirmed-project-direction.md)。 ## 原合同与固定现象 按 [R2终端合同](https://github.com/JavaZeroo/termforge/blob/main/docs/milestones/R2-local-terminal.md)及 Microsoft 每缓冲区 margin 语义,主屏2;3r、备用屏4;5r在1049切换后应独立恢复,区域外内容、光标/样式、历史及resize交叉需要实际验证。 原175B在本机系统ConPTY产生 REGION_CIXED 而不是 REGION_C,BOTTOM_FIXED受覆盖;原生控制台和 transport/末端各有独立观测。固定 WindTerm 只读符号/反汇编仅是screen归属线索,未证明运行时行为,不作为合同豁免。 ## 已有基础 PR #48 的 [A/B与第一方来源](https://github.com/JavaZeroo/termforge/blob/main/docs/research/conpty-margin-backends.md)保留原175B与四阶段CHAR_INFO:系统VT-on失败,固定官方1.25同包后端可保留必要VT、候选末端正确,但原生CHAR_INFO margin仍错。VT-off有合法窄屏反例;旧0x08不是受支持passthrough。公开feed的候选margin修复不替代真实产品路径。 ## 剩余交付与验收 - [ ] #56 精确核对原合同必须保留的native字段与末端语义、支持Windows/API/版本边界及第一方依据,给出能保留原合同的受支持路径和可复验证据;上游修复/可维护MIT fork/其他路径的许可部署维护明确。 - [ ] #47(#55/#51/#52/#53)在同源码实际Session/GUI整合该路径,保留API族/生命期、原输入、原生/transport/候选各层结果与回收;默认后端不因实验整合静默改变。 - [ ] 原场景在目标实现恢复main2;3r、alternate4;5r;区域外内容、文字/光标/样式、历史及resize交叉独立通过,原生字段不能由末端绿替代。 - [ ] #27/#28/#29/#35、FEATURES/EVIDENCE 与支持/限制同步。不同源码/flags旧失败保留,未知WindTerm运行行为和未测端点不回填。 ## 真实前置与完成边界 父项 #27;开放原生阻塞 #47、#56,整体 blocked。#56 可直接用原固定175B/1.25探针先做,不等待 #47 或联合基线;#47 的最终修复使用 #55。 “新引擎本来不同”、描述平台差异或移除native检查不能关闭原功能缺口。若确需改原合同,必须另行明确决策并保留原未完成项;本次规划整理不批准调整、不锁产品默认后端或 #34 架构。 ## #56 的同源原生证据进展 [Draft PR #98](https://github.com/JavaZeroo/termforge/pull/98) 使用 [PR96构建](https://github.com/JavaZeroo/termforge/pull/96) 的同源 baseline/patched;原175B、两尺寸、四阶段、原期限下,baseline原生final红、patched全部原生字段绿,两版末端正确,VT-off反例保持一致;8次均自然退出/EOF/Job0。另有15个API/身份场景与8个清单拒绝,来源/源码/工具/双SHA和限制见[证据说明](https://github.com/JavaZeroo/termforge/blob/678804ff5201fab4296b133af9457b7120739b68/docs/research/conpty-source-margin-runtime.md)。 这是独立探针的限定因果对照,未整合为产品后端。显式样式、历史、重复/默认margin、resize、查询/API及最终Session/GUI联合合同未闭合;原WindTerm运行行为和官方旧失败不回填。本项仍由 #56/#47 阻塞,PR50仍Draft。#97的candidate/system退出失败另列,不由本证据覆盖。
Activity
fix: preserve per-buffer scroll margins
JavaZeroo commentedon Oct 29, 2026
上游依赖 #56 已完成路径分析并收口(决策记录):根因定位到固定 1.25 源码、MIT fork 在 adapter 412/412 与 20 次同源运行中给出 red→green,另有 VT-off/passthrough/换 server 的拒绝证据。
本项原合同仍开放:是否采用 fork 属于依赖变更,需用户按 ADR-0006 在 #34 确认;确认后在最终 fork 产物上重验本项全部判据(含样式/历史/resize/查询/API 交叉与最低系统边界),才能关闭。当前产品后端仍为随包官方 ConPTY,不带本补丁。
JavaZeroo commentedon Oct 30, 2026
裁决结论:不能「接受差异」;只能「修复」,而修复分两层——其中一层现在就能动
三条结论,逐条有原文和源码支撑:
blocked的实际含义)。1. 判据原文(决定能不能关、能不能改合同)
→ 「接受差异」既被第 3 条(原生不能由末端绿替代)也被里程碑第 66 行(核心要有各自滚动区域)否掉;要改合同必须走一次性显式决策,本项明确写了「本次规划整理不批准调整」。
2. 现状分四层,证据各在不同 artifact
expected_source())与 experiments/shell/text_client.cpp:214-217 一致observed=["TOP_FIXED","REGION_A","REGION_B","REGION_CIXED","REGION_D","TF_MARGIN_DONE"],required=["TOP_FIXED","REGION_C","REGION_D","BOTTOM_FIXED","","TF_MARGIN_DONE"],且第 55 行断言差异存在(final["lines"][:6] != required才判「ConPTY margin behavior changed」)。REGION_CIXED= REGION_C 写在第 4 行覆盖 BOTTOM_FIXED 的前 8 列后残留的尾部candidate-margins*.transport.bin:系统侧如D:\Code\termforge\build\test-artifacts\candidate-shell\run-o97hkqm3\candidate-margins-0\candidate-margins.transport.bin(1088 B)无2;3r/4;5r;打过 margin 补丁的后端如...\termforge-fix-conpty-backend-r47\local\joint-r55\official-artifacts\candidate-shell\run-ug63mxjq\candidate-margins-0\candidate-margins.transport.bin(4551 B)两者都有;?1049h/l两侧都有2;3r + ?1049h + 4;5r组合断言;docs/FEATURES.md:43 明确候选「每缓冲区 margin」新事实:系统后端的 transport 在本机全部样本里都不再发出 DECSTBM(宿主自己消化后只发渲染结果),所以今天产品核心的 margin 代码在这条链路上根本不参与;一旦换成打补丁的固定后端,transport 开始携带
2;3r/4;5r——「下游终端怎么处理每缓冲区 margin」此时才第一次成为产品问题。3. 产品核心今天对主/备用屏的具体行为(静态读码)
scroll_top_/scroll_bottom_,不是每帧状态FrameState(含swap)只有 row/column/last_row/last_column/wrap_pending/discarded/style/lines/history/ordered_,不含 marginactivate_buffer只交换FrameState,且注释明说「without applying a terminal mode's clearing, inheritance or cursor-reset policy」?1049h/l只做 activate_buffer + (进入时)颜色复位/ED2/归位,不碰 margin2;3r的区域滚动、IL/DL 尊重 margin、resize 丢弃 margin),1049 交叉没有;1049 有独立用例但不带 margin即:主屏设
2;3r、备用屏设4;5r、再?1049l回主屏后,核心仍按4;5r滚动。第一阶后果:\x1b[3;1H后的 LF 在本应触发 2;3 区域滚动时不动,REGION_C 被写到主屏第 4 行覆盖 BOTTOM_FIXED(与原生REGION_CIXED同形),而合同 required 要求它落在第 2 行;完整末屏我未运行,不给结论(见第 5 节)。4. 一处必须纠正的证据归属
experiments/shell/results/2026-10-26-margin-state/validation.json:22-107的source_contract(main_margin_restored: true、margins_per_buffer_verified: true、final为["TOP_FIXED","REGION_C"," REGION_D","BOTTOM_FIXED",...])来自 alacritty 候选,不是自主 C++ 核心:local_trace指向build/margin-trace-sv_5qxte,该目录只有candidate.jsonl(由 experiments/candidates/alacritty/run.py:50 写入,行格式含mode_bits/replies),没有 core 侧 trace;而同文件real_conpty_observations(:323-481)才是真实 ConPTY 的两份系统后端观测。里程碑第 66 行「历史候选 feed 正确不等于 C++ 已实现」说的正是这件事。5. 能不能现在裁决 + 单一观测
required比对。入口现成:terminal_trace.exe <源> 24 80 100 <chunks.txt>(experiments/core/trace.cpp:25-76,默认构建产物在D:\Code\termforge\build\bin\Release\terminal_trace.exe)。取值只有两种:产出required→ 只缺后端;产出行序错乱(例如 REGION_C 落在第 4 行)→ 核心也缺每缓冲区 margin,后端修复后仍需第二处改动。这一条从未做过。边界
D:\Code下 60 余份candidate-margins*.transport.bin的字节检查。未改产品代码/断言/合同,未重跑、未 dispatch、未下载 artifact。fix(core): only the bottom margin scrolls on a line feed refs #41
JavaZeroo commentedon Oct 30, 2026
决定性观测:产品核心的末屏完全等于
required按本项此前记下的唯一下一步观测执行:把
margin_checks.expected_source()的 175 字节源喂给产品核心(terminal_trace),与margin_checks.py里的required比对。命令:
(源经 LF→CRLF 归一,因为真实控制台在 ONLCR 下会把
\n输出为 CRLF;不归一的话列号会差 8,见下。)结果(24×80,末屏前 6 行):
requiredobserved(ConPTY 实测)matches required: True,matches observed: False;光标位于 row 6 / col 0,与required的光标期望一致。判读
observed那一侧;observed的差异只能来自后端(系统 ConPTY 1.25 丢失主屏 margin),这与本项此前的根因判断一致;过程中发现并修复的一个真实缺陷
首次运行(未归一、且核心当时只有屏幕级单对边距)时末屏是
TOP_FIXED / REGION_D@col8 / 空 / BOTTOM_FIXED,REGION_C整行丢失。定位到newline()的区域分支:只要设置了边距就滚动区域,连光标在区域下方(\x1b[6;1H之后的那次换行)也会滚动。修复后:只有光标恰在底边时才滚动区域;区域之上正常下移,之下既不滚动也不影响区域。该修复与"每缓冲区边距"一起在 PR #249。
边界
test(core): pin the 175 byte margin source result refs #41
Merge pull request #249 from JavaZeroo/feat/per-buffer-margins
Merge pull request #260 from JavaZeroo/docs/r2-margin-known-difference
JavaZeroo commentedon Oct 31, 2026
裁决完成:选项 B(书面接受原生 CHAR_INFO 的 margin 差异)
本项要裁决的是「主/备用屏 margin 恢复差异」如何处置。已由 #260 合入 main,按选项 B 落地:
docs/adr/0007-bundled-microsoft-conpty.md的「已知差异」小节docs/milestones/R2-local-terminal.md:66为什么是选项 B 而不是继续修
本项正文记录的现象已经说明差异在原生控制台层:175B 在本机系统 ConPTY 产生
REGION_CIXED而非REGION_C,BOTTOM_FIXED被覆盖;而 transport 与末端两层是独立的。固定 WindTerm 的只读符号线索也没有证明运行时行为。也就是说:这一差异处在 Microsoft 固定后端内部,我们既不拥有那段实现,也无法在不替换后端的前提下消除它。把两层拆开、只在末端的合同上要求匹配,是能站住的验收口径;继续把它当缺陷追,会永远停在"目标侧不归我们控制"这一点上。
仍由其他项承接的部分
R2-local-terminal.md的末端层定义验收docs/EVIDENCE.md的「每缓冲区 margin 与宿主差异([R2-04][终端] 实现备用屏、滚动区域及关联模式 #27/[R2-04][终端] 裁决 ConPTY 主/备用屏 margin 恢复差异 #41)」行本项关闭后,margin 相关的新证据应记入 #27 或 #56,不再回到本项。
JavaZeroo commentedon Oct 31, 2026
裁决:差异来自后端(系统 ConPTY),产品路径用官方 side-by-side 包规避
同源 A/B(
experiments/conpty/results/2026-10-26-margin-backends/validation.json):2;3r/4;5r(REGION_CIXED)2;3r/4;5rREGION_C/REGION_D/BOTTOM_FIXED正确我们的核心侧另有一份独立证据:175 字节 margin 源喂给产品核心,末屏与
margin_checks.py的required逐行一致(含光标 row 6 / col 0),说明解析与恢复逻辑本身正确。产品路径
CMakeLists.txt:417(termforge_qt_entry)调用termforge_use_bundled_conpty,把官方 1.25 包作为 side-by-side 后端部署(cmake/ConptyBackend.cmake:5-34,摘要校验见third_party/conpty/manifest.json)。关闭依据与限制
native_api_margin_gap_closed=false);边界
Merge pull request #294 from JavaZeroo/docs/margin-wording