@kungfu-tech/buildchain 3.0.9-alpha.8 → 4.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +39 -0
- package/README.md +17 -13
- package/actions/promote-buildchain-ref/README.md +0 -10
- package/actions/release-tail/README.md +6 -10
- package/architecture/internal-capabilities.json +502 -0
- package/architecture/maintainability-baseline.json +59 -0
- package/architecture/maintainability-policy.json +1384 -0
- package/architecture/release-tail-contract-inventory.json +587 -0
- package/architecture/v3-core-mechanism-inventory.json +1043 -0
- package/architecture/v3-core-mechanism-inventory.md +67 -0
- package/architecture/v4-adopter-delivery-parity.json +47 -0
- package/architecture/v4-architecture-constitution.md +210 -0
- package/architecture/v4-bootstrap-authority.json +56 -0
- package/architecture/v4-canonical-contract-fixtures.json +105 -0
- package/architecture/v4-capability-state-machine-manifest.json +480 -0
- package/architecture/v4-capability-state-machine-manifest.schema.json +202 -0
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +830 -0
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.md +223 -0
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.schema.json +318 -0
- package/architecture/v4-delivery-warrant-shadow-fixtures.json +227 -0
- package/architecture/v4-delivery-warrant-shadow-fixtures.schema.json +67 -0
- package/architecture/v4-exception-ledger.json +5 -0
- package/architecture/v4-exception-ledger.schema.json +56 -0
- package/architecture/v4-partial-mutation-recovery-qualification.json +65 -0
- package/architecture/v4-platform-stage-checkpoints.json +97 -0
- package/architecture/v4-provider-operation-journal-contract.json +113 -0
- package/architecture/v4-release-activation-shadow-domain.json +61 -0
- package/architecture/v4-release-train-parity.json +68 -0
- package/architecture/v4-rust-libnode-bridge-evaluation.json +107 -0
- package/architecture/v4-rust-libnode-bridge-spike.md +85 -0
- package/architecture/v4-stable-publication-fence.json +66 -0
- package/architecture/v4-stage-capsule-contract.json +90 -0
- package/architecture/v4-stage-capsule-qualification.json +99 -0
- package/architecture/v4-stage-capsule-resume-planner.json +52 -0
- package/architecture/v4-stage-capsule-store-contract.json +72 -0
- package/bin/buildchain.mjs +15 -6
- package/contracts/auditable-demo-scenario-v1.schema.json +1 -1
- package/contracts/buildchain-v2-residuals-v1.json +2 -2
- package/contracts/fixtures/v4-delivery-warrant-trace-v1/golden.json +158 -0
- package/contracts/fixtures/v4-delivery-warrant-trace-v1/property.json +380 -0
- package/contracts/fixtures/v4-delivery-warrant-trace-v1/replay.json +163 -0
- package/contracts/fixtures/v4-partial-mutation-recovery-v1/shared.json +155 -0
- package/contracts/fixtures/v4-provider-operation-journal-v1/shared.json +457 -0
- package/contracts/fixtures/v4-provider-readback-idempotency-v1/shared.json +682 -0
- package/contracts/fixtures/v4-release-activation-shadow-v1/shared.json +53 -0
- package/contracts/fixtures/v4-stable-publication-fence-v1/shared.json +56 -0
- package/contracts/fixtures/v4-stage-capsule-resume-v1/late-platform-failure.json +176 -0
- package/contracts/fixtures/v4-stage-capsule-store-v1/shared.json +132 -0
- package/contracts/fixtures/v4-stage-capsule-v1/shared.json +111 -0
- package/contracts/v4-canonical-contracts-v1.schema.json +182 -0
- package/contracts/v4-delivery-warrant-semantic-diff-report-v1.schema.json +284 -0
- package/contracts/v4-delivery-warrant-trace-v1.schema.json +215 -0
- package/contracts/v4-host-contract-v1.schema.json +135 -0
- package/contracts/v4-partial-mutation-recovery-v1.schema.json +168 -0
- package/contracts/v4-provider-operation-journal-v1.schema.json +381 -0
- package/contracts/v4-release-activation-shadow-v1.schema.json +186 -0
- package/contracts/v4-stable-publication-fence-v1.schema.json +125 -0
- package/contracts/v4-stage-capsule-resume-v1.schema.json +225 -0
- package/contracts/v4-stage-capsule-store-v1.schema.json +154 -0
- package/contracts/v4-stage-capsule-v1.schema.json +178 -0
- package/crates/buildchain-v4-bridge/Cargo.lock +213 -0
- package/crates/buildchain-v4-bridge/Cargo.toml +12 -0
- package/crates/buildchain-v4-bridge/src/main.rs +495 -0
- package/dist/site/agent-index.json +0 -3
- package/dist/site/artifact-schemas.json +0 -6
- package/dist/site/buildchain-contract.json +103 -397
- package/dist/site/buildchain-site.json +302 -270
- package/dist/site/capability-registry.json +9 -11
- package/dist/site/cli-registry.json +8 -30
- package/dist/site/controller-registry.json +48 -8
- package/dist/site/kfd-claims.json +129 -142
- package/dist/site/kfd-upstream-aggregate.json +9 -9
- package/dist/site/manual-registry.json +18 -49
- package/dist/site/node-api-registry.json +1882 -4118
- package/dist/site/page-registry.json +278 -230
- package/dist/site/public-surface-audit.json +87 -185
- package/dist/site/publication-authority-registry.json +11 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +3 -7
- package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
- package/dist/site/site-manifest.json +22 -38
- package/dist/site/workflow-registry.json +80 -35
- package/docs/MAP.md +8 -4
- package/docs/auditable-demo.md +2 -2
- package/docs/aws-us-elastic-runner-burst-plane.md +7 -59
- package/docs/cli-reference.md +15 -92
- package/docs/cli.md +14 -14
- package/docs/dev-alpha-candidate-patrol.md +3 -11
- package/docs/dev-delivery-warrant.md +28 -100
- package/docs/engineering-housekeeper.md +12 -4
- package/docs/getting-started.md +1 -1
- package/docs/install.md +5 -5
- package/docs/kfd-support.md +2 -7
- package/docs/lifecycle-protocol.md +2 -4
- package/docs/node-api-reference.md +414 -523
- package/docs/release-flow.md +31 -31
- package/docs/release-governance.md +16 -28
- package/docs/release-passport.md +2 -15
- package/docs/release-tail-contract.md +13 -6
- package/docs/release-tail-provider-plane.md +13 -19
- package/docs/release-train.md +4 -4
- package/docs/reusable-build-surface.md +14 -27
- package/docs/site-bundle-contract.md +1 -5
- package/docs/stable-candidate-patrol.md +7 -7
- package/docs/v4-canonical-contracts.md +92 -0
- package/docs/v4-delivery-warrant-read-candidate.md +73 -0
- package/docs/v4-delivery-warrant-semantic-diff.md +75 -0
- package/docs/v4-production-release.md +63 -0
- package/docs/v4-stage-capsule.md +193 -0
- package/docs/versioning.md +3 -3
- package/package.json +19 -17
- package/packages/core/adopter-delivery-gate.js +576 -0
- package/packages/core/adopter-delivery-json.js +66 -0
- package/packages/core/artifact-signing.js +0 -61
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/build-facts.js +12 -4
- package/packages/core/buildchain-agent-manuals.js +0 -2
- package/packages/core/buildchain-config.js +4 -69
- package/packages/core/buildchain-contract.js +232 -46
- package/packages/core/buildchain-kfd-claims.js +1 -1
- package/packages/core/channel-candidate.js +0 -8
- package/packages/core/channel-promotion-baseline.js +0 -52
- package/packages/core/controller-evidence.js +3 -4
- package/packages/core/dev-alpha-candidate-selection.js +2 -10
- package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
- package/packages/core/dev-delivery-warrant-settlement.js +1 -5
- package/packages/core/dev-delivery-warrant.js +12 -52
- package/packages/core/diagnostics.js +3 -8
- package/packages/core/github-governance-authority.js +3 -1
- package/packages/core/kfd-adopter-category-driver.js +167 -0
- package/packages/core/kfd-adopter-manifest.js +47 -46
- package/packages/core/kfd-gate.js +15 -45
- package/packages/core/paper-agent-entry.js +7 -16
- package/packages/core/paper-fleet.js +2 -2
- package/packages/core/paper-repository.js +2 -3
- package/packages/core/paper-scaffold-content.js +2 -23
- package/packages/core/paper.js +11 -43
- package/packages/core/publication-reproducibility.js +4 -4
- package/packages/core/release-line-bootstrap.js +21 -8
- package/packages/core/release-passport-contract.js +5 -5
- package/packages/core/release-passport.js +20 -131
- package/packages/core/self-dogfood-version.js +48 -35
- package/packages/core/spawn-command.js +232 -8
- package/packages/core/v4-adopter-delivery-parity.js +219 -0
- package/packages/core/v4-canonical-contracts.js +284 -0
- package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
- package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
- package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
- package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
- package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
- package/packages/core/v4-platform-stage-checkpoints.js +471 -0
- package/packages/core/v4-provider-operation-journal.js +531 -0
- package/packages/core/v4-provider-readback-idempotency.js +394 -0
- package/packages/core/v4-release-activation-shadow.js +519 -0
- package/packages/core/v4-stable-publication-fence.js +357 -0
- package/packages/core/v4-stage-capsule-local-store.js +426 -0
- package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
- package/packages/core/v4-stage-capsule-qualification.js +456 -0
- package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
- package/packages/core/v4-stage-capsule-store.js +401 -0
- package/packages/core/v4-stage-capsule.js +319 -0
- package/scripts/assemble-self-publication-admission.mjs +1 -1
- package/scripts/audit-publication-control-plane.mjs +5 -5
- package/scripts/auditable-demo-bundle-verification.mjs +3 -2
- package/scripts/auditable-demo-platform.mjs +2 -2
- package/scripts/auditable-demo-renditions.mjs +1 -1
- package/scripts/auditable-demo.mjs +2 -2
- package/scripts/aws-macos-jit-controller-core.mjs +13 -346
- package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
- package/scripts/aws-macos-jit-controller.mjs +37 -275
- package/scripts/aws-macos-jit-core.mjs +3 -41
- package/scripts/aws-macos-jit.mjs +0 -12
- package/scripts/aws-windows-jit-campaign.mjs +2 -2
- package/scripts/aws-windows-jit-controller-core.mjs +1 -1
- package/scripts/aws-windows-jit-controller.mjs +3 -3
- package/scripts/build-contract-core.mjs +3 -8
- package/scripts/build-standalone-binary.mjs +3 -14
- package/scripts/buildchain-channel-router.mjs +4 -0
- package/scripts/buildchain-cli-help.mjs +7 -13
- package/scripts/buildchain-contract-lock.mjs +0 -6
- package/scripts/check-action-bundles.mjs +3 -4
- package/scripts/check-internal-architecture.mjs +7 -6
- package/scripts/check-inventory.mjs +30 -25
- package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
- package/scripts/create-release-bundle.mjs +8 -4
- package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
- package/scripts/dev-delivery-proof.mjs +2 -54
- package/scripts/dev-delivery-warrant.mjs +59 -77
- package/scripts/dev-pr-auto-merge.mjs +4 -30
- package/scripts/dev-pr-delivery-warrant.mjs +0 -55
- package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
- package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
- package/scripts/generate-channel-build-workflow.mjs +54 -24
- package/scripts/generate-channel-promotion-workflow.mjs +15 -6
- package/scripts/generate-site-bundle.mjs +5 -21
- package/scripts/git-fetch-process-tree.mjs +34 -1
- package/scripts/init-repo.mjs +64 -159
- package/scripts/inspect-artifact-signing-requests.mjs +0 -6
- package/scripts/locked-source-checkout.mjs +3 -4
- package/scripts/maintainability-metrics.mjs +8 -2
- package/scripts/npm-publish-dry-run.mjs +2 -2
- package/scripts/npm-publish-transaction.mjs +2 -2
- package/scripts/publication-commit-evidence.mjs +23 -69
- package/scripts/release-candidate-resolver.mjs +11 -17
- package/scripts/release-tail.mjs +3 -49
- package/scripts/resume-from-candidate-run.mjs +9 -123
- package/scripts/run-lifecycle-core.mjs +12 -13
- package/scripts/seal-artifact-signing-requests.mjs +17 -21
- package/scripts/site-capability-metadata.mjs +2 -7
- package/scripts/stable-candidate-qualification.mjs +10 -10
- package/scripts/v4-architecture.mjs +12 -2
- package/scripts/v4-bridge-bootstrap.mjs +141 -0
- package/scripts/v4-bridge-evidence.mjs +141 -0
- package/scripts/v4-host-adapter.mjs +182 -0
- package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
- package/scripts/v4-stage-capsule-qualification.mjs +528 -0
- package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
- package/scripts/v4-warrant-shadow-plan.mjs +601 -0
- package/scripts/verify-golden-path.mjs +5 -5
- package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
- package/scripts/web-surface-core.mjs +2 -8
- package/scripts/workflow-call-contract.mjs +5 -184
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
- package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
- package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
- package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
- package/contracts/next-development-request-v1.schema.json +0 -66
- package/contracts/next-development-transition-v1.schema.json +0 -292
- package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
- package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
- package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
- package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
- package/docs/next-development-transition.md +0 -119
- package/docs/publication-rehearsal.md +0 -94
- package/packages/core/buildchain-compatibility-proof.js +0 -631
- package/packages/core/dev-delivery-native-proof.js +0 -333
- package/packages/core/dev-delivery-warrant-shadow.js +0 -502
- package/packages/core/next-development-candidate-reservation.js +0 -186
- package/packages/core/next-development-controller.js +0 -726
- package/packages/core/next-development-projection.js +0 -288
- package/packages/core/next-development-transition.js +0 -738
- package/packages/core/publication-rehearsal-projection.js +0 -173
- package/packages/core/publication-rehearsal-runtime.js +0 -921
- package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
- package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
- package/scripts/dev-delivery-native-run.mjs +0 -187
- package/scripts/dev-delivery-two-phase.mjs +0 -598
- package/scripts/generate-next-development-guidance.mjs +0 -49
- package/scripts/materialize-self-release-candidate-version.mjs +0 -137
- package/scripts/next-development-self-dogfood-harness.mjs +0 -409
- package/scripts/next-development-self-dogfood.mjs +0 -532
- package/scripts/next-development-transition.mjs +0 -47
- package/scripts/release-candidate-tail-reseal.mjs +0 -426
- package/templates/native-dev-delivery.yml +0 -82
|
@@ -97,14 +97,6 @@ export function decideChannelCandidate(input) {
|
|
|
97
97
|
const sourceSha = sha(input.sourceSha, "sourceSha");
|
|
98
98
|
const targetSha = sha(input.targetSha, "targetSha");
|
|
99
99
|
const selection = normalizeChannelCandidateSelection(input.selection);
|
|
100
|
-
if (
|
|
101
|
-
selection?.versionReservation &&
|
|
102
|
-
selection.versionReservation.candidateSha !== sourceSha
|
|
103
|
-
) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
"selection version reservation must bind the selected source SHA",
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
100
|
const now = required(input.now || new Date().toISOString(), "now");
|
|
109
101
|
const maxAgeSeconds = Number(input.maxAgeSeconds ?? 7 * 24 * 60 * 60);
|
|
110
102
|
if (!Number.isSafeInteger(maxAgeSeconds) || maxAgeSeconds <= 0) {
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
nextDevelopmentPatrolContext,
|
|
5
|
-
normalizeNextDevelopmentVersionReservation,
|
|
6
|
-
} from "./next-development-candidate-reservation.js";
|
|
7
|
-
|
|
8
3
|
const SHA = /^[0-9a-f]{40}$/;
|
|
9
4
|
|
|
10
5
|
function text(value = "") {
|
|
@@ -64,18 +59,6 @@ export function normalizeChannelCandidateSelection(input) {
|
|
|
64
59
|
),
|
|
65
60
|
}
|
|
66
61
|
: {}),
|
|
67
|
-
...(input.versionReservation
|
|
68
|
-
? {
|
|
69
|
-
versionReservation: normalizeNextDevelopmentVersionReservation(
|
|
70
|
-
input.versionReservation,
|
|
71
|
-
{
|
|
72
|
-
reservationSha: input.versionReservation.reservationSha,
|
|
73
|
-
candidateSha: input.versionReservation.candidateSha,
|
|
74
|
-
targetVersion: input.versionReservation.targetVersion,
|
|
75
|
-
},
|
|
76
|
-
),
|
|
77
|
-
}
|
|
78
|
-
: {}),
|
|
79
62
|
};
|
|
80
63
|
}
|
|
81
64
|
|
|
@@ -134,7 +117,6 @@ export async function resolvePatrolSourceInputs({
|
|
|
134
117
|
let comparison = headComparison;
|
|
135
118
|
let workflowEvidence = [];
|
|
136
119
|
let skippedNewerCommitCount = 0;
|
|
137
|
-
let versionReservation;
|
|
138
120
|
let qualificationError;
|
|
139
121
|
if (
|
|
140
122
|
headComparison.status === "ahead" &&
|
|
@@ -148,8 +130,6 @@ export async function resolvePatrolSourceInputs({
|
|
|
148
130
|
),
|
|
149
131
|
]);
|
|
150
132
|
try {
|
|
151
|
-
const { preparations, ignoredSourceShas } =
|
|
152
|
-
nextDevelopmentPatrolContext(sourceHistory);
|
|
153
133
|
const selected = selectQualifiedSource({
|
|
154
134
|
sourceHistory,
|
|
155
135
|
workflowRunsByPath: new Map(
|
|
@@ -161,39 +141,8 @@ export async function resolvePatrolSourceInputs({
|
|
|
161
141
|
requiredWorkflowPaths,
|
|
162
142
|
now: options.now,
|
|
163
143
|
maxAgeSeconds: options.maxAgeSeconds,
|
|
164
|
-
ignoredSourceShas,
|
|
165
144
|
});
|
|
166
145
|
({ sourceSha, skippedNewerCommitCount, workflowEvidence } = selected);
|
|
167
|
-
const selectedIndex = sourceHistory.findIndex((entry) =>
|
|
168
|
-
(typeof entry === "string" ? entry : entry?.sha) === sourceSha,
|
|
169
|
-
);
|
|
170
|
-
const reservation = preparations.find(
|
|
171
|
-
({ index }) => index > selectedIndex,
|
|
172
|
-
)?.preparation;
|
|
173
|
-
if (reservation) {
|
|
174
|
-
if (typeof client.readNextDevelopmentVersionReservation !== "function") {
|
|
175
|
-
throw new Error(
|
|
176
|
-
"candidate follows next-development preparation but reservation readback is unavailable",
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
versionReservation = normalizeNextDevelopmentVersionReservation(
|
|
180
|
-
await client.readNextDevelopmentVersionReservation({
|
|
181
|
-
reservationSha: reservation.sha,
|
|
182
|
-
candidateSha: sourceSha,
|
|
183
|
-
targetVersion: reservation.targetVersion,
|
|
184
|
-
}),
|
|
185
|
-
{
|
|
186
|
-
reservationSha: reservation.sha,
|
|
187
|
-
candidateSha: sourceSha,
|
|
188
|
-
targetVersion: reservation.targetVersion,
|
|
189
|
-
},
|
|
190
|
-
);
|
|
191
|
-
if (versionReservation.status !== "current") {
|
|
192
|
-
throw new Error(
|
|
193
|
-
`next-development version reservation is ${versionReservation.status} for candidate ${sourceSha}`,
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
146
|
if (sourceSha !== observedSourceHeadSha)
|
|
198
147
|
comparison = await client.compare(boundarySha, sourceSha);
|
|
199
148
|
} catch (error) {
|
|
@@ -209,7 +158,6 @@ export async function resolvePatrolSourceInputs({
|
|
|
209
158
|
comparison,
|
|
210
159
|
workflowEvidence,
|
|
211
160
|
skippedNewerCommitCount,
|
|
212
|
-
versionReservation,
|
|
213
161
|
qualificationError,
|
|
214
162
|
};
|
|
215
163
|
}
|
|
@@ -34,14 +34,13 @@ const CONTROLLER_SPECS = [
|
|
|
34
34
|
"resolve-runtime",
|
|
35
35
|
"resolve-source",
|
|
36
36
|
"anchored-release-preflight",
|
|
37
|
-
"pre-build-contracts",
|
|
38
37
|
"build",
|
|
39
38
|
"signing-finalization",
|
|
40
39
|
"credential-island",
|
|
41
40
|
"verify",
|
|
42
41
|
"aggregate",
|
|
43
42
|
],
|
|
44
|
-
optionalStages: ["anchored-release-preflight", "
|
|
43
|
+
optionalStages: ["anchored-release-preflight", "credential-island"],
|
|
45
44
|
evidence: [
|
|
46
45
|
"platform-manifests",
|
|
47
46
|
"build-summary",
|
|
@@ -53,8 +52,8 @@ const CONTROLLER_SPECS = [
|
|
|
53
52
|
workflowId: "build",
|
|
54
53
|
version: 1,
|
|
55
54
|
capabilities: ["channel-selection", "runtime-selection", "build-delegation"],
|
|
56
|
-
stages: ["resolve-channel", "alpha", "stable", "aggregate"],
|
|
57
|
-
optionalStages: ["alpha", "stable"],
|
|
55
|
+
stages: ["resolve-channel", "override", "alpha", "stable", "aggregate"],
|
|
56
|
+
optionalStages: ["override", "alpha", "stable"],
|
|
58
57
|
evidence: ["nested-controller-receipt", "controller-receipt"],
|
|
59
58
|
},
|
|
60
59
|
{
|
|
@@ -82,9 +82,7 @@ export function selectLatestQualifiedSource({
|
|
|
82
82
|
requiredWorkflowPaths,
|
|
83
83
|
now,
|
|
84
84
|
maxAgeSeconds,
|
|
85
|
-
ignoredSourceShas = [],
|
|
86
85
|
}) {
|
|
87
|
-
const ignored = new Set(ignoredSourceShas);
|
|
88
86
|
const latestByPath = new Map(
|
|
89
87
|
requiredWorkflowPaths.map((workflow) => [
|
|
90
88
|
workflow,
|
|
@@ -92,11 +90,7 @@ export function selectLatestQualifiedSource({
|
|
|
92
90
|
]),
|
|
93
91
|
);
|
|
94
92
|
for (let index = 0; index < sourceHistory.length; index += 1) {
|
|
95
|
-
const sourceSha =
|
|
96
|
-
typeof sourceHistory[index] === "string"
|
|
97
|
-
? sourceHistory[index]
|
|
98
|
-
: sourceHistory[index]?.sha;
|
|
99
|
-
if (ignored.has(sourceSha)) continue;
|
|
93
|
+
const sourceSha = sourceHistory[index];
|
|
100
94
|
const rows = requiredWorkflowPaths.map((workflow) =>
|
|
101
95
|
latestByPath.get(workflow).get(sourceSha),
|
|
102
96
|
);
|
|
@@ -121,9 +115,7 @@ export function selectLatestQualifiedSource({
|
|
|
121
115
|
};
|
|
122
116
|
}
|
|
123
117
|
}
|
|
124
|
-
const staleSuccessfulPair = sourceHistory.some((
|
|
125
|
-
const sourceSha = typeof entry === "string" ? entry : entry?.sha;
|
|
126
|
-
if (ignored.has(sourceSha)) return false;
|
|
118
|
+
const staleSuccessfulPair = sourceHistory.some((sourceSha) => {
|
|
127
119
|
const rows = requiredWorkflowPaths.map((workflow) =>
|
|
128
120
|
latestByPath.get(workflow).get(sourceSha),
|
|
129
121
|
);
|
|
@@ -33,11 +33,7 @@ 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
|
|
37
|
-
const activeCandidate = queue.activeWarrant
|
|
38
|
-
? matchingHead.find((entry) => entry.candidateId === queue.activeWarrant.candidateId)
|
|
39
|
-
: null;
|
|
40
|
-
const candidate = activeCandidate || matchingHead.at(-1) || null;
|
|
36
|
+
const candidate = samePullRequest.find((entry) => entry.sourceHead === identity.sourceHead) || null;
|
|
41
37
|
if (!candidate && samePullRequest.length > 0) throw new Error("terminal event sourceHead does not match the recorded candidate");
|
|
42
38
|
|
|
43
39
|
if (candidate && terminalStates.has(candidate.status)) {
|
|
@@ -2,12 +2,10 @@ import { devDeliveryClone as clone, devDeliveryContentRoot, devDeliveryExactRoot
|
|
|
2
2
|
import { chainedDevDeliveryAttemptInput, createDevDeliveryCandidateIdentity, validateDevDeliveryCandidateChain } from "./dev-delivery-candidate-identity.js";
|
|
3
3
|
import { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA, createCancelQueuedDevDeliveryCandidate } from "./dev-delivery-warrant-cancellation.js";
|
|
4
4
|
import { DEV_DELIVERY_SETTLEMENT_RECEIPT_SCHEMA, createDevDeliveryTerminalSettler } from "./dev-delivery-warrant-settlement.js";
|
|
5
|
-
import { createDevDeliveryWarrantQualifier } from "./dev-delivery-native-proof.js";
|
|
6
5
|
import { compareReleaseBlockerPriority, normalizeReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
|
|
7
6
|
export { devDeliveryContentRoot } from "./dev-delivery-common.js";
|
|
8
7
|
export { RELEASE_BLOCKER_PRIORITY_CLAIM_SCHEMA, createReleaseBlockerPriorityClaim } from "./release-blocker-priority.js";
|
|
9
8
|
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";
|
|
11
9
|
export { DEV_DELIVERY_CANCELLATION_RECEIPT_SCHEMA };
|
|
12
10
|
export const DEV_DELIVERY_QUEUE_CONTRACT = "kungfu-buildchain-dev-delivery-warrant-queue";
|
|
13
11
|
export const DEV_DELIVERY_WARRANT_SCHEMA = "kungfu.buildchain.dev-delivery-warrant/v1";
|
|
@@ -61,7 +59,7 @@ function normalizeCandidate(input, expected) {
|
|
|
61
59
|
throw new Error(`candidateId mismatch for PR #${identity.pullRequestNumber}`);
|
|
62
60
|
}
|
|
63
61
|
const status = text(input.status || "queued");
|
|
64
|
-
if (!["queued", "selected", "
|
|
62
|
+
if (!["queued", "selected", "proving", "waiting", "blocked", ...TERMINAL_STATES].includes(status)) {
|
|
65
63
|
throw new Error(`unsupported candidate status ${status || "<empty>"}`);
|
|
66
64
|
}
|
|
67
65
|
const candidate = {
|
|
@@ -73,7 +71,6 @@ function normalizeCandidate(input, expected) {
|
|
|
73
71
|
closureRoot: exactRoot(input.closureRoot, "closureRoot"),
|
|
74
72
|
dependencyRoot: exactRoot(input.dependencyRoot, "dependencyRoot"),
|
|
75
73
|
toolchainRoot: exactRoot(input.toolchainRoot, "toolchainRoot"),
|
|
76
|
-
...(Object.hasOwn(input, "sourceWorkflowRunId") ? { sourceWorkflowRunId: nonNegativeInteger(input.sourceWorkflowRunId, "candidate sourceWorkflowRunId", 0) } : {}),
|
|
77
74
|
priority: priority(input.priority),
|
|
78
75
|
enqueuedAt: timestamp(input.enqueuedAt, "candidate enqueuedAt"),
|
|
79
76
|
updatedAt: timestamp(input.updatedAt || input.enqueuedAt, "candidate updatedAt"),
|
|
@@ -82,10 +79,6 @@ function normalizeCandidate(input, expected) {
|
|
|
82
79
|
status,
|
|
83
80
|
terminal: input.terminal || null,
|
|
84
81
|
};
|
|
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
|
-
}
|
|
89
82
|
if (Object.hasOwn(input, "releaseBlockerPriority")) candidate.releaseBlockerPriority = normalizeReleaseBlockerPriorityClaim(input.releaseBlockerPriority, candidate, expected);
|
|
90
83
|
return candidate;
|
|
91
84
|
}
|
|
@@ -146,20 +139,12 @@ export function normalizeDevDeliveryQueue(input, expected = {}) {
|
|
|
146
139
|
warrant.generation = positiveInteger(warrant.generation, "Warrant generation");
|
|
147
140
|
warrant.issuedAt = timestamp(warrant.issuedAt, "Warrant issuedAt");
|
|
148
141
|
warrant.expiresAt = timestamp(warrant.expiresAt, "Warrant expiresAt");
|
|
149
|
-
const
|
|
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));
|
|
142
|
+
const activeCandidates = queue.candidates.filter((candidate) => ["selected", "proving", "waiting", "blocked"].includes(candidate.status));
|
|
158
143
|
if (activeCandidates.length !== 1 || activeCandidates[0].candidateId !== warrant.candidateId) {
|
|
159
144
|
throw new Error("exactly one active candidate must match the active Warrant");
|
|
160
145
|
}
|
|
161
146
|
if (warrant.releaseBlockerPriority?.claimRoot !== activeCandidates[0].releaseBlockerPriority?.claimRoot) throw new Error("active Warrant release-blocker priority drift");
|
|
162
|
-
} else if (queue.candidates.some((candidate) => ["selected", "
|
|
147
|
+
} else if (queue.candidates.some((candidate) => ["selected", "proving", "waiting", "blocked"].includes(candidate.status))) {
|
|
163
148
|
throw new Error("active candidate exists without an active Warrant");
|
|
164
149
|
}
|
|
165
150
|
const rooted = withQueueRoot(queue);
|
|
@@ -198,7 +183,6 @@ function submissionReceipt({ before, after, candidate, action, now }) {
|
|
|
198
183
|
closureRoot: candidate.closureRoot,
|
|
199
184
|
dependencyRoot: candidate.dependencyRoot,
|
|
200
185
|
toolchainRoot: candidate.toolchainRoot,
|
|
201
|
-
...(Object.hasOwn(candidate, "affectedPaths") ? { affectedPaths: candidate.affectedPaths } : {}),
|
|
202
186
|
sourceWorkflowRunId: candidate.sourceWorkflowRunId,
|
|
203
187
|
...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
|
|
204
188
|
deliveryClass: candidate.deliveryClass,
|
|
@@ -240,24 +224,17 @@ export function submitDevDeliveryCandidate(queueInput, input, { now = new Date()
|
|
|
240
224
|
throw new Error(`candidate ${attemptedCandidate.candidateId} is terminal and cannot be resubmitted`);
|
|
241
225
|
}
|
|
242
226
|
const exactProofFields = ["sourcePatchRoot", "sourceProofRoot", "planRoot", "closureRoot", "dependencyRoot", "toolchainRoot"];
|
|
243
|
-
const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]) &&
|
|
227
|
+
const exactProofMatches = exactProofFields.every((field) => existing[field] === attemptedCandidate[field]) && existing.releaseBlockerPriority?.claimRoot === attemptedCandidate.releaseBlockerPriority?.claimRoot;
|
|
244
228
|
if (existing.sourceHead === attemptedCandidate.sourceHead && exactProofMatches) {
|
|
245
229
|
action = "duplicate-noop";
|
|
246
230
|
selected = existing;
|
|
247
231
|
} else {
|
|
248
232
|
if (before.activeWarrant?.candidateId === existing.candidateId) {
|
|
249
|
-
|
|
250
|
-
throw new Error("selected candidate sourceHead cannot change before terminal Warrant closeout");
|
|
251
|
-
}
|
|
252
|
-
action = "active-warrant-retained-noop";
|
|
253
|
-
selected = existing;
|
|
254
|
-
return { candidate: selected, action };
|
|
233
|
+
throw new Error("selected candidate sourceHead cannot change before terminal Warrant closeout");
|
|
255
234
|
}
|
|
256
235
|
const headChanged = existing.sourceHead !== attemptedCandidate.sourceHead;
|
|
257
236
|
existing.sourceHead = attemptedCandidate.sourceHead;
|
|
258
237
|
for (const field of exactProofFields) existing[field] = attemptedCandidate[field];
|
|
259
|
-
if (Object.hasOwn(attemptedCandidate, "affectedPaths")) existing.affectedPaths = attemptedCandidate.affectedPaths;
|
|
260
|
-
else delete existing.affectedPaths;
|
|
261
238
|
if (Object.hasOwn(attemptedCandidate, "releaseBlockerPriority")) existing.releaseBlockerPriority = attemptedCandidate.releaseBlockerPriority;
|
|
262
239
|
else delete existing.releaseBlockerPriority;
|
|
263
240
|
existing.updatedAt = currentTime;
|
|
@@ -342,7 +319,7 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
|
|
|
342
319
|
candidateId: queue.activeWarrant.candidateId,
|
|
343
320
|
fencingToken: queue.activeWarrant.fencingToken,
|
|
344
321
|
leaseGeneration: queue.activeWarrant.generation,
|
|
345
|
-
expectedOldStateRoot:
|
|
322
|
+
expectedOldStateRoot: queue.stateRoot,
|
|
346
323
|
nextStateRoot: queue.stateRoot,
|
|
347
324
|
nextAction: "Continue the active delivery attempt; later candidates remain visibly queued.",
|
|
348
325
|
};
|
|
@@ -396,17 +373,15 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
|
|
|
396
373
|
closureRoot: candidate.closureRoot,
|
|
397
374
|
dependencyRoot: candidate.dependencyRoot,
|
|
398
375
|
toolchainRoot: candidate.toolchainRoot,
|
|
399
|
-
...(Object.hasOwn(candidate, "affectedPaths") ? { affectedPaths: candidate.affectedPaths } : {}),
|
|
400
376
|
sourceWorkflowRunId: candidate.sourceWorkflowRunId,
|
|
401
377
|
...(Object.hasOwn(candidate, "releaseBlockerPriority") ? { releaseBlockerPriority: candidate.releaseBlockerPriority } : {}),
|
|
402
378
|
deliveryClass: candidate.deliveryClass,
|
|
403
379
|
generation: next.fencingCounter,
|
|
404
|
-
phase: "provisional",
|
|
405
380
|
expectedOldStateRoot: before.stateRoot,
|
|
406
381
|
issuedAt,
|
|
407
382
|
expiresAt: new Date(Date.parse(issuedAt) + effectiveLeaseSeconds * 1000).toISOString(),
|
|
408
383
|
fencingToken: "",
|
|
409
|
-
nextAction: "
|
|
384
|
+
nextAction: "Replay on the exact current dev base, prove required checks, then enqueue the unchanged PR head.",
|
|
410
385
|
};
|
|
411
386
|
warrant.fencingToken = warrantToken(warrant);
|
|
412
387
|
next.activeWarrant = warrant;
|
|
@@ -443,7 +418,7 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
|
|
|
443
418
|
effectivePriority: selected.priority.score,
|
|
444
419
|
fencingToken: transaction.result.warrant.fencingToken,
|
|
445
420
|
leaseGeneration: transaction.result.warrant.generation,
|
|
446
|
-
expectedOldStateRoot:
|
|
421
|
+
expectedOldStateRoot: transaction.expectedOldStateRoot,
|
|
447
422
|
nextStateRoot: transaction.after.stateRoot,
|
|
448
423
|
nextAction: transaction.result.warrant.nextAction,
|
|
449
424
|
};
|
|
@@ -456,12 +431,12 @@ export function selectDevDeliveryWarrant(queueInput, { now = new Date().toISOStr
|
|
|
456
431
|
};
|
|
457
432
|
}
|
|
458
433
|
|
|
459
|
-
function assertWarrantMutation(queue, warrant, now
|
|
434
|
+
function assertWarrantMutation(queue, warrant, now) {
|
|
460
435
|
if (!queue.activeWarrant) throw new Error("no active Delivery Warrant");
|
|
461
436
|
if (text(warrant?.fencingToken) !== queue.activeWarrant.fencingToken) throw new Error("stale fencing token");
|
|
462
437
|
if (Number(warrant?.generation) !== queue.activeWarrant.generation) throw new Error("stale lease generation");
|
|
463
438
|
if (text(warrant?.candidateId) !== queue.activeWarrant.candidateId) throw new Error("Warrant candidate mismatch");
|
|
464
|
-
if (
|
|
439
|
+
if (Date.parse(queue.activeWarrant.expiresAt) <= Date.parse(now)) throw new Error("Delivery Warrant lease expired");
|
|
465
440
|
}
|
|
466
441
|
|
|
467
442
|
export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Date().toISOString(), leaseSeconds } = {}) {
|
|
@@ -473,7 +448,7 @@ export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Dat
|
|
|
473
448
|
const effectiveLeaseSeconds = positiveInteger(leaseSeconds, "leaseSeconds", queue.policy.leaseSeconds);
|
|
474
449
|
queue.activeWarrant.expiresAt = new Date(Date.parse(currentTime) + effectiveLeaseSeconds * 1000).toISOString();
|
|
475
450
|
const candidate = queue.candidates.find((entry) => entry.candidateId === queue.activeWarrant.candidateId);
|
|
476
|
-
candidate.status =
|
|
451
|
+
candidate.status = "proving";
|
|
477
452
|
candidate.updatedAt = currentTime;
|
|
478
453
|
return { candidate, warrant: queue.activeWarrant };
|
|
479
454
|
},
|
|
@@ -497,8 +472,6 @@ export function heartbeatDevDeliveryWarrant(queueInput, warrant, { now = new Dat
|
|
|
497
472
|
};
|
|
498
473
|
}
|
|
499
474
|
|
|
500
|
-
const qualifyDevDeliveryWarrantTransition = createDevDeliveryWarrantQualifier({ transition, assertWarrantMutation });
|
|
501
|
-
export function qualifyDevDeliveryWarrant(queueInput, warrant, options) { return qualifyDevDeliveryWarrantTransition(queueInput, warrant, options); }
|
|
502
475
|
export function recoverExpiredDevDeliveryWarrant(queueInput, { now = new Date().toISOString() } = {}) {
|
|
503
476
|
const currentTime = timestamp(now, "now");
|
|
504
477
|
const before = normalizeDevDeliveryQueue(queueInput);
|
|
@@ -558,7 +531,7 @@ export function closeDevDeliveryWarrant(queueInput, warrant, { outcome, evidence
|
|
|
558
531
|
const transaction = transition(
|
|
559
532
|
queueInput,
|
|
560
533
|
(queue, before) => {
|
|
561
|
-
assertWarrantMutation(before, warrant, currentTime
|
|
534
|
+
assertWarrantMutation(before, warrant, currentTime);
|
|
562
535
|
const active = clone(queue.activeWarrant);
|
|
563
536
|
const candidate = queue.candidates.find((entry) => entry.candidateId === active.candidateId);
|
|
564
537
|
candidate.status = normalizedOutcome;
|
|
@@ -625,19 +598,6 @@ export function observeDevDeliveryQueue(queueInput, { now = new Date().toISOStri
|
|
|
625
598
|
queueAgeSeconds: entry.priority.ageSeconds,
|
|
626
599
|
attempts: entry.candidate.attempts,
|
|
627
600
|
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,
|
|
641
601
|
nextAction: index === 0 && !queue.activeWarrant ? "eligible-for-selection" : "wait-for-active-warrant",
|
|
642
602
|
})),
|
|
643
603
|
observedAt: currentTime,
|
|
@@ -84,14 +84,10 @@ function fileStats(cwd, entries = []) {
|
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
function commandVersion(command, args = ["--version"]) {
|
|
87
|
+
function commandVersion(command, args = ["--version"], cwd = process.cwd()) {
|
|
90
88
|
try {
|
|
91
89
|
return execFileSync(command, args, {
|
|
92
|
-
|
|
93
|
-
// bounded instead of scanning an arbitrary consumer or shared temp root.
|
|
94
|
-
cwd: TOOL_VERSION_PROBE_CWD,
|
|
90
|
+
cwd,
|
|
95
91
|
encoding: "utf8",
|
|
96
92
|
stdio: ["ignore", "pipe", "ignore"],
|
|
97
93
|
timeout: 5000,
|
|
@@ -497,8 +493,7 @@ export function collectRunnerDiagnostics() {
|
|
|
497
493
|
}
|
|
498
494
|
|
|
499
495
|
export function collectToolDiagnostics({ cwd = process.cwd(), tools = ["node", "pnpm", "npm", "git", "cmake", "ninja", "ccache", "sccache"] } = {}) {
|
|
500
|
-
|
|
501
|
-
return Object.fromEntries(tools.map((tool) => [tool, { version: commandVersion(tool) }]));
|
|
496
|
+
return Object.fromEntries(tools.map((tool) => [tool, { version: commandVersion(tool, ["--version"], cwd) }]));
|
|
502
497
|
}
|
|
503
498
|
|
|
504
499
|
function parseJsonDiagnostics(value = "") {
|
|
@@ -54,9 +54,11 @@ const PUBLIC_REPOSITORY_TARGETS = Object.freeze({
|
|
|
54
54
|
target("publish-gate/major", [check("check")], true),
|
|
55
55
|
],
|
|
56
56
|
buildchain: [
|
|
57
|
-
|
|
57
|
+
...["v3/v3.0", "v4/v4.0"].map((line) => target(`dev/${line}`, [check("check")], false)),
|
|
58
58
|
target("alpha/v3/v3.0", [check("check"), check("verify")], false),
|
|
59
59
|
target("release/v3/v3.0", [check("check")], true),
|
|
60
|
+
target("alpha/v4/v4.0", [check("check"), check("verify")], false),
|
|
61
|
+
target("release/v4/v4.0", [check("check"), check("verify")], true),
|
|
60
62
|
target("authority/v3/v3.0/artifact-signing", [check("check"), check("verify")], true),
|
|
61
63
|
target("publish-gate/major", [check("check")], true),
|
|
62
64
|
],
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import kfdCategoryCatalog from "@kungfu-tech/kfd/adopter-conformance/category-profiles.json" with { type: "json" };
|
|
2
|
+
import kfdPackageJson from "@kungfu-tech/kfd/package.json" with { type: "json" };
|
|
3
|
+
import { resolveAdopterCategoryProfiles } from "@kungfu-tech/kfd/adopter-conformance/category-profile-resolver";
|
|
4
|
+
import { verifyAdopterCategoryInstanceManifest } from "@kungfu-tech/kfd/adopter-conformance/category-instance-verifier";
|
|
5
|
+
import { verifyAdopterManifestFromPackage } from "@kungfu-tech/kfd/adopter-conformance/toolchain";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ADOPTER_PROTOCOL_DRIVER_INTERFACE,
|
|
9
|
+
adopterDeliveryGateDigest,
|
|
10
|
+
defineAdopterProtocolDriver,
|
|
11
|
+
} from "./adopter-delivery-gate.js";
|
|
12
|
+
|
|
13
|
+
export const KFD_ADOPTER_CATEGORY_PROTOCOL_ID =
|
|
14
|
+
"kfd.adopter-category/instance-manifest";
|
|
15
|
+
export const KFD_ADOPTER_CATEGORY_PROTOCOL_VERSION = "1.0.0";
|
|
16
|
+
export const KFD_ADOPTER_CATEGORY_DRIVER_REPORT_CONTRACT =
|
|
17
|
+
"kungfu-buildchain-kfd-adopter-category-driver-report";
|
|
18
|
+
|
|
19
|
+
function freezeJson(value) {
|
|
20
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
21
|
+
Object.freeze(value);
|
|
22
|
+
for (const child of Object.values(value)) freezeJson(child);
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const publishedCatalog = freezeJson(structuredClone(kfdCategoryCatalog));
|
|
28
|
+
|
|
29
|
+
function catalogCopy() {
|
|
30
|
+
return structuredClone(publishedCatalog);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function sameJson(left, right) {
|
|
34
|
+
try {
|
|
35
|
+
return adopterDeliveryGateDigest(left) === adopterDeliveryGateDigest(right);
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function issue(code, path, message) {
|
|
42
|
+
return { code, path, message };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function resolvePublishedKfdAdopterCategoryProfiles(selection) {
|
|
46
|
+
return resolveAdopterCategoryProfiles(
|
|
47
|
+
structuredClone(selection),
|
|
48
|
+
catalogCopy(),
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function verifyPublishedKfdAdopterCategoryInstance(
|
|
53
|
+
instanceManifest,
|
|
54
|
+
{ adopterManifest, verifiedAt, maxAgeSeconds } = {},
|
|
55
|
+
) {
|
|
56
|
+
const adopterReport = verifyAdopterManifestFromPackage(adopterManifest, {
|
|
57
|
+
packageArtifactRoot: instanceManifest?.kfdCut?.packageRoot,
|
|
58
|
+
verifiedAt,
|
|
59
|
+
maxAgeSeconds,
|
|
60
|
+
});
|
|
61
|
+
return verifyAdopterCategoryInstanceManifest(instanceManifest, {
|
|
62
|
+
catalog: catalogCopy(),
|
|
63
|
+
adopterManifest,
|
|
64
|
+
adopterReport,
|
|
65
|
+
verifiedAt,
|
|
66
|
+
maxAgeSeconds,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function deliveryBindingIssues(request, adopterManifest) {
|
|
71
|
+
const instance = request.declaration;
|
|
72
|
+
const issues = [];
|
|
73
|
+
if (
|
|
74
|
+
request.project.instanceId !== instance?.instanceId ||
|
|
75
|
+
request.project.adopterId !== instance?.project?.adopterId
|
|
76
|
+
) {
|
|
77
|
+
issues.push(
|
|
78
|
+
issue(
|
|
79
|
+
"delivery-kfd-instance-binding-mismatch",
|
|
80
|
+
"/project",
|
|
81
|
+
"Delivery project identity must match the KFD category instance.",
|
|
82
|
+
),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (!sameJson(request.artifact, instance?.project?.artifact)) {
|
|
86
|
+
issues.push(
|
|
87
|
+
issue(
|
|
88
|
+
"delivery-kfd-instance-binding-mismatch",
|
|
89
|
+
"/artifact",
|
|
90
|
+
"Delivery artifact must match the KFD category instance artifact.",
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (
|
|
95
|
+
adopterManifest?.kfdCut?.package?.name !== kfdPackageJson.name ||
|
|
96
|
+
adopterManifest?.kfdCut?.package?.version !== kfdPackageJson.version ||
|
|
97
|
+
instance?.kfdCut?.packageVersion !== kfdPackageJson.version
|
|
98
|
+
) {
|
|
99
|
+
issues.push(
|
|
100
|
+
issue(
|
|
101
|
+
"delivery-kfd-package-cut-mismatch",
|
|
102
|
+
"/declaration/kfdCut",
|
|
103
|
+
"KFD declarations must bind the exact installed published package version.",
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return issues;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function driverReport(categoryReport, adapterIssues) {
|
|
111
|
+
const valid = categoryReport?.valid === true && adapterIssues.length === 0;
|
|
112
|
+
const report = {
|
|
113
|
+
schemaVersion: 1,
|
|
114
|
+
contract: KFD_ADOPTER_CATEGORY_DRIVER_REPORT_CONTRACT,
|
|
115
|
+
valid,
|
|
116
|
+
conforming: valid,
|
|
117
|
+
qualifying: false,
|
|
118
|
+
selfCertified: false,
|
|
119
|
+
independentlyCertified: false,
|
|
120
|
+
kfdPackage: {
|
|
121
|
+
name: kfdPackageJson.name,
|
|
122
|
+
version: kfdPackageJson.version,
|
|
123
|
+
},
|
|
124
|
+
categoryReport,
|
|
125
|
+
adapterIssues,
|
|
126
|
+
nonClaims: [
|
|
127
|
+
"Category conformance does not grant runtime permission or release authorization.",
|
|
128
|
+
"Buildchain carries the published KFD decision and does not certify or reinterpret it.",
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
valid,
|
|
133
|
+
report,
|
|
134
|
+
reportRoot: adopterDeliveryGateDigest(report),
|
|
135
|
+
issues: [...(categoryReport?.issues ?? []), ...adapterIssues],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function createKfdAdopterCategoryProtocolDriver() {
|
|
140
|
+
return defineAdopterProtocolDriver({
|
|
141
|
+
interface: ADOPTER_PROTOCOL_DRIVER_INTERFACE,
|
|
142
|
+
id: KFD_ADOPTER_CATEGORY_PROTOCOL_ID,
|
|
143
|
+
version: KFD_ADOPTER_CATEGORY_PROTOCOL_VERSION,
|
|
144
|
+
verify({ request, context }) {
|
|
145
|
+
const adapterIssues = deliveryBindingIssues(
|
|
146
|
+
request,
|
|
147
|
+
context?.adopterManifest,
|
|
148
|
+
);
|
|
149
|
+
let categoryReport = null;
|
|
150
|
+
try {
|
|
151
|
+
categoryReport = verifyPublishedKfdAdopterCategoryInstance(
|
|
152
|
+
request.declaration,
|
|
153
|
+
context,
|
|
154
|
+
);
|
|
155
|
+
} catch {
|
|
156
|
+
adapterIssues.push(
|
|
157
|
+
issue(
|
|
158
|
+
"delivery-kfd-verification-context-invalid",
|
|
159
|
+
"/protocol",
|
|
160
|
+
"Published KFD verification could not reproduce from the supplied exact context.",
|
|
161
|
+
),
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return driverReport(categoryReport, adapterIssues);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|