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

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 (75) hide show
  1. package/architecture/decisions/0003-two-phase-delivery-warrant.md +152 -0
  2. package/architecture/internal-capabilities.json +94 -0
  3. package/architecture/maintainability-policy.json +75 -8
  4. package/architecture/v3-core-mechanism-inventory.json +2 -0
  5. package/architecture/v4-delivery-authority-parity.json +250 -0
  6. package/architecture/v4-delivery-warrant-shadow-fixtures.json +29 -6
  7. package/bin/buildchain.mjs +9 -1
  8. package/contracts/dev-delivery-authority-v2.schema.json +662 -0
  9. package/dist/site/agent-index.json +1 -0
  10. package/dist/site/artifact-schemas.json +2 -0
  11. package/dist/site/buildchain-contract.json +89 -6
  12. package/dist/site/buildchain-site.json +169 -18
  13. package/dist/site/capability-registry.json +2 -2
  14. package/dist/site/cli-registry.json +46 -2
  15. package/dist/site/kfd-claims.json +43 -9
  16. package/dist/site/kfd-upstream-aggregate.json +1 -1
  17. package/dist/site/manual-registry.json +3 -3
  18. package/dist/site/node-api-registry.json +1694 -165
  19. package/dist/site/page-registry.json +162 -11
  20. package/dist/site/public-surface-audit.json +367 -7
  21. package/dist/site/publication-registry.json +4 -4
  22. package/dist/site/release-provenance.json +2 -0
  23. package/dist/site/schemas/dev-delivery-authority-v2.schema.json +662 -0
  24. package/dist/site/site-manifest.json +7 -7
  25. package/dist/site/workflow-registry.json +22 -6
  26. package/docs/MAP.md +1 -0
  27. package/docs/cli-reference.md +211 -13
  28. package/docs/dev-delivery-qualification-landing-adr.md +251 -0
  29. package/docs/dev-delivery-warrant.md +326 -38
  30. package/docs/node-api-reference.md +113 -53
  31. package/package.json +5 -1
  32. package/packages/core/buildchain-contract.js +3 -2
  33. package/packages/core/dev-delivery-authority-candidate.js +270 -0
  34. package/packages/core/dev-delivery-authority-evidence.js +146 -0
  35. package/packages/core/dev-delivery-authority-landing.js +461 -0
  36. package/packages/core/dev-delivery-authority-observation.js +48 -0
  37. package/packages/core/dev-delivery-authority-qualification.js +591 -0
  38. package/packages/core/dev-delivery-authority-settlement.js +213 -0
  39. package/packages/core/dev-delivery-authority-state.js +583 -0
  40. package/packages/core/dev-delivery-candidate-identity.js +13 -0
  41. package/packages/core/dev-delivery-contract-surface.js +76 -0
  42. package/packages/core/dev-delivery-execution-failure.js +133 -0
  43. package/packages/core/dev-delivery-execution-transfer.js +572 -0
  44. package/packages/core/dev-delivery-landing-admission-core.js +119 -0
  45. package/packages/core/dev-delivery-landing-readback.js +598 -0
  46. package/packages/core/dev-delivery-landing-terminal-evidence.js +271 -0
  47. package/packages/core/dev-delivery-landing-testing-port.js +6 -0
  48. package/packages/core/dev-delivery-native-execution.js +110 -0
  49. package/packages/core/dev-delivery-native-proof.js +546 -0
  50. package/packages/core/dev-delivery-process-boundary.js +551 -0
  51. package/packages/core/dev-delivery-provider-attempt.js +127 -0
  52. package/packages/core/dev-delivery-provider-heartbeat.js +370 -0
  53. package/packages/core/dev-delivery-warrant-cancellation.js +1 -0
  54. package/packages/core/dev-delivery-warrant-qualification.js +145 -0
  55. package/packages/core/dev-delivery-warrant-settlement.js +237 -36
  56. package/packages/core/dev-delivery-warrant-state.js +565 -0
  57. package/packages/core/dev-delivery-warrant.js +320 -368
  58. package/scripts/buildchain-cli-help.mjs +11 -2
  59. package/scripts/dev-delivery-authority-command-adapters.mjs +206 -0
  60. package/scripts/dev-delivery-authority-provider.mjs +28 -0
  61. package/scripts/dev-delivery-authority.mjs +490 -0
  62. package/scripts/dev-delivery-native-run.mjs +177 -0
  63. package/scripts/dev-delivery-process-boundary.mjs +260 -0
  64. package/scripts/dev-delivery-proof.mjs +67 -2
  65. package/scripts/dev-delivery-provider-heartbeat.mjs +215 -0
  66. package/scripts/dev-delivery-two-phase-resume.mjs +345 -0
  67. package/scripts/dev-delivery-two-phase.mjs +573 -0
  68. package/scripts/dev-delivery-warrant-options.mjs +266 -0
  69. package/scripts/dev-delivery-warrant-store.mjs +227 -0
  70. package/scripts/dev-delivery-warrant.mjs +227 -193
  71. package/scripts/dev-pr-delivery-warrant.mjs +10 -0
  72. package/scripts/generate-site-bundle.mjs +26 -4
  73. package/scripts/npm-publish-transaction.mjs +2 -2
  74. package/scripts/site-capability-metadata.mjs +12 -0
  75. package/templates/native-dev-delivery.yml +141 -0
@@ -1,310 +1,108 @@
1
- import { devDeliveryClone as clone, devDeliveryContentRoot, devDeliveryExactRoot as exactRoot, devDeliveryExactSha as exactSha, devDeliveryPositiveInteger as positiveInteger, devDeliveryProtectedBase as protectedBase, devDeliveryRepository as repository, devDeliveryText as text, devDeliveryTimestamp as timestamp } from "./dev-delivery-common.js";
2
- import { chainedDevDeliveryAttemptInput, createDevDeliveryCandidateIdentity, validateDevDeliveryCandidateChain } from "./dev-delivery-candidate-identity.js";
3
- import { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA, createCancelQueuedDevDeliveryCandidate } from "./dev-delivery-warrant-cancellation.js";
4
- import { DEV_DELIVERY_SETTLEMENT_RECEIPT_SCHEMA, createDevDeliveryTerminalSettler } from "./dev-delivery-warrant-settlement.js";
5
- import { compareReleaseBlockerPriority, normalizeReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
1
+ import {
2
+ devDeliveryClone as clone,
3
+ devDeliveryContentRoot,
4
+ devDeliveryExactRoot as exactRoot,
5
+ devDeliveryPositiveInteger as positiveInteger,
6
+ devDeliveryText as text,
7
+ devDeliveryTimestamp as timestamp,
8
+ } from "./dev-delivery-common.js";
9
+ import {
10
+ DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA,
11
+ createCancelQueuedDevDeliveryCandidate,
12
+ } from "./dev-delivery-warrant-cancellation.js";
13
+ import {
14
+ DEV_DELIVERY_SETTLEMENT_RECEIPT_SCHEMA,
15
+ createDevDeliveryTerminalSettler,
16
+ normalizeProviderFailureAuthorityBinding,
17
+ } from "./dev-delivery-warrant-settlement.js";
18
+ import {
19
+ normalizeNativeCommandContract,
20
+ validateActiveDevDeliveryWarrant,
21
+ } from "./dev-delivery-native-proof.js";
22
+ import { createDevDeliveryWarrantQualifier } from "./dev-delivery-warrant-qualification.js";
23
+ import {
24
+ DEV_DELIVERY_CLASSES,
25
+ DEV_DELIVERY_LEASE_RECEIPT_SCHEMA,
26
+ DEV_DELIVERY_PRIORITIES,
27
+ DEV_DELIVERY_QUEUE_CONTRACT,
28
+ DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA,
29
+ DEV_DELIVERY_SUBMISSION_RECEIPT_SCHEMA,
30
+ DEV_DELIVERY_WARRANT_SCHEMA,
31
+ TERMINAL_STATES,
32
+ createDevDeliveryQueue,
33
+ issueDevDeliveryWarrant,
34
+ normalizeDevDeliveryQueue,
35
+ rankDevDeliveryCandidates,
36
+ submitDevDeliveryCandidate,
37
+ transitionDevDeliveryQueue as transition,
38
+ } from "./dev-delivery-warrant-state.js";
39
+
6
40
  export { devDeliveryContentRoot } from "./dev-delivery-common.js";
7
- export { RELEASE_BLOCKER_PRIORITY_CLAIM_SCHEMA, createReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
8
- export { SOURCE_QUALIFICATION_PROOF_SCHEMA, SOURCE_QUALIFICATION_PROOF_V2_SCHEMA, PROJECT_CUT_REPLAY_PROOF_SCHEMA, INTEGRATION_DELIVERY_PROOF_SCHEMA, classifyDevDeliveryDelta, createIntegrationDeliveryProof, createProjectCutReplayPlan, createProjectCutReplayProof, createSourceQualificationProof, createSourceQualificationProofV2, verifyIntegrationDeliveryProof, verifyProjectCutReplayProof, verifySourceQualificationProof } from "./dev-delivery-proof.js";
41
+ export {
42
+ RELEASE_BLOCKER_PRIORITY_CLAIM_SCHEMA,
43
+ createReleaseBlockerPriorityClaim,
44
+ } from "./release-blocker-priority.js";
45
+ export {
46
+ SOURCE_QUALIFICATION_PROOF_SCHEMA,
47
+ SOURCE_QUALIFICATION_PROOF_V2_SCHEMA,
48
+ PROJECT_CUT_REPLAY_PROOF_SCHEMA,
49
+ INTEGRATION_DELIVERY_PROOF_SCHEMA,
50
+ classifyDevDeliveryDelta,
51
+ createIntegrationDeliveryProof,
52
+ createProjectCutReplayPlan,
53
+ createProjectCutReplayProof,
54
+ createSourceQualificationProof,
55
+ createSourceQualificationProofV2,
56
+ verifyIntegrationDeliveryProof,
57
+ verifyProjectCutReplayProof,
58
+ verifySourceQualificationProof,
59
+ } from "./dev-delivery-proof.js";
60
+ export {
61
+ DEV_DELIVERY_QUALIFICATION_RECEIPT_SCHEMA,
62
+ NATIVE_COMMAND_CONTRACT_SCHEMA,
63
+ NATIVE_EXECUTION_BINDING_SCHEMA,
64
+ NATIVE_EXECUTION_RECEIPT_SCHEMA,
65
+ NATIVE_PROOF_BASE_DELTA_SCHEMA,
66
+ NATIVE_PROOF_REUSE_DECISION_SCHEMA,
67
+ NATIVE_QUALIFICATION_PROOF_SCHEMA,
68
+ createNativeCommandContract,
69
+ createNativeExecutionBinding,
70
+ createNativeExecutionReceipt,
71
+ createNativeProofBaseDelta,
72
+ createNativeProofReuseDecision,
73
+ createNativeQualificationProof,
74
+ normalizeNativeCommandContract,
75
+ verifyNativeExecutionReceipt,
76
+ verifyNativeProofReuseDecision,
77
+ verifyNativeQualificationProof,
78
+ } from "./dev-delivery-native-proof.js";
79
+ export {
80
+ DEV_DELIVERY_CLASSES,
81
+ DEV_DELIVERY_LEASE_RECEIPT_SCHEMA,
82
+ DEV_DELIVERY_PRIORITIES,
83
+ DEV_DELIVERY_QUEUE_CONTRACT,
84
+ DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA,
85
+ DEV_DELIVERY_SUBMISSION_RECEIPT_SCHEMA,
86
+ DEV_DELIVERY_WARRANT_SCHEMA,
87
+ createDevDeliveryQueue,
88
+ normalizeDevDeliveryQueue,
89
+ rankDevDeliveryCandidates,
90
+ submitDevDeliveryCandidate,
91
+ };
9
92
  export { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA };
10
- export const DEV_DELIVERY_QUEUE_CONTRACT = "kungfu-buildchain-dev-delivery-warrant-queue";
11
- export const DEV_DELIVERY_WARRANT_SCHEMA = "kungfu.buildchain.dev-delivery-warrant/v1";
12
- export const DEV_DELIVERY_SUBMISSION_RECEIPT_SCHEMA = "kungfu.buildchain.dev-delivery-submission-receipt/v1";
13
- export const DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA = "kungfu.buildchain.dev-delivery-selection-receipt/v1";
14
- export const DEV_DELIVERY_LEASE_RECEIPT_SCHEMA = "kungfu.buildchain.dev-delivery-lease-receipt/v1";
15
93
  export { DEV_DELIVERY_SETTLEMENT_RECEIPT_SCHEMA };
16
- export const DEV_DELIVERY_PRIORITIES = Object.freeze({
17
- ordinary: 0,
18
- expedited: 1,
19
- emergency: 2,
20
- });
21
-
22
- export const DEV_DELIVERY_CLASSES = Object.freeze(["non-native-fast", "native-proof-required", "cross-platform", "release"]);
23
-
24
- const TERMINAL_STATES = new Set(["merged", "terminal-failure", "dequeued", "cancelled"]);
25
- function nonNegativeInteger(value, label, fallback = 0) {
26
- const parsed = Number(value ?? fallback);
27
- if (!Number.isInteger(parsed) || parsed < 0) throw new Error(`${label} must be a non-negative integer`);
28
- return parsed;
29
- }
30
-
31
- function priority(value = "ordinary") {
32
- const normalized = text(value || "ordinary").toLowerCase();
33
- if (!(normalized in DEV_DELIVERY_PRIORITIES)) {
34
- throw new Error(`priority must be one of ${Object.keys(DEV_DELIVERY_PRIORITIES).join(", ")}`);
35
- }
36
- return normalized;
37
- }
38
-
39
- function deliveryClass(value) {
40
- const normalized = text(value);
41
- if (!DEV_DELIVERY_CLASSES.includes(normalized)) {
42
- throw new Error(`deliveryClass must be one of ${DEV_DELIVERY_CLASSES.join(", ")}`);
43
- }
44
- return normalized;
45
- }
46
-
47
- function normalizePolicy(policy = {}) {
48
- return {
49
- agingSeconds: positiveInteger(policy.agingSeconds, "policy agingSeconds", 900),
50
- maxPriority: positiveInteger(policy.maxPriority, "policy maxPriority", 2),
51
- leaseSeconds: positiveInteger(policy.leaseSeconds, "policy leaseSeconds", 3600),
52
- emergencyPolicy: text(policy.emergencyPolicy || "reviewed-explicit-only"),
53
- };
54
- }
55
-
56
- function normalizeCandidate(input, expected) {
57
- const identity = createDevDeliveryCandidateIdentity(input, expected, deliveryClass);
58
- if (input.candidateId && input.candidateId !== identity.candidateId) {
59
- throw new Error(`candidateId mismatch for PR #${identity.pullRequestNumber}`);
60
- }
61
- const status = text(input.status || "queued");
62
- if (!["queued", "selected", "proving", "waiting", "blocked", ...TERMINAL_STATES].includes(status)) {
63
- throw new Error(`unsupported candidate status ${status || "<empty>"}`);
64
- }
65
- const candidate = {
66
- ...identity,
67
- sourceHead: exactSha(input.sourceHead, "sourceHead"),
68
- sourcePatchRoot: exactRoot(input.sourcePatchRoot, "sourcePatchRoot"),
69
- sourceProofRoot: exactRoot(input.sourceProofRoot, "sourceProofRoot"),
70
- planRoot: exactRoot(input.planRoot, "planRoot"),
71
- closureRoot: exactRoot(input.closureRoot, "closureRoot"),
72
- dependencyRoot: exactRoot(input.dependencyRoot, "dependencyRoot"),
73
- toolchainRoot: exactRoot(input.toolchainRoot, "toolchainRoot"), ...(input.environmentRoot ? { environmentRoot: exactRoot(input.environmentRoot, "environmentRoot") } : {}), ...(Object.hasOwn(input, "sourceWorkflowRunId") ? { sourceWorkflowRunId: nonNegativeInteger(input.sourceWorkflowRunId, "candidate sourceWorkflowRunId", 0) } : {}),
74
- priority: priority(input.priority),
75
- enqueuedAt: timestamp(input.enqueuedAt, "candidate enqueuedAt"),
76
- updatedAt: timestamp(input.updatedAt || input.enqueuedAt, "candidate updatedAt"),
77
- attempts: positiveInteger(input.attempts, "candidate attempts", 1),
78
- recoveries: nonNegativeInteger(input.recoveries, "candidate recoveries", 0),
79
- status,
80
- terminal: input.terminal || null,
81
- };
82
- if (Object.hasOwn(input, "affectedPaths")) { if (!Array.isArray(input.affectedPaths)) throw new Error("candidate affectedPaths must be an array"); candidate.affectedPaths = [...new Set(input.affectedPaths.map(text).filter(Boolean))].sort(); } if (Object.hasOwn(input, "releaseBlockerPriority")) candidate.releaseBlockerPriority = normalizeReleaseBlockerPriorityClaim(input.releaseBlockerPriority, candidate, expected);
83
- return candidate;
84
- }
85
-
86
- function queueBody(queue) {
87
- const body = clone(queue);
88
- delete body.stateRoot;
89
- return body;
90
- }
91
-
92
- function withQueueRoot(queue) {
93
- return {
94
- ...queueBody(queue),
95
- stateRoot: devDeliveryContentRoot(queueBody(queue)),
96
- };
97
- }
98
-
99
- export function createDevDeliveryQueue({ repository: repositoryInput, protectedBase: protectedBaseInput, policy = {}, now = new Date().toISOString() } = {}) {
100
- return withQueueRoot({
101
- schemaVersion: 1,
102
- contract: DEV_DELIVERY_QUEUE_CONTRACT,
103
- repository: repository(repositoryInput),
104
- protectedBase: protectedBase(protectedBaseInput),
105
- generation: 0,
106
- fencingCounter: 0,
107
- policy: normalizePolicy(policy),
108
- activeWarrant: null,
109
- candidates: [],
110
- updatedAt: timestamp(now, "now"),
111
- });
112
- }
113
-
114
- export function normalizeDevDeliveryQueue(input, expected = {}) {
115
- const queue = clone(input || {});
116
- if (queue.contract !== DEV_DELIVERY_QUEUE_CONTRACT || Number(queue.schemaVersion) !== 1) {
117
- throw new Error(`dev delivery queue must use ${DEV_DELIVERY_QUEUE_CONTRACT} schemaVersion 1`);
118
- }
119
- queue.repository = repository(queue.repository);
120
- queue.protectedBase = protectedBase(queue.protectedBase);
121
- if (expected.repository && queue.repository !== expected.repository) {
122
- throw new Error(`dev delivery queue repository mismatch: ${queue.repository} != ${expected.repository}`);
123
- }
124
- if (expected.protectedBase && queue.protectedBase !== expected.protectedBase) {
125
- throw new Error(`dev delivery queue protectedBase mismatch: ${queue.protectedBase} != ${expected.protectedBase}`);
126
- }
127
- queue.generation = nonNegativeInteger(queue.generation, "queue generation");
128
- queue.fencingCounter = nonNegativeInteger(queue.fencingCounter, "queue fencingCounter");
129
- queue.policy = normalizePolicy(queue.policy);
130
- queue.candidates = (queue.candidates || []).map((candidate) => normalizeCandidate(candidate, queue));
131
- validateDevDeliveryCandidateChain(queue.candidates, TERMINAL_STATES);
132
- queue.updatedAt = timestamp(queue.updatedAt, "queue updatedAt");
133
- if (queue.activeWarrant) {
134
- const warrant = queue.activeWarrant;
135
- if (warrant.schema !== DEV_DELIVERY_WARRANT_SCHEMA) throw new Error("active Warrant schema is unsupported");
136
- warrant.candidateId = exactRoot(warrant.candidateId, "Warrant candidateId");
137
- warrant.fencingToken = exactRoot(warrant.fencingToken, "Warrant fencingToken");
138
- warrant.expectedOldStateRoot = exactRoot(warrant.expectedOldStateRoot, "Warrant expectedOldStateRoot");
139
- warrant.generation = positiveInteger(warrant.generation, "Warrant generation");
140
- warrant.issuedAt = timestamp(warrant.issuedAt, "Warrant issuedAt");
141
- warrant.expiresAt = timestamp(warrant.expiresAt, "Warrant expiresAt");
142
- const activeCandidates = queue.candidates.filter((candidate) => ["selected", "proving", "waiting", "blocked"].includes(candidate.status));
143
- if (activeCandidates.length !== 1 || activeCandidates[0].candidateId !== warrant.candidateId) {
144
- throw new Error("exactly one active candidate must match the active Warrant");
145
- }
146
- if (warrant.releaseBlockerPriority?.claimRoot !== activeCandidates[0].releaseBlockerPriority?.claimRoot) throw new Error("active Warrant release-blocker priority drift");
147
- } else if (queue.candidates.some((candidate) => ["selected", "proving", "waiting", "blocked"].includes(candidate.status))) {
148
- throw new Error("active candidate exists without an active Warrant");
149
- }
150
- const rooted = withQueueRoot(queue);
151
- if (input.stateRoot && input.stateRoot !== rooted.stateRoot) throw new Error("dev delivery queue stateRoot drift");
152
- return rooted;
153
- }
154
-
155
- function transition(queueInput, mutate, nowInput) {
156
- const before = normalizeDevDeliveryQueue(queueInput);
157
- const expectedOldStateRoot = before.stateRoot;
158
- const queue = clone(before);
159
- delete queue.stateRoot;
160
- const now = timestamp(nowInput, "now");
161
- const result = mutate(queue, before, now);
162
- queue.generation += 1;
163
- queue.updatedAt = now;
164
- const after = withQueueRoot(queue);
165
- return { before, after, expectedOldStateRoot, result };
166
- }
167
-
168
- function submissionReceipt({ before, after, candidate, action, now }) {
169
- const queueAgeSeconds = Math.max(0, Math.floor((Date.parse(now) - Date.parse(candidate.enqueuedAt)) / 1000));
170
- return {
171
- schema: DEV_DELIVERY_SUBMISSION_RECEIPT_SCHEMA,
172
- repository: after.repository,
173
- protectedBase: after.protectedBase,
174
- candidateId: candidate.candidateId,
175
- pullRequestNumber: candidate.pullRequestNumber,
176
- sourceHead: candidate.sourceHead,
177
- assignmentRoot: candidate.assignmentRoot,
178
- initiativeRoot: candidate.initiativeRoot,
179
- sourceIdentityRoot: candidate.sourceIdentityRoot,
180
- sourcePatchRoot: candidate.sourcePatchRoot,
181
- sourceProofRoot: candidate.sourceProofRoot,
182
- planRoot: candidate.planRoot,
183
- closureRoot: candidate.closureRoot,
184
- dependencyRoot: candidate.dependencyRoot,
185
- toolchainRoot: candidate.toolchainRoot,
186
- sourceWorkflowRunId: candidate.sourceWorkflowRunId,
187
- ...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
188
- deliveryClass: candidate.deliveryClass,
189
- priority: candidate.priority,
190
- retainedEnqueuedAt: candidate.enqueuedAt,
191
- queueAgeSeconds,
192
- attempts: candidate.attempts,
193
- action,
194
- expectedOldStateRoot: before.stateRoot,
195
- nextStateRoot: after.stateRoot,
196
- nextAction: "Wait for deterministic Warrant selection or observe the active predecessor.",
197
- };
198
- }
199
-
200
- export function submitDevDeliveryCandidate(queueInput, input, { now = new Date().toISOString() } = {}) {
201
- const transaction = transition(
202
- queueInput,
203
- (queue, before, currentTime) => {
204
- const candidate = normalizeCandidate(
205
- {
206
- ...input,
207
- enqueuedAt: input.enqueuedAt || currentTime,
208
- updatedAt: currentTime,
209
- attempts: input.attempts || 1,
210
- recoveries: input.recoveries || 0,
211
- status: "queued",
212
- },
213
- queue,
214
- );
215
- const chainedInput = chainedDevDeliveryAttemptInput({ queue, candidate, input, currentTime, terminalStates: TERMINAL_STATES });
216
- const attemptedCandidate = chainedInput ? normalizeCandidate(chainedInput, queue) : candidate;
217
- const conflicting = queue.candidates.find((entry) => entry.pullRequestNumber === attemptedCandidate.pullRequestNumber && entry.candidateId !== attemptedCandidate.candidateId && !TERMINAL_STATES.has(entry.status));
218
- if (conflicting) throw new Error(`PR #${candidate.pullRequestNumber} already has a different active semantic source`);
219
- const existing = queue.candidates.find((entry) => entry.candidateId === attemptedCandidate.candidateId);
220
- let action = "submitted";
221
- let selected = attemptedCandidate;
222
- if (existing) {
223
- if (TERMINAL_STATES.has(existing.status)) {
224
- throw new Error(`candidate ${attemptedCandidate.candidateId} is terminal and cannot be resubmitted`);
225
- }
226
- const exactProofFields = ["sourcePatchRoot", "sourceProofRoot", "planRoot", "closureRoot", "dependencyRoot", "toolchainRoot"];
227
- const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]) && existing.releaseBlockerPriority?.claimRoot === attemptedCandidate.releaseBlockerPriority?.claimRoot;
228
- if (existing.sourceHead === attemptedCandidate.sourceHead && exactProofMatches) {
229
- action = "duplicate-noop";
230
- selected = existing;
231
- } else {
232
- if (before.activeWarrant?.candidateId === existing.candidateId) {
233
- throw new Error("selected candidate sourceHead cannot change before terminal Warrant closeout");
234
- }
235
- const headChanged = existing.sourceHead !== attemptedCandidate.sourceHead;
236
- existing.sourceHead = attemptedCandidate.sourceHead;
237
- for (const field of exactProofFields) existing[field] = attemptedCandidate[field];
238
- if (Object.hasOwn(attemptedCandidate, "releaseBlockerPriority")) existing.releaseBlockerPriority = attemptedCandidate.releaseBlockerPriority;
239
- else delete existing.releaseBlockerPriority;
240
- existing.updatedAt = currentTime;
241
- existing.attempts += 1;
242
- existing.status = "queued";
243
- action = headChanged ? "safe-head-repair-retained-age" : "safe-proof-refresh-retained-age";
244
- selected = existing;
245
- }
246
- } else {
247
- queue.candidates.push(attemptedCandidate);
248
- }
249
- return { candidate: selected, action };
250
- },
251
- now,
252
- );
253
- const receipt = submissionReceipt({
254
- before: transaction.before,
255
- after: transaction.after,
256
- candidate: transaction.result.candidate,
257
- action: transaction.result.action,
258
- now: timestamp(now, "now"),
259
- });
260
- return {
261
- queue: transaction.after,
262
- receipt,
263
- receiptRoot: devDeliveryContentRoot(receipt),
264
- };
265
- }
266
-
267
- function effectivePriority(candidate, policy, now) {
268
- const ageSeconds = Math.max(0, Math.floor((Date.parse(now) - Date.parse(candidate.enqueuedAt)) / 1000));
269
- const agingBoost = Math.floor(ageSeconds / policy.agingSeconds);
270
- return {
271
- ageSeconds,
272
- basePriority: DEV_DELIVERY_PRIORITIES[candidate.priority],
273
- agingBoost,
274
- score: Math.min(policy.maxPriority, DEV_DELIVERY_PRIORITIES[candidate.priority] + agingBoost),
275
- releaseBlocker: Boolean(candidate.releaseBlockerPriority),
276
- };
277
- }
278
-
279
- export function rankDevDeliveryCandidates(queueInput, { now = new Date().toISOString() } = {}) {
280
- const queue = normalizeDevDeliveryQueue(queueInput);
281
- const currentTime = timestamp(now, "now");
282
- return queue.candidates
283
- .filter((candidate) => candidate.status === "queued")
284
- .map((candidate) => ({
285
- candidate,
286
- priority: effectivePriority(candidate, queue.policy, currentTime),
287
- }))
288
- .sort((left, right) => compareReleaseBlockerPriority(left, right) || right.priority.score - left.priority.score || left.candidate.enqueuedAt.localeCompare(right.candidate.enqueuedAt) || left.candidate.candidateId.localeCompare(right.candidate.candidateId));
289
- }
290
94
 
291
- function warrantToken(input) {
292
- return devDeliveryContentRoot({
293
- schema: DEV_DELIVERY_WARRANT_SCHEMA,
294
- repository: input.repository,
295
- protectedBase: input.protectedBase,
296
- candidateId: input.candidateId,
297
- generation: input.generation,
298
- expectedOldStateRoot: input.expectedOldStateRoot,
299
- issuedAt: input.issuedAt,
300
- });
301
- }
302
-
303
- export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOString(), leaseSeconds } = {}) {
95
+ export function selectDevDeliveryWarrant(
96
+ queueInput,
97
+ { now = new Date().toISOString(), leaseSeconds } = {},
98
+ ) {
304
99
  const currentTime = timestamp(now, "now");
305
100
  let queue = normalizeDevDeliveryQueue(queueInput);
306
101
  let recoveryReceipt = null;
307
- if (queue.activeWarrant && Date.parse(queue.activeWarrant.expiresAt) <= Date.parse(currentTime)) {
102
+ if (
103
+ queue.activeWarrant &&
104
+ Date.parse(queue.activeWarrant.expiresAt) <= Date.parse(currentTime)
105
+ ) {
308
106
  const recovered = recoverExpiredDevDeliveryWarrant(queue, {
309
107
  now: currentTime,
310
108
  });
@@ -312,16 +110,22 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
312
110
  recoveryReceipt = recovered.receipt;
313
111
  }
314
112
  if (queue.activeWarrant) {
113
+ const stopRequired =
114
+ recoveryReceipt?.action === "expired-lease-fenced-stop-required";
315
115
  const receipt = {
316
116
  schema: DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA,
317
- selected: true,
318
- reason: "non-preemptive-active-warrant",
117
+ selected: !stopRequired,
118
+ reason: stopRequired
119
+ ? "expired-provisional-warrant-stop-required"
120
+ : "non-preemptive-active-warrant",
319
121
  candidateId: queue.activeWarrant.candidateId,
320
122
  fencingToken: queue.activeWarrant.fencingToken,
321
123
  leaseGeneration: queue.activeWarrant.generation,
322
124
  expectedOldStateRoot: queue.stateRoot,
323
125
  nextStateRoot: queue.stateRoot,
324
- nextAction: "Continue the active delivery attempt; later candidates remain visibly queued.",
126
+ nextAction: stopRequired
127
+ ? recoveryReceipt.nextAction
128
+ : "Continue the active delivery attempt; later candidates remain visibly queued.",
325
129
  };
326
130
  return {
327
131
  queue,
@@ -353,37 +157,16 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
353
157
  const transaction = transition(
354
158
  queue,
355
159
  (next, before) => {
356
- const candidate = next.candidates.find((entry) => entry.candidateId === selected.candidate.candidateId);
357
- next.fencingCounter += 1;
358
- const issuedAt = currentTime;
359
- const effectiveLeaseSeconds = positiveInteger(leaseSeconds, "leaseSeconds", next.policy.leaseSeconds);
360
- const warrant = {
361
- schema: DEV_DELIVERY_WARRANT_SCHEMA,
362
- repository: next.repository,
363
- protectedBase: next.protectedBase,
364
- candidateId: candidate.candidateId,
365
- pullRequestNumber: candidate.pullRequestNumber,
366
- sourceHead: candidate.sourceHead,
367
- assignmentRoot: candidate.assignmentRoot,
368
- initiativeRoot: candidate.initiativeRoot,
369
- sourceIdentityRoot: candidate.sourceIdentityRoot,
370
- sourcePatchRoot: candidate.sourcePatchRoot,
371
- sourceProofRoot: candidate.sourceProofRoot,
372
- planRoot: candidate.planRoot,
373
- closureRoot: candidate.closureRoot,
374
- dependencyRoot: candidate.dependencyRoot,
375
- toolchainRoot: candidate.toolchainRoot,
376
- sourceWorkflowRunId: candidate.sourceWorkflowRunId,
377
- ...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
378
- deliveryClass: candidate.deliveryClass,
379
- generation: next.fencingCounter,
380
- expectedOldStateRoot: before.stateRoot,
381
- issuedAt,
382
- expiresAt: new Date(Date.parse(issuedAt) + effectiveLeaseSeconds * 1000).toISOString(),
383
- fencingToken: "",
384
- nextAction: "Replay on the exact current dev base, prove required checks, then enqueue the unchanged PR head.",
385
- };
386
- warrant.fencingToken = warrantToken(warrant);
160
+ const candidate = next.candidates.find(
161
+ (entry) => entry.candidateId === selected.candidate.candidateId,
162
+ );
163
+ const warrant = issueDevDeliveryWarrant(
164
+ next,
165
+ before,
166
+ candidate,
167
+ currentTime,
168
+ leaseSeconds,
169
+ );
387
170
  next.activeWarrant = warrant;
388
171
  candidate.status = "selected";
389
172
  candidate.updatedAt = currentTime;
@@ -394,7 +177,11 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
394
177
  const receipt = {
395
178
  schema: DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA,
396
179
  selected: true,
397
- reason: selected.priority.releaseBlocker ? "release-blocker-bounded-priority" : selected.priority.agingBoost > 0 ? "fifo-aging-bounded-priority" : "fifo-bounded-priority",
180
+ reason: selected.priority.releaseBlocker
181
+ ? "release-blocker-bounded-priority"
182
+ : selected.priority.agingBoost > 0
183
+ ? "fifo-aging-bounded-priority"
184
+ : "fifo-bounded-priority",
398
185
  repository: transaction.after.repository,
399
186
  protectedBase: transaction.after.protectedBase,
400
187
  candidateId: transaction.result.candidate.candidateId,
@@ -410,7 +197,23 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
410
197
  dependencyRoot: transaction.result.candidate.dependencyRoot,
411
198
  toolchainRoot: transaction.result.candidate.toolchainRoot,
412
199
  sourceWorkflowRunId: transaction.result.candidate.sourceWorkflowRunId,
413
- ...(Object.hasOwn(transaction.result.candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: transaction.result.candidate.releaseBlockerPriority } : {}),
200
+ ...(transaction.result.candidate.nativeCommandContract
201
+ ? {
202
+ nativeCommandContract:
203
+ transaction.result.candidate.nativeCommandContract,
204
+ }
205
+ : {}),
206
+ ...(transaction.result.candidate.shardEvidenceRoots
207
+ ? {
208
+ shardEvidenceRoots: transaction.result.candidate.shardEvidenceRoots,
209
+ }
210
+ : {}),
211
+ ...(Object.hasOwn(transaction.result.candidate, "releaseBlockerPriority")
212
+ ? {
213
+ releaseBlockerPriority:
214
+ transaction.result.candidate.releaseBlockerPriority,
215
+ }
216
+ : {}),
414
217
  deliveryClass: transaction.result.candidate.deliveryClass,
415
218
  queueAgeSeconds: selected.priority.ageSeconds,
416
219
  basePriority: selected.priority.basePriority,
@@ -430,25 +233,48 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
430
233
  recoveryReceipt,
431
234
  };
432
235
  }
433
-
434
- function assertWarrantMutation(queue, warrant, now) {
236
+ function assertWarrantMutation(
237
+ queue,
238
+ warrant,
239
+ now,
240
+ { allowExpired = false } = {},
241
+ ) {
435
242
  if (!queue.activeWarrant) throw new Error("no active Delivery Warrant");
436
- if (text(warrant?.fencingToken) !== queue.activeWarrant.fencingToken) throw new Error("stale fencing token");
437
- if (Number(warrant?.generation) !== queue.activeWarrant.generation) throw new Error("stale lease generation");
438
- if (text(warrant?.candidateId) !== queue.activeWarrant.candidateId) throw new Error("Warrant candidate mismatch");
439
- if (Date.parse(queue.activeWarrant.expiresAt) <= Date.parse(now)) throw new Error("Delivery Warrant lease expired");
243
+ if (text(warrant?.fencingToken) !== queue.activeWarrant.fencingToken)
244
+ throw new Error("stale fencing token");
245
+ if (Number(warrant?.generation) !== queue.activeWarrant.generation)
246
+ throw new Error("stale lease generation");
247
+ if (text(warrant?.candidateId) !== queue.activeWarrant.candidateId)
248
+ throw new Error("Warrant candidate mismatch");
249
+ if (
250
+ !allowExpired &&
251
+ Date.parse(queue.activeWarrant.expiresAt) <= Date.parse(now)
252
+ )
253
+ throw new Error("Delivery Warrant lease expired");
440
254
  }
441
-
442
- export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Date().toISOString(), leaseSeconds } = {}) {
255
+ export function heartbeatDevDeliveryWarrant(
256
+ queueInput,
257
+ warrant,
258
+ { now = new Date().toISOString(), leaseSeconds } = {},
259
+ ) {
443
260
  const currentTime = timestamp(now, "now");
444
261
  const transaction = transition(
445
262
  queueInput,
446
263
  (queue, before) => {
447
264
  assertWarrantMutation(before, warrant, currentTime);
448
- const effectiveLeaseSeconds = positiveInteger(leaseSeconds, "leaseSeconds", queue.policy.leaseSeconds);
449
- queue.activeWarrant.expiresAt = new Date(Date.parse(currentTime) + effectiveLeaseSeconds * 1000).toISOString();
450
- const candidate = queue.candidates.find((entry) => entry.candidateId === queue.activeWarrant.candidateId);
451
- candidate.status = "proving";
265
+ const effectiveLeaseSeconds = positiveInteger(
266
+ leaseSeconds,
267
+ "leaseSeconds",
268
+ queue.policy.leaseSeconds,
269
+ );
270
+ queue.activeWarrant.expiresAt = new Date(
271
+ Date.parse(currentTime) + effectiveLeaseSeconds * 1000,
272
+ ).toISOString();
273
+ const candidate = queue.candidates.find(
274
+ (entry) => entry.candidateId === queue.activeWarrant.candidateId,
275
+ );
276
+ candidate.status =
277
+ queue.activeWarrant.phase === "qualified" ? "qualified" : "proving";
452
278
  candidate.updatedAt = currentTime;
453
279
  return { candidate, warrant: queue.activeWarrant };
454
280
  },
@@ -471,18 +297,44 @@ export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Dat
471
297
  receiptRoot: devDeliveryContentRoot(receipt),
472
298
  };
473
299
  }
474
-
475
- export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().toISOString() } = {}) {
300
+ export function recoverExpiredDevDeliveryWarrant(
301
+ queueInput,
302
+ { now = new Date().toISOString() } = {},
303
+ ) {
476
304
  const currentTime = timestamp(now, "now");
477
305
  const before = normalizeDevDeliveryQueue(queueInput);
478
- if (!before.activeWarrant || Date.parse(before.activeWarrant.expiresAt) > Date.parse(currentTime)) {
306
+ if (
307
+ !before.activeWarrant ||
308
+ Date.parse(before.activeWarrant.expiresAt) > Date.parse(currentTime)
309
+ ) {
479
310
  const receipt = {
480
311
  schema: DEV_DELIVERY_LEASE_RECEIPT_SCHEMA,
481
312
  action: "recovery-noop",
482
313
  reason: before.activeWarrant ? "lease-active" : "no-active-warrant",
483
314
  expectedOldStateRoot: before.stateRoot,
484
315
  nextStateRoot: before.stateRoot,
485
- nextAction: before.activeWarrant ? "Continue the active delivery attempt." : "Select the next queued candidate.",
316
+ nextAction: before.activeWarrant
317
+ ? "Continue the active delivery attempt."
318
+ : "Select the next queued candidate.",
319
+ };
320
+ return {
321
+ queue: before,
322
+ receipt,
323
+ receiptRoot: devDeliveryContentRoot(receipt),
324
+ };
325
+ }
326
+ if (before.activeWarrant.phase === "provisional") {
327
+ const receipt = {
328
+ schema: DEV_DELIVERY_LEASE_RECEIPT_SCHEMA,
329
+ action: "expired-lease-fenced-stop-required",
330
+ reason: "provisional-native-worker-stop-unproven",
331
+ candidateId: before.activeWarrant.candidateId,
332
+ rejectedFencingToken: before.activeWarrant.fencingToken,
333
+ expiredLeaseGeneration: before.activeWarrant.generation,
334
+ expectedOldStateRoot: before.stateRoot,
335
+ nextStateRoot: before.stateRoot,
336
+ nextAction:
337
+ "Prove the fenced native worker stopped, then close this exact generation with rooted terminal evidence.",
486
338
  };
487
339
  return {
488
340
  queue: before,
@@ -494,7 +346,9 @@ export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().
494
346
  before,
495
347
  (queue) => {
496
348
  const expired = clone(queue.activeWarrant);
497
- const candidate = queue.candidates.find((entry) => entry.candidateId === expired.candidateId);
349
+ const candidate = queue.candidates.find(
350
+ (entry) => entry.candidateId === expired.candidateId,
351
+ );
498
352
  candidate.status = "queued";
499
353
  candidate.recoveries += 1;
500
354
  candidate.attempts += 1;
@@ -513,7 +367,8 @@ export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().
513
367
  retainedEnqueuedAt: transaction.result.candidate.enqueuedAt,
514
368
  expectedOldStateRoot: transaction.expectedOldStateRoot,
515
369
  nextStateRoot: transaction.after.stateRoot,
516
- nextAction: "Re-select through the queue to mint a new lease generation and fencing token.",
370
+ nextAction:
371
+ "Re-select through the queue to mint a new lease generation and fencing token.",
517
372
  };
518
373
  return {
519
374
  queue: transaction.after,
@@ -521,19 +376,54 @@ export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().
521
376
  receiptRoot: devDeliveryContentRoot(receipt),
522
377
  };
523
378
  }
524
-
525
- export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidenceRoot, reason = "", now = new Date().toISOString() } = {}) {
379
+ export const qualifyDevDeliveryWarrant = createDevDeliveryWarrantQualifier({
380
+ transition,
381
+ assertWarrantMutation,
382
+ });
383
+ export function closeDevDeliveryWarrant(
384
+ queueInput,
385
+ warrant,
386
+ {
387
+ outcome,
388
+ evidenceRoot,
389
+ reason = "",
390
+ providerFailureAuthority = null,
391
+ now = new Date().toISOString(),
392
+ } = {},
393
+ ) {
526
394
  const currentTime = timestamp(now, "now");
527
395
  const normalizedOutcome = text(outcome);
528
396
  if (!TERMINAL_STATES.has(normalizedOutcome)) {
529
- throw new Error(`outcome must be one of ${[...TERMINAL_STATES].join(", ")}`);
397
+ throw new Error(
398
+ `outcome must be one of ${[...TERMINAL_STATES].join(", ")}`,
399
+ );
400
+ }
401
+ const failureAuthority = normalizeProviderFailureAuthorityBinding(
402
+ providerFailureAuthority || {},
403
+ );
404
+ if (failureAuthority && normalizedOutcome !== "terminal-failure") {
405
+ throw new Error(
406
+ "provider failure authority is valid only for terminal-failure",
407
+ );
530
408
  }
531
409
  const transaction = transition(
532
410
  queueInput,
533
411
  (queue, before) => {
534
- assertWarrantMutation(before, warrant, currentTime);
412
+ assertWarrantMutation(before, warrant, currentTime, {
413
+ allowExpired: true,
414
+ });
415
+ if (
416
+ (before.activeWarrant.phase || "qualified") !== "qualified" &&
417
+ normalizedOutcome === "merged"
418
+ ) {
419
+ throw new Error(
420
+ "provisional Warrant cannot settle as merged before native qualification",
421
+ );
422
+ }
535
423
  const active = clone(queue.activeWarrant);
536
- const candidate = queue.candidates.find((entry) => entry.candidateId === active.candidateId);
424
+ const candidate = queue.candidates.find(
425
+ (entry) => entry.candidateId === active.candidateId,
426
+ );
537
427
  candidate.status = normalizedOutcome;
538
428
  candidate.updatedAt = currentTime;
539
429
  candidate.terminal = {
@@ -543,6 +433,7 @@ export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidence
543
433
  closedAt: currentTime,
544
434
  fencingToken: active.fencingToken,
545
435
  leaseGeneration: active.generation,
436
+ ...(failureAuthority || {}),
546
437
  };
547
438
  queue.activeWarrant = null;
548
439
  return { candidate, active };
@@ -558,8 +449,13 @@ export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidence
558
449
  fencingToken: transaction.result.active.fencingToken,
559
450
  leaseGeneration: transaction.result.active.generation,
560
451
  evidenceRoot: transaction.result.candidate.terminal.evidenceRoot,
452
+ ...(failureAuthority || {}),
561
453
  expectedOldStateRoot: transaction.expectedOldStateRoot,
562
454
  nextStateRoot: transaction.after.stateRoot,
455
+ successorWake: createDevDeliverySuccessorWake(
456
+ transaction.after,
457
+ currentTime,
458
+ ),
563
459
  nextAction: "Select the next queued candidate, if any.",
564
460
  };
565
461
  return {
@@ -568,16 +464,64 @@ export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidence
568
464
  receiptRoot: devDeliveryContentRoot(receipt),
569
465
  };
570
466
  }
571
-
572
- const cancelQueuedDevDeliveryCandidateTransition = createCancelQueuedDevDeliveryCandidate(normalizeDevDeliveryQueue);
573
- export function cancelQueuedDevDeliveryCandidate(queueInput, input, options) { return cancelQueuedDevDeliveryCandidateTransition(queueInput, input, options); }
574
- export const settleDevDeliveryTerminalEvent = createDevDeliveryTerminalSettler({ normalizeQueue: normalizeDevDeliveryQueue, closeWarrant: closeDevDeliveryWarrant, cancelQueued: cancelQueuedDevDeliveryCandidate, terminalStates: TERMINAL_STATES });
575
-
576
- export function observeDevDeliveryQueue(queueInput, { now = new Date().toISOString() } = {}) {
467
+ function createDevDeliverySuccessorWake(queue, now) {
468
+ const next = rankDevDeliveryCandidates(queue, { now })[0]?.candidate;
469
+ if (!next) return null;
470
+ return {
471
+ schema: "kungfu.buildchain.dev-delivery-wake/v1",
472
+ targetBranch: queue.protectedBase,
473
+ ...Object.fromEntries(
474
+ [
475
+ "candidateId",
476
+ "pullRequestNumber",
477
+ "sourceHead",
478
+ "assignmentRoot",
479
+ "initiativeRoot",
480
+ "sourceIdentityRoot",
481
+ "sourcePatchRoot",
482
+ "sourceProofRoot",
483
+ "planRoot",
484
+ "closureRoot",
485
+ "dependencyRoot",
486
+ "toolchainRoot",
487
+ "deliveryClass",
488
+ "priority",
489
+ "nativeCommandContract",
490
+ "shardEvidenceRoots",
491
+ ]
492
+ .filter((field) => next[field] !== undefined)
493
+ .map((field) => [field, next[field]]),
494
+ ),
495
+ ...(next.environmentRoot ? { environmentRoot: next.environmentRoot } : {}),
496
+ ...(next.affectedPaths ? { affectedPaths: next.affectedPaths } : {}),
497
+ ...(Object.hasOwn(next, "sourceWorkflowRunId")
498
+ ? { sourceWorkflowRunId: next.sourceWorkflowRunId }
499
+ : {}),
500
+ ...(next.releaseBlockerPriority
501
+ ? { releaseBlockerPriority: next.releaseBlockerPriority }
502
+ : {}),
503
+ };
504
+ }
505
+ const cancelQueuedDevDeliveryCandidateTransition =
506
+ createCancelQueuedDevDeliveryCandidate(normalizeDevDeliveryQueue);
507
+ export function cancelQueuedDevDeliveryCandidate(queueInput, input, options) {
508
+ return cancelQueuedDevDeliveryCandidateTransition(queueInput, input, options);
509
+ }
510
+ export const settleDevDeliveryTerminalEvent = createDevDeliveryTerminalSettler({
511
+ normalizeQueue: normalizeDevDeliveryQueue,
512
+ closeWarrant: closeDevDeliveryWarrant,
513
+ cancelQueued: cancelQueuedDevDeliveryCandidate,
514
+ terminalStates: TERMINAL_STATES,
515
+ });
516
+ export function observeDevDeliveryQueue(
517
+ queueInput,
518
+ { now = new Date().toISOString() } = {},
519
+ ) {
577
520
  const queue = normalizeDevDeliveryQueue(queueInput);
578
521
  const currentTime = timestamp(now, "now");
579
522
  const states = {};
580
- for (const candidate of queue.candidates) states[candidate.status] = (states[candidate.status] || 0) + 1;
523
+ for (const candidate of queue.candidates)
524
+ states[candidate.status] = (states[candidate.status] || 0) + 1;
581
525
  const queued = rankDevDeliveryCandidates(queue, { now: currentTime });
582
526
  return {
583
527
  schema: "kungfu.buildchain.dev-delivery-queue-observation/v1",
@@ -586,7 +530,12 @@ export function observeDevDeliveryQueue(queueInput, { now = new Date().toISOStri
586
530
  stateRoot: queue.stateRoot,
587
531
  generation: queue.generation,
588
532
  activeWarrant: queue.activeWarrant,
589
- activeCandidate: queue.activeWarrant ? queue.candidates.find((candidate) => candidate.candidateId === queue.activeWarrant.candidateId) || null : null,
533
+ activeCandidate: queue.activeWarrant
534
+ ? queue.candidates.find(
535
+ (candidate) =>
536
+ candidate.candidateId === queue.activeWarrant.candidateId,
537
+ ) || null
538
+ : null,
590
539
  states,
591
540
  queued: queued.map((entry, index) => ({
592
541
  position: index + 1,
@@ -598,7 +547,10 @@ export function observeDevDeliveryQueue(queueInput, { now = new Date().toISOStri
598
547
  queueAgeSeconds: entry.priority.ageSeconds,
599
548
  attempts: entry.candidate.attempts,
600
549
  recoveries: entry.candidate.recoveries,
601
- nextAction: index === 0 && !queue.activeWarrant ? "eligible-for-selection" : "wait-for-active-warrant",
550
+ nextAction:
551
+ index === 0 && !queue.activeWarrant
552
+ ? "eligible-for-selection"
553
+ : "wait-for-active-warrant",
602
554
  })),
603
555
  observedAt: currentTime,
604
556
  };