simfile 0.0.1

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 (249) hide show
  1. package/README.md +143 -0
  2. package/dist/cli/index.d.ts +3 -0
  3. package/dist/cli/index.d.ts.map +1 -0
  4. package/dist/cli/index.js +348 -0
  5. package/dist/coverage/index.d.ts +2 -0
  6. package/dist/coverage/index.d.ts.map +1 -0
  7. package/dist/coverage/index.js +1 -0
  8. package/dist/coverage/matrix.d.ts +21 -0
  9. package/dist/coverage/matrix.d.ts.map +1 -0
  10. package/dist/coverage/matrix.js +173 -0
  11. package/dist/coverage/render.d.ts +3 -0
  12. package/dist/coverage/render.d.ts.map +1 -0
  13. package/dist/coverage/render.js +26 -0
  14. package/dist/index.d.ts +8 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +7 -0
  17. package/dist/kernel/duration.d.ts +9 -0
  18. package/dist/kernel/duration.d.ts.map +1 -0
  19. package/dist/kernel/duration.js +44 -0
  20. package/dist/kernel/index.d.ts +4 -0
  21. package/dist/kernel/index.d.ts.map +1 -0
  22. package/dist/kernel/index.js +3 -0
  23. package/dist/kernel/range.d.ts +6 -0
  24. package/dist/kernel/range.d.ts.map +1 -0
  25. package/dist/kernel/range.js +16 -0
  26. package/dist/kernel/stochastic.d.ts +10 -0
  27. package/dist/kernel/stochastic.d.ts.map +1 -0
  28. package/dist/kernel/stochastic.js +25 -0
  29. package/dist/ledger/index.d.ts +4 -0
  30. package/dist/ledger/index.d.ts.map +1 -0
  31. package/dist/ledger/index.js +3 -0
  32. package/dist/ledger/markers.d.ts +46 -0
  33. package/dist/ledger/markers.d.ts.map +1 -0
  34. package/dist/ledger/markers.js +108 -0
  35. package/dist/ledger/stable.d.ts +65 -0
  36. package/dist/ledger/stable.d.ts.map +1 -0
  37. package/dist/ledger/stable.js +78 -0
  38. package/dist/ledger/validation.d.ts +16 -0
  39. package/dist/ledger/validation.d.ts.map +1 -0
  40. package/dist/ledger/validation.js +127 -0
  41. package/dist/moltnet/index.d.ts +3 -0
  42. package/dist/moltnet/index.d.ts.map +1 -0
  43. package/dist/moltnet/index.js +2 -0
  44. package/dist/moltnet/transcript-export.d.ts +34 -0
  45. package/dist/moltnet/transcript-export.d.ts.map +1 -0
  46. package/dist/moltnet/transcript-export.js +68 -0
  47. package/dist/moltnet/world-participant.d.ts +77 -0
  48. package/dist/moltnet/world-participant.d.ts.map +1 -0
  49. package/dist/moltnet/world-participant.js +221 -0
  50. package/dist/observe/artifacts.d.ts +16 -0
  51. package/dist/observe/artifacts.d.ts.map +1 -0
  52. package/dist/observe/artifacts.js +31 -0
  53. package/dist/observe/causalStreams.d.ts +19 -0
  54. package/dist/observe/causalStreams.d.ts.map +1 -0
  55. package/dist/observe/causalStreams.js +38 -0
  56. package/dist/observe/compute.d.ts +17 -0
  57. package/dist/observe/compute.d.ts.map +1 -0
  58. package/dist/observe/compute.js +97 -0
  59. package/dist/observe/index.d.ts +11 -0
  60. package/dist/observe/index.d.ts.map +1 -0
  61. package/dist/observe/index.js +10 -0
  62. package/dist/observe/manifest.d.ts +79 -0
  63. package/dist/observe/manifest.d.ts.map +1 -0
  64. package/dist/observe/manifest.js +87 -0
  65. package/dist/observe/memoryBanks.d.ts +38 -0
  66. package/dist/observe/memoryBanks.d.ts.map +1 -0
  67. package/dist/observe/memoryBanks.js +86 -0
  68. package/dist/observe/observe.d.ts +32 -0
  69. package/dist/observe/observe.d.ts.map +1 -0
  70. package/dist/observe/observe.js +73 -0
  71. package/dist/observe/report.d.ts +165 -0
  72. package/dist/observe/report.d.ts.map +1 -0
  73. package/dist/observe/report.js +138 -0
  74. package/dist/observe/seedSpread.d.ts +49 -0
  75. package/dist/observe/seedSpread.d.ts.map +1 -0
  76. package/dist/observe/seedSpread.js +262 -0
  77. package/dist/observe/seedSpreadArtifacts.d.ts +49 -0
  78. package/dist/observe/seedSpreadArtifacts.d.ts.map +1 -0
  79. package/dist/observe/seedSpreadArtifacts.js +118 -0
  80. package/dist/observe/spreadMatcher.d.ts +45 -0
  81. package/dist/observe/spreadMatcher.d.ts.map +1 -0
  82. package/dist/observe/spreadMatcher.js +124 -0
  83. package/dist/report/index.d.ts +4 -0
  84. package/dist/report/index.d.ts.map +1 -0
  85. package/dist/report/index.js +3 -0
  86. package/dist/report/probeArtifact.d.ts +26 -0
  87. package/dist/report/probeArtifact.d.ts.map +1 -0
  88. package/dist/report/probeArtifact.js +119 -0
  89. package/dist/report/probes.d.ts +52 -0
  90. package/dist/report/probes.d.ts.map +1 -0
  91. package/dist/report/probes.js +164 -0
  92. package/dist/report/score.d.ts +27 -0
  93. package/dist/report/score.d.ts.map +1 -0
  94. package/dist/report/score.js +14 -0
  95. package/dist/report/transcripts.d.ts +12 -0
  96. package/dist/report/transcripts.d.ts.map +1 -0
  97. package/dist/report/transcripts.js +17 -0
  98. package/dist/runtime/causal-fixture.d.ts +26 -0
  99. package/dist/runtime/causal-fixture.d.ts.map +1 -0
  100. package/dist/runtime/causal-fixture.js +36 -0
  101. package/dist/runtime/clock.d.ts +25 -0
  102. package/dist/runtime/clock.d.ts.map +1 -0
  103. package/dist/runtime/clock.js +63 -0
  104. package/dist/runtime/condition.d.ts +55 -0
  105. package/dist/runtime/condition.d.ts.map +1 -0
  106. package/dist/runtime/condition.js +122 -0
  107. package/dist/runtime/emit-causal-fixture.d.ts +2 -0
  108. package/dist/runtime/emit-causal-fixture.d.ts.map +1 -0
  109. package/dist/runtime/emit-causal-fixture.js +45 -0
  110. package/dist/runtime/expression.d.ts +11 -0
  111. package/dist/runtime/expression.d.ts.map +1 -0
  112. package/dist/runtime/expression.js +305 -0
  113. package/dist/runtime/numeric.d.ts +7 -0
  114. package/dist/runtime/numeric.d.ts.map +1 -0
  115. package/dist/runtime/numeric.js +11 -0
  116. package/dist/runtime/rule-actions.d.ts +5 -0
  117. package/dist/runtime/rule-actions.d.ts.map +1 -0
  118. package/dist/runtime/rule-actions.js +82 -0
  119. package/dist/runtime/run-record.d.ts +73 -0
  120. package/dist/runtime/run-record.d.ts.map +1 -0
  121. package/dist/runtime/run-record.js +179 -0
  122. package/dist/runtime/step-tick.d.ts +43 -0
  123. package/dist/runtime/step-tick.d.ts.map +1 -0
  124. package/dist/runtime/step-tick.js +177 -0
  125. package/dist/runtime/trace-compile.d.ts +66 -0
  126. package/dist/runtime/trace-compile.d.ts.map +1 -0
  127. package/dist/runtime/trace-compile.js +157 -0
  128. package/dist/runtime/trace-export.d.ts +5 -0
  129. package/dist/runtime/trace-export.d.ts.map +1 -0
  130. package/dist/runtime/trace-export.js +4 -0
  131. package/dist/runtime/trace-run.d.ts +15 -0
  132. package/dist/runtime/trace-run.d.ts.map +1 -0
  133. package/dist/runtime/trace-run.js +92 -0
  134. package/dist/runtime/trace.d.ts +10 -0
  135. package/dist/runtime/trace.d.ts.map +1 -0
  136. package/dist/runtime/trace.js +9 -0
  137. package/dist/runtime/types.d.ts +61 -0
  138. package/dist/runtime/types.d.ts.map +1 -0
  139. package/dist/runtime/types.js +1 -0
  140. package/dist/runtime/viewer-trace.d.ts +64 -0
  141. package/dist/runtime/viewer-trace.d.ts.map +1 -0
  142. package/dist/runtime/viewer-trace.js +164 -0
  143. package/dist/runtime/world-act.d.ts +55 -0
  144. package/dist/runtime/world-act.d.ts.map +1 -0
  145. package/dist/runtime/world-act.js +156 -0
  146. package/dist/schema/binding.d.ts +23 -0
  147. package/dist/schema/binding.d.ts.map +1 -0
  148. package/dist/schema/binding.js +249 -0
  149. package/dist/schema/index.d.ts +5 -0
  150. package/dist/schema/index.d.ts.map +1 -0
  151. package/dist/schema/index.js +4 -0
  152. package/dist/schema/model.d.ts +244 -0
  153. package/dist/schema/model.d.ts.map +1 -0
  154. package/dist/schema/model.js +222 -0
  155. package/dist/schema/parse.d.ts +10 -0
  156. package/dist/schema/parse.d.ts.map +1 -0
  157. package/dist/schema/parse.js +15 -0
  158. package/dist/schema/semantic.d.ts +3 -0
  159. package/dist/schema/semantic.d.ts.map +1 -0
  160. package/dist/schema/semantic.js +135 -0
  161. package/dist/sims/composeRunManifest.d.ts +54 -0
  162. package/dist/sims/composeRunManifest.d.ts.map +1 -0
  163. package/dist/sims/composeRunManifest.js +40 -0
  164. package/dist/sims/composedJungianSimDriver.d.ts +50 -0
  165. package/dist/sims/composedJungianSimDriver.d.ts.map +1 -0
  166. package/dist/sims/composedJungianSimDriver.js +199 -0
  167. package/dist/sims/composedOfficeSimDriver.d.ts +53 -0
  168. package/dist/sims/composedOfficeSimDriver.d.ts.map +1 -0
  169. package/dist/sims/composedOfficeSimDriver.js +162 -0
  170. package/dist/sims/exchangeWait.d.ts +56 -0
  171. package/dist/sims/exchangeWait.d.ts.map +1 -0
  172. package/dist/sims/exchangeWait.js +66 -0
  173. package/dist/sims/index.d.ts +14 -0
  174. package/dist/sims/index.d.ts.map +1 -0
  175. package/dist/sims/index.js +13 -0
  176. package/dist/sims/moltnetRoomClient.d.ts +47 -0
  177. package/dist/sims/moltnetRoomClient.d.ts.map +1 -0
  178. package/dist/sims/moltnetRoomClient.js +41 -0
  179. package/dist/sims/poll.d.ts +19 -0
  180. package/dist/sims/poll.d.ts.map +1 -0
  181. package/dist/sims/poll.js +23 -0
  182. package/dist/sims/spawnfileCli.d.ts +49 -0
  183. package/dist/sims/spawnfileCli.d.ts.map +1 -0
  184. package/dist/sims/spawnfileCli.js +90 -0
  185. package/dist/sims/spawnfileReceipts.d.ts +76 -0
  186. package/dist/sims/spawnfileReceipts.d.ts.map +1 -0
  187. package/dist/sims/spawnfileReceipts.js +107 -0
  188. package/dist/sims/worldDrivenOfficeSimDriver.d.ts +59 -0
  189. package/dist/sims/worldDrivenOfficeSimDriver.d.ts.map +1 -0
  190. package/dist/sims/worldDrivenOfficeSimDriver.js +182 -0
  191. package/dist/sims/worldLedgerWriter.d.ts +32 -0
  192. package/dist/sims/worldLedgerWriter.d.ts.map +1 -0
  193. package/dist/sims/worldLedgerWriter.js +39 -0
  194. package/dist/sims/worldSeedLint.d.ts +42 -0
  195. package/dist/sims/worldSeedLint.d.ts.map +1 -0
  196. package/dist/sims/worldSeedLint.js +73 -0
  197. package/dist/sims/worldTickIngest.d.ts +27 -0
  198. package/dist/sims/worldTickIngest.d.ts.map +1 -0
  199. package/dist/sims/worldTickIngest.js +35 -0
  200. package/dist/sims/worldTickLoop.d.ts +64 -0
  201. package/dist/sims/worldTickLoop.d.ts.map +1 -0
  202. package/dist/sims/worldTickLoop.js +122 -0
  203. package/dist/view/engineProvenance.d.ts +46 -0
  204. package/dist/view/engineProvenance.d.ts.map +1 -0
  205. package/dist/view/engineProvenance.js +76 -0
  206. package/dist/view/index.d.ts +14 -0
  207. package/dist/view/index.d.ts.map +1 -0
  208. package/dist/view/index.js +107 -0
  209. package/dist/view/membranes.d.ts +14 -0
  210. package/dist/view/membranes.d.ts.map +1 -0
  211. package/dist/view/membranes.js +127 -0
  212. package/dist/view/runDetect.d.ts +2 -0
  213. package/dist/view/runDetect.d.ts.map +1 -0
  214. package/dist/view/runDetect.js +47 -0
  215. package/dist/view/runRawArtifacts.d.ts +48 -0
  216. package/dist/view/runRawArtifacts.d.ts.map +1 -0
  217. package/dist/view/runRawArtifacts.js +143 -0
  218. package/dist/view/runTimeline.d.ts +24 -0
  219. package/dist/view/runTimeline.d.ts.map +1 -0
  220. package/dist/view/runTimeline.js +204 -0
  221. package/dist/view/runTimelineRecords.d.ts +42 -0
  222. package/dist/view/runTimelineRecords.d.ts.map +1 -0
  223. package/dist/view/runTimelineRecords.js +244 -0
  224. package/dist/view/runTimelineRefs.d.ts +27 -0
  225. package/dist/view/runTimelineRefs.d.ts.map +1 -0
  226. package/dist/view/runTimelineRefs.js +31 -0
  227. package/dist/view/runTimelineTypes.d.ts +99 -0
  228. package/dist/view/runTimelineTypes.d.ts.map +1 -0
  229. package/dist/view/runTimelineTypes.js +1 -0
  230. package/dist/view/runViewModel.d.ts +21 -0
  231. package/dist/view/runViewModel.d.ts.map +1 -0
  232. package/dist/view/runViewModel.js +66 -0
  233. package/dist/view/runViewModelCompute.d.ts +24 -0
  234. package/dist/view/runViewModelCompute.d.ts.map +1 -0
  235. package/dist/view/runViewModelCompute.js +157 -0
  236. package/dist/view/runViewModelTypes.d.ts +177 -0
  237. package/dist/view/runViewModelTypes.d.ts.map +1 -0
  238. package/dist/view/runViewModelTypes.js +1 -0
  239. package/dist/view/runWorldTrace.d.ts +97 -0
  240. package/dist/view/runWorldTrace.d.ts.map +1 -0
  241. package/dist/view/runWorldTrace.js +88 -0
  242. package/dist/view/server.d.ts +12 -0
  243. package/dist/view/server.d.ts.map +1 -0
  244. package/dist/view/server.js +306 -0
  245. package/package.json +65 -0
  246. package/web/dist/assets/index-CJHLjfsG.js +49 -0
  247. package/web/dist/assets/index-DJOsPsU8.css +1 -0
  248. package/web/dist/index.html +13 -0
  249. package/web/dist/models/AnimatedMushnub.glb +0 -0
@@ -0,0 +1,305 @@
1
+ import { parseDurationSeconds } from "../kernel/duration.js";
2
+ const FUNCTION_ARITY = {
3
+ sin: { min: 1, max: 1 },
4
+ cos: { min: 1, max: 1 },
5
+ abs: { min: 1, max: 1 },
6
+ sqrt: { min: 1, max: 1 },
7
+ exp: { min: 1, max: 1 },
8
+ log: { min: 1, max: 1 },
9
+ floor: { min: 1, max: 1 },
10
+ ceil: { min: 1, max: 1 },
11
+ mod: { min: 2, max: 2 },
12
+ pow: { min: 2, max: 2 },
13
+ min: { min: 2, max: Number.POSITIVE_INFINITY },
14
+ max: { min: 2, max: Number.POSITIVE_INFINITY },
15
+ clamp: { min: 3, max: 3 },
16
+ lerp: { min: 3, max: 3 },
17
+ step: { min: 2, max: 2 },
18
+ smoothstep: { min: 3, max: 3 }
19
+ };
20
+ const FUNCTIONS = {
21
+ sin: (x) => finite(Math.sin(x)),
22
+ cos: (x) => finite(Math.cos(x)),
23
+ abs: (x) => finite(Math.abs(x)),
24
+ sqrt: (x) => finite(x < 0 ? 0 : Math.sqrt(x)),
25
+ exp: (x) => finite(Math.exp(finite(x))),
26
+ log: (x) => finite(x <= 0 ? 0 : Math.log(x)),
27
+ floor: (x) => finite(Math.floor(x)),
28
+ ceil: (x) => finite(Math.ceil(x)),
29
+ mod: (x, y) => finite(y === 0 ? 0 : x % y),
30
+ pow: (x, y) => finite(Math.pow(x, y)),
31
+ min: (...values) => finite(Math.min(...values)),
32
+ max: (...values) => finite(Math.max(...values)),
33
+ clamp: (value, lo, hi) => finite(Math.max(lo, Math.min(hi, value))),
34
+ lerp: (start, end, step) => finite(start + (end - start) * clamp01(step)),
35
+ step: (edge, value) => finite(value < edge ? 0 : 1),
36
+ smoothstep: (edge0, edge1, value) => {
37
+ if (edge0 === edge1) {
38
+ return 1;
39
+ }
40
+ const t = clamp01((value - edge0) / (edge1 - edge0));
41
+ return finite(t * t * (3 - 2 * t));
42
+ }
43
+ };
44
+ const RESERVED = new Set(["t", "tick", "pi", "e"]);
45
+ const NUMBER = /^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?/u;
46
+ const IDENT = /^[a-zA-Z_][a-zA-Z0-9_-]*/u;
47
+ const finite = (value) => (Number.isFinite(value) ? value : 0);
48
+ const clamp01 = (value) => {
49
+ if (!Number.isFinite(value) || value < 0) {
50
+ return 0;
51
+ }
52
+ if (value > 1) {
53
+ return 1;
54
+ }
55
+ return value;
56
+ };
57
+ const rewriteDurations = (source) => source.replace(/-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:ms|s|m|h|d|w)\b/gu, (raw) => String(parseDurationSeconds(raw)));
58
+ class Lexer {
59
+ tokens = [];
60
+ cursor = 0;
61
+ constructor(source) {
62
+ let index = 0;
63
+ while (index < source.length) {
64
+ const current = source[index];
65
+ if (/\s/u.test(current)) {
66
+ index += 1;
67
+ continue;
68
+ }
69
+ const remainder = source.slice(index);
70
+ if (remainder.startsWith("**")) {
71
+ this.tokens.push({ type: "operator", value: "**" });
72
+ index += 2;
73
+ continue;
74
+ }
75
+ if (current === "+" || current === "-" || current === "*" || current === "/" || current === "(" || current === ")" || current === ",") {
76
+ this.tokens.push({
77
+ type: current === "(" ? "left-paren" : current === ")" ? "right-paren" : current === "," ? "comma" : "operator",
78
+ value: current
79
+ });
80
+ index += 1;
81
+ continue;
82
+ }
83
+ if (NUMBER.test(remainder)) {
84
+ const matched = remainder.match(/^((?:0|[1-9][0-9]*)(?:\.[0-9]+)?)/u);
85
+ if (!matched) {
86
+ throw new Error(`invalid number token at ${index}`);
87
+ }
88
+ this.tokens.push({ type: "number", value: matched[0] });
89
+ index += matched[0].length;
90
+ continue;
91
+ }
92
+ if (IDENT.test(remainder)) {
93
+ const matched = remainder.match(IDENT);
94
+ if (!matched) {
95
+ throw new Error(`invalid identifier token at ${index}`);
96
+ }
97
+ this.tokens.push({ type: "identifier", value: matched[0] });
98
+ index += matched[0].length;
99
+ continue;
100
+ }
101
+ throw new Error(`unexpected token at ${index}: ${current}`);
102
+ }
103
+ this.tokens.push({ type: "eof", value: "" });
104
+ }
105
+ peek(offset = 0) {
106
+ return this.tokens[this.cursor + offset] ?? { type: "eof", value: "" };
107
+ }
108
+ advance() {
109
+ const current = this.peek();
110
+ this.cursor += 1;
111
+ return current;
112
+ }
113
+ match(type, value) {
114
+ const current = this.peek();
115
+ return current.type === type && (value === undefined || current.value === value);
116
+ }
117
+ consume(type, value) {
118
+ if (!this.match(type, value)) {
119
+ const current = this.peek();
120
+ throw new Error(`expected ${value ?? type}, got ${current.type} ${current.value}`);
121
+ }
122
+ return this.advance();
123
+ }
124
+ }
125
+ class Parser {
126
+ lexer;
127
+ constructor(source) {
128
+ this.lexer = new Lexer(source);
129
+ }
130
+ parseExpression() {
131
+ return this.parseAdditive();
132
+ }
133
+ parseRootExpression() {
134
+ const output = this.parseExpression();
135
+ if (!this.lexer.match("eof")) {
136
+ throw new Error(`unexpected token: ${this.lexer.peek().value}`);
137
+ }
138
+ return output;
139
+ }
140
+ parseAdditive() {
141
+ let node = this.parseMultiplicative();
142
+ while (this.lexer.match("operator", "+") || this.lexer.match("operator", "-")) {
143
+ const operator = this.lexer.advance().value;
144
+ const right = this.parseMultiplicative();
145
+ node = { kind: "binary", operator, left: node, right };
146
+ }
147
+ return node;
148
+ }
149
+ parseMultiplicative() {
150
+ let node = this.parseExponent();
151
+ while (this.lexer.match("operator", "*") || this.lexer.match("operator", "/")) {
152
+ const operator = this.lexer.advance().value;
153
+ const right = this.parseExponent();
154
+ node = { kind: "binary", operator, left: node, right };
155
+ }
156
+ return node;
157
+ }
158
+ parseExponent() {
159
+ const node = this.parseUnary();
160
+ if (this.lexer.match("operator", "**")) {
161
+ this.lexer.advance();
162
+ const right = this.parseExponent();
163
+ return { kind: "binary", operator: "**", left: node, right };
164
+ }
165
+ return node;
166
+ }
167
+ parseUnary() {
168
+ if (this.lexer.match("operator", "+") || this.lexer.match("operator", "-")) {
169
+ const operator = this.lexer.advance().value;
170
+ return { kind: "unary", operator, argument: this.parseUnary() };
171
+ }
172
+ return this.parsePrimary();
173
+ }
174
+ parsePrimary() {
175
+ if (this.lexer.match("number")) {
176
+ return { kind: "number", value: Number(this.lexer.advance().value) };
177
+ }
178
+ if (this.lexer.match("identifier")) {
179
+ const token = this.lexer.advance();
180
+ const name = token.value;
181
+ if (this.lexer.match("left-paren")) {
182
+ this.lexer.consume("left-paren");
183
+ const args = [];
184
+ if (!this.lexer.match("right-paren")) {
185
+ args.push(this.parseExpression());
186
+ while (this.lexer.match("comma")) {
187
+ this.lexer.consume("comma");
188
+ args.push(this.parseExpression());
189
+ }
190
+ }
191
+ this.lexer.consume("right-paren");
192
+ return { kind: "call", callee: name, args };
193
+ }
194
+ return { kind: "variable", name };
195
+ }
196
+ if (this.lexer.match("left-paren")) {
197
+ this.lexer.consume("left-paren");
198
+ const output = this.parseExpression();
199
+ this.lexer.consume("right-paren");
200
+ return output;
201
+ }
202
+ throw new Error(`unexpected token: ${this.lexer.peek().value}`);
203
+ }
204
+ }
205
+ const collectDependencies = (node, output) => {
206
+ if (node.kind === "variable") {
207
+ output.add(node.name);
208
+ return;
209
+ }
210
+ if (node.kind === "unary") {
211
+ collectDependencies(node.argument, output);
212
+ return;
213
+ }
214
+ if (node.kind === "binary") {
215
+ collectDependencies(node.left, output);
216
+ collectDependencies(node.right, output);
217
+ return;
218
+ }
219
+ if (node.kind === "call") {
220
+ node.args.forEach((arg) => collectDependencies(arg, output));
221
+ }
222
+ };
223
+ const validate = (node) => {
224
+ if (node.kind === "binary") {
225
+ validate(node.left);
226
+ validate(node.right);
227
+ return;
228
+ }
229
+ if (node.kind === "unary") {
230
+ validate(node.argument);
231
+ return;
232
+ }
233
+ if (node.kind === "call") {
234
+ if (FUNCTION_ARITY[node.callee] === undefined) {
235
+ throw new Error(`unknown function '${node.callee}'`);
236
+ }
237
+ const arity = FUNCTION_ARITY[node.callee];
238
+ if (node.args.length < arity.min || node.args.length > arity.max) {
239
+ throw new Error(`function '${node.callee}' arity mismatch`);
240
+ }
241
+ node.args.forEach(validate);
242
+ }
243
+ };
244
+ const evaluateNode = (node, variables, tick, simTime) => {
245
+ if (node.kind === "number") {
246
+ return node.value;
247
+ }
248
+ if (node.kind === "variable") {
249
+ if (node.name === "t") {
250
+ return simTime;
251
+ }
252
+ if (node.name === "tick") {
253
+ return tick;
254
+ }
255
+ if (node.name === "pi") {
256
+ return Math.PI;
257
+ }
258
+ if (node.name === "e") {
259
+ return Math.E;
260
+ }
261
+ return finite(variables[node.name]);
262
+ }
263
+ if (node.kind === "unary") {
264
+ const value = evaluateNode(node.argument, variables, tick, simTime);
265
+ return node.operator === "-" ? -value : value;
266
+ }
267
+ if (node.kind === "binary") {
268
+ const left = evaluateNode(node.left, variables, tick, simTime);
269
+ const right = evaluateNode(node.right, variables, tick, simTime);
270
+ if (node.operator === "+") {
271
+ return left + right;
272
+ }
273
+ if (node.operator === "-") {
274
+ return left - right;
275
+ }
276
+ if (node.operator === "*") {
277
+ return left * right;
278
+ }
279
+ if (node.operator === "/") {
280
+ return right === 0 ? 0 : left / right;
281
+ }
282
+ return finite(Math.pow(left, right));
283
+ }
284
+ const impl = FUNCTIONS[node.callee];
285
+ const args = node.args.map((arg) => evaluateNode(arg, variables, tick, simTime));
286
+ return finite(impl(...args));
287
+ };
288
+ export const compileExpression = (source) => {
289
+ const rewritten = rewriteDurations(source);
290
+ const parser = new Parser(rewritten);
291
+ const ast = parser.parseRootExpression();
292
+ validate(ast);
293
+ const dependencySet = new Set();
294
+ collectDependencies(ast, dependencySet);
295
+ for (const name of dependencySet) {
296
+ if (RESERVED.has(name) || name in FUNCTIONS) {
297
+ dependencySet.delete(name);
298
+ }
299
+ }
300
+ return {
301
+ source: rewritten,
302
+ dependencies: [...dependencySet],
303
+ evaluate: ({ variables, tick, t }) => finite(evaluateNode(ast, variables, tick, t))
304
+ };
305
+ };
@@ -0,0 +1,7 @@
1
+ export interface RangeSpec {
2
+ min: number;
3
+ max: number;
4
+ }
5
+ export declare const finite: (value: number) => number;
6
+ export declare const clampAndRound: (value: number, range: RangeSpec, precision: number) => number;
7
+ //# sourceMappingURL=numeric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numeric.d.ts","sourceRoot":"","sources":["../../src/runtime/numeric.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,MAAM,GAAI,OAAO,MAAM,KAAG,MAA8C,CAAC;AAEtF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,OAAO,SAAS,EAAE,WAAW,MAAM,KAAG,MASlF,CAAC"}
@@ -0,0 +1,11 @@
1
+ export const finite = (value) => (Number.isFinite(value) ? value : 0);
2
+ export const clampAndRound = (value, range, precision) => {
3
+ const rounded = Number(finite(value).toFixed(precision));
4
+ if (rounded < range.min) {
5
+ return range.min;
6
+ }
7
+ if (rounded > range.max) {
8
+ return range.max;
9
+ }
10
+ return rounded === -0 ? 0 : rounded;
11
+ };
@@ -0,0 +1,5 @@
1
+ import type { SimfileRuleAction } from "../schema/model.js";
2
+ import { type RangeSpec } from "./numeric.js";
3
+ import type { RuntimeTraceEvent } from "./types.js";
4
+ export declare const runRuleActions: (runId: string, seq: number, ruleId: string, tick: number, simTime: number, phase: string | undefined, actions: readonly SimfileRuleAction[], templateVariables: Readonly<Record<string, number>>, precision: number, ranges: Map<string, RangeSpec>, nextVariables: Record<string, number>, causeEventIds: readonly string[], variableIds: readonly string[], emit: (event: RuntimeTraceEvent) => void) => number;
5
+ //# sourceMappingURL=rule-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-actions.d.ts","sourceRoot":"","sources":["../../src/runtime/rule-actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAyHpD,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,KAAK,MAAM,EACX,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,SAAS,MAAM,EACf,OAAO,MAAM,GAAG,SAAS,EACzB,SAAS,SAAS,iBAAiB,EAAE,EACrC,mBAAmB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACnD,WAAW,MAAM,EACjB,QAAQ,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAC9B,eAAe,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACrC,eAAe,SAAS,MAAM,EAAE,EAChC,aAAa,SAAS,MAAM,EAAE,EAC9B,MAAM,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,KACvC,MAqCF,CAAC"}
@@ -0,0 +1,82 @@
1
+ import { createCanonicalEventEnvelope, DEFAULT_EMITTER_STREAM_ID, DEFAULT_PRINCIPAL_ID } from "../ledger/stable.js";
2
+ import { clampAndRound } from "./numeric.js";
3
+ const WORLD_ACTOR = "@world";
4
+ const replaceTemplateValues = (source, variables, precision) => source.replace(/\{([a-z][a-z0-9_-]*)\}/giu, (match, variableId) => {
5
+ const value = variables[variableId];
6
+ return Number.isFinite(value) ? value.toFixed(precision) : match;
7
+ });
8
+ /** Unique, deterministic identifier for a single world act (rule-emitted action). */
9
+ const actId = (runId, seq) => `${runId}:act:${seq}`;
10
+ const createActionEvent = (runId, seq, kind, simTime, actor, target, scope, payload, causeEventIds) => createCanonicalEventEnvelope({
11
+ runId,
12
+ seq,
13
+ kind,
14
+ simTime,
15
+ provenance: "mechanical",
16
+ actor,
17
+ target,
18
+ scope,
19
+ payload,
20
+ streamId: DEFAULT_EMITTER_STREAM_ID,
21
+ principalId: DEFAULT_PRINCIPAL_ID,
22
+ causeEventIds
23
+ });
24
+ /**
25
+ * world.act payload minimum: {sim_time, provenance, actor, target, scope,
26
+ * act_id, action, value}. Rule-emitted world events (world.message, world.dm,
27
+ * wake.recommended) are simfile's world.act variants, so every one of these
28
+ * carries the minimum keys directly in payload alongside its existing fields.
29
+ */
30
+ const worldActPayload = (fields, extra) => ({
31
+ sim_time: fields.simTime,
32
+ provenance: "mechanical",
33
+ actor: fields.actor,
34
+ target: fields.target,
35
+ scope: fields.scope,
36
+ act_id: actId(fields.runId, fields.seq),
37
+ action: fields.action,
38
+ value: fields.value,
39
+ ...extra
40
+ });
41
+ /** `{ variables: variableIds }` when non-empty, else `{}` — spread into a payload's `extra` so a rule with no variable condition emits byte-identical payloads to before this field existed (never a fabricated empty array). */
42
+ const variablesExtra = (variableIds) => variableIds.length > 0 ? { variables: [...variableIds] } : {};
43
+ const emitRuleActionEvents = (runId, seq, ruleId, tick, simTime, phase, action, templateVariables, precision, causeEventIds, variableIds, emit) => {
44
+ if (action.action === "variable:set" || action.action === "variable:delta") {
45
+ return seq;
46
+ }
47
+ if (action.action === "moltnet:message") {
48
+ const content = replaceTemplateValues(action.content, templateVariables, precision);
49
+ emit(createActionEvent(runId, seq, "world.message", simTime, WORLD_ACTOR, action.to, action.to, worldActPayload({ simTime, actor: WORLD_ACTOR, target: action.to, scope: action.to, seq, runId, action: action.action, value: content }, { rule: ruleId, content, tick, phase, ...variablesExtra(variableIds) }), causeEventIds));
50
+ return seq + 1;
51
+ }
52
+ if (action.action === "moltnet:dm") {
53
+ const content = replaceTemplateValues(action.content, templateVariables, precision);
54
+ emit(createActionEvent(runId, seq, "world.dm", simTime, WORLD_ACTOR, action.to, action.to, worldActPayload({ simTime, actor: WORLD_ACTOR, target: action.to, scope: action.to, seq, runId, action: action.action, value: content }, { rule: ruleId, content, tick, phase, ...variablesExtra(variableIds) }), causeEventIds));
55
+ return seq + 1;
56
+ }
57
+ emit(createActionEvent(runId, seq, "wake.recommended", simTime, ruleId, action.to, action.to, worldActPayload({ simTime, actor: ruleId, target: action.to, scope: action.to, seq, runId, action: action.action, value: null }, { reason: ruleId, target: action.to, tick, phase, ...variablesExtra(variableIds) }), causeEventIds));
58
+ return seq + 1;
59
+ };
60
+ export const runRuleActions = (runId, seq, ruleId, tick, simTime, phase, actions, templateVariables, precision, ranges, nextVariables, causeEventIds, variableIds, emit) => {
61
+ let nextSeq = seq;
62
+ for (const action of actions) {
63
+ if (action.action === "variable:set") {
64
+ const range = ranges.get(action.variable);
65
+ if (!range) {
66
+ throw new Error(`action variable:set references unknown variable ${action.variable}`);
67
+ }
68
+ nextVariables[action.variable] = clampAndRound(action.value, range, precision);
69
+ continue;
70
+ }
71
+ if (action.action === "variable:delta") {
72
+ const range = ranges.get(action.variable);
73
+ if (!range) {
74
+ throw new Error(`action variable:delta references unknown variable ${action.variable}`);
75
+ }
76
+ nextVariables[action.variable] = clampAndRound((nextVariables[action.variable] ?? 0) + action.value, range, precision);
77
+ continue;
78
+ }
79
+ nextSeq = emitRuleActionEvents(runId, nextSeq, ruleId, tick, simTime, phase, action, templateVariables, precision, causeEventIds, variableIds, emit);
80
+ }
81
+ return nextSeq;
82
+ };
@@ -0,0 +1,73 @@
1
+ import { type MarkerCoverageResult } from "../ledger/markers.js";
2
+ import { type ProbeEvaluationResult } from "../report/probes.js";
3
+ import { type TranscriptAcceptanceResult } from "../report/transcripts.js";
4
+ import type { Simfile } from "../schema/model.js";
5
+ import type { QueuedWorldAct, RuntimeTrace, RuntimeVariableSample, WorldActResult } from "./types.js";
6
+ import { type ViewerContractTrace } from "./viewer-trace.js";
7
+ export { buildCausalFixtureRecords, toCausalFixtureRecord, type CausalFixtureRecord } from "./causal-fixture.js";
8
+ export interface RunRecordOptions {
9
+ moltnetArtifact?: MoltnetArtifactKind;
10
+ outDir: string;
11
+ precision?: number;
12
+ runId: string;
13
+ seed: string;
14
+ simfile: Simfile;
15
+ sourcePath: string;
16
+ sourceText: string;
17
+ ticks: number;
18
+ worldActs?: readonly QueuedWorldAct[];
19
+ }
20
+ export interface RunReport {
21
+ markers: MarkerCoverageResult[];
22
+ moltnet?: {
23
+ transcript?: TranscriptAcceptanceResult;
24
+ };
25
+ probes: ProbeEvaluationResult[];
26
+ run_id: string;
27
+ seed: string;
28
+ ticks: number;
29
+ world_acts: WorldActResult[];
30
+ }
31
+ export interface TelemetryArtifact {
32
+ run_id: string;
33
+ samples: RuntimeVariableSample[];
34
+ snapshot_every?: number;
35
+ version: "simfile.telemetry.v1";
36
+ }
37
+ export type MoltnetArtifactKind = "delivery" | "transcript";
38
+ export interface MoltnetArtifactEntry {
39
+ event_id: string;
40
+ kind: "wake.recommended" | "world.dm" | "world.message";
41
+ marker_ids: string[];
42
+ rule_id?: string;
43
+ scope: string;
44
+ sim_time: number;
45
+ target: string;
46
+ text?: string;
47
+ }
48
+ export interface MoltnetTranscriptArtifact {
49
+ source: "harness-derived";
50
+ entries: MoltnetArtifactEntry[];
51
+ run_id: string;
52
+ version: "simfile.moltnet.transcript.v1";
53
+ }
54
+ export interface MoltnetDeliveryArtifact {
55
+ source: "harness-derived";
56
+ deliveries: MoltnetArtifactEntry[];
57
+ run_id: string;
58
+ version: "simfile.moltnet.delivery.v1";
59
+ }
60
+ export interface RunRecordResult {
61
+ ledgerPath: string;
62
+ manifestPath: string;
63
+ moltnetArtifactPath?: string;
64
+ outDir: string;
65
+ report: RunReport;
66
+ reportPath: string;
67
+ telemetryPath: string;
68
+ trace: RuntimeTrace;
69
+ viewerTrace: ViewerContractTrace;
70
+ viewerTracePath: string;
71
+ }
72
+ export declare const writeRunRecord: (options: RunRecordOptions) => Promise<RunRecordResult>;
73
+ //# sourceMappingURL=run-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-record.d.ts","sourceRoot":"","sources":["../../src/runtime/run-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,179 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import YAML from "yaml";
5
+ import { evaluateContainmentMarker, evaluatePropagationMarker, scanMarkers } from "../ledger/markers.js";
6
+ import { parseCanonicalLedgerJsonl } from "../ledger/validation.js";
7
+ import { evaluateProbe } from "../report/probes.js";
8
+ import { evaluateTranscriptAcceptance } from "../report/transcripts.js";
9
+ import { serializeCanonicalEvents } from "./trace-export.js";
10
+ import { runSimfileTrace } from "./trace-run.js";
11
+ import { buildViewerTrace } from "./viewer-trace.js";
12
+ // Re-exported so the `emit-causal-fixture` npm script (B92's real entry
13
+ // point into simfile) has a single, stable import surface next to the rest
14
+ // of run-record's artifact-writing API. See causal-fixture.ts for the
15
+ // noopolis.causal-event.v1 wire mapping.
16
+ export { buildCausalFixtureRecords, toCausalFixtureRecord } from "./causal-fixture.js";
17
+ const sha256 = (value) => createHash("sha256").update(value, "utf8").digest("hex");
18
+ const evaluateMarkers = (simfile, trace) => {
19
+ const hits = scanMarkers(trace.events, simfile.markers);
20
+ return Object.entries(simfile.markers).map(([markerId, marker]) => {
21
+ const markerHits = hits[markerId] ?? [];
22
+ return marker.mode === "containment"
23
+ ? evaluateContainmentMarker(markerId, marker, markerHits)
24
+ : evaluatePropagationMarker(markerId, marker, markerHits);
25
+ });
26
+ };
27
+ const evaluateProbes = (simfile, trace) => Object.entries(simfile.probes).map(([probeId, probe]) => evaluateProbe(probeId, { events: trace.events, samples: trace.samples }, probe));
28
+ const manifestFor = (options) => {
29
+ const artifacts = {
30
+ ledger: "ledger.jsonl",
31
+ report: "report.json",
32
+ telemetry: "telemetry.json",
33
+ viewer_trace: "viewer-trace.json"
34
+ };
35
+ if (options.moltnetArtifact) {
36
+ artifacts.moltnet = `moltnet-${options.moltnetArtifact}.json`;
37
+ }
38
+ return {
39
+ simfile_version: options.simfile.simfile_version,
40
+ run_id: options.runId,
41
+ run_name: options.simfile.name,
42
+ seed: options.seed,
43
+ ticks: options.ticks,
44
+ source: {
45
+ path: options.sourcePath,
46
+ sha256: sha256(options.sourceText)
47
+ },
48
+ artifacts
49
+ };
50
+ };
51
+ const telemetryFor = (simfile, trace) => {
52
+ const snapshotEvery = simfile.telemetry?.snapshot_every;
53
+ const samples = snapshotEvery === undefined
54
+ ? trace.samples
55
+ : trace.samples.filter((sample, index) => index === trace.samples.length - 1 || sample.tick % snapshotEvery === 0);
56
+ return {
57
+ run_id: trace.runId,
58
+ samples,
59
+ snapshot_every: snapshotEvery,
60
+ version: "simfile.telemetry.v1"
61
+ };
62
+ };
63
+ const MOLTNET_EVENT_KINDS = new Set(["wake.recommended", "world.dm", "world.message"]);
64
+ const markerIdsByEvent = (simfile, trace) => {
65
+ const hits = scanMarkers(trace.events, simfile.markers);
66
+ const markersByEvent = new Map();
67
+ for (const [markerId, markerHits] of Object.entries(hits)) {
68
+ for (const hit of markerHits) {
69
+ const existing = markersByEvent.get(hit.eventId) ?? [];
70
+ existing.push(markerId);
71
+ markersByEvent.set(hit.eventId, existing);
72
+ }
73
+ }
74
+ for (const markerIds of markersByEvent.values()) {
75
+ markerIds.sort();
76
+ }
77
+ return markersByEvent;
78
+ };
79
+ const toMoltnetEntry = (event, markersByEvent) => {
80
+ const payload = event.payload && typeof event.payload === "object"
81
+ ? event.payload
82
+ : undefined;
83
+ return {
84
+ event_id: event.event_id,
85
+ kind: event.kind,
86
+ marker_ids: markersByEvent.get(event.event_id) ?? [],
87
+ rule_id: typeof payload?.rule === "string" ? payload.rule : undefined,
88
+ scope: event.scope,
89
+ sim_time: event.sim_time,
90
+ target: event.target,
91
+ text: typeof payload?.content === "string"
92
+ ? payload.content
93
+ : typeof payload?.reason === "string"
94
+ ? payload.reason
95
+ : undefined
96
+ };
97
+ };
98
+ const buildMoltnetArtifact = (kind, simfile, trace) => {
99
+ const markersByEvent = markerIdsByEvent(simfile, trace);
100
+ const entries = trace.events
101
+ .filter((event) => MOLTNET_EVENT_KINDS.has(event.kind))
102
+ .map((event) => toMoltnetEntry(event, markersByEvent));
103
+ return kind === "delivery"
104
+ ? {
105
+ source: "harness-derived",
106
+ deliveries: entries,
107
+ run_id: trace.runId,
108
+ version: "simfile.moltnet.delivery.v1"
109
+ }
110
+ : {
111
+ source: "harness-derived",
112
+ entries,
113
+ run_id: trace.runId,
114
+ version: "simfile.moltnet.transcript.v1"
115
+ };
116
+ };
117
+ const reportMoltnetSection = (options) => {
118
+ if (options.moltnetArtifact !== "transcript") {
119
+ return undefined;
120
+ }
121
+ return {
122
+ transcript: evaluateTranscriptAcceptance({ source: "harness-derived" })
123
+ };
124
+ };
125
+ export const writeRunRecord = async (options) => {
126
+ const trace = runSimfileTrace(options.simfile, {
127
+ precision: options.precision,
128
+ runId: options.runId,
129
+ seed: options.seed,
130
+ ticks: options.ticks,
131
+ worldActs: options.worldActs
132
+ });
133
+ const markers = evaluateMarkers(options.simfile, trace);
134
+ const probes = evaluateProbes(options.simfile, trace);
135
+ const moltnet = reportMoltnetSection(options);
136
+ const report = {
137
+ markers,
138
+ ...(moltnet ? { moltnet } : {}),
139
+ probes,
140
+ run_id: options.runId,
141
+ seed: options.seed,
142
+ ticks: options.ticks,
143
+ world_acts: trace.actResults
144
+ };
145
+ const telemetry = telemetryFor(options.simfile, trace);
146
+ const viewerTrace = buildViewerTrace(options.simfile, trace, markers, probes);
147
+ await mkdir(options.outDir, { recursive: true });
148
+ const manifestPath = join(options.outDir, "manifest.yaml");
149
+ const ledgerPath = join(options.outDir, "ledger.jsonl");
150
+ const reportPath = join(options.outDir, "report.json");
151
+ const telemetryPath = join(options.outDir, "telemetry.json");
152
+ const viewerTracePath = join(options.outDir, "viewer-trace.json");
153
+ const moltnetArtifactPath = options.moltnetArtifact
154
+ ? join(options.outDir, `moltnet-${options.moltnetArtifact}.json`)
155
+ : undefined;
156
+ const ledgerJsonl = `${serializeCanonicalEvents(trace.events).join("\n")}\n`;
157
+ parseCanonicalLedgerJsonl(ledgerJsonl, { runId: options.runId });
158
+ await writeFile(manifestPath, YAML.stringify(manifestFor(options)), "utf8");
159
+ await writeFile(ledgerPath, ledgerJsonl, "utf8");
160
+ await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
161
+ await writeFile(telemetryPath, `${JSON.stringify(telemetry, null, 2)}\n`, "utf8");
162
+ await writeFile(viewerTracePath, `${JSON.stringify(viewerTrace, null, 2)}\n`, "utf8");
163
+ if (options.moltnetArtifact && moltnetArtifactPath) {
164
+ const moltnetArtifact = buildMoltnetArtifact(options.moltnetArtifact, options.simfile, trace);
165
+ await writeFile(moltnetArtifactPath, `${JSON.stringify(moltnetArtifact, null, 2)}\n`, "utf8");
166
+ }
167
+ return {
168
+ ledgerPath,
169
+ manifestPath,
170
+ moltnetArtifactPath,
171
+ outDir: options.outDir,
172
+ report,
173
+ reportPath,
174
+ telemetryPath,
175
+ trace,
176
+ viewerTrace,
177
+ viewerTracePath
178
+ };
179
+ };