@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,55 @@
|
|
|
1
|
+
import { TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
|
|
2
|
+
import type { EventScope, PresentationCoordinate, RealTimeCoordinate } from "./event-fabric.js";
|
|
3
|
+
import { type CrossingDirection, type TmwEffectiveTime } from "./time-domains.js";
|
|
4
|
+
import { type RuntimeClockTraceDetail, type TmwJsonValue } from "./runtime-trace.js";
|
|
5
|
+
export interface SchedulerCoordinates {
|
|
6
|
+
readonly logicalSeq: number;
|
|
7
|
+
readonly worldTime: number | null;
|
|
8
|
+
readonly presentation: PresentationCoordinate | null;
|
|
9
|
+
readonly realTime: Readonly<Partial<Record<RealTimeCoordinate["clock"], number>>>;
|
|
10
|
+
}
|
|
11
|
+
export interface SuspensionRecord {
|
|
12
|
+
readonly suspensionId: string;
|
|
13
|
+
readonly epoch: number;
|
|
14
|
+
readonly runtimeGeneration: typeof TMW_RUNTIME_GENERATION;
|
|
15
|
+
readonly runtimeContractHash: string;
|
|
16
|
+
readonly artifactDigest: string;
|
|
17
|
+
readonly sourceRevision: string;
|
|
18
|
+
readonly timelineRevision: string;
|
|
19
|
+
readonly scope: EventScope;
|
|
20
|
+
readonly effectiveTime: TmwEffectiveTime;
|
|
21
|
+
readonly resumeNodeId: string;
|
|
22
|
+
readonly correlationId: string;
|
|
23
|
+
readonly cancellationKey: string | null;
|
|
24
|
+
readonly createdSnapshotHash: string;
|
|
25
|
+
readonly durablePayload: TmwJsonValue;
|
|
26
|
+
}
|
|
27
|
+
export interface SchedulerDueReceipt {
|
|
28
|
+
readonly suspensionId: string;
|
|
29
|
+
readonly status: "due" | "pending" | "direction_filtered" | "wall_clock_rejected";
|
|
30
|
+
readonly effectiveTime: TmwEffectiveTime;
|
|
31
|
+
readonly observedValue: number | null;
|
|
32
|
+
readonly crossingDirection: CrossingDirection;
|
|
33
|
+
readonly clockTrace: RuntimeClockTraceDetail;
|
|
34
|
+
}
|
|
35
|
+
export interface SchedulerSnapshot {
|
|
36
|
+
/** Last authority-observed coordinates. Missing on pre-clock Runtime3 saves. */
|
|
37
|
+
readonly cursor?: SchedulerCoordinates | null;
|
|
38
|
+
readonly suspensions: ReadonlyArray<SuspensionRecord>;
|
|
39
|
+
}
|
|
40
|
+
export declare function canonicalSchedulerCoordinates(input: SchedulerCoordinates): SchedulerCoordinates;
|
|
41
|
+
export declare function mergeSchedulerCoordinates(previousInput: SchedulerCoordinates | null, observedInput: SchedulerCoordinates, crossingDirection: CrossingDirection): SchedulerCoordinates;
|
|
42
|
+
export declare function canonicalSchedulerSnapshot(input: SchedulerSnapshot): SchedulerSnapshot;
|
|
43
|
+
export declare function canonicalSuspension(input: SuspensionRecord): SuspensionRecord;
|
|
44
|
+
export declare function evaluateSuspensionDue(suspensionInput: SuspensionRecord, coordinates: SchedulerCoordinates, crossingDirection: CrossingDirection, previousCoordinates?: SchedulerCoordinates | null): SchedulerDueReceipt;
|
|
45
|
+
export declare class TmwScheduler {
|
|
46
|
+
#private;
|
|
47
|
+
constructor(snapshot?: SchedulerSnapshot);
|
|
48
|
+
schedule(input: SuspensionRecord): SuspensionRecord;
|
|
49
|
+
cancel(cancellationKey: string): ReadonlyArray<SuspensionRecord>;
|
|
50
|
+
poll(coordinates: SchedulerCoordinates, crossingDirection: CrossingDirection): ReadonlyArray<SchedulerDueReceipt>;
|
|
51
|
+
/** Advances only from caller-provided coordinates; it never samples a host clock. */
|
|
52
|
+
advance(coordinatesInput: SchedulerCoordinates, crossingDirection: CrossingDirection): ReadonlyArray<SchedulerDueReceipt>;
|
|
53
|
+
consumeDue(suspensionId: string): SuspensionRecord;
|
|
54
|
+
snapshot(): SchedulerSnapshot;
|
|
55
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
|
|
2
|
+
import { canonicalTmwClockCoordinate, canonicalTmwEffectiveTime, crossingPolicyAllows, tmwEffectiveTimeCrossedDue, } from "./time-domains.js";
|
|
3
|
+
import { canonicalTmwJsonValue, requireTmwIdentifier, requireTmwSafeInteger, requireTmwSha256, } from "./runtime-trace.js";
|
|
4
|
+
function finiteCoordinate(value, label) {
|
|
5
|
+
if (!Number.isFinite(value) || Object.is(value, -0)) {
|
|
6
|
+
throw new Error(`tmw_scheduler_${label}_invalid`);
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
export function canonicalSchedulerCoordinates(input) {
|
|
11
|
+
const realTime = Object.create(null);
|
|
12
|
+
for (const clock of ["monotonic_session", "active_play", "wall_clock"]) {
|
|
13
|
+
const value = input.realTime[clock];
|
|
14
|
+
if (value !== undefined)
|
|
15
|
+
realTime[clock] = finiteCoordinate(value, `real_time_${clock}`);
|
|
16
|
+
}
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
logicalSeq: canonicalTmwClockCoordinate(input.logicalSeq, "logical_seq"),
|
|
19
|
+
worldTime: input.worldTime === null
|
|
20
|
+
? null
|
|
21
|
+
: canonicalTmwClockCoordinate(input.worldTime, "world_time"),
|
|
22
|
+
presentation: input.presentation === null
|
|
23
|
+
? null
|
|
24
|
+
: Object.freeze({
|
|
25
|
+
planId: requireTmwIdentifier(input.presentation.planId, "scheduler_presentation_plan_id"),
|
|
26
|
+
segmentId: requireTmwIdentifier(input.presentation.segmentId, "scheduler_presentation_segment_id"),
|
|
27
|
+
cursor: canonicalTmwClockCoordinate(input.presentation.cursor, "presentation_seq"),
|
|
28
|
+
eventSeq: canonicalTmwClockCoordinate(input.presentation.eventSeq, "presentation_seq"),
|
|
29
|
+
}),
|
|
30
|
+
realTime: Object.freeze(realTime),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function mergePresentation(previous, observed) {
|
|
34
|
+
if (observed === null)
|
|
35
|
+
return previous;
|
|
36
|
+
if (previous !== null
|
|
37
|
+
&& previous.planId === observed.planId
|
|
38
|
+
&& previous.segmentId === observed.segmentId
|
|
39
|
+
&& (observed.cursor < previous.cursor || observed.eventSeq < previous.eventSeq)) {
|
|
40
|
+
throw new Error("tmw_scheduler_presentation_clock_regressed");
|
|
41
|
+
}
|
|
42
|
+
return observed;
|
|
43
|
+
}
|
|
44
|
+
export function mergeSchedulerCoordinates(previousInput, observedInput, crossingDirection) {
|
|
45
|
+
const observed = canonicalSchedulerCoordinates(observedInput);
|
|
46
|
+
if (previousInput === null)
|
|
47
|
+
return observed;
|
|
48
|
+
const previous = canonicalSchedulerCoordinates(previousInput);
|
|
49
|
+
if (observed.logicalSeq < previous.logicalSeq) {
|
|
50
|
+
throw new Error("tmw_scheduler_logical_clock_regressed");
|
|
51
|
+
}
|
|
52
|
+
if (observed.worldTime !== null && previous.worldTime !== null
|
|
53
|
+
&& ((crossingDirection === "forward" && observed.worldTime < previous.worldTime)
|
|
54
|
+
|| (crossingDirection === "backward" && observed.worldTime > previous.worldTime))) {
|
|
55
|
+
throw new Error("tmw_scheduler_world_clock_direction_mismatch");
|
|
56
|
+
}
|
|
57
|
+
const realTime = {
|
|
58
|
+
...previous.realTime,
|
|
59
|
+
};
|
|
60
|
+
for (const clock of ["monotonic_session", "active_play", "wall_clock"]) {
|
|
61
|
+
const value = observed.realTime[clock];
|
|
62
|
+
if (value === undefined)
|
|
63
|
+
continue;
|
|
64
|
+
const prior = previous.realTime[clock];
|
|
65
|
+
if (prior !== undefined && value < prior) {
|
|
66
|
+
throw new Error(`tmw_scheduler_real_time_clock_regressed:${clock}`);
|
|
67
|
+
}
|
|
68
|
+
realTime[clock] = value;
|
|
69
|
+
}
|
|
70
|
+
return Object.freeze({
|
|
71
|
+
logicalSeq: observed.logicalSeq,
|
|
72
|
+
worldTime: observed.worldTime ?? previous.worldTime,
|
|
73
|
+
presentation: mergePresentation(previous.presentation, observed.presentation),
|
|
74
|
+
realTime: Object.freeze(realTime),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export function canonicalSchedulerSnapshot(input) {
|
|
78
|
+
const suspensions = input.suspensions.map(canonicalSuspension).sort((left, right) => left.suspensionId < right.suspensionId ? -1 : left.suspensionId > right.suspensionId ? 1 : 0);
|
|
79
|
+
if (new Set(suspensions.map((item) => item.suspensionId)).size !== suspensions.length) {
|
|
80
|
+
throw new Error("tmw_scheduler_suspension_duplicate");
|
|
81
|
+
}
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
cursor: input.cursor === undefined || input.cursor === null
|
|
84
|
+
? null
|
|
85
|
+
: canonicalSchedulerCoordinates(input.cursor),
|
|
86
|
+
suspensions: Object.freeze(suspensions),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function canonicalScope(scope) {
|
|
90
|
+
return Object.freeze({
|
|
91
|
+
scenarioId: requireTmwIdentifier(scope.scenarioId, "scheduler_scenario_id"),
|
|
92
|
+
saveId: requireTmwIdentifier(scope.saveId, "scheduler_save_id"),
|
|
93
|
+
worldlineId: requireTmwIdentifier(scope.worldlineId, "scheduler_worldline_id"),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
export function canonicalSuspension(input) {
|
|
97
|
+
if (input.runtimeGeneration !== 3)
|
|
98
|
+
throw new Error("unsupported_runtime_generation");
|
|
99
|
+
const effectiveTime = canonicalTmwEffectiveTime(input.effectiveTime);
|
|
100
|
+
return Object.freeze({
|
|
101
|
+
suspensionId: requireTmwIdentifier(input.suspensionId, "scheduler_suspension_id"),
|
|
102
|
+
epoch: requireTmwSafeInteger(input.epoch, "scheduler_epoch", 1),
|
|
103
|
+
runtimeGeneration: TMW_RUNTIME_GENERATION,
|
|
104
|
+
runtimeContractHash: requireTmwSha256(input.runtimeContractHash, "scheduler_contract_hash"),
|
|
105
|
+
artifactDigest: requireTmwSha256(input.artifactDigest, "scheduler_artifact_digest"),
|
|
106
|
+
sourceRevision: requireTmwIdentifier(input.sourceRevision, "scheduler_source_revision"),
|
|
107
|
+
timelineRevision: requireTmwIdentifier(input.timelineRevision, "scheduler_timeline_revision"),
|
|
108
|
+
scope: canonicalScope(input.scope),
|
|
109
|
+
effectiveTime,
|
|
110
|
+
resumeNodeId: requireTmwIdentifier(input.resumeNodeId, "scheduler_resume_node_id"),
|
|
111
|
+
correlationId: requireTmwIdentifier(input.correlationId, "scheduler_correlation_id"),
|
|
112
|
+
cancellationKey: input.cancellationKey === null
|
|
113
|
+
? null
|
|
114
|
+
: requireTmwIdentifier(input.cancellationKey, "scheduler_cancellation_key"),
|
|
115
|
+
createdSnapshotHash: requireTmwSha256(input.createdSnapshotHash, "scheduler_snapshot_hash"),
|
|
116
|
+
durablePayload: canonicalTmwJsonValue(input.durablePayload, "scheduler_payload"),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function presentationValue(value) {
|
|
120
|
+
return value?.eventSeq ?? null;
|
|
121
|
+
}
|
|
122
|
+
function observedValue(suspension, coordinates) {
|
|
123
|
+
switch (suspension.effectiveTime.domain) {
|
|
124
|
+
case "logical_seq": return coordinates.logicalSeq;
|
|
125
|
+
case "world_time": return coordinates.worldTime;
|
|
126
|
+
case "presentation_seq": return presentationValue(coordinates.presentation);
|
|
127
|
+
case "real_time": {
|
|
128
|
+
const clock = suspension.effectiveTime.real_time_clock;
|
|
129
|
+
if (clock === null)
|
|
130
|
+
throw new Error("tmw_scheduler_real_time_clock_missing");
|
|
131
|
+
return coordinates.realTime[clock] ?? null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function previousObservedValue(suspension, cursor) {
|
|
136
|
+
return cursor === null
|
|
137
|
+
? suspension.effectiveTime.effective_value
|
|
138
|
+
: observedValue(suspension, cursor) ?? suspension.effectiveTime.effective_value;
|
|
139
|
+
}
|
|
140
|
+
export function evaluateSuspensionDue(suspensionInput, coordinates, crossingDirection, previousCoordinates = null) {
|
|
141
|
+
if (crossingDirection !== "forward" && crossingDirection !== "backward") {
|
|
142
|
+
throw new Error("tmw_scheduler_crossing_direction_invalid");
|
|
143
|
+
}
|
|
144
|
+
const suspension = canonicalSuspension(suspensionInput);
|
|
145
|
+
const observed = observedValue(suspension, coordinates);
|
|
146
|
+
const previousObserved = previousObservedValue(suspension, previousCoordinates);
|
|
147
|
+
let status = "pending";
|
|
148
|
+
if (!crossingPolicyAllows(suspension.effectiveTime.crossing_policy, crossingDirection)) {
|
|
149
|
+
status = "direction_filtered";
|
|
150
|
+
}
|
|
151
|
+
else if (suspension.effectiveTime.real_time_clock === "wall_clock"
|
|
152
|
+
&& suspension.effectiveTime.wall_clock_policy === "reject") {
|
|
153
|
+
status = "wall_clock_rejected";
|
|
154
|
+
}
|
|
155
|
+
else if (observed !== null && tmwEffectiveTimeCrossedDue(suspension.effectiveTime, previousObserved, observed, crossingDirection)) {
|
|
156
|
+
status = "due";
|
|
157
|
+
}
|
|
158
|
+
return Object.freeze({
|
|
159
|
+
suspensionId: suspension.suspensionId,
|
|
160
|
+
status,
|
|
161
|
+
effectiveTime: suspension.effectiveTime,
|
|
162
|
+
observedValue: observed,
|
|
163
|
+
crossingDirection,
|
|
164
|
+
clockTrace: Object.freeze({
|
|
165
|
+
clockDomain: suspension.effectiveTime.domain,
|
|
166
|
+
observedValue: observed,
|
|
167
|
+
dueValue: suspension.effectiveTime.due_value,
|
|
168
|
+
previousObservedValue: previousObserved,
|
|
169
|
+
crossingDirection,
|
|
170
|
+
}),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
export class TmwScheduler {
|
|
174
|
+
#suspensions = new Map();
|
|
175
|
+
#cursor = null;
|
|
176
|
+
constructor(snapshot) {
|
|
177
|
+
if (snapshot === undefined)
|
|
178
|
+
return;
|
|
179
|
+
const canonical = canonicalSchedulerSnapshot(snapshot);
|
|
180
|
+
this.#cursor = canonical.cursor ?? null;
|
|
181
|
+
for (const suspension of canonical.suspensions) {
|
|
182
|
+
this.#suspensions.set(suspension.suspensionId, suspension);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
schedule(input) {
|
|
186
|
+
const suspension = canonicalSuspension(input);
|
|
187
|
+
const existing = this.#suspensions.get(suspension.suspensionId);
|
|
188
|
+
if (existing !== undefined) {
|
|
189
|
+
if (JSON.stringify(existing) !== JSON.stringify(suspension)) {
|
|
190
|
+
throw new Error("tmw_scheduler_suspension_identity_conflict");
|
|
191
|
+
}
|
|
192
|
+
return existing;
|
|
193
|
+
}
|
|
194
|
+
this.#suspensions.set(suspension.suspensionId, suspension);
|
|
195
|
+
return suspension;
|
|
196
|
+
}
|
|
197
|
+
cancel(cancellationKey) {
|
|
198
|
+
const key = requireTmwIdentifier(cancellationKey, "scheduler_cancellation_key");
|
|
199
|
+
const cancelled = [];
|
|
200
|
+
for (const [id, suspension] of this.#suspensions) {
|
|
201
|
+
if (suspension.cancellationKey !== key)
|
|
202
|
+
continue;
|
|
203
|
+
this.#suspensions.delete(id);
|
|
204
|
+
cancelled.push(suspension);
|
|
205
|
+
}
|
|
206
|
+
return Object.freeze(cancelled.sort((left, right) => left.suspensionId < right.suspensionId ? -1 : left.suspensionId > right.suspensionId ? 1 : 0));
|
|
207
|
+
}
|
|
208
|
+
poll(coordinates, crossingDirection) {
|
|
209
|
+
return Object.freeze([...this.#suspensions.values()]
|
|
210
|
+
.sort((left, right) => left.effectiveTime.due_value - right.effectiveTime.due_value
|
|
211
|
+
|| (left.suspensionId < right.suspensionId ? -1 : 1))
|
|
212
|
+
.map((suspension) => evaluateSuspensionDue(suspension, coordinates, crossingDirection, this.#cursor)));
|
|
213
|
+
}
|
|
214
|
+
/** Advances only from caller-provided coordinates; it never samples a host clock. */
|
|
215
|
+
advance(coordinatesInput, crossingDirection) {
|
|
216
|
+
const coordinates = mergeSchedulerCoordinates(this.#cursor, coordinatesInput, crossingDirection);
|
|
217
|
+
const receipts = this.poll(coordinates, crossingDirection);
|
|
218
|
+
this.#cursor = coordinates;
|
|
219
|
+
return receipts;
|
|
220
|
+
}
|
|
221
|
+
consumeDue(suspensionId) {
|
|
222
|
+
const id = requireTmwIdentifier(suspensionId, "scheduler_suspension_id");
|
|
223
|
+
const suspension = this.#suspensions.get(id);
|
|
224
|
+
if (suspension === undefined)
|
|
225
|
+
throw new Error("tmw_scheduler_suspension_missing");
|
|
226
|
+
this.#suspensions.delete(id);
|
|
227
|
+
return suspension;
|
|
228
|
+
}
|
|
229
|
+
snapshot() {
|
|
230
|
+
return Object.freeze({
|
|
231
|
+
cursor: this.#cursor,
|
|
232
|
+
suspensions: Object.freeze([...this.#suspensions.values()].sort((left, right) => left.suspensionId < right.suspensionId ? -1 : left.suspensionId > right.suspensionId ? 1 : 0)),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TmwJsonPrimitive } from "./runtime-contract.js";
|
|
2
|
+
export type SelectorComparisonOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "contains";
|
|
3
|
+
export type SelectorAstV3 = {
|
|
4
|
+
readonly op: "entity_id";
|
|
5
|
+
readonly entity_id: string;
|
|
6
|
+
} | {
|
|
7
|
+
readonly op: "entity_kind";
|
|
8
|
+
readonly entity_kind: string;
|
|
9
|
+
} | {
|
|
10
|
+
readonly op: "attribute";
|
|
11
|
+
readonly source: SelectorAstV3;
|
|
12
|
+
readonly path: readonly string[];
|
|
13
|
+
readonly comparison: SelectorComparisonOperator;
|
|
14
|
+
readonly value: TmwJsonPrimitive;
|
|
15
|
+
} | {
|
|
16
|
+
readonly op: "union" | "intersection";
|
|
17
|
+
readonly selectors: readonly SelectorAstV3[];
|
|
18
|
+
} | {
|
|
19
|
+
readonly op: "difference";
|
|
20
|
+
readonly left: SelectorAstV3;
|
|
21
|
+
readonly right: SelectorAstV3;
|
|
22
|
+
};
|
|
23
|
+
export declare const SELECTOR_AST_V3_OPS: readonly ["entity_id", "entity_kind", "attribute", "union", "intersection", "difference"];
|
|
24
|
+
export declare function selectorAstStableIdentity(selector: SelectorAstV3): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const SELECTOR_AST_V3_OPS = Object.freeze([
|
|
2
|
+
"entity_id",
|
|
3
|
+
"entity_kind",
|
|
4
|
+
"attribute",
|
|
5
|
+
"union",
|
|
6
|
+
"intersection",
|
|
7
|
+
"difference",
|
|
8
|
+
]);
|
|
9
|
+
export function selectorAstStableIdentity(selector) {
|
|
10
|
+
switch (selector.op) {
|
|
11
|
+
case "entity_id": return `entity_id:${selector.entity_id}`;
|
|
12
|
+
case "entity_kind": return `entity_kind:${selector.entity_kind}`;
|
|
13
|
+
case "attribute": return `attribute:${selectorAstStableIdentity(selector.source)}:${selector.path.join(".")}:${selector.comparison}:${JSON.stringify(selector.value)}`;
|
|
14
|
+
case "union":
|
|
15
|
+
case "intersection": return `${selector.op}:${selector.selectors.map(selectorAstStableIdentity).sort().join("|")}`;
|
|
16
|
+
case "difference": return `difference:${selectorAstStableIdentity(selector.left)}:${selectorAstStableIdentity(selector.right)}`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
|
|
2
|
+
export type SemanticTruth = "true" | "false" | "unknown";
|
|
3
|
+
export type SemanticVerdictState = "pending" | "accepted" | "rejected" | "failed";
|
|
4
|
+
export interface SemanticVerdictV3 {
|
|
5
|
+
readonly schemaVersion: 3;
|
|
6
|
+
readonly epoch: number;
|
|
7
|
+
readonly runtimeGeneration: typeof TMW_RUNTIME_GENERATION;
|
|
8
|
+
readonly runtimeContractHash: string;
|
|
9
|
+
readonly artifactDigest: string;
|
|
10
|
+
readonly scenarioId: string;
|
|
11
|
+
readonly sourceRevision: string;
|
|
12
|
+
readonly timelineRevision: string;
|
|
13
|
+
readonly turnId: string;
|
|
14
|
+
readonly operationId: string;
|
|
15
|
+
readonly intentId: string;
|
|
16
|
+
readonly idempotencyKey: string;
|
|
17
|
+
readonly evidenceSetDigest: string;
|
|
18
|
+
readonly budgetReceiptDigest: string;
|
|
19
|
+
readonly state: SemanticVerdictState;
|
|
20
|
+
readonly truth: SemanticTruth;
|
|
21
|
+
readonly confidenceMillionths: number;
|
|
22
|
+
readonly reasonCode: string;
|
|
23
|
+
readonly providerOperationId: string;
|
|
24
|
+
readonly providerReceiptDigest: string;
|
|
25
|
+
readonly verdictDigest: string;
|
|
26
|
+
}
|
|
27
|
+
export interface SemanticVerdictStore {
|
|
28
|
+
read(idempotencyKey: string): Promise<SemanticVerdictV3 | null>;
|
|
29
|
+
putIfAbsent(verdict: SemanticVerdictV3): Promise<Readonly<{
|
|
30
|
+
status: "stored" | "exists";
|
|
31
|
+
verdict: SemanticVerdictV3;
|
|
32
|
+
}>>;
|
|
33
|
+
}
|
|
34
|
+
export declare function parseSemanticVerdict(value: unknown): SemanticVerdictV3;
|
|
35
|
+
export declare function storeSemanticVerdict(candidateInput: unknown, expected: Readonly<{
|
|
36
|
+
epoch: number;
|
|
37
|
+
runtimeContractHash: string;
|
|
38
|
+
artifactDigest: string;
|
|
39
|
+
scenarioId: string;
|
|
40
|
+
sourceRevision: string;
|
|
41
|
+
timelineRevision: string;
|
|
42
|
+
turnId: string;
|
|
43
|
+
operationId: string;
|
|
44
|
+
intentId: string;
|
|
45
|
+
idempotencyKey: string;
|
|
46
|
+
evidenceSetDigest: string;
|
|
47
|
+
budgetReceiptDigest: string;
|
|
48
|
+
}>, store: SemanticVerdictStore): Promise<SemanticVerdictV3>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
|
|
2
|
+
import { canonicalTmwJson, requireTmwIdentifier, requireTmwSafeInteger, requireTmwSha256, tmwSha256Hex, } from "./runtime-trace.js";
|
|
3
|
+
const VERDICT_KEYS = [
|
|
4
|
+
"artifactDigest",
|
|
5
|
+
"budgetReceiptDigest",
|
|
6
|
+
"confidenceMillionths",
|
|
7
|
+
"epoch",
|
|
8
|
+
"evidenceSetDigest",
|
|
9
|
+
"idempotencyKey",
|
|
10
|
+
"intentId",
|
|
11
|
+
"operationId",
|
|
12
|
+
"providerOperationId",
|
|
13
|
+
"providerReceiptDigest",
|
|
14
|
+
"reasonCode",
|
|
15
|
+
"runtimeContractHash",
|
|
16
|
+
"runtimeGeneration",
|
|
17
|
+
"scenarioId",
|
|
18
|
+
"schemaVersion",
|
|
19
|
+
"sourceRevision",
|
|
20
|
+
"state",
|
|
21
|
+
"timelineRevision",
|
|
22
|
+
"truth",
|
|
23
|
+
"turnId",
|
|
24
|
+
"verdictDigest",
|
|
25
|
+
];
|
|
26
|
+
function isRecord(value) {
|
|
27
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28
|
+
}
|
|
29
|
+
export function parseSemanticVerdict(value) {
|
|
30
|
+
if (!isRecord(value))
|
|
31
|
+
throw new Error("tmw_semantic_verdict_object_required");
|
|
32
|
+
if (Object.keys(value).sort().join("\0") !== [...VERDICT_KEYS].sort().join("\0")) {
|
|
33
|
+
throw new Error("tmw_semantic_verdict_exact_keys_invalid");
|
|
34
|
+
}
|
|
35
|
+
if (value.schemaVersion !== 3 || value.runtimeGeneration !== 3) {
|
|
36
|
+
throw new Error("unsupported_runtime_generation");
|
|
37
|
+
}
|
|
38
|
+
if (value.state !== "pending" && value.state !== "accepted"
|
|
39
|
+
&& value.state !== "rejected" && value.state !== "failed") {
|
|
40
|
+
throw new Error("tmw_semantic_verdict_state_invalid");
|
|
41
|
+
}
|
|
42
|
+
if (value.truth !== "true" && value.truth !== "false" && value.truth !== "unknown") {
|
|
43
|
+
throw new Error("tmw_semantic_verdict_truth_invalid");
|
|
44
|
+
}
|
|
45
|
+
const confidenceMillionths = requireTmwSafeInteger(value.confidenceMillionths, "semantic_confidence");
|
|
46
|
+
if (confidenceMillionths > 1_000_000)
|
|
47
|
+
throw new Error("tmw_semantic_confidence_invalid");
|
|
48
|
+
return Object.freeze({
|
|
49
|
+
schemaVersion: 3,
|
|
50
|
+
epoch: requireTmwSafeInteger(value.epoch, "semantic_epoch", 1),
|
|
51
|
+
runtimeGeneration: TMW_RUNTIME_GENERATION,
|
|
52
|
+
runtimeContractHash: requireTmwSha256(value.runtimeContractHash, "semantic_contract_hash"),
|
|
53
|
+
artifactDigest: requireTmwSha256(value.artifactDigest, "semantic_artifact_digest"),
|
|
54
|
+
scenarioId: requireTmwIdentifier(value.scenarioId, "semantic_scenario_id"),
|
|
55
|
+
sourceRevision: requireTmwIdentifier(value.sourceRevision, "semantic_source_revision"),
|
|
56
|
+
timelineRevision: requireTmwIdentifier(value.timelineRevision, "semantic_timeline_revision"),
|
|
57
|
+
turnId: requireTmwIdentifier(value.turnId, "semantic_turn_id"),
|
|
58
|
+
operationId: requireTmwIdentifier(value.operationId, "semantic_operation_id"),
|
|
59
|
+
intentId: requireTmwIdentifier(value.intentId, "semantic_intent_id"),
|
|
60
|
+
idempotencyKey: requireTmwIdentifier(value.idempotencyKey, "semantic_idempotency_key"),
|
|
61
|
+
evidenceSetDigest: requireTmwSha256(value.evidenceSetDigest, "semantic_evidence_digest"),
|
|
62
|
+
budgetReceiptDigest: requireTmwSha256(value.budgetReceiptDigest, "semantic_budget_digest"),
|
|
63
|
+
state: value.state,
|
|
64
|
+
truth: value.truth,
|
|
65
|
+
confidenceMillionths,
|
|
66
|
+
reasonCode: requireTmwIdentifier(value.reasonCode, "semantic_reason_code"),
|
|
67
|
+
providerOperationId: requireTmwIdentifier(value.providerOperationId, "semantic_provider_operation_id"),
|
|
68
|
+
providerReceiptDigest: requireTmwSha256(value.providerReceiptDigest, "semantic_provider_receipt_digest"),
|
|
69
|
+
verdictDigest: requireTmwSha256(value.verdictDigest, "semantic_verdict_digest"),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export async function storeSemanticVerdict(candidateInput, expected, store) {
|
|
73
|
+
const candidate = parseSemanticVerdict(candidateInput);
|
|
74
|
+
const { verdictDigest: _claimedDigest, ...digestImage } = candidate;
|
|
75
|
+
const computedDigest = await tmwSha256Hex(canonicalTmwJson(digestImage));
|
|
76
|
+
if (computedDigest !== candidate.verdictDigest) {
|
|
77
|
+
throw new Error("tmw_semantic_verdict_digest_mismatch");
|
|
78
|
+
}
|
|
79
|
+
for (const [label, actual, wanted] of [
|
|
80
|
+
["epoch", candidate.epoch, expected.epoch],
|
|
81
|
+
["contract", candidate.runtimeContractHash, expected.runtimeContractHash],
|
|
82
|
+
["artifact", candidate.artifactDigest, expected.artifactDigest],
|
|
83
|
+
["scenario", candidate.scenarioId, expected.scenarioId],
|
|
84
|
+
["source", candidate.sourceRevision, expected.sourceRevision],
|
|
85
|
+
["timeline", candidate.timelineRevision, expected.timelineRevision],
|
|
86
|
+
["turn", candidate.turnId, expected.turnId],
|
|
87
|
+
["operation", candidate.operationId, expected.operationId],
|
|
88
|
+
["intent", candidate.intentId, expected.intentId],
|
|
89
|
+
["idempotency", candidate.idempotencyKey, expected.idempotencyKey],
|
|
90
|
+
["evidence", candidate.evidenceSetDigest, expected.evidenceSetDigest],
|
|
91
|
+
["budget", candidate.budgetReceiptDigest, expected.budgetReceiptDigest],
|
|
92
|
+
]) {
|
|
93
|
+
if (actual !== wanted)
|
|
94
|
+
throw new Error(`tmw_semantic_${label}_mismatch`);
|
|
95
|
+
}
|
|
96
|
+
const outcome = await store.putIfAbsent(candidate);
|
|
97
|
+
if (outcome.verdict.verdictDigest !== candidate.verdictDigest) {
|
|
98
|
+
throw new Error("tmw_semantic_verdict_identity_conflict");
|
|
99
|
+
}
|
|
100
|
+
return outcome.verdict;
|
|
101
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { CanonicalTmwCapabilityRegistryV3 } from "./capability-registry.js";
|
|
2
|
+
import type { TmwDiagnostic } from "./diagnostics.js";
|
|
3
|
+
import type { TmwJsonValue } from "./runtime-contract.js";
|
|
4
|
+
import type { TriggerDocumentV3 } from "./trigger-document-v3.js";
|
|
5
|
+
import type { EffectExecutionPolicy, EffectRewritePolicy } from "./effect-flow.js";
|
|
6
|
+
import type { CrossingPolicy, RealTimeClock, TmwClockDomain, WallClockPolicy } from "./time-domains.js";
|
|
7
|
+
import { type ConditionEvaluationResult } from "./condition-graph.js";
|
|
8
|
+
import type { TmwValueContextV1 } from "./value-graph.js";
|
|
9
|
+
export interface SimulateTmw3Options {
|
|
10
|
+
readonly max_steps?: number;
|
|
11
|
+
readonly max_trace_entries?: number;
|
|
12
|
+
readonly event_payload?: Readonly<Record<string, TmwJsonValue>>;
|
|
13
|
+
readonly value_context?: TmwValueContextV1;
|
|
14
|
+
}
|
|
15
|
+
export interface TmwSimulationTraceEntry {
|
|
16
|
+
readonly step: number;
|
|
17
|
+
readonly stable_id: string;
|
|
18
|
+
readonly kind: "event" | "condition" | "effect" | "presentation";
|
|
19
|
+
readonly clock_domain: TmwClockDomain;
|
|
20
|
+
readonly due_value: number;
|
|
21
|
+
readonly effective_value: number;
|
|
22
|
+
readonly crossing_policy: CrossingPolicy;
|
|
23
|
+
readonly real_time_clock: RealTimeClock | null;
|
|
24
|
+
readonly wall_clock_policy: WallClockPolicy | null;
|
|
25
|
+
readonly execution_policy: EffectExecutionPolicy | null;
|
|
26
|
+
readonly rewrite_policy: EffectRewritePolicy | null;
|
|
27
|
+
readonly priority: number | null;
|
|
28
|
+
readonly idempotency_key: string | null;
|
|
29
|
+
readonly read_set: readonly string[];
|
|
30
|
+
readonly disposition: "evaluated" | "planned";
|
|
31
|
+
readonly condition_result: ConditionEvaluationResult | null;
|
|
32
|
+
}
|
|
33
|
+
export interface TmwSimulationResult {
|
|
34
|
+
readonly ok: true;
|
|
35
|
+
readonly plan_sha256: string;
|
|
36
|
+
readonly trace: readonly TmwSimulationTraceEntry[];
|
|
37
|
+
readonly steps_used: number;
|
|
38
|
+
readonly side_effect_receipts: readonly never[];
|
|
39
|
+
readonly diagnostics: readonly TmwDiagnostic[];
|
|
40
|
+
}
|
|
41
|
+
export type SimulateTmw3Outcome = TmwSimulationResult | {
|
|
42
|
+
readonly ok: false;
|
|
43
|
+
readonly diagnostics: readonly TmwDiagnostic[];
|
|
44
|
+
};
|
|
45
|
+
export declare function simulateTmw3(document: TriggerDocumentV3 | unknown, registry: CanonicalTmwCapabilityRegistryV3, options?: SimulateTmw3Options): Promise<SimulateTmw3Outcome>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { compileTmw3 } from "./compiler.js";
|
|
2
|
+
import { evaluateConditionGraph } from "./condition-graph.js";
|
|
3
|
+
import { buildTmwConditionExpressionSnapshotV3 } from "./runtime.js";
|
|
4
|
+
export async function simulateTmw3(document, registry, options = {}) {
|
|
5
|
+
const compiled = await compileTmw3(document, registry, { runtime_target: "simulation" });
|
|
6
|
+
if (!compiled.ok)
|
|
7
|
+
return compiled;
|
|
8
|
+
const maxSteps = options.max_steps ?? 10_000;
|
|
9
|
+
const maxTrace = options.max_trace_entries ?? 1_000;
|
|
10
|
+
if (!Number.isSafeInteger(maxSteps) || maxSteps < 1 || !Number.isSafeInteger(maxTrace) || maxTrace < 1)
|
|
11
|
+
throw new Error("simulation_budget_invalid");
|
|
12
|
+
const trace = [];
|
|
13
|
+
let step = 0;
|
|
14
|
+
for (const node of compiled.plan.nodes) {
|
|
15
|
+
step += 1;
|
|
16
|
+
if (step > maxSteps)
|
|
17
|
+
throw new Error("simulation_step_budget_exceeded");
|
|
18
|
+
const conditionResult = node.kind !== "condition"
|
|
19
|
+
? null
|
|
20
|
+
: (() => {
|
|
21
|
+
const payload = node.canonical_payload;
|
|
22
|
+
const snapshot = buildTmwConditionExpressionSnapshotV3(payload.expression, options.event_payload ?? Object.freeze({}), node.stable_id, new Set(), options.value_context ?? {}, compiled.plan.value_graph);
|
|
23
|
+
return evaluateConditionGraph(snapshot.graph, {
|
|
24
|
+
snapshotHash: compiled.plan.document_sha256,
|
|
25
|
+
values: snapshot.values,
|
|
26
|
+
evidenceRefs: Object.freeze({}),
|
|
27
|
+
frozenFacts: options.event_payload ?? Object.freeze({}),
|
|
28
|
+
});
|
|
29
|
+
})();
|
|
30
|
+
if (trace.length < maxTrace)
|
|
31
|
+
trace.push(Object.freeze({
|
|
32
|
+
step,
|
|
33
|
+
stable_id: node.stable_id,
|
|
34
|
+
kind: node.kind,
|
|
35
|
+
clock_domain: node.effective_time.domain,
|
|
36
|
+
due_value: node.effective_time.due_value,
|
|
37
|
+
effective_value: node.effective_time.effective_value,
|
|
38
|
+
crossing_policy: node.effective_time.crossing_policy,
|
|
39
|
+
real_time_clock: node.effective_time.real_time_clock,
|
|
40
|
+
wall_clock_policy: node.effective_time.wall_clock_policy,
|
|
41
|
+
execution_policy: node.kind === "effect" ? node.execution_policy : null,
|
|
42
|
+
rewrite_policy: node.kind === "effect" ? node.rewrite_policy : null,
|
|
43
|
+
priority: node.kind === "effect" ? node.priority : null,
|
|
44
|
+
idempotency_key: node.kind === "effect" ? node.idempotency_key : null,
|
|
45
|
+
read_set: node.dependencies,
|
|
46
|
+
disposition: node.kind === "effect" || node.kind === "presentation" ? "planned" : "evaluated",
|
|
47
|
+
condition_result: conditionResult,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
return Object.freeze({
|
|
51
|
+
ok: true,
|
|
52
|
+
plan_sha256: compiled.plan.plan_sha256,
|
|
53
|
+
trace: Object.freeze(trace),
|
|
54
|
+
steps_used: step,
|
|
55
|
+
side_effect_receipts: Object.freeze([]),
|
|
56
|
+
diagnostics: compiled.diagnostics,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AuthenticatedCreateNewSourceInput, AuthorScenarioSourceV3 } from "./author-scenario-source-v3.js";
|
|
2
|
+
export declare function createCanonicalEmptyAuthorScenarioSourceV3(input: AuthenticatedCreateNewSourceInput): Promise<AuthorScenarioSourceV3>;
|
|
3
|
+
export declare function canonicalAuthorScenarioSourceV3Bytes(source: AuthorScenarioSourceV3): Uint8Array;
|
|
4
|
+
export declare function authorScenarioSourceV3Digest(source: AuthorScenarioSourceV3): Promise<string>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { canonicalTmwBytes, runtimeContractHashV3, tmwSha256Hex, TMW_RUNTIME_GENERATION, TRIGGER_DOCUMENT_V3_VERSION, AUTHOR_SCENARIO_SOURCE_V3_SCHEMA_VERSION } from "./runtime-contract.js";
|
|
2
|
+
function canonicalId(value, code) {
|
|
3
|
+
if (value.length === 0 || value.trim() !== value || value.normalize("NFC") !== value)
|
|
4
|
+
throw new Error(code);
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
export async function createCanonicalEmptyAuthorScenarioSourceV3(input) {
|
|
8
|
+
if (input.operation !== "create-new")
|
|
9
|
+
throw new Error("source_create_new_required");
|
|
10
|
+
const ownerId = canonicalId(input.owner_id, "source_owner_invalid");
|
|
11
|
+
if (canonicalId(input.auth_principal_id, "source_principal_invalid") !== ownerId)
|
|
12
|
+
throw new Error("source_owner_forbidden");
|
|
13
|
+
const scenarioId = canonicalId(input.scenario_id, "source_scenario_invalid");
|
|
14
|
+
const registryVersion = canonicalId(input.registry_version, "source_registry_version_invalid");
|
|
15
|
+
if (!Number.isSafeInteger(input.epoch) || input.epoch < 1)
|
|
16
|
+
throw new Error("content_epoch_required");
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
schema_version: AUTHOR_SCENARIO_SOURCE_V3_SCHEMA_VERSION,
|
|
19
|
+
runtime_generation: TMW_RUNTIME_GENERATION,
|
|
20
|
+
owner_id: ownerId,
|
|
21
|
+
scenario_id: scenarioId,
|
|
22
|
+
epoch: input.epoch,
|
|
23
|
+
source_revision: 1,
|
|
24
|
+
previous_revision_digest: null,
|
|
25
|
+
trigger_document: Object.freeze({
|
|
26
|
+
version: TRIGGER_DOCUMENT_V3_VERSION,
|
|
27
|
+
runtime_generation: TMW_RUNTIME_GENERATION,
|
|
28
|
+
runtime_contract_hash: await runtimeContractHashV3(),
|
|
29
|
+
registry_version: registryVersion,
|
|
30
|
+
events: Object.freeze([]),
|
|
31
|
+
conditions: Object.freeze([]),
|
|
32
|
+
effects: Object.freeze([]),
|
|
33
|
+
presentations: Object.freeze([]),
|
|
34
|
+
edges: Object.freeze([]),
|
|
35
|
+
}),
|
|
36
|
+
view_interaction_mobile: null,
|
|
37
|
+
view_interaction_pc: null,
|
|
38
|
+
music_candidate_source: Object.freeze({
|
|
39
|
+
schema: "music-candidate-source.v3",
|
|
40
|
+
generation: TMW_RUNTIME_GENERATION,
|
|
41
|
+
candidates: Object.freeze([]),
|
|
42
|
+
}),
|
|
43
|
+
source_metadata: Object.freeze({}),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function canonicalAuthorScenarioSourceV3Bytes(source) {
|
|
47
|
+
return canonicalTmwBytes(source);
|
|
48
|
+
}
|
|
49
|
+
export async function authorScenarioSourceV3Digest(source) {
|
|
50
|
+
return tmwSha256Hex(canonicalAuthorScenarioSourceV3Bytes(source));
|
|
51
|
+
}
|