@kungfu-tech/buildchain 3.0.9-alpha.1 → 3.0.9-alpha.10

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 (100) hide show
  1. package/bin/buildchain.mjs +9 -1
  2. package/contracts/dev-delivery-authority-v2.schema.json +253 -0
  3. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  4. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  5. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  6. package/contracts/next-development-request-v1.schema.json +66 -0
  7. package/contracts/next-development-transition-v1.schema.json +292 -0
  8. package/dist/site/agent-index.json +1 -0
  9. package/dist/site/artifact-schemas.json +2 -0
  10. package/dist/site/buildchain-contract.json +74 -14
  11. package/dist/site/buildchain-site.json +334 -36
  12. package/dist/site/capability-registry.json +7 -6
  13. package/dist/site/cli-registry.json +41 -2
  14. package/dist/site/kfd-claims.json +193 -9
  15. package/dist/site/kfd-upstream-aggregate.json +9 -9
  16. package/dist/site/manual-registry.json +23 -7
  17. package/dist/site/node-api-registry.json +7789 -4648
  18. package/dist/site/page-registry.json +315 -25
  19. package/dist/site/public-surface-audit.json +353 -8
  20. package/dist/site/publication-registry.json +4 -4
  21. package/dist/site/release-passport-check-manifest.json +1 -0
  22. package/dist/site/release-provenance.json +12 -0
  23. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +442 -0
  24. package/dist/site/schemas/release-passport-v1.schema.json +3 -0
  25. package/dist/site/site-manifest.json +19 -11
  26. package/dist/site/workflow-registry.json +15 -7
  27. package/docs/MAP.md +5 -2
  28. package/docs/adopter-delivery-gate.md +106 -0
  29. package/docs/aws-us-elastic-runner-burst-plane.md +30 -3
  30. package/docs/cli-reference.md +200 -13
  31. package/docs/dev-alpha-candidate-patrol.md +8 -0
  32. package/docs/dev-delivery-qualification-landing-adr.md +137 -0
  33. package/docs/dev-delivery-warrant.md +149 -22
  34. package/docs/kfd-support.md +7 -2
  35. package/docs/next-development-transition.md +119 -0
  36. package/docs/node-api-reference.md +381 -204
  37. package/docs/release-governance.md +10 -7
  38. package/docs/release-passport.md +8 -2
  39. package/docs/versioning.md +4 -1
  40. package/package.json +21 -6
  41. package/packages/core/README.md +25 -0
  42. package/packages/core/adopter-delivery-gate.js +576 -0
  43. package/packages/core/adopter-delivery-json.js +66 -0
  44. package/packages/core/adopter-delivery-passport.js +259 -0
  45. package/packages/core/adopter-delivery-vectors.js +158 -0
  46. package/packages/core/adopter-delivery-vectors.json +77 -0
  47. package/packages/core/artifact-verification-envelope.js +5 -5
  48. package/packages/core/buildchain-agent-manuals.js +1 -0
  49. package/packages/core/buildchain-channel-identity.js +2 -3
  50. package/packages/core/buildchain-compatibility-proof.js +22 -0
  51. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  52. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  53. package/packages/core/channel-candidate.js +8 -0
  54. package/packages/core/channel-promotion-baseline.js +52 -0
  55. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  56. package/packages/core/dev-delivery-authority.js +996 -0
  57. package/packages/core/dev-delivery-native-proof.js +418 -0
  58. package/packages/core/dev-delivery-warrant-settlement.js +67 -20
  59. package/packages/core/dev-delivery-warrant.js +128 -46
  60. package/packages/core/kfd-adopter-category-driver.js +167 -0
  61. package/packages/core/kfd-adopter-manifest.js +49 -50
  62. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  63. package/packages/core/next-development-candidate-reservation.js +186 -0
  64. package/packages/core/next-development-controller.js +726 -0
  65. package/packages/core/next-development-projection.js +288 -0
  66. package/packages/core/next-development-transition.js +738 -0
  67. package/packages/core/paper-agent-entry.js +7 -4
  68. package/packages/core/paper.js +14 -7
  69. package/packages/core/release-passport-contract.js +10 -6
  70. package/packages/core/release-passport.js +29 -12
  71. package/scripts/aws-macos-jit-controller-core.mjs +239 -4
  72. package/scripts/aws-macos-jit-controller.mjs +198 -2
  73. package/scripts/aws-macos-jit-instance-rehydrate.mjs +260 -0
  74. package/scripts/aws-macos-jit-source-rebind.mjs +235 -14
  75. package/scripts/aws-macos-jit.mjs +12 -0
  76. package/scripts/buildchain-cli-help.mjs +9 -2
  77. package/scripts/check-internal-architecture.mjs +1 -0
  78. package/scripts/check-inventory.mjs +12 -1
  79. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  80. package/scripts/dev-delivery-authority.mjs +368 -0
  81. package/scripts/dev-delivery-native-run.mjs +235 -0
  82. package/scripts/dev-delivery-proof.mjs +64 -2
  83. package/scripts/dev-delivery-two-phase-resume.mjs +90 -0
  84. package/scripts/dev-delivery-two-phase.mjs +577 -0
  85. package/scripts/dev-delivery-warrant.mjs +47 -5
  86. package/scripts/dev-pr-delivery-warrant.mjs +19 -14
  87. package/scripts/generate-buildchain-kfd-witnesses.mjs +2 -2
  88. package/scripts/generate-channel-build-workflow.mjs +4 -0
  89. package/scripts/generate-next-development-guidance.mjs +49 -0
  90. package/scripts/generate-site-bundle.mjs +8 -3
  91. package/scripts/init-repo.mjs +135 -62
  92. package/scripts/next-development-self-dogfood-harness.mjs +409 -0
  93. package/scripts/next-development-self-dogfood.mjs +532 -0
  94. package/scripts/next-development-transition.mjs +47 -0
  95. package/scripts/release-candidate-tail-reseal.mjs +426 -0
  96. package/scripts/seal-artifact-signing-requests.mjs +7 -4
  97. package/scripts/site-capability-metadata.mjs +23 -1
  98. package/scripts/stable-candidate-qualification.mjs +7 -7
  99. package/scripts/workflow-call-contract.mjs +1 -1
  100. package/templates/native-dev-delivery.yml +86 -0
@@ -13,6 +13,7 @@ import {
13
13
  workCheck,
14
14
  } from "./paper-repository.js";
15
15
  import { mergePublicationRehearsalAgentInstructions } from "./publication-rehearsal-projection.js";
16
+ import { mergeNextDevelopmentAgentInstructions } from "./next-development-projection.js";
16
17
 
17
18
  export const PAPER_AGENT_ENTRY_CONTRACT = "kungfu-buildchain-paper-agent-entry";
18
19
  export const PAPER_AGENT_ENTRY_SCHEMA_VERSION = 1;
@@ -168,10 +169,12 @@ export function paperAgentEntryFiles({
168
169
  [PAPER_PATHS.agentEntry, jsonText(entry)],
169
170
  [
170
171
  PAPER_PATHS.agentInstructions,
171
- mergePublicationRehearsalAgentInstructions(
172
- mergePaperAgentEntryInstructions(currentAgents, {
173
- developmentRef: resolvedDevelopmentRef,
174
- }),
172
+ mergeNextDevelopmentAgentInstructions(
173
+ mergePublicationRehearsalAgentInstructions(
174
+ mergePaperAgentEntryInstructions(currentAgents, {
175
+ developmentRef: resolvedDevelopmentRef,
176
+ }),
177
+ ),
175
178
  ),
176
179
  ],
177
180
  ]);
@@ -51,6 +51,11 @@ import {
51
51
  projectPublicationRehearsalToml,
52
52
  publicationRehearsalWorkflow,
53
53
  } from "./publication-rehearsal-projection.js";
54
+ import {
55
+ appendNextDevelopmentToml,
56
+ nextDevelopmentWorkflowHeader,
57
+ projectNextDevelopmentToml,
58
+ } from "./next-development-projection.js";
54
59
 
55
60
  export { PAPER_PATHS, resolvePaperRepository } from "./paper-repository.js";
56
61
  export {
@@ -356,7 +361,7 @@ immutable_base_url = ${tomlString(joinUrl(siteBaseUrl, "archive").replace(/\/$/,
356
361
  registry_path = ".buildchain/publication/publication-registry.json"
357
362
  `
358
363
  : "";
359
- return appendPublicationRehearsalToml(`schema = 1
364
+ return appendNextDevelopmentToml(appendPublicationRehearsalToml(`schema = 1
360
365
 
361
366
  [project]
362
367
  type = "publication-artifact"
@@ -390,14 +395,14 @@ command = "make pdf"
390
395
 
391
396
  [lifecycle.verify]
392
397
  command = "make check"
393
- `);
398
+ `));
394
399
  }
395
400
 
396
401
  function scaffoldBuildWorkflow(
397
402
  buildchainSha,
398
403
  { artifactName = "paper-publication" } = {},
399
404
  ) {
400
- return `name: Build
405
+ return `${nextDevelopmentWorkflowHeader()}name: Build
401
406
 
402
407
  on:
403
408
  workflow_dispatch:
@@ -425,7 +430,7 @@ jobs:
425
430
  }
426
431
 
427
432
  function scaffoldVerifyWorkflow(buildchainSha) {
428
- return `name: Verify
433
+ return `${nextDevelopmentWorkflowHeader()}name: Verify
429
434
 
430
435
  on:
431
436
  pull_request:
@@ -456,7 +461,7 @@ function scaffoldReleaseWorkflow(
456
461
  const passportInput = releasePassportProductName
457
462
  ? ` release-passport-product-name: ${JSON.stringify(releasePassportProductName)}\n`
458
463
  : "";
459
- return `name: Paper Release
464
+ return `${nextDevelopmentWorkflowHeader()}name: Paper Release
460
465
 
461
466
  on:
462
467
  workflow_dispatch:
@@ -1017,8 +1022,10 @@ function migrationFiles({
1017
1022
  const files = new Map([
1018
1023
  [
1019
1024
  PAPER_PATHS.config,
1020
- projectPublicationRehearsalToml(
1021
- fs.readFileSync(path.resolve(cwd, PAPER_PATHS.config), "utf8"),
1025
+ projectNextDevelopmentToml(
1026
+ projectPublicationRehearsalToml(
1027
+ fs.readFileSync(path.resolve(cwd, PAPER_PATHS.config), "utf8"),
1028
+ ),
1022
1029
  ),
1023
1030
  ],
1024
1031
  [PAPER_PATHS.contractLock, contractLockText],
@@ -10,6 +10,7 @@ import {
10
10
  installedKfdPackageArtifactRoot,
11
11
  validateKfdAdopterReleaseBinding,
12
12
  } from "./artifact-verification-envelope.js";
13
+ import { normalizeAdopterDeliveryPassportBinding } from "./adopter-delivery-passport.js";
13
14
 
14
15
  export const RELEASE_PASSPORT_CONTRACT = "kungfu-buildchain-release-passport";
15
16
  export const RELEASE_CHECK_REPORT_CONTRACT = "kungfu-buildchain-release-check-report";
@@ -110,6 +111,7 @@ export const RELEASE_PASSPORT_SCHEMA = {
110
111
  "kfd-1": OBJECT,
111
112
  "kfd-2": OBJECT,
112
113
  "kfd-3": OBJECT,
114
+ adopterDelivery: OBJECT,
113
115
  kfdAdopter: OBJECT,
114
116
  kfdSupport: OBJECT,
115
117
  },
@@ -134,6 +136,7 @@ const BUILDCHAIN_AGGREGATION_FIELDS = [
134
136
  "platformArtifactManifests",
135
137
  "distTagPromotion",
136
138
  "controllerReceipts",
139
+ "adopterDelivery",
137
140
  "kfdAdopter",
138
141
  "kfdSupport",
139
142
  "githubArtifactAttestations",
@@ -356,7 +359,7 @@ export function defaultReleaseLlmsText({ tag = "", passportPath = "buildchain.re
356
359
  ].join("\n");
357
360
  }
358
361
 
359
- export function buildReleaseArtifactEvidence({ normalizedAssets = [], repository = "", tag = "", sourceSha = "", workflow = {}, kfdAdopter } = {}) {
362
+ export function buildReleaseArtifactEvidence({ normalizedAssets = [], repository = "", tag = "", sourceSha = "", workflow = {}, adopterDelivery, kfdAdopter } = {}) {
360
363
  return {
361
364
  schemaVersion: 1,
362
365
  contract: "kungfu-buildchain-artifact-evidence",
@@ -381,6 +384,7 @@ export function buildReleaseArtifactEvidence({ normalizedAssets = [], repository
381
384
  sha256: asset.sha256, url: asset.url, githubAssetId: asset.githubAssetId,
382
385
  attestation: passportOptional(asset.attestation || ""),
383
386
  })),
387
+ ...(adopterDelivery ? { adopterDelivery: normalizeAdopterDeliveryPassportBinding(adopterDelivery) } : {}),
384
388
  ...(kfdAdopter ? { kfdAdopter: structuredClone(kfdAdopter) } : {}),
385
389
  };
386
390
  }
@@ -405,7 +409,7 @@ export function prepareReleasePassportKfdSections({ kfd1, kfd2Claims, kfd3, kfdA
405
409
  };
406
410
  }
407
411
 
408
- export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], comparisonMatrix, sourceSha = "", checkedAt } = {}) {
412
+ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], comparisonMatrix, expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", sourceSha = "", checkedAt } = {}) {
409
413
  if (!manifest) {
410
414
  if (comparisonMatrix || gateResults.length > 0) {
411
415
  throw new Error("KFD support and product-gate inputs require --kfd-adopter-manifest-json; --kfd-support-matrix-json is comparison-only");
@@ -414,7 +418,7 @@ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], c
414
418
  }
415
419
  const manifestGate = createKfdAdopterManifestGate({
416
420
  manifest, packageArtifactRoot: installedKfdPackageArtifactRoot(), gateResults,
417
- expectedSourceSha: sourceSha, checkedAt,
421
+ authorityPath: "kfd-adopter-manifest.json", expectedAdopterId, expectedSourceRepository, expectedSourceSha: sourceSha, checkedAt,
418
422
  });
419
423
  const legacyProjection = createKfdLegacySupportMatrixProjection({ manifest, manifestGate });
420
424
  if (comparisonMatrix) {
@@ -425,18 +429,18 @@ export function collectKfdAdopterReleaseEvidence({ manifest, gateResults = [], c
425
429
  }
426
430
  return {
427
431
  manifest, manifestGate, legacyProjection,
428
- binding: createKfdAdopterReleaseBinding({ manifest, manifestGate, legacyProjection, expectedSourceSha: sourceSha }),
432
+ binding: createKfdAdopterReleaseBinding({ manifest, manifestGate, legacyProjection, expectedAdopterId, expectedSourceRepository, expectedSourceSha: sourceSha }),
429
433
  };
430
434
  }
431
435
 
432
- export function validateKfdAdopterReleaseEvidence({ binding, artifactBinding, manifest, manifestGate, legacyProjection, passportLegacyProjection, expectedSourceSha = "" } = {}) {
436
+ export function validateKfdAdopterReleaseEvidence({ binding, artifactBinding, manifest, manifestGate, legacyProjection, passportLegacyProjection, expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", expectedSourceSha = "" } = {}) {
433
437
  if (!binding) {
434
438
  return passportLegacyProjection
435
439
  ? [{ code: "kfdSupport.authority", message: "legacy KFD support projection requires the standard adopter manifest binding" }]
436
440
  : [];
437
441
  }
438
442
  const issues = validateKfdAdopterReleaseBinding(binding, {
439
- manifest, manifestGate, legacyProjection, expectedSourceSha,
443
+ manifest, manifestGate, legacyProjection, expectedAdopterId, expectedSourceRepository, expectedSourceSha,
440
444
  }).issues.map((entry) => ({ code: `kfdAdopter.${entry.path || entry.code}`, message: entry.message, details: entry }));
441
445
  if (!artifactBinding || passportStableJson(artifactBinding) !== passportStableJson(binding)) {
442
446
  issues.push({ code: "kfdAdopter.artifactEvidence", message: "release passport and artifact evidence must bind the same exact KFD adopter closure" });
@@ -33,6 +33,10 @@ import { normalizeControllerReceiptReferences } from "./controller-evidence.js";
33
33
  import {
34
34
  normalizeGitHubArtifactAttestationPolicy,
35
35
  } from "./github-artifact-attestation.js";
36
+ import {
37
+ normalizeAdopterDeliveryPassportBinding,
38
+ validateAdopterDeliveryReleaseEvidence,
39
+ } from "./adopter-delivery-passport.js";
36
40
 
37
41
  export { RELEASE_CHECK_REPORT_CONTRACT, RELEASE_PASSPORT_CONTRACT };
38
42
  export const ARTIFACT_EVIDENCE_CONTRACT = "kungfu-buildchain-artifact-evidence";
@@ -1160,9 +1164,9 @@ function normalizePromotionRouting(value = undefined) {
1160
1164
  return JSON.parse(JSON.stringify(value));
1161
1165
  }
1162
1166
 
1163
- export function createArtifactEvidence({ assets = [], repository = "", tag = "", sourceSha = "", workflow = {}, kfdAdopter = undefined } = {}) {
1167
+ export function createArtifactEvidence({ assets = [], repository = "", tag = "", sourceSha = "", workflow = {}, adopterDelivery = undefined, kfdAdopter = undefined } = {}) {
1164
1168
  const normalizedAssets = assets.map((asset, index) => normalizeAsset(asset, index));
1165
- return buildReleaseArtifactEvidence({ normalizedAssets, repository, tag, sourceSha, workflow, kfdAdopter });
1169
+ return buildReleaseArtifactEvidence({ normalizedAssets, repository, tag, sourceSha, workflow, adopterDelivery, kfdAdopter });
1166
1170
  }
1167
1171
 
1168
1172
  function firstTruthy(...values) {
@@ -1187,11 +1191,13 @@ function acceptedControllerSourceShas(input) {
1187
1191
  : [];
1188
1192
  }
1189
1193
 
1190
- function prepareReleaseKfdAdopterArtifacts({ kfdAdopter, assets, repository, tag, sourceSha, workflow }) {
1191
- const normalized = kfdAdopter ? structuredClone(kfdAdopter) : undefined;
1194
+ function prepareReleaseAdopterArtifacts({ adopterDelivery, kfdAdopter, assets, repository, tag, sourceSha, workflow }) {
1195
+ const normalizedAdopterDelivery = normalizeAdopterDeliveryPassportBinding(adopterDelivery);
1196
+ const normalizedKfdAdopter = kfdAdopter ? structuredClone(kfdAdopter) : undefined;
1192
1197
  return {
1193
- normalized,
1194
- artifactEvidence: createArtifactEvidence({ assets, repository, tag, sourceSha, workflow, kfdAdopter: normalized }),
1198
+ normalizedAdopterDelivery,
1199
+ normalizedKfdAdopter,
1200
+ artifactEvidence: createArtifactEvidence({ assets, repository, tag, sourceSha, workflow, adopterDelivery: normalizedAdopterDelivery, kfdAdopter: normalizedKfdAdopter }),
1195
1201
  };
1196
1202
  }
1197
1203
 
@@ -1229,6 +1235,7 @@ export function createReleasePassport({
1229
1235
  kfd1 = undefined,
1230
1236
  kfd2Claims = [],
1231
1237
  kfd3 = undefined,
1238
+ adopterDelivery = undefined,
1232
1239
  kfdAdopter = undefined,
1233
1240
  kfdAdopterManifestEvidencePath = "",
1234
1241
  kfdAdopterGateEvidencePath = "",
@@ -1244,8 +1251,8 @@ export function createReleasePassport({
1244
1251
  checkedAt = "",
1245
1252
  } = {}) {
1246
1253
  const normalizedTag = nonEmptyString(tag, "tag");
1247
- const { normalized: normalizedKfdAdopter, artifactEvidence } = prepareReleaseKfdAdopterArtifacts({
1248
- kfdAdopter, assets, repository, tag: normalizedTag, sourceSha, workflow,
1254
+ const { normalizedAdopterDelivery, normalizedKfdAdopter, artifactEvidence } = prepareReleaseAdopterArtifacts({
1255
+ adopterDelivery, kfdAdopter, assets, repository, tag: normalizedTag, sourceSha, workflow,
1249
1256
  });
1250
1257
  const normalizedPublishEvidence = normalizePublishEvidence(publishEvidence);
1251
1258
  const normalizedPackageSet = normalizePackageSet(packageSet, { packageName, packageVersion, publish });
@@ -1405,6 +1412,7 @@ export function createReleasePassport({
1405
1412
  ["buildFacts", normalizedBuildFacts],
1406
1413
  ["platformArtifactManifests", normalizedPlatformArtifactManifests],
1407
1414
  ["distTagPromotion", normalizedDistTagPromotionEvidence],
1415
+ ["adopterDelivery", normalizedAdopterDelivery],
1408
1416
  ...kfdParts.sectionEntries,
1409
1417
  ["kfdAgentHub", normalizedKfdAgentHub],
1410
1418
  ["invariantPassports", invariantPassports],
@@ -1465,7 +1473,7 @@ export function createReleasePassport({
1465
1473
  };
1466
1474
  }
1467
1475
 
1468
- function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson, productGateJsons, sourceSha, checkedAt }) {
1476
+ function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson, productGateJsons, repository, sourceSha, checkedAt }) {
1469
1477
  const manifestMeta = parseJsonInputWithMeta(manifestJson, undefined, { cwd, label: "kfdAdopterManifestJson" });
1470
1478
  const supportMatrixMeta = parseJsonInputWithMeta(supportMatrixJson, undefined, { cwd, label: "kfdSupportMatrixJson" });
1471
1479
  const productGateMetas = (productGateJsons || [])
@@ -1476,7 +1484,7 @@ function collectKfdAdopterReleaseInputs({ cwd, manifestJson, supportMatrixJson,
1476
1484
  manifest: manifestMeta.value,
1477
1485
  gateResults: productGateMetas.map((meta) => meta.value),
1478
1486
  comparisonMatrix: supportMatrixMeta.value,
1479
- sourceSha,
1487
+ expectedAdopterId: repository || "kungfu-systems/buildchain", expectedSourceRepository: repository, sourceSha,
1480
1488
  checkedAt,
1481
1489
  });
1482
1490
  }
@@ -1662,7 +1670,7 @@ export function collectGitHubReleasePassport({
1662
1670
  const productMechanism = defaultProductMechanism({ repository, productName });
1663
1671
  const kfdAdopterEvidence = collectKfdAdopterReleaseInputs({
1664
1672
  cwd, manifestJson: kfdAdopterManifestJson, supportMatrixJson: kfdSupportMatrixJson,
1665
- productGateJsons: kfdProductGateJsons, sourceSha, checkedAt: resolvedCheckedAt,
1673
+ productGateJsons: kfdProductGateJsons, repository, sourceSha, checkedAt: resolvedCheckedAt,
1666
1674
  });
1667
1675
  const {
1668
1676
  manifest: kfdAdopterManifest,
@@ -2094,6 +2102,13 @@ function validateReleaseEvidenceContracts({
2094
2102
  validateContract(agentIndex, AGENT_INDEX_CONTRACT, "agentIndex", issues);
2095
2103
  validateContract(productMechanism, PRODUCT_MECHANISM_CONTRACT, "productMechanism", issues);
2096
2104
  validateKfdAgentHubReleaseEvidence(passport?.kfdAgentHub, kfdAgentHubEvidence, issues);
2105
+ for (const entry of validateAdopterDeliveryReleaseEvidence({
2106
+ binding: passport?.adopterDelivery,
2107
+ artifactBinding: artifactEvidence?.adopterDelivery,
2108
+ expectedProjectRepository: optionalString(passport?.product?.repository),
2109
+ })) {
2110
+ issues.push(issue("error", entry.code, entry.message, entry.details));
2111
+ }
2097
2112
  for (const entry of validateKfdAdopterReleaseEvidence({
2098
2113
  binding: passport?.kfdAdopter,
2099
2114
  artifactBinding: artifactEvidence?.kfdAdopter,
@@ -2101,7 +2116,8 @@ function validateReleaseEvidenceContracts({
2101
2116
  manifestGate: kfdAdopterManifestGate,
2102
2117
  legacyProjection: kfdSupportEvidence,
2103
2118
  passportLegacyProjection: passport?.kfdSupport,
2104
- expectedSourceSha: optionalString(passport?.release?.sourceSha),
2119
+ expectedAdopterId: optionalString(passport?.product?.repository) || "kungfu-systems/buildchain",
2120
+ expectedSourceRepository: optionalString(passport?.product?.repository), expectedSourceSha: optionalString(passport?.release?.sourceSha),
2105
2121
  })) {
2106
2122
  issues.push(issue("error", entry.code, entry.message, entry.details));
2107
2123
  }
@@ -2650,6 +2666,7 @@ function buildReleaseCheckReport({
2650
2666
  ? passport.platformArtifactManifests.length
2651
2667
  : 0,
2652
2668
  distTagPromotionEvidencePresent: Boolean(passport?.distTagPromotion),
2669
+ adopterDeliveryPresent: Boolean(passport?.adopterDelivery),
2653
2670
  impactPresent: Boolean(impact),
2654
2671
  agentIndexPresent: Boolean(agentIndex),
2655
2672
  productMechanismPresent: Boolean(productMechanism),
@@ -75,6 +75,103 @@ function qualificationId(value) {
75
75
  return exact(value, /^mac-(?:smoke-0[12]|full-01)$/, "qualificationId");
76
76
  }
77
77
 
78
+ function terminalFailureRunIds(value) {
79
+ if (!Array.isArray(value) || value.length === 0) {
80
+ throw new Error("terminalFailureRunIds must be a non-empty array");
81
+ }
82
+ const normalized = value.map((entry) =>
83
+ exact(entry, /^[1-9]\d*$/, "terminalFailureRunId"),
84
+ );
85
+ if (new Set(normalized).size !== normalized.length) {
86
+ throw new Error("terminalFailureRunIds must be unique");
87
+ }
88
+ return [...normalized].sort((left, right) => Number(left) - Number(right));
89
+ }
90
+
91
+ function preflightFailureRunIds(value) {
92
+ if (!Array.isArray(value) || value.length === 0) {
93
+ throw new Error("preflightFailureRunIds must be a non-empty array");
94
+ }
95
+ const normalized = value.map((entry) =>
96
+ exact(entry, /^[1-9]\d*$/, "preflightFailureRunId"),
97
+ );
98
+ if (new Set(normalized).size !== normalized.length) {
99
+ throw new Error("preflightFailureRunIds must be unique");
100
+ }
101
+ return [...normalized].sort((left, right) => Number(left) - Number(right));
102
+ }
103
+
104
+ function successfulRunIds(value) {
105
+ if (value === undefined) return [];
106
+ if (!Array.isArray(value)) {
107
+ throw new Error("successfulRunIds must be an array");
108
+ }
109
+ const normalized = value.map((entry) =>
110
+ exact(entry, /^[1-9]\d*$/, "successfulRunId"),
111
+ );
112
+ if (new Set(normalized).size !== normalized.length) {
113
+ throw new Error("successfulRunIds must be unique");
114
+ }
115
+ return [...normalized].sort((left, right) => Number(left) - Number(right));
116
+ }
117
+
118
+ function startupFailureRuns(value) {
119
+ if (value === undefined) return [];
120
+ if (!Array.isArray(value)) {
121
+ throw new Error("startupFailureRuns must be an array");
122
+ }
123
+ const normalized = value.map((entry) => ({
124
+ runId: exact(entry?.runId, /^[1-9]\d*$/, "startupFailureRunId"),
125
+ sourceSha: exactSha(entry?.sourceSha),
126
+ }));
127
+ if (
128
+ new Set(normalized.map(({ runId }) => runId)).size !== normalized.length
129
+ ) {
130
+ throw new Error("startupFailureRuns must use unique run ids");
131
+ }
132
+ return [...normalized].sort(
133
+ (left, right) => Number(left.runId) - Number(right.runId),
134
+ );
135
+ }
136
+
137
+ function historicalTerminalFailureRuns(value) {
138
+ if (value === undefined) return [];
139
+ if (!Array.isArray(value)) {
140
+ throw new Error("historicalTerminalFailureRuns must be an array");
141
+ }
142
+ const normalized = value.map((entry) => ({
143
+ runId: exact(entry?.runId, /^[1-9]\d*$/, "historicalTerminalFailureRunId"),
144
+ sourceSha: exactSha(entry?.sourceSha),
145
+ }));
146
+ if (
147
+ new Set(normalized.map(({ runId }) => runId)).size !== normalized.length
148
+ ) {
149
+ throw new Error("historicalTerminalFailureRuns must use unique run ids");
150
+ }
151
+ return [...normalized].sort(
152
+ (left, right) => Number(left.runId) - Number(right.runId),
153
+ );
154
+ }
155
+
156
+ function historicalPreflightFailureRuns(value) {
157
+ if (value === undefined) return [];
158
+ if (!Array.isArray(value)) {
159
+ throw new Error("historicalPreflightFailureRuns must be an array");
160
+ }
161
+ const normalized = value.map((entry) => ({
162
+ runId: exact(entry?.runId, /^[1-9]\d*$/, "historicalPreflightFailureRunId"),
163
+ sourceSha: exactSha(entry?.sourceSha),
164
+ }));
165
+ if (
166
+ new Set(normalized.map(({ runId }) => runId)).size !== normalized.length
167
+ ) {
168
+ throw new Error("historicalPreflightFailureRuns must use unique run ids");
169
+ }
170
+ return [...normalized].sort(
171
+ (left, right) => Number(left.runId) - Number(right.runId),
172
+ );
173
+ }
174
+
78
175
  function commonAws(values) {
79
176
  const region = exact(
80
177
  values.region || MACOS_EC2_JIT.region,
@@ -203,6 +300,87 @@ export function createMacosJitCampaignPlan(values = {}) {
203
300
  return { ...plan, digest: digest(plan) };
204
301
  }
205
302
 
303
+ export function createMacosJitInstanceRehydratePlan(values = {}) {
304
+ const id = campaignId(values.campaignId);
305
+ const boundSource = source(values);
306
+ const aws = commonAws(values);
307
+ const regionConfig = macosJitRegionConfig(aws.region);
308
+ const tags = ownershipTags({ id, sourceSha: boundSource.sha });
309
+ const rehydrationId = exact(
310
+ values.rehydrationId,
311
+ /^r[1-9]\d{0,2}$/,
312
+ "rehydrationId",
313
+ );
314
+ const instanceClientToken = `kungfu-mac-rehydrate-${id}-${rehydrationId}`;
315
+ if (instanceClientToken.length > 64) {
316
+ throw new Error("rehydration client token exceeds the EC2 limit");
317
+ }
318
+ const plan = {
319
+ schemaVersion: 1,
320
+ contract: AWS_MACOS_JIT_CONTROLLER_CONTRACT,
321
+ kind: "instance-rehydrate-plan",
322
+ repository: repository(values.repository),
323
+ account: {
324
+ id: exact(values.accountId, /^\d{12}$/, "accountId"),
325
+ },
326
+ github: {
327
+ workflowId: MACOS_EC2_JIT.workflowId,
328
+ requiredState: "disabled_manually",
329
+ },
330
+ campaign: { id },
331
+ source: boundSource,
332
+ aws: {
333
+ ...aws,
334
+ hostId: exact(values.hostId, /^h-[0-9a-f]+$/, "hostId"),
335
+ hostAllocatedAt: iso(values.hostAllocatedAt, "hostAllocatedAt"),
336
+ replacesInstanceId: exact(
337
+ values.replacesInstanceId,
338
+ /^i-[0-9a-f]+$/,
339
+ "replacesInstanceId",
340
+ ),
341
+ rehydrationId,
342
+ instanceTags: tags,
343
+ volumeTags: tags,
344
+ instanceClientToken,
345
+ rootVolume: {
346
+ deviceName: "/dev/sda1",
347
+ deleteOnTermination: true,
348
+ encrypted: true,
349
+ volumeSizeGiB: 200,
350
+ volumeType: "gp3",
351
+ },
352
+ metadata: {
353
+ httpEndpoint: "enabled",
354
+ httpTokens: "required",
355
+ httpPutResponseHopLimit: 1,
356
+ instanceMetadataTags: "disabled",
357
+ },
358
+ },
359
+ safety: {
360
+ applyMode: values.execute === true ? "execute" : "dry-run",
361
+ exactSourceRequired: true,
362
+ existingCampaignHostRequired: true,
363
+ noHostAllocation: true,
364
+ zeroActiveInstanceRequired: true,
365
+ zeroRunnerResidueRequired: true,
366
+ awsDryRunRequiredBeforeLaunch: true,
367
+ cleanupOwner: "scheduled-card-scoped-reaper",
368
+ budget: {
369
+ name: regionConfig.budgetName,
370
+ limitUsd: MACOS_EC2_JIT.budgetLimitUsd,
371
+ metrics: ["UnblendedCost"],
372
+ dimensionFilter: {
373
+ usageTypes: regionConfig.budgetUsageTypes,
374
+ operation: MACOS_EC2_JIT.budgetOperation,
375
+ regions: regionConfig.budgetRegions,
376
+ },
377
+ requiredActualThresholds: [80, 95],
378
+ },
379
+ },
380
+ };
381
+ return { ...plan, digest: digest(plan) };
382
+ }
383
+
206
384
  export function createMacosJitSourceRebindPlan(values = {}) {
207
385
  const id = campaignId(values.campaignId);
208
386
  const boundSource = source(values);
@@ -219,6 +397,48 @@ export function createMacosJitSourceRebindPlan(values = {}) {
219
397
  if (workflowId !== MACOS_EC2_JIT.workflowId) {
220
398
  throw new Error(`workflowId must be ${MACOS_EC2_JIT.workflowId}`);
221
399
  }
400
+ const priorRunPolicy = values.priorRunPolicy || "unused";
401
+ if (
402
+ !["unused", "terminal-failure", "preflight-failure"].includes(
403
+ priorRunPolicy,
404
+ )
405
+ ) {
406
+ throw new Error(
407
+ "priorRunPolicy must be unused, terminal-failure, or preflight-failure",
408
+ );
409
+ }
410
+ const terminalRunIds =
411
+ priorRunPolicy === "terminal-failure"
412
+ ? terminalFailureRunIds(values.terminalFailureRunIds)
413
+ : [];
414
+ const preflightRunIds =
415
+ priorRunPolicy === "preflight-failure"
416
+ ? preflightFailureRunIds(values.preflightFailureRunIds)
417
+ : [];
418
+ const startupRuns = startupFailureRuns(values.startupFailureRuns);
419
+ const historicalTerminalRuns = historicalTerminalFailureRuns(
420
+ values.historicalTerminalFailureRuns,
421
+ );
422
+ const historicalPreflightRuns = historicalPreflightFailureRuns(
423
+ values.historicalPreflightFailureRuns,
424
+ );
425
+ const successfulRuns = successfulRunIds(values.successfulRunIds);
426
+ if (priorRunPolicy === "unused" && startupRuns.length !== 0) {
427
+ throw new Error("startupFailureRuns require a failed priorRunPolicy");
428
+ }
429
+ if (priorRunPolicy === "unused" && historicalTerminalRuns.length !== 0) {
430
+ throw new Error(
431
+ "historicalTerminalFailureRuns require a failed priorRunPolicy",
432
+ );
433
+ }
434
+ if (priorRunPolicy === "unused" && historicalPreflightRuns.length !== 0) {
435
+ throw new Error(
436
+ "historicalPreflightFailureRuns require a failed priorRunPolicy",
437
+ );
438
+ }
439
+ if (priorRunPolicy === "unused" && successfulRuns.length !== 0) {
440
+ throw new Error("successfulRunIds require a failed priorRunPolicy");
441
+ }
222
442
  const plan = {
223
443
  schemaVersion: 1,
224
444
  contract: AWS_MACOS_JIT_CONTROLLER_CONTRACT,
@@ -233,6 +453,13 @@ export function createMacosJitSourceRebindPlan(values = {}) {
233
453
  github: {
234
454
  workflowId,
235
455
  requiredState: "disabled_manually",
456
+ priorRunPolicy,
457
+ terminalFailureRunIds: terminalRunIds,
458
+ preflightFailureRunIds: preflightRunIds,
459
+ startupFailureRuns: startupRuns,
460
+ historicalTerminalFailureRuns: historicalTerminalRuns,
461
+ historicalPreflightFailureRuns: historicalPreflightRuns,
462
+ successfulRunIds: successfulRuns,
236
463
  },
237
464
  aws: {
238
465
  ...aws,
@@ -246,8 +473,16 @@ export function createMacosJitSourceRebindPlan(values = {}) {
246
473
  forwardOnlySource: true,
247
474
  sameSourceRefRequired: true,
248
475
  workflowDisabledRequired: true,
249
- zeroPriorJobsRequired: true,
250
- zeroPriorArtifactsRequired: true,
476
+ zeroPriorJobsRequired: priorRunPolicy === "unused",
477
+ zeroPriorArtifactsRequired: priorRunPolicy === "unused",
478
+ terminalFailureEvidencePreserved: priorRunPolicy === "terminal-failure",
479
+ preflightFailureEvidencePreserved: priorRunPolicy === "preflight-failure",
480
+ startupFailureEvidencePreserved: startupRuns.length !== 0,
481
+ historicalTerminalFailureEvidencePreserved:
482
+ historicalTerminalRuns.length !== 0,
483
+ historicalPreflightFailureEvidencePreserved:
484
+ historicalPreflightRuns.length !== 0,
485
+ successfulRunEvidencePreserved: successfulRuns.length !== 0,
251
486
  zeroJitResidueRequired: true,
252
487
  zeroEvidenceRequired: true,
253
488
  exactCampaignResourcesRequired: true,
@@ -301,9 +536,9 @@ export function macosAllocateHostsArgs(plan) {
301
536
  export function macosRunInstancesArgs(plan, { hostId, dryRun = false } = {}) {
302
537
  if (
303
538
  plan?.contract !== AWS_MACOS_JIT_CONTROLLER_CONTRACT ||
304
- plan.kind !== "campaign-launch-plan"
539
+ !["campaign-launch-plan", "instance-rehydrate-plan"].includes(plan.kind)
305
540
  ) {
306
- throw new Error("macOS JIT campaign launch plan contract is invalid");
541
+ throw new Error("macOS JIT instance launch plan contract is invalid");
307
542
  }
308
543
  const resolvedHostId = exact(hostId, /^h-[0-9a-f]+$/, "hostId");
309
544
  const args = [