Recipe:领域无关的契约对象校验¶
1. 场景与非场景¶
适用:需要校验一份文档是否符合 Foundation 已登记的契约对象(如 project-manifest),按方言选择校验策略。
不适用:需要校验消费者自有业务 Schema(消费者应自行持有,Foundation 不取代);需要把领域语义校验混入通用契约。
Quickstart Profile v2 是单独的 candidate 路径。消费者仍拥有业务 Schema;Engineering Kit 只在构建阶段把显式 Schema 集合编译成按 $id 查询的离线 validator,不接管 method 到 Schema 的选择。
2. 架构选择及能力 ID¶
首选能力:foundation.contracts.object-validation(validateDocument / compileSchema / detectDialect)。纯 Ajv 实现,支持 draft-07 与 2020-12。
3. 前置条件与信任边界¶
- 待校验文档带有已登记契约对象的
$id。 - 信任边界:
validateDocument永不修改调用者输入;规范化副本只在结果data字段返回。
4. 最小代码¶
import { validateDocument } from "skill-family-contracts";
const document = {
schemaVersion: 1,
kind: "skill-family.project-manifest",
project: { id: "my-project", name: "My Project", description: "Example" },
contracts: { version: "1.0.0", profile: "generic" },
managedFiles: ["package.json"],
updatedAt: "2026-01-01T00:00:00Z",
};
const result = validateDocument(document, {
schemaId: "https://contracts.skill-family.example/v1/project-manifest.json",
dialect: "2020-12",
});
if (!result.valid) console.error(result.errorCode);
以上代码展示了用 $id 指定目标 Schema 并取回 { valid, errorCode, errors, data }。
5. 预期输出与证据¶
校验通过时 result.valid 为 true;失败时 errorCode 为 SFC1001 等稳定码。证据:packages/skill-family-contracts/test/validator.test.mjs 与 test/schemas.test.mjs。
6. 安全/失败负例¶
// 负例:未知 $id -> 返回 valid:false,errorCode = SFC1002 (UNKNOWN_SCHEMA_ID)
const bad = validateDocument(document, {
schemaId: "https://contracts.skill-family.example/v1/does-not-exist.json",
dialect: "2020-12",
});
// 不抛异常,返回结构化结果:
// { valid: false, errorCode: "SFC1002",
// errors: [{ message: "unknown schema $id: https://contracts.skill-family.example/v1/does-not-exist.json" }] }
if (!bad.valid) console.error(bad.errorCode); // SFC1002
7. 可复制验证命令¶
node --test packages/skill-family-contracts/test/validator.test.mjs \
packages/skill-family-contracts/test/schemas.test.mjs
8. 调用方继续拥有的业务逻辑¶
- 具体业务字段的语义解释。
- 领域级校验规则(不在 Foundation 通用契约内)。
9. 升级与回滚注意事项¶
- 契约权威版本
CONTRACTS_VERSION = 1.4.0,npm 包版本0.3.0并行,不混用。 - 错误码冻结不漂移;Schema 变更作为新的合同版本任务进行,不就地改冻结内容。
- candidate v2 必须精确锁定 0.3.0;仍需 v1 的接入继续精确锁定 0.2.1。