@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.
Files changed (120) hide show
  1. package/LICENSE +46 -0
  2. package/dist/activation.d.ts +50 -0
  3. package/dist/activation.js +113 -0
  4. package/dist/audio-presentation-projection.d.ts +23 -0
  5. package/dist/audio-presentation-projection.js +39 -0
  6. package/dist/author-scenario-source-v3.d.ts +34 -0
  7. package/dist/author-scenario-source-v3.js +1 -0
  8. package/dist/authoring-runtime.d.ts +76 -0
  9. package/dist/authoring-runtime.js +282 -0
  10. package/dist/builder-diagnostics.d.ts +3 -0
  11. package/dist/builder-diagnostics.js +8 -0
  12. package/dist/builder-node.d.ts +178 -0
  13. package/dist/builder-node.js +212 -0
  14. package/dist/builder.d.ts +32 -0
  15. package/dist/builder.js +127 -0
  16. package/dist/capability-registry.d.ts +32 -0
  17. package/dist/capability-registry.js +33 -0
  18. package/dist/compile-target-profile.d.ts +16 -0
  19. package/dist/compile-target-profile.js +70 -0
  20. package/dist/compiled-plan.d.ts +44 -0
  21. package/dist/compiled-plan.js +1 -0
  22. package/dist/compiler-compatibility-gate.d.ts +96 -0
  23. package/dist/compiler-compatibility-gate.js +609 -0
  24. package/dist/compiler-release-authority.d.ts +212 -0
  25. package/dist/compiler-release-authority.js +676 -0
  26. package/dist/compiler-stage-cache.d.ts +42 -0
  27. package/dist/compiler-stage-cache.js +100 -0
  28. package/dist/compiler-stage-registry.d.ts +48 -0
  29. package/dist/compiler-stage-registry.js +126 -0
  30. package/dist/compiler.d.ts +7 -0
  31. package/dist/compiler.js +68 -0
  32. package/dist/condition-graph.d.ts +46 -0
  33. package/dist/condition-graph.js +135 -0
  34. package/dist/diagnostics.d.ts +20 -0
  35. package/dist/diagnostics.js +20 -0
  36. package/dist/durable-intent.d.ts +29 -0
  37. package/dist/durable-intent.js +60 -0
  38. package/dist/effect-flow.d.ts +69 -0
  39. package/dist/effect-flow.js +98 -0
  40. package/dist/event-fabric.d.ts +81 -0
  41. package/dist/event-fabric.js +227 -0
  42. package/dist/event-lifecycle.d.ts +59 -0
  43. package/dist/event-lifecycle.js +161 -0
  44. package/dist/evidence.d.ts +37 -0
  45. package/dist/evidence.js +92 -0
  46. package/dist/gameplay-state.d.ts +127 -0
  47. package/dist/gameplay-state.js +214 -0
  48. package/dist/index.d.ts +66 -0
  49. package/dist/index.js +52 -0
  50. package/dist/isolated-replay.d.ts +81 -0
  51. package/dist/isolated-replay.js +316 -0
  52. package/dist/music-candidate-set.d.ts +38 -0
  53. package/dist/music-candidate-set.js +102 -0
  54. package/dist/natural-language-chunking.d.ts +10 -0
  55. package/dist/natural-language-chunking.js +62 -0
  56. package/dist/natural-language-ingestion.d.ts +14 -0
  57. package/dist/natural-language-ingestion.js +128 -0
  58. package/dist/natural-language-structured-decode.d.ts +2 -0
  59. package/dist/natural-language-structured-decode.js +69 -0
  60. package/dist/natural-language-world-types.d.ts +142 -0
  61. package/dist/natural-language-world-types.js +2 -0
  62. package/dist/neutral-source-compiler.d.ts +135 -0
  63. package/dist/neutral-source-compiler.js +608 -0
  64. package/dist/presentation-intent.d.ts +42 -0
  65. package/dist/presentation-intent.js +137 -0
  66. package/dist/recall-query-envelope.d.ts +32 -0
  67. package/dist/recall-query-envelope.js +51 -0
  68. package/dist/rewrite-compensation.d.ts +28 -0
  69. package/dist/rewrite-compensation.js +85 -0
  70. package/dist/runtime-contract.d.ts +56 -0
  71. package/dist/runtime-contract.js +96 -0
  72. package/dist/runtime-domain-capabilities.d.ts +12 -0
  73. package/dist/runtime-domain-capabilities.js +20 -0
  74. package/dist/runtime-sav.d.ts +117 -0
  75. package/dist/runtime-sav.js +356 -0
  76. package/dist/runtime-trace.d.ts +44 -0
  77. package/dist/runtime-trace.js +119 -0
  78. package/dist/runtime.d.ts +238 -0
  79. package/dist/runtime.js +1887 -0
  80. package/dist/scene-author-source.d.ts +13 -0
  81. package/dist/scene-author-source.js +25 -0
  82. package/dist/scene-state.d.ts +275 -0
  83. package/dist/scene-state.js +334 -0
  84. package/dist/scheduler.d.ts +55 -0
  85. package/dist/scheduler.js +235 -0
  86. package/dist/selector-ast.d.ts +24 -0
  87. package/dist/selector-ast.js +18 -0
  88. package/dist/semantic-verdict.d.ts +48 -0
  89. package/dist/semantic-verdict.js +101 -0
  90. package/dist/simulator.d.ts +45 -0
  91. package/dist/simulator.js +58 -0
  92. package/dist/source-canonical.d.ts +4 -0
  93. package/dist/source-canonical.js +51 -0
  94. package/dist/source-crypto.d.ts +20 -0
  95. package/dist/source-crypto.js +17 -0
  96. package/dist/source-revision.d.ts +22 -0
  97. package/dist/source-revision.js +43 -0
  98. package/dist/spatial-impact-receipt.d.ts +38 -0
  99. package/dist/spatial-impact-receipt.js +67 -0
  100. package/dist/temporal-rewrite.d.ts +59 -0
  101. package/dist/temporal-rewrite.js +214 -0
  102. package/dist/time-domains.d.ts +37 -0
  103. package/dist/time-domains.js +142 -0
  104. package/dist/timeline-revision.d.ts +28 -0
  105. package/dist/timeline-revision.js +59 -0
  106. package/dist/trigger-document-v3.d.ts +99 -0
  107. package/dist/trigger-document-v3.js +334 -0
  108. package/dist/turn-commit.d.ts +56 -0
  109. package/dist/turn-commit.js +190 -0
  110. package/dist/validator.d.ts +7 -0
  111. package/dist/validator.js +142 -0
  112. package/dist/value-graph.d.ts +98 -0
  113. package/dist/value-graph.js +318 -0
  114. package/dist/view-event-delivery.d.ts +47 -0
  115. package/dist/view-event-delivery.js +197 -0
  116. package/dist/view-interaction-manifest-v3.d.ts +60 -0
  117. package/dist/view-interaction-manifest-v3.js +198 -0
  118. package/dist/view-payload-schema.d.ts +17 -0
  119. package/dist/view-payload-schema.js +84 -0
  120. package/package.json +62 -0
@@ -0,0 +1,42 @@
1
+ import type { TmwDiagnostic } from "./diagnostics.js";
2
+ export interface CompilerStageCacheIdentity {
3
+ readonly scenario_id: string;
4
+ readonly source_manifest_sha256: string;
5
+ readonly stage_id: string;
6
+ readonly stage_version: string;
7
+ readonly target_profile_sha256: string;
8
+ readonly section_sha256s: readonly Readonly<{
9
+ section_key: string;
10
+ sha256: string;
11
+ }>[];
12
+ readonly dependency_sha256s: readonly Readonly<{
13
+ stage_id: string;
14
+ sha256: string;
15
+ }>[];
16
+ }
17
+ export type CompilerStageContentCacheIdentity = Omit<CompilerStageCacheIdentity, "source_manifest_sha256">;
18
+ export interface CompilerStageCacheEntry {
19
+ readonly cache_key: string;
20
+ readonly bytes: Uint8Array;
21
+ readonly output_sha256: string;
22
+ readonly diagnostics: readonly TmwDiagnostic[];
23
+ }
24
+ export interface CompilerStageCache {
25
+ read(cacheKey: string): Promise<CompilerStageCacheEntry | null>;
26
+ writeOnce(entry: CompilerStageCacheEntry): Promise<"stored" | "already_present">;
27
+ delete(cacheKey: string): Promise<void>;
28
+ }
29
+ export declare function compilerStageCacheKey(identity: CompilerStageCacheIdentity): Promise<string>;
30
+ /**
31
+ * Reusable stage-output identity. The complete receipt still records
32
+ * `compilerStageCacheKey`, which binds the captured manifest; storage lookup
33
+ * omits that aggregate digest so an unchanged section can survive an
34
+ * unrelated-section edit.
35
+ */
36
+ export declare function compilerStageContentCacheKey(identity: CompilerStageContentCacheIdentity): Promise<string>;
37
+ export declare class InMemoryCompilerStageCache implements CompilerStageCache {
38
+ #private;
39
+ read(cacheKey: string): Promise<CompilerStageCacheEntry | null>;
40
+ writeOnce(entry: CompilerStageCacheEntry): Promise<"stored" | "already_present">;
41
+ delete(cacheKey: string): Promise<void>;
42
+ }
@@ -0,0 +1,100 @@
1
+ import { canonicalTmwBytes, isSha256Hex, tmwSha256Hex } from "./runtime-contract.js";
2
+ function compareAscii(left, right) {
3
+ return left < right ? -1 : left > right ? 1 : 0;
4
+ }
5
+ export async function compilerStageCacheKey(identity) {
6
+ if (identity.scenario_id.length === 0
7
+ || identity.scenario_id !== identity.scenario_id.trim().normalize("NFC")
8
+ || !isSha256Hex(identity.source_manifest_sha256)
9
+ || !isSha256Hex(identity.target_profile_sha256)
10
+ || identity.section_sha256s.some((section) => !isSha256Hex(section.sha256))
11
+ || identity.dependency_sha256s.some((stage) => !isSha256Hex(stage.sha256)))
12
+ throw new Error("compiler_stage_cache_identity_invalid");
13
+ return tmwSha256Hex(canonicalTmwBytes({
14
+ scenario_id: identity.scenario_id,
15
+ source_manifest_sha256: identity.source_manifest_sha256,
16
+ stage_id: identity.stage_id,
17
+ stage_version: identity.stage_version,
18
+ target_profile_sha256: identity.target_profile_sha256,
19
+ section_sha256s: [...identity.section_sha256s]
20
+ .sort((left, right) => compareAscii(left.section_key, right.section_key)),
21
+ dependency_sha256s: [...identity.dependency_sha256s]
22
+ .sort((left, right) => compareAscii(left.stage_id, right.stage_id)),
23
+ }));
24
+ }
25
+ /**
26
+ * Reusable stage-output identity. The complete receipt still records
27
+ * `compilerStageCacheKey`, which binds the captured manifest; storage lookup
28
+ * omits that aggregate digest so an unchanged section can survive an
29
+ * unrelated-section edit.
30
+ */
31
+ export async function compilerStageContentCacheKey(identity) {
32
+ if (identity.scenario_id.length === 0
33
+ || identity.scenario_id !== identity.scenario_id.trim().normalize("NFC")
34
+ || !isSha256Hex(identity.target_profile_sha256)
35
+ || identity.section_sha256s.some((section) => !isSha256Hex(section.sha256))
36
+ || identity.dependency_sha256s.some((stage) => !isSha256Hex(stage.sha256)))
37
+ throw new Error("compiler_stage_content_cache_identity_invalid");
38
+ return tmwSha256Hex(canonicalTmwBytes({
39
+ scenario_id: identity.scenario_id,
40
+ stage_id: identity.stage_id,
41
+ stage_version: identity.stage_version,
42
+ target_profile_sha256: identity.target_profile_sha256,
43
+ section_sha256s: [...identity.section_sha256s]
44
+ .sort((left, right) => compareAscii(left.section_key, right.section_key)),
45
+ dependency_sha256s: [...identity.dependency_sha256s]
46
+ .sort((left, right) => compareAscii(left.stage_id, right.stage_id)),
47
+ }));
48
+ }
49
+ function cloneDiagnostic(diagnostic) {
50
+ return Object.freeze({
51
+ ...diagnostic,
52
+ related_stable_ids: Object.freeze([...diagnostic.related_stable_ids]),
53
+ });
54
+ }
55
+ function cloneEntry(entry) {
56
+ return Object.freeze({
57
+ cache_key: entry.cache_key,
58
+ bytes: entry.bytes.slice(),
59
+ output_sha256: entry.output_sha256,
60
+ diagnostics: Object.freeze(entry.diagnostics.map(cloneDiagnostic)),
61
+ });
62
+ }
63
+ function bytesEqual(left, right) {
64
+ if (left.byteLength !== right.byteLength)
65
+ return false;
66
+ let difference = 0;
67
+ for (let index = 0; index < left.byteLength; index += 1) {
68
+ difference |= (left[index] ?? 0) ^ (right[index] ?? 0);
69
+ }
70
+ return difference === 0;
71
+ }
72
+ export class InMemoryCompilerStageCache {
73
+ #entries = new Map();
74
+ async read(cacheKey) {
75
+ const entry = this.#entries.get(cacheKey);
76
+ return entry === undefined ? null : cloneEntry(entry);
77
+ }
78
+ async writeOnce(entry) {
79
+ if (!isSha256Hex(entry.cache_key)
80
+ || !isSha256Hex(entry.output_sha256)
81
+ || entry.diagnostics.some((diagnostic) => diagnostic.severity === "error"))
82
+ throw new Error("compiler_stage_cache_entry_invalid");
83
+ const observedHash = await tmwSha256Hex(entry.bytes);
84
+ if (observedHash !== entry.output_sha256) {
85
+ throw new Error("compiler_stage_cache_entry_hash_mismatch");
86
+ }
87
+ const existing = this.#entries.get(entry.cache_key);
88
+ if (existing !== undefined) {
89
+ if (existing.output_sha256 !== entry.output_sha256
90
+ || !bytesEqual(existing.bytes, entry.bytes))
91
+ throw new Error("compiler_stage_cache_write_conflict");
92
+ return "already_present";
93
+ }
94
+ this.#entries.set(entry.cache_key, cloneEntry(entry));
95
+ return "stored";
96
+ }
97
+ async delete(cacheKey) {
98
+ this.#entries.delete(cacheKey);
99
+ }
100
+ }
@@ -0,0 +1,48 @@
1
+ import type { CompileTargetProfile } from "./compile-target-profile.js";
2
+ import type { TmwDiagnostic } from "./diagnostics.js";
3
+ export interface NeutralCompilerSection {
4
+ readonly section_key: string;
5
+ readonly media_type: string;
6
+ readonly canonical_encoding: string;
7
+ readonly byte_length: number;
8
+ readonly sha256: string;
9
+ readonly payload_bytes: Uint8Array;
10
+ }
11
+ export interface CompilerStageDependencyOutput {
12
+ readonly stage_id: string;
13
+ readonly stage_version: string;
14
+ readonly bytes: Uint8Array;
15
+ readonly sha256: string;
16
+ }
17
+ export interface CompilerStageExecutionInput {
18
+ readonly scenario_id: string;
19
+ readonly target_profile: CompileTargetProfile;
20
+ readonly target_profile_sha256: string;
21
+ readonly sections: readonly NeutralCompilerSection[];
22
+ readonly dependency_outputs: readonly CompilerStageDependencyOutput[];
23
+ }
24
+ export type CompilerStageExecutionResult = {
25
+ readonly ok: true;
26
+ readonly bytes: Uint8Array;
27
+ readonly diagnostics: readonly TmwDiagnostic[];
28
+ } | {
29
+ readonly ok: false;
30
+ readonly diagnostics: readonly TmwDiagnostic[];
31
+ };
32
+ export interface CompilerStageDescriptor {
33
+ readonly stage_id: string;
34
+ readonly stage_version: string;
35
+ readonly section_keys: readonly string[];
36
+ readonly depends_on: readonly string[];
37
+ }
38
+ export interface CompilerStage {
39
+ readonly descriptor: CompilerStageDescriptor;
40
+ execute(input: CompilerStageExecutionInput): Promise<CompilerStageExecutionResult>;
41
+ }
42
+ export interface CompilerStageRegistry {
43
+ readonly stages: readonly CompilerStage[];
44
+ }
45
+ export declare function buildCompilerStageRegistry(stages: readonly CompilerStage[]): CompilerStageRegistry;
46
+ export declare function compilerStageById(registry: CompilerStageRegistry, stageId: string): CompilerStage | undefined;
47
+ export declare function assertRegistryMatchesTargetProfile(registry: CompilerStageRegistry, profile: CompileTargetProfile): void;
48
+ export declare function createPassThroughCompilerStage(descriptor: CompilerStageDescriptor): CompilerStage;
@@ -0,0 +1,126 @@
1
+ const IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/u;
2
+ const SECTION_KEY_PATTERN = /^[a-z][a-z0-9_.-]{0,127}$/u;
3
+ function requireIdentifier(value, code) {
4
+ if (!IDENTIFIER_PATTERN.test(value) || value !== value.normalize("NFC"))
5
+ throw new Error(code);
6
+ }
7
+ function requireUnique(values, code) {
8
+ if (new Set(values).size !== values.length)
9
+ throw new Error(code);
10
+ }
11
+ function normalizeStage(stage) {
12
+ const descriptor = stage.descriptor;
13
+ requireIdentifier(descriptor.stage_id, `compiler_stage_id_invalid:${descriptor.stage_id}`);
14
+ requireIdentifier(descriptor.stage_version, `compiler_stage_version_invalid:${descriptor.stage_id}`);
15
+ if (descriptor.section_keys.length === 0) {
16
+ throw new Error(`compiler_stage_sections_required:${descriptor.stage_id}`);
17
+ }
18
+ for (const key of descriptor.section_keys) {
19
+ if (!SECTION_KEY_PATTERN.test(key) || key !== key.normalize("NFC")) {
20
+ throw new Error(`compiler_stage_section_key_invalid:${descriptor.stage_id}`);
21
+ }
22
+ }
23
+ for (const dependency of descriptor.depends_on) {
24
+ requireIdentifier(dependency, `compiler_stage_dependency_invalid:${descriptor.stage_id}`);
25
+ }
26
+ requireUnique(descriptor.section_keys, `compiler_stage_section_key_duplicate:${descriptor.stage_id}`);
27
+ requireUnique(descriptor.depends_on, `compiler_stage_dependency_duplicate:${descriptor.stage_id}`);
28
+ if (descriptor.depends_on.includes(descriptor.stage_id)) {
29
+ throw new Error(`compiler_stage_self_dependency:${descriptor.stage_id}`);
30
+ }
31
+ return Object.freeze({
32
+ descriptor: Object.freeze({
33
+ stage_id: descriptor.stage_id,
34
+ stage_version: descriptor.stage_version,
35
+ section_keys: Object.freeze([...descriptor.section_keys].sort()),
36
+ depends_on: Object.freeze([...descriptor.depends_on].sort()),
37
+ }),
38
+ execute: stage.execute.bind(stage),
39
+ });
40
+ }
41
+ export function buildCompilerStageRegistry(stages) {
42
+ if (stages.length === 0)
43
+ throw new Error("compiler_stage_registry_empty");
44
+ const normalized = stages.map(normalizeStage);
45
+ requireUnique(normalized.map((stage) => stage.descriptor.stage_id), "compiler_stage_id_duplicate");
46
+ const byId = new Map(normalized.map((stage) => [stage.descriptor.stage_id, stage]));
47
+ for (const stage of normalized) {
48
+ for (const dependency of stage.descriptor.depends_on) {
49
+ if (!byId.has(dependency)) {
50
+ throw new Error(`compiler_stage_dependency_missing:${stage.descriptor.stage_id}:${dependency}`);
51
+ }
52
+ }
53
+ }
54
+ const visiting = new Set();
55
+ const visited = new Set();
56
+ const ordered = [];
57
+ const visit = (stageId) => {
58
+ if (visiting.has(stageId))
59
+ throw new Error(`compiler_stage_dependency_cycle:${stageId}`);
60
+ if (visited.has(stageId))
61
+ return;
62
+ visiting.add(stageId);
63
+ const stage = byId.get(stageId);
64
+ if (stage === undefined)
65
+ throw new Error(`compiler_stage_missing:${stageId}`);
66
+ for (const dependency of stage.descriptor.depends_on)
67
+ visit(dependency);
68
+ visiting.delete(stageId);
69
+ visited.add(stageId);
70
+ ordered.push(stage);
71
+ };
72
+ for (const stageId of [...byId.keys()].sort())
73
+ visit(stageId);
74
+ return Object.freeze({ stages: Object.freeze(ordered) });
75
+ }
76
+ export function compilerStageById(registry, stageId) {
77
+ return registry.stages.find((stage) => stage.descriptor.stage_id === stageId);
78
+ }
79
+ export function assertRegistryMatchesTargetProfile(registry, profile) {
80
+ const profileVersions = new Map(profile.stage_versions.map((stage) => [stage.stage_id, stage.stage_version]));
81
+ if (profileVersions.size !== registry.stages.length) {
82
+ throw new Error("compile_target_stage_set_mismatch");
83
+ }
84
+ for (const stage of registry.stages) {
85
+ if (profileVersions.get(stage.descriptor.stage_id) !== stage.descriptor.stage_version) {
86
+ throw new Error(`compile_target_stage_version_mismatch:${stage.descriptor.stage_id}`);
87
+ }
88
+ }
89
+ }
90
+ export function createPassThroughCompilerStage(descriptor) {
91
+ if (descriptor.section_keys.length !== 1 || descriptor.depends_on.length !== 0) {
92
+ throw new Error("pass_through_stage_descriptor_invalid");
93
+ }
94
+ const sectionKey = descriptor.section_keys[0];
95
+ if (sectionKey === undefined)
96
+ throw new Error("pass_through_stage_descriptor_invalid");
97
+ const stableDescriptor = Object.freeze({
98
+ stage_id: descriptor.stage_id,
99
+ stage_version: descriptor.stage_version,
100
+ section_keys: Object.freeze([sectionKey]),
101
+ depends_on: Object.freeze([]),
102
+ });
103
+ return {
104
+ descriptor: stableDescriptor,
105
+ async execute(input) {
106
+ const section = input.sections.find((candidate) => candidate.section_key === sectionKey);
107
+ if (section === undefined) {
108
+ return {
109
+ ok: false,
110
+ diagnostics: Object.freeze([{
111
+ severity: "error",
112
+ code: "compiler_stage_section_missing",
113
+ path: `$/sections/${sectionKey}`,
114
+ message: "compiler stage input section is missing",
115
+ related_stable_ids: Object.freeze([]),
116
+ }]),
117
+ };
118
+ }
119
+ return Object.freeze({
120
+ ok: true,
121
+ bytes: section.payload_bytes.slice(),
122
+ diagnostics: Object.freeze([]),
123
+ });
124
+ },
125
+ };
126
+ }
@@ -0,0 +1,7 @@
1
+ import type { CanonicalTmwCapabilityRegistryV3 } from "./capability-registry.js";
2
+ import type { CompileTmw3Result } from "./compiled-plan.js";
3
+ import { type TriggerDocumentV3 } from "./trigger-document-v3.js";
4
+ import { type TmwRuntimeCapabilityTarget } from "./runtime-domain-capabilities.js";
5
+ export declare function compileTmw3(value: TriggerDocumentV3 | unknown, registry: CanonicalTmwCapabilityRegistryV3, options?: Readonly<{
6
+ runtime_target?: TmwRuntimeCapabilityTarget;
7
+ }>): Promise<CompileTmw3Result>;
@@ -0,0 +1,68 @@
1
+ import { canonicalTmwBytes, canonicalTmwJson, tmwSha256Hex, TMW_COMPILED_PLAN_VERSION, TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
2
+ import { allTriggerNodesV3 } from "./trigger-document-v3.js";
3
+ import { compareTmwEffectiveTime } from "./time-domains.js";
4
+ import { validateTmw3 } from "./validator.js";
5
+ import { tmwDiagnostic } from "./diagnostics.js";
6
+ import { tmwRuntimeProducesClockDomain } from "./runtime-domain-capabilities.js";
7
+ function nodeKind(node) {
8
+ return node.kind;
9
+ }
10
+ export async function compileTmw3(value, registry, options = {}) {
11
+ const validated = await validateTmw3(value, registry);
12
+ if (!validated.ok)
13
+ return validated;
14
+ const document = validated.value;
15
+ const runtimeTarget = options.runtime_target ?? "production";
16
+ const unsupportedDomains = allTriggerNodesV3(document)
17
+ .filter((node) => !tmwRuntimeProducesClockDomain(runtimeTarget, node.effective_time.domain))
18
+ .map((node) => tmwDiagnostic("clock_domain_producer_unavailable", `$/nodes/${node.stable_id}/effective_time/domain`, `runtime target ${runtimeTarget} has no producer for clock domain ${node.effective_time.domain}`, [node.stable_id]));
19
+ if (unsupportedDomains.length > 0)
20
+ return Object.freeze({ ok: false, diagnostics: Object.freeze(unsupportedDomains) });
21
+ const executableNodes = allTriggerNodesV3(document).filter((node) => node.enabled !== false);
22
+ const executableIds = new Set(executableNodes.map((node) => node.stable_id));
23
+ const executableEdges = document.edges.filter((edge) => executableIds.has(edge.from_stable_id) && executableIds.has(edge.to_stable_id));
24
+ const dependencies = new Map();
25
+ for (const node of executableNodes)
26
+ dependencies.set(node.stable_id, []);
27
+ for (const edge of executableEdges)
28
+ dependencies.get(edge.to_stable_id)?.push(edge.from_stable_id);
29
+ const nodes = executableNodes.map((node) => {
30
+ const base = {
31
+ stable_id: node.stable_id,
32
+ kind: nodeKind(node),
33
+ effective_time: node.effective_time,
34
+ dependencies: Object.freeze([...(dependencies.get(node.stable_id) ?? [])].sort()),
35
+ canonical_payload: JSON.parse(canonicalTmwJson(node)),
36
+ };
37
+ return node.kind === "effect"
38
+ ? Object.freeze({
39
+ ...base,
40
+ kind: "effect",
41
+ execution_policy: node.execution_policy,
42
+ rewrite_policy: node.rewrite_policy,
43
+ priority: node.priority,
44
+ idempotency_key: node.idempotency_key,
45
+ })
46
+ : Object.freeze({ ...base, kind: node.kind });
47
+ }).sort((left, right) => compareTmwEffectiveTime(left.effective_time, right.effective_time)
48
+ || left.stable_id.localeCompare(right.stable_id));
49
+ const edges = [...executableEdges].sort((left, right) => left.from_stable_id.localeCompare(right.from_stable_id)
50
+ || left.to_stable_id.localeCompare(right.to_stable_id));
51
+ const documentSha256 = await tmwSha256Hex(canonicalTmwBytes(document));
52
+ const core = Object.freeze({
53
+ plan_version: TMW_COMPILED_PLAN_VERSION,
54
+ runtime_generation: TMW_RUNTIME_GENERATION,
55
+ runtime_contract_hash: document.runtime_contract_hash,
56
+ registry_version: document.registry_version,
57
+ document_sha256: documentSha256,
58
+ nodes: Object.freeze(nodes),
59
+ edges: Object.freeze(edges),
60
+ ...(document.value_graph === undefined ? {} : { value_graph: Object.freeze({ ...document.value_graph, edges: Object.freeze(document.value_graph.edges.filter((edge) => executableIds.has(edge.to_node) || document.value_graph.nodes.some((node) => node.stable_id === edge.to_node))) }) }),
61
+ });
62
+ const planSha256 = await tmwSha256Hex(canonicalTmwBytes(core));
63
+ return Object.freeze({
64
+ ok: true,
65
+ plan: Object.freeze({ ...core, plan_sha256: planSha256 }),
66
+ diagnostics: validated.diagnostics,
67
+ });
68
+ }
@@ -0,0 +1,46 @@
1
+ import { type TmwJsonValue } from "./runtime-trace.js";
2
+ export type ConditionTruth = "true" | "false" | "unknown";
3
+ export interface ConditionLeaf {
4
+ readonly nodeId: string;
5
+ readonly kind: "leaf";
6
+ readonly predicateKey: string;
7
+ }
8
+ export interface ConditionAll {
9
+ readonly nodeId: string;
10
+ readonly kind: "all";
11
+ readonly children: ReadonlyArray<string>;
12
+ }
13
+ export interface ConditionAny {
14
+ readonly nodeId: string;
15
+ readonly kind: "any";
16
+ readonly children: ReadonlyArray<string>;
17
+ }
18
+ export interface ConditionNot {
19
+ readonly nodeId: string;
20
+ readonly kind: "not";
21
+ readonly child: string;
22
+ }
23
+ export type ConditionNode = ConditionLeaf | ConditionAll | ConditionAny | ConditionNot;
24
+ export interface ConditionGraph {
25
+ readonly rootNodeId: string;
26
+ readonly nodes: ReadonlyArray<ConditionNode>;
27
+ }
28
+ export interface EvaluationSnapshot {
29
+ readonly snapshotHash: string;
30
+ readonly values: Readonly<Record<string, ConditionTruth>>;
31
+ readonly evidenceRefs: Readonly<Record<string, ReadonlyArray<string>>>;
32
+ readonly frozenFacts: TmwJsonValue;
33
+ }
34
+ export interface ConditionNodeEvaluation {
35
+ readonly nodeId: string;
36
+ readonly truth: ConditionTruth;
37
+ }
38
+ export interface ConditionEvaluationResult {
39
+ readonly rootNodeId: string;
40
+ readonly truth: ConditionTruth;
41
+ readonly snapshotHash: string;
42
+ readonly nodeResults: ReadonlyArray<ConditionNodeEvaluation>;
43
+ readonly unknownPredicateKeys: ReadonlyArray<string>;
44
+ readonly evidenceRefs: ReadonlyArray<string>;
45
+ }
46
+ export declare function evaluateConditionGraph(graph: ConditionGraph, snapshotInput: EvaluationSnapshot): ConditionEvaluationResult;
@@ -0,0 +1,135 @@
1
+ import { canonicalTmwJsonValue, requireTmwIdentifier, requireTmwSha256, } from "./runtime-trace.js";
2
+ function combineAll(values) {
3
+ if (values.includes("false"))
4
+ return "false";
5
+ return values.includes("unknown") ? "unknown" : "true";
6
+ }
7
+ function combineAny(values) {
8
+ if (values.includes("true"))
9
+ return "true";
10
+ return values.includes("unknown") ? "unknown" : "false";
11
+ }
12
+ function invert(value) {
13
+ return value === "true" ? "false" : value === "false" ? "true" : "unknown";
14
+ }
15
+ function canonicalNode(node) {
16
+ const nodeId = requireTmwIdentifier(node.nodeId, "condition_node_id");
17
+ switch (node.kind) {
18
+ case "leaf": return Object.freeze({
19
+ nodeId,
20
+ kind: "leaf",
21
+ predicateKey: requireTmwIdentifier(node.predicateKey, "condition_predicate_key"),
22
+ });
23
+ case "not": return Object.freeze({
24
+ nodeId,
25
+ kind: "not",
26
+ child: requireTmwIdentifier(node.child, "condition_child"),
27
+ });
28
+ case "all":
29
+ case "any": {
30
+ if (node.children.length === 0)
31
+ throw new Error("tmw_condition_children_empty");
32
+ const children = Object.freeze(node.children.map((child) => requireTmwIdentifier(child, "condition_child")));
33
+ if (new Set(children).size !== children.length)
34
+ throw new Error("tmw_condition_child_duplicate");
35
+ return Object.freeze({ nodeId, kind: node.kind, children });
36
+ }
37
+ }
38
+ }
39
+ export function evaluateConditionGraph(graph, snapshotInput) {
40
+ const snapshot = Object.freeze({
41
+ snapshotHash: requireTmwSha256(snapshotInput.snapshotHash, "condition_snapshot_hash"),
42
+ values: snapshotInput.values,
43
+ evidenceRefs: snapshotInput.evidenceRefs,
44
+ frozenFacts: canonicalTmwJsonValue(snapshotInput.frozenFacts, "condition_frozen_facts"),
45
+ });
46
+ const nodes = new Map();
47
+ for (const input of graph.nodes) {
48
+ const node = canonicalNode(input);
49
+ if (nodes.has(node.nodeId))
50
+ throw new Error("tmw_condition_node_duplicate");
51
+ nodes.set(node.nodeId, node);
52
+ }
53
+ const rootNodeId = requireTmwIdentifier(graph.rootNodeId, "condition_root_node_id");
54
+ if (!nodes.has(rootNodeId))
55
+ throw new Error("tmw_condition_root_missing");
56
+ const validating = new Set();
57
+ const validated = new Set();
58
+ const validateNode = (nodeId, depth = 0) => {
59
+ if (depth >= 32)
60
+ throw new Error("tmw_condition_depth_exceeded");
61
+ if (validated.has(nodeId))
62
+ return;
63
+ if (validating.has(nodeId))
64
+ throw new Error("tmw_condition_cycle");
65
+ const node = nodes.get(nodeId);
66
+ if (node === undefined)
67
+ throw new Error("tmw_condition_reference_missing");
68
+ validating.add(nodeId);
69
+ if (node.kind === "not")
70
+ validateNode(node.child, depth + 1);
71
+ else if (node.kind === "all" || node.kind === "any") {
72
+ for (const child of node.children)
73
+ validateNode(child, depth + 1);
74
+ }
75
+ validating.delete(nodeId);
76
+ validated.add(nodeId);
77
+ };
78
+ for (const nodeId of [...nodes.keys()].sort())
79
+ validateNode(nodeId);
80
+ const visiting = new Set();
81
+ const evaluated = new Map();
82
+ const unknownKeys = new Set();
83
+ const evidence = new Set();
84
+ const visit = (nodeId, depth = 0) => {
85
+ if (depth >= 32)
86
+ throw new Error("tmw_condition_depth_exceeded");
87
+ const previous = evaluated.get(nodeId);
88
+ if (previous !== undefined)
89
+ return previous;
90
+ if (visiting.has(nodeId))
91
+ throw new Error("tmw_condition_cycle");
92
+ const node = nodes.get(nodeId);
93
+ if (node === undefined)
94
+ throw new Error("tmw_condition_reference_missing");
95
+ visiting.add(nodeId);
96
+ let truth;
97
+ switch (node.kind) {
98
+ case "leaf": {
99
+ truth = snapshot.values[node.predicateKey] ?? "unknown";
100
+ if (truth !== "true" && truth !== "false" && truth !== "unknown") {
101
+ throw new Error("tmw_condition_truth_invalid");
102
+ }
103
+ if (truth === "unknown")
104
+ unknownKeys.add(node.predicateKey);
105
+ for (const ref of snapshot.evidenceRefs[node.predicateKey] ?? []) {
106
+ evidence.add(requireTmwIdentifier(ref, "condition_evidence_ref"));
107
+ }
108
+ break;
109
+ }
110
+ case "not":
111
+ truth = invert(visit(node.child, depth + 1));
112
+ break;
113
+ case "all":
114
+ truth = combineAll(node.children.map((child) => visit(child, depth + 1)));
115
+ break;
116
+ case "any":
117
+ truth = combineAny(node.children.map((child) => visit(child, depth + 1)));
118
+ break;
119
+ }
120
+ visiting.delete(nodeId);
121
+ evaluated.set(nodeId, truth);
122
+ return truth;
123
+ };
124
+ const truth = visit(rootNodeId);
125
+ return Object.freeze({
126
+ rootNodeId,
127
+ truth,
128
+ snapshotHash: snapshot.snapshotHash,
129
+ nodeResults: Object.freeze([...evaluated.entries()]
130
+ .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
131
+ .map(([nodeId, nodeTruth]) => Object.freeze({ nodeId, truth: nodeTruth }))),
132
+ unknownPredicateKeys: Object.freeze([...unknownKeys].sort()),
133
+ evidenceRefs: Object.freeze([...evidence].sort()),
134
+ });
135
+ }
@@ -0,0 +1,20 @@
1
+ export type TmwDiagnosticSeverity = "error" | "warning";
2
+ export interface TmwDiagnostic {
3
+ readonly severity: TmwDiagnosticSeverity;
4
+ readonly code: string;
5
+ readonly path: string;
6
+ readonly message: string;
7
+ readonly related_stable_ids: readonly string[];
8
+ }
9
+ export type TmwResult<T> = {
10
+ readonly ok: true;
11
+ readonly value: T;
12
+ readonly diagnostics: readonly TmwDiagnostic[];
13
+ } | {
14
+ readonly ok: false;
15
+ readonly diagnostics: readonly TmwDiagnostic[];
16
+ };
17
+ export declare function tmwDiagnostic(code: string, path: string, message: string, relatedStableIds?: readonly string[], severity?: TmwDiagnosticSeverity): TmwDiagnostic;
18
+ export declare function orderTmwDiagnostics(diagnostics: readonly TmwDiagnostic[]): readonly TmwDiagnostic[];
19
+ export declare function tmwFailure<T>(diagnostics: readonly TmwDiagnostic[]): TmwResult<T>;
20
+ export declare function tmwSuccess<T>(value: T, diagnostics?: readonly TmwDiagnostic[]): TmwResult<T>;
@@ -0,0 +1,20 @@
1
+ export function tmwDiagnostic(code, path, message, relatedStableIds = [], severity = "error") {
2
+ return Object.freeze({
3
+ severity,
4
+ code,
5
+ path,
6
+ message,
7
+ related_stable_ids: Object.freeze([...relatedStableIds].sort()),
8
+ });
9
+ }
10
+ export function orderTmwDiagnostics(diagnostics) {
11
+ return Object.freeze([...diagnostics].sort((left, right) => left.path.localeCompare(right.path)
12
+ || left.code.localeCompare(right.code)
13
+ || left.message.localeCompare(right.message)));
14
+ }
15
+ export function tmwFailure(diagnostics) {
16
+ return Object.freeze({ ok: false, diagnostics: orderTmwDiagnostics(diagnostics) });
17
+ }
18
+ export function tmwSuccess(value, diagnostics = []) {
19
+ return Object.freeze({ ok: true, value, diagnostics: orderTmwDiagnostics(diagnostics) });
20
+ }
@@ -0,0 +1,29 @@
1
+ import { TMW_RUNTIME_GENERATION } from "./runtime-contract.js";
2
+ import { type TmwJsonValue } from "./runtime-trace.js";
3
+ export type DurableIntentState = "active" | "blocked" | "applying" | "satisfied" | "cancelled" | "superseded" | "invalidated" | "failed";
4
+ export interface DurableIntentV3 {
5
+ readonly intentId: string;
6
+ readonly epoch: number;
7
+ readonly runtimeGeneration: typeof TMW_RUNTIME_GENERATION;
8
+ readonly runtimeContractHash: string;
9
+ readonly artifactDigest: string;
10
+ readonly sourceRevision: string;
11
+ readonly timelineRevision: string;
12
+ readonly turnId: string;
13
+ readonly operationId: string;
14
+ readonly capabilityId: string;
15
+ readonly idempotencyKey: string;
16
+ readonly conflictKey: string;
17
+ readonly priority: number;
18
+ readonly state: DurableIntentState;
19
+ readonly selectorSnapshotHash: string;
20
+ readonly payload: TmwJsonValue;
21
+ readonly lastReceiptDigest: string | null;
22
+ readonly reasonCode: string | null;
23
+ }
24
+ export declare function canonicalDurableIntent(input: DurableIntentV3): DurableIntentV3;
25
+ export declare function transitionDurableIntent(currentInput: DurableIntentV3, next: Readonly<{
26
+ state: DurableIntentState;
27
+ lastReceiptDigest: string | null;
28
+ reasonCode: string | null;
29
+ }>): DurableIntentV3;