@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,583 @@
1
+ import {
2
+ devDeliveryClone as clone,
3
+ devDeliveryContentRoot,
4
+ devDeliveryExactRoot as exactRoot,
5
+ devDeliveryExactSha as exactSha,
6
+ devDeliveryPositiveInteger as positiveInteger,
7
+ devDeliveryProtectedBase as protectedBase,
8
+ devDeliveryRepository as repository,
9
+ devDeliveryText as text,
10
+ devDeliveryTimestamp as timestamp,
11
+ } from "./dev-delivery-common.js";
12
+ import { validateDevDeliveryCandidateChain } from "./dev-delivery-candidate-identity.js";
13
+ import { normalizeDevDeliveryQueue } from "./dev-delivery-warrant.js";
14
+ import { normalizeDevDeliveryProviderAttempt } from "./dev-delivery-provider-attempt.js";
15
+
16
+ export const DEV_DELIVERY_AUTHORITY_CONTRACT =
17
+ "kungfu-buildchain-dev-delivery-authority";
18
+ export const DEV_DELIVERY_AUTHORITY_MODE = "bounded-qualification-landing";
19
+ export const DEV_DELIVERY_QUALIFICATION_LEASE_SCHEMA =
20
+ "kungfu.buildchain.dev-delivery-qualification-lease/v1";
21
+ export const DEV_DELIVERY_LANDING_WARRANT_SCHEMA =
22
+ "kungfu.buildchain.dev-delivery-landing-warrant/v1";
23
+ export const DEV_DELIVERY_AUTHORITY_RECEIPT_SCHEMA =
24
+ "kungfu.buildchain.dev-delivery-authority-receipt/v1";
25
+ export const DEV_DELIVERY_MERGE_GROUP_ADMISSION_SCHEMA =
26
+ "kungfu.buildchain.dev-delivery-merge-group-admission/v1";
27
+ export const DEV_DELIVERY_AUTHORITY_MIGRATION_SCHEMA =
28
+ "kungfu.buildchain.dev-delivery-authority-migration/v1";
29
+ export const DEV_DELIVERY_SCHEDULER_REASON_SCHEMA =
30
+ "kungfu.buildchain.dev-delivery-scheduler-reason/v1";
31
+ export const DEV_DELIVERY_SCHEDULER_WAKE_SCHEMA =
32
+ "kungfu.buildchain.dev-delivery-scheduler-wake/v1";
33
+
34
+ import {
35
+ DEV_DELIVERY_COMPATIBILITY_QUALIFICATION_SCHEMA,
36
+ DEV_DELIVERY_NATIVE_QUALIFICATION_SCHEMA,
37
+ TERMINAL_STATES,
38
+ normalizeDevDeliveryAuthorityCandidate as normalizeCandidate,
39
+ } from "./dev-delivery-authority-candidate.js";
40
+ export {
41
+ DEV_DELIVERY_NATIVE_QUALIFICATION_SCHEMA,
42
+ TERMINAL_STATES,
43
+ normalizeCandidate,
44
+ };
45
+
46
+ function nonNegativeInteger(value, label, fallback = 0) {
47
+ const parsed = Number(value ?? fallback);
48
+ if (!Number.isInteger(parsed) || parsed < 0)
49
+ throw new Error(`${label} must be a non-negative integer`);
50
+ return parsed;
51
+ }
52
+
53
+ function stateBody(state) {
54
+ const body = clone(state);
55
+ delete body.stateRoot;
56
+ return body;
57
+ }
58
+
59
+ export function withStateRoot(state) {
60
+ const body = stateBody(state);
61
+ return { ...body, stateRoot: devDeliveryContentRoot(body) };
62
+ }
63
+
64
+ function normalizePolicy(
65
+ policy = {},
66
+ { materializeSchedulerDefaults = false } = {},
67
+ ) {
68
+ const normalized = {
69
+ maxQualificationLeases: positiveInteger(
70
+ policy.maxQualificationLeases,
71
+ "policy maxQualificationLeases",
72
+ 2,
73
+ ),
74
+ qualificationLeaseSeconds: positiveInteger(
75
+ policy.qualificationLeaseSeconds,
76
+ "policy qualificationLeaseSeconds",
77
+ 3600,
78
+ ),
79
+ landingLeaseSeconds: positiveInteger(
80
+ policy.landingLeaseSeconds,
81
+ "policy landingLeaseSeconds",
82
+ 900,
83
+ ),
84
+ };
85
+ if (
86
+ materializeSchedulerDefaults ||
87
+ Object.hasOwn(policy, "maxLandingOvertakes")
88
+ ) {
89
+ normalized.maxLandingOvertakes = nonNegativeInteger(
90
+ policy.maxLandingOvertakes,
91
+ "policy maxLandingOvertakes",
92
+ 2,
93
+ );
94
+ }
95
+ if (
96
+ materializeSchedulerDefaults ||
97
+ Object.hasOwn(policy, "maxQualificationAttempts")
98
+ ) {
99
+ normalized.maxQualificationAttempts = positiveInteger(
100
+ policy.maxQualificationAttempts,
101
+ "policy maxQualificationAttempts",
102
+ 3,
103
+ );
104
+ }
105
+ return normalized;
106
+ }
107
+
108
+ export function schedulerPolicy(state) {
109
+ return {
110
+ maxLandingOvertakes: nonNegativeInteger(
111
+ state.policy.maxLandingOvertakes,
112
+ "policy maxLandingOvertakes",
113
+ 2,
114
+ ),
115
+ maxQualificationAttempts: positiveInteger(
116
+ state.policy.maxQualificationAttempts,
117
+ "policy maxQualificationAttempts",
118
+ 3,
119
+ ),
120
+ };
121
+ }
122
+
123
+ function normalizeQualificationLease(input) {
124
+ if (input.schema !== DEV_DELIVERY_QUALIFICATION_LEASE_SCHEMA)
125
+ throw new Error("qualification lease schema is unsupported");
126
+ if (input.authority !== "qualification-only")
127
+ throw new Error("qualification lease authority must be qualification-only");
128
+ if (input.mergeGroupAdmission !== false)
129
+ throw new Error("qualification lease cannot carry merge_group admission");
130
+ const lease = {
131
+ schema: input.schema,
132
+ authority: input.authority,
133
+ mergeGroupAdmission: false,
134
+ candidateId: exactRoot(
135
+ input.candidateId,
136
+ "qualification lease candidateId",
137
+ ),
138
+ token: exactRoot(input.token, "qualification lease token"),
139
+ generation: positiveInteger(
140
+ input.generation,
141
+ "qualification lease generation",
142
+ ),
143
+ issuedAt: timestamp(input.issuedAt, "qualification lease issuedAt"),
144
+ expiresAt: timestamp(input.expiresAt, "qualification lease expiresAt"),
145
+ };
146
+ if (Object.hasOwn(input, "heartbeatAt"))
147
+ lease.heartbeatAt = timestamp(
148
+ input.heartbeatAt,
149
+ "qualification lease heartbeatAt",
150
+ );
151
+ return lease;
152
+ }
153
+
154
+ function normalizeLandingWarrant(input) {
155
+ if (input.schema !== DEV_DELIVERY_LANDING_WARRANT_SCHEMA)
156
+ throw new Error("Landing Warrant schema is unsupported");
157
+ if (input.authority !== "merge-group-admission")
158
+ throw new Error("Landing Warrant authority must be merge-group-admission");
159
+ if (input.mergeGroupAdmission !== true)
160
+ throw new Error(
161
+ "Landing Warrant must explicitly carry merge_group admission",
162
+ );
163
+ const warrant = {
164
+ schema: input.schema,
165
+ authority: input.authority,
166
+ mergeGroupAdmission: true,
167
+ candidateId: exactRoot(input.candidateId, "Landing Warrant candidateId"),
168
+ token: exactRoot(input.token, "Landing Warrant token"),
169
+ generation: positiveInteger(input.generation, "Landing Warrant generation"),
170
+ issuedAt: timestamp(input.issuedAt, "Landing Warrant issuedAt"),
171
+ expiresAt: timestamp(input.expiresAt, "Landing Warrant expiresAt"),
172
+ };
173
+ if (Object.hasOwn(input, "heartbeatAt"))
174
+ warrant.heartbeatAt = timestamp(
175
+ input.heartbeatAt,
176
+ "Landing Warrant heartbeatAt",
177
+ );
178
+ if (Object.hasOwn(input, "mergeGroupHead")) {
179
+ warrant.mergeGroupHead = exactSha(
180
+ input.mergeGroupHead,
181
+ "Landing Warrant mergeGroupHead",
182
+ );
183
+ warrant.mergeGroupAdmissionRoot = exactRoot(
184
+ input.mergeGroupAdmissionRoot,
185
+ "Landing Warrant mergeGroupAdmissionRoot",
186
+ );
187
+ warrant.expectedAdmissionStateRoot = exactRoot(
188
+ input.expectedAdmissionStateRoot,
189
+ "Landing Warrant expectedAdmissionStateRoot",
190
+ );
191
+ warrant.admittedAt = timestamp(
192
+ input.admittedAt,
193
+ "Landing Warrant admittedAt",
194
+ );
195
+ warrant.providerAttempt = normalizeDevDeliveryProviderAttempt(
196
+ input.providerAttempt,
197
+ {
198
+ mergeGroupHead: warrant.mergeGroupHead,
199
+ },
200
+ );
201
+ } else if (
202
+ input.mergeGroupAdmissionRoot ||
203
+ input.admittedAt ||
204
+ input.expectedAdmissionStateRoot ||
205
+ input.providerAttempt
206
+ ) {
207
+ throw new Error("Landing Warrant admission evidence is incomplete");
208
+ }
209
+ return warrant;
210
+ }
211
+
212
+ export function createDevDeliveryAuthorityState({
213
+ repository: repositoryInput,
214
+ protectedBase: protectedBaseInput,
215
+ policy = {},
216
+ now = new Date().toISOString(),
217
+ } = {}) {
218
+ return withStateRoot({
219
+ schemaVersion: 2,
220
+ contract: DEV_DELIVERY_AUTHORITY_CONTRACT,
221
+ authorityMode: DEV_DELIVERY_AUTHORITY_MODE,
222
+ repository: repository(repositoryInput),
223
+ protectedBase: protectedBase(protectedBaseInput),
224
+ generation: 0,
225
+ qualificationCounter: 0,
226
+ landingCounter: 0,
227
+ policy: normalizePolicy(policy, { materializeSchedulerDefaults: true }),
228
+ qualificationLeases: [],
229
+ landingWarrant: null,
230
+ candidates: [],
231
+ migration: null,
232
+ updatedAt: timestamp(now, "now"),
233
+ });
234
+ }
235
+
236
+ function validateQualificationBindings(state) {
237
+ if (state.qualificationLeases.length > state.policy.maxQualificationLeases)
238
+ throw new Error("qualification lease bound exceeded");
239
+ const qualificationIds = new Set();
240
+ for (const lease of state.qualificationLeases) {
241
+ if (qualificationIds.has(lease.candidateId))
242
+ throw new Error("candidate cannot hold two qualification leases");
243
+ qualificationIds.add(lease.candidateId);
244
+ const candidate = state.candidates.find(
245
+ (entry) => entry.candidateId === lease.candidateId,
246
+ );
247
+ if (!candidate || candidate.status !== "qualifying")
248
+ throw new Error(
249
+ "qualification lease must match one qualifying candidate",
250
+ );
251
+ }
252
+ return qualificationIds;
253
+ }
254
+
255
+ function validateCandidateBindings(state, qualificationIds) {
256
+ for (const candidate of state.candidates) {
257
+ if (
258
+ candidate.status === "qualifying" &&
259
+ !qualificationIds.has(candidate.candidateId)
260
+ )
261
+ throw new Error(
262
+ "qualifying candidate exists without a Qualification Lease",
263
+ );
264
+ if (
265
+ candidate.status === "landing" &&
266
+ state.landingWarrant?.candidateId !== candidate.candidateId
267
+ )
268
+ throw new Error(
269
+ "landing candidate exists without the exclusive Landing Warrant",
270
+ );
271
+ if (
272
+ ["qualified", "landing"].includes(candidate.status) &&
273
+ !candidate.qualification
274
+ )
275
+ throw new Error(
276
+ "qualified or landing candidate requires qualification evidence",
277
+ );
278
+ if (
279
+ ["queued", "qualifying"].includes(candidate.status) &&
280
+ candidate.qualification
281
+ )
282
+ throw new Error(
283
+ "unqualified candidate cannot carry qualification evidence",
284
+ );
285
+ if (!TERMINAL_STATES.has(candidate.status) && candidate.terminal)
286
+ throw new Error("active candidate cannot carry terminal evidence");
287
+ if (
288
+ TERMINAL_STATES.has(candidate.status) &&
289
+ candidate.terminal?.outcome !== candidate.status
290
+ )
291
+ throw new Error(
292
+ "terminal candidate status and evidence outcome must match",
293
+ );
294
+ }
295
+ const active = state.candidates.filter((candidate) =>
296
+ ["qualifying", "qualified", "landing"].includes(candidate.status),
297
+ );
298
+ for (let leftIndex = 0; leftIndex < active.length; leftIndex += 1) {
299
+ for (
300
+ let rightIndex = leftIndex + 1;
301
+ rightIndex < active.length;
302
+ rightIndex += 1
303
+ ) {
304
+ const left = active[leftIndex];
305
+ const right = active[rightIndex];
306
+ const leftDomains = left.qualificationDomains || [];
307
+ const rightDomains = right.qualificationDomains || [];
308
+ if (
309
+ leftDomains.length === 0 ||
310
+ rightDomains.length === 0 ||
311
+ leftDomains.some((domain) => rightDomains.includes(domain))
312
+ ) {
313
+ throw new Error(
314
+ "active candidates violate the rooted qualification-domain safety boundary",
315
+ );
316
+ }
317
+ }
318
+ }
319
+ const { maxLandingOvertakes } = schedulerPolicy(state);
320
+ if (
321
+ state.candidates.some(
322
+ (candidate) => (candidate.landingOvertakes || 0) > maxLandingOvertakes,
323
+ )
324
+ ) {
325
+ throw new Error("candidate landing overtake bound exceeded");
326
+ }
327
+ }
328
+
329
+ export function normalizeDevDeliveryAuthorityState(input, expected = {}) {
330
+ const state = clone(input || {});
331
+ if (
332
+ state.contract !== DEV_DELIVERY_AUTHORITY_CONTRACT ||
333
+ Number(state.schemaVersion) !== 2 ||
334
+ state.authorityMode !== DEV_DELIVERY_AUTHORITY_MODE
335
+ ) {
336
+ throw new Error(
337
+ `${DEV_DELIVERY_AUTHORITY_MODE} state must use ${DEV_DELIVERY_AUTHORITY_CONTRACT} schemaVersion 2`,
338
+ );
339
+ }
340
+ state.repository = repository(state.repository);
341
+ state.protectedBase = protectedBase(state.protectedBase);
342
+ if (expected.repository && state.repository !== expected.repository)
343
+ throw new Error("dev delivery authority repository mismatch");
344
+ if (expected.protectedBase && state.protectedBase !== expected.protectedBase)
345
+ throw new Error("dev delivery authority protectedBase mismatch");
346
+ state.generation = nonNegativeInteger(
347
+ state.generation,
348
+ "authority generation",
349
+ );
350
+ state.qualificationCounter = nonNegativeInteger(
351
+ state.qualificationCounter,
352
+ "qualificationCounter",
353
+ );
354
+ state.landingCounter = nonNegativeInteger(
355
+ state.landingCounter,
356
+ "landingCounter",
357
+ );
358
+ state.policy = normalizePolicy(state.policy);
359
+ state.migration = state.migration
360
+ ? {
361
+ schema: text(state.migration.schema),
362
+ legacyContract: text(state.migration.legacyContract),
363
+ legacyStateRoot: exactRoot(
364
+ state.migration.legacyStateRoot,
365
+ "migration legacyStateRoot",
366
+ ),
367
+ migratedAt: timestamp(
368
+ state.migration.migratedAt,
369
+ "migration migratedAt",
370
+ ),
371
+ }
372
+ : null;
373
+ if (
374
+ state.migration &&
375
+ state.migration.schema !== DEV_DELIVERY_AUTHORITY_MIGRATION_SCHEMA
376
+ )
377
+ throw new Error("authority migration schema is unsupported");
378
+ state.candidates = (state.candidates || []).map((candidate) =>
379
+ normalizeCandidate(candidate, state),
380
+ );
381
+ validateDevDeliveryCandidateChain(state.candidates, TERMINAL_STATES);
382
+ if (
383
+ new Set(state.candidates.map((candidate) => candidate.candidateId)).size !==
384
+ state.candidates.length
385
+ )
386
+ throw new Error("candidateId must be unique within authority state");
387
+ state.qualificationLeases = (state.qualificationLeases || []).map(
388
+ normalizeQualificationLease,
389
+ );
390
+ const qualificationIds = validateQualificationBindings(state);
391
+ state.landingWarrant = state.landingWarrant
392
+ ? normalizeLandingWarrant(state.landingWarrant)
393
+ : null;
394
+ if (state.landingWarrant) {
395
+ if (qualificationIds.has(state.landingWarrant.candidateId))
396
+ throw new Error(
397
+ "candidate cannot hold qualification and Landing authority together",
398
+ );
399
+ const candidate = state.candidates.find(
400
+ (entry) => entry.candidateId === state.landingWarrant.candidateId,
401
+ );
402
+ if (!candidate || candidate.status !== "landing")
403
+ throw new Error(
404
+ "the exclusive Landing Warrant must match one landing candidate",
405
+ );
406
+ }
407
+ validateCandidateBindings(state, qualificationIds);
408
+ state.updatedAt = timestamp(state.updatedAt, "authority updatedAt");
409
+ const rooted = withStateRoot(state);
410
+ if (input.stateRoot && input.stateRoot !== rooted.stateRoot)
411
+ throw new Error("dev delivery authority stateRoot drift");
412
+ return rooted;
413
+ }
414
+
415
+ function migratedCandidate(candidate, state) {
416
+ return normalizeCandidate(
417
+ {
418
+ ...candidate,
419
+ status: TERMINAL_STATES.has(candidate.status)
420
+ ? candidate.status
421
+ : "queued",
422
+ qualification: null,
423
+ terminal: candidate.terminal
424
+ ? {
425
+ outcome: candidate.terminal.outcome,
426
+ evidenceRoot: candidate.terminal.evidenceRoot,
427
+ reason: candidate.terminal.reason,
428
+ settledAt: candidate.terminal.closedAt,
429
+ }
430
+ : null,
431
+ qualificationDomains: [],
432
+ qualificationAttempts: candidate.attempts || 0,
433
+ landingOvertakes: 0,
434
+ },
435
+ state,
436
+ );
437
+ }
438
+
439
+ export function migrateDevDeliveryAuthorityState(
440
+ queueInput,
441
+ { policy = {}, now = new Date().toISOString() } = {},
442
+ ) {
443
+ const legacy = normalizeDevDeliveryQueue(queueInput);
444
+ const state = createDevDeliveryAuthorityState({
445
+ repository: legacy.repository,
446
+ protectedBase: legacy.protectedBase,
447
+ policy,
448
+ now,
449
+ });
450
+ state.candidates = legacy.candidates.map((candidate) =>
451
+ migratedCandidate(candidate, state),
452
+ );
453
+ state.generation = legacy.generation;
454
+ state.qualificationCounter = legacy.fencingCounter;
455
+ state.landingCounter = legacy.fencingCounter;
456
+ state.migration = {
457
+ schema: DEV_DELIVERY_AUTHORITY_MIGRATION_SCHEMA,
458
+ legacyContract: legacy.contract,
459
+ legacyStateRoot: legacy.stateRoot,
460
+ migratedAt: timestamp(now, "now"),
461
+ };
462
+ if (legacy.activeWarrant) {
463
+ const warrant = legacy.activeWarrant;
464
+ const historicalPhaseLess = !Object.hasOwn(warrant, "phase");
465
+ state.qualificationCounter = Math.max(
466
+ state.qualificationCounter,
467
+ warrant.generation,
468
+ );
469
+ state.landingCounter = Math.max(state.landingCounter, warrant.generation);
470
+ const candidate = state.candidates.find(
471
+ (entry) => entry.candidateId === warrant.candidateId,
472
+ );
473
+ if (historicalPhaseLess || warrant.phase === "qualified") {
474
+ candidate.status = "landing";
475
+ candidate.qualification = {
476
+ schema: DEV_DELIVERY_COMPATIBILITY_QUALIFICATION_SCHEMA,
477
+ authority: "legacy-compatibility-only",
478
+ nativeProofAuthority: false,
479
+ legacyStateRoot: legacy.stateRoot,
480
+ legacyWarrantPhase: historicalPhaseLess ? "phase-less" : "qualified",
481
+ legacyFencingToken: warrant.fencingToken,
482
+ legacyGeneration: warrant.generation,
483
+ qualificationReceiptRoot: historicalPhaseLess
484
+ ? null
485
+ : exactRoot(
486
+ warrant.qualificationReceiptRoot,
487
+ "Warrant qualificationReceiptRoot",
488
+ ),
489
+ sourceProofRoot: candidate.sourceProofRoot,
490
+ nativeProofRoot: historicalPhaseLess
491
+ ? null
492
+ : exactRoot(warrant.nativeProofRoot, "Warrant nativeProofRoot"),
493
+ nativeExecutionBindingRoot: null,
494
+ nativeExecutionReceiptRoot: historicalPhaseLess
495
+ ? null
496
+ : exactRoot(
497
+ warrant.nativeExecutionReceiptRoot,
498
+ "Warrant nativeExecutionReceiptRoot",
499
+ ),
500
+ nativeCommandRoot: historicalPhaseLess
501
+ ? null
502
+ : candidate.nativeCommandContract?.commandRoot || null,
503
+ qualificationContractRoot: null,
504
+ qualifiedAt: historicalPhaseLess
505
+ ? null
506
+ : timestamp(warrant.qualifiedAt, "Warrant qualifiedAt"),
507
+ };
508
+ state.landingWarrant = {
509
+ schema: DEV_DELIVERY_LANDING_WARRANT_SCHEMA,
510
+ authority: "merge-group-admission",
511
+ mergeGroupAdmission: true,
512
+ candidateId: warrant.candidateId,
513
+ token: warrant.fencingToken,
514
+ generation: warrant.generation,
515
+ issuedAt: warrant.issuedAt,
516
+ expiresAt: warrant.expiresAt,
517
+ };
518
+ } else {
519
+ candidate.status = "qualifying";
520
+ state.qualificationLeases = [
521
+ {
522
+ schema: DEV_DELIVERY_QUALIFICATION_LEASE_SCHEMA,
523
+ authority: "qualification-only",
524
+ mergeGroupAdmission: false,
525
+ candidateId: warrant.candidateId,
526
+ token: warrant.fencingToken,
527
+ generation: warrant.generation,
528
+ issuedAt: warrant.issuedAt,
529
+ expiresAt: warrant.expiresAt,
530
+ },
531
+ ];
532
+ }
533
+ }
534
+ const migrated = normalizeDevDeliveryAuthorityState(withStateRoot(state));
535
+ const receipt = {
536
+ schema: DEV_DELIVERY_AUTHORITY_MIGRATION_SCHEMA,
537
+ legacyStateRoot: legacy.stateRoot,
538
+ nextStateRoot: migrated.stateRoot,
539
+ activeAuthority: migrated.landingWarrant
540
+ ? "landing-warrant"
541
+ : migrated.qualificationLeases.length
542
+ ? "qualification-lease"
543
+ : "none",
544
+ };
545
+ return {
546
+ state: migrated,
547
+ receipt,
548
+ receiptRoot: devDeliveryContentRoot(receipt),
549
+ };
550
+ }
551
+
552
+ export function transition(stateInput, mutate, nowInput) {
553
+ const before = normalizeDevDeliveryAuthorityState(stateInput);
554
+ const state = clone(before);
555
+ const now = timestamp(nowInput, "now");
556
+ const result = mutate(state, before, now);
557
+ if (result?.mutated === false)
558
+ return {
559
+ before,
560
+ after: before,
561
+ expectedOldStateRoot: before.stateRoot,
562
+ result,
563
+ };
564
+ state.generation += 1;
565
+ state.updatedAt = now;
566
+ const after = withStateRoot(state);
567
+ return { before, after, expectedOldStateRoot: before.stateRoot, result };
568
+ }
569
+
570
+ export function receipt(transaction, action, details = {}) {
571
+ const value = {
572
+ schema: DEV_DELIVERY_AUTHORITY_RECEIPT_SCHEMA,
573
+ action,
574
+ ...details,
575
+ expectedOldStateRoot: transaction.expectedOldStateRoot,
576
+ nextStateRoot: transaction.after.stateRoot,
577
+ };
578
+ return {
579
+ state: transaction.after,
580
+ receipt: value,
581
+ receiptRoot: devDeliveryContentRoot(value),
582
+ };
583
+ }
@@ -44,7 +44,14 @@ export function createDevDeliveryCandidateIdentity(
44
44
 
45
45
  export function validateDevDeliveryCandidateChain(candidates, terminalStates) {
46
46
  const precedingCandidates = new Map();
47
+ const latestByPullRequest = new Map();
47
48
  for (const candidate of candidates) {
49
+ const latest = latestByPullRequest.get(candidate.pullRequestNumber);
50
+ if (latest && candidate.identitySemantics !== CHAINED_ATTEMPT_IDENTITY) {
51
+ throw new Error(
52
+ "same-PR successor must chain the latest durable predecessor",
53
+ );
54
+ }
48
55
  if (candidate.identitySemantics === CHAINED_ATTEMPT_IDENTITY) {
49
56
  const predecessor = precedingCandidates.get(
50
57
  candidate.predecessorCandidateId,
@@ -61,8 +68,14 @@ export function validateDevDeliveryCandidateChain(candidates, terminalStates) {
61
68
  if (!terminalStates.has(predecessor.status)) {
62
69
  throw new Error("chained candidate predecessor must be terminal");
63
70
  }
71
+ if (latest?.candidateId !== predecessor.candidateId) {
72
+ throw new Error(
73
+ "chained candidate must bind the latest durable predecessor",
74
+ );
75
+ }
64
76
  }
65
77
  precedingCandidates.set(candidate.candidateId, candidate);
78
+ latestByPullRequest.set(candidate.pullRequestNumber, candidate);
66
79
  }
67
80
  }
68
81
 
@@ -0,0 +1,76 @@
1
+ export function devDeliveryWorkflowContractSurface(pkg, majorLine) {
2
+ return {
3
+ id: "dev-pr-auto-merge",
4
+ kind: "workflow",
5
+ path: ".github/workflows/dev-pr-auto-merge.yml",
6
+ publicRef: `${pkg.repository ? "kungfu-systems/buildchain" : "buildchain"}/.github/workflows/dev-pr-auto-merge.yml@${majorLine}-alpha`,
7
+ requiredInputs: [
8
+ "target-branch",
9
+ "expected-pr-number",
10
+ "expected-head-sha",
11
+ ],
12
+ requiredOutputs: [
13
+ "admission-receipt-root",
14
+ "warrant-state-root",
15
+ "provider-heartbeat-receipt-root",
16
+ "provider-finalizer-boundary-root",
17
+ ],
18
+ breakingDefaults: {
19
+ runtimeSelectorDefault: majorLine,
20
+ authorityMode: "two-phase-delivery-warrant",
21
+ boundedAuthorityWorkflowIntegration: "not-advertised",
22
+ boundedAuthoritySupportedSurfaces: ["cli", "node-api", "schema"],
23
+ publicFloatingCaller: `${majorLine}-alpha`,
24
+ durableSelfDeliveryRef: `${majorLine}-alpha`,
25
+ independentHeartbeatRunner: "macos-15",
26
+ candidateCredentialAccess: "forbidden",
27
+ },
28
+ optionalInputs: [
29
+ "buildchain-repository",
30
+ "buildchain-ref",
31
+ "source-workflow-run-id",
32
+ "legacy-active-owner-binding-json",
33
+ "delivery-warrant-mode",
34
+ "handoff-workflow-id",
35
+ "source-workflow-id",
36
+ "assignment-root",
37
+ "initiative-root",
38
+ "source-identity-root",
39
+ "source-patch-root",
40
+ "plan-root",
41
+ "closure-root",
42
+ "dependency-root",
43
+ "toolchain-root",
44
+ "environment-root",
45
+ "affected-paths-json",
46
+ "shard-evidence-roots-json",
47
+ "release-blocker-priority-json",
48
+ "native-proof-json",
49
+ "native-command",
50
+ "native-command-root",
51
+ "native-heartbeat-seconds",
52
+ "delivery-class",
53
+ "delivery-priority",
54
+ "required-status-checks",
55
+ "queue-admission-context",
56
+ "active-lease-context",
57
+ "ready-label",
58
+ "block-labels",
59
+ "allowed-head-prefixes",
60
+ "require-approval",
61
+ "same-repository-only",
62
+ "max-merges",
63
+ "merge-method",
64
+ "landing-mode",
65
+ "dry-run",
66
+ ],
67
+ guarantees: [
68
+ "this reusable workflow executes the single-flight v1 Delivery Warrant and does not advertise bounded v2 Landing integration",
69
+ "bounded v2 authority is a separate opt-in CLI, Node API, and schema surface whose controller deployment must be explicit",
70
+ "candidate execution and evidence sealing receive no provider write credentials",
71
+ "a separate credentialed hosted runner durably heartbeats the exact fence through provider-confirmed native and seal completion",
72
+ "the finalizer validates rooted heartbeat continuity and latest durable state before qualification, failure settlement, or landing",
73
+ "durable consumers call the public floating workflow and may route a train or exact runtime only through trusted non-persistent dispatch input",
74
+ ],
75
+ };
76
+ }