Preserve legacy style mode during migration

Constraint: legacy preferences may have defaultMode without activeStylePackId, and Raw style packs may still use the LLM path
Rejected: defaulting missing activeStylePackId to builtin.light | silently changes Raw, Structured, and Formal users during upgrade
Rejected: skipping script normalization for Raw LLM output | lets Simplified/Traditional preferences be bypassed by raw style packs
Confidence: high
Scope-risk: narrow
Directive: treat missing activeStylePackId as a migration case derived from defaultMode, not as the new-user default
Tested: cargo fmt --manifest-path src-tauri/Cargo.toml; git diff --check; cargo test --manifest-path src-tauri/Cargo.toml --lib types::tests::missing_active_style_pack_id_uses_legacy_default_mode; cargo test --manifest-path src-tauri/Cargo.toml --lib types::tests::explicit_active_style_pack_id_is_preserved; cargo test --manifest-path src-tauri/Cargo.toml --lib coordinator::dictation::tests::raw_llm_output_still_applies_script_preference; cargo test --manifest-path src-tauri/Cargo.toml --lib
Not-tested: full app build; desktop runtime smoke on macOS/Windows
This commit is contained in:
H-Chris233 committed 2026-05-14 11:16:52 +08:00
1 parent b3a2bc393d
commit 426bd8fe38
2 files changed
+52 -10

No files matched your search

@@ -289,7 +289,7 @@ async fn run_streaming_polish(
fn finalize_polished_text(
polished: String,
translation_active: bool,
raw_uses_llm: bool,
_raw_uses_llm: bool,
mode: PolishMode,
polish_error: &Option<String>,
chinese_script_preference: crate::types::ChineseScriptPreference,
@@ -302,7 +302,7 @@ fn finalize_polished_text(
let should_force_script = if translation_active {
polish_error.is_some()
} else {
(!raw_uses_llm && mode == PolishMode::Raw) || polish_error.is_some()
mode == PolishMode::Raw || polish_error.is_some()
};
let polished = if should_force_script {
apply_chinese_script_preference(&polished, chinese_script_preference)
@@ -1650,6 +1650,22 @@ mod tests {
assert_eq!(result, "Open AI");
}
#[test]
fn raw_llm_output_still_applies_script_preference() {
let result = finalize_polished_text(
"繁體".into(),
false,
true,
PolishMode::Raw,
&None,
ChineseScriptPreference::Simplified,
&[],
false,
);
assert_eq!(result, "繁体");
}
#[test]
fn non_streamed_output_still_applies_correction_rules() {
let rules = vec![correction_rule("Open AI", "OpenAI")];
+34 -8
View File
@@ -644,8 +644,8 @@ struct UserPreferencesWire {
dictation_hotkey: Option<ShortcutBinding>,
default_mode: PolishMode,
enabled_modes: Vec<PolishMode>,
#[serde(default = "default_active_style_pack_id")]
active_style_pack_id: String,
#[serde(default)]
active_style_pack_id: Option<String>,
#[serde(default)]
style_system_prompts: StyleSystemPrompts,
#[serde(default)]
@@ -711,7 +711,7 @@ impl Default for UserPreferencesWire {
dictation_hotkey: None,
default_mode: prefs.default_mode,
enabled_modes: prefs.enabled_modes,
active_style_pack_id: prefs.active_style_pack_id,
active_style_pack_id: Some(prefs.active_style_pack_id),
style_system_prompts: prefs.style_system_prompts,
custom_style_prompts: prefs.custom_style_prompts,
launch_at_login: prefs.launch_at_login,
@@ -767,11 +767,10 @@ impl<'de> Deserialize<'de> for UserPreferences {
dictation_hotkey,
default_mode: wire.default_mode,
enabled_modes: wire.enabled_modes,
active_style_pack_id: if wire.active_style_pack_id.trim().is_empty() {
builtin_style_pack_id(wire.default_mode).to_string()
} else {
wire.active_style_pack_id
},
active_style_pack_id: wire
.active_style_pack_id
.filter(|id| !id.trim().is_empty())
.unwrap_or_else(|| builtin_style_pack_id(wire.default_mode).to_string()),
style_system_prompts: wire
.style_system_prompts
.with_legacy_custom_prompts(&wire.custom_style_prompts),
@@ -1770,6 +1769,33 @@ mod tests {
assert!(prefs.custom_style_prompts.has_for_mode(PolishMode::Formal));
}
#[test]
fn missing_active_style_pack_id_uses_legacy_default_mode() {
let prefs: UserPreferences = serde_json::from_str(
r#"{
"defaultMode": "structured"
}"#,
)
.unwrap();
assert_eq!(prefs.default_mode, PolishMode::Structured);
assert_eq!(prefs.active_style_pack_id, BUILTIN_STYLE_PACK_STRUCTURED_ID);
}
#[test]
fn explicit_active_style_pack_id_is_preserved() {
let prefs: UserPreferences = serde_json::from_str(
r#"{
"defaultMode": "formal",
"activeStylePackId": "custom.meeting"
}"#,
)
.unwrap();
assert_eq!(prefs.default_mode, PolishMode::Formal);
assert_eq!(prefs.active_style_pack_id, "custom.meeting");
}
#[test]
fn legacy_custom_style_prompts_are_not_appended_twice() {
let base = StyleSystemPrompts::default();