@kungfu-tech/buildchain 4.0.2-alpha.0 → 4.0.2-alpha.11

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 (82) hide show
  1. package/architecture/agent-change-map.md +52 -5
  2. package/architecture/ci-lane-change-budget.json +408 -8
  3. package/architecture/internal-capabilities.json +44 -1
  4. package/architecture/maintainability-debt.json +65 -133
  5. package/architecture/maintainability-policy.json +20 -15
  6. package/architecture/release-tail-contract-inventory.json +4 -4
  7. package/architecture/v3-core-mechanism-inventory.json +1 -0
  8. package/architecture/v3-v4-live-capability-inventory.json +17 -17
  9. package/architecture/v4-delivery-warrant-shadow-fixtures.json +5 -5
  10. package/architecture/v4-release-invocation-fixtures.json +139 -0
  11. package/architecture/v4-release-topology.json +317 -0
  12. package/architecture/v4-runtime-semantic-closure.json +4 -1
  13. package/architecture/v4-universal-workflow-bootstrap.json +181 -0
  14. package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
  15. package/architecture/v4-universal-workflow-train-admission.json +40 -0
  16. package/contracts/buildchain-v2-residuals-v1.json +0 -9
  17. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  18. package/contracts/v4-release-invocation-v1.schema.json +134 -0
  19. package/dist/site/buildchain-contract.json +87 -42
  20. package/dist/site/buildchain-site.json +15 -10
  21. package/dist/site/capability-registry.json +1 -1
  22. package/dist/site/controller-registry.json +46 -10
  23. package/dist/site/kfd-claims.json +176 -69
  24. package/dist/site/kfd-upstream-aggregate.json +1 -1
  25. package/dist/site/manual-registry.json +2 -2
  26. package/dist/site/node-api-registry.json +97 -22
  27. package/dist/site/page-registry.json +9 -4
  28. package/dist/site/public-surface-audit.json +190 -71
  29. package/dist/site/publication-authority-registry.json +68 -3
  30. package/dist/site/publication-registry.json +4 -4
  31. package/dist/site/site-manifest.json +6 -6
  32. package/dist/site/workflow-registry.json +221 -72
  33. package/docs/node-api-reference.md +28 -25
  34. package/docs/reusable-build-surface.md +16 -0
  35. package/package.json +2 -2
  36. package/packages/core/buildchain-publication-authority.js +3 -0
  37. package/packages/core/ci-lane-change-budget.js +14 -1
  38. package/packages/core/dev-delivery-candidate-identity.js +45 -17
  39. package/packages/core/dev-delivery-execution-transfer.js +6 -7
  40. package/packages/core/dev-delivery-provider-heartbeat.js +22 -6
  41. package/packages/core/dev-delivery-warrant-legacy-recovery.js +4 -2
  42. package/packages/core/dev-delivery-warrant-native-compatibility.js +33 -0
  43. package/packages/core/dev-delivery-warrant-state.js +54 -54
  44. package/packages/core/dev-delivery-warrant.js +8 -0
  45. package/packages/core/dev-delivery-writer-protocol-transition.js +72 -0
  46. package/packages/core/release-tail-product-capabilities.js +29 -0
  47. package/packages/core/release-tail-provider-plane.js +3 -3
  48. package/packages/core/v4-canonical-contracts.js +14 -0
  49. package/packages/core/v4-floating-consumer-policy.js +4 -1
  50. package/packages/core/v4-product-publication.js +387 -0
  51. package/packages/core/v4-protected-publication-source.js +93 -0
  52. package/packages/core/v4-publication-qualification.js +1 -0
  53. package/packages/core/v4-release-invocation.js +425 -0
  54. package/packages/core/v4-universal-workflow-bootstrap.js +596 -0
  55. package/scripts/audit-publication-control-plane.mjs +0 -1
  56. package/scripts/check-inventory.mjs +27 -59
  57. package/scripts/check-maintainability.mjs +29 -118
  58. package/scripts/check-v3-v4-capability-inventory.mjs +3 -61
  59. package/scripts/check-v4-floating-consumer-policy-contract.mjs +10 -20
  60. package/scripts/check-v4-release-topology.mjs +493 -0
  61. package/scripts/check-v4-universal-workflow-bootstrap.mjs +257 -0
  62. package/scripts/dev-delivery-warrant.mjs +26 -5
  63. package/scripts/generate-channel-build-workflow.mjs +5 -1
  64. package/scripts/generate-channel-promotion-workflow.mjs +17 -57
  65. package/scripts/generate-v4-universal-workflow-facades.mjs +415 -0
  66. package/scripts/maintainability-public-surface.mjs +115 -0
  67. package/scripts/release-candidate-resolver.mjs +23 -24
  68. package/scripts/resume-from-candidate-run.mjs +16 -17
  69. package/scripts/universal-facade-maintainability.mjs +82 -0
  70. package/scripts/v3-v4-capability-catalog.mjs +107 -0
  71. package/scripts/v4-declarative-promotion-admission.mjs +4 -1
  72. package/scripts/v4-product-publication-intent.mjs +114 -0
  73. package/scripts/v4-release-candidate-adapter.mjs +41 -0
  74. package/scripts/v4-universal-workflow-backflow.mjs +212 -0
  75. package/scripts/v4-universal-workflow-engine.mjs +586 -0
  76. package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
  77. package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
  78. package/templates/universal-buildchain-bootstrap.yml +28 -0
  79. package/scripts/capture-package-release-propagation.mjs +0 -263
  80. package/scripts/publication-commit-evidence.mjs +0 -444
  81. package/scripts/publish-github-artifact-attestation-evidence.mjs +0 -201
  82. package/scripts/stage-github-artifact-attestation-inputs.mjs +0 -65
@@ -0,0 +1,425 @@
1
+ import {
2
+ V4ContractFault,
3
+ v4CanonicalBytes,
4
+ v4ContentRoot,
5
+ validateV4Root,
6
+ } from "./v4-canonical-contracts.js";
7
+
8
+ export const V4_RELEASE_INVOCATION_CONTRACT =
9
+ "kungfu-buildchain-v4-release-invocation/v1";
10
+ export const V4_RELEASE_INVOCATION_ADAPTER_CONTRACT =
11
+ "kungfu-buildchain-v4-release-invocation-adapter/v1";
12
+ export const V4_RELEASE_TRANSACTION_CONTRACT =
13
+ "kungfu-buildchain-v4-release-transaction/v1";
14
+ export const V4_RELEASE_RECEIPT_CONTRACT =
15
+ "kungfu-buildchain-v4-release-receipt/v1";
16
+ export const V4_RELEASE_PROVIDER_CONTRACT =
17
+ "kungfu-buildchain-release-tail-provider/v1";
18
+
19
+ const SHA_PATTERN = /^[0-9a-f]{40}$/u;
20
+ const TAG_PATTERN = /^v[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/u;
21
+ const ROUTE_SURFACES = new Set([
22
+ "alpha",
23
+ "stable",
24
+ "public",
25
+ "private",
26
+ "declarative",
27
+ "legacy-compatible",
28
+ ]);
29
+ const EXECUTION_MODES = new Set(["fresh", "resume"]);
30
+ const COMPARISON_STATES = new Set(["identical", "ahead", "behind", "diverged"]);
31
+
32
+ function fault(code, path, message) {
33
+ throw new V4ContractFault(code, path, message);
34
+ }
35
+
36
+ function exactKeys(value, keys, path) {
37
+ if (!value || typeof value !== "object" || Array.isArray(value))
38
+ fault("invalid-release-invocation", path, `${path} must be an object`);
39
+ const actual = Object.keys(value).sort();
40
+ const expected = [...keys].sort();
41
+ if (
42
+ actual.length !== expected.length ||
43
+ actual.some((key, index) => key !== expected[index])
44
+ )
45
+ fault(
46
+ "invalid-release-invocation-shape",
47
+ path,
48
+ `${path} keys are not canonical`,
49
+ );
50
+ }
51
+
52
+ function sha(value, path, nullable = false) {
53
+ if (nullable && value === null) return value;
54
+ if (typeof value !== "string" || !SHA_PATTERN.test(value))
55
+ fault("invalid-release-sha", path, `${path} must be an exact Git SHA`);
56
+ return value;
57
+ }
58
+
59
+ function text(value, path) {
60
+ if (
61
+ typeof value !== "string" ||
62
+ value.length === 0 ||
63
+ /[^\x20-\x7e]/u.test(value)
64
+ )
65
+ fault("invalid-release-text", path, `${path} must be printable ASCII`);
66
+ return value;
67
+ }
68
+
69
+ function validatePublisher(value) {
70
+ exactKeys(
71
+ value,
72
+ ["repository", "workflow", "workflowSha", "job"],
73
+ "$/publisher",
74
+ );
75
+ if (
76
+ value.repository !== "kungfu-systems/buildchain" ||
77
+ value.workflow !== ".github/workflows/.release-candidate-promote.yml" ||
78
+ value.job !== "apply"
79
+ )
80
+ fault(
81
+ "invalid-publisher-identity",
82
+ "$/publisher",
83
+ "publisher identity is not the canonical v4 APPLY job",
84
+ );
85
+ sha(value.workflowSha, "$/publisher/workflowSha");
86
+ }
87
+
88
+ function validateRuntime(value) {
89
+ exactKeys(value, ["repository", "commit", "tree"], "$/runtime");
90
+ if (value.repository !== "kungfu-systems/buildchain")
91
+ fault(
92
+ "invalid-runtime-identity",
93
+ "$/runtime/repository",
94
+ "runtime repository is not canonical",
95
+ );
96
+ sha(value.commit, "$/runtime/commit");
97
+ sha(value.tree, "$/runtime/tree");
98
+ }
99
+
100
+ function validateCandidate(value) {
101
+ exactKeys(value, ["repository", "commit", "tree", "version"], "$/candidate");
102
+ text(value.repository, "$/candidate/repository");
103
+ sha(value.commit, "$/candidate/commit");
104
+ sha(value.tree, "$/candidate/tree");
105
+ text(value.version, "$/candidate/version");
106
+ }
107
+
108
+ function validateTarget(value) {
109
+ exactKeys(value, ["channel", "tag", "expectedOldSha"], "$/target");
110
+ if (
111
+ !["alpha", "stable"].includes(value.channel) ||
112
+ !TAG_PATTERN.test(value.tag)
113
+ )
114
+ fault(
115
+ "invalid-release-target",
116
+ "$/target",
117
+ "release channel and exact tag are not canonical",
118
+ );
119
+ sha(value.expectedOldSha, "$/target/expectedOldSha", true);
120
+ }
121
+
122
+ function validateAuthority(value) {
123
+ exactKeys(
124
+ value,
125
+ ["policyRoot", "qualificationRoot", "warrantRoot"],
126
+ "$/authority",
127
+ );
128
+ for (const name of ["policyRoot", "qualificationRoot", "warrantRoot"])
129
+ validateV4Root(value[name], `$/authority/${name}`);
130
+ }
131
+
132
+ function validateProvider(value, candidate) {
133
+ exactKeys(value, ["adapter", "contract", "repository"], "$/provider");
134
+ if (
135
+ value.adapter !== "built-in-provider-plane" ||
136
+ value.contract !== V4_RELEASE_PROVIDER_CONTRACT ||
137
+ value.repository !== candidate.repository
138
+ )
139
+ fault(
140
+ "invalid-release-provider",
141
+ "$/provider",
142
+ "provider identity must bind the built-in Provider Plane and candidate repository",
143
+ );
144
+ }
145
+
146
+ function validateParent(value) {
147
+ exactKeys(
148
+ value,
149
+ ["invocationRoot", "transactionRoot", "receiptRoot"],
150
+ "$/parent",
151
+ );
152
+ const roots = [
153
+ value.invocationRoot,
154
+ value.transactionRoot,
155
+ value.receiptRoot,
156
+ ];
157
+ if (roots.every((root) => root === null)) return;
158
+ if (roots.some((root) => root === null))
159
+ fault(
160
+ "invalid-release-parent-lineage",
161
+ "$/parent",
162
+ "parent lineage roots must be either all null or all present",
163
+ );
164
+ roots.forEach((root, index) =>
165
+ validateV4Root(
166
+ root,
167
+ `$/parent/${["invocationRoot", "transactionRoot", "receiptRoot"][index]}`,
168
+ ),
169
+ );
170
+ }
171
+
172
+ export function createV4ReleaseInvocation(value) {
173
+ exactKeys(
174
+ value,
175
+ [
176
+ "schema",
177
+ "publisher",
178
+ "runtime",
179
+ "candidate",
180
+ "target",
181
+ "authority",
182
+ "provider",
183
+ "parent",
184
+ ],
185
+ "$",
186
+ );
187
+ if (value.schema !== V4_RELEASE_INVOCATION_CONTRACT)
188
+ fault(
189
+ "invalid-release-invocation",
190
+ "$/schema",
191
+ "unsupported invocation schema",
192
+ );
193
+ validatePublisher(value.publisher);
194
+ validateRuntime(value.runtime);
195
+ validateCandidate(value.candidate);
196
+ validateTarget(value.target);
197
+ validateAuthority(value.authority);
198
+ validateProvider(value.provider, value.candidate);
199
+ validateParent(value.parent);
200
+ v4CanonicalBytes(value);
201
+ const roots = {
202
+ publisherRoot: v4ContentRoot(
203
+ "release-invocation-publisher",
204
+ value.publisher,
205
+ ),
206
+ runtimeRoot: v4ContentRoot("release-invocation-runtime", value.runtime),
207
+ candidateRoot: v4ContentRoot(
208
+ "release-invocation-candidate",
209
+ value.candidate,
210
+ ),
211
+ targetRoot: v4ContentRoot("release-invocation-target", value.target),
212
+ authorityRoot: v4ContentRoot(
213
+ "release-invocation-authority",
214
+ value.authority,
215
+ ),
216
+ providerRoot: v4ContentRoot("release-invocation-provider", value.provider),
217
+ parentRoot: v4ContentRoot("release-invocation-parent", value.parent),
218
+ };
219
+ const invocationRoot = v4ContentRoot("release-invocation", {
220
+ schema: V4_RELEASE_INVOCATION_CONTRACT,
221
+ ...roots,
222
+ });
223
+ return { invocation: value, roots: { ...roots, invocationRoot } };
224
+ }
225
+
226
+ export function adaptV4ReleaseInvocation(value) {
227
+ exactKeys(value, ["schema", "route", "invocation"], "$adapter");
228
+ if (value.schema !== V4_RELEASE_INVOCATION_ADAPTER_CONTRACT)
229
+ fault(
230
+ "invalid-release-adapter",
231
+ "$adapter/schema",
232
+ "unsupported adapter schema",
233
+ );
234
+ exactKeys(value.route, ["surface", "execution"], "$adapter/route");
235
+ if (!ROUTE_SURFACES.has(value.route.surface))
236
+ fault(
237
+ "invalid-release-adapter",
238
+ "$adapter/route/surface",
239
+ "unsupported route surface",
240
+ );
241
+ if (!EXECUTION_MODES.has(value.route.execution))
242
+ fault(
243
+ "invalid-release-adapter",
244
+ "$adapter/route/execution",
245
+ "unsupported execution mode",
246
+ );
247
+ return createV4ReleaseInvocation(value.invocation);
248
+ }
249
+
250
+ export function planV4ReleaseRoute({
251
+ requestedSha,
252
+ observedSha,
253
+ comparisonStatus,
254
+ requestedChannel = "",
255
+ targetRef,
256
+ dryRun = false,
257
+ resume = false,
258
+ }) {
259
+ sha(requestedSha, "$route/requestedSha");
260
+ sha(observedSha, "$route/observedSha");
261
+ if (!COMPARISON_STATES.has(comparisonStatus))
262
+ fault(
263
+ "invalid-release-route",
264
+ "$route/comparisonStatus",
265
+ "unsupported source comparison state",
266
+ );
267
+ text(targetRef, "$route/targetRef");
268
+ const alphaLane = /^alpha\/v[0-9]+\/v[0-9]+\.[0-9]+$/u.test(targetRef);
269
+ const stableLane =
270
+ /^release\/v[0-9]+\/v[0-9]+\.[0-9]+$/u.test(targetRef) ||
271
+ ["publish-gate/major", "major-gate"].includes(targetRef);
272
+ if (!alphaLane && !stableLane)
273
+ fault(
274
+ "invalid-release-route",
275
+ "$route/targetRef",
276
+ "source lane is not a supported v4 release lane",
277
+ );
278
+ const derivedChannel = alphaLane ? "alpha" : "stable";
279
+ const normalizedRequested =
280
+ requestedChannel === "alpha"
281
+ ? "alpha"
282
+ : ["release", "stable", "major"].includes(requestedChannel)
283
+ ? "stable"
284
+ : requestedChannel === ""
285
+ ? derivedChannel
286
+ : "";
287
+ if (!normalizedRequested || normalizedRequested !== derivedChannel)
288
+ fault(
289
+ "invalid-release-route",
290
+ "$route/channel",
291
+ "requested channel does not match the source lane",
292
+ );
293
+ let decision = resume ? "Resume" : "Fresh";
294
+ let reason = resume ? "resume" : "fresh";
295
+ if (comparisonStatus === "ahead" && !resume && !dryRun) {
296
+ decision = "NoOp";
297
+ reason = "source-advanced";
298
+ } else if (
299
+ requestedSha !== observedSha &&
300
+ !(resume && comparisonStatus === "ahead") &&
301
+ !(dryRun && comparisonStatus === "ahead")
302
+ ) {
303
+ decision = "Blocked";
304
+ reason = `source-${comparisonStatus}`;
305
+ }
306
+ return Object.freeze({
307
+ decision,
308
+ reason,
309
+ channel: normalizedRequested,
310
+ targetRef,
311
+ requestedSha,
312
+ observedSha,
313
+ });
314
+ }
315
+
316
+ export function createV4ReleaseTransaction(value) {
317
+ exactKeys(
318
+ value,
319
+ [
320
+ "invocationRoot",
321
+ "publisherRoot",
322
+ "runtimeRoot",
323
+ "providerRoot",
324
+ "parentRoot",
325
+ ],
326
+ "$transaction",
327
+ );
328
+ for (const name of [
329
+ "invocationRoot",
330
+ "publisherRoot",
331
+ "runtimeRoot",
332
+ "providerRoot",
333
+ "parentRoot",
334
+ ])
335
+ validateV4Root(value[name], `$transaction/${name}`);
336
+ const transaction = {
337
+ schema: V4_RELEASE_TRANSACTION_CONTRACT,
338
+ invocationRoot: value.invocationRoot,
339
+ publisherRoot: value.publisherRoot,
340
+ runtimeRoot: value.runtimeRoot,
341
+ providerRoot: value.providerRoot,
342
+ parentRoot: value.parentRoot,
343
+ phases: ["QUALIFY", "APPLY", "SETTLE"],
344
+ writer: "canonical-v4-apply",
345
+ };
346
+ return {
347
+ transaction,
348
+ transactionRoot: v4ContentRoot("release-transaction", transaction),
349
+ };
350
+ }
351
+
352
+ export function createV4ReleaseReceipt(value) {
353
+ exactKeys(
354
+ value,
355
+ [
356
+ "schema",
357
+ "transactionRoot",
358
+ "outcome",
359
+ "releasePassportRoot",
360
+ "providerTransactionRoot",
361
+ "providerStateRoot",
362
+ "providerReceiptRoots",
363
+ ],
364
+ "$receipt",
365
+ );
366
+ if (value.schema !== V4_RELEASE_RECEIPT_CONTRACT)
367
+ fault(
368
+ "invalid-release-receipt",
369
+ "$receipt/schema",
370
+ "unsupported receipt schema",
371
+ );
372
+ validateV4Root(value.transactionRoot, "$receipt/transactionRoot");
373
+ if (!["complete", "blocked"].includes(value.outcome))
374
+ fault(
375
+ "invalid-release-receipt",
376
+ "$receipt/outcome",
377
+ "unsupported receipt outcome",
378
+ );
379
+ for (const name of [
380
+ "releasePassportRoot",
381
+ "providerTransactionRoot",
382
+ "providerStateRoot",
383
+ ]) {
384
+ if (value[name] !== null) validateV4Root(value[name], `$receipt/${name}`);
385
+ }
386
+ if (!Array.isArray(value.providerReceiptRoots))
387
+ fault(
388
+ "invalid-release-receipt",
389
+ "$receipt/providerReceiptRoots",
390
+ "receipt roots must be an array",
391
+ );
392
+ value.providerReceiptRoots.forEach((root, index) =>
393
+ validateV4Root(root, `$receipt/providerReceiptRoots/${index}`),
394
+ );
395
+ const canonicalRoots = [...new Set(value.providerReceiptRoots)].sort();
396
+ if (
397
+ canonicalRoots.length !== value.providerReceiptRoots.length ||
398
+ canonicalRoots.some(
399
+ (root, index) => root !== value.providerReceiptRoots[index],
400
+ )
401
+ )
402
+ fault(
403
+ "invalid-release-receipt",
404
+ "$receipt/providerReceiptRoots",
405
+ "provider receipt roots must be sorted and unique",
406
+ );
407
+ if (
408
+ value.outcome === "complete" &&
409
+ [
410
+ value.releasePassportRoot,
411
+ value.providerTransactionRoot,
412
+ value.providerStateRoot,
413
+ ].some((root) => root === null)
414
+ )
415
+ fault(
416
+ "invalid-release-receipt",
417
+ "$receipt/outcome",
418
+ "complete receipt requires every terminal root",
419
+ );
420
+ v4CanonicalBytes(value);
421
+ return {
422
+ receipt: value,
423
+ receiptRoot: v4ContentRoot("release-receipt", value),
424
+ };
425
+ }