Skip to content
Merged
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
55 changes: 55 additions & 0 deletions docs/research/conpty-resize-repaint-timing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# resize 期间 ConPTY 重绘与终端网格的时序(#194 设计记录)

本页把 [#194](../..#194) 的观测与候选方案固定下来,便于决定方向后直接实现。它不改变任何行为。

## 观测事实

在 hosted windows-2025 上用 dispatch-only 复现作业采样,失败轮(`text_actions` 的 `actions geometry lost terminal selection`)留下三份互相对得上的证据:

1. **选区丢弃诊断**:`row-text-changed row=78, saved_bytes=29, current_bytes=29, saved_columns=111, current_columns=111` —— 字节数与列数都不变,说明是整行内容被换成了相邻行,不是裁剪。
2. **进度记录**:几何变化前 `grid=[111,7] top=75`,缩放到 75% 时 `grid=[149,10] top=75`,回到 100% 时 `grid=[111,7] top=78`,且 `selected` 由 true 变 false。
3. **输出轨迹**:一轮几何序列里出现约 10 次"回 home 重打尾部 6 行(075–080)"的重绘批次,并带 `ESC[7;1H` 与若干 `ESC[K CR LF`。

把三者合起来:重绘批次按**旧几何**(10 行、首行 075)生成,被**新几何**(7 行、首行 078)消费,于是行 0–5 被写成 075–080,整体错位 **10 − 7 = 3 行**。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep the repaint-generation ordering labeled as a hypothesis

The listed observations establish a content change and a three-row displacement, but do not establish that the repaint was generated for the ten-row geometry. In the reviewed code, experiments/shell/shell.cpp records output timestamps and dimensions at consumption, not generation or arrival. Moreover, experiments/shell/results/2026-10-29-resize-repaint-witness/README.md explicitly preserves two distinct interleavings producing the bad state and says the actual CI cut remains unknown. Presenting one ordering as an observed fact here can incorrectly constrain the proposed fix before the timing experiment below has resolved it. Label this explanation as a hypothesis and retain the unresolved generation/arrival/consumption ordering.

AGENTS.md reference: AGENTS.md:L13-L13

Useful? React with 👍 / 👎.


## 为什么这是产品问题而不是测试问题

- 终端把 ConPTY 的重绘当作普通 VT 输出应用,是标准行为;问题在于**重绘对应的几何与当前网格不一致**;
- 真实用户在 DPI/缩放变化时同样可能遇到:内容错行、选区/Find 失效;
- 该形状在 `local` 与 `system` 两种动作场景都出现过,不依赖剪贴板路径。

## 候选方向

### 方向 1:切换网格前先消费完已到达的输出(保守)

- 在 `size_changed` 应用新网格前,先把输出队列中已到达的块按旧尺寸喂给解析器;
- 优点:不改协议、不改期限,纯粹调整本进程的消费顺序;
- 风险:如果重绘批次在 resize 请求**之后**才到达(当前证据倾向于如此),仅"先排空已到达"不够,需要把"等待重绘批次"也纳入窗口,复杂度上升;
- 需要先做一个小实验确认重绘的到达时机(输出轨迹 + 尺寸轨迹即可判定)。

### 方向 2:按尺寸世代标记输出(结构性)

- 为 ConPTY 输出附带"消费时应使用的网格尺寸",重绘批次按其生成时的尺寸消费;
- 优点:语义清晰,可同时覆盖 DPI、缩放、窗口尺寸变化;
- 风险:需要改动 `Session`/读取路径的状态模型,属于架构级变更,必须单独立项评审。

### 方向 3:识别并吸收重绘批次(启发式)

- 识别以 `ESC[?25l ESC[H` 开头、且内容与当前可见尾部匹配的重绘序列,在尺寸切换瞬间丢弃或重放;
- 优点:改动局部;
- 风险:启发式识别可能误伤正常程序输出(例如自己实现重绘的 TUI 应用),不建议作为首选。

## 建议顺序

先做方向 1 的**可行性实验**(不改产品):

1. 扩展输出轨迹,标记"每个重绘批次的起始偏移与到达时刻";
2. 与 `geometry-*` 阶段的时间戳对照,确认重绘是"resize 前生成、resize 后到达"还是相反;
3. 若确为后者,则方向 1 需要扩展为"延迟应用新网格直到该批次消费完",并评估对交互延迟的影响;
4. 以上结论再交用户确认后实施。

## 证据入口

- 复现作业:`.github/workflows/conpty-compat.yml` 的 `windows-2025-actions-repeat`(覆盖 `text_actions|selection_context|shell`);
- 诊断变量:`TERMFORGE_CAPTURE_OUTPUT`、`TERMFORGE_OUTPUT_TRACE`、`TERMFORGE_SELECTION_DIAG`;
- 相关讨论:[#194](../..#194)、[#156](../..#156)(已关闭,机制记录)、[#38](../..#38)(托管稳定性汇总)。