跳转至

简体中文

Recipe: Domain-Agnostic Contract Object Validation

1. Scenario and Non-Scenario

Applicable: you need to validate whether a document conforms to a Foundation-registered contract object (e.g., project-manifest), choosing a validation strategy by dialect.

Not applicable: needs to validate the consumer's own business Schema (the consumer should hold it itself; Foundation does not replace it); needs to mix domain-semantic validation into the generic contract.

Quickstart Profile v2 is a separate candidate path. The consumer still owns its business schemas; Engineering Kit only compiles an explicit schema collection into offline validators selected by $id, and does not own the method-to-schema choice.

2. Architecture Choice and Capability ID

Preferred capability: foundation.contracts.object-validation (validateDocument / compileSchema / detectDialect). A pure Ajv implementation, supporting draft-07 and 2020-12.

3. Preconditions and Trust Boundary

  • The document to be validated carries the $id of a registered contract object.
  • Trust boundary: validateDocument never modifies the caller's input; a normalized copy is returned only in the result's data field.

4. Minimal Code

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);

The code above shows using $id to specify the target Schema and retrieving { valid, errorCode, errors, data }.

5. Expected Output and Evidence

On successful validation result.valid is true; on failure errorCode is a stable code such as SFC1001. Evidence: packages/skill-family-contracts/test/validator.test.mjs and test/schemas.test.mjs.

6. Safety / Failure Negative Case

// Negative case: unknown $id -> returns 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",
});
// does not throw, returns a structured result:
// { 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. Copy-Paste Verification Command

node --test packages/skill-family-contracts/test/validator.test.mjs \
           packages/skill-family-contracts/test/schemas.test.mjs

8. Business Logic the Caller Continues to Own

  • Semantic interpretation of specific business fields.
  • Domain-level validation rules (not within the Foundation generic contract).

9. Upgrade and Rollback Notes

  • The contract authority version CONTRACTS_VERSION = 1.4.0, and the npm package version 0.3.0 run in parallel and are not mixed.
  • Error codes are frozen and do not drift; Schema changes are handled as a new contract-version task, not by modifying frozen content in place.
  • Candidate v2 must be pinned to exactly 0.3.0; integrations that still require v1 must remain pinned to exactly 0.2.1.