文档: 签名发布SOP与两份走查报告落档
- 签名与发布 SOP: 签名→打包→发布清单→自动升级全链可重复执行 - 上下文管理五维走查全文(瓶颈清单已登记 939) - 版本升级链走查报告
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# 上下文管理五维走查(2026-10-10)
|
||||
|
||||
> 走查方式:五路只读代理并行(组装/预算 · 压缩 · 自愈清洗 · 记忆召回 · 工具结果),全程源码取证;瓶颈清单摘要登记看板 `docs/todo.md` #939,本文为全文落档。
|
||||
> ⚠️ 行号快照:`crates/df-ai/**` 与 `src-tauri` 部分文件当日有并行改动(工具结果外置 P1 WIP / Wave J 修复),行号为 2026-10-10 走查时点,批次开工以现场源码为准再核对。
|
||||
> 关联设计:`docs/02-架构设计/上下文根治设计-20261006.md`(223:1 根治总纲)· `docs/02-架构设计/专项设计/上下文分层组装器-落地方案-2026-10-10.md`(五病灶锚点实测 + 接口化落地方案)。
|
||||
> 状态标注:【已修-工作区】= 修复已落工作区待提交(Wave J/守夜期产出);【待解禁】= 修复点在 `crates/df-ai`,需并行写者完工后接手;★ = 可先在 src-tauri 侧落。
|
||||
|
||||
---
|
||||
|
||||
## 零、背景与铁证
|
||||
|
||||
- **223:1 出处**:84cb104c 会话 2.2 天烧 4.3 亿 tokens,prompt:completion = **223:1**,日均 1.9 亿(`上下文根治设计-20261006.md` §量化预期)。
|
||||
- 走查定位出该结构性浪费的共同根因:**记账(history_tokens)与真实发送体量脱钩 → 三重门槛(预算门/裁剪门/压缩门)恒不触发 → 窗口永不收敛 → 每轮全量重发**。
|
||||
|
||||
---
|
||||
|
||||
## 一、组装/预算维度
|
||||
|
||||
### HIGH① history_tokens 与真实请求体量脱钩(根因,最重)【待解禁】
|
||||
|
||||
机制链四步,环环实证:
|
||||
|
||||
1. **引用化发生在 push 前**:工具结果在审计层先经 `should_use_namespace` 判定(`audit/mod.rs:1184-1191`;`namespace_store.rs:47-53`),`ALWAYS_LARGE_TOOLS = read_file/list_directory/grep/diff_files`(`namespace_store.rs:38`)**命中即引用、与实际体积无关** → `store()`(`namespace_store.rs:124-131`)入内存池,消息里只留短串 `namespace://tool/{hash}`。
|
||||
2. **记账只数短串**:`ContextManager::push`(`context/mod.rs:101-143`)对这条短串跑 `estimate_message`(`context_helpers.rs:62-105`),`history_tokens += tokens` 在 `:108-110` → **单条上万 token 的大结果只记 ~15 token(~30 字符)**。
|
||||
3. **展开发生在发送时**:`agentic/mod.rs:1927-1944` 才把引用展开为真实体量(单条 max 150KB,见 P1 注释 `context_helpers.rs:427-432`)。
|
||||
4. **三重门槛双双恒不触发**:
|
||||
- 预算门 `context/mod.rs:198`:`history_tokens <= available` 恒真 → 直接返回全量;
|
||||
- 裁剪门 `context/mod.rs:239-246`:永不达阈值;
|
||||
- 压缩门 `context_lifecycle.rs:133-135`:`available*6/10 < history_tokens` 恒假。
|
||||
|
||||
→ 每轮实际重发展开后的全量历史 → 223:1。
|
||||
|
||||
- **修**(二选一或组合):push/外置时按**原文体量**入账(记账基点 = 发送视图尺寸单一真值,见组装器方案 §3.1,兼解 HIGH② 的自愈重算);或估算器识别 namespace ref 取池内真实大小。修复点在 `crates/df-ai`(估算器)+ `src-tauri`(入账点),df-ai 侧待解禁。
|
||||
- **本质澄清**:namespace_store 是**内存态引用化**,只省进程内存,发 LLM 前展开全文 → **token 零收益**(与 P1 落盘外置的对比见维度五)。
|
||||
|
||||
### HIGH② 每轮 O(n) 全量克隆 + sanitize + 展开 + 摘要 → 会话累计 O(n²)【待解禁】
|
||||
|
||||
- 未超预算分支 `context/mod.rs:198-205` 走 `all_messages_clone()`(`:294-296`,逐条深克隆)+ sanitize + 出口断言;
|
||||
- 展开 `agentic/mod.rs:1927-1944` 对**全部**历史逐条 `read_only` + String 克隆;
|
||||
- 摘要 `summarize_tool_results`(`stall_detector.rs:313-385`)再遍历全部消息做内容变换。
|
||||
- 三者每轮各 O(n)(调度点 `agentic/mod.rs:1904-1921/1945-1957/1981-1984`),会话累计 **O(n²) = 全量重发本体**。根因与①同源:门失效 → 窗口永不收敛 → n 随会话单调涨。**治本 = 组装器方案 P2 分层组装**(接口化,见关联设计)。
|
||||
|
||||
### ★HIGH③ 预算上限恒 128K,不随模型真实窗口【已修-工作区(主会话);子代理残留】
|
||||
|
||||
- 原状:主会话构造点 `commands/ai/mod.rs`(走查时点 :1239)`ContextManager::new(ContextConfig::default())`;`context_helpers.rs:128-136` `max_tokens=128_000`,`budget_limit` 由它算(`:138-143`);子代理同病 `sub_agent.rs:117-127`。真实窗口在 `ModelConfig.context_window`(`df-ai-core/src/model.rs:138-139`)却只被 router 使用,代码自陈该维度「恒过、失效」(`agentic/mod.rs:2012` 注释)。
|
||||
- 影响:1M 窗口模型被当 128K 裁(**能力降级**);小窗口模型(如 deepseek-chat 64K)预算高于实际窗口(**超发风险**)。上界取 1M 而非 128K 的理由:`max_tokens` 只是**裁剪预算**——历史不足则不裁、不会撑大实际发送,卡 128K 等于不治根因。
|
||||
- 修复(Wave J,工作区):`commands/ai/model_context.rs` 新增 `context_config_for_model` 三级优先(预设表/用户手填可信窗口/未知回退 128K)+ 仅按窗口下调或持平、绝不放大 + 安全顶挡脏预设值;主会话收口单一入口 `apply_model_window`(`commands/ai/mod.rs:1274-1284`,构造仍 default、发送入口按 resolved_model 重设)+ 7 单测。
|
||||
- **残留缺口**:子代理未接——`sub_agent.rs:119`(`SUB_AGENT_CONTEXT_MAX_TOKENS=128_000`)、`:123-126`、`:761` 仍固定 128K,待改走 `context_config_for_model` 统一口径。
|
||||
|
||||
### MED⑤ 估算器 chars_ratio=0.35 系统性偏差【待解禁】
|
||||
|
||||
`context_helpers.rs:29-44/73-74`:中文低估 2-3 倍、base64 高估(注释自陈 OpenAI 按像素计而非字节,0.35 偏保守)。多模态回归修正已并入(parts 文本/base64 计入 + url 图 1600 token 地板折算在 ×ratio 之后),但系数本身未分语种/分载荷。方向:分系数校准,需独立评估裁剪边界。
|
||||
|
||||
### MED⑥ 保护区固定 6 条 + 淘汰补偿仅 300 字【待解禁】
|
||||
|
||||
`context/mod.rs:648/:655`:保护区条数硬编码;被淘汰内容的补偿摘要极短,早期主题对 LLM 快速失忆。与⑦(无召回)叠加后**窗口外内容实质永久丢失**。
|
||||
|
||||
### LOW⑬ 估值双轨从不互相校准
|
||||
|
||||
`estimated_prompt`(路由用,较准)与 `history_tokens`(预算用,失真)两轨并存,无任何校准/对账点——①的失真因此长期无告警。修①时可顺带加「双轨偏差超阈即 warn」的可观测。
|
||||
|
||||
### LOW⑭ sys_tokens 未计工具 schema
|
||||
|
||||
system 侧估算不含工具 schema 体积,预算口径偏乐观。
|
||||
|
||||
### 前缀缓存两处失效源(组装侧)
|
||||
|
||||
- **⑨ 滑动裁剪位移前缀【待解禁】**:超预算时 `context/mod.rs:239-246` 切 `messages[trim_end..]`——头部被切,整个请求前缀位移,provider 自动前缀缓存(DeepSeek/Anthropic)整段失效。已有部分缓解:淘汰摘要改尾部追加(`:259-261`)、`push_system_anchor` 避让悬空头(`:582-595`)、`tool_view_decisions` 冻结压缩决策防跨轮翻转(`stall_detector.rs:352-363`);但**基础裁剪本身仍位移前缀**,且淘汰摘要内容逐轮漂移(`:259` 每轮即时重生成,被淘汰区单调增长)。
|
||||
- **⑧ system 可变段内嵌稳定段【已修-工作区】**:可变段(日期 + 项目/任务清单)混在稳定前缀内致前缀缓存失效;清单描述不截断(走查时点 `prompt.rs:565/:584`)加剧体量。修复(Wave J):`df-ai-anthropic-cache` 拆分开关**默认开**(`prompt.rs:653-687`,键名保留历史名、语义扩展覆盖 openai_compat 自动前缀缓存——易变段挪到消息流末尾,开关关时非官方网关零风险)+ 清单描述截断 `CONTEXT_DESC_MAX_CHARS=120`(`prompt.rs:562/:604/:629`)。
|
||||
|
||||
---
|
||||
|
||||
## 二、压缩维度
|
||||
|
||||
### HIGH④ 压缩单向不可逆,被压原文对 LLM 永久不可见【待解禁】
|
||||
|
||||
- `compress_old_messages`(`context/mod.rs:664-699`)标记 Compressed(幂等:已压跳过、token 只扣首次)→ 发送视图 sanitize step0 按 `is_active` 过滤出局(`context/mod.rs:107-108` 统一剔除)。
|
||||
- 后果:压缩后 LLM 对早期细节**不可回读**;窗口外内容(见⑥⑦叠加)实质永久丢失。设计 C-r1「压缩不丢/可召回」未落地。
|
||||
- 方向:复用 P1 句柄模式——压缩写 pointer 可回读(压缩摘要 + 「原文句柄路径」,agent 需要时 read_file 找得回),与工具结果外置同构。
|
||||
|
||||
### MED⑩ 一次压尽,无分批【待解禁】
|
||||
|
||||
触发压缩时一次压完可压区,无 windows 式分批(分批可平摊摘要质量波动与 token 峰值)。
|
||||
|
||||
### HIGH⑪ 后台压缩无 epoch/内容版本守卫【已修-工作区】
|
||||
|
||||
- 原状(`context_lifecycle.rs:206-323` 走查时点):后台 task 无任何守卫——`clear()` 保留 per_conv 条目且复位 is_compressing → **压缩窗口内旧摘要可注入已清空的新上下文**(跨代污染)。loop 侧有 F1 epoch,task 侧没有。
|
||||
- 修复(Wave J,工作区):**内容版本哨兵 = 首条消息全局唯一 id**(`context_lifecycle.rs:63-68`)——否掉 len 方案:压缩期间 loop 正常 append 会使 len 增长,以 len 相等为守卫永不生效;重建后首条必换新 id,是「上下文被整体替换」的准确且零成本哨兵。快照触发时首条 id,后台 task 提交前比对(`:74/:153`),不匹配即丢弃本次摘要。
|
||||
|
||||
### HIGH⑫ 后台压缩无 panic 兜底【已修-工作区】
|
||||
|
||||
- 原状:后台 task panic → is_compressing 永真 → **该会话压缩永久停摆**。
|
||||
- 修复(Wave J,工作区):整个后台 body 包 `catch_unwind`(复用 `mod.rs::unwind_to_result` 薄包装,`context_lifecycle.rs:236-244`、复位句柄 `:79-82`),panic 以 Err 返回 → 复位 is_compressing + warn。依赖 panic=unwind(tokio 默认);panic=abort 构建下退化为进程终止(尽力兜底,已在注释声明)。
|
||||
|
||||
---
|
||||
|
||||
## 三、自愈清洗维度(sanitize)
|
||||
|
||||
本维整体结论**良好**,一处缺陷已修:
|
||||
|
||||
- **已核良好**:裁剪三元组原子性正确(`context/mod.rs:612-642`);909① 两处修复现状有效——`push_system_anchor` 锚点避让悬空头(`:582-595`)、压缩重入单锁复位,未见旧窗口复现。
|
||||
- **出口防御在位**:畸形配对自愈后 `assert_placeholder_pairing` 出口断言(`context/mod.rs:198-205` 路径内),失败降级 `TOOL_MISSING_PREFIX` 自愈,防 400 orphan 复发。
|
||||
- **已修【已修-工作区】多夹层归位有损**(对抗审查③):原 `reorder_interlopers_after_tool_run` 只把头与「首个连续 tool 段」间的夹层后移 → `[head(c1,c2), X, tool(c1), Y, tool(c2)]` 时 c2 仍被判未闭合剥除(非回归,但「无损」宣称不成立)。守夜期重写为**聚拢该头全部响应(保序)到夹层之前**,边界语义不变(遇下一个头即停/响应集合耗尽即停),更名 `gather_tool_responses`(`sanitize.rs:223`,调用点 `:50`,描述做的事、短一半);新增多夹层 + 幂等单测。「无损归位」至此对多夹层成立。复验:`cargo test -p df-ai --lib context` 157 passed / 0 failed。
|
||||
|
||||
---
|
||||
|
||||
## 四、记忆召回维度
|
||||
|
||||
- **⑦ 窗口外历史零召回【待解禁(属 P2 分层组装)】**:组装是隐式的——system 由 `build_runtime_prompt`(`agentic/mod.rs:3042`)拼、历史由 `build_for_request` 拼、易变尾由 `merge_volatile_tail` 拼,无统一组装器对象、无可观测统计;检索**仅覆盖知识库**:`hybrid_search`(`knowledge_inject.rs:421`)→ `build_knowledge_context`(`:508`)→ `build_knowledge_context_for_conv`(`:587`),**窗口外对话历史与压缩摘要无处可召回**。与⑥(补偿仅 300 字)叠加 = 「裁掉即失忆」。
|
||||
- **方向(组装器方案 §3.3 已定)**:检索召回复用 `knowledge_inject` 单入口——把窗口外历史/压缩摘要作为第三类召回源挂进既有管线,不另造第二套检索;L3 记忆卡(`上下文三层记忆-设计-2026-10-04.md` C-m1)是召回的内容来源,组装器只提供入口。
|
||||
- **跨会话召回底座查证(Wave L)**:文件租约与跨会话召回 **HEAD 已实现**(`src-tauri/src/commands/ai/lease.rs`,cb260ab;召回链 cb260ab+9e81182)——未另造双轨,只补纯函数与单测(lease 11 / knowledge_inject 29 通过),W-h 已销账。新需求只接既有底座,勿重建。
|
||||
|
||||
---
|
||||
|
||||
## 五、工具结果维度
|
||||
|
||||
- **namespace 引用化机制(HIGH① 的机制载体)**:判定 `should_use_namespace`(`namespace_store.rs:47-53`)两条路——`ALWAYS_LARGE_TOOLS` 四工具命中即引用(与体积无关)或超 `NAMESPACE_BYTE_THRESHOLD`/`NAMESPACE_LINE_THRESHOLD`;入池 `store()`(`:124-131`),pin 占比上限 0.5(`:44`),EvictionLog 容量 50 条(`:41`)。**定位澄清**:它治的是进程内存,不治 token——发送时展开回全文。
|
||||
- **P1 工具结果外置(真正治 token)【并行写者 WIP,未提交】**:`crates/df-ai/src/tool_offload.rs`(新,~117 行)+ `context_helpers.rs`(`READ_FILE_OFFLOAD_BYTES=8KB` / `extract_key_info` 句柄追加)+ `lib.rs`(pub mod)+ `tests/**`——超阈值结果**正文落盘**、上下文只留「摘要 + 句柄路径」,agent 可 read_file 展开回读:被省略的中段不进 prompt 但找得回 → 真正减 token 且不丢信息。与 namespace_store 互补不冲突;降级契约(base 未注入返回 None)+ 幂等(内容稳定哈希只落盘一次)+ 只增不减保留策略齐备。该批静置归属待用户拍板(含 `src-tauri/src/lib.rs`、`stall_detector.rs` 挂点)。
|
||||
- **HIGH① 的入账修复与外置的衔接**:外置落地后,push 侧按**落盘前原文体量**入账即可同源治掉①(记账基点 = 发送视图尺寸);两者是同一根因(记账失真)的内容侧与账本侧修复,须协同验收。
|
||||
|
||||
---
|
||||
|
||||
## 六、修复状态总表(截至 2026-10-10 收盘)
|
||||
|
||||
| # | 瓶颈 | 级别 | 状态 | 落点 |
|
||||
|---|------|------|------|------|
|
||||
| ① | history_tokens 与真实体量脱钩 | HIGH | 待解禁(依赖 df-ai) | 入账点 src-tauri + 估算器 df-ai |
|
||||
| ② | 每轮 O(n) 全量重发 → O(n²) | HIGH | 待解禁(P2 分层组装) | 组装器方案 |
|
||||
| ③ | 预算恒 128K | ★HIGH | **主会话已修-工作区**;子代理残留 | `model_context.rs` + `mod.rs:1274`;子代理 `sub_agent.rs:761` 待接 |
|
||||
| ④ | 压缩不可逆无重载 | HIGH | 待解禁(C-r1 句柄化) | df-ai |
|
||||
| ⑤ | chars_ratio 偏差 | MED | 待解禁 | df-ai |
|
||||
| ⑥ | 保护区 6 条 + 补偿 300 字 | MED | 待解禁 | df-ai |
|
||||
| ⑦ | 窗口外零召回 | MED | 待解禁(复用 knowledge_inject 入口) | src-tauri |
|
||||
| ⑧ | system 可变段毁前缀缓存 | ★ | **已修-工作区**(开关默认开 + 描述截断 120) | `prompt.rs` |
|
||||
| ⑨ | 滑动裁剪位移前缀 | MED | 待解禁 | df-ai |
|
||||
| ⑩ | 一次压尽无分批 | MED | 待解禁 | df-ai |
|
||||
| ⑪ | 后台压缩无版本守卫 | HIGH | **已修-工作区**(首条消息 id 哨兵) | `context_lifecycle.rs:63-74` |
|
||||
| ⑫ | 后台压缩无 panic 兜底 | HIGH | **已修-工作区**(catch_unwind 复位) | `context_lifecycle.rs:79-82,236-244` |
|
||||
| ⑬ | 估值双轨无校准 | LOW | 随①顺带 | — |
|
||||
| ⑭ | sys_tokens 无工具 schema | LOW | 待解禁 | df-ai |
|
||||
| — | 多夹层归位有损(自愈维) | 缺陷 | **已修-工作区**(`gather_tool_responses`) | `sanitize.rs:223` |
|
||||
|
||||
> 收敛路线:★ 项与守卫类已落;①④⑨ 等 df-ai 侧修复待并行写者(工具结果外置 P1)完工解禁后接手,届时以「记账基点 = 发送视图尺寸单一真值」一条主线串起 ①→②自愈,量化目标 223:1 → ≤50:1(根治设计 §四)。
|
||||
@@ -0,0 +1,84 @@
|
||||
# 版本升级链走查(2026-10-10)
|
||||
|
||||
> 走查方式:用户要求的只读走查 + 本地全链演练(零线上影响),源码与现场日志取证;本文为全文落档(看板/汇总仅摘要)。
|
||||
> 铁证来源:应用 trace(`%TEMP%/devflow-trace.log`)· 演练服务访问日志(`temp/upgrade-drill/access.log`)· 脚本与配置现场(`scripts/publish-release.ps1` / `scripts/package-devflow.ps1` / `src-tauri/tauri.conf.json` / `src-tauri/src/commands/update.rs`)。
|
||||
> 结论先行:**升级核心机制本身零缺陷**——四发现全在链路外围(端点发布/脚本产物格式/传输协议/本地打包拆分),这也是本地演练能全链闭环的前提。
|
||||
|
||||
---
|
||||
|
||||
## 一、链路全景(走查基线:代码链本身完整 ✓)
|
||||
|
||||
- **后端**:`app_check_update` / `app_download_install_update`(`src-tauri/src/commands/update.rs`)——走 Tauri updater `check()` 拉 `tauri.conf.json` 的 `plugins.updater.endpoints` 配置的 latest.json,**内建 ed25519 签名校验**(公钥 `tauri.conf.json:47`);无更新返回 `has_update=false`,网络/解析失败返回 Err(前端据此提示,不谎报「已是最新」)。
|
||||
- **前端**:`useUpdateCheck` → 徽章 / 设置页(徽章事件通道错配——Tauri 事件 vs window CustomEvent 同名不同通道致徽章永不触发——已于前批修复并登记看板 925)。
|
||||
- **发布侧**:`publish-release.ps1` 六步(版本双源校验 → 构建 → 定位产物 → 生成 latest.json → 上传 app.1216.top);版本双源校验 `:28-38`(tauri.conf.json vs Cargo.toml 必须同值,防 D1 复发);私钥已就位 `~/.tauri/devflow.key`。
|
||||
- **版本一致性闸**:`update.rs:89-104` 用 `CARGO_PKG_VERSION` 与 latest.json 的 `version` 比较,非更新返回 `has_update=false`(演练中验证其正确拦截,见 §三)。
|
||||
|
||||
---
|
||||
|
||||
## 二、四发现(按严重度)
|
||||
|
||||
### 发现 1 🔴 线上端点从未发布——应用内升级从未真正可用【已修复:v0.1.2 发布上线】
|
||||
|
||||
- 事实:`https://app.1216.top/download/devflow/latest.json` **404**;目录 403(存在但空)——从未有产物上传过。
|
||||
- 铁证:应用 trace 每 15 分钟报 `update endpoint did not respond with a successful status code`,**07:33 / 07:48 / 08:03 / 08:18 / 08:23 连续五次**——自动检查一直在跑、一直失败。
|
||||
- 影响:发布流程「能构建能上传产物」但 latest.json 这最后一环缺失,应用内升级通道自上线以来形同虚设。
|
||||
|
||||
### 发现 2 🟠 发布脚本产物名与 Tauri v2 不匹配——跑通也会 404【已修复:脚本 v2 适配】
|
||||
|
||||
- 事实:`publish-release.ps1` 期待 v1 格式 `...setup.nsis.zip` + `.nsis.zip.sig`;而 `createUpdaterArtifacts: true`(`tauri.conf.json:33`)在 **Tauri v2 实际产出 `...setup.exe.sig`**(更新包即安装器本身)。
|
||||
- 两个后果:① 脚本停在「未找到 .sig 签名文件」直接 exit;② 即使产物名对上,它写进 latest.json 的 url 也指向不存在的 `.nsis.zip` → 客户端下载 404。
|
||||
- 修法二选一(当时列出):脚本改读 `.exe.sig` + url 指 exe(v2 格式,**已采纳**);或配置改 `createUpdaterArtifacts: "v1Compatible"`。
|
||||
|
||||
### 发现 3 🟡 updater 强制 https——自建 http 更新源不可行【机制确认,线上无碍】
|
||||
|
||||
- 事实:本地 http 端点被 updater 拒绝,实测报错原文 `The configured updater endpoint must use a secure protocol like https`。
|
||||
- 判定:线上是 https 无碍;但**演练/私有 http 更新源**必须二选一——真证书,或构建期 `--config` 注入 `dangerousInsecureTransportProtocol: true`(演练采纳后者,见 §三,仅演练专用构建携带、不改生产配置语义)。
|
||||
|
||||
### 发现 4 🟡 本地 `package-devflow -Mode full` 缺密钥必报「失败」并跳过安装段【已修复:换装与签名拆开】
|
||||
|
||||
- 事实:本机未设 `TAURI_SIGNING_PRIVATE_KEY` 时,产包 updater 签名段必报失败并**跳过安装段**——这正是此前每次都要手工跑 `swap-install.ps1` 的根因(2026-10-10 实录:`package-devflow -Mode full` 产包后因缺密钥报失败跳过安装)。
|
||||
- 本质:本地换装(自用安装最新构建)与发版签名(updater 产物)是两类需求被一个开关捆死。修法:本地换装不需要签名产物,两者拆开。
|
||||
|
||||
---
|
||||
|
||||
## 三、本地全链演练(零线上影响)
|
||||
|
||||
### 演练设施
|
||||
|
||||
| 件 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| 端点覆盖 | `update.rs:63-84` `build_updater` | env `DEVFLOW_UPDATER_ENDPOINT` 覆盖端点,**不设即走 tauri.conf 配置**(生产零影响);覆盖时 warn 日志「更新端点被环境变量覆盖(本地演练模式)」 |
|
||||
| 传输放开 | `temp/drill-tauri-override.json` | 仅 `dangerousInsecureTransportProtocol: true`,演练专用构建以 `--config` 注入(治发现 3 的演练侧) |
|
||||
| 真 v2 产物 | `temp/upgrade-drill/` | `devflow_0.1.2_x64-setup.exe`(13.4MB)+ `.exe.sig`(436B,base64 minisign 格式,与 `tauri.conf.json:47` pubkey 配对)+ `latest.json`(version/notes/pub_date/platforms.windows-x86_64.{signature,url},url 指 `http://127.0.0.1:8765/...exe`) |
|
||||
| 带日志本地源 | 同目录 `access.log` | 8765 端口静态服务,全量记录请求 |
|
||||
|
||||
### 演练链与现场证据(access.log 时间线)
|
||||
|
||||
1. **端点覆盖生效 → 检查 200**:`08:47:51 GET /latest.json 200`——env 覆盖后的首次检查即通(对照发现 1 的 trace 连续失败,同一检查链路换个可用端点立即恢复)。
|
||||
2. **发现更新 → 下载 200**:`09:31:36-09:32:16` latest.json 200 → `GET /devflow_0.1.2_x64-setup.exe 200`(完整下载 13.4MB)。
|
||||
3. **验签通过**:latest.json 的 signature(ed25519)经 `tauri.conf.json:47` 公钥校验通过——签名/公钥/私钥三件套自洽(此后下载才允许进入安装)。
|
||||
4. **版本一致性闸正确拦截**:`update.rs:89-104` 以 `CARGO_PKG_VERSION` 与 latest.json `version` 比较——当本机版本 ≥ 通告版本时返回 `has_update=false` 拒绝安装(闸本身行为正确);演练初期版本差未成立即被此闸拦下,**0.1.2 产物重建(本机保持 0.1.1 演练版)后版本差成立**。
|
||||
5. **闭环复现**:`12:43:03-12:43:50` 第二轮完整通过(latest.json 200 → exe 200 → 回查 latest.json)——检查→下载→验签→版本判定全链跑通;且 `09:43:43→11:46:37` 每 ~15 分钟一次的周期自动检查连续 9 次全部 200——自动检查定时器在演练端点下工作正常(对照发现 1:同一台机器同一定时器,此前对线上端点连续失败)。
|
||||
|
||||
> 演练结论:**升级核心链(检查→下载→ed25519 验签→版本一致性闸→安装)在本机全链可用**,四发现均为外围问题且逐一有解。
|
||||
|
||||
---
|
||||
|
||||
## 四、已落地修复清单(截至当日收盘,均在盘待提交)
|
||||
|
||||
| # | 修复 | 落点 | 治哪个发现 |
|
||||
|---|---|---|---|
|
||||
| 1 | env 端点覆盖 `DEVFLOW_UPDATER_ENDPOINT`(不设即走配置 + warn 日志) | `src-tauri/src/commands/update.rs:63-84` | 演练设施(兼私有源能力) |
|
||||
| 2 | 脚本 v2 产物适配:`.exe.sig`/`.nsis.zip.sig` 双格式探测,与更新产物正确配对(v2 签名配 setup.exe,v1 配 zip);url 指向真实产物 | `scripts/publish-release.ps1:65-71` | 发现 2 |
|
||||
| 3 | SHA256 计算兜底:本机 PowerShell 5.1 缺 `Get-FileHash`,异常走 `certutil -hashfile`(同 swap-install 兜底口径) | `scripts/publish-release.ps1:84-87` | 发布机环境鲁棒性 |
|
||||
| 4 | **v0.1.2 正式发布上线**:`publish-release.ps1 -SkipBuild` 上传成功,线上 latest.json 实测 **200**(version 0.1.2)——应用内升级通道正式激活 | 线上 `app.1216.top/download/devflow/` | **发现 1(🔴 404 清零)** |
|
||||
| 5 | 本地换装与发版签名拆开:未设 `TAURI_SIGNING_PRIVATE_KEY` 时以 `--config` 关掉 `createUpdaterArtifacts`,不再假失败、不再跳过安装段;发版(需签名)走 `publish-release.ps1` | `scripts/package-devflow.ps1:39-44` | 发现 4 |
|
||||
| 6 | (前批)UpdateBadge 通道错配修复:补 window CustomEvent 监听 + 卸载清理 | `src/components/layout/UpdateBadge.vue` | 前端侧「有更新不亮徽章」 |
|
||||
|
||||
---
|
||||
|
||||
## 五、待办与纪律留痕
|
||||
|
||||
- **正式验收未走完**:本机装的仍是 **0.1.1 演练版**(带 env 覆盖构建)。验收动线:正常重启应用(**不设 env**)→ 检查更新 → 从**线上**发现 0.1.2 → 升级 → 关于页显示 v0.1.2 → 再查一次显「已是最新」。
|
||||
- **纪律事件**:当日 e296c84 提交经用户令「撤」已回退,升级链 4 文件(update.rs / publish-release.ps1 / package-devflow.ps1 / tauri.conf.json)回工作区零丢失;纪律强化为**一切提交攒批、最后由用户显式发令**。
|
||||
- **遗留提示**:发现 3 的 `dangerousInsecureTransportProtocol` 仅存在于演练 override 配置,生产 `tauri.conf.json` 未含、也不应含;若未来要私有 http 源,正路是证书而非放开传输。
|
||||
Reference in New Issue
Block a user