@kungfu-tech/buildchain 4.0.1-alpha.4 → 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.
- package/architecture/decisions/0002-next-development-transition.md +101 -0
- package/architecture/internal-capabilities.json +52 -3
- package/architecture/maintainability-policy.json +22 -10
- package/architecture/v3-core-mechanism-inventory.json +89 -0
- package/architecture/v4-capability-state-machine-manifest.json +73 -0
- package/architecture/v4-compatibility-facts-parity.json +77 -0
- package/architecture/v4-next-development-parity.json +192 -0
- package/architecture/v4-release-train-parity.json +1 -0
- package/architecture/v4-tail-reseal-parity.json +150 -0
- package/bin/buildchain.mjs +16 -1
- package/bin/internal/command-registry.mjs +2 -0
- package/bin/internal/compatibility-facts-cli.mjs +101 -0
- package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +47 -0
- package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +40 -0
- package/contracts/fixtures/v4-compatibility-facts-v1/shared.json +1129 -0
- package/contracts/fixtures/v4-floating-consumer-policy-v1/cases.json +7 -1
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +229 -0
- package/contracts/next-development-request-v1.schema.json +66 -0
- package/contracts/next-development-transition-v1.schema.json +292 -0
- package/contracts/v4-compatibility-facts-v1.schema.json +230 -0
- package/contracts/v4-tail-reseal-v1.schema.json +276 -0
- package/dist/site/agent-index.json +1 -0
- package/dist/site/artifact-schemas.json +2 -0
- package/dist/site/buildchain-contract.json +1388 -23
- package/dist/site/buildchain-site.json +257 -19
- package/dist/site/capability-registry.json +10 -8
- package/dist/site/cli-registry.json +106 -0
- package/dist/site/kfd-claims.json +187 -12
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +35 -4
- package/dist/site/node-api-registry.json +6579 -4493
- package/dist/site/page-registry.json +233 -11
- package/dist/site/public-surface-audit.json +241 -7
- package/dist/site/publication-authority-registry.json +6 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +7 -0
- package/dist/site/schemas/v4-compatibility-facts-v1.schema.json +230 -0
- package/dist/site/site-manifest.json +24 -8
- package/dist/site/workflow-registry.json +36 -4
- package/docs/MAP.md +4 -1
- package/docs/cli-reference.md +125 -0
- package/docs/dev-alpha-candidate-patrol.md +8 -0
- package/docs/next-development-transition.md +118 -0
- package/docs/node-api-reference.md +250 -117
- package/docs/v4-compatibility-facts.md +91 -0
- package/docs/v4-tail-reseal.md +73 -0
- package/docs/versioning.md +4 -3
- package/package.json +14 -5
- package/packages/core/buildchain-agent-manuals.js +2 -0
- package/packages/core/buildchain-compatibility-authority.js +336 -0
- package/packages/core/buildchain-compatibility-fact.js +394 -0
- package/packages/core/buildchain-compatibility-facts.json +217 -0
- package/packages/core/buildchain-compatibility-proof.js +566 -0
- package/packages/core/buildchain-contract.js +93 -141
- package/packages/core/channel-candidate.js +8 -0
- package/packages/core/channel-promotion-baseline.js +55 -0
- package/packages/core/dev-alpha-candidate-selection.js +10 -2
- package/packages/core/dev-delivery-execution-transfer.js +21 -1
- package/packages/core/dev-delivery-process-boundary.js +19 -6
- package/packages/core/dev-delivery-provider-heartbeat.js +18 -6
- package/packages/core/kungfu-temporal-fact.js +557 -0
- package/packages/core/next-development-candidate-reservation.js +186 -0
- package/packages/core/next-development-controller.js +728 -0
- package/packages/core/next-development-projection.js +287 -0
- package/packages/core/next-development-transition.js +738 -0
- package/packages/core/paper-agent-entry.js +11 -5
- package/packages/core/paper.js +16 -5
- package/packages/core/v4-canonical-contracts.js +5 -0
- package/packages/core/v4-floating-consumer-policy.js +29 -9
- package/packages/core/v4-tail-reseal-contract.js +26 -0
- package/packages/core/v4-tail-reseal-github.js +178 -0
- package/packages/core/v4-tail-reseal-receipt.js +225 -0
- package/packages/core/v4-tail-reseal.js +594 -0
- package/scripts/buildchain-cli-help.mjs +20 -0
- package/scripts/check-inventory.mjs +11 -0
- package/scripts/dev-alpha-candidate-patrol.mjs +22 -1
- package/scripts/generate-next-development-guidance.mjs +49 -0
- package/scripts/generate-site-bundle.mjs +16 -3
- package/scripts/init-repo.mjs +22 -4
- package/scripts/next-development-self-dogfood-harness.mjs +460 -0
- package/scripts/next-development-self-dogfood.mjs +597 -0
- package/scripts/next-development-transition.mjs +47 -0
- package/scripts/site-capability-metadata.mjs +12 -0
- package/scripts/v4-consumer-policy.mjs +1 -5
- package/scripts/v4-tail-reseal-macos-rehearsal.mjs +134 -0
- package/scripts/v4-tail-reseal.mjs +416 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
|
|
5
|
+
const SHA = /^[0-9a-f]{40}$/u;
|
|
6
|
+
const ROOT = /^sha256:[0-9a-f]{64}$/u;
|
|
7
|
+
|
|
8
|
+
function text(value = "") {
|
|
9
|
+
return String(value ?? "").trim();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function exactSha(value, label) {
|
|
13
|
+
const normalized = text(value).toLowerCase();
|
|
14
|
+
if (!SHA.test(normalized)) {
|
|
15
|
+
throw new Error(`${label} must be an exact 40-character SHA`);
|
|
16
|
+
}
|
|
17
|
+
return normalized;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function exactRoot(value, label) {
|
|
21
|
+
const normalized = text(value).toLowerCase();
|
|
22
|
+
if (!ROOT.test(normalized)) {
|
|
23
|
+
throw new Error(`${label} must be an exact sha256 content root`);
|
|
24
|
+
}
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function canonical(value) {
|
|
29
|
+
if (Array.isArray(value)) return value.map(canonical);
|
|
30
|
+
if (value && typeof value === "object") {
|
|
31
|
+
return Object.fromEntries(
|
|
32
|
+
Object.entries(value)
|
|
33
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
34
|
+
.map(([key, item]) => [key, canonical(item)]),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function evidenceRoot(value) {
|
|
41
|
+
return `sha256:${crypto
|
|
42
|
+
.createHash("sha256")
|
|
43
|
+
.update(JSON.stringify(canonical(value)))
|
|
44
|
+
.digest("hex")}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function nextDevelopmentPreparedVersion(message) {
|
|
48
|
+
const title = text(message).split("\n", 1)[0];
|
|
49
|
+
return (
|
|
50
|
+
title.match(
|
|
51
|
+
/^(?:chore\(release\): prepare|Prepare)\s+v?([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)$/u,
|
|
52
|
+
)?.[1] || ""
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function preparation(entry) {
|
|
57
|
+
if (!entry || typeof entry === "string") return undefined;
|
|
58
|
+
const targetVersion = nextDevelopmentPreparedVersion(entry.message);
|
|
59
|
+
if (!targetVersion) return undefined;
|
|
60
|
+
return {
|
|
61
|
+
sha: exactSha(entry.sha, "sourceHistory.sha"),
|
|
62
|
+
targetVersion,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function nextDevelopmentPatrolContext(sourceHistory) {
|
|
67
|
+
const preparations = sourceHistory
|
|
68
|
+
.map((entry, index) => ({ index, preparation: preparation(entry) }))
|
|
69
|
+
.filter((entry) => entry.preparation);
|
|
70
|
+
const preparationShas = new Set(
|
|
71
|
+
preparations.map(({ preparation: item }) => item.sha),
|
|
72
|
+
);
|
|
73
|
+
const integrationShas = sourceHistory
|
|
74
|
+
.filter(
|
|
75
|
+
(entry) =>
|
|
76
|
+
entry &&
|
|
77
|
+
typeof entry !== "string" &&
|
|
78
|
+
Array.isArray(entry.parents) &&
|
|
79
|
+
entry.parents.length === 2 &&
|
|
80
|
+
entry.parents.some((parent) => preparationShas.has(parent)),
|
|
81
|
+
)
|
|
82
|
+
.map((entry) => exactSha(entry.sha, "sourceHistory.sha"));
|
|
83
|
+
return {
|
|
84
|
+
preparations,
|
|
85
|
+
ignoredSourceShas: [...preparationShas, ...integrationShas],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function normalizeNextDevelopmentVersionReservation(input, expected) {
|
|
90
|
+
const status = text(input?.status);
|
|
91
|
+
if (!["current", "absent", "stale"].includes(status)) {
|
|
92
|
+
throw new Error("next-development version reservation status is invalid");
|
|
93
|
+
}
|
|
94
|
+
const normalized = {
|
|
95
|
+
status,
|
|
96
|
+
reservationSha: exactSha(
|
|
97
|
+
input?.reservationSha,
|
|
98
|
+
"versionReservation.reservationSha",
|
|
99
|
+
),
|
|
100
|
+
candidateSha: exactSha(
|
|
101
|
+
input?.candidateSha,
|
|
102
|
+
"versionReservation.candidateSha",
|
|
103
|
+
),
|
|
104
|
+
targetVersion: text(input?.targetVersion),
|
|
105
|
+
paths: [...new Set((input?.paths || []).map(text))].sort(),
|
|
106
|
+
evidenceRoot: exactRoot(
|
|
107
|
+
input?.evidenceRoot,
|
|
108
|
+
"versionReservation.evidenceRoot",
|
|
109
|
+
),
|
|
110
|
+
};
|
|
111
|
+
if (
|
|
112
|
+
normalized.reservationSha !== expected.reservationSha ||
|
|
113
|
+
normalized.candidateSha !== expected.candidateSha ||
|
|
114
|
+
normalized.targetVersion !== expected.targetVersion
|
|
115
|
+
) {
|
|
116
|
+
throw new Error("next-development version reservation identity drifted");
|
|
117
|
+
}
|
|
118
|
+
if (normalized.paths.length === 0 || normalized.paths.some((path) => !path)) {
|
|
119
|
+
throw new Error("next-development version reservation paths are required");
|
|
120
|
+
}
|
|
121
|
+
return normalized;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function encodeRepositoryPath(value) {
|
|
125
|
+
return value.split("/").map(encodeURIComponent).join("/");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function readGitHubNextDevelopmentVersionReservation({
|
|
129
|
+
api,
|
|
130
|
+
owner,
|
|
131
|
+
repo,
|
|
132
|
+
reservationSha,
|
|
133
|
+
candidateSha,
|
|
134
|
+
targetVersion,
|
|
135
|
+
}) {
|
|
136
|
+
const commit = await api(
|
|
137
|
+
`/repos/${owner}/${repo}/commits/${encodeURIComponent(reservationSha)}`,
|
|
138
|
+
);
|
|
139
|
+
if (
|
|
140
|
+
text(commit.sha) !== reservationSha ||
|
|
141
|
+
nextDevelopmentPreparedVersion(commit.commit?.message) !== targetVersion
|
|
142
|
+
) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
"next-development preparation commit identity or version drifted",
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
const paths = [
|
|
148
|
+
...new Set((commit.files || []).map((file) => text(file.filename))),
|
|
149
|
+
]
|
|
150
|
+
.filter(Boolean)
|
|
151
|
+
.sort();
|
|
152
|
+
if (paths.length === 0) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"next-development preparation commit has no version-state paths",
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const observations = [];
|
|
158
|
+
let status = "current";
|
|
159
|
+
for (const filePath of paths) {
|
|
160
|
+
const endpoint = `/repos/${owner}/${repo}/contents/${encodeRepositoryPath(filePath)}`;
|
|
161
|
+
const prepared = await api(
|
|
162
|
+
`${endpoint}?ref=${encodeURIComponent(reservationSha)}`,
|
|
163
|
+
{ allow404: true },
|
|
164
|
+
);
|
|
165
|
+
const candidate = await api(
|
|
166
|
+
`${endpoint}?ref=${encodeURIComponent(candidateSha)}`,
|
|
167
|
+
{ allow404: true },
|
|
168
|
+
);
|
|
169
|
+
const preparedBlob =
|
|
170
|
+
text(prepared?.type) === "file" ? text(prepared?.sha) : "";
|
|
171
|
+
const candidateBlob =
|
|
172
|
+
text(candidate?.type) === "file" ? text(candidate?.sha) : "";
|
|
173
|
+
if (!candidateBlob) status = "absent";
|
|
174
|
+
else if (!preparedBlob || candidateBlob !== preparedBlob) status = "stale";
|
|
175
|
+
observations.push({ path: filePath, preparedBlob, candidateBlob });
|
|
176
|
+
}
|
|
177
|
+
const body = {
|
|
178
|
+
status,
|
|
179
|
+
reservationSha,
|
|
180
|
+
candidateSha,
|
|
181
|
+
targetVersion,
|
|
182
|
+
paths,
|
|
183
|
+
observations,
|
|
184
|
+
};
|
|
185
|
+
return { ...body, evidenceRoot: evidenceRoot(body) };
|
|
186
|
+
}
|