@kungfu-tech/buildchain 4.0.2-alpha.8 → 4.0.2

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 (157) hide show
  1. package/AGENTS.md +10 -1
  2. package/CONTRIBUTING.md +24 -0
  3. package/README.md +2 -2
  4. package/actions/promote-buildchain-ref/README.md +1 -1
  5. package/actions/v4-release-candidate-promote/README.md +28 -0
  6. package/architecture/agent-change-map.md +64 -7
  7. package/architecture/ci-lane-change-budget.json +366 -0
  8. package/architecture/internal-capabilities.json +53 -8
  9. package/architecture/maintainability-debt.json +147 -93
  10. package/architecture/maintainability-policy.json +32 -28
  11. package/architecture/release-tail-contract-inventory.json +6 -6
  12. package/architecture/v4-architecture-constitution.md +23 -20
  13. package/architecture/v4-cross-platform-adopter-qualification.json +1 -1
  14. package/architecture/v4-delivery-authority-parity.json +2 -2
  15. package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +1 -1
  16. package/architecture/v4-floating-consumer-policy.json +2 -2
  17. package/architecture/v4-next-development-parity.json +5 -5
  18. package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
  19. package/architecture/v4-platform-stage-checkpoints.json +1 -1
  20. package/architecture/v4-provider-operation-journal-contract.json +5 -2
  21. package/architecture/v4-publication-facade-patches.json +64 -0
  22. package/architecture/v4-release-activation-shadow-domain.json +5 -2
  23. package/architecture/v4-release-topology.json +74 -39
  24. package/architecture/v4-rust-wasm-production-authority.json +58 -0
  25. package/architecture/v4-stable-publication-fence.json +5 -2
  26. package/architecture/v4-stage-capsule-qualification.json +2 -2
  27. package/architecture/v4-tail-reseal-parity.json +8 -6
  28. package/architecture/v4-universal-workflow-bootstrap.json +171 -0
  29. package/architecture/v4-universal-workflow-fault-campaign.json +72 -0
  30. package/architecture/v4-universal-workflow-train-admission.json +40 -0
  31. package/architecture/workflow-taxonomy.json +1451 -0
  32. package/bin/buildchain.mjs +7 -7
  33. package/contracts/buildchain-v2-residuals-v1.json +57 -48
  34. package/contracts/dev-delivery-authority-v2.schema.json +16 -2
  35. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  36. package/contracts/v4-canonical-contracts-v1.schema.json +1 -0
  37. package/dist/site/buildchain-contract.json +93 -48
  38. package/dist/site/buildchain-site.json +222 -69
  39. package/dist/site/capability-registry.json +4 -4
  40. package/dist/site/controller-registry.json +50 -13
  41. package/dist/site/kfd-claims.json +2585 -1000
  42. package/dist/site/kfd-upstream-aggregate.json +1 -1
  43. package/dist/site/manual-registry.json +13 -13
  44. package/dist/site/node-api-registry.json +120 -115
  45. package/dist/site/page-registry.json +204 -51
  46. package/dist/site/public-surface-audit.json +3205 -1219
  47. package/dist/site/publication-authority-registry.json +1124 -362
  48. package/dist/site/publication-registry.json +4 -4
  49. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +16 -2
  50. package/dist/site/site-manifest.json +17 -17
  51. package/dist/site/workflow-registry.json +5061 -1659
  52. package/docs/MAP.md +1 -0
  53. package/docs/auditable-demo.md +1 -1
  54. package/docs/cli.md +21 -8
  55. package/docs/dev-delivery-warrant.md +1 -1
  56. package/docs/engineering-housekeeper.md +3 -3
  57. package/docs/kfd-support.md +26 -2
  58. package/docs/next-development-transition.md +2 -2
  59. package/docs/node-api-reference.md +190 -190
  60. package/docs/publication-authority.md +2 -2
  61. package/docs/release-candidate.md +3 -3
  62. package/docs/release-flow.md +67 -19
  63. package/docs/release-governance.md +8 -8
  64. package/docs/release-passport.md +27 -2
  65. package/docs/reusable-build-surface.md +16 -0
  66. package/docs/v4-adopter-delivery.md +2 -2
  67. package/docs/v4-production-release.md +71 -8
  68. package/docs/v4-rust-wasm-production-authority.md +58 -0
  69. package/docs/v4-stage-capsule.md +2 -2
  70. package/docs/v4-tail-reseal.md +1 -1
  71. package/docs/workflow-catalog.md +154 -0
  72. package/docs/workflow-path-migration.md +109 -0
  73. package/package.json +10 -6
  74. package/packages/core/artifact-verification-envelope.js +5 -5
  75. package/packages/core/buildchain-contract.js +1 -1
  76. package/packages/core/buildchain-kfd-claims.js +2 -2
  77. package/packages/core/buildchain-publication-authority.js +42 -26
  78. package/packages/core/buildchain-v4-domain.wasm +0 -0
  79. package/packages/core/ci-lane-change-budget.js +14 -1
  80. package/packages/core/controller-evidence.js +4 -1
  81. package/packages/core/dev-delivery-candidate-identity.js +40 -6
  82. package/packages/core/dev-delivery-warrant-state.js +3 -4
  83. package/packages/core/dev-delivery-warrant.js +12 -2
  84. package/packages/core/github-governance-authority.js +4 -4
  85. package/packages/core/kfd-adopter-manifest.js +46 -47
  86. package/packages/core/next-development-projection.js +2 -2
  87. package/packages/core/paper-agent-entry.js +30 -4
  88. package/packages/core/paper-fleet.js +1 -1
  89. package/packages/core/paper-runtime-channels.js +348 -0
  90. package/packages/core/paper-scaffold-content.js +10 -0
  91. package/packages/core/paper.js +37 -71
  92. package/packages/core/release-line-dry-run.js +1 -1
  93. package/packages/core/release-passport-contract.js +5 -5
  94. package/packages/core/release-passport.js +5 -4
  95. package/packages/core/release-tail-provider-plane.js +68 -1048
  96. package/packages/core/v4-canonical-contracts.js +10 -75
  97. package/packages/core/v4-domain-wasm-artifact.js +7 -0
  98. package/packages/core/v4-domain-wasm.js +216 -0
  99. package/packages/core/v4-floating-consumer-evidence.js +1 -1
  100. package/packages/core/v4-floating-consumer-policy.js +1 -1
  101. package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
  102. package/packages/core/v4-product-publication.js +19 -349
  103. package/packages/core/v4-protected-publication-source.js +19 -21
  104. package/packages/core/v4-provider-operation-journal.js +18 -487
  105. package/packages/core/v4-provider-readback-idempotency.js +12 -97
  106. package/packages/core/v4-release-activation-shadow.js +13 -500
  107. package/packages/core/v4-release-invocation.js +28 -389
  108. package/packages/core/v4-stable-publication-fence.js +13 -342
  109. package/packages/core/v4-universal-workflow-bootstrap.js +586 -0
  110. package/scripts/binary-publication-evidence.mjs +135 -0
  111. package/scripts/build-contract-core.mjs +1 -14
  112. package/scripts/build-v4-domain-wasm.mjs +189 -0
  113. package/scripts/check-action-bundles.mjs +12 -2
  114. package/scripts/check-ci-lane-change-budget.mjs +4 -1
  115. package/scripts/check-core-mechanism-inventory.mjs +4 -3
  116. package/scripts/check-inventory.mjs +35 -44
  117. package/scripts/check-maintainability.mjs +16 -113
  118. package/scripts/check-v4-floating-consumer-policy-contract.mjs +2 -2
  119. package/scripts/check-v4-public-dogfood-contract.mjs +22 -9
  120. package/scripts/check-v4-release-topology.mjs +90 -33
  121. package/scripts/check-v4-runtime-semantic-closure.mjs +4 -1
  122. package/scripts/check-v4-universal-workflow-bootstrap.mjs +266 -0
  123. package/scripts/check-workflow-taxonomy.mjs +6 -0
  124. package/scripts/copy-v4-domain-wasm.mjs +14 -0
  125. package/scripts/dev-delivery-authority-command-adapters.mjs +1 -1
  126. package/scripts/dev-delivery-authority.mjs +8 -8
  127. package/scripts/dev-delivery-source-proof-reuse.mjs +2 -1
  128. package/scripts/dev-delivery-warrant-options.mjs +14 -9
  129. package/scripts/dev-delivery-warrant-store.mjs +73 -7
  130. package/scripts/dev-delivery-warrant-transition.mjs +109 -0
  131. package/scripts/dev-delivery-warrant.mjs +76 -99
  132. package/scripts/dev-pr-auto-merge.mjs +15 -15
  133. package/scripts/generate-channel-build-workflow.mjs +7 -2
  134. package/scripts/generate-channel-promotion-workflow.mjs +7 -5
  135. package/scripts/generate-site-bundle.mjs +11 -11
  136. package/scripts/generate-v4-universal-workflow-facades.mjs +458 -0
  137. package/scripts/generate-workflow-taxonomy.mjs +25 -0
  138. package/scripts/github-output.mjs +31 -0
  139. package/scripts/maintainability-metrics.mjs +16 -5
  140. package/scripts/maintainability-public-surface.mjs +115 -0
  141. package/scripts/next-development-review.mjs +307 -0
  142. package/scripts/paper-work-fleet-cli.mjs +2 -0
  143. package/scripts/release-asset-client.mjs +91 -0
  144. package/scripts/release-candidate-resolver.mjs +9 -9
  145. package/scripts/source-verification-evidence.mjs +344 -0
  146. package/scripts/stable-candidate-qualification.mjs +1 -1
  147. package/scripts/universal-facade-maintainability.mjs +82 -0
  148. package/scripts/v4-product-publication-intent.mjs +13 -6
  149. package/scripts/v4-publication-settlement.mjs +211 -0
  150. package/scripts/v4-universal-workflow-backflow.mjs +212 -0
  151. package/scripts/v4-universal-workflow-engine.mjs +618 -0
  152. package/scripts/v4-universal-workflow-self-dogfood.mjs +205 -0
  153. package/scripts/verify-version-state-delta.mjs +173 -0
  154. package/scripts/workflow-taxonomy.mjs +507 -0
  155. package/templates/native-dev-delivery.yml +4 -7
  156. package/templates/universal-buildchain-bootstrap-recovery.yml +282 -0
  157. package/templates/universal-buildchain-bootstrap.yml +28 -0
@@ -19,6 +19,8 @@ import {
19
19
  evaluateTestBudgets,
20
20
  evaluateWorkflowBudgets,
21
21
  } from "./maintainability-governance.mjs";
22
+ import { governUniversalFacadeWorkflowMetrics } from "./universal-facade-maintainability.mjs";
23
+ import { evaluatePublicSurface } from "./maintainability-public-surface.mjs";
22
24
 
23
25
  function collectHotspots(
24
26
  root,
@@ -162,116 +164,6 @@ function selectedFunction(metrics, file, name) {
162
164
  return metrics.files[file]?.functions.find((entry) => entry.name === name);
163
165
  }
164
166
 
165
- function readJsonAtRevision(root, revision, file) {
166
- return JSON.parse(gitOutput(root, ["show", `${revision}:${file}`]));
167
- }
168
-
169
- function publicSurfaceContract(entry, kind) {
170
- if (kind === "cli") return { id: entry.id, usage: entry.usage };
171
- if (kind === "node")
172
- return {
173
- export: entry.export,
174
- specifier: entry.specifier,
175
- target: entry.target,
176
- };
177
- return {
178
- id: entry.id,
179
- path: entry.path,
180
- reusable: entry.reusable,
181
- inputs: entry.inputs || [],
182
- secrets: entry.secrets || [],
183
- outputs: entry.outputs || [],
184
- };
185
- }
186
-
187
- function evaluatePublicSurface({ root, revision, policy }) {
188
- const issues = [];
189
- const lifecycleFields = policy.publicSurfacePolicy.requiredLifecycleFields;
190
- const capabilityGroups = new Set(
191
- readJson(root, "dist/site/capability-registry.json").groups.map(
192
- (entry) => entry.id,
193
- ),
194
- );
195
- const definitions = [
196
- {
197
- file: "dist/site/cli-registry.json",
198
- collection: "commands",
199
- kind: "cli",
200
- key: "id",
201
- },
202
- {
203
- file: "dist/site/node-api-registry.json",
204
- collection: "exports",
205
- kind: "node",
206
- key: "export",
207
- },
208
- {
209
- file: "dist/site/workflow-registry.json",
210
- collection: "workflows",
211
- kind: "workflow",
212
- key: "id",
213
- },
214
- {
215
- file: "dist/site/workflow-registry.json",
216
- collection: "actions",
217
- kind: "action",
218
- key: "id",
219
- },
220
- ];
221
- for (const definition of definitions) {
222
- const current =
223
- readJson(root, definition.file)[definition.collection] || [];
224
- const baseline =
225
- readJsonAtRevision(root, revision, definition.file)[
226
- definition.collection
227
- ] || [];
228
- const baselineByKey = new Map(
229
- baseline.map((entry) => [entry[definition.key], entry]),
230
- );
231
- for (const entry of current) {
232
- const label = `${definition.kind}:${entry[definition.key]}`;
233
- for (const field of lifecycleFields) {
234
- if (
235
- !Object.prototype.hasOwnProperty.call(entry, field) ||
236
- typeof entry[field] !== "string"
237
- ) {
238
- issues.push(`${label}: lifecycle field ${field} is missing`);
239
- }
240
- }
241
- if (!capabilityGroups.has(entry.capabilityGroup)) {
242
- issues.push(
243
- `${label}: capability group ${entry.capabilityGroup || "<empty>"} is not registered`,
244
- );
245
- }
246
- const previous = baselineByKey.get(entry[definition.key]);
247
- const currentContract = publicSurfaceContract(entry, definition.kind);
248
- if (
249
- previous &&
250
- JSON.stringify(currentContract) !==
251
- JSON.stringify(publicSurfaceContract(previous, definition.kind))
252
- ) {
253
- const approval = policy.approvedPublicSurfaceTransitions?.[label];
254
- const approved =
255
- approval?.fromRevision === revision &&
256
- String(approval?.rationale || "").trim() &&
257
- JSON.stringify(approval?.contract) ===
258
- JSON.stringify(currentContract);
259
- if (!approved) {
260
- issues.push(
261
- `${label}: existing public contract drifted from ${revision}`,
262
- );
263
- }
264
- }
265
- if (!previous && !entry.nonDuplicationRationale) {
266
- issues.push(
267
- `${label}: new public surface requires a non-duplication rationale`,
268
- );
269
- }
270
- }
271
- }
272
- return issues;
273
- }
274
-
275
167
  function evaluateAddedFunctionBudgets({
276
168
  file,
277
169
  metrics,
@@ -497,12 +389,18 @@ function checkMaintainability({ root = process.cwd() } = {}) {
497
389
  root,
498
390
  extendedCoverageRevision,
499
391
  );
392
+ const { governed: governedCurrent, migration: facadeMigration } =
393
+ governUniversalFacadeWorkflowMetrics({
394
+ root,
395
+ current,
396
+ workflowMetricsAtRevision,
397
+ });
500
398
  const issues = evaluateExceptionGovernance({ policy });
501
399
  issues.push(...evaluateExceptionBudget({ policy }));
502
400
  const hotspots = collectHotspots(root, current, 20, debt.hotspots || []);
503
401
  issues.push(
504
402
  ...evaluateDebtAuthority({
505
- current,
403
+ current: governedCurrent,
506
404
  policy,
507
405
  debt,
508
406
  capabilityIds: new Set(
@@ -518,14 +416,19 @@ function checkMaintainability({ root = process.cwd() } = {}) {
518
416
  );
519
417
  issues.push(
520
418
  ...evaluateWorkflowBudgets({
521
- current,
419
+ current: governedCurrent,
522
420
  baselineFiles: baselineWorkflows,
523
421
  policy,
524
422
  }),
525
423
  );
526
424
  issues.push(...evaluateRepositoryBudgets({ current, policy }));
527
425
  issues.push(
528
- ...evaluatePublicSurface({ root, revision: enforcementRevision, policy }),
426
+ ...evaluatePublicSurface({
427
+ root,
428
+ revision: enforcementRevision,
429
+ policy,
430
+ migration: facadeMigration,
431
+ }),
529
432
  );
530
433
  if (issues.length > 0) {
531
434
  throw new Error(`maintainability check failed:\n- ${issues.join("\n- ")}`);
@@ -80,7 +80,7 @@ function assertPersistedSelectors() {
80
80
  const selector = match[2];
81
81
  const protectedBootstrap =
82
82
  relative ===
83
- ".github/workflows/buildchain-ref-promotion-recovery.yml" &&
83
+ ".github/workflows/self-ops-promotion-recovery.yml" &&
84
84
  match[1] === ".github/workflows/.release-candidate-promote.yml" &&
85
85
  selector === "alpha/v4/v4.0";
86
86
  const isV4 =
@@ -148,7 +148,7 @@ export function checkV4FloatingConsumerPolicyContract() {
148
148
  "Resolve controller identities",
149
149
  "Install Buildchain runtime dependencies",
150
150
  ]);
151
- const stageCanary = read(".github/workflows/v4-stage-capsule-canary.yml");
151
+ const stageCanary = read(".github/workflows/public-build-stage-capsule-canary.yml");
152
152
  if (
153
153
  !stageCanary.includes("consumer-admission:") ||
154
154
  !stageCanary.includes("needs: consumer-admission")
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import fs from "node:fs";
4
+ import { readWorkflowTaxonomy, workflowPath } from "./workflow-taxonomy.mjs";
4
5
  import path from "node:path";
5
6
  import { fileURLToPath } from "node:url";
6
7
 
@@ -8,8 +9,8 @@ const DEFAULT_ROOT = path.resolve(
8
9
  path.dirname(fileURLToPath(import.meta.url)),
9
10
  "..",
10
11
  );
11
- const CALLER_PATH = ".github/workflows/v4-public-consumer-dogfood.yml";
12
- const REUSABLE_PATH = ".github/workflows/v4-stage-capsule-canary.yml";
12
+ const CALLER_PATH = ".github/workflows/self-build-public-consumer-dogfood.yml";
13
+ const REUSABLE_PATH = ".github/workflows/public-build-stage-capsule-canary.yml";
13
14
  export const V4_PUBLIC_DOGFOOD_ALPHA_REF = "v4-alpha";
14
15
  const PRIVATE_CONSUMER = ["buildchain", "self", "dogfood"].join("-");
15
16
  const PRIVATE_SHADOW = ["kungfu", "shadow"].join("-");
@@ -26,7 +27,7 @@ permissions:
26
27
 
27
28
  jobs:
28
29
  dogfood:
29
- uses: kungfu-systems/buildchain/.github/workflows/v4-stage-capsule-canary.yml@${validationRef}
30
+ uses: kungfu-systems/buildchain/.github/workflows/public-build-stage-capsule-canary.yml@${validationRef}
30
31
  with:
31
32
  consumer: buildchain
32
33
  node-version: "24"
@@ -93,10 +94,19 @@ function assertReusableWorkflow(root) {
93
94
 
94
95
  function assertWorkflowInventory(root) {
95
96
  const workflowRoot = path.join(root, ".github/workflows");
97
+ const taxonomy = readWorkflowTaxonomy(root);
96
98
  for (const entry of fs.readdirSync(workflowRoot, { withFileTypes: true })) {
97
99
  if (!entry.isFile() || !/\.ya?ml$/u.test(entry.name)) continue;
98
- const relative = `.github/workflows/${entry.name}`;
100
+ let relative = `.github/workflows/${entry.name}`;
99
101
  const text = read(root, relative);
102
+ const canonical = taxonomy?.entries.find(
103
+ (item) => workflowPath(item) === relative && item.compatibility,
104
+ );
105
+ if (canonical) {
106
+ if (read(root, canonical.compatibility.path) !== text)
107
+ fail(`${relative} differs from its public compatibility identity`);
108
+ relative = canonical.compatibility.path;
109
+ }
100
110
  if (
101
111
  relative !== REUSABLE_PATH &&
102
112
  text.includes("scripts/v4-stage-capsule-qualification.mjs")
@@ -104,7 +114,7 @@ function assertWorkflowInventory(root) {
104
114
  fail(`${relative} invokes the private qualification script directly`);
105
115
  if (
106
116
  relative !== CALLER_PATH &&
107
- text.includes(".github/workflows/v4-stage-capsule-canary.yml@")
117
+ text.includes(".github/workflows/public-build-stage-capsule-canary.yml@")
108
118
  )
109
119
  fail(`${relative} creates a second v4 dogfood caller`);
110
120
  if (relative !== REUSABLE_PATH && relative !== CALLER_PATH)
@@ -113,11 +123,13 @@ function assertWorkflowInventory(root) {
113
123
  }
114
124
 
115
125
  function assertProtectedVerify(root) {
116
- const verify = read(root, ".github/workflows/verify.yml");
126
+ const verify = read(root, ".github/workflows/self-build-verify.yml");
117
127
  for (const required of [
118
128
  "needs: stage-capsule-checkpoints",
119
- "name: Enforce public consumer-only v4 dogfood",
120
- "run: node scripts/check-v4-public-dogfood-contract.mjs",
129
+ "name: Run declared verify lifecycle (full source tests and generated artifact checks)",
130
+ "node .buildchain/runtime/bin/buildchain.mjs lifecycle run verify",
131
+ "run: node scripts/source-verification-evidence.mjs plan",
132
+ "run: node scripts/source-verification-evidence.mjs seal",
121
133
  ])
122
134
  if (!verify.includes(required))
123
135
  fail(`Verify is missing protected gate ${required}`);
@@ -150,7 +162,7 @@ function assertArchitecture(root) {
150
162
  !dogfood ||
151
163
  dogfood.callerWorkflow !== CALLER_PATH ||
152
164
  dogfood.reusableWorkflow !==
153
- "kungfu-systems/buildchain/.github/workflows/v4-stage-capsule-canary.yml" ||
165
+ "kungfu-systems/buildchain/.github/workflows/public-build-stage-capsule-canary.yml" ||
154
166
  dogfood.runtimeBinding !== "job.workflow_sha" ||
155
167
  dogfood.consumerSourceBinding !== "github.sha" ||
156
168
  JSON.stringify(dogfood.executableStages) !==
@@ -193,6 +205,7 @@ function assertConsumerLifecycle(root) {
193
205
  '[lifecycle.install]\ncommand = "corepack enable pnpm && corepack pnpm@11.7.0 install --frozen-lockfile"',
194
206
  '[lifecycle.build]\ncommand = "corepack pnpm@11.7.0 run build && corepack pnpm@11.7.0 run generate:site"',
195
207
  "[lifecycle.verify]\ncommands = [",
208
+ '"corepack pnpm@11.7.0 run check",',
196
209
  ])
197
210
  if (!lifecycle.includes(declaration))
198
211
  fail(
@@ -3,6 +3,8 @@
3
3
  import assert from "node:assert/strict";
4
4
  import crypto from "node:crypto";
5
5
  import fs from "node:fs";
6
+ import ts from "typescript";
7
+ import { workflowCompatibilityIdentity } from "./workflow-taxonomy.mjs";
6
8
  import path from "node:path";
7
9
  import { fileURLToPath, pathToFileURL } from "node:url";
8
10
 
@@ -21,13 +23,35 @@ function read(relative) {
21
23
  const LOCAL_MODULE_EXTENSIONS = ["", ".js", ".mjs", ".cjs"];
22
24
  const PRIVILEGED_ENTRYPOINTS = [
23
25
  "actions/v4-release-candidate-promote/index.js",
26
+ "scripts/binary-publication-evidence.mjs",
27
+ "scripts/next-development-review.mjs",
28
+ "scripts/v4-publication-settlement.mjs",
24
29
  ];
25
30
 
26
- function localModuleSpecifiers(source) {
31
+ export function localModuleSpecifiers(source) {
27
32
  const specifiers = [];
28
- const expression =
29
- /(?:\bfrom\s+|\bimport\s*\(\s*|\bimport\s+)["'](\.[^"']+)["']/gu;
30
- for (const match of source.matchAll(expression)) specifiers.push(match[1]);
33
+ const visit = (node) => {
34
+ let value;
35
+ if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node))
36
+ value = node.moduleSpecifier;
37
+ else if (
38
+ ts.isCallExpression(node) &&
39
+ node.expression.kind === ts.SyntaxKind.ImportKeyword
40
+ )
41
+ value = node.arguments[0];
42
+ if (value && ts.isStringLiteral(value) && value.text.startsWith("."))
43
+ specifiers.push(value.text);
44
+ ts.forEachChild(node, visit);
45
+ };
46
+ visit(
47
+ ts.createSourceFile(
48
+ "module.mjs",
49
+ source,
50
+ ts.ScriptTarget.Latest,
51
+ true,
52
+ ts.ScriptKind.JS,
53
+ ),
54
+ );
31
55
  return [...new Set(specifiers)].sort();
32
56
  }
33
57
 
@@ -83,6 +107,13 @@ function rootedPathSet(paths) {
83
107
  .digest("hex")}`;
84
108
  }
85
109
 
110
+ function fileSha256(relative) {
111
+ return `sha256:${crypto
112
+ .createHash("sha256")
113
+ .update(fs.readFileSync(path.join(root, relative)))
114
+ .digest("hex")}`;
115
+ }
116
+
86
117
  function productionFiles(relative, extensions) {
87
118
  const absolute = path.join(root, relative);
88
119
  if (!fs.existsSync(absolute)) return [];
@@ -128,6 +159,12 @@ export function discoverV4ReleaseAuthorityClosure() {
128
159
  /(?:createV4ReleaseReceipt|release-receipt\.json|V4_RELEASE_RECEIPT_CONTRACT)/u,
129
160
  );
130
161
  const privilegedModules = discoverStaticModuleClosure(PRIVILEGED_ENTRYPOINTS);
162
+ const rustWasmArtifact = "packages/core/buildchain-v4-domain.wasm";
163
+ const rustWasmDistributions = [
164
+ "actions/promote-buildchain-ref/dist/buildchain-v4-domain.wasm",
165
+ "actions/release-tail/dist/buildchain-v4-domain.wasm",
166
+ "actions/v4-release-candidate-promote/dist/buildchain-v4-domain.wasm",
167
+ ];
131
168
  const legacyEngineModules = productionFiles(
132
169
  "actions/promote-buildchain-ref",
133
170
  [".js", ".mjs", ".cjs"],
@@ -153,6 +190,17 @@ export function discoverV4ReleaseAuthorityClosure() {
153
190
  modules: privilegedModules,
154
191
  root: rootedPathSet(privilegedModules),
155
192
  },
193
+ rustWasmAuthority: {
194
+ loader: "packages/core/v4-domain-wasm.js",
195
+ metadata: "packages/core/v4-domain-wasm-artifact.js",
196
+ artifact: rustWasmArtifact,
197
+ artifactRoot: fileSha256(rustWasmArtifact),
198
+ distributedArtifacts: rustWasmDistributions,
199
+ byteIdenticalDistributions: rustWasmDistributions.every(
200
+ (relative) => fileSha256(relative) === fileSha256(rustWasmArtifact),
201
+ ),
202
+ fallbackWriterCount: 0,
203
+ },
156
204
  legacyEngineModules,
157
205
  };
158
206
  }
@@ -180,33 +228,36 @@ function permission(block, name) {
180
228
  function workflowSnapshot(relative) {
181
229
  const source = read(relative);
182
230
  const document = parseWorkflowDocument(source);
183
- const jobs = document.jobs.map((job) => {
184
- const block = jobBlock(source, job.id);
185
- const uses = job.uses || null;
186
- return {
187
- id: job.id,
188
- kind: uses ? "reusable-call" : "runner",
189
- uses,
190
- permissions: {
191
- contents: permission(block, "contents"),
192
- idToken: permission(block, "id-token"),
193
- },
194
- carriers: {
195
- artifactDownload: /uses:\s+actions\/download-artifact@/u.test(block),
196
- artifactUpload: /uses:\s+actions\/upload-artifact@/u.test(block),
197
- jobOutput: /GITHUB_OUTPUT/u.test(block),
198
- },
199
- mutationSignals: [
200
- /contents:\s*write/u.test(block) && "contents-write",
201
- /id-token:\s*write/u.test(block) && "oidc-write",
202
- /(?:promote-buildchain-ref|v4-release-candidate-promote)/u.test(
203
- block,
204
- ) && "promotion-runtime",
205
- /(?:git push|npm publish|gh release (?:create|upload))/u.test(block) &&
206
- "direct-publication-command",
207
- ].filter(Boolean),
208
- };
209
- });
231
+ const jobs = document.jobs
232
+ .filter((job) => job.id !== "universal-bootstrap")
233
+ .map((job) => {
234
+ const block = jobBlock(source, job.id);
235
+ const uses = job.uses || null;
236
+ return {
237
+ id: job.id,
238
+ kind: uses ? "reusable-call" : "runner",
239
+ uses,
240
+ permissions: {
241
+ contents: permission(block, "contents"),
242
+ idToken: permission(block, "id-token"),
243
+ },
244
+ carriers: {
245
+ artifactDownload: /uses:\s+actions\/download-artifact@/u.test(block),
246
+ artifactUpload: /uses:\s+actions\/upload-artifact@/u.test(block),
247
+ jobOutput: /GITHUB_OUTPUT/u.test(block),
248
+ },
249
+ mutationSignals: [
250
+ /contents:\s*write/u.test(block) && "contents-write",
251
+ /id-token:\s*write/u.test(block) && "oidc-write",
252
+ /(?:promote-buildchain-ref|v4-release-candidate-promote)/u.test(
253
+ block,
254
+ ) && "promotion-runtime",
255
+ /(?:git push|npm publish|gh release (?:create|upload))/u.test(
256
+ block,
257
+ ) && "direct-publication-command",
258
+ ].filter(Boolean),
259
+ };
260
+ });
210
261
  return {
211
262
  path: relative,
212
263
  triggers: document.triggers,
@@ -214,6 +265,7 @@ function workflowSnapshot(relative) {
214
265
  reusableEdges: parseYamlUses(source)
215
266
  .map(({ value }) => value)
216
267
  .filter((value) => /\.github\/workflows\//u.test(value))
268
+ .filter((value) => !/\/bootstrap\.yml(?:@v4)?$/u.test(value))
217
269
  .sort(),
218
270
  };
219
271
  }
@@ -313,7 +365,12 @@ export function findUnknownV4ReleaseTopology(
313
365
  ) {
314
366
  const declared = new Set(workflowPaths);
315
367
  return allWorkflowPaths
316
- .filter((relative) => !declared.has(relative))
368
+ .filter(
369
+ (relative) =>
370
+ !declared.has(
371
+ workflowCompatibilityIdentity(root, relative, readWorkflow(relative)),
372
+ ),
373
+ )
317
374
  .filter((relative) => {
318
375
  const source = readWorkflow(relative);
319
376
  const usesReleaseAuthority = parseYamlUses(source).some(({ value }) =>
@@ -403,7 +460,7 @@ function assertAuthorityClosure(ledger) {
403
460
  );
404
461
  assert.equal(
405
462
  closure.recoveryEntry,
406
- ".github/workflows/buildchain-ref-promotion-recovery.yml",
463
+ ".github/workflows/self-ops-promotion-recovery.yml",
407
464
  );
408
465
  const engineSurface = [
409
466
  ".github/workflows/.release-candidate-promote.yml",
@@ -35,7 +35,10 @@ function publicSurfaceIds(root) {
35
35
  return new Set([
36
36
  ...Object.keys(packageJson.exports || {}).map((id) => `export:${id}`),
37
37
  ...(cli.commands || []).map((entry) => `cli:${entry.id}`),
38
- ...(workflows.workflows || []).map((entry) => `workflow:${entry.id}`),
38
+ ...(workflows.workflows || []).flatMap((entry) => [
39
+ `workflow:${entry.id}`,
40
+ ...(entry.taxonomy ? [`workflow:${entry.taxonomy.id}`] : []),
41
+ ]),
39
42
  ...(workflows.actions || []).map((entry) => `action:${entry.id}`),
40
43
  ]);
41
44
  }