@kungfu-tech/buildchain 4.0.2-alpha.44 → 4.0.2-alpha.46

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 (42) hide show
  1. package/architecture/agent-change-map.md +1 -1
  2. package/architecture/maintainability-debt.json +24 -25
  3. package/architecture/maintainability-policy.json +4 -4
  4. package/architecture/v4-release-topology.json +9 -6
  5. package/architecture/v4-universal-workflow-train-admission.json +1 -1
  6. package/dist/site/buildchain-contract.json +7 -7
  7. package/dist/site/buildchain-site.json +55 -14
  8. package/dist/site/capability-registry.json +2 -2
  9. package/dist/site/kfd-claims.json +29 -5
  10. package/dist/site/kfd-upstream-aggregate.json +1 -1
  11. package/dist/site/manual-registry.json +3 -3
  12. package/dist/site/node-api-registry.json +154 -13
  13. package/dist/site/page-registry.json +48 -7
  14. package/dist/site/public-surface-audit.json +7 -3
  15. package/dist/site/publication-authority-registry.json +5 -17
  16. package/dist/site/publication-registry.json +4 -4
  17. package/dist/site/release-provenance.json +2 -1
  18. package/dist/site/site-manifest.json +7 -7
  19. package/dist/site/workflow-registry.json +5 -5
  20. package/docs/MAP.md +1 -0
  21. package/docs/node-api-reference.md +26 -15
  22. package/docs/oci-publication.md +82 -0
  23. package/docs/publish-transaction.md +36 -3
  24. package/package.json +3 -2
  25. package/packages/core/buildchain-v4-domain.wasm +0 -0
  26. package/packages/core/next-development-transition.js +5 -6
  27. package/packages/core/oci-publication-bundle.js +241 -0
  28. package/packages/core/publication-sealed-bundle.js +77 -13
  29. package/packages/core/release-tail-product-capabilities.js +9 -0
  30. package/packages/core/v4-canonical-contracts.js +1 -0
  31. package/packages/core/v4-domain-wasm-artifact.js +2 -2
  32. package/packages/core/v4-product-publication.js +2 -0
  33. package/scripts/check-v4-release-topology.mjs +14 -4
  34. package/scripts/generate-channel-promotion-workflow.mjs +2 -19
  35. package/scripts/generate-v4-universal-workflow-facades.mjs +8 -2
  36. package/scripts/publication-candidate-kind.mjs +92 -0
  37. package/scripts/publication-candidate-sealer.mjs +16 -1
  38. package/scripts/release-candidate-resolver.mjs +6 -17
  39. package/scripts/resume-from-candidate-run.mjs +10 -17
  40. package/scripts/site-capability-metadata.mjs +1 -0
  41. package/scripts/v4-product-publication-intent.mjs +9 -1
  42. package/scripts/v4-universal-workflow-engine.mjs +2 -0
@@ -7,7 +7,7 @@ import { execFileSync } from "node:child_process";
7
7
  import { Readable } from "node:stream";
8
8
  import { pipeline } from "node:stream/promises";
9
9
  import { pathToFileURL } from "node:url";
10
- import { createResolvedPublicationSealedBundle } from "./publication-candidate-sealer.mjs";
10
+ import { resolveCandidatePublicationBundle } from "./publication-candidate-sealer.mjs";
11
11
  import { writeGitHubOutputs } from "./build-contract-core.mjs";
12
12
  import { v4ContentRoot } from "../packages/core/v4-canonical-contracts.js";
13
13
  import { v4PublicationQualificationRoot, validateV4PublicationQualificationReceipt } from "../packages/core/v4-publication-qualification.js";
@@ -725,23 +725,12 @@ export async function resolveReleaseCandidateArtifacts({
725
725
  const noun = publishArtifactKind === "npm" ? "npm package tarballs" : "platform manifests";
726
726
  throw new Error(`expected at least ${minimumPayloadCount} downloaded ${noun}, found ${downloadedRequiredArtifactCount}`);
727
727
  }
728
- const sealedBundle = publishArtifactKind === "npm"
729
- ? createResolvedPublicationSealedBundle({
730
- bundleRoot: payloadDir,
731
- repository: repoInfo.fullName,
732
- sourceSha: passport.source?.headSha,
733
- sourceTreeSha: passport.source?.treeHash,
734
- runtimeSha: releaseCandidateRuntimeSha(passport),
735
- releaseCandidateRoot: passport.candidateHash,
736
- npmArtifacts: npmTarballPaths.map((tarballPath) => ({
737
- path: tarballPath,
738
- ...readNpmPackageArtifact({ tarballPath, mainPackage: publishPackageMain }),
739
- })),
740
- releaseAssetPaths,
741
- })
742
- : undefined;
728
+ const sealedBundle = resolveCandidatePublicationBundle({ kind: publishArtifactKind, payloadDir, passport,
729
+ runtimeSha: releaseCandidateRuntimeSha(passport), releaseAssetPaths,
730
+ npmArtifacts: npmTarballPaths.map((tarballPath) => ({ path: tarballPath,
731
+ ...readNpmPackageArtifact({ tarballPath, mainPackage: publishPackageMain }) })) });
743
732
  const manifests = platformManifestPaths.map((manifestPath) => JSON.parse(fs.readFileSync(manifestPath, "utf8"))), publicationVersion = resolveFreshPublicationVersion({ sealedBundle, candidateVersion: passport.target?.version });
744
- const generatedRequiredArtifacts = generatePublishRequiredArtifacts({
733
+ const generatedRequiredArtifacts = sealedBundle?.requiredArtifacts || generatePublishRequiredArtifacts({
745
734
  manifests,
746
735
  version: publicationVersion,
747
736
  kind: publishArtifactKind,
@@ -6,6 +6,8 @@ import path from "node:path";
6
6
  import { execFileSync } from "node:child_process";
7
7
  import { fileURLToPath, pathToFileURL } from "node:url";
8
8
 
9
+ import { resolveOciCandidate, resolveRecoveredPublicationVersion, resolveRecoveredCandidateVersion } from "./publication-candidate-kind.mjs";
10
+ export { resolveRecoveredPublicationVersion, resolveRecoveredCandidateVersion } from "./publication-candidate-kind.mjs";
9
11
  import { writeGitHubOutputs } from "./build-contract-core.mjs";
10
12
  import { compareSemver } from "./publication-registry-hydrate.mjs";
11
13
  import { normalizeAnchorProvenance, normalizeCandidateRun, recoverCandidateProvenance } from "./release-candidate-anchor-provenance.mjs";
@@ -695,22 +697,6 @@ export function createRecoveredPublicationCandidate({
695
697
  };
696
698
  return { ...payload, candidateDigest: publicationArtifactCandidateDigest(payload) };
697
699
  }
698
- export function resolveRecoveredPublicationVersion({ artifactVersion, channel, rematerializeOnResume = false } = {}) {
699
- const version = String(artifactVersion || "").trim(), match = version.match(/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u);
700
- if (!match) throw new Error(`recovered npm artifact has invalid publication version: ${version || "<empty>"}`);
701
- return channel === "release" && rematerializeOnResume ? match[1] : version;
702
- }
703
- export function resolveRecoveredCandidateVersion({ artifactVersion, publicationVersion, channel, rematerializeOnResume = false, targetRef = "", candidateRef = "" } = {}) {
704
- const version = String(artifactVersion || "").trim(), target = String(targetRef || "").replace(/^refs\/heads\//u, ""), candidate = String(candidateRef || "").replace(/^refs\/heads\//u, "");
705
- if (channel !== "release" || !rematerializeOnResume) return version;
706
- const prefix = `publish-gate/${target}/`;
707
- if (!target || !candidate.startsWith(prefix)) throw new Error(`stable recovery candidate ref must descend from ${prefix || "publish-gate/<target>/"}`);
708
- const candidateVersion = candidate.slice(prefix.length);
709
- if (!/^\d+\.\d+\.\d+-alpha\.\d+$/u.test(candidateVersion)) throw new Error(`stable recovery candidate ref must bind an exact alpha version, got ${candidateVersion || "<empty>"}`);
710
- if (candidateVersion.replace(/-alpha\.\d+$/u, "") !== publicationVersion) throw new Error(`stable recovery candidate ${candidateVersion} does not match publication ${publicationVersion || "<empty>"}`);
711
- if ((version.match(/^(\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u)?.[1] || "") !== publicationVersion) throw new Error(`recovered npm artifact version ${version || "<empty>"} does not match publication ${publicationVersion}`);
712
- return candidateVersion;
713
- }
714
700
  export function createRecoveredPublication({ downloads, bundleRoot, repository, passport, candidateRuntimeSha, publishArtifactKind, publishPackageMain, releasePatterns, platformManifests, channel, targetRef = "", candidateRef = "", rematerializeOnResume = false }) {
715
701
  const allFiles = downloads.flatMap((download) => download.files.map((file) => ({ path: path.relative(bundleRoot, file.absolutePath).split(path.sep).join("/"),
716
702
  size: file.size, sha256: file.sha256.replace(/^sha256:/, ""), absolutePath: file.absolutePath })))
@@ -718,6 +704,13 @@ export function createRecoveredPublication({ downloads, bundleRoot, repository,
718
704
  const kind = String(publishArtifactKind || "npm");
719
705
  const releaseMatchers = splitPatterns(releasePatterns).map(patternMatcher);
720
706
  const releaseAssets = allFiles.filter((file) => releaseMatchers.some((matcher) => matcher.test(path.basename(file.path))));
707
+ if (kind === "oci") {
708
+ createRecoveredPublicationCandidate({ allFiles, repository, passport, candidateRuntimeSha });
709
+ const sealed = resolveOciCandidate({ payloadRoot: bundleRoot, passport });
710
+ return { manifest: sealed.manifest, bundleRoot: sealed.root, npmArtifacts: [], allFiles, releaseAssets,
711
+ version: sealed.manifest.version, candidateVersion: sealed.manifest.version,
712
+ publishRequiredArtifacts: sealed.requiredArtifacts };
713
+ }
721
714
  if (kind !== "npm") {
722
715
  createRecoveredPublicationCandidate({ allFiles, repository, passport, candidateRuntimeSha });
723
716
  const version = String(passport.target?.version || "").trim();
@@ -1019,7 +1012,7 @@ export async function resumeFromCandidateRun({
1019
1012
  npmTarballs: tarballs,
1020
1013
  releaseAssets: publication.releaseAssets.map((asset) => outputPath(asset.absolutePath)),
1021
1014
  publishRequiredArtifacts: outputPath(requiredArtifactsPath),
1022
- sealedBundleRoot: publication.manifest ? outputPath(bundleRoot) : "",
1015
+ sealedBundleRoot: publication.manifest ? outputPath(publication.bundleRoot || bundleRoot) : "",
1023
1016
  sealedBundleManifest: publication.manifest ? outputPath(sealedManifestPath) : "",
1024
1017
  recoveryReceipt: outputPath(recoveryReceiptPath),
1025
1018
  stageCapsules: stageCapsuleFile ? outputPath(stageCapsuleFile.absolutePath) : "",
@@ -206,6 +206,7 @@ export function nodeApiMeta(exportName) {
206
206
  "./publication-artifact": { group: "reusable-build", summary: "Publication artifact manifest, source bundle, and publication passport APIs." },
207
207
  "./publication-package": { group: "reusable-build", summary: "Publication npm package synthesis APIs for Buildchain-managed paper release presets." },
208
208
  "./publication-reproducibility": { group: "reusable-build", summary: "Two-clean-build publication byte reproducibility receipt APIs." },
209
+ "./oci-publication": { group: "reusable-build", summary: "Sealed OCI image family verification, provenance, and smoke evidence APIs." },
209
210
  "./publication-sealed-bundle": { group: "reusable-build", summary: "Build-once publication bundle manifests and exact-byte resume verification APIs." },
210
211
  "./paper": { group: "reusable-build", summary: "Unified Paper work, fleet, scaffold, preflight, npm bootstrap, build, Alpha, status, and resume planning APIs." },
211
212
  "./publication-authority": { group: "release-passport-trust", summary: "Sealed publication authority registry, runner provenance, control-plane audit, admission, and independent verification APIs." },
@@ -65,7 +65,7 @@ export function resolveV4ProductPublicationIntent() {
65
65
  const sourceSha = env("BUILDCHAIN_SOURCE_SHA", true);
66
66
  const manifestPath = env(
67
67
  "BUILDCHAIN_SEALED_BUNDLE_MANIFEST",
68
- artifactKind === "npm",
68
+ artifactKind !== "custom",
69
69
  );
70
70
  const manifest = manifestPath ? readJson(manifestPath) : null;
71
71
  const requiredArtifacts = readJson(
@@ -80,6 +80,14 @@ export function resolveV4ProductPublicationIntent() {
80
80
  repository: env("BUILDCHAIN_REPOSITORY", true),
81
81
  artifactKind,
82
82
  packageName: name,
83
+ ...(manifest?.npmPackages
84
+ ? {
85
+ npmPackages: manifest.npmPackages.map((entry) => ({
86
+ ...entry,
87
+ sha256: `sha256:${entry.sha256}`,
88
+ })),
89
+ }
90
+ : {}),
83
91
  distTag:
84
92
  env("BUILDCHAIN_PUBLISH_DIST_TAG") ||
85
93
  (channel === "alpha" ? "alpha" : "latest"),
@@ -306,6 +306,7 @@ async function materializeProductPublicationIntent({
306
306
  BUILDCHAIN_SEALED_BUNDLE_MANIFEST: candidate.paths.sealedBundleManifest,
307
307
  BUILDCHAIN_REQUIRED_ARTIFACTS_PATH:
308
308
  candidate.paths.publishRequiredArtifacts,
309
+ BUILDCHAIN_PUBLISH_ARTIFACT_KIND: inputs["publish-artifact-kind"] || "npm",
309
310
  BUILDCHAIN_PUBLISH_PACKAGE_MAIN: inputs["publish-package-main"] || "",
310
311
  BUILDCHAIN_PUBLISH_DIST_TAG: inputs["publish-dist-tag"] || "",
311
312
  BUILDCHAIN_PRODUCT_PUBLICATION_INTENT_PATH: intentPath,
@@ -449,6 +450,7 @@ async function executeReleasePromotion(request, admission) {
449
450
  "candidate-build-summary-path": candidate.paths.buildSummary,
450
451
  "stage-capsules-path": candidate.paths.stageCapsules,
451
452
  "publication-qualification-path": candidate.paths.publicationQualification,
453
+ "publish-artifact-kind": payload.inputs["publish-artifact-kind"] || "npm",
452
454
  "sealed-bundle-root": candidate.paths.sealedBundleRoot,
453
455
  "sealed-bundle-manifest": candidate.paths.sealedBundleManifest,
454
456
  "required-artifacts-path": candidate.paths.publishRequiredArtifacts,