{"record":{"id":"1acab990c39e4da7","repo":"BigPizzaV3/CodexPlusPlus","slug":"manager-navigation","errorCode":null,"errorMessage":"不支持的管理工具导航：{}/{}","messagePattern":"不支持的管理工具导航：(.+?)/(.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/codex-plus-core/src/manager_navigation.rs","lineNumber":123,"sourceCode":"    };\n    let pending: ManagerNavigationIntent =\n        serde_json::from_str(&contents).context(\"管理工具导航内容无效\")?;\n    if pending != *navigation {\n        return Ok(false);\n    }\n    match std::fs::remove_file(path) {\n        Ok(()) => Ok(true),\n        Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(false),\n        Err(error) => {\n            Err(error).with_context(|| format!(\"清理管理工具导航失败：{}\", path.to_string_lossy()))\n        }\n    }\n}\n\nfn validate_navigation(navigation: &ManagerNavigationIntent) -> anyhow::Result<()> {\n    match (navigation.page.as_str(), navigation.section.as_deref()) {\n        (\"settings\", None | Some(\"stepwise\")) => Ok(()),\n        _ => anyhow::bail!(\n            \"不支持的管理工具导航：{}/{}\",\n            navigation.page,\n            navigation.section.as_deref().unwrap_or(\"\")\n        ),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn saves_and_consumes_stepwise_navigation_once() {\n        let dir = tempfile::tempdir().unwrap();\n        let path = dir.path().join(\"pending-manager-navigation.json\");\n        let navigation = ManagerNavigationIntent {\n            page: \"settings\".to_string(),\n            section: Some(\"stepwise\".to_string()),","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/manager_navigation.rs#L105-L141","documentation":"Manager navigation intents are validated against a whitelist: only page \"settings\" with no section or section \"stepwise\" is accepted. Any other page/section combination fails validation with this message embedding the offending values, preventing the frontend from navigating the manager desktop app to unknown routes.","triggerScenarios":"`validate_navigation` receives a ManagerNavigationIntent whose (page, section) pair is not (\"settings\", None) or (\"settings\", Some(\"stepwise\")) — e.g. page \"models\" or section \"advanced\".","commonSituations":"Frontend emitting a stale/renamed page id; new page added to App.tsx without updating the validator whitelist; corrupted or hand-edited pending-navigation payload.","solutions":["Change the navigation intent to an allowed pair: page \"settings\" with section null or \"stepwise\"","If a new page/section is intended, add it to the match arms in validate_navigation in manager_navigation.rs","Verify the frontend payload field names/values match the backend enum (check App.tsx navigation emit code)"],"exampleFix":"// before\nfn validate_navigation(navigation: &ManagerNavigationIntent) -> anyhow::Result<()> {\n    match (navigation.page.as_str(), navigation.section.as_deref()) {\n        (\"settings\", None | Some(\"stepwise\")) => Ok(()),\n        _ => anyhow::bail!(\"不支持的管理工具导航：{}/{}\", navigation.page, navigation.section.as_deref().unwrap_or(\"\")),\n    }\n}\n// after\nmatch (navigation.page.as_str(), navigation.section.as_deref()) {\n    (\"settings\", None | Some(\"stepwise\")) => Ok(()),\n    (\"models\", None | Some(\"context\")) => Ok(()), // newly supported page\n    _ => anyhow::bail!(...),\n}","handlingStrategy":"validation","validationCode":"// frontend check before emitting intent\nconst ALLOWED = new Set([\"settings\"]);\nif (!ALLOWED.has(intent.page)) throw new Error(`page ${intent.page} not navigable`);\nif (intent.page === \"settings\" && intent.section && intent.section !== \"stepwise\") {\n  throw new Error(`section ${intent.section} not allowed for settings`);\n}","typeGuard":"fn is_valid_navigation(page: &str, section: Option<&str>) -> bool {\n    matches!((page, section), (\"settings\", None | Some(\"stepwise\")))\n}","tryCatchPattern":"match manager_navigation::validate_navigation(&intent) {\n    Ok(()) => save_pending(intent),\n    Err(e) => {\n        log::warn!(\"navigation rejected: {e}\");\n        // fall back to default settings page\n        save_pending(default_settings_intent());\n    }\n}","preventionTips":["Keep the frontend page-id constants in sync with the Rust whitelist","Add a unit test per allowed (page, section) pair","Fail loudly in dev builds when a navigation intent is rejected","Validate payloads at the IPC boundary with a shared schema"],"tags":["rust","navigation","validation","whitelist","tauri"],"backgroundTag":"invalid-argument-value","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}