@kungfu-tech/buildchain 2.8.0 → 2.8.1

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.
@@ -7,6 +7,9 @@ const require = createRequire(import.meta.url);
7
7
 
8
8
  export const KFD1_RELEASE_GATE_CONTRACT = "kungfu-buildchain-kfd-1-release-gate";
9
9
  export const KFD1_WITNESS_SET_CONTRACT = "kungfu-buildchain-kfd-1-witness-set";
10
+ export const KFD3_RELEASE_GATE_CONTRACT = "kungfu-buildchain-kfd-3-collaboration-interface-release-gate";
11
+ export const KFD3_PREBUILD_WITNESS_CONTRACT = "kungfu-buildchain-kfd-3-collaboration-interface-prebuild-witness";
12
+ export const KFD3_ARTIFACT_WITNESS_CONTRACT = "kungfu-buildchain-kfd-3-collaboration-interface-artifact-witness";
10
13
  export const BUILDCHAIN_JSON_FORMATTING_POLICY = Object.freeze({
11
14
  name: "buildchain-release-evidence-json-v1",
12
15
  indentation: 2,
@@ -100,6 +103,51 @@ export function resolveKfd1Metadata() {
100
103
  };
101
104
  }
102
105
 
106
+ export function resolveKfd3Metadata({ requireSchemas = false } = {}) {
107
+ const { packageJson, standards } = loadKfdPackageMetadata();
108
+ const entries = Object.entries(standards.standards || {});
109
+ const entry = entries.find(([key, value]) => {
110
+ const names = [key, value?.key, value?.id, value?.label]
111
+ .filter(Boolean)
112
+ .map((name) => String(name).toLowerCase());
113
+ return names.includes("kfd-3");
114
+ });
115
+ if (!entry) {
116
+ throw new Error("KFD metadata package does not expose KFD-3 metadata");
117
+ }
118
+ const [key, standard] = entry;
119
+ const schemaIds = { ...(standard.schemaIds || {}) };
120
+ const schemaPaths = { ...(standard.schemaPaths || {}) };
121
+ const hasCollaborationSchemas = Boolean(
122
+ schemaIds.collaborationInterface &&
123
+ schemaIds.witness &&
124
+ schemaPaths.collaborationInterface &&
125
+ schemaPaths.witness,
126
+ );
127
+ if (requireSchemas && !hasCollaborationSchemas) {
128
+ throw new Error("KFD metadata package does not expose the KFD-3 collaboration-interface witness standard");
129
+ }
130
+ return {
131
+ key: standard.key || key,
132
+ id: standard.id || standard.label || key,
133
+ label: standard.label || standard.id || key,
134
+ title: standard.title || "",
135
+ status: standard.status || "",
136
+ revision: standard.revision || 0,
137
+ package: {
138
+ name: packageJson.name,
139
+ version: packageJson.version,
140
+ repository: packageJson.repository?.url || "",
141
+ },
142
+ schemaIds,
143
+ schemaPaths,
144
+ hasCollaborationSchemas,
145
+ concepts: { ...(standard.concepts || {}) },
146
+ metadataSchema: standards.metadataSchema || {},
147
+ source: standards.source || {},
148
+ };
149
+ }
150
+
103
151
  function normalizeHash(value, label, { required = false } = {}) {
104
152
  const text = optionalString(value).replace(/^sha256:/, "").trim();
105
153
  if (!text && !required) {
@@ -158,13 +206,504 @@ function normalizeSurface(surface, index) {
158
206
  };
159
207
  }
160
208
 
209
+ function normalizeStringArray(value) {
210
+ return Array.isArray(value) ? value.map((entry) => optionalString(entry)).filter(Boolean) : [];
211
+ }
212
+
213
+ const KFD3_SURFACE_GROUPS = [
214
+ {
215
+ kind: "documentation",
216
+ keys: ["docs", "documents", "documentation"],
217
+ },
218
+ {
219
+ kind: "schema",
220
+ keys: ["schemas"],
221
+ },
222
+ {
223
+ kind: "standards-metadata",
224
+ keys: ["standardsMetadata", "standards_metadata", "standards", "metadata"],
225
+ },
226
+ {
227
+ kind: "package-export",
228
+ keys: ["packageExports", "package_exports", "exports"],
229
+ },
230
+ {
231
+ kind: "site-consumption-contract",
232
+ keys: ["siteConsumptionContracts", "site_consumption_contracts", "siteContracts", "site_contracts"],
233
+ },
234
+ ];
235
+
236
+ function groupedKfd3SurfacesFromSource(source = {}) {
237
+ if (!source || typeof source !== "object" || Array.isArray(source)) {
238
+ return [];
239
+ }
240
+ const surfaces = [];
241
+ for (const group of KFD3_SURFACE_GROUPS) {
242
+ const values = group.keys
243
+ .map((key) => source[key])
244
+ .find((entry) => Array.isArray(entry));
245
+ if (!values) {
246
+ continue;
247
+ }
248
+ values.forEach((entry, index) => {
249
+ if (typeof entry === "string") {
250
+ surfaces.push({
251
+ id: entry,
252
+ name: entry,
253
+ kind: group.kind,
254
+ availability: "shipped",
255
+ visibility: "public",
256
+ participantFacing: true,
257
+ public: true,
258
+ });
259
+ return;
260
+ }
261
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
262
+ throw new Error(`${group.keys[0]}[${index}] must be a string or object`);
263
+ }
264
+ surfaces.push({
265
+ kind: group.kind,
266
+ availability: "shipped",
267
+ visibility: "public",
268
+ participantFacing: true,
269
+ public: true,
270
+ ...entry,
271
+ });
272
+ });
273
+ }
274
+ return surfaces;
275
+ }
276
+
277
+ function groupedKfd1SurfacesFromSource(source = {}) {
278
+ return groupedKfd3SurfacesFromSource(source).map((surface) => ({
279
+ name: surface.name || surface.id,
280
+ sourcePath: surface.sourcePath || surface.source_path || "",
281
+ sourceSha256: surface.sourceSha256 || surface.source_sha256 || surface.sha256 || "",
282
+ artifactPath: surface.artifactPath || surface.artifact_path || surface.path || surface.sourcePath || surface.source_path || "",
283
+ expectedSha256: surface.expectedSha256 || surface.expected_sha256 || surface.artifactSha256 || surface.artifact_sha256 || surface.sha256 || "",
284
+ byteForByte: surface.byteForByte ?? surface.byte_for_byte ?? true,
285
+ }));
286
+ }
287
+
288
+ function normalizeKfd3Surface(surface, index, label) {
289
+ if (!surface || typeof surface !== "object" || Array.isArray(surface)) {
290
+ throw new Error(`${label}[${index}] must be an object`);
291
+ }
292
+ const visibility = optionalString(surface.visibility || (surface.public === false ? "internal" : "public")).toLowerCase();
293
+ const availability = optionalString(surface.availability || surface.state || surface.maturity || (surface.shipped === false ? "not-shipped" : "shipped")).toLowerCase();
294
+ const participantFacing = surface.participantFacing ?? surface.participant_facing ?? true;
295
+ const publicSurface = surface.public ?? (visibility === "public");
296
+ return {
297
+ id: nonEmptyString(surface.id || surface.name || surface.command, `${label}[${index}].id`),
298
+ name: optionalString(surface.name || surface.label || surface.id),
299
+ kind: optionalString(surface.kind || surface.type || "control-surface"),
300
+ participantProfile: optionalString(surface.participantProfile || surface.participant_profile || surface.profile),
301
+ availability,
302
+ visibility,
303
+ participantFacing: Boolean(participantFacing),
304
+ public: Boolean(publicSurface),
305
+ sourcePath: surface.sourcePath || surface.source_path
306
+ ? normalizePath(surface.sourcePath || surface.source_path, `${label}[${index}].sourcePath`)
307
+ : "",
308
+ evidencePath: surface.evidencePath || surface.evidence_path
309
+ ? normalizePath(surface.evidencePath || surface.evidence_path, `${label}[${index}].evidencePath`)
310
+ : "",
311
+ };
312
+ }
313
+
314
+ function declaredSurfacesFromWitness(witness) {
315
+ return [
316
+ ...(Array.isArray(witness.declaredSurfaces) ? witness.declaredSurfaces : []),
317
+ ...(Array.isArray(witness.declared_surfaces) ? witness.declared_surfaces : []),
318
+ ...(Array.isArray(witness.surfaces) ? witness.surfaces : []),
319
+ ...(Array.isArray(witness.collaborationInterface?.surfaces) ? witness.collaborationInterface.surfaces : []),
320
+ ...(Array.isArray(witness.collaboration_interface?.surfaces) ? witness.collaboration_interface.surfaces : []),
321
+ ...(Array.isArray(witness.collaborationInterfaceDocument?.surfaces) ? witness.collaborationInterfaceDocument.surfaces : []),
322
+ ...(Array.isArray(witness.collaboration_interface_document?.surfaces) ? witness.collaboration_interface_document.surfaces : []),
323
+ ...groupedKfd3SurfacesFromSource(witness),
324
+ ...groupedKfd3SurfacesFromSource(witness.collaborationInterface),
325
+ ...groupedKfd3SurfacesFromSource(witness.collaboration_interface),
326
+ ...groupedKfd3SurfacesFromSource(witness.collaborationInterfaceDocument),
327
+ ...groupedKfd3SurfacesFromSource(witness.collaboration_interface_document),
328
+ ];
329
+ }
330
+
331
+ function artifactSurfacesFromWitness(witness) {
332
+ const groupedSurfaces = [
333
+ ...groupedKfd3SurfacesFromSource(witness),
334
+ ...groupedKfd3SurfacesFromSource(witness.artifact),
335
+ ...groupedKfd3SurfacesFromSource(witness.closure),
336
+ ];
337
+ const explicitSurfaces = [
338
+ ...(Array.isArray(witness.exposedSurfaces) ? witness.exposedSurfaces : []),
339
+ ...(Array.isArray(witness.exposed_surfaces) ? witness.exposed_surfaces : []),
340
+ ...(Array.isArray(witness.artifactPublicSurfaces) ? witness.artifactPublicSurfaces : []),
341
+ ...(Array.isArray(witness.artifact_public_surfaces) ? witness.artifact_public_surfaces : []),
342
+ ...(Array.isArray(witness.surfaces) ? witness.surfaces : []),
343
+ ];
344
+ if (Array.isArray(witness.closure?.reachableEntrypoints)) {
345
+ explicitSurfaces.push(...witness.closure.reachableEntrypoints.map((id) => ({
346
+ id,
347
+ kind: "entrypoint",
348
+ availability: "shipped",
349
+ visibility: "public",
350
+ participantFacing: true,
351
+ public: true,
352
+ })));
353
+ }
354
+ return [...explicitSurfaces, ...groupedSurfaces];
355
+ }
356
+
357
+ function normalizeRegistry(value = {}) {
358
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
359
+ return {};
360
+ }
361
+ return {
362
+ id: optionalString(value.id || value.name),
363
+ version: optionalString(value.version),
364
+ path: value.path ? normalizePath(value.path, "registry.path") : "",
365
+ sha256: value.sha256 ? normalizeHash(value.sha256, "registry.sha256") : "",
366
+ digest: optionalString(value.digest || (value.sha256 ? `sha256:${normalizeHash(value.sha256, "registry.sha256")}` : "")),
367
+ };
368
+ }
369
+
370
+ function normalizeArtifactIdentity(value = {}) {
371
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
372
+ return {};
373
+ }
374
+ return {
375
+ name: optionalString(value.name || value.fileName || value.filename),
376
+ path: value.path ? normalizePath(value.path, "artifact.path") : "",
377
+ digest: optionalString(value.digest || (value.sha256 ? `sha256:${normalizeHash(value.sha256, "artifact.sha256")}` : "")),
378
+ };
379
+ }
380
+
381
+ function normalizeStringObjectArray(value, label) {
382
+ if (!Array.isArray(value)) {
383
+ return [];
384
+ }
385
+ return value
386
+ .map((entry, index) => {
387
+ if (typeof entry === "string") {
388
+ return { id: entry, note: "" };
389
+ }
390
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
391
+ throw new Error(`${label}[${index}] must be a string or object`);
392
+ }
393
+ return {
394
+ id: optionalString(entry.id || entry.name || entry.surface || entry.path || entry.kind || `entry-${index}`),
395
+ kind: optionalString(entry.kind || entry.type),
396
+ reason: optionalString(entry.reason || entry.rationale || entry.note || entry.description),
397
+ owner: optionalString(entry.owner),
398
+ };
399
+ })
400
+ .filter((entry) => entry.id || entry.reason);
401
+ }
402
+
403
+ function normalizeKfd3AuditBoundary(value = {}, { closure = {}, label = "auditBoundary" } = {}) {
404
+ const boundary = value && typeof value === "object" && !Array.isArray(value) ? value : {};
405
+ const sourceClosure = closure && typeof closure === "object" && !Array.isArray(closure) ? closure : {};
406
+ const nonExhaustiveSource =
407
+ boundary.nonExhaustivelyEnumerableSurfaces ||
408
+ boundary.non_exhaustively_enumerable_surfaces ||
409
+ boundary.nonExhaustiveSurfaces ||
410
+ boundary.non_exhaustive_surfaces ||
411
+ sourceClosure.nonExhaustivelyEnumerableSurfaces ||
412
+ sourceClosure.non_exhaustively_enumerable_surfaces ||
413
+ sourceClosure.nonExhaustiveSurfaces ||
414
+ sourceClosure.non_exhaustive_surfaces ||
415
+ [];
416
+ return {
417
+ mode: optionalString(boundary.mode || boundary.classificationMode || sourceClosure.classificationMode || "closed-world"),
418
+ scope: optionalString(boundary.scope || "participant-facing public collaboration/control surfaces"),
419
+ reachableSurfaceMode: optionalString(
420
+ boundary.reachableSurfaceMode ||
421
+ boundary.reachable_surface_mode ||
422
+ sourceClosure.reachableSurfaceMode ||
423
+ sourceClosure.reachable_surface_mode ||
424
+ sourceClosure.classificationMode ||
425
+ "declared-boundary",
426
+ ),
427
+ unclassifiedPolicy: optionalString(
428
+ boundary.unclassifiedPolicy ||
429
+ boundary.unclassified_policy ||
430
+ sourceClosure.unclassifiedEntrypointsPolicy ||
431
+ sourceClosure.unclassified_entrypoints_policy ||
432
+ "fail",
433
+ ),
434
+ nonExhaustivelyEnumerableSurfaces: normalizeStringObjectArray(nonExhaustiveSource, `${label}.nonExhaustivelyEnumerableSurfaces`),
435
+ explicitlyExemptedSurfaces: normalizeStringObjectArray(
436
+ boundary.explicitlyExemptedSurfaces ||
437
+ boundary.explicitly_exempted_surfaces ||
438
+ boundary.exemptions ||
439
+ sourceClosure.explicitlyExemptedSurfaces ||
440
+ sourceClosure.exemptions ||
441
+ [],
442
+ `${label}.explicitlyExemptedSurfaces`,
443
+ ),
444
+ };
445
+ }
446
+
447
+ function normalizeKfd3ResidualRisk(value = [], { auditBoundary = {} } = {}) {
448
+ const explicitRisks = normalizeStringObjectArray(value, "residualRisk");
449
+ const boundaryRisks = (auditBoundary.nonExhaustivelyEnumerableSurfaces || []).map((entry) => ({
450
+ id: entry.id,
451
+ kind: entry.kind || "non-exhaustive-surface",
452
+ reason: entry.reason || "Surface cannot be exhaustively enumerated by the release passport.",
453
+ owner: entry.owner || "",
454
+ }));
455
+ const byId = new Map();
456
+ for (const entry of [...explicitRisks, ...boundaryRisks]) {
457
+ byId.set(entry.id || entry.reason, entry);
458
+ }
459
+ return [...byId.values()];
460
+ }
461
+
462
+ function normalizeKfd3Responsibility(value = {}, { registry = {}, artifactVerifyCommand = "" } = {}) {
463
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
464
+ return {
465
+ registryFactsOwner: optionalString(
466
+ source.registryFactsOwner ||
467
+ source.registry_facts_owner ||
468
+ source.productRegistryOwner ||
469
+ source.product_registry_owner ||
470
+ source.product ||
471
+ registry.id ||
472
+ "product",
473
+ ),
474
+ artifactVerificationOwner: optionalString(
475
+ source.artifactVerificationOwner ||
476
+ source.artifact_verification_owner ||
477
+ source.verifierOwner ||
478
+ source.verifier_owner ||
479
+ (artifactVerifyCommand ? "product-owned verify command" : "product"),
480
+ ),
481
+ releasePassportProofOwner: optionalString(
482
+ source.releasePassportProofOwner ||
483
+ source.release_passport_proof_owner ||
484
+ source.passportOwner ||
485
+ source.passport_owner ||
486
+ "buildchain",
487
+ ),
488
+ };
489
+ }
490
+
491
+ export function normalizeKfd3CollaborationInterfacePrebuildWitness(witness, { metadata = resolveKfd3Metadata() } = {}) {
492
+ if (!witness || typeof witness !== "object" || Array.isArray(witness)) {
493
+ throw new Error("KFD-3 pre-build witness must be a JSON object");
494
+ }
495
+ const standard = optionalString(witness.standard || metadata.key);
496
+ if (standard && standard !== metadata.key && standard !== metadata.id && standard !== metadata.label) {
497
+ throw new Error(`KFD-3 witness standard must match ${metadata.key}`);
498
+ }
499
+ const declaredSurfaces = declaredSurfacesFromWitness(witness).map((surface, index) => normalizeKfd3Surface(surface, index, "declaredSurfaces"));
500
+ if (declaredSurfaces.length === 0) {
501
+ throw new Error("KFD-3 pre-build witness must declare at least one collaboration/control surface");
502
+ }
503
+ const registry = normalizeRegistry(witness.registry || witness.sourceRegistry || witness.source_registry || witness.collaborationInterface?.sourceRegistry || witness.collaboration_interface?.sourceRegistry);
504
+ const closure = witness.collaborationInterface?.closure || witness.collaboration_interface?.closure || {};
505
+ const auditBoundary = normalizeKfd3AuditBoundary(witness.auditBoundary || witness.audit_boundary || closure, { closure });
506
+ const expectedArtifactVerification = witness.expectedArtifactVerification && typeof witness.expectedArtifactVerification === "object" && !Array.isArray(witness.expectedArtifactVerification)
507
+ ? { ...witness.expectedArtifactVerification, command: optionalString(witness.expectedArtifactVerification.command) }
508
+ : { command: optionalString(witness.artifactVerifyCommand || witness.artifact_verify_command) };
509
+ return {
510
+ schemaVersion: 1,
511
+ contract: KFD3_PREBUILD_WITNESS_CONTRACT,
512
+ id: nonEmptyString(witness.id, "KFD-3 pre-build witness id"),
513
+ standard: metadata.key,
514
+ standardLabel: metadata.label,
515
+ supportLevel: optionalString(witness.supportLevel || witness.support_level || witness.support?.level || "release"),
516
+ source: witness.source && typeof witness.source === "object" && !Array.isArray(witness.source)
517
+ ? { ...witness.source }
518
+ : {},
519
+ registry,
520
+ participantProfiles: normalizeStringArray(
521
+ witness.participantProfiles ||
522
+ witness.participant_profiles ||
523
+ witness.profiles ||
524
+ witness.collaborationInterface?.participants?.map((entry) => entry.id || entry.name) ||
525
+ witness.collaboration_interface?.participants?.map((entry) => entry.id || entry.name),
526
+ ),
527
+ expectedArtifactVerification,
528
+ collaborationInterfaceDigest: optionalString(
529
+ witness.collaborationInterfaceDigest ||
530
+ witness.collaboration_interface_digest ||
531
+ witness.collaborationInterface?.digest ||
532
+ witness.collaboration_interface?.digest,
533
+ ),
534
+ auditBoundary,
535
+ residualRisk: normalizeKfd3ResidualRisk(
536
+ witness.residualRisk || witness.residual_risk || witness.auditBoundary?.residualRisk || witness.audit_boundary?.residual_risk || [],
537
+ { auditBoundary },
538
+ ),
539
+ responsibility: normalizeKfd3Responsibility(witness.responsibility || witness.owners, {
540
+ registry,
541
+ artifactVerifyCommand: expectedArtifactVerification.command,
542
+ }),
543
+ declaredSurfaces,
544
+ metadata: {
545
+ kfdPackage: metadata.package,
546
+ schemaIds: metadata.schemaIds,
547
+ schemaPaths: metadata.schemaPaths,
548
+ hasCollaborationSchemas: Boolean(metadata.hasCollaborationSchemas),
549
+ },
550
+ };
551
+ }
552
+
553
+ export function normalizeKfd3CollaborationInterfaceArtifactWitness(witness, { metadata = resolveKfd3Metadata() } = {}) {
554
+ if (!witness || typeof witness !== "object" || Array.isArray(witness)) {
555
+ throw new Error("KFD-3 artifact witness must be a JSON object");
556
+ }
557
+ const standard = optionalString(witness.standard || metadata.key);
558
+ if (standard && standard !== metadata.key && standard !== metadata.id && standard !== metadata.label) {
559
+ throw new Error(`KFD-3 artifact witness standard must match ${metadata.key}`);
560
+ }
561
+ const exposedSurfaces = artifactSurfacesFromWitness(witness).map((surface, index) => normalizeKfd3Surface(surface, index, "exposedSurfaces"));
562
+ return {
563
+ schemaVersion: 1,
564
+ contract: KFD3_ARTIFACT_WITNESS_CONTRACT,
565
+ id: nonEmptyString(witness.id, "KFD-3 artifact witness id"),
566
+ standard: metadata.key,
567
+ standardLabel: metadata.label,
568
+ artifact: normalizeArtifactIdentity(witness.artifact),
569
+ registry: normalizeRegistry(witness.registry || witness.sourceRegistry || witness.source_registry),
570
+ collaborationInterfaceDigest: optionalString(
571
+ witness.collaborationInterfaceDigest ||
572
+ witness.collaboration_interface_digest ||
573
+ witness.collaborationInterface?.digest ||
574
+ witness.collaboration_interface?.digest,
575
+ ),
576
+ exposedSurfaces,
577
+ verifier: witness.verifier && typeof witness.verifier === "object" && !Array.isArray(witness.verifier)
578
+ ? { ...witness.verifier }
579
+ : {},
580
+ metadata: {
581
+ kfdPackage: metadata.package,
582
+ schemaIds: metadata.schemaIds,
583
+ schemaPaths: metadata.schemaPaths,
584
+ hasCollaborationSchemas: Boolean(metadata.hasCollaborationSchemas),
585
+ },
586
+ };
587
+ }
588
+
589
+ function isParticipantPublic(surface) {
590
+ return Boolean(surface.public && surface.participantFacing);
591
+ }
592
+
593
+ function isDeclaredShipped(surface) {
594
+ return ["shipped", "stable", "available", "ga", "production"].includes(surface.availability);
595
+ }
596
+
597
+ function isDeclaredPublic(surface) {
598
+ return isParticipantPublic(surface) && !["internal", "unsupported", "not-shipped", "not_shipped"].includes(surface.availability);
599
+ }
600
+
601
+ function idSet(surfaces) {
602
+ return new Set(surfaces.map((surface) => surface.id));
603
+ }
604
+
605
+ function sortedSetDiff(left, right) {
606
+ return [...left].filter((entry) => !right.has(entry)).sort();
607
+ }
608
+
609
+ function kfd3ReleaseStatus({ comparisonStatus, supportLevel, residualRisk = [] } = {}) {
610
+ if (comparisonStatus === "passed") {
611
+ return residualRisk.length > 0 ? "audited" : "enforced";
612
+ }
613
+ if (["draft", "partial", "missing", "unsupported"].includes(supportLevel)) {
614
+ return "draft";
615
+ }
616
+ return "declared";
617
+ }
618
+
619
+ function kfd3TrustResult(comparisonStatus) {
620
+ if (comparisonStatus === "passed") return "pass";
621
+ if (comparisonStatus === "downgraded") return "downgraded";
622
+ return "fail";
623
+ }
624
+
625
+ function kfd3TrustStatement({
626
+ comparisonStatus,
627
+ missingDeclaredShipped = [],
628
+ unclassifiedArtifactPublic = [],
629
+ residualRisk = [],
630
+ } = {}) {
631
+ if (comparisonStatus === "passed") {
632
+ return unclassifiedArtifactPublic.length === 0
633
+ ? "No unclassified reachable surface within the declared audit boundary."
634
+ : "Unclassified reachable surfaces remain within the declared audit boundary.";
635
+ }
636
+ if (missingDeclaredShipped.length > 0) {
637
+ return "One or more declared shipped public surfaces are missing from the artifact evidence.";
638
+ }
639
+ if (unclassifiedArtifactPublic.length > 0) {
640
+ return "The artifact exposes participant-facing public surfaces not declared by the pre-build witness.";
641
+ }
642
+ if (residualRisk.length > 0) {
643
+ return "KFD-3 proof is downgraded and residual risks remain explicit.";
644
+ }
645
+ return "KFD-3 collaboration-interface proof did not pass.";
646
+ }
647
+
648
+ function evidenceDescriptor({ path = "", sha256 = "", canonicalSha256 = "" } = {}) {
649
+ return {
650
+ path: optionalString(path),
651
+ sha256: optionalString(sha256),
652
+ canonicalSha256: optionalString(canonicalSha256),
653
+ };
654
+ }
655
+
656
+ function kfd1SurfacesFromWitness(witness = {}) {
657
+ return [
658
+ ...(Array.isArray(witness.surfaces) ? witness.surfaces : []),
659
+ ...groupedKfd1SurfacesFromSource(witness),
660
+ ...groupedKfd1SurfacesFromSource(witness.standardContract),
661
+ ...groupedKfd1SurfacesFromSource(witness.standard_contract),
662
+ ...groupedKfd1SurfacesFromSource(witness.selfContract),
663
+ ...groupedKfd1SurfacesFromSource(witness.self_contract),
664
+ ...groupedKfd1SurfacesFromSource(witness.contractWorld),
665
+ ];
666
+ }
667
+
668
+ function normalizeKfd1SelfHostingBoundary(value = {}, { contractWorld = {} } = {}) {
669
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
670
+ return {
671
+ mode: optionalString(source.mode || (source.enabled || contractWorld.selfHosted ? "self-hosted-standard-contract" : "external-contract-world")),
672
+ sourceScope: optionalString(source.sourceScope || source.source_scope || "KFD source standard metadata, schemas, package exports, and site-consumption entrypoints"),
673
+ artifactScope: optionalString(source.artifactScope || source.artifact_scope || "packaged public artifact surfaces"),
674
+ boundary: optionalString(source.boundary || "source-to-artifact byte equality for declared standard-contract surfaces"),
675
+ residualRisk: normalizeStringObjectArray(
676
+ source.residualRisk || source.residual_risk || source.nonEnumerableResidualRisk || source.non_enumerable_residual_risk || [],
677
+ "selfHostingBoundary.residualRisk",
678
+ ),
679
+ };
680
+ }
681
+
682
+ function normalizeKfd1Responsibility(value = {}, { contractWorld = {} } = {}) {
683
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
684
+ return {
685
+ sourceContractOwner: optionalString(source.sourceContractOwner || source.source_contract_owner || source.standardOwner || source.standard_owner || contractWorld.owner || "product"),
686
+ artifactVerificationOwner: optionalString(source.artifactVerificationOwner || source.artifact_verification_owner || "buildchain-release-passport"),
687
+ releasePassportProofOwner: optionalString(source.releasePassportProofOwner || source.release_passport_proof_owner || "buildchain"),
688
+ };
689
+ }
690
+
691
+ function normalizeKfd1StandardContract(value = {}, { metadata = resolveKfd1Metadata() } = {}) {
692
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
693
+ return {
694
+ id: optionalString(source.id || source.name),
695
+ schemaId: optionalString(source.schemaId || source.schema_id || metadata.schemaIds.contractWorld),
696
+ path: source.path ? normalizePath(source.path, "standardContract.path") : "",
697
+ sha256: source.sha256 ? normalizeHash(source.sha256, "standardContract.sha256") : "",
698
+ digest: optionalString(source.digest || (source.sha256 ? `sha256:${normalizeHash(source.sha256, "standardContract.sha256")}` : "")),
699
+ };
700
+ }
701
+
161
702
  export function normalizeKfd1ContractWorldWitness(witness, { metadata = resolveKfd1Metadata() } = {}) {
162
703
  if (!witness || typeof witness !== "object" || Array.isArray(witness)) {
163
704
  throw new Error("KFD-1 witness must be a JSON object");
164
705
  }
165
- const surfaces = Array.isArray(witness.surfaces)
166
- ? witness.surfaces.map((surface, index) => normalizeSurface(surface, index))
167
- : [];
706
+ const surfaces = kfd1SurfacesFromWitness(witness).map((surface, index) => normalizeSurface(surface, index));
168
707
  if (surfaces.length === 0) {
169
708
  throw new Error("KFD-1 witness surfaces[] must include at least one artifact surface");
170
709
  }
@@ -191,6 +730,14 @@ export function normalizeKfd1ContractWorldWitness(witness, { metadata = resolveK
191
730
  schemaId: metadata.schemaIds.contractWorld,
192
731
  digest: "",
193
732
  },
733
+ standardContract: normalizeKfd1StandardContract(witness.standardContract || witness.standard_contract || witness.selfContract || witness.self_contract || witness.contractWorld, { metadata }),
734
+ selfHostingBoundary: normalizeKfd1SelfHostingBoundary(witness.selfHostingBoundary || witness.self_hosting_boundary, {
735
+ contractWorld: witness.contractWorld,
736
+ }),
737
+ responsibility: normalizeKfd1Responsibility(witness.responsibility || witness.owners, {
738
+ contractWorld: witness.contractWorld,
739
+ }),
740
+ sourceVerificationRequired: Boolean(witness.standardContract || witness.standard_contract || witness.selfContract || witness.self_contract || witness.selfHostingBoundary || witness.self_hosting_boundary),
194
741
  canonicalPolicy: normalizeEvidenceFile(witness.canonicalPolicy || witness.canonical_policy, "canonicalPolicy"),
195
742
  registry: normalizeEvidenceFile(witness.registry, "registry"),
196
743
  surfaces,
@@ -224,6 +771,14 @@ function resolveArtifactFile({ cwd, artifactRoot, artifacts = [], artifactPath }
224
771
  return candidates.find((candidate) => candidate && fs.existsSync(candidate) && fs.statSync(candidate).isFile()) || "";
225
772
  }
226
773
 
774
+ function resolveSourceFile({ cwd, sourcePath }) {
775
+ if (!sourcePath) {
776
+ return "";
777
+ }
778
+ const candidate = path.resolve(cwd, sourcePath);
779
+ return fs.existsSync(candidate) && fs.statSync(candidate).isFile() ? candidate : "";
780
+ }
781
+
227
782
  export function createKfd1ReleaseGateEvidence({
228
783
  cwd = process.cwd(),
229
784
  artifactRoot = "",
@@ -238,6 +793,39 @@ export function createKfd1ReleaseGateEvidence({
238
793
  }
239
794
  const worlds = normalizedWitnesses.map((witness) => {
240
795
  const preBuildWitnessSha256 = sha256Json(witness);
796
+ const sourceResults = witness.surfaces.map((surface) => {
797
+ if (!surface.sourcePath || !surface.sourceSha256) {
798
+ return {
799
+ name: surface.name,
800
+ sourcePath: surface.sourcePath,
801
+ expectedSha256: surface.sourceSha256,
802
+ actualSha256: "",
803
+ status: witness.sourceVerificationRequired ? "failed" : "not-declared",
804
+ reason: witness.sourceVerificationRequired ? "source-digest-not-declared" : "",
805
+ };
806
+ }
807
+ const filePath = resolveSourceFile({ cwd, sourcePath: surface.sourcePath });
808
+ if (!filePath) {
809
+ return {
810
+ name: surface.name,
811
+ sourcePath: surface.sourcePath,
812
+ expectedSha256: surface.sourceSha256,
813
+ actualSha256: "",
814
+ status: witness.sourceVerificationRequired ? "failed" : "unavailable",
815
+ reason: "source-missing",
816
+ };
817
+ }
818
+ const actualSha256 = sha256File(filePath);
819
+ const passed = actualSha256 === surface.sourceSha256;
820
+ return {
821
+ name: surface.name,
822
+ sourcePath: surface.sourcePath,
823
+ expectedSha256: surface.sourceSha256,
824
+ actualSha256,
825
+ status: passed ? "passed" : "failed",
826
+ reason: passed ? "" : "source-digest-mismatch",
827
+ };
828
+ });
241
829
  const surfaceResults = witness.surfaces.map((surface) => {
242
830
  const filePath = resolveArtifactFile({
243
831
  cwd,
@@ -248,6 +836,8 @@ export function createKfd1ReleaseGateEvidence({
248
836
  if (!filePath) {
249
837
  return {
250
838
  name: surface.name,
839
+ sourcePath: surface.sourcePath,
840
+ sourceSha256: surface.sourceSha256,
251
841
  artifactPath: surface.artifactPath,
252
842
  expectedSha256: surface.expectedSha256,
253
843
  actualSha256: "",
@@ -260,6 +850,8 @@ export function createKfd1ReleaseGateEvidence({
260
850
  const passed = actualSha256 === surface.expectedSha256;
261
851
  return {
262
852
  name: surface.name,
853
+ sourcePath: surface.sourcePath,
854
+ sourceSha256: surface.sourceSha256,
263
855
  artifactPath: surface.artifactPath,
264
856
  expectedSha256: surface.expectedSha256,
265
857
  actualSha256,
@@ -269,12 +861,35 @@ export function createKfd1ReleaseGateEvidence({
269
861
  };
270
862
  });
271
863
  const status = surfaceResults.every((surface) => surface.status === "passed") ? "passed" : "failed";
864
+ const sourceStatus = sourceResults.every((surface) => ["passed", "not-declared", "unavailable"].includes(surface.status)) &&
865
+ (!witness.sourceVerificationRequired || sourceResults.every((surface) => surface.status === "passed"))
866
+ ? "passed"
867
+ : "failed";
868
+ const worldStatus = status === "passed" && sourceStatus === "passed" ? "passed" : "failed";
272
869
  return {
273
870
  id: witness.id,
274
871
  standard: metadata.label,
275
872
  standardKey: metadata.key,
873
+ result: worldStatus,
276
874
  preBuildWitnessSha256,
875
+ sourceHashes: {
876
+ sha256: sha256Json(sourceResults),
877
+ surfaceCount: sourceResults.length,
878
+ },
879
+ artifactHashes: {
880
+ sha256: sha256Json(surfaceResults),
881
+ surfaceCount: surfaceResults.length,
882
+ },
277
883
  witness,
884
+ standardContract: witness.standardContract,
885
+ selfHostingBoundary: witness.selfHostingBoundary,
886
+ responsibility: witness.responsibility,
887
+ sourceVerification: {
888
+ status: sourceStatus,
889
+ verifiedAt,
890
+ required: Boolean(witness.sourceVerificationRequired),
891
+ surfaces: sourceResults,
892
+ },
278
893
  artifactVerification: {
279
894
  status,
280
895
  verifiedAt,
@@ -282,13 +897,21 @@ export function createKfd1ReleaseGateEvidence({
282
897
  },
283
898
  };
284
899
  });
285
- const status = worlds.every((world) => world.artifactVerification.status === "passed") ? "passed" : "failed";
900
+ const status = worlds.every((world) => world.result === "passed") ? "passed" : "failed";
286
901
  return {
287
902
  key: metadata.key,
288
903
  passportSection: {
289
904
  schemaVersion: 1,
290
905
  contract: KFD1_RELEASE_GATE_CONTRACT,
291
906
  status,
907
+ selfContractVerification: {
908
+ result: status === "passed" ? "pass" : "fail",
909
+ contractWorldCount: worlds.length,
910
+ selfHosted: worlds.some((world) => world.sourceVerification.required),
911
+ responsibility: {
912
+ proofOwner: "buildchain-release-passport",
913
+ },
914
+ },
292
915
  metadata: {
293
916
  standard: {
294
917
  key: metadata.key,
@@ -311,6 +934,207 @@ export function createKfd1ReleaseGateEvidence({
311
934
  };
312
935
  }
313
936
 
937
+ export function createKfd3CollaborationInterfaceReleaseGateEvidence({
938
+ prebuildWitnesses = [],
939
+ artifactWitnesses = [],
940
+ prebuildWitnessMetas = [],
941
+ artifactWitnessMetas = [],
942
+ artifactCommandMeta = undefined,
943
+ verifiedAt = new Date().toISOString(),
944
+ metadata = resolveKfd3Metadata(),
945
+ } = {}) {
946
+ const normalizedPrebuildWitnesses = (prebuildWitnesses || [])
947
+ .filter(Boolean)
948
+ .map((witness) => normalizeKfd3CollaborationInterfacePrebuildWitness(witness, { metadata }));
949
+ if (normalizedPrebuildWitnesses.length === 0) {
950
+ return undefined;
951
+ }
952
+ const normalizedArtifactWitnesses = (artifactWitnesses || [])
953
+ .filter(Boolean)
954
+ .map((witness) => normalizeKfd3CollaborationInterfaceArtifactWitness(witness, { metadata }));
955
+ const artifactById = new Map(normalizedArtifactWitnesses.map((witness) => [witness.id, witness]));
956
+ const singleArtifactWitness = normalizedArtifactWitnesses.length === 1 ? normalizedArtifactWitnesses[0] : undefined;
957
+ const prebuildMetaById = new Map((prebuildWitnessMetas || [])
958
+ .filter((meta) => meta?.value?.id)
959
+ .map((meta) => [meta.value.id, meta]));
960
+ const artifactMetaById = new Map((artifactWitnessMetas || [])
961
+ .filter((meta) => meta?.value?.id)
962
+ .map((meta) => [meta.value.id, meta]));
963
+ const singleArtifactMeta = (artifactWitnessMetas || []).filter((meta) => meta?.value).length === 1
964
+ ? (artifactWitnessMetas || []).find((meta) => meta?.value)
965
+ : undefined;
966
+ const worlds = normalizedPrebuildWitnesses.map((prebuildWitness) => {
967
+ const artifactWitness = artifactById.get(prebuildWitness.id) || singleArtifactWitness;
968
+ const prebuildMeta = prebuildMetaById.get(prebuildWitness.id) || {};
969
+ const artifactMeta = artifactWitness ? (artifactMetaById.get(artifactWitness.id) || singleArtifactMeta || artifactCommandMeta || {}) : {};
970
+ const preBuildWitnessSha256 = sha256Json(prebuildWitness);
971
+ const artifactWitnessSha256 = artifactWitness ? sha256Json(artifactWitness) : "";
972
+ const declaredPublic = prebuildWitness.declaredSurfaces.filter(isDeclaredPublic);
973
+ const declaredShippedPublic = declaredPublic.filter(isDeclaredShipped);
974
+ const artifactPublic = artifactWitness
975
+ ? artifactWitness.exposedSurfaces.filter(isParticipantPublic)
976
+ : [];
977
+ const declaredPublicIds = idSet(declaredPublic);
978
+ const declaredShippedIds = idSet(declaredShippedPublic);
979
+ const artifactPublicIds = idSet(artifactPublic);
980
+ const missingDeclaredShipped = sortedSetDiff(declaredShippedIds, artifactPublicIds);
981
+ const unclassifiedArtifactPublic = sortedSetDiff(artifactPublicIds, declaredPublicIds);
982
+ const reasons = [];
983
+ if (!metadata.hasCollaborationSchemas) {
984
+ reasons.push("kfd-metadata-schema-missing");
985
+ }
986
+ if (!artifactWitness) {
987
+ reasons.push("artifact-witness-missing");
988
+ }
989
+ if (
990
+ prebuildWitness.collaborationInterfaceDigest &&
991
+ artifactWitness?.collaborationInterfaceDigest &&
992
+ prebuildWitness.collaborationInterfaceDigest !== artifactWitness.collaborationInterfaceDigest
993
+ ) {
994
+ reasons.push("collaboration-interface-digest-mismatch");
995
+ }
996
+ if (missingDeclaredShipped.length > 0) {
997
+ reasons.push("declared-shipped-surface-missing");
998
+ }
999
+ if (unclassifiedArtifactPublic.length > 0) {
1000
+ reasons.push("artifact-public-surface-not-declared");
1001
+ }
1002
+ const supportLevel = prebuildWitness.supportLevel || "release";
1003
+ if (["draft", "partial", "missing", "unsupported"].includes(supportLevel)) {
1004
+ reasons.push(`support-level-${supportLevel}`);
1005
+ }
1006
+ const status = reasons.length === 0 ? "passed" : supportLevel === "release" ? "failed" : "downgraded";
1007
+ const residualRisk = prebuildWitness.residualRisk || [];
1008
+ const releaseStatus = kfd3ReleaseStatus({ comparisonStatus: status, supportLevel, residualRisk });
1009
+ const trustResult = kfd3TrustResult(status);
1010
+ const declaredCapabilityVerification = {
1011
+ status,
1012
+ result: missingDeclaredShipped.length === 0 ? "passed" : "failed",
1013
+ declaredCapabilityCount: declaredPublic.length,
1014
+ declaredShippedPublicSurfaceCount: declaredShippedPublic.length,
1015
+ implementedPublicSurfaceCount: artifactPublic.length,
1016
+ missingDeclaredShipped,
1017
+ };
1018
+ const reverseAudit = {
1019
+ status: unclassifiedArtifactPublic.length === 0 ? "passed" : "failed",
1020
+ auditBoundary: prebuildWitness.auditBoundary,
1021
+ reachablePublicSurfaceCount: artifactPublic.length,
1022
+ unclassifiedReachableSurfaces: unclassifiedArtifactPublic,
1023
+ explicitlyExemptedSurfaces: prebuildWitness.auditBoundary.explicitlyExemptedSurfaces,
1024
+ nonExhaustivelyEnumerableSurfaces: prebuildWitness.auditBoundary.nonExhaustivelyEnumerableSurfaces,
1025
+ statement: unclassifiedArtifactPublic.length === 0
1026
+ ? "No unclassified reachable surface within the declared audit boundary."
1027
+ : "Unclassified reachable surfaces were found within the declared audit boundary.",
1028
+ };
1029
+ const witnessEvidence = {
1030
+ prebuild: evidenceDescriptor({
1031
+ path: prebuildMeta.path,
1032
+ sha256: prebuildMeta.sha256,
1033
+ canonicalSha256: preBuildWitnessSha256,
1034
+ }),
1035
+ artifact: evidenceDescriptor({
1036
+ path: artifactMeta.path,
1037
+ sha256: artifactMeta.sha256,
1038
+ canonicalSha256: artifactWitnessSha256,
1039
+ }),
1040
+ artifactVerifyCommandSha256: optionalString(artifactCommandMeta?.sha256),
1041
+ };
1042
+ return {
1043
+ id: prebuildWitness.id,
1044
+ standard: metadata.label,
1045
+ standardKey: metadata.key,
1046
+ preBuildWitnessSha256,
1047
+ artifactWitnessSha256,
1048
+ prebuildWitness,
1049
+ artifactWitness: artifactWitness || undefined,
1050
+ declaredSurfaces: prebuildWitness.declaredSurfaces,
1051
+ exposedSurfaces: artifactPublic,
1052
+ factSource: {
1053
+ role: "product-owned",
1054
+ registry: prebuildWitness.registry,
1055
+ collaborationInterfaceDigest: prebuildWitness.collaborationInterfaceDigest,
1056
+ },
1057
+ witnessEvidence,
1058
+ auditBoundary: prebuildWitness.auditBoundary,
1059
+ residualRisk,
1060
+ responsibility: prebuildWitness.responsibility,
1061
+ releaseStatus,
1062
+ trustProof: {
1063
+ contract: "kungfu-buildchain-kfd-3-passport-trust-proof",
1064
+ result: trustResult,
1065
+ releaseStatus,
1066
+ statement: kfd3TrustStatement({
1067
+ comparisonStatus: status,
1068
+ missingDeclaredShipped,
1069
+ unclassifiedArtifactPublic,
1070
+ residualRisk,
1071
+ }),
1072
+ factSourceRole: "product-owned-registry-and-witnesses",
1073
+ proofOwner: "buildchain-release-passport",
1074
+ declaredCapabilityVerification,
1075
+ reverseAudit,
1076
+ residualRisk,
1077
+ responsibility: prebuildWitness.responsibility,
1078
+ },
1079
+ declaredCapabilityVerification,
1080
+ reverseAudit,
1081
+ comparison: {
1082
+ status,
1083
+ verifiedAt,
1084
+ supportLevel,
1085
+ declaredPublicSurfaceCount: declaredPublic.length,
1086
+ declaredShippedPublicSurfaceCount: declaredShippedPublic.length,
1087
+ artifactPublicSurfaceCount: artifactPublic.length,
1088
+ missingDeclaredShipped,
1089
+ unclassifiedArtifactPublic,
1090
+ reasons,
1091
+ },
1092
+ };
1093
+ });
1094
+ const status = worlds.every((world) => world.comparison.status === "passed") ? "passed" : "failed";
1095
+ const releaseStatuses = [...new Set(worlds.map((world) => world.releaseStatus))];
1096
+ const trustResult = status === "passed" ? "pass" : worlds.some((world) => world.trustProof.result === "downgraded") ? "downgraded" : "fail";
1097
+ return {
1098
+ key: metadata.key,
1099
+ passportSection: {
1100
+ schemaVersion: 1,
1101
+ contract: KFD3_RELEASE_GATE_CONTRACT,
1102
+ status,
1103
+ releaseStatus: releaseStatuses.length === 1 ? releaseStatuses[0] : status === "passed" ? "audited" : "declared",
1104
+ trustProof: {
1105
+ contract: "kungfu-buildchain-kfd-3-passport-trust-proof",
1106
+ result: trustResult,
1107
+ statement: status === "passed"
1108
+ ? "No unclassified reachable surface within the declared audit boundary."
1109
+ : "One or more KFD-3 collaboration-interface witness pairs failed or downgraded.",
1110
+ factSourceRole: "product-owned-registry-and-witnesses",
1111
+ proofOwner: "buildchain-release-passport",
1112
+ collaborationInterfaceCount: worlds.length,
1113
+ audited: worlds.every((world) => world.trustProof.result === "pass"),
1114
+ },
1115
+ metadata: {
1116
+ standard: {
1117
+ key: metadata.key,
1118
+ id: metadata.id,
1119
+ label: metadata.label,
1120
+ title: metadata.title,
1121
+ revision: metadata.revision,
1122
+ status: metadata.status,
1123
+ },
1124
+ schemas: {
1125
+ ids: metadata.schemaIds,
1126
+ paths: metadata.schemaPaths,
1127
+ metadata: metadata.metadataSchema,
1128
+ hasCollaborationSchemas: Boolean(metadata.hasCollaborationSchemas),
1129
+ },
1130
+ package: metadata.package,
1131
+ },
1132
+ formatting: BUILDCHAIN_JSON_FORMATTING_POLICY,
1133
+ collaborationInterfaces: worlds,
1134
+ },
1135
+ };
1136
+ }
1137
+
314
1138
  export function validateKfd1ReleaseGateEvidence(section, { metadata = resolveKfd1Metadata() } = {}) {
315
1139
  const issues = [];
316
1140
  if (!section) {
@@ -367,6 +1191,38 @@ export function validateKfd1ReleaseGateEvidence(section, { metadata = resolveKfd
367
1191
  details: { expected: metadata.key, actual: world.standardKey || "" },
368
1192
  });
369
1193
  }
1194
+ if (!world.sourceHashes?.sha256 || !world.artifactHashes?.sha256) {
1195
+ issues.push({
1196
+ level: "error",
1197
+ code: `${metadata.key}.contractWorlds[${worldIndex}].hashes`,
1198
+ message: "KFD-1 self contract evidence must record source and artifact hash summaries",
1199
+ details: { id: world.id || "" },
1200
+ });
1201
+ }
1202
+ if (!world.selfHostingBoundary || typeof world.selfHostingBoundary !== "object" || Array.isArray(world.selfHostingBoundary)) {
1203
+ issues.push({
1204
+ level: "error",
1205
+ code: `${metadata.key}.contractWorlds[${worldIndex}].selfHostingBoundary`,
1206
+ message: "KFD-1 contract world must record the self-hosting boundary",
1207
+ details: { id: world.id || "" },
1208
+ });
1209
+ }
1210
+ if (!world.responsibility?.sourceContractOwner || !world.responsibility?.artifactVerificationOwner || !world.responsibility?.releasePassportProofOwner) {
1211
+ issues.push({
1212
+ level: "error",
1213
+ code: `${metadata.key}.contractWorlds[${worldIndex}].responsibility`,
1214
+ message: "KFD-1 contract world must record source, artifact verification, and passport proof owners",
1215
+ details: { id: world.id || "" },
1216
+ });
1217
+ }
1218
+ if (world.sourceVerification?.required && world.sourceVerification?.status !== "passed") {
1219
+ issues.push({
1220
+ level: "error",
1221
+ code: `${metadata.key}.contractWorlds[${worldIndex}].sourceVerification`,
1222
+ message: "KFD-1 self contract source verification must pass before release passport finalization",
1223
+ details: { id: world.id || "", status: world.sourceVerification?.status || "" },
1224
+ });
1225
+ }
370
1226
  if (world.artifactVerification?.status !== "passed") {
371
1227
  issues.push({
372
1228
  level: "error",
@@ -411,3 +1267,207 @@ export function validateKfd1ReleaseGateEvidence(section, { metadata = resolveKfd
411
1267
  }
412
1268
  return issues;
413
1269
  }
1270
+
1271
+ export function validateKfd3CollaborationInterfaceReleaseGateEvidence(section, { metadata = resolveKfd3Metadata() } = {}) {
1272
+ const issues = [];
1273
+ if (!section) {
1274
+ return issues;
1275
+ }
1276
+ if (typeof section !== "object" || Array.isArray(section)) {
1277
+ issues.push({
1278
+ level: "error",
1279
+ code: `${metadata.key}.object`,
1280
+ message: `${metadata.key} collaboration-interface evidence must be an object`,
1281
+ details: {},
1282
+ });
1283
+ return issues;
1284
+ }
1285
+ if (section.contract !== KFD3_RELEASE_GATE_CONTRACT) {
1286
+ issues.push({
1287
+ level: "error",
1288
+ code: `${metadata.key}.contract`,
1289
+ message: `${metadata.key}.contract must be ${KFD3_RELEASE_GATE_CONTRACT}`,
1290
+ details: {},
1291
+ });
1292
+ }
1293
+ if (section.metadata?.standard?.key !== metadata.key) {
1294
+ issues.push({
1295
+ level: "error",
1296
+ code: `${metadata.key}.metadata.standard.key`,
1297
+ message: `${metadata.key} metadata key must come from the KFD metadata package`,
1298
+ details: { expected: metadata.key, actual: section.metadata?.standard?.key || "" },
1299
+ });
1300
+ }
1301
+ if (!section.metadata?.schemas?.hasCollaborationSchemas) {
1302
+ issues.push({
1303
+ level: "error",
1304
+ code: `${metadata.key}.metadata.schemas.collaborationInterface`,
1305
+ message: "KFD-3 release evidence requires KFD package metadata for collaboration-interface and witness schemas",
1306
+ details: { package: metadata.package, schemaIds: section.metadata?.schemas?.ids || {} },
1307
+ });
1308
+ }
1309
+ const interfaces = Array.isArray(section.collaborationInterfaces) ? section.collaborationInterfaces : [];
1310
+ if (interfaces.length === 0) {
1311
+ issues.push({
1312
+ level: "error",
1313
+ code: `${metadata.key}.collaborationInterfaces.empty`,
1314
+ message: `${metadata.key}.collaborationInterfaces must include at least one witness pair`,
1315
+ details: {},
1316
+ });
1317
+ }
1318
+ if (!section.trustProof || typeof section.trustProof !== "object" || Array.isArray(section.trustProof)) {
1319
+ issues.push({
1320
+ level: "error",
1321
+ code: `${metadata.key}.trustProof`,
1322
+ message: "KFD-3 release evidence must include a release-passport trust proof summary",
1323
+ details: {},
1324
+ });
1325
+ } else {
1326
+ const allowedStatuses = new Set(["not-applicable", "declared", "draft", "audited", "enforced"]);
1327
+ if (!allowedStatuses.has(section.releaseStatus)) {
1328
+ issues.push({
1329
+ level: "error",
1330
+ code: `${metadata.key}.releaseStatus`,
1331
+ message: "KFD-3 release status must be not-applicable, declared, draft, audited, or enforced",
1332
+ details: { status: section.releaseStatus || "" },
1333
+ });
1334
+ }
1335
+ if (!["pass", "fail", "downgraded"].includes(section.trustProof.result)) {
1336
+ issues.push({
1337
+ level: "error",
1338
+ code: `${metadata.key}.trustProof.result`,
1339
+ message: "KFD-3 trust proof result must be pass, fail, or downgraded",
1340
+ details: { result: section.trustProof.result || "" },
1341
+ });
1342
+ }
1343
+ }
1344
+ for (const [index, entry] of interfaces.entries()) {
1345
+ if (!entry.preBuildWitnessSha256) {
1346
+ issues.push({
1347
+ level: "error",
1348
+ code: `${metadata.key}.collaborationInterfaces[${index}].preBuildWitnessSha256`,
1349
+ message: "KFD-3 collaboration-interface evidence must record the frozen pre-build witness digest",
1350
+ details: {},
1351
+ });
1352
+ }
1353
+ if (!entry.artifactWitnessSha256) {
1354
+ issues.push({
1355
+ level: "error",
1356
+ code: `${metadata.key}.collaborationInterfaces[${index}].artifactWitnessSha256`,
1357
+ message: "KFD-3 collaboration-interface evidence must record the artifact-side witness digest",
1358
+ details: { id: entry.id || "" },
1359
+ });
1360
+ }
1361
+ if (entry.standardKey !== metadata.key) {
1362
+ issues.push({
1363
+ level: "error",
1364
+ code: `${metadata.key}.collaborationInterfaces[${index}].standardKey`,
1365
+ message: "KFD-3 collaboration-interface standardKey must match KFD metadata",
1366
+ details: { expected: metadata.key, actual: entry.standardKey || "" },
1367
+ });
1368
+ }
1369
+ const comparison = entry.comparison || {};
1370
+ if (comparison.status !== "passed") {
1371
+ issues.push({
1372
+ level: "error",
1373
+ code: `${metadata.key}.collaborationInterfaces[${index}].comparison`,
1374
+ message: "KFD-3 collaboration-interface artifact closure verification must pass before release passport finalization",
1375
+ details: {
1376
+ id: entry.id || "",
1377
+ status: comparison.status || "",
1378
+ reasons: comparison.reasons || [],
1379
+ },
1380
+ });
1381
+ }
1382
+ if (Array.isArray(comparison.missingDeclaredShipped) && comparison.missingDeclaredShipped.length > 0) {
1383
+ issues.push({
1384
+ level: "error",
1385
+ code: `${metadata.key}.collaborationInterfaces[${index}].missingDeclaredShipped`,
1386
+ message: "KFD-3 artifact is missing declared shipped public surfaces",
1387
+ details: { id: entry.id || "", surfaces: comparison.missingDeclaredShipped },
1388
+ });
1389
+ }
1390
+ if (Array.isArray(comparison.unclassifiedArtifactPublic) && comparison.unclassifiedArtifactPublic.length > 0) {
1391
+ issues.push({
1392
+ level: "error",
1393
+ code: `${metadata.key}.collaborationInterfaces[${index}].unclassifiedArtifactPublic`,
1394
+ message: "KFD-3 artifact exposes public participant-facing surfaces not declared by the pre-build witness",
1395
+ details: { id: entry.id || "", surfaces: comparison.unclassifiedArtifactPublic },
1396
+ });
1397
+ }
1398
+ if (!entry.trustProof || typeof entry.trustProof !== "object" || Array.isArray(entry.trustProof)) {
1399
+ issues.push({
1400
+ level: "error",
1401
+ code: `${metadata.key}.collaborationInterfaces[${index}].trustProof`,
1402
+ message: "KFD-3 collaboration-interface evidence must include a trust proof",
1403
+ details: { id: entry.id || "" },
1404
+ });
1405
+ } else {
1406
+ if (entry.trustProof.result === "pass" && comparison.status !== "passed") {
1407
+ issues.push({
1408
+ level: "error",
1409
+ code: `${metadata.key}.collaborationInterfaces[${index}].trustProof.result`,
1410
+ message: "KFD-3 trust proof cannot pass when closure comparison did not pass",
1411
+ details: { id: entry.id || "", result: entry.trustProof.result, comparisonStatus: comparison.status || "" },
1412
+ });
1413
+ }
1414
+ if (!entry.trustProof.declaredCapabilityVerification) {
1415
+ issues.push({
1416
+ level: "error",
1417
+ code: `${metadata.key}.collaborationInterfaces[${index}].trustProof.declaredCapabilityVerification`,
1418
+ message: "KFD-3 trust proof must record declared capability verification",
1419
+ details: { id: entry.id || "" },
1420
+ });
1421
+ }
1422
+ if (!entry.trustProof.reverseAudit) {
1423
+ issues.push({
1424
+ level: "error",
1425
+ code: `${metadata.key}.collaborationInterfaces[${index}].trustProof.reverseAudit`,
1426
+ message: "KFD-3 trust proof must record reverse audit results",
1427
+ details: { id: entry.id || "" },
1428
+ });
1429
+ }
1430
+ }
1431
+ if (!entry.witnessEvidence?.prebuild?.canonicalSha256 || !entry.witnessEvidence?.artifact?.canonicalSha256) {
1432
+ issues.push({
1433
+ level: "error",
1434
+ code: `${metadata.key}.collaborationInterfaces[${index}].witnessEvidence`,
1435
+ message: "KFD-3 trust proof must record pre-build and artifact witness hashes",
1436
+ details: { id: entry.id || "" },
1437
+ });
1438
+ }
1439
+ if (!entry.auditBoundary || typeof entry.auditBoundary !== "object" || Array.isArray(entry.auditBoundary)) {
1440
+ issues.push({
1441
+ level: "error",
1442
+ code: `${metadata.key}.collaborationInterfaces[${index}].auditBoundary`,
1443
+ message: "KFD-3 trust proof must record the reverse audit boundary",
1444
+ details: { id: entry.id || "" },
1445
+ });
1446
+ }
1447
+ if (!Array.isArray(entry.residualRisk)) {
1448
+ issues.push({
1449
+ level: "error",
1450
+ code: `${metadata.key}.collaborationInterfaces[${index}].residualRisk`,
1451
+ message: "KFD-3 trust proof must record residual risk as an array, even when empty",
1452
+ details: { id: entry.id || "" },
1453
+ });
1454
+ }
1455
+ if (!entry.responsibility?.registryFactsOwner || !entry.responsibility?.artifactVerificationOwner || !entry.responsibility?.releasePassportProofOwner) {
1456
+ issues.push({
1457
+ level: "error",
1458
+ code: `${metadata.key}.collaborationInterfaces[${index}].responsibility`,
1459
+ message: "KFD-3 trust proof must record registry, artifact verification, and passport proof owners",
1460
+ details: { id: entry.id || "" },
1461
+ });
1462
+ }
1463
+ }
1464
+ if (section.status !== "passed") {
1465
+ issues.push({
1466
+ level: "error",
1467
+ code: `${metadata.key}.status`,
1468
+ message: "KFD-3 collaboration-interface release gate status must be passed",
1469
+ details: { status: section.status || "" },
1470
+ });
1471
+ }
1472
+ return issues;
1473
+ }