fix(app-iced): M119 r2 —— 四处「模拟」文案全由 simulated 驱动;确认条不再替用户 arm 键盘
复审 r2 的两条 p2 都是「上一轮各差一步」:字段/焦点都真的做了,但**另有三处没接上**、
**键盘闸是代码自己打开的**。
## P2-1:四处文案只认一个开关
r1 只有标题胶囊由 `simulated` 驱动;副标题 / 输入框占位符 / 空态正文是**无条件取词**,
而它们的译文里写着「模拟 / 没接真实模型」——接上真 transport 之后这三句会**反向**留着
(`simulated == false` 时界面还在声明「没接真实模型」)。而且没有一条测试钉得住那个声明。
现在:
- 新增 `pages/agent::Disclaimer { simulated, subtitle, placeholder, empty_body }`,
`Disclaimer::of(catalog, simulated)` 一次算好;`Conversation.simulated: bool` 换成
`Conversation.note: Disclaimer`,header / composer / transcript 三处各自从它取词——
**视图里没有第二种取词路径**;
- i18n 配成对:模拟态用既有的 `AgentSubtitle` / `AgentPlaceholder` / `AgentEmptyBody`,
真实态新增 `AgentSubtitleReal` / `AgentPlaceholderReal` / `AgentEmptyBodyReal`(中性话)。
(没有把三句改成中性话:那句告知本身有价值,接真模型后它才该消失。)
- 证据:`crates/app-iced/src/pages/agent/tests/disclaimer.rs`
—— `all_four_disclaimers_appear_when_the_backend_is_simulated`(四处都提模拟)、
`no_disclaimer_survives_when_a_real_backend_is_wired`(四处都不提,且不许用空串糊)、
`the_two_states_use_different_keys`(两态不能共用同一个 key)。
**golden.rs 的 400 行边界**:+3 条会破线。按「按功能拆、不压注释」处理——把这张表的
**说明文档**(35 行)原样搬到 `catalog.rs` 里 `mod golden;` 的文档上(一个字的说明都没删),
`golden.rs` 只留表数据 + 3 行指针。现在 `golden.rs` 374 行、`catalog.rs` 328 行。
## P2-2:键盘闸不许由代码替用户打开
r1 在 `sync_confirm_focus`(`on_agent` 的无条件尾巴,`Events` 又由心跳驱动)里顺手
`keyboard_mode = true`——于是**只要冒出待确认,全局键盘闸就开了**;用户发完那句话接着打下一句,
第一个空格就成了「批准写操作」。复审用临时用例复现过(`rail.confirm` 变 `None`)。
现在:
- `sync_confirm_focus` **只挪焦点**到「允许」,不再碰 `keyboard_mode`(字段文档里写清了为什么);
- 键盘用户的表态是 `Tab`:`AgentUi::step_focus` 加了一条 **arming 规则**——待确认、焦点已在
确认条上、但键盘闸还关着时,这一次 `Tab` **只点亮焦点环、不移动焦点**(否则第一次 Tab 会把
「允许」挪到「拒绝」,用户按 Enter 就是反着裁决);之后再 Tab 才逐格走;
- 反向回归:`a_stray_space_or_enter_never_approves_a_pending_write`(打字 → 空格 / 回车都不得裁决,
审计也不许留);`a_blocking_confirm_can_be_decided_with_the_keyboard_alone` 改成
「确认到达时未 armed → Tab 点亮 → Enter 允许;第二轮 Tab·Tab 到拒绝 → Space」。
## 出图
`DevDocs/artifacts/m119/` 18 张全部重出(新增取证夹具 `ULL_AGENT_FIXTURE=armed`:
跑一轮真提交后再按一次 Tab,专供「焦点环可见」那张图):
- `08-agent-simulated-{light,dark}`:`simulated = true` 下四处「模拟」同时可见;
- `09-agent-confirm-focus-{light,dark}`:**按过 Tab 之后**的确认条(焦点环在「允许」上);
- `05-agent-confirm-{light,dark}`:确认条刚出现、**还没 arm**(无焦点环)——与 09 成对,
正好把 r2 的行为差异拍下来。
## 门禁(真实退出码,最终树)
| 命令 | 退出码 |
|---|---|
| `cargo fmt --all --check` | 0 |
| `cargo clippy -p unlucky-app-iced -p unlucky-presenter -p unlucky-agent -p unlucky-i18n --all-targets -- -D warnings` | 0(0 warning)|
| `cargo test -p unlucky-app-iced --lib` | 0(605 passed / 0 failed / 2 ignored)|
| `cargo test --workspace --exclude unlucky-app` | 0(58 套 2281 passed / 0 failed / 11 ignored)|
全树受检文件无 >400(`golden.rs` 374、`catalog.rs` 328、`pages/agent/mod.rs` 371)。
This commit is contained in:
1 parent
a22baebe70
commit
0e48ea15b8
14 files changed
+332
-81
No files matched your search
@@ -126,6 +126,39 @@ mod logs;
|
||||
mod nav;
|
||||
mod settings;
|
||||
|
||||
/// 拆分前的 `key -> (en, zh-CN)` **逐字快照**(金表)。
|
||||
///
|
||||
/// ## 它是什么
|
||||
///
|
||||
/// M99 把 `catalog.rs` 的单张条目表按域拆到 `catalog/<域>.rs` 之后,这 72 行就是「拆分前那一份」
|
||||
/// 的原样导出:由拆分前的 `Catalog::of(En)` / `Catalog::of(ZhCn)` 逐条 `println!` 出来,
|
||||
/// 再原封不动抄进来(生成方式见 `tests.rs` 里 `split_keeps_every_translation` 的注释)。
|
||||
/// M108 在它上面改了 3 条(`NavDownload` / `DownloadTitle` / `DownloadSubtitle`)、追加了 1 条
|
||||
/// (`NavDownloadExpanded`);M105/M106/M107 各自追加的条目也都在,整表现在是 138 条。
|
||||
///
|
||||
/// ## 为什么不是「数条数」
|
||||
///
|
||||
/// 条数相等抓不住任何一种真会发生的坏法:某条译文在搬移时被漏掉、另一条被复制两次,条数照旧。
|
||||
/// 这张表比的是**全量、逐字节、按声明顺序**的三元组,于是下面四种坏法都会红:
|
||||
///
|
||||
/// | 坏法 | 红在哪 |
|
||||
/// |---|---|
|
||||
/// | 某个 key 整条被搬丢 | 条数不等 / 该行 key 名对不上 |
|
||||
/// | 两条 key 的译文互抄(同 key 被覆盖到别的译文) | 该行 en 或 zh 不等 |
|
||||
/// | 某条译文改了一个字符 | 该行不等(`assert_eq!` 带原文) |
|
||||
/// | 域的顺序被调换(`Key` 的 `Ord` 与导出表顺序都靠它) | 该行 key 名对不上 |
|
||||
///
|
||||
/// **抓不住**:译文本身翻得对不对(金表是「拆分前」的快照,它只能证明「没变」)。
|
||||
///
|
||||
/// ## M108 更新了三条、新增了一条(版本管理改名)
|
||||
///
|
||||
/// 用户令(2026-11-04)把这页的显示名从「下载 / Downloads」改成「版本管理 / Version management」:
|
||||
/// [`Key::NavDownload`] / [`Key::DownloadTitle`] / [`Key::DownloadSubtitle`]
|
||||
/// 三条译文按令改掉,并**新增** [`Key::NavDownloadExpanded`](240 展开态的全标签,
|
||||
/// 88 轨放不下 18 字符的英文,见 `catalog/nav.rs` 的「两条 key」一节)。
|
||||
///
|
||||
/// 其余各行仍逐字节等于拆分前那份快照——也就是说这张表现在证明的是「除这几条按令改过的,
|
||||
/// 其余一字未动」,不再是「整表一字未动」。
|
||||
#[cfg(test)]
|
||||
mod golden;
|
||||
|
||||
|
||||
@@ -50,6 +50,15 @@ macro_rules! agent_entries {
|
||||
AgentConfirmDeny => ("Deny", "拒绝"),
|
||||
// 头部常驻小标记(P2-1):与副标题/占位符互为冗余,三个位置都能看到「这是模拟」
|
||||
AgentSimulated => ("Simulated", "模拟"),
|
||||
// ── M119 r2:三处文案的**真实态**配对(模拟态用上面那三条已有的 key)
|
||||
//
|
||||
// 复审 r2 的 P2-1:上一轮只有标题胶囊由 `simulated` 驱动,副标题/占位符/空态正文是
|
||||
// 无条件取词,而那三条译文里写着「模拟 / 没接真实模型」——接上真 transport 之后
|
||||
// 这三句会**反方向**地留着。现在配成对:`simulated == true` 走模拟态,
|
||||
// `false` 走这三条中性话(`pages/agent/tests/disclaimer.rs` 钉住四处一起变)。
|
||||
AgentSubtitleReal => ("Conversation", "会话"),
|
||||
AgentPlaceholderReal => ("Message the assistant…", "给助手发消息…"),
|
||||
AgentEmptyBodyReal => ("Ask about instances, downloads or logs.", "可以问实例、下载或日志。"),
|
||||
} }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,36 +1,7 @@
|
||||
//! 拆分前的 `key -> (en, zh-CN)` **逐字快照**(金表)。
|
||||
//! 金表的**表数据**(`Key::ALL` 顺序 × (en, zh-CN) 的逐字快照)。
|
||||
//!
|
||||
//! ## 它是什么
|
||||
//!
|
||||
//! M99 把 `catalog.rs` 的单张条目表按域拆到 `catalog/<域>.rs` 之后,这 72 行就是「拆分前那一份」
|
||||
//! 的原样导出:由拆分前的 `Catalog::of(En)` / `Catalog::of(ZhCn)` 逐条 `println!` 出来,
|
||||
//! 再原封不动抄进来(生成方式见 `catalog/tests.rs` 里 `split_keeps_every_translation` 的注释)。
|
||||
//! M108 在它上面改了 3 条(`NavDownload` / `DownloadTitle` / `DownloadSubtitle`)、追加了 1 条
|
||||
//! (`NavDownloadExpanded`);M105/M106/M107 各自追加的条目也都在,整表现在是 138 条。
|
||||
//!
|
||||
//! ## 为什么不是「数条数」
|
||||
//!
|
||||
//! 条数相等抓不住任何一种真会发生的坏法:某条译文在搬移时被漏掉、另一条被复制两次,条数照旧。
|
||||
//! 这张表比的是**全量、逐字节、按声明顺序**的三元组,于是下面四种坏法都会红:
|
||||
//!
|
||||
//! | 坏法 | 红在哪 |
|
||||
//! |---|---|
|
||||
//! | 某个 key 整条被搬丢 | 条数不等 / 该行 key 名对不上 |
|
||||
//! | 两条 key 的译文互抄(同 key 被覆盖到别的译文) | 该行 en 或 zh 不等 |
|
||||
//! | 某条译文改了一个字符 | 该行不等(`assert_eq!` 带原文) |
|
||||
//! | 域的顺序被调换(`Key` 的 `Ord` 与导出表顺序都靠它) | 该行 key 名对不上 |
|
||||
//!
|
||||
//! **抓不住**:译文本身翻得对不对(金表是「拆分前」的快照,它只能证明「没变」)。
|
||||
//!
|
||||
//! ## M108 更新了三条、新增了一条(版本管理改名)
|
||||
//!
|
||||
//! 用户令(2026-11-04)把这页的显示名从「下载 / Downloads」改成「版本管理 / Version management」:
|
||||
//! [`super::Key::NavDownload`] / [`super::Key::DownloadTitle`] / [`super::Key::DownloadSubtitle`]
|
||||
//! 三条译文按令改掉,并**新增** [`super::Key::NavDownloadExpanded`](240 展开态的全标签,
|
||||
//! 88 轨放不下 18 字符的英文,见 `catalog/nav.rs` 的「两条 key」一节)。
|
||||
//!
|
||||
//! 其余各行仍逐字节等于拆分前那份快照——也就是说这张表现在证明的是「除这几条按令改过的,
|
||||
//! 其余一字未动」,不再是「整表一字未动」。
|
||||
//! 「为什么有这么一张表、它抓得住什么」写在 `catalog.rs` 中 `mod golden;` 的文档里——
|
||||
//! M119 r2 把它搬到那儿,是为了给这张表腾出追加新 key 的行数(400 行硬线),一个字的说明都没删。
|
||||
|
||||
/// 拆分前 `Key::ALL` 的顺序 × (en, zh-CN)。第一列是变体名(`Key::name()` 的返回值)。
|
||||
pub(super) const GOLDEN: &[(&str, &str, &str)] = &[
|
||||
@@ -150,6 +121,9 @@ pub(super) const GOLDEN: &[(&str, &str, &str)] = &[
|
||||
("AgentConfirmAllow", "Allow", "允许"),
|
||||
("AgentConfirmDeny", "Deny", "拒绝"),
|
||||
("AgentSimulated", "Simulated", "模拟"),
|
||||
("AgentSubtitleReal", "Conversation", "会话"),
|
||||
("AgentPlaceholderReal", "Message the assistant…", "给助手发消息…"),
|
||||
("AgentEmptyBodyReal", "Ask about instances, downloads or logs.", "可以问实例、下载或日志。"),
|
||||
// ── M106 `I18NFOLLOW`:General 分组真控件(语言选择器 + 其余三行)。**只追加在链尾**,
|
||||
// 上一行到 `LogsEmptyAction` 的既有顺序一字未动(金表要证明的正是这件事)。
|
||||
("SettingsLanguageFollowSystem", "Follow system", "跟随系统"),
|
||||
|
||||
Reference in new issue
Block a user