Repository navigation
fix(desktop): open the local workspace before background updates - #6835
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
…ypoints Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
songoow
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=GPT-6 Astra Pro; provider=OpenAI; declaration_source=self_reported
PR #6835 实现评审
结论:REQUEST_CHANGES。当前头有 2 项 P2;本地优先启动的主方向成立,但手动更新的选择和取消还不可靠。
审查绑定 7749fdbde3acbc616b452af759846b059fe14616;本次接受规范和本地 baseline 固定在 API 快照 base 82f9c09bd61e26e458cecfd4cffeab2350359381,PR 共同祖先仍为 d6de821eb3abfd24184a849a7d0bf9ddd7ca2c6b,相关原生树、基线说明和 UI 在两者相同。发布前发现新头后,保留了尚未发布的 3491c08b698be5fbe35a78a53e3570fb353fd267 全部报告与证据,重新阅读新 body、四个 commits、十二个文件及空 reviews/comments;没有继承作者自审结论。3491→7749 只新增安全缓存失败的呈现细化、两个测试、README 和一张原生 JPG。两个 P2、实际本地启动和对应原生/React 入口均已在新头重新执行。下文另行标明未变源码的历史缓存验证,以及作者 QA、CI、独立本机执行的不同边界。
动机
普通 macOS 桌面用户打开 LoopX 准备继续工作时,更新服务的连接或下载不应占住已经可用的本地工作区。
原来的普通启动先等待自动检查和可能的下载安装;这次先验证并打开本地服务,再在后台准备更新,把替换留到下一次正常打开。
独立对照已验证更新请求未完成时,两个真实本地 HTTP 服务仍能读到同一已安装运行时身份,退出的 Status 子进程也能恢复而不更换健康的 Chat 进程。
本次不新增 Agent、Goal、模型执行或 CLI 安装所有权,也不等同于完整签名发布、真实 macOS 窗口启动和系统重启安装已经验收。
新头重跑仍须修复 F1/F2。作者已补充有隔离边界的 macOS QA 过程和截图;本轮没有独立执行其系统窗口、签名替换或普通关闭重开。独立原 owner、真实进程/HTTP 和 React 的验证范围见新头回执。
改动思路
继续由现有 Maintenance 串行决定安装和恢复,网络下载只做后台准备,符合桌面 owner 的既有边界;新增缓存是经过再次校验才可使用的派生材料,不是第二个安装权限来源。
本 PR 的合理边界是普通打开的本地可用性、后台准备及下一次打开的验证交接;显式 CLI 升级、原子替换、备份和回滚继续由原 owner 负责。
| 路径 | 基线 | 当前实现与验证边界 |
|---|---|---|
| 普通打开 | 自动检查/可能安装先占住启动,再连接本地服务 | 先消费已准备的本地缓存;无缓存时直接进入原服务入口。成功后才启动后台网络任务。原函数加真实 HTTP 子进程的对照已验证这个先后关系。 |
| 后台检查/下载 | 没有独立的后台准备路径 | 使用单独的 task、generation 和 status snapshot,不持有服务 supervision;只保存更新,不替换当前 App。取消 fence 的准入窗口存在 F1。 |
| 用户手动操作 | 原 Maintenance 的 busy/supervision 与 pending 事务 | 仍走同一套固定 action/channel,先取消后台,再执行检查、安装或恢复;UI 允许后台时主动检查,但通道切换存在 F2 的旧读回灌。 |
| 真正安装 | 原签名、备份、原子替换和恢复 | 共享抽出的 install_verified_app;缓存再次验签、验 hash、验通道/版本,macOS 再校验 sealed plist 的版本。真实系统安装未在本机执行。 |
这里不需要额外的配置向导、用户声明或第二个升级服务。正常打开没有新增交互轮次;后台网络可用性也不产生 Goal、Agent 或 CLI 所有权。新增状态的生产者是现有本地启动和下载入口,缓存字段是下载事实的派生记录,用户不需要维护两套版本真相。现有签名/安装 owner 仍足够,修复应落在其取消准入和 UI 读代次上。
具体改动
全文按变更前的 apps/desktop/loopx-control-plane/README.md,固定版本 82f9c09bd61e26e458cecfd4cffeab2350359381 审查;辅助核对 docs/architecture/rfcs/desktop-execution-frontends-v0.md 的 State and identity boundaries 与 Native service ownership。当前 PR 对 README 的新描述不是独立验收依据。
| 基线条目 | 本头对应结论 |
|---|---|
| Updates And Recovery | not_met:固定通道、原备份与显式 CLI 路径仍在,但 F1 使已经完成的手动选择失去对应 pending 对象,随后同通道安装不能继续。 |
| Runtime Model | implemented,限已验证边界:原 ServiceSet 实際起两个固定隔离的 Core HTTP 子进程,读到相同 package fingerprint,结束后关闭私有端口;没有以相同源码版本替代安装身份。 |
Coexistence With loopx dashboard |
implemented,限进程/HTTP边界:后台请求保持未完成,杀掉精确拥有的 Status 子进程后由原恢复入口重建;健康 Chat PID 不变,Status 身份不变。没有操作全局 CLI 端口。 |
| Validation | deferred,限独立执行范围:作者新 body 给出 149 passed / 6 ignored 和隔离 macOS 关闭/重开、激活/恢复记录;本轮未独立执行这些 OS 效果。新头的 Linux owner、React 和真实 HTTP 已重跑,fresh macOS CI 仍只有 build/package。 |
| Recover An Interrupted App Update | deferred,限独立执行范围:完整读取签名、sealed version、备份、权限与原子替换路径;缓存原模块的密码学执行可按未变 hash 保留。作者新增 QA key/version/identifier 的激活、恢复和拒绝记录已有明确边界,本机没有把它们计作自己的 macOS 安装执行。 |
关键代码讲解
-
automatic_app_update/start_services与lib.rs成功分支:普通打开只读已准备的本地材料,不再先访问更新 feed;显式UpgradeRequest继续走原同步检查/安装及 service-ready receipt。lib.rs只有在两个服务通过原身份 fence 后,才在 handoff 后调用start_background_update。新变化是启动顺序,运行时资格仍由 Core 和原服务 owner 决定。源代码 -
start_background_update/run_background_update/cancel_background_update:后台使用自己的快照,只有主状态 ready 且非 busy 时才覆盖展示;错误保留到last_failure,不制造手动失败 latch。检查和下载不持有 supervision。写缓存与 pending 仍在 generation 检查内,但 starter 在准入之后才读取 generation,F1 正发生于两者之间。源代码 -
prepared_update::save/load/clear/is_newer:真实下载完成才产生缓存;新进程加载检查文件名/路径、完整 hash、minisign、通道和版本次序。独立探针使用原模块和真实签名,验证完整字节重开、篡改后重算 hash 仍拒、错 key/签名/trusted comment、旧 Ed 签名、通道及版本退役、路径逃逸不删除外部文件等,共 18/18;另 288 个版本/通道组合与基线 inline comparator 一致。这些保留为旧头的真实执行,prepared_update.rs、依赖锁及安装/调用函数逐字节相同,未伪标为本次重新运行。源代码 -
install_verified_app与macos_update::install_archive/install_prepared:原安装事务被抽为共同入口,先备份、再替换,失败仍区分当前 App 完好与 incomplete。安装成功后的缓存清理失败不把已完成替换误报失败。下载签名不能证明本地 cache 宣称的版本,因此安装器额外比较已验签 bundle 的CFBundleShortVersionString;准备包遇权限限制保留当前 App,显式操作仍有原授权适配器。这个防线的 placement 合理,实际 macOS效果仍未验证。源代码 新头run_automatic_update/failure_details:只对已经检查过 prepared 材料、错误为update_download_or_signature_failed或经过原恢复判断的app_install_failed,且没有 incomplete、manual-failure、busy 标记时,保留last_failure并把启动投影设为 connecting。返回值仍是 Err,journal_discarded的消费仍只有一次。其余错误维持原 error 投影;这不意味着任何 unknown 错误都会永久阻止之后的服务启动。我在新源码的原 generic owner 上实际执行 7 个错误/标记组合:四个 App 可用性/journal/prepared 组合,加签名拒绝、unknown 和 manual-latch 对照,全部通过。它验证失败分类与投影,未冒充实际签名安装、CLI receipt 或 OS 窗口测试。源代码 -
DesktopUpdate:把“需要持续观察”的 observing 和“应暂禁手动操作”的 working 分开,新增后台与准备完成的中英文说明。原run()的 busy/read generation fence 保留;独立组件验证 prepared 读回不自动发送 apply,手动 Check 可用,已有显式 Check 能拒绝旧 poll。F2 则是新解禁 select 后没有延伸同样的失效规则。 源代码
其余改动均已纳入:Cargo 把签名依赖用于生产并直接使用 semver;README 说明新顺序、错误投影和 QA 入口隔离;smoke 增加后台手动 Check、prepared、双语和窄宽观察。两张原 PNG 已实际查看,其字节未变,仍是作者明确标注的 synthetic native IPC 呈现。新增 2560×1640 JPG 也已实际查看:连接的空工作区正常可见,原生更新面板读为 0.1.1 稳定版,离线更新失败有可用的重试按钮。新 body 将其解释为隔离 QA App 的真实 native panel;图像能核实这一呈现,不能单独核实替换、重启、验签和服务清理的整个过程。
对主干的风险
F1 · P2:后台启动不能继承一次已经完成的取消代次
定位:maintenance.rs:1091–1095。普通打开完成服务交接后,后台 starter 先通过 busy/checked 判断,再另行读取 background.generation。如果此时线程让出,用户完整执行一次 check(main),该手动事务已经 acquire、cancel(增加 generation)、写入 main pending/available 并释放 busy;旧 starter 恢复后却会读到这个新 generation,把自己当成未被取消的后台工作。
原 owner 的确定调度复现结果是:手动响应与最后可见状态均为 main / available,但后台 stable 下载把 pending 改成 stable 并保存缓存;接着实际调用原 desktop_update(apply, main) 返回 update_check_required。通道检查阻止了错误安装,但用户刚成功检查的操作已无法直接继续。后台快照只在主状态 ready 时覆盖展示,所以它并不会诚实显示自己替换了手动候选。
最小修复是把 generation 捕获与准入绑定在取消之前的同一代次,例如在 gate 前捕获,或在同一 background 锁内完成判断和捕获。我用隔离副本只移动这一捕获位置、保留相同 provider 和调度:pending 保持 main,没有 stable 缓存,原 apply 通过通道检查,随后止于测试刻意禁止的安装适配器。这是反例敏感性,不是对生产修复或成功安装的声明。新加的 blocked-IO 测试先固定 generation=0 再取消,覆盖的是旧代次的迟到写入,不能发现本例“取消后才捕获新代次”的窗口。
F2 · P2:切换通道必须使在途后台状态读失效
新 working = observing && background !== true 允许用户在后台下载时改通道,但原 select 的 onChange 仍只修改 channel 和 state,没有增加 statusGeneration。我在真实 DesktopUpdate 组件中先发出后台 poll,再把 stable 改为 main,最后交付旧的 stable prepared 响应:刚变成 idle 的页面重新出现旧版本目标和“安装更新”,而安装请求使用 main。原 native owner 的独立场景确认 stable prepared/pending 本身完全正确,apply(main) 随后返回 update_check_required;这里没有 F1 的启动暂停或手动取消竞争。
最小修复是在通道变化时使旧状态读失效,并阻止旧通道候选恢复成新通道的可安装结果。保留后台时手动检查可用的设计。既有 run(check) 已有代次 fence,其正向对照通过,因此不应把整个后台轮询禁用。定位为 DesktopUpdate 的新后台 working 分支,具体补 fence 的调用点是同文件第 177 行 select onChange。React 验证使用受控 IPC、计时器与 popover 替身;它证明组件生命周期和实际调用参数,不是浏览器或布局资格。
实际验证范围与剩余边界
本机这次从 7749fdbde3acbc616b452af759846b059fe14616 的完整 maintenance 源文件重新生成并编译 owner probe,源 SHA256 为 29758c856472b3743c2799e97a7a7032cca39d1a2152f7923fed045633f690c8。F1、捕获前移的隔离反例、F2 独立原生状态来源、真实服务启动/恢复和 disabled 入口均为新头执行;React 也重新从新 checkout 转译并运行六个场景。历史 base 对照和缓存 18/288 执行保持原路径,依据完整函数/模块 hash 判定可复用,没有改名成新头测试。
为在 Linux 执行,隔离副本移除了 Tauri command 属性,仅对三个更新入口注入 macOS 资格;Tauri app/state/path、updater transport/provider 与 OS 安装适配器是替身,F1 额外使用一个精确调度屏障。真实部分包括原锁/代次/pending/公开 action 函数、未改的进程及 HTTP owner,以及同一 noneditable Core 的两个真实子进程。新头中 Status PID 203003→203237,Chat 203004 不变,更新 future 仍未完成,最终自有端口关闭。这证明原 owner 因果关系与进程/HTTP 边界,不证明原生 macOS 窗口、签名更新安装或 UI 首次交互时间。F2 的 React 调用与原生三段读回是分别执行的相邻边界,未写成一次实际 macOS IPC 全程测试。
Core 的独立 installation-only doctor 成功;实际身份是 package 2.0.0a1、source_revision=null,fingerprint 为 sha256:62cfeab3e6eb109afb1b458ae63a40b57bf56707d3b2668d010b388112468c96。构建来源与本 PR 是不同概念,未把另一提交的 Core 伪标为本头安装。入口固定空 registry/runtime,关闭 usage ping,无模型或 benchmark 执行;只终止自己的 Status/Chat,未修改用户 App、全局 registry 或生产源码。
语义与 CI 对齐
这里复用现有 Maintenance 与 phase/channel 词汇,新增的 background/prepared 只是本地派生投影。语义缺口是上面的2个可重复竞争,不是需要新 Goal schema、重做状态机或更换安装 owner。复核命令应分别覆盖“准入后完成取消”和“通道改变后旧 poll 返回”,两者不能互相替代。
新头 CI 在 18:45 UTC 前取得的快照为 32 条:12 success、5 skipped、12 in_progress、2 queued、1 failure;旧头 18:27 的快照只保留为历史。新 macOS desktop job 实际编译并打包成功,但仍只运行 tauri build --bundles dmg app --no-sign,没有执行 cargo test/clippy。日志中的测试对象是 synthetic merge d2fe85ebe973ff2b81bb754ebaf69b3b83539294,把本头合入 8220f4cae38ee78db39955de312ac0df20437e06;这是 CI 的实际基底,和本次 accepted spec/本地 baseline 的 82f9c09bd61e26e458cecfd4cffeab2350359381 分开记录。
作者更新后的 149 passed / 6 ignored、Clippy 及原生 QA 记录已完整阅读,包括临时 QA key/version/identifier、正常 Command-Q、prepared 激活与恢复、篡改与版本重标拒绝,以及非 official-feed OTA/非用户安装采用的限制。这些作者提供的结果与我们查看的原生截图、fresh hosted build 和独立 Linux owner 执行分别列明,没有把其中一种替代另一种。
唯一当前失败仍是新 Windows job,同样测试上述新 synthetic merge。cli-output-budget-regression-smoke.py 在创建 D:\tmp\loopx-brief-* 时出现 FileNotFoundError / WinError 3,发生在预算 CLI 调用之前。旧头及同类日志只是归因线索;没有 immutable exact-base 的同平台执行,故仍标 unresolved,未概括为已独立证明的既有失败。其余 pending/queued 没有被当作代码缺陷,也没有持续轮询补成 all-green。
我的整体评价
这是一个有用且范围合理的本地可用性增量:原 owner 加真实 HTTP 的 base/head 对照表明,可选更新不再占住本地服务,健康 peer 和精确运行时身份在故障恢复中仍保留。对 long_horizon 的本次有限结论是 improved,针对的是这个已测服务继续工作的边界,未外推到模型 Turn、原生窗口重开或安装后的完整长期运行。对 user_experience 的结论是 regression:F1/F2会让已知通道选择与可操作结果失配,使更新请求在安装前被拒,并迫使用户重复检查;正常打开本身没有理由再新增用户确认轮次。
架构和代码量可以保留在当前 owner 内:一份重新验证的派生缓存、一个后台观察任务和共享的安装入口,与每次打开都会遇到的 IO 问题相称。完整签名/版本/权限/备份边界不能删掉来减少行数;并发 fence 和 UI read generation 的最小修复也不需要新抽象层。既有显式 CLI 事务、persisted recovery journal 和独立安装所有权有真实兼容需求,继续保留是合理选择。
**当前头不能批准。**先修复上述2项 P2,并用同样的负向时间顺序复核;保留本次已通过的本地启动、固定 Core 身份、真实 child-exit recovery、缓存密码学及正确显式 Check 控制。作者补充的原生 QA 记录和我们的独立平台资格分别保留;Windows 新头失败另行完成归因。本结论没有把测试环境限制、作者自报通过或 hosted 打包成功替换为完整产品资格。
English verdict: REQUEST_CHANGES — reviewed 7749fdbde3acbc616b452af759846b059fe14616. Two P2 findings remain after fresh original-owner and React replay: an admitted background starter can adopt a completed manual cancellation's generation and overwrite the checked channel; independently, changing channels leaves an in-flight old-channel status poll valid and exposes a mismatched Install action. Both original native apply paths reject before installation. The same-source capture-before-admission counterfactual preserves main pending. Fresh head process/HTTP probes confirm local startup and owned-child recovery while updater IO is held. The new safe cached-failure projection passes seven original-owner error/flag cases. Prior cache/crypto18 and comparator288 executions are retained only after source/dependency fingerprint validation. Author149/6 native QA, viewed native JPEG, hosted macOS build/package and independent Linux/React execution remain separate evidence; neither the facade nor renderer qualifies a native macOS window or installation. Fresh Windows fixture failure remains unattributed on an immutable same-platform base; current CI uses synthetic merge d2fe85ebe973ff2b81bb754ebaf69b3b83539294 on 8220f4cae38ee78db39955de312ac0df20437e06.
| || state.automatic_update_checked.swap(true, Ordering::AcqRel) | ||
| { | ||
| return; | ||
| } | ||
| let generation = state.background_update.lock().unwrap().generation; |
There was a problem hiding this comment.
[P2] 将取消代次的捕获纳入后台任务准入。
这里通过 busy / automatic_update_checked 判断后,才读取 background.generation。如果 starter 在两步之间让出线程,一次完整的手动 check(main) 可以先完成 acquire、cancel、发布 Main pending/available 并释放 busy。旧 starter 随后会取得取消后的新 generation,继续以有效后台任务的身份保存 Stable 缓存并覆盖 pending。
我在原 maintenance 入口上控制这一个调度窗口:手动 check 返回 Main available,最后主状态仍是 Main available,但 pending 已变成 Stable;实际 desktop_update(apply, main) 返回 update_check_required。将 generation 捕获移到 gate 前的隔离对照保留 Main pending、不写 Stable 缓存,并通过同通道检查直到测试禁止的安装适配器。Tauri/平台/provider 是明确的测试替身,没有执行 App 替换。
请把 generation 与准入绑定,保证取消前已经开始的 starter 不能认领取消后的代次。回归应保留完整 check → 后台恢复 → apply 的原入口,以及 pending 通道和 superseded cache 的断言。
| const invoke = (window as DesktopWindow).__TAURI__?.core.invoke; | ||
| const working = workingPhases.includes(state.phase); | ||
| const observing = workingPhases.includes(state.phase); | ||
| const working = observing && state.details?.background !== true; |
There was a problem hiding this comment.
[P2] 开放通道切换时同步失效在途状态读。
这个新分支允许用户在后台检查/下载时操作通道 select,但同文件第 177 行的 onChange 只修改 channel 和 state,没有使 statusGeneration 失效。已发出的 Stable poll 在用户切到 Main 后仍能被 commitStatus 接受,把刚清空的状态恢复为旧 Stable 目标的 available/prepared,并再次显示安装按钮。
真实 DesktopUpdate 组件复现了 Stable poll 发出 → 选择 Main → 旧 Stable prepared 返回 → 按钮实际发送 apply(main)。独立调用原 native 后台入口和 status/apply,确认正常 Stable pending 会将该请求拒绝为 update_check_required;这条路径不需要另一条 finding 的准入暂停或手动取消竞争。
请在通道变化时失效旧的状态读取,并让可安装候选保持与所选通道一致;保留后台期间手动检查可用的行为。现有 run(check) 的 generation fence 正向对照能够拒绝旧 poll,可以沿用同一个读代次机制。
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; reasoning_effort=max; declaration_source=runtime_reported
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
APPROVE — 完整复评绑定 04808b8b8cf96af75cd956ca1c9bce5af13888f1,基线为 dc9fdbb5186618ec2e797a9d7545e2fe524fee56。F1、F2 均已在实际入口的反例敏感检查中通过;当前没有待修复的 PR 代码阻塞项。
本次结论来自全量 14 个文件及周边调用链的复核,并未把旧 review 的结论或作者自报作为批准。GitHub 作者账号与本机账号相同,因此使用 COMMENTED 承载批准结论。批准、旧 review 核销、合并及安装资格分别记录。
动机
普通 macOS 桌面用户打开 LoopX 准备继续工作时,更新连接或下载不应占住已经可用的本地工作区。
以前普通打开先等更新网络和可能的安装;现在先打开合格的本地服务,后台只准备更新,下次打开才重新校验并替换,手动检查仍可立即接管。
本头已验证手动选择不会再被迟到后台任务或旧通道响应覆盖;可选更新失败仍保留诊断和可操作的重试入口。
本次不新增 Goal、Agent 或独立 CLI 安装权限;完整官方 OTA、正式发布、系统重启安装和用户安装采用仍是独立资格。
这是可独立交付的桌面可用性增量。本轮没有执行真实 macOS 窗口关闭重开、跨卷替换、官方签名 OTA 或全局安装;这些保留给既有桌面发布与 #5204 的逐平台验收。 不把一次启动、测试数或源码状态当作整个桌面路线图完成。
改动思路
后台网络、可丢弃缓存和界面投影都留在现有桌面维护边界;安装、备份、回滚继续共用原事务入口,没有增加第二个控制面决策者。
当前 PR 的完整可回滚边界是普通打开先使用本地工作区、后台准备、下一次打开重新验证,以及手动操作可正确接管;正式发布和每个平台的安装资格另行验收。
下面是本头的源码行为对照;表格是解释,不是额外执行证据。
| 用户触发 | 基线 | 本头及失败边界 |
|---|---|---|
| 普通打开,无可用缓存 | 先走自动检查及可能的下载安装,再启动服务 | 先连接合格本地服务,handoff 后后台检查;网络失败留诊断,不抢占现有工作区。 |
| 下一次打开,有已准备缓存 | 没有可重开消费的缓存 | 再验签名、hash、通道和版本,安装器再验 sealed bundle 版本;当前 App 完好的拒绝可继续启动,incomplete 与 unknown 保留恢复边界。 |
| 用户主动检查或安装 | 现有固定 action/channel 与串行事务 | 先取消后台,再走原公开入口;取消代次与准入绑定,主通道候选不会被旧 stable 任务覆盖。 |
| 后台时改变通道 | 新解禁选择后曾有旧 poll 回灌 | 选择递增读代次,且按实际所选通道过滤状态;旧目标和安装按钮保持清空,下一次主动检查使用新选择。 |
不需要额外设置向导、复制命令或重新声明已经知道的安装意图。普通打开没有新增确认轮次;主动检查、换通道和修复仍是按需入口。后台准备不是安装授权,缓存存在也不能越过 shipped key、版本绑定和现有安装所有权。
具体改动
先按变更前的 apps/desktop/loopx-control-plane/README.md、固定 dc9fdbb5186618ec2e797a9d7545e2fe524fee56 审查,再看本 PR 对 README 的修改。辅助核对同一基线 docs/architecture/rfcs/desktop-execution-frontends-v0.md 的 State and identity boundaries 与 Native service ownership。这几份规范及原启动/服务 owner 与旧独立评审采用的 82f9c09bd61e26e458cecfd4cffeab2350359381 逐文件 blob 相同,基线整合未改变该验收框架。
| 规范原条目 | 当前判定与证据边界 |
|---|---|
| Updates And Recovery | implemented:固定通道、手动优先、签名与恢复 owner 保留。F1 的完整 check→background resume→apply 及 F2 的真实构建界面重放通过。 |
| Runtime Model | implemented,限本地服务/身份边界:ServiceSet 未改;保留旧独立真实双服务、固定 Core 身份证据,本轮构建及隔离真实 HTTP 也通过。不把 source revision 当安装身份。 |
Coexistence With loopx dashboard |
implemented,限服务所有权边界:原私有端口、健康 peer 保留和 owned-child recovery 未改。旧独立验证在 updater future 未完成时恢复 Status、保留 Chat;本轮对其源码重新做了失效核查。 |
| Recover An Interrupted App Update | implemented,限被检查的 owner/缓存/恢复语义:当前原生套件及原安装器版本绑定测试通过;未改缓存/签名模块的旧独立 18 项密码学、288 项比较器对照按 hash 保留。真实发布安装资格没有因此获得。 |
| Validation | implemented,限源码交付:本头原生、Clippy、格式、TypeScript、打包和 premerge 已独立执行;签名 App、跨卷/OS 重开及正式安装采用仍属上述逐平台发布验收范围。 |
关键代码讲解
-
automatic_app_update、start_services与lib.rshandoff 成功分支:普通打开只消费本地已准备材料;没有缓存就进入原服务入口,两个服务 ready 后才启动后台任务。显式UpgradeRequest继续原同步更新和 service-ready receipt 路径。可选 IO 不再拥有本地服务启动顺序,也没有改变 Core 的资格来源。启动 owner、handoff。 -
admit_background_update/start_background_update/cancel_background_update:准入时在取消共用的 background 锁内读取 generation,结束了“已过 gate,取消完成后才捕获新代次”的 F1 窗口。已准入但未发 IO 的任务仍持旧代次,注册时会被 abort 或在发布/保存时拒绝;网络任务不持有 supervision,保存缓存和 pending 则在同一 generation/busy fence 内。准入、后台实际入口。 -
prepared_update::save/load/clear/is_newer:缓存由真实下载结果自动产生,先完成 archive 再发布 pointer;重开时重新核验 shipped key、完整字节 hash、通道/版本,过期候选被退役。它是可删除的派生材料,不是另一份安装权限。旧签名、路径逃逸和比较器证据只按未变源码/依赖复用,未标为本轮重新运行。缓存模块。 -
install_verified_app、macos_update::install_prepared与失败投影:手动和缓存路径共用备份/替换事务,sealedCFBundleShortVersionString必须等于已公告版本。prepared 安装不会自动提权;手动路径保留原授权适配器。安全拒绝保留last_failure并继续 connecting;incomplete、unknown、journal 失败及手动失败 latch 没有被清掉。回滚先清准备缓存,避免下次打开撤销用户恢复;成功替换后清缓存失败不伪报安装失败。共同事务、版本绑定。 -
DesktopUpdate.commitStatus/onChange:observing 允许观察后台进展,working 只暂禁真正手动事务。通道选择同时失效旧读并更新 selectedChannel;即使后来轮询取得新代次,也不能把另一通道的候选写回。手动run使用当前选择,finally 只补读 metadata,不覆盖操作结论。状态接纳、选择入口。
其余文件一并纳入:Cargo 将原签名依赖投入生产并直接依赖 semver,lock 只增一条直接依赖;README 解释启动、失败及隔离 QA 的真实边界;浏览器 smoke 增加迟到通道、后台手动检查和呈现断言。14 个文件共 +955/-70,包括大量原生回归测试和 5 张截图,不能把这些全算新增生产机制。全部图片已实际查看,当前桌面/窄屏图片明确绑定本头的打包前端和 synthetic native IPC;原生 JPG 属旧 QA 激活记录。没有把截图等同于验签、安装或重启执行。
对主干的风险
**F1 已核销,带反例敏感性。**我从本头提取原 desktop_update、perform、starter 和锁/pending/cache 路径,在隔离适配器中精确暂停 starter。置换回 7749fdbde3acbc616b452af759846b059fe14616 的旧 starter 后,完整手动 check(main) 虽返回 main/available,后台恢复却保存 stable 缓存并覆盖 pending,随后原 apply(main) 返回 update_check_required。当前 starter 在准入前暂停和准入后暂停两种顺序中,都保留 main/2.0.0、无 stable 缓存,原 apply 通过候选检查,止于测试主动禁止的安装适配器。Tauri app/state、下载 provider 与 OS 效果是替身;原公开 action、锁、代次、pending 和缓存写入是实际源码。该检查没有执行安装。
**F2 已核销,分别验证读代次和通道过滤。**在本头真实打包前端、隔离真实 Chat HTTP 服务和受控 native IPC 下,先挂起 stable prepared 读,选择 main 后释放:没有旧目标、没有安装按钮、没有自动更新调用;主动检查随后发出 main。只换回旧 React 组件,同一类顺序重新出现 stable/1.1.0 的安装按钮而选择仍为 main。另单独调用已取得新代次的旧通道 poll,本头仍拒绝其候选,覆盖了单靠递增 generation 不够的方向。错误后可检查/修复、Escape 关闭、1280×900 与 390×844 无横向溢出和面板裁切均通过,整幅截图已查看。这里的 native IPC 是 synthetic,不是实际 macOS IPC/系统安装全程。
| 本轮独立检查 | 结果 |
|---|---|
cargo test --locked |
152 passed;单元 suite 6 ignored,另 signed_bundle 集成 1 ignored,共 7 个需签名/隔离打包输入的案例未执行。 |
cargo clippy --locked --all-targets -- -D warnings、cargo fmt --check |
passed。 |
桌面 Chat build、TypeScript、scripts/chat_bundle.py build |
passed;打包 manifest 的 source_revision 为本头。Vite 大 chunk 提示保留,不是失败。 |
exact-head loopx canary premerge --from-git-diff --git-diff-base dc9fdbb5186618ec2e797a9d7545e2fe524fee56 |
passed:4 项直接检查、10 个 catalog、8 个 risk smoke、1 个 public-boundary;没有用自动选择替代原生检查。 |
| 原入口 F1 反例/修复及边界对照 | 旧缺陷重现;两种修复顺序通过;非官方 identifier、显式 CLI 请求、busy 三组 old/current starter 对照不启动后台,随后手动检查仍可继续。 |
| 真实构建浏览器重放 | F2 修复、旧组件反例、新代次错通道过滤、错误恢复、Escape、桌面与窄屏通过;隔离服务与测试页已关闭。 |
| 同命令 Python base/head 对照 | 两边均 53 passed / 6 failed;归因如下,未改测试或预算。 |
Python 用同一解释器、两个检出来源分别执行 python -m pytest -q tests/control_plane/test_monitor_target_transport.py tests/test_chat_manager_inspection.py。不可变 base dc9fdbb5186618ec2e797a9d7545e2fe524fee56 和本头的六个失败身份、期望异常与实际细节一致:test_real_large_authority_returns_complete_target[120000-file]、[120000-sqlite] 均未抛出 LocalCoordinationAuthorityUnavailable;test_manager_runtime_installs_tool_and_records_real_subprocess_read 的 todos、todos_exact、agents、agent_route 均在 thread/name/set 报 CodexChatTimeoutError。整棵 loopx/、tests/、scripts/ 在 base/head 相同,当前桌面不调用这些失败路径,且桌面不变量另有独立通过证据。因此六项为 pre_existing_unrelated,属于监控传输/manager fixture 的单独修复事项,不是本 PR 已修好,也没有被改成 passing skip。这里的 59 项选择与作者报告的 61 项选择不同,不混用计数。
7 个 ignored 案例的签名 App、正式签名 archive、私有 Core 和跨 APFS/HFS+ fixture 未在本轮提供;原套件明确需要这些输入。本轮通过原生版本绑定等测试、未变模块的旧独立缓存/签名与服务证据,覆盖本次源码判断;真实 native Command-Q、替换/恢复和重开仍只引用作者明确隔离的 QA 报告,保留 key/version/identifier 替换与非官方 OTA 的限制。作者提过的早期 service/listener fixture 间歇失败没有被声明修好;当前 owner/HTTP/取消证据限定覆盖本次变更风险,不外推系统 soak 稳定性。未重跑仓库 Playwright 脚本,而是用 Ego 在真实构建上重放风险相同的路径,两个边界分别记载。
按当前 review 的 wait_for_ci=false,本轮没有查询、轮询或等待 CI;没有把旧 Windows 红项或 pending 状态继承为本头代码缺陷。相关 Windows NSIS PR #6854 尚未并入,本头仍是原 macOS 门;以后整合需重新检查该门和更新入口,不能从本次结果推导 Windows 更新资格。完整官方 OTA、installed adoption 与合并 readiness 均不由本次 APPROVE 代替。
我的整体评价
本头是范围合理的 justified_increment。对持续有用工作的有限结论是 improved:可选网络不再占用本地服务与其恢复 owner;对用户体验是 improved:打开不增加准备轮次,用户接管及换通道不会再把旧候选装扮成当前选择。没有测模型 Turn 收益、安装后长期采用或通用启动 p95。
后台网络、可丢弃缓存和界面投影都留在现有桌面维护边界;安装、备份、回滚继续共用原事务入口,没有增加第二个控制面决策者。 当前 PR 的完整可回滚边界是普通打开先使用本地工作区、后台准备、下一次打开重新验证,以及手动操作可正确接管;正式发布和每个平台的安装资格另行验收。 缓存完整性、版本绑定和恢复并非为了增加行数;删掉它们不能得到同等合法且更小的方案。把网络仅缩短 timeout 仍会每次占住打开,不如现有 owner 的准备/消费分离。已采用的共用安装、比较器和失败详情属于同域有价值的整理;更大语言迁移、独立升级服务或新配置层没有当前必要。
已重新按原问题评估代码量和架构,没有把修复上次两条意见等同于整 PR 批准。旧独立评审的具体执行仅在源/依赖失效核查后保留为历史证据,结论未继承;当前 F1/F2 均重新执行。可核查的 旧完整评审 和两条 inline discussion 应保留;旧阻塞 review 的原生核销另行读回。当前代码可批准;合并、发布及安装仍有各自权限与验收。
English verdict: APPROVE — reviewed 04808b8b8cf96af75cd956ca1c9bce5af13888f1 against dc9fdbb5186618ec2e797a9d7545e2fe524fee56. The original public check/apply owner reproduces F1 with the old starter and preserves main pending/no stale cache in both fixed admission orders; installation stops at a prohibited test adapter. Built-frontend browser replay rejects delayed and new-generation wrong-channel status; the old-component mutation restores the defect. Native 152 tests, Clippy, formatting, TypeScript/package and premerge pass. Seven environment-dependent native cases were not run. The same six Python failures reproduce on immutable base with unchanged causal trees and are pre-existing/unrelated. Historical independent cache/service evidence is reused only after source/dependency checks; synthetic IPC and author-only native QA are identified. CI was not consulted. Official OTA, installed adoption and merge authority remain separate.
Ordinary macOS opens currently wait for automatic update network work before starting local services. Start the qualified local workspace first, then check, download and verify the official update in the background. Prepare verified bytes for the next normal open; background work never replaces or restarts an active workspace.
The existing Desktop maintenance owner retains authority. The disposable cache rechecks the shipped updater key, content hash, channel/version order and sealed bundle version before replacement. Manual actions supersede background work. Explicit CLI upgrade receipts, independent newer CLI selection, developer pins, signed replacement and backup/rollback retain their existing paths.
A rejected cached signature or verified-safe replacement failure now retains diagnostics while startup continues. It no longer briefly tells the user startup has stopped while services are connecting. Incomplete targets, failed journal retirement, unknown failures and explicit-operation errors retain their recovery boundaries. Failure-detail construction is shared; no additional configuration or state authority is introduced.
Two review findings are repaired at
04808b8b8cf96af75cd956ca1c9bce5af13888f1: background admission captures its generation under the same lock as cancellation, so a delayed starter cannot adopt a completed manual check's generation. Selecting another channel invalidates pending status reads and filters mismatched channel snapshots; an old prepared response cannot restore its install action.Current validation
--all-targets -- -D warnings, Rust formatting, TypeScript and packaged Chat build passed. Tests cover completed manual work before admission, cancellation after admission before IO, and retry after busy admission.Current native workspace acceptance
At
04808b8b8cf96af75cd956ca1c9bce5af13888f1, an isolated packaged debug native App, using actual native IPC and actual Core HTTP services, displayed the workspace while the official update connection was held. The native interface still displayed “后台更新中” when Settings completed loading. Command-Q exited the native process and both owned services naturally; the test ports closed. Three current-head functional runs were retained, with the final run verifying the pending-update/loaded-Settings overlap directly. The isolated baseline Settings path was also exercised.The test used a distinct QA identifier/product name, two matching eligibility substitutions and the same immutable qualified Core wheel for base/head. Its registry had no Goals or Sessions; the fault proxy was process-local and did not forward TLS. The official App and its data were not replaced. Initial launcher/binding mistakes and delayed observations were excluded and retained as invalid harness attempts. This proves native responsiveness during the pending update; it does not establish first-paint latency, a cold-start percentile, full official-feed OTA or installed adoption. The existing HTTP-only comparisons below retain their original limits.
Earlier native qualification
--all-targets -- -D warnings.3f82753d3e642a5b41fc6a9a988ad22c197124dc. Its automatic selection does not qualify Rust; the native suite and Clippy provide that coverage. The final commit adds only the native capture below.0.1.0with0.1.1, restarted into a new process, opened both qualified HTTP services, and cleared the prepared pointer. The native panel read back0.1.1. Manual restore preserved the old signed bundle and required an explicit restart; afterward the panel read0.1.0, with the same independently owned Core identity and no silent cache reapply.0.1.1archive relabeled9.9.9. Both kept the original target hash/signature and opened the real workspace. Before refinement the latter briefly displayed terminal recovery language, then opened; it was not a persistent hang. After refinement both logs proceed through connecting/ready without that false error phase.These native fixtures use a distinct QA identifier, eligibility substitution and an executable-bound isolated registry/runtime with no Goals or Sessions. The cached-activation fixture additionally substitutes QA versions and its ephemeral public key. It qualifies local prepared activation/recovery, not a complete official-feed OTA download or official installed adoption. The official installation was not replaced. Earlier intermittent existing service/listener fixture failures remain recorded; the final full serial run passed, without claiming those intermittent failures fixed.
Controlled startup observation
Same machine, immutable qualified Core wheel, empty isolated registry, fresh processes and a per-process proxy holding the official update connection. Native debug QA bundles used the same separate QA identifier/eligibility substitution in both revisions. Measured process spawn to independent real service identities plus the first status-data read; not first interactive window time.
All after reads completed while the connection was still held. Filesystem/framework caches were not controlled; these observations do not establish p95, generic speedup or installed-product latency. An additional OS sample observed the baseline startup worker blocked in
automatic_app_update/run_automatic_update. These comparison builds predate the error-presentation refinement.CI limits
This branch incorporates target
mainatdc9fdbb5186618ec2e797a9d7545e2fe524fee56, including the Windows long-path fixture repair and explicit UTF-8 source-manifest decoding. At the current exact head, macOS desktop and Windows desktop packaging passed, and the independent review approved the code. Other CI jobs remain pending/in progress.The Windows PowerShell job failed three CLI output-budget fixture tests:
heartbeat_prompt_brief/jsonemitted 10,522 characters against its 10,500 ceiling; six selected tests passed. The affected Python/testing/workflow trees are identical to the target baseline, and the same failure is already recorded on the preceding fixture-repair path. No native-Windows base rerun was performed here, no budget was relaxed, and this failed check remains unresolved. Earlier failed runs and the six independently attributed Python failures remain visible. Code approval and successful desktop packaging do not establish merge readiness, complete OTA or installed adoption.Visual evidence
Current frontend code/build:
04808b8b8cf96af75cd956ca1c9bce5af13888f1. Real packaged frontend and isolated source-checkout HTTP backend; native updater IPC is synthetic and installation is prohibited. Desktop shows the main selection after a stale stable response has returned; the narrow view shows the new main result after an explicit check. No persistent preview is offered.Earlier native capture and qualification follow unchanged:
Native behavior build:
3f82753d3e642a5b41fc6a9a988ad22c197124dc; capture commit7749fdbde3acbc616b452af759846b059fe14616adds this public-safe native capture only. Actual QA App after verified local activation, actual native panel version and actual empty Core services; no synthetic IPC in this capture. Offline background failure remains visible without blocking the workspace.The unchanged dashboard progress layout and 390px view below were captured at
22041220202e277d296a91c69afe3e7fbe134a98with actual packaged UI/isolated HTTP services and synthetic native progress IPC. The refinement changes native failure projection, not these layouts. No persistent preview service is offered.Scope/refinement: reuse the updater installer and feed-version comparison; keep the cache provider-local and disposable. QA guidance binds isolation at the bundle executable because an OS/window-tool relaunch can drop caller-only environment. Merge, release, complete official OTA and installed adoption remain separate gates.