@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.
Files changed (44) hide show
  1. package/architecture/agent-change-map.md +4 -1
  2. package/architecture/maintainability-debt.json +90 -58
  3. package/architecture/maintainability-policy.json +22 -23
  4. package/architecture/v4-architecture-constitution.md +23 -20
  5. package/architecture/v4-partial-mutation-recovery-qualification.json +4 -1
  6. package/architecture/v4-provider-operation-journal-contract.json +5 -2
  7. package/architecture/v4-release-activation-shadow-domain.json +5 -2
  8. package/architecture/v4-release-topology.json +17 -2
  9. package/architecture/v4-rust-wasm-production-authority.json +57 -0
  10. package/architecture/v4-stable-publication-fence.json +5 -2
  11. package/dist/site/buildchain-contract.json +5 -5
  12. package/dist/site/buildchain-site.json +44 -8
  13. package/dist/site/capability-registry.json +1 -1
  14. package/dist/site/kfd-claims.json +17 -5
  15. package/dist/site/kfd-upstream-aggregate.json +1 -1
  16. package/dist/site/manual-registry.json +1 -1
  17. package/dist/site/node-api-registry.json +27 -27
  18. package/dist/site/page-registry.json +39 -3
  19. package/dist/site/public-surface-audit.json +7 -3
  20. package/dist/site/publication-registry.json +4 -4
  21. package/dist/site/site-manifest.json +5 -5
  22. package/dist/site/workflow-registry.json +4 -4
  23. package/docs/node-api-reference.md +60 -60
  24. package/docs/v4-rust-wasm-production-authority.md +58 -0
  25. package/package.json +5 -3
  26. package/packages/core/buildchain-v4-domain.wasm +0 -0
  27. package/packages/core/dev-delivery-candidate-identity.js +48 -11
  28. package/packages/core/release-tail-provider-plane.js +68 -1048
  29. package/packages/core/v4-canonical-contracts.js +9 -75
  30. package/packages/core/v4-domain-wasm-artifact.js +7 -0
  31. package/packages/core/v4-domain-wasm.js +216 -0
  32. package/packages/core/v4-partial-mutation-recovery-qualification.js +9 -386
  33. package/packages/core/v4-product-publication.js +18 -384
  34. package/packages/core/v4-provider-operation-journal.js +18 -487
  35. package/packages/core/v4-provider-readback-idempotency.js +12 -97
  36. package/packages/core/v4-release-activation-shadow.js +13 -500
  37. package/packages/core/v4-release-invocation.js +28 -389
  38. package/packages/core/v4-stable-publication-fence.js +13 -342
  39. package/scripts/build-v4-domain-wasm.mjs +189 -0
  40. package/scripts/check-action-bundles.mjs +12 -2
  41. package/scripts/check-v4-release-topology.mjs +50 -25
  42. package/scripts/copy-v4-domain-wasm.mjs +14 -0
  43. package/scripts/dev-delivery-warrant.mjs +7 -3
  44. package/scripts/generate-v4-universal-workflow-facades.mjs +8 -3
@@ -1,4 +1,4 @@
1
- import crypto from "node:crypto";
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 canonicalize(value, path, active) {
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
- if (Array.isArray(value))
153
- return Array.from(value, (entry, index) =>
154
- canonicalize(entry, `${path}/${index}`, active),
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
- return result;
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
- if (!ROOT_DOMAINS.has(domain))
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
+ }