跳到正文

客户端加载与请求排查

证据日期:2026-09-17。代码基线:f3917816;下文“已修复”指本次工作区改动,尚未代表安装版或生产环境。范围包括启动、项目切换、Memory、Guidelines、Reviews、Bundles、Activity、检索诊断、管理页面,以及 App → XPC → daemon → HTTP 的请求链路。服务器资源扩容不在本次范围内。

结论

问题同时存在于界面状态和请求安排。客户端并非完全没有加载状态:Reviews、Bundles、管理页面已有加载与失败分支,Workspace 也有并发限制、版本校验和刷新节流。但占位方式不一致,文档和 Activity 的失败没有在对应内容区域正确结束加载;启动和部分列表还等待了本来可以延后的工作。

Guidelines 预览读取随 App 打包的 Markdown,不发 HTTP 请求。原实现分别维护“是否打开”和可选预览内容,允许弹窗先出现而正文为空。本次改为由非空预览数据直接驱动弹窗。代码证明了这个状态缺口,但没有对截图发生的那一次点击做性能录制,因此不能断言那次空白的全部耗时来自该缺口。

本次已修复

位置原问题当前行为
启动窗口加载页沿用登录表单的高窗口加载页高度 360 pt,登录表单仍使用原尺寸;切换保留窗口中心
Guidelines 入口两个主操作争夺空间,文案截断保留 Set Up Guidelines;预览仍是辅助链接
Guidelines 预览展示开关与正文分离.sheet(item:) 收到文档后才展示;可预览全部初始化文件
初始化记忆空间只创建规范正文同一 SQLite 事务创建规范和三个目录 README,失败全部回滚;保留已有规范、目录和内容
Guidelines 检查页面准备重复读取组织版本、目录和草稿;写入前又重复校验首次展示使用已加载元数据,用户采用时重新校验一次,并将该版本交给批量创建
Memory、Reviews、Bundles、Activity、项目准备同一区域叠加转圈和装饰性骨架共用局部原生加载指示器;已有数据的刷新保留内容
文档正文失败只写入全局错误,正文仍转圈;重复读者拿不到同一失败结果就地错误与重试;相同资源版本共用请求和结果,权限上下文改变会取消旧任务
Activity错误被表现为“没有数据”,旧项目结果可能覆盖新状态区分首次加载、成功为空、失败;同上下文请求去重,旧结果失效,刷新失败保留已有内容
请求观测成功响应缺少 App 端耗时server_completed 记录 elapsed_ms,覆盖排队、XPC 和响应返回时间

默认骨架为:

text
CLUMSIES.md
knowledge/README.md
procedures/README.md
lessons/README.md

README 只说明目录用途,不虚构项目知识。这些文件进入现有 Draft 和评审流程,不直接发布组织记忆。详见 Memory Guidelines

9 月 18 日 Activity 后续修复

Activity 已拆分为摘要游标分页和选中会话的任务分页。发现日志在阻塞线程池执行,后续页复用快照;只为当前任务页关联检索详情。首个请求前恢复项目选择,长会话不再静默截断。通用加载组件已移除转圈与骨架叠加,改为一个原生指示器。

具体边界与恢复方式见 Activity。初次发现仍需遍历有界日志头;安装版耗时需另行实测,不能从回归测试通过推断速度。

仍需调整的请求设计

以下是代码确认的结构问题,尚未在本次修改中实现。优先级按用户可用性和数据正确性排序。

优先级证据位置问题与下一步
AppDelegate.startAfterNativeSetupCheckWorkspaceLoader.loadAuthenticatedWorkspaceIdentityreconcileManagedAgentAdapters启动先等 /setup,再等已配置的插件维护,之后才读取账号与 Workspace。set_agent_adapter 的 XPC 预算达 130 秒。把插件维护移到独立状态任务,保留退出登录和离线时也能维护的要求;界面就绪不应等待它完成。setup 探测也需要与离线启动协调。
RetrievalDiagnosticsModel.loadMore分页响应缺少项目/加载代次校验;切换上下文时旧页可能追加到新列表。先分开列表与详情的代次,给分页补齐失效和取消保护;同项目刷新失败保留已显示数据。
WorkspaceLoader.load单项目、组织与项目目录各一页时,首次就绪需要约 9 次 GET:身份 1 次、初始版本/选择 3 次、目录 2 次、最终校验 3 次。部分已并行,但最终组织和项目校验仍串行。保留一致性校验,先并行独立的最终检查,再评估携带版本的聚合快照接口。
WorkspaceLoader.loadBundlesBundleNavigator列表先加载所有 Bundle 的详情,形成 N+1;打开导航还会准备全工作区索引。列表只取展示所需摘要,详情及项目资源选择器按需读取。
DaemonXPCClient.callstate.rs:HTTP_REQUEST_TIMEOUTserver_request普通 XPC 和单次 HTTP 都是 30 秒。daemon 等网络失败才退回缓存,加上凭证刷新或重试,外层可能先超时。建立整个操作的统一期限和取消传递,为缓存回退留预算;只读展示与写入前权威校验应有不同读取策略。
ServerRequestLimiter当前最多 12 个并发请求,但等待槽位的队列不立即响应取消。取消请求等到获准后才退出,不一定发出 HTTP,但会继续占据等待队列。需要可取消排队;跨视图 GET 去重应以相同身份、路径和版本为边界,不能仅按 URL 复用。

不能把版本校验、权限检查或写入前确认删掉来缩短时间。当前 Workspace 的状态轮询与数据刷新分别受 2 秒/30 秒节流和在途保护约束;本次没有发现据此认定“无限重复请求风暴”的证据。

本机日志证据及限制

只读检查了当天已安装客户端和 daemon 的日志。以下为北京时间;未导出正文、凭证或项目标识。

时间观察能支持的结论
13:26:38/setup 返回 200,169 ms这一次 setup 请求不是数秒延迟的来源;不能代表其他启动
13:37:48、13:38:48Review 文件加载 5,710/5,873 ms,之后命中本地内容为 0–2 ms首次正文路径明显较慢;缓存有收益,但这些数字不能区分服务器执行、传输和排队
13:38:07list_recalls 经 31,282 ms 报 XPC 超时本机会话加载也存在超时;该请求不是服务器下载链路
13:37–13:38若干 daemon server_request 为约 3.2–5.8 秒网络请求链路确实慢过;没有同请求的上游/传输分段证据,不能归因于带宽

这些是单机历史样本,不是 p95、不构成改动后的性能对比,也不能证明所有空白弹窗都由网络造成。

加载状态约定与验收

复用现有状态模型和原生 SwiftUI,不引入新的状态管理框架:首次加载只在等待区域显示一个原生指示器;成功且无数据才显示空状态;首次失败显示就地重试;同上下文刷新保留数据并显示进度或错误;切换项目后丢弃旧结果。指示器提供辅助功能标签,不再叠加装饰性骨架。

本次已运行 macOS 完整测试、daemon 单元与生命周期测试、Rust Clippy,以及文档构建。新增回归覆盖初始化资产与保留策略、Swift/daemon 批量协议、事务回滚、并发文档读取共用失败结果、Activity 旧结果与重复请求、失败重试和启动窗口尺寸。

后续请求架构改动需要在隔离环境补齐慢响应、离线、401 刷新、取消排队和大量会话文件的实测,记录 first-ready 与内容可用时间。当前未完成逐页面视觉验收、修改后安装版性能录制或服务器扩容;不能据此宣称性能问题全部解决。