StreamFab 热修通道:业界方案调研¶
- 调研日期: 2026-07-20
- 调研问题: 为 StreamFab(Windows/macOS,Qt/CEF 桌面客户端)建立独立于完整版本发布的热修下发通道(站点适配规则更新为主、补丁代码为辅、配置开关),需要签名与完整性校验、灰度下发、快速回滚。业界成熟方案是怎么做的?
- 调研方法: 全部结论追溯到一手来源(官方文档 / 源码仓库 / 规范文档 / 官方 RCA),每条结论标注来源 URL。二手资料未采信。
结论摘要¶
- 最直接的对标是 Firefox Remote Settings:数据集合 + 增量同步(
last_modified/changeset)+ 应用层 content signature(ECDSA P-384,根证书硬编码)+ 内置本地 dump 兜底 + 多人签核发布流程,与"站点适配规则热下发"场景几乎一一对应(client spec)。 - 签名选型:采用"平台代码签名(Authenticode / Developer ID+notarization)保护宿主与可执行补丁"+"应用层内容签名(Ed25519 或 ECDSA)保护热修数据包"的双层组合,这是 Sparkle、CRX3、Firefox 共同的模式;密钥/角色分层与防回滚攻击设计参照 TUF 规范。
- 热修元数据(相当于 Sparkle appcast / variations seed)本身必须签名并带版本单调性,否则通道可被降级/冻结攻击利用(TUF 威胁模型;Chrome CUP 甚至假设 TLS 被攻破仍保护 update check)。
- 灰度 + 回滚参照 Chrome variations 的 "signed seed + safe seed" 双份机制:客户端保留上一份"已验证可用"的规则包,新包导致启动失败/关键指标劣化时自动回退;服务端可下发空更新/旧版本强制回滚。
- CrowdStrike Channel File 291 是反面教材:内容通道绕过分级发布、内容校验器有缺陷、无 canary,官方整改就是"内容更新也要 staged/canary 部署 + 客户可控 + 加强内容验证"——StreamFab 的规则通道必须从第一天就带灰度与校验。
主题 1:业界桌面客户端热更新 / 组件更新方案¶
1.1 Chrome Component Updater¶
一手来源:components/component_updater/README.md
- 与完整更新的关系:组件(component)是可以独立于浏览器发布节奏更新的功能模块,目的是"faster (or desynchronized) release cadences, lower bandwidth consumption",并避免安装包膨胀。即:完整更新走 Chrome 自身的 updater,组件走 component updater,两条通道并存、节奏解耦。
- 下发机制:组件以 CRX 文件(带签名头的 ZIP 归档)形式发布;客户端通过 Omaha 协议做 update check;浏览器启动时注册组件,启动约 6 分钟后开始检查更新(避免抢占启动资源)。
- 差分更新:支持 differential update 以降低带宽。Omaha 协议层面通过 "differential fingerprint" 机制实现:客户端回报上次安装包的 fingerprint,服务端据此下发差分补丁,并对每个包提供 SHA-256 hash 与多个带回退顺序的下载 URL(protocol_3_1.md)。
- 版本兼容性处理:README 明确指出设计代价——浏览器必须容忍组件缺失(组件可能尚未下载或安装失败),这增加了宿主代码复杂性;组件也可选择随安装包捆绑一份初始版本(官方不推荐,因为增加体积)。推断:对 StreamFab 的含义是,宿主必须内置"无热修包/热修包版本不匹配也能工作"的默认行为。
- 通道自身的抗篡改:update check 响应由 CUP(Client Update Protocol)用 ECDSA 保护,官方文档明确"the integrity of the update check is protected by CUP, even in the presence of compromised TLS",即设计假设是 TLS 可能被企业中间盒或攻击者剥离,更新元数据仍需应用层签名(protocol_3_1.md)。
1.2 CRX3 包格式与签名¶
一手来源:components/crx_file/README.md、crx3.proto
- 结构:
"Cr24" magic (4B) + version=3 (4B) + header length (4B) + protobuf header + ZIP 数据。 - 签名覆盖范围:签名计算的消息是
"CRX3 SignedData\x00" + 4 字节小端 header 长度 + SignedData + ZIP 归档内容——即签名同时覆盖签名头元数据与包内容,防止"换头"或"换体"攻击。 - 算法:支持
sha256_with_rsa(X.509 SubjectPublicKeyInfo)与sha256_with_ecdsa(NIST P-256)两组 proof,可并存多个签名。 - 身份绑定:
crx_id为 16 字节,对开发者密钥要求 "the first 128 bits of the SHA-256 hash of the public key must equal the crx_id"——包 ID 由公钥派生,天然把"包身份"和"签名密钥"绑定,防止用合法密钥给别的组件 ID 签名。 - 头部还可携带
verified_contents(对归档内文件的逐文件签名,UTF-8 + GZIP),用于安装后按文件校验。
1.3 Sparkle(macOS)¶
一手来源:sparkle-project.org/documentation、delta updates 文档
- appcast 机制:更新源是一个 RSS feed(appcast),App 在
Info.plist配SUFeedURL,客户端用CFBundleVersion对比判断有无更新。appcast 即"更新元数据文件"。 - EdDSA 签名:
generate_keys生成 ed25519 密钥对(私钥进 Keychain),公钥以SUPublicEDKey内置于 App 的Info.plist;generate_appcast工具自动为更新归档(dmg/zip)、delta 补丁、安装包生成签名;开启SURequireSignedFeed后 appcast 与 release notes 本身也被签名。 - 与 Apple 签名/公证的关系:官方推荐 HTTPS 分发 + 对 App 做 code signing 与 notarization,EdDSA 是在此之上的独立校验层;当 App 同时具备 Developer ID code signing 和 EdDSA 公钥时,Sparkle 允许轮换其中一个(不能同时轮换两个)——两层签名互为密钥轮换的信任锚。沙盒 App 有专门的 sandboxing 配置指引(XPC service)。
- delta 更新:appcast 的
<sparkle:deltas>内为每个.delta声明sparkle:deltaFrom来源版本、大小、URL 与签名;客户端自动优先选 delta,官方文档明确"如果用户运行的版本没有对应的 delta,或补丁应用失败,则回退使用完整包",并通过校验和验证补丁结果——这是"差分失败自动降级全量"的标准范式。
1.4 Squirrel(Windows / macOS,Electron 生态)¶
一手来源:github.com/Squirrel/Squirrel.Windows、github.com/Squirrel/Squirrel.Mac
- Squirrel.Windows:基于 NuGet 包分发,支持 full package 与 delta package;卖点是无向导、无 UAC 弹窗、无强制重启的静默安装/更新体验。README 层面未描述应用层密码学签名校验机制。维护状态差:最后一个 release 为 2.0.1(2020-09),仓库积压数百 issue,公开征集维护者(issue #1470)。
- Squirrel.Mac:客户端定期请求更新 JSON API(200+JSON 表示有更新,204 表示无),下载 ZIP,在 App 退出时自动安装或经
relaunchToInstallUpdate手动触发;版本判断基于CFBundleShortVersionString。文档中没有任何应用层签名校验的描述;最后 release 为 0.3.2(2017-08),项目基本停滞。 - 结论(事实 + 推断):Squirrel 展示了"面向完整 App 的静默更新",但两个仓库均处于弃维护状态、且缺少 Sparkle/CRX3 那样的内容签名层;推断:不适合作为 StreamFab 热修通道的参照实现,仅可参考其"退出时替换 + delta/full 双轨"的流程设计。
1.5 游戏行业热修¶
一手来源:Unreal ChunkDownloader 文档、Unreal General Patching Information、Unity Addressables Remote Content Distribution、Apple App Review Guidelines
- Unreal ChunkDownloader / pak 机制:内容按 cook + chunk 流程切成
.pak文件;ChunkDownloader 从远端拉取 manifest,UpdateBuild下载新 manifest 即可让客户端获得更新内容,官方文档明确该机制"支持 update patches 而无需下发全新可执行文件";LoadCachedBuild利用本地缓存跳过已是最新的 chunk。即:热更单位是内容资产(pak/chunk),由远端 manifest 驱动,可执行代码不在此通道内。 - Unity Addressables:通过 remote catalog(远端清单)+ 远端 AssetBundle 实现内容更新,配套 AssetBundle 缓存与 Cloud Content Delivery 集成;可远程更新的是 assets/AssetBundles,代码更新不属于 Addressables 的能力范围(文档主题仅覆盖内容分发与缓存)。
- "资源热更 vs 代码热更"的边界(平台合规):Apple Guideline 2.5.2 原文:"Apps should be self-contained in their bundles … nor may they download, install, or execute code which introduces or changes features or functionality of the app"(仅教育类 App 有限豁免)。这是 App Store 分发渠道对"下发可执行代码"的硬性禁令。推断:StreamFab 若不经 Mac App Store 分发,2.5.2 不直接约束,但 macOS 的 hardened runtime + notarization 仍会限制加载未签名代码(见 2.2);业界游戏方案普遍把热更边界画在"数据/资源/脚本配置"而非原生代码,正是同时受平台政策与签名体系约束的结果。
1.6 规则/配置类热下发:Firefox Remote Settings(最直接对标)¶
一手来源:remote-settings.readthedocs.io Introduction、Client Specifications、Firefox Source Docs: Services/Settings
Mozilla 用它向 Firefox 下发各类"数据型"配置(拦截列表、CA 吊销、实验 recipe 等),架构要点:
- 数据模型:服务端(Kinto REST API)按 bucket/collection/record 组织,每条 record 带
last_modified时间戳。 - 增量同步:客户端先轮询
GET /buckets/monitor/collections/changes/changeset?_expected={timestamp}获知哪些 collection 变了,再用?_since=只拉取增量;支持服务端实时 push 触发同步。 - 内容签名:官方表述"数据在服务器端签名,在客户端透明验证"。验证规范:从
x5uURL 下载证书链→对照硬编码根证书验证链与有效期→把 records 按 id 排序serialize 成 Canonical JSON→用 leaf 证书公钥按ECDSA_P384_SHA384验证"Content-Signature:\x00" + serialized_data。签名服务由 Autograph 承担(Mozilla 的集中签名服务,支持 Content-Signature PKI、XPI、MAR 等,支持 HSM)。 - 附件:大文件走 attachment(CDN),record 中带文件大小与 SHA-256,客户端强制校验以"guarantee integrity and authenticity of CDN content"。
- 失败兜底:客户端安装包内置 JSON dump 作为默认数据集(空 profile 首次使用不依赖网络);同步/验证失败时静默返回(可配置
emptyListFallback返回空列表),同时上报 uptake telemetry;签名验证失败时客户端会重试/换证书链条目再验。 - 发布流程与回滚:内置多人签核(编辑提交→审核人预览→批准/拒绝),每条 record 有版本时间戳;推断:回滚即再发布一次旧内容(时间戳前进、内容回退),客户端按正常同步收敛——这与"服务端强制回滚"语义一致。
- 还内置 JEXL targeting 过滤(可按客户端属性定向下发)与 uptake telemetry。
- 官方同时警告:"strongly discourage the implementation of new ad-hoc clients"(协议细节多、易碎)。推断:StreamFab 自建客户端时应把协议面收窄(单 collection、固定格式),降低实现风险。
主题 2:补丁包签名与完整性校验的标准做法¶
2.1 The Update Framework (TUF)¶
一手来源:TUF Specification (latest)
- 威胁模型(规范明确防御的攻击):
- rollback attack:诱导客户端安装旧版(含已知漏洞)——靠元数据版本号单调递增 + 客户端拒绝回退来防御;
- fast-forward attack:攻击者人为抬高版本号使后续真更新被拒——靠密钥泄露后的版本号回收流程防御;
- freeze attack:让客户端永远停留在旧状态——靠元数据的短过期时间(timestamp 角色频繁重签)防御;
- mix-and-match attack:组合不同版本的文件——靠 snapshot 角色对全部 targets 元数据版本的一致性快照防御;
- key compromise:靠角色分离 + 阈值签名限制单密钥泄露的影响范围。
- 角色与密钥分层:四个顶级角色——
root(信任根,授权其他角色、管理密钥轮换)、targets(声明可信文件,可再委托 delegation)、snapshot(记录所有 targets 元数据版本)、timestamp(高频重签,防重放/冻结)。root 与 targets 密钥离线保存;timestamp 密钥在线但泄露损失有限。每个角色支持"阈值签名"(需 N 把密钥中的 M 把)。 - 客户端工作流(严格顺序):加载内置可信 root → 按链式托管更新 root → 更新 timestamp → snapshot → targets → 下载目标文件;每步验签、查版本回退、查过期。
- 推断(对 StreamFab):不必完整实现 TUF,但三条最小可行原则必须吸收——(a) 热修索引/清单文件本身要签名且带单调版本与过期时间;(b) 签发内容的在线密钥与授权密钥分层,根公钥硬编码进客户端;(c) 客户端拒绝接受比本地已见版本更旧的清单。
2.2 代码签名 vs 内容签名¶
- Windows Authenticode(Microsoft Learn):对 PE 文件嵌入数字签名(或经签名的 catalog 文件做分离签名),验证发布者身份(证书链上溯到受信 CA)与文件自签名后未被篡改。覆盖对象是可执行文件本身。
- macOS codesign + notarization(Apple Developer 文档):Developer ID 签名是前置条件,notary service 做恶意软件扫描并发 ticket,Gatekeeper 在首次运行时校验签名、ticket 与吊销状态;hardened runtime 是配套要求。覆盖 App、插件、dmg/pkg/zip 等分发物。
- 应用层内容签名(Ed25519/ECDSA,如 Sparkle EdDSA、Firefox Content Signature):由厂商自持密钥对"更新数据"(归档、规则 JSON、元数据 feed)签名,客户端用内置公钥验证。它保护的是更新通道内容的来源与完整性,与 CA/平台无关,不依赖 TLS。
- 组合方式(事实归纳):
- 平台代码签名覆盖:宿主程序、热修引擎、任何最终会被 OS 加载执行的二进制(macOS 上未用 Developer ID 签名/公证的可执行物会被 Gatekeeper/hardened runtime 拦截)。
- 内容签名覆盖:热修数据包 + 热修清单/appcast 本身(Sparkle
SURequireSignedFeed、Chrome CUP 对 update check 响应签名都是"元数据也要签"的实践)。 - 二者互补:Sparkle 明确支持"EdDSA 公钥与 Apple code signing 互为轮换锚"(一次只换一个)(Sparkle docs)。
2.3 三个实际方案的签名链对比¶
| 方案 | 算法 | 信任锚 | 签名覆盖 | 特点 |
|---|---|---|---|---|
| Sparkle EdDSA (docs) | ed25519 | 公钥内置 Info.plist(SUPublicEDKey) |
更新归档、delta、pkg;可选 appcast 与 release notes | 单级密钥,轮换依赖 Apple code signing 作第二锚 |
| CRX3 (crx3.proto) | RSA-SHA256 / ECDSA P-256 | crx_id = 公钥 SHA-256 前 128 bit(身份即密钥) | "CRX3 SignedData\x00"+header+ZIP 全量;可另带逐文件 verified_contents |
多 proof 并存,包身份与密钥强绑定 |
| Firefox Content Signature (client spec / Autograph) | ECDSA P-384 | 硬编码根证书 → 中间证书 → leaf(x5u 链下发) | Canonical JSON 序列化后的整个 records 集合(前缀 Content-Signature:\x00) |
三级证书链支持在线密钥短周期轮换;集中签名服务 + HSM |
推断:三者分别代表"单密钥直签"(最简单)、"密钥即身份"(适合多来源包)、"PKI 链 + 集中签名服务"(适合高频签发、需密钥轮换)。StreamFab 规则更新频繁、签发点单一,介于 Sparkle 与 Firefox 之间。
主题 3:灰度下发与自动回滚架构¶
3.1 Chrome variations(Finch)¶
一手来源:variations_seed.proto、variations_seed_store.h、chromium-variations README
- seed 下发:服务端下发一个 protobuf
VariationsSeed(内含多个Study,带serial_number供客户端快速判断是否变化;M109+ 增加 layers 机制做互斥分层)。定向/过滤字段(channel、platform、country、版本区间)与probability_weight百分比分桶定义在 study proto 中。 - seed 签名:seed 数据附带密码学签名,客户端
VariationsSeedStore在存储前用ValidateSeedBytes()验证 seed 字节与 base64 签名;验证失败则不落盘、保持现状(源码另有variations_seed_signature_analyzer把签名异常作为安全事件上报)。 - safe seed 双份机制:seed store 同时维护 latest seed 与 safe seed——后者定义为"已观察到能让 Chrome 保持基本可用状态"的 seed;当最新 seed 引发问题(如启动失败)时回退加载 safe seed,并保证回退状态下仍能接收服务端新 seed(留有恢复通道)。
- kill switch(推断 + 源码佐证):Finch 常被用来远程关闭出问题的 feature——study 强制指定某 experiment 即可全量关闭功能;这是"配置开关 + 灰度平台"合一的形态。
3.2 Firefox Normandy/Nimbus¶
一手来源:experimenter.info、Rollouts、Client SDK Lifecycle
- 通道复用:Nimbus 的实验/rollout recipe 全部经 Remote Settings 下发(状态流转 = 向 Remote Settings 发布更新),即灰度平台构建在"带签名的规则下发通道"之上——通道与策略分层。
- 分桶:bucketing 在客户端完成(SDK 在 Enrolling 状态评估 targeting + 随机化决定分组);rollout 与 experiment 使用独立的 bucketing namespace避免人群冲突;experiment 优先于 rollout。
- rollout 生命周期:rollout 单分支、无对照组("not measurement tools");上线后可随时编辑 population percent(改百分比→请求审核→生效);结束时直接 Live→Complete。客户端状态机(Enrolled/Disqualified/WasEnrolled 等)+ Glean telemetry 全程上报 enrollment/exposure,供服务端观测 uptake。
- 推断:Nimbus 展示了"percent 可上可下"即天然的灰度回滚手段——把 rollout 百分比调回 0 等价于撤回。
3.3 自动回滚设计(事实归纳 + 推断)¶
业界一手资料中可确认的回滚构件:
- 客户端本地回滚:Chrome 的 safe seed(保留上一份验证可用的配置,新配置疑似导致故障时自动回退,variations_seed_store.h);Sparkle 的 delta 失败自动降级完整包(delta docs);Firefox 的内置 dump + 失败返回空列表/旧数据(Firefox Source Docs)。
- 服务端强制回滚:Remote Settings 重新发布旧内容即回滚(时间戳前进、内容回退);Nimbus 调低/归零 rollout 百分比;Chrome 组件通道下发旧版本组件。
- 基于指标的触发:Nimbus/Remote Settings 全链路 uptake telemetry;CrowdStrike 整改承诺把 staged deployment 与监控挂钩(见 3.4)。推断:业界公开资料中"崩溃率阈值→自动回滚"多为内部系统,未见完整一手规范;StreamFab 需自定义:热修包激活后 N 分钟内的崩溃/成功率指标回传 → 服务端自动把该包灰度归零并重新下发上一版本。
- 启动失败检测(推断,源自 Chrome safe mode 思路):客户端记录"新包激活后是否成功完成一次健康启动/一次成功适配",连续失败即本地弃用新包回退旧包,并上报。
3.4 失败案例:CrowdStrike Channel File 291(2024-07-19)¶
一手来源:官方完整 RCA PDF、RCA 发布博客、初步事故报告
- 两条通道、两种待遇:Sensor Content(传感器代码)走完整的分级发布、客户可控节奏;Rapid Response Content(内容/规则更新)为追求响应速度直接全量下发,绕过分级保护——与 StreamFab"站点适配规则要快"的诉求同构。
- 根因(RCA 六条 findings):新 IPC Template Type 定义 21 个输入字段,但调用方只提供 20 个,Content Interpreter 对第 21 个字段做通配以外匹配时发生 out-of-bounds read,导致 Windows 内核崩溃。缺陷穿过了:编译期字段数不校验、运行时无数组越界检查、模板测试覆盖不足、Content Validator 自身存在逻辑缺陷、验证未延伸到 Interpreter 实际执行、内容实例无分级部署。
- 官方整改措施:为内容处理增加运行时边界检查;扩大模板测试覆盖;对 Template Instances 实施 staged/canary deployment;把验证测试延伸到内容解释执行阶段;向客户开放内容更新的部署控制。
- 对本项目的教训(事实支撑的推断):(a) "内容/规则不是代码所以低风险"是伪命题——规则由客户端解释器执行,解释器缺陷 × 未灰度的内容 = 全量事故;(b) 服务端 Validator 通过不等于安全,必须在真实客户端解释器上做发布前回放测试;(c) 规则通道的灰度不能为速度让路,至少保留小时级 canary 环。
对 StreamFab 的启示¶
针对三类热修内容(站点适配规则为主、补丁代码为辅、配置开关):
A. 签名方案选型
- 双层签名:平台层——Windows 补丁二进制用 Authenticode 签名(Microsoft),macOS 任何可执行补丁必须 Developer ID 签名(必要时公证,否则被 Gatekeeper/hardened runtime 拦截,Apple);应用层——所有热修内容(规则包、配置、补丁)统一用自持 Ed25519 内容签名,公钥硬编码进客户端(参照 Sparkle
SUPublicEDKey模式,Sparkle)。 - 清单也要签:热修清单(manifest,含各内容项的版本、SHA-256、灰度参数)本身必须签名、带单调递增版本号与过期时间,客户端拒绝旧版本清单——防 rollback/freeze/mix-and-match(依据 TUF spec;Chrome 甚至假设 TLS 失效仍签 update check 响应,protocol_3_1)。
- 密钥分层:根公钥硬编码;日常签发用在线密钥;若签发频繁,可演进为 Firefox 式"硬编码根 + 短期 leaf 证书链"(x5u 下发)以支持轮换(Remote Settings client spec、Autograph);起步阶段至少做到"签发私钥不落 CI、进 HSM/KMS"。推断:单 Ed25519 密钥 + 预埋一把备用公钥(应急轮换)是最小可行方案。
- 附件校验:大体积规则包走 CDN 时,清单中带 size + SHA-256,客户端强制校验(Remote Settings attachment 模式)。
B. 通道与内容隔离
- 三类内容分通道(collection)管理、共用一套签名与同步协议:仿 Remote Settings 的 bucket/collection 模型——
site-rules、code-patch、config-flags各自独立版本线与灰度参数;补丁代码通道默认更保守的灰度曲线。依据:Chrome 组件与浏览器更新解耦(component_updater);CrowdStrike 教训是"快通道"不能绕过慢通道的保护(RCA)。 - 宿主容错:客户端必须在"无热修包/热修包被拒/版本不匹配"时回到内置默认行为(component updater 的设计代价即宿主容忍组件缺失);安装包内置一份规则 dump 作为零网络兜底(Remote Settings dump 模式)。
- 代码热更边界:macOS 侧任何原生代码补丁必须走 Developer ID 签名产物;推断:优先把"补丁代码"限制为签名过的动态库/脚本化规则(如 JS 规则由内置解释器执行),避免动态下发未签名原生代码;若未来上架 Mac App Store,2.5.2 将直接禁止代码下发,规则/配置通道不受影响(Apple Guidelines)。
- 规则解释器按"不可信输入"标准加固:边界检查、字段数校验、解析失败即拒用并回退——CrowdStrike 六条根因里四条落在解释器/验证器上(RCA)。
C. 灰度与回滚
- 客户端分桶灰度:清单中带灰度参数(percent、渠道、版本区间、地区),客户端用稳定设备 ID hash 落桶(Nimbus 客户端 bucketing + 独立 namespace 模式,Nimbus SDK;Chrome study 的 filter + probability_weight 模式,variations_seed.proto);百分比可上调也可归零(Nimbus rollout 可随时改 percent,Rollouts)。
- 双份规则包(latest + safe):客户端始终保留上一份"验证可用"的规则包;新包激活后若健康检查失败(进程崩溃、站点适配成功率骤降、解析异常)自动回退 safe 包并上报——直接移植 Chrome safe seed 设计(variations_seed_store.h)。
- 服务端强制回滚:通过"发布旧内容为新版本"实现(版本号前进、内容回退),兼容防回滚校验(Remote Settings 模式);配合把灰度 percent 归零截断扩散。
- uptake telemetry 闭环:每次同步/激活/回退上报(参照 Remote Settings uptake telemetry 与 Nimbus enrollment 事件);服务端按"包版本 × 崩溃率/适配成功率"看板决策,先人工回滚按钮、后自动化阈值触发。推断:自动回滚初期用"canary 环(内部/1% 用户)+ 小时级观察 + 人工放量"即可覆盖大部分风险。
- 发布流程带双人签核与真机预览:规则编辑→审核人在真实客户端预览→批准发布(Remote Settings multi-signoff 流程,Introduction);发布前在真实客户端解释器上回放规则(CrowdStrike 整改项)。
开放问题¶
以下问题需结合 StreamFab 代码库与运营现状才能回答,公开资料无法确定:
- 站点适配规则当前的载体形态:是纯数据(JSON/正则)、脚本(JS 在 CEF 中执行)、还是编译进二进制的 C++ 逻辑?这决定"规则热更"能覆盖现有适配逻辑的比例,以及是否需要先做"规则外置化"重构。
- 补丁代码的技术形态:计划下发动态库(dll/dylib)、还是脚本?Qt/CEF 宿主是否已有插件加载框架?macOS 侧动态库签名(是否随主 App 的 Developer ID 签、是否需单独公证)如何进 CI?
- 是否存在稳定、抗重装的设备/用户 ID 可用作灰度分桶的 randomization unit?现有激活体系能否复用?
- 现有更新服务端(完整版本发布用)能否扩展承载热修清单与 CDN 附件,还是需要新建服务?现有服务端是否已有按地区/版本下发的能力?
- 崩溃率与适配成功率指标的现状:客户端目前是否已回传站点适配成功/失败事件?崩溃收集(Crashpad)能否按"热修包版本"维度聚合?——这是自动回滚阈值的前提。
- 密钥管理设施:公司是否已有 HSM/KMS 与代码签名流程可复用给内容签名?签发审批走什么系统?
- CEF 版本差异:不同在网版本的 CEF/Qt 差异是否要求热修清单支持"按宿主版本区间定向"(类似 Chrome study 的 min/max version filter)?在网版本分布如何?
- 法务/商店合规:StreamFab 是否有任何经 Mac App Store / Microsoft Store 分发的 SKU?若有,代码补丁通道需按 2.5.2 类政策单独评估。