@kungfu-tech/buildchain 4.0.1-alpha.2 → 4.0.1-alpha.21

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 (203) hide show
  1. package/actions/release-tail/README.md +8 -0
  2. package/architecture/ci-lane-change-budget.json +187 -0
  3. package/architecture/decisions/0002-next-development-transition.md +101 -0
  4. package/architecture/decisions/0003-two-phase-delivery-warrant.md +152 -0
  5. package/architecture/internal-capabilities.json +211 -8
  6. package/architecture/maintainability-policy.json +113 -28
  7. package/architecture/release-tail-contract-inventory.json +5 -2
  8. package/architecture/v3-core-mechanism-inventory.json +91 -0
  9. package/architecture/v4-adopter-delivery-parity.json +32 -5
  10. package/architecture/v4-capability-state-machine-manifest.json +73 -0
  11. package/architecture/v4-compatibility-facts-parity.json +77 -0
  12. package/architecture/v4-delivery-authority-parity.json +250 -0
  13. package/architecture/v4-delivery-warrant-shadow-fixtures.json +41 -9
  14. package/architecture/v4-floating-consumer-policy.json +6 -0
  15. package/architecture/v4-next-development-parity.json +192 -0
  16. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  17. package/architecture/v4-release-train-parity.json +1 -0
  18. package/architecture/v4-tail-reseal-parity.json +150 -0
  19. package/bin/buildchain.mjs +32 -3
  20. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  21. package/bin/internal/command-registry.mjs +3 -0
  22. package/bin/internal/compatibility-facts-cli.mjs +101 -0
  23. package/contracts/dev-delivery-authority-v2.schema.json +662 -0
  24. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  25. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  26. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  27. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  28. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  29. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  30. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  31. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  32. package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
  33. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
  34. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  35. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  36. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  37. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  38. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  39. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  40. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  41. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  42. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  43. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
  44. package/contracts/next-development-request-v1.schema.json +66 -0
  45. package/contracts/next-development-transition-v1.schema.json +292 -0
  46. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  47. package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
  48. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +4 -2
  49. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  50. package/contracts/v4-tail-reseal-v1.schema.json +276 -0
  51. package/dist/site/agent-index.json +5 -0
  52. package/dist/site/artifact-schemas.json +10 -0
  53. package/dist/site/buildchain-contract.json +1475 -27
  54. package/dist/site/buildchain-site.json +627 -31
  55. package/dist/site/capability-registry.json +17 -14
  56. package/dist/site/cli-registry.json +205 -3
  57. package/dist/site/kfd-claims.json +490 -16
  58. package/dist/site/kfd-upstream-aggregate.json +1 -1
  59. package/dist/site/manual-registry.json +52 -6
  60. package/dist/site/node-api-registry.json +14736 -8851
  61. package/dist/site/page-registry.json +593 -21
  62. package/dist/site/public-surface-audit.json +837 -48
  63. package/dist/site/publication-authority-registry.json +44 -8
  64. package/dist/site/publication-registry.json +4 -4
  65. package/dist/site/release-provenance.json +24 -0
  66. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +662 -0
  67. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  68. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  69. package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
  70. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  71. package/dist/site/site-manifest.json +34 -10
  72. package/dist/site/workflow-registry.json +160 -10
  73. package/docs/MAP.md +8 -2
  74. package/docs/cli-reference.md +404 -13
  75. package/docs/cli.md +8 -0
  76. package/docs/dev-alpha-candidate-patrol.md +8 -0
  77. package/docs/dev-delivery-qualification-landing-adr.md +251 -0
  78. package/docs/dev-delivery-warrant.md +351 -38
  79. package/docs/next-development-transition.md +118 -0
  80. package/docs/node-api-reference.md +646 -293
  81. package/docs/release-tail-provider-plane.md +30 -0
  82. package/docs/v4-adopter-delivery.md +133 -0
  83. package/docs/v4-compatibility-facts.md +91 -0
  84. package/docs/v4-publication-rehearsal.md +130 -0
  85. package/docs/v4-tail-reseal.md +73 -0
  86. package/docs/versioning.md +4 -3
  87. package/package.json +34 -6
  88. package/packages/core/adopter-delivery-passport.js +259 -0
  89. package/packages/core/adopter-delivery-vectors.js +158 -0
  90. package/packages/core/adopter-delivery-vectors.json +77 -0
  91. package/packages/core/buildchain-agent-manuals.js +3 -0
  92. package/packages/core/buildchain-compatibility-authority.js +336 -0
  93. package/packages/core/buildchain-compatibility-fact.js +394 -0
  94. package/packages/core/buildchain-compatibility-facts.json +217 -0
  95. package/packages/core/buildchain-compatibility-proof.js +566 -0
  96. package/packages/core/buildchain-config.js +84 -0
  97. package/packages/core/buildchain-contract.js +96 -143
  98. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  99. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  100. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  101. package/packages/core/buildchain-publication-authority.js +1 -0
  102. package/packages/core/channel-candidate.js +8 -0
  103. package/packages/core/channel-promotion-baseline.js +55 -0
  104. package/packages/core/ci-lane-change-budget.js +247 -0
  105. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  106. package/packages/core/dev-delivery-authority-candidate.js +270 -0
  107. package/packages/core/dev-delivery-authority-evidence.js +146 -0
  108. package/packages/core/dev-delivery-authority-landing.js +461 -0
  109. package/packages/core/dev-delivery-authority-observation.js +48 -0
  110. package/packages/core/dev-delivery-authority-qualification.js +591 -0
  111. package/packages/core/dev-delivery-authority-settlement.js +213 -0
  112. package/packages/core/dev-delivery-authority-state.js +583 -0
  113. package/packages/core/dev-delivery-candidate-identity.js +13 -0
  114. package/packages/core/dev-delivery-contract-surface.js +76 -0
  115. package/packages/core/dev-delivery-execution-failure.js +133 -0
  116. package/packages/core/dev-delivery-execution-transfer.js +592 -0
  117. package/packages/core/dev-delivery-landing-admission-core.js +119 -0
  118. package/packages/core/dev-delivery-landing-readback.js +598 -0
  119. package/packages/core/dev-delivery-landing-terminal-evidence.js +271 -0
  120. package/packages/core/dev-delivery-landing-testing-port.js +6 -0
  121. package/packages/core/dev-delivery-native-execution.js +110 -0
  122. package/packages/core/dev-delivery-native-proof.js +562 -0
  123. package/packages/core/dev-delivery-process-boundary.js +563 -0
  124. package/packages/core/dev-delivery-provider-attempt.js +127 -0
  125. package/packages/core/dev-delivery-provider-heartbeat.js +382 -0
  126. package/packages/core/dev-delivery-warrant-cancellation.js +1 -0
  127. package/packages/core/dev-delivery-warrant-qualification.js +145 -0
  128. package/packages/core/dev-delivery-warrant-settlement.js +237 -36
  129. package/packages/core/dev-delivery-warrant-state.js +587 -0
  130. package/packages/core/dev-delivery-warrant.js +328 -370
  131. package/packages/core/github-governance-authority.js +1 -0
  132. package/packages/core/index.js +5 -0
  133. package/packages/core/kungfu-temporal-fact.js +557 -0
  134. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  135. package/packages/core/next-development-candidate-reservation.js +186 -0
  136. package/packages/core/next-development-controller.js +728 -0
  137. package/packages/core/next-development-projection.js +287 -0
  138. package/packages/core/next-development-transition.js +738 -0
  139. package/packages/core/paper-agent-entry.js +11 -5
  140. package/packages/core/paper.js +16 -5
  141. package/packages/core/published-delivery-authority.js +266 -0
  142. package/packages/core/release-candidate-recovery.js +70 -15
  143. package/packages/core/release-candidate.js +2 -2
  144. package/packages/core/release-passport.js +36 -9
  145. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  146. package/packages/core/v4-adopter-delivery.js +359 -0
  147. package/packages/core/v4-canonical-contracts.js +5 -0
  148. package/packages/core/v4-delivery-warrant-read-candidate.js +10 -3
  149. package/packages/core/v4-floating-consumer-evidence.js +18 -4
  150. package/packages/core/v4-floating-consumer-policy.js +143 -20
  151. package/packages/core/v4-floating-consumer-release-passport.js +32 -5
  152. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  153. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  154. package/packages/core/v4-publication-rehearsal.js +481 -0
  155. package/packages/core/v4-tail-reseal-contract.js +26 -0
  156. package/packages/core/v4-tail-reseal-github.js +178 -0
  157. package/packages/core/v4-tail-reseal-receipt.js +225 -0
  158. package/packages/core/v4-tail-reseal.js +594 -0
  159. package/packages/core/workflow-yaml-contract.js +24 -2
  160. package/scripts/buildchain-cli-help.mjs +41 -2
  161. package/scripts/check-ci-lane-change-budget.mjs +100 -0
  162. package/scripts/check-inventory.mjs +14 -3
  163. package/scripts/check-v4-floating-consumer-policy-contract.mjs +23 -4
  164. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  165. package/scripts/dev-delivery-authority-command-adapters.mjs +206 -0
  166. package/scripts/dev-delivery-authority-provider.mjs +28 -0
  167. package/scripts/dev-delivery-authority.mjs +490 -0
  168. package/scripts/dev-delivery-native-run.mjs +177 -0
  169. package/scripts/dev-delivery-process-boundary.mjs +260 -0
  170. package/scripts/dev-delivery-proof.mjs +67 -2
  171. package/scripts/dev-delivery-provider-heartbeat.mjs +215 -0
  172. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  173. package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
  174. package/scripts/dev-delivery-two-phase-resume.mjs +345 -0
  175. package/scripts/dev-delivery-two-phase.mjs +573 -0
  176. package/scripts/dev-delivery-warrant-options.mjs +266 -0
  177. package/scripts/dev-delivery-warrant-store.mjs +231 -0
  178. package/scripts/dev-delivery-warrant.mjs +232 -194
  179. package/scripts/dev-pr-auto-merge.mjs +1 -1
  180. package/scripts/dev-pr-delivery-warrant.mjs +11 -0
  181. package/scripts/dev-qualification-patrol.mjs +9 -9
  182. package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
  183. package/scripts/generate-channel-promotion-workflow.mjs +2 -2
  184. package/scripts/generate-next-development-guidance.mjs +49 -0
  185. package/scripts/generate-release-candidate-passport.mjs +152 -0
  186. package/scripts/generate-site-bundle.mjs +69 -4
  187. package/scripts/init-repo.mjs +22 -4
  188. package/scripts/next-development-self-dogfood-harness.mjs +460 -0
  189. package/scripts/next-development-self-dogfood.mjs +597 -0
  190. package/scripts/next-development-transition.mjs +47 -0
  191. package/scripts/npm-publish-transaction.mjs +2 -2
  192. package/scripts/promotion-channel-router.mjs +4 -4
  193. package/scripts/release-candidate-anchor-provenance.mjs +99 -0
  194. package/scripts/release-tail.mjs +51 -3
  195. package/scripts/release-train-self-dogfood.mjs +94 -92
  196. package/scripts/resume-from-candidate-run.mjs +557 -30
  197. package/scripts/site-capability-metadata.mjs +41 -0
  198. package/scripts/stable-candidate-qualification.mjs +9 -10
  199. package/scripts/v4-consumer-policy.mjs +5 -5
  200. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
  201. package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
  202. package/scripts/v4-tail-reseal.mjs +416 -0
  203. package/templates/native-dev-delivery.yml +143 -0
@@ -0,0 +1,461 @@
1
+ import {
2
+ devDeliveryClone as clone,
3
+ devDeliveryExactSha as exactSha,
4
+ devDeliveryPositiveInteger as positiveInteger,
5
+ devDeliveryTimestamp as timestamp,
6
+ } from "./dev-delivery-common.js";
7
+ import {
8
+ DEV_DELIVERY_LANDING_WARRANT_SCHEMA,
9
+ normalizeDevDeliveryAuthorityState,
10
+ receipt,
11
+ transition,
12
+ } from "./dev-delivery-authority-state.js";
13
+ import {
14
+ authorityToken,
15
+ landingEligibility,
16
+ recoverExpiredQualificationLeases,
17
+ schedulerWake,
18
+ } from "./dev-delivery-authority-qualification.js";
19
+ import {
20
+ readGitHubLandingActiveProviderAttempt,
21
+ readGitHubLandingProviderAttempt,
22
+ readGitHubLandingTerminalState,
23
+ } from "./dev-delivery-landing-readback.js";
24
+ import { admitDevDeliveryMergeGroupWithVerifiedProviderAttempt } from "./dev-delivery-landing-admission-core.js";
25
+ import { DEV_DELIVERY_TESTING_PROVIDER_READBACK } from "./dev-delivery-landing-testing-port.js";
26
+ import { normalizeDevDeliveryProviderAttempt } from "./dev-delivery-provider-attempt.js";
27
+ import {
28
+ assertDevDeliveryLandingWarrant,
29
+ settleDevDeliveryAuthorityCandidateInternal,
30
+ } from "./dev-delivery-authority-settlement.js";
31
+
32
+ export {
33
+ DEV_DELIVERY_AUTHORITY_CONTRACT,
34
+ DEV_DELIVERY_AUTHORITY_MIGRATION_SCHEMA,
35
+ DEV_DELIVERY_AUTHORITY_MODE,
36
+ DEV_DELIVERY_AUTHORITY_RECEIPT_SCHEMA,
37
+ DEV_DELIVERY_LANDING_WARRANT_SCHEMA,
38
+ DEV_DELIVERY_MERGE_GROUP_ADMISSION_SCHEMA,
39
+ DEV_DELIVERY_QUALIFICATION_LEASE_SCHEMA,
40
+ DEV_DELIVERY_SCHEDULER_REASON_SCHEMA,
41
+ DEV_DELIVERY_SCHEDULER_WAKE_SCHEMA,
42
+ createDevDeliveryAuthorityState,
43
+ migrateDevDeliveryAuthorityState,
44
+ normalizeDevDeliveryAuthorityState,
45
+ } from "./dev-delivery-authority-state.js";
46
+ export {
47
+ acquireDevDeliveryQualificationLease,
48
+ completeDevDeliveryQualification,
49
+ heartbeatDevDeliveryQualificationLease,
50
+ submitDevDeliveryAuthorityCandidate,
51
+ } from "./dev-delivery-authority-qualification.js";
52
+ export {
53
+ DEV_DELIVERY_BOUNDED_QUALIFICATION_CONTRACT_SCHEMA,
54
+ DEV_DELIVERY_BOUNDED_QUALIFICATION_RECEIPT_SCHEMA,
55
+ createDevDeliveryQualificationContract,
56
+ verifyDevDeliveryQualificationEvidence,
57
+ } from "./dev-delivery-authority-evidence.js";
58
+ export { observeDevDeliveryAuthorityState } from "./dev-delivery-authority-observation.js";
59
+ export {
60
+ DEV_DELIVERY_LANDING_TERMINAL_READBACK_SCHEMA,
61
+ deriveDevDeliveryLandingProviderAttempt,
62
+ readGitHubLandingActiveProviderAttempt,
63
+ readGitHubLandingProviderAttempt,
64
+ readGitHubLandingTerminalState,
65
+ verifyLandingSettlementReadback,
66
+ verifyExpiredLandingSettlementReadback,
67
+ } from "./dev-delivery-landing-readback.js";
68
+ function recoverExpiredLandingWarrant(state, now) {
69
+ if (
70
+ !state.landingWarrant ||
71
+ Date.parse(state.landingWarrant.expiresAt) > Date.parse(now)
72
+ )
73
+ return null;
74
+ return clone(state.landingWarrant);
75
+ }
76
+
77
+ export function recoverDevDeliveryAuthority(
78
+ stateInput,
79
+ { now = new Date().toISOString() } = {},
80
+ ) {
81
+ const currentTime = timestamp(now, "now");
82
+ const transaction = transition(
83
+ stateInput,
84
+ (state) => {
85
+ const qualificationLeases = recoverExpiredQualificationLeases(
86
+ state,
87
+ currentTime,
88
+ );
89
+ const landingWarrant = recoverExpiredLandingWarrant(state, currentTime);
90
+ return {
91
+ qualificationLeases,
92
+ landingWarrant,
93
+ action:
94
+ qualificationLeases.length > 0 && landingWarrant
95
+ ? "expired-qualification-recovered-landing-stop-required"
96
+ : qualificationLeases.length > 0
97
+ ? "expired-qualification-authority-recovered"
98
+ : landingWarrant
99
+ ? "expired-landing-warrant-stop-required-noop"
100
+ : "no-expired-authority-noop",
101
+ mutated: qualificationLeases.length > 0,
102
+ };
103
+ },
104
+ currentTime,
105
+ );
106
+ const changed = receipt(transaction, transaction.result.action, {
107
+ recoveredQualificationTokens: transaction.result.qualificationLeases.map(
108
+ (lease) => lease.token,
109
+ ),
110
+ retainedExpiredLandingToken:
111
+ transaction.result.landingWarrant?.token || null,
112
+ nextAction: transaction.result.landingWarrant
113
+ ? "Prove the admitted provider attempt stopped or reconcile its terminal outcome, then settle this exact Landing fence."
114
+ : "Wake the next eligible qualification or landing candidate.",
115
+ });
116
+ return { ...changed, wake: schedulerWake(changed.state) };
117
+ }
118
+
119
+ export function acquireDevDeliveryLandingWarrant(
120
+ stateInput,
121
+ { now = new Date().toISOString(), leaseSeconds } = {},
122
+ ) {
123
+ const currentTime = timestamp(now, "now");
124
+ const transaction = transition(
125
+ stateInput,
126
+ (state, before) => {
127
+ const recovered = recoverExpiredLandingWarrant(state, currentTime);
128
+ if (state.landingWarrant) {
129
+ return {
130
+ warrant: recovered ? null : state.landingWarrant,
131
+ recovered,
132
+ action: recovered
133
+ ? "expired-landing-warrant-stop-required-noop"
134
+ : "exclusive-landing-warrant-retained-noop",
135
+ mutated: false,
136
+ };
137
+ }
138
+ const qualified = state.candidates
139
+ .filter((entry) => entry.status === "qualified")
140
+ .sort(
141
+ (left, right) =>
142
+ left.enqueuedAt.localeCompare(right.enqueuedAt) ||
143
+ left.candidateId.localeCompare(right.candidateId),
144
+ );
145
+ let candidate = null;
146
+ let blockedReason = null;
147
+ let older = [];
148
+ for (const entry of qualified) {
149
+ const eligibility = landingEligibility(state, entry);
150
+ if (eligibility.eligible) {
151
+ candidate = entry;
152
+ older = eligibility.older;
153
+ break;
154
+ }
155
+ blockedReason ||= eligibility.reason;
156
+ }
157
+ if (!candidate) {
158
+ return {
159
+ warrant: null,
160
+ recovered,
161
+ blockedReason,
162
+ action: blockedReason
163
+ ? "landing-overtake-bound-noop"
164
+ : "no-qualified-candidate-noop",
165
+ mutated: Boolean(recovered),
166
+ };
167
+ }
168
+ state.landingCounter += 1;
169
+ const duration = positiveInteger(
170
+ leaseSeconds,
171
+ "landing leaseSeconds",
172
+ state.policy.landingLeaseSeconds,
173
+ );
174
+ const warrant = {
175
+ schema: DEV_DELIVERY_LANDING_WARRANT_SCHEMA,
176
+ authority: "merge-group-admission",
177
+ mergeGroupAdmission: true,
178
+ candidateId: candidate.candidateId,
179
+ generation: state.landingCounter,
180
+ issuedAt: currentTime,
181
+ heartbeatAt: currentTime,
182
+ expiresAt: new Date(
183
+ Date.parse(currentTime) + duration * 1000,
184
+ ).toISOString(),
185
+ token: "",
186
+ };
187
+ warrant.token = authorityToken(
188
+ warrant.schema,
189
+ before,
190
+ candidate,
191
+ warrant.generation,
192
+ currentTime,
193
+ );
194
+ state.landingWarrant = warrant;
195
+ candidate.status = "landing";
196
+ candidate.updatedAt = currentTime;
197
+ for (const predecessor of older)
198
+ predecessor.landingOvertakes = (predecessor.landingOvertakes || 0) + 1;
199
+ return {
200
+ warrant,
201
+ recovered,
202
+ candidate,
203
+ blockedReason: null,
204
+ action: "landing-warrant-acquired",
205
+ };
206
+ },
207
+ currentTime,
208
+ );
209
+ const changed = receipt(transaction, transaction.result.action, {
210
+ candidateId: transaction.result.warrant?.candidateId || null,
211
+ authority: transaction.result.warrant?.authority || null,
212
+ mergeGroupAdmission: Boolean(transaction.result.warrant),
213
+ retainedExpiredLandingWarrant: Boolean(transaction.result.recovered),
214
+ blockedReason: transaction.result.blockedReason || null,
215
+ nextAction: transaction.result.warrant
216
+ ? "Admit only this exact candidate to merge_group."
217
+ : transaction.result.recovered
218
+ ? "Prove provider stop or reconcile terminal outcome, then settle the retained Landing fence."
219
+ : "Wait for a qualified candidate.",
220
+ });
221
+ return {
222
+ ...changed,
223
+ warrant: transaction.result.warrant,
224
+ wake: schedulerWake(changed.state),
225
+ };
226
+ }
227
+
228
+ function applyDevDeliveryLandingHeartbeat(
229
+ stateInput,
230
+ warrantInput,
231
+ { now = new Date().toISOString(), leaseSeconds, providerAttempt } = {},
232
+ ) {
233
+ const currentTime = timestamp(now, "now");
234
+ const transaction = transition(
235
+ stateInput,
236
+ (state, before) => {
237
+ const warrant = assertDevDeliveryLandingWarrant(
238
+ before,
239
+ warrantInput,
240
+ currentTime,
241
+ );
242
+ if (!warrant.providerAttempt) {
243
+ throw new Error(
244
+ "Landing heartbeat requires a persisted admitted provider attempt",
245
+ );
246
+ }
247
+ if (!providerAttempt) {
248
+ throw new Error(
249
+ "Landing heartbeat requires the persisted admitted provider attempt input",
250
+ );
251
+ }
252
+ const exactProviderAttempt = normalizeDevDeliveryProviderAttempt(
253
+ providerAttempt,
254
+ {
255
+ repository: before.repository,
256
+ sourceHead: state.candidates.find(
257
+ (entry) => entry.candidateId === warrant.candidateId,
258
+ )?.sourceHead,
259
+ mergeGroupHead: warrant.mergeGroupHead,
260
+ protectedBase: before.protectedBase,
261
+ },
262
+ );
263
+ if (
264
+ JSON.stringify(exactProviderAttempt) !==
265
+ JSON.stringify(warrant.providerAttempt)
266
+ ) {
267
+ throw new Error(
268
+ "Landing heartbeat provider attempt does not match persisted admission",
269
+ );
270
+ }
271
+ if (warrant.heartbeatAt === currentTime)
272
+ return {
273
+ warrant,
274
+ action: "duplicate-landing-heartbeat-noop",
275
+ mutated: false,
276
+ };
277
+ const duration = positiveInteger(
278
+ leaseSeconds,
279
+ "landing leaseSeconds",
280
+ state.policy.landingLeaseSeconds,
281
+ );
282
+ state.landingWarrant.heartbeatAt = currentTime;
283
+ state.landingWarrant.expiresAt = new Date(
284
+ Date.parse(currentTime) + duration * 1000,
285
+ ).toISOString();
286
+ return { warrant: state.landingWarrant, action: "landing-heartbeat" };
287
+ },
288
+ currentTime,
289
+ );
290
+ const changed = receipt(transaction, transaction.result.action, {
291
+ candidateId: transaction.result.warrant.candidateId,
292
+ authorityGeneration: transaction.result.warrant.generation,
293
+ expiresAt: transaction.result.warrant.expiresAt,
294
+ nextAction:
295
+ "Continue the exact landing attempt while the Warrant remains current.",
296
+ });
297
+ return {
298
+ ...changed,
299
+ warrant: transaction.result.warrant,
300
+ wake: schedulerWake(changed.state),
301
+ };
302
+ }
303
+
304
+ export async function heartbeatDevDeliveryLandingWarrant(
305
+ stateInput,
306
+ warrantInput,
307
+ {
308
+ providerAttempt,
309
+ now = new Date().toISOString(),
310
+ leaseSeconds,
311
+ token = process.env.GITHUB_TOKEN,
312
+ apiUrl = process.env.GITHUB_API_URL || "https://api.github.com",
313
+ } = {},
314
+ ) {
315
+ const state = normalizeDevDeliveryAuthorityState(stateInput);
316
+ const currentTime = timestamp(now, "now");
317
+ const warrant = assertDevDeliveryLandingWarrant(
318
+ state,
319
+ warrantInput,
320
+ currentTime,
321
+ );
322
+ const candidate = state.candidates.find(
323
+ (entry) => entry.candidateId === warrant.candidateId,
324
+ );
325
+ if (!candidate || !warrant.providerAttempt) {
326
+ throw new Error(
327
+ "Landing heartbeat requires the persisted admitted provider attempt",
328
+ );
329
+ }
330
+ if (!providerAttempt) {
331
+ throw new Error(
332
+ "Landing heartbeat requires the persisted admitted provider attempt input",
333
+ );
334
+ }
335
+ const exactProviderAttempt = normalizeDevDeliveryProviderAttempt(
336
+ providerAttempt,
337
+ {
338
+ repository: state.repository,
339
+ sourceHead: candidate.sourceHead,
340
+ mergeGroupHead: warrant.mergeGroupHead,
341
+ protectedBase: state.protectedBase,
342
+ },
343
+ );
344
+ if (
345
+ JSON.stringify(exactProviderAttempt) !==
346
+ JSON.stringify(warrant.providerAttempt)
347
+ ) {
348
+ throw new Error(
349
+ "Landing heartbeat provider attempt does not match persisted admission",
350
+ );
351
+ }
352
+ const activeAttempt = await readGitHubLandingActiveProviderAttempt({
353
+ state,
354
+ candidate,
355
+ warrant,
356
+ providerAttempt: exactProviderAttempt,
357
+ token,
358
+ apiUrl,
359
+ now: currentTime,
360
+ });
361
+ return applyDevDeliveryLandingHeartbeat(state, warrantInput, {
362
+ now: currentTime,
363
+ leaseSeconds,
364
+ providerAttempt: activeAttempt,
365
+ });
366
+ }
367
+
368
+ export const heartbeatDevDeliveryLandingWarrantWithGitHubProvider =
369
+ heartbeatDevDeliveryLandingWarrant;
370
+
371
+ export async function admitDevDeliveryMergeGroup(
372
+ stateInput,
373
+ authorityInput,
374
+ {
375
+ mergeGroupHead,
376
+ providerRunId,
377
+ providerRunAttempt,
378
+ token = process.env.GITHUB_TOKEN,
379
+ apiUrl = process.env.GITHUB_API_URL || "https://api.github.com",
380
+ now = new Date().toISOString(),
381
+ } = {},
382
+ ) {
383
+ const state = normalizeDevDeliveryAuthorityState(stateInput);
384
+ const currentTime = timestamp(now, "now");
385
+ const warrant = assertDevDeliveryLandingWarrant(
386
+ state,
387
+ authorityInput,
388
+ currentTime,
389
+ );
390
+ const candidate = state.candidates.find(
391
+ (entry) => entry.candidateId === warrant.candidateId,
392
+ );
393
+ if (!candidate) {
394
+ throw new Error("merge_group admission requires the warranted candidate");
395
+ }
396
+ const providerAttempt = await readGitHubLandingProviderAttempt({
397
+ state,
398
+ candidate,
399
+ mergeGroupHead,
400
+ providerRunId,
401
+ providerRunAttempt,
402
+ token,
403
+ apiUrl,
404
+ });
405
+ return admitDevDeliveryMergeGroupWithVerifiedProviderAttempt(
406
+ state,
407
+ authorityInput,
408
+ { mergeGroupHead, providerAttempt, now: currentTime },
409
+ );
410
+ }
411
+
412
+ export function settleDevDeliveryAuthorityCandidate(
413
+ stateInput,
414
+ input,
415
+ options = {},
416
+ ) {
417
+ const now = options.now || new Date().toISOString();
418
+ return settleDevDeliveryAuthorityCandidateInternal(stateInput, input, {
419
+ now,
420
+ sealedProviderReadback:
421
+ options[DEV_DELIVERY_TESTING_PROVIDER_READBACK] || null,
422
+ });
423
+ }
424
+
425
+ export async function settleDevDeliveryAuthorityCandidateWithGitHubProvider(
426
+ stateInput,
427
+ input,
428
+ {
429
+ now = new Date().toISOString(),
430
+ token = process.env.GITHUB_TOKEN,
431
+ apiUrl = process.env.GITHUB_API_URL || "https://api.github.com",
432
+ } = {},
433
+ ) {
434
+ const initial = normalizeDevDeliveryAuthorityState(stateInput);
435
+ const pullRequestNumber = positiveInteger(
436
+ input?.pullRequestNumber,
437
+ "pullRequestNumber",
438
+ );
439
+ const sourceHead = exactSha(input?.sourceHead, "sourceHead");
440
+ const candidate = initial.candidates.find(
441
+ (entry) =>
442
+ entry.pullRequestNumber === pullRequestNumber &&
443
+ entry.sourceHead === sourceHead &&
444
+ initial.landingWarrant?.candidateId === entry.candidateId,
445
+ );
446
+ const sealedProviderReadback =
447
+ candidate && initial.landingWarrant?.providerAttempt
448
+ ? await readGitHubLandingTerminalState({
449
+ state: initial,
450
+ candidate,
451
+ warrant: initial.landingWarrant,
452
+ token,
453
+ apiUrl,
454
+ now,
455
+ })
456
+ : null;
457
+ return settleDevDeliveryAuthorityCandidateInternal(stateInput, input, {
458
+ now,
459
+ sealedProviderReadback,
460
+ });
461
+ }
@@ -0,0 +1,48 @@
1
+ import { devDeliveryTimestamp as timestamp } from "./dev-delivery-common.js";
2
+ import {
3
+ TERMINAL_STATES,
4
+ normalizeDevDeliveryAuthorityState,
5
+ schedulerPolicy,
6
+ } from "./dev-delivery-authority-state.js";
7
+ import { schedulerWake } from "./dev-delivery-authority-qualification.js";
8
+
9
+ export function observeDevDeliveryAuthorityState(
10
+ stateInput,
11
+ { now = new Date().toISOString() } = {},
12
+ ) {
13
+ const state = normalizeDevDeliveryAuthorityState(stateInput);
14
+ const states = {};
15
+ for (const candidate of state.candidates) {
16
+ states[candidate.status] = (states[candidate.status] || 0) + 1;
17
+ }
18
+ return {
19
+ schema: "kungfu.buildchain.dev-delivery-authority-observation/v1",
20
+ authorityMode: state.authorityMode,
21
+ repository: state.repository,
22
+ protectedBase: state.protectedBase,
23
+ stateRoot: state.stateRoot,
24
+ generation: state.generation,
25
+ qualification: {
26
+ bound: state.policy.maxQualificationLeases,
27
+ active: state.qualificationLeases,
28
+ mergeGroupAdmission: false,
29
+ },
30
+ landing: {
31
+ bound: 1,
32
+ active: state.landingWarrant,
33
+ mergeGroupAdmission: Boolean(state.landingWarrant),
34
+ },
35
+ fairness: {
36
+ maxLandingOvertakes: schedulerPolicy(state).maxLandingOvertakes,
37
+ candidates: state.candidates
38
+ .filter((candidate) => !TERMINAL_STATES.has(candidate.status))
39
+ .map((candidate) => ({
40
+ candidateId: candidate.candidateId,
41
+ landingOvertakes: candidate.landingOvertakes || 0,
42
+ })),
43
+ },
44
+ wake: schedulerWake(state),
45
+ states,
46
+ observedAt: timestamp(now, "now"),
47
+ };
48
+ }