客户改过接口后,应用升级到底该覆盖谁?

升级不是把新包抄进数据库,而是先判断资源归谁、改动从哪里来。
摘要| Microi吾码AI 分析当前应用商城文档、导入器和 69 项本地测试后发现:一段接口代码能否被升级覆盖,不能只看版本号。普通应用要比较 Base、Local、Incoming 三份事实;可信官方 Platform 包的 Managed 核心可以恢复官方版本;CreateIfMissing Hook 一旦交给租户,就永久禁止被官方重新接管。
✦ ① 升级最危险的动作,是把“最新版”当成绝对正确
应用包里带来一段新接口代码,目标租户也已经有同名接口。最省事的实现是按 Key 覆盖,最常见的补丁是比较版本号后覆盖。这两种办法都忽略了真正的业务事实:目标端那段代码可能是客户为了通知、日志或审批写下的定制,也可能只是官网旧版的完整副本。
所以问题不能写成“新版本是否更大”,而要写成三个连续问题:这份资源归应用还是归租户?本地内容是否仍等于已安装基线?本次包是否来自可证明的官方发行链?答案不同,升级动作就应该不同。
核心结论| 版本号只描述先后,不描述所有权;内容摘要只描述差异,不自动授权覆盖。
✦ ② Base、Local、Incoming 让“客户改过”变成可计算状态

Base 是上次安装成功的摘要,Local 是目标租户当前代码,Incoming 是新包代码。
Base 不是发布者记忆中的旧代码,而是目标租户上一次成功安装后持久化的资源状态;Local 必须对当前接口正文重新计算摘要;Incoming 来自已验签、已校验的本次包。三者同桌比较,才能区分“没有改过”“已经是新版本”和“出现独立分叉”。
Local == Incoming → 已经一致,可幂等应用
Local == Base → 本地未改,可升级 Incoming
Local != Base
&& Local != Incoming → 冲突,整包回滚
冲突回滚看似保守,却保护了事务闭包:如果表和菜单已经升级、接口代码却被静默覆盖或跳过,系统会落在无法复现的半版本。明确失败,管理员才有机会把租户逻辑迁到正式扩展点。
✦ ③ Managed 与 CreateIfMissing 不是两个开关,而是两种所有权

核心协议由应用维护,业务个性化进入租户拥有的 Hook。
Managed 表示应用拥有的核心协议,它负责稳定输入、鉴权、事务和默认行为;CreateIfMissing 表示租户拥有的扩展 Hook,只在第一次缺失时创建。后续官方包即使带来同 Key 新代码,也必须跳过已有 Hook 的源码、启用状态和软删除状态。
{
"core": {"Ownership":"Application","UpgradePolicy":"Managed"},
"hook": {"Ownership":"Tenant","UpgradePolicy":"CreateIfMissing"}
}
不可逆边界| 同一 Key 一旦按 CreateIfMissing 交给租户,后续版本禁止改回 Managed;需要新核心时应发布新 Key 并显式迁移。
✦ ④ 为什么可信官方 Managed 有一个窄例外
普通应用始终走三方保护。但平台自身的核心接口如果被历史租户误改,最新版官方应用会被 Local != Base 永久阻断。当前实现因此给受信官方 Platform 包一个窄例外。
只有来源固定为 https://api.itdos.com 与 iTdos、商城模型实时回读确认 ApplicationType=Platform,并且策略确实是 Application + Managed,才允许用 Incoming 恢复官方核心。

来源、应用类型、资源所有权和升级策略必须同时成立,缺一项都回到普通三方保护。
trusted source
+ Platform application
+ Ownership = Application
+ UpgradePolicy = Managed
= 允许恢复官方核心
离线包、自定义商城源、社区应用或仅在 JSON 中自报“官方”的包都拿不到这个权限。例外不是“官方永远正确”,而是由可回读信任链限定的一种发行语义。
✦ ⑤ 为什么文件头变化不该制造假冲突
官方源码顶部会写所有权提示和版本说明。历史包可能只改了这一段注释,执行正文完全相同;如果直接对整文件做 SHA-256,会把说明文字变化误判成客户修改。当前导入器先规范化 BOM、换行、尾部空白,并且只移除开头第一个生成式块注释,再计算可执行正文摘要。
刻意保持严格| 正文里的任意语句、注释或字符变化仍会产生不同摘要;不能用压缩全部空白、去掉所有注释等模糊规则绕过冲突。
这条边界很小,却很重要:它允许发行说明自然演进,同时确保真正的租户逻辑变化仍被看见。兼容旧官方基线也只能接受已验证的 64 位摘要集合,未知本地代码继续失败关闭。
✦ ⑥ 69 项测试证明了什么,又没有证明什么

本轮直接执行当前 import-package.test.mjs,69/69 通过。
聚焦测试覆盖可信官方 Managed 覆盖、普通包三方冲突、兼容基线、生成式文件头等价、CreateIfMissing 所有权不可逆,以及应用商城包内嵌导入器与独立源码一致。它还覆盖后台分片、资产恢复、菜单权限等导入闭包,因此不是只对一个孤立函数做字符串断言。
- 可信官方 Platform + Managed:本地有差异时恢复 Incoming。
- 普通或社区应用:只有 Local 等于 Base、兼容基线或 Incoming 才继续。
- CreateIfMissing:已有租户资源永远跳过,不能被后续 Managed 接管。
- 生成式文件头可等价;可执行正文变化仍冲突。
证据边界| 69 项本地测试证明当前源码与包内契约一致;它不等同于真实客户租户安装、官网包发布回读或生产 UI 验收。
✦ ⑦ 上线前用这张清单替代“覆盖还是不覆盖”的争论

所有权、基线、来源、事务、扩展点与回读缺一不可。
- 包内每个接口是否显式声明 ResourcePolicies.ApiEngines。
- Managed 核心与 CreateIfMissing Hook 是否使用不同稳定 Key。
- BaseHash 是否来自上一版真实包或安装成功后的 ResourceState。
- 官方覆盖例外是否由实时来源与 Platform 身份共同证明。
- 冲突是否让整包事务回滚,而不是留下半升级资源。
- 安装后是否回读策略、代码摘要、启用状态和包版本。
真正可靠的升级系统,不会承诺“永不冲突”。它会把冲突变成可定位、可回滚、可迁移的工程事件:官方核心回到官方轨道,租户逻辑留在租户轨道,两者通过稳定 Hook 协作。
AI 声明| 本文短图文技术概念卡片底图由AI生成并经确定性程序叠加准确中文;长文架构图、源码分析与本地测试证据来自当前工作区,概念图不冒充运行证据。
更多推荐




所有评论(0)