@world-engines/tmw 0.1.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/LICENSE +46 -0
- package/dist/activation.d.ts +50 -0
- package/dist/activation.js +113 -0
- package/dist/audio-presentation-projection.d.ts +23 -0
- package/dist/audio-presentation-projection.js +39 -0
- package/dist/author-scenario-source-v3.d.ts +34 -0
- package/dist/author-scenario-source-v3.js +1 -0
- package/dist/authoring-runtime.d.ts +76 -0
- package/dist/authoring-runtime.js +282 -0
- package/dist/builder-diagnostics.d.ts +3 -0
- package/dist/builder-diagnostics.js +8 -0
- package/dist/builder-node.d.ts +178 -0
- package/dist/builder-node.js +212 -0
- package/dist/builder.d.ts +32 -0
- package/dist/builder.js +127 -0
- package/dist/capability-registry.d.ts +32 -0
- package/dist/capability-registry.js +33 -0
- package/dist/compile-target-profile.d.ts +16 -0
- package/dist/compile-target-profile.js +70 -0
- package/dist/compiled-plan.d.ts +44 -0
- package/dist/compiled-plan.js +1 -0
- package/dist/compiler-compatibility-gate.d.ts +96 -0
- package/dist/compiler-compatibility-gate.js +609 -0
- package/dist/compiler-release-authority.d.ts +212 -0
- package/dist/compiler-release-authority.js +676 -0
- package/dist/compiler-stage-cache.d.ts +42 -0
- package/dist/compiler-stage-cache.js +100 -0
- package/dist/compiler-stage-registry.d.ts +48 -0
- package/dist/compiler-stage-registry.js +126 -0
- package/dist/compiler.d.ts +7 -0
- package/dist/compiler.js +68 -0
- package/dist/condition-graph.d.ts +46 -0
- package/dist/condition-graph.js +135 -0
- package/dist/diagnostics.d.ts +20 -0
- package/dist/diagnostics.js +20 -0
- package/dist/durable-intent.d.ts +29 -0
- package/dist/durable-intent.js +60 -0
- package/dist/effect-flow.d.ts +69 -0
- package/dist/effect-flow.js +98 -0
- package/dist/event-fabric.d.ts +81 -0
- package/dist/event-fabric.js +227 -0
- package/dist/event-lifecycle.d.ts +59 -0
- package/dist/event-lifecycle.js +161 -0
- package/dist/evidence.d.ts +37 -0
- package/dist/evidence.js +92 -0
- package/dist/gameplay-state.d.ts +127 -0
- package/dist/gameplay-state.js +214 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +52 -0
- package/dist/isolated-replay.d.ts +81 -0
- package/dist/isolated-replay.js +316 -0
- package/dist/music-candidate-set.d.ts +38 -0
- package/dist/music-candidate-set.js +102 -0
- package/dist/natural-language-chunking.d.ts +10 -0
- package/dist/natural-language-chunking.js +62 -0
- package/dist/natural-language-ingestion.d.ts +14 -0
- package/dist/natural-language-ingestion.js +128 -0
- package/dist/natural-language-structured-decode.d.ts +2 -0
- package/dist/natural-language-structured-decode.js +69 -0
- package/dist/natural-language-world-types.d.ts +142 -0
- package/dist/natural-language-world-types.js +2 -0
- package/dist/neutral-source-compiler.d.ts +135 -0
- package/dist/neutral-source-compiler.js +608 -0
- package/dist/presentation-intent.d.ts +42 -0
- package/dist/presentation-intent.js +137 -0
- package/dist/recall-query-envelope.d.ts +32 -0
- package/dist/recall-query-envelope.js +51 -0
- package/dist/rewrite-compensation.d.ts +28 -0
- package/dist/rewrite-compensation.js +85 -0
- package/dist/runtime-contract.d.ts +56 -0
- package/dist/runtime-contract.js +96 -0
- package/dist/runtime-domain-capabilities.d.ts +12 -0
- package/dist/runtime-domain-capabilities.js +20 -0
- package/dist/runtime-sav.d.ts +117 -0
- package/dist/runtime-sav.js +356 -0
- package/dist/runtime-trace.d.ts +44 -0
- package/dist/runtime-trace.js +119 -0
- package/dist/runtime.d.ts +238 -0
- package/dist/runtime.js +1887 -0
- package/dist/scene-author-source.d.ts +13 -0
- package/dist/scene-author-source.js +25 -0
- package/dist/scene-state.d.ts +275 -0
- package/dist/scene-state.js +334 -0
- package/dist/scheduler.d.ts +55 -0
- package/dist/scheduler.js +235 -0
- package/dist/selector-ast.d.ts +24 -0
- package/dist/selector-ast.js +18 -0
- package/dist/semantic-verdict.d.ts +48 -0
- package/dist/semantic-verdict.js +101 -0
- package/dist/simulator.d.ts +45 -0
- package/dist/simulator.js +58 -0
- package/dist/source-canonical.d.ts +4 -0
- package/dist/source-canonical.js +51 -0
- package/dist/source-crypto.d.ts +20 -0
- package/dist/source-crypto.js +17 -0
- package/dist/source-revision.d.ts +22 -0
- package/dist/source-revision.js +43 -0
- package/dist/spatial-impact-receipt.d.ts +38 -0
- package/dist/spatial-impact-receipt.js +67 -0
- package/dist/temporal-rewrite.d.ts +59 -0
- package/dist/temporal-rewrite.js +214 -0
- package/dist/time-domains.d.ts +37 -0
- package/dist/time-domains.js +142 -0
- package/dist/timeline-revision.d.ts +28 -0
- package/dist/timeline-revision.js +59 -0
- package/dist/trigger-document-v3.d.ts +99 -0
- package/dist/trigger-document-v3.js +334 -0
- package/dist/turn-commit.d.ts +56 -0
- package/dist/turn-commit.js +190 -0
- package/dist/validator.d.ts +7 -0
- package/dist/validator.js +142 -0
- package/dist/value-graph.d.ts +98 -0
- package/dist/value-graph.js +318 -0
- package/dist/view-event-delivery.d.ts +47 -0
- package/dist/view-event-delivery.js +197 -0
- package/dist/view-interaction-manifest-v3.d.ts +60 -0
- package/dist/view-interaction-manifest-v3.js +198 -0
- package/dist/view-payload-schema.d.ts +17 -0
- package/dist/view-payload-schema.js +84 -0
- package/package.json +62 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
import { compileTargetProfileDigest, parseCompileTargetProfile, } from "./compile-target-profile.js";
|
|
2
|
+
import { evaluateCompilerCandidate, parseAcceptedNeutralSourceCorpus, } from "./compiler-compatibility-gate.js";
|
|
3
|
+
import { InMemoryCompilerStageCache, } from "./compiler-stage-cache.js";
|
|
4
|
+
import { assertRegistryMatchesTargetProfile, } from "./compiler-stage-registry.js";
|
|
5
|
+
import { canonicalNeutralSourceCompilerReceiptBytes, compileNeutralScenarioSource, } from "./neutral-source-compiler.js";
|
|
6
|
+
import { canonicalTmwBytes, isSha256Hex, tmwSha256Hex, } from "./runtime-contract.js";
|
|
7
|
+
import { captureNeutralSourceCompileInput, } from "@world-engines/scenario-author-source";
|
|
8
|
+
export const COMPILER_RELEASE_AUTHORITY_SCHEMA_VERSION = 1;
|
|
9
|
+
function requireRecord(value, code) {
|
|
10
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
11
|
+
throw new Error(code);
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
async function parseReleaseIdentity(value) {
|
|
16
|
+
if (value === null)
|
|
17
|
+
return null;
|
|
18
|
+
const record = requireRecord(value, "compiler_release_identity_invalid");
|
|
19
|
+
const compilerRelease = requireIdentifier(String(record.compiler_release ?? ""), "compiler_release_identity_invalid");
|
|
20
|
+
const targetProfile = parseCompileTargetProfile(record.target_profile);
|
|
21
|
+
const targetProfileSha256 = requireSha256(String(record.target_profile_sha256 ?? ""), "compiler_release_identity_digest_invalid");
|
|
22
|
+
if (compilerRelease !== targetProfile.compiler_release) {
|
|
23
|
+
throw new Error("compiler_release_identity_profile_mismatch");
|
|
24
|
+
}
|
|
25
|
+
if (await compileTargetProfileDigest(targetProfile) !== targetProfileSha256) {
|
|
26
|
+
throw new Error("compiler_release_identity_digest_mismatch");
|
|
27
|
+
}
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
compiler_release: compilerRelease,
|
|
30
|
+
target_profile: targetProfile,
|
|
31
|
+
target_profile_sha256: targetProfileSha256,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Browser 与 Node 生产消费者共用的只读 authority adapter。唯一状态来自调用方
|
|
36
|
+
* 注入的 Edge readback;adapter 不缓存、不初始化 active,也不能执行 promotion。
|
|
37
|
+
*/
|
|
38
|
+
export class ReadbackCompilerReleaseStore {
|
|
39
|
+
#load;
|
|
40
|
+
constructor(load) {
|
|
41
|
+
this.#load = load;
|
|
42
|
+
}
|
|
43
|
+
async read() {
|
|
44
|
+
return parseAuthoritySnapshot(await this.#load());
|
|
45
|
+
}
|
|
46
|
+
async writeOnce() {
|
|
47
|
+
throw new Error("compiler_release_readback_store_read_only");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function parseAuthoritySnapshot(value) {
|
|
51
|
+
const envelope = requireRecord(value, "compiler_release_readback_invalid");
|
|
52
|
+
if (envelope.schema_version !== COMPILER_RELEASE_AUTHORITY_SCHEMA_VERSION) {
|
|
53
|
+
throw new Error("compiler_release_readback_schema_invalid");
|
|
54
|
+
}
|
|
55
|
+
if (!Number.isSafeInteger(envelope.revision) || Number(envelope.revision) < 0) {
|
|
56
|
+
throw new Error("compiler_release_readback_revision_invalid");
|
|
57
|
+
}
|
|
58
|
+
return Object.freeze({
|
|
59
|
+
schema_version: COMPILER_RELEASE_AUTHORITY_SCHEMA_VERSION,
|
|
60
|
+
revision: Number(envelope.revision),
|
|
61
|
+
active: await parseReleaseIdentity(envelope.active),
|
|
62
|
+
previous_active: await parseReleaseIdentity(envelope.previous_active),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export class RemoteCompilerReleaseAuthority {
|
|
66
|
+
#transport;
|
|
67
|
+
#currentPath;
|
|
68
|
+
constructor(transport, currentPath = "/v1/compiler-releases/current") {
|
|
69
|
+
this.#transport = transport;
|
|
70
|
+
this.#currentPath = currentPath;
|
|
71
|
+
}
|
|
72
|
+
async read() {
|
|
73
|
+
const response = await this.#transport.request({
|
|
74
|
+
method: "GET",
|
|
75
|
+
path: this.#currentPath,
|
|
76
|
+
});
|
|
77
|
+
if (response.status !== 200)
|
|
78
|
+
throw new Error(`compiler_release_readback_failed:${response.status}`);
|
|
79
|
+
return parseAuthoritySnapshot(response.body);
|
|
80
|
+
}
|
|
81
|
+
async readOperation(operationId) {
|
|
82
|
+
requireIdentifier(operationId, "compiler_release_operation_id_invalid");
|
|
83
|
+
const response = await this.#transport.request({
|
|
84
|
+
method: "GET",
|
|
85
|
+
path: `/_internal/compiler-releases/operations/${encodeURIComponent(operationId)}`,
|
|
86
|
+
});
|
|
87
|
+
if (response.status === 404)
|
|
88
|
+
return null;
|
|
89
|
+
if (response.status !== 200)
|
|
90
|
+
throw new Error(`compiler_release_operation_readback_failed:${response.status}`);
|
|
91
|
+
const envelope = requireRecord(response.body, "compiler_release_operation_readback_invalid");
|
|
92
|
+
if (envelope.operation_id !== operationId) {
|
|
93
|
+
throw new Error("compiler_release_operation_readback_identity_mismatch");
|
|
94
|
+
}
|
|
95
|
+
const receipt = requireRecord(envelope.receipt, "compiler_release_operation_receipt_invalid");
|
|
96
|
+
if (receipt.operation_id !== operationId) {
|
|
97
|
+
throw new Error("compiler_release_operation_receipt_identity_mismatch");
|
|
98
|
+
}
|
|
99
|
+
const digest = requireSha256(String(receipt.receipt_sha256 ?? ""), "compiler_release_operation_receipt_digest_invalid");
|
|
100
|
+
const { receipt_sha256: _digest, ...core } = receipt;
|
|
101
|
+
if (await tmwSha256Hex(canonicalTmwBytes(core)) !== digest) {
|
|
102
|
+
throw new Error("compiler_release_operation_receipt_digest_mismatch");
|
|
103
|
+
}
|
|
104
|
+
return receipt;
|
|
105
|
+
}
|
|
106
|
+
async apply(kind, expectedRevision, receipt) {
|
|
107
|
+
const response = await this.#transport.request({
|
|
108
|
+
method: "POST",
|
|
109
|
+
path: `/_internal/compiler-releases/${kind}`,
|
|
110
|
+
body: {
|
|
111
|
+
operation_id: receipt.operation_id,
|
|
112
|
+
expected_revision: expectedRevision,
|
|
113
|
+
receipt,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
if (response.status !== 200)
|
|
117
|
+
throw new Error(`compiler_release_mutation_failed:${response.status}`);
|
|
118
|
+
const envelope = requireRecord(response.body, "compiler_release_mutation_readback_invalid");
|
|
119
|
+
return parseAuthoritySnapshot(envelope.authority);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 生产 promotion:先从唯一 Edge authority 做 operation readback;未提交时在冻结快照上
|
|
124
|
+
* 执行完整 corpus KAT,再把完整 receipt 交给 Edge CAS。网络结果不确定时以同一
|
|
125
|
+
* operation_id 重试会先读回 receipt,不会重复推进 pointer。
|
|
126
|
+
*/
|
|
127
|
+
export async function promotePersistedCompilerReleaseCandidate(input) {
|
|
128
|
+
const replay = await input.authority.readOperation(input.operation_id);
|
|
129
|
+
if (replay !== null) {
|
|
130
|
+
if (replay.operation_kind !== "promote_candidate") {
|
|
131
|
+
throw new Error(`compiler_release_operation_conflict:${input.operation_id}`);
|
|
132
|
+
}
|
|
133
|
+
const candidate = await identityFromCandidate(input.candidate);
|
|
134
|
+
const source = sourceIdentity(cloneSourceSnapshot(await input.live_store.snapshot()));
|
|
135
|
+
if (!identitiesEqual(replay.candidate, candidate)
|
|
136
|
+
|| replay.corpus_digest !== await digestCorpus(input.corpus_value)
|
|
137
|
+
|| !sourceIdentitiesEqual(replay.source_before, source)
|
|
138
|
+
|| !sourceIdentitiesEqual(replay.source_after, source)) {
|
|
139
|
+
throw new Error(`compiler_release_operation_conflict:${input.operation_id}`);
|
|
140
|
+
}
|
|
141
|
+
return Object.freeze({ promotable: true, switched: false, receipt: replay });
|
|
142
|
+
}
|
|
143
|
+
const before = await input.authority.read();
|
|
144
|
+
const localStore = new InMemoryCompilerReleaseStore(before);
|
|
145
|
+
const outcome = await promoteCompilerReleaseCandidate({ ...input, store: localStore });
|
|
146
|
+
if (!outcome.promotable)
|
|
147
|
+
return outcome;
|
|
148
|
+
const after = await input.authority.apply("promote", before.revision, outcome.receipt);
|
|
149
|
+
if (!identitiesEqual(after.active, outcome.receipt.active_after)) {
|
|
150
|
+
throw new Error("compiler_release_promotion_readback_mismatch");
|
|
151
|
+
}
|
|
152
|
+
const persisted = await input.authority.readOperation(input.operation_id);
|
|
153
|
+
if (persisted?.receipt_sha256 !== outcome.receipt.receipt_sha256) {
|
|
154
|
+
throw new Error("compiler_release_operation_readback_mismatch");
|
|
155
|
+
}
|
|
156
|
+
return Object.freeze({ ...outcome, receipt: persisted });
|
|
157
|
+
}
|
|
158
|
+
export async function rollbackPersistedCompilerRelease(input) {
|
|
159
|
+
const replay = await input.authority.readOperation(input.operation_id);
|
|
160
|
+
if (replay !== null) {
|
|
161
|
+
if (replay.operation_kind !== "rollback_active") {
|
|
162
|
+
throw new Error(`compiler_release_operation_conflict:${input.operation_id}`);
|
|
163
|
+
}
|
|
164
|
+
const source = sourceIdentity(cloneSourceSnapshot(await input.live_store.snapshot()));
|
|
165
|
+
if (replay.corpus_digest !== requireSha256(input.corpus_digest, "compiler_release_corpus_digest_invalid")
|
|
166
|
+
|| !sourceIdentitiesEqual(replay.source_before, source)
|
|
167
|
+
|| !sourceIdentitiesEqual(replay.source_after, source)) {
|
|
168
|
+
throw new Error(`compiler_release_operation_conflict:${input.operation_id}`);
|
|
169
|
+
}
|
|
170
|
+
return replay;
|
|
171
|
+
}
|
|
172
|
+
const before = await input.authority.read();
|
|
173
|
+
const localStore = new InMemoryCompilerReleaseStore(before);
|
|
174
|
+
const receipt = await rollbackCompilerRelease({ ...input, store: localStore });
|
|
175
|
+
const after = await input.authority.apply("rollback", before.revision, receipt);
|
|
176
|
+
if (!identitiesEqual(after.active, receipt.active_after)) {
|
|
177
|
+
throw new Error("compiler_release_rollback_readback_mismatch");
|
|
178
|
+
}
|
|
179
|
+
const persisted = await input.authority.readOperation(input.operation_id);
|
|
180
|
+
if (persisted?.receipt_sha256 !== receipt.receipt_sha256) {
|
|
181
|
+
throw new Error("compiler_release_operation_readback_mismatch");
|
|
182
|
+
}
|
|
183
|
+
return persisted;
|
|
184
|
+
}
|
|
185
|
+
function requireIdentifier(value, code) {
|
|
186
|
+
if (value.length === 0 || value !== value.trim().normalize("NFC")) {
|
|
187
|
+
throw new Error(code);
|
|
188
|
+
}
|
|
189
|
+
return value;
|
|
190
|
+
}
|
|
191
|
+
function requireSha256(value, code) {
|
|
192
|
+
if (!isSha256Hex(value))
|
|
193
|
+
throw new Error(code);
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
function bytesEqual(left, right) {
|
|
197
|
+
if (left.byteLength !== right.byteLength)
|
|
198
|
+
return false;
|
|
199
|
+
let difference = 0;
|
|
200
|
+
for (let index = 0; index < left.byteLength; index += 1) {
|
|
201
|
+
difference |= (left[index] ?? 0) ^ (right[index] ?? 0);
|
|
202
|
+
}
|
|
203
|
+
return difference === 0;
|
|
204
|
+
}
|
|
205
|
+
function cloneBytes(bytes) {
|
|
206
|
+
return bytes.slice();
|
|
207
|
+
}
|
|
208
|
+
function cloneIdentity(identity) {
|
|
209
|
+
if (identity === null)
|
|
210
|
+
return null;
|
|
211
|
+
return Object.freeze({
|
|
212
|
+
compiler_release: identity.compiler_release,
|
|
213
|
+
target_profile: parseCompileTargetProfile(identity.target_profile),
|
|
214
|
+
target_profile_sha256: requireSha256(identity.target_profile_sha256, "compiler_release_identity_digest_invalid"),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function sourceIdentity(snapshot) {
|
|
218
|
+
return Object.freeze({
|
|
219
|
+
source_sha256: snapshot.source_sha256,
|
|
220
|
+
manifest_sha256: snapshot.manifest_sha256,
|
|
221
|
+
head_digest: snapshot.head_digest,
|
|
222
|
+
source_revision: snapshot.source_revision,
|
|
223
|
+
author_operation_count: snapshot.author_operation_count,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
function sourceIdentitiesEqual(left, right) {
|
|
227
|
+
return left.source_sha256 === right.source_sha256
|
|
228
|
+
&& left.manifest_sha256 === right.manifest_sha256
|
|
229
|
+
&& left.head_digest === right.head_digest
|
|
230
|
+
&& left.source_revision === right.source_revision
|
|
231
|
+
&& left.author_operation_count === right.author_operation_count;
|
|
232
|
+
}
|
|
233
|
+
function cloneSourceSnapshot(snapshot) {
|
|
234
|
+
if (!(snapshot.source_bytes instanceof Uint8Array)
|
|
235
|
+
|| !Number.isSafeInteger(snapshot.source_revision)
|
|
236
|
+
|| snapshot.source_revision < 1
|
|
237
|
+
|| !Number.isSafeInteger(snapshot.author_operation_count)
|
|
238
|
+
|| snapshot.author_operation_count < 0)
|
|
239
|
+
throw new Error("compiler_release_source_snapshot_invalid");
|
|
240
|
+
return Object.freeze({
|
|
241
|
+
source_bytes: cloneBytes(snapshot.source_bytes),
|
|
242
|
+
source_sha256: requireSha256(snapshot.source_sha256, "compiler_release_source_digest_invalid"),
|
|
243
|
+
manifest_sha256: requireSha256(snapshot.manifest_sha256, "compiler_release_manifest_digest_invalid"),
|
|
244
|
+
head_digest: requireSha256(snapshot.head_digest, "compiler_release_head_digest_invalid"),
|
|
245
|
+
source_revision: snapshot.source_revision,
|
|
246
|
+
author_operation_count: snapshot.author_operation_count,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function sourceSnapshotsEqual(left, right) {
|
|
250
|
+
return left.source_sha256 === right.source_sha256
|
|
251
|
+
&& left.manifest_sha256 === right.manifest_sha256
|
|
252
|
+
&& left.head_digest === right.head_digest
|
|
253
|
+
&& left.source_revision === right.source_revision
|
|
254
|
+
&& left.author_operation_count === right.author_operation_count
|
|
255
|
+
&& bytesEqual(left.source_bytes, right.source_bytes);
|
|
256
|
+
}
|
|
257
|
+
function identitiesEqual(left, right) {
|
|
258
|
+
if (left === null || right === null)
|
|
259
|
+
return left === right;
|
|
260
|
+
return left.compiler_release === right.compiler_release
|
|
261
|
+
&& left.target_profile_sha256 === right.target_profile_sha256;
|
|
262
|
+
}
|
|
263
|
+
function compilerIdentitiesCompatible(left, right) {
|
|
264
|
+
const expected = left.target_profile;
|
|
265
|
+
const actual = right.target_profile;
|
|
266
|
+
return left.compiler_release === right.compiler_release
|
|
267
|
+
&& expected.schema_version === actual.schema_version
|
|
268
|
+
&& expected.sdk_schema === actual.sdk_schema
|
|
269
|
+
&& expected.artifact_format === actual.artifact_format
|
|
270
|
+
&& expected.stage_versions.length === actual.stage_versions.length
|
|
271
|
+
&& expected.stage_versions.every((stage, index) => {
|
|
272
|
+
const other = actual.stage_versions[index];
|
|
273
|
+
return other !== undefined
|
|
274
|
+
&& stage.stage_id === other.stage_id
|
|
275
|
+
&& stage.stage_version === other.stage_version;
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
function storeSnapshotsEqual(left, right) {
|
|
279
|
+
return identitiesEqual(left.active, right.active)
|
|
280
|
+
&& identitiesEqual(left.previous_active, right.previous_active);
|
|
281
|
+
}
|
|
282
|
+
async function identityFromCandidate(candidate) {
|
|
283
|
+
const targetProfile = parseCompileTargetProfile(candidate.target_profile);
|
|
284
|
+
assertRegistryMatchesTargetProfile(candidate.registry, targetProfile);
|
|
285
|
+
return Object.freeze({
|
|
286
|
+
compiler_release: targetProfile.compiler_release,
|
|
287
|
+
target_profile: targetProfile,
|
|
288
|
+
target_profile_sha256: await compileTargetProfileDigest(targetProfile),
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
async function digestCorpus(value) {
|
|
292
|
+
return tmwSha256Hex(canonicalTmwBytes(parseAcceptedNeutralSourceCorpus(value)));
|
|
293
|
+
}
|
|
294
|
+
function unknownContentWitnessesFromPasses(corpusValue, passes) {
|
|
295
|
+
const corpus = parseAcceptedNeutralSourceCorpus(corpusValue);
|
|
296
|
+
const passed = new Set(passes.map((entry) => entry.fixture_id));
|
|
297
|
+
const witnesses = [];
|
|
298
|
+
for (const entry of corpus.sources) {
|
|
299
|
+
if (!passed.has(entry.fixture_id))
|
|
300
|
+
continue;
|
|
301
|
+
for (const witness of entry.byte_range_witnesses) {
|
|
302
|
+
witnesses.push(Object.freeze({
|
|
303
|
+
kind: witness.kind,
|
|
304
|
+
path: `${entry.fixture_id}:${witness.path}`,
|
|
305
|
+
sha256: witness.sha256,
|
|
306
|
+
}));
|
|
307
|
+
}
|
|
308
|
+
for (const witness of entry.content_witnesses) {
|
|
309
|
+
if (witness.kind === "unknown_protobuf_fields"
|
|
310
|
+
|| witness.kind === "unknown_future_section"
|
|
311
|
+
|| witness.kind === "empty_section_payload") {
|
|
312
|
+
witnesses.push(Object.freeze({
|
|
313
|
+
kind: witness.kind,
|
|
314
|
+
path: `${entry.fixture_id}:${witness.section_key}`,
|
|
315
|
+
sha256: witness.sha256,
|
|
316
|
+
}));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return Object.freeze(witnesses);
|
|
321
|
+
}
|
|
322
|
+
async function sealReceipt(core) {
|
|
323
|
+
return Object.freeze({
|
|
324
|
+
...core,
|
|
325
|
+
receipt_sha256: await tmwSha256Hex(canonicalTmwBytes(core)),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
function replayOrConflict(existing, next) {
|
|
329
|
+
if (existing.receipt_sha256 === next.receipt_sha256)
|
|
330
|
+
return existing;
|
|
331
|
+
if (existing.operation_id === next.operation_id
|
|
332
|
+
&& existing.operation_kind === next.operation_kind
|
|
333
|
+
&& existing.corpus_digest === next.corpus_digest
|
|
334
|
+
&& identitiesEqual(existing.candidate, next.candidate)
|
|
335
|
+
&& identitiesEqual(existing.active_before, next.active_before)
|
|
336
|
+
&& identitiesEqual(existing.active_after, next.active_after)
|
|
337
|
+
&& sourceIdentitiesEqual(existing.source_before, next.source_before)
|
|
338
|
+
&& sourceIdentitiesEqual(existing.source_after, next.source_after))
|
|
339
|
+
return existing;
|
|
340
|
+
throw new Error(`compiler_release_operation_conflict:${next.operation_id}`);
|
|
341
|
+
}
|
|
342
|
+
export class InMemoryCompilerReleaseStore {
|
|
343
|
+
#snapshot;
|
|
344
|
+
constructor(initial = Object.freeze({
|
|
345
|
+
active: null,
|
|
346
|
+
previous_active: null,
|
|
347
|
+
})) {
|
|
348
|
+
this.#snapshot = Object.freeze({
|
|
349
|
+
active: cloneIdentity(initial.active),
|
|
350
|
+
previous_active: cloneIdentity(initial.previous_active),
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
async read() {
|
|
354
|
+
return Object.freeze({
|
|
355
|
+
active: cloneIdentity(this.#snapshot.active),
|
|
356
|
+
previous_active: cloneIdentity(this.#snapshot.previous_active),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
async writeOnce(expected, next) {
|
|
360
|
+
const current = await this.read();
|
|
361
|
+
const wanted = Object.freeze({
|
|
362
|
+
active: cloneIdentity(expected.active),
|
|
363
|
+
previous_active: cloneIdentity(expected.previous_active),
|
|
364
|
+
});
|
|
365
|
+
const following = Object.freeze({
|
|
366
|
+
active: cloneIdentity(next.active),
|
|
367
|
+
previous_active: cloneIdentity(next.previous_active),
|
|
368
|
+
});
|
|
369
|
+
if (storeSnapshotsEqual(current, following))
|
|
370
|
+
return "already_present";
|
|
371
|
+
if (!storeSnapshotsEqual(current, wanted)) {
|
|
372
|
+
throw new Error("compiler_release_store_cas_mismatch");
|
|
373
|
+
}
|
|
374
|
+
this.#snapshot = following;
|
|
375
|
+
return "stored";
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
export class MapBackedCompilerReleaseClearableCache {
|
|
379
|
+
#inner = new InMemoryCompilerStageCache();
|
|
380
|
+
#keys = new Set();
|
|
381
|
+
async read(cacheKey) {
|
|
382
|
+
return this.#inner.read(cacheKey);
|
|
383
|
+
}
|
|
384
|
+
async writeOnce(entry) {
|
|
385
|
+
const result = await this.#inner.writeOnce(entry);
|
|
386
|
+
this.#keys.add(entry.cache_key);
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
async delete(cacheKey) {
|
|
390
|
+
this.#keys.delete(cacheKey);
|
|
391
|
+
await this.#inner.delete(cacheKey);
|
|
392
|
+
}
|
|
393
|
+
async keys() {
|
|
394
|
+
return Object.freeze([...this.#keys].sort());
|
|
395
|
+
}
|
|
396
|
+
async clear() {
|
|
397
|
+
const observed = await this.keys();
|
|
398
|
+
await Promise.all(observed.map((cacheKey) => this.delete(cacheKey)));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
export class InMemoryCompilerReleaseDerivedStore {
|
|
402
|
+
#objects = new Map();
|
|
403
|
+
async read(objectId) {
|
|
404
|
+
const bytes = this.#objects.get(objectId);
|
|
405
|
+
return bytes === undefined ? null : cloneBytes(bytes);
|
|
406
|
+
}
|
|
407
|
+
async writeOnce(objectId, bytes) {
|
|
408
|
+
requireIdentifier(objectId, "compiler_release_derived_object_id_invalid");
|
|
409
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
410
|
+
throw new Error("compiler_release_derived_bytes_invalid");
|
|
411
|
+
}
|
|
412
|
+
const existing = this.#objects.get(objectId);
|
|
413
|
+
if (existing !== undefined) {
|
|
414
|
+
if (!bytesEqual(existing, bytes)) {
|
|
415
|
+
throw new Error("compiler_release_derived_write_conflict");
|
|
416
|
+
}
|
|
417
|
+
return "already_present";
|
|
418
|
+
}
|
|
419
|
+
this.#objects.set(objectId, cloneBytes(bytes));
|
|
420
|
+
return "stored";
|
|
421
|
+
}
|
|
422
|
+
async delete(objectId) {
|
|
423
|
+
this.#objects.delete(objectId);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
export class FrozenCompilerReleaseLiveStore {
|
|
427
|
+
#snapshot;
|
|
428
|
+
constructor(snapshot) {
|
|
429
|
+
this.#snapshot = cloneSourceSnapshot(snapshot);
|
|
430
|
+
}
|
|
431
|
+
async snapshot() {
|
|
432
|
+
return cloneSourceSnapshot(this.#snapshot);
|
|
433
|
+
}
|
|
434
|
+
async mutateWorkingProjection(mutator) {
|
|
435
|
+
const nextBytes = mutator(cloneBytes(this.#snapshot.source_bytes));
|
|
436
|
+
if (!(nextBytes instanceof Uint8Array)) {
|
|
437
|
+
throw new Error("compiler_release_live_store_mutation_invalid");
|
|
438
|
+
}
|
|
439
|
+
this.#snapshot = Object.freeze({
|
|
440
|
+
...this.#snapshot,
|
|
441
|
+
source_bytes: cloneBytes(nextBytes),
|
|
442
|
+
source_sha256: await tmwSha256Hex(nextBytes),
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
const operationReceipts = new Map();
|
|
447
|
+
function existingOperationReceipt(operationId) {
|
|
448
|
+
return operationReceipts.get(operationId);
|
|
449
|
+
}
|
|
450
|
+
function rememberReceipt(receipt) {
|
|
451
|
+
const existing = existingOperationReceipt(receipt.operation_id);
|
|
452
|
+
if (existing !== undefined)
|
|
453
|
+
return replayOrConflict(existing, receipt);
|
|
454
|
+
operationReceipts.set(receipt.operation_id, receipt);
|
|
455
|
+
return receipt;
|
|
456
|
+
}
|
|
457
|
+
async function buildPromotionReceipt(input, kind, candidateIdentity, activeBefore, activeAfter, previousActive, sourceBefore, sourceAfter, passes, failures) {
|
|
458
|
+
if (!sourceSnapshotsEqual(sourceBefore, sourceAfter)) {
|
|
459
|
+
throw new Error("compiler_release_source_mutated");
|
|
460
|
+
}
|
|
461
|
+
const core = Object.freeze({
|
|
462
|
+
receipt_schema_version: COMPILER_RELEASE_AUTHORITY_SCHEMA_VERSION,
|
|
463
|
+
operation_id: requireIdentifier(input.operation_id, "compiler_release_operation_id_invalid"),
|
|
464
|
+
operation_kind: kind,
|
|
465
|
+
corpus_digest: await digestCorpus(input.corpus_value),
|
|
466
|
+
candidate: candidateIdentity,
|
|
467
|
+
active_before: cloneIdentity(activeBefore),
|
|
468
|
+
active_after: cloneIdentity(activeAfter),
|
|
469
|
+
previous_active: cloneIdentity(previousActive),
|
|
470
|
+
source_before: sourceIdentity(sourceBefore),
|
|
471
|
+
source_after: sourceIdentity(sourceAfter),
|
|
472
|
+
fixture_passes: Object.freeze([...passes]),
|
|
473
|
+
fixture_failures: Object.freeze([...failures]),
|
|
474
|
+
unknown_content_witnesses: unknownContentWitnessesFromPasses(input.corpus_value, passes),
|
|
475
|
+
});
|
|
476
|
+
return rememberReceipt(await sealReceipt(core));
|
|
477
|
+
}
|
|
478
|
+
async function inspectCompilerReleaseCandidate(input) {
|
|
479
|
+
const sourceBefore = cloneSourceSnapshot(await input.live_store.snapshot());
|
|
480
|
+
const candidateIdentity = await identityFromCandidate(input.candidate);
|
|
481
|
+
const gate = await evaluateCompilerCandidate(input.candidate, input.corpus_value, input.load_fixture);
|
|
482
|
+
const sourceAfter = cloneSourceSnapshot(await input.live_store.snapshot());
|
|
483
|
+
return Object.freeze({
|
|
484
|
+
candidateIdentity,
|
|
485
|
+
sourceBefore,
|
|
486
|
+
sourceAfter,
|
|
487
|
+
passes: gate.passes,
|
|
488
|
+
failures: gate.failures,
|
|
489
|
+
promotable: gate.promotable,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
export async function evaluateCompilerReleaseCandidate(input, activeBefore = null) {
|
|
493
|
+
const inspected = await inspectCompilerReleaseCandidate(input);
|
|
494
|
+
if (inspected.promotable) {
|
|
495
|
+
return Object.freeze({
|
|
496
|
+
promotable: true,
|
|
497
|
+
switched: false,
|
|
498
|
+
receipt: await buildPromotionReceipt(input, "evaluate_candidate", inspected.candidateIdentity, activeBefore, activeBefore, activeBefore, inspected.sourceBefore, inspected.sourceAfter, inspected.passes, inspected.failures),
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
return Object.freeze({
|
|
502
|
+
promotable: false,
|
|
503
|
+
switched: false,
|
|
504
|
+
receipt: await buildPromotionReceipt(input, "reject_candidate", inspected.candidateIdentity, activeBefore, activeBefore, activeBefore, inspected.sourceBefore, inspected.sourceAfter, inspected.passes, inspected.failures),
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
export async function promoteCompilerReleaseCandidate(input) {
|
|
508
|
+
const existing = existingOperationReceipt(input.operation_id);
|
|
509
|
+
if (existing !== undefined) {
|
|
510
|
+
if (existing.operation_kind === "reject_candidate") {
|
|
511
|
+
return Object.freeze({
|
|
512
|
+
promotable: false,
|
|
513
|
+
switched: false,
|
|
514
|
+
receipt: existing,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
if (existing.operation_kind !== "promote_candidate") {
|
|
518
|
+
throw new Error(`compiler_release_operation_conflict:${input.operation_id}`);
|
|
519
|
+
}
|
|
520
|
+
return Object.freeze({
|
|
521
|
+
promotable: true,
|
|
522
|
+
switched: false,
|
|
523
|
+
receipt: existing,
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
const storeBefore = await input.store.read();
|
|
527
|
+
const inspected = await inspectCompilerReleaseCandidate(input);
|
|
528
|
+
if (!inspected.promotable) {
|
|
529
|
+
const current = await input.store.read();
|
|
530
|
+
if (!identitiesEqual(current.active, storeBefore.active)) {
|
|
531
|
+
throw new Error("compiler_release_active_drift");
|
|
532
|
+
}
|
|
533
|
+
return Object.freeze({
|
|
534
|
+
promotable: false,
|
|
535
|
+
switched: false,
|
|
536
|
+
receipt: await buildPromotionReceipt(input, "reject_candidate", inspected.candidateIdentity, storeBefore.active, storeBefore.active, storeBefore.previous_active, inspected.sourceBefore, inspected.sourceAfter, inspected.passes, inspected.failures),
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
const next = Object.freeze({
|
|
540
|
+
active: inspected.candidateIdentity,
|
|
541
|
+
previous_active: storeBefore.active,
|
|
542
|
+
});
|
|
543
|
+
await input.store.writeOnce(storeBefore, next);
|
|
544
|
+
const storeAfter = await input.store.read();
|
|
545
|
+
const sourceAfter = cloneSourceSnapshot(await input.live_store.snapshot());
|
|
546
|
+
if (!sourceSnapshotsEqual(inspected.sourceBefore, sourceAfter)) {
|
|
547
|
+
throw new Error("compiler_release_source_mutated");
|
|
548
|
+
}
|
|
549
|
+
return Object.freeze({
|
|
550
|
+
promotable: true,
|
|
551
|
+
switched: !identitiesEqual(storeBefore.active, storeAfter.active),
|
|
552
|
+
receipt: await buildPromotionReceipt(input, "promote_candidate", inspected.candidateIdentity, storeBefore.active, storeAfter.active, storeAfter.previous_active, inspected.sourceBefore, sourceAfter, inspected.passes, inspected.failures),
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
export async function rollbackCompilerRelease(input) {
|
|
556
|
+
const existing = existingOperationReceipt(input.operation_id);
|
|
557
|
+
if (existing !== undefined) {
|
|
558
|
+
if (existing.operation_kind !== "rollback_active") {
|
|
559
|
+
throw new Error(`compiler_release_operation_conflict:${input.operation_id}`);
|
|
560
|
+
}
|
|
561
|
+
return existing;
|
|
562
|
+
}
|
|
563
|
+
const sourceBefore = cloneSourceSnapshot(await input.live_store.snapshot());
|
|
564
|
+
const storeBefore = await input.store.read();
|
|
565
|
+
if (storeBefore.previous_active === null) {
|
|
566
|
+
throw new Error("compiler_release_rollback_previous_missing");
|
|
567
|
+
}
|
|
568
|
+
const next = Object.freeze({
|
|
569
|
+
active: storeBefore.previous_active,
|
|
570
|
+
previous_active: storeBefore.active,
|
|
571
|
+
});
|
|
572
|
+
await input.store.writeOnce(storeBefore, next);
|
|
573
|
+
const storeAfter = await input.store.read();
|
|
574
|
+
const sourceAfter = cloneSourceSnapshot(await input.live_store.snapshot());
|
|
575
|
+
if (!sourceSnapshotsEqual(sourceBefore, sourceAfter)) {
|
|
576
|
+
throw new Error("compiler_release_source_mutated");
|
|
577
|
+
}
|
|
578
|
+
if (storeBefore.active === null) {
|
|
579
|
+
throw new Error("compiler_release_rollback_active_missing");
|
|
580
|
+
}
|
|
581
|
+
const core = Object.freeze({
|
|
582
|
+
receipt_schema_version: COMPILER_RELEASE_AUTHORITY_SCHEMA_VERSION,
|
|
583
|
+
operation_id: requireIdentifier(input.operation_id, "compiler_release_operation_id_invalid"),
|
|
584
|
+
operation_kind: "rollback_active",
|
|
585
|
+
corpus_digest: requireSha256(input.corpus_digest, "compiler_release_corpus_digest_invalid"),
|
|
586
|
+
candidate: storeBefore.active,
|
|
587
|
+
active_before: storeBefore.active,
|
|
588
|
+
active_after: storeAfter.active,
|
|
589
|
+
previous_active: storeAfter.previous_active,
|
|
590
|
+
source_before: sourceIdentity(sourceBefore),
|
|
591
|
+
source_after: sourceIdentity(sourceAfter),
|
|
592
|
+
fixture_passes: Object.freeze([]),
|
|
593
|
+
fixture_failures: Object.freeze([]),
|
|
594
|
+
unknown_content_witnesses: Object.freeze([]),
|
|
595
|
+
});
|
|
596
|
+
return rememberReceipt(await sealReceipt(core));
|
|
597
|
+
}
|
|
598
|
+
export async function captureCompilerReleaseBuild(input) {
|
|
599
|
+
const snapshot = cloneSourceSnapshot(await input.live_store.snapshot());
|
|
600
|
+
const targetProfile = parseCompileTargetProfile(input.target_profile);
|
|
601
|
+
const source = await captureNeutralSourceCompileInput({
|
|
602
|
+
witness: input.witness,
|
|
603
|
+
source_bytes: snapshot.source_bytes,
|
|
604
|
+
});
|
|
605
|
+
return Object.freeze({
|
|
606
|
+
operation_id: requireIdentifier(input.operation_id, "compiler_release_operation_id_invalid"),
|
|
607
|
+
source,
|
|
608
|
+
target_profile: targetProfile,
|
|
609
|
+
target_profile_sha256: await compileTargetProfileDigest(targetProfile),
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
async function derivedDigest(objects) {
|
|
613
|
+
return tmwSha256Hex(canonicalTmwBytes(objects.map((object) => ({
|
|
614
|
+
stage_id: object.stage_id,
|
|
615
|
+
stage_version: object.stage_version,
|
|
616
|
+
media_type: object.media_type,
|
|
617
|
+
byte_length: object.byte_length,
|
|
618
|
+
sha256: object.sha256,
|
|
619
|
+
}))));
|
|
620
|
+
}
|
|
621
|
+
export async function rebuildCompilerReleaseArtifact(input) {
|
|
622
|
+
assertRegistryMatchesTargetProfile(input.registry, input.captured.target_profile);
|
|
623
|
+
const compiled = await compileNeutralScenarioSource(input.captured.source, input.captured.target_profile, input.registry, input.cache);
|
|
624
|
+
if (!compiled.ok) {
|
|
625
|
+
const first = compiled.diagnostics[0];
|
|
626
|
+
throw new Error(first?.code ?? "compiler_release_rebuild_failed");
|
|
627
|
+
}
|
|
628
|
+
const receiptBytes = canonicalNeutralSourceCompilerReceiptBytes(compiled.receipt);
|
|
629
|
+
const artifactDigest = await derivedDigest(compiled.derived_objects);
|
|
630
|
+
const witnessDigest = await tmwSha256Hex(receiptBytes);
|
|
631
|
+
if (compiled.receipt.receipt_sha256 !== witnessDigest) {
|
|
632
|
+
throw new Error("compiler_release_rebuild_witness_mismatch");
|
|
633
|
+
}
|
|
634
|
+
await input.derived_store.writeOnce(input.object_id, receiptBytes);
|
|
635
|
+
return Object.freeze({
|
|
636
|
+
ok: true,
|
|
637
|
+
operation_id: input.captured.operation_id,
|
|
638
|
+
compiler_release: compiled.receipt.compiler_release,
|
|
639
|
+
target_profile_sha256: compiled.receipt.target_profile_sha256,
|
|
640
|
+
source_manifest_sha256: compiled.receipt.source_manifest_sha256,
|
|
641
|
+
receipt: compiled.receipt,
|
|
642
|
+
derived_objects: compiled.derived_objects,
|
|
643
|
+
artifact_digest: artifactDigest,
|
|
644
|
+
witness_digest: witnessDigest,
|
|
645
|
+
cache_keys: await input.cache.keys(),
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
export async function clearAndRebuildCompilerReleaseArtifact(input) {
|
|
649
|
+
await input.cache.clear();
|
|
650
|
+
await input.derived_store.delete(input.object_id);
|
|
651
|
+
return rebuildCompilerReleaseArtifact(input);
|
|
652
|
+
}
|
|
653
|
+
export async function requireActiveCompilerRelease(store, expected) {
|
|
654
|
+
const current = await store.read();
|
|
655
|
+
if (current.active === null) {
|
|
656
|
+
throw new Error("compiler_release_active_missing");
|
|
657
|
+
}
|
|
658
|
+
const expectedIdentity = Object.freeze({
|
|
659
|
+
compiler_release: expected.compiler_release,
|
|
660
|
+
target_profile: parseCompileTargetProfile(expected),
|
|
661
|
+
target_profile_sha256: await compileTargetProfileDigest(expected),
|
|
662
|
+
});
|
|
663
|
+
if (!compilerIdentitiesCompatible(current.active, expectedIdentity)) {
|
|
664
|
+
throw new Error(`compiler_release_active_mismatch:${current.active.compiler_release}`);
|
|
665
|
+
}
|
|
666
|
+
return expectedIdentity;
|
|
667
|
+
}
|
|
668
|
+
/** @deprecated 生产 caller 必须注入 Edge readback;保留导出仅为增量兼容并始终 fail-closed。 */
|
|
669
|
+
export const defaultCompilerReleaseStore = Object.freeze({
|
|
670
|
+
async read() {
|
|
671
|
+
throw new Error("compiler_release_authority_unconfigured");
|
|
672
|
+
},
|
|
673
|
+
async writeOnce() {
|
|
674
|
+
throw new Error("compiler_release_authority_unconfigured");
|
|
675
|
+
},
|
|
676
|
+
});
|