| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
fix(engine,cli): 教学告警不再随转译缓存命中与否出现,并按文件名归属 缺陷 B。引擎把教学告警挂在 cache.get_or_transpile 的转译闭包里,闭包只在 未命中时执行;CLI 那份带文件名的 emit_teaching_warnings_for_file 又只在兄弟 文件循环的 None =>(未命中)分支里调用。实测同一份含魔法数字的项目连跑两次 rzc check src/main.zh(独立 HOME,第二遍缓存命中): - 改前:第一次两条——「[警告] [lint] 第 4 行第 12 列:魔法数字「5」」(入口 这条不带文件名)与「[警告] [lint] 工具.zh:第 2 行第 12 列:魔法数字「42」」; 第二次两条全没了,只剩「✅ 编译成功,没有错误。」学习者会读成「提示消失= 问题已修」。 - 改后:两遍输出逐字相同、每条都带文件名前缀,各 2 行、无重复。 顺带收掉两处口径分叉:入口走引擎匿名告警、兄弟走 CLI 带名告警,同一次运行 混着两种格式;且 CLI 那份用 lint_teaching_with_buckets_chars,比引擎的 lint_teaching_all_chars 少「英文回落」「保留字撞名」两类——同一份代码走入口 路径会提示、走兄弟路径不提示。 做法: - engine 新增 emit_teaching_warnings(source, manager, label),成为扫描集合的 唯一出口(label 决定要不要拼 {文件名}: 前缀);transpile_source_with_project 把告警移到缓存查询之后,与缓存状态无关;配套 transpile_source_with_project_quiet 给「自己负责归属」的调用方。 - CLI transpile_with_map_cached_in_project 增 display_name,走静默入口再带名 输出;回退分支改用 transpile_pipeline_quiet_with_project,避免静默/非静默 两套管线各出一遍;新增 teaching_display_name 统一归属名口径(相对 src/, 取不到退相对项目根);emit_teaching_warnings_for_file 缩为一行委托; transpile_project_files 把 emit 移出 match;transpile_for_export 增 display_name。 回归锁:crates/cli/tests/cli_basic.rs 的 test_teaching_warnings_survive_transpile_cache(真 rzc 子进程,同内容跑两遍, 剔掉时间戳后逐字比对 [lint] 正文)。旧代码判红实测:该用例 FAILED 于 cli_basic.rs:277,实际 stderr 正是那条不带文件名的「第 4 行第 12 列:魔法数字 「5」」。不误伤:--no-lint 两遍均 0 条教学告警;rzc transpile 两遍同样一致。 代价与取舍:transpile_source 这条带缓存的公开入口,命中路径从此每次多跑一遍 教学扫描——engine 基线 pipeline_cache_hit 23741→213575 ns、 pipeline_cache_hit_2000 138081→815871 ns(BENCH_RUNS=3 取最小值),增量与单独 计费的 teaching_all_scan(180573 ns)对得上,仍只有同规模全量转译 (571647 ns)的 37%。没把告警随产物一起写进持久缓存来省这一遍:那要改 ~/.rz/cache/transpile-v1.json 的条目结构,存量旧条目缺字段等于对它们把缺陷 B 原样长回来,还得连带升版本号;真实链路里 CLI 走 *_quiet、LSP 走静默管线,多付 的只有「库调用方直接用带缓存入口」一种场景。LSP 五组基线未动(-2.3%~+1.9%)。 验证:cargo fmt --check / check --workspace --all-targets / clippy --workspace --all-targets -D warnings / test -p engine -p rzc 全绿; tools/bench-check.sh --only engine 复跑 13 项全在阈值内; ui-keys-index --write 同步 docs/ui-keys.en.md(main.rs 调用点行号漂移); check-prod-panics / check-ui-keys / check-extension-ui-keys / check-lang-packs --strict / check-readme-parity / check-glossary-consistency / check-mapping-warnings(告警数 2 与基线一致)全 EXIT=0;码位级自检新增 472 个 不同汉字、语料外 0 个。 | 2 天前 | |
fix(engine,cli): 教学告警不再随转译缓存命中与否出现,并按文件名归属 缺陷 B。引擎把教学告警挂在 cache.get_or_transpile 的转译闭包里,闭包只在 未命中时执行;CLI 那份带文件名的 emit_teaching_warnings_for_file 又只在兄弟 文件循环的 None =>(未命中)分支里调用。实测同一份含魔法数字的项目连跑两次 rzc check src/main.zh(独立 HOME,第二遍缓存命中): - 改前:第一次两条——「[警告] [lint] 第 4 行第 12 列:魔法数字「5」」(入口 这条不带文件名)与「[警告] [lint] 工具.zh:第 2 行第 12 列:魔法数字「42」」; 第二次两条全没了,只剩「✅ 编译成功,没有错误。」学习者会读成「提示消失= 问题已修」。 - 改后:两遍输出逐字相同、每条都带文件名前缀,各 2 行、无重复。 顺带收掉两处口径分叉:入口走引擎匿名告警、兄弟走 CLI 带名告警,同一次运行 混着两种格式;且 CLI 那份用 lint_teaching_with_buckets_chars,比引擎的 lint_teaching_all_chars 少「英文回落」「保留字撞名」两类——同一份代码走入口 路径会提示、走兄弟路径不提示。 做法: - engine 新增 emit_teaching_warnings(source, manager, label),成为扫描集合的 唯一出口(label 决定要不要拼 {文件名}: 前缀);transpile_source_with_project 把告警移到缓存查询之后,与缓存状态无关;配套 transpile_source_with_project_quiet 给「自己负责归属」的调用方。 - CLI transpile_with_map_cached_in_project 增 display_name,走静默入口再带名 输出;回退分支改用 transpile_pipeline_quiet_with_project,避免静默/非静默 两套管线各出一遍;新增 teaching_display_name 统一归属名口径(相对 src/, 取不到退相对项目根);emit_teaching_warnings_for_file 缩为一行委托; transpile_project_files 把 emit 移出 match;transpile_for_export 增 display_name。 回归锁:crates/cli/tests/cli_basic.rs 的 test_teaching_warnings_survive_transpile_cache(真 rzc 子进程,同内容跑两遍, 剔掉时间戳后逐字比对 [lint] 正文)。旧代码判红实测:该用例 FAILED 于 cli_basic.rs:277,实际 stderr 正是那条不带文件名的「第 4 行第 12 列:魔法数字 「5」」。不误伤:--no-lint 两遍均 0 条教学告警;rzc transpile 两遍同样一致。 代价与取舍:transpile_source 这条带缓存的公开入口,命中路径从此每次多跑一遍 教学扫描——engine 基线 pipeline_cache_hit 23741→213575 ns、 pipeline_cache_hit_2000 138081→815871 ns(BENCH_RUNS=3 取最小值),增量与单独 计费的 teaching_all_scan(180573 ns)对得上,仍只有同规模全量转译 (571647 ns)的 37%。没把告警随产物一起写进持久缓存来省这一遍:那要改 ~/.rz/cache/transpile-v1.json 的条目结构,存量旧条目缺字段等于对它们把缺陷 B 原样长回来,还得连带升版本号;真实链路里 CLI 走 *_quiet、LSP 走静默管线,多付 的只有「库调用方直接用带缓存入口」一种场景。LSP 五组基线未动(-2.3%~+1.9%)。 验证:cargo fmt --check / check --workspace --all-targets / clippy --workspace --all-targets -D warnings / test -p engine -p rzc 全绿; tools/bench-check.sh --only engine 复跑 13 项全在阈值内; ui-keys-index --write 同步 docs/ui-keys.en.md(main.rs 调用点行号漂移); check-prod-panics / check-ui-keys / check-extension-ui-keys / check-lang-packs --strict / check-readme-parity / check-glossary-consistency / check-mapping-warnings(告警数 2 与基线一致)全 EXIT=0;码位级自检新增 472 个 不同汉字、语料外 0 个。 | 2 天前 | |
fix(lsp): 启动时把界面语言同步给引擎,编辑器内引擎教学文本不再恒为中文 缺陷 C。crates/lsp/src/ui.rs 的 init 只加载 LSP 自己的 lsp_* 消息表,从不调 语言::set_language(CLI 在启动时就同步),于是引擎侧的全局语言停在默认 zh。 后果有两层: - 非中文用户在编辑器里看到的引擎用户可见文本(Unicode 混淆、全角标点、教学 lint、诊断模板)全是中文,与同一条提示在 CLI 里的母语输出对不上; - 语言::uses_cyrillic_script 与 localized_char_name 也读这个全局:恒为 zh 时 俄文方言的合法西里尔标识符被逐个判成「同形异义字符」,对正确代码刷假告警 (translation_cache.rs 把 check_unicode_confusion 的结果直接 log::warn 出去)。 修复让语言码与消息表由同一条链产出:新增 Ui::load_with_lang,五档优先级每档 都返回实际命中的语言码(第 1 档自定义目录里的 ui.toml 无语言身份,按目录名 登记——未知代码在引擎侧逐级回退内置中文表,与登记 zh 同形);load 退化为取 .0;init 拿到码后调 语言::set_language 再装 GLOBAL。 取证三例: - 修复前必红:临时探针只调旧 ui::init,panic 于 「assertion left == right failed: init 后引擎全局语言应为 ru」 left: "zh" / right: "ru";同探针先钉住 zh 语境下 «функция главная() { пусть количество = 5; }» 必报同形异义(假告警成立)。 - 修复后必绿:同一探针转绿——current_language() == "ru"、同源码告警清零、 语言::t("unicode_cat_homoglyph") == "символ-омоглиф"、 ui::global().t("lsp_about") == "LSP-прокси-сервер i18n-rust"(界面消息与 引擎模板同源)。探针已删除,改留 crates/lsp/tests/lang_sync.rs 两个用例。 - 对照不误伤:init 会写进程级全局(GLOBAL 与 CURRENT_LANG),故新用例单独成 测试二进制,不与依赖默认语言的既有用例同进程;本机有 rust-analyzer,把 #[ignore] 的真实子进程 e2e 全量跑一遍——12 项全绿,含 zh 包中文断言的 e2e_fullwidth_diagnostic_injected、e2e_teaching_lint_diagnostic_injected, 以及 e2e_teaching_warnings_do_not_leak_to_server_stderr。 验证:cargo fmt --check / check --workspace --all-targets / clippy --workspace --all-targets -D warnings / cargo test -p i18n-rust-lsp (137 单测 + 4 + 2/12 ignored + 新增 lang_sync 2 项)/ e2e --ignored 12 项 全绿;check-prod-panics、check-ui-keys、ui-keys-index(docs/ui-keys.en.md 按 ui.rs 与 main.rs 调用点行号重生成)全 EXIT=0;码位级自检语料外新字 0 个。 | 2 天前 | |
feat(cli): rzc doctor 体检语言服务器就位情况与版本漂移 编辑器链路的两必需件此前完全不在 doctor 视野里:i18n-rust-lsp 缺失 只印一行「未找到」(甚至根本没这一行),rust-analyzer 缺失同样只说 「未找到」而不给安装命令——而这两者正是「Server initialization failed.」的第一大成因,doctor 是用户唯一能自查的入口。 - component_status_lines 扩到 4 件(rustc/cargo/rust-analyzer/ i18n-rust-lsp),未找到时紧跟一行可复制的安装命令;抽出 locate_component + ComponentSource 供状态行与版本探测共用 - 新增 lsp_version_line:比对服务器与 rzc 版本,漂移时提示 rzc install lsp --force;拿不到版本(旧二进制无 --version) 不给结论,宁可不报也不误报 - 扩展两条启动失败文案从 extension.ts 内联中文改走 ui.toml 的 ext_ 键(界面消息键 620 → 622,11 语言): ext_lsp_binary_missing / ext_lsp_start_failed({} 为协议层原因) - 二进制未找到的提示去掉「或 cargo install i18n-rust-lsp」:它装 registry 最新版(实测 0.8.4)与 rzc 不一致,rzc install lsp 才按 当前版本精确锁定 - 新增门禁 tools/check-extension-ui-keys.py(make gate + ci.yml unix/windows + release.yml):代码消费键 = 生成器「消费的键」= 生成表,且生成表与 ui.toml 逐字相等;漏跑 gen:ui 即失败,不再 等到运行时拿到 undefined。纯 Python,免 npm/node_modules, 已用生成物陈旧/白名单缺键/语言块缺失三类反向用例验证会报错 - 发布准备清单记录实测:crates.io 最新 0.8.4 vs 源码 0.8.12, 未发布版本会让 rzc install lsp 直接失败(发布三 crate 是唯一解) - install.rs 新增 2 个单测;版本号 0.8.11 → 0.8.12(四 crate + cli/lsp 对 engine 依赖 + 扩展 package.json/lock + Cargo.lock) 门禁:fmt/clippy 干净,cargo test --workspace 766 passed, 7 个检查器全绿,教程 320/381(预期失败 61、真实失败 0)。 未验证:扩展 npm run typecheck(沙箱无 npm/node_modules)。 | 7 天前 |