diff --git a/apps/desktop-shell/scripts/check-config.mjs b/apps/desktop-shell/scripts/check-config.mjs index 2633a1579..4020bbe1c 100644 --- a/apps/desktop-shell/scripts/check-config.mjs +++ b/apps/desktop-shell/scripts/check-config.mjs @@ -2056,14 +2056,18 @@ for (const snippet of [ 'resolve_desktop_host_bridge_network_status_payload', 'resolve_desktop_host_bridge_network_status_payload_with', 'network_status_unavailable_response', + 'log_desktop_network_failure', + 'desktop network failed for {label}: {error}', 'spawn_blocking(resolver)', 'resolve_desktop_host_bridge_network_status_payload_with(resolve_desktop_network_status)', + 'log_desktop_network_failure("status.resolve", &error)', '"isConnected": true', '"connectionType": "unknown"', '"network status unavailable"', 'network_status_unavailable_response_is_stable', 'network_status_success_response_reports_contract_shape', 'network_status_failure_hides_native_error_detail', + 'network_status_failures_are_logged_without_exposing_native_detail', 'private native resolver detail', ]) { if (!desktopHostBridgeNetworkSource.includes(snippet)) { diff --git a/apps/desktop-shell/src-tauri/src/host_bridge/network.rs b/apps/desktop-shell/src-tauri/src/host_bridge/network.rs index c51dbc227..e200a3c76 100644 --- a/apps/desktop-shell/src-tauri/src/host_bridge/network.rs +++ b/apps/desktop-shell/src-tauri/src/host_bridge/network.rs @@ -8,7 +8,10 @@ fn map_desktop_host_bridge_network_status_result( ) -> HostBridgeResponse { match status { Ok(status) => ok(request.id.clone(), status), - Err(_) => network_status_unavailable_response(request), + Err(error) => { + log_desktop_network_failure("status.resolve", &error); + network_status_unavailable_response(request) + } } } @@ -37,6 +40,14 @@ fn network_status_unavailable_response(request: &HostBridgeRequest) -> HostBridg failed(request.id.clone(), "host_error", "network status unavailable") } +fn log_desktop_network_failure(label: &str, error: &str) -> bool { + if !error.is_empty() { + eprintln!("desktop network failed for {label}: {error}"); + } + + false +} + #[cfg(test)] mod tests { use super::*; @@ -85,4 +96,12 @@ mod tests { assert_eq!(error.message, "network status unavailable"); assert!(!error.message.contains("private native resolver detail")); } + + #[test] + fn network_status_failures_are_logged_without_exposing_native_detail() { + assert!(!log_desktop_network_failure( + "status.resolve", + "private network detail" + )); + } } diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 200c7b04b..ddbe3aaee 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -3142,6 +3142,12 @@ - 决策:`apps/desktop-shell/src-tauri/src/host_bridge/navigation.rs` 必须在外链打开失败、同源 H5 route 导航失败、WebView reload 失败和主窗口缺失时记录 `desktop navigation failed for ...` 日志。HostBridge 对 H5 仍只返回稳定 `external URL cannot be opened`、`native page unavailable` 或 `webview reload unavailable`,不透传系统错误、窗口内部信息或平台细节。 - 验证方式:`cargo test --manifest-path apps/desktop-shell/src-tauri/Cargo.toml host_bridge::navigation`、`npm run desktop-shell:typecheck`、`npm run check:native-shells`、`npm run check:encoding`、`git diff --check`。 +## 2026-06-20 桌面壳网络状态系统异常必须可观测 + +- 背景:桌面壳 `network.status` 通过后台任务解析系统网络状态,H5 只需要稳定在线 / 离线语义;但后台任务 join 失败时,如果只返回稳定 `host_error`,开发侧无法区分正常离线、解析任务失败和系统异常。 +- 决策:`apps/desktop-shell/src-tauri/src/host_bridge/network.rs` 必须在网络状态解析失败时记录 `desktop network failed for status.resolve` 日志。HostBridge 对 H5 仍只返回稳定 `network status unavailable`,不透传 resolver、线程或系统错误细节。 +- 验证方式:`cargo test --manifest-path apps/desktop-shell/src-tauri/Cargo.toml host_bridge::network`、`npm run desktop-shell:typecheck`、`npm run check:native-shells`、`npm run check:encoding`、`git diff --check`。 + ## 2026-06-20 移动壳门禁脚本必须自登记自扫描 - 背景:Expo 移动壳单端检查已把 `apps/mobile-shell/scripts/` 纳入生产源码扫描入口,但 `check-config.mjs` 自身仍被排除在脚本清单和替身词扫描之外;这会让移动壳与桌面壳门禁结构不一致,也可能让后续门禁反查内容绕过生产替身词规则。 diff --git a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md index 32164c08e..b8aeecefe 100644 --- a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md +++ b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md @@ -354,6 +354,8 @@ GameBridge 禁止: 2026-06-20 追加:桌面壳导航系统异常必须可观测。Tauri 外链打开失败、同源 H5 route 导航失败、WebView reload 失败或主窗口缺失时,桌面壳必须记录 `desktop navigation failed for ...` 日志;HostBridge 回包仍只暴露稳定 `external URL cannot be opened`、`native page unavailable` 或 `webview reload unavailable` 语义,不透传系统错误、窗口内部信息或平台细节。 +2026-06-20 追加:桌面壳网络状态查询系统异常必须可观测。Tauri 桌面壳后台解析网络状态任务失败时必须记录 `desktop network failed for status.resolve` 日志;HostBridge 回包仍只暴露稳定 `network status unavailable` 语义,不透传 resolver、线程或系统错误细节。 + 2026-06-18 追加:H5 账号状态刷新开始消费 `app.reloadWebView`。用户登录成功、退出登录、其它身份边界变化或登录状态异常页点击重新尝试时,`AuthGate` 会优先请求 Expo 壳刷新当前 WebView;宿主未声明或刷新失败时再回退浏览器刷新,避免在移动壳内绕过受控容器刷新入口。 2026-06-18 追加:移动壳 WebView 内容 / 渲染进程终止时复用同一受控刷新路径。iOS `onContentProcessDidTerminate` 和 Android `onRenderProcessGone` 只调用当前 `react-native-webview` 的 `reload()`,不改写 H5 URL、不注入额外脚本、不新增宿主恢复页面,避免系统回收 WebView 进程后留下空白容器。