diff --git a/ROADMAP.md b/ROADMAP.md index 64c2d04..53571eb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -245,7 +245,8 @@ ADR-147:Terminal正常实际提交“你”及wq前缀确认后的failure/INT/ - [ ] **2026-10-27 MVP 正式发布(目标 `1.0.0`,ADR-298)**:阶段 A 在 0.1.16/26 上演练 IT-22(`docs/tasks/T-ITER-22.md`)→ 修复入库 → 阶段 B 递增 1.0.0(build 27)并双机装同一包(同时闭环「更新器自更新」)→ 阶段 C 只在 1.0.0 上做正式 IT-22、IT-15 独立重建、IT-23 五工作日 → 阶段 D `tag v1.0.0` 打在验收候选提交 → Release → Pages。 - [x] 2026-10-28 **锁定候选 1.0.0 / build 29**(报告217):提交 `11abece3`、ZIP `aca4ed5c…`、宿主执行 `4ad949e6…`,air 已装同包。装机定向复验:2.1 多词拼接 PASS、9.1 编码播报 PASS、11.1 候选跟随(6 张截图:下方/镜像/底部翻上,无压字)PASS。**IT-22 限定范围通过**(必查 11 + 抽查 8 全 PASS,其余沿用报告216 基线)。 - [x] 2026-10-28 **IT-15 独立离线重建通过(报告218)**:用户在 air 上从候选自带源码包离线重建 1.0.0/build 29,身份链与逐架构网络导入 PASS、**默认数据 4/4 逐字节一致**、空闲 0 外联;可执行文件因本机 SDK 27.0 vs 发布 26.5 不同(ADR-033 边界)。顺带修掉 `run-repro.sh` 的缺陷:原来 `cmp` 可执行文件失败会中断,导致数据表比对根本没跑,且漏比 `variant-s2t.tsv`。 -- [ ] 2026-10-29 IT-23 五工作日试用(**1.0.0 / build 31**,air 与 pro 执行 SHA 均为 `9cbe8a22…`):两台设备已装同一包(报告217 §8)。29→30 修「候选窗跟随鼠标」,30→31 只加 HUD 诊断(报告220,实为旧进程未退出);IT-23 尚未起算。 +- [ ] 2026-10-29 IT-23 五工作日试用(**1.0.0 / build 32**,air 与 pro 执行 SHA 均为 `ddd33b7a…`):两台设备已装同一包(报告217 §8)。29→30 修「候选窗跟随鼠标」,30→31 加 HUD 诊断,31→32 改「组合态切换不丢字」(ADR-302);IT-23 尚未起算。 +- [x] 2026-10-29 **组合态切换不再丢字(ADR-302,报告221,build 32)**:`toggle_width`/`set_mode` 去掉 `cancel()`(保留组合、按新模式重算且不自动上屏),Shift 切英文改为**原样上屏编码**;core 新增 3 个单测,`ime-ffi` 旧用例改为先 Esc;两台设备已装 build 32。 - [x] 2026-10-29 **「HUD 不显示」结案(报告220)**:三次报告分别是诊断开关未生效无法取证、候选窗跟随鼠标(真缺陷,build 30 修)、**换包后旧进程仍在运行**。build 31 把诊断改为文件开关并给 `showStateFeedback`/`hudCaretRect` 各分支打点;`iterate-macos-ime` 收尾清单新增「`lsof … | grep -c deleted` 必须为 0」。 - [x] 2026-10-29 **候选窗跟着鼠标而不是插入点(报告219,build 30)**:`caretRect` 给解析器传了 `allowsEmptyCaret: false`,`length()==0` 时解析直接返回 nil → 落到鼠标兜底;改为 `true`,并把回退链收敛为「本轮 → 上次成功位置 → 鼠标」,新增 3 条断言。两台设备已装 build 30。 - [~] I3/IT-12/23:IT-12 性能/内存/久用已 PASS(报告191/192/199/207);**IT-23 五工作日试用尚未开始**(模板报告211)。 diff --git a/docs/reviews/217-1.0.0-freeze.md b/docs/reviews/217-1.0.0-freeze.md index 7822d52..d1dcdbe 100644 --- a/docs/reviews/217-1.0.0-freeze.md +++ b/docs/reviews/217-1.0.0-freeze.md @@ -123,15 +123,15 @@ platforms/macos/tests/run-repro.sh \ - **静态零外联**:`./scripts/verify-no-network.sh`(或 `make verify-no-network`)通过。 - **运行时零外联**:一边打字一边 `lsof -i -a -p "$(pgrep -x Lampyris)"`,预期**无输出**。 -## 8. IT-23 试用基线:两台设备装同一个包(2026-10-29 更新为 build 31) +## 8. IT-23 试用基线:两台设备装同一个包(2026-10-29 更新为 build 32) | 项 | air(本机,arm64 / macOS 27.0.1) | pro(x86_64 / macOS 13.7.8) | |---|---|---| -| 版本 / 构建 | **1.0.0 / 31** | **1.0.0 / 31** | -| 宿主执行 SHA-256 | `9cbe8a22e7e4d5af5e67e4e60bf00e5e53bd3e7032d02dfab8264b997c1c630b` | **同值**(同一个二进制) | -| 更新程序构建号 | 31 | 31 | +| 版本 / 构建 | **1.0.0 / 32** | **1.0.0 / 32** | +| 宿主执行 SHA-256 | `ddd33b7aa2962a6b4e5cc3f662624931b67f713c6428201d61979edec17dd66e` | **同值**(同一个二进制) | +| 更新程序构建号 | 32 | 32 | | 签名 / 公证 | Developer ID + `spctl` Notarized | 同(`codesign --strict`、`stapler validate` 均 PASS) | -| 用户数据 | config `cfc86cff…`、词库 800+ 行 | config `cb8e7d05…`、词库 **690 行**(build 31 装前装后一致) | +| 用户数据 | config `cfc86cff…`、词库 800+ 行 | config `cb8e7d05…`、词库 **727 行**(build 32 装前装后一致) | | 旧版本备份 | `updates/`、`uninstalled/` 历史项 | `uninstalled/bundle.aPZKev`(0.1.16) | | 输入源 | `cn.jokerhub.inputmethod.Lampyris.default` 已启用 | 已启用;当前停在 ABC,使用时按 ⌃Space 切 | @@ -145,3 +145,5 @@ pro 的安装记录:`ev-95-pro-stage.log`(ZIP 校验 → 解包 → 停宿 > 根因与修法见报告 219。IT-23 尚未开始记第 1 天,因此换包不影响试用基线;两台设备均已升级到 30。 > **再从 30 换到 31 的原因**:31 只增加 HUD 诊断(文件开关 + 分支打点),用于证实第三次「HUD 不显示」 > 实为**旧进程仍在运行**(报告 220),不是产品缺陷。诊断文件已删除,无文件时零开销;两台设备均已在 31。 +> **31 → 32 的原因**:组合态下按 Shift/⌥M/⌥F 会丢字(报告 221 / ADR-302),改为「Shift 原样上屏编码、⌥M/⌥F 保留组合」。 +> IT-23 仍未起算,基线跟随最终行为。 diff --git a/docs/reviews/221-switch-keeps-composition.md b/docs/reviews/221-switch-keeps-composition.md index ae3ab01..99b1680 100644 --- a/docs/reviews/221-switch-keeps-composition.md +++ b/docs/reviews/221-switch-keeps-composition.md @@ -32,7 +32,7 @@ - core 新增 3 个单测(全角保留组合与候选、切模式保留缓冲区并重算、新模式无候选时保留编码且 Esc 仍可取消)。 - `ime-ffi` 的 `candidates_expose_source_codes` 原先依赖"切模式会清空缓冲",改为先 Esc 再切模式。 - 离线回归 56 文件 / 303 例、`make verify` 全绿;实机复验见 §5。 -- 实机复验(build 32,两台设备):待填。 +- 装机:air 与 pro 均为 1.0.0/build 32(执行 `ddd33b7a…`),待用户按 §5 复验三条快捷键。 ## 5. 遗留 diff --git a/packaging/build-number b/packaging/build-number index f5c8955..bb95160 100644 --- a/packaging/build-number +++ b/packaging/build-number @@ -1 +1 @@ -32 +33 diff --git a/platforms/macos/Sources/InputController.swift b/platforms/macos/Sources/InputController.swift index 8725c89..89ce211 100644 --- a/platforms/macos/Sources/InputController.swift +++ b/platforms/macos/Sources/InputController.swift @@ -483,9 +483,10 @@ final class LampyrisInputController: IMKInputController { defer { refreshStateMenu() } if ImeConfig.string("mode") != next, !ImeConfig.setString("mode", next) { presentConfigError(); return } guard session?.mode != next else { return } - cancelClientComposition() + // ADR-302:组合中切模式保留编码,由核心按新模式重算候选(报告 222:这里原先会先取消组合)。 session?.setMode(next) showStateFeedback(StateFeedback.mode(next)) + refreshAfterStateChange() } // MARK: - 按键处理 @@ -506,13 +507,24 @@ final class LampyrisInputController: IMKInputController { session?.noteModifierChange(event) let other = flags.contains(.control) || flags.contains(.option) || flags.contains(.command) - if let session, - session.shiftTransition(isDown: flags.contains(.shift), otherModifier: other) - { - if let client = activeClient ?? (sender as? IMKTextInput) { clearMarked(client) } - candidateWindow?.hide() - // 键盘单独 Shift 与菜单/快捷键走同一提示:候选窗已隐藏,这里应弹 HUD。 - showStateFeedback(StateFeedback.language(session.isEnglish)) + if let session { + // ADR-302:切到英文前把编码原样上屏。必须在 `shiftTransition` 之前取, + // 它内部会 `cancel()` 掉缓冲区(报告 222)。 + let pendingRaw = session.isComposing && !session.isEnglish ? session.buffer : nil + let toggled = session.shiftTransition( + isDown: flags.contains(.shift), otherModifier: other) + if toggled { + let client = activeClient ?? (sender as? IMKTextInput) + if let client { clearMarked(client) } + if let raw = pendingRaw, !raw.isEmpty, let client { + client.insertText(raw, + replacementRange: NSRange(location: NSNotFound, length: 0)) + if Self.hudDiagEnabled { Self.hudDiag("shift committed raw=\(raw)") } + } + candidateWindow?.hide() + // 键盘单独 Shift 与菜单/快捷键走同一提示:候选窗已隐藏,这里应弹 HUD。 + showStateFeedback(StateFeedback.language(session.isEnglish)) + } } return false }