@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
package/LICENSE
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
WorldEngine 官方作者工具许可证
|
|
2
|
+
|
|
3
|
+
版权所有 (c) 2026 Nixdorfer。保留所有权利。
|
|
4
|
+
|
|
5
|
+
本仓库的源代码、构建材料及附带资源(统称“本作品”)不是开源软件,
|
|
6
|
+
不适用任何 OSI 认证的开源许可证。
|
|
7
|
+
|
|
8
|
+
一、官方作者工具分发许可
|
|
9
|
+
|
|
10
|
+
版权所有者可以通过其官方网站、npm registry、签名安装包或其他官方渠道,
|
|
11
|
+
复制并分发由本作品构建的 WorldEngine 作者工具及其必要运行资源
|
|
12
|
+
(统称“官方作者工具”)。仅版权所有者或其书面指定的发布者享有此分发权。
|
|
13
|
+
|
|
14
|
+
二、作者用户许可
|
|
15
|
+
|
|
16
|
+
从官方渠道取得官方作者工具的作者用户,可以:
|
|
17
|
+
|
|
18
|
+
1. 安装和运行官方作者工具;
|
|
19
|
+
2. 使用官方作者工具创作、编辑、预览、导入、导出和提交其有权处理的内容;
|
|
20
|
+
3. 为上述使用目的制作合理必要的本地备份副本。
|
|
21
|
+
|
|
22
|
+
三、未授予的权利
|
|
23
|
+
|
|
24
|
+
除第二条明确允许的行为外,本许可证不授予作者用户或其他第三方以下权利:
|
|
25
|
+
|
|
26
|
+
1. 修改、改编、反编译、反汇编或制作官方作者工具的派生作品;
|
|
27
|
+
2. 复制、镜像、转发、再上传、出售、出租、再分发或再许可官方作者工具;
|
|
28
|
+
3. 使用本作品的源代码、构建材料或任何部分开发、提供或训练其他产品或服务;
|
|
29
|
+
4. 删除或规避版权、许可、签名、访问控制或其他权利管理信息。
|
|
30
|
+
|
|
31
|
+
法律强制允许且合同不得排除的权利不受上述限制影响。
|
|
32
|
+
|
|
33
|
+
四、源代码查看
|
|
34
|
+
|
|
35
|
+
第三方可以在已获合法访问权限的范围内查看本作品,用于审查、安全研究或学习参考;
|
|
36
|
+
查看不授予运行、复制、修改、分发、再许可或用于其他产品与服务的权利。
|
|
37
|
+
|
|
38
|
+
五、无担保与责任限制
|
|
39
|
+
|
|
40
|
+
本作品与官方作者工具均按“现状”提供,不附带任何明示或暗示的担保。
|
|
41
|
+
在适用法律允许的最大范围内,版权所有者不对因访问或使用本作品或官方作者工具
|
|
42
|
+
造成的任何损失承担责任。
|
|
43
|
+
|
|
44
|
+
六、终止
|
|
45
|
+
|
|
46
|
+
违反本许可证将立即终止相应的访问与使用权;终止不影响版权所有者已经产生的权利和救济。
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
|
|
2
|
+
import { type AudioPresentationProjectionV1 } from "./audio-presentation-projection.js";
|
|
3
|
+
import { type DurableIntentV3 } from "./durable-intent.js";
|
|
4
|
+
import type { RuntimeSavExtensionSectionV3 } from "./runtime-sav.js";
|
|
5
|
+
import type { TimelineHeadV3, TimelineRevisionV3 } from "./timeline-revision.js";
|
|
6
|
+
import { type TmwJsonValue } from "./runtime-trace.js";
|
|
7
|
+
export interface TmwActivationExpectedHead extends TimelineHeadV3 {
|
|
8
|
+
}
|
|
9
|
+
export interface TmwActivationCandidateV3 {
|
|
10
|
+
readonly operationId: string;
|
|
11
|
+
readonly epoch: number;
|
|
12
|
+
readonly runtimeGeneration: typeof TMW_RUNTIME_GENERATION;
|
|
13
|
+
readonly runtimeContractHash: string;
|
|
14
|
+
readonly artifactDigest: string;
|
|
15
|
+
readonly sourceRevision: string;
|
|
16
|
+
readonly expectedHead: TmwActivationExpectedHead | null;
|
|
17
|
+
readonly timeline: TimelineRevisionV3;
|
|
18
|
+
readonly ledger: TmwJsonValue;
|
|
19
|
+
readonly ledgerHead: string;
|
|
20
|
+
readonly narrative: TmwJsonValue;
|
|
21
|
+
readonly narrativeDigest: string;
|
|
22
|
+
readonly savSection: RuntimeSavExtensionSectionV3;
|
|
23
|
+
readonly savSectionDigest: string;
|
|
24
|
+
readonly intents: ReadonlyArray<DurableIntentV3>;
|
|
25
|
+
readonly intentSetDigest: string;
|
|
26
|
+
readonly presentationIntents: ReadonlyArray<TmwJsonValue>;
|
|
27
|
+
readonly presentationIntentSetDigest: string;
|
|
28
|
+
readonly audioPresentation?: AudioPresentationProjectionV1 | null;
|
|
29
|
+
readonly preActivationTerminalDigest: string;
|
|
30
|
+
}
|
|
31
|
+
export interface TmwActivationReceiptV3 {
|
|
32
|
+
readonly operationId: string;
|
|
33
|
+
readonly status: "committed" | "already_committed" | "conflict";
|
|
34
|
+
readonly previousHead: TmwActivationExpectedHead | null;
|
|
35
|
+
readonly activeHead: TmwActivationExpectedHead;
|
|
36
|
+
readonly atomicWriteCount: number;
|
|
37
|
+
readonly candidateDigest: string;
|
|
38
|
+
readonly receiptDigest: string;
|
|
39
|
+
}
|
|
40
|
+
export interface TmwActivationAtomicPort {
|
|
41
|
+
/**
|
|
42
|
+
* Player-owned TurnCommit/CAS primitive. Edge must never implement or call
|
|
43
|
+
* this port; Edge returns only validated compute/Judge candidates.
|
|
44
|
+
*/
|
|
45
|
+
commitAtomic(candidate: TmwActivationCandidateV3): Promise<TmwActivationReceiptV3>;
|
|
46
|
+
readByOperation(operationId: string): Promise<TmwActivationReceiptV3 | null>;
|
|
47
|
+
}
|
|
48
|
+
export declare function canonicalTmwActivationCandidate(input: TmwActivationCandidateV3): TmwActivationCandidateV3;
|
|
49
|
+
export declare function tmwActivationCandidateDigest(candidateInput: TmwActivationCandidateV3): Promise<string>;
|
|
50
|
+
export declare function activateTmwCandidate(candidateInput: TmwActivationCandidateV3, port: TmwActivationAtomicPort): Promise<TmwActivationReceiptV3>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
|
|
2
|
+
import { canonicalAudioPresentationProjection } from "./audio-presentation-projection.js";
|
|
3
|
+
import { canonicalDurableIntent } from "./durable-intent.js";
|
|
4
|
+
import { assertTimelineSuccessor } from "./timeline-revision.js";
|
|
5
|
+
import { canonicalTmwJson, canonicalTmwJsonValue, requireTmwIdentifier, requireTmwSafeInteger, requireTmwSha256, tmwSha256Hex, } from "./runtime-trace.js";
|
|
6
|
+
export function canonicalTmwActivationCandidate(input) {
|
|
7
|
+
if (input.runtimeGeneration !== 3)
|
|
8
|
+
throw new Error("unsupported_runtime_generation");
|
|
9
|
+
const timeline = assertTimelineSuccessor(input.expectedHead, input.timeline);
|
|
10
|
+
if (timeline.epoch !== input.epoch
|
|
11
|
+
|| timeline.runtimeContractHash !== input.runtimeContractHash
|
|
12
|
+
|| timeline.artifactDigest !== input.artifactDigest
|
|
13
|
+
|| timeline.sourceRevision !== input.sourceRevision
|
|
14
|
+
|| timeline.operationId !== input.operationId) {
|
|
15
|
+
throw new Error("tmw_activation_timeline_binding_mismatch");
|
|
16
|
+
}
|
|
17
|
+
if (timeline.ledgerHead !== input.ledgerHead)
|
|
18
|
+
throw new Error("tmw_activation_ledger_head_mismatch");
|
|
19
|
+
if (timeline.narrativeDigest !== input.narrativeDigest) {
|
|
20
|
+
throw new Error("tmw_activation_narrative_digest_mismatch");
|
|
21
|
+
}
|
|
22
|
+
if (timeline.savSectionDigest !== input.savSectionDigest) {
|
|
23
|
+
throw new Error("tmw_activation_sav_digest_mismatch");
|
|
24
|
+
}
|
|
25
|
+
if (timeline.intentSetDigest !== input.intentSetDigest
|
|
26
|
+
|| timeline.presentationIntentSetDigest !== input.presentationIntentSetDigest) {
|
|
27
|
+
throw new Error("tmw_activation_intent_digest_mismatch");
|
|
28
|
+
}
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
operationId: requireTmwIdentifier(input.operationId, "activation_operation_id"),
|
|
31
|
+
epoch: requireTmwSafeInteger(input.epoch, "activation_epoch", 1),
|
|
32
|
+
runtimeGeneration: TMW_RUNTIME_GENERATION,
|
|
33
|
+
runtimeContractHash: requireTmwSha256(input.runtimeContractHash, "activation_contract_hash"),
|
|
34
|
+
artifactDigest: requireTmwSha256(input.artifactDigest, "activation_artifact_digest"),
|
|
35
|
+
sourceRevision: requireTmwIdentifier(input.sourceRevision, "activation_source_revision"),
|
|
36
|
+
expectedHead: input.expectedHead,
|
|
37
|
+
timeline,
|
|
38
|
+
ledger: canonicalTmwJsonValue(input.ledger, "activation_ledger"),
|
|
39
|
+
ledgerHead: requireTmwSha256(input.ledgerHead, "activation_ledger_head"),
|
|
40
|
+
narrative: canonicalTmwJsonValue(input.narrative, "activation_narrative"),
|
|
41
|
+
narrativeDigest: requireTmwSha256(input.narrativeDigest, "activation_narrative_digest"),
|
|
42
|
+
savSection: input.savSection,
|
|
43
|
+
savSectionDigest: requireTmwSha256(input.savSectionDigest, "activation_sav_digest"),
|
|
44
|
+
intents: Object.freeze(input.intents.map(canonicalDurableIntent).sort((left, right) => left.intentId < right.intentId ? -1 : left.intentId > right.intentId ? 1 : 0)),
|
|
45
|
+
intentSetDigest: requireTmwSha256(input.intentSetDigest, "activation_intent_digest"),
|
|
46
|
+
presentationIntents: Object.freeze(input.presentationIntents.map((intent) => canonicalTmwJsonValue(intent, "activation_presentation_intent"))),
|
|
47
|
+
presentationIntentSetDigest: requireTmwSha256(input.presentationIntentSetDigest, "activation_presentation_digest"),
|
|
48
|
+
audioPresentation: input.audioPresentation == null
|
|
49
|
+
? null
|
|
50
|
+
: canonicalAudioPresentationProjection(input.audioPresentation),
|
|
51
|
+
preActivationTerminalDigest: requireTmwSha256(input.preActivationTerminalDigest, "activation_terminal_digest"),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function bytesToHex(bytes) {
|
|
55
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
56
|
+
}
|
|
57
|
+
function candidateDigestImage(candidate) {
|
|
58
|
+
return canonicalTmwJsonValue({
|
|
59
|
+
operationId: candidate.operationId,
|
|
60
|
+
epoch: candidate.epoch,
|
|
61
|
+
runtimeGeneration: candidate.runtimeGeneration,
|
|
62
|
+
runtimeContractHash: candidate.runtimeContractHash,
|
|
63
|
+
artifactDigest: candidate.artifactDigest,
|
|
64
|
+
sourceRevision: candidate.sourceRevision,
|
|
65
|
+
expectedHead: candidate.expectedHead,
|
|
66
|
+
timeline: candidate.timeline,
|
|
67
|
+
ledger: candidate.ledger,
|
|
68
|
+
ledgerHead: candidate.ledgerHead,
|
|
69
|
+
narrative: candidate.narrative,
|
|
70
|
+
narrativeDigest: candidate.narrativeDigest,
|
|
71
|
+
savSection: {
|
|
72
|
+
extensionId: candidate.savSection.extension_id,
|
|
73
|
+
schemaVersion: candidate.savSection.schema_version,
|
|
74
|
+
required: candidate.savSection.required,
|
|
75
|
+
payloadHex: bytesToHex(candidate.savSection.payload),
|
|
76
|
+
codec: candidate.savSection.codec,
|
|
77
|
+
sha256Hex: bytesToHex(candidate.savSection.payload_sha256),
|
|
78
|
+
},
|
|
79
|
+
savSectionDigest: candidate.savSectionDigest,
|
|
80
|
+
intents: candidate.intents,
|
|
81
|
+
intentSetDigest: candidate.intentSetDigest,
|
|
82
|
+
presentationIntents: candidate.presentationIntents,
|
|
83
|
+
presentationIntentSetDigest: candidate.presentationIntentSetDigest,
|
|
84
|
+
audioPresentation: candidate.audioPresentation ?? null,
|
|
85
|
+
preActivationTerminalDigest: candidate.preActivationTerminalDigest,
|
|
86
|
+
}, "activation_candidate_digest_image");
|
|
87
|
+
}
|
|
88
|
+
export async function tmwActivationCandidateDigest(candidateInput) {
|
|
89
|
+
const candidate = canonicalTmwActivationCandidate(candidateInput);
|
|
90
|
+
return await tmwSha256Hex(canonicalTmwJson(candidateDigestImage(candidate)));
|
|
91
|
+
}
|
|
92
|
+
export async function activateTmwCandidate(candidateInput, port) {
|
|
93
|
+
const candidate = canonicalTmwActivationCandidate(candidateInput);
|
|
94
|
+
const candidateDigest = await tmwActivationCandidateDigest(candidate);
|
|
95
|
+
const existing = await port.readByOperation(candidate.operationId);
|
|
96
|
+
if (existing !== null) {
|
|
97
|
+
if (existing.candidateDigest !== candidateDigest) {
|
|
98
|
+
throw new Error("tmw_activation_operation_identity_conflict");
|
|
99
|
+
}
|
|
100
|
+
return existing;
|
|
101
|
+
}
|
|
102
|
+
const receipt = await port.commitAtomic(candidate);
|
|
103
|
+
if (receipt.candidateDigest !== candidateDigest) {
|
|
104
|
+
throw new Error("tmw_activation_receipt_candidate_mismatch");
|
|
105
|
+
}
|
|
106
|
+
if (receipt.status !== "conflict" && receipt.activeHead.revisionId !== candidate.timeline.revisionId) {
|
|
107
|
+
throw new Error("tmw_activation_readback_mismatch");
|
|
108
|
+
}
|
|
109
|
+
if (receipt.atomicWriteCount !== (receipt.status === "conflict" ? 0 : 5)) {
|
|
110
|
+
throw new Error("tmw_activation_atomic_write_count_invalid");
|
|
111
|
+
}
|
|
112
|
+
return receipt;
|
|
113
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface AudioPresentationSegmentV1 {
|
|
2
|
+
readonly segmentId: string;
|
|
3
|
+
readonly ordinal: number;
|
|
4
|
+
readonly text: string;
|
|
5
|
+
readonly speakerLabel: string | null;
|
|
6
|
+
readonly sfx: ReadonlyArray<Readonly<{
|
|
7
|
+
cueId: string;
|
|
8
|
+
ruleId: string;
|
|
9
|
+
resourceId: string;
|
|
10
|
+
priority: number;
|
|
11
|
+
cooldownMs: number;
|
|
12
|
+
}>>;
|
|
13
|
+
}
|
|
14
|
+
export interface AudioPresentationProjectionV1 {
|
|
15
|
+
readonly schema: "audio-presentation.v1";
|
|
16
|
+
readonly messageId: string;
|
|
17
|
+
readonly planHash: string;
|
|
18
|
+
readonly mode: "document" | "galgame";
|
|
19
|
+
readonly fullText: string;
|
|
20
|
+
readonly segments: ReadonlyArray<AudioPresentationSegmentV1>;
|
|
21
|
+
}
|
|
22
|
+
export declare const canonicalAudioPresentationProjection: (input: AudioPresentationProjectionV1) => AudioPresentationProjectionV1;
|
|
23
|
+
export declare const audioPresentationDigestImage: (input: AudioPresentationProjectionV1) => string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { canonicalTmwJson, requireTmwIdentifier, requireTmwSafeInteger, requireTmwSha256 } from "./runtime-trace.js";
|
|
2
|
+
export const canonicalAudioPresentationProjection = (input) => {
|
|
3
|
+
if (input.schema !== "audio-presentation.v1")
|
|
4
|
+
throw new Error("audio_presentation_schema_invalid");
|
|
5
|
+
const segments = input.segments.map((segment, index) => {
|
|
6
|
+
if (requireTmwIdentifier(segment.segmentId, "audio_presentation_segment_id") !== segment.segmentId
|
|
7
|
+
|| requireTmwSafeInteger(segment.ordinal, "audio_presentation_segment_ordinal", 0) !== index
|
|
8
|
+
|| typeof segment.text !== "string"
|
|
9
|
+
|| (segment.speakerLabel !== null && typeof segment.speakerLabel !== "string")) {
|
|
10
|
+
throw new Error("audio_presentation_segment_invalid");
|
|
11
|
+
}
|
|
12
|
+
return Object.freeze({
|
|
13
|
+
...segment,
|
|
14
|
+
sfx: Object.freeze(segment.sfx.map((cue) => Object.freeze({
|
|
15
|
+
cueId: requireTmwIdentifier(cue.cueId, "audio_presentation_cue_id"),
|
|
16
|
+
ruleId: requireTmwIdentifier(cue.ruleId, "audio_presentation_rule_id"),
|
|
17
|
+
resourceId: requireTmwIdentifier(cue.resourceId, "audio_presentation_resource_id"),
|
|
18
|
+
priority: requireTmwSafeInteger(cue.priority, "audio_presentation_priority", 0),
|
|
19
|
+
cooldownMs: requireTmwSafeInteger(cue.cooldownMs, "audio_presentation_cooldown", 0),
|
|
20
|
+
}))),
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
if (segments.length === 0 || segments.length > 128 || (input.mode !== "document" && input.mode !== "galgame")) {
|
|
24
|
+
throw new Error("audio_presentation_plan_invalid");
|
|
25
|
+
}
|
|
26
|
+
const projection = Object.freeze({
|
|
27
|
+
schema: "audio-presentation.v1",
|
|
28
|
+
messageId: requireTmwIdentifier(input.messageId, "audio_presentation_message_id"),
|
|
29
|
+
planHash: requireTmwSha256(input.planHash, "audio_presentation_plan_hash"),
|
|
30
|
+
mode: input.mode,
|
|
31
|
+
fullText: input.fullText,
|
|
32
|
+
segments: Object.freeze(segments),
|
|
33
|
+
});
|
|
34
|
+
if (projection.fullText !== projection.segments.map((segment) => segment.text).join("")) {
|
|
35
|
+
throw new Error("audio_presentation_text_mismatch");
|
|
36
|
+
}
|
|
37
|
+
return projection;
|
|
38
|
+
};
|
|
39
|
+
export const audioPresentationDigestImage = (input) => canonicalTmwJson(canonicalAudioPresentationProjection(input));
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TmwJsonValue } from "./runtime-contract.js";
|
|
2
|
+
import { AUTHOR_SCENARIO_SOURCE_V3_SCHEMA_VERSION, TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
|
|
3
|
+
import type { TriggerDocumentV3 } from "./trigger-document-v3.js";
|
|
4
|
+
import type { MusicCandidateSourceV3 } from "./music-candidate-set.js";
|
|
5
|
+
import type { ViewInteractionSourceV3 } from "./view-interaction-manifest-v3.js";
|
|
6
|
+
export interface AuthorScenarioSourceV3 {
|
|
7
|
+
readonly schema_version: typeof AUTHOR_SCENARIO_SOURCE_V3_SCHEMA_VERSION;
|
|
8
|
+
readonly runtime_generation: typeof TMW_RUNTIME_GENERATION;
|
|
9
|
+
readonly owner_id: string;
|
|
10
|
+
readonly scenario_id: string;
|
|
11
|
+
readonly epoch: number;
|
|
12
|
+
readonly source_revision: number;
|
|
13
|
+
readonly previous_revision_digest: string | null;
|
|
14
|
+
readonly trigger_document: TriggerDocumentV3;
|
|
15
|
+
readonly view_interaction_mobile: ViewInteractionSourceV3 | null;
|
|
16
|
+
readonly view_interaction_pc: ViewInteractionSourceV3 | null;
|
|
17
|
+
readonly music_candidate_source: MusicCandidateSourceV3;
|
|
18
|
+
readonly source_metadata: Readonly<Record<string, TmwJsonValue>>;
|
|
19
|
+
}
|
|
20
|
+
export interface AuthenticatedCreateNewSourceInput {
|
|
21
|
+
readonly operation: "create-new";
|
|
22
|
+
readonly auth_principal_id: string;
|
|
23
|
+
readonly owner_id: string;
|
|
24
|
+
readonly scenario_id: string;
|
|
25
|
+
readonly epoch: number;
|
|
26
|
+
readonly registry_version: string;
|
|
27
|
+
}
|
|
28
|
+
export interface AuthorSourceIdentityV3 {
|
|
29
|
+
readonly owner_id: string;
|
|
30
|
+
readonly scenario_id: string;
|
|
31
|
+
readonly epoch: number;
|
|
32
|
+
readonly source_revision: number;
|
|
33
|
+
readonly source_sha256: string;
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type TmwActivationReceiptV3 } from "./activation.js";
|
|
2
|
+
import type { TmwDiagnostic } from "./diagnostics.js";
|
|
3
|
+
import { type CommittedEventEnvelope } from "./event-fabric.js";
|
|
4
|
+
import type { EffectPlan } from "./effect-flow.js";
|
|
5
|
+
import type { RuntimeSavPayloadV3 } from "./runtime-sav.js";
|
|
6
|
+
import { type RuntimeTraceSnapshot, type TmwJsonValue } from "./runtime-trace.js";
|
|
7
|
+
import { type TmwSimulationTraceEntry } from "./simulator.js";
|
|
8
|
+
export interface TmwAuthoringEventV3 {
|
|
9
|
+
readonly event_type: string;
|
|
10
|
+
readonly payload: Readonly<Record<string, TmwJsonValue>>;
|
|
11
|
+
readonly event_id?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface TmwAuthoringEffectStageInput {
|
|
14
|
+
readonly operation_id: string;
|
|
15
|
+
readonly event: CommittedEventEnvelope;
|
|
16
|
+
readonly plans: ReadonlyArray<EffectPlan>;
|
|
17
|
+
readonly state: TmwJsonValue;
|
|
18
|
+
}
|
|
19
|
+
export interface TmwAuthoringEffectStageReceipt {
|
|
20
|
+
readonly state: TmwJsonValue;
|
|
21
|
+
readonly receipt_digest: string;
|
|
22
|
+
readonly world_mutation_recovery_operation?: TmwJsonValue;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 作者试玩的受控 effect seam。实现方只能消费 Runtime3 已冻结的 EffectPlan,
|
|
26
|
+
* 不能获得数据库、文件系统或任意代码执行 capability。
|
|
27
|
+
*/
|
|
28
|
+
export interface TmwAuthoringEffectPort {
|
|
29
|
+
stage(input: TmwAuthoringEffectStageInput): Promise<TmwAuthoringEffectStageReceipt>;
|
|
30
|
+
}
|
|
31
|
+
export interface ExecuteTmw3AuthoringInput {
|
|
32
|
+
readonly document: unknown;
|
|
33
|
+
readonly event: TmwAuthoringEventV3;
|
|
34
|
+
readonly initial_state: TmwJsonValue;
|
|
35
|
+
readonly effect_port: TmwAuthoringEffectPort;
|
|
36
|
+
readonly semantic_predicates?: Readonly<Record<string, "true" | "false" | "unknown">>;
|
|
37
|
+
/** Explicit authoring-simulator clock authority; never inferred from authored effective_time. */
|
|
38
|
+
readonly clock_observation?: Readonly<{
|
|
39
|
+
coordinates: CommittedEventEnvelope["coordinates"];
|
|
40
|
+
crossing_direction: CommittedEventEnvelope["crossingDirection"];
|
|
41
|
+
}>;
|
|
42
|
+
readonly source_revision?: string;
|
|
43
|
+
readonly max_trace_entries?: number;
|
|
44
|
+
}
|
|
45
|
+
export type ExecuteTmw3AuthoringOutcome = {
|
|
46
|
+
readonly ok: false;
|
|
47
|
+
readonly diagnostics: readonly TmwDiagnostic[];
|
|
48
|
+
} | {
|
|
49
|
+
readonly ok: true;
|
|
50
|
+
readonly document_sha256: string;
|
|
51
|
+
readonly plan_sha256: string;
|
|
52
|
+
readonly simulation_trace: readonly TmwSimulationTraceEntry[];
|
|
53
|
+
readonly runtime_trace: RuntimeTraceSnapshot;
|
|
54
|
+
readonly state: TmwJsonValue;
|
|
55
|
+
readonly state_digest: string;
|
|
56
|
+
readonly runtime_sav: RuntimeSavPayloadV3;
|
|
57
|
+
readonly activation: TmwActivationReceiptV3;
|
|
58
|
+
readonly diagnostics: readonly TmwDiagnostic[];
|
|
59
|
+
};
|
|
60
|
+
export type ValidateTmw3AuthoringOutcome = {
|
|
61
|
+
readonly ok: false;
|
|
62
|
+
readonly diagnostics: readonly TmwDiagnostic[];
|
|
63
|
+
} | {
|
|
64
|
+
readonly ok: true;
|
|
65
|
+
readonly document_sha256: string;
|
|
66
|
+
readonly plan_sha256: string;
|
|
67
|
+
readonly simulation_trace: readonly TmwSimulationTraceEntry[];
|
|
68
|
+
readonly diagnostics: readonly TmwDiagnostic[];
|
|
69
|
+
};
|
|
70
|
+
/** 只做真实 parser/validator/compiler 与无副作用计划模拟,不创建执行 receipt。 */
|
|
71
|
+
export declare function validateTmw3Authoring(document: unknown): Promise<ValidateTmw3AuthoringOutcome>;
|
|
72
|
+
/**
|
|
73
|
+
* Node/Browser 均可消费的作者试玩入口。simulation_trace 只用于计划预览;
|
|
74
|
+
* runtime_trace 仅记录 Runtime3 的真实 executeCommittedEvent 阶段。
|
|
75
|
+
*/
|
|
76
|
+
export declare function executeTmw3Authoring(input: ExecuteTmw3AuthoringInput): Promise<ExecuteTmw3AuthoringOutcome>;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { tmwActivationCandidateDigest } from "./activation.js";
|
|
2
|
+
import { getCanonicalTmwCapabilityRegistryV3 } from "./capability-registry.js";
|
|
3
|
+
import { compileTmw3 } from "./compiler.js";
|
|
4
|
+
import { TMW_EMPTY_LEDGER_HEAD } from "./event-fabric.js";
|
|
5
|
+
import { createTmwRuntimeHost } from "./runtime.js";
|
|
6
|
+
import { BoundedRuntimeTrace, canonicalTmwJson, canonicalTmwJsonValue, tmwSha256Hex } from "./runtime-trace.js";
|
|
7
|
+
import { simulateTmw3 } from "./simulator.js";
|
|
8
|
+
import { validateTmw3 } from "./validator.js";
|
|
9
|
+
import { canonicalTmwSceneStateV1 } from "./scene-state.js";
|
|
10
|
+
import { initialTmwGameplayStateFromWorldV1 } from "./gameplay-state.js";
|
|
11
|
+
const ZERO_SHA256 = "0".repeat(64);
|
|
12
|
+
async function prepareTmw3Authoring(document, runtimeTarget = "production") {
|
|
13
|
+
const registry = getCanonicalTmwCapabilityRegistryV3();
|
|
14
|
+
const validated = await validateTmw3(document, registry);
|
|
15
|
+
if (!validated.ok)
|
|
16
|
+
return validated;
|
|
17
|
+
const compiled = await compileTmw3(validated.value, registry, { runtime_target: runtimeTarget });
|
|
18
|
+
if (!compiled.ok)
|
|
19
|
+
return compiled;
|
|
20
|
+
const simulation = await simulateTmw3(validated.value, registry);
|
|
21
|
+
if (!simulation.ok)
|
|
22
|
+
return simulation;
|
|
23
|
+
return Object.freeze({
|
|
24
|
+
ok: true,
|
|
25
|
+
document: validated.value,
|
|
26
|
+
plan: compiled.plan,
|
|
27
|
+
simulation_trace: simulation.trace,
|
|
28
|
+
diagnostics: compiled.diagnostics,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** 只做真实 parser/validator/compiler 与无副作用计划模拟,不创建执行 receipt。 */
|
|
32
|
+
export async function validateTmw3Authoring(document) {
|
|
33
|
+
const prepared = await prepareTmw3Authoring(document);
|
|
34
|
+
if (!prepared.ok)
|
|
35
|
+
return prepared;
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
ok: true,
|
|
38
|
+
document_sha256: prepared.plan.document_sha256,
|
|
39
|
+
plan_sha256: prepared.plan.plan_sha256,
|
|
40
|
+
simulation_trace: prepared.simulation_trace,
|
|
41
|
+
diagnostics: prepared.diagnostics,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function initialSav(input) {
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
schemaVersion: 3,
|
|
47
|
+
epoch: 1,
|
|
48
|
+
runtimeGeneration: 3,
|
|
49
|
+
runtimeContractHash: input.runtimeContractHash,
|
|
50
|
+
artifactDigest: input.artifactDigest,
|
|
51
|
+
sourceRevision: input.sourceRevision,
|
|
52
|
+
activeTimelineRevision: input.timelineRevision,
|
|
53
|
+
turnId: "tmw3:authoring:fresh",
|
|
54
|
+
preActivationTerminalDigest: ZERO_SHA256,
|
|
55
|
+
activeTimeline: Object.freeze({
|
|
56
|
+
revisionId: input.timelineRevision,
|
|
57
|
+
parentRevisionId: null,
|
|
58
|
+
revisionSequence: 0,
|
|
59
|
+
epoch: 1,
|
|
60
|
+
runtimeGeneration: 3,
|
|
61
|
+
runtimeContractHash: input.runtimeContractHash,
|
|
62
|
+
artifactDigest: input.artifactDigest,
|
|
63
|
+
sourceRevision: input.sourceRevision,
|
|
64
|
+
worldlineId: input.worldlineId,
|
|
65
|
+
operationId: "tmw3:authoring:fresh",
|
|
66
|
+
ledgerHead: TMW_EMPTY_LEDGER_HEAD,
|
|
67
|
+
narrativeDigest: input.narrativeDigest,
|
|
68
|
+
savSectionDigest: ZERO_SHA256,
|
|
69
|
+
intentSetDigest: input.intentSetDigest,
|
|
70
|
+
presentationIntentSetDigest: input.intentSetDigest,
|
|
71
|
+
createdFrom: "fresh",
|
|
72
|
+
active: true,
|
|
73
|
+
}),
|
|
74
|
+
ledgerHead: TMW_EMPTY_LEDGER_HEAD,
|
|
75
|
+
eventLedger: Object.freeze({ events: Object.freeze([]) }),
|
|
76
|
+
narrative: Object.freeze({}),
|
|
77
|
+
scene: input.scene,
|
|
78
|
+
gameplayState: input.gameplayState,
|
|
79
|
+
pendingSceneClockCrossings: Object.freeze([]),
|
|
80
|
+
scheduler: Object.freeze({
|
|
81
|
+
cursor: input.scene === null ? null : Object.freeze({
|
|
82
|
+
logicalSeq: 0,
|
|
83
|
+
worldTime: input.scene.worldTime,
|
|
84
|
+
presentation: null,
|
|
85
|
+
realTime: Object.freeze({}),
|
|
86
|
+
}),
|
|
87
|
+
suspensions: Object.freeze([]),
|
|
88
|
+
}),
|
|
89
|
+
conditionState: Object.freeze({}),
|
|
90
|
+
durableIntents: Object.freeze([]),
|
|
91
|
+
presentationIntents: Object.freeze([]),
|
|
92
|
+
semanticVerdictRefs: Object.freeze([]),
|
|
93
|
+
candidateSetRevisions: Object.freeze([]),
|
|
94
|
+
operationReceiptDigests: Object.freeze([]),
|
|
95
|
+
worldMutationRecoveryOperations: Object.freeze([]),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Node/Browser 均可消费的作者试玩入口。simulation_trace 只用于计划预览;
|
|
100
|
+
* runtime_trace 仅记录 Runtime3 的真实 executeCommittedEvent 阶段。
|
|
101
|
+
*/
|
|
102
|
+
export async function executeTmw3Authoring(input) {
|
|
103
|
+
const registry = getCanonicalTmwCapabilityRegistryV3();
|
|
104
|
+
const prepared = await prepareTmw3Authoring(input.document, "simulation");
|
|
105
|
+
if (!prepared.ok)
|
|
106
|
+
return prepared;
|
|
107
|
+
const trace = new BoundedRuntimeTrace(input.max_trace_entries);
|
|
108
|
+
trace.append({ kind: "validated", stableId: prepared.plan.document_sha256 });
|
|
109
|
+
trace.append({ kind: "compiled", stableId: prepared.plan.plan_sha256 });
|
|
110
|
+
const sourceRevision = input.source_revision ?? "tmw3:authoring:source";
|
|
111
|
+
const timelineRevision = "tmw3:authoring:timeline:0";
|
|
112
|
+
const worldlineId = "tmw3:authoring:worldline";
|
|
113
|
+
const [narrativeDigest, emptySetDigest] = await Promise.all([
|
|
114
|
+
tmwSha256Hex(canonicalTmwJson({})),
|
|
115
|
+
tmwSha256Hex(canonicalTmwJson([])),
|
|
116
|
+
]);
|
|
117
|
+
const runtime = createTmwRuntimeHost({
|
|
118
|
+
binding: Object.freeze({
|
|
119
|
+
epoch: 1,
|
|
120
|
+
runtimeGeneration: 3,
|
|
121
|
+
runtimeContractHash: prepared.document.runtime_contract_hash,
|
|
122
|
+
artifactDigest: prepared.plan.plan_sha256,
|
|
123
|
+
sourceRevision,
|
|
124
|
+
timelineRevision,
|
|
125
|
+
leaseId: "tmw3:authoring:lease",
|
|
126
|
+
}),
|
|
127
|
+
compiledPlan: prepared.plan,
|
|
128
|
+
capabilityRegistry: registry,
|
|
129
|
+
});
|
|
130
|
+
const authoringState = input.initial_state !== null && typeof input.initial_state === "object" && !Array.isArray(input.initial_state)
|
|
131
|
+
? input.initial_state : {};
|
|
132
|
+
const scene = authoringState.scene === undefined || authoringState.scene === null ? null
|
|
133
|
+
: canonicalTmwSceneStateV1(authoringState.scene);
|
|
134
|
+
runtime.restore(initialSav({
|
|
135
|
+
runtimeContractHash: prepared.document.runtime_contract_hash,
|
|
136
|
+
artifactDigest: prepared.plan.plan_sha256,
|
|
137
|
+
sourceRevision,
|
|
138
|
+
timelineRevision,
|
|
139
|
+
worldlineId,
|
|
140
|
+
narrativeDigest,
|
|
141
|
+
intentSetDigest: emptySetDigest,
|
|
142
|
+
scene,
|
|
143
|
+
gameplayState: initialTmwGameplayStateFromWorldV1(authoringState),
|
|
144
|
+
}));
|
|
145
|
+
const payload = canonicalTmwJsonValue(input.event.payload, "authoring_event_payload");
|
|
146
|
+
const payloadHash = await tmwSha256Hex(canonicalTmwJson(payload));
|
|
147
|
+
const eventId = input.event.event_id ?? `tmw3:authoring:event:${payloadHash.slice(0, 24)}`;
|
|
148
|
+
const eventContext = runtime.viewEventCommitContext(input.event.event_type, input.clock_observation === undefined
|
|
149
|
+
? Object.freeze({
|
|
150
|
+
coordinates: Object.freeze({
|
|
151
|
+
logicalSeq: 0,
|
|
152
|
+
worldTime: scene?.worldTime ?? null,
|
|
153
|
+
presentation: Object.freeze({
|
|
154
|
+
planId: prepared.plan.plan_sha256,
|
|
155
|
+
segmentId: "tmw3:authoring:test-clock",
|
|
156
|
+
cursor: 0,
|
|
157
|
+
eventSeq: 0,
|
|
158
|
+
}),
|
|
159
|
+
realTime: null,
|
|
160
|
+
}),
|
|
161
|
+
crossingDirection: "forward",
|
|
162
|
+
})
|
|
163
|
+
: Object.freeze({
|
|
164
|
+
coordinates: input.clock_observation.coordinates,
|
|
165
|
+
crossingDirection: input.clock_observation.crossing_direction,
|
|
166
|
+
}));
|
|
167
|
+
const commitReceiptDigest = await tmwSha256Hex(canonicalTmwJson({ eventId, payloadHash }));
|
|
168
|
+
const event = Object.freeze({
|
|
169
|
+
eventId,
|
|
170
|
+
eventType: input.event.event_type,
|
|
171
|
+
hardFact: eventContext.hardFact,
|
|
172
|
+
epoch: 1,
|
|
173
|
+
runtimeGeneration: 3,
|
|
174
|
+
runtimeContractHash: prepared.document.runtime_contract_hash,
|
|
175
|
+
artifactDigest: prepared.plan.plan_sha256,
|
|
176
|
+
sourceRevision,
|
|
177
|
+
timelineRevision,
|
|
178
|
+
scope: Object.freeze({ scenarioId: "tmw3:authoring:scenario", saveId: "tmw3:authoring:save", worldlineId }),
|
|
179
|
+
coordinates: eventContext.coordinates,
|
|
180
|
+
effectiveTime: eventContext.effectiveTime,
|
|
181
|
+
crossingDirection: eventContext.crossingDirection,
|
|
182
|
+
correlationId: "tmw3:authoring:turn",
|
|
183
|
+
causationId: null,
|
|
184
|
+
replacementLineage: Object.freeze([]),
|
|
185
|
+
payloadHash,
|
|
186
|
+
payload,
|
|
187
|
+
commitReceiptDigest,
|
|
188
|
+
});
|
|
189
|
+
let state = canonicalTmwJsonValue(input.initial_state, "authoring_initial_state");
|
|
190
|
+
const activationReceipts = new Map();
|
|
191
|
+
let activeHead = Object.freeze({
|
|
192
|
+
revisionId: timelineRevision,
|
|
193
|
+
revisionSequence: 0,
|
|
194
|
+
ledgerHead: TMW_EMPTY_LEDGER_HEAD,
|
|
195
|
+
});
|
|
196
|
+
const preparedWorldMutations = new Map();
|
|
197
|
+
trace.append({ kind: "event_prepared", stableId: event.eventId, detail: { payloadHash } });
|
|
198
|
+
const execution = await runtime.executeCommittedEvent(event, {
|
|
199
|
+
semanticJudge: {
|
|
200
|
+
async judge(request) {
|
|
201
|
+
const predicates = Object.freeze(Object.fromEntries(request.predicateKeys.map((key) => [
|
|
202
|
+
key,
|
|
203
|
+
input.semantic_predicates?.[key] ?? "unknown",
|
|
204
|
+
])));
|
|
205
|
+
const digest = await tmwSha256Hex(canonicalTmwJson(predicates));
|
|
206
|
+
trace.append({ kind: "semantic_judged", stableId: request.intentId, detail: { digest } });
|
|
207
|
+
return Object.freeze({
|
|
208
|
+
predicateValues: predicates,
|
|
209
|
+
budgetReceiptDigest: digest,
|
|
210
|
+
evidenceSetDigest: digest,
|
|
211
|
+
providerReceiptDigest: digest,
|
|
212
|
+
verdictDigest: digest,
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
effectCommit: {
|
|
217
|
+
async prepareWorldMutation(request) {
|
|
218
|
+
const binding = Object.freeze({ bindingId: `tmw3:authoring:binding:${request.operationId}`, operationId: request.operationId, turnId: request.turnId });
|
|
219
|
+
preparedWorldMutations.set(request.operationId, binding);
|
|
220
|
+
trace.append({ kind: "effect_prepared", stableId: request.operationId, detail: { worldEffectNodeIds: request.worldEffectNodeIds } });
|
|
221
|
+
return binding;
|
|
222
|
+
},
|
|
223
|
+
async stage(request) {
|
|
224
|
+
const receipt = await input.effect_port.stage({ operation_id: request.operationId, event: request.event, plans: request.plans, state });
|
|
225
|
+
state = canonicalTmwJsonValue(receipt.state, "authoring_effect_state");
|
|
226
|
+
trace.append({ kind: "effect_staged", stableId: request.operationId, detail: { receiptDigest: receipt.receipt_digest } });
|
|
227
|
+
return Object.freeze({
|
|
228
|
+
preActivationTerminalDigest: receipt.receipt_digest,
|
|
229
|
+
worldMutationRecoveryOperation: receipt.world_mutation_recovery_operation ?? null,
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
async finalizeWorldMutation(request) {
|
|
233
|
+
preparedWorldMutations.delete(request.operationId);
|
|
234
|
+
trace.append({ kind: "effect_finalized", stableId: request.operationId });
|
|
235
|
+
},
|
|
236
|
+
async rollbackWorldMutation(request) {
|
|
237
|
+
preparedWorldMutations.delete(request.operationId);
|
|
238
|
+
trace.append({ kind: "effect_rolled_back", stableId: request.operationId, detail: { reason: request.reason } });
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
activation: {
|
|
242
|
+
async readByOperation(operationId) {
|
|
243
|
+
return activationReceipts.get(operationId) ?? null;
|
|
244
|
+
},
|
|
245
|
+
async commitAtomic(candidate) {
|
|
246
|
+
const candidateDigest = await tmwActivationCandidateDigest(candidate);
|
|
247
|
+
const status = candidate.expectedHead?.revisionId === activeHead.revisionId
|
|
248
|
+
&& candidate.expectedHead.revisionSequence === activeHead.revisionSequence
|
|
249
|
+
&& candidate.expectedHead.ledgerHead === activeHead.ledgerHead
|
|
250
|
+
? "committed"
|
|
251
|
+
: "conflict";
|
|
252
|
+
const previousHead = activeHead;
|
|
253
|
+
if (status === "committed") {
|
|
254
|
+
activeHead = Object.freeze({ revisionId: candidate.timeline.revisionId, revisionSequence: candidate.timeline.revisionSequence, ledgerHead: candidate.ledgerHead });
|
|
255
|
+
}
|
|
256
|
+
const receiptCore = { operationId: candidate.operationId, status, previousHead, activeHead, atomicWriteCount: status === "committed" ? 5 : 0, candidateDigest };
|
|
257
|
+
const receipt = Object.freeze({ ...receiptCore, receiptDigest: await tmwSha256Hex(canonicalTmwJson(receiptCore)) });
|
|
258
|
+
activationReceipts.set(candidate.operationId, receipt);
|
|
259
|
+
trace.append({ kind: "activation_committed", stableId: candidate.operationId, detail: { candidateDigest } });
|
|
260
|
+
return receipt;
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
trace.append({ kind: "readback_verified", stableId: execution.activation.operationId, detail: { receiptDigest: execution.activation.receiptDigest } });
|
|
265
|
+
const runtimeSav = runtime.restoredSav();
|
|
266
|
+
if (runtimeSav === null)
|
|
267
|
+
throw new Error("tmw_authoring_runtime_sav_missing");
|
|
268
|
+
runtime.dispose();
|
|
269
|
+
const stateDigest = await tmwSha256Hex(canonicalTmwJson(state));
|
|
270
|
+
return Object.freeze({
|
|
271
|
+
ok: true,
|
|
272
|
+
document_sha256: prepared.plan.document_sha256,
|
|
273
|
+
plan_sha256: prepared.plan.plan_sha256,
|
|
274
|
+
simulation_trace: prepared.simulation_trace,
|
|
275
|
+
runtime_trace: trace.snapshot(),
|
|
276
|
+
state,
|
|
277
|
+
state_digest: stateDigest,
|
|
278
|
+
runtime_sav: runtimeSav,
|
|
279
|
+
activation: execution.activation,
|
|
280
|
+
diagnostics: prepared.diagnostics,
|
|
281
|
+
});
|
|
282
|
+
}
|