diff --git a/HANDOFF.md b/HANDOFF.md index 9dedd5f..6a5a726 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -117,6 +117,9 @@ make macos-offline-tests ## 9. 会话日志(最近) +- 2026-11-12 / Claude Code(air):**首键 +4.6 MiB 归因完成(报告 265 §4.2),不改产品代码**。读 `vmmap` 的 MALLOC ZONE 存活分配:首键时点只有两种状态——5.2 MiB(无会话存活,数据已随 `Weak` 缓存释放)或约 19 MiB(有会话存活);新包 8 轮里 3 轮撞上后者、旧包 5 轮 0 轮(偶然概率约 20%),无会话的轮次新旧完全相同。稳态存活堆新包 +0.5 MiB(21.0 vs 20.5)。`memory-gate.sh` 新增参考字段 `heap_live_mb` / `heap_allocations`。副产结论:冷首键 ~30 ms 很可能来自「最后一个会话释放后重新读盘解析」,与本批无关,是否常驻数据需 ADR。PR #273 待合并;已装仍是 `3e428b7`。 +- 2026-11-12 / Claude Code(air):**内存新旧包 A/B(报告 265 §4.1)**。新→旧(1.2.1 发布版)→新,各经 `install.sh` 覆盖安装。稳态私有中位数:`six-words` 新 31.8 / 旧 33.0,`idle-8s` 新 31.6 / 旧 31.0 → **稳态无回归**;但学习区开启时两者都贴 34 MiB 门槛(旧包最高 33.7,新包 11 个样本 2 个超限,同包三次运行 FAIL/PASS/FAIL)。**新发现:首键时点新包 +4.6 MiB(27.8 vs 23.2),未归因。** 结束状态:已装新包 `f38e4e1a…`(`3e428b7`)、输入源萤火虫、config 未变;`updates/` 多出两份 A/B 产生的备份(`…T105406Z`、`…T110001Z`)未删。待用户裁定:门槛是否重测调整、首键内存是否发版前归因。 +- 2026-11-12 / Claude Code(air):**报告 265:延迟 PASS、内存门禁 FAIL(未定性)**。PR #272 已合并,`dev`=`main`,无开放 PR、无多余分支。补 `;` 选第二候选真机样本(PASS;`keytopid` 加命名键 `semicolon`),`12:30` 与五笔码浮层探针测不了。`perf-session`:稳态 p95 7.33 ms / 0 外联(2 轮失焦,汇总脚本崩溃,按原始数据重算)。`memory-gate`:学习区开、门槛 34 MiB,稳态私有 31.0–34.6 MiB,1/6 样本超限;当时 load 12–41、swap 10.2/11.3 GB。**下一步:对新旧包做同条件内存 A/B(旧包在 `updates/install-backup-20261112T060612Z/`),结论出来前不升版本号、不发版。** 已装仍是 `3e428b7`,输入源已选回萤火虫。 - 2026-11-12 / Claude Code(air):**P1-U 真机键入复验 22/22 PASS(报告 264 §3.1)**。用户为代理会话的责任进程(`~/Library/Application Support/Claude/claude-code/<版本>/…/claude.app`,不是 `/Applications/Claude.app`)授了辅助功能权限后复跑 `quality-samples.sh`:原 13 条 + ADR-325…336 的 9 条全过。跑后 `config.toml` 取值还原但多出两行显式默认值(SHA `88651507…`→`52af2b90…`);词库 1713→1715 行(含样本副作用 `pinyin zhuang 装 1`)。**未验证**:`;`/`12:30`、五笔码浮层、练习新题型、设置页新开关、DMG 完成页(需人工目视);内存门禁与延迟未复测。PR #272(报告与探针工具)待合并。 - 2026-11-12 / Claude Code(air):**P1-U 候选 `3e428b7` 装机 PASS、真机键入复验 BLOCKED(报告 264)**。PR #271 已合并;从 CI 验收包(run `43163118879`,ZIP `8e7aece7…`,Notarized)覆盖安装:切 ABC → 停宿主 → `install.sh`,装后执行 `f38e4e1a…` = 包内,config/词库/练习进度 SHA 不变,宿主跑新二进制。**键入复验一条都没跑成**:本会话进程 `AXIsProcessTrusted=false`,合成按键被系统丢弃。已给 `quality-samples.sh` 加 9 条 ADR-325…336 样本,并让 preflight 能识别「无事件投递权限」(`keytopid --check-access`)。**下一步:用户在已授权终端跑报告 264 §4 的一条命令,再按 §5 目视 5 类项**;通过后才谈升版本号与发版。 - 2026-11-12 / Claude Code(air):**P1-U 第三批(ADR-333…336)+ 前两档已合入 main**。PR [#269](https://github.com/EasyIndie/EasyInputMethod/pull/269)(第一档)与 [#270](https://github.com/EasyIndie/EasyInputMethod/pull/270)(第二档)均已用合并提交并入(`c882c06`、`2f8ee06`),**下面一条日志里「第二档未推送」已过时**。第三批:按应用记住中英状态(仅内存)、练习「词组」题型(随包码表前 800 词)、薄弱字清单(`practice.collect_weak_chars` 默认关,`weak-chars.tsv`)、小鹤双拼(`pinyin.scheme`,仅拼音模式;425 个音节 419 个可达)。Schema 27→30。四道检查全绿、评测 98.2%/86.4% 与基线一致。**三批改动全部未装机**,复验清单见 `docs/待办与积压.md` P1-U;P1-U 剩余 8 项都需用户先定口径或授权取数据(同处有表)。仓库已开启 auto-merge。 diff --git a/docs/reviews/265-p1u-followup-latency-memory.md b/docs/reviews/265-p1u-followup-latency-memory.md new file mode 100644 index 0000000..b137eea --- /dev/null +++ b/docs/reviews/265-p1u-followup-latency-memory.md @@ -0,0 +1,133 @@ +# 265 · P1-U 候选 `3e428b7` 补充复验:分号选词、延迟、内存 + +- 日期:2026-11-12 / Claude Code(air 本机) +- 范围:报告 264 之后的收尾——仓库状态核对、把探针测不了的项尽量补上、延迟与内存门禁复测 +- 结论:**延迟 PASS(稳态 p95 7.33 ms,0 外联);内存门禁在学习区开启时不稳定——新旧包 A/B 显示稳态无回归,但两者都贴着 34 MiB 门槛**(§4.1)。 + 新包「首键」时点高约 4.6 MiB 已归因(§4.2):**不是泄漏、也不是数据变多**,是采样时是否恰好有一个输入会话存活;稳态存活堆新包多约 0.5 MiB。 + +## 1. 仓库状态(核对时) + +- 工作区干净;`dev` = `main` = `1265fa7`;开放 PR 0 个;远端只有 `dev` / `main`。 +- 清理:本地 `main` 落后 273 个提交 → 快进到 `origin/main`;`/private/tmp/main-wt` 的失效工作树记录 → `git worktree prune`。无其它分支可清。 + +## 2. 补样本 + +| 项 | 结果 | 说明 | +|---|---|---| +| `;` 选第二候选(ADR-327) | **PASS**(真机) | `keytopid` 新增命名键 `semicolon`。`nihao` `;` `⏎` 实得「你好吗」——第二候选是用户词库里学过的补全词,选中的确实是第二候选而不是「你好;」。因第二候选随用户词库变化,样本只断言「不是首选、也不是首选+;」 | +| `12:30`(ADR-325) | **探针测不了** | 合成的 Shift+; 到宿主时仍是 `;`(实得 `12;30`),无法区分;仍只有 `ime-core` 单测覆盖,需人工打一次 | +| 五笔码浮层(ADR-331) | **可见性未证实** | 诊断日志显示拼音上屏后提示路径已执行且取到了有效光标矩形(TextEdit,`pick … rect=…`);但窗口列表里看不到宿主的在屏窗口,浮层又不在 AX 树里,**是否真的显示出来仍需目视** | + +`quality-samples.sh` 现为 23 条(原 13 + ADR-325…336 的 10 条)。全量第三轮:原 22 条全部 PASS;本轮试加的 3 条里 2 条因上述原因撤掉、1 条改写后单独复跑 PASS。 + +## 3. 延迟(PASS) + +`perf-session.sh`,三段各 10 轮;口径按 ADR-307(稳态不含每轮首键)。 + +| 段 | 有效轮 | 稳态键数 | p50 | **p95** | max | 冷首键 p95 | +|---|---|---|---|---|---|---| +| basic | 8 | 120 | 3.78 | **7.96** | 11.07 | 35.72 | +| long-code | 10 | 119 | 3.58 | **6.95** | 9.68 | 29.88 | +| paging | 10 | 90 | 2.92 | **5.69** | 6.50 | 36.48 | +| **合计** | 28 | 329 | — | **7.33**(门槛 16) | 11.07 | 35.72(不设门槛) | + +- 网络:485 次采样,TCP/UDP 连接合计 **0**。 +- 对比:1.2.0 候选稳态 p95 5.80 ms、冷首键 28.86 / 33.39 ms(报告 259)。稳态略高但远低于门槛;冷首键略高,按 ADR-307 只记录。 + **本机当时负载很高(load average 12–41),数字偏悲观。** +- **工具缺陷(未修)**:`basic` 第 8、9 轮测试窗口没拿到前台(BLOCKED),脚本的汇总步骤读到空结果直接崩溃、没有给出判定; + 上表是用 28 个有效轮的原始数据按同一口径重算的。应让汇总跳过 BLOCKED 轮并如实报告轮数。 + +## 4. 内存门禁(FAIL,未定性) + +`memory-gate.sh` 3 轮;口径 = 稳态时点的「私有已提交」。用户配置开着学习区,按 ADR-312 门槛为 **34 MiB**。 + +| 轮 | first-key | six-words(稳态) | idle-8s(稳态) | +|---|---|---|---| +| 1 | 27.2 | **34.6** ✗ | 31.5 | +| 2 | 27.0 | 31.1 | 31.0 | +| 3 | 26.7 | 33.7 | 31.7 | + +- 6 个稳态样本里 1 个超限(34.6 > 34.0),脚本判 FAIL。 +- **不能据此断定是回归**:测量时 swap 已用 10.2 / 11.3 GB、load average 最高 41,而该口径把换出页也计入; + 三轮之间 `six-words` 相差 3.5 MiB,噪声与超限幅度同量级。学习区开启时的历史参考是「比关闭多约 3 MiB」(报告 256),即约 31–32 MiB。 +- **也不能排除是回归**:本批新增了拼音补全与分段候选(每键多产生最多几十个候选对象)、更多配置项与两个新窗口题型的代码。 +- **定性方法(未做,需再换两次包)**:同一时段、同一配置下,对旧包(`updates/install-backup-20261112T060612Z/`,1.2.1 发布版) + 与新包各跑一次 `memory-gate.sh ROUNDS=5`,比较稳态中位数;差值 > 1 MiB 才按回归处理。最好在重启后、负载正常时做。 + +### 4.1 新旧包 A/B(同机、同配置、同一时段) + +顺序:新包 → 旧包(1.2.1 发布版 `3eeeb0aa…`,取自 `updates/install-backup-20261112T060612Z/`)→ 新包。测量期间 load average 3.7–24,swap 约 10.9 / 12 GB。 +单位 MiB,「私有已提交」。 + +| 包 | 轮数 | first-key | six-words(稳态) | idle-8s(稳态) | 脚本判定 | +|---|---|---|---|---|---| +| 新 `f38e4e1a…`(第 1 次) | 3 | 25.4 / 27.2 / 30.7 | 33.2 / 31.8 / 31.5 | 33.1 / 31.6 / 31.3 | PASS | +| 旧 `3eeeb0aa…` | 5 | 23.2 / 25.5 / 23.7 / 23.2 / 22.6 | 33.5 / 33.7 / 31.0 / 32.1 / 33.0 | 31.5 / 31.0 / 30.8 / 30.3 / 31.0 | PASS | +| 新 `f38e4e1a…`(第 2 次) | 5 | 25.6 / 24.7 / 28.3 / 28.9 / 31.8 | 31.6 / **34.2** / 33.0 / 31.8 / 31.8 | 31.5 / 30.9 / 32.1 / 31.8 / 31.6 | **FAIL** | + +| 时点 | 旧包中位数 | 新包中位数(8 轮合并) | 差 | +|---|---|---|---| +| six-words | 33.0 | 31.8 | **−1.2**(新包不高于旧包) | +| idle-8s | 31.0 | 31.6 | **+0.6**(低于预设的 1 MiB 回归阈值) | +| first-key(不在门禁口径内) | 23.2 | 27.8 | **+4.6** | + +判读: + +1. **稳态没有可判定的回归**:`six-words` 新包反而低,`idle-8s` 高 0.6 MiB,小于事先定的 1 MiB 阈值,也小于轮间抖动(约 3 MiB)。 +2. **门禁本身在这个配置下贴线**:学习区开启时旧包稳态最高已到 33.7 MiB,离 34 只有 0.3;新包 11 个 `six-words` 样本里 2 个超限 + (34.6、34.2),同一份包三次运行出现 FAIL / PASS / FAIL。门槛 34 是按「开学习区多约 3 MiB」定的(ADR-312),在本机当前系统状态下余量不够。 +3. **新包首键时点高约 4.6 MiB**:这是真实差异(两次新包测量一致偏高,旧包 5 轮都低)。它不计入门禁,稳态会收敛到同一水平, + 但说明首键路径上多分配了内存——最可能来自拼音补全/分段候选(首键即扫描词表前缀区间并构造候选),**未做归因**。 + +处置建议(需用户裁定,未自行改门槛): +- a) 认定「稳态无回归」,把学习区开启时的门槛问题单列——在重启后、swap 正常时各测 5 轮,再决定是否调 ADR-312 的 34 MiB; +- b) 另开一项归因首键 +4.6 MiB(看是否能让补全/分段候选惰性化),与发版解耦或作为发版前的小修,二选一。 + +A/B 过程中的换包:旧包与新包各经 `install.sh` 覆盖安装一次,`updates/` 下因此多出两份备份 +(`install-backup-20261112T105406Z` 是新包、`…T110001Z` 是旧包),未删除。结束状态:已装新包 `f38e4e1a…`(`3e428b7`)、 +宿主跑新二进制、输入源为萤火虫、`config.toml` 未变(`99-restore-ab.txt`)。 + +### 4.2 首键 +4.6 MiB 的归因 + +从 A/B 留下的 `vmmap` 快照里读 MALLOC ZONE 表的**存活分配**(字节与个数),而不是「私有已提交」: + +| 包 | 时点 | 存活堆 MiB(逐轮) | 存活分配个数(逐轮,千) | +|---|---|---|---| +| 旧 | first-key | 5.2 / 5.2 / 5.2 / 5.2 / 5.2 | 26.7 ×5 | +| 新(两次共 8 轮) | first-key | 5.1 / 5.2 / **19.2** / 5.2 / 5.2 / 5.2 / **19.4** / **19.2** | 26.7 ×5,**188–191 ×3** | +| 旧 | six-words / idle-8s | 20.5–20.6 / 20.4–20.5 | 188–189 | +| 新 | six-words / idle-8s | 21.0–21.2 / 20.9–21.2 | 190–193 | + +1. **首键时点的存活堆只有两种状态**:5.2 MiB(约 2.67 万个分配)或约 19 MiB(约 19 万个分配)。差的那 14 MiB 就是码表与拼音数据。 + 引擎数据由会话以 `Arc` 持有、缓存只留 `Weak`(`ime-ffi/src/data.rs`)——**没有任何会话存活时数据整体释放**。 + 所以这个时点测到的是「测试窗口退出后,是否恰好有别的客户端的输入会话已经激活」,而不是首键路径分配了多少。 +2. 新包 8 轮里 3 轮处于「有会话存活」状态,旧包 5 轮里 0 轮;把这 3 轮按「私有已提交」算进中位数,就得到了 +4.6 MiB。 + **在「无会话存活」的那 5 轮里,新包的存活堆与旧包完全相同**(5.2 MiB,分配个数相差不到 30)。 +3. 这是采样时机问题:13 轮里共 3 轮「有会话」,全落在新包的概率按超几何分布约 20%,不足以说明是新代码造成的; + 新增代码里也没有会延长控制器或会话生命周期的引用(闭包均为 `weak self`,`AppLanguageMemory` 只存字符串与布尔)。 + **不能完全排除**新包让别的客户端更早激活,但没有找到机制。 +4. **稳态存活堆新包多约 0.5 MiB**(21.0 vs 20.5,分配多约 1,500–4,000 个)。这是真实增长,量级与「每次组合多保留几十个补全/分段候选、 + `Candidate` 多一个字段、更多配置项」相符,未进一步拆分。 +5. 「私有已提交」在首键时点远大于存活堆(23–28 MiB 对 5.2 MiB):多出来的是分配器已释放但尚未归还系统的页。 + 该口径受采样时机与碎片影响大,这也是 §4.1 里同一份包三次判定不一致的原因之一。 + +**结论**:首键内存不需要改产品代码。**工具已改**:`memory-gate.sh` 的每个采样现在额外输出 `heap_live_mb` 与 `heap_allocations` +(只作参考、不参与判定),以后能直接区分「数据真变多了」与「分配器残留 / 会话是否存活」。 + +**对冷首键延迟的含义**:数据随最后一个会话释放,意味着「所有输入框都失焦后的第一次按键」要重新读盘解析码表—— +这很可能就是冷首键 30 ms 量级延迟(ADR-307)的主要来源,且与本批改动无关。是否改成「宿主存活期间常驻数据」是内存换延迟的取舍, +需单独立 ADR(会让无会话时的常驻内存从约 5 MiB 升到约 20 MiB)。 + +## 5. 仍未验证 + +`12:30`、五笔码浮层是否可见、练习「字根」「词组」题型、设置页 7 个新开关、DMG 安装完成页——都需人工目视。 + +## 6. 跑完后的状态 + +输入源已切回萤火虫(内存门禁结束时停在 ABC,已手动选回);已装执行 SHA `f38e4e1a…` 未变;`config.toml` SHA `52af2b90…` 未变; +`weak-chars.tsv` 不存在;探针自开的 TextEdit 文档已关闭并退出。 + +## 7. 证据 + +`platforms/macos/build/acceptance-air-p1u-3e428b7/`:`22-quality.txt`、`quality-3/`、`30-perf.stderr`、`perf/`(逐轮 JSON 与 `net.csv`)、 +`31-memory.txt`、`memory/`、`40-mem-new1.txt`、`41-mem-old.txt`、`42-mem-new2.txt`、`memory-ab-*/`、`99-restore-ab.txt`。 diff --git a/docs/reviews/README.md b/docs/reviews/README.md index a34d34d..5ec9e1e 100644 --- a/docs/reviews/README.md +++ b/docs/reviews/README.md @@ -39,6 +39,7 @@ | 1.1.0 发布线 | 225–250 | 简码/排序、验收成本、延迟归因、1.1.0 发布与站点 | | 1.2.0 候选与发布 | 251–262 | B1 门禁、B0 运行时、学习区、练习四题型与键位图、1.2.0 发布 | | 1.2.1 清理 | 263 | 安装/无障碍补丁、死代码与文档审计 | +| P1-U 补充复验 | 265 | 分号选词真机 PASS;延迟稳态 p95 7.33 ms PASS;内存 A/B:稳态无回归但学习区开启时贴 34 MiB 门槛;首键 +4.6 MiB 归因为采样时会话是否存活(非泄漏),稳态存活堆 +0.5 MiB | | P1-U 装机 | 264 | ADR-324…336 候选 `3e428b7` 装机 PASS;真机键入复验 22/22 PASS(首轮因无辅助功能权限 BLOCKED,授权后复跑);5 类目视项待人工 | ## 4. 常见查找 diff --git a/docs/tasks/T-ITER-22-coverage.md b/docs/tasks/T-ITER-22-coverage.md index b9fe4db..054cf31 100644 --- a/docs/tasks/T-ITER-22-coverage.md +++ b/docs/tasks/T-ITER-22-coverage.md @@ -13,7 +13,7 @@ | IT-22 条目 | 覆盖手段 | 怎么跑 | |---|---|---| -| 1.1–1.3、1.7–1.12 上屏/标点/全角/简繁/模式/中英 | 热键探针 + 质量样本 | `make macos-auto-acceptance`(7 项)、`tools/macos-probe/quality-samples.sh`(22 项) | +| 1.1–1.3、1.7–1.12 上屏/标点/全角/简繁/模式/中英 | 热键探针 + 质量样本 | `make macos-auto-acceptance`(7 项)、`tools/macos-probe/quality-samples.sh`(23 项) | | 1.4 翻页、1.5 方向键选择 | 组合导航单测 + 质量样本「翻页键不破坏输入」 | `make test`、`quality-samples.sh` | | 2.1 长组合不丢字 | 质量样本「长文本不丢字」 | `quality-samples.sh` | | 2.2–2.6 退格/Esc/Home/End/Delete/Tab | 核心与 FFI 单测(ADR-164) | `make test`(`ime-core`/`ime-ffi`) | @@ -77,7 +77,7 @@ make macos-acceptance-full # ~5 分钟:preflight → 热键/上屏 → ## 4. 与旧清单的差异(为什么能砍掉 47 项) 0. **只依赖系统自带应用**(报告234):TextEdit / Safari / Terminal 之外的一律 optional(装了才测、没装 SKIP),由 `test-acceptance-portability.py` 强制。 -1. **同一件事此前被写了三遍**:`quality-samples.sh`(16 项)、`acceptance-auto.sh`(8 项)、IT-22 手工表(12 项重叠)。报告 230 之后两份脚本**按行为分工**:`quality-samples.sh` 断言打字产物(22 项;报告264 起含 ADR-325…336 的 9 条:数字后标点、拼音补全、以词定字、分段选词、双拼、薄弱字、按应用记住英文),`acceptance-auto.sh` 断言热键状态语义(7 项),重复项已删并由 `test-acceptance-map.py` 守住不再回流。 +1. **同一件事此前被写了三遍**:`quality-samples.sh`(16 项)、`acceptance-auto.sh`(8 项)、IT-22 手工表(12 项重叠)。报告 230 之后两份脚本**按行为分工**:`quality-samples.sh` 断言打字产物(23 项;报告264/265 起含 ADR-325…336 的 10 条:数字后标点、拼音补全、分号选词、以词定字、分段选词、双拼、薄弱字、按应用记住英文),`acceptance-auto.sh` 断言热键状态语义(7 项),重复项已删并由 `test-acceptance-map.py` 守住不再回流。 2. **离屏单测已经断言了 GUI 结构**:候选/设置/关于/学习的布局与文案由 `test-*-presentation.py` 断言,手工"看一眼分组是否连续"不再重复。 3. **几何/落点类**(多屏、边缘、翻页位置)已有 `CaretPlacement` 与离屏快照对比度自动判定(ADR-301、报告 197)。 4. **安装类**从"每次走查"降为"每版一次",因为它们只在换包时才有意义。 diff --git "a/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" "b/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" index e4c9d1d..1234205 100644 --- "a/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" +++ "b/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" @@ -80,7 +80,11 @@ > > **装机状态(报告 264)**:三批已合入 `main`,候选 `3e428b7` 已装 air;**真机键入复验 22/22 PASS**(含 ADR-325/326/327/330/333/335/336 的 9 条新样本)。 > **仍待人工目视的 5 类**:`;` 选第二候选与 `12:30`、五笔码提示浮层、练习「字根」「词组」题型、设置页 7 个新开关、DMG 安装完成页。 -> 发版前还需:升版本号(候选与线上同为 1.2.1/40)、IT-22 A 档人工走查、内存门禁与延迟复测(本轮未跑)。 +> **内存(报告 265 §4.1)**:新旧包 A/B——稳态无回归(`six-words` 中位数 新 31.8 / 旧 33.0;`idle-8s` 新 31.6 / 旧 31.0), +> 但学习区开启时两者都贴 34 MiB 门槛,同一份新包三次运行 FAIL / PASS / FAIL。首键时点 +4.6 MiB 已归因(§4.2):采样时是否有会话存活, +> 非泄漏;稳态存活堆新包 +0.5 MiB。待裁定:① 是否在干净系统状态下重测并调整 ADR-312 的门槛(或把判定口径换成存活堆); +> ② 是否让引擎数据在宿主存活期间常驻以消除冷首键重载(内存换延迟,需 ADR)。延迟已复测 PASS(稳态 p95 7.33 ms,0 外联)。 +> 其余发版前事项:升版本号(候选与线上同为 1.2.1/40;**要等内存结论,否则升号后的新候选会让现有真机证据失效**)、IT-22 A 档人工走查、5 类目视项。 > > **P1-U 里剩下的,全部卡在「先要你定一件事」或「先要数据」上**: > diff --git a/tools/macos-probe/keytopid.swift b/tools/macos-probe/keytopid.swift index 447def8..2418c88 100644 --- a/tools/macos-probe/keytopid.swift +++ b/tools/macos-probe/keytopid.swift @@ -40,6 +40,8 @@ let source = CGEventSource(stateID: .hidSystemState) let named: [String: CGKeyCode] = [ "left": 123, "right": 124, "down": 125, "up": 126, "esc": 53, "tab": 48, "return": 36, "delete": 51, "space": 49, + // 报告265:按键串以分号分段,字面的 `;` 打不出来;用命名键 semicolon(`shift+semicolon` 即冒号)。 + "semicolon": 41, ] let modifiers: [String: (CGKeyCode, CGEventFlags)] = [ "shift": (56, .maskShift), "opt": (58, .maskAlternate), "ctrl": (59, .maskControl), diff --git a/tools/macos-probe/memory-gate.sh b/tools/macos-probe/memory-gate.sh index 7a18963..99ba170 100755 --- a/tools/macos-probe/memory-gate.sh +++ b/tools/macos-probe/memory-gate.sh @@ -76,10 +76,15 @@ def parse(path): if not footprint or not writable: return None resident, swapped = to_mb(writable.group(1)), to_mb(writable.group(2)) + # 报告265:「私有已提交」含分配器已释放但未归还的页,受采样时机影响很大; + # 同时记下 MALLOC ZONE 表里的存活分配(字节与个数),用来区分「数据真变多了」与「分配器残留」。只作参考,不参与判定。 + zone = re.search(r"^DefaultMallocZone\S*\s+\S+\s+\S+\s+\S+\s+\S+\s+(\d+)\s+([0-9.]+[KMG]?)", text, re.M) return { "physical_footprint_mb": round(to_mb(footprint.group(1)), 1), "physical_footprint_peak_mb": round(to_mb(peak.group(1)), 1) if peak else None, "private_committed_mb": round(resident + swapped, 1), + "heap_live_mb": round(to_mb(zone.group(2)), 1) if zone else None, + "heap_allocations": int(zone.group(1)) if zone else None, } results, missing, failed = {}, [], False diff --git a/tools/macos-probe/quality-samples.sh b/tools/macos-probe/quality-samples.sh index 3297ad3..235696c 100755 --- a/tools/macos-probe/quality-samples.sh +++ b/tools/macos-probe/quality-samples.sh @@ -115,7 +115,7 @@ run "撤销回到空态" 'wqiy;cmd+z' 'emp run "长文本不丢字" 'nihao nihao nihao nihao wqiy ' 'contains:你好你好' # —— 1.2.1 之后的输入体验(ADR-325…336) —— -# 限制:按键串用分号分段,探针打不出字面的 `;` 与 `:`,所以「; 选第二候选」「12:30」只有单测覆盖。 +# 字面的 `;` 用命名键 semicolon,冒号是 shift+semicolon(按键串本身以分号分段)。 ensure_cn >/dev/null 2>&1 run "数字后句点保持半角" '3.14' 'exact:3.14' run "数字后逗号仍是中文" '3,' 'exact:3,' @@ -124,6 +124,16 @@ run "以词定字取首字" 'nihao[' 'e run "以词定字取末字" 'nihao]' 'exact:好' # 选走前半段(第二候选「你好」只覆盖 nihao)后回车:已选文字 + 余码原文一起上屏。 run "分段选词后回车" 'nihaoshijie2;return' 'exact:你好shijie' +# 冒号没有样本:合成的 Shift+; 到宿主时仍是 `;`(报告265),`12:30` 只有单测覆盖。 +# `;` 选第二候选:第二候选是什么取决于用户词库(学过的词会排上来),所以只断言「不是首选、也不是首选+;」。 +case_semicolon_second() { + TOTAL=$((TOTAL + 1)) + got=$(type_read 'nihao;semicolon;return') + if [ -n "$got" ] && [ "$got" != "你好" ] && [ "$got" != "你好;" ] && check 'unicode:' "$got"; then + printf '%-26s PASS %s\n' "分号选第二候选" "$got" + else printf '%-26s FAIL 应是第二候选,实得 %s\n' "分号选第二候选" "$got"; FAILED=$((FAILED + 1)); fi +} +case_semicolon_second # 改配置只走 ime-config 的写路径(ime-cli :set),用完还原;缺 ime-cli 就记 BLOCKED,不手改 config.toml。 ROOT="$(cd "$PROBE/../.." && pwd)" @@ -171,6 +181,8 @@ case_remember_english() { else printf '%-26s FAIL 期望 nihao,实得 %s\n' "按应用记住英文状态" "$got"; FAILED=$((FAILED + 1)); fi } +# 五笔码浮层(ADR-331)没有样本:浮层不在 AX 树里,窗口列表也看不到它是否可见(报告265),需目视。 + case_double_pinyin case_weak_chars case_remember_english