Repository navigation
fix(desktop): preserve feed checks and progressing downloads - #6937
Conversation
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; declaration_source=runtime_reported; reasoning_effort=max
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Exact head: bb24de33c8f1d5953997e394979cb84ddf95c384; immutable base: d95839c16b9e98dbd0c3aa4341b717056547e464.
动机
通过 App 检查并下载官方签名更新的用户。旧更新器即使持续收到安装包数据,也会在三十秒总期限后失败,导致已打开的工作区一直无法准备更新。新下载入口允许有进展的传输继续,并限制连接和读取停滞;但它把下载的客户端设置同时施加给清单检查,使仍承诺四十五秒的手动检查提前约三十秒失败。本轮不安装或替换 App、不重启正式服务、不调用模型;签名完整发行包、正式自动更新与重开采用、其他系统平台仍不在本次独立实跑范围。
用户要完成的是在继续使用工作区时准备可用更新,不应因为包稍大就反复重试,也不应通过修改一项网络预算破坏另一个正常入口。该动机由真实签名传输验证支持;作者的完整发行包与安装态声明没有被借作本次独立验收。
改动思路
继续复用原生 updater 的下载、TLS/代理、签名与缓存 owner;两处活动调用共用一份下载策略是合适的相邻整理,固定渠道和现有取消/安装事务不应另建状态系统。当前 PR 应完整交付安装包持续下载与停滞上限,同时保留清单检查原期限;需先修复共享客户端误伤手动检查,正式安装、重开和原始采用验收仍分别保留。维持旧三十秒总期限会留下已复现的失败;无界等待会掩盖停滞;另写一套下载/签名实现则增加维护和边界风险。当前拆分连接、空闲读取及总期限的设计有价值,问题在于 client callback 的适用阶段。
| 调用 | 既有或本次合理预期 | 当前独立观察 |
|---|---|---|
| 持续收到包数据 | 可超过旧三十秒,总计仍有限 | 72 字节签名合成包在 35.237 秒完成 |
| 包响应头/正文停滞 | 三十秒左右退出 | 30.002/30.013 秒退出 |
| 手动清单检查 | 保留原四十五秒窗口 | 第 34 秒才到的合法正文在 30.014 秒已被拒 |
表格绑定当前 head;其中对照是仅撤去新增 shared-client 设置的当前候选变体,成功耗时 34.013 秒,不冒称整个不可变 base 的同一延迟探针实跑。
具体改动
判断依据是变更前 apps/desktop/loopx-control-plane/README.md @ d95839c16b9e98dbd0c3aa4341b717056547e464:固定官方渠道、签名后才发布/安装、后台不占服务监督,以及手动检查四十五秒与后台检查三十秒的边界。持续下载超出旧三十秒是本次修复目标,不冒称旧 README 已承诺它。既有规范映射中,signature_before_publication 已实现,feed_budget_preserved 未满足。这些是评审映射标签,新 README 不是自己的独立验收 oracle。
[P2] 下载读取期限同时缩短了手动清单检查
在 find_update 的共享客户端设置 中,.read_timeout(30s) 经 updater context 同时用于 check() 和 download()。desktop_update → perform(check) 仍传入四十五秒,下载 helper 事后再改 Update.timeout 不能恢复已经完成或失败的清单检查。
独立真实 HTTP 探针立即返回响应头、第 34 秒返回合法清单,直接调用当前 find_update(...,45s),得到 update_check_timeout,耗时 30.014 秒。保留全部其他代码、依赖和 fixture,只撤去新 callback 的受控变体在 34.013 秒返回可用更新。窗口 runtime 是 test runtime;HTTP 与 updater 请求是真实的。最初私有副本缺少被 Git 忽略的构建资源,尚未执行测试即失败;补入未改动的现有资源后才得到上述结果,初始失败没有删除或改写。
请把安装包的连接/读取策略限定到下载阶段,保留原清单期限,并补这个真实入口反例;若有意改变 feed 策略,应明确接受并披露,而不能继续宣称不变。同时统一 README 后文仍称“独立三十秒下载期限不变”的遗留句。不要只调 Update.timeout 或只重跑 150ms 的短清单失败用例:它们区分不了这个窗口收缩。
关键代码讲解
- download_update 克隆已有 Update,设置三十分钟总期限后调用原生下载及签名验证;manual 和 background 两个生产调用均已接入。
- find_update 仍拥有 feed 查询、固定版本比较和错误映射,但新增 client callback 在两个阶段共用,造成上述范围错误。
- desktop_update 保留显式动作的事务与四十五秒检查参数;start_background_update 保留 generation 取消、签名后缓存及旧状态读回。恢复可用性的流式断言验证的是后台 recovery owner 的准入,不等于真实已安装服务已重启。
全四路径 +378/-25 都已读:主要新增量是 302 行真实 HTTP/签名 fixture;生产改动在同一 Maintenance owner,Cargo 将 updater 限定在现有 2.11 minor 并仅为测试开启 Tauri test。锁文件仍解析 updater 2.11.0、reqwest 0.13.4;没有改变生产 insecure-transport 设置、固定渠道或 IPC 数据结构。
对主干的风险
独立 cargo test --all-targets --locked 为 154 library + 8 example passed,最初有 9 项 library、1 项 integration ignore。另显式运行的两个慢传输测试通过,覆盖上述进展与两种停滞;完整发行包、替换/备份卷和其他 artifact/platform 可选检查没有被记作通过。未继承作者 79,832,945 字节包的运行结果。
不可变 base 的原生全量检查 152 library + 8 example passed,对应旧 oracle 均仍在当前集合;库外旧 8 个 example 也保持。缓存、macOS 安装、备份及 UI 的原 blob/tree 未变。Clippy 全 targets、改动 Rust 文件格式和标准 premerge 4 项直接 + 17 项选中检查通过,无 manual hold;这些绿测没有覆盖新的手动清单反例。没有查询或等待 CI,也没有据此获得 merge 权限。
现有桌面与窄屏合成图已逐张查看,候选 UI 源码相对 base 未改;它们来自较早的展示场景,只说明复用的进度/准备入口,不是本候选安装或真实 OTA 的像素证据。手动安装仍受原事务锁保护,长下载会延长其维护区间;本次没有把后台 recovery-admission 的测试外推成完整手动/正式 App 可用性验收。
语义与 CI 对齐
新增的是已有入口默认使用的原生时间策略,不是 Goal 额度、可选建议或第二个执行 owner。configure_client 的 typed API 没有按字符串猜业务,但阶段范围仍过宽。清单四十五秒承诺在文档和调用参数中保留,实际却提前失败;最小修复必须同时保留下载停滞保护与清单原窗口。文档既不能证明运行时等价,也不能授权静默收缩另一个调用者的默认行为。
我的整体评价
请求修改。持续安装包传输与停滞退出已经有真实正证据,复用和代码规模也合理;但手动检查的用户旅程出现可重复回归,导致符合原窗口的更新无法被发现,长期重试不会解决。继续复用原生 updater 的下载、TLS/代理、签名与缓存 owner;两处活动调用共用一份下载策略是合适的相邻整理,固定渠道和现有取消/安装事务不应另建状态系统。当前 PR 应完整交付安装包持续下载与停滞上限,同时保留清单检查原期限;需先修复共享客户端误伤手动检查,正式安装、重开和原始采用验收仍分别保留。不要求更换 updater、另建服务、增加用户配置或重做 UI;修正这个阶段边界、补反例并重核新 head 即可继续。正式安装采用与长程净益保持未验证。
English verdict: REQUEST_CHANGES — bb24de3. Archive progress/idle behavior is supported, but the shared client read timeout shrinks the existing45s manual feed window: a valid body at34s fails at30.014s; removing only the new shared client configuration in a controlled head variant succeeds34.013s.154library/8example and2slow tests passed; base152library/8example, Clippy,format and4direct/17selected premerge passed. No CI,full-release transfer,installation or merge authority claimed.
…transfer-20261020 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>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
APPROVE — 04c147c6ceab2118f6c6de51d22a9598e6e48ff4。这是作者的完整自查结论,独立复评和受保护合并仍分别办理。未发现此范围的剩余阻塞代码问题。
动机
用户在 LoopX App 检查并下载更新时会遇到这个问题。安装包持续收到数据却在三十秒被终止;当前修复允许它继续下载,同时按原期限结束停滞请求。真实 HTTP 中的三十四秒清单响应、超过三十五秒的签名包传输和约三十秒停滞退出均已验证。本 PR 不证明正式 App 已安装新版、完成全部启动矩阵或产生长程效果收益。正式安装与跨版本启动、重开及自动 OTA 的完整采用验收仍在原任务中。
原始问题是两个下载调用都把整包传输限制为三十秒;只重试不会让一个需要更长时间的健康传输完成。上一候选又把原生客户端的读取限制同时作用于清单检查,导致原本允许四十五秒的手动检查在第三十秒失败。本次审查同时判断完整 PR 和这项修复,没有仅凭旧意见已回复或检查变绿继承批准。
改动思路
既有原生更新器保留网络与签名权威,局部阶段标记只隔离两段超时,不增加用户配置或持久化状态。本 PR 交付原生下载阶段的有限超时及清单窗口保留;安装采用与完整启动验收继续由原任务承担。
find_update 先按调用者的原始窗口发现更新,返回后才启用安装包客户端策略。download_update 统一手动安装与后台准备所用的整包期限,继续调用 SDK 下载及验签。有效字节再进入原有缓存、安装与回滚事务,后台网络不占用服务监督锁。新增标记来自这一次查找的完成事实,不由用户填写,也不跨会话持久化;因此不会形成第二份更新状态或授权。
下表根据当前源码说明阶段边界,执行证据另列于后文:
| 阶段 | 原行为/上一候选问题 | 当前行为 |
|---|---|---|
| 手动清单 | 原四十五秒被共享读取策略缩至三十秒 | 保留四十五秒,包括正文到达前的等待 |
| 后台清单 | 原三十秒 | 保留三十秒 |
| 安装包 | 三十秒总期限,持续传输也失败 | 连接十秒、单次读取停滞三十秒、总计三十分钟 |
| 验签和发布 | SDK 验签后才缓存/安装 | 保留同一 SDK 和原有事务 |
只增加总期限会扩大停滞等待,重建下载客户端会复制代理、TLS 和验签职责。SDK 把同一 callback 保留给两个阶段,且没有公开的事后 context 修改接口;当前请求内的一次切换比第二次查找或另一下载器更小。依赖限定在 ~2.11,测试特性仅用于开发依赖。
具体改动
评审依据为上一轮完整评审,其所评版本为 bb24de33c8f1d5953997e394979cb84ddf95c384。三个准则逐项映射:feed-window 保留清单窗口,三十四秒响应头/正文反例通过;native-transfer 保留持续传输及停滞上界,真实 HTTP 和完整签名包通过;owner-boundary 保留原生验签、缓存、取消及安装事务,调用与 SDK 顺序均已读取核对。
完整范围四文件,增加四百四十行、删除二十九行;其中三百四十三行为可复用的真实 HTTP 传输测试。生产行为集中在原 maintenance owner。README 双语解释最终时限并删除过时的“三十秒整包期限不变”说法;Cargo 仅限定 SDK 次版本并启用开发测试能力。没有新的 Goal、公共字段、凭据、原始会话或独立服务。
关键代码讲解
find_update:原生检查期间 callback 原样返回客户端,保留传入的四十五/三十秒期限。只有check().await成功返回后才把本次标记切换为 archive 阶段;返回的 Update 及其克隆保留这个标记。失败不会暴露可下载的 Update。download_update:克隆原生 Update 并给整包传输三十分钟总限,进度回调和 SDK 验签保持。手动perform和后台准备都调用它,删除两处局部三十秒总限;错误仍由原更新面板及恢复入口处理。start_background_update:保留 generation、取消和准备缓存 owner。网络请求不持有服务监督锁;被手动操作取代的工作不能覆盖新状态,验签成功的字节才交给缓存。此处没有提前安装或重启工作区。
对主干的风险
最强反例仍是第三十四秒才返回合法清单正文:短响应和极短超时测试看不出原窗口被缩短。修复前候选在约三十秒失败;修复后响应头和正文分别在 34.026/34.038 秒成功,并继续验签下载。健康签名包传输 35.313 秒通过,响应头及正文停滞在 30.003/30.012 秒退出。完整已发布包 79,832,945 字节在 38.265 秒传输并通过原公钥与缓存重开验证,没有安装这个包。
这些耗时证据来自 316612b479308295a65a1a1640c1e420d7ff1527。本次同步不可变主干 f72b67113ff42ccf385519222a530a11ce22659c 后,四个 native 文件的 Git blob、Cargo 依赖和原生配置均逐一核对未变;另在当前整合版本重新通过签名、篡改、截断和缓存读回用例。原完整套件为 154 库用例及 8 example 用例通过,11 库用例和 1 integration 用例显式忽略;其中五个相关传输/包用例已单独执行。Clippy、改变的 Rust 文件格式及当前四项直接检查、十七项选中 premerge 检查通过,当前精确范围 CQR 有效。
第一次完整运行曾等待未改动的服务监督 fixture 超时;隔离运行和随后完整运行通过,未修改代码或延长期限。该首次失败保留,原因仍未知,不能称为已修复或用最后一次绿检查抹去。完整三十分钟总限未按墙钟耗尽测试;其 SDK timeout 配置和调用路径已核对。窗口运行时是测试替身,HTTP、原生下载器、验签和缓存为真实路径;正式 App 安装、重开及真实网络 OTA 仍未资格化。
语义与 CI 对齐
为处理本次明确要求的失败归因,读取了旧精确版本的三份失败日志:都停在 Personal workspace prefers the registered Goal display name。同一 Node 命令在不可变 CI base d12c249381e0e9fb83e47182452a85f76f0267fd、当前 base f72b67113ff42ccf385519222a530a11ce22659c、修复前整合版本及当前 head 均复现相同断言。断言要求源码直接使用 goal.display_name,实际原有表达式先采用 source_access.label;相关测试及源码不是此 PR 的改动。此为已复现的基础版本失败,不能宣称远端 CI 全绿。Goal 的评审策略为本地验证,本轮没有轮询、重跑或等待 CI,也未删除该断言。
没有新增共享语义词表或 Goal 权限。Rust 回调标记是请求局部事实,测试 mode 是合成 fixture 输入;Python/TypeScript 语义 advisory 不覆盖 Rust,结论来自人工调用边界核对。此修改有意改变两个原生下载调用的默认超时,README 已说明;没有 default-off 隔离主张,也没有把强制网络时限称作建议。
我的整体评价
本版本在所声明的原生传输边界可批准,未发现剩余阻塞代码问题。长程持续工作判为 preserved:后台准备保留取消和缓存恢复,不新增 Goal 执行;用户体验判为 improved:原动作无需新增配置或交互轮次即可完成慢速有效传输,清单等待窗口不收缩。没有据此推断已安装采用或效果收益。
范围与问题相称:一个共用 helper 和一次请求内阶段切换,替代重复期限并保留原生权威;没有兼容分支或迁移负担。当前 author review 与独立复评分开,旧讨论的核销、分支规则和受保护合并也仍要按当前目标完成。基础版本前端断言、首次 supervisor fixture 失败及完整安装矩阵的未知边界全部保留。
English verdict: APPROVE — 04c147c. Author self-review; independent review and protected merge remain separate. The request-local callback preserves45s manual feeds while native downloads retain finite connect/idle/total limits. Real34s feeds,35s progress,30s stalls and79,832,945 signed bytes/cache passed at identical native blobs; current fast corruption/cache tests and4direct/17selected premerge checks passed. The unchanged frontend source assertion and initial supervisor-fixture failure remain disclosed. No installed App, full startup matrix or live OTA acceptance claimed.
Signed App downloads currently fail after thirty seconds even when chunks keep arriving. This affects explicit updates and background preparation. The corrected native transport allows progressing archives to finish while bounding connection and idle reads, and preserves the feed's existing 45-second manual and 30-second background check windows.
Both active callers reuse one native archive helper: ten seconds to connect, thirty seconds without a response read, and a thirty-minute total archive deadline. The native SDK retains its client callback across check and download; a request-local marker enables archive limits only after the feed check completes. This avoids a second feed request or a separate HTTP/signature implementation. The updater remains on its existing 2.11 minor line; Tauri's test runtime is a development-only feature.
Transport validation at
316612b479308295a65a1a1640c1e420d7ff1527, retained at integrated head04c147c6ceab2118f6c6de51d22a9598e6e48ff4after verifying identical four native file blobs, Cargo resolution and native configuration:update_check_timeoutat 30.04scargo test --all-targets --locked: 154 library and 8 example cases pass; all five opt-in transport/artifact cases also pass. Clippy all targets with warnings denied and changed-file rustfmt passThe HTTP tests use a Tauri test window runtime with production network/updater/signature code. Eleven library and one integration artifact/platform ignores remain visible in the ordinary suite; the five relevant opt-in cases were explicitly executed. The complete released archive is downloaded and its verified cache reopened; it is not installed.
The first full run failed waiting for an unchanged supervisor listener fixture. Its isolated run and a subsequent complete run pass without changing its code or deadline. The initial failure and cleanup of that owned test listener are retained; its cause remains unqualified. This does not qualify the broader startup matrix.
Bounded refactoring keeps both active callers on one archive policy and the existing native TLS/proxy, signature, prepared-cache, cancellation, activation, backup and rollback owners. The feed/archive phase marker is local to one lookup and its returned Update clones, with no persisted or caller-facing configuration. The README's stale thirty-second archive sentence is corrected. Goal/session state, IPC and UI layout are unchanged.
Visual evidence — existing presentation retained
These desktop/narrow captures from
3491c08b698be5fbe35a78a53e3570fb353fd267have been inspected and show the reused progress/prepared journey with synthetic data and a native IPC double. They are presentation evidence for the unchanged panel, rather than this candidate installed or a new native OTA run.Delivery boundary
Author proposal at
04c147c6ceab2118f6c6de51d22a9598e6e48ff4, with signed target-main integration. A fresh native signature/tamper/truncation/cache check and current risk premerge pass. Candidate installation, native automatic replacement/reopen and the broader startup matrix remain open. Independent exact-head re-review and protected merge remain separate.For the explicit failure-diagnosis request, the three failed chat browser job logs at316612b4 were read once: each ends at
Personal workspace prefers the registered Goal display name. The same Node command reproduces that exact assertion at immutable CI based12c249381e0e9fb83e47182452a85f76f0267fd, current basef72b67113ff42ccf385519222a530a11ce22659c,316612b4 and04c147c6. The unchanged assertion expects a directgoal.display_namesource expression; the pre-existing source now preferssource_access.labelbefore that fallback. This native four-file diff does not enter that causal path. The initial incomplete baseline extraction was repaired by supplying its unchanged source dependency before comparison. No assertion was deleted, CI retried or remote green claimed; ongoing CI was not polled or waited on.Change-quality receipt
cqr_0870efea590c5ce9ad83, fingerprint0870efea590c5ce9ad837b6fbc3a79511721a98c037aa4c4c981fbc331713062, qualifies the four-file diff against verified immutablemainsnapshotf72b67113ff42ccf385519222a530a11ce22659c. Strict exact-scope verification and risk-selected premerge pass: 4 direct and 17 selected checks, with no failed checks or manual holds. The initial supervisor fixture and independently attributed frontend assertion warnings remain recorded. The first integration premerge attempt had an unavailable exact-scope quality receipt; after its valid receipt was recorded, the full current premerge passed. No product deadline or check was weakened.