@kungfu-tech/buildchain 3.0.9-alpha.9 → 4.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/AGENTS.md +39 -0
  2. package/README.md +17 -13
  3. package/actions/promote-buildchain-ref/README.md +0 -10
  4. package/actions/release-tail/README.md +6 -10
  5. package/architecture/internal-capabilities.json +502 -0
  6. package/architecture/maintainability-baseline.json +59 -0
  7. package/architecture/maintainability-policy.json +1384 -0
  8. package/architecture/release-tail-contract-inventory.json +587 -0
  9. package/architecture/v3-core-mechanism-inventory.json +1043 -0
  10. package/architecture/v3-core-mechanism-inventory.md +67 -0
  11. package/architecture/v4-adopter-delivery-parity.json +47 -0
  12. package/architecture/v4-architecture-constitution.md +210 -0
  13. package/architecture/v4-bootstrap-authority.json +56 -0
  14. package/architecture/v4-canonical-contract-fixtures.json +105 -0
  15. package/architecture/v4-capability-state-machine-manifest.json +480 -0
  16. package/architecture/v4-capability-state-machine-manifest.schema.json +202 -0
  17. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +830 -0
  18. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.md +223 -0
  19. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.schema.json +318 -0
  20. package/architecture/v4-delivery-warrant-shadow-fixtures.json +227 -0
  21. package/architecture/v4-delivery-warrant-shadow-fixtures.schema.json +67 -0
  22. package/architecture/v4-exception-ledger.json +5 -0
  23. package/architecture/v4-exception-ledger.schema.json +56 -0
  24. package/architecture/v4-partial-mutation-recovery-qualification.json +65 -0
  25. package/architecture/v4-platform-stage-checkpoints.json +97 -0
  26. package/architecture/v4-provider-operation-journal-contract.json +113 -0
  27. package/architecture/v4-release-activation-shadow-domain.json +61 -0
  28. package/architecture/v4-release-train-parity.json +68 -0
  29. package/architecture/v4-rust-libnode-bridge-evaluation.json +107 -0
  30. package/architecture/v4-rust-libnode-bridge-spike.md +85 -0
  31. package/architecture/v4-stable-publication-fence.json +66 -0
  32. package/architecture/v4-stage-capsule-contract.json +90 -0
  33. package/architecture/v4-stage-capsule-qualification.json +99 -0
  34. package/architecture/v4-stage-capsule-resume-planner.json +52 -0
  35. package/architecture/v4-stage-capsule-store-contract.json +72 -0
  36. package/bin/buildchain.mjs +15 -10
  37. package/contracts/auditable-demo-scenario-v1.schema.json +1 -1
  38. package/contracts/buildchain-v2-residuals-v1.json +2 -2
  39. package/contracts/fixtures/v4-delivery-warrant-trace-v1/golden.json +158 -0
  40. package/contracts/fixtures/v4-delivery-warrant-trace-v1/property.json +380 -0
  41. package/contracts/fixtures/v4-delivery-warrant-trace-v1/replay.json +163 -0
  42. package/contracts/fixtures/v4-partial-mutation-recovery-v1/shared.json +155 -0
  43. package/contracts/fixtures/v4-provider-operation-journal-v1/shared.json +457 -0
  44. package/contracts/fixtures/v4-provider-readback-idempotency-v1/shared.json +682 -0
  45. package/contracts/fixtures/v4-release-activation-shadow-v1/shared.json +53 -0
  46. package/contracts/fixtures/v4-stable-publication-fence-v1/shared.json +56 -0
  47. package/contracts/fixtures/v4-stage-capsule-resume-v1/late-platform-failure.json +176 -0
  48. package/contracts/fixtures/v4-stage-capsule-store-v1/shared.json +132 -0
  49. package/contracts/fixtures/v4-stage-capsule-v1/shared.json +111 -0
  50. package/contracts/v4-canonical-contracts-v1.schema.json +182 -0
  51. package/contracts/v4-delivery-warrant-semantic-diff-report-v1.schema.json +284 -0
  52. package/contracts/v4-delivery-warrant-trace-v1.schema.json +215 -0
  53. package/contracts/v4-host-contract-v1.schema.json +135 -0
  54. package/contracts/v4-partial-mutation-recovery-v1.schema.json +168 -0
  55. package/contracts/v4-provider-operation-journal-v1.schema.json +381 -0
  56. package/contracts/v4-release-activation-shadow-v1.schema.json +186 -0
  57. package/contracts/v4-stable-publication-fence-v1.schema.json +125 -0
  58. package/contracts/v4-stage-capsule-resume-v1.schema.json +225 -0
  59. package/contracts/v4-stage-capsule-store-v1.schema.json +154 -0
  60. package/contracts/v4-stage-capsule-v1.schema.json +178 -0
  61. package/crates/buildchain-v4-bridge/Cargo.lock +213 -0
  62. package/crates/buildchain-v4-bridge/Cargo.toml +12 -0
  63. package/crates/buildchain-v4-bridge/src/main.rs +495 -0
  64. package/dist/site/agent-index.json +0 -4
  65. package/dist/site/artifact-schemas.json +0 -8
  66. package/dist/site/buildchain-contract.json +103 -397
  67. package/dist/site/buildchain-site.json +302 -386
  68. package/dist/site/capability-registry.json +9 -11
  69. package/dist/site/cli-registry.json +8 -53
  70. package/dist/site/controller-registry.json +48 -8
  71. package/dist/site/kfd-claims.json +129 -167
  72. package/dist/site/kfd-upstream-aggregate.json +9 -9
  73. package/dist/site/manual-registry.json +18 -49
  74. package/dist/site/node-api-registry.json +4345 -7345
  75. package/dist/site/page-registry.json +278 -346
  76. package/dist/site/public-surface-audit.json +85 -404
  77. package/dist/site/publication-authority-registry.json +11 -1
  78. package/dist/site/publication-registry.json +4 -4
  79. package/dist/site/release-provenance.json +3 -9
  80. package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
  81. package/dist/site/site-manifest.json +22 -38
  82. package/dist/site/workflow-registry.json +78 -35
  83. package/docs/MAP.md +8 -5
  84. package/docs/auditable-demo.md +2 -2
  85. package/docs/aws-us-elastic-runner-burst-plane.md +7 -59
  86. package/docs/cli-reference.md +15 -213
  87. package/docs/cli.md +14 -14
  88. package/docs/dev-alpha-candidate-patrol.md +3 -11
  89. package/docs/dev-delivery-warrant.md +29 -194
  90. package/docs/engineering-housekeeper.md +12 -4
  91. package/docs/getting-started.md +1 -1
  92. package/docs/install.md +5 -5
  93. package/docs/kfd-support.md +2 -7
  94. package/docs/lifecycle-protocol.md +2 -4
  95. package/docs/node-api-reference.md +414 -554
  96. package/docs/release-flow.md +31 -31
  97. package/docs/release-governance.md +16 -28
  98. package/docs/release-passport.md +2 -15
  99. package/docs/release-tail-contract.md +13 -6
  100. package/docs/release-tail-provider-plane.md +13 -19
  101. package/docs/release-train.md +4 -4
  102. package/docs/reusable-build-surface.md +14 -27
  103. package/docs/site-bundle-contract.md +1 -5
  104. package/docs/stable-candidate-patrol.md +7 -7
  105. package/docs/v4-canonical-contracts.md +92 -0
  106. package/docs/v4-delivery-warrant-read-candidate.md +73 -0
  107. package/docs/v4-delivery-warrant-semantic-diff.md +75 -0
  108. package/docs/v4-production-release.md +63 -0
  109. package/docs/v4-stage-capsule.md +193 -0
  110. package/docs/versioning.md +3 -5
  111. package/package.json +19 -19
  112. package/packages/core/adopter-delivery-gate.js +576 -0
  113. package/packages/core/adopter-delivery-json.js +66 -0
  114. package/packages/core/artifact-signing.js +0 -61
  115. package/packages/core/artifact-verification-envelope.js +5 -5
  116. package/packages/core/build-facts.js +12 -4
  117. package/packages/core/buildchain-agent-manuals.js +0 -2
  118. package/packages/core/buildchain-channel-identity.js +3 -2
  119. package/packages/core/buildchain-config.js +4 -69
  120. package/packages/core/buildchain-contract.js +232 -46
  121. package/packages/core/buildchain-kfd-claims.js +1 -1
  122. package/packages/core/channel-candidate.js +0 -8
  123. package/packages/core/channel-promotion-baseline.js +0 -52
  124. package/packages/core/controller-evidence.js +3 -4
  125. package/packages/core/dev-alpha-candidate-selection.js +2 -10
  126. package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
  127. package/packages/core/dev-delivery-warrant-settlement.js +20 -67
  128. package/packages/core/dev-delivery-warrant.js +50 -138
  129. package/packages/core/diagnostics.js +3 -8
  130. package/packages/core/github-governance-authority.js +3 -1
  131. package/packages/core/kfd-adopter-category-driver.js +167 -0
  132. package/packages/core/kfd-adopter-manifest.js +47 -46
  133. package/packages/core/kfd-gate.js +15 -45
  134. package/packages/core/paper-agent-entry.js +7 -16
  135. package/packages/core/paper-fleet.js +2 -2
  136. package/packages/core/paper-repository.js +2 -3
  137. package/packages/core/paper-scaffold-content.js +2 -23
  138. package/packages/core/paper.js +11 -43
  139. package/packages/core/publication-reproducibility.js +4 -4
  140. package/packages/core/release-line-bootstrap.js +21 -8
  141. package/packages/core/release-passport-contract.js +5 -5
  142. package/packages/core/release-passport.js +20 -131
  143. package/packages/core/self-dogfood-version.js +48 -35
  144. package/packages/core/spawn-command.js +232 -8
  145. package/packages/core/v4-adopter-delivery-parity.js +219 -0
  146. package/packages/core/v4-canonical-contracts.js +284 -0
  147. package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
  149. package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
  150. package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
  151. package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
  152. package/packages/core/v4-platform-stage-checkpoints.js +471 -0
  153. package/packages/core/v4-provider-operation-journal.js +531 -0
  154. package/packages/core/v4-provider-readback-idempotency.js +394 -0
  155. package/packages/core/v4-release-activation-shadow.js +519 -0
  156. package/packages/core/v4-stable-publication-fence.js +357 -0
  157. package/packages/core/v4-stage-capsule-local-store.js +426 -0
  158. package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
  159. package/packages/core/v4-stage-capsule-qualification.js +456 -0
  160. package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
  161. package/packages/core/v4-stage-capsule-store.js +401 -0
  162. package/packages/core/v4-stage-capsule.js +319 -0
  163. package/scripts/assemble-self-publication-admission.mjs +1 -1
  164. package/scripts/audit-publication-control-plane.mjs +5 -5
  165. package/scripts/auditable-demo-bundle-verification.mjs +3 -2
  166. package/scripts/auditable-demo-platform.mjs +2 -2
  167. package/scripts/auditable-demo-renditions.mjs +1 -1
  168. package/scripts/auditable-demo.mjs +2 -2
  169. package/scripts/aws-macos-jit-controller-core.mjs +13 -346
  170. package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
  171. package/scripts/aws-macos-jit-controller.mjs +37 -275
  172. package/scripts/aws-macos-jit-core.mjs +3 -41
  173. package/scripts/aws-macos-jit.mjs +0 -12
  174. package/scripts/aws-windows-jit-campaign.mjs +2 -2
  175. package/scripts/aws-windows-jit-controller-core.mjs +1 -1
  176. package/scripts/aws-windows-jit-controller.mjs +3 -3
  177. package/scripts/build-contract-core.mjs +3 -8
  178. package/scripts/build-standalone-binary.mjs +3 -14
  179. package/scripts/buildchain-channel-router.mjs +4 -0
  180. package/scripts/buildchain-cli-help.mjs +7 -16
  181. package/scripts/buildchain-contract-lock.mjs +0 -6
  182. package/scripts/check-action-bundles.mjs +3 -4
  183. package/scripts/check-internal-architecture.mjs +7 -6
  184. package/scripts/check-inventory.mjs +30 -25
  185. package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
  186. package/scripts/create-release-bundle.mjs +8 -4
  187. package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
  188. package/scripts/dev-delivery-proof.mjs +2 -64
  189. package/scripts/dev-delivery-warrant.mjs +61 -86
  190. package/scripts/dev-pr-auto-merge.mjs +4 -30
  191. package/scripts/dev-pr-delivery-warrant.mjs +0 -55
  192. package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
  193. package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
  194. package/scripts/generate-channel-build-workflow.mjs +54 -24
  195. package/scripts/generate-channel-promotion-workflow.mjs +15 -6
  196. package/scripts/generate-site-bundle.mjs +8 -27
  197. package/scripts/git-fetch-process-tree.mjs +34 -1
  198. package/scripts/init-repo.mjs +64 -159
  199. package/scripts/inspect-artifact-signing-requests.mjs +0 -6
  200. package/scripts/locked-source-checkout.mjs +3 -4
  201. package/scripts/maintainability-metrics.mjs +8 -2
  202. package/scripts/npm-publish-dry-run.mjs +2 -2
  203. package/scripts/npm-publish-transaction.mjs +2 -2
  204. package/scripts/publication-commit-evidence.mjs +23 -69
  205. package/scripts/release-candidate-resolver.mjs +11 -17
  206. package/scripts/release-tail.mjs +3 -49
  207. package/scripts/resume-from-candidate-run.mjs +9 -123
  208. package/scripts/run-lifecycle-core.mjs +12 -13
  209. package/scripts/seal-artifact-signing-requests.mjs +17 -21
  210. package/scripts/site-capability-metadata.mjs +3 -20
  211. package/scripts/stable-candidate-qualification.mjs +10 -10
  212. package/scripts/v4-architecture.mjs +12 -2
  213. package/scripts/v4-bridge-bootstrap.mjs +141 -0
  214. package/scripts/v4-bridge-evidence.mjs +141 -0
  215. package/scripts/v4-host-adapter.mjs +182 -0
  216. package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
  217. package/scripts/v4-stage-capsule-qualification.mjs +528 -0
  218. package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
  219. package/scripts/v4-warrant-shadow-plan.mjs +601 -0
  220. package/scripts/verify-golden-path.mjs +5 -5
  221. package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
  222. package/scripts/web-surface-core.mjs +2 -8
  223. package/scripts/workflow-call-contract.mjs +5 -184
  224. package/contracts/dev-delivery-authority-v2.schema.json +0 -253
  225. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
  226. package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
  227. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
  228. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
  229. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
  230. package/contracts/next-development-request-v1.schema.json +0 -66
  231. package/contracts/next-development-transition-v1.schema.json +0 -292
  232. package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
  233. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +0 -442
  234. package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
  235. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
  236. package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
  237. package/docs/dev-delivery-qualification-landing-adr.md +0 -137
  238. package/docs/next-development-transition.md +0 -119
  239. package/docs/publication-rehearsal.md +0 -94
  240. package/packages/core/buildchain-compatibility-proof.js +0 -631
  241. package/packages/core/dev-delivery-authority.js +0 -996
  242. package/packages/core/dev-delivery-native-proof.js +0 -418
  243. package/packages/core/dev-delivery-warrant-shadow.js +0 -502
  244. package/packages/core/next-development-candidate-reservation.js +0 -186
  245. package/packages/core/next-development-controller.js +0 -726
  246. package/packages/core/next-development-projection.js +0 -288
  247. package/packages/core/next-development-transition.js +0 -738
  248. package/packages/core/publication-rehearsal-projection.js +0 -173
  249. package/packages/core/publication-rehearsal-runtime.js +0 -921
  250. package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
  251. package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
  252. package/scripts/dev-delivery-authority.mjs +0 -368
  253. package/scripts/dev-delivery-native-run.mjs +0 -235
  254. package/scripts/dev-delivery-two-phase-resume.mjs +0 -90
  255. package/scripts/dev-delivery-two-phase.mjs +0 -577
  256. package/scripts/generate-next-development-guidance.mjs +0 -49
  257. package/scripts/materialize-self-release-candidate-version.mjs +0 -137
  258. package/scripts/next-development-self-dogfood-harness.mjs +0 -409
  259. package/scripts/next-development-self-dogfood.mjs +0 -532
  260. package/scripts/next-development-transition.mjs +0 -47
  261. package/scripts/release-candidate-tail-reseal.mjs +0 -426
  262. package/templates/native-dev-delivery.yml +0 -86
@@ -0,0 +1,576 @@
1
+ import {
2
+ adopterDeliveryGateDigest,
3
+ isAdopterDeliveryJsonValue,
4
+ } from "./adopter-delivery-json.js";
5
+
6
+ export { adopterDeliveryGateDigest } from "./adopter-delivery-json.js";
7
+
8
+ export const ADOPTER_DELIVERY_GATE_REQUEST_CONTRACT =
9
+ "kungfu-buildchain-adopter-delivery-request";
10
+ export const ADOPTER_DELIVERY_GATE_RESULT_CONTRACT =
11
+ "kungfu-buildchain-adopter-delivery-result";
12
+ export const ADOPTER_PROTOCOL_DRIVER_INTERFACE =
13
+ "kungfu-buildchain-adopter-protocol-driver/v1";
14
+ export const ADOPTER_ARTIFACT_PROFILE_INTERFACE =
15
+ "kungfu-buildchain-adopter-artifact-profile/v1";
16
+
17
+ const ROOT_PATTERN = /^sha256:[0-9a-f]{64}$/;
18
+ const ID_PATTERN = /^[a-z][a-z0-9.-]*(?:\/[a-z][a-z0-9.-]*)*$/;
19
+ const VERSION_PATTERN = /^[1-9][0-9]*\.[0-9]+\.[0-9]+$/;
20
+ const GIT_COMMIT_COORDINATE_PATTERN = /^[^@\s]+@[0-9a-f]{40}$/;
21
+ const PACKAGE_COORDINATE_PATTERN =
22
+ /^(?:@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)@[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
23
+
24
+ function issue(code, path, message) {
25
+ return { code, path, message };
26
+ }
27
+
28
+ function compareIssues(left, right) {
29
+ return Buffer.compare(
30
+ Buffer.from(`${left.code}\0${left.path}\0${left.message}`, "utf8"),
31
+ Buffer.from(`${right.code}\0${right.path}\0${right.message}`, "utf8"),
32
+ );
33
+ }
34
+
35
+ function exactObject(value, path, fields, issues) {
36
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
37
+ issues.push(
38
+ issue("delivery-input-invalid", path, "Expected a JSON object."),
39
+ );
40
+ return false;
41
+ }
42
+ const admitted = new Set(fields);
43
+ for (const key of Object.keys(value)) {
44
+ if (!admitted.has(key)) {
45
+ issues.push(
46
+ issue(
47
+ "delivery-input-invalid",
48
+ `${path}/${key}`,
49
+ "Unknown fields fail closed.",
50
+ ),
51
+ );
52
+ }
53
+ }
54
+ for (const key of fields) {
55
+ if (!Object.hasOwn(value, key)) {
56
+ issues.push(
57
+ issue(
58
+ "delivery-input-invalid",
59
+ `${path}/${key}`,
60
+ "Required field is missing.",
61
+ ),
62
+ );
63
+ }
64
+ }
65
+ return true;
66
+ }
67
+
68
+ function exactReference(value, path, issues) {
69
+ if (!exactObject(value, path, ["id", "version"], issues)) return;
70
+ if (!ID_PATTERN.test(value.id ?? "")) {
71
+ issues.push(
72
+ issue("delivery-input-invalid", `${path}/id`, "Identifier is invalid."),
73
+ );
74
+ }
75
+ if (!VERSION_PATTERN.test(value.version ?? "")) {
76
+ issues.push(
77
+ issue("delivery-input-invalid", `${path}/version`, "Version is invalid."),
78
+ );
79
+ }
80
+ }
81
+
82
+ function validateRequest(request) {
83
+ const issues = [];
84
+ if (
85
+ !exactObject(
86
+ request,
87
+ "/",
88
+ [
89
+ "schemaVersion",
90
+ "contract",
91
+ "protocol",
92
+ "artifactProfile",
93
+ "project",
94
+ "artifact",
95
+ "declaration",
96
+ ],
97
+ issues,
98
+ )
99
+ )
100
+ return issues;
101
+ if (
102
+ request.schemaVersion !== 1 ||
103
+ request.contract !== ADOPTER_DELIVERY_GATE_REQUEST_CONTRACT
104
+ ) {
105
+ issues.push(
106
+ issue(
107
+ "delivery-input-invalid",
108
+ "/contract",
109
+ "Delivery request contract is unsupported.",
110
+ ),
111
+ );
112
+ }
113
+ exactReference(request.protocol, "/protocol", issues);
114
+ exactReference(request.artifactProfile, "/artifactProfile", issues);
115
+ if (
116
+ exactObject(
117
+ request.project,
118
+ "/project",
119
+ ["instanceId", "adopterId"],
120
+ issues,
121
+ )
122
+ ) {
123
+ for (const field of ["instanceId", "adopterId"]) {
124
+ if (
125
+ typeof request.project[field] !== "string" ||
126
+ request.project[field].length === 0
127
+ ) {
128
+ issues.push(
129
+ issue(
130
+ "delivery-input-invalid",
131
+ `/project/${field}`,
132
+ "Expected a non-empty string.",
133
+ ),
134
+ );
135
+ }
136
+ }
137
+ }
138
+ if (
139
+ exactObject(
140
+ request.artifact,
141
+ "/artifact",
142
+ ["kind", "coordinate", "root"],
143
+ issues,
144
+ )
145
+ ) {
146
+ for (const field of ["kind", "coordinate"]) {
147
+ if (
148
+ typeof request.artifact[field] !== "string" ||
149
+ request.artifact[field].length === 0
150
+ ) {
151
+ issues.push(
152
+ issue(
153
+ "delivery-input-invalid",
154
+ `/artifact/${field}`,
155
+ "Expected a non-empty string.",
156
+ ),
157
+ );
158
+ }
159
+ }
160
+ if (!ROOT_PATTERN.test(request.artifact.root ?? "")) {
161
+ issues.push(
162
+ issue(
163
+ "delivery-input-invalid",
164
+ "/artifact/root",
165
+ "Expected a canonical lowercase sha256 root.",
166
+ ),
167
+ );
168
+ }
169
+ }
170
+ if (
171
+ !request.declaration ||
172
+ typeof request.declaration !== "object" ||
173
+ Array.isArray(request.declaration) ||
174
+ !isAdopterDeliveryJsonValue(request.declaration)
175
+ ) {
176
+ issues.push(
177
+ issue(
178
+ "delivery-input-invalid",
179
+ "/declaration",
180
+ "Expected a finite acyclic protocol-owned JSON object.",
181
+ ),
182
+ );
183
+ }
184
+ return issues;
185
+ }
186
+
187
+ function definitionReference(definition, interfaceContract, label) {
188
+ if (
189
+ !definition ||
190
+ typeof definition !== "object" ||
191
+ Array.isArray(definition)
192
+ ) {
193
+ throw new TypeError(`${label} must be an object`);
194
+ }
195
+ if (definition.interface !== interfaceContract) {
196
+ throw new TypeError(`${label}.interface must be ${interfaceContract}`);
197
+ }
198
+ if (
199
+ !ID_PATTERN.test(definition.id ?? "") ||
200
+ !VERSION_PATTERN.test(definition.version ?? "")
201
+ ) {
202
+ throw new TypeError(`${label} identity or version is invalid`);
203
+ }
204
+ if (typeof definition.verify !== "function") {
205
+ throw new TypeError(`${label}.verify must be a function`);
206
+ }
207
+ }
208
+
209
+ function validIssue(entry) {
210
+ return (
211
+ entry &&
212
+ typeof entry === "object" &&
213
+ !Array.isArray(entry) &&
214
+ typeof entry.code === "string" &&
215
+ entry.code.length > 0 &&
216
+ typeof entry.path === "string" &&
217
+ typeof entry.message === "string" &&
218
+ entry.message.length > 0
219
+ );
220
+ }
221
+
222
+ export function defineAdopterProtocolDriver(definition) {
223
+ definitionReference(
224
+ definition,
225
+ ADOPTER_PROTOCOL_DRIVER_INTERFACE,
226
+ "protocol driver",
227
+ );
228
+ return Object.freeze({
229
+ interface: definition.interface,
230
+ id: definition.id,
231
+ version: definition.version,
232
+ verify: definition.verify,
233
+ });
234
+ }
235
+
236
+ export function defineAdopterArtifactProfile(definition) {
237
+ definitionReference(
238
+ definition,
239
+ ADOPTER_ARTIFACT_PROFILE_INTERFACE,
240
+ "artifact profile",
241
+ );
242
+ if (
243
+ !Array.isArray(definition.kinds) ||
244
+ definition.kinds.length === 0 ||
245
+ definition.kinds.some(
246
+ (kind) => typeof kind !== "string" || kind.length === 0,
247
+ ) ||
248
+ new Set(definition.kinds).size !== definition.kinds.length
249
+ ) {
250
+ throw new TypeError(
251
+ "artifact profile kinds must be a non-empty unique string array",
252
+ );
253
+ }
254
+ return Object.freeze({
255
+ interface: definition.interface,
256
+ id: definition.id,
257
+ version: definition.version,
258
+ kinds: Object.freeze([...definition.kinds]),
259
+ verify: definition.verify,
260
+ });
261
+ }
262
+
263
+ function coordinateProfile({ id, version, kind, pattern, message }) {
264
+ return defineAdopterArtifactProfile({
265
+ interface: ADOPTER_ARTIFACT_PROFILE_INTERFACE,
266
+ id,
267
+ version,
268
+ kinds: [kind],
269
+ verify(artifact) {
270
+ const issues = [];
271
+ if (!pattern.test(artifact.coordinate)) {
272
+ issues.push(
273
+ issue("delivery-artifact-invalid", "/artifact/coordinate", message),
274
+ );
275
+ }
276
+ return { valid: issues.length === 0, issues };
277
+ },
278
+ });
279
+ }
280
+
281
+ export function createGitCommitArtifactProfile({
282
+ id = "buildchain.artifact/git-commit",
283
+ version = "1.0.0",
284
+ } = {}) {
285
+ return coordinateProfile({
286
+ id,
287
+ version,
288
+ kind: "git-commit",
289
+ pattern: GIT_COMMIT_COORDINATE_PATTERN,
290
+ message:
291
+ "Git commit coordinates must bind one repository and exact lowercase 40-hex commit.",
292
+ });
293
+ }
294
+
295
+ export function createPackageArtifactProfile({
296
+ id = "buildchain.artifact/package",
297
+ version = "1.0.0",
298
+ } = {}) {
299
+ return coordinateProfile({
300
+ id,
301
+ version,
302
+ kind: "package",
303
+ pattern: PACKAGE_COORDINATE_PATTERN,
304
+ message:
305
+ "Package coordinates must bind one package name and immutable version.",
306
+ });
307
+ }
308
+
309
+ function registry(definitions, label) {
310
+ const result = new Map();
311
+ for (const definition of definitions) {
312
+ const key = `${definition.id}@${definition.version}`;
313
+ if (result.has(key)) throw new TypeError(`${label} ${key} is duplicated`);
314
+ result.set(key, definition);
315
+ }
316
+ return result;
317
+ }
318
+
319
+ function normalizeProfileResult(result) {
320
+ if (
321
+ !result ||
322
+ typeof result !== "object" ||
323
+ Array.isArray(result) ||
324
+ typeof result.valid !== "boolean" ||
325
+ !Array.isArray(result.issues) ||
326
+ result.issues.some((entry) => !validIssue(entry))
327
+ ) {
328
+ return {
329
+ valid: false,
330
+ issues: [
331
+ issue(
332
+ "delivery-artifact-profile-result-invalid",
333
+ "/artifactProfile",
334
+ "Artifact profile returned an invalid result.",
335
+ ),
336
+ ],
337
+ };
338
+ }
339
+ return {
340
+ valid: result.valid,
341
+ issues: result.issues.map(({ code, path, message }) => ({
342
+ code,
343
+ path,
344
+ message,
345
+ })),
346
+ };
347
+ }
348
+
349
+ function normalizeDriverResult(result) {
350
+ if (
351
+ !result ||
352
+ typeof result !== "object" ||
353
+ Array.isArray(result) ||
354
+ typeof result.valid !== "boolean" ||
355
+ !ROOT_PATTERN.test(result.reportRoot ?? "") ||
356
+ !Array.isArray(result.issues) ||
357
+ result.issues.some((entry) => !validIssue(entry)) ||
358
+ !Object.hasOwn(result, "report") ||
359
+ !isAdopterDeliveryJsonValue(result.report)
360
+ ) {
361
+ return {
362
+ valid: false,
363
+ report: null,
364
+ reportRoot: null,
365
+ issues: [
366
+ issue(
367
+ "delivery-driver-result-invalid",
368
+ "/protocol",
369
+ "Protocol driver returned an invalid result.",
370
+ ),
371
+ ],
372
+ };
373
+ }
374
+ return {
375
+ valid: result.valid,
376
+ report: structuredClone(result.report),
377
+ reportRoot: result.reportRoot,
378
+ issues: result.issues.map(({ code, path, message }) => ({
379
+ code,
380
+ path,
381
+ message,
382
+ })),
383
+ };
384
+ }
385
+
386
+ function gateResult(
387
+ request,
388
+ protocolDriver,
389
+ artifactProfile,
390
+ profileResult,
391
+ driverResult,
392
+ issues,
393
+ ) {
394
+ const result = {
395
+ schemaVersion: 1,
396
+ contract: ADOPTER_DELIVERY_GATE_RESULT_CONTRACT,
397
+ status: issues.length === 0 ? "passed" : "failed",
398
+ qualifying: false,
399
+ selfCertified: false,
400
+ project: request?.project ? structuredClone(request.project) : null,
401
+ artifact: request?.artifact ? structuredClone(request.artifact) : null,
402
+ protocol: request?.protocol
403
+ ? {
404
+ ...structuredClone(request.protocol),
405
+ loaded: Boolean(protocolDriver),
406
+ reportRoot: driverResult?.reportRoot ?? null,
407
+ }
408
+ : null,
409
+ artifactProfile: request?.artifactProfile
410
+ ? {
411
+ ...structuredClone(request.artifactProfile),
412
+ loaded: Boolean(artifactProfile),
413
+ valid: profileResult?.valid ?? false,
414
+ }
415
+ : null,
416
+ semanticReport: driverResult?.report ?? null,
417
+ nonClaims: [
418
+ "A passing delivery gate does not grant runtime permission, release authorization, or independent certification.",
419
+ "Protocol semantics remain owned by the selected protocol driver and its published authority.",
420
+ ],
421
+ issues: [...issues].sort(compareIssues),
422
+ };
423
+ result.gateRoot = adopterDeliveryGateDigest(result);
424
+ return result;
425
+ }
426
+
427
+ export function createAdopterDeliveryGate({
428
+ drivers = [],
429
+ artifactProfiles = [],
430
+ } = {}) {
431
+ if (!Array.isArray(drivers) || !Array.isArray(artifactProfiles)) {
432
+ throw new TypeError("drivers and artifactProfiles must be arrays");
433
+ }
434
+ drivers.forEach((driver) =>
435
+ definitionReference(
436
+ driver,
437
+ ADOPTER_PROTOCOL_DRIVER_INTERFACE,
438
+ "protocol driver",
439
+ ),
440
+ );
441
+ artifactProfiles.forEach((profile) => {
442
+ definitionReference(
443
+ profile,
444
+ ADOPTER_ARTIFACT_PROFILE_INTERFACE,
445
+ "artifact profile",
446
+ );
447
+ if (
448
+ !Array.isArray(profile.kinds) ||
449
+ profile.kinds.length === 0 ||
450
+ profile.kinds.some(
451
+ (kind) => typeof kind !== "string" || kind.length === 0,
452
+ ) ||
453
+ new Set(profile.kinds).size !== profile.kinds.length
454
+ ) {
455
+ throw new TypeError(
456
+ "artifact profile kinds must be a non-empty unique string array",
457
+ );
458
+ }
459
+ });
460
+ const driverRegistry = registry(drivers, "protocol driver");
461
+ const profileRegistry = registry(artifactProfiles, "artifact profile");
462
+
463
+ return Object.freeze({
464
+ evaluate(request, context = {}) {
465
+ const issues = validateRequest(request);
466
+ if (issues.length > 0)
467
+ return gateResult(request, null, null, null, null, issues);
468
+
469
+ const driver = driverRegistry.get(
470
+ `${request.protocol.id}@${request.protocol.version}`,
471
+ );
472
+ if (!driver) {
473
+ issues.push(
474
+ issue(
475
+ "delivery-driver-unknown",
476
+ "/protocol",
477
+ "No exact protocol driver is registered.",
478
+ ),
479
+ );
480
+ }
481
+ const profile = profileRegistry.get(
482
+ `${request.artifactProfile.id}@${request.artifactProfile.version}`,
483
+ );
484
+ if (!profile) {
485
+ issues.push(
486
+ issue(
487
+ "delivery-artifact-profile-unknown",
488
+ "/artifactProfile",
489
+ "No exact artifact profile is registered.",
490
+ ),
491
+ );
492
+ } else if (!profile.kinds.includes(request.artifact.kind)) {
493
+ issues.push(
494
+ issue(
495
+ "delivery-artifact-kind-mismatch",
496
+ "/artifact/kind",
497
+ "Artifact kind is not admitted by the selected profile.",
498
+ ),
499
+ );
500
+ }
501
+
502
+ let profileResult = null;
503
+ if (profile && profile.kinds.includes(request.artifact.kind)) {
504
+ try {
505
+ profileResult = normalizeProfileResult(
506
+ profile.verify(structuredClone(request.artifact)),
507
+ );
508
+ } catch {
509
+ profileResult = {
510
+ valid: false,
511
+ issues: [
512
+ issue(
513
+ "delivery-artifact-profile-error",
514
+ "/artifactProfile",
515
+ "Artifact profile execution failed closed.",
516
+ ),
517
+ ],
518
+ };
519
+ }
520
+ issues.push(...profileResult.issues);
521
+ if (!profileResult.valid && profileResult.issues.length === 0) {
522
+ issues.push(
523
+ issue(
524
+ "delivery-artifact-rejected",
525
+ "/artifact",
526
+ "Artifact profile rejected the artifact.",
527
+ ),
528
+ );
529
+ }
530
+ }
531
+
532
+ let driverResult = null;
533
+ if (driver && profileResult?.valid === true) {
534
+ try {
535
+ driverResult = normalizeDriverResult(
536
+ driver.verify({
537
+ request: structuredClone(request),
538
+ context: structuredClone(context),
539
+ }),
540
+ );
541
+ } catch {
542
+ driverResult = {
543
+ valid: false,
544
+ report: null,
545
+ reportRoot: null,
546
+ issues: [
547
+ issue(
548
+ "delivery-driver-error",
549
+ "/protocol",
550
+ "Protocol driver execution failed closed.",
551
+ ),
552
+ ],
553
+ };
554
+ }
555
+ issues.push(...driverResult.issues);
556
+ if (!driverResult.valid && driverResult.issues.length === 0) {
557
+ issues.push(
558
+ issue(
559
+ "delivery-semantic-rejected",
560
+ "/declaration",
561
+ "Protocol driver rejected the declaration.",
562
+ ),
563
+ );
564
+ }
565
+ }
566
+ return gateResult(
567
+ request,
568
+ driver,
569
+ profile,
570
+ profileResult,
571
+ driverResult,
572
+ issues,
573
+ );
574
+ },
575
+ });
576
+ }
@@ -0,0 +1,66 @@
1
+ import crypto from "node:crypto";
2
+
3
+ export function isAdopterDeliveryJsonValue(value, ancestors = new Set()) {
4
+ try {
5
+ if (
6
+ value === null ||
7
+ typeof value === "string" ||
8
+ typeof value === "boolean"
9
+ ) {
10
+ return true;
11
+ }
12
+ if (typeof value === "number") return Number.isFinite(value);
13
+ if (typeof value !== "object" || ancestors.has(value)) return false;
14
+
15
+ ancestors.add(value);
16
+ let valid = true;
17
+ if (Array.isArray(value)) {
18
+ valid =
19
+ Reflect.ownKeys(value).length === value.length + 1 &&
20
+ Array.from(
21
+ { length: value.length },
22
+ (_, index) =>
23
+ Object.hasOwn(value, index) &&
24
+ isAdopterDeliveryJsonValue(value[index], ancestors),
25
+ ).every(Boolean);
26
+ } else {
27
+ const prototype = Object.getPrototypeOf(value);
28
+ const keys = Reflect.ownKeys(value);
29
+ valid =
30
+ (prototype === Object.prototype || prototype === null) &&
31
+ keys.every((key) => {
32
+ if (typeof key !== "string") return false;
33
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
34
+ return (
35
+ descriptor?.enumerable === true &&
36
+ Object.hasOwn(descriptor, "value") &&
37
+ isAdopterDeliveryJsonValue(descriptor.value, ancestors)
38
+ );
39
+ });
40
+ }
41
+ ancestors.delete(value);
42
+ return valid;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ function stableJson(value) {
49
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
50
+ if (value && typeof value === "object") {
51
+ return `{${Object.keys(value)
52
+ .sort()
53
+ .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`)
54
+ .join(",")}}`;
55
+ }
56
+ return JSON.stringify(value);
57
+ }
58
+
59
+ export function adopterDeliveryGateDigest(value) {
60
+ if (!isAdopterDeliveryJsonValue(value)) {
61
+ throw new TypeError(
62
+ "delivery gate digests require finite acyclic JSON values",
63
+ );
64
+ }
65
+ return `sha256:${crypto.createHash("sha256").update(stableJson(value)).digest("hex")}`;
66
+ }