@kungfu-tech/buildchain 3.0.9-alpha.4 → 3.0.9-alpha.6

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 (42) hide show
  1. package/bin/buildchain.mjs +5 -1
  2. package/dist/site/buildchain-contract.json +9 -9
  3. package/dist/site/buildchain-site.json +56 -26
  4. package/dist/site/cli-registry.json +18 -2
  5. package/dist/site/kfd-claims.json +8 -5
  6. package/dist/site/kfd-upstream-aggregate.json +1 -1
  7. package/dist/site/manual-registry.json +6 -6
  8. package/dist/site/node-api-registry.json +290 -49
  9. package/dist/site/page-registry.json +46 -16
  10. package/dist/site/public-surface-audit.json +122 -6
  11. package/dist/site/publication-registry.json +4 -4
  12. package/dist/site/site-manifest.json +10 -10
  13. package/dist/site/workflow-registry.json +12 -6
  14. package/docs/cli-reference.md +79 -13
  15. package/docs/dev-delivery-warrant.md +53 -19
  16. package/docs/kfd-support.md +7 -2
  17. package/docs/node-api-reference.md +59 -51
  18. package/docs/release-governance.md +5 -4
  19. package/docs/release-passport.md +8 -2
  20. package/docs/versioning.md +1 -0
  21. package/package.json +3 -2
  22. package/packages/core/artifact-verification-envelope.js +5 -5
  23. package/packages/core/dev-delivery-native-proof.js +333 -0
  24. package/packages/core/dev-delivery-warrant-settlement.js +5 -1
  25. package/packages/core/dev-delivery-warrant.js +40 -6
  26. package/packages/core/kfd-adopter-manifest.js +46 -47
  27. package/packages/core/release-passport-contract.js +5 -5
  28. package/packages/core/release-passport.js +5 -4
  29. package/scripts/aws-macos-jit-controller-core.mjs +82 -2
  30. package/scripts/aws-macos-jit-controller.mjs +81 -1
  31. package/scripts/aws-macos-jit-source-rebind.mjs +147 -24
  32. package/scripts/buildchain-cli-help.mjs +6 -2
  33. package/scripts/check-internal-architecture.mjs +1 -0
  34. package/scripts/dev-delivery-native-run.mjs +187 -0
  35. package/scripts/dev-delivery-proof.mjs +54 -2
  36. package/scripts/dev-delivery-two-phase.mjs +598 -0
  37. package/scripts/dev-delivery-warrant.mjs +38 -3
  38. package/scripts/dev-pr-delivery-warrant.mjs +6 -1
  39. package/scripts/generate-channel-build-workflow.mjs +4 -0
  40. package/scripts/init-repo.mjs +16 -0
  41. package/scripts/release-candidate-tail-reseal.mjs +426 -0
  42. package/templates/native-dev-delivery.yml +82 -0
@@ -410,8 +410,14 @@ Pass the standard full-cut declaration with `--kfd-adopter-manifest-json`
410
410
  together with three `--kfd-product-gate-json` arguments for KFD-4, KFD-5, and
411
411
  KFD-7. The collector invokes the verifier from the exact installed
412
412
  `@kungfu-tech/kfd` package, binds the package artifact, registry and verifier
413
- roots, the exact Buildchain source, the manifest/report/bundle witness roots,
414
- and the existing product-gate roots. It emits `kfd-adopter-manifest.json`,
413
+ roots, the collector's exact product repository and source, the
414
+ manifest/report/bundle witness roots, and the existing product-gate roots. A
415
+ non-Buildchain adopter is accepted only when its manifest identity, artifact
416
+ coordinate, and all three product-gate repositories match the collector's
417
+ `--repository` value. The lower-level Node API exposes the same boundary as
418
+ `expectedAdopterId`, `expectedSourceRepository`, and `expectedSourceSha`, while
419
+ omitted identity/repository values retain the Buildchain self-release default.
420
+ It emits `kfd-adopter-manifest.json`,
415
421
  `kfd-adopter-manifest-gate.json`, and a legacy `kfd-support.json` projection.
416
422
  The release passport and `artifact-evidence.json` carry the same rooted
417
423
  `kfdAdopter` binding.
@@ -79,6 +79,7 @@ repository changes are patch".
79
79
 
80
80
  | Date | Action | Line | Faces | Class | Rationale | PR |
81
81
  | ---------- | ------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
82
+ | 2026-08-11 | extend-minor | `v3.0` | provisional-delivery-warrant, qualified-delivery-warrant, native-qualification-proof, native-proof-reuse-decision, generated-native-delivery-workflow | additive | Reserve protected-dev order after exact source acceptance and approval, then require an atomic native-proof-bound qualification before merge-queue admission. Reuse is limited to stable semantic source, closure, dependencies, and toolchain with a fully attributed disjoint base delta; overlap and uncertainty fail closed to revalidation. | |
82
83
  | 2026-08-11 | extend-minor | `v3.0` | release-blocker-repair-contract, release-blocker-priority-claim, release-train-node-export, dev-delivery-warrant-node-export, next-development-transition, next-development-projection | additive | Add rooted successor candidate generations on a frozen Release Cut, exact semantic patch identity across cut and Dev landings, publication blocking through conflict or mismatch, a narrow non-preemptive Warrant blocker lane, and a separate rooted transition that preserves completed Alpha success while the following development version is materialized. | |
83
84
  | 2026-08-10 | extend-minor | `v3.0` | release-cut-contract, release-train-state-machine, release-train-node-export | additive | Add a provider-neutral rooted Release Cut and idempotent Release Train state contract that freezes candidate, tree, Alpha base, runtime, generation, and authority while treating later Dev movement as observation rather than implicit supersession. | |
84
85
  | 2026-08-05 | extend-minor | `v3.0` | auditable-demo-scenario, auditable-demo-capture, auditable-demo-adapter | additive | Add an opt-in deterministic readable-playback declaration that preserves captured terminal payloads and order while normalizing only presentation timing; omitted playback continues to use observed PTY timestamps, and existing composition modes remain unchanged. | |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungfu-tech/buildchain",
3
- "version": "3.0.9-alpha.4",
3
+ "version": "3.0.9-alpha.6",
4
4
  "private": false,
5
5
  "description": "Buildchain Release Passport, release governance, CLI toolkit, and site facts.",
6
6
  "repository": "https://github.com/kungfu-systems/buildchain",
@@ -111,7 +111,8 @@
111
111
  "SECURITY.md",
112
112
  "docs/*.md",
113
113
  "actions/*/README.md",
114
- "fixtures/*/README.md"
114
+ "fixtures/*/README.md",
115
+ "templates/"
115
116
  ],
116
117
  "engines": {
117
118
  "node": ">=22.14.0"
@@ -417,7 +417,7 @@ function kfdBindingBody({ manifest, manifestGate, legacyProjection, paths }) {
417
417
  gatePath: paths.gate,
418
418
  gateRoot: manifestGate.gateRoot,
419
419
  },
420
- source: jsonClone(manifestGate.source),
420
+ adopter: jsonClone(manifestGate.adopter), source: jsonClone(manifestGate.source),
421
421
  standardPackage: jsonClone(manifestGate.standardPackage),
422
422
  witness: {
423
423
  decisionRoot: manifestGate.decisionWitness.root,
@@ -445,10 +445,10 @@ export function createKfdAdopterReleaseBinding({
445
445
  manifestPath = "kfd-adopter-manifest.json",
446
446
  gatePath = "kfd-adopter-manifest-gate.json",
447
447
  legacyProjectionPath = "kfd-support.json",
448
- expectedSourceSha = "",
448
+ expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", expectedSourceSha = "",
449
449
  } = {}) {
450
450
  const gate = validateKfdAdopterManifestGate(manifestGate, {
451
- expectedSourceSha,
451
+ expectedAdopterId, expectedSourceRepository, expectedSourceSha,
452
452
  checkedAt: manifestGate?.checkedAt,
453
453
  });
454
454
  const legacy = validateKfdLegacySupportMatrixProjection(legacyProjection, { manifest, manifestGate });
@@ -468,7 +468,7 @@ export function validateKfdAdopterReleaseBinding(binding, {
468
468
  manifest,
469
469
  manifestGate,
470
470
  legacyProjection,
471
- expectedSourceSha = "",
471
+ expectedAdopterId = "kungfu-systems/buildchain", expectedSourceRepository = "", expectedSourceSha = "",
472
472
  } = {}) {
473
473
  const issues = [];
474
474
  if (!binding || binding.schemaVersion !== 1 || binding.contract !== KFD_ADOPTER_RELEASE_BINDING_CONTRACT) {
@@ -488,7 +488,7 @@ export function validateKfdAdopterReleaseBinding(binding, {
488
488
  manifestPath: binding.authority?.manifestPath,
489
489
  gatePath: binding.authority?.gatePath,
490
490
  legacyProjectionPath: binding.legacyProjection?.path,
491
- expectedSourceSha,
491
+ expectedAdopterId, expectedSourceRepository, expectedSourceSha,
492
492
  });
493
493
  if (stableJson(binding) !== stableJson(expected)) {
494
494
  issues.push({ code: "adopter-release-binding-drift", path: "", message: "release binding differs from the exact manifest, gate, or legacy projection closure" });
@@ -0,0 +1,333 @@
1
+ import {
2
+ devDeliveryClone as clone,
3
+ devDeliveryContentRoot,
4
+ devDeliveryExactRoot as exactRoot,
5
+ devDeliveryExactSha as exactSha,
6
+ devDeliveryProtectedBase as protectedBase,
7
+ devDeliveryRepository as repository,
8
+ devDeliveryText as text,
9
+ devDeliveryTimestamp as timestamp,
10
+ } from "./dev-delivery-common.js";
11
+
12
+ export const NATIVE_QUALIFICATION_PROOF_SCHEMA =
13
+ "kungfu.buildchain.native-qualification-proof/v1";
14
+ export const NATIVE_PROOF_REUSE_DECISION_SCHEMA =
15
+ "kungfu.buildchain.native-proof-reuse-decision/v1";
16
+ export const DEV_DELIVERY_QUALIFICATION_RECEIPT_SCHEMA =
17
+ "kungfu.buildchain.dev-delivery-qualification-receipt/v1";
18
+
19
+ const NATIVE_QUALIFICATION_ROOT_SEMANTICS = "semantic-native-identity-v1";
20
+
21
+ function exactRoots(values, label) {
22
+ if (!Array.isArray(values) || values.length === 0) {
23
+ throw new Error(`${label} must contain at least one content root`);
24
+ }
25
+ return [...new Set(values.map((value) => exactRoot(value, label)))].sort();
26
+ }
27
+
28
+ function normalizedPaths(values) {
29
+ if (!Array.isArray(values)) throw new Error("paths must be a JSON array");
30
+ return [
31
+ ...new Set(
32
+ values
33
+ .map(text)
34
+ .map((entry) => entry.replace(/^\.\//u, "").replace(/\/+$/u, ""))
35
+ .filter(Boolean),
36
+ ),
37
+ ].sort();
38
+ }
39
+
40
+ function proofIdentity(body) {
41
+ const identity = clone(body);
42
+ delete identity.qualifiedAt;
43
+ delete identity.observationRoot;
44
+ return identity;
45
+ }
46
+
47
+ function proofObservation(body) {
48
+ return { qualifiedAt: body.qualifiedAt };
49
+ }
50
+
51
+ function rooted(body) {
52
+ return { ...body, decisionRoot: devDeliveryContentRoot(body) };
53
+ }
54
+
55
+ export function createNativeQualificationProof(input = {}) {
56
+ const body = {
57
+ schema: NATIVE_QUALIFICATION_PROOF_SCHEMA,
58
+ rootSemantics: NATIVE_QUALIFICATION_ROOT_SEMANTICS,
59
+ repository: repository(input.repository),
60
+ protectedBase: protectedBase(input.protectedBase),
61
+ sourceIdentityRoot: exactRoot(
62
+ input.sourceIdentityRoot,
63
+ "sourceIdentityRoot",
64
+ ),
65
+ sourcePatchRoot: exactRoot(input.sourcePatchRoot, "sourcePatchRoot"),
66
+ planRoot: exactRoot(input.planRoot, "planRoot"),
67
+ closureRoot: exactRoot(input.closureRoot, "closureRoot"),
68
+ dependencyRoot: exactRoot(input.dependencyRoot, "dependencyRoot"),
69
+ toolchainRoot: exactRoot(input.toolchainRoot, "toolchainRoot"),
70
+ qualifiedBase: exactSha(input.qualifiedBase, "qualifiedBase"),
71
+ affectedPaths: normalizedPaths(input.affectedPaths || []),
72
+ shardEvidenceRoots: exactRoots(
73
+ input.shardEvidenceRoots,
74
+ "shardEvidenceRoots",
75
+ ),
76
+ qualifiedAt: timestamp(input.qualifiedAt, "qualifiedAt"),
77
+ };
78
+ body.observationRoot = devDeliveryContentRoot(proofObservation(body));
79
+ return {
80
+ ...body,
81
+ proofRoot: devDeliveryContentRoot(proofIdentity(body)),
82
+ };
83
+ }
84
+
85
+ export function verifyNativeQualificationProof(proofInput, expected = {}) {
86
+ try {
87
+ const proof = clone(proofInput || {});
88
+ if (proof.schema !== NATIVE_QUALIFICATION_PROOF_SCHEMA) {
89
+ return { ok: false, reason: "unsupported-schema" };
90
+ }
91
+ const proofRoot = proof.proofRoot;
92
+ delete proof.proofRoot;
93
+ if (proof.rootSemantics !== NATIVE_QUALIFICATION_ROOT_SEMANTICS) {
94
+ return { ok: false, reason: "unsupported-root-semantics" };
95
+ }
96
+ if (devDeliveryContentRoot(proofIdentity(proof)) !== proofRoot) {
97
+ return { ok: false, reason: "proof-root-drift" };
98
+ }
99
+ if (
100
+ devDeliveryContentRoot(proofObservation(proof)) !== proof.observationRoot
101
+ ) {
102
+ return { ok: false, reason: "observation-root-drift" };
103
+ }
104
+ for (const [field, value] of Object.entries(expected)) {
105
+ if (value !== undefined && proof[field] !== value) {
106
+ return { ok: false, reason: `${field}-mismatch` };
107
+ }
108
+ }
109
+ createNativeQualificationProof(proof);
110
+ return { ok: true, reason: "exact-native-proof", proofRoot };
111
+ } catch (error) {
112
+ return { ok: false, reason: "invalid-proof", error: error.message };
113
+ }
114
+ }
115
+
116
+ function pathsOverlap(changedPath, affectedPath) {
117
+ if (affectedPath === "*" || affectedPath === "**") return true;
118
+ return (
119
+ changedPath === affectedPath ||
120
+ changedPath.startsWith(`${affectedPath}/`) ||
121
+ affectedPath.startsWith(`${changedPath}/`)
122
+ );
123
+ }
124
+
125
+ function nativeReuseBody(proof, current) {
126
+ const verification = verifyNativeQualificationProof(proof);
127
+ const currentBase = current.currentBase
128
+ ? exactSha(current.currentBase, "currentBase")
129
+ : null;
130
+ const changedPaths = normalizedPaths(current.changedPaths || []);
131
+ const base = {
132
+ schema: NATIVE_PROOF_REUSE_DECISION_SCHEMA,
133
+ proofRoot: verification.ok ? proof.proofRoot : null,
134
+ repository: verification.ok ? proof.repository : null,
135
+ protectedBase: verification.ok ? proof.protectedBase : null,
136
+ qualifiedBase: verification.ok ? proof.qualifiedBase : null,
137
+ currentBase,
138
+ graphKnown: current.graphKnown === true,
139
+ changedPaths,
140
+ overlappingPaths: [],
141
+ reusable: false,
142
+ action: "rerun-full-native-qualification",
143
+ reason: verification.reason,
144
+ requiredValidation: "full-native",
145
+ };
146
+ if (!verification.ok) return base;
147
+
148
+ const semanticFields = [
149
+ "sourceIdentityRoot",
150
+ "sourcePatchRoot",
151
+ "planRoot",
152
+ "closureRoot",
153
+ "dependencyRoot",
154
+ "toolchainRoot",
155
+ ];
156
+ for (const field of semanticFields) {
157
+ if (!current[field] || current[field] !== proof[field]) {
158
+ return {
159
+ ...base,
160
+ reason: `${field}-changed-or-unknown`,
161
+ };
162
+ }
163
+ }
164
+ if (!currentBase) {
165
+ return { ...base, reason: "current-base-unknown" };
166
+ }
167
+ if (currentBase === proof.qualifiedBase) {
168
+ return {
169
+ ...base,
170
+ reusable: true,
171
+ action: "accept-fresh-native-proof",
172
+ reason: "exact-qualified-base",
173
+ requiredValidation: "exact-merge-group",
174
+ };
175
+ }
176
+ if (current.graphKnown !== true || !Array.isArray(current.changedPaths)) {
177
+ return { ...base, reason: "base-delta-attribution-unknown" };
178
+ }
179
+ if (proof.affectedPaths.length === 0) {
180
+ return { ...base, reason: "affected-closure-paths-unknown" };
181
+ }
182
+ const overlap = changedPaths.filter((changedPath) =>
183
+ proof.affectedPaths.some((affectedPath) =>
184
+ pathsOverlap(changedPath, affectedPath),
185
+ ),
186
+ );
187
+ if (overlap.length > 0) {
188
+ return {
189
+ ...base,
190
+ action: "rerun-affected-native-shards",
191
+ reason: "base-delta-overlaps-affected-closure",
192
+ requiredValidation: "incremental-or-full-native",
193
+ overlappingPaths: overlap,
194
+ };
195
+ }
196
+ return {
197
+ ...base,
198
+ reusable: true,
199
+ action: "reuse-native-proof",
200
+ reason: "semantic-source-stable-and-base-delta-disjoint",
201
+ requiredValidation: "exact-merge-group",
202
+ };
203
+ }
204
+
205
+ export function createNativeProofReuseDecision({ proof, current = {} } = {}) {
206
+ return rooted(nativeReuseBody(proof, current));
207
+ }
208
+
209
+ export function verifyNativeProofReuseDecision(
210
+ decisionInput,
211
+ { proof, current = {} } = {},
212
+ ) {
213
+ try {
214
+ const decision = clone(decisionInput || {});
215
+ if (decision.schema !== NATIVE_PROOF_REUSE_DECISION_SCHEMA) {
216
+ return { ok: false, reason: "unsupported-schema" };
217
+ }
218
+ const decisionRoot = decision.decisionRoot;
219
+ delete decision.decisionRoot;
220
+ if (devDeliveryContentRoot(decision) !== decisionRoot) {
221
+ return { ok: false, reason: "decision-root-drift" };
222
+ }
223
+ const recomputed = nativeReuseBody(proof, current);
224
+ if (JSON.stringify(decision) !== JSON.stringify(recomputed)) {
225
+ return { ok: false, reason: "decision-input-drift" };
226
+ }
227
+ return {
228
+ ok: decision.reusable === true,
229
+ reason: decision.reason,
230
+ decisionRoot,
231
+ action: decision.action,
232
+ };
233
+ } catch (error) {
234
+ return { ok: false, reason: "invalid-decision", error: error.message };
235
+ }
236
+ }
237
+
238
+ export function createDevDeliveryWarrantQualifier({
239
+ transition,
240
+ assertWarrantMutation,
241
+ } = {}) {
242
+ return function qualifyDevDeliveryWarrant(
243
+ queueInput,
244
+ warrant,
245
+ {
246
+ nativeProof,
247
+ reuseDecision,
248
+ current = {},
249
+ now = new Date().toISOString(),
250
+ } = {},
251
+ ) {
252
+ const currentTime = timestamp(now, "now");
253
+ const transaction = transition(
254
+ queueInput,
255
+ (queue, before) => {
256
+ assertWarrantMutation(before, warrant, currentTime);
257
+ if (before.activeWarrant.phase !== "provisional") {
258
+ throw new Error(
259
+ "only a provisional Delivery Warrant can be qualified",
260
+ );
261
+ }
262
+ const active = before.activeWarrant;
263
+ const proofVerification = verifyNativeQualificationProof(nativeProof, {
264
+ repository: before.repository,
265
+ protectedBase: before.protectedBase,
266
+ sourceIdentityRoot: active.sourceIdentityRoot,
267
+ sourcePatchRoot: active.sourcePatchRoot,
268
+ planRoot: active.planRoot,
269
+ closureRoot: active.closureRoot,
270
+ dependencyRoot: active.dependencyRoot,
271
+ toolchainRoot: active.toolchainRoot,
272
+ });
273
+ if (!proofVerification.ok) {
274
+ throw new Error(`native proof rejected: ${proofVerification.reason}`);
275
+ }
276
+ const reuseVerification = verifyNativeProofReuseDecision(
277
+ reuseDecision,
278
+ {
279
+ proof: nativeProof,
280
+ current: {
281
+ ...current,
282
+ sourceIdentityRoot: active.sourceIdentityRoot,
283
+ sourcePatchRoot: active.sourcePatchRoot,
284
+ planRoot: active.planRoot,
285
+ closureRoot: active.closureRoot,
286
+ dependencyRoot: active.dependencyRoot,
287
+ toolchainRoot: active.toolchainRoot,
288
+ },
289
+ },
290
+ );
291
+ if (!reuseVerification.ok) {
292
+ throw new Error(
293
+ `native proof is not reusable: ${reuseVerification.reason}`,
294
+ );
295
+ }
296
+ queue.activeWarrant.phase = "qualified";
297
+ queue.activeWarrant.nativeProofRoot = proofVerification.proofRoot;
298
+ queue.activeWarrant.nativeProofReuseRoot =
299
+ reuseVerification.decisionRoot;
300
+ queue.activeWarrant.qualifiedAt = currentTime;
301
+ queue.activeWarrant.nextAction =
302
+ "Enter the GitHub merge queue at the exact fenced PR head; merge_group remains final authority.";
303
+ const candidate = queue.candidates.find(
304
+ (entry) => entry.candidateId === queue.activeWarrant.candidateId,
305
+ );
306
+ candidate.status = "qualified";
307
+ candidate.updatedAt = currentTime;
308
+ return { candidate, warrant: queue.activeWarrant };
309
+ },
310
+ currentTime,
311
+ );
312
+ const receipt = {
313
+ schema: DEV_DELIVERY_QUALIFICATION_RECEIPT_SCHEMA,
314
+ action: "qualified-warrant",
315
+ candidateId: transaction.result.candidate.candidateId,
316
+ fencingToken: transaction.result.warrant.fencingToken,
317
+ leaseGeneration: transaction.result.warrant.generation,
318
+ phase: transaction.result.warrant.phase,
319
+ nativeProofRoot: transaction.result.warrant.nativeProofRoot,
320
+ nativeProofReuseRoot: transaction.result.warrant.nativeProofReuseRoot,
321
+ qualifiedAt: transaction.result.warrant.qualifiedAt,
322
+ expectedOldStateRoot: transaction.expectedOldStateRoot,
323
+ nextStateRoot: transaction.after.stateRoot,
324
+ nextAction: transaction.result.warrant.nextAction,
325
+ };
326
+ return {
327
+ queue: transaction.after,
328
+ warrant: transaction.result.warrant,
329
+ receipt,
330
+ receiptRoot: devDeliveryContentRoot(receipt),
331
+ };
332
+ };
333
+ }
@@ -33,7 +33,11 @@ export function createDevDeliveryTerminalSettler({ normalizeQueue, closeWarrant,
33
33
  };
34
34
  if (!terminalStates.has(identity.outcome)) throw new Error(`outcome must be one of ${[...terminalStates].join(", ")}`);
35
35
  const samePullRequest = queue.candidates.filter((entry) => entry.pullRequestNumber === identity.pullRequestNumber);
36
- const candidate = samePullRequest.find((entry) => entry.sourceHead === identity.sourceHead) || null;
36
+ const matchingHead = samePullRequest.filter((entry) => entry.sourceHead === identity.sourceHead);
37
+ const activeCandidate = queue.activeWarrant
38
+ ? matchingHead.find((entry) => entry.candidateId === queue.activeWarrant.candidateId)
39
+ : null;
40
+ const candidate = activeCandidate || matchingHead.at(-1) || null;
37
41
  if (!candidate && samePullRequest.length > 0) throw new Error("terminal event sourceHead does not match the recorded candidate");
38
42
 
39
43
  if (candidate && terminalStates.has(candidate.status)) {
@@ -2,10 +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";
5
6
  import { compareReleaseBlockerPriority, normalizeReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
6
7
  export { devDeliveryContentRoot } from "./dev-delivery-common.js";
7
8
  export { RELEASE_BLOCKER_PRIORITY_CLAIM_SCHEMA, createReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
8
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, createNativeProofReuseDecision, createNativeQualificationProof, verifyNativeProofReuseDecision, verifyNativeQualificationProof } from "./dev-delivery-native-proof.js";
9
11
  export { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA };
10
12
  export const DEV_DELIVERY_QUEUE_CONTRACT = "kungfu-buildchain-dev-delivery-warrant-queue";
11
13
  export const DEV_DELIVERY_WARRANT_SCHEMA = "kungfu.buildchain.dev-delivery-warrant/v1";
@@ -59,7 +61,7 @@ function normalizeCandidate(input, expected) {
59
61
  throw new Error(`candidateId mismatch for PR #${identity.pullRequestNumber}`);
60
62
  }
61
63
  const status = text(input.status || "queued");
62
- if (!["queued", "selected", "proving", "waiting", "blocked", ...TERMINAL_STATES].includes(status)) {
64
+ if (!["queued", "selected", "provisional", "proving", "qualified", "waiting", "blocked", ...TERMINAL_STATES].includes(status)) {
63
65
  throw new Error(`unsupported candidate status ${status || "<empty>"}`);
64
66
  }
65
67
  const candidate = {
@@ -80,6 +82,10 @@ function normalizeCandidate(input, expected) {
80
82
  status,
81
83
  terminal: input.terminal || null,
82
84
  };
85
+ if (Object.hasOwn(input, "affectedPaths")) {
86
+ if (!Array.isArray(input.affectedPaths)) throw new Error("candidate affectedPaths must be an array");
87
+ candidate.affectedPaths = [...new Set(input.affectedPaths.map(text).filter(Boolean))].sort();
88
+ }
83
89
  if (Object.hasOwn(input, "releaseBlockerPriority")) candidate.releaseBlockerPriority = normalizeReleaseBlockerPriorityClaim(input.releaseBlockerPriority, candidate, expected);
84
90
  return candidate;
85
91
  }
@@ -140,12 +146,20 @@ export function normalizeDevDeliveryQueue(input, expected = {}) {
140
146
  warrant.generation = positiveInteger(warrant.generation, "Warrant generation");
141
147
  warrant.issuedAt = timestamp(warrant.issuedAt, "Warrant issuedAt");
142
148
  warrant.expiresAt = timestamp(warrant.expiresAt, "Warrant expiresAt");
143
- const activeCandidates = queue.candidates.filter((candidate) => ["selected", "proving", "waiting", "blocked"].includes(candidate.status));
149
+ const warrantPhase = text(warrant.phase || "qualified");
150
+ if (!["provisional", "qualified"].includes(warrantPhase)) throw new Error("active Warrant phase is unsupported");
151
+ if (Object.hasOwn(warrant, "phase")) warrant.phase = warrantPhase;
152
+ if (warrantPhase === "qualified") {
153
+ if (warrant.nativeProofRoot) warrant.nativeProofRoot = exactRoot(warrant.nativeProofRoot, "Warrant nativeProofRoot");
154
+ if (warrant.nativeProofReuseRoot) warrant.nativeProofReuseRoot = exactRoot(warrant.nativeProofReuseRoot, "Warrant nativeProofReuseRoot");
155
+ if (warrant.qualifiedAt) warrant.qualifiedAt = timestamp(warrant.qualifiedAt, "Warrant qualifiedAt");
156
+ }
157
+ const activeCandidates = queue.candidates.filter((candidate) => ["selected", "provisional", "proving", "qualified", "waiting", "blocked"].includes(candidate.status));
144
158
  if (activeCandidates.length !== 1 || activeCandidates[0].candidateId !== warrant.candidateId) {
145
159
  throw new Error("exactly one active candidate must match the active Warrant");
146
160
  }
147
161
  if (warrant.releaseBlockerPriority?.claimRoot !== activeCandidates[0].releaseBlockerPriority?.claimRoot) throw new Error("active Warrant release-blocker priority drift");
148
- } else if (queue.candidates.some((candidate) => ["selected", "proving", "waiting", "blocked"].includes(candidate.status))) {
162
+ } else if (queue.candidates.some((candidate) => ["selected", "provisional", "proving", "qualified", "waiting", "blocked"].includes(candidate.status))) {
149
163
  throw new Error("active candidate exists without an active Warrant");
150
164
  }
151
165
  const rooted = withQueueRoot(queue);
@@ -184,6 +198,7 @@ function submissionReceipt({ before, after, candidate, action, now }) {
184
198
  closureRoot: candidate.closureRoot,
185
199
  dependencyRoot: candidate.dependencyRoot,
186
200
  toolchainRoot: candidate.toolchainRoot,
201
+ ...(Object.hasOwn(candidate, "affectedPaths") ? { affectedPaths: candidate.affectedPaths } : {}),
187
202
  sourceWorkflowRunId: candidate.sourceWorkflowRunId,
188
203
  ...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
189
204
  deliveryClass: candidate.deliveryClass,
@@ -225,7 +240,7 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
225
240
  throw new Error(`candidate ${attemptedCandidate.candidateId} is terminal and cannot be resubmitted`);
226
241
  }
227
242
  const exactProofFields = ["sourcePatchRoot", "sourceProofRoot", "planRoot", "closureRoot", "dependencyRoot", "toolchainRoot"];
228
- const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]) && existing.releaseBlockerPriority?.claimRoot === attemptedCandidate.releaseBlockerPriority?.claimRoot;
243
+ const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]) && JSON.stringify(existing.affectedPaths || []) === JSON.stringify(attemptedCandidate.affectedPaths || []) && existing.releaseBlockerPriority?.claimRoot === attemptedCandidate.releaseBlockerPriority?.claimRoot;
229
244
  if (existing.sourceHead === attemptedCandidate.sourceHead && exactProofMatches) {
230
245
  action = "duplicate-noop";
231
246
  selected = existing;
@@ -241,6 +256,8 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
241
256
  const headChanged = existing.sourceHead !== attemptedCandidate.sourceHead;
242
257
  existing.sourceHead = attemptedCandidate.sourceHead;
243
258
  for (const field of exactProofFields) existing[field] = attemptedCandidate[field];
259
+ if (Object.hasOwn(attemptedCandidate, "affectedPaths")) existing.affectedPaths = attemptedCandidate.affectedPaths;
260
+ else delete existing.affectedPaths;
244
261
  if (Object.hasOwn(attemptedCandidate, "releaseBlockerPriority")) existing.releaseBlockerPriority = attemptedCandidate.releaseBlockerPriority;
245
262
  else delete existing.releaseBlockerPriority;
246
263
  existing.updatedAt = currentTime;
@@ -379,15 +396,17 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
379
396
  closureRoot: candidate.closureRoot,
380
397
  dependencyRoot: candidate.dependencyRoot,
381
398
  toolchainRoot: candidate.toolchainRoot,
399
+ ...(Object.hasOwn(candidate, "affectedPaths") ? { affectedPaths: candidate.affectedPaths } : {}),
382
400
  sourceWorkflowRunId: candidate.sourceWorkflowRunId,
383
401
  ...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
384
402
  deliveryClass: candidate.deliveryClass,
385
403
  generation: next.fencingCounter,
404
+ phase: "provisional",
386
405
  expectedOldStateRoot: before.stateRoot,
387
406
  issuedAt,
388
407
  expiresAt: new Date(Date.parse(issuedAt) + effectiveLeaseSeconds * 1000).toISOString(),
389
408
  fencingToken: "",
390
- nextAction: "Replay on the exact current dev base, prove required checks, then enqueue the unchanged PR head.",
409
+ nextAction: "Run or reuse the exact semantic native proof, then atomically qualify this fenced Warrant.",
391
410
  };
392
411
  warrant.fencingToken = warrantToken(warrant);
393
412
  next.activeWarrant = warrant;
@@ -454,7 +473,7 @@ export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Dat
454
473
  const effectiveLeaseSeconds = positiveInteger(leaseSeconds, "leaseSeconds", queue.policy.leaseSeconds);
455
474
  queue.activeWarrant.expiresAt = new Date(Date.parse(currentTime) + effectiveLeaseSeconds * 1000).toISOString();
456
475
  const candidate = queue.candidates.find((entry) => entry.candidateId === queue.activeWarrant.candidateId);
457
- candidate.status = "proving";
476
+ candidate.status = queue.activeWarrant.phase === "qualified" ? "qualified" : "proving";
458
477
  candidate.updatedAt = currentTime;
459
478
  return { candidate, warrant: queue.activeWarrant };
460
479
  },
@@ -478,6 +497,8 @@ export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Dat
478
497
  };
479
498
  }
480
499
 
500
+ const qualifyDevDeliveryWarrantTransition = createDevDeliveryWarrantQualifier({ transition, assertWarrantMutation });
501
+ export function qualifyDevDeliveryWarrant(queueInput, warrant, options) { return qualifyDevDeliveryWarrantTransition(queueInput, warrant, options); }
481
502
  export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().toISOString() } = {}) {
482
503
  const currentTime = timestamp(now, "now");
483
504
  const before = normalizeDevDeliveryQueue(queueInput);
@@ -604,6 +625,19 @@ export function observeDevDeliveryQueue(queueInput, { now = new Date().toISOStri
604
625
  queueAgeSeconds: entry.priority.ageSeconds,
605
626
  attempts: entry.candidate.attempts,
606
627
  recoveries: entry.candidate.recoveries,
628
+ assignmentRoot: entry.candidate.assignmentRoot,
629
+ initiativeRoot: entry.candidate.initiativeRoot,
630
+ sourceIdentityRoot: entry.candidate.sourceIdentityRoot,
631
+ sourcePatchRoot: entry.candidate.sourcePatchRoot,
632
+ sourceProofRoot: entry.candidate.sourceProofRoot,
633
+ planRoot: entry.candidate.planRoot,
634
+ closureRoot: entry.candidate.closureRoot,
635
+ dependencyRoot: entry.candidate.dependencyRoot,
636
+ toolchainRoot: entry.candidate.toolchainRoot,
637
+ sourceWorkflowRunId: entry.candidate.sourceWorkflowRunId || 0,
638
+ affectedPaths: entry.candidate.affectedPaths || [],
639
+ deliveryClass: entry.candidate.deliveryClass,
640
+ priority: entry.candidate.priority,
607
641
  nextAction: index === 0 && !queue.activeWarrant ? "eligible-for-selection" : "wait-for-active-warrant",
608
642
  })),
609
643
  observedAt: currentTime,