From 6abca8a6ec38a0732599266163ccb5dff6d649a3 Mon Sep 17 00:00:00 2001 From: JavaZeroo-Bot <133958205+JavaZeroo-Bot@users.noreply.github.com> Date: Wed, 4 Nov 2026 16:20:53 +0800 Subject: [PATCH] test(research): complete the hidden-height supplemental audit The preserved seven-stage original recording still fails its strict text allowlist audit. Recover the complete recording from the evidence runtime and run the offline tail supplement against it without rerunning the target: the original failure stays preserved, zero additional runs are claimed, and the derived tail is limited to the fixed source interval. Publish the supplement, its report and the runtime recovery inventory. The audited return phase clips the hidden row to the current width, which differs from the merged engineering retention contract; the difference is recorded and left for user confirmation. No production code changes. Co-authored-by: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com> --- CMakeLists.txt | 4 +- docs/EVIDENCE.md | 4 +- docs/FEATURES.md | 4 +- .../original-evidence-runtime-2026-11-04.md | 41 + .../README.md | 2 + .../ui/audit_resize_hidden_height_tail.py | 193 ++ .../README.md | 58 + .../hidden-height-tail-supplement.json | 2508 +++++++++++++++++ .../test_audit_resize_hidden_height_tail.py | 172 ++ 9 files changed, 2981 insertions(+), 5 deletions(-) create mode 100644 docs/research/original-evidence-runtime-2026-11-04.md create mode 100644 research/ui/audit_resize_hidden_height_tail.py create mode 100644 research/ui/results/2026-11-02-resize-hidden-height-reference/README.md create mode 100644 research/ui/results/2026-11-02-resize-hidden-height-reference/hidden-height-tail-supplement.json create mode 100644 research/ui/test_audit_resize_hidden_height_tail.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 07812493..e765316c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -537,8 +537,8 @@ add_test(NAME edit_csi_core COMMAND edit_csi_test) termforge_add_python_test(windterm_resize_height_measured_optimized -O -m unittest research.ui.test_resize_height_measured_reference research.ui.test_export_resize_height_measured_reference -v) termforge_add_python_test(windterm_resize_combined_reference -m unittest research.ui.test_resize_combined_reference research.ui.test_export_resize_combined_reference -v) termforge_add_python_test(windterm_resize_combined_optimized -O -m unittest research.ui.test_resize_combined_reference research.ui.test_export_resize_combined_reference -v) - termforge_add_python_test(windterm_resize_hidden_height_reference -m unittest research.ui.test_resize_hidden_height_reference research.ui.test_export_resize_hidden_height_reference -v) - termforge_add_python_test(windterm_resize_hidden_height_optimized -O -m unittest research.ui.test_resize_hidden_height_reference research.ui.test_export_resize_hidden_height_reference -v) + termforge_add_python_test(windterm_resize_hidden_height_reference -m unittest research.ui.test_resize_hidden_height_reference research.ui.test_export_resize_hidden_height_reference research.ui.test_audit_resize_hidden_height_tail -v) + termforge_add_python_test(windterm_resize_hidden_height_optimized -O -m unittest research.ui.test_resize_hidden_height_reference research.ui.test_export_resize_hidden_height_reference research.ui.test_audit_resize_hidden_height_tail -v) find_program(TERMFORGE_NODE_EXECUTABLE NAMES node) if(TERMFORGE_NODE_EXECUTABLE) add_test(NAME windterm_resize_address_controller COMMAND ${TERMFORGE_NODE_EXECUTABLE} diff --git a/docs/EVIDENCE.md b/docs/EVIDENCE.md index be60b677..99e7ed39 100644 --- a/docs/EVIDENCE.md +++ b/docs/EVIDENCE.md @@ -18,7 +18,9 @@ | 原版 resize 后寻址与自主核心字面诊断 | [独立直接协议样本](../research/ui/results/2026-11-02-resize-address-reference/README.md)、[默认裁剪路径的失败诊断](../experiments/core/results/2026-11-02-resize-address/README.md) | 四例自然追加、CR、LF、CUP 保留动作前观测,文档、DSR、显示坐标分别核对;第五例 EL1 保留原审计失败。默认 `Screen::resize` 历史诊断仅 16/64 阶段通过、退出 1;当时 `EXCLUDE_FROM_ALL`,现参与默认构建但 CTest 只注册另行验证的显式保留入口。旧红不设 `WILL_FAIL`,常规 CI 或另一入口通过不能豁免默认路径差异 | | 缩窄后跨前方显示重排的 CUP/DSR 寻址(#27/#29 显式入口) | [单例原版四阶段严格记录](../research/ui/results/2026-11-03-reflow-addressing-reference/README.md)、[核心字面回放与身份](../experiments/core/results/2026-11-03-reflow-addressing/README.md):`CSI 8;2HQ` 写入文档行 6(保留的缩放前源片段行)而非重排行 5,DSR `8;3`、caret 同口径;窄屏矩形 (155,144) 恢复 (155,126) 证实显示页独立 +1 行重排 | 单例固定 ASCII、`91×20→61×20→91×20`、一个动作、最大一次运行;只补既有样本无法区分的行映射,不含备用屏、高度、Unicode、历史、样式、Qt/固定 ConPTY 或性能;默认 `Screen::resize`/Qt 未切换,#27/#29 不关闭 | | 正式 Qt / 固定 ConPTY 接入保留事务、显示投影与显示光标 | [契约、身份与差异](../experiments/shell/results/2026-11-03-qt-retained-display/README.md):可达真实 child→固定 ConPTY→core→widget;新 `qt_terminal_modes_retained` 12/12 检查通过,只缩宽后显示页第 8 行与原生重排逐字节一致,B/C/D 保留源位,命中经 layout revision 回到源格;Qt 正式路径 CTest 5/5,核心 36/36(含 `display_cursor_core`) | 旧六阶段 `--resize` 仍 exit 1 且失败信息不变,保留为原生重排网格与保留行合同的坐标差;同时缩宽+缩高的原版视口/滚动与后续 CUP 仍缺独立证据;不覆盖真实呈现/DPI/历史/Find/性能,#27/#29 不关闭 | -| 隐藏主屏纯高度变化的正文保留(#27 工程合同) | [RED/GREEN、命令与边界](../experiments/core/results/2026-11-04-hidden-height-retention/README.md):修复前 `resize_hidden_height_test` 证明隐藏 live/历史被按未变宽度裁剪并丢失保留尾;`resize_preserving` 改为只在宽度实际变化时适配隐藏帧后,三场景通过并注册 `retained_resize_hidden_height_core`;组合回放 20/20、事务检查不变,正式 Qt CTest 5/5 | 工程不变量,不是原版隐藏高度 oracle:原版七阶段记录仍为严格审计失败,归档缺少取证运行时的完整发行物/profile,无法在本工作区严格复核;未覆盖备用屏后续输出、保存光标交叉、Unicode、历史淘汰、Qt 物理呈现/DPI 或性能;#27/#29 不关闭 | +| 隐藏主屏纯高度变化的正文保留(#27 工程合同) | [RED/GREEN、命令与边界](../experiments/core/results/2026-11-04-hidden-height-retention/README.md):修复前 `resize_hidden_height_test` 证明隐藏 live/历史被按未变宽度裁剪并丢失保留尾;`resize_preserving` 改为只在宽度实际变化时适配隐藏帧后,三场景通过并注册 `retained_resize_hidden_height_core`;组合回放 20/20、事务检查不变,正式 Qt CTest 5/5 | 工程不变量;原版对照见下一行。未覆盖备用屏后续输出、保存光标交叉、Unicode、历史淘汰、Qt 物理呈现/DPI 或性能;#27/#29 不关闭 | +| 原版隐藏主屏高度的录制恢复与离线补充审计(#27/#29) | [补充审计、阶段观察与差异](../research/ui/results/2026-11-02-resize-hidden-height-reference/README.md):七阶段原版录制的严格审计失败保留;从仍可用的取证环境只读恢复完整输入后,离线补充审计通过(计划 `938992c4…`、参考 EXE `7b1053…`/4047 清单 `e459adf2…`、执行源清单 `51e80b93…`,0 次重跑),补充件 `4c0f28f2…` | 审计显示返回主屏后宽行按当前宽度裁剪为 61 空格 + `w`(62 字符)、DSR `19;7→14;7`,与 #311 的保留合同存在待用户确认的差异;本记录不修改实现、不重跑、不关闭 #27/#29;语义验收 false,备用屏阶段 API 文本不等于活动备用屏网格 | +| 原版取证运行时与归档可恢复性盘点 | [环境类别、已核验身份、解除方式与条件](research/original-evidence-runtime-2026-11-04.md):原取证 QEMU 域仍可用,参考 EXE `7b1053…`、4047 文件清单 `e459adf2…`、隐藏高度计划 `938992c4…`、执行源清单 `51e80b93…` 与完整录制输入均在;宿主归档缺少 `app`/`profile`/`reference-source.json` 是此前 blocked 的原因 | 只发布路径类别、哈希与证明字段;私有录制/profile/原包不发布;解除方式只适用于原始输入完整且允许只读复核的记录,不外推到未核对归档;环境丢失后同类旧失败只能保持 blocked | | 自主 C++ 同 owner 保留列宽事务与有限编辑(#27/#29 独立入口) | [源码、定向红绿与限制](../experiments/core/results/2026-11-02-retained-columns/README.md):`a35be70` 的四个寻址 case 为 64/64 阶段;`fdeaed6` 使打印/ICH/DCH 按协议宽更新目标行,内容长度与 `written` 分离,三例编辑为 64/64 阶段。该固定源码重新构建后核心 22/22、Qt/固定 ConPTY 4/4,各配置身份独立记录 | 默认 resize / Qt 未切换;Qt 回归不执行新保留入口。Q/R 与 ICH/DCH 红绿分别保留,owner 存储及空白长度工程检查没有独立先行 RED。后续光标与隐藏帧修正另列,不继承本轮结果;默认裁剪与 B/CD 失败不豁免 | | 原版活动/隐藏帧与缩放后下一字符 | [6次原版、29阶段](../research/ui/results/2026-11-02-resize-frame-reference/README.md):5次原审计通过、1次隐藏主屏原审计失败后独立离线补充通过;无补跑。文档、DSR与显示分别记录 | 活动备用屏保留正文;隐藏主屏返回的正文和边界不同;4个ON/OFF缩放末列样本支持下一字符覆盖当前位置。原版Document索引差异、私有模式位及完整网格不据此判定 | | 自主 C++ 缩放后的末列输入与隐藏主屏 | [末列输入红绿](../experiments/core/results/2026-11-02-resize-pending/README.md):`9b67886` 的4例44/72→72/72;[隐藏主屏红绿](../experiments/core/results/2026-11-02-resize-hidden/README.md):`afdcf59` 的12/32→32/32,精确比较正文空白长度、源位置、显示与DSR | 定向实现均只走显式保留入口;默认 resize / Qt 尚未接入。隐藏主屏样本不能推出活动帧 margin、单纯隐藏增宽或完整 Unicode 语义;各报告区分固定生产源码、执行后身份与缺失的历史二进制 | diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 3bd874e3..c1b52a5f 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -31,7 +31,7 @@ 行存储已由 owner 封装,行 ID 与文档顺序分离;[精确查询](../experiments/core/results/2026-10-29-order-query/README.md)、[封存存储](../experiments/core/results/2026-10-29-sealed-row-storage/README.md)及 `text_search.hpp` 的顺序 revision 处理已在 main(#170/#172/#175)。#169 的关闭本身不证明 Qt 历史/选择/Find 已交付。[#29](https://github.com/JavaZeroo/termforge/issues/29) 的叠加 `ViewMapping` 已引入(#264),`HistoryViewport` 快照现携带显示页映射;部分列选区不再投影成整行。Qt 基础拖选通过同一映射命中与高亮,颜色只写入显示副本,普通点击清除选区;[模型与 Qt 接线记录](../experiments/shell/results/2026-11-01-r2-core-input/README.md)分列核心映射和用户事件证据。系统复制/粘贴、选词/选行、历史浏览/自动滚动与 Find 仍未迁移,物理 resize 仍会丢弃裁掉的正文;#29/#30 均未结项。旧 #108–#113 堆叠方案已关闭,不再列为待合入产品实现。 -[有界 Unicode Cell 显示投影](../experiments/core/results/2026-11-02-display-projection-unicode/README.md)保留完整宽字、已有组合标/样式、源身份和选择/Find范围,显示补白不创造源文字。[增量 `ProjectionJob`](../experiments/core/results/2026-11-02-projection-job/README.md)每步最多读200个源片段,保存未完成半行和页面,完整页才发布;500个单列片段实际按200/200/100步完成,跨步骤选择、复制与Find映射通过。每片段仍限500 Cell,每lead最多68字节/16个mark;不完整原子、trail起点及一列放不下宽字等请求拒绝。任务绑定owner、epoch、order、独立content revision与请求代次;旧单次`project`的source_limit可能停滞,需使用分步入口。源锚点不是全局显示行号,任意显示位置定位与持续输出下的进展保证仍待实现。默认 `Screen::resize` 仍物理裁剪;正式 Qt 路径已改走保留事务并绘制独立显示页、显示光标与映射命中([只缩宽契约](../experiments/shell/results/2026-11-03-qt-retained-display/README.md)),旧六阶段 native-sync 失败保留为原生重排网格与保留行坐标层的差异;隐藏主屏在纯高度变化时保留正文([工程合同](../experiments/core/results/2026-11-04-hidden-height-retention/README.md)),原版隐藏高度严格证据仍缺。#27/#29保持开放。 +[有界 Unicode Cell 显示投影](../experiments/core/results/2026-11-02-display-projection-unicode/README.md)保留完整宽字、已有组合标/样式、源身份和选择/Find范围,显示补白不创造源文字。[增量 `ProjectionJob`](../experiments/core/results/2026-11-02-projection-job/README.md)每步最多读200个源片段,保存未完成半行和页面,完整页才发布;500个单列片段实际按200/200/100步完成,跨步骤选择、复制与Find映射通过。每片段仍限500 Cell,每lead最多68字节/16个mark;不完整原子、trail起点及一列放不下宽字等请求拒绝。任务绑定owner、epoch、order、独立content revision与请求代次;旧单次`project`的source_limit可能停滞,需使用分步入口。源锚点不是全局显示行号,任意显示位置定位与持续输出下的进展保证仍待实现。默认 `Screen::resize` 仍物理裁剪;正式 Qt 路径已改走保留事务并绘制独立显示页、显示光标与映射命中([只缩宽契约](../experiments/shell/results/2026-11-03-qt-retained-display/README.md)),旧六阶段 native-sync 失败保留为原生重排网格与保留行坐标层的差异;隐藏主屏纯高度变化保留正文的[工程合同](../experiments/core/results/2026-11-04-hidden-height-retention/README.md)与[原版补充审计](../research/ui/results/2026-11-02-resize-hidden-height-reference/README.md)已分别记录:原版返回时按当前宽度裁剪隐藏行,与当前保留合同存在待确认差异。#27/#29保持开放。 [同 owner 保留列宽事务](../experiments/core/results/2026-11-02-retained-columns/README.md)使用独立 `Screen::resize_columns_preserving` 入口:活动正文保留源 Cell、ID/version 与有效软续接,历史不被补齐或重写;普通打印、ICH/DCH 按当前协议宽度更新目标行,独立内容长度保留有意义的尾空白。实际列宽变化会[限制活动光标并取消延迟末列写入](../experiments/core/results/2026-11-02-resize-pending/README.md),并[复位两帧的滚动边界](../experiments/core/results/2026-11-02-resize-mode/README.md);[隐藏主屏](../experiments/core/results/2026-11-02-resize-hidden/README.md)还会裁剪 live 正文,不与活动正文采用同一保留策略。原版字面回放分别覆盖寻址、写入/插删、缩放后下一字符和隐藏主屏返回,各组身份与验证范围在对应报告中独立记录。[缩窄后跨前方重排的 CUP/DSR 寻址原版样本](../research/ui/results/2026-11-03-reflow-addressing-reference/README.md)与[对应核心回放](../experiments/core/results/2026-11-03-reflow-addressing/README.md)确认协议行仍是保留的缩放前行、DSR/caret 同口径,显示页独立重排;仍只走显式入口,默认 `Screen::resize` 与 Qt 未切换。 @@ -56,7 +56,7 @@ Qt 构建显式准备并部署[固定微软 CRT 14.51.36247.0](../third_party/ms | 中文 IME 与键盘 | **限定验收**:基础按键/修饰键/UTF-16 与实际接收字节;[固定 ZWJ/keycap 输入](../experiments/shell/results/2026-10-26-unicode-keyboard/validation.json)在默认/候选各两轮精确接收。固定 Microsoft 拼音[产品场景](../research/ime/results/2026-10-24-product-ime-contexts/validation.json)覆盖两区域组合/提交/取消、候选、输出/resize/zoom/受控 DPI、隐藏/关闭、历史阅读和原生控件 | 限定 Windows Server 2025 固定拼音及已有场景;同次组合由八会话工作流另验收。固定字素绘制/选择已由 #39 限定完成,但所有输入法、应用键盘模式、完整 IME 和真实不同 DPI 跨屏仍未完成 | R1 / R2 | | VT 核心 | **实现中,未验收**:默认自研支持基础光标/擦除(含 ECH)、CR/LF/BS/TAB、有限 SGR(粗体/暗色/下划线/反显/删除线/隐藏/上划线)和有界恢复;新增编辑类 `ICH`/`DCH`(`CSI @`/`CSI P`)、`IL`/`DL`(`CSI L`/`CSI M`)、滚动区域 `DECSTBM`(`CSI Pt;Pb r`,归位与非法区域行为按参考实现)、`ED3`(`CSI 3J` 只清回滚)与 `RIS`(`ESC c`),`DSR 6n` 回复、`DECCKM`(`?1`)与 `DECTCEM`(`?25`)已接入 Win32 与 Qt 两个入口,均有[核心契约测试](../experiments/core/edit_csi_test.cpp)与[回复测试](../experiments/core/reply_test.cpp)。显式候选 `.4` 接入 `Term/Processor`、C++ 拥有值适配、稳定行元数据、每缓冲区 margin 与流式字素;[共同轨迹](../experiments/differential/results/2026-10-26-candidate-common-v6/summary.json)及[源 margin 合同](../experiments/shell/results/2026-10-26-margin-state/validation.json)为各自固定版本结果 | [#27](https://github.com/JavaZeroo/termforge/issues/27) 的 origin/wrap、模式/resize、插删与滚动区域交叉未闭合;[#41](https://github.com/JavaZeroo/termforge/issues/41) 系统 ConPTY 已丢失的 margin 不能由末端补回。ECH pending-wrap 差异见[限定合同](research/more-capture-ech.md);`DA1` 仅 strict 回放回复 VT102,recovery 产品路径不回复;`DA2` 与 `OSC 10/11` 回复未实现,原版未知仍不算匹配;`SGR 58` 等下划线颜色属性亦未实现;#36/#38、完整呈现和平台支持独立验收 | R2 / R4 | | Unicode 与文字显示 | **实现中,未验收**:默认自研保留 Unicode 15。显式候选 `.4` 的 [#39 Unicode 17 流式字素合同](research/streaming-graphemes.md)已限定验收:固定 ZWJ/keycap 的单 lead/两列、光标、SGR/查询、原子选择复制、单列 resize 与有界无损分片;实际 ConPTY/DWrite 核对固定样本的单 glyph、字体和网格 | [#30](https://github.com/JavaZeroo/termforge/issues/30) 仍需完整输入/IME 交叉;所有脚本/整形、通用 fallback、所有原生重放、真彩色/更多属性、Powerline 和真实跨屏未验收。分段 helper 的规范数据通过不代表完整终端 Unicode 正确性;[#54](https://github.com/JavaZeroo/termforge/issues/54) 保留已观察的性能成本 | R2 / R4 | -| resize 与 reflow | **实现中,未验收**:默认仍按 ADR-0005 物理行裁剪;[显式保留列宽事务与显示投影](../experiments/core/results/2026-11-02-retained-columns/README.md)通过四例有限寻址诊断;[同 owner 宽高组合保留事务](../experiments/core/results/2026-11-02-retained-combined/README.md)把固定五阶段原版回放从 8/20 阶段修至 20/20,并注册核心门禁;正式 Qt 路径已接入该事务、独立显示页、显示光标与映射命中([只缩宽契约](../experiments/shell/results/2026-11-03-qt-retained-display/README.md) 12/12、Qt 正式 CTest 5/5),默认 resize 入口未替换;[隐藏主屏纯高度变化保留正文的工程合同](../experiments/core/results/2026-11-04-hidden-height-retention/README.md)已注册门禁。历史候选在[固定 ConPTY 重放](../experiments/core/results/2026-10-26-resize-replay/validation.json)与连续同步中保持行身份、Find/选区和有界历史,淘汰/清空不复活;候选 `.4` 另覆盖主/备用屏缩到单列 | [ADR-0010](adr/0010-bounded-resize-retention.md)已确认正文保留与显示投影方向,#27/#29 联合交叉仍未完成;[正式路径 B/CD 缩放诊断](../experiments/shell/results/2026-11-02-qt-terminal-modes/README.md)仍红且失败信息保留,已归类为原生重排网格与保留行坐标层差异,同时缩宽+缩高的原版视口/滚动与后续 CUP 仍缺独立证据;隐藏主屏高度的原版严格取证未完成,当前合同为工程不变量。固定事务不等于完整 reflow 或 WindTerm 等价。[#156固定交错诊断](../experiments/shell/results/2026-10-29-resize-repaint-witness/README.md)见证默认核心在两种时序下选区失效,历史几何错配已有字节/消费网格证据;[#194](https://github.com/JavaZeroo/termforge/issues/194) 后续按用户接受未复现收口,未证明产品修复,重现时按该项条件重开。系统/实验 ConPTY、备用屏/滚动区、真实 DPI、呈现、性能及 #36/#38 分别验收;默认缩窄不可恢复 | R2 | +| resize 与 reflow | **实现中,未验收**:默认仍按 ADR-0005 物理行裁剪;[显式保留列宽事务与显示投影](../experiments/core/results/2026-11-02-retained-columns/README.md)通过四例有限寻址诊断;[同 owner 宽高组合保留事务](../experiments/core/results/2026-11-02-retained-combined/README.md)把固定五阶段原版回放从 8/20 阶段修至 20/20,并注册核心门禁;正式 Qt 路径已接入该事务、独立显示页、显示光标与映射命中([只缩宽契约](../experiments/shell/results/2026-11-03-qt-retained-display/README.md) 12/12、Qt 正式 CTest 5/5),默认 resize 入口未替换;[隐藏主屏纯高度变化保留正文的工程合同](../experiments/core/results/2026-11-04-hidden-height-retention/README.md)已注册门禁,[原版七阶段补充审计](../research/ui/results/2026-11-02-resize-hidden-height-reference/README.md)显示返回主屏时按当前宽度裁剪隐藏行,与当前保留合同存在待确认差异。历史候选在[固定 ConPTY 重放](../experiments/core/results/2026-10-26-resize-replay/validation.json)与连续同步中保持行身份、Find/选区和有界历史,淘汰/清空不复活;候选 `.4` 另覆盖主/备用屏缩到单列 | [ADR-0010](adr/0010-bounded-resize-retention.md)已确认正文保留与显示投影方向,#27/#29 联合交叉仍未完成;[正式路径 B/CD 缩放诊断](../experiments/shell/results/2026-11-02-qt-terminal-modes/README.md)仍红且失败信息保留,已归类为原生重排网格与保留行坐标层差异,同时缩宽+缩高的原版视口/滚动与后续 CUP 仍缺独立证据;隐藏主屏高度的严格审计失败保留、离线补充审计已通过(单次七阶段,0 次重跑),返回时按当前宽度裁剪与当前保留合同的差异待用户确认。固定事务不等于完整 reflow 或 WindTerm 等价。[#156固定交错诊断](../experiments/shell/results/2026-10-29-resize-repaint-witness/README.md)见证默认核心在两种时序下选区失效,历史几何错配已有字节/消费网格证据;[#194](https://github.com/JavaZeroo/termforge/issues/194) 后续按用户接受未复现收口,未证明产品修复,重现时按该项条件重开。系统/实验 ConPTY、备用屏/滚动区、真实 DPI、呈现、性能及 #36/#38 分别验收;默认缩窄不可恢复 | R2 | | 本地 shell 选择 | **实现中,未验收**:`ShellLaunch` 分离可执行文件、参数、工作目录及 shell 命令差异;cmd、Windows PowerShell 5.1、PowerShell 7、显式 Ubuntu WSL 各有[两轮真实启动/目录/尺寸/正常退出证据](../experiments/shell/results/2026-10-24-r2-shell-lifecycle/validation.json),无效程序启动错误可见且可关闭后恢复 cmd。四 shell 测试已补 [WSL 原生尺寸程序返回后的新提示符同步](research/wsl-size-return.md),正常退出证据只在实际全部回收后写入;默认/system 的事件反例、原两轮及完整回归分别留证 | 仅声明上述固定入口和隔离目录;#80 原 hosted stage6 是否同因仍未知,#81 hosted 准备超时另行定位;任意 profile/参数、通用分屏/排序、全部运行时错误提示及管理员 shell 未完成 | R2;权限场景 R4 | | 常用 TUI | **实现中,未验收**:显式候选 + 系统 ConPTY 有固定 Vim 进入、编辑、60×12 resize、退出写盘、主屏恢复及光标回复的[产品证据](../experiments/core/CANDIDATE.md);More 尾部 ECH 与捕获端点有[限定修复](research/more-capture-ech.md) | [#28](https://github.com/JavaZeroo/termforge/issues/28) 的更多应用及完整输入/输出模式未完成;PR #50 实验后端的 GUI Vim [#52](https://github.com/JavaZeroo/termforge/issues/52) 仍有失败;[native 捕获目录复用](research/vim-fixture-isolation.md)已独立定位并修正,不能代替 GUI 或完整 TUI 验收。headless 比较与自有 DIB 不等于真实呈现,`presented_done=null` | R2 | diff --git a/docs/research/original-evidence-runtime-2026-11-04.md b/docs/research/original-evidence-runtime-2026-11-04.md new file mode 100644 index 00000000..d797e385 --- /dev/null +++ b/docs/research/original-evidence-runtime-2026-11-04.md @@ -0,0 +1,41 @@ +# 原版取证运行时与归档可恢复性盘点(2026-11-04) + +本文记录 #27/#29 原版取证环境在恢复暂停工作后的一次实际盘点与一次证据缺口解除。只记录可核验的路径类别、版本/哈希与恢复条件,不发布私有路径、凭据、原包或 profile。 + +## 结论 + +- 取证环境仍在:本机 QEMU 域 `termforge-r2-win11-20261028-7d7e678b` 运行中,可通过宿主 `virsh` + QGA 只读访问。 +- 环境内保留完整工具、发放的发行物与历史录制:`C:\TermForgeHarness`(`Tools`/`Results`/`State`)。 +- 此前在宿主侧“blocked”的隐藏主屏高度审计不是不可恢复:宿主归档只含 27 个结果文件,缺 `app`、`profile`、`reference-source.json` 等取证输入;完整输入仍在环境内。 +- 已用其余正确归档完成一次**离线补充审计**(不重跑原版、不改旧失败):见[隐藏主屏高度结果](../ui/results/2026-11-02-resize-hidden-height-reference/README.md)。 + +## 已核验身份 + +| 对象 | 实际身份 | +|---|---| +| 参考发行物 EXE | `WindTerm.exe` SHA256 `7b10531dccc7cd614ae559f36f1ef518e0c96335637431b4646354823b2804d0` | +| 参考发行物清单 | 4047 文件,清单 SHA256 `e459adf2f12adb6a1b7f55e66a9da1c22794185e66e848057d21e0c60d669203` | +| 便携运行时 | `r27-reference-runtime-0`(portable Python 104,952 B、Node 93,922,624 B;运行产物另计) | +| 隐藏高度计划 | SHA256 `938992c4c68eb0c0587d3c789e4d1711a70264df5f7631c904707e29c7280fb`;`.attempted` 单次标记存在 | +| 执行源码快照 | 含 `reference-source.json`,清单 SHA256 `51e80b939c4c026a88fd098eeffe4473921815601fbb1435cb7eabd7adedb5cf`;执行基 `88ace8dec723f0fe2fb41d7077e83b6cda6a4d61` | +| 隐藏高度录制 | 七阶段;`app` 4048 文件、`profile`(含 `user.sessions`)在;`mechanics-check.json` 按原审计失败保持缺失 | +| 旧严格导出 | 原失败保留(文本白名单 `Only fixed hidden-height-source synthetic document lines are allowed`),未改写 | +| 补充审计 | `termforge-original-resize-hidden-height-tail-supplement-v1`;`additional_original_runs=0`;公开件 SHA256 `4c0f28f25adf2acc6c5124889ae0dd430425f871a7de0d1fdb68ffacb78564ed` | + +## 为什么宿主侧曾显示 blocked + +宿主归档(`hidden-height-0-raw.zip`,27 个文件)只是一份结果子集:缺 `app/`(4047 文件发行物副本)、`profile/`(合成 profile 与 `user.sessions`)和 `reference-source.json`(源码归档清单)。严格导出会在 `provenance_facts` 前失败,无法在宿主完成来源复核。归档不是“不可恢复”,而是**未包含全部输入**。 + +## 本次解除方式 + +1. 只读列出环境内的工具、运行时、录制与结果;核对 EXE、清单、计划、源码归档清单哈希。 +2. 把执行源码快照复制为**新目录**(`r29-hidden-height-audit-tail-0`),只加入离线审计脚本;原始快照、计划、录制和结果不改。 +3. 以原始录制、原始计划、原始参考发行物在新目录运行 `research.ui.audit_resize_hidden_height_tail`,输出到**新结果文件**;旧失败保留。 +4. 把公开结果复制回仓库并新增结果记录与测试/CTest 注册;不把新环境倒填为旧 provenance,不重跑原版。 + +## 可继续复用的条件与边界 + +- 环境仍可用时,`Tools` 下的其他 `r29-*-source-0` 快照与 `Results` 下的对应 `-raw`/`-public` 件可用于同类离线补充审计;每例必须使用自己的计划哈希与新输出文件。 +- 一旦环境或录制丢失,这些旧失败只能保持 blocked;解除条件为:原始计划 `.attempted`、完整原始录制(`app`/`profile`/结果)、冻结执行源码与参考发行物同时存在,且允许只读复核。 +- 本盘点不证明其他 archived 原件完整,也不把某一次解除外推到未核对的记录。 +- 环境内的私有路径、profile、原包与凭据只留本地,不提交;仓库只发布可派生文本、哈希与证明字段。 diff --git a/experiments/core/results/2026-11-04-hidden-height-retention/README.md b/experiments/core/results/2026-11-04-hidden-height-retention/README.md index bf0a7e02..e996d7e0 100644 --- a/experiments/core/results/2026-11-04-hidden-height-retention/README.md +++ b/experiments/core/results/2026-11-04-hidden-height-retention/README.md @@ -33,3 +33,5 @@ ctest --test-dir build/qt-cpp -C Release -R "^(qt_cpp_(shell|resize)|qt_unicode_ - 纯高度变化后隐藏行可宽于当前协议宽度,与活动保留行同一表示;显示投影/编辑路径沿用既有有界处理。隐藏帧在宽度改变时仍按单独记录的隐藏宽度策略适配足迹。 - 未覆盖备用屏活动期间的后续输出、保存光标交叉、Unicode/宽字/结合字、历史淘汰上限、Qt 物理呈现/DPI、选择/Find 用户流程或性能。 - #27/#29 保持 OPEN;本切片不声明完整 resize/reflow、WindTerm 等价或 R2 完成。 + +**2026-11-04 后续:** 取证环境内完整录制恢复后,隐藏主屏高度七阶段记录的离线补充审计已完成,旧严格失败保留;审计显示返回主屏时按当前宽度裁剪隐藏行,与本报告的保留合同存在差异。见[补充审计](../../../../research/ui/results/2026-11-02-resize-hidden-height-reference/README.md);本报告的工程验证与 #311 身份保持不变。 diff --git a/research/ui/audit_resize_hidden_height_tail.py b/research/ui/audit_resize_hidden_height_tail.py new file mode 100644 index 00000000..fc36dc7f --- /dev/null +++ b/research/ui/audit_resize_hidden_height_tail.py @@ -0,0 +1,193 @@ +"""Supplement one preserved hidden-height recording without rerunning its probe. + +The original audit must still fail with its exact text-allowlist error. A fresh +namespace adds only S[:61]+S[91:] from S = 89 spaces + uvw, at document row 11 +of phases 5 and 6. The original mechanics file must remain absent. +""" +from __future__ import annotations +import argparse +import hashlib +import json +from pathlib import Path +import sys +from types import FunctionType, SimpleNamespace + +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT)) +from research.ui import export_resize_hidden_height_reference as exporter +from research.ui import resize_hidden_height_reference as probe + +require, read, sha, digest = exporter.require, exporter.read, exporter.sha, exporter.digest +CASE = "hidden-primary-height" +ORIGINAL_ERROR = "Only fixed hidden-height-source synthetic document lines are allowed" +RAW_NAMES = tuple(name for name in exporter.raw_names(CASE) if name != "mechanics-check.json") +AUDIT_SOURCES = ("research/ui/audit_resize_hidden_height_tail.py", *exporter.EXPORT_SOURCES) +FROZEN_SOURCES = { + 'research/ui/resize_hidden_height_reference.py': '565d10b69b7a1015c3412b4b5fd974818acd395aa8ba846835d23cc8998bb0bc', + 'research/ui/resize_hidden_height_reference.js': 'd03cb790dd9db24275f859e297d867453e35675db2ab3f730e0b3f775fd57bc9', + 'research/ui/resize_state_reference.py': '628f9e3a5e3ecea6c34829810df2cdf0e93dc221bd3d19b31b3f5028759f07fd', + 'research/ui/mode_state_reference.py': 'bac745e74a2653412ea7a701e3a1f3defa1fb97fdd7841b73fad483120496ec4', + 'research/ui/alternate_reference.py': '94b85d49347e0e9813f7acddf0244f58520a7d1fce14084677c91cf4ddafffea', + 'research/ui/r1_launch.py': '54fb41872c6abcc48242a0938044184854b016785cc13659c66b1bf404da0d8a', + 'research/ui/launch.py': '6970e0d4f2fe5e7ec4827df7aa1026cd0e74aeb828cdc9b7a0b42b3c887eb4e6', + 'research/ui/qt_r1_text.js': 'f5820d413fdd72c13dffcefbf4d0ade615abfe15754c6b0b52e1e098814eea6f', + 'research/ui/r1_vt_fixture.py': '5853f684d5b8a4c17a30f22a536f04f0eb212813b8d6b3cc3c197df392eb732a', + 'experiments/conpty/run.py': '3766879cafe38aabf53cfac8ab2f62985b1976b6fa24c8b6031258bdc914258f', + 'research/ui/export_resize_hidden_height_reference.py': 'bcd8ed771ca0233dfb63b2a11876daf5a13020ba612e4bc6f306acdb9133094f', + 'research/ui/export_resize_state_reference.py': '473e901305354d4ba8b22c08d22fa506c4d40da0e73bed3bf3122e4ff0e3c9b7', + 'research/ui/export_mode_state_reference.py': '7e0a1e0e49f149791464c0dec357d3b5260bc2c34ca9f9c1be4edab35626cdf3', +} + + +def frozen_sources(): + require(all(sha(ROOT / name) == expected for name, expected in FROZEN_SOURCES.items()), + "Frozen original audit/source bytes differ") + + +def synthetic_lines(case, phase): + require(case == CASE, "Supplement applies only to the fixed hidden-height case") + result = set(probe.synthetic_lines(case, phase)) + if phase in (5, 6): + original = " " * 89 + "uvw" + result.add(original[:61] + original[91:]) + return result + + +def validate_document(case, phase, terminal): + original = probe.validate_document + bounded = FunctionType(original.__code__, {**original.__globals__, "synthetic_lines": synthetic_lines}, + argdefs=original.__defaults__) + bounded(case, phase, terminal) + candidate = " " * 61 + "w" + if candidate in terminal["lines"]: + require(phase in (5, 6) and len(terminal["lines"]) > 11 and terminal["lines"][11] == candidate, + "Supplemental tail must stay at captured document row 11") + # Every nonblank source marker occurs at most once in the fixed input. + # Repeating an otherwise allowed line must not duplicate those markers. + for marker in exporter.MARKERS: + require(sum(line.count(marker) for line in terminal["lines"]) <= 1, + "Repeated synthetic source marker") + + +def reproduce_failure(directory): + require(not (directory / "mechanics-check.json").exists(), "Original mechanics file must remain absent") + try: + probe.audit_mechanics(directory, CASE) + except ValueError as error: + require(type(error) is ValueError and str(error) == ORIGINAL_ERROR, + "Original audit failed for a different reason") + else: + raise ValueError("Original fixed text-allowlist failure did not reproduce") + + +def capture_facts(directory, plan, source_root=ROOT): + frozen_sources() + require(plan["case_id"] == CASE, "Supplement applies only to the fixed hidden-height case") + # Fail closed on duplicate fields and nonfinite values before the frozen + # runtime's ordinary json.loads sees the same immutable recording. + for name in RAW_NAMES: + if name.endswith(".json"): + read(directory / name) + reproduce_failure(directory) + raw = read(directory / probe.RESULT_FILE) + for phase in (5, 6): + lines = raw["observations"][phase]["terminal"]["lines"] + require(len(lines) > 11 and lines[11] == " " * 61 + "w", + "Preserved return-phase tail observation differs") + original = probe.audit_mechanics + mechanics = FunctionType(original.__code__, {**original.__globals__, "validate_document": validate_document}, + argdefs=original.__defaults__) + adapted_probe = SimpleNamespace(**{**vars(probe), "audit_mechanics": mechanics, + "synthetic_lines": synthetic_lines, "validate_document": validate_document}) + source = exporter.adapt(exporter._source, { + 'require(read(directory / "mechanics-check.json") == mechanics, "Saved mechanics audit differs")': + 'require(not (directory / "mechanics-check.json").exists(), "Original mechanics file must remain absent")', + }) + namespace = {**exporter._CAPTURE, "probe": adapted_probe} + exec(compile(source, str(Path(exporter.__file__)), "exec"), namespace) + # Keep the existing stage roles and document hashes, as well as all its + # provider, script, exact geometry, NAWS, DSR and marker-text checks. + wrapper = exporter.capture_facts + capture = FunctionType(wrapper.__code__, {**wrapper.__globals__, "_CAPTURE": namespace, "probe": adapted_probe}, + argdefs=wrapper.__defaults__) + facts = capture(directory, plan, source_root) + for phase in facts["phases"]: + phase["document_projection"]["synthetic_text"]["catalog_source"] = ( + "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order") + return facts + + +def export(directory, plan_path, destination, expected_plan_sha256, source_root=ROOT, reference_source=None): + directory, plan_path, destination, source_root = [Path(path).resolve() for path in + (directory, plan_path, destination, source_root)] + # The caller supplies the old authorized plan's external hash. Never infer + # that authorization from a mutable plan read from the recording directory. + require(sha(plan_path) == digest(expected_plan_sha256), "Authorized plan bytes differ") + require(not destination.exists(), "Export destination must be new") + plan = read(plan_path) + require(plan.get("case_id") == CASE and all(type(plan.get(k)) is type(v) and plan[k] == v + for k, v in probe.fixed_contract(CASE).items()), "Fixed hidden-height contract differs") + require(plan.get("execution_authorized") is True, "Plan did not authorize execution") + before = {name: sha(directory / name) for name in RAW_NAMES} + facts = capture_facts(directory, plan, source_root) + original = exporter.provenance_facts + provenance_function = FunctionType(original.__code__, {**original.__globals__, "raw_names": lambda case: RAW_NAMES}, + argdefs=original.__defaults__) + reference_source = Path(plan["source"]) if reference_source is None else Path(reference_source) + provenance = provenance_function(directory, plan_path, plan, source_root, reference_source.resolve()) + require(before == {name: sha(directory / name) for name in RAW_NAMES} and + sha(plan_path) == expected_plan_sha256 and not (directory / "mechanics-check.json").exists(), + "Preserved recording/plan changed during supplemental audit") + basis = probe.fixed_contract(CASE)["geometry_basis"]["combined"] + result = { + "schema": "termforge-original-resize-hidden-height-tail-supplement-v1", "issue": 29, "related_issue": 27, + "case_id": CASE, "authorized_plan_sha256": expected_plan_sha256, + "offline_audit_source_files_sha256": {name: sha(ROOT / name) for name in AUDIT_SOURCES}, + "status": "original-audit-failed-offline-supplement-passed", "failure_preserved": True, + "original_audit": {"status": "failed", "error_type": "ValueError", "message": ORIGINAL_ERROR, + "failure_reproduced": True, "mechanics_file_absent": True}, + "offline_supplemental_audit": {"status": "passed", "additional_original_runs": 0, + "source_interval": {"source_ascii_bytes": 92, "begin": 61, "end": 91, + "operation": "S[:61] + S[91:]", "source_utf8_hex": (" "*89+"uvw").encode().hex(), + "candidate_utf8_hex": (" "*61+"w").encode().hex(), + "candidate_sha256": "fd45397fff8c462d3d86f913e07aab5f74f3e2675d07c05fdc61ad7e0a08110a"}, + "additional_text_candidates": 1, "applicable_phases": [5, 6], "document_line": 11}, + "geometry_basis": {"combined": {"reference": basis["reference"], + "strict_export_sha256": digest(basis["strict_export_sha256"]), + "execution_source_base_commit": basis["execution_source_base_commit"]}, + "hidden_primary_height_previously_observed": False}, + "actual_original_runs": 1, "maximum_original_runs": 1, "semantic_acceptance": False, + "hidden_height_policy_classification": None, "full_active_grid_verified": False, + "terminal_styles_verified": False, "local_shell_transport_verified": False, "presented_done": None, + "performance_gate": "not_evaluated", "r2_complete": False, "rea_capture_seconds": 45, + "cli_wait_timeout_seconds": 60, "whole_lifecycle_bound_seconds": None, + "deliberate_original_process_termination": True, "natural_gui_exit_verified": False, + "capture": facts, "provenance": provenance, + "limitations": [ + "The original fixed audit failed; that failure is reproduced and its missing mechanics file is not fabricated.", + "Only S[:61]+S[91:] from the fixed 89-space-plus-uvw source is added, at document row11 in phases5/6; no target is rerun.", + "The separate offline audit rechecks the frozen protocol, geometry, generated script, provider, complete original package, sources and profile.", + "Document markers, DSR and visible rectangles remain separate observations; exposed text during alternate stages is not classified as the active alternate grid or private buffer storage.", + "This one direct Telnet recording does not establish full grid, styles, local-shell transport, reliability repetition or performance acceptance.", + "Only complete finite source-derived ASCII arrays are reconstructed publicly; unrestricted raw text, paths, process identifiers, profiles and original artifacts remain private.", + ], + } + payload = (json.dumps(result, ensure_ascii=False, indent=2, allow_nan=False) + "\n").encode() + destination.parent.mkdir(parents=True, exist_ok=True) + with destination.open("xb") as stream: + stream.write(payload) + return result + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description=__doc__) + for name in ("directory", "plan", "destination"): + parser.add_argument("--" + name, type=Path, required=True) + parser.add_argument("--expected-plan-sha256", required=True) + parser.add_argument("--source-root", type=Path, default=ROOT) + parser.add_argument("--reference-source", type=Path) + args = parser.parse_args() + result = export(args.directory, args.plan, args.destination, args.expected_plan_sha256, + args.source_root, args.reference_source) + print(json.dumps({"exported": True, "schema": result["schema"], "original_audit_failed": True, + "supplemental_audit_passed": True, "sha256": sha(args.destination)})) diff --git a/research/ui/results/2026-11-02-resize-hidden-height-reference/README.md b/research/ui/results/2026-11-02-resize-hidden-height-reference/README.md new file mode 100644 index 00000000..fb98f725 --- /dev/null +++ b/research/ui/results/2026-11-02-resize-hidden-height-reference/README.md @@ -0,0 +1,58 @@ +# 隐藏主屏高度:原版严格审计失败保留,离线补充审计通过 + +[隐藏主屏高度探针](../../resize_hidden_height_reference.md)于 2026-11-02 在受控取证环境完成一次七阶段原版运行(`primary 91×20 → 61×20 → 1049h → 61×14 → 61×20 → 1049l → 91×20`)。严格导出被固定文本白名单拒绝(`Only fixed hidden-height-source synthetic document lines are allowed`),该失败原样保留。 + +本次从仍可用的取证环境恢复出完整录制(含 `app`、`profile` 与运行结果),以**只读原始录制、不重跑原版、不改旧失败记录**的方式完成独立离线补充审计: + +- 补充结果:[hidden-height-tail-supplement.json](hidden-height-tail-supplement.json),SHA256 `4c0f28f25adf2acc6c5124889ae0dd430425f871a7de0d1fdb68ffacb78564ed`。 +- `schema=termforge-original-resize-hidden-height-tail-supplement-v1`,`status=original-audit-failed-offline-supplement-passed`,`failure_preserved=true`,`additional_original_runs=0`。 +- 原失败复现为同一 `ValueError` 且 `mechanics-check.json` 仍不存在;新增派生文本仅为固定源 `S[:61]+S[91:]`(`S = 89 spaces + uvw`),仅适用于返回阶段 5/6 的文档行 11。 +- 授权计划 SHA256 `938992c4c68eb0c0587d3c789e4d1711a70264df5f7631c904707e29c7280fb`;执行源码基 `88ace8dec723f0fe2fb41d7077e83b6cda6a4d61`;执行源归档清单 `51e80b93…`;原版 `WindTerm.exe` `7b1053…` 与 4047 文件清单 `e459adf2…` 重新核验通过。 +- 七阶段、源 91 B、DSR 请求 28 B;公开件只含来源可派生文本,不含私有路径、原包或 profile。 + +## 审计后的阶段观察 + +| 阶段 | 网格 | DSR | 文档行数 | 文档行 11(零基) | +|---|---|---|---|---| +| 0 primary-initial-body | 91×20 | 19;7 | 19 | 89 空格 + `uvw`(92) | +| 1 primary-width-shrunk | 61×20 | 19;7 | 19 | 89 空格 + `uvw`(92) | +| 2 alternate-entered | 61×20 | 1;1 | 20 | 89 空格 + `uvw`(92) | +| 3 alternate-height-shrunk | 61×14 | 1;1 | 20 | 89 空格 + `uvw`(92) | +| 4 alternate-height-restored | 61×20 | 1;1 | 20 | 89 空格 + `uvw`(92) | +| 5 primary-restored | 61×20 | 14;7 | 19 | **61 空格 + `w`(62)** | +| 6 primary-width-restored | 91×20 | 14;7 | 18 | 61 空格 + `w`(62) | + +即:备用屏活动期间 API 仍返回主文档(不能当作活动备用屏网格);返回主屏后,宽行被恢复到**当前协议宽度**:`u`、`v` 与 61..90 列的空格消失,仅软续接的 `w` 保留,DSR 由 `19;7` 变为 `14;7`。文档行 18(末尾空行)在阶段 6 的公开数组中不再出现。 + +## 与当前核心的差异 + +当前核心在 #311 后的工程合同是“隐藏帧只在宽度实际变化时适配足迹,纯高度变化保留源 Cell”(`resize_hidden_height_test`,已合入)。实测该路径返回主屏后保留 `89 空格 + uvw`(92 字符);上表原版返回后为 `61 空格 + w`(62 字符)。因此: + +- 原版行为更接近“返回时按当前宽度裁剪隐藏主屏保留行”,与 #311 的保留合同**不一致**; +- 当前产品按 ADR-0010 已确认的正文保留方向实现,属于对原版观察的**有意差异**,但差异本身尚未经用户确认,也未据本记录修改实现或 #311 报告; +- 该差异涉及隐藏帧/1049 返回的具体行为选择,按项目规则应提交用户确认后再决定是否调整合同或实现。 + +本记录只完成取证与对比,不修改核心代码,不关闭 #27/#29,`semantic_acceptance=false`、`hidden_height_policy_classification=null`。 + +## 复验 + +离线审计与测试(不启动原版;证据环境内的录制路径不发布): + +```powershell +python -B -X utf8 -m unittest research.ui.test_resize_hidden_height_reference research.ui.test_export_resize_hidden_height_reference research.ui.test_audit_resize_hidden_height_tail -v +python -B -O -X utf8 -m unittest research.ui.test_resize_hidden_height_reference research.ui.test_export_resize_hidden_height_reference research.ui.test_audit_resize_hidden_height_tail -v +``` + +补充审计命令(在保留冻结源/录制/计划的环境执行,输出必须为新文件): + +```text +python -m research.ui.audit_resize_hidden_height_tail --directory --plan + --destination --expected-plan-sha256 938992c4c68eb0c0587d3c789e4d1711a70264df5f7631c904707e29c7280fb +``` + +## 边界 + +- 单次直接 Telnet 记录;备用屏阶段的 API 文本不等于活动备用屏网格,矩形/像素与完整 grid、样式未验证。 +- 未重跑,未修改旧失败或旧计划;补充件不把新环境倒填为旧运行 provenance。 +- 未覆盖 Unicode、其他尺寸/连续输出、保存光标交叉、历史淘汰、Qt/固定 ConPTY 或性能。 +- 环境盘点与恢复条件见[取证环境记录](../../../../docs/research/original-evidence-runtime-2026-11-04.md)。 diff --git a/research/ui/results/2026-11-02-resize-hidden-height-reference/hidden-height-tail-supplement.json b/research/ui/results/2026-11-02-resize-hidden-height-reference/hidden-height-tail-supplement.json new file mode 100644 index 00000000..ad33ffde --- /dev/null +++ b/research/ui/results/2026-11-02-resize-hidden-height-reference/hidden-height-tail-supplement.json @@ -0,0 +1,2508 @@ +{ + "schema": "termforge-original-resize-hidden-height-tail-supplement-v1", + "issue": 29, + "related_issue": 27, + "case_id": "hidden-primary-height", + "authorized_plan_sha256": "938992c4c68eb0c0587d3c789e4d17121a70264df5f7631c904707e29c7280fb", + "offline_audit_source_files_sha256": { + "research/ui/audit_resize_hidden_height_tail.py": "6e829ca05e0aeda2363f9985f585a62d105c858a929c0c64e5bcd54bfdf184d0", + "research/ui/export_resize_hidden_height_reference.py": "bcd8ed771ca0233dfb63b2a11876daf5a13020ba612e4bc6f306acdb9133094f", + "research/ui/export_resize_state_reference.py": "473e901305354d4ba8b22c08d22fa506c4d40da0e73bed3bf3122e4ff0e3c9b7", + "research/ui/export_mode_state_reference.py": "7e0a1e0e49f149791464c0dec357d3b5260bc2c34ca9f9c1be4edab35626cdf3" + }, + "status": "original-audit-failed-offline-supplement-passed", + "failure_preserved": true, + "original_audit": { + "status": "failed", + "error_type": "ValueError", + "message": "Only fixed hidden-height-source synthetic document lines are allowed", + "failure_reproduced": true, + "mechanics_file_absent": true + }, + "offline_supplemental_audit": { + "status": "passed", + "additional_original_runs": 0, + "source_interval": { + "source_ascii_bytes": 92, + "begin": 61, + "end": 91, + "operation": "S[:61] + S[91:]", + "source_utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020757677", + "candidate_utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202077", + "candidate_sha256": "fd45397fff8c462d3d86f913e07aab5f74f3e2675d07c05fdc61ad7e0a08110a" + }, + "additional_text_candidates": 1, + "applicable_phases": [ + 5, + 6 + ], + "document_line": 11 + }, + "geometry_basis": { + "combined": { + "reference": "research/ui/results/2026-11-02-resize-combined-reference/strict-export.json", + "strict_export_sha256": "6a1561f3e6f6bc480c6a2f086adf7ed4798d5007b04a7bc71c7ae9deba90cfe6", + "execution_source_base_commit": "2c7c5929e11d911ad69a7e2b7c420120591862ed" + }, + "hidden_primary_height_previously_observed": false + }, + "actual_original_runs": 1, + "maximum_original_runs": 1, + "semantic_acceptance": false, + "hidden_height_policy_classification": null, + "full_active_grid_verified": false, + "terminal_styles_verified": false, + "local_shell_transport_verified": false, + "presented_done": null, + "performance_gate": "not_evaluated", + "r2_complete": false, + "rea_capture_seconds": 45, + "cli_wait_timeout_seconds": 60, + "whole_lifecycle_bound_seconds": null, + "deliberate_original_process_termination": true, + "natural_gui_exit_verified": false, + "capture": { + "phases": [ + { + "phase": 0, + "label": "primary-initial-body", + "source_hex": "1b5b3f366c1b5b3f37681b5b721b5b306d1b5b324a1b5b323b314848544f501b5b363b3148484152445f410d0a484152445f421b5b31323b3930487576771b5b31393b31484c4f57454e44", + "source_bytes": 75, + "source_sha256": "ff48cd41220a72e5da2350dc97c3c8c8c884d48cc4f7fa2328609bf8bc0cb09e", + "dsr_suffix_hex": "1b5b366e", + "cursor_reply": [ + 19, + 7 + ], + "response_hex": "1b5b31393b3752", + "private_dsr_prefix": false, + "frozen_grid": [ + 91, + 20 + ], + "window_rect": [ + 102, + 102, + 1461, + 850 + ], + "window_size": [ + 1360, + 749 + ], + "document_projection": { + "line_count": 19, + "capacity": 20, + "top": null, + "scroll": 0, + "caret_api": { + "caretLine": 17, + "caretColumn": 0, + "caretPosition": 131 + }, + "markers": [ + { + "label": "HTOP", + "document_line": 1, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 1, + "requested_position_api_value": 1, + "rect": { + "x": 147, + "y": 18, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_A", + "document_line": 5, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 9, + "requested_position_api_value": 9, + "rect": { + "x": 147, + "y": 90, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_B", + "document_line": 6, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 16, + "requested_position_api_value": 16, + "rect": { + "x": 147, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "u", + "document_line": 11, + "line_text_offset_utf16": 89, + "line_text_offset_scalar": 89, + "line_text_prefix_utf8_bytes": 89, + "line_start_api_value": 27, + "requested_position_api_value": 116, + "rect": { + "x": 859, + "y": 198, + "width": 8, + "height": 18 + } + }, + { + "label": "v", + "document_line": 11, + "line_text_offset_utf16": 90, + "line_text_offset_scalar": 90, + "line_text_prefix_utf8_bytes": 90, + "line_start_api_value": 27, + "requested_position_api_value": 117, + "rect": { + "x": 867, + "y": 198, + "width": 8, + "height": 18 + } + }, + { + "label": "w", + "document_line": 11, + "line_text_offset_utf16": 91, + "line_text_offset_scalar": 91, + "line_text_prefix_utf8_bytes": 91, + "line_start_api_value": 27, + "requested_position_api_value": 118, + "rect": { + "x": 147, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "LOWEND", + "document_line": 17, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 125, + "requested_position_api_value": 125, + "rect": { + "x": 147, + "y": 324, + "width": 8, + "height": 18 + } + } + ], + "synthetic_lines_sha256": "ac5cc0c46768d14945e8c63103f3d7d56f9a5fc2f5631dd4fe8f485e9ba19efc", + "synthetic_text": { + "encoding": "UTF-8", + "catalog_source": "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order", + "catalog_count": 13, + "catalog_sha256": "c420a7173a140e0651f3704d8e12996e4b4ff448809df62a104ba8505d68f5f5", + "lines": [ + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 8, + "utf8_hex": "48544f50", + "utf8_bytes": 4, + "unicode_scalars": 4, + "utf16_code_units": 4 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 4, + "utf8_hex": "484152445f41", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 6, + "utf8_hex": "484152445f42", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 3, + "utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020757677", + "utf8_bytes": 92, + "unicode_scalars": 92, + "utf16_code_units": 92 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 10, + "utf8_hex": "4c4f57454e44", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + } + ] + } + }, + "stage_role": "primary-initial-body" + }, + { + "phase": 1, + "label": "primary-width-shrunk", + "source_hex": "", + "source_bytes": 0, + "source_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "dsr_suffix_hex": "1b5b366e", + "cursor_reply": [ + 19, + 7 + ], + "response_hex": "1b5b31393b3752", + "private_dsr_prefix": false, + "frozen_grid": [ + 61, + 20 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "document_projection": { + "line_count": 19, + "capacity": 20, + "top": null, + "scroll": 0, + "caret_api": { + "caretLine": 17, + "caretColumn": 0, + "caretPosition": 131 + }, + "markers": [ + { + "label": "HTOP", + "document_line": 1, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 1, + "requested_position_api_value": 1, + "rect": { + "x": 147, + "y": 18, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_A", + "document_line": 5, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 9, + "requested_position_api_value": 9, + "rect": { + "x": 147, + "y": 90, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_B", + "document_line": 6, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 16, + "requested_position_api_value": 16, + "rect": { + "x": 147, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "u", + "document_line": 11, + "line_text_offset_utf16": 89, + "line_text_offset_scalar": 89, + "line_text_prefix_utf8_bytes": 89, + "line_start_api_value": 27, + "requested_position_api_value": 116, + "rect": { + "x": 371, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "v", + "document_line": 11, + "line_text_offset_utf16": 90, + "line_text_offset_scalar": 90, + "line_text_prefix_utf8_bytes": 90, + "line_start_api_value": 27, + "requested_position_api_value": 117, + "rect": { + "x": 379, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "w", + "document_line": 11, + "line_text_offset_utf16": 91, + "line_text_offset_scalar": 91, + "line_text_prefix_utf8_bytes": 91, + "line_start_api_value": 27, + "requested_position_api_value": 118, + "rect": { + "x": 387, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "LOWEND", + "document_line": 17, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 125, + "requested_position_api_value": 125, + "rect": { + "x": 147, + "y": 324, + "width": 8, + "height": 18 + } + } + ], + "synthetic_lines_sha256": "ac5cc0c46768d14945e8c63103f3d7d56f9a5fc2f5631dd4fe8f485e9ba19efc", + "synthetic_text": { + "encoding": "UTF-8", + "catalog_source": "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order", + "catalog_count": 19, + "catalog_sha256": "0b70999b5513a2dc9b22820cdea8ef8509adc6f52a1759c9417209fac376f5f2", + "lines": [ + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 12, + "utf8_hex": "48544f50", + "utf8_bytes": 4, + "unicode_scalars": 4, + "utf16_code_units": 4 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 6, + "utf8_hex": "484152445f41", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 9, + "utf8_hex": "484152445f42", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 4, + "utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020757677", + "utf8_bytes": 92, + "unicode_scalars": 92, + "utf16_code_units": 92 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 15, + "utf8_hex": "4c4f57454e44", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + } + ] + } + }, + "stage_role": "primary-width-shrunk" + }, + { + "phase": 2, + "label": "alternate-entered", + "source_hex": "1b5b3f3130343968", + "source_bytes": 8, + "source_sha256": "b7c9b6f9082bb2a92f63566d8800008f96b5dee9d380c2d460b2466ad1496440", + "dsr_suffix_hex": "1b5b366e", + "cursor_reply": [ + 1, + 1 + ], + "response_hex": "1b5b313b3152", + "private_dsr_prefix": false, + "frozen_grid": [ + 61, + 20 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "document_projection": { + "line_count": 20, + "capacity": 20, + "top": null, + "scroll": 0, + "caret_api": { + "caretLine": 0, + "caretColumn": 0, + "caretPosition": 0 + }, + "markers": [ + { + "label": "HTOP", + "document_line": 1, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 1, + "requested_position_api_value": 1, + "rect": { + "x": 147, + "y": 18, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_A", + "document_line": 5, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 9, + "requested_position_api_value": 9, + "rect": { + "x": 147, + "y": 90, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_B", + "document_line": 6, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 16, + "requested_position_api_value": 16, + "rect": { + "x": 147, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "u", + "document_line": 11, + "line_text_offset_utf16": 89, + "line_text_offset_scalar": 89, + "line_text_prefix_utf8_bytes": 89, + "line_start_api_value": 27, + "requested_position_api_value": 116, + "rect": { + "x": 371, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "v", + "document_line": 11, + "line_text_offset_utf16": 90, + "line_text_offset_scalar": 90, + "line_text_prefix_utf8_bytes": 90, + "line_start_api_value": 27, + "requested_position_api_value": 117, + "rect": { + "x": 379, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "w", + "document_line": 11, + "line_text_offset_utf16": 91, + "line_text_offset_scalar": 91, + "line_text_prefix_utf8_bytes": 91, + "line_start_api_value": 27, + "requested_position_api_value": 118, + "rect": { + "x": 387, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "LOWEND", + "document_line": 17, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 125, + "requested_position_api_value": 125, + "rect": { + "x": 147, + "y": 324, + "width": 8, + "height": 18 + } + } + ], + "synthetic_lines_sha256": "89149529a66cb9534a3fedc373b2090abef15f5c0f1752a3a247c8ed09b090c0", + "synthetic_text": { + "encoding": "UTF-8", + "catalog_source": "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order", + "catalog_count": 19, + "catalog_sha256": "0b70999b5513a2dc9b22820cdea8ef8509adc6f52a1759c9417209fac376f5f2", + "lines": [ + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 12, + "utf8_hex": "48544f50", + "utf8_bytes": 4, + "unicode_scalars": 4, + "utf16_code_units": 4 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 6, + "utf8_hex": "484152445f41", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 9, + "utf8_hex": "484152445f42", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 4, + "utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020757677", + "utf8_bytes": 92, + "unicode_scalars": 92, + "utf16_code_units": 92 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 15, + "utf8_hex": "4c4f57454e44", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + } + ] + } + }, + "stage_role": "alternate-entered" + }, + { + "phase": 3, + "label": "alternate-height-shrunk", + "source_hex": "", + "source_bytes": 0, + "source_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "dsr_suffix_hex": "1b5b366e", + "cursor_reply": [ + 1, + 1 + ], + "response_hex": "1b5b313b3152", + "private_dsr_prefix": false, + "frozen_grid": [ + 61, + 14 + ], + "window_rect": [ + 102, + 102, + 1101, + 670 + ], + "window_size": [ + 1000, + 569 + ], + "document_projection": { + "line_count": 20, + "capacity": 14, + "top": null, + "scroll": 6, + "caret_api": { + "caretLine": 0, + "caretColumn": 0, + "caretPosition": 0 + }, + "markers": [ + { + "label": "HTOP", + "document_line": 1, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 1, + "requested_position_api_value": 1, + "rect": { + "x": 147, + "y": -90, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_A", + "document_line": 5, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 9, + "requested_position_api_value": 9, + "rect": { + "x": 147, + "y": -18, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_B", + "document_line": 6, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 16, + "requested_position_api_value": 16, + "rect": { + "x": 147, + "y": 0, + "width": 8, + "height": 18 + } + }, + { + "label": "u", + "document_line": 11, + "line_text_offset_utf16": 89, + "line_text_offset_scalar": 89, + "line_text_prefix_utf8_bytes": 89, + "line_start_api_value": 27, + "requested_position_api_value": 116, + "rect": { + "x": 371, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "v", + "document_line": 11, + "line_text_offset_utf16": 90, + "line_text_offset_scalar": 90, + "line_text_prefix_utf8_bytes": 90, + "line_start_api_value": 27, + "requested_position_api_value": 117, + "rect": { + "x": 379, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "w", + "document_line": 11, + "line_text_offset_utf16": 91, + "line_text_offset_scalar": 91, + "line_text_prefix_utf8_bytes": 91, + "line_start_api_value": 27, + "requested_position_api_value": 118, + "rect": { + "x": 387, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "LOWEND", + "document_line": 17, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 125, + "requested_position_api_value": 125, + "rect": { + "x": 147, + "y": 216, + "width": 8, + "height": 18 + } + } + ], + "synthetic_lines_sha256": "89149529a66cb9534a3fedc373b2090abef15f5c0f1752a3a247c8ed09b090c0", + "synthetic_text": { + "encoding": "UTF-8", + "catalog_source": "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order", + "catalog_count": 19, + "catalog_sha256": "0b70999b5513a2dc9b22820cdea8ef8509adc6f52a1759c9417209fac376f5f2", + "lines": [ + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 12, + "utf8_hex": "48544f50", + "utf8_bytes": 4, + "unicode_scalars": 4, + "utf16_code_units": 4 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 6, + "utf8_hex": "484152445f41", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 9, + "utf8_hex": "484152445f42", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 4, + "utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020757677", + "utf8_bytes": 92, + "unicode_scalars": 92, + "utf16_code_units": 92 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 15, + "utf8_hex": "4c4f57454e44", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + } + ] + } + }, + "stage_role": "alternate-height-shrunk" + }, + { + "phase": 4, + "label": "alternate-height-restored", + "source_hex": "", + "source_bytes": 0, + "source_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "dsr_suffix_hex": "1b5b366e", + "cursor_reply": [ + 1, + 1 + ], + "response_hex": "1b5b313b3152", + "private_dsr_prefix": false, + "frozen_grid": [ + 61, + 20 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "document_projection": { + "line_count": 20, + "capacity": 20, + "top": null, + "scroll": 0, + "caret_api": { + "caretLine": 0, + "caretColumn": 0, + "caretPosition": 0 + }, + "markers": [ + { + "label": "HTOP", + "document_line": 1, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 1, + "requested_position_api_value": 1, + "rect": { + "x": 147, + "y": 18, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_A", + "document_line": 5, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 9, + "requested_position_api_value": 9, + "rect": { + "x": 147, + "y": 90, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_B", + "document_line": 6, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 16, + "requested_position_api_value": 16, + "rect": { + "x": 147, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "u", + "document_line": 11, + "line_text_offset_utf16": 89, + "line_text_offset_scalar": 89, + "line_text_prefix_utf8_bytes": 89, + "line_start_api_value": 27, + "requested_position_api_value": 116, + "rect": { + "x": 371, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "v", + "document_line": 11, + "line_text_offset_utf16": 90, + "line_text_offset_scalar": 90, + "line_text_prefix_utf8_bytes": 90, + "line_start_api_value": 27, + "requested_position_api_value": 117, + "rect": { + "x": 379, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "w", + "document_line": 11, + "line_text_offset_utf16": 91, + "line_text_offset_scalar": 91, + "line_text_prefix_utf8_bytes": 91, + "line_start_api_value": 27, + "requested_position_api_value": 118, + "rect": { + "x": 387, + "y": 216, + "width": 8, + "height": 18 + } + }, + { + "label": "LOWEND", + "document_line": 17, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 125, + "requested_position_api_value": 125, + "rect": { + "x": 147, + "y": 324, + "width": 8, + "height": 18 + } + } + ], + "synthetic_lines_sha256": "89149529a66cb9534a3fedc373b2090abef15f5c0f1752a3a247c8ed09b090c0", + "synthetic_text": { + "encoding": "UTF-8", + "catalog_source": "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order", + "catalog_count": 19, + "catalog_sha256": "0b70999b5513a2dc9b22820cdea8ef8509adc6f52a1759c9417209fac376f5f2", + "lines": [ + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 12, + "utf8_hex": "48544f50", + "utf8_bytes": 4, + "unicode_scalars": 4, + "utf16_code_units": 4 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 6, + "utf8_hex": "484152445f41", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 9, + "utf8_hex": "484152445f42", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 4, + "utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020757677", + "utf8_bytes": 92, + "unicode_scalars": 92, + "utf16_code_units": 92 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 15, + "utf8_hex": "4c4f57454e44", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + } + ] + } + }, + "stage_role": "alternate-height-restored" + }, + { + "phase": 5, + "label": "primary-restored", + "source_hex": "1b5b3f313034396c", + "source_bytes": 8, + "source_sha256": "36a3d2013e70720f8d7c0105d9b9c23acfa208b175099330c7c820ad3e1e1df5", + "dsr_suffix_hex": "1b5b366e", + "cursor_reply": [ + 14, + 7 + ], + "response_hex": "1b5b31343b3752", + "private_dsr_prefix": false, + "frozen_grid": [ + 61, + 20 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "document_projection": { + "line_count": 19, + "capacity": 20, + "top": null, + "scroll": 5, + "caret_api": { + "caretLine": 17, + "caretColumn": 0, + "caretPosition": 101 + }, + "markers": [ + { + "label": "HTOP", + "document_line": 1, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 1, + "requested_position_api_value": 1, + "rect": { + "x": 147, + "y": -72, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_A", + "document_line": 5, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 9, + "requested_position_api_value": 9, + "rect": { + "x": 147, + "y": 0, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_B", + "document_line": 6, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 16, + "requested_position_api_value": 16, + "rect": { + "x": 147, + "y": 18, + "width": 8, + "height": 18 + } + }, + { + "label": "w", + "document_line": 11, + "line_text_offset_utf16": 61, + "line_text_offset_scalar": 61, + "line_text_prefix_utf8_bytes": 61, + "line_start_api_value": 27, + "requested_position_api_value": 88, + "rect": { + "x": 147, + "y": 126, + "width": 8, + "height": 18 + } + }, + { + "label": "LOWEND", + "document_line": 17, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 95, + "requested_position_api_value": 95, + "rect": { + "x": 147, + "y": 234, + "width": 8, + "height": 18 + } + } + ], + "synthetic_lines_sha256": "25924feb7d89f603c4a830f2019744954b17404094046606e1b2b26772d6a567", + "synthetic_text": { + "encoding": "UTF-8", + "catalog_source": "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order", + "catalog_count": 20, + "catalog_sha256": "9e005e66ee762dc91d979bff86b06ab41c7e61f10d2a48c351f8384f586e510a", + "lines": [ + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 13, + "utf8_hex": "48544f50", + "utf8_bytes": 4, + "unicode_scalars": 4, + "utf16_code_units": 4 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 7, + "utf8_hex": "484152445f41", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 10, + "utf8_hex": "484152445f42", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 5, + "utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202077", + "utf8_bytes": 62, + "unicode_scalars": 62, + "utf16_code_units": 62 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 16, + "utf8_hex": "4c4f57454e44", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + } + ] + } + }, + "stage_role": "primary-restored" + }, + { + "phase": 6, + "label": "primary-width-restored", + "source_hex": "", + "source_bytes": 0, + "source_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "dsr_suffix_hex": "1b5b366e", + "cursor_reply": [ + 14, + 7 + ], + "response_hex": "1b5b31343b3752", + "private_dsr_prefix": false, + "frozen_grid": [ + 91, + 20 + ], + "window_rect": [ + 102, + 102, + 1461, + 850 + ], + "window_size": [ + 1360, + 749 + ], + "document_projection": { + "line_count": 18, + "capacity": 20, + "top": null, + "scroll": 5, + "caret_api": { + "caretLine": 17, + "caretColumn": 0, + "caretPosition": 101 + }, + "markers": [ + { + "label": "HTOP", + "document_line": 1, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 1, + "requested_position_api_value": 1, + "rect": { + "x": 147, + "y": -72, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_A", + "document_line": 5, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 9, + "requested_position_api_value": 9, + "rect": { + "x": 147, + "y": 0, + "width": 8, + "height": 18 + } + }, + { + "label": "HARD_B", + "document_line": 6, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 16, + "requested_position_api_value": 16, + "rect": { + "x": 147, + "y": 18, + "width": 8, + "height": 18 + } + }, + { + "label": "w", + "document_line": 11, + "line_text_offset_utf16": 61, + "line_text_offset_scalar": 61, + "line_text_prefix_utf8_bytes": 61, + "line_start_api_value": 27, + "requested_position_api_value": 88, + "rect": { + "x": 635, + "y": 108, + "width": 8, + "height": 18 + } + }, + { + "label": "LOWEND", + "document_line": 17, + "line_text_offset_utf16": 0, + "line_text_offset_scalar": 0, + "line_text_prefix_utf8_bytes": 0, + "line_start_api_value": 95, + "requested_position_api_value": 95, + "rect": { + "x": 147, + "y": 216, + "width": 8, + "height": 18 + } + } + ], + "synthetic_lines_sha256": "853a67974b10be59a009598f60433e26c04da68177094eec790bb239dee511d0", + "synthetic_text": { + "encoding": "UTF-8", + "catalog_source": "audit_resize_hidden_height_tail.synthetic_lines(case_id, phase); sorted ASCII scalar order", + "catalog_count": 20, + "catalog_sha256": "9e005e66ee762dc91d979bff86b06ab41c7e61f10d2a48c351f8384f586e510a", + "lines": [ + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 13, + "utf8_hex": "48544f50", + "utf8_bytes": 4, + "unicode_scalars": 4, + "utf16_code_units": 4 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 7, + "utf8_hex": "484152445f41", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 10, + "utf8_hex": "484152445f42", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 5, + "utf8_hex": "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202077", + "utf8_bytes": 62, + "unicode_scalars": 62, + "utf16_code_units": 62 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 0, + "utf8_hex": "", + "utf8_bytes": 0, + "unicode_scalars": 0, + "utf16_code_units": 0 + }, + { + "catalog_index": 16, + "utf8_hex": "4c4f57454e44", + "utf8_bytes": 6, + "unicode_scalars": 6, + "utf16_code_units": 6 + } + ] + } + }, + "stage_role": "primary-width-restored" + } + ], + "source_bytes": 91, + "dsr_request_bytes": 28, + "application_reply_bytes": 46, + "window_rect_format": "qt-qrect-inclusive-ltrb", + "geometry_checks": [ + { + "phase": 0, + "expected_size": [ + 1360, + 749 + ], + "window_rect": [ + 102, + 102, + 1461, + 850 + ], + "window_size": [ + 1360, + 749 + ], + "observed_grid": [ + 91, + 20 + ], + "terminal_capacity": 20, + "event_count": 1 + }, + { + "phase": 1, + "expected_size": [ + 1000, + 749 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "observed_grid": [ + 61, + 20 + ], + "terminal_capacity": 20, + "event_count": 2 + }, + { + "phase": 2, + "expected_size": [ + 1000, + 749 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "observed_grid": [ + 61, + 20 + ], + "terminal_capacity": 20, + "event_count": 2 + }, + { + "phase": 3, + "expected_size": [ + 1000, + 569 + ], + "window_rect": [ + 102, + 102, + 1101, + 670 + ], + "window_size": [ + 1000, + 569 + ], + "observed_grid": [ + 61, + 14 + ], + "terminal_capacity": 14, + "event_count": 3 + }, + { + "phase": 4, + "expected_size": [ + 1000, + 749 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "observed_grid": [ + 61, + 20 + ], + "terminal_capacity": 20, + "event_count": 4 + }, + { + "phase": 5, + "expected_size": [ + 1000, + 749 + ], + "window_rect": [ + 102, + 102, + 1101, + 850 + ], + "window_size": [ + 1000, + 749 + ], + "observed_grid": [ + 61, + 20 + ], + "terminal_capacity": 20, + "event_count": 4 + }, + { + "phase": 6, + "expected_size": [ + 1360, + 749 + ], + "window_rect": [ + 102, + 102, + 1461, + 850 + ], + "window_size": [ + 1360, + 749 + ], + "observed_grid": [ + 91, + 20 + ], + "terminal_capacity": 20, + "event_count": 5 + } + ], + "frozen_grids": [ + [ + 91, + 20 + ], + [ + 61, + 20 + ], + [ + 61, + 20 + ], + [ + 61, + 14 + ], + [ + 61, + 20 + ], + [ + 61, + 20 + ], + [ + 91, + 20 + ] + ], + "naws_history": [ + [ + 91, + 20 + ], + [ + 61, + 20 + ], + [ + 61, + 14 + ], + [ + 61, + 20 + ], + [ + 91, + 20 + ] + ], + "freeze_event_counts": [ + 1, + 2, + 2, + 3, + 4, + 4, + 5 + ], + "resize_boundaries": [ + { + "phase": 1, + "before_event_count": 1, + "after_event_count": 2, + "requested_window": [ + 1000, + 749 + ] + }, + { + "phase": 3, + "before_event_count": 2, + "after_event_count": 3, + "requested_window": [ + 1000, + 569 + ] + }, + { + "phase": 4, + "before_event_count": 3, + "after_event_count": 4, + "requested_window": [ + 1000, + 749 + ] + }, + { + "phase": 6, + "before_event_count": 4, + "after_event_count": 5, + "requested_window": [ + 1360, + 749 + ] + } + ], + "job_after": { + "active": 0, + "total": 3, + "terminated": 0 + }, + "provider": { + "id": "frida", + "version": null, + "confidence": "observed", + "evidence_id": "ev_d894daedf05e12cc18827784a565dc3df084caf26fdcf528edab65d15c834bd4", + "messages": 12, + "readiness_messages": 3, + "phase_messages": 7, + "messages_truncated": false, + "cleanup_error": null + }, + "stateful_observation_count": 7, + "post_initial_terminal_input": "1049h atphase2 and1049l atphase5, each followed by DSR; otherwise DSR only, no replacement text or redraw", + "independent_dsr_bounds": { + "row": [ + 1, + 200 + ], + "column": [ + 1, + 500 + ] + }, + "text_units": { + "source": "UTF-8 bytes", + "document_line": "original public API index", + "marker_text_offsets": "JS UTF-16 code units; scalar count coincides only for this ASCII source alphabet", + "position_api": "recorded lineStart API value plus JS UTF-16 offset, passed unchanged to visibleRectFromPosition", + "caret_api": "original API scalar values; numbering policy not inferred", + "rectangles": "actual public API pixel rectangles, kept separate from protocol cells", + "protocol_cursor": "DSR values kept independent of text offsets and pixel rectangles", + "cpp_cell_column_mapping": null, + "document_position_unit_classification": null, + "ascii_only": true + } + }, + "provenance": { + "source_identity": { + "kind": "source-archive", + "manifest_sha256": "51e80b939c4c026a88fd098eeffe4473921815601fbb1435cb7eabd7adedb5cf" + }, + "execution_source_base_commit": "88ace8dec723f0fe2fb41d7077e83b6cda6a4d61", + "execution_source_files_sha256": { + "research/ui/resize_hidden_height_reference.py": "565d10b69b7a1015c3412b4b5fd974818acd395aa8ba846835d23cc8998bb0bc", + "research/ui/resize_hidden_height_reference.js": "d03cb790dd9db24275f859e297d867453e35675db2ab3f730e0b3f775fd57bc9", + "research/ui/resize_state_reference.py": "628f9e3a5e3ecea6c34829810df2cdf0e93dc221bd3d19b31b3f5028759f07fd", + "research/ui/mode_state_reference.py": "bac745e74a2653412ea7a701e3a1f3defa1fb97fdd7841b73fad483120496ec4", + "research/ui/alternate_reference.py": "94b85d49347e0e9813f7acddf0244f58520a7d1fce14084677c91cf4ddafffea", + "research/ui/r1_launch.py": "54fb41872c6abcc48242a0938044184854b016785cc13659c66b1bf404da0d8a", + "research/ui/launch.py": "6970e0d4f2fe5e7ec4827df7aa1026cd0e74aeb828cdc9b7a0b42b3c887eb4e6", + "research/ui/qt_r1_text.js": "f5820d413fdd72c13dffcefbf4d0ade615abfe15754c6b0b52e1e098814eea6f", + "research/ui/r1_vt_fixture.py": "5853f684d5b8a4c17a30f22a536f04f0eb212813b8d6b3cc3c197df392eb732a", + "experiments/conpty/run.py": "3766879cafe38aabf53cfac8ab2f62985b1976b6fa24c8b6031258bdc914258f" + }, + "launcher_namespace_sha256": "87991144533e11820b03cc9fcf49e0afa14ae99106f75bed81231247a53bcdbd", + "reference_identity": { + "exe_sha256": "7b10531dccc7cd614ae559f36f1ef518e0c96335637431b4646354823b2804d0", + "manifest_sha256": "e459adf2f12adb6a1b7f55e66a9da1c22794185e66e848057d21e0c60d669203", + "files_verified": 4047, + "module_files_sha256": { + "WindTerm.exe": "7b10531dccc7cd614ae559f36f1ef518e0c96335637431b4646354823b2804d0", + "Qt5Core.dll": "8d2ff4ce9096ddccc4f4cd62c2e41fc854cfd1b0d6e8d296645a7f5fd4ae565a", + "Qt5Gui.dll": "5e7d2d41b8b92a880e83b8cc0ca173f5da61218604186196787ee1600956be1e", + "Qt5Widgets.dll": "3788c669d4b645e5a576de9fc77fca776bf516d43c89143dc2ca28291ba14358", + "Qt5Qml.dll": "30035484c81590976627f8face9507caa8581a7dc7630cccf6a8d6de65cab707" + } + }, + "launch_host": { + "windows_version": "10.0.26300", + "python_version_number": "3.12.10", + "python_exe_sha256": "4d6f5f81a4bca11191c4c7c6b43632694d0a4ce74e068619d8fdc161d469859a", + "node_exe_sha256": "1c331340fa6cac5e4294725959070a143fa0507195a78ad77eed7943f719aac9", + "rea_package_version": "6.7.0", + "rea_shim_sha256": "d092352a4088e7df223e9fe39039d703411dc5cbd39990f69756ade448ef1de4", + "rea_package_json_sha256": "3f6c47fb12c8388f291a21e7f99a876495d03aee671b3b6a0708dd12d6ebb570", + "rea_entry_sha256": "ed06cee49505b95a3cc5fceb1b4b279167e26df86227c644bb366ffffdbaf738", + "runtime_identity_source": "recorded execution plan; exporter does not execute the captured runtimes" + }, + "raw_files": { + "evidence.json": { + "bytes": 27809, + "sha256": "20699f4afbb0bfeb437839d6c42495977f4e2997f3a9c2d55b008da648adf755" + }, + "run.json": { + "bytes": 617, + "sha256": "fb49d299168f82634da6319ab9ab65d03123dcd6052951dc8fc8b578835c4e71" + }, + "probe.js": { + "bytes": 26320, + "sha256": "e4452806e0eddf45b7588af89276536465d904f36b52d8f3fc67eab74ef43396" + }, + "peer.json": { + "bytes": 3343, + "sha256": "66489b4315e5fa7f635aecd11bba99404dcb228bc78f7852ef0ee679eca09b52" + }, + "resize-hidden-height-result.json": { + "bytes": 13066, + "sha256": "c70c40bc3bbe0a0cd27ce4ea783bc62ccf25a97fec3179991996f3646729f979" + }, + "files.json": { + "bytes": 637666, + "sha256": "a25c87cba935294d5bfd3bbc76c650d31a8473809564d798ad5a889e4aea00e8" + }, + "stderr.txt": { + "bytes": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "profile-check.json": { + "bytes": 52, + "sha256": "5e522a64e98197722ccd084639b1ce50258b238e03be2f016e81c8af023b5ee1" + }, + "cleanup.json": { + "bytes": 42, + "sha256": "8400f93b6a4a4a50cde35b5d474660590ed215732f55772a9d8afac138da4f1d" + }, + "fixture-ready": { + "bytes": 32, + "sha256": "1f0b8ece17746ce41c81df65e45a6f8480747d9b69858dc905a29ae8d4c449cb" + }, + "ack-0": { + "bytes": 8, + "sha256": "604cee807f644af47487bf2bbab442b94212ac5119f36f995f78e9e4694dae8c" + }, + "ack-1": { + "bytes": 8, + "sha256": "604cee807f644af47487bf2bbab442b94212ac5119f36f995f78e9e4694dae8c" + }, + "ack-2": { + "bytes": 8, + "sha256": "604cee807f644af47487bf2bbab442b94212ac5119f36f995f78e9e4694dae8c" + }, + "ack-3": { + "bytes": 8, + "sha256": "604cee807f644af47487bf2bbab442b94212ac5119f36f995f78e9e4694dae8c" + }, + "ack-4": { + "bytes": 8, + "sha256": "604cee807f644af47487bf2bbab442b94212ac5119f36f995f78e9e4694dae8c" + }, + "ack-5": { + "bytes": 8, + "sha256": "604cee807f644af47487bf2bbab442b94212ac5119f36f995f78e9e4694dae8c" + }, + "ack-6": { + "bytes": 8, + "sha256": "604cee807f644af47487bf2bbab442b94212ac5119f36f995f78e9e4694dae8c" + }, + "resize-request-1": { + "bytes": 31, + "sha256": "38caa2237388a5f1b45a7e96077c0f8424d279f6c34ca97d177e16cc47b99fe9" + }, + "resize-ready-1": { + "bytes": 42, + "sha256": "311f5ead4d5362d9c2e384404d7d2b293d6cbd037cefa590190e8b208c00a89c" + }, + "resize-request-3": { + "bytes": 31, + "sha256": "73aa257b7660d2159287f7b1e9a6f11aafcb03a68232a4570b6b855b2acb4d44" + }, + "resize-ready-3": { + "bytes": 42, + "sha256": "46b124472a0f3d50a84e690e7eec5d4cf679ea908611ccfacbcc223dcc1c7948" + }, + "resize-request-4": { + "bytes": 31, + "sha256": "90e0e09f8ab7c5ca1c8f408880ba931490e6841a6527b4304ef3d4bba91e32bb" + }, + "resize-ready-4": { + "bytes": 42, + "sha256": "1b44f9cbaf24d2e1a09d2d730c32e6c8b61578c7f617281b2dc69e30b7b9b747" + }, + "resize-request-6": { + "bytes": 31, + "sha256": "31e66f70e3c075552d07158146b4b58eae1775b25bd5e29526dbdc317a955983" + }, + "resize-ready-6": { + "bytes": 42, + "sha256": "d6701e5a8b78e229395c936079bc41b1348bb8d7c66d42e7cc841ecab9a0c2cc" + } + }, + "authorized_plan": { + "bytes": 8077, + "sha256": "938992c4c68eb0c0587d3c789e4d17121a70264df5f7631c904707e29c7280fb" + } + }, + "limitations": [ + "The original fixed audit failed; that failure is reproduced and its missing mechanics file is not fabricated.", + "Only S[:61]+S[91:] from the fixed 89-space-plus-uvw source is added, at document row11 in phases5/6; no target is rerun.", + "The separate offline audit rechecks the frozen protocol, geometry, generated script, provider, complete original package, sources and profile.", + "Document markers, DSR and visible rectangles remain separate observations; exposed text during alternate stages is not classified as the active alternate grid or private buffer storage.", + "This one direct Telnet recording does not establish full grid, styles, local-shell transport, reliability repetition or performance acceptance.", + "Only complete finite source-derived ASCII arrays are reconstructed publicly; unrestricted raw text, paths, process identifiers, profiles and original artifacts remain private." + ] +} diff --git a/research/ui/test_audit_resize_hidden_height_tail.py b/research/ui/test_audit_resize_hidden_height_tail.py new file mode 100644 index 00000000..4c27760d --- /dev/null +++ b/research/ui/test_audit_resize_hidden_height_tail.py @@ -0,0 +1,172 @@ +"""Independent hidden-height tail supplement using inert recordings and package files.""" +from contextlib import contextmanager +import copy +import json +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest +from unittest.mock import patch + +from research.ui import audit_resize_hidden_height_tail as audit +from research.ui import resize_hidden_height_reference as probe +from research.ui.test_export_resize_hidden_height_reference import complete_fixture, fixture, marker_rows, save + + +def capture_fixture(root): + directory, data, plan = fixture(root, audit.CASE) + # Negative capture/CLI cases stop before provenance. Keep its required raw + # inventory present; the complete export test supplies a real inert manifest. + (directory / "files.json").write_text("{}") + return directory, data, plan + + +def delete_interval(directory, data): + for observed in data[probe.RESULT_FILE]["observations"][5:]: + terminal = observed["terminal"] + source = " " * 89 + "uvw" + terminal["lines"][11] = source[:61] + source[91:] + terminal["markers"] = marker_rows(terminal["lines"]) + save(directory, data) + (directory / "mechanics-check.json").unlink() + + +@contextmanager +def preserved_fixture(root): + with complete_fixture(root, audit.CASE) as values: + directory, data, *_ = values + delete_interval(directory, data) + yield values + + +class HiddenHeightTailSupplementTests(unittest.TestCase): + def test_exact_interval_is_new_only_after_action_and_old_audit_still_rejects_it(self): + added = " " * 61 + "w" + for phase in range(7): + terminal = {"line_count": 12, "lines": [""] * 11 + [added]} + with self.assertRaisesRegex(ValueError, audit.ORIGINAL_ERROR): + probe.validate_document(audit.CASE, phase, terminal) + if phase in (5, 6): + audit.validate_document(audit.CASE, phase, terminal) + self.assertEqual(audit.synthetic_lines(audit.CASE, phase) - probe.synthetic_lines(audit.CASE, phase), {added}) + else: + with self.assertRaises(ValueError): audit.validate_document(audit.CASE, phase, terminal) + + def test_complete_export_preserves_failure_all_files_and_original_namespace(self): + frozen = {name: audit.sha(probe.ROOT / name) for name in probe.SOURCE_FILES} + original_document, original_mechanics = probe.validate_document, probe.audit_mechanics + with tempfile.TemporaryDirectory() as temporary, preserved_fixture(Path(temporary).resolve()) as values: + directory, _, _, plan_path, source_root, official = values + before = {p.name: p.read_bytes() for p in directory.iterdir() if p.is_file()} + destination = Path(temporary) / "public/result.json" + result = audit.export(directory, plan_path, destination, audit.sha(plan_path), source_root, official) + self.assertEqual(result["status"], "original-audit-failed-offline-supplement-passed") + self.assertTrue(result["failure_preserved"]) + self.assertEqual(result["original_audit"]["message"], audit.ORIGINAL_ERROR) + self.assertEqual(result["offline_supplemental_audit"]["additional_original_runs"], 0) + self.assertEqual(len(result["capture"]["phases"]), 7) + self.assertEqual(result["capture"]["source_bytes"], 91) + self.assertEqual(result["capture"]["dsr_request_bytes"], 28) + supplement = result["offline_supplemental_audit"] + self.assertEqual(supplement["applicable_phases"], [5,6]) + self.assertEqual(supplement["document_line"], 11) + self.assertEqual(supplement["source_interval"]["begin"], 61) + self.assertEqual(supplement["source_interval"]["end"], 91) + self.assertEqual(supplement["source_interval"]["candidate_sha256"], + "fd45397fff8c462d3d86f913e07aab5f74f3e2675d07c05fdc61ad7e0a08110a") + self.assertEqual(set(result["provenance"]["raw_files"]), set(audit.RAW_NAMES)) + self.assertNotIn("mechanics-check.json", result["provenance"]["raw_files"]) + self.assertEqual(before, {p.name: p.read_bytes() for p in directory.iterdir() if p.is_file()}) + self.assertNotIn(str(directory), destination.read_text()) + for phase in result["capture"]["phases"]: + public = phase["document_projection"]["synthetic_text"] + self.assertIn("audit_resize_hidden_height_tail.synthetic_lines", public["catalog_source"]) + if phase["phase"] in (5,6): + self.assertEqual(bytes.fromhex(public["lines"][11]["utf8_hex"]).decode("ascii"), " "*61+"w") + self.assertIs(probe.validate_document, original_document) + self.assertIs(probe.audit_mechanics, original_mechanics) + self.assertEqual(frozen, {name: audit.sha(probe.ROOT / name) for name in probe.SOURCE_FILES}) + + def test_unknown_text_overflow_and_repeated_source_markers_fail(self): + for lines in (["PRIVATE"], [" " * 61 + "w "], [" " * 62 + "w"], ["Q"], + [""]*11+[" "*61+"w"," "*61+"w"], ["HTOP", "HTOP"], [" "*61+"w"]): + with self.subTest(lines=lines), self.assertRaises(ValueError): + audit.validate_document(audit.CASE, 5, {"line_count": len(lines), "lines": lines}) + with self.assertRaises(ValueError): audit.synthetic_lines("width-height-retention", 5) + + def test_plan_hash_is_checked_before_reading_or_auditing_recording(self): + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary).resolve(); plan = root / "plan.json"; plan.write_text("{}") + with patch.object(audit, "capture_facts", side_effect=AssertionError("Must not inspect recording")): + with self.assertRaisesRegex(ValueError, "Authorized plan bytes differ"): + audit.export(root / "missing", plan, root / "public/result.json", "0" * 64) + self.assertFalse((root / "public").exists()) + + def test_other_mechanical_errors_before_and_after_old_text_failure_are_not_swallowed(self): + for changed in ("early-naws", "late-geometry", "late-ack", "extra-reply", "private-text", "duplicate-marker", + "provider", "provider-observations", "script", "partial", "mechanics-present", "old-audit-passes"): + with self.subTest(changed=changed), tempfile.TemporaryDirectory() as temporary: + root = Path(temporary).resolve(); directory, data, plan = capture_fixture(root) + original = copy.deepcopy(data) + delete_interval(directory, data) + result, peer = data[probe.RESULT_FILE], data["peer.json"] + if changed == "early-naws": peer["frozen_grids"][0] = [92, 20] + elif changed == "late-geometry": result["observations"][6]["window_rect"][2] += 1 + elif changed == "late-ack": (directory / "ack-6").write_text("missing") + elif changed == "extra-reply": peer["received_hex"] += "1b5b313b3152" + elif changed == "private-text": result["observations"][6]["terminal"]["lines"][1] = "PRIVATE" + elif changed == "duplicate-marker": result["observations"][5]["terminal"]["markers"].append(copy.deepcopy(result["observations"][5]["terminal"]["markers"][0])) + elif changed == "provider": data["evidence.json"]["data"]["evidence"]["provider"]["id"] = "other" + elif changed == "script": (directory / "probe.js").write_bytes(b"changed") + elif changed == "partial": result["observations"].pop() + elif changed == "mechanics-present": (directory / "mechanics-check.json").write_text("{}") + elif changed == "old-audit-passes": data = original + save(directory, data) + if changed == "provider-observations": + data["evidence.json"]["data"]["evidence"]["normalized_result"]["messages"][-1]["payload"]["error"] = "changed" + save(directory, data, synchronize=False) + with self.assertRaises(ValueError): audit.capture_facts(directory, plan) + + def test_full_identity_profile_attempt_and_source_guards_still_apply(self): + for changed in ("module", "source", "manifest", "profile", "attempt", "plan", "destination"): + with self.subTest(changed=changed), tempfile.TemporaryDirectory() as temporary, preserved_fixture(Path(temporary).resolve()) as values: + directory, _, _, plan_path, source_root, official = values + expected = audit.sha(plan_path); destination = Path(temporary) / "public/result.json" + if changed == "module": (directory / "app/Qt5Core.dll").write_bytes(b"changed") + elif changed == "source": (source_root / "research/ui/resize_hidden_height_reference.py").write_bytes(b"changed") + elif changed == "manifest": (directory / "files.json").write_text("{}") + elif changed == "profile": (directory / "profile/.wind/profiles/default.v10/terminal/user.sessions").write_text("[]") + elif changed == "attempt": plan_path.with_suffix(".attempted").write_text("changed") + elif changed == "plan": plan_path.write_bytes(plan_path.read_bytes() + b" ") + elif changed == "destination": destination.parent.mkdir(); destination.write_text("preserved") + with self.assertRaises(ValueError): audit.export(directory, plan_path, destination, expected, source_root, official) + if changed == "destination": self.assertEqual(destination.read_text(), "preserved") + else: self.assertFalse(destination.parent.exists()) + + def test_duplicate_and_nonfinite_recordings_are_rejected(self): + for content in ('{"active":0,"active":0}', '{"active":NaN}'): + with self.subTest(content=content), tempfile.TemporaryDirectory() as temporary: + directory, data, plan = capture_fixture(Path(temporary).resolve()) + delete_interval(directory, data); (directory / "cleanup.json").write_text(content) + with self.assertRaises(ValueError): audit.capture_facts(directory, plan) + + def test_cli_rejects_private_text_normally_and_with_optimization(self): + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary).resolve(); directory, data, plan = capture_fixture(root) + delete_interval(directory, data) + data[probe.RESULT_FILE]["observations"][6]["terminal"]["lines"][1] = "PRIVATE" + save(directory, data); plan_path = root / "plan.json"; plan_path.write_text(json.dumps(plan)) + for optimize in (False, True): + destination = root / ("optimized/result.json" if optimize else "normal/result.json") + command = [sys.executable, "-B", *(["-O"] if optimize else []), "-X", "utf8", "-m", + "research.ui.audit_resize_hidden_height_tail", "--directory", str(directory), "--plan", str(plan_path), + "--expected-plan-sha256", audit.sha(plan_path), "--destination", str(destination)] + result = subprocess.run(command, cwd=probe.ROOT, capture_output=True, text=True, encoding="utf-8", timeout=10) + self.assertNotEqual(result.returncode, 0) + self.assertIn(audit.ORIGINAL_ERROR, result.stderr) + self.assertFalse(destination.parent.exists()) + + +if __name__ == "__main__": + unittest.main()