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

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 (95) hide show
  1. package/architecture/decisions/0002-next-development-transition.md +101 -0
  2. package/architecture/internal-capabilities.json +52 -3
  3. package/architecture/maintainability-policy.json +22 -10
  4. package/architecture/v3-core-mechanism-inventory.json +89 -0
  5. package/architecture/v4-capability-state-machine-manifest.json +73 -0
  6. package/architecture/v4-compatibility-facts-parity.json +77 -0
  7. package/architecture/v4-delivery-warrant-shadow-fixtures.json +15 -6
  8. package/architecture/v4-next-development-parity.json +192 -0
  9. package/architecture/v4-release-train-parity.json +1 -0
  10. package/architecture/v4-tail-reseal-parity.json +150 -0
  11. package/bin/buildchain.mjs +16 -1
  12. package/bin/internal/command-registry.mjs +2 -0
  13. package/bin/internal/compatibility-facts-cli.mjs +101 -0
  14. package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
  15. package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
  16. package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
  17. package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
  18. package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
  19. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
  20. package/contracts/next-development-request-v1.schema.json +66 -0
  21. package/contracts/next-development-transition-v1.schema.json +292 -0
  22. package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
  23. package/contracts/v4-tail-reseal-v1.schema.json +276 -0
  24. package/dist/site/agent-index.json +1 -0
  25. package/dist/site/artifact-schemas.json +2 -0
  26. package/dist/site/buildchain-contract.json +1388 -23
  27. package/dist/site/buildchain-site.json +259 -21
  28. package/dist/site/capability-registry.json +10 -8
  29. package/dist/site/cli-registry.json +106 -0
  30. package/dist/site/kfd-claims.json +187 -12
  31. package/dist/site/kfd-upstream-aggregate.json +1 -1
  32. package/dist/site/manual-registry.json +35 -4
  33. package/dist/site/node-api-registry.json +6578 -4492
  34. package/dist/site/page-registry.json +235 -13
  35. package/dist/site/public-surface-audit.json +241 -7
  36. package/dist/site/publication-authority-registry.json +6 -1
  37. package/dist/site/publication-registry.json +4 -4
  38. package/dist/site/release-provenance.json +7 -0
  39. package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
  40. package/dist/site/site-manifest.json +24 -8
  41. package/dist/site/workflow-registry.json +36 -4
  42. package/docs/MAP.md +4 -1
  43. package/docs/cli-reference.md +125 -0
  44. package/docs/dev-alpha-candidate-patrol.md +8 -0
  45. package/docs/dev-delivery-warrant.md +8 -4
  46. package/docs/next-development-transition.md +118 -0
  47. package/docs/node-api-reference.md +256 -123
  48. package/docs/v4-compatibility-facts.md +91 -0
  49. package/docs/v4-tail-reseal.md +73 -0
  50. package/docs/versioning.md +4 -3
  51. package/package.json +14 -5
  52. package/packages/core/buildchain-agent-manuals.js +2 -0
  53. package/packages/core/buildchain-compatibility-authority.js +336 -0
  54. package/packages/core/buildchain-compatibility-fact.js +394 -0
  55. package/packages/core/buildchain-compatibility-facts.json +217 -0
  56. package/packages/core/buildchain-compatibility-proof.js +566 -0
  57. package/packages/core/buildchain-contract.js +93 -141
  58. package/packages/core/channel-candidate.js +8 -0
  59. package/packages/core/channel-promotion-baseline.js +55 -0
  60. package/packages/core/dev-alpha-candidate-selection.js +10 -2
  61. package/packages/core/dev-delivery-execution-transfer.js +21 -1
  62. package/packages/core/dev-delivery-process-boundary.js +19 -7
  63. package/packages/core/dev-delivery-provider-heartbeat.js +18 -6
  64. package/packages/core/dev-delivery-warrant-state.js +4 -5
  65. package/packages/core/dev-delivery-warrant.js +1 -0
  66. package/packages/core/kungfu-temporal-fact.js +557 -0
  67. package/packages/core/next-development-candidate-reservation.js +186 -0
  68. package/packages/core/next-development-controller.js +728 -0
  69. package/packages/core/next-development-projection.js +287 -0
  70. package/packages/core/next-development-transition.js +738 -0
  71. package/packages/core/paper-agent-entry.js +11 -5
  72. package/packages/core/paper.js +16 -5
  73. package/packages/core/v4-canonical-contracts.js +5 -0
  74. package/packages/core/v4-floating-consumer-policy.js +29 -9
  75. package/packages/core/v4-tail-reseal-contract.js +26 -0
  76. package/packages/core/v4-tail-reseal-github.js +178 -0
  77. package/packages/core/v4-tail-reseal-receipt.js +225 -0
  78. package/packages/core/v4-tail-reseal.js +594 -0
  79. package/scripts/buildchain-cli-help.mjs +20 -0
  80. package/scripts/check-inventory.mjs +11 -0
  81. package/scripts/check-v4-floating-consumer-policy-contract.mjs +1 -1
  82. package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
  83. package/scripts/dev-pr-auto-merge.mjs +1 -1
  84. package/scripts/generate-next-development-guidance.mjs +49 -0
  85. package/scripts/generate-site-bundle.mjs +16 -3
  86. package/scripts/init-repo.mjs +22 -4
  87. package/scripts/next-development-self-dogfood-harness.mjs +460 -0
  88. package/scripts/next-development-self-dogfood.mjs +597 -0
  89. package/scripts/next-development-transition.mjs +47 -0
  90. package/scripts/release-train-self-dogfood.mjs +94 -92
  91. package/scripts/site-capability-metadata.mjs +12 -0
  92. package/scripts/v4-consumer-policy.mjs +1 -5
  93. package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
  94. package/scripts/v4-tail-reseal.mjs +416 -0
  95. package/templates/native-dev-delivery.yml +2 -0
@@ -0,0 +1,594 @@
1
+ import {
2
+ v4ContentRoot,
3
+ validateV4Clock,
4
+ validateV4Root,
5
+ } from "./v4-canonical-contracts.js";
6
+ import {
7
+ V4_TAIL_RESEAL_PLAN_CONTRACT,
8
+ V4_TAIL_RESEAL_PLATFORMS as PLATFORM_IDS,
9
+ V4_TAIL_RESEAL_PLATFORM_RUNNERS as PLATFORM_RUNNERS,
10
+ V4_TAIL_RESEAL_REQUEST_CONTRACT,
11
+ V4_TAIL_RESEAL_REUSED_STAGE_KEYS as REUSED_STAGE_KEYS,
12
+ } from "./v4-tail-reseal-contract.js";
13
+
14
+ export {
15
+ V4_TAIL_RESEAL_PLAN_CONTRACT,
16
+ V4_TAIL_RESEAL_REQUEST_CONTRACT,
17
+ } from "./v4-tail-reseal-contract.js";
18
+
19
+ const SHA = /^[0-9a-f]{40}$/u;
20
+ const TOKEN = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u;
21
+ const V4_RUNTIME_REF = /^(?:v4-alpha|train\/v4\/v4\.0\/[A-Za-z0-9._/-]+)$/u;
22
+
23
+ export class V4TailResealFault extends Error {
24
+ constructor(code, path, message) {
25
+ super(`${path}: ${message}`);
26
+ this.name = "V4TailResealFault";
27
+ this.code = code;
28
+ this.path = path;
29
+ }
30
+ }
31
+
32
+ function fault(code, path, message) {
33
+ throw new V4TailResealFault(code, path, message);
34
+ }
35
+
36
+ function exactKeys(value, expected, path) {
37
+ if (!value || typeof value !== "object" || Array.isArray(value))
38
+ fault("invalid-tail-reseal-shape", path, "object required");
39
+ const actual = Object.keys(value).sort();
40
+ const canonical = [...expected].sort();
41
+ if (
42
+ actual.length !== canonical.length ||
43
+ actual.some((key, index) => key !== canonical[index])
44
+ )
45
+ fault(
46
+ "invalid-tail-reseal-shape",
47
+ path,
48
+ "keys do not match the closed tail-reseal contract",
49
+ );
50
+ }
51
+
52
+ function token(value, path) {
53
+ if (typeof value !== "string" || !TOKEN.test(value))
54
+ fault("invalid-tail-reseal-token", path, "ASCII identity token required");
55
+ return value;
56
+ }
57
+
58
+ function text(value, path) {
59
+ if (typeof value !== "string" || value.trim() === "")
60
+ fault("invalid-tail-reseal-text", path, "non-empty string required");
61
+ return value.trim();
62
+ }
63
+
64
+ function artifactPath(value, path) {
65
+ const normalized = text(value, path).replaceAll("\\", "/");
66
+ if (
67
+ normalized.startsWith("/") ||
68
+ normalized.split("/").includes("..") ||
69
+ normalized.startsWith(".buildchain/tail-reseal")
70
+ )
71
+ fault(
72
+ "invalid-tail-reseal-artifact-path",
73
+ path,
74
+ "artifact paths must be safe relative payload paths",
75
+ );
76
+ return normalized;
77
+ }
78
+
79
+ function sha(value, path) {
80
+ if (typeof value !== "string" || !SHA.test(value))
81
+ fault("invalid-tail-reseal-sha", path, "exact lowercase Git SHA required");
82
+ return value;
83
+ }
84
+
85
+ function root(value, path) {
86
+ try {
87
+ validateV4Root(value, path);
88
+ } catch (error) {
89
+ fault("invalid-tail-reseal-root", path, error.message);
90
+ }
91
+ return value;
92
+ }
93
+
94
+ function clock(value, path) {
95
+ try {
96
+ validateV4Clock(value, path);
97
+ } catch (error) {
98
+ fault("invalid-tail-reseal-clock", path, error.message);
99
+ }
100
+ return value;
101
+ }
102
+
103
+ function positiveInteger(value, path) {
104
+ if (!Number.isSafeInteger(value) || value < 1)
105
+ fault(
106
+ "invalid-tail-reseal-integer",
107
+ path,
108
+ "positive safe integer required",
109
+ );
110
+ return value;
111
+ }
112
+
113
+ function sortedUnique(values, path, validate = token) {
114
+ if (!Array.isArray(values) || values.length === 0)
115
+ fault("invalid-tail-reseal-shape", path, "non-empty array required");
116
+ const normalized = values.map((value, index) =>
117
+ validate(value, `${path}/${index}`),
118
+ );
119
+ const canonical = [...new Set(normalized)].sort((left, right) =>
120
+ Buffer.from(left).compare(Buffer.from(right)),
121
+ );
122
+ if (
123
+ normalized.length !== canonical.length ||
124
+ normalized.some((value, index) => value !== canonical[index])
125
+ )
126
+ fault(
127
+ "unordered-tail-reseal-evidence",
128
+ path,
129
+ "values must be byte-sorted and duplicate-free",
130
+ );
131
+ return normalized;
132
+ }
133
+
134
+ function validateSource(value) {
135
+ exactKeys(
136
+ value,
137
+ [
138
+ "runId",
139
+ "runAttempt",
140
+ "sha",
141
+ "treeSha",
142
+ "sourceRoot",
143
+ "workflowFile",
144
+ "workflowName",
145
+ ],
146
+ "$/source",
147
+ );
148
+ positiveInteger(value.runId, "$/source/runId");
149
+ positiveInteger(value.runAttempt, "$/source/runAttempt");
150
+ sha(value.sha, "$/source/sha");
151
+ sha(value.treeSha, "$/source/treeSha");
152
+ root(value.sourceRoot, "$/source/sourceRoot");
153
+ text(value.workflowFile, "$/source/workflowFile");
154
+ text(value.workflowName, "$/source/workflowName");
155
+ }
156
+
157
+ function validateTarget(value) {
158
+ exactKeys(value, ["channel", "ref", "baseSha", "version"], "$/target");
159
+ if (value.channel !== "alpha" || value.ref !== "alpha/v4/v4.0")
160
+ fault(
161
+ "tail-reseal-target-mismatch",
162
+ "$/target",
163
+ "tail reseal is limited to alpha/v4/v4.0",
164
+ );
165
+ sha(value.baseSha, "$/target/baseSha");
166
+ if (!/^4\.0\.0-alpha\.\d+$/u.test(value.version))
167
+ fault(
168
+ "tail-reseal-target-mismatch",
169
+ "$/target/version",
170
+ "v4 Alpha version required",
171
+ );
172
+ }
173
+
174
+ function validateRuntime(value) {
175
+ exactKeys(
176
+ value,
177
+ ["repository", "ref", "sha", "contractRoot", "consumerPolicyReceiptRoot"],
178
+ "$/runtime",
179
+ );
180
+ if (value.repository !== "kungfu-systems/buildchain")
181
+ fault(
182
+ "tail-reseal-runtime-mismatch",
183
+ "$/runtime/repository",
184
+ "official Buildchain runtime required",
185
+ );
186
+ if (!V4_RUNTIME_REF.test(value.ref))
187
+ fault(
188
+ "tail-reseal-runtime-mismatch",
189
+ "$/runtime/ref",
190
+ "v4-alpha or a transient v4 train is required",
191
+ );
192
+ sha(value.sha, "$/runtime/sha");
193
+ root(value.contractRoot, "$/runtime/contractRoot");
194
+ root(value.consumerPolicyReceiptRoot, "$/runtime/consumerPolicyReceiptRoot");
195
+ }
196
+
197
+ function validateWarrant(value) {
198
+ exactKeys(
199
+ value,
200
+ [
201
+ "candidateId",
202
+ "generation",
203
+ "fencingToken",
204
+ "status",
205
+ "lineageRoot",
206
+ "qualificationRoot",
207
+ "stateReadbackRoot",
208
+ ],
209
+ "$/warrant",
210
+ );
211
+ token(value.candidateId, "$/warrant/candidateId");
212
+ positiveInteger(value.generation, "$/warrant/generation");
213
+ token(value.fencingToken, "$/warrant/fencingToken");
214
+ if (value.status !== "qualified")
215
+ fault(
216
+ "tail-reseal-warrant-ineligible",
217
+ "$/warrant/status",
218
+ "exact qualified Warrant required",
219
+ );
220
+ root(value.lineageRoot, "$/warrant/lineageRoot");
221
+ root(value.qualificationRoot, "$/warrant/qualificationRoot");
222
+ root(value.stateReadbackRoot, "$/warrant/stateReadbackRoot");
223
+ }
224
+
225
+ function validateRetention(value, evaluatedAt) {
226
+ exactKeys(
227
+ value,
228
+ ["status", "retainUntil", "policyRoot", "readbackRoot"],
229
+ "$/retention",
230
+ );
231
+ if (value.status !== "retained")
232
+ fault(
233
+ "tail-reseal-retention-invalid",
234
+ "$/retention/status",
235
+ "retained artifact status required",
236
+ );
237
+ clock(value.retainUntil, "$/retention/retainUntil");
238
+ if (Date.parse(value.retainUntil) <= Date.parse(evaluatedAt))
239
+ fault(
240
+ "tail-reseal-retention-expired",
241
+ "$/retention/retainUntil",
242
+ "retention must extend beyond evaluation",
243
+ );
244
+ root(value.policyRoot, "$/retention/policyRoot");
245
+ root(value.readbackRoot, "$/retention/readbackRoot");
246
+ }
247
+
248
+ function validateFailure(value) {
249
+ exactKeys(
250
+ value,
251
+ [
252
+ "platformId",
253
+ "stage",
254
+ "jobId",
255
+ "jobName",
256
+ "stepName",
257
+ "code",
258
+ "evidenceRoot",
259
+ ],
260
+ "$/failure",
261
+ );
262
+ const exactFailure =
263
+ value.platformId === "macos-arm64" &&
264
+ value.stage === "signing-finalization" &&
265
+ value.jobName === "build / Finalize signed artifact macOS ARM64" &&
266
+ value.stepName === "Recompute manifest over final signed bytes";
267
+ if (!exactFailure)
268
+ fault(
269
+ "tail-reseal-failure-mismatch",
270
+ "$/failure",
271
+ "single known macOS signing-finalization failure required",
272
+ );
273
+ positiveInteger(value.jobId, "$/failure/jobId");
274
+ token(value.code, "$/failure/code");
275
+ root(value.evidenceRoot, "$/failure/evidenceRoot");
276
+ }
277
+
278
+ function validateStageResume(value) {
279
+ exactKeys(
280
+ value,
281
+ ["planRoot", "qualificationRoot", "zeroEffectReuse", "decisions"],
282
+ "$/stageResume",
283
+ );
284
+ root(value.planRoot, "$/stageResume/planRoot");
285
+ root(value.qualificationRoot, "$/stageResume/qualificationRoot");
286
+ if (value.zeroEffectReuse !== true)
287
+ fault(
288
+ "tail-reseal-capsule-effect",
289
+ "$/stageResume/zeroEffectReuse",
290
+ "Stage Capsule reuse must remain effect-pure",
291
+ );
292
+ if (!Array.isArray(value.decisions))
293
+ fault(
294
+ "invalid-tail-reseal-shape",
295
+ "$/stageResume/decisions",
296
+ "array required",
297
+ );
298
+ const stageKeys = [];
299
+ for (const [index, decision] of value.decisions.entries()) {
300
+ const path = `$/stageResume/decisions/${index}`;
301
+ exactKeys(
302
+ decision,
303
+ ["stageKey", "decision", "capsuleRoot", "evidenceRoot"],
304
+ path,
305
+ );
306
+ stageKeys.push(token(decision.stageKey, `${path}/stageKey`));
307
+ if (decision.decision !== "reuse")
308
+ fault(
309
+ "tail-reseal-rebuild-required",
310
+ `${path}/decision`,
311
+ "all pre-tail stages must be exact reusable capsules",
312
+ );
313
+ root(decision.capsuleRoot, `${path}/capsuleRoot`);
314
+ root(decision.evidenceRoot, `${path}/evidenceRoot`);
315
+ }
316
+ if (JSON.stringify(stageKeys) !== JSON.stringify(REUSED_STAGE_KEYS))
317
+ fault(
318
+ "tail-reseal-stage-coverage-mismatch",
319
+ "$/stageResume/decisions",
320
+ "exact install, build, verify, and package reuse proof is required for every platform",
321
+ );
322
+ }
323
+
324
+ function validateSigning(value, evaluatedAt) {
325
+ exactKeys(
326
+ value,
327
+ [
328
+ "authorityRepository",
329
+ "authorityRunId",
330
+ "runtimeSha",
331
+ "requestRoot",
332
+ "delegationRoot",
333
+ "resultArtifact",
334
+ "resultArtifactRoot",
335
+ "credentialAuthorityId",
336
+ "credentialScopeRoot",
337
+ "credentialLeaseRoot",
338
+ "credentialExpiresAt",
339
+ "providerReadbackRoot",
340
+ ],
341
+ "$/signing",
342
+ );
343
+ text(value.authorityRepository, "$/signing/authorityRepository");
344
+ positiveInteger(value.authorityRunId, "$/signing/authorityRunId");
345
+ sha(value.runtimeSha, "$/signing/runtimeSha");
346
+ for (const field of [
347
+ "requestRoot",
348
+ "delegationRoot",
349
+ "resultArtifactRoot",
350
+ "credentialScopeRoot",
351
+ "credentialLeaseRoot",
352
+ "providerReadbackRoot",
353
+ ])
354
+ root(value[field], `$/signing/${field}`);
355
+ text(value.resultArtifact, "$/signing/resultArtifact");
356
+ token(value.credentialAuthorityId, "$/signing/credentialAuthorityId");
357
+ clock(value.credentialExpiresAt, "$/signing/credentialExpiresAt");
358
+ if (Date.parse(value.credentialExpiresAt) <= Date.parse(evaluatedAt))
359
+ fault(
360
+ "tail-reseal-credential-expired",
361
+ "$/signing/credentialExpiresAt",
362
+ "live credential authority is required",
363
+ );
364
+ }
365
+
366
+ function validateReleaseTail(value) {
367
+ exactKeys(
368
+ value,
369
+ [
370
+ "declarationRoot",
371
+ "transactionRoot",
372
+ "operationRoot",
373
+ "idempotencyKey",
374
+ "providerReadbackRoot",
375
+ ],
376
+ "$/releaseTail",
377
+ );
378
+ for (const field of [
379
+ "declarationRoot",
380
+ "transactionRoot",
381
+ "operationRoot",
382
+ "providerReadbackRoot",
383
+ ])
384
+ root(value[field], `$/releaseTail/${field}`);
385
+ token(value.idempotencyKey, "$/releaseTail/idempotencyKey");
386
+ }
387
+
388
+ function validatePlatforms(values) {
389
+ if (!Array.isArray(values) || values.length !== PLATFORM_IDS.length)
390
+ fault(
391
+ "tail-reseal-platform-mismatch",
392
+ "$/platforms",
393
+ "exact four-platform candidate required",
394
+ );
395
+ const ids = [];
396
+ const names = new Set();
397
+ for (const [index, value] of values.entries()) {
398
+ const path = `$/platforms/${index}`;
399
+ exactKeys(
400
+ value,
401
+ [
402
+ "id",
403
+ "name",
404
+ "runner",
405
+ "artifactName",
406
+ "artifactRoot",
407
+ "artifactArchiveRoot",
408
+ "manifestArtifactName",
409
+ "manifestRoot",
410
+ "manifestArchiveRoot",
411
+ "artifactPaths",
412
+ "capsuleRoot",
413
+ ],
414
+ path,
415
+ );
416
+ ids.push(token(value.id, `${path}/id`));
417
+ text(value.name, `${path}/name`);
418
+ text(value.runner, `${path}/runner`);
419
+ if (value.runner !== PLATFORM_RUNNERS[value.id])
420
+ fault(
421
+ "tail-reseal-runner-mismatch",
422
+ `${path}/runner`,
423
+ "platform runner differs from the declared v4 platform authority",
424
+ );
425
+ for (const field of ["artifactName", "manifestArtifactName"]) {
426
+ const name = text(value[field], `${path}/${field}`);
427
+ if (names.has(name))
428
+ fault(
429
+ "tail-reseal-artifact-ambiguous",
430
+ `${path}/${field}`,
431
+ "artifact names must be unique",
432
+ );
433
+ names.add(name);
434
+ }
435
+ root(value.artifactRoot, `${path}/artifactRoot`);
436
+ root(value.artifactArchiveRoot, `${path}/artifactArchiveRoot`);
437
+ root(value.manifestRoot, `${path}/manifestRoot`);
438
+ root(value.manifestArchiveRoot, `${path}/manifestArchiveRoot`);
439
+ const artifactPaths = sortedUnique(
440
+ value.artifactPaths,
441
+ `${path}/artifactPaths`,
442
+ artifactPath,
443
+ );
444
+ if (artifactPaths.length !== 2)
445
+ fault(
446
+ "tail-reseal-artifact-path-mismatch",
447
+ `${path}/artifactPaths`,
448
+ "exactly two declared payload roots are required",
449
+ );
450
+ root(value.capsuleRoot, `${path}/capsuleRoot`);
451
+ }
452
+ if (JSON.stringify(ids) !== JSON.stringify(PLATFORM_IDS))
453
+ fault(
454
+ "tail-reseal-platform-mismatch",
455
+ "$/platforms",
456
+ `platforms must be byte-ordered as ${PLATFORM_IDS.join(", ")}`,
457
+ );
458
+ }
459
+
460
+ export function normalizeV4TailResealRequest(request) {
461
+ exactKeys(
462
+ request,
463
+ [
464
+ "schema",
465
+ "evaluatedAt",
466
+ "repository",
467
+ "source",
468
+ "target",
469
+ "runtime",
470
+ "warrant",
471
+ "retention",
472
+ "failure",
473
+ "stageResume",
474
+ "signing",
475
+ "releaseTail",
476
+ "platforms",
477
+ ],
478
+ "$",
479
+ );
480
+ if (request.schema !== V4_TAIL_RESEAL_REQUEST_CONTRACT)
481
+ fault(
482
+ "unsupported-tail-reseal-version",
483
+ "$/schema",
484
+ "unsupported v4 tail-reseal request",
485
+ );
486
+ clock(request.evaluatedAt, "$/evaluatedAt");
487
+ text(request.repository, "$/repository");
488
+ validateSource(request.source);
489
+ validateTarget(request.target);
490
+ validateRuntime(request.runtime);
491
+ validateWarrant(request.warrant);
492
+ validateRetention(request.retention, request.evaluatedAt);
493
+ validateFailure(request.failure);
494
+ validateStageResume(request.stageResume);
495
+ validateSigning(request.signing, request.evaluatedAt);
496
+ validateReleaseTail(request.releaseTail);
497
+ validatePlatforms(request.platforms);
498
+ if (request.signing.runtimeSha !== request.runtime.sha)
499
+ fault(
500
+ "tail-reseal-signing-runtime-mismatch",
501
+ "$/signing/runtimeSha",
502
+ "signing authority runtime differs from candidate runtime",
503
+ );
504
+ const capsuleRoots = new Map(
505
+ request.platforms.map((platform) => [platform.id, platform.capsuleRoot]),
506
+ );
507
+ for (const decision of request.stageResume.decisions) {
508
+ const platformId = decision.stageKey.split(":", 1)[0];
509
+ if (decision.capsuleRoot !== capsuleRoots.get(platformId))
510
+ fault(
511
+ "tail-reseal-capsule-mismatch",
512
+ "$/stageResume/decisions",
513
+ `Stage Capsule root drifted for ${platformId}`,
514
+ );
515
+ }
516
+ return structuredClone(request);
517
+ }
518
+
519
+ export function planV4TailReseal(request) {
520
+ const normalized = normalizeV4TailResealRequest(request);
521
+ const payload = {
522
+ schema: V4_TAIL_RESEAL_PLAN_CONTRACT,
523
+ mode: "production",
524
+ productionAuthority: "v4",
525
+ evaluatedAt: normalized.evaluatedAt,
526
+ repository: normalized.repository,
527
+ sourceRoot: normalized.source.sourceRoot,
528
+ runtimeSha: normalized.runtime.sha,
529
+ warrantLineageRoot: normalized.warrant.lineageRoot,
530
+ stageResumePlanRoot: normalized.stageResume.planRoot,
531
+ retainedPlatformRoots: normalized.platforms.map((platform) => ({
532
+ platformId: platform.id,
533
+ artifactRoot: platform.artifactRoot,
534
+ artifactArchiveRoot: platform.artifactArchiveRoot,
535
+ manifestRoot: platform.manifestRoot,
536
+ manifestArchiveRoot: platform.manifestArchiveRoot,
537
+ capsuleRoot: platform.capsuleRoot,
538
+ })),
539
+ skippedStages: ["build", "install", "package", "platform-matrix", "verify"],
540
+ rerunStages: [
541
+ "macos-signing-finalization",
542
+ "aggregate",
543
+ "candidate-passport",
544
+ "protected-readback",
545
+ ],
546
+ capsuleReuse: {
547
+ authority: "content-addressed-stage-capsule",
548
+ effectAuthority: "none",
549
+ zeroExternalMutations: true,
550
+ qualificationRoot: normalized.stageResume.qualificationRoot,
551
+ },
552
+ signingEffect: {
553
+ authority: "explicit-live-release-tail",
554
+ platformId: "macos-arm64",
555
+ operationRoot: normalized.releaseTail.operationRoot,
556
+ idempotencyKey: normalized.releaseTail.idempotencyKey,
557
+ fencedBy: [
558
+ normalized.warrant.stateReadbackRoot,
559
+ normalized.signing.credentialLeaseRoot,
560
+ normalized.releaseTail.transactionRoot,
561
+ ].sort(),
562
+ providerReadbackRoots: [
563
+ normalized.signing.providerReadbackRoot,
564
+ normalized.releaseTail.providerReadbackRoot,
565
+ ].sort(),
566
+ },
567
+ passport: {
568
+ contract: "kungfu-buildchain-release-candidate-passport",
569
+ consumerPolicyReceiptRoot: normalized.runtime.consumerPolicyReceiptRoot,
570
+ sourceSha: normalized.source.sha,
571
+ version: normalized.target.version,
572
+ },
573
+ invalidationConditions: [
574
+ "artifact-byte-drift",
575
+ "credential-authority-drift",
576
+ "manifest-drift",
577
+ "platform-drift",
578
+ "prior-failure-drift",
579
+ "retention-expired",
580
+ "signer-authority-drift",
581
+ "source-drift",
582
+ "warrant-lineage-drift",
583
+ ],
584
+ };
585
+ return {
586
+ ...payload,
587
+ planRoot: v4ContentRoot("tail-reseal-plan", payload),
588
+ };
589
+ }
590
+
591
+ export {
592
+ V4_TAIL_RESEAL_PLATFORMS,
593
+ V4_TAIL_RESEAL_REUSED_STAGE_KEYS,
594
+ } from "./v4-tail-reseal-contract.js";
@@ -44,6 +44,18 @@ export const BUILDCHAIN_USAGE = `Usage:
44
44
  buildchain release-tail init --declaration <json-or-path> [--state <path>]
45
45
  buildchain release-tail <status|verify> [--state <path>] [--output <path>]
46
46
  buildchain release-tail compat --hooks-json <json-or-path> [--output <path>]
47
+ buildchain tail-reseal plan --request <request.json> [--output <plan.json>]
48
+ buildchain tail-reseal admit --request <request.json> [--output <admission.json>]
49
+ buildchain tail-reseal verify-platform --request <request.json> --platform <id>
50
+ [--artifact-root <dir>] [--mode retained|resealed]
51
+ [--provider-readback-root <sha256:...>]
52
+ [--output <readback.json>]
53
+ buildchain tail-reseal seal --request <request.json> --plan <plan.json>
54
+ --readbacks <dir> --passport <passport.json>
55
+ --protected-readback-root <sha256:...>
56
+ [--output <receipt.json>]
57
+ buildchain next-development materialize --input <request.json> [--cwd <dir>]
58
+ [--write] [--output <path>] [--json]
47
59
  buildchain github-governance <plan|apply|rollback|protection-policy-plan|ruleset-policy-plan> ...
48
60
  buildchain release <inspect|recover|finalize|abort> ...
49
61
  buildchain transaction inspect ...
@@ -154,6 +166,14 @@ export const BUILDCHAIN_USAGE = `Usage:
154
166
  [--module-fact <file>]... [--artifact <path>]...
155
167
  [--output <file>] [--json]
156
168
  buildchain facts verify [--cwd <dir>] --fact <file> [--json]
169
+ buildchain facts compatibility project [--cwd <dir>] [--registry <json-or-path>]
170
+ [--output <file>] [--json]
171
+ buildchain facts compatibility verify [--cwd <dir>] [--registry <json-or-path>] [--json]
172
+ buildchain facts compatibility query --query <json-or-path>
173
+ [--registry <json-or-path>] [--cwd <dir>] [--json]
174
+ buildchain facts compatibility query-template --fact-root <sha256:...>
175
+ [--query-id <id>] [--registry <json-or-path>]
176
+ [--cwd <dir>] [--json]
157
177
  buildchain kfd ...
158
178
  buildchain kfd hub <init|inspect|test|explain> [--cwd <dir>]
159
179
  [--declaration <path>] [--output-dir <path>]
@@ -54,6 +54,10 @@ const requiredPaths = [
54
54
  "packages/core/homebrew.js",
55
55
  "packages/core/artifact-verification-envelope.js",
56
56
  "packages/core/anchored-version-material.js",
57
+ "packages/core/next-development-transition.js",
58
+ "packages/core/next-development-controller.js",
59
+ "packages/core/next-development-candidate-reservation.js",
60
+ "packages/core/next-development-projection.js",
57
61
  "packages/core/build-facts.js",
58
62
  "packages/core/publication-package.js",
59
63
  "packages/core/publication-reproducibility.js",
@@ -76,6 +80,8 @@ const requiredPaths = [
76
80
  "docs/auditable-demo.md",
77
81
  "contracts/auditable-demo-scenario-v1.schema.json",
78
82
  "contracts/release-candidate-recovery-v1.schema.json",
83
+ "contracts/next-development-request-v1.schema.json",
84
+ "contracts/next-development-transition-v1.schema.json",
79
85
  "contracts/auditable-demo-media-profiles-v1.json",
80
86
  "contracts/evidence/auditable-demo-web-delivery-v1.json",
81
87
  "contracts/evidence/auditable-demo-responsive-web-delivery-v1.json",
@@ -87,10 +93,15 @@ const requiredPaths = [
87
93
  "contracts/fixtures/auditable-demo-responsive-web-delivery-v1/public-projection.json",
88
94
  "contracts/fixtures/auditable-demo-responsive-web-delivery-v1/scene.json",
89
95
  "docs/release-propagation.md",
96
+ "docs/next-development-transition.md",
90
97
  "docs/site-bundle-contract.md",
91
98
  "docs/toolkit-observability.md",
92
99
  "docs/versioning.md",
93
100
  "scripts/release-line-dry-run.mjs",
101
+ "scripts/next-development-transition.mjs",
102
+ "scripts/next-development-self-dogfood.mjs",
103
+ "scripts/next-development-self-dogfood-harness.mjs",
104
+ "scripts/generate-next-development-guidance.mjs",
94
105
  "scripts/reconcile-release-governance.mjs",
95
106
  "scripts/buildchain-channel-router.mjs",
96
107
  "scripts/generate-channel-build-workflow.mjs",
@@ -6,7 +6,6 @@ import { parseYamlUses } from "../packages/core/workflow-yaml-contract.js";
6
6
 
7
7
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
8
8
  const read = (relative) => fs.readFileSync(path.join(root, relative), "utf8");
9
-
10
9
  function fail(message) {
11
10
  throw new Error(`v4-floating-consumer-policy-contract: ${message}`);
12
11
  }
@@ -113,6 +112,7 @@ export function checkV4FloatingConsumerPolicyContract() {
113
112
  "Enforce v4 floating consumer policy",
114
113
  "Validate consumer package manager contract",
115
114
  ]);
115
+ if (!read(".github/workflows/.build.yml").includes("BUILDCHAIN_EXPECTED_INVOCATION_CHANNEL: ${{ inputs.buildchain-expected-channel }}")) fail("channel builds must disambiguate dual-channel caller invocations");
116
116
  assertTrustGatedJobs(read(".github/workflows/.build.yml"), [
117
117
  "resolve-source",
118
118
  "resolve-contract",