Skip to content

[windows] visible 与 ready 脱钩,主窗口在 hotkey ready 前提前可见 #98

@Cooper-X-Oak

Description

@Cooper-X-Oak

治理归属

  • 族群:C 族群 / 启动视觉暴露契约
  • canonical PR:fix(windows): 收口 startup visible-ready 生命周期并进入评审观察 #145
  • 主修范围:visible-before-ready、cold-start visual exposure、first visible frame、first usable state
  • 不默认并入:主窗口外观贴合、capsule geometry、helper-window 生命周期、双事件源重构
  • 参考:
    • docs/windows-window-governance-board.zh-CN.md
    • docs/2026-05-02-window-capability-family-audit.md
    • docs/github-tracking/windows-window-family-canonical-map.md

现象 / Symptom

Windows 冷启动路径里,visibleready 目前是脱钩的:主窗口可以先被用户看见,但 global hotkey / runtime lifecycle 还在后台异步安装。

这不是单纯的 UI 小闪烁,而是 startup lifecycle ownership 不统一:

  • main 的可见时机与 runtime ready 不是同一个 source of truth
  • backend 负责 show_main_window() / tray reopen / single-instance focus
  • frontend App.tsx 又在 mount 后主动 currentWindow.show()
  • Windows 路径下 gate 初始值直接是 ready

证据 / Evidence

  • openless-all/app/src-tauri/tauri.conf.json
    • 主窗口创建阶段的 visible 策略与 frontend 显示策略没有被单点收口
  • openless-all/app/src-tauri/src/lib.rs
    • backend 明确拥有 show_main_window() / hide_main_window() 生命周期入口
    • hotkey listener 与 QA hotkey listener 在 setup 后异步启动
  • openless-all/app/src/App.tsx
    • Windows 路径初始化时直接 gate='ready'
    • mount 后又在 requestAnimationFrame 里调用 currentWindow.show()
  • docs/2026-05-02-platform-lifecycle-audit.md
    • 审计已将该问题归类为 startup lifecycle ownership 偏差

与 macOS 原始设计意图的偏差 / Deviation from macOS design intent

  • macOS 的原始设计意图更接近“用户第一次看见主窗口时,它已经处于可理解、可交互、视觉稳定的状态”。
  • Windows 当前更像“窗口先到,能力后到”,visible lifecycle 先于 ready lifecycle,先暴露过渡态而不是设计态。
  • 这不是单纯的速度差异,而是生命周期 contract 没有对齐。

5 Whys / 根因分析

  1. 为什么用户会看到一个看似 ready 的窗口,但热键 / 运行态未必已经 ready?
    • 因为窗口可见时机和 runtime readiness 时机不是一个 source of truth。
  2. 为什么这两个时机分离了?
    • 因为 backend 和 frontend 同时持有 main visibility 的一部分控制权。
  3. 为什么 Windows 上更明显?
    • 因为 Windows 启动路径跳过了更明确的 startup gate,正式 UI 更早暴露。
  4. 为什么这偏离了 macOS 的原始设计意图?
    • 原始意图是“用户看见主窗口时,它已经进入可用或可解释的阶段”;Windows 当前更像“窗口先到,能力后到”。
  5. 为什么之前没被系统性识别?
    • 现有 smoke 更关注“进程活着 + 稍后日志出现 hotkey installed”,没有验证“first visible frame == operationally ready”。

平台边界 / Platform Scope

  • 直接症状范围:当前主要在 Windows 冷启动观察到。
  • 问题层面:startup lifecycle ownership、window visibility contract、runtime readiness contract。
  • 全平台风险判断:这是全平台架构层风险,但 Windows 因跳过 startup gate、前端主动 show,最先表现为真实用户问题。

认领 / Ownership

影响 / Impact

  • 用户会把尚未 ready 的窗口误判为已经 ready
  • 会放大“热键没反应 / 运行态未安装”的首屏困惑
  • 会和 Windows 主窗口自绘 chrome 问题叠加,进一步放大 first-paint 不稳定感
  • 让后续任何 Windows 启动问题更难分辨是 UI 问题、hotkey 问题,还是 lifecycle contract 问题

建议接受标准 / Proposed Acceptance Criteria

  • main 窗口的首次可见时机只由一个 owner 控制
  • first visible frame 与 runtime readiness 的关系被明确定义并可验证
  • Windows 冷启动下,用户首次看到主窗口时,至少处于明确的 startupready 状态,而不是 ambiguous ready
  • 增加一条启动 smoke:覆盖 visiblehotkey installedfirst usable state 的先后顺序
  • issue 生命周期由 draft PR fix(windows): 收口 startup visible-ready 生命周期并进入评审观察 #145 承接并在 merge 时闭环

TODO / 不确定项

  • 是否应把 main visibility 完全收回 backend,frontend 只负责内容 gate
  • 是否应把 first visible frame == final UI state 提炼成单独的跨平台 startup invariant
  • 与主窗口圆角 / 外框问题如何分层验收,避免 frame-layer 问题和 startup-layer 问题相互污染

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingwindowsWindows-specific issue

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions