@kungfu-tech/buildchain 4.0.2-alpha.30 → 4.0.2-alpha.32
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/agent-change-map.md +4 -1
- package/architecture/maintainability-debt.json +90 -58
- package/architecture/maintainability-policy.json +22 -23
- package/architecture/v4-architecture-constitution.md +23 -20
- package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
- package/architecture/v4-provider-operation-journal-contract.json +5 -2
- package/architecture/v4-release-activation-shadow-domain.json +5 -2
- package/architecture/v4-release-topology.json +17 -2
- package/architecture/v4-rust-wasm-production-authority.json +57 -0
- package/architecture/v4-stable-publication-fence.json +5 -2
- package/dist/site/buildchain-contract.json +5 -5
- package/dist/site/buildchain-site.json +44 -8
- package/dist/site/capability-registry.json +1 -1
- package/dist/site/kfd-claims.json +17 -5
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +1 -1
- package/dist/site/node-api-registry.json +27 -27
- package/dist/site/page-registry.json +39 -3
- package/dist/site/public-surface-audit.json +7 -3
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/site-manifest.json +5 -5
- package/dist/site/workflow-registry.json +4 -4
- package/docs/node-api-reference.md +60 -60
- package/docs/v4-rust-wasm-production-authority.md +58 -0
- package/package.json +5 -3
- package/packages/core/buildchain-v4-domain.wasm +0 -0
- package/packages/core/dev-delivery-candidate-identity.js +48 -11
- package/packages/core/release-tail-provider-plane.js +68 -1048
- package/packages/core/v4-canonical-contracts.js +9 -75
- package/packages/core/v4-domain-wasm-artifact.js +7 -0
- package/packages/core/v4-domain-wasm.js +216 -0
- package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
- package/packages/core/v4-product-publication.js +18 -384
- package/packages/core/v4-provider-operation-journal.js +18 -487
- package/packages/core/v4-provider-readback-idempotency.js +12 -97
- package/packages/core/v4-release-activation-shadow.js +13 -500
- package/packages/core/v4-release-invocation.js +28 -389
- package/packages/core/v4-stable-publication-fence.js +13 -342
- package/scripts/build-v4-domain-wasm.mjs +189 -0
- package/scripts/check-action-bundles.mjs +12 -2
- package/scripts/check-v4-release-topology.mjs +50 -25
- package/scripts/copy-v4-domain-wasm.mjs +14 -0
- package/scripts/dev-delivery-warrant.mjs +7 -3
- package/scripts/generate-v4-universal-workflow-facades.mjs +8 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { V4DomainWasmFault, invokeV4DomainWasm } from "./v4-domain-wasm.js";
|
|
2
2
|
|
|
3
3
|
export const V4_CANONICAL_JSON_CONTRACT = "buildchain-canonical-json/v1";
|
|
4
4
|
export const V4_EVENT_ENVELOPE_CONTRACT = "buildchain-v4-event-envelope/v1";
|
|
@@ -110,89 +110,23 @@ function exactKeys(value, keys, path) {
|
|
|
110
110
|
fault("invalid-envelope-shape", path, `${path} keys are not canonical`);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function
|
|
114
|
-
if (value === null || typeof value === "boolean") return value;
|
|
115
|
-
if (typeof value === "string") {
|
|
116
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
117
|
-
const code = value.charCodeAt(index);
|
|
118
|
-
if (code >= 0xd800 && code <= 0xdbff) {
|
|
119
|
-
const next = value.charCodeAt(index + 1);
|
|
120
|
-
if (!(next >= 0xdc00 && next <= 0xdfff))
|
|
121
|
-
fault(
|
|
122
|
-
"unsupported-string",
|
|
123
|
-
path,
|
|
124
|
-
`${path} contains an unpaired surrogate`,
|
|
125
|
-
);
|
|
126
|
-
index += 1;
|
|
127
|
-
} else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
128
|
-
fault(
|
|
129
|
-
"unsupported-string",
|
|
130
|
-
path,
|
|
131
|
-
`${path} contains an unpaired surrogate`,
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return value;
|
|
136
|
-
}
|
|
137
|
-
if (typeof value === "number") {
|
|
138
|
-
if (!Number.isSafeInteger(value) || Object.is(value, -0))
|
|
139
|
-
fault(
|
|
140
|
-
"unsupported-number",
|
|
141
|
-
path,
|
|
142
|
-
`${path} must be a safe base-10 integer and must not be negative zero`,
|
|
143
|
-
);
|
|
144
|
-
return value;
|
|
145
|
-
}
|
|
146
|
-
if (!value || typeof value !== "object")
|
|
147
|
-
fault("unsupported-json-value", path, `${path} is not a JSON value`);
|
|
148
|
-
if (active.has(value))
|
|
149
|
-
fault("cyclic-json-value", path, `${path} contains a cycle`);
|
|
150
|
-
active.add(value);
|
|
113
|
+
function wasm(operation, payload) {
|
|
151
114
|
try {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
);
|
|
156
|
-
const prototype = Object.getPrototypeOf(value);
|
|
157
|
-
if (prototype !== Object.prototype && prototype !== null)
|
|
158
|
-
fault("unsupported-json-value", path, `${path} must be a plain object`);
|
|
159
|
-
const result = Object.create(null);
|
|
160
|
-
for (const key of Object.keys(value).sort((left, right) =>
|
|
161
|
-
left < right ? -1 : left > right ? 1 : 0,
|
|
162
|
-
)) {
|
|
163
|
-
if (!ASCII_KEY_PATTERN.test(key))
|
|
164
|
-
fault(
|
|
165
|
-
"unsupported-object-key",
|
|
166
|
-
`${path}/${key}`,
|
|
167
|
-
"object keys must be non-empty printable ASCII",
|
|
168
|
-
);
|
|
169
|
-
result[key] = canonicalize(value[key], `${path}/${key}`, active);
|
|
115
|
+
return invokeV4DomainWasm(operation, payload);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (error instanceof V4DomainWasmFault) {
|
|
118
|
+
fault(error.code, error.path, error.message);
|
|
170
119
|
}
|
|
171
|
-
|
|
172
|
-
} finally {
|
|
173
|
-
active.delete(value);
|
|
120
|
+
throw error;
|
|
174
121
|
}
|
|
175
122
|
}
|
|
176
123
|
|
|
177
124
|
export function v4CanonicalBytes(value) {
|
|
178
|
-
return Buffer.from(
|
|
179
|
-
`${JSON.stringify(canonicalize(value, "$", new Set()))}\n`,
|
|
180
|
-
"utf8",
|
|
181
|
-
);
|
|
125
|
+
return Buffer.from(wasm("canonical-json", value).canonicalUtf8, "utf8");
|
|
182
126
|
}
|
|
183
127
|
|
|
184
128
|
export function v4ContentRoot(domain, value) {
|
|
185
|
-
|
|
186
|
-
fault(
|
|
187
|
-
"unsupported-root-domain",
|
|
188
|
-
"$.domain",
|
|
189
|
-
`unsupported root domain: ${domain}`,
|
|
190
|
-
);
|
|
191
|
-
const hash = crypto.createHash("sha256");
|
|
192
|
-
hash.update(domain, "ascii");
|
|
193
|
-
hash.update(Buffer.from([0]));
|
|
194
|
-
hash.update(v4CanonicalBytes(value));
|
|
195
|
-
return `sha256:${hash.digest("hex")}`;
|
|
129
|
+
return wasm("content-root", { domain, value }).root;
|
|
196
130
|
}
|
|
197
131
|
|
|
198
132
|
export function validateV4Root(value, path = "$.root") {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Generated by scripts/build-v4-domain-wasm.mjs.
|
|
2
|
+
export const V4_DOMAIN_WASM_ABI_VERSION = 1;
|
|
3
|
+
export const V4_DOMAIN_WASM_RUSTC = "rustc 1.96.0 (ac68faa20 2026-05-25)";
|
|
4
|
+
export const V4_DOMAIN_WASM_SOURCE_SHA256 =
|
|
5
|
+
"28838018db7d5794f9fe2eb546044c8a7a715f08b20af01b95975a8671d0f78a";
|
|
6
|
+
export const V4_DOMAIN_WASM_SHA256 =
|
|
7
|
+
"32a808ba9b749d1297c0ce4b7be1586afdae3d849e44f3f7ffb1742e572f5627";
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
V4_DOMAIN_WASM_ABI_VERSION,
|
|
6
|
+
V4_DOMAIN_WASM_SHA256,
|
|
7
|
+
} from "./v4-domain-wasm-artifact.js";
|
|
8
|
+
|
|
9
|
+
export const V4_DOMAIN_WASM_REQUEST_CONTRACT =
|
|
10
|
+
"kungfu-buildchain-v4-domain-wasm-request/v1";
|
|
11
|
+
export const V4_DOMAIN_WASM_RESPONSE_CONTRACT =
|
|
12
|
+
"kungfu-buildchain-v4-domain-wasm-response/v1";
|
|
13
|
+
|
|
14
|
+
const WASM_URL = new URL("./buildchain-v4-domain.wasm", import.meta.url);
|
|
15
|
+
const REQUIRED_EXPORTS = [
|
|
16
|
+
"memory",
|
|
17
|
+
"buildchain_v4_wasm_abi_version",
|
|
18
|
+
"buildchain_v4_wasm_alloc",
|
|
19
|
+
"buildchain_v4_wasm_dealloc",
|
|
20
|
+
"buildchain_v4_wasm_invoke",
|
|
21
|
+
"buildchain_v4_wasm_response_pointer",
|
|
22
|
+
"buildchain_v4_wasm_response_length",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
let loaded;
|
|
26
|
+
|
|
27
|
+
export class V4DomainWasmFault extends Error {
|
|
28
|
+
constructor(fault) {
|
|
29
|
+
super(fault?.message || "Rust/WASM domain request failed");
|
|
30
|
+
this.name = "V4DomainWasmFault";
|
|
31
|
+
this.fault = fault;
|
|
32
|
+
this.code = fault?.code || "rust-wasm-domain-failed";
|
|
33
|
+
this.path = fault?.path || "$";
|
|
34
|
+
this.retry = fault?.retry || "stop";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function failClosed(message, cause) {
|
|
39
|
+
const error = new Error(`Buildchain v4 Rust/WASM authority: ${message}`);
|
|
40
|
+
error.code = "rust-wasm-authority-unavailable";
|
|
41
|
+
error.cause = cause;
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function invalidTransport(code, path, message) {
|
|
46
|
+
throw new V4DomainWasmFault({ code, path, message, retry: "stop" });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function validateJsonTransport(value, path, active) {
|
|
50
|
+
if (value === null || typeof value === "boolean") return;
|
|
51
|
+
if (typeof value === "string") {
|
|
52
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
53
|
+
const code = value.charCodeAt(index);
|
|
54
|
+
if (code >= 0xd800 && code <= 0xdbff) {
|
|
55
|
+
const next = value.charCodeAt(index + 1);
|
|
56
|
+
if (!(next >= 0xdc00 && next <= 0xdfff)) {
|
|
57
|
+
invalidTransport(
|
|
58
|
+
"unsupported-string",
|
|
59
|
+
path,
|
|
60
|
+
`${path} contains an unpaired surrogate`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
index += 1;
|
|
64
|
+
} else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
65
|
+
invalidTransport(
|
|
66
|
+
"unsupported-string",
|
|
67
|
+
path,
|
|
68
|
+
`${path} contains an unpaired surrogate`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (typeof value === "number") {
|
|
75
|
+
if (!Number.isSafeInteger(value) || Object.is(value, -0)) {
|
|
76
|
+
invalidTransport(
|
|
77
|
+
"unsupported-number",
|
|
78
|
+
path,
|
|
79
|
+
`${path} must be a safe base-10 integer and must not be negative zero`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!value || typeof value !== "object") {
|
|
85
|
+
invalidTransport(
|
|
86
|
+
"unsupported-json-value",
|
|
87
|
+
path,
|
|
88
|
+
`${path} is not a JSON value`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (active.has(value)) {
|
|
92
|
+
invalidTransport("cyclic-json-value", path, `${path} contains a cycle`);
|
|
93
|
+
}
|
|
94
|
+
active.add(value);
|
|
95
|
+
try {
|
|
96
|
+
if (Array.isArray(value)) {
|
|
97
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
98
|
+
validateJsonTransport(value[index], `${path}/${index}`, active);
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const prototype = Object.getPrototypeOf(value);
|
|
103
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
104
|
+
invalidTransport(
|
|
105
|
+
"unsupported-json-value",
|
|
106
|
+
path,
|
|
107
|
+
`${path} must be a plain object`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
for (const key of Object.keys(value)) {
|
|
111
|
+
if (!/^[\x20-\x7e]+$/u.test(key)) {
|
|
112
|
+
invalidTransport(
|
|
113
|
+
"unsupported-object-key",
|
|
114
|
+
`${path}/${key}`,
|
|
115
|
+
"object keys must be non-empty printable ASCII",
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
validateJsonTransport(value[key], `${path}/${key}`, active);
|
|
119
|
+
}
|
|
120
|
+
} finally {
|
|
121
|
+
active.delete(value);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function loadAuthority() {
|
|
126
|
+
if (loaded) return loaded;
|
|
127
|
+
let bytes;
|
|
128
|
+
try {
|
|
129
|
+
bytes = fs.readFileSync(WASM_URL);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
failClosed(`cannot read ${WASM_URL.pathname}`, error);
|
|
132
|
+
}
|
|
133
|
+
const observedSha256 = createHash("sha256").update(bytes).digest("hex");
|
|
134
|
+
if (observedSha256 !== V4_DOMAIN_WASM_SHA256) {
|
|
135
|
+
failClosed(
|
|
136
|
+
`artifact digest mismatch (expected ${V4_DOMAIN_WASM_SHA256}, observed ${observedSha256})`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
let instance;
|
|
140
|
+
try {
|
|
141
|
+
instance = new WebAssembly.Instance(new WebAssembly.Module(bytes), {});
|
|
142
|
+
} catch (error) {
|
|
143
|
+
failClosed("artifact compilation or instantiation failed", error);
|
|
144
|
+
}
|
|
145
|
+
const missing = REQUIRED_EXPORTS.filter(
|
|
146
|
+
(name) => instance.exports[name] === undefined,
|
|
147
|
+
);
|
|
148
|
+
if (missing.length > 0) {
|
|
149
|
+
failClosed(`artifact is missing exports: ${missing.join(", ")}`);
|
|
150
|
+
}
|
|
151
|
+
const abiVersion = instance.exports.buildchain_v4_wasm_abi_version();
|
|
152
|
+
if (abiVersion !== V4_DOMAIN_WASM_ABI_VERSION) {
|
|
153
|
+
failClosed(
|
|
154
|
+
`ABI mismatch (expected ${V4_DOMAIN_WASM_ABI_VERSION}, observed ${abiVersion})`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
loaded = instance.exports;
|
|
158
|
+
return loaded;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function invokeV4DomainWasm(operation, payload) {
|
|
162
|
+
if (
|
|
163
|
+
["canonical-json", "content-root", "release-tail-root"].includes(operation)
|
|
164
|
+
) {
|
|
165
|
+
validateJsonTransport(payload, "$/payload", new Set());
|
|
166
|
+
}
|
|
167
|
+
const authority = loadAuthority();
|
|
168
|
+
const input = new TextEncoder().encode(
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
schema: V4_DOMAIN_WASM_REQUEST_CONTRACT,
|
|
171
|
+
operation,
|
|
172
|
+
payload,
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
const inputPointer = authority.buildchain_v4_wasm_alloc(input.byteLength);
|
|
176
|
+
try {
|
|
177
|
+
new Uint8Array(authority.memory.buffer, inputPointer, input.byteLength).set(
|
|
178
|
+
input,
|
|
179
|
+
);
|
|
180
|
+
try {
|
|
181
|
+
authority.buildchain_v4_wasm_invoke(inputPointer, input.byteLength);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
failClosed(`operation '${operation}' trapped`, error);
|
|
184
|
+
}
|
|
185
|
+
const responsePointer = authority.buildchain_v4_wasm_response_pointer();
|
|
186
|
+
const responseLength = authority.buildchain_v4_wasm_response_length();
|
|
187
|
+
let response;
|
|
188
|
+
try {
|
|
189
|
+
const responseBytes = new Uint8Array(
|
|
190
|
+
authority.memory.buffer,
|
|
191
|
+
responsePointer,
|
|
192
|
+
responseLength,
|
|
193
|
+
);
|
|
194
|
+
response = JSON.parse(new TextDecoder().decode(responseBytes));
|
|
195
|
+
} catch (error) {
|
|
196
|
+
failClosed(
|
|
197
|
+
`operation '${operation}' returned an invalid response`,
|
|
198
|
+
error,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
if (
|
|
202
|
+
response?.schema !== V4_DOMAIN_WASM_RESPONSE_CONTRACT ||
|
|
203
|
+
typeof response.ok !== "boolean"
|
|
204
|
+
) {
|
|
205
|
+
failClosed(`operation '${operation}' returned an unsupported response`);
|
|
206
|
+
}
|
|
207
|
+
if (!response.ok) throw new V4DomainWasmFault(response.fault);
|
|
208
|
+
return response.value;
|
|
209
|
+
} finally {
|
|
210
|
+
authority.buildchain_v4_wasm_dealloc(inputPointer, input.byteLength);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function v4DomainWasmInfo() {
|
|
215
|
+
return invokeV4DomainWasm("abi-info", {});
|
|
216
|
+
}
|