@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
@@ -127,7 +127,6 @@ const requiredPaths = [
127
127
  "scripts/npm-publish-transaction.mjs",
128
128
  "scripts/paper.mjs",
129
129
  "scripts/publication-package.mjs",
130
- "scripts/publication-commit-evidence.mjs",
131
130
  "scripts/publication-reproducibility.mjs",
132
131
  "scripts/release-candidate-resolver.mjs",
133
132
  "scripts/resume-from-candidate-run.mjs",
@@ -300,8 +299,8 @@ if (channelPromotionWorkflow !== generateChannelPromotionWorkflow(advancedPromot
300
299
  throw new Error("generated channel promotion workflow is stale");
301
300
  }
302
301
  for (const requiredSnippet of [
303
- "uses: kungfu-systems/buildchain/.github/workflows/.release-candidate-promote.yml@alpha/v4/v4.0",
304
- "promotion-shell-ref: ${{ needs.consumer-admission.outputs.shell-call-ref }}",
302
+ "name: Adapt recovery inputs into the canonical v4 publisher",
303
+ "uses: kungfu-systems/buildchain/.github/workflows/release-candidate-promote.yml@v4-alpha",
305
304
  "declarative-release-tail: true",
306
305
  ]) {
307
306
  if (!boundedAlphaRecoveryWorkflow.includes(requiredSnippet)) {
@@ -316,8 +315,8 @@ for (const workflowSource of [boundedAlphaRecoveryWorkflow, channelPromotionWork
316
315
  for (const requiredSnippet of [
317
316
  "buildchain-channel:",
318
317
  `/${promotionShellRouting.alpha.workflowPath}@${promotionShellRouting.alpha.callRef}`,
319
- `/${promotionShellRouting.stable.workflowPath}@${promotionShellRouting.stable.callRef}`,
320
- `STABLE_SHELL_REF: v${selfDogfoodMajor}`,
318
+ `SELECTED_SHELL_REF: v${selfDogfoodMajor}-alpha`,
319
+ "name: Invoke the single v4 publisher adapter",
321
320
  "promotion-contract-lock-digest:",
322
321
  "authorize-promotion-runtime-override.cjs",
323
322
  "BUILDCHAIN_ROUTER_REPOSITORY: ${{ inputs.buildchain-repository }}",
@@ -329,6 +328,9 @@ for (const requiredSnippet of [
329
328
  throw new Error(`channel promotion workflow missing routing contract: ${requiredSnippet}`);
330
329
  }
331
330
  }
331
+ if (channelPromotionWorkflow.includes("Promote with stable workflow shell")) {
332
+ throw new Error("channel promotion workflow retains a parallel stable publisher");
333
+ }
332
334
  for (const forbiddenSnippet of ["job.workflow_repository", "job.workflow_sha"]) {
333
335
  if (channelPromotionWorkflow.includes(forbiddenSnippet)) {
334
336
  throw new Error(`channel promotion workflow uses unsupported GitHub context: ${forbiddenSnippet}`);
@@ -1046,7 +1048,6 @@ for (const requiredSnippet of [
1046
1048
  "resume-candidate-run-id:",
1047
1049
  "resume-expected-source-tree:",
1048
1050
  "resume-buildchain-runtime-ref:",
1049
- "uses: kungfu-systems/buildchain/.github/workflows/release-candidate-promote.yml@v4",
1050
1051
  "release-passport-buildchain-self-kfd: true",
1051
1052
  "declarative-release-tail: true",
1052
1053
  "release-passport-impact-json: .buildchain/release-impact.json",
@@ -1057,61 +1058,28 @@ for (const requiredSnippet of [
1057
1058
  }
1058
1059
  const releaseCandidatePromoteWorkflow = fs.readFileSync(path.join(root, ".github/workflows/.release-candidate-promote.yml"), "utf8");
1059
1060
  for (const requiredSnippet of [
1060
- "release-passport-kfd-1-witness-jsons:",
1061
- "release-passport-kfd-1-witness-jsons: ${{ inputs.release-passport-kfd-1-witness-jsons }}",
1062
- "release-passport-kfd-2-claim-jsons:",
1063
- "release-passport-kfd-2-claim-jsons: ${{ inputs.release-passport-kfd-2-claim-jsons }}",
1064
- "release-passport-kfd-3-prebuild-witness-jsons:",
1065
- "release-passport-kfd-3-prebuild-witness-jsons: ${{ inputs.release-passport-kfd-3-prebuild-witness-jsons }}",
1066
- "release-passport-kfd-3-artifact-witness-jsons:",
1067
- "release-passport-kfd-3-artifact-witness-jsons: ${{ inputs.release-passport-kfd-3-artifact-witness-jsons }}",
1068
- "release-passport-kfd-3-artifact-verify-command:",
1069
- "release-passport-kfd-adopter-manifest-json:", "release-passport-kfd-adopter-manifest-json: ${{ inputs.release-passport-kfd-adopter-manifest-json }}",
1070
- "release-passport-kfd-support-matrix-json:", "release-passport-kfd-support-matrix-json: ${{ inputs.release-passport-kfd-support-matrix-json }}",
1071
- "release-passport-kfd-product-gate-jsons:",
1072
- "release-passport-kfd-product-gate-jsons: ${{ inputs.release-passport-kfd-product-gate-jsons }}",
1073
- "release-passport-invariant-passport-jsons:",
1074
- "release-passport-invariant-passport-jsons: ${{ inputs.release-passport-invariant-passport-jsons }}",
1075
- "release-passport-invariant-passport-command:",
1076
- "release-passport-invariant-passport-command: ${{ inputs.release-passport-invariant-passport-command }}",
1077
- "release-passport-buildchain-self-kfd:",
1078
- "release-passport-buildchain-self-kfd: ${{ inputs.release-passport-buildchain-self-kfd }}",
1079
- "github-release:",
1080
- "default: true",
1081
- "github-release: ${{ inputs.github-release }}",
1082
- "github-release-payload-patterns:",
1083
- "github-release-artifact-paths: ${{ steps.rc.outputs.release-candidate-github-release-artifact-paths }}",
1084
- "github-release-title: ${{ inputs.github-release-title }}",
1085
- "github-release-notes: ${{ inputs.github-release-notes }}",
1086
- "publication-commit-command:",
1087
- "BUILDCHAIN_PUBLICATION_COMMIT_SIGNING_KEY:",
1088
- "KUNGFU_GOVERNANCE_AUDITOR_APP_PRIVATE_KEY:",
1089
- "Commit consumer publication authority last",
1090
- "node .buildchain/runtime/scripts/publication-commit-evidence.mjs",
1091
- "require-publish-source-lock: \"true\"",
1092
- "publish-source-ref: ${{ steps.publish-gate.outputs.ref }}",
1093
- "publish-source-sha: ${{ steps.publish-gate.outputs.sha }}",
1094
- "publish-source-locked: ${{ steps.publish-gate.outputs.locked }}",
1095
- "expected-publication-version: ${{ needs.publication-plan.outputs.version }}",
1096
- "publication-version: ${{ needs.publication-plan.outputs.version }}",
1097
- "name: Plan exact publication version",
1098
- "name: Install exact publication planning dependencies",
1099
- "DRY_RUN: ${{ inputs.dry-run }}",
1100
- "if (dryRun) {",
1101
- "Enforce Buildchain stable release canary gate",
1102
- "BUILDCHAIN_STABLE_RELEASE_POLICY: .buildchain/stable-release-policy.json",
1103
- "Consumer has no binary-distribution.yml; standalone binary dispatch is not applicable.",
1104
- "gh workflow view binary-distribution.yml",
1105
- "resume-candidate-run-id:",
1106
- "node .buildchain/runtime/scripts/resume-from-candidate-run.mjs",
1107
- "publish-sealed-bundle-root: ${{ steps.rc.outputs.publish-sealed-bundle-root }}",
1108
- "BUILDCHAIN_EXPECTED_TRANSACTION_ID: ${{ inputs.resume-transaction-id }}",
1109
- "if: ${{ inputs.resume-candidate-run-id == '' }}",
1110
- "Bridge Buildchain self-runtime dependencies",
1111
- "ln -s .buildchain/runtime/node_modules node_modules",
1061
+ "name: QUALIFY canonical v4 release invocation inputs",
1062
+ "name: APPLY one rooted provider transaction",
1063
+ "name: SETTLE terminal ReleaseReceipt projection",
1064
+ "uses: ./.buildchain/runtime/actions/v4-release-candidate-promote",
1065
+ "publisher-workflow-sha:",
1066
+ "runtime-commit:",
1067
+ "runtime-tree:",
1068
+ "release-invocation-root:",
1069
+ "release-transaction-root:",
1070
+ "release-receipt-root:",
1112
1071
  ]) {
1113
1072
  if (!releaseCandidatePromoteWorkflow.includes(requiredSnippet)) {
1114
- throw new Error(`release candidate promote workflow missing KFD gate pass-through: ${requiredSnippet}`);
1073
+ throw new Error(`release candidate promote workflow missing canonical v4 boundary: ${requiredSnippet}`);
1074
+ }
1075
+ }
1076
+ for (const retiredSnippet of [
1077
+ "Commit consumer publication authority last",
1078
+ "publish-github-artifact-attestation-evidence.mjs",
1079
+ "capture-package-release-propagation.mjs",
1080
+ ]) {
1081
+ if (releaseCandidatePromoteWorkflow.includes(retiredSnippet)) {
1082
+ throw new Error(`release candidate promote workflow retains parallel publication authority: ${retiredSnippet}`);
1115
1083
  }
1116
1084
  }
1117
1085
  const workflowDir = path.join(root, ".github/workflows");
@@ -19,18 +19,28 @@ 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
- function collectHotspots(root, current, limit = 20, shallowFallback = []) {
25
+ function collectHotspots(
26
+ root,
27
+ current,
28
+ limit = 20,
29
+ shallowFallback = [],
30
+ {
31
+ baseRef = process.env.GITHUB_BASE_REF || process.env.GITHUB_REF_NAME || "",
32
+ } = {},
33
+ ) {
24
34
  const maintained = new Set([
25
35
  ...Object.keys(current.files || {}),
26
36
  ...Object.keys(current.tests || {}),
27
37
  ...Object.keys(current.workflows || {}),
28
38
  ]);
29
- // Shallow consumers cannot reproduce repository-wide churn ranking.
30
- // Reuse the audited routes; full clones still re-rank them below.
31
- // This keeps consumer verification deterministic without inventing history.
39
+ // Release-line reconciliation reuses audited routes across equivalent-tree DAG shapes.
32
40
  if (
33
- gitOutput(root, ["rev-parse", "--is-shallow-repository"]).trim() === "true"
41
+ gitOutput(root, ["rev-parse", "--is-shallow-repository"]).trim() ===
42
+ "true" ||
43
+ /^(?:alpha|release|publish-gate)\//u.test(baseRef)
34
44
  ) {
35
45
  return shallowFallback.slice(0, limit);
36
46
  }
@@ -154,116 +164,6 @@ function selectedFunction(metrics, file, name) {
154
164
  return metrics.files[file]?.functions.find((entry) => entry.name === name);
155
165
  }
156
166
 
157
- function readJsonAtRevision(root, revision, file) {
158
- return JSON.parse(gitOutput(root, ["show", `${revision}:${file}`]));
159
- }
160
-
161
- function publicSurfaceContract(entry, kind) {
162
- if (kind === "cli") return { id: entry.id, usage: entry.usage };
163
- if (kind === "node")
164
- return {
165
- export: entry.export,
166
- specifier: entry.specifier,
167
- target: entry.target,
168
- };
169
- return {
170
- id: entry.id,
171
- path: entry.path,
172
- reusable: entry.reusable,
173
- inputs: entry.inputs || [],
174
- secrets: entry.secrets || [],
175
- outputs: entry.outputs || [],
176
- };
177
- }
178
-
179
- function evaluatePublicSurface({ root, revision, policy }) {
180
- const issues = [];
181
- const lifecycleFields = policy.publicSurfacePolicy.requiredLifecycleFields;
182
- const capabilityGroups = new Set(
183
- readJson(root, "dist/site/capability-registry.json").groups.map(
184
- (entry) => entry.id,
185
- ),
186
- );
187
- const definitions = [
188
- {
189
- file: "dist/site/cli-registry.json",
190
- collection: "commands",
191
- kind: "cli",
192
- key: "id",
193
- },
194
- {
195
- file: "dist/site/node-api-registry.json",
196
- collection: "exports",
197
- kind: "node",
198
- key: "export",
199
- },
200
- {
201
- file: "dist/site/workflow-registry.json",
202
- collection: "workflows",
203
- kind: "workflow",
204
- key: "id",
205
- },
206
- {
207
- file: "dist/site/workflow-registry.json",
208
- collection: "actions",
209
- kind: "action",
210
- key: "id",
211
- },
212
- ];
213
- for (const definition of definitions) {
214
- const current =
215
- readJson(root, definition.file)[definition.collection] || [];
216
- const baseline =
217
- readJsonAtRevision(root, revision, definition.file)[
218
- definition.collection
219
- ] || [];
220
- const baselineByKey = new Map(
221
- baseline.map((entry) => [entry[definition.key], entry]),
222
- );
223
- for (const entry of current) {
224
- const label = `${definition.kind}:${entry[definition.key]}`;
225
- for (const field of lifecycleFields) {
226
- if (
227
- !Object.prototype.hasOwnProperty.call(entry, field) ||
228
- typeof entry[field] !== "string"
229
- ) {
230
- issues.push(`${label}: lifecycle field ${field} is missing`);
231
- }
232
- }
233
- if (!capabilityGroups.has(entry.capabilityGroup)) {
234
- issues.push(
235
- `${label}: capability group ${entry.capabilityGroup || "<empty>"} is not registered`,
236
- );
237
- }
238
- const previous = baselineByKey.get(entry[definition.key]);
239
- const currentContract = publicSurfaceContract(entry, definition.kind);
240
- if (
241
- previous &&
242
- JSON.stringify(currentContract) !==
243
- JSON.stringify(publicSurfaceContract(previous, definition.kind))
244
- ) {
245
- const approval = policy.approvedPublicSurfaceTransitions?.[label];
246
- const approved =
247
- approval?.fromRevision === revision &&
248
- String(approval?.rationale || "").trim() &&
249
- JSON.stringify(approval?.contract) ===
250
- JSON.stringify(currentContract);
251
- if (!approved) {
252
- issues.push(
253
- `${label}: existing public contract drifted from ${revision}`,
254
- );
255
- }
256
- }
257
- if (!previous && !entry.nonDuplicationRationale) {
258
- issues.push(
259
- `${label}: new public surface requires a non-duplication rationale`,
260
- );
261
- }
262
- }
263
- }
264
- return issues;
265
- }
266
-
267
167
  function evaluateAddedFunctionBudgets({
268
168
  file,
269
169
  metrics,
@@ -489,12 +389,18 @@ function checkMaintainability({ root = process.cwd() } = {}) {
489
389
  root,
490
390
  extendedCoverageRevision,
491
391
  );
392
+ const { governed: governedCurrent, migration: facadeMigration } =
393
+ governUniversalFacadeWorkflowMetrics({
394
+ root,
395
+ current,
396
+ workflowMetricsAtRevision,
397
+ });
492
398
  const issues = evaluateExceptionGovernance({ policy });
493
399
  issues.push(...evaluateExceptionBudget({ policy }));
494
400
  const hotspots = collectHotspots(root, current, 20, debt.hotspots || []);
495
401
  issues.push(
496
402
  ...evaluateDebtAuthority({
497
- current,
403
+ current: governedCurrent,
498
404
  policy,
499
405
  debt,
500
406
  capabilityIds: new Set(
@@ -510,14 +416,19 @@ function checkMaintainability({ root = process.cwd() } = {}) {
510
416
  );
511
417
  issues.push(
512
418
  ...evaluateWorkflowBudgets({
513
- current,
419
+ current: governedCurrent,
514
420
  baselineFiles: baselineWorkflows,
515
421
  policy,
516
422
  }),
517
423
  );
518
424
  issues.push(...evaluateRepositoryBudgets({ current, policy }));
519
425
  issues.push(
520
- ...evaluatePublicSurface({ root, revision: enforcementRevision, policy }),
426
+ ...evaluatePublicSurface({
427
+ root,
428
+ revision: enforcementRevision,
429
+ policy,
430
+ migration: facadeMigration,
431
+ }),
521
432
  );
522
433
  if (issues.length > 0) {
523
434
  throw new Error(`maintainability check failed:\n- ${issues.join("\n- ")}`);
@@ -8,6 +8,7 @@ import {
8
8
  collectHistoryRows,
9
9
  collectRevisionCatalog,
10
10
  countsBy,
11
+ ensureCapabilityCutLineage,
11
12
  git,
12
13
  sha256,
13
14
  } from "./v3-v4-capability-catalog.mjs";
@@ -17,9 +18,8 @@ export const V3_V4_CAPABILITY_INVENTORY_CONTRACT =
17
18
  export const V3_V4_CAPABILITY_CUTS = Object.freeze({
18
19
  priorFamilyV3: "6b96bdad8d9f8ccf9275f27d9370a226a9c78465",
19
20
  liveV3: "8493bf140a7f567e76aff3119f3d39ff026afc84",
20
- liveV4: "11b4ab21405cdffcc9d6dc10cd947618d9d1bf9c",
21
+ liveV4: "97edd5b93eb67e5bf36ad55726e08231b47b70c0",
21
22
  });
22
-
23
23
  const INVENTORY_PATH = "architecture/v3-v4-live-capability-inventory.json";
24
24
  const ALLOWED_DISPOSITIONS = new Set([
25
25
  "v4-native",
@@ -92,64 +92,6 @@ function capabilityCutAvailable(root, revision) {
92
92
  }
93
93
  }
94
94
 
95
- export function assertCapabilityCutAncestor({
96
- root = process.cwd(),
97
- revision,
98
- descendant = "HEAD",
99
- label = "capability cut",
100
- } = {}) {
101
- try {
102
- execFileSync("git", ["merge-base", "--is-ancestor", revision, descendant], {
103
- cwd: root,
104
- stdio: "ignore",
105
- });
106
- } catch {
107
- throw new Error(
108
- `${label} ${revision} must be an ancestor of ${descendant}; regenerate the cut after rebasing instead of relying on a retained local object`,
109
- );
110
- }
111
- }
112
-
113
- function repositoryIsShallow(root) {
114
- return (
115
- execFileSync("git", ["rev-parse", "--is-shallow-repository"], {
116
- cwd: root,
117
- encoding: "utf8",
118
- }).trim() === "true"
119
- );
120
- }
121
-
122
- export function ensureCapabilityCutAncestor({
123
- root = process.cwd(),
124
- revision,
125
- descendant = "HEAD",
126
- label = "capability cut",
127
- } = {}) {
128
- try {
129
- assertCapabilityCutAncestor({ root, revision, descendant, label });
130
- return;
131
- } catch (error) {
132
- if (!repositoryIsShallow(root)) throw error;
133
- }
134
- const descendantCommit = execFileSync(
135
- "git",
136
- ["rev-parse", `${descendant}^{commit}`],
137
- { cwd: root, encoding: "utf8" },
138
- ).trim();
139
- try {
140
- execFileSync(
141
- "git",
142
- ["fetch", "--no-tags", "--depth=128", "origin", descendantCommit],
143
- { cwd: root, stdio: "ignore" },
144
- );
145
- } catch {
146
- throw new Error(
147
- `${label} ${revision} ancestry could not be hydrated from ${descendantCommit} through a bounded origin fetch`,
148
- );
149
- }
150
- assertCapabilityCutAncestor({ root, revision, descendant, label });
151
- }
152
-
153
95
  function ensureCapabilityCutsAvailable(root) {
154
96
  const revisions = Object.values(V3_V4_CAPABILITY_CUTS);
155
97
  const missing = revisions.filter(
@@ -170,7 +112,7 @@ function ensureCapabilityCutsAvailable(root) {
170
112
  `v3/v4 capability cuts are unavailable after a bounded origin fetch: ${unavailable.join(", ")}`,
171
113
  );
172
114
  }
173
- ensureCapabilityCutAncestor({
115
+ ensureCapabilityCutLineage({
174
116
  root,
175
117
  revision: V3_V4_CAPABILITY_CUTS.liveV4,
176
118
  label: "live v4 capability cut",
@@ -52,16 +52,11 @@ function assertOrdered(relative, markers) {
52
52
 
53
53
  export function assertPromotionCertificationWiring(source) {
54
54
  for (const marker of [
55
- "path: .buildchain/runtime/candidate-policy-runtime",
56
- "BUILDCHAIN_EXPECTED_RUNTIME_SHA: ${{ steps.v4-policy-caller.outputs.runtime-sha }}",
57
- "policy_runtime=.buildchain/runtime",
58
- 'node "${policy_runtime}/scripts/v4-consumer-policy.mjs" certify',
59
- "passport.consumerPolicy?.receipt?.caller?.sourceSha",
60
- "path: .buildchain/runtime/policy-caller",
61
- '--caller-root "${{ github.workspace }}/.buildchain/runtime/policy-caller"',
62
- '--stable-lock "${{ inputs.buildchain-stable-contract-lock-path }}"',
63
- '--alpha-lock "${{ inputs.buildchain-alpha-contract-lock-path }}"',
64
- "release-passport-v4-consumer-policy-certification-root: ${{ steps.v4-policy-certification.outputs.v4-consumer-policy-certification-root }}",
55
+ "Translate and admit legacy-compatible inputs",
56
+ "BUILDCHAIN_PROMOTION_INPUTS_JSON: ${{ toJSON(inputs) }}",
57
+ "Resolve and qualify the sealed release candidate",
58
+ "BUILDCHAIN_RUNTIME_AUTHORIZATION_JSON",
59
+ "QUALIFY canonical v4 release invocation inputs",
65
60
  ]) {
66
61
  if (!source.includes(marker)) {
67
62
  fail(`promotion certification is missing ${marker}`);
@@ -165,8 +160,7 @@ export function checkV4FloatingConsumerPolicyContract() {
165
160
  const promotion = read(".github/workflows/release-candidate-promote.yml");
166
161
  if (
167
162
  !promotion.includes("consumer-admission:") ||
168
- !jobDependsOn(promotion, "alpha", "consumer-admission") ||
169
- !jobDependsOn(promotion, "stable", "consumer-admission")
163
+ !jobDependsOn(promotion, "invoke", "consumer-admission")
170
164
  ) {
171
165
  fail(
172
166
  "release candidate promotion is not transitively gated by consumer admission",
@@ -179,16 +173,12 @@ export function checkV4FloatingConsumerPolicyContract() {
179
173
  ["packages/core/release-candidate.js", "consumerPolicy"],
180
174
  ["packages/core/release-passport.js", "v4ConsumerPolicy"],
181
175
  [
182
- "actions/promote-buildchain-ref/action.yml",
183
- "release-passport-v4-consumer-policy-certification-json",
176
+ "actions/v4-release-candidate-promote/index.js",
177
+ "candidate.consumerPolicy?.receiptRoot",
184
178
  ],
185
179
  [
186
- "actions/promote-buildchain-ref/action.yml",
187
- "release-passport-v4-consumer-policy-certification-root",
188
- ],
189
- [
190
- ".github/workflows/.release-candidate-promote.yml",
191
- "v4-policy-certification",
180
+ "actions/v4-release-candidate-promote/index.js",
181
+ "createV4ReleaseInvocation",
192
182
  ],
193
183
  ]) {
194
184
  if (!read(relative).includes(marker)) {