@kungfu-tech/buildchain 4.0.1-alpha.5 → 4.0.1-alpha.8

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 (108) hide show
  1. package/actions/release-tail/README.md +8 -0
  2. package/architecture/ci-lane-change-budget.json +187 -0
  3. package/architecture/internal-capabilities.json +65 -5
  4. package/architecture/maintainability-policy.json +27 -21
  5. package/architecture/release-tail-contract-inventory.json +5 -2
  6. package/architecture/v4-adopter-delivery-parity.json +32 -5
  7. package/architecture/v4-floating-consumer-policy.json +6 -0
  8. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  9. package/bin/buildchain.mjs +7 -1
  10. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  11. package/bin/internal/command-registry.mjs +1 -0
  12. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  13. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  14. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  15. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  16. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  17. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  18. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  19. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  20. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  21. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  22. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  23. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  24. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  25. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  26. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  27. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  28. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +4 -2
  29. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  30. package/dist/site/agent-index.json +3 -0
  31. package/dist/site/artifact-schemas.json +6 -0
  32. package/dist/site/buildchain-contract.json +14 -14
  33. package/dist/site/buildchain-site.json +231 -24
  34. package/dist/site/capability-registry.json +11 -10
  35. package/dist/site/cli-registry.json +53 -1
  36. package/dist/site/kfd-claims.json +279 -14
  37. package/dist/site/kfd-upstream-aggregate.json +1 -1
  38. package/dist/site/manual-registry.json +20 -5
  39. package/dist/site/node-api-registry.json +11569 -9299
  40. package/dist/site/page-registry.json +214 -15
  41. package/dist/site/public-surface-audit.json +206 -11
  42. package/dist/site/publication-authority-registry.json +39 -8
  43. package/dist/site/publication-registry.json +4 -4
  44. package/dist/site/release-provenance.json +15 -0
  45. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  46. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  47. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  48. package/dist/site/site-manifest.json +17 -9
  49. package/dist/site/workflow-registry.json +110 -8
  50. package/docs/MAP.md +3 -1
  51. package/docs/cli-reference.md +68 -0
  52. package/docs/cli.md +8 -0
  53. package/docs/dev-delivery-warrant.md +22 -1
  54. package/docs/node-api-reference.md +332 -172
  55. package/docs/release-tail-provider-plane.md +30 -0
  56. package/docs/v4-adopter-delivery.md +133 -0
  57. package/docs/v4-publication-rehearsal.md +130 -0
  58. package/package.json +18 -3
  59. package/packages/core/adopter-delivery-passport.js +259 -0
  60. package/packages/core/adopter-delivery-vectors.js +158 -0
  61. package/packages/core/adopter-delivery-vectors.json +77 -0
  62. package/packages/core/buildchain-agent-manuals.js +1 -0
  63. package/packages/core/buildchain-config.js +84 -0
  64. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  65. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  66. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  67. package/packages/core/buildchain-publication-authority.js +1 -0
  68. package/packages/core/ci-lane-change-budget.js +247 -0
  69. package/packages/core/dev-delivery-native-proof.js +43 -27
  70. package/packages/core/dev-delivery-warrant-state.js +31 -8
  71. package/packages/core/dev-delivery-warrant.js +8 -3
  72. package/packages/core/github-governance-authority.js +1 -0
  73. package/packages/core/index.js +5 -0
  74. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  75. package/packages/core/published-delivery-authority.js +266 -0
  76. package/packages/core/release-candidate-recovery.js +66 -11
  77. package/packages/core/release-candidate.js +2 -2
  78. package/packages/core/release-passport.js +36 -9
  79. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  80. package/packages/core/v4-adopter-delivery.js +359 -0
  81. package/packages/core/v4-delivery-warrant-read-candidate.js +10 -3
  82. package/packages/core/v4-floating-consumer-evidence.js +18 -4
  83. package/packages/core/v4-floating-consumer-policy.js +138 -35
  84. package/packages/core/v4-floating-consumer-release-passport.js +30 -3
  85. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  86. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  87. package/packages/core/v4-publication-rehearsal.js +481 -0
  88. package/packages/core/workflow-yaml-contract.js +24 -2
  89. package/scripts/buildchain-cli-help.mjs +10 -0
  90. package/scripts/check-ci-lane-change-budget.mjs +100 -0
  91. package/scripts/check-inventory.mjs +3 -3
  92. package/scripts/check-v4-floating-consumer-policy-contract.mjs +23 -4
  93. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  94. package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
  95. package/scripts/dev-delivery-warrant-store.mjs +10 -6
  96. package/scripts/dev-delivery-warrant.mjs +5 -1
  97. package/scripts/dev-pr-delivery-warrant.mjs +1 -0
  98. package/scripts/dev-qualification-patrol.mjs +9 -9
  99. package/scripts/generate-channel-promotion-workflow.mjs +2 -2
  100. package/scripts/generate-release-candidate-passport.mjs +152 -0
  101. package/scripts/generate-site-bundle.mjs +30 -0
  102. package/scripts/promotion-channel-router.mjs +4 -4
  103. package/scripts/release-candidate-anchor-provenance.mjs +99 -0
  104. package/scripts/release-tail.mjs +51 -3
  105. package/scripts/resume-from-candidate-run.mjs +556 -29
  106. package/scripts/site-capability-metadata.mjs +17 -0
  107. package/scripts/v4-consumer-policy.mjs +4 -0
  108. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
@@ -0,0 +1,158 @@
1
+ import vectorSuite from "./adopter-delivery-vectors.json" with { type: "json" };
2
+
3
+ import { adopterDeliveryGateDigest } from "./adopter-delivery-gate.js";
4
+
5
+ export const ADOPTER_DELIVERY_VECTOR_SUITE_CONTRACT =
6
+ "kungfu-buildchain-adopter-delivery-vectors/v1";
7
+
8
+ const ROOT_PATTERN = /^sha256:[0-9a-f]{64}$/;
9
+ const REQUIRED_CASES = new Map([
10
+ ["golden-two-driver-offline-replay", "golden"],
11
+ ["negative-driver-mismatch", "negative"],
12
+ ["negative-category-conflict", "negative"],
13
+ ["negative-evidence-substitution", "negative"],
14
+ ["negative-stale-package-cut", "negative"],
15
+ ["fault-driver-throw", "fault"],
16
+ ]);
17
+
18
+ function freezeJson(value) {
19
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
20
+ Object.freeze(value);
21
+ for (const child of Object.values(value)) freezeJson(child);
22
+ }
23
+ return value;
24
+ }
25
+
26
+ function issue(code, path, message) {
27
+ return { code, path, message };
28
+ }
29
+
30
+ function suiteDigest(suite) {
31
+ const preimage = structuredClone(suite);
32
+ delete preimage.suiteRoot;
33
+ return adopterDeliveryGateDigest(preimage);
34
+ }
35
+
36
+ export function validateAdopterDeliveryVectorSuite(suite) {
37
+ const issues = [];
38
+ if (!suite || typeof suite !== "object" || Array.isArray(suite)) {
39
+ return {
40
+ valid: false,
41
+ issues: [
42
+ issue(
43
+ "adopter-delivery-vectors.invalid",
44
+ "/",
45
+ "Vector suite must be a JSON object.",
46
+ ),
47
+ ],
48
+ };
49
+ }
50
+ if (
51
+ suite.schemaVersion !== 1 ||
52
+ suite.contract !== ADOPTER_DELIVERY_VECTOR_SUITE_CONTRACT
53
+ ) {
54
+ issues.push(
55
+ issue(
56
+ "adopter-delivery-vectors.contract",
57
+ "/contract",
58
+ "Vector suite contract is unsupported.",
59
+ ),
60
+ );
61
+ }
62
+ if (!Array.isArray(suite.cases)) {
63
+ issues.push(
64
+ issue(
65
+ "adopter-delivery-vectors.cases",
66
+ "/cases",
67
+ "Vector suite cases must be an array.",
68
+ ),
69
+ );
70
+ } else {
71
+ const seen = new Set();
72
+ for (const [index, entry] of suite.cases.entries()) {
73
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
74
+ issues.push(
75
+ issue(
76
+ "adopter-delivery-vectors.case",
77
+ `/cases/${index}`,
78
+ "Vector case must be an object.",
79
+ ),
80
+ );
81
+ continue;
82
+ }
83
+ if (typeof entry.id !== "string" || seen.has(entry.id)) {
84
+ issues.push(
85
+ issue(
86
+ "adopter-delivery-vectors.case-id",
87
+ `/cases/${index}/id`,
88
+ "Vector case id must be non-empty and unique.",
89
+ ),
90
+ );
91
+ }
92
+ seen.add(entry.id);
93
+ if (!entry.expected || typeof entry.expected !== "object") {
94
+ issues.push(
95
+ issue(
96
+ "adopter-delivery-vectors.expected",
97
+ `/cases/${index}/expected`,
98
+ "Vector case must declare its expected result.",
99
+ ),
100
+ );
101
+ }
102
+ }
103
+ for (const [id, className] of REQUIRED_CASES) {
104
+ const entry = suite.cases.find((candidate) => candidate?.id === id);
105
+ if (!entry || entry.class !== className) {
106
+ issues.push(
107
+ issue(
108
+ "adopter-delivery-vectors.required-case",
109
+ "/cases",
110
+ `Required ${className} vector ${id} is missing.`,
111
+ ),
112
+ );
113
+ }
114
+ }
115
+ }
116
+ if (!ROOT_PATTERN.test(suite.suiteRoot ?? "")) {
117
+ issues.push(
118
+ issue(
119
+ "adopter-delivery-vectors.root",
120
+ "/suiteRoot",
121
+ "Vector suite root must be a canonical sha256 root.",
122
+ ),
123
+ );
124
+ } else {
125
+ try {
126
+ if (suiteDigest(suite) !== suite.suiteRoot) {
127
+ issues.push(
128
+ issue(
129
+ "adopter-delivery-vectors.root",
130
+ "/suiteRoot",
131
+ "Vector suite root does not match the exact JSON closure.",
132
+ ),
133
+ );
134
+ }
135
+ } catch {
136
+ issues.push(
137
+ issue(
138
+ "adopter-delivery-vectors.root",
139
+ "/suiteRoot",
140
+ "Vector suite must contain finite acyclic JSON.",
141
+ ),
142
+ );
143
+ }
144
+ }
145
+ return { valid: issues.length === 0, issues };
146
+ }
147
+
148
+ export const ADOPTER_DELIVERY_VECTOR_SUITE = freezeJson(
149
+ structuredClone(vectorSuite),
150
+ );
151
+
152
+ export function getAdopterDeliveryVector(id) {
153
+ const entry = ADOPTER_DELIVERY_VECTOR_SUITE.cases.find(
154
+ (candidate) => candidate.id === id,
155
+ );
156
+ if (!entry) throw new RangeError(`Unknown adopter delivery vector: ${id}`);
157
+ return structuredClone(entry);
158
+ }
@@ -0,0 +1,77 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "contract": "kungfu-buildchain-adopter-delivery-vectors/v1",
4
+ "rootAlgorithm": "sha256-buildchain-canonical-json-v1",
5
+ "authorities": {
6
+ "kfdPackage": "@kungfu-tech/kfd@1.0.0-alpha.65",
7
+ "categoryProfileVectors": "@kungfu-tech/kfd/adopter-conformance/category-profile-vectors.json",
8
+ "categoryInstanceVectors": "@kungfu-tech/kfd/adopter-conformance/category-instance-vectors.json"
9
+ },
10
+ "cases": [
11
+ {
12
+ "id": "golden-two-driver-offline-replay",
13
+ "class": "golden",
14
+ "surface": "protocol-neutral-gate",
15
+ "operation": "evaluate identical exact requests with two isolated protocol drivers and replay each request offline",
16
+ "expected": {
17
+ "statuses": ["passed", "passed"],
18
+ "issueCodes": [],
19
+ "deterministicRoots": true,
20
+ "qualifying": false,
21
+ "selfCertified": false
22
+ }
23
+ },
24
+ {
25
+ "id": "negative-driver-mismatch",
26
+ "class": "negative",
27
+ "surface": "protocol-neutral-gate",
28
+ "operation": "select an exact protocol identity and version that are not registered",
29
+ "expected": {
30
+ "status": "failed",
31
+ "issueCodes": ["delivery-driver-unknown"]
32
+ }
33
+ },
34
+ {
35
+ "id": "negative-category-conflict",
36
+ "class": "negative",
37
+ "surface": "published-kfd-category-driver",
38
+ "operation": "append a duplicate published category profile to the exact KFD instance selection",
39
+ "expected": {
40
+ "status": "failed",
41
+ "issueCodes": ["acp-composition-invalid"]
42
+ }
43
+ },
44
+ {
45
+ "id": "negative-evidence-substitution",
46
+ "class": "negative",
47
+ "surface": "release-passport-binding",
48
+ "operation": "substitute the artifact root in artifact evidence after binding the passport",
49
+ "expected": {
50
+ "status": "failed",
51
+ "issueCodes": ["adopterDelivery.artifactEvidence"]
52
+ }
53
+ },
54
+ {
55
+ "id": "negative-stale-package-cut",
56
+ "class": "negative",
57
+ "surface": "published-kfd-category-driver",
58
+ "operation": "replace the KFD instance package version with an uninstalled stale cut",
59
+ "expected": {
60
+ "status": "failed",
61
+ "issueCodes": ["delivery-kfd-package-cut-mismatch"]
62
+ }
63
+ },
64
+ {
65
+ "id": "fault-driver-throw",
66
+ "class": "fault",
67
+ "surface": "protocol-neutral-gate",
68
+ "operation": "throw a private exception from the selected protocol driver",
69
+ "expected": {
70
+ "status": "failed",
71
+ "issueCodes": ["delivery-driver-error"],
72
+ "privateDetailRedacted": true
73
+ }
74
+ }
75
+ ],
76
+ "suiteRoot": "sha256:c978707556406ffda4ef4192032332c01c2da1cebb6ad8c4f0edfc65d5cef0c7"
77
+ }
@@ -30,6 +30,7 @@ export const BUILDCHAIN_AGENT_MANUALS = Object.freeze([
30
30
  { id: "kfd-agent-hub", title: "KFD Agent Hub Builder flow", path: "docs/kfd-agent-hub.md", plane: "use" },
31
31
  { id: "lifecycle-protocol", title: "Lifecycle protocol", path: "docs/lifecycle-protocol.md", plane: "use" },
32
32
  { id: "reusable-build-surface", title: "Reusable build surface", path: "docs/reusable-build-surface.md", plane: "use" },
33
+ { id: "v4-adopter-delivery", title: "V4 public adopter delivery", path: "docs/v4-adopter-delivery.md", plane: "verify" },
33
34
  { id: "publish-transaction", title: "Publish transaction", path: "docs/publish-transaction.md", plane: "verify" },
34
35
  { id: "release-tail-contract", title: "Declarative release-tail contract", path: "docs/release-tail-contract.md", plane: "verify" },
35
36
  { id: "release-tail-provider-plane", title: "Declarative release-tail provider plane", path: "docs/release-tail-provider-plane.md", plane: "use" },
@@ -236,6 +236,16 @@ export function normalizeBuildchainConfig(config) {
236
236
  if (normalized.publication !== undefined) {
237
237
  normalized.publication = normalizePublicationSection(normalized.publication);
238
238
  }
239
+ if (normalized.publication_rehearsal !== undefined) {
240
+ normalized.publication_rehearsal = normalizePublicationRehearsalSection(
241
+ normalized.publication_rehearsal,
242
+ );
243
+ }
244
+ if (normalized.adopter_delivery !== undefined) {
245
+ normalized.adopter_delivery = normalizeAdopterDeliverySection(
246
+ normalized.adopter_delivery,
247
+ );
248
+ }
239
249
  if (normalized.consumers !== undefined) {
240
250
  normalized.consumers = normalizeConsumersSection(normalized.consumers);
241
251
  }
@@ -700,6 +710,80 @@ function normalizePublicationSection(publication) {
700
710
  };
701
711
  }
702
712
 
713
+ function normalizePublicationRehearsalSection(rehearsal) {
714
+ assertPlainObject(rehearsal, "publication_rehearsal");
715
+ const allowed = ["contract", "capsule_path", "candidate_root", "state_path", "evidence_path", "effect_default"];
716
+ const unknown = Object.keys(rehearsal).filter((key) => !allowed.includes(key));
717
+ if (unknown.length > 0) {
718
+ throw new Error(`publication_rehearsal contains unsupported fields: ${unknown.join(", ")}`);
719
+ }
720
+ const normalized = {
721
+ contract: assertString(rehearsal.contract, "publication_rehearsal.contract"),
722
+ capsulePath: posixPath(assertString(rehearsal.capsule_path, "publication_rehearsal.capsule_path")),
723
+ candidateRoot: posixPath(assertString(rehearsal.candidate_root, "publication_rehearsal.candidate_root")),
724
+ statePath: posixPath(assertString(rehearsal.state_path, "publication_rehearsal.state_path")),
725
+ evidencePath: posixPath(assertString(rehearsal.evidence_path, "publication_rehearsal.evidence_path")),
726
+ effectDefault: assertString(rehearsal.effect_default, "publication_rehearsal.effect_default"),
727
+ };
728
+ if (
729
+ normalized.contract !== "buildchain-v4-publication-rehearsal-capsule/v1" ||
730
+ normalized.effectDefault !== "disabled"
731
+ ) {
732
+ throw new Error("publication_rehearsal must use the v4 capsule contract with effect_default = disabled");
733
+ }
734
+ for (const [key, value] of Object.entries({
735
+ capsule_path: normalized.capsulePath,
736
+ candidate_root: normalized.candidateRoot,
737
+ state_path: normalized.statePath,
738
+ evidence_path: normalized.evidencePath,
739
+ })) {
740
+ if (value.startsWith("/") || value.includes("\\") || value.split("/").includes("..")) {
741
+ throw new Error(`publication_rehearsal.${key} must be repository-relative`);
742
+ }
743
+ }
744
+ return normalized;
745
+ }
746
+
747
+ function normalizeAdopterDeliverySection(delivery) {
748
+ assertPlainObject(delivery, "adopter_delivery");
749
+ const allowed = ["contract", "input_path", "readback_path", "bootstrap_path", "archive_path", "result_path", "driver_selector", "artifact_profile_selector"];
750
+ const unknown = Object.keys(delivery).filter((key) => !allowed.includes(key));
751
+ if (unknown.length > 0) {
752
+ throw new Error(`adopter_delivery contains unsupported fields: ${unknown.join(", ")}`);
753
+ }
754
+ const normalized = {
755
+ contract: assertString(delivery.contract, "adopter_delivery.contract"),
756
+ inputPath: posixPath(assertString(delivery.input_path, "adopter_delivery.input_path")),
757
+ readbackPath: posixPath(assertString(delivery.readback_path, "adopter_delivery.readback_path")),
758
+ bootstrapPath: posixPath(assertString(delivery.bootstrap_path, "adopter_delivery.bootstrap_path")),
759
+ archivePath: posixPath(assertString(delivery.archive_path, "adopter_delivery.archive_path")),
760
+ resultPath: posixPath(assertString(delivery.result_path, "adopter_delivery.result_path")),
761
+ driverSelector: assertString(delivery.driver_selector, "adopter_delivery.driver_selector"),
762
+ artifactProfileSelector: assertString(delivery.artifact_profile_selector, "adopter_delivery.artifact_profile_selector"),
763
+ };
764
+ if (normalized.contract !== "kungfu-buildchain-v4-adopter-delivery/v1") {
765
+ throw new Error("adopter_delivery contract is unsupported");
766
+ }
767
+ if (
768
+ !["json-assertion", "kfd-category", "legacy-kfd"].includes(normalized.driverSelector) ||
769
+ !["git-commit", "package"].includes(normalized.artifactProfileSelector)
770
+ ) {
771
+ throw new Error("adopter_delivery selector is unsupported");
772
+ }
773
+ for (const [key, value] of Object.entries({
774
+ input_path: normalized.inputPath,
775
+ readback_path: normalized.readbackPath,
776
+ bootstrap_path: normalized.bootstrapPath,
777
+ archive_path: normalized.archivePath,
778
+ result_path: normalized.resultPath,
779
+ })) {
780
+ if (value.startsWith("/") || value.includes("\\") || value.split("/").includes("..")) {
781
+ throw new Error(`adopter_delivery.${key} must be repository-relative`);
782
+ }
783
+ }
784
+ return normalized;
785
+ }
786
+
703
787
  function normalizePublicationArchive(archive = undefined) {
704
788
  if (archive === undefined) {
705
789
  return undefined;
@@ -0,0 +1,240 @@
1
+ import { adopterDeliveryGateDigest } from "./adopter-delivery-gate.js";
2
+ import { validateAdopterDeliveryGateResult } from "./adopter-delivery-passport.js";
3
+
4
+ export const BUILDCHAIN_DELIVERY_BOOTSTRAP_CONTRACT =
5
+ "kungfu-buildchain-delivery-infrastructure-bootstrap/v1";
6
+
7
+ const ROOT_PATTERN = /^sha256:[0-9a-f]{64}$/;
8
+ const SHA_PATTERN = /^[0-9a-f]{40}$/;
9
+ const SEMVER_PATTERN =
10
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
11
+
12
+ function issue(code, message) {
13
+ return { code, message };
14
+ }
15
+
16
+ function exactRoot(value) {
17
+ return ROOT_PATTERN.test(value ?? "");
18
+ }
19
+
20
+ function exactCut(cut) {
21
+ return (
22
+ cut &&
23
+ typeof cut === "object" &&
24
+ typeof cut.version === "string" &&
25
+ SHA_PATTERN.test(cut.sourceCommit ?? "") &&
26
+ exactRoot(cut.packageRoot) &&
27
+ exactRoot(cut.gateRoot) &&
28
+ typeof cut.protocol?.id === "string" &&
29
+ typeof cut.protocol?.version === "string" &&
30
+ exactRoot(cut.protocol?.root) &&
31
+ typeof cut.profile?.id === "string" &&
32
+ typeof cut.profile?.version === "string" &&
33
+ exactRoot(cut.profile?.root)
34
+ );
35
+ }
36
+
37
+ function parseSemver(value) {
38
+ const match = SEMVER_PATTERN.exec(value ?? "");
39
+ if (!match) return null;
40
+ return {
41
+ core: match.slice(1, 4).map(Number),
42
+ prerelease: match[4] ? match[4].split(".") : [],
43
+ };
44
+ }
45
+
46
+ function compareIdentifier(left, right) {
47
+ const leftNumber = /^\d+$/.test(left) ? Number(left) : null;
48
+ const rightNumber = /^\d+$/.test(right) ? Number(right) : null;
49
+ if (leftNumber !== null && rightNumber !== null) {
50
+ return Math.sign(leftNumber - rightNumber);
51
+ }
52
+ if (leftNumber !== null) return -1;
53
+ if (rightNumber !== null) return 1;
54
+ return left === right ? 0 : left < right ? -1 : 1;
55
+ }
56
+
57
+ function compareSemver(leftValue, rightValue) {
58
+ const left = parseSemver(leftValue);
59
+ const right = parseSemver(rightValue);
60
+ if (!left || !right) return null;
61
+ for (let index = 0; index < left.core.length; index += 1) {
62
+ if (left.core[index] !== right.core[index]) {
63
+ return Math.sign(left.core[index] - right.core[index]);
64
+ }
65
+ }
66
+ if (left.prerelease.length === 0 || right.prerelease.length === 0) {
67
+ if (left.prerelease.length === right.prerelease.length) return 0;
68
+ return left.prerelease.length === 0 ? 1 : -1;
69
+ }
70
+ const width = Math.max(left.prerelease.length, right.prerelease.length);
71
+ for (let index = 0; index < width; index += 1) {
72
+ if (left.prerelease[index] === undefined) return -1;
73
+ if (right.prerelease[index] === undefined) return 1;
74
+ const comparison = compareIdentifier(
75
+ left.prerelease[index],
76
+ right.prerelease[index],
77
+ );
78
+ if (comparison !== 0) return comparison;
79
+ }
80
+ return 0;
81
+ }
82
+
83
+ function sameProtocol(left, right) {
84
+ return (
85
+ left?.id === right?.id &&
86
+ left?.version === right?.version &&
87
+ left?.root === right?.root
88
+ );
89
+ }
90
+
91
+ function validTransition(transition, authority, candidate) {
92
+ if (!transition || typeof transition !== "object") return false;
93
+ const body = structuredClone(transition);
94
+ const transitionRoot = body.transitionRoot;
95
+ delete body.transitionRoot;
96
+ return (
97
+ exactRoot(transitionRoot) &&
98
+ adopterDeliveryGateDigest(body) === transitionRoot &&
99
+ body.fromGateRoot === authority.gateRoot &&
100
+ body.toGateRoot === candidate.gateRoot &&
101
+ body.fromProtocolRoot === authority.protocol.root &&
102
+ body.toProtocolRoot === candidate.protocol.root &&
103
+ body.fromProfileRoot === authority.profile.root &&
104
+ body.toProfileRoot === candidate.profile.root &&
105
+ exactRoot(body.compatibilityProofRoot) &&
106
+ exactRoot(body.independentReviewRoot)
107
+ );
108
+ }
109
+
110
+ function validateWarrant(warrant, candidate) {
111
+ return (
112
+ warrant &&
113
+ typeof warrant === "object" &&
114
+ warrant.outcome === "merged" &&
115
+ warrant.sourceHead === candidate.sourceCommit &&
116
+ exactRoot(warrant.sourceProofRoot) &&
117
+ exactRoot(warrant.nativeProofRoot) &&
118
+ exactRoot(warrant.integrationProofRoot)
119
+ );
120
+ }
121
+
122
+ export function qualifyBuildchainDeliveryInfrastructureBootstrap({
123
+ authority,
124
+ candidate,
125
+ gateResult,
126
+ warrant,
127
+ transitionEvidence,
128
+ } = {}) {
129
+ const issues = [];
130
+ if (!exactCut(authority)) {
131
+ issues.push(
132
+ issue("bootstrap.authority.cut", "N-1 authority cut is incomplete"),
133
+ );
134
+ }
135
+ if (!exactCut(candidate)) {
136
+ issues.push(
137
+ issue("bootstrap.candidate.cut", "candidate cut is incomplete"),
138
+ );
139
+ }
140
+ if (authority?.protected !== true || authority?.published !== true) {
141
+ issues.push(
142
+ issue(
143
+ "bootstrap.authority.release",
144
+ "N-1 authority must be both protected and publicly released",
145
+ ),
146
+ );
147
+ }
148
+ if (candidate?.authorityVersion !== authority?.version) {
149
+ issues.push(
150
+ issue(
151
+ "bootstrap.authority.stale",
152
+ "candidate must name the exact N-1 authority version",
153
+ ),
154
+ );
155
+ }
156
+ const versionOrder = compareSemver(authority?.version, candidate?.version);
157
+ if (versionOrder === null || versionOrder >= 0) {
158
+ issues.push(
159
+ issue(
160
+ "bootstrap.authority.order",
161
+ "N-1 authority version must precede the candidate version",
162
+ ),
163
+ );
164
+ }
165
+ if (
166
+ authority?.sourceCommit === candidate?.sourceCommit ||
167
+ authority?.packageRoot === candidate?.packageRoot
168
+ ) {
169
+ issues.push(
170
+ issue(
171
+ "bootstrap.self-authorization",
172
+ "candidate source or package cannot serve as its own N-1 authority",
173
+ ),
174
+ );
175
+ }
176
+
177
+ const gateValidation = validateAdopterDeliveryGateResult(gateResult);
178
+ if (!gateValidation.passed) {
179
+ issues.push(
180
+ issue(
181
+ "bootstrap.gate.failed",
182
+ "candidate must retain a passed public adopter delivery gate result",
183
+ ),
184
+ );
185
+ }
186
+ if (
187
+ gateResult?.artifact?.root !== candidate?.packageRoot ||
188
+ gateResult?.project?.adopterId !== "kungfu-systems/buildchain"
189
+ ) {
190
+ issues.push(
191
+ issue(
192
+ "bootstrap.gate.candidate",
193
+ "gate result must bind the exact Buildchain candidate package",
194
+ ),
195
+ );
196
+ }
197
+ if (!validateWarrant(warrant, candidate)) {
198
+ issues.push(
199
+ issue(
200
+ "bootstrap.warrant",
201
+ "merged Delivery Warrant evidence must bind the candidate source",
202
+ ),
203
+ );
204
+ }
205
+
206
+ const transitionRequired =
207
+ !sameProtocol(authority?.protocol, candidate?.protocol) ||
208
+ !sameProtocol(authority?.profile, candidate?.profile) ||
209
+ authority?.gateRoot !== candidate?.gateRoot;
210
+ if (
211
+ transitionRequired &&
212
+ !validTransition(transitionEvidence, authority, candidate)
213
+ ) {
214
+ issues.push(
215
+ issue(
216
+ "bootstrap.transition",
217
+ "gate, protocol, or profile changes require exact independent transition evidence",
218
+ ),
219
+ );
220
+ }
221
+
222
+ const result = {
223
+ schemaVersion: 1,
224
+ contract: BUILDCHAIN_DELIVERY_BOOTSTRAP_CONTRACT,
225
+ status: issues.length === 0 ? "passed" : "failed",
226
+ authority: structuredClone(authority ?? null),
227
+ candidate: structuredClone(candidate ?? null),
228
+ gateResultRoot: gateResult?.gateRoot ?? null,
229
+ warrant: structuredClone(warrant ?? null),
230
+ transitionRequired,
231
+ transitionEvidenceRoot: transitionEvidence?.transitionRoot ?? null,
232
+ issues,
233
+ qualifying: false,
234
+ selfCertified: false,
235
+ releaseAuthorized: false,
236
+ finalAuthority: "protected-n-minus-one-plus-exact-delivery-evidence",
237
+ };
238
+ result.bootstrapRoot = adopterDeliveryGateDigest(result);
239
+ return result;
240
+ }