@kungfu-tech/buildchain 3.0.9-alpha.1 → 3.0.9-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 (105) hide show
  1. package/actions/promote-buildchain-ref/README.md +4 -0
  2. package/bin/buildchain.mjs +9 -1
  3. package/bin/internal/trust-release-release-handlers.mjs +1 -0
  4. package/contracts/dev-delivery-authority-v2.schema.json +253 -0
  5. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  6. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  7. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  8. package/contracts/next-development-request-v1.schema.json +66 -0
  9. package/contracts/next-development-transition-v1.schema.json +292 -0
  10. package/dist/site/agent-index.json +1 -0
  11. package/dist/site/artifact-schemas.json +2 -0
  12. package/dist/site/buildchain-contract.json +92 -27
  13. package/dist/site/buildchain-site.json +351 -38
  14. package/dist/site/capability-registry.json +7 -6
  15. package/dist/site/cli-registry.json +43 -3
  16. package/dist/site/controller-registry.json +6 -2
  17. package/dist/site/kfd-claims.json +223 -12
  18. package/dist/site/kfd-upstream-aggregate.json +9 -9
  19. package/dist/site/manual-registry.json +23 -7
  20. package/dist/site/node-api-registry.json +7926 -4533
  21. package/dist/site/page-registry.json +332 -27
  22. package/dist/site/public-surface-audit.json +359 -11
  23. package/dist/site/publication-registry.json +4 -4
  24. package/dist/site/release-passport-check-manifest.json +1 -0
  25. package/dist/site/release-provenance.json +14 -0
  26. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +442 -0
  27. package/dist/site/schemas/release-passport-v1.schema.json +3 -0
  28. package/dist/site/site-manifest.json +19 -11
  29. package/dist/site/workflow-registry.json +21 -10
  30. package/docs/MAP.md +5 -2
  31. package/docs/adopter-delivery-gate.md +106 -0
  32. package/docs/aws-us-elastic-runner-burst-plane.md +30 -3
  33. package/docs/cli-reference.md +202 -15
  34. package/docs/dev-alpha-candidate-patrol.md +8 -0
  35. package/docs/dev-delivery-qualification-landing-adr.md +137 -0
  36. package/docs/dev-delivery-warrant.md +149 -22
  37. package/docs/kfd-support.md +7 -2
  38. package/docs/next-development-transition.md +119 -0
  39. package/docs/node-api-reference.md +402 -204
  40. package/docs/release-governance.md +10 -7
  41. package/docs/release-passport.md +18 -2
  42. package/docs/versioning.md +4 -1
  43. package/package.json +23 -6
  44. package/packages/core/README.md +25 -0
  45. package/packages/core/adopter-delivery-gate.js +576 -0
  46. package/packages/core/adopter-delivery-json.js +66 -0
  47. package/packages/core/adopter-delivery-passport.js +259 -0
  48. package/packages/core/adopter-delivery-vectors.js +158 -0
  49. package/packages/core/adopter-delivery-vectors.json +77 -0
  50. package/packages/core/artifact-verification-envelope.js +5 -5
  51. package/packages/core/buildchain-agent-manuals.js +1 -0
  52. package/packages/core/buildchain-channel-identity.js +2 -3
  53. package/packages/core/buildchain-compatibility-proof.js +22 -0
  54. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  55. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  56. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  57. package/packages/core/channel-candidate.js +8 -0
  58. package/packages/core/channel-promotion-baseline.js +52 -0
  59. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  60. package/packages/core/dev-delivery-authority.js +996 -0
  61. package/packages/core/dev-delivery-native-proof.js +418 -0
  62. package/packages/core/dev-delivery-warrant-settlement.js +67 -20
  63. package/packages/core/dev-delivery-warrant.js +129 -46
  64. package/packages/core/kfd-adopter-category-driver.js +167 -0
  65. package/packages/core/kfd-adopter-manifest.js +49 -50
  66. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  67. package/packages/core/next-development-candidate-reservation.js +186 -0
  68. package/packages/core/next-development-controller.js +726 -0
  69. package/packages/core/next-development-projection.js +288 -0
  70. package/packages/core/next-development-transition.js +738 -0
  71. package/packages/core/paper-agent-entry.js +7 -4
  72. package/packages/core/paper.js +14 -7
  73. package/packages/core/published-delivery-authority.js +247 -0
  74. package/packages/core/release-passport-contract.js +10 -6
  75. package/packages/core/release-passport.js +37 -13
  76. package/scripts/aws-macos-jit-controller-core.mjs +239 -4
  77. package/scripts/aws-macos-jit-controller.mjs +198 -2
  78. package/scripts/aws-macos-jit-instance-rehydrate.mjs +260 -0
  79. package/scripts/aws-macos-jit-source-rebind.mjs +235 -14
  80. package/scripts/aws-macos-jit.mjs +12 -0
  81. package/scripts/buildchain-cli-help.mjs +10 -2
  82. package/scripts/check-internal-architecture.mjs +1 -0
  83. package/scripts/check-inventory.mjs +12 -1
  84. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  85. package/scripts/dev-delivery-authority.mjs +368 -0
  86. package/scripts/dev-delivery-native-run.mjs +235 -0
  87. package/scripts/dev-delivery-proof.mjs +64 -2
  88. package/scripts/dev-delivery-two-phase-resume.mjs +90 -0
  89. package/scripts/dev-delivery-two-phase.mjs +577 -0
  90. package/scripts/dev-delivery-warrant.mjs +48 -6
  91. package/scripts/dev-pr-delivery-warrant.mjs +19 -14
  92. package/scripts/generate-buildchain-kfd-witnesses.mjs +2 -2
  93. package/scripts/generate-channel-build-workflow.mjs +4 -0
  94. package/scripts/generate-next-development-guidance.mjs +49 -0
  95. package/scripts/generate-site-bundle.mjs +8 -3
  96. package/scripts/init-repo.mjs +135 -62
  97. package/scripts/next-development-self-dogfood-harness.mjs +409 -0
  98. package/scripts/next-development-self-dogfood.mjs +532 -0
  99. package/scripts/next-development-transition.mjs +47 -0
  100. package/scripts/release-candidate-tail-reseal.mjs +426 -0
  101. package/scripts/seal-artifact-signing-requests.mjs +7 -4
  102. package/scripts/site-capability-metadata.mjs +25 -1
  103. package/scripts/stable-candidate-qualification.mjs +7 -7
  104. package/scripts/workflow-call-contract.mjs +1 -1
  105. package/templates/native-dev-delivery.yml +86 -0
@@ -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 = [
@@ -6,6 +6,7 @@ import {
6
6
  AWS_MACOS_JIT_CONTROLLER_CONTRACT,
7
7
  createMacosJitCampaignPlan,
8
8
  createMacosJitClosePlan,
9
+ createMacosJitInstanceRehydratePlan,
9
10
  createMacosJitJobPlan,
10
11
  createMacosJitSourceRebindPlan,
11
12
  macosAllocateHostsArgs,
@@ -13,6 +14,7 @@ import {
13
14
  macosRunInstancesArgs,
14
15
  } from "./aws-macos-jit-controller-core.mjs";
15
16
  import { MACOS_EC2_JIT_REGIONS } from "./aws-macos-jit-core.mjs";
17
+ import { executeMacosJitInstanceRehydrate } from "./aws-macos-jit-instance-rehydrate.mjs";
16
18
  import { executeMacosJitJob } from "./aws-macos-jit-job-controller.mjs";
17
19
  import { executeMacosJitSourceRebind } from "./aws-macos-jit-source-rebind.mjs";
18
20
  import {
@@ -36,6 +38,19 @@ function flag(name) {
36
38
  return process.argv.includes(`--${name}`);
37
39
  }
38
40
 
41
+ function jsonArrayArg(name) {
42
+ let parsed;
43
+ try {
44
+ parsed = JSON.parse(arg(name));
45
+ } catch {
46
+ throw new Error(`--${name} must be valid JSON`);
47
+ }
48
+ if (!Array.isArray(parsed)) {
49
+ throw new Error(`--${name} must be a JSON array`);
50
+ }
51
+ return parsed;
52
+ }
53
+
39
54
  function assertCampaignLaunchPreflight(plan, profile) {
40
55
  const launchGate = assertMacosBudgetLaunchGate(plan, profile);
41
56
  const commit = ghJson(
@@ -493,6 +508,20 @@ function commonValues(execute) {
493
508
  };
494
509
  }
495
510
 
511
+ function confirmHistoricalPreflightFailures(plan) {
512
+ const confirmed = flag("confirm-historical-preflight-failure-runs-json")
513
+ ? jsonArrayArg("confirm-historical-preflight-failure-runs-json")
514
+ : [];
515
+ if (
516
+ JSON.stringify(confirmed) !==
517
+ JSON.stringify(plan.github.historicalPreflightFailureRuns)
518
+ ) {
519
+ throw new Error(
520
+ "--confirm-historical-preflight-failure-runs-json must equal the exact historical preflight failure inventory",
521
+ );
522
+ }
523
+ }
524
+
496
525
  function confirm(plan) {
497
526
  if (arg("confirm-source-sha") !== plan.source.sha) {
498
527
  throw new Error("--confirm-source-sha must equal the exact source SHA");
@@ -515,6 +544,115 @@ function confirm(plan) {
515
544
  if (!flag("confirm-zero-allocation")) {
516
545
  throw new Error("--confirm-zero-allocation is required");
517
546
  }
547
+ if (plan.github.priorRunPolicy === "terminal-failure") {
548
+ const confirmed = jsonArrayArg(
549
+ "confirm-terminal-failure-run-ids-json",
550
+ ).map(String);
551
+ if (
552
+ JSON.stringify(confirmed) !==
553
+ JSON.stringify(plan.github.terminalFailureRunIds)
554
+ ) {
555
+ throw new Error(
556
+ "--confirm-terminal-failure-run-ids-json must equal the exact failed run inventory",
557
+ );
558
+ }
559
+ const confirmedStartupFailures = flag("confirm-startup-failure-runs-json")
560
+ ? jsonArrayArg("confirm-startup-failure-runs-json")
561
+ : [];
562
+ if (
563
+ JSON.stringify(confirmedStartupFailures) !==
564
+ JSON.stringify(plan.github.startupFailureRuns)
565
+ ) {
566
+ throw new Error(
567
+ "--confirm-startup-failure-runs-json must equal the exact startup failure inventory",
568
+ );
569
+ }
570
+ const confirmedHistoricalTerminalFailures = flag(
571
+ "confirm-historical-terminal-failure-runs-json",
572
+ )
573
+ ? jsonArrayArg("confirm-historical-terminal-failure-runs-json")
574
+ : [];
575
+ if (
576
+ JSON.stringify(confirmedHistoricalTerminalFailures) !==
577
+ JSON.stringify(plan.github.historicalTerminalFailureRuns)
578
+ ) {
579
+ throw new Error(
580
+ "--confirm-historical-terminal-failure-runs-json must equal the exact historical terminal failure inventory",
581
+ );
582
+ }
583
+ const confirmedSuccessfulRuns = flag("confirm-successful-run-ids-json")
584
+ ? jsonArrayArg("confirm-successful-run-ids-json").map(String)
585
+ : [];
586
+ if (
587
+ JSON.stringify(confirmedSuccessfulRuns) !==
588
+ JSON.stringify(plan.github.successfulRunIds)
589
+ ) {
590
+ throw new Error(
591
+ "--confirm-successful-run-ids-json must equal the exact successful run inventory",
592
+ );
593
+ }
594
+ } else if (plan.github.priorRunPolicy === "preflight-failure") {
595
+ const confirmed = jsonArrayArg(
596
+ "confirm-preflight-failure-run-ids-json",
597
+ ).map(String);
598
+ if (
599
+ JSON.stringify(confirmed) !==
600
+ JSON.stringify(plan.github.preflightFailureRunIds)
601
+ ) {
602
+ throw new Error(
603
+ "--confirm-preflight-failure-run-ids-json must equal the exact preflight failure inventory",
604
+ );
605
+ }
606
+ const confirmedStartupFailures = flag("confirm-startup-failure-runs-json")
607
+ ? jsonArrayArg("confirm-startup-failure-runs-json")
608
+ : [];
609
+ if (
610
+ JSON.stringify(confirmedStartupFailures) !==
611
+ JSON.stringify(plan.github.startupFailureRuns)
612
+ ) {
613
+ throw new Error(
614
+ "--confirm-startup-failure-runs-json must equal the exact startup failure inventory",
615
+ );
616
+ }
617
+ const confirmedHistoricalTerminalFailures = flag(
618
+ "confirm-historical-terminal-failure-runs-json",
619
+ )
620
+ ? jsonArrayArg("confirm-historical-terminal-failure-runs-json")
621
+ : [];
622
+ if (
623
+ JSON.stringify(confirmedHistoricalTerminalFailures) !==
624
+ JSON.stringify(plan.github.historicalTerminalFailureRuns)
625
+ ) {
626
+ throw new Error(
627
+ "--confirm-historical-terminal-failure-runs-json must equal the exact historical terminal failure inventory",
628
+ );
629
+ }
630
+ const confirmedSuccessfulRuns = flag("confirm-successful-run-ids-json")
631
+ ? jsonArrayArg("confirm-successful-run-ids-json").map(String)
632
+ : [];
633
+ if (
634
+ JSON.stringify(confirmedSuccessfulRuns) !==
635
+ JSON.stringify(plan.github.successfulRunIds)
636
+ ) {
637
+ throw new Error(
638
+ "--confirm-successful-run-ids-json must equal the exact successful run inventory",
639
+ );
640
+ }
641
+ }
642
+ confirmHistoricalPreflightFailures(plan);
643
+ }
644
+ if (plan.kind === "instance-rehydrate-plan") {
645
+ if (arg("confirm-host-id") !== plan.aws.hostId) {
646
+ throw new Error("--confirm-host-id must equal the exact host id");
647
+ }
648
+ if (arg("confirm-replaces-instance-id") !== plan.aws.replacesInstanceId) {
649
+ throw new Error(
650
+ "--confirm-replaces-instance-id must equal replacesInstanceId",
651
+ );
652
+ }
653
+ if (!flag("confirm-no-host-allocation")) {
654
+ throw new Error("--confirm-no-host-allocation is required");
655
+ }
518
656
  }
519
657
  }
520
658
 
@@ -541,7 +679,32 @@ export function main() {
541
679
  executeMacosJitCampaignLaunch(plan, { profile: arg("aws-profile") }),
542
680
  );
543
681
  }
544
- if (["plan-rebind", "rebind-campaign"].includes(mode)) {
682
+ if (["plan-rehydrate", "rehydrate-instance"].includes(mode)) {
683
+ const plan = createMacosJitInstanceRehydratePlan({
684
+ ...commonValues(execute),
685
+ hostId: arg("host-id"),
686
+ hostAllocatedAt: arg("host-allocated-at"),
687
+ replacesInstanceId: arg("replaces-instance-id"),
688
+ rehydrationId: arg("rehydration-id"),
689
+ });
690
+ return emit(plan, mode, execute, () =>
691
+ executeMacosJitInstanceRehydrate(plan, {
692
+ profile: arg("aws-profile"),
693
+ }),
694
+ );
695
+ }
696
+ if (
697
+ [
698
+ "plan-rebind",
699
+ "rebind-campaign",
700
+ "plan-rebind-after-failure",
701
+ "rebind-campaign-after-failure",
702
+ "plan-rebind-after-preflight-failure",
703
+ "rebind-campaign-after-preflight-failure",
704
+ ].includes(mode)
705
+ ) {
706
+ const afterFailure = mode.endsWith("after-failure");
707
+ const afterPreflightFailure = mode.endsWith("after-preflight-failure");
545
708
  const plan = createMacosJitSourceRebindPlan({
546
709
  ...commonValues(execute),
547
710
  previousSourceSha: arg("previous-source-sha"),
@@ -549,8 +712,41 @@ export function main() {
549
712
  workflowId: arg("workflow-id"),
550
713
  hostId: arg("host-id"),
551
714
  instanceId: arg("instance-id"),
715
+ priorRunPolicy: afterPreflightFailure
716
+ ? "preflight-failure"
717
+ : afterFailure
718
+ ? "terminal-failure"
719
+ : "unused",
720
+ terminalFailureRunIds: afterFailure
721
+ ? jsonArrayArg("terminal-failure-run-ids-json")
722
+ : [],
723
+ preflightFailureRunIds: afterPreflightFailure
724
+ ? jsonArrayArg("preflight-failure-run-ids-json")
725
+ : [],
726
+ startupFailureRuns:
727
+ (afterFailure || afterPreflightFailure) &&
728
+ flag("startup-failure-runs-json")
729
+ ? jsonArrayArg("startup-failure-runs-json")
730
+ : [],
731
+ historicalTerminalFailureRuns:
732
+ (afterFailure || afterPreflightFailure) &&
733
+ flag("historical-terminal-failure-runs-json")
734
+ ? jsonArrayArg("historical-terminal-failure-runs-json")
735
+ : [],
736
+ historicalPreflightFailureRuns:
737
+ (afterFailure || afterPreflightFailure) &&
738
+ flag("historical-preflight-failure-runs-json")
739
+ ? jsonArrayArg("historical-preflight-failure-runs-json")
740
+ : [],
741
+ successfulRunIds:
742
+ (afterFailure || afterPreflightFailure) &&
743
+ flag("successful-run-ids-json")
744
+ ? jsonArrayArg("successful-run-ids-json")
745
+ : [],
552
746
  });
553
- return emit(plan, mode, execute, () => executeMacosJitSourceRebind(plan, { profile: arg("aws-profile") }));
747
+ return emit(plan, mode, execute, () =>
748
+ executeMacosJitSourceRebind(plan, { profile: arg("aws-profile") }),
749
+ );
554
750
  }
555
751
  if (["plan-job", "run-job"].includes(mode)) {
556
752
  const plan = createMacosJitJobPlan({