适用范围
约束所有对外承诺的版本声明、兼容判定、旧版本行为与退役流程。
不约束:软件发布版本号规则(由发布流程决定);实现仓内部重构。
规范条款
什么需要版本
- 下列内容必须有显式版本,且必须可被对端声明与校验:
| 对象 | 说明 |
|---|
| 形状版本 | 接口的请求/响应结构 |
| 语义版本 | 同一形状下的行为含义 |
| 词汇表版本 | 封闭枚举的取值集合 |
| 持久化形状 | 存储对象的稳定字段集合 |
- 必须不存在无版本的对外承诺;必须不以"当前版本"隐含表达。
兼容判定
- 变更必须先判定为下列之一,必须在变更说明中显式标注:
| 判定 | 定义 | 是否需对端改动 |
|---|
| 兼容 | 现有对端无需改动即可继续工作 | 否 |
| 需升级 | 现有对端必须升级后才能继续工作 | 是 |
| 破坏 | 语义改变或取值删除,无法通过升级平滑过渡 | 是 + 迁移 |
- 下列变更必须视为破坏,必须不以兼容方式发布:
| 变更 | 为什么是破坏 |
|---|
| 改变既有取值的含义 | 同样的输入产生不同结果 |
| 删除既有取值 | 对端可能仍在发送或依赖 |
| 收紧既有校验(原来接受现在拒绝) | 对端会突然失败 |
| 改变必填性 | 对端可能缺字段或多余字段 |
| 改变幂等或重放语义 | 可能产生重复副作用 |
| 改变终态集合 | 对端的终态处理会遗漏 |
- 下列变更可以视为兼容:
| 变更 | 条件 |
|---|
| 新增可选字段 | 不影响既有字段语义,且严格校验下对端必须声明版本 |
| 新增错误类别 | 对端能按错误分类学处理未知类别 |
| 新增枚举取值 | 仅当对端被要求对未知取值失败关闭而非静默忽略 |
- 新增封闭枚举取值必须默认按需升级处理;必须不假设对端会忽略未知取值。
声明与校验
- 每次请求与响应必须能确定双方版本;必须在版本不受支持时拒绝,必须不降级为"尽力解析"。
- 版本不受支持必须返回可判定的错误类别(归属错误分类学的形状/版本错误),且必须无副作用。
旧版本行为
- 旧版本对端遇到不支持的版本时必须:停止产生新副作用,必须不继续以旧语义执行。
- 已处于进行中的工作必须按声明的方式收束:必须允许收敛到终态,必须不留下无主对象。
- 必须不假设"旧版本会自行消失";必须声明旧版本的支持窗口与到期行为。
- 退役必须是显式动作:必须先声明退役、再撤销支持、最后移除代码与文档。
- 退役条款必须从规格与文档中删除;必须不保留兼容说明、别名或"旧值"标注。
- 追溯必须使用版本历史或证据面;必须不在正文保留历史痕迹。
- 已写入的不可变数据必须保持可读与可审计;退役必须不改写历史。
违反时的失败语义
| 违反情形 | 必须的行为 |
|---|
| 无版本的对外承诺 | 视为规格违反;评审阶段必须拦截 |
| 破坏性变更按兼容发布 | 必须撤回;改走需升级或破坏流程 |
| 版本不受支持却尽力解析 | 必须改为拒绝并返回版本错误 |
| 旧版本继续产生副作用 | 必须停止副作用并收敛 |
| 退役后保留别名 | 必须删除 |
| 退役改写历史数据 | 必须停止 |
校验方式
| 校验对象 | 判据 | 失败表现 |
|---|
| 版本可声明 | 每个对外承诺必须能定位到其版本 | 缺失即失败 |
| 判定标注 | 每次承诺变更必须标注兼容 / 需升级 / 破坏 | 未标注即失败 |
| 未知版本拒绝 | 发送不受支持版本必须被拒绝且无副作用 | 被接受即失败 |
| 破坏清单 | 出现破坏清单中任一项变更时必须标注为破坏 | 标注为兼容即失败 |
| 枚举封闭 | 新增取值时旧对端必须失败关闭而非忽略 | 静默忽略即失败 |
| 旧版本收敛 | 旧版本必须停止副作用并能收敛到终态 | 留下无主对象即失败 |
| 退役清理 | 退役后正文不得残留别名与兼容说明 | 残留即失败 |
| 历史可读 | 退役后既有不可变数据仍可读 | 不可读即失败 |
相关规格