From 0156adb44d8fc25c7b123ab62b03ee44683ba5f3 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Fri, 13 Nov 2026 22:56:44 +0800 Subject: [PATCH] =?UTF-8?q?fix(presenter):=20M306=20r1=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E3=80=8C=E7=BC=96=E8=AF=91=E5=99=A8=E4=B8=80?= =?UTF-8?q?=E5=A3=B0=E4=B8=8D=E5=90=AD=E3=80=8D=E6=98=AF=E9=94=99=E7=9A=84?= =?UTF-8?q?=EF=BC=9A=E6=94=B9=E5=87=86=E4=B8=A4=E5=A4=84=E6=96=87=E6=A1=A3?= =?UTF-8?q?=20+=20=E8=A1=A5=E4=B8=80=E6=9D=A1=E6=BA=90=E7=A0=81=E7=BA=A7?= =?UTF-8?q?=E5=AE=88=E5=8D=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit r1 复审实测:只删 `live.rs::discovered` 那三行 ⇒ `unused_imports` 点名 `legacy_external_instance_id`,`clippy -- -D warnings` 直接红(EXIT=101)。 `#![allow(dead_code)]` 只盖「函数变死码」,盖不住「use 行变空」——那是 `unused` 组另一条 lint。 - `live.rs` / `game/tests.rs` 两处文档改成准确版本:删掉那三行 ⇒ `cargo test` 仍全绿,但 `unused_imports` 会让 CI 红;而**这道保险可绕过**(连 import 一起删 / 加 `#[allow(unused_imports)]` ⇒ 编译期一条 warning 都没有),所以行为用例之外再加一道源码网 - `game/tests.rs` 新增 `the_legacy_pass_through_is_still_in_the_source`:`include_str!` 扫 `live.rs` 的**代码**(每行剥掉 `//` 之后的部分——注释里残留的那条 `if` 原文不算数),断言 放行分支与 import 原样还在、且没有 `unused_imports` 豁免 - 变异实测:把 import 里的名字一起删掉(编译器真不吭声,`grep -c '^warning'` = 0)⇒ 新守卫红 「分支在 = false,import 在 = false」,行为用例同时红;两条网互补 --- .../presenter/src/host/game/refresh/live.rs | 16 ++++-- crates/presenter/src/host/game/tests.rs | 52 ++++++++++++++++++- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/crates/presenter/src/host/game/refresh/live.rs b/crates/presenter/src/host/game/refresh/live.rs index 33c8371..324caef 100644 --- a/crates/presenter/src/host/game/refresh/live.rs +++ b/crates/presenter/src/host/game/refresh/live.rs @@ -103,10 +103,18 @@ fn profile(env: &HostEnv, instance: &InstanceSummary) -> Result<(), String> { /// 反查不到根 ⇒ 放行(M273 老档案,理由见模块文档):不猜、也不在这里改成「拒绝」, /// 否则所有老用户的 `ext-` 磁贴会集体点不动。 /// -/// **末尾那条放行分支由 `host::game::tests::a_m273_legacy_ext_id_is_allowed` 守着**:本 crate 头是 -/// `#![allow(dead_code)]`,删掉它编译器一个信号都不给(M304 r2 复审实测:删掉后整棵 presenter -/// 426 passed / 0 failed),所以「清死代码」之前请先跑那条用例。拒绝那一侧由同文件的 -/// `an_ext_id_from_no_visible_root_is_refused` 守着。 +/// **别把末尾那三行当死代码删掉**(M306 两次复审的账,别只记一半): +/// +/// - 删掉它,`cargo test` **仍然全绿**(M304 r2 实测:整棵 presenter 426 passed / 0 failed); +/// - 但**不是无声的**:`unused_imports` 会点名 `legacy_external_instance_id`, +/// `clippy -- -D warnings` 当场红(M306 r1 复审实测 EXIT=101)。`#![allow(dead_code)]` 只盖 +/// 「函数变死码」,盖不住「use 行变空」——那是 `unused` 组里**另一条** lint; +/// - **这道保险可以被绕过**:把 import 一起删掉、或在那行加 `#[allow(unused_imports)]`,编译器 +/// 就真的不吭声了。所以还有两道网,删之前先跑: +/// `host::game::tests::a_m273_legacy_ext_id_is_allowed`(判**行为**)与 +/// `the_legacy_pass_through_is_still_in_the_source`(直接扫本文件的**源码**)。 +/// +/// 拒绝那一侧由 `an_ext_id_from_no_visible_root_is_refused` 守着。 fn discovered(env: &HostEnv, instance: &InstanceSummary) -> Result<(), String> { for root in roots::all(env) { if external_instance_id(root.key(), &instance.version_id) != instance.id { diff --git a/crates/presenter/src/host/game/tests.rs b/crates/presenter/src/host/game/tests.rs index dd82ede..e0b4d82 100644 --- a/crates/presenter/src/host/game/tests.rs +++ b/crates/presenter/src/host/game/tests.rs @@ -254,8 +254,14 @@ fn bare_root(label: &str) -> (HostEnv, std::path::PathBuf) { /// /// 抓得住:**只**删掉 `live.rs::discovered` 里 /// `if legacy_external_instance_id(&instance.version_id) == instance.id { return Ok(()); }` 这三行 -/// ——本条立即红。这是它唯一的网:crate 头是 `#![allow(dead_code)]`,编译器一声不吭(M304 r2 -/// 实测过删掉后整棵 presenter 426 passed / 0 failed)。 +/// ——本条立即红(M306 实测:`Err("实例 `1.20.4` 所属的游戏目录已不在…")`)。 +/// +/// 但**别把编译器当第二道网**(M306 r1 复审实测,本文件早先那句「编译器一声不吭」是错的): +/// `#![allow(dead_code)]` 只盖「函数变死码」,盖不住「use 行变空」——`unused_imports` 属于 +/// `unused` 组里另一条 lint,删掉那三行时它会点名 `legacy_external_instance_id`,CI 的 +/// `-D warnings` 当场红。可**这道保险也能绕过**:连 import 一起删、或在那行加 +/// `#[allow(unused_imports)]`,编译器就真的不吭声了(那时 `cargo test` 依旧全绿)。 +/// 所以源码侧由下面的 `the_legacy_pass_through_is_still_in_the_source` 兜底。 /// 抓不住:反查落空后「该拒绝」那一侧(下一条用例管)。 #[test] fn a_m273_legacy_ext_id_is_allowed() { @@ -297,3 +303,45 @@ fn an_ext_id_from_no_visible_root_is_refused() { "具名原因要说清是哪条实例、为什么(现在是:{reason})" ); } + +/// `live.rs` 的**代码**:每行剥掉 `//` 之后的部分(`//` / `///` / `//!` 都从此处走)。 +/// +/// 必须剥:`live.rs` 的文档里写着那条 `if` 的原文(就是给下一个「清死代码」的人看的),注释里 +/// 出现不算数——否则下面的守卫会**自证**地永远绿(M306 r1 复审要的正是这道网,别让它空转)。 +fn live_code() -> String { + include_str!("refresh/live.rs") + .lines() + .map(|line| line.split("//").next().unwrap_or_default()) + .collect::>() + .join("\n") +} + +/// **源码级守卫**:`live.rs` 里那条「M273 老档案放行」必须**原样还在**,且没人把编译器的提醒关掉。 +/// +/// 为什么行为用例不够(M306 r1 复审证明):删掉那三行时编译器**会**给信号(`unused_imports` +/// 点名 `legacy_external_instance_id`,`-D warnings` 判红)——**但这道保险可绕过**:把 import +/// 一起删掉、或加 `#[allow(unused_imports)]`,编译期**一条 warning 都不打**(M306 r1 实测: +/// `grep -c '^warning'` = 0),`cargo test` 也依旧全绿。 +/// 那时只有扫源码能说话:`a_m273_legacy_ext_id_is_allowed` 判**行为**,本条判**判据还在不在**。 +/// +/// 抓得住:那三行被删(注释里残留的原文不算)/import 里的名字被删/有人加 `unused_imports` 豁免。 +/// 抓不住:把判据换个写法搬去别处——那时本条会红,请顺手把下面的字面量改成新形状(别把守卫删了)。 +#[test] +fn the_legacy_pass_through_is_still_in_the_source() { + let code = live_code(); + let branch = "if legacy_external_instance_id(&instance.version_id) == instance.id {"; + let import = + "use super::super::discovered::{external_instance_id, legacy_external_instance_id};"; + assert!( + code.contains(branch) && code.contains(import), + "live.rs::discovered 里那条「M273 老档案放行」不见了(分支在 = {},import 在 = {}):\ + 删掉它会让所有存量 M273 用户的 `ext-` 磁贴点不动,还配一句错的「所属的游戏目录已不在」", + code.contains(branch), + code.contains(import) + ); + assert!( + !code.contains("unused_imports"), + "live.rs 里出现了 `unused_imports` 豁免:它会把「删掉放行分支后 use 行变空」这条唯一的\ + 编译期提醒关掉——那是本条守卫存在的理由,不许豁免" + ); +}