@kungfu-tech/buildchain 3.0.9-alpha.0 → 3.0.9-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/buildchain.mjs +9 -1
- package/contracts/dev-delivery-authority-v2.schema.json +253 -0
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +16 -0
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +57 -0
- package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
- package/contracts/next-development-request-v1.schema.json +66 -0
- package/contracts/next-development-transition-v1.schema.json +292 -0
- package/contracts/release-cut-v1.schema.json +1 -0
- package/contracts/release-train-transition-v1.schema.json +1 -0
- package/dist/site/agent-index.json +1 -0
- package/dist/site/artifact-schemas.json +2 -0
- package/dist/site/buildchain-contract.json +91 -32
- package/dist/site/buildchain-site.json +353 -45
- package/dist/site/capability-registry.json +7 -6
- package/dist/site/cli-registry.json +41 -2
- package/dist/site/controller-registry.json +8 -4
- package/dist/site/kfd-claims.json +193 -9
- package/dist/site/kfd-upstream-aggregate.json +9 -9
- package/dist/site/manual-registry.json +26 -10
- package/dist/site/node-api-registry.json +8012 -4574
- package/dist/site/page-registry.json +331 -31
- package/dist/site/public-surface-audit.json +353 -8
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-passport-check-manifest.json +1 -0
- package/dist/site/release-provenance.json +12 -0
- package/dist/site/schemas/dev-delivery-authority-v2.schema.json +442 -0
- package/dist/site/schemas/release-passport-v1.schema.json +3 -0
- package/dist/site/site-manifest.json +22 -14
- package/dist/site/workflow-registry.json +15 -7
- package/docs/MAP.md +5 -2
- package/docs/adopter-delivery-gate.md +106 -0
- package/docs/aws-us-elastic-runner-burst-plane.md +30 -3
- package/docs/cli-reference.md +200 -13
- package/docs/dev-alpha-candidate-patrol.md +8 -0
- package/docs/dev-delivery-qualification-landing-adr.md +137 -0
- package/docs/dev-delivery-warrant.md +164 -27
- package/docs/kfd-support.md +7 -2
- package/docs/next-development-transition.md +119 -0
- package/docs/node-api-reference.md +464 -277
- package/docs/release-governance.md +10 -7
- package/docs/release-passport.md +15 -2
- package/docs/release-train.md +46 -4
- package/docs/reusable-build-surface.md +26 -9
- package/docs/runtime-train-validation.md +6 -0
- package/docs/versioning.md +6 -2
- package/package.json +21 -6
- package/packages/core/README.md +25 -0
- package/packages/core/adopter-delivery-gate.js +576 -0
- package/packages/core/adopter-delivery-json.js +66 -0
- package/packages/core/adopter-delivery-passport.js +259 -0
- package/packages/core/adopter-delivery-vectors.js +158 -0
- package/packages/core/adopter-delivery-vectors.json +77 -0
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/buildchain-agent-manuals.js +1 -0
- package/packages/core/buildchain-channel-identity.js +118 -0
- package/packages/core/buildchain-compatibility-proof.js +54 -0
- package/packages/core/buildchain-contract.js +7 -0
- package/packages/core/buildchain-delivery-bootstrap.js +240 -0
- package/packages/core/buildchain-delivery-infrastructure.js +164 -0
- package/packages/core/channel-candidate.js +8 -0
- package/packages/core/channel-promotion-baseline.js +52 -0
- package/packages/core/controller-evidence.js +2 -1
- package/packages/core/dev-alpha-candidate-selection.js +10 -2
- package/packages/core/dev-delivery-authority.js +996 -0
- package/packages/core/dev-delivery-native-proof.js +418 -0
- package/packages/core/dev-delivery-warrant-settlement.js +67 -20
- package/packages/core/dev-delivery-warrant.js +141 -48
- package/packages/core/kfd-adopter-category-driver.js +167 -0
- package/packages/core/kfd-adopter-manifest.js +49 -50
- package/packages/core/legacy-kfd-adopter-driver.js +167 -0
- package/packages/core/next-development-candidate-reservation.js +186 -0
- package/packages/core/next-development-controller.js +726 -0
- package/packages/core/next-development-projection.js +288 -0
- package/packages/core/next-development-transition.js +738 -0
- package/packages/core/paper-agent-entry.js +7 -4
- package/packages/core/paper.js +14 -7
- package/packages/core/release-blocker-priority.js +192 -0
- package/packages/core/release-passport-contract.js +10 -6
- package/packages/core/release-passport.js +29 -12
- package/packages/core/release-train.js +220 -0
- package/scripts/aws-macos-jit-controller-core.mjs +239 -4
- package/scripts/aws-macos-jit-controller.mjs +198 -2
- package/scripts/aws-macos-jit-instance-rehydrate.mjs +260 -0
- package/scripts/aws-macos-jit-source-rebind.mjs +235 -14
- package/scripts/aws-macos-jit.mjs +12 -0
- package/scripts/buildchain-channel-router.mjs +18 -2
- package/scripts/buildchain-cli-help.mjs +9 -2
- package/scripts/buildchain-contract-lock.mjs +11 -1
- package/scripts/check-internal-architecture.mjs +1 -0
- package/scripts/check-inventory.mjs +14 -3
- package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
- package/scripts/dev-delivery-authority.mjs +368 -0
- package/scripts/dev-delivery-native-run.mjs +235 -0
- package/scripts/dev-delivery-proof.mjs +64 -2
- package/scripts/dev-delivery-two-phase-resume.mjs +90 -0
- package/scripts/dev-delivery-two-phase.mjs +577 -0
- package/scripts/dev-delivery-warrant.mjs +47 -5
- package/scripts/dev-pr-delivery-warrant.mjs +19 -14
- package/scripts/generate-buildchain-kfd-witnesses.mjs +88 -94
- package/scripts/generate-channel-build-workflow.mjs +82 -31
- package/scripts/generate-next-development-guidance.mjs +49 -0
- package/scripts/generate-site-bundle.mjs +8 -3
- package/scripts/init-repo.mjs +135 -62
- package/scripts/next-development-self-dogfood-harness.mjs +409 -0
- package/scripts/next-development-self-dogfood.mjs +532 -0
- package/scripts/next-development-transition.mjs +47 -0
- package/scripts/promotion-channel-router.mjs +5 -3
- package/scripts/release-candidate-tail-reseal.mjs +426 -0
- package/scripts/release-train-self-dogfood.mjs +579 -0
- package/scripts/runtime-ref-core.mjs +4 -17
- package/scripts/seal-artifact-signing-requests.mjs +7 -4
- package/scripts/site-capability-metadata.mjs +23 -1
- package/scripts/stable-candidate-qualification.mjs +7 -7
- package/scripts/workflow-call-contract.mjs +1 -1
- package/templates/native-dev-delivery.yml +86 -0
|
@@ -2,8 +2,12 @@ import { devDeliveryClone as clone, devDeliveryContentRoot, devDeliveryExactRoot
|
|
|
2
2
|
import { chainedDevDeliveryAttemptInput, createDevDeliveryCandidateIdentity, validateDevDeliveryCandidateChain } from "./dev-delivery-candidate-identity.js";
|
|
3
3
|
import { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA, createCancelQueuedDevDeliveryCandidate } from "./dev-delivery-warrant-cancellation.js";
|
|
4
4
|
import { DEV_DELIVERY_SETTLEMENT_RECEIPT_SCHEMA, createDevDeliveryTerminalSettler } from "./dev-delivery-warrant-settlement.js";
|
|
5
|
+
import { createDevDeliveryWarrantQualifier } from "./dev-delivery-native-proof.js";
|
|
6
|
+
import { compareReleaseBlockerPriority, normalizeReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
|
|
5
7
|
export { devDeliveryContentRoot } from "./dev-delivery-common.js";
|
|
8
|
+
export { RELEASE_BLOCKER_PRIORITY_CLAIM_SCHEMA, createReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
|
|
6
9
|
export { SOURCE_QUALIFICATION_PROOF_SCHEMA, PROJECT_CUT_REPLAY_PROOF_SCHEMA, INTEGRATION_DELIVERY_PROOF_SCHEMA, classifyDevDeliveryDelta, createIntegrationDeliveryProof, createProjectCutReplayPlan, createProjectCutReplayProof, createSourceQualificationProof, verifyIntegrationDeliveryProof, verifyProjectCutReplayProof, verifySourceQualificationProof } from "./dev-delivery-proof.js";
|
|
10
|
+
export { DEV_DELIVERY_QUALIFICATION_RECEIPT_SCHEMA, NATIVE_QUALIFICATION_PROOF_SCHEMA, NATIVE_PROOF_REUSE_DECISION_SCHEMA, NATIVE_PROOF_BASE_DELTA_SCHEMA, createNativeProofBaseDelta, createNativeProofReuseDecision, createNativeQualificationProof, verifyNativeProofReuseDecision, verifyNativeQualificationProof } from "./dev-delivery-native-proof.js";
|
|
7
11
|
export { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA };
|
|
8
12
|
export const DEV_DELIVERY_QUEUE_CONTRACT = "kungfu-buildchain-dev-delivery-warrant-queue";
|
|
9
13
|
export const DEV_DELIVERY_WARRANT_SCHEMA = "kungfu.buildchain.dev-delivery-warrant/v1";
|
|
@@ -19,7 +23,14 @@ export const DEV_DELIVERY_PRIORITIES = Object.freeze({
|
|
|
19
23
|
|
|
20
24
|
export const DEV_DELIVERY_CLASSES = Object.freeze(["non-native-fast", "native-proof-required", "cross-platform", "release"]);
|
|
21
25
|
|
|
22
|
-
const TERMINAL_STATES = new Set(["merged", "terminal-failure", "dequeued", "cancelled"]);
|
|
26
|
+
const TERMINAL_STATES = new Set(["merged", "terminal-failure", "dequeued", "cancelled", "superseded"]);
|
|
27
|
+
const TERMINAL_CLASSES = Object.freeze({
|
|
28
|
+
merged: "authoritative-completion",
|
|
29
|
+
"terminal-failure": "authoritative-failure",
|
|
30
|
+
cancelled: "authoritative-cancellation",
|
|
31
|
+
superseded: "authoritative-supersession",
|
|
32
|
+
dequeued: "transient-dequeue",
|
|
33
|
+
});
|
|
23
34
|
function nonNegativeInteger(value, label, fallback = 0) {
|
|
24
35
|
const parsed = Number(value ?? fallback);
|
|
25
36
|
if (!Number.isInteger(parsed) || parsed < 0) throw new Error(`${label} must be a non-negative integer`);
|
|
@@ -57,10 +68,10 @@ function normalizeCandidate(input, expected) {
|
|
|
57
68
|
throw new Error(`candidateId mismatch for PR #${identity.pullRequestNumber}`);
|
|
58
69
|
}
|
|
59
70
|
const status = text(input.status || "queued");
|
|
60
|
-
if (!["queued", "selected", "proving", "waiting", "blocked", ...TERMINAL_STATES].includes(status)) {
|
|
71
|
+
if (!["queued", "selected", "provisional", "proving", "qualified", "waiting", "blocked", ...TERMINAL_STATES].includes(status)) {
|
|
61
72
|
throw new Error(`unsupported candidate status ${status || "<empty>"}`);
|
|
62
73
|
}
|
|
63
|
-
|
|
74
|
+
const candidate = {
|
|
64
75
|
...identity,
|
|
65
76
|
sourceHead: exactSha(input.sourceHead, "sourceHead"),
|
|
66
77
|
sourcePatchRoot: exactRoot(input.sourcePatchRoot, "sourcePatchRoot"),
|
|
@@ -69,7 +80,14 @@ function normalizeCandidate(input, expected) {
|
|
|
69
80
|
closureRoot: exactRoot(input.closureRoot, "closureRoot"),
|
|
70
81
|
dependencyRoot: exactRoot(input.dependencyRoot, "dependencyRoot"),
|
|
71
82
|
toolchainRoot: exactRoot(input.toolchainRoot, "toolchainRoot"),
|
|
72
|
-
...(
|
|
83
|
+
...(input.environmentRoot
|
|
84
|
+
? { environmentRoot: exactRoot(input.environmentRoot, "environmentRoot") }
|
|
85
|
+
: {}),
|
|
86
|
+
...(Object.hasOwn(input, "sourceWorkflowRunId")
|
|
87
|
+
? {
|
|
88
|
+
sourceWorkflowRunId: nonNegativeInteger(input.sourceWorkflowRunId, "candidate sourceWorkflowRunId", 0),
|
|
89
|
+
}
|
|
90
|
+
: {}),
|
|
73
91
|
priority: priority(input.priority),
|
|
74
92
|
enqueuedAt: timestamp(input.enqueuedAt, "candidate enqueuedAt"),
|
|
75
93
|
updatedAt: timestamp(input.updatedAt || input.enqueuedAt, "candidate updatedAt"),
|
|
@@ -78,6 +96,12 @@ function normalizeCandidate(input, expected) {
|
|
|
78
96
|
status,
|
|
79
97
|
terminal: input.terminal || null,
|
|
80
98
|
};
|
|
99
|
+
if (Object.hasOwn(input, "affectedPaths")) {
|
|
100
|
+
if (!Array.isArray(input.affectedPaths)) throw new Error("candidate affectedPaths must be an array");
|
|
101
|
+
candidate.affectedPaths = [...new Set(input.affectedPaths.map(text).filter(Boolean))].sort();
|
|
102
|
+
}
|
|
103
|
+
if (Object.hasOwn(input, "releaseBlockerPriority")) candidate.releaseBlockerPriority = normalizeReleaseBlockerPriorityClaim(input.releaseBlockerPriority, candidate, expected);
|
|
104
|
+
return candidate;
|
|
81
105
|
}
|
|
82
106
|
|
|
83
107
|
function queueBody(queue) {
|
|
@@ -136,11 +160,20 @@ export function normalizeDevDeliveryQueue(input, expected = {}) {
|
|
|
136
160
|
warrant.generation = positiveInteger(warrant.generation, "Warrant generation");
|
|
137
161
|
warrant.issuedAt = timestamp(warrant.issuedAt, "Warrant issuedAt");
|
|
138
162
|
warrant.expiresAt = timestamp(warrant.expiresAt, "Warrant expiresAt");
|
|
139
|
-
const
|
|
163
|
+
const warrantPhase = text(warrant.phase || "qualified");
|
|
164
|
+
if (!["provisional", "qualified"].includes(warrantPhase)) throw new Error("active Warrant phase is unsupported");
|
|
165
|
+
if (Object.hasOwn(warrant, "phase")) warrant.phase = warrantPhase;
|
|
166
|
+
if (warrantPhase === "qualified") {
|
|
167
|
+
if (warrant.nativeProofRoot) warrant.nativeProofRoot = exactRoot(warrant.nativeProofRoot, "Warrant nativeProofRoot");
|
|
168
|
+
if (warrant.nativeProofReuseRoot) warrant.nativeProofReuseRoot = exactRoot(warrant.nativeProofReuseRoot, "Warrant nativeProofReuseRoot");
|
|
169
|
+
if (warrant.qualifiedAt) warrant.qualifiedAt = timestamp(warrant.qualifiedAt, "Warrant qualifiedAt");
|
|
170
|
+
}
|
|
171
|
+
const activeCandidates = queue.candidates.filter((candidate) => ["selected", "provisional", "proving", "qualified", "waiting", "blocked"].includes(candidate.status));
|
|
140
172
|
if (activeCandidates.length !== 1 || activeCandidates[0].candidateId !== warrant.candidateId) {
|
|
141
173
|
throw new Error("exactly one active candidate must match the active Warrant");
|
|
142
174
|
}
|
|
143
|
-
|
|
175
|
+
if (warrant.releaseBlockerPriority?.claimRoot !== activeCandidates[0].releaseBlockerPriority?.claimRoot) throw new Error("active Warrant release-blocker priority drift");
|
|
176
|
+
} else if (queue.candidates.some((candidate) => ["selected", "provisional", "proving", "qualified", "waiting", "blocked"].includes(candidate.status))) {
|
|
144
177
|
throw new Error("active candidate exists without an active Warrant");
|
|
145
178
|
}
|
|
146
179
|
const rooted = withQueueRoot(queue);
|
|
@@ -178,8 +211,10 @@ function submissionReceipt({ before, after, candidate, action, now }) {
|
|
|
178
211
|
planRoot: candidate.planRoot,
|
|
179
212
|
closureRoot: candidate.closureRoot,
|
|
180
213
|
dependencyRoot: candidate.dependencyRoot,
|
|
181
|
-
toolchainRoot: candidate.toolchainRoot,
|
|
214
|
+
toolchainRoot: candidate.toolchainRoot, ...(candidate.environmentRoot ? { environmentRoot: candidate.environmentRoot } : {}),
|
|
215
|
+
...(Object.hasOwn(candidate, "affectedPaths") ? { affectedPaths: candidate.affectedPaths } : {}),
|
|
182
216
|
sourceWorkflowRunId: candidate.sourceWorkflowRunId,
|
|
217
|
+
...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
|
|
183
218
|
deliveryClass: candidate.deliveryClass,
|
|
184
219
|
priority: candidate.priority,
|
|
185
220
|
retainedEnqueuedAt: candidate.enqueuedAt,
|
|
@@ -192,6 +227,21 @@ function submissionReceipt({ before, after, candidate, action, now }) {
|
|
|
192
227
|
};
|
|
193
228
|
}
|
|
194
229
|
|
|
230
|
+
function reconcileSourceWorkflowRunId(existing, attempted, activeCandidateId, currentTime) {
|
|
231
|
+
const current = existing.sourceWorkflowRunId || 0;
|
|
232
|
+
const next = attempted.sourceWorkflowRunId || 0;
|
|
233
|
+
if (existing.sourceHead !== attempted.sourceHead) {
|
|
234
|
+
existing.sourceWorkflowRunId = next;
|
|
235
|
+
return "head-change";
|
|
236
|
+
}
|
|
237
|
+
if (current > 0 && next > 0 && current !== next) throw new Error("candidate sourceWorkflowRunId cannot change for the same sourceHead");
|
|
238
|
+
if (current !== 0 || next === 0) return "retained";
|
|
239
|
+
if (activeCandidateId === existing.candidateId) return "active";
|
|
240
|
+
existing.sourceWorkflowRunId = next;
|
|
241
|
+
existing.updatedAt = currentTime;
|
|
242
|
+
return "upgraded";
|
|
243
|
+
}
|
|
244
|
+
|
|
195
245
|
export function submitDevDeliveryCandidate(queueInput, input, { now = new Date().toISOString() } = {}) {
|
|
196
246
|
const transaction = transition(
|
|
197
247
|
queueInput,
|
|
@@ -207,7 +257,13 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
|
|
|
207
257
|
},
|
|
208
258
|
queue,
|
|
209
259
|
);
|
|
210
|
-
const chainedInput = chainedDevDeliveryAttemptInput({
|
|
260
|
+
const chainedInput = chainedDevDeliveryAttemptInput({
|
|
261
|
+
queue,
|
|
262
|
+
candidate,
|
|
263
|
+
input,
|
|
264
|
+
currentTime,
|
|
265
|
+
terminalStates: TERMINAL_STATES,
|
|
266
|
+
});
|
|
211
267
|
const attemptedCandidate = chainedInput ? normalizeCandidate(chainedInput, queue) : candidate;
|
|
212
268
|
const conflicting = queue.candidates.find((entry) => entry.pullRequestNumber === attemptedCandidate.pullRequestNumber && entry.candidateId !== attemptedCandidate.candidateId && !TERMINAL_STATES.has(entry.status));
|
|
213
269
|
if (conflicting) throw new Error(`PR #${candidate.pullRequestNumber} already has a different active semantic source`);
|
|
@@ -218,10 +274,12 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
|
|
|
218
274
|
if (TERMINAL_STATES.has(existing.status)) {
|
|
219
275
|
throw new Error(`candidate ${attemptedCandidate.candidateId} is terminal and cannot be resubmitted`);
|
|
220
276
|
}
|
|
221
|
-
const exactProofFields = ["sourcePatchRoot", "sourceProofRoot", "planRoot", "closureRoot", "dependencyRoot", "toolchainRoot"];
|
|
222
|
-
const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]);
|
|
277
|
+
const exactProofFields = ["sourcePatchRoot", "sourceProofRoot", "planRoot", "closureRoot", "dependencyRoot", "toolchainRoot", "environmentRoot"];
|
|
278
|
+
const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]) && JSON.stringify(existing.affectedPaths || []) === JSON.stringify(attemptedCandidate.affectedPaths || []) && existing.releaseBlockerPriority?.claimRoot === attemptedCandidate.releaseBlockerPriority?.claimRoot;
|
|
279
|
+
const bindingAction = reconcileSourceWorkflowRunId(existing, attemptedCandidate, before.activeWarrant?.candidateId, currentTime);
|
|
223
280
|
if (existing.sourceHead === attemptedCandidate.sourceHead && exactProofMatches) {
|
|
224
|
-
|
|
281
|
+
if (bindingAction === "active") return { candidate: existing, action: "active-warrant-retained-noop" };
|
|
282
|
+
action = bindingAction === "upgraded" ? "source-workflow-run-upgrade-retained-age" : "duplicate-noop";
|
|
225
283
|
selected = existing;
|
|
226
284
|
} else {
|
|
227
285
|
if (before.activeWarrant?.candidateId === existing.candidateId) {
|
|
@@ -235,6 +293,10 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
|
|
|
235
293
|
const headChanged = existing.sourceHead !== attemptedCandidate.sourceHead;
|
|
236
294
|
existing.sourceHead = attemptedCandidate.sourceHead;
|
|
237
295
|
for (const field of exactProofFields) existing[field] = attemptedCandidate[field];
|
|
296
|
+
if (Object.hasOwn(attemptedCandidate, "affectedPaths")) existing.affectedPaths = attemptedCandidate.affectedPaths;
|
|
297
|
+
else delete existing.affectedPaths;
|
|
298
|
+
if (Object.hasOwn(attemptedCandidate, "releaseBlockerPriority")) existing.releaseBlockerPriority = attemptedCandidate.releaseBlockerPriority;
|
|
299
|
+
else delete existing.releaseBlockerPriority;
|
|
238
300
|
existing.updatedAt = currentTime;
|
|
239
301
|
existing.attempts += 1;
|
|
240
302
|
existing.status = "queued";
|
|
@@ -270,6 +332,7 @@ function effectivePriority(candidate, policy, now) {
|
|
|
270
332
|
basePriority: DEV_DELIVERY_PRIORITIES[candidate.priority],
|
|
271
333
|
agingBoost,
|
|
272
334
|
score: Math.min(policy.maxPriority, DEV_DELIVERY_PRIORITIES[candidate.priority] + agingBoost),
|
|
335
|
+
releaseBlocker: Boolean(candidate.releaseBlockerPriority),
|
|
273
336
|
};
|
|
274
337
|
}
|
|
275
338
|
|
|
@@ -282,7 +345,7 @@ export function rankDevDeliveryCandidates(queueInput, { now = new Date().toISOSt
|
|
|
282
345
|
candidate,
|
|
283
346
|
priority: effectivePriority(candidate, queue.policy, currentTime),
|
|
284
347
|
}))
|
|
285
|
-
.sort((left, right) => right.priority.score - left.priority.score || left.candidate.enqueuedAt.localeCompare(right.candidate.enqueuedAt) || left.candidate.candidateId.localeCompare(right.candidate.candidateId));
|
|
348
|
+
.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));
|
|
286
349
|
}
|
|
287
350
|
|
|
288
351
|
function warrantToken(input) {
|
|
@@ -299,26 +362,26 @@ function warrantToken(input) {
|
|
|
299
362
|
|
|
300
363
|
export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOString(), leaseSeconds } = {}) {
|
|
301
364
|
const currentTime = timestamp(now, "now");
|
|
302
|
-
|
|
365
|
+
const queue = normalizeDevDeliveryQueue(queueInput);
|
|
303
366
|
let recoveryReceipt = null;
|
|
304
367
|
if (queue.activeWarrant && Date.parse(queue.activeWarrant.expiresAt) <= Date.parse(currentTime)) {
|
|
305
368
|
const recovered = recoverExpiredDevDeliveryWarrant(queue, {
|
|
306
369
|
now: currentTime,
|
|
307
370
|
});
|
|
308
|
-
queue = recovered.queue;
|
|
309
371
|
recoveryReceipt = recovered.receipt;
|
|
310
372
|
}
|
|
311
373
|
if (queue.activeWarrant) {
|
|
374
|
+
const expired = Date.parse(queue.activeWarrant.expiresAt) <= Date.parse(currentTime);
|
|
312
375
|
const receipt = {
|
|
313
376
|
schema: DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA,
|
|
314
|
-
selected:
|
|
315
|
-
reason: "non-preemptive-active-warrant",
|
|
377
|
+
selected: !expired,
|
|
378
|
+
reason: expired ? "expired-active-warrant-awaits-fenced-settlement" : "non-preemptive-active-warrant",
|
|
316
379
|
candidateId: queue.activeWarrant.candidateId,
|
|
317
380
|
fencingToken: queue.activeWarrant.fencingToken,
|
|
318
381
|
leaseGeneration: queue.activeWarrant.generation,
|
|
319
382
|
expectedOldStateRoot: recoveryReceipt?.expectedOldStateRoot || queue.stateRoot,
|
|
320
383
|
nextStateRoot: queue.stateRoot,
|
|
321
|
-
nextAction: "Continue the active delivery attempt; later candidates remain visibly queued.",
|
|
384
|
+
nextAction: expired ? "Prove the stale native worker stopped, then close this exact fenced generation before selecting a successor." : "Continue the active delivery attempt; later candidates remain visibly queued.",
|
|
322
385
|
};
|
|
323
386
|
return {
|
|
324
387
|
queue,
|
|
@@ -369,15 +432,18 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
|
|
|
369
432
|
planRoot: candidate.planRoot,
|
|
370
433
|
closureRoot: candidate.closureRoot,
|
|
371
434
|
dependencyRoot: candidate.dependencyRoot,
|
|
372
|
-
toolchainRoot: candidate.toolchainRoot,
|
|
435
|
+
toolchainRoot: candidate.toolchainRoot, ...(candidate.environmentRoot ? { environmentRoot: candidate.environmentRoot } : {}),
|
|
436
|
+
...(Object.hasOwn(candidate, "affectedPaths") ? { affectedPaths: candidate.affectedPaths } : {}),
|
|
373
437
|
sourceWorkflowRunId: candidate.sourceWorkflowRunId,
|
|
438
|
+
...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
|
|
374
439
|
deliveryClass: candidate.deliveryClass,
|
|
375
440
|
generation: next.fencingCounter,
|
|
441
|
+
phase: "provisional",
|
|
376
442
|
expectedOldStateRoot: before.stateRoot,
|
|
377
443
|
issuedAt,
|
|
378
444
|
expiresAt: new Date(Date.parse(issuedAt) + effectiveLeaseSeconds * 1000).toISOString(),
|
|
379
445
|
fencingToken: "",
|
|
380
|
-
nextAction: "
|
|
446
|
+
nextAction: "Run or reuse the exact semantic native proof, then atomically qualify this fenced Warrant.",
|
|
381
447
|
};
|
|
382
448
|
warrant.fencingToken = warrantToken(warrant);
|
|
383
449
|
next.activeWarrant = warrant;
|
|
@@ -390,7 +456,7 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
|
|
|
390
456
|
const receipt = {
|
|
391
457
|
schema: DEV_DELIVERY_SELECTION_RECEIPT_SCHEMA,
|
|
392
458
|
selected: true,
|
|
393
|
-
reason: selected.priority.agingBoost > 0 ? "fifo-aging-bounded-priority" : "fifo-bounded-priority",
|
|
459
|
+
reason: selected.priority.releaseBlocker ? "release-blocker-bounded-priority" : selected.priority.agingBoost > 0 ? "fifo-aging-bounded-priority" : "fifo-bounded-priority",
|
|
394
460
|
repository: transaction.after.repository,
|
|
395
461
|
protectedBase: transaction.after.protectedBase,
|
|
396
462
|
candidateId: transaction.result.candidate.candidateId,
|
|
@@ -404,8 +470,13 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
|
|
|
404
470
|
planRoot: transaction.result.candidate.planRoot,
|
|
405
471
|
closureRoot: transaction.result.candidate.closureRoot,
|
|
406
472
|
dependencyRoot: transaction.result.candidate.dependencyRoot,
|
|
407
|
-
toolchainRoot: transaction.result.candidate.toolchainRoot,
|
|
473
|
+
toolchainRoot: transaction.result.candidate.toolchainRoot, ...(transaction.result.candidate.environmentRoot ? { environmentRoot: transaction.result.candidate.environmentRoot } : {}),
|
|
408
474
|
sourceWorkflowRunId: transaction.result.candidate.sourceWorkflowRunId,
|
|
475
|
+
...(Object.hasOwn(transaction.result.candidate, "releaseBlockerPriority")
|
|
476
|
+
? {
|
|
477
|
+
releaseBlockerPriority: transaction.result.candidate.releaseBlockerPriority,
|
|
478
|
+
}
|
|
479
|
+
: {}),
|
|
409
480
|
deliveryClass: transaction.result.candidate.deliveryClass,
|
|
410
481
|
queueAgeSeconds: selected.priority.ageSeconds,
|
|
411
482
|
basePriority: selected.priority.basePriority,
|
|
@@ -443,7 +514,7 @@ export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Dat
|
|
|
443
514
|
const effectiveLeaseSeconds = positiveInteger(leaseSeconds, "leaseSeconds", queue.policy.leaseSeconds);
|
|
444
515
|
queue.activeWarrant.expiresAt = new Date(Date.parse(currentTime) + effectiveLeaseSeconds * 1000).toISOString();
|
|
445
516
|
const candidate = queue.candidates.find((entry) => entry.candidateId === queue.activeWarrant.candidateId);
|
|
446
|
-
candidate.status = "proving";
|
|
517
|
+
candidate.status = queue.activeWarrant.phase === "qualified" ? "qualified" : "proving";
|
|
447
518
|
candidate.updatedAt = currentTime;
|
|
448
519
|
return { candidate, warrant: queue.activeWarrant };
|
|
449
520
|
},
|
|
@@ -467,6 +538,13 @@ export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Dat
|
|
|
467
538
|
};
|
|
468
539
|
}
|
|
469
540
|
|
|
541
|
+
const qualifyDevDeliveryWarrantTransition = createDevDeliveryWarrantQualifier({
|
|
542
|
+
transition,
|
|
543
|
+
assertWarrantMutation,
|
|
544
|
+
});
|
|
545
|
+
export function qualifyDevDeliveryWarrant(queueInput, warrant, options) {
|
|
546
|
+
return qualifyDevDeliveryWarrantTransition(queueInput, warrant, options);
|
|
547
|
+
}
|
|
470
548
|
export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().toISOString() } = {}) {
|
|
471
549
|
const currentTime = timestamp(now, "now");
|
|
472
550
|
const before = normalizeDevDeliveryQueue(queueInput);
|
|
@@ -485,33 +563,21 @@ export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().
|
|
|
485
563
|
receiptRoot: devDeliveryContentRoot(receipt),
|
|
486
564
|
};
|
|
487
565
|
}
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
(queue) => {
|
|
491
|
-
const expired = clone(queue.activeWarrant);
|
|
492
|
-
const candidate = queue.candidates.find((entry) => entry.candidateId === expired.candidateId);
|
|
493
|
-
candidate.status = "queued";
|
|
494
|
-
candidate.recoveries += 1;
|
|
495
|
-
candidate.attempts += 1;
|
|
496
|
-
candidate.updatedAt = currentTime;
|
|
497
|
-
queue.activeWarrant = null;
|
|
498
|
-
return { candidate, expired };
|
|
499
|
-
},
|
|
500
|
-
currentTime,
|
|
501
|
-
);
|
|
566
|
+
const expired = before.activeWarrant;
|
|
567
|
+
const candidate = before.candidates.find((entry) => entry.candidateId === expired.candidateId);
|
|
502
568
|
const receipt = {
|
|
503
569
|
schema: DEV_DELIVERY_LEASE_RECEIPT_SCHEMA,
|
|
504
|
-
action: "
|
|
505
|
-
candidateId:
|
|
506
|
-
rejectedFencingToken:
|
|
507
|
-
expiredLeaseGeneration:
|
|
508
|
-
retainedEnqueuedAt:
|
|
509
|
-
expectedOldStateRoot:
|
|
510
|
-
nextStateRoot:
|
|
511
|
-
nextAction: "
|
|
570
|
+
action: "expired-lease-fenced-stop-required",
|
|
571
|
+
candidateId: candidate.candidateId,
|
|
572
|
+
rejectedFencingToken: expired.fencingToken,
|
|
573
|
+
expiredLeaseGeneration: expired.generation,
|
|
574
|
+
retainedEnqueuedAt: candidate.enqueuedAt,
|
|
575
|
+
expectedOldStateRoot: before.stateRoot,
|
|
576
|
+
nextStateRoot: before.stateRoot,
|
|
577
|
+
nextAction: "Prove the stale native worker stopped, then close this exact fenced generation before selecting a successor.",
|
|
512
578
|
};
|
|
513
579
|
return {
|
|
514
|
-
queue:
|
|
580
|
+
queue: before,
|
|
515
581
|
receipt,
|
|
516
582
|
receiptRoot: devDeliveryContentRoot(receipt),
|
|
517
583
|
};
|
|
@@ -523,16 +589,22 @@ export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidence
|
|
|
523
589
|
if (!TERMINAL_STATES.has(normalizedOutcome)) {
|
|
524
590
|
throw new Error(`outcome must be one of ${[...TERMINAL_STATES].join(", ")}`);
|
|
525
591
|
}
|
|
592
|
+
if (normalizedOutcome === "dequeued") {
|
|
593
|
+
throw new Error("transient dequeue cannot close an active Delivery Warrant");
|
|
594
|
+
}
|
|
526
595
|
const transaction = transition(
|
|
527
596
|
queueInput,
|
|
528
597
|
(queue, before) => {
|
|
529
|
-
assertWarrantMutation(before, warrant, currentTime, {
|
|
598
|
+
assertWarrantMutation(before, warrant, currentTime, {
|
|
599
|
+
allowExpired: true,
|
|
600
|
+
});
|
|
530
601
|
const active = clone(queue.activeWarrant);
|
|
531
602
|
const candidate = queue.candidates.find((entry) => entry.candidateId === active.candidateId);
|
|
532
603
|
candidate.status = normalizedOutcome;
|
|
533
604
|
candidate.updatedAt = currentTime;
|
|
534
605
|
candidate.terminal = {
|
|
535
606
|
outcome: normalizedOutcome,
|
|
607
|
+
terminalClass: TERMINAL_CLASSES[normalizedOutcome],
|
|
536
608
|
reason: text(reason),
|
|
537
609
|
evidenceRoot: exactRoot(evidenceRoot, "evidenceRoot"),
|
|
538
610
|
closedAt: currentTime,
|
|
@@ -548,6 +620,7 @@ export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidence
|
|
|
548
620
|
schema: DEV_DELIVERY_LEASE_RECEIPT_SCHEMA,
|
|
549
621
|
action: "terminal-closeout",
|
|
550
622
|
outcome: normalizedOutcome,
|
|
623
|
+
terminalClass: TERMINAL_CLASSES[normalizedOutcome],
|
|
551
624
|
reason: text(reason),
|
|
552
625
|
candidateId: transaction.result.candidate.candidateId,
|
|
553
626
|
fencingToken: transaction.result.active.fencingToken,
|
|
@@ -565,8 +638,15 @@ export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidence
|
|
|
565
638
|
}
|
|
566
639
|
|
|
567
640
|
const cancelQueuedDevDeliveryCandidateTransition = createCancelQueuedDevDeliveryCandidate(normalizeDevDeliveryQueue);
|
|
568
|
-
export function cancelQueuedDevDeliveryCandidate(queueInput, input, options) {
|
|
569
|
-
|
|
641
|
+
export function cancelQueuedDevDeliveryCandidate(queueInput, input, options) {
|
|
642
|
+
return cancelQueuedDevDeliveryCandidateTransition(queueInput, input, options);
|
|
643
|
+
}
|
|
644
|
+
export const settleDevDeliveryTerminalEvent = createDevDeliveryTerminalSettler({
|
|
645
|
+
normalizeQueue: normalizeDevDeliveryQueue,
|
|
646
|
+
closeWarrant: closeDevDeliveryWarrant,
|
|
647
|
+
cancelQueued: cancelQueuedDevDeliveryCandidate,
|
|
648
|
+
terminalStates: TERMINAL_STATES,
|
|
649
|
+
});
|
|
570
650
|
|
|
571
651
|
export function observeDevDeliveryQueue(queueInput, { now = new Date().toISOString() } = {}) {
|
|
572
652
|
const queue = normalizeDevDeliveryQueue(queueInput);
|
|
@@ -593,6 +673,19 @@ export function observeDevDeliveryQueue(queueInput, { now = new Date().toISOStri
|
|
|
593
673
|
queueAgeSeconds: entry.priority.ageSeconds,
|
|
594
674
|
attempts: entry.candidate.attempts,
|
|
595
675
|
recoveries: entry.candidate.recoveries,
|
|
676
|
+
assignmentRoot: entry.candidate.assignmentRoot,
|
|
677
|
+
initiativeRoot: entry.candidate.initiativeRoot,
|
|
678
|
+
sourceIdentityRoot: entry.candidate.sourceIdentityRoot,
|
|
679
|
+
sourcePatchRoot: entry.candidate.sourcePatchRoot,
|
|
680
|
+
sourceProofRoot: entry.candidate.sourceProofRoot,
|
|
681
|
+
planRoot: entry.candidate.planRoot,
|
|
682
|
+
closureRoot: entry.candidate.closureRoot,
|
|
683
|
+
dependencyRoot: entry.candidate.dependencyRoot,
|
|
684
|
+
toolchainRoot: entry.candidate.toolchainRoot, ...(entry.candidate.environmentRoot ? { environmentRoot: entry.candidate.environmentRoot } : {}),
|
|
685
|
+
sourceWorkflowRunId: entry.candidate.sourceWorkflowRunId || 0,
|
|
686
|
+
affectedPaths: entry.candidate.affectedPaths || [],
|
|
687
|
+
deliveryClass: entry.candidate.deliveryClass,
|
|
688
|
+
priority: entry.candidate.priority,
|
|
596
689
|
nextAction: index === 0 && !queue.activeWarrant ? "eligible-for-selection" : "wait-for-active-warrant",
|
|
597
690
|
})),
|
|
598
691
|
observedAt: currentTime,
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import kfdCategoryCatalog from "@kungfu-tech/kfd/adopter-conformance/category-profiles.json" with { type: "json" };
|
|
2
|
+
import kfdPackageJson from "@kungfu-tech/kfd/package.json" with { type: "json" };
|
|
3
|
+
import { resolveAdopterCategoryProfiles } from "@kungfu-tech/kfd/adopter-conformance/category-profile-resolver";
|
|
4
|
+
import { verifyAdopterCategoryInstanceManifest } from "@kungfu-tech/kfd/adopter-conformance/category-instance-verifier";
|
|
5
|
+
import { verifyAdopterManifestFromPackage } from "@kungfu-tech/kfd/adopter-conformance/toolchain";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ADOPTER_PROTOCOL_DRIVER_INTERFACE,
|
|
9
|
+
adopterDeliveryGateDigest,
|
|
10
|
+
defineAdopterProtocolDriver,
|
|
11
|
+
} from "./adopter-delivery-gate.js";
|
|
12
|
+
|
|
13
|
+
export const KFD_ADOPTER_CATEGORY_PROTOCOL_ID =
|
|
14
|
+
"kfd.adopter-category/instance-manifest";
|
|
15
|
+
export const KFD_ADOPTER_CATEGORY_PROTOCOL_VERSION = "1.0.0";
|
|
16
|
+
export const KFD_ADOPTER_CATEGORY_DRIVER_REPORT_CONTRACT =
|
|
17
|
+
"kungfu-buildchain-kfd-adopter-category-driver-report";
|
|
18
|
+
|
|
19
|
+
function freezeJson(value) {
|
|
20
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
21
|
+
Object.freeze(value);
|
|
22
|
+
for (const child of Object.values(value)) freezeJson(child);
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const publishedCatalog = freezeJson(structuredClone(kfdCategoryCatalog));
|
|
28
|
+
|
|
29
|
+
function catalogCopy() {
|
|
30
|
+
return structuredClone(publishedCatalog);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function sameJson(left, right) {
|
|
34
|
+
try {
|
|
35
|
+
return adopterDeliveryGateDigest(left) === adopterDeliveryGateDigest(right);
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function issue(code, path, message) {
|
|
42
|
+
return { code, path, message };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function resolvePublishedKfdAdopterCategoryProfiles(selection) {
|
|
46
|
+
return resolveAdopterCategoryProfiles(
|
|
47
|
+
structuredClone(selection),
|
|
48
|
+
catalogCopy(),
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function verifyPublishedKfdAdopterCategoryInstance(
|
|
53
|
+
instanceManifest,
|
|
54
|
+
{ adopterManifest, verifiedAt, maxAgeSeconds } = {},
|
|
55
|
+
) {
|
|
56
|
+
const adopterReport = verifyAdopterManifestFromPackage(adopterManifest, {
|
|
57
|
+
packageArtifactRoot: instanceManifest?.kfdCut?.packageRoot,
|
|
58
|
+
verifiedAt,
|
|
59
|
+
maxAgeSeconds,
|
|
60
|
+
});
|
|
61
|
+
return verifyAdopterCategoryInstanceManifest(instanceManifest, {
|
|
62
|
+
catalog: catalogCopy(),
|
|
63
|
+
adopterManifest,
|
|
64
|
+
adopterReport,
|
|
65
|
+
verifiedAt,
|
|
66
|
+
maxAgeSeconds,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function deliveryBindingIssues(request, adopterManifest) {
|
|
71
|
+
const instance = request.declaration;
|
|
72
|
+
const issues = [];
|
|
73
|
+
if (
|
|
74
|
+
request.project.instanceId !== instance?.instanceId ||
|
|
75
|
+
request.project.adopterId !== instance?.project?.adopterId
|
|
76
|
+
) {
|
|
77
|
+
issues.push(
|
|
78
|
+
issue(
|
|
79
|
+
"delivery-kfd-instance-binding-mismatch",
|
|
80
|
+
"/project",
|
|
81
|
+
"Delivery project identity must match the KFD category instance.",
|
|
82
|
+
),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (!sameJson(request.artifact, instance?.project?.artifact)) {
|
|
86
|
+
issues.push(
|
|
87
|
+
issue(
|
|
88
|
+
"delivery-kfd-instance-binding-mismatch",
|
|
89
|
+
"/artifact",
|
|
90
|
+
"Delivery artifact must match the KFD category instance artifact.",
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (
|
|
95
|
+
adopterManifest?.kfdCut?.package?.name !== kfdPackageJson.name ||
|
|
96
|
+
adopterManifest?.kfdCut?.package?.version !== kfdPackageJson.version ||
|
|
97
|
+
instance?.kfdCut?.packageVersion !== kfdPackageJson.version
|
|
98
|
+
) {
|
|
99
|
+
issues.push(
|
|
100
|
+
issue(
|
|
101
|
+
"delivery-kfd-package-cut-mismatch",
|
|
102
|
+
"/declaration/kfdCut",
|
|
103
|
+
"KFD declarations must bind the exact installed published package version.",
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return issues;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function driverReport(categoryReport, adapterIssues) {
|
|
111
|
+
const valid = categoryReport?.valid === true && adapterIssues.length === 0;
|
|
112
|
+
const report = {
|
|
113
|
+
schemaVersion: 1,
|
|
114
|
+
contract: KFD_ADOPTER_CATEGORY_DRIVER_REPORT_CONTRACT,
|
|
115
|
+
valid,
|
|
116
|
+
conforming: valid,
|
|
117
|
+
qualifying: false,
|
|
118
|
+
selfCertified: false,
|
|
119
|
+
independentlyCertified: false,
|
|
120
|
+
kfdPackage: {
|
|
121
|
+
name: kfdPackageJson.name,
|
|
122
|
+
version: kfdPackageJson.version,
|
|
123
|
+
},
|
|
124
|
+
categoryReport,
|
|
125
|
+
adapterIssues,
|
|
126
|
+
nonClaims: [
|
|
127
|
+
"Category conformance does not grant runtime permission or release authorization.",
|
|
128
|
+
"Buildchain carries the published KFD decision and does not certify or reinterpret it.",
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
valid,
|
|
133
|
+
report,
|
|
134
|
+
reportRoot: adopterDeliveryGateDigest(report),
|
|
135
|
+
issues: [...(categoryReport?.issues ?? []), ...adapterIssues],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function createKfdAdopterCategoryProtocolDriver() {
|
|
140
|
+
return defineAdopterProtocolDriver({
|
|
141
|
+
interface: ADOPTER_PROTOCOL_DRIVER_INTERFACE,
|
|
142
|
+
id: KFD_ADOPTER_CATEGORY_PROTOCOL_ID,
|
|
143
|
+
version: KFD_ADOPTER_CATEGORY_PROTOCOL_VERSION,
|
|
144
|
+
verify({ request, context }) {
|
|
145
|
+
const adapterIssues = deliveryBindingIssues(
|
|
146
|
+
request,
|
|
147
|
+
context?.adopterManifest,
|
|
148
|
+
);
|
|
149
|
+
let categoryReport = null;
|
|
150
|
+
try {
|
|
151
|
+
categoryReport = verifyPublishedKfdAdopterCategoryInstance(
|
|
152
|
+
request.declaration,
|
|
153
|
+
context,
|
|
154
|
+
);
|
|
155
|
+
} catch {
|
|
156
|
+
adapterIssues.push(
|
|
157
|
+
issue(
|
|
158
|
+
"delivery-kfd-verification-context-invalid",
|
|
159
|
+
"/protocol",
|
|
160
|
+
"Published KFD verification could not reproduce from the supplied exact context.",
|
|
161
|
+
),
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return driverReport(categoryReport, adapterIssues);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|