@kungfu-tech/buildchain 2.14.2 → 2.14.3-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/site/agent-index.json +2 -0
  2. package/dist/site/artifact-schemas.json +4 -0
  3. package/dist/site/badge-endpoint-registry.json +320 -0
  4. package/dist/site/badges/v1/kfd-5/aligned.json +14 -0
  5. package/dist/site/badges/v1/kfd-5/declared.json +14 -0
  6. package/dist/site/badges/v1/kfd-5/downgraded.json +14 -0
  7. package/dist/site/badges/v1/kfd-5/draft.json +14 -0
  8. package/dist/site/badges/v1/kfd-5/failed.json +14 -0
  9. package/dist/site/badges/v1/kfd-5/missing.json +14 -0
  10. package/dist/site/badges/v1/kfd-5/passed.json +14 -0
  11. package/dist/site/badges/v1/kfd-5/planned.json +14 -0
  12. package/dist/site/badges/v1/kfd-6/aligned.json +14 -0
  13. package/dist/site/badges/v1/kfd-6/declared.json +14 -0
  14. package/dist/site/badges/v1/kfd-6/downgraded.json +14 -0
  15. package/dist/site/badges/v1/kfd-6/draft.json +14 -0
  16. package/dist/site/badges/v1/kfd-6/failed.json +14 -0
  17. package/dist/site/badges/v1/kfd-6/missing.json +14 -0
  18. package/dist/site/badges/v1/kfd-6/passed.json +14 -0
  19. package/dist/site/badges/v1/kfd-6/planned.json +14 -0
  20. package/dist/site/buildchain-contract.json +34 -19
  21. package/dist/site/buildchain-site.json +13 -11
  22. package/dist/site/capability-registry.json +1 -1
  23. package/dist/site/controller-registry.json +14 -2
  24. package/dist/site/kfd-claims.json +21 -6
  25. package/dist/site/kfd-upstream-aggregate.json +12 -12
  26. package/dist/site/manual-registry.json +2 -2
  27. package/dist/site/node-api-registry.json +15 -2
  28. package/dist/site/page-registry.json +4 -4
  29. package/dist/site/public-surface-audit.json +12 -4
  30. package/dist/site/publication-registry.json +4 -4
  31. package/dist/site/release-model.json +3 -1
  32. package/dist/site/release-passport-check-manifest.json +167 -0
  33. package/dist/site/release-provenance.json +3 -0
  34. package/dist/site/schemas/release-passport-v1.schema.json +198 -0
  35. package/dist/site/site-manifest.json +6 -6
  36. package/dist/site/workflow-registry.json +4 -1
  37. package/docs/release-passport.md +19 -0
  38. package/docs/release-propagation.md +19 -7
  39. package/package.json +5 -2
  40. package/packages/core/index.js +9 -0
  41. package/packages/core/package-manager.js +32 -0
  42. package/packages/core/release-passport-contract.js +249 -0
  43. package/scripts/check-inventory.mjs +7 -1
  44. package/scripts/generate-site-bundle.mjs +15 -0
  45. package/scripts/validate-package-manager-contract.mjs +24 -0
@@ -0,0 +1,198 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://buildchain.libkungfu.dev/schemas/release-passport-v1.schema.json",
4
+ "title": "Buildchain Release Passport v1",
5
+ "description": "Standalone structural schema for the Buildchain-owned release-passport envelope. KFD subsection semantics remain owned by their canonical KFD schemas.",
6
+ "type": "object",
7
+ "required": [
8
+ "schemaVersion",
9
+ "contract",
10
+ "product",
11
+ "release",
12
+ "artifacts",
13
+ "evidence",
14
+ "recovery"
15
+ ],
16
+ "properties": {
17
+ "schemaVersion": {
18
+ "const": 1
19
+ },
20
+ "contract": {
21
+ "const": "kungfu-buildchain-release-passport"
22
+ },
23
+ "generatedAt": {
24
+ "type": "string",
25
+ "format": "date-time"
26
+ },
27
+ "product": {
28
+ "type": "object",
29
+ "required": [
30
+ "name",
31
+ "repository",
32
+ "mechanism"
33
+ ],
34
+ "properties": {
35
+ "name": {
36
+ "type": "string",
37
+ "minLength": 1
38
+ },
39
+ "repository": {
40
+ "type": "string",
41
+ "minLength": 1
42
+ },
43
+ "mechanism": {
44
+ "type": "string",
45
+ "minLength": 1
46
+ }
47
+ },
48
+ "additionalProperties": true
49
+ },
50
+ "release": {
51
+ "type": "object",
52
+ "required": [
53
+ "tag"
54
+ ],
55
+ "properties": {
56
+ "tag": {
57
+ "type": "string",
58
+ "minLength": 1
59
+ },
60
+ "sourceSha": {
61
+ "type": "string"
62
+ },
63
+ "releaseSha": {
64
+ "type": "string"
65
+ },
66
+ "releaseMaterialSha": {
67
+ "type": "string"
68
+ },
69
+ "targetRef": {
70
+ "type": "string"
71
+ },
72
+ "channel": {
73
+ "type": "string"
74
+ },
75
+ "line": {
76
+ "type": "string"
77
+ },
78
+ "package": {
79
+ "type": "object"
80
+ }
81
+ },
82
+ "additionalProperties": true
83
+ },
84
+ "artifacts": {
85
+ "type": "array",
86
+ "minItems": 1,
87
+ "items": {
88
+ "type": "object",
89
+ "required": [
90
+ "name"
91
+ ],
92
+ "properties": {
93
+ "name": {
94
+ "type": "string",
95
+ "minLength": 1
96
+ }
97
+ },
98
+ "additionalProperties": true
99
+ }
100
+ },
101
+ "evidence": {
102
+ "type": "object",
103
+ "required": [
104
+ "artifactEvidence",
105
+ "impact",
106
+ "agentIndex"
107
+ ],
108
+ "properties": {
109
+ "artifactEvidence": {
110
+ "type": "string",
111
+ "minLength": 1
112
+ },
113
+ "impact": {
114
+ "type": "string",
115
+ "minLength": 1
116
+ },
117
+ "agentIndex": {
118
+ "type": "string",
119
+ "minLength": 1
120
+ },
121
+ "publishEvidence": {
122
+ "type": "string"
123
+ },
124
+ "transactionState": {
125
+ "type": "string"
126
+ }
127
+ },
128
+ "additionalProperties": true
129
+ },
130
+ "recovery": {
131
+ "type": "object"
132
+ },
133
+ "workflow": {
134
+ "type": "object"
135
+ },
136
+ "runnerPolicy": {
137
+ "type": "object"
138
+ },
139
+ "versionImpact": {
140
+ "type": "object"
141
+ },
142
+ "surfaceImpacts": {
143
+ "type": "array",
144
+ "items": {
145
+ "type": "object"
146
+ }
147
+ },
148
+ "packageSet": {
149
+ "type": "object"
150
+ },
151
+ "anchorManifest": {
152
+ "type": "object"
153
+ },
154
+ "trustedPublishing": {
155
+ "type": "object"
156
+ },
157
+ "transaction": {
158
+ "type": "object"
159
+ },
160
+ "surfaceTimestampPolicy": {
161
+ "type": "object"
162
+ },
163
+ "buildFacts": {
164
+ "type": "array",
165
+ "items": {
166
+ "type": "object"
167
+ }
168
+ },
169
+ "buildSummary": {
170
+ "type": "object"
171
+ },
172
+ "platformArtifactManifests": {
173
+ "type": "array",
174
+ "items": {
175
+ "type": "object"
176
+ }
177
+ },
178
+ "distTagPromotion": {
179
+ "type": "object"
180
+ },
181
+ "controllerReceipts": {
182
+ "type": "array",
183
+ "items": {
184
+ "type": "object"
185
+ }
186
+ },
187
+ "kfd-1": {
188
+ "type": "object"
189
+ },
190
+ "kfd-2": {
191
+ "type": "object"
192
+ },
193
+ "kfd-3": {
194
+ "type": "object"
195
+ }
196
+ },
197
+ "additionalProperties": true
198
+ }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "contract": "kungfu-buildchain-site-manifest",
4
- "generatedAt": "2026-07-18T01:00:00.995Z",
5
- "publishedAt": "2026-07-18T01:00:00.995Z",
4
+ "generatedAt": "2026-07-18T22:57:23.219Z",
5
+ "publishedAt": "2026-07-18T22:57:23.219Z",
6
6
  "reproducible": true,
7
7
  "timestampPolicy": "ci-injected",
8
8
  "deterministicInputs": [
@@ -19,7 +19,7 @@
19
19
  "declared Buildchain surface manifest contract"
20
20
  ],
21
21
  "sourceDateEpoch": "0",
22
- "sourceRevision": "ae16e640bf2f21c8f981ffa8b3523c8aae9200b2",
22
+ "sourceRevision": "8b0423396f09f29e2ea05c38896228751767ab21",
23
23
  "timestampPolicyDetails": {
24
24
  "contract": "kungfu-buildchain-surface-timestamp-policy",
25
25
  "timestampFields": [
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "package": {
39
39
  "name": "@kungfu-tech/buildchain",
40
- "version": "2.14.2",
40
+ "version": "2.14.3-alpha.0",
41
41
  "versionSource": "package.json#version"
42
42
  },
43
43
  "entrypoint": "buildchain-site.json",
@@ -69,7 +69,7 @@
69
69
  "path": "docs/release-passport.md",
70
70
  "plane": "verify",
71
71
  "exists": true,
72
- "digest": "sha256:2421e3e9f2dd892971bea5deb605492dfec38f3a83e539229442b55380bebe25"
72
+ "digest": "sha256:0029014ffab7d7228a12d8b92326b78cf6757a41f481b661c5997e2cef06d3cc"
73
73
  },
74
74
  {
75
75
  "id": "controller-evidence",
@@ -101,7 +101,7 @@
101
101
  "path": "docs/release-propagation.md",
102
102
  "plane": "use",
103
103
  "exists": true,
104
- "digest": "sha256:d5877075eb41a3d41e531549da113756d29d6f34c91e3b68b8ce650753d5ca1d"
104
+ "digest": "sha256:fc2b743e3d76c4f90cdd8c6560cf9d619ad25d74c15c074be96db7bcb6cc2a29"
105
105
  },
106
106
  {
107
107
  "id": "readme-badges",
@@ -1444,17 +1444,20 @@
1444
1444
  "buildchain-repository",
1445
1445
  "downstream-base-ref",
1446
1446
  "downstream-branch",
1447
+ "downstream-prepare-command",
1447
1448
  "downstream-repository",
1448
1449
  "downstream-target",
1450
+ "downstream-verify-command",
1449
1451
  "dry-run",
1450
1452
  "graph-json",
1451
1453
  "lock-path",
1452
1454
  "pr-body",
1453
1455
  "pr-title",
1456
+ "refresh-managed-readme-badges",
1454
1457
  "source-node",
1455
1458
  "upstream-release-json"
1456
1459
  ],
1457
- "inputCount": 13,
1460
+ "inputCount": 16,
1458
1461
  "secrets": [
1459
1462
  "propagation-token"
1460
1463
  ],
@@ -19,6 +19,25 @@ do not infer execution evidence from a green job. See
19
19
  The release passport surface is a welded contract. Additive fields are allowed;
20
20
  breaking semantic changes require a new major line.
21
21
 
22
+ Independent verifiers can pin two package-owned, standalone files without
23
+ scraping this implementation:
24
+
25
+ - `dist/site/schemas/release-passport-v1.schema.json` is the self-contained
26
+ JSON Schema for the Buildchain-owned envelope;
27
+ - `dist/site/release-passport-check-manifest.json` names the normative checker,
28
+ required and conditional sibling evidence, local-resolution rules,
29
+ Buildchain aggregation fields, canonical KFD subsection schema authorities,
30
+ and forward-compatibility policy.
31
+
32
+ The same files are exported as
33
+ `@kungfu-tech/buildchain/site/schemas/release-passport-v1.schema.json` and
34
+ `@kungfu-tech/buildchain/site/release-passport-check-manifest.json`. The schema
35
+ checks the envelope shape. `buildchain verify release-passport` remains the
36
+ normative semantic checker: it resolves sibling evidence relative to the
37
+ passport and fails closed on missing evidence, digest drift, or inconsistent
38
+ release facts. Buildchain owns envelope aggregation; KFD retains schema and
39
+ compatibility authority for the `kfd-1`, `kfd-2`, and `kfd-3` subsections.
40
+
22
41
  P0 protocol artifacts:
23
42
 
24
43
  - `product-mechanism.json`
@@ -182,6 +182,8 @@ jobs:
182
182
  downstream-target: site-libkungfu-dev
183
183
  downstream-repository: kungfu-systems/site-libkungfu-dev
184
184
  downstream-base-ref: dev/v2/v2.7
185
+ downstream-prepare-command: pnpm install --frozen-lockfile --ignore-scripts
186
+ downstream-verify-command: pnpm run check
185
187
  dry-run: false
186
188
  secrets:
187
189
  propagation-token: ${{ secrets.BUILDCHAIN_PROMOTION_TOKEN }}
@@ -199,13 +201,23 @@ open PR.
199
201
  The workflow checks out the Buildchain runtime selected by
200
202
  `buildchain-repository` and `buildchain-ref` into `.buildchain/runtime`, invokes
201
203
  that runtime for the propagation plan and lock write, then checks out the
202
- downstream repository, writes the exact lock, and opens or updates a PR. It does
203
- not publish the downstream release directly. The downstream repository keeps its
204
- normal Buildchain governance: the PR updates source-of-truth facts, then
205
- downstream alpha or release publication runs through its own protected channel.
206
- The workflow stages the declared lock path before checking the index, so the
207
- first propagation creates a PR even when the lock did not previously exist; a
208
- byte-identical rerun is an explicit successful no-op.
204
+ downstream repository and writes the exact lock. A consumer that must pin the
205
+ exact upstream package or regenerate deterministic files declares
206
+ `downstream-prepare-command`. The command receives
207
+ `BUILDCHAIN_UPSTREAM_PACKAGE_NAME`, `BUILDCHAIN_UPSTREAM_PACKAGE_VERSION`, and
208
+ `BUILDCHAIN_UPSTREAM_RELEASE_LOCK`. After preparation, Buildchain refreshes an
209
+ existing `<!-- buildchain:badges:start -->` README block by default. Consumers
210
+ can disable that step with `refresh-managed-readme-badges: false`.
211
+
212
+ `downstream-verify-command` runs against the final tree before any commit or
213
+ push, so consumers can use the same check as their PR workflow. Preparation,
214
+ badge refresh, and verification failures all fail closed. The workflow stages
215
+ the complete deterministic result, signs the propagation commit with DCO, and
216
+ then opens or updates the PR. It does not publish the downstream release
217
+ directly. The downstream repository keeps its normal Buildchain governance: the
218
+ PR updates source-of-truth facts, then downstream alpha or release publication
219
+ runs through its own protected channel. A byte-identical rerun is an explicit
220
+ successful no-op.
209
221
  For unreleased runtime validation, keep the caller's reusable workflow reference
210
222
  on `@v2` and pass a temporary train ref through `buildchain-ref`.
211
223
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "2.14.2",
3
+ "version": "2.14.3-alpha.0",
4
4
  "private": false,
5
5
  "description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
6
6
  "repository": "https://github.com/kungfu-systems/buildchain",
@@ -38,6 +38,7 @@
38
38
  "./release-candidate": "./packages/core/release-candidate.js",
39
39
  "./stable-candidate-ledger": "./packages/core/stable-candidate-ledger.js",
40
40
  "./release-passport": "./packages/core/release-passport.js",
41
+ "./release-passport-contract": "./packages/core/release-passport-contract.js",
41
42
  "./release-propagation": "./packages/core/release-propagation.js",
42
43
  "./surface-manifest": "./packages/core/surface-manifest.js",
43
44
  "./buildchain-kfd-claims": "./packages/core/buildchain-kfd-claims.js",
@@ -57,6 +58,8 @@
57
58
  "./site/kfd-upstream-aggregate.json": "./dist/site/kfd-upstream-aggregate.json",
58
59
  "./site/release-model.json": "./dist/site/release-model.json",
59
60
  "./site/artifact-schemas.json": "./dist/site/artifact-schemas.json",
61
+ "./site/release-passport-check-manifest.json": "./dist/site/release-passport-check-manifest.json",
62
+ "./site/schemas/release-passport-v1.schema.json": "./dist/site/schemas/release-passport-v1.schema.json",
60
63
  "./site/buildchain-contract.json": "./dist/site/buildchain-contract.json",
61
64
  "./site/product-mechanism.json": "./dist/site/product-mechanism.json",
62
65
  "./site/release-provenance.json": "./dist/site/release-provenance.json",
@@ -104,7 +107,7 @@
104
107
  "vitest": "^4.1.9"
105
108
  },
106
109
  "dependencies": {
107
- "@kungfu-tech/kfd": "1.0.0-alpha.21",
110
+ "@kungfu-tech/kfd": "1.0.0-alpha.29",
108
111
  "smol-toml": "1.7.0"
109
112
  }
110
113
  }
@@ -37,6 +37,7 @@ export {
37
37
  detectPackageManager,
38
38
  getWorkspaceInfo,
39
39
  shellJoin,
40
+ validatePackageManagerContract,
40
41
  } from "./package-manager.js";
41
42
 
42
43
  export {
@@ -320,6 +321,14 @@ export {
320
321
  verifyReleasePassport,
321
322
  } from "./release-passport.js";
322
323
 
324
+ export {
325
+ RELEASE_PASSPORT_CHECK_MANIFEST_CONTRACT,
326
+ RELEASE_PASSPORT_SCHEMA,
327
+ RELEASE_PASSPORT_SCHEMA_ID,
328
+ createReleasePassportCheckManifest,
329
+ validateReleasePassportSchema,
330
+ } from "./release-passport-contract.js";
331
+
323
332
  export {
324
333
  BUILDCHAIN_CONSUMER_ISSUE_CONTRACT,
325
334
  BUILDCHAIN_WORKFLOW_FRICTION_ISSUE_CONTRACT,
@@ -15,6 +15,37 @@ function parsePackageManager(value) {
15
15
  return match ? match[1] : null;
16
16
  }
17
17
 
18
+ export function validatePackageManagerContract({ cwd = process.cwd(), expectedManager = "" } = {}) {
19
+ const resolvedCwd = path.resolve(cwd);
20
+ const pkg = readJsonIfExists(path.join(resolvedCwd, "package.json"));
21
+ const declaredSpec = String(pkg?.packageManager || "").trim();
22
+ const declaredMatch = declaredSpec.match(/^([A-Za-z0-9._-]+)@([^\s]+)$/);
23
+
24
+ if (declaredSpec && !declaredMatch) {
25
+ throw new Error(
26
+ `Invalid packageManager declaration: ${declaredSpec}. Expected <manager>@<version>.`,
27
+ );
28
+ }
29
+
30
+ const declaredName = declaredMatch?.[1] || "";
31
+ const detected = declaredName && !KNOWN_MANAGERS.has(declaredName)
32
+ ? { name: "custom", reason: "packageManager" }
33
+ : detectPackageManager(resolvedCwd);
34
+ const expected = String(expectedManager || "").trim();
35
+ if (expected && expected !== "custom" && detected.name !== expected) {
36
+ throw new Error(
37
+ `Package manager mismatch: workflow requested ${expected}, but the consumer declares ${detected.name}.`,
38
+ );
39
+ }
40
+
41
+ return {
42
+ name: detected.name,
43
+ reason: detected.reason,
44
+ declaredSpec,
45
+ declaredVersion: declaredMatch?.[2] || "",
46
+ };
47
+ }
48
+
18
49
  export function assertPackageManager(manager) {
19
50
  if (!KNOWN_MANAGERS.has(manager)) {
20
51
  throw new Error(`Unsupported package manager: ${manager}`);
@@ -288,4 +319,5 @@ export default {
288
319
  getWorkspaceInfo,
289
320
  getYarnLockInfo,
290
321
  shellJoin,
322
+ validatePackageManagerContract,
291
323
  };
@@ -0,0 +1,249 @@
1
+ import kfdStandards from "@kungfu-tech/kfd/standards.json" with { type: "json" };
2
+ import {
3
+ RELEASE_CHECK_REPORT_CONTRACT,
4
+ RELEASE_PASSPORT_CONTRACT,
5
+ } from "./release-passport.js";
6
+
7
+ export const RELEASE_PASSPORT_SCHEMA_ID =
8
+ "https://buildchain.libkungfu.dev/schemas/release-passport-v1.schema.json";
9
+ export const RELEASE_PASSPORT_CHECK_MANIFEST_CONTRACT =
10
+ "kungfu-buildchain-release-passport-check-manifest";
11
+
12
+ const OBJECT = { type: "object" };
13
+ const STRING = { type: "string", minLength: 1 };
14
+ const OPTIONAL_STRING = { type: "string" };
15
+
16
+ export const RELEASE_PASSPORT_SCHEMA = {
17
+ $schema: "https://json-schema.org/draft/2020-12/schema",
18
+ $id: RELEASE_PASSPORT_SCHEMA_ID,
19
+ title: "Buildchain Release Passport v1",
20
+ description:
21
+ "Standalone structural schema for the Buildchain-owned release-passport envelope. KFD subsection semantics remain owned by their canonical KFD schemas.",
22
+ type: "object",
23
+ required: [
24
+ "schemaVersion",
25
+ "contract",
26
+ "product",
27
+ "release",
28
+ "artifacts",
29
+ "evidence",
30
+ "recovery",
31
+ ],
32
+ properties: {
33
+ schemaVersion: { const: 1 },
34
+ contract: { const: RELEASE_PASSPORT_CONTRACT },
35
+ generatedAt: { type: "string", format: "date-time" },
36
+ product: {
37
+ type: "object",
38
+ required: ["name", "repository", "mechanism"],
39
+ properties: {
40
+ name: STRING,
41
+ repository: STRING,
42
+ mechanism: STRING,
43
+ },
44
+ additionalProperties: true,
45
+ },
46
+ release: {
47
+ type: "object",
48
+ required: ["tag"],
49
+ properties: {
50
+ tag: STRING,
51
+ sourceSha: OPTIONAL_STRING,
52
+ releaseSha: OPTIONAL_STRING,
53
+ releaseMaterialSha: OPTIONAL_STRING,
54
+ targetRef: OPTIONAL_STRING,
55
+ channel: OPTIONAL_STRING,
56
+ line: OPTIONAL_STRING,
57
+ package: OBJECT,
58
+ },
59
+ additionalProperties: true,
60
+ },
61
+ artifacts: {
62
+ type: "array",
63
+ minItems: 1,
64
+ items: {
65
+ type: "object",
66
+ required: ["name"],
67
+ properties: { name: STRING },
68
+ additionalProperties: true,
69
+ },
70
+ },
71
+ evidence: {
72
+ type: "object",
73
+ required: ["artifactEvidence", "impact", "agentIndex"],
74
+ properties: {
75
+ artifactEvidence: STRING,
76
+ impact: STRING,
77
+ agentIndex: STRING,
78
+ publishEvidence: OPTIONAL_STRING,
79
+ transactionState: OPTIONAL_STRING,
80
+ },
81
+ additionalProperties: true,
82
+ },
83
+ recovery: OBJECT,
84
+ workflow: OBJECT,
85
+ runnerPolicy: OBJECT,
86
+ versionImpact: OBJECT,
87
+ surfaceImpacts: { type: "array", items: OBJECT },
88
+ packageSet: OBJECT,
89
+ anchorManifest: OBJECT,
90
+ trustedPublishing: OBJECT,
91
+ transaction: OBJECT,
92
+ surfaceTimestampPolicy: OBJECT,
93
+ buildFacts: { type: "array", items: OBJECT },
94
+ buildSummary: OBJECT,
95
+ platformArtifactManifests: { type: "array", items: OBJECT },
96
+ distTagPromotion: OBJECT,
97
+ controllerReceipts: { type: "array", items: OBJECT },
98
+ "kfd-1": OBJECT,
99
+ "kfd-2": OBJECT,
100
+ "kfd-3": OBJECT,
101
+ },
102
+ additionalProperties: true,
103
+ };
104
+
105
+ const BUILDCHAIN_AGGREGATION_FIELDS = [
106
+ "product",
107
+ "release",
108
+ "workflow",
109
+ "runnerPolicy",
110
+ "versionImpact",
111
+ "surfaceImpacts",
112
+ "packageSet",
113
+ "anchorManifest",
114
+ "trustedPublishing",
115
+ "transaction",
116
+ "surfaceTimestampPolicy",
117
+ "buildFacts",
118
+ "buildSummary",
119
+ "platformArtifactManifests",
120
+ "distTagPromotion",
121
+ "controllerReceipts",
122
+ "artifacts",
123
+ "evidence",
124
+ "recovery",
125
+ ];
126
+
127
+ function kfdSectionAuthority(id, standards = kfdStandards) {
128
+ const standard = standards?.standards?.[id] || {};
129
+ return {
130
+ section: id,
131
+ owner: "KFD",
132
+ package: standards?.source?.package || "@kungfu-tech/kfd",
133
+ metadataSchema: standards?.metadataSchema || {},
134
+ schemaIds: standard.schemaIds || {},
135
+ schemaPaths: standard.schemaPaths || {},
136
+ compatibility: standard.compatibility || {},
137
+ rule: `Buildchain aggregates and checks ${id} evidence but does not redefine its schema semantics.`,
138
+ };
139
+ }
140
+
141
+ export function createReleasePassportCheckManifest({ standards = kfdStandards } = {}) {
142
+ return {
143
+ schemaVersion: 1,
144
+ contract: RELEASE_PASSPORT_CHECK_MANIFEST_CONTRACT,
145
+ passport: {
146
+ contract: RELEASE_PASSPORT_CONTRACT,
147
+ schemaVersion: 1,
148
+ schema: {
149
+ id: RELEASE_PASSPORT_SCHEMA_ID,
150
+ path: "schemas/release-passport-v1.schema.json",
151
+ npmExport: "@kungfu-tech/buildchain/site/schemas/release-passport-v1.schema.json",
152
+ },
153
+ checker: {
154
+ contract: RELEASE_CHECK_REPORT_CONTRACT,
155
+ command: "buildchain verify release-passport <buildchain.release.json>",
156
+ nodeApi: "@kungfu-tech/buildchain/release-passport#verifyReleasePassport",
157
+ result: "check-report.json",
158
+ },
159
+ },
160
+ ownership: {
161
+ envelopeOwner: "Buildchain",
162
+ aggregationFields: BUILDCHAIN_AGGREGATION_FIELDS,
163
+ kfdSections: ["kfd-1", "kfd-2", "kfd-3"].map((id) =>
164
+ kfdSectionAuthority(id, standards),
165
+ ),
166
+ },
167
+ localClosure: {
168
+ entrypoint: "buildchain.release.json",
169
+ resolutionBase: "directory containing the passport",
170
+ requiredSiblings: [
171
+ "product.mechanism",
172
+ "evidence.artifactEvidence",
173
+ "evidence.impact",
174
+ "evidence.agentIndex",
175
+ ],
176
+ conditionalSiblings: [
177
+ {
178
+ when: "evidence.publishEvidence is present or packageSet is present",
179
+ pointer: "evidence.publishEvidence",
180
+ },
181
+ {
182
+ when: "evidence.transactionState is present",
183
+ pointer: "evidence.transactionState",
184
+ },
185
+ ],
186
+ rule:
187
+ "The normative checker resolves every declared sibling relative to the passport and fails closed on missing required evidence, digest drift, or semantic mismatch.",
188
+ },
189
+ compatibility: {
190
+ envelope:
191
+ "Compatible optional fields may be added while schemaVersion remains 1; removing or changing required-field semantics requires a new schema id or contract version.",
192
+ siblings:
193
+ "New optional siblings may be added in v1; making a sibling required requires a new schema id or contract version.",
194
+ kfdSections:
195
+ "Each KFD subsection follows the compatibility metadata published by @kungfu-tech/kfd; Buildchain must not silently reinterpret a KFD schema version.",
196
+ unknownFields: "Independent readers must preserve or ignore unknown additive fields.",
197
+ },
198
+ };
199
+ }
200
+
201
+ function matchesType(value, type) {
202
+ if (type === "object") return Boolean(value) && typeof value === "object" && !Array.isArray(value);
203
+ if (type === "array") return Array.isArray(value);
204
+ if (type === "integer") return Number.isInteger(value);
205
+ return typeof value === type;
206
+ }
207
+
208
+ function validateSchemaNode(schema, value, pointer, issues) {
209
+ if (schema.type && !matchesType(value, schema.type)) {
210
+ issues.push({ pointer, code: "type", message: `${pointer} must be ${schema.type}` });
211
+ return;
212
+ }
213
+ if (Object.hasOwn(schema, "const") && value !== schema.const) {
214
+ issues.push({ pointer, code: "const", message: `${pointer} must equal ${JSON.stringify(schema.const)}` });
215
+ }
216
+ if (schema.minLength && typeof value === "string" && value.length < schema.minLength) {
217
+ issues.push({ pointer, code: "minLength", message: `${pointer} must not be empty` });
218
+ }
219
+ if (schema.minItems && Array.isArray(value) && value.length < schema.minItems) {
220
+ issues.push({ pointer, code: "minItems", message: `${pointer} must contain at least ${schema.minItems} item(s)` });
221
+ }
222
+ if (Array.isArray(value) && schema.items) {
223
+ value.forEach((entry, index) => validateSchemaNode(schema.items, entry, `${pointer}/${index}`, issues));
224
+ }
225
+ if (matchesType(value, "object")) {
226
+ for (const key of schema.required || []) {
227
+ if (!Object.hasOwn(value, key)) {
228
+ issues.push({ pointer: `${pointer}/${key}`, code: "required", message: `${pointer}/${key} is required` });
229
+ }
230
+ }
231
+ for (const [key, childSchema] of Object.entries(schema.properties || {})) {
232
+ if (Object.hasOwn(value, key)) {
233
+ validateSchemaNode(childSchema, value[key], `${pointer}/${key}`, issues);
234
+ }
235
+ }
236
+ }
237
+ }
238
+
239
+ export function validateReleasePassportSchema(passport) {
240
+ const issues = [];
241
+ validateSchemaNode(RELEASE_PASSPORT_SCHEMA, passport, "#", issues);
242
+ return {
243
+ schemaVersion: 1,
244
+ contract: "kungfu-buildchain-release-passport-schema-validation",
245
+ schemaId: RELEASE_PASSPORT_SCHEMA_ID,
246
+ ok: issues.length === 0,
247
+ issues,
248
+ };
249
+ }