Skip to content

Bruce v0.12.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 10:11
· 471 commits to main since this release

Bruce 0.12.0 发布说明

调整与优化 (Changed)

  • 发版封箱归档首次执行 (v0.12.0):按 docs/archive/README.md 的 SOP 建立 docs/archive/0.12.0/,把 29 张 closed 变更卡(C015–C041,以及 v0.12.0 发布后回补并随本次封箱归档的 C056/C057)与 2 张 completed 任务卡(T05 Jev 适配、T06 ClinePass 适配)物理迁入,同步刷新 change/index.json 与 task/index.json 的 file 映射,并为两本总账各写入一份冻结快照。卡片内容一字未改;全仓 6 条指向卡片的 Markdown 链接(均指向仍留在 docs/devel/ 的 C001–C004)0 断链。说明:该 SOP 自 2026-09-23 写下后 16 个历史 tag 均未执行,本次为首度执行,故也一并收拢了此前已发版但未归档的 C015–C018(其自身 version 声明为 v0.11.3/0.11.4/0.11.5,原样保留);C001–C014 虽随 v0.9.0–v0.11.2 发布但状态仍为 verified 而非 closed,按「仅迁移 closed 卡片」留在原处。
  • 变更总账 topics[].changes 语义定稿 (TD-011 结清):把此前从未写明的口径写入 docs/devel/change/README.md §3.1 —— 下限(机器强制):数组必须包含所有以该设计文档为主设计文档的卡;上限(人工维护):允许登记「非主卡归属但确实改过该文档」的卡以实现跨文档多归属。新增 scripts/check-change-ledger.mjs 校验该下限与路径存在性,并接入 verify-local.sh,使此前导致 C039/C040/C041 脱节与 PricingEngine topic 整体缺失的这类漂移此后由门禁兜住。
  • README 精简与排版重构 (C054):仓库门面文档自 C001 Monorepo 重构(v0.10.0)后未同步实现,按预检实测存在 21 处失效路径引用(其中 8 个被引用路径在文件系统中已不存在)与整节死链。本次对齐 v0.11.5 现状并压缩排版,仅改动表述层,不涉及代码、脚本与设计基线规则:
    • 结构树与关键入口重写:顶层由 macos/BruceApp、bridge、rust/Bruce-collector、agent-usage 旧命名改为 apps/(macos / win / widget)+ core/collector/ 双层;关键入口更正为 apps/macos/Sources/BruceApp/BruceApp.swift、core/collector/bin/Bruce-collector/src/main.rs 与 core/collector/schemas/。
    • 文档索引去死链:「更多文档」7 条指向已归档的 docs/development/*.md,改为现行 ad-flow 入口(文档中心、设计基线 00~05、变更总账、部署指南、资源库)。
    • 命令路径修正:按需验证命令由 rust/Bruce-collector/Cargo.toml / --package-path macos/BruceApp 更正为 core/collector/Cargo.toml / --package-path apps/macos,并补 verify-rust.sh 跨平台入口与 15 个 Swift Harness 口径。
    • 安全模型描述对齐:订阅凭证存储由 macOS Keychain service 更正为 ~/Library/Application Support/Bruce/credentials.json(POSIX 0600 + 父目录 0700 + 临时文件原子替换 + 写后重读校验,含 C042 的损坏三态读语义)。
    • 能力清单补全:本机会话补齐至 10 个 Agent(Kimi Work / Kimi Code CLI / Claude Code / Codex / Grok / OpenCode / Orca / Pi / ZCode / CodeBuddy),订阅额度 10 家并标注 Cline 三窗口直读服务端权威端点(C039);补 43 款定价表规模、采集缓存 collector-cache-v1 与 Windows 数据位置。
    • 排版去重:合并重复的签名/公证叙述与架构图后冗余的 5 步运行链路列表,安全/隐私与数据位置并为一节;247 → 206 行。
    • 核验证据:README 内 18 条仓库相对引用经脚本解析全部可达(dead=0);Markdown 围栏 14 处平衡、表格 0 错列、7 处脚本引用全部存在;C054.json 与 change/index.json JSON 解析通过(总账 54 卡)。
    • 衍生发现(未在本卡修复):design/01 第 192 行称缓存位于 ~/Library/Caches/Bruce/collector-cache/,与实现 ~/Library/Application Support/Bruce/collector-cache-v1 不符,已登记 docs/devel/todo/now.md B-001 待单独建卡回写。

修复 (Fixed)

  • 发布产物并非 Universal 2 (C057):v0.12.0 发布后核对产物时发现,线上 Bruce.zip 解包后 Contents/MacOS/BruceApp 与内置 Contents/Resources/Bruce-collector 经 lipo -archs 实测均为 arm64 单架构(该 zip 的 SHA256 与 Release 上的 SHA256SUMS 校验一致,排除下载损坏),即 Intel Mac 用户拿到的产物无法启动 —— 而 AGENTS.md、design/01 的 NFR 与 README 均声明 macOS 侧具备 Universal 2(Apple Silicon + Intel Mac 原生)能力。根因:build-test-app.sh 的 --universal 能力自 v0.9.0 起就可用,但 CI 的两个构建步骤都未传该选项,流水线一直走单架构分支;而架构属性只在「构建 + 解包 + lipo」时才可见,push 级门禁只看编译通过,单架构产物照样全绿。修复:两个作业改以 --universal 构建、构建前显式 rustup target add x86_64-apple-darwin(该 target 是否预装随 runner 镜像而变),并新增「校验产物为 Universal 2」步骤对两个二进制分别断言双架构(App 与 Collector 分别构建,任一退化为单架构都会让对应平台无法启动)。设计基线新增 design/00 §3.3「发布产物规格」,并提炼纪律「凡只在 tag 场景被消费的产物属性(版本号 / 架构 / 文件名),必须在 push 级或流水线内附带断言」。产物已就地重打包:该修复生效后, 维护者授权拆除 tag、把 v0.12.0 重指到修复提交并重跑流水线, 故 v0.12.0 自身的产物已为 Universal 2 (详见本次发版的封箱说明)。
  • Windows 应用版本号脱离单一事实源 (C056):v0.12.0 发版后核对产物时发现,本应名为 Bruce_0.12.0_x64-setup.exe 的 Windows 安装包实际命名为 Bruce_0.11.5_x64-setup.exe,且该构建的应用内「版本」行会向用户显示 0.11.5。根因:apps/win/src-tauri/tauri.conf.json 的 version 自 v0.11.5 起一直硬编码,而 Windows 侧从未接入仓库根 VERSION 这一权威源(build-win-app.ps1 / upload-win-release.ps1 均不读取它,grep 零命中)—— 该字段同时决定 NSIS 安装包文件名与 get_runtime_info 返回的 package_info().version(即设置中心版本行)。macOS 侧不受影响(build-test-app.sh 读取 VERSION 注入 CFBundleShortVersionString)。修复:把 conf 版本对齐到 0.12.0,并在 scripts/check-win-frontend.mjs 新增 push 级一致性断言(conf 版本必须等于根 VERSION,不等即红灯)—— 此前该字段只在 tag 场景被消费,漂移可静默存活整个版本周期。红绿双向实测:conf 改回 0.11.5 → 退出码 1 并输出可定位诊断;恢复 → 退出码 0。另修正 README 两处不实的发布口径:原文称 CI「产出未签名 Preview 草稿 Release」,实际 upload-win-release.ps1 在两端产物齐备后执行 draft=false + make_latest(v0.12.0 实测 08:20:42Z 建草稿、08:43:31Z 转为公开),现按两段式如实描述。设计基线 05-§6.4 同步新增「应用版本号单一事实源」条与纪律「凡 tag 场景才消费的字段,必须在 push 级至少校验其与权威源的相等性」。
  • 设计基线与 UI 的本机数据落盘事实校正 (C055):由 C054 的衍生发现复核扩大而来的同类失真批次 —— 设计基线与用户界面中关于「缓存根 / 配置文件名 / 快照文件名」的表述从未与实现对齐,且全部系自诞生即错(非重构失同步)。逐项:
    • design/01 §7.1 缓存持久化三条断言全部失真:(a) 路径 ~/Library/Caches/Bruce/collector-cache/ 从未存在过 —— C001 重构之前的代码(b2b580e^)已是 ~/Library/Application Support/Bruce/collector-cache-v1,全仓零 Library/Caches,且 App 侧无能力覆盖该值(collector-application 恒调 default_cache_root,仅 Windows 壳注入且注入同值)。(b) 字段名 last_byte_offset / parsed_turn_count / bucket_deltas 在全部 git 历史中零命中(git log --all -S 唯一次命中即 C001 引入该正文本身,对照组 safe_offset 命中 6 次),且模型实为 C021 起的源级缓存。(c) 「版本升级时自动淘汰旧缓存文件」实为「身份失配即忽略条目并重建」,文件删除只发生在源文件从源路径集合消失时。现按实现重写为「位置(default_cache_root 双平台真值)+ 四层缓存表(Kimi Code CLI 专用 / JSONL 源级 / SQLite 源级 / Codex 树缓存,各自 schema 常量、覆盖源与身份判定)+ 复用与版本迁移」,并声明「字段全集以代码为准,不做逐字段镜像」以免再次腐化。
    • design/04 五处 config.json 不存在:真值为 config/onboarding-v1.json(OnboardingConfiguration.configURL,AtomicJSONStore 0600 文件 / 0700 目录)。简介、NFR、时序图 participant 与 store 消息、§3 单价覆盖契约五处一并更正。
    • design/00 快照文件名不存在:snapshots/current.json / snapshots/previous.json 真值为按模块分文件 <module>.json / <module>.previous.json(当前唯一模块 agent-usage,本机 snapshots/ 目录实测为 agent-usage.json / agent-usage.previous.json / agent-usage.json.backup.json),并补记 AtomicJSONStore 写入前备份与旧 schema 迁移备份两条旁路副本。
    • design/05 待办表述过期:§6.1 的 R1(缓存根平台化)/ R2(Windows CI job)/ R3(verify-rust.sh 抽取)均已实施,现补「实施状态」列并注明 R4 真机实测仍欠账、R5 走了壳侧 CredentialPayloads 注入的替代路线;§8 去掉会随文件增长漂移的 文件:行号 改为符号锚点;§3.1 显式标注为 v0.9.0 / 0a7f2e2 的时间点存档并加「后续落地」注记,避免其结论列被误读为现状。
    • Windows 侧顺带修掉一个真实渲染缺陷:设置中心说明卡的展示路径字面量 "%APPDATA%\Bruce\config\settings.json" 中 \B / \c / \s 是 JS 无效转义、反斜杠会被丢弃 —— node -e 实测求值为 %APPDATA%Bruceconfigsettings.json,Windows 用户一直看到残缺路径(同文件另有 :48、:761 两处写法正确,仅此一处疏漏)。现修正转义并把标签一并对齐为 settings.json;mac 侧标签由 config.json 改为 onboarding-v1.json。apps/win/tests/frontend.test.mjs 新增两条断言锁定标签与完整路径(该文案此前无任何测试覆盖,故长期未被发现),测试标题同步为 settings json。
    • 变更总账挂接补齐:C039/C040/C041 的卡条目已声明 topic 却未登记进对应 topics[].changes,现补齐;design/04 回链的 PricingEngine topic 在 index.json 中根本不存在,现新增(changes = C001/C002/C052/C055,即 git 历史与本卡实测确认改过该文档的卡)。跨文档归属语义(「主卡归属」vs「改过即登记」)现行两种混用,已登记 future.md TD-011 待定稿后全量重算,未擅自定名。
  • 全仓对抗性审查缺陷批次修复 (C042–C052):2026-10-16 对主干做了一次全仓对抗性审查(覆盖 41 张已闭环变更卡 + 19.1k 行 Rust + 52.4k 行 Swift + 9.3k 行 Windows),按「有真实失败路径」优先的次序立项 12 张卡并完成 10 张修复(另 2 张为结构性债,已登记 future.md TD-005/TD-006 待独立开批)。逐卡要点:
    • C042 凭据文件存储加固(数据丢失路径):ProtectedFileCredentialStore.loadPayloadLocked 原以 try? 把任何读/解码失败折叠为空 payload,而 saveCredential 是「读全量 → 改一个 key → 整体覆盖写」——文件一旦损坏,用户下次保存任一凭据即永久抹除其余全部凭据(无备份无回滚)。现读路径改为三态(不存在→空 / 损坏→保留现场副本后抛 corrupted / 正常→解码);写路径对齐 AtomicJSONStore 规格:createFile(0600) → write → synchronize → 重读解码校验 → 备份 .bak → replaceItemAt → 复位 0600 且失败即抛;目录存在时也校正为 0700。新增两条 Harness 用例(损坏不被静默抹除 / 写入加固),BruceOnboardingCoreHarness 165 项全绿。
    • C043 消除生产 panic 路径(进程硬崩路径):sqlite_cache.rs 增量合并路径的 CompactContribution::from_domain(...).expect(...) 在窗口不匹配时会 panic(而窗口身份错位正是 C040 认定「现实中会发生」的情形);collector-application 的三处 join().expect 会把 worker panic 升级为主线程 panic;bin/Bruce-collector 无兜底 → panic 时 stdout 无任何 JSON envelope,宿主只看到非零退出码。现缓存编码失败回退为「跳过写条目 + 计 cache_corruptions」(与 C040 语义一致),worker 失败降级为 COLLECTOR_WORKER_PANICKED 诊断,入口改用 run_bytes_panic_safe(catch_unwind 兜底输出 BRIDGE_INTERNAL_PANIC error envelope);Windows 侧采集入口同步切换(apps/win/src-tauri/src/collector.rs 原直调 run_bytes)。collector workspace 138 项全绿(基线 132)。
    • C044 面板隐藏态可见性门控补齐:项目曾因「隐藏面板动画不暂停致 ~40% CPU」建立 DashboardPanelAnimationPolicy,但只覆盖 hero/heatmap 两条路径。实测遗漏三处:订阅卡定向刷新 ProgressView(未透传 panelVisible,而定向刷新最长 90s)、SuppressorView 的 0.3s 看门狗(面板 orderOut 不触发视图离窗 → 首次打开后 Timer 终身运行)、小时卡柱体生长 .task(绕过策略)。现三处全部纳入策略并加断言(allowsRefreshProgress / allowsHourlyGrowth / allowsSuppressorWatchdog),NativeLifecycleHarness 14 项含 7 条新门控断言。
    • C045 目录递归防护统一(栈溢出风险):同仓 walk_jsonl_tree 有深度上限 + 已访问集合与 symlink 环测试,而新增的 jsonl_cache::visit_tree 与 sources.rs::collect_codex_files 两样都没有。现 MAX_DIRECTORY_SCAN_DEPTH 收敛为单一 pub(crate) 常量、四个 walker 共用双护栏;新增用例以 files_visited 计数锁定护栏有效性(红绿验证:撤掉深度检查 → 用例 FAILED left:2 right:1;恢复 → 全绿)。用例注释同时如实记录实测事实:symlink 环在 macOS 被内核路径长度限制拦截,故断言对准深度上限而非「环致崩溃」。
    • C046 静默吞错改为故障可见:finalize_local_agent 原 let _ = accumulator.merge_delta(...) 吞掉合并失败而 agent 仍报 ok(用量静默丢失,且与 aggregation.rs 同类失败产诊断的口径自相矛盾)→ 现降级 partial 并说明「数据不完整」;次要源 I/O 错误原完全静默 → 现产出信息级 LOCAL_SOURCE_IO_DEGRADED(区分「源不存在」与「读取失败」);Codex 树缓存解码异常原静默 → 现计 cache_corruptions 并在 note 说明;mac 侧 ProviderAccountStore.loadIndex/loadRecord 解码失败原返回空索引/nil(空索引被后续 saveIndex 覆盖会使遗留记录成孤儿)→ 现抛 ProviderAccountStoreError,removeAllAccounts 失败上抛。新增 3 条用例(Rust partial 降级 / Swift 索引与记录损坏 fail-closed,含「损坏原文未被覆盖」断言),SubscriptionCredentialsHarness 33→35 项。
    • C047 缓存写盘权限口径统一:sources.rs 的 Codex 树缓存是仓内唯一用 File::create 继承 umask 的缓存写盘,现改为 create_new + 显式 0600。三个同名辅助函数(fingerprint_range/append_is_safe/ends_with_newline)经核实分属两套不同签名类型,机械合并需先统一类型契约,已登记 TD-004 并入 C053 结构重构。
    • C048 provider 专属逻辑下沉(已登记待实施):execution.rs 的 app == "codex" 分支、resolve_credential 的 claude/grok 硬编码、codexQuotaRetryOnly 编排层短路等,改法已定(provider 层标准化输出 ProviderOutcome),但触及刚经 C037/C041 验证的 codex 重试/降级路径,需独立回归窗口 → 登记 TD-005,卡状态 open。
    • C049 provider 映射表单一事实源:前缀字符串原在 CATALOG_SPECS / ACCOUNT_FIELDS / account_prefix 三处手工重复且无编译期约束 → 现 CatalogSpec 增加 credential_field 并对外暴露 catalog_entries() 投影,collector-application 全部派生、删除两份手写映射;新增 catalog_entries_are_complete_and_unique 一致性用例(10 条目齐备唯一 + 关键前缀逐字抽查)。
    • C050 截断文案失真:C041 把上限从 1 万改 3 万时漏改 opencode 诊断文案(仍写「最新 10000 条」),现 opencode 与 zcode 两处均改为引用 MAX_SOURCE_ROWS 生成。
    • C051 死代码/协议面裁定:逐项核实后确认三项均属「有意保留但缺说明」而非死代码 —— collector-credential 只读探测函数有测试消费者(提供 claude/grok 凭据解析语义覆盖)、bridge 白名单的 subscriptionQuotaOnly/subscriptionProviders 是 Swift 侧标记且被 C038 预检脚本当契约使用、#[cfg(test)] 探针与既有 collect_agent_usage_with_final_probe 范式一致;已全部登记 TD-007/TD-010 说明取舍。
    • C052 设计基线回写(文档失真):design/00–04 的「最后更新」原停留 2026-09-23 与 C027–C041 演进脱节。回写四处量化失真:provider 计数统一为 10 家(原 8/11 两份说法,实际实现 10 家)、定价表 26→43 款(pricing.rs 的 add() 去重实测 43,17 款新增从未回写,涉及 5 处文档)、design/00 补 Windows 平台模块矩阵行、schemas/*.json 表述由「IPC 通信契约规范」改述为「协议字段参考(强制力在 bridge 白名单 + schemaVersion 比对)」;future.md 技术债池由 1 条恢复至 10 条(TD-004..TD-010)。
    • 本轮验证:cargo test --workspace 138 项全绿(基线 132)、cargo fmt/clippy -D warnings 零告警、swift build 退出码 0、Swift Harness(OnboardingCore 165 / SubscriptionCredentials 35 / NativeLifecycle 14 / PanelViewModel 53 等)全绿、Windows cargo check 通过、zsh scripts/verify-local.sh 退出码 0。
    • 未闭环项(诚实记账):C048(provider 抽象下沉)与 C053(四个巨型文件按职责拆分:sources.rs 5,231 行 / collector-provider/lib.rs 4,155 行 / SettingsView.swift 1,972 行 / SubscriptionService.swift 1,630 行)为结构性重构,无即时故障路径,登记 future.md 后独立开批;本批 10 张卡状态为 verified(证据已回填卡内),待用户复核后转 closed。
  • ZCode 万行截断被误报为故障致菜单栏红圈修复 (C041):修复菜单栏配额环误变红(警告三角)的缺陷。排查确认配额余量最低 40%(智谱周窗)不满足红圈阈值(<15%),红圈来自采集 envelope partial。根因:ZCode DB model_usage 在 182 天窗口内已有 10,986 行,超过 MAX_SOURCE_ROWS = 10,000,扫描按计划内语义「保留最新、丢最旧」降级并附诊断,但该降级被两处按故障处理 —— collect_local_usage 把任意源诊断统一挂 LOCAL_SOURCE_SCHEMA_INCOMPATIBLE(名不符实,并非 schema 问题)并计入 response_status 诊断计数,finalize_local_agent 见诊断即置 agent.status=error。按当前用量(约 500 行/天)上限将长期触发:红圈不可自愈,半年视图静默只保留最近约 3 周,且截断后缓存 append_safe=false 每轮全量重扫 1 万行。现将上限提至 MAX_SOURCE_ROWS = 30,000(覆盖 ZCode 自身修剪天花板约 1.1 万行,上限休眠;opencode 同享),截断路径新增结构化 capped 标记贯穿缓存条目,对外改用独立信息级诊断码 LOCAL_SOURCE_ROWS_CAPPED:agent 状态保持 ok 仅记 note(诊断与降级说明仍可见,可观测性不降),response_status 改为按诊断列表判定、信息级不参与 Partial,LOCAL_SOURCE_SCHEMA_INCOMPATIBLE 仅用于真实 schema/读取故障。实测:Universal 包重打包安装并强制重启后,app artifact zcode 恢复 status=ok / note「本机会话聚合」(11K 行 < 3 万新上限,万行截断诊断消失),today.total 持续正常累计,全部订阅服务 ok → envelope Success → 菜单栏恢复绿色配额环(红圈两触发条件均排除:余量最低 40% > 15%、模块状态 fresh)。
  • SQLite 增量缓存跨窗口身份错位静默清空历史 base 修复 (C040):修复 ZCode 今日 token 统计大幅偏低(cline-pass/deepseek-v4.1-flash 今日真实 99.7M+ 完全不可见,今日全量 134M 只显示约 1-4.5M)的缺陷。对账锁定根因在 scan_sqlite_cached 追加路径:缓存身份(窗口长度/时区/今日)不匹配时不命中缓存但仍允许增量追加,旧条目的 days 索引在新窗口 day_list 下有两种败坏形态 —— 越界时 to_domain 返 None 被静默替换为空 base(历史清零),索引恰在界内时解码「成功」但数据整体平移到错误日期(实锤:今日桶 139M 被挪到 13 天前);两形态均照常前推游标且无自愈(诱因是探测脚本直跑 collector 未带 days/timezone,默认 14 天/UTC 与 app 实际 182 天/本机时区错位,但缺陷本身潜伏:任何窗口/时区配置变更都会触发)。现增量追加必须以缓存身份全匹配为前置(cache_identity_matches),身份错位一律回退全量重建;base 解码失败不再以空 base 合并后推进游标。新增回归用例 zcode_sqlite_cache_window_mismatch_rebuilds_instead_of_empty_append(已做红绿验证:修复后通过、旧代码上失败)。实测:Universal 包重打包安装并强制重启后,app artifact today.total = ΣtodayModels = 163,747,628 逐 token 一致,cline-pass 今日 99,783,779 恢复可见。
  • Cline 三窗口改直读网页同源服务端权威端点 (C039):修复 Cline 三窗口与网页控制台偏差大的缺陷(面板 24.05%/12.02% vs 网页 34%/17%)。对账锁定两层根因:(1) 台账翻页截断 —— 安装中的构建仍是 C038 之前版本(12 页 × 200 = 2400 单上限,静默截断),本机台账已达 3319 单,最旧 919 单(约周分子 30.1%)被丢弃;(2) 客户端窗口建模与服务端口径的结构性漂移 —— 5h 实为「上一块到期后首单开块 [t, t+5h)」的服务端活动块(纳秒级实证:端点 resetsAt 减 5h 恰为台账开块那一单),纪元网格固定槽(5 日轮转)与之语义不同。扫描 app.cline.bot 前端 bundle 发现网页 USAGE LIMITS 的真实数据源 GET /api/v1/users/me/plan/usage-limits(Bearer API key 直连 200),返回三窗口整数百分比 + 纳秒级 resetsAt,与网页逐字一致。现三窗口直读该权威端点,删除台账翻页、user id 获取与全部窗口建模代码;C038 引入的 LedgerCache 脚手架(端口 + FileLedgerCache + RunContext 接线)因失去唯一消费者整体回收(git 历史保留,/usages 与 /usages/daily 在 design/02 备案为将来模型级明细或端点失效时的既定回退路径);design/02 规则 5 改写为「数据源直读 + 失败语义」,红线改为严禁在客户端复刻服务端窗口建模。
  • Cline 逐单台账跨运行增量缓存 (C038):修复 Cline 长窗口(7d/30d)用量分子被单轮页数上限截断导致系统性偏低的问题。/usages 接口不支持时间过滤且单页硬上限 200,历史实现每轮固定深翻 12 页(约 2400 单、约 8s),30 天内单据数超过该上限的账户(本机账户实测 30 天 3464 单)其 7d/30d 分子被静默截断。现引入跨运行台账缓存:新增 LedgerCache 端口(定义于零依赖的 collector-runtime,实现 FileLedgerCache 归 collector-local,落 <cache_root>/provider-ledger/,临时文件 + rename 原子替换),provider 保持无状态、缓存缺失或损坏按空态自愈;取数分两段 —— 追新(从首页起直到一页不再产出新单据,稳态仅 1 页)与回溯(未覆盖 30 天 horizon 时从上次中断游标续翻,每轮最多 8 页分次收敛,游标失效则放弃本轮并于下轮重新收敛)。单据按服务端 id(实测存在)去重,缺失时回退内容指纹,跨页重复单据不再被重复计入。实测:首次深翻 12 页即触上限(2400 单,complete=false,复现截断)→ 回溯收敛至 3464 单覆盖完整 30 天,7d 分子由 29.61% 修正至 35.44%、30d 由 14.8% 修正至 17.72%;稳态每轮 1 页约 1.3s(原 12 页约 5.3s)。fixture 通道保持 NoLedgerCache,无外部 I/O 的测试契约不变。
  • 额度窗口边界唤醒与过期窗口文案 (C037):修复「到点不刷新」的观感缺陷 —— 订阅刷新间隔(默认 1800s)与额度窗口的重置时刻无关,槽/窗口边界过后至下次定时刷新之间(最长约 30 分钟)面板仍展示上一窗口的百分比,并把倒计时写成「已到期」。现新增窗口边界唤醒:下次定时唤醒 = min(间隔剩余, 最近一个未来窗口重置时刻 + 20s slack),边界取自 artifact services[].windows[].resetsAt,只在采集成功时参与调度(退避路径语义不变)。为杜绝刷新风暴设三道防线:只认严格在未来的边界(滚动窗口的滑出时刻随刷新前移时天然不触发)、同一「边界值」只消费一次(epoch 秒精确去重)、未命中或边界比间隔更远时回落原间隔 —— 这是 C025「滚动窗口倒计时恒贴近当前时刻」教训的直接防护。同时把过期窗口(resetsAt <= now:窗口已重置、数据仍属上一窗口)的文案由「已到期」改为「刷新中」,mac 与 Windows 两端一致(PanelModels.resetText / viewmodel::reset_text),配合边界唤醒该中间态通常只持续数十秒。mac 侧新增 SubscriptionBoundaryWakePolicy(纯策略,与 Windows runtime_core::boundary_wake 同构),双端各带边界提取/防风暴回归用例。
  • Windows 发布流水线三处缺陷修复与发布脚本可验证化 (C036):修复 Windows 安装包上传环节的三处缺陷。(1) release 列表分页:上传步骤经列表端点取草稿 release 的 upload_url,但未传分页参数(该端点默认 30 条/页),仓库 release 总数超过 30 后目标草稿不在首页会导致查找落空、发版失败(当前 16 个 release,属潜伏缺陷;已用 per_page=2 模拟超页场景复现旧逻辑命中数为 0)。现改为 gh api --paginate --slurp …?per_page=100 取全量并逐页展平 —— 实测 --slurp 输出为「外层数组套各页数组」(单页亦然),不展平会把 upload_url/assets 取成数组并拼出损坏的上传 URL(该陷阱已在实现中踩到并修正)。(2) tauri-cli 钉版:cargo install tauri-cli --locked 的 --locked 只钉 CLI 自身依赖树,不钉 CLI 版本本身——v0.11.5 发布实测装的是当时的 latest 2.12.2,如今已是 2.12.3 且 3.0.0-alpha 已发布,3.0 稳定后该命令会跨大版本升级并冲掉已验证的 NSIS 打包链路。CI 与 scripts/build-win-app.ps1 现统一钉 =2.12.2(v0.11.5 发布实测通过版本),消除本地与 CI 的打包链路漂移。(3) 重跑幂等:同名资产已存在时上传返回 422 already_exists,而「重试失败的 Windows 发布作业」正是最自然的恢复动作,此前必然再次失败并只能人工删资产;现上传前按 assets[].name 清理同名残留。(4) 发布脚本可验证:上传逻辑抽出为 scripts/upload-win-release.ps1,并由 verify-windows 作业新增的 AST 解析步骤在每次 push 对 build-win-app.ps1 / upload-win-release.ps1 做语法门禁(这些脚本只在 tag 场景执行,此前任何改动都无法在 push 场景验证)。
  • 看板面板任务栏四方向自适应定位 (C035):修复 Windows 任务栏停靠左/右侧时面板定位错乱的缺陷。原实现的定位判据只有一个「任务栏在上还是在下」的布尔量,左右停靠方向在代码中没有任何表示:左侧任务栏 + 全局热键(或首次用托盘右键菜单「显示看板」)唤出时,横向兜底恒取工作区右缘,面板会跑到屏幕另一端(1920×1080、48px 左栏实测 x=1468,正确值 60,距任务栏 1420px);纵向任务栏下的沿轴对齐也只是巧合(托盘恒落在纵向栏底部,被误判为「任务栏在下方」而套用横向上方贴靠逻辑,右栏实测 y=250,统一模型下应为 y=310)。现改为四边统一模型:由系统真实工作区相对显示器四边的内缩量判定任务栏所在边(detect_taskbar_edge),托盘 rect 落在候选条带内时用于消歧(第三方 appbar/dock 与真任务栏共存场景),定位统一为「贴边轴恒贴任务栏内侧(水平 12 / 垂直 10 逻辑px)+ 对齐轴沿任务栏轴向居中于托盘,无可用托盘坐标时贴托盘所在角落」,两轴均按含边距区间夹紧,面板矩形恒在工作区内且与任务栏条带不相交。同时补齐两处健壮性:托盘 rect 与判定出的任务栏边不一致(任务栏换边/换屏后的陈旧坐标)时丢弃并走贴角兜底;任务栏自动隐藏(工作区无内缩)时按托盘贴边方向推断停靠边。顶/底任务栏与各档分辨率/DPI 的既有行为逐字符保持不变(原 7 项几何测试期望值未变)。
  • 面板几何 Demo 与实现的可证明同构 (C035):任务栏交互 Demo 扩展为四方向停靠 + 模拟屏幕缩放框,面板位置/尺寸/DPI 内容缩放全部由与 runtime_core::compute_dashboard_geometry 逐行同构的内联几何镜像驱动;新增 tests/fixtures/geometry-parity/cases.json(50 例:5 档分辨率/DPI × 4 方向 × 有/无托盘 + 竖屏 + 自动隐藏 + 第三方 appbar 消歧 + 陈旧 rect + 负坐标副屏),由 Rust 与 Node 双侧读取对拍(apps/win/tests/geometry-parity.test.mjs 随 scripts/check-win-frontend.mjs 进 CI),消除维护者无 Windows 机器时「Demo 与实现漂移而核验失效」的风险。

新功能 (Added)

  • 订阅用量卡徽章升级为品牌图形 (C026):仪表盘订阅区各 Provider 的身份标识由「品牌色首字母字母标」升级为品牌图形徽章(品牌色瓷砖 + 白色品牌图形),10 家 provider(Kimi / DeepSeek / 火山引擎 / Z.ai / ChatGPT / Claude / Grok / OpenCode GO / StepFun / Cline)各取官方 mark,未收录图形的 provider(Jev)保持首字母兜底:
    • 多图标库取材:Simple Icons(CC0,Kimi / DeepSeek / Claude / Cline / OpenCode)、theSVG(MIT,火山引擎 / 阶跃星辰)、SVG Logos(CC0,ChatGPT / Grok);Z.ai 因图标库仅有「智谱」点阵 mark 与现显示名不符,改取其官方 logo 的 Z 字形;
    • 单一事实源数据管线:源 SVG 归档于 docs/assets/provider-icons/(含逐图标来源与许可证登记),scripts/gen-provider-glyphs.mjs 归一化为绝对 M/L/C/Z 路径(圆弧与简写曲线在生成期展开为三次贝塞尔),同一份数据生成 macOS 与 Windows 两端产物,verify-local 校验产物与源文件一致;
    • 双端实现:macOS 新增 ProviderBrandGlyphData / SVGPathBuilder / ProviderBrandGlyph / ProviderBrandPalette 与共享徽章视图 ProviderBrandBadge;Windows 端徽章改为 DOM API 构建内联 SVG;新增 SubscriptionBrandGlyphHarness 7 项边界测试(覆盖率 / 兜底 / 画布适配 / 命令集纪律 / 色板 / 深色集合 / 透明度保留);
    • 品牌色板调整:Z.ai 改用官方锁版深色 #2D2D2D(与其官方 logo 深色瓷砖一致,取代旧蓝 #3859ff),补齐此前缺失的 Cline 品牌色 #18181b(原先落默认灰 #8e8e93);Nothing 主题深色品牌色(Grok / Z.ai / Cline)沿用 secondary 灰兜底;
    • 设置中心同步图标化:设置中心「订阅额度」Provider 行首加入 26pt 品牌图形大图标(拖拽柄右侧),配置弹窗标题前置 20pt 品牌徽章;徽章组件尺寸参数化(15pt 仪表盘 / 26pt 设置行 / 20pt 弹窗标题),圆角与首字母字号按比例缩放;
    • 「添加服务」下拉选项带品牌图标:选择 Provider 的下拉保持原有控件与两步(选择 → 添加…)流程不变——改用同一原生 NSPopUpButton(SwiftUI Picker 的菜单项不渲染图像),每个选项前为 16pt 品牌瓷砖 + 白色图形(NSMenuItem.image,非模板染色保留品牌色),图形右侧留 6pt 留白把标题右移(AppKit 菜单标题位置由图像列宽决定),闭合态由系统自动带出所选 provider 的图标。