diff --git a/CLAUDE.md b/CLAUDE.md index 3e83351..82fe89b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,3 +3,18 @@ | 项目 | 规则 | | --- | --- | | Commit 身份 | 仅以用户身份提交,**禁止**添加 `Co-Authored-By`、AI 署名或任何 AI 辅助标记 | + +## Provider 数据向后兼容规约(强制) + +`schemas/provider.schema.json` 是已发布客户端的兼容契约(frozen baseline),推送数据前必须理解两类变更的风险差异: + +| 变更类型 | 风险 | 规则 | +| --- | --- | --- | +| **已知字段扩 enum 值**(如 `credentialSource` 加新值) | **毒丸**:老客户端把「已知字段的非法枚举值」判为结构性错误。pre-#1021(≤10.0.82)客户端会整份拒绝合并 → 停收所有预设更新;新装用户 compute.json 建不出来 | 必须先发布并**铺开**支持该值的客户端版本,再推送数据(v68/v69 事故教训,见 desirecore #1016/#1021) | +| **新增可选字段** | 安全:已铺开韧性(#848/#1021)的客户端把它当未知字段(读时内存剥离、写时原样保留) | 先在 desirecore 主仓 `computeProviderSchema` 声明该字段(否则新客户端也读不到),再更新本仓 schema,最后推数据 | + +**requiredClientVersion 强制规约**: + +- 新增依赖新凭据源(`credentialSource` 新值)或新客户端能力的 provider 时,**必须**声明 `requiredClientVersion`(取包含该能力支持的客户端发布版本号)。≥ desirecore #1038 的客户端据此把不满足版本的 provider 优雅门控为「需更新客户端」 +- 注意它保护不了 pre-#1038 的存量客户端——enum 扩值场景仍必须遵守上表第一行的"先发版铺开"规则,二者不可互替 +- 降低/解除版本要求时**改为更小版本号**(如 `0.0.0`)而非删除字段:客户端预设合并只遍历上游存在的字段,不回传字段删除 diff --git a/schemas/provider.schema.json b/schemas/provider.schema.json index 0a9c1f4..6b898d3 100644 --- a/schemas/provider.schema.json +++ b/schemas/provider.schema.json @@ -181,6 +181,11 @@ "type": "array", "description": "预置显式删除的模型 modelName 白名单", "items": { "type": "string" } + }, + "requiredClientVersion": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$", + "description": "使用此 provider 所需的最低客户端版本(semver x.y.z)。对已铺开韧性(#848/#1021)的客户端是可安全推送的未知字段(非毒丸——毒丸只源自已知字段的 enum 值扩展);≥ 支持版本(含 desirecore #1038)的客户端据此把 provider 优雅门控为「需更新客户端」并从模型选择器排除。规约:新凭据源/新能力 provider 必须声明本字段;降低/解除要求请改为更小版本号而非删除字段(预设合并不回传字段删除)" } }, "additionalProperties": false,