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

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 (159) hide show
  1. package/README.md +9 -6
  2. package/actions/release-tail/README.md +8 -0
  3. package/actions/v4-release-candidate-promote/README.md +3 -0
  4. package/architecture/agent-change-map.md +1015 -0
  5. package/architecture/ci-lane-change-budget.json +256 -0
  6. package/architecture/decisions/0004-v4-declarative-release-tail.md +47 -0
  7. package/architecture/internal-capabilities.json +220 -15
  8. package/architecture/maintainability-debt.json +3229 -0
  9. package/architecture/maintainability-policy.json +489 -132
  10. package/architecture/release-tail-contract-inventory.json +5 -2
  11. package/architecture/v3-core-mechanism-inventory.json +4 -3
  12. package/architecture/v3-v4-capability-closure.md +59 -0
  13. package/architecture/v3-v4-live-capability-inventory.json +102404 -0
  14. package/architecture/v4-adopter-delivery-parity.json +32 -5
  15. package/architecture/v4-cross-platform-adopter-qualification.json +52 -0
  16. package/architecture/v4-delivery-warrant-shadow-fixtures.json +3 -3
  17. package/architecture/v4-floating-consumer-policy.json +6 -0
  18. package/architecture/v4-publication-rehearsal-parity.json +84 -0
  19. package/architecture/v4-runtime-semantic-closure.json +710 -0
  20. package/bin/buildchain.mjs +7 -1
  21. package/bin/internal/adopter-delivery-cli.mjs +70 -0
  22. package/bin/internal/command-registry.mjs +1 -0
  23. package/bin/internal/trust-release-release-handlers.mjs +5 -0
  24. package/contracts/fixtures/v4-adopter-delivery-v1/archive-template.json +19 -0
  25. package/contracts/fixtures/v4-adopter-delivery-v1/bootstrap-positive.json +93 -0
  26. package/contracts/fixtures/v4-adopter-delivery-v1/gate-positive.json +29 -0
  27. package/contracts/fixtures/v4-adopter-delivery-v1/gate-unknown-selector.json +26 -0
  28. package/contracts/fixtures/v4-adopter-delivery-v1/offline-vectors.json +50 -0
  29. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/artifacts/product.bin +1 -0
  30. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/config/buildchain.toml +5 -0
  31. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/release-activation.json +1 -0
  32. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/documents/signed-channel.json +1 -0
  33. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/evidence/qualification.json +1 -0
  34. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/candidate.json +5 -0
  35. package/contracts/fixtures/v4-publication-rehearsal-v1/candidate/manifests/release-passport.json +1 -0
  36. package/contracts/fixtures/v4-publication-rehearsal-v1/capsule.json +707 -0
  37. package/contracts/fixtures/v4-publication-rehearsal-v1/offline-vectors.json +27 -0
  38. package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
  39. package/contracts/v4-adopter-delivery-v1.schema.json +81 -0
  40. package/contracts/v4-floating-consumer-policy-receipt-v1.schema.json +4 -2
  41. package/contracts/v4-publication-qualification-v1.schema.json +51 -0
  42. package/contracts/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  43. package/dist/site/agent-index.json +4 -0
  44. package/dist/site/artifact-schemas.json +8 -0
  45. package/dist/site/buildchain-contract.json +125 -34
  46. package/dist/site/buildchain-site.json +308 -33
  47. package/dist/site/capability-registry.json +13 -12
  48. package/dist/site/cli-registry.json +57 -2
  49. package/dist/site/controller-registry.json +41 -5
  50. package/dist/site/kfd-claims.json +438 -24
  51. package/dist/site/kfd-upstream-aggregate.json +1 -1
  52. package/dist/site/manual-registry.json +22 -7
  53. package/dist/site/node-api-registry.json +12843 -9314
  54. package/dist/site/page-registry.json +288 -21
  55. package/dist/site/public-surface-audit.json +281 -21
  56. package/dist/site/publication-authority-registry.json +66 -8
  57. package/dist/site/publication-registry.json +4 -4
  58. package/dist/site/release-provenance.json +20 -0
  59. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +199 -0
  60. package/dist/site/schemas/v4-adopter-delivery-v1.schema.json +81 -0
  61. package/dist/site/schemas/v4-publication-qualification-v1.schema.json +51 -0
  62. package/dist/site/schemas/v4-publication-rehearsal-capsule-v1.schema.json +233 -0
  63. package/dist/site/site-manifest.json +19 -11
  64. package/dist/site/workflow-registry.json +195 -17
  65. package/docs/MAP.md +4 -2
  66. package/docs/cli-reference.md +70 -2
  67. package/docs/cli.md +8 -0
  68. package/docs/dev-delivery-warrant.md +34 -10
  69. package/docs/node-api-reference.md +524 -279
  70. package/docs/publish-transaction.md +11 -4
  71. package/docs/release-candidate.md +7 -0
  72. package/docs/release-tail-provider-plane.md +30 -0
  73. package/docs/v4-adopter-delivery.md +152 -0
  74. package/docs/v4-declarative-release-tail-migration.md +43 -0
  75. package/docs/v4-publication-rehearsal.md +130 -0
  76. package/package.json +24 -4
  77. package/packages/core/adopter-delivery-passport.js +295 -0
  78. package/packages/core/adopter-delivery-vectors.js +158 -0
  79. package/packages/core/adopter-delivery-vectors.json +77 -0
  80. package/packages/core/buildchain-agent-manuals.js +1 -0
  81. package/packages/core/buildchain-config.js +84 -0
  82. package/packages/core/buildchain-contract.js +31 -1
  83. package/packages/core/buildchain-delivery-bootstrap.js +240 -0
  84. package/packages/core/buildchain-delivery-infrastructure.js +164 -0
  85. package/packages/core/buildchain-delivery-self-dogfood.js +395 -0
  86. package/packages/core/buildchain-publication-authority.js +2 -0
  87. package/packages/core/ci-lane-change-budget.js +247 -0
  88. package/packages/core/dev-delivery-native-proof.js +43 -27
  89. package/packages/core/dev-delivery-warrant-settlement.js +239 -3
  90. package/packages/core/dev-delivery-warrant-state.js +46 -10
  91. package/packages/core/dev-delivery-warrant.js +29 -7
  92. package/packages/core/github-governance-authority.js +5 -4
  93. package/packages/core/index.js +6 -0
  94. package/packages/core/legacy-kfd-adopter-driver.js +167 -0
  95. package/packages/core/paper-scaffold-content.js +401 -0
  96. package/packages/core/paper.js +12 -378
  97. package/packages/core/publication-control-plane-audit.js +135 -111
  98. package/packages/core/publication-rehearsal-projection.js +104 -0
  99. package/packages/core/publication-rehearsal-runtime.js +190 -0
  100. package/packages/core/published-delivery-authority.js +266 -0
  101. package/packages/core/release-candidate-recovery.js +71 -15
  102. package/packages/core/release-candidate.js +2 -2
  103. package/packages/core/release-passport.js +95 -170
  104. package/packages/core/v4-adopter-delivery-parity.js +3 -3
  105. package/packages/core/v4-adopter-delivery.js +359 -0
  106. package/packages/core/v4-cross-platform-adopter-qualification.js +343 -0
  107. package/packages/core/v4-delivery-warrant-read-candidate.js +10 -3
  108. package/packages/core/v4-floating-consumer-evidence.js +18 -4
  109. package/packages/core/v4-floating-consumer-policy.js +139 -35
  110. package/packages/core/v4-floating-consumer-release-passport.js +154 -8
  111. package/packages/core/v4-publication-qualification.js +222 -0
  112. package/packages/core/v4-publication-rehearsal-capsule.js +468 -0
  113. package/packages/core/v4-publication-rehearsal-provider-bindings.js +212 -0
  114. package/packages/core/v4-publication-rehearsal.js +481 -0
  115. package/packages/core/workflow-yaml-contract.js +24 -2
  116. package/scripts/artifact-signing-controller-core.mjs +1 -1
  117. package/scripts/audit-publication-control-plane.mjs +17 -17
  118. package/scripts/buildchain-cli-help.mjs +13 -0
  119. package/scripts/check-ci-lane-change-budget.mjs +100 -0
  120. package/scripts/check-internal-architecture.mjs +23 -3
  121. package/scripts/check-inventory.mjs +24 -6
  122. package/scripts/check-maintainability.mjs +145 -4
  123. package/scripts/check-project-cut-merge-queue-admission.mjs +87 -0
  124. package/scripts/check-v3-v4-capability-inventory.mjs +574 -0
  125. package/scripts/check-v4-floating-consumer-policy-contract.mjs +30 -4
  126. package/scripts/check-v4-runtime-semantic-closure.mjs +266 -0
  127. package/scripts/dev-delivery-source-proof-replay.mjs +153 -0
  128. package/scripts/dev-delivery-source-proof-reuse.mjs +13 -97
  129. package/scripts/dev-delivery-warrant-options.mjs +27 -11
  130. package/scripts/dev-delivery-warrant-store.mjs +10 -6
  131. package/scripts/dev-delivery-warrant.mjs +50 -6
  132. package/scripts/dev-pr-auto-merge.mjs +25 -11
  133. package/scripts/dev-pr-delivery-warrant.mjs +45 -0
  134. package/scripts/dev-pr-prequeue-guard.mjs +0 -18
  135. package/scripts/dev-qualification-patrol.mjs +9 -9
  136. package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
  137. package/scripts/generate-agent-change-map.mjs +118 -0
  138. package/scripts/generate-channel-promotion-workflow.mjs +2 -2
  139. package/scripts/generate-release-candidate-passport.mjs +177 -0
  140. package/scripts/generate-site-bundle.mjs +36 -0
  141. package/scripts/maintainability-domain-metrics.mjs +237 -0
  142. package/scripts/maintainability-governance.mjs +473 -0
  143. package/scripts/maintainability-metrics.mjs +28 -6
  144. package/scripts/project-cut-merge-queue-admission.mjs +394 -0
  145. package/scripts/promotion-channel-router.mjs +4 -4
  146. package/scripts/promotion-routing-evidence.mjs +35 -6
  147. package/scripts/release-candidate-anchor-provenance.mjs +99 -0
  148. package/scripts/release-candidate-resolver.mjs +44 -0
  149. package/scripts/release-line-policy.mjs +25 -15
  150. package/scripts/release-tail.mjs +68 -3
  151. package/scripts/resume-from-candidate-run.mjs +595 -65
  152. package/scripts/run-lifecycle-core.mjs +341 -376
  153. package/scripts/site-capability-metadata.mjs +21 -0
  154. package/scripts/stable-candidate-qualification.mjs +9 -10
  155. package/scripts/v3-v4-capability-catalog.mjs +439 -0
  156. package/scripts/v4-consumer-policy.mjs +4 -0
  157. package/scripts/v4-cross-platform-adopter-qualification.mjs +228 -0
  158. package/scripts/v4-declarative-promotion-admission.mjs +42 -0
  159. package/scripts/v4-publication-rehearsal-fixture.mjs +144 -0
@@ -5,11 +5,183 @@ import { execFileSync } from "node:child_process";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import { createReleaseCandidatePassport, validateReleaseCandidatePassport } from "../packages/core/release-candidate.js";
7
7
  import { scanV4FloatingConsumerPolicy, v4ConsumerPolicyScannerRoot } from "../packages/core/v4-floating-consumer-policy.js";
8
+ import { v4ContentRoot } from "../packages/core/v4-canonical-contracts.js";
9
+ import { V4_STAGE_CAPSULE_CONTRACT, V4_STAGE_CAPSULE_IDENTITY_CONTRACT, v4StageCapsuleIdentityRoot, v4StageCapsuleRoot, validateV4StageCapsule } from "../packages/core/v4-stage-capsule.js";
10
+ import { v4RuntimeResumeDocumentRoot } from "../packages/core/v4-runtime-ref-resume-authority.js";
11
+ import { createV4PublicationQualificationReceipt } from "../packages/core/v4-publication-qualification.js";
8
12
  import { writeGitHubOutputs } from "./build-contract-core.mjs";
9
13
 
10
14
  const env = (name, fallback = "") => process.env[name] || fallback;
11
15
  const readJsonFile = (filePath) => JSON.parse(fs.readFileSync(filePath, "utf8"));
12
16
 
17
+ export function createReleaseCandidateStageCapsules({
18
+ passport,
19
+ buildSummary,
20
+ coordinates,
21
+ }) {
22
+ if (!passport.consumerPolicy?.receiptRoot) return undefined;
23
+ if (
24
+ coordinates.repository !== passport.repository ||
25
+ String(coordinates.runId) !== String(passport.workflow.runId) ||
26
+ String(coordinates.runAttempt) !== String(passport.workflow.runAttempt) ||
27
+ coordinates.sourceSha !== passport.source.headSha
28
+ ) {
29
+ throw new Error(
30
+ "Stage Capsule coordinate set does not bind the candidate run",
31
+ );
32
+ }
33
+ const coordinateByPlatform = new Map(
34
+ coordinates.artifacts.map((entry) => [entry.platformId, entry]),
35
+ );
36
+ const qualificationArtifacts = passport.platformMatrix.map((platform) => {
37
+ const coordinate = coordinateByPlatform.get(platform.platformId);
38
+ if (!coordinate || coordinate.name !== platform.artifactName) throw new Error(`Stage Capsule coordinate missing for ${platform.platformId}`);
39
+ const manifest = readJsonFile(platform.manifestPath);
40
+ return { role: platform.artifactName, platform: platform.platformId, artifactRoot: coordinate.digest, manifestRoot: v4ContentRoot("stage-capsule-artifact-manifest", manifest) };
41
+ });
42
+ const qualificationExpiresAt = coordinates.artifacts.map((entry) => entry.expiresAt).sort((left, right) => Date.parse(left) - Date.parse(right))[0];
43
+ const qualificationReceipt = createV4PublicationQualificationReceipt({
44
+ repository: passport.repository, candidateRoot: `sha256:${passport.candidateHash}`,
45
+ sourceSha: passport.source.headSha, sourceRoot: v4ContentRoot("candidate-identity", passport.source),
46
+ policyDigest: passport.consumerPolicy.receiptRoot, artifacts: qualificationArtifacts,
47
+ issuedAt: passport.createdAt || new Date(Date.parse(qualificationExpiresAt) - 86_400_000).toISOString(), expiresAt: qualificationExpiresAt,
48
+ });
49
+ const qualificationRoot = qualificationReceipt.receiptRoot;
50
+ const entries = passport.platformMatrix
51
+ .map((platform) => {
52
+ const coordinate = coordinateByPlatform.get(platform.platformId);
53
+ if (!coordinate || coordinate.name !== platform.artifactName) {
54
+ throw new Error(
55
+ `Stage Capsule coordinate missing for ${platform.platformId}`,
56
+ );
57
+ }
58
+ const manifest = readJsonFile(platform.manifestPath);
59
+ const identity = {
60
+ schema: V4_STAGE_CAPSULE_IDENTITY_CONTRACT,
61
+ sourceRoot: v4ContentRoot("candidate-identity", passport.source),
62
+ platform: platform.platformId,
63
+ platformRoot: v4ContentRoot("candidate-identity", manifest.platform),
64
+ stage: "verify",
65
+ toolchainRoots: [],
66
+ runtimeRoot: v4ContentRoot("candidate-identity", {
67
+ sha: passport.buildchain.sha,
68
+ }),
69
+ policyRoot: passport.consumerPolicy.receiptRoot,
70
+ declaredInputs: [
71
+ {
72
+ name: "release-candidate",
73
+ root: `sha256:${passport.candidateHash}`,
74
+ },
75
+ ],
76
+ transformationRoot: v4ContentRoot("candidate-identity", {
77
+ lifecycle: manifest.lifecycle,
78
+ summary: platform.summary,
79
+ }),
80
+ outputManifestRoot: v4ContentRoot(
81
+ "stage-capsule-artifact-manifest",
82
+ { artifact: coordinate, manifest },
83
+ ),
84
+ qualificationRoot,
85
+ observationRoots: [
86
+ {
87
+ name: "provider-coordinate",
88
+ root: v4ContentRoot("provider-readback-sample", coordinate),
89
+ },
90
+ ],
91
+ };
92
+ const capsule = {
93
+ schema: V4_STAGE_CAPSULE_CONTRACT,
94
+ writerAuthority: "typescript-v3",
95
+ rustAuthority: "validation-only",
96
+ identity,
97
+ identityRoot: v4StageCapsuleIdentityRoot(identity),
98
+ retentionPromise: {
99
+ class: "github-artifact",
100
+ retainUntil: coordinate.expiresAt,
101
+ },
102
+ capsuleRoot: `sha256:${"0".repeat(64)}`,
103
+ };
104
+ capsule.capsuleRoot = v4StageCapsuleRoot(capsule);
105
+ validateV4StageCapsule(capsule);
106
+ return {
107
+ platform: platform.platformId,
108
+ artifactName: coordinate.name,
109
+ artifactDigest: coordinate.digest,
110
+ publicationArtifact: qualificationArtifacts.find(
111
+ ({ platform: platformId }) => platformId === platform.platformId,
112
+ ),
113
+ artifact: coordinate,
114
+ capsule,
115
+ };
116
+ })
117
+ .sort((left, right) => left.platform.localeCompare(right.platform));
118
+ const body = {
119
+ schemaVersion: 1,
120
+ contract: "kungfu-buildchain-v4-release-candidate-stage-capsules/v1",
121
+ status: "sealed",
122
+ repository: passport.repository,
123
+ buildAttempt: {
124
+ id: `github-run:${passport.workflow.runId}:attempt:${passport.workflow.runAttempt}`,
125
+ runtimeSha: passport.buildchain.sha,
126
+ },
127
+ source: {
128
+ sha: passport.source.headSha,
129
+ treeSha: passport.source.treeHash,
130
+ },
131
+ consumerPolicyReceiptRoot: passport.consumerPolicy.receiptRoot,
132
+ publicationQualificationRoot: qualificationRoot,
133
+ publicationQualificationReceipt: qualificationReceipt,
134
+ capsules: entries,
135
+ };
136
+ return { ...body, root: v4RuntimeResumeDocumentRoot(body) };
137
+ }
138
+
139
+ function writeReleaseCandidateStageCapsules({
140
+ passport,
141
+ buildSummary,
142
+ outputPath,
143
+ }) {
144
+ const coordinatesPath = path.resolve(
145
+ env(
146
+ "BUILDCHAIN_ARTIFACT_COORDINATES_PATH",
147
+ ".buildchain/artifacts/artifact-coordinates.json",
148
+ ),
149
+ );
150
+ if (!fs.existsSync(coordinatesPath)) {
151
+ if (passport.consumerPolicy?.receiptRoot) {
152
+ throw new Error(
153
+ "v4 release candidate Stage Capsules require exact artifact coordinates",
154
+ );
155
+ }
156
+ return { path: "", root: "" };
157
+ }
158
+ const stageCapsules = createReleaseCandidateStageCapsules({
159
+ passport,
160
+ buildSummary,
161
+ coordinates: readJsonFile(coordinatesPath),
162
+ });
163
+ if (!stageCapsules) return { path: "", root: "" };
164
+ const stageCapsulesPath = path.join(
165
+ path.dirname(outputPath),
166
+ "release-candidate-stage-capsules.json",
167
+ );
168
+ fs.writeFileSync(
169
+ stageCapsulesPath,
170
+ `${JSON.stringify(stageCapsules, null, 2)}\n`,
171
+ );
172
+ const qualificationPath = path.join(path.dirname(outputPath), "release-candidate-publication-qualification.json");
173
+ fs.writeFileSync(qualificationPath, `${JSON.stringify(stageCapsules.publicationQualificationReceipt, null, 2)}\n`);
174
+ return {
175
+ path: path
176
+ .relative(process.cwd(), stageCapsulesPath)
177
+ .split(path.sep)
178
+ .join("/"),
179
+ root: stageCapsules.root,
180
+ qualificationPath: path.relative(process.cwd(), qualificationPath).split(path.sep).join("/"),
181
+ qualificationRoot: stageCapsules.publicationQualificationRoot,
182
+ };
183
+ }
184
+
13
185
  export function resolveLegacyConsumerPolicyReceipt(options = {}) {
14
186
  if (options.json) return { receipt: JSON.parse(options.json), receiptRoot: options.receiptRoot };
15
187
  if (options.repository !== "kungfu-systems/buildchain" || options.targetChannel !== "alpha" || options.workflowShellRef !== "v4-alpha" || options.runtimeOverride !== true) return undefined;
@@ -80,6 +252,7 @@ export function generateReleaseCandidatePassportCli() {
80
252
  if (!validation.ok) throw new Error(`release candidate passport invalid: ${validation.errors.join("; ")}`);
81
253
  fs.mkdirSync(path.dirname(outputPath), { recursive: true });
82
254
  fs.writeFileSync(outputPath, `${JSON.stringify(passport, null, 2)}\n`);
255
+ const stageCapsules = writeReleaseCandidateStageCapsules({ passport, buildSummary, outputPath });
83
256
  writeGitHubOutputs({
84
257
  "release-candidate-passport-path": path.relative(process.cwd(), outputPath).split(path.sep).join("/"),
85
258
  "release-candidate-passport-json": JSON.stringify({
@@ -94,6 +267,10 @@ export function generateReleaseCandidatePassportCli() {
94
267
  consumerPolicy: passport.consumerPolicy,
95
268
  controllerReceipts: passport.controllerReceipts || [],
96
269
  }),
270
+ "release-candidate-stage-capsules-path": stageCapsules.path,
271
+ "release-candidate-stage-capsules-root": stageCapsules.root,
272
+ "release-candidate-publication-qualification-path": stageCapsules.qualificationPath,
273
+ "release-candidate-publication-qualification-root": stageCapsules.qualificationRoot,
97
274
  });
98
275
  return passport;
99
276
  }
@@ -54,6 +54,28 @@ const V4_COMPATIBILITY_FACTS_SCHEMA =
54
54
  "schemas/v4-compatibility-facts-v1.schema.json";
55
55
  const V4_COMPATIBILITY_FACTS_SCHEMA_SOURCE =
56
56
  "contracts/v4-compatibility-facts-v1.schema.json";
57
+ const V4_PUBLICATION_REHEARSAL_SCHEMA =
58
+ "schemas/v4-publication-rehearsal-capsule-v1.schema.json";
59
+ const V4_PUBLICATION_REHEARSAL_SCHEMA_SOURCE =
60
+ "contracts/v4-publication-rehearsal-capsule-v1.schema.json";
61
+ const V4_ADOPTER_DELIVERY_SCHEMA =
62
+ "schemas/v4-adopter-delivery-v1.schema.json";
63
+ const V4_ADOPTER_DELIVERY_SCHEMA_SOURCE =
64
+ "contracts/v4-adopter-delivery-v1.schema.json";
65
+ const RELEASE_TAIL_CAPABILITIES_SCHEMA =
66
+ "schemas/release-tail-capabilities-v1.schema.json";
67
+ const RELEASE_TAIL_CAPABILITIES_SCHEMA_SOURCE =
68
+ "contracts/release-tail-capabilities-v1.schema.json";
69
+ const V4_PUBLICATION_QUALIFICATION_SCHEMA =
70
+ "schemas/v4-publication-qualification-v1.schema.json";
71
+ const V4_PUBLICATION_QUALIFICATION_SCHEMA_SOURCE =
72
+ "contracts/v4-publication-qualification-v1.schema.json";
73
+ const PUBLICATION_REHEARSAL_SITE_SCHEMAS = [
74
+ V4_PUBLICATION_REHEARSAL_SCHEMA,
75
+ V4_ADOPTER_DELIVERY_SCHEMA,
76
+ RELEASE_TAIL_CAPABILITIES_SCHEMA,
77
+ V4_PUBLICATION_QUALIFICATION_SCHEMA,
78
+ ];
57
79
  const root = path.resolve(import.meta.dirname, "..");
58
80
  const outputDir = path.join(root, "dist", "site");
59
81
  const requireFromHere = createRequire(import.meta.url);
@@ -84,6 +106,10 @@ function stableJson(value) {
84
106
  function siteFileBytes(name, value) {
85
107
  if (name === DEV_DELIVERY_AUTHORITY_SCHEMA) return readText(DEV_DELIVERY_AUTHORITY_SCHEMA_SOURCE);
86
108
  if (name === V4_COMPATIBILITY_FACTS_SCHEMA) return readText(V4_COMPATIBILITY_FACTS_SCHEMA_SOURCE);
109
+ if (name === V4_PUBLICATION_REHEARSAL_SCHEMA) return readText(V4_PUBLICATION_REHEARSAL_SCHEMA_SOURCE);
110
+ if (name === V4_PUBLICATION_QUALIFICATION_SCHEMA) return readText(V4_PUBLICATION_QUALIFICATION_SCHEMA_SOURCE);
111
+ if (name === V4_ADOPTER_DELIVERY_SCHEMA) return readText(V4_ADOPTER_DELIVERY_SCHEMA_SOURCE);
112
+ if (name === RELEASE_TAIL_CAPABILITIES_SCHEMA) return readText(RELEASE_TAIL_CAPABILITIES_SCHEMA_SOURCE);
87
113
  return stableJson(value);
88
114
  }
89
115
 
@@ -396,6 +422,7 @@ const manualMetaById = new Map(Object.entries({
396
422
  "observed-evidence-patrol": { capabilityGroup: "governance-versioning", audience: ["release-operator", "consumer", "agent"], maturity: "preview", order: 140 },
397
423
  "engineering-housekeeper": { capabilityGroup: "governance-versioning", audience: ["maintainer", "consumer", "agent"], maturity: "preview", order: 145 },
398
424
  "reusable-build-surface": { capabilityGroup: "reusable-build", audience: ["consumer", "release-operator"], maturity: "stable", order: 200 },
425
+ "v4-adopter-delivery": { capabilityGroup: "reusable-build", audience: ["consumer", "developer", "agent"], maturity: "preview", order: 205 },
399
426
  "lifecycle-protocol": { capabilityGroup: "reusable-build", audience: ["consumer", "developer"], maturity: "stable", order: 210 },
400
427
  "runtime-train-validation": { capabilityGroup: "governance-versioning", audience: ["maintainer", "consumer"], maturity: "stable", order: 220 },
401
428
  "kfd-support": { capabilityGroup: "kfd-trust", audience: ["agent", "maintainer"], maturity: "stable", order: 300 },
@@ -956,6 +983,7 @@ function buildSiteBundle() {
956
983
  "schemas/kfd-product-gate-input-v1.schema.json",
957
984
  "schemas/dev-delivery-authority-v2.schema.json",
958
985
  "schemas/v4-compatibility-facts-v1.schema.json",
986
+ ...PUBLICATION_REHEARSAL_SITE_SCHEMAS,
959
987
  "kfd-support.json",
960
988
  "artifact-evidence.json",
961
989
  "product-mechanism.json",
@@ -992,6 +1020,7 @@ function buildSiteBundle() {
992
1020
  "schemas/kfd-product-gate-input-v1.schema.json",
993
1021
  "schemas/dev-delivery-authority-v2.schema.json",
994
1022
  "schemas/v4-compatibility-facts-v1.schema.json",
1023
+ ...PUBLICATION_REHEARSAL_SITE_SCHEMAS,
995
1024
  "buildchain-contract.json",
996
1025
  "kfd-claims.json",
997
1026
  "product-mechanism.json",
@@ -1124,6 +1153,7 @@ function buildSiteBundle() {
1124
1153
  "schemas/kfd-product-gate-input-v1.schema.json",
1125
1154
  "schemas/dev-delivery-authority-v2.schema.json",
1126
1155
  "schemas/v4-compatibility-facts-v1.schema.json",
1156
+ ...PUBLICATION_REHEARSAL_SITE_SCHEMAS,
1127
1157
  "buildchain-contract.json",
1128
1158
  "kfd-upstream-aggregate.json",
1129
1159
  "kfd-claims.json",
@@ -1304,6 +1334,12 @@ function buildSiteBundle() {
1304
1334
  [V4_COMPATIBILITY_FACTS_SCHEMA]: readJson(
1305
1335
  V4_COMPATIBILITY_FACTS_SCHEMA_SOURCE,
1306
1336
  ),
1337
+ ...Object.fromEntries(
1338
+ PUBLICATION_REHEARSAL_SITE_SCHEMAS.map((name) => [
1339
+ name,
1340
+ JSON.parse(siteFileBytes(name)),
1341
+ ]),
1342
+ ),
1307
1343
  "badge-endpoint-registry.json": badgeEndpointRegistry,
1308
1344
  "publication-registry.json": publicationRegistry,
1309
1345
  "buildchain-contract.json": createBuildchainContractWorld({ root, controllerRegistry }),
@@ -0,0 +1,237 @@
1
+ import { parseWorkflowDocument } from "../packages/core/workflow-yaml-contract.js";
2
+
3
+ function lineCount(source) {
4
+ const text = String(source || "");
5
+ if (!text) return 0;
6
+ const lines = text.split(/\r?\n/u);
7
+ return lines.at(-1) === "" ? lines.length - 1 : lines.length;
8
+ }
9
+
10
+ function rustTokens(source) {
11
+ const tokens = [];
12
+ let index = 0;
13
+ let line = 1;
14
+ const advance = () => {
15
+ if (source[index] === "\n") line += 1;
16
+ index += 1;
17
+ };
18
+ while (index < source.length) {
19
+ if (/\s/u.test(source[index])) {
20
+ advance();
21
+ continue;
22
+ }
23
+ if (source.startsWith("//", index)) {
24
+ while (index < source.length && source[index] !== "\n") advance();
25
+ continue;
26
+ }
27
+ if (source.startsWith("/*", index)) {
28
+ let depth = 1;
29
+ advance();
30
+ advance();
31
+ while (index < source.length && depth > 0) {
32
+ if (source.startsWith("/*", index)) {
33
+ depth += 1;
34
+ advance();
35
+ advance();
36
+ } else if (source.startsWith("*/", index)) {
37
+ depth -= 1;
38
+ advance();
39
+ advance();
40
+ } else {
41
+ advance();
42
+ }
43
+ }
44
+ continue;
45
+ }
46
+ const raw = source.slice(index).match(/^(?:br|r)(#+)?"/u);
47
+ if (raw) {
48
+ const suffix = `"${raw[1] || ""}`;
49
+ for (let count = 0; count < raw[0].length; count += 1) advance();
50
+ while (index < source.length && !source.startsWith(suffix, index)) {
51
+ advance();
52
+ }
53
+ for (let count = 0; count < suffix.length; count += 1) advance();
54
+ continue;
55
+ }
56
+ if (source[index] === '"' || source.startsWith('b"', index)) {
57
+ if (source[index] === "b") advance();
58
+ advance();
59
+ while (index < source.length) {
60
+ if (source[index] === "\\") {
61
+ advance();
62
+ if (index < source.length) advance();
63
+ } else if (source[index] === '"') {
64
+ advance();
65
+ break;
66
+ } else {
67
+ advance();
68
+ }
69
+ }
70
+ continue;
71
+ }
72
+ const character = source.slice(index).match(/^'(?:\\.|[^'\\\n])'/u);
73
+ if (character) {
74
+ for (let count = 0; count < character[0].length; count += 1) advance();
75
+ continue;
76
+ }
77
+ const identifier = source.slice(index).match(/^[A-Za-z_][A-Za-z0-9_]*/u);
78
+ if (identifier) {
79
+ tokens.push({ value: identifier[0], line });
80
+ index += identifier[0].length;
81
+ continue;
82
+ }
83
+ const operator = [
84
+ "=>",
85
+ "&&",
86
+ "||",
87
+ "::",
88
+ "->",
89
+ "<=",
90
+ ">=",
91
+ "==",
92
+ "!=",
93
+ ].find((candidate) => source.startsWith(candidate, index));
94
+ tokens.push({ value: operator || source[index], line });
95
+ index += (operator || source[index]).length;
96
+ }
97
+ return tokens;
98
+ }
99
+
100
+ function rustFunctions(tokens) {
101
+ const functions = [];
102
+ for (let index = 0; index < tokens.length; index += 1) {
103
+ if (tokens[index].value !== "fn") continue;
104
+ const name =
105
+ tokens[index + 1]?.value || `<anonymous@${tokens[index].line}>`;
106
+ let body = index + 2;
107
+ while (body < tokens.length && !["{", ";"].includes(tokens[body].value)) {
108
+ body += 1;
109
+ }
110
+ if (tokens[body]?.value !== "{") continue;
111
+ let depth = 1;
112
+ let end = body + 1;
113
+ while (end < tokens.length && depth > 0) {
114
+ if (tokens[end].value === "{") depth += 1;
115
+ if (tokens[end].value === "}") depth -= 1;
116
+ end += 1;
117
+ }
118
+ if (depth !== 0) continue;
119
+ functions.push({ name, token: index, body, end: end - 1 });
120
+ }
121
+ return functions;
122
+ }
123
+
124
+ function isRustDecision(tokens, index) {
125
+ const value = tokens[index].value;
126
+ if (["if", "for", "while", "loop", "?", "=>"].includes(value)) return true;
127
+ if (!["&&", "||"].includes(value)) return false;
128
+ return !["=", "(", "{", "[", ",", ";", "return", "move"].includes(
129
+ tokens[index - 1]?.value,
130
+ );
131
+ }
132
+
133
+ function analyzeRust(_file, source) {
134
+ const tokens = rustTokens(source);
135
+ const parsed = rustFunctions(tokens);
136
+ const byStart = new Map(parsed.map((entry) => [entry.token, entry]));
137
+ const functions = parsed.map((entry) => {
138
+ let complexity = 1;
139
+ for (let index = entry.body + 1; index < entry.end; index += 1) {
140
+ const nested = byStart.get(index);
141
+ if (nested && nested.end <= entry.end) {
142
+ index = nested.end;
143
+ continue;
144
+ }
145
+ if (isRustDecision(tokens, index)) complexity += 1;
146
+ }
147
+ const start = tokens[entry.token].line;
148
+ const end = tokens[entry.end].line;
149
+ return {
150
+ name: entry.name,
151
+ start,
152
+ end,
153
+ lines: end - start + 1,
154
+ complexity,
155
+ };
156
+ });
157
+ return {
158
+ lines: lineCount(source),
159
+ complexity: functions.reduce((total, entry) => total + entry.complexity, 0),
160
+ functions,
161
+ };
162
+ }
163
+
164
+ function semanticYamlLines(source) {
165
+ const result = [];
166
+ let blockIndent = null;
167
+ for (const [line, raw] of String(source || "")
168
+ .split(/\r?\n/u)
169
+ .entries()) {
170
+ const indent = raw.match(/^(\s*)/u)?.[1].length || 0;
171
+ if (blockIndent !== null) {
172
+ if (!raw.trim() || indent > blockIndent) continue;
173
+ blockIndent = null;
174
+ }
175
+ const text = raw.trim();
176
+ if (!text || text.startsWith("#")) continue;
177
+ result.push({ line: line + 1, indent, text });
178
+ if (/:\s*[>|][+-]?\s*(?:#.*)?$/u.test(raw)) blockIndent = indent;
179
+ }
180
+ return result;
181
+ }
182
+
183
+ function analyzeWorkflow(_file, source) {
184
+ const lines = semanticYamlLines(source);
185
+ const document = parseWorkflowDocument(source);
186
+ const jobsEntry = lines.find(
187
+ (entry) => entry.indent === 0 && entry.text === "jobs:",
188
+ );
189
+ const jobs = [];
190
+ if (jobsEntry) {
191
+ const candidates = lines.filter(
192
+ (entry) => entry.line > jobsEntry.line && entry.indent > jobsEntry.indent,
193
+ );
194
+ const jobIndent = Math.min(...candidates.map((entry) => entry.indent));
195
+ for (const entry of candidates) {
196
+ if (
197
+ entry.indent === jobIndent &&
198
+ /^[A-Za-z0-9_.-]+:\s*(?:#.*)?$/u.test(entry.text)
199
+ ) {
200
+ jobs.push(entry);
201
+ }
202
+ }
203
+ }
204
+ const stepsByJob = jobs.map((job, jobIndex) => {
205
+ const endLine = jobs[jobIndex + 1]?.line || Number.POSITIVE_INFINITY;
206
+ const stepRoot = lines.find(
207
+ (entry) =>
208
+ entry.line > job.line &&
209
+ entry.line < endLine &&
210
+ entry.indent > job.indent &&
211
+ entry.text === "steps:",
212
+ );
213
+ if (!stepRoot) return 0;
214
+ const stepLines = lines.filter(
215
+ (entry) =>
216
+ entry.line > stepRoot.line &&
217
+ entry.line < endLine &&
218
+ entry.indent > stepRoot.indent,
219
+ );
220
+ const stepIndent = Math.min(...stepLines.map((entry) => entry.indent));
221
+ return stepLines.filter(
222
+ (entry) => entry.indent === stepIndent && entry.text.startsWith("- "),
223
+ ).length;
224
+ });
225
+ const decisions = lines.filter((entry) =>
226
+ /^(?:-\s+)?(?:if|matrix):/u.test(entry.text),
227
+ ).length;
228
+ return {
229
+ lines: lineCount(source),
230
+ jobs: document.jobs.length,
231
+ steps: stepsByJob.reduce((total, count) => total + count, 0),
232
+ maxStepsPerJob: Math.max(0, ...stepsByJob),
233
+ decisions,
234
+ };
235
+ }
236
+
237
+ export { analyzeRust, analyzeWorkflow };