@atsumell/trace-weave 0.1.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 +21 -0
- package/README.ja.md +99 -0
- package/README.md +105 -0
- package/dist/ai/index.d.ts +32 -0
- package/dist/ai/index.js +121 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/builder/index.d.ts +26 -0
- package/dist/builder/index.js +47 -0
- package/dist/builder/index.js.map +1 -0
- package/dist/chunk-35PKIXFV.js +90 -0
- package/dist/chunk-35PKIXFV.js.map +1 -0
- package/dist/chunk-AS6LZLUH.js +32 -0
- package/dist/chunk-AS6LZLUH.js.map +1 -0
- package/dist/chunk-B4SEKVLL.js +29 -0
- package/dist/chunk-B4SEKVLL.js.map +1 -0
- package/dist/chunk-EICHUHZH.js +689 -0
- package/dist/chunk-EICHUHZH.js.map +1 -0
- package/dist/chunk-WIW3TVEK.js +324 -0
- package/dist/chunk-WIW3TVEK.js.map +1 -0
- package/dist/compiler/index.d.ts +19 -0
- package/dist/compiler/index.js +24 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +37 -0
- package/dist/core/index.js.map +1 -0
- package/dist/fast-check/index.d.ts +34 -0
- package/dist/fast-check/index.js +64 -0
- package/dist/fast-check/index.js.map +1 -0
- package/dist/formula-document-ChXznpvJ.d.ts +99 -0
- package/dist/formula-expr-DAHklv9S.d.ts +111 -0
- package/dist/monitor/index.d.ts +23 -0
- package/dist/monitor/index.js +251 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/patterns/index.d.ts +61 -0
- package/dist/patterns/index.js +57 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/prepare-CrKEArDt.d.ts +8 -0
- package/dist/runtime-Do1rQFhQ.d.ts +9 -0
- package/dist/types-xatgZlwH.d.ts +35 -0
- package/dist/values-CEF1lKTL.d.ts +48 -0
- package/dist/verdict-DYG0WE3o.d.ts +7 -0
- package/dist/vitest/index.d.ts +24 -0
- package/dist/vitest/index.js +40 -0
- package/dist/vitest/index.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
import {
|
|
2
|
+
andV,
|
|
3
|
+
impliesV,
|
|
4
|
+
notV,
|
|
5
|
+
orV
|
|
6
|
+
} from "./chunk-AS6LZLUH.js";
|
|
7
|
+
import {
|
|
8
|
+
compile,
|
|
9
|
+
print,
|
|
10
|
+
validate
|
|
11
|
+
} from "./chunk-WIW3TVEK.js";
|
|
12
|
+
import {
|
|
13
|
+
activationId
|
|
14
|
+
} from "./chunk-B4SEKVLL.js";
|
|
15
|
+
|
|
16
|
+
// src/monitor/eval-common.ts
|
|
17
|
+
function envKey(env) {
|
|
18
|
+
const entries = [...env.entries()].sort(([left], [right]) => left.localeCompare(right));
|
|
19
|
+
return JSON.stringify(entries);
|
|
20
|
+
}
|
|
21
|
+
function cacheKey(nodeId, pos, env) {
|
|
22
|
+
return `${nodeId}:${pos}:${envKey(env)}`;
|
|
23
|
+
}
|
|
24
|
+
function resolveArg(arg, event, runtime) {
|
|
25
|
+
if (arg.kind === "literal") {
|
|
26
|
+
return arg.value;
|
|
27
|
+
}
|
|
28
|
+
const selectorFn = runtime.selectors[arg.selectorId];
|
|
29
|
+
if (!selectorFn) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return selectorFn(event);
|
|
33
|
+
}
|
|
34
|
+
function jsonEqual(a, b) {
|
|
35
|
+
if (a === b) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (a === null || b === null) {
|
|
39
|
+
return a === b;
|
|
40
|
+
}
|
|
41
|
+
if (typeof a !== typeof b) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (typeof a !== "object") {
|
|
45
|
+
return a === b;
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(a)) {
|
|
48
|
+
if (!Array.isArray(b) || a.length !== b.length) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return a.every((value, index) => jsonEqual(value, b[index]));
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(b)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const aObject = a;
|
|
57
|
+
const bObject = b;
|
|
58
|
+
const aKeys = Object.keys(aObject).sort();
|
|
59
|
+
const bKeys = Object.keys(bObject).sort();
|
|
60
|
+
if (aKeys.length !== bKeys.length) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return aKeys.every(
|
|
64
|
+
(key, index) => key === bKeys[index] && jsonEqual(aObject[key], bObject[key])
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/monitor/unsupported.ts
|
|
69
|
+
var WITHIN_MS_RUNTIME_MESSAGE = "withinMs requires MonitorRuntime.timestamp to be defined and return event timestamps in milliseconds.";
|
|
70
|
+
var WITHIN_MS_TIMESTAMP_MESSAGE = "MonitorRuntime.timestamp must return a finite number of milliseconds for every event.";
|
|
71
|
+
var WITHIN_MS_NON_MONOTONIC_MESSAGE = "MonitorRuntime.timestamp must be non-decreasing across the trace when using withinMs.";
|
|
72
|
+
function usesWithinMs(doc) {
|
|
73
|
+
for (const node of Object.values(doc.nodes)) {
|
|
74
|
+
if (node.kind === "withinMs") {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
function assertWithinMsRuntimeSupport(doc, runtime) {
|
|
81
|
+
if (usesWithinMs(doc) && !runtime.timestamp) {
|
|
82
|
+
throw new Error(WITHIN_MS_RUNTIME_MESSAGE);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/monitor/time.ts
|
|
87
|
+
function getTimestamp(runtime, event) {
|
|
88
|
+
const timestamp = runtime.timestamp?.(event);
|
|
89
|
+
if (timestamp === void 0 || !Number.isFinite(timestamp)) {
|
|
90
|
+
throw new Error(WITHIN_MS_TIMESTAMP_MESSAGE);
|
|
91
|
+
}
|
|
92
|
+
return timestamp;
|
|
93
|
+
}
|
|
94
|
+
function assertTimeSupportForTrace(doc, runtime, trace) {
|
|
95
|
+
if (!usesWithinMs(doc)) return;
|
|
96
|
+
assertWithinMsRuntimeSupport(doc, runtime);
|
|
97
|
+
let previous = Number.NEGATIVE_INFINITY;
|
|
98
|
+
for (const event of trace) {
|
|
99
|
+
const current = getTimestamp(runtime, event);
|
|
100
|
+
if (current < previous) {
|
|
101
|
+
throw new Error(WITHIN_MS_NON_MONOTONIC_MESSAGE);
|
|
102
|
+
}
|
|
103
|
+
previous = current;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/monitor/evaluate-finite.ts
|
|
108
|
+
function createFiniteEvalContext(doc, runtime, trace) {
|
|
109
|
+
assertTimeSupportForTrace(doc, runtime, trace);
|
|
110
|
+
return {
|
|
111
|
+
doc,
|
|
112
|
+
runtime,
|
|
113
|
+
trace,
|
|
114
|
+
cache: /* @__PURE__ */ new Map()
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function evaluateFiniteFormula(doc, runtime, trace) {
|
|
118
|
+
const ctx = createFiniteEvalContext(doc, runtime, trace);
|
|
119
|
+
return evaluateFiniteNode(ctx, doc.root, 0, /* @__PURE__ */ new Map());
|
|
120
|
+
}
|
|
121
|
+
function evaluateFiniteNode(ctx, nodeId, pos, env) {
|
|
122
|
+
const entryKey = cacheKey(nodeId, pos, env);
|
|
123
|
+
const cached = ctx.cache.get(entryKey);
|
|
124
|
+
if (cached !== void 0) {
|
|
125
|
+
return cached;
|
|
126
|
+
}
|
|
127
|
+
const node = ctx.doc.nodes[nodeId];
|
|
128
|
+
if (!node) {
|
|
129
|
+
return "violated";
|
|
130
|
+
}
|
|
131
|
+
ctx.cache.set(entryKey, "pending");
|
|
132
|
+
const verdict = evaluateFiniteNodeInner(ctx, node, pos, env);
|
|
133
|
+
ctx.cache.set(entryKey, verdict);
|
|
134
|
+
return verdict;
|
|
135
|
+
}
|
|
136
|
+
function evaluateFiniteNodeInner(ctx, node, pos, env) {
|
|
137
|
+
const len = ctx.trace.length;
|
|
138
|
+
switch (node.kind) {
|
|
139
|
+
case "literal":
|
|
140
|
+
return node.value ? "satisfied" : "violated";
|
|
141
|
+
case "predicate": {
|
|
142
|
+
if (pos >= len) {
|
|
143
|
+
return "violated";
|
|
144
|
+
}
|
|
145
|
+
const predicateFn = ctx.runtime.predicates[node.predicateId];
|
|
146
|
+
if (!predicateFn) {
|
|
147
|
+
return "violated";
|
|
148
|
+
}
|
|
149
|
+
const event = ctx.trace[pos];
|
|
150
|
+
const args = (node.args ?? []).map((arg) => resolveArg(arg, event, ctx.runtime));
|
|
151
|
+
return predicateFn(event, args) ? "satisfied" : "violated";
|
|
152
|
+
}
|
|
153
|
+
case "when": {
|
|
154
|
+
if (pos >= len) {
|
|
155
|
+
return "violated";
|
|
156
|
+
}
|
|
157
|
+
const captured = env.get(node.captureName);
|
|
158
|
+
if (captured === void 0) {
|
|
159
|
+
return "violated";
|
|
160
|
+
}
|
|
161
|
+
const selectorFn = ctx.runtime.selectors[node.selectorId];
|
|
162
|
+
if (!selectorFn) {
|
|
163
|
+
return "violated";
|
|
164
|
+
}
|
|
165
|
+
const currentValue = selectorFn(ctx.trace[pos]);
|
|
166
|
+
if (!jsonEqual(captured, currentValue)) {
|
|
167
|
+
return "violated";
|
|
168
|
+
}
|
|
169
|
+
return evaluateFiniteNode(ctx, node.child, pos, env);
|
|
170
|
+
}
|
|
171
|
+
case "capture": {
|
|
172
|
+
if (pos >= len) {
|
|
173
|
+
return "violated";
|
|
174
|
+
}
|
|
175
|
+
const selectorFn = ctx.runtime.selectors[node.selectorId];
|
|
176
|
+
if (!selectorFn) {
|
|
177
|
+
return "violated";
|
|
178
|
+
}
|
|
179
|
+
const nextEnv = new Map(env);
|
|
180
|
+
nextEnv.set(node.captureName, selectorFn(ctx.trace[pos]));
|
|
181
|
+
return evaluateFiniteNode(ctx, node.child, pos, nextEnv);
|
|
182
|
+
}
|
|
183
|
+
case "not":
|
|
184
|
+
return notV(evaluateFiniteNode(ctx, node.child, pos, env));
|
|
185
|
+
case "and": {
|
|
186
|
+
let result = "satisfied";
|
|
187
|
+
for (const childId of node.children) {
|
|
188
|
+
result = andV(result, evaluateFiniteNode(ctx, childId, pos, env));
|
|
189
|
+
if (result === "violated") {
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
case "or": {
|
|
196
|
+
let result = "violated";
|
|
197
|
+
for (const childId of node.children) {
|
|
198
|
+
result = orV(result, evaluateFiniteNode(ctx, childId, pos, env));
|
|
199
|
+
if (result === "satisfied") {
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
case "implies":
|
|
206
|
+
return impliesV(
|
|
207
|
+
evaluateFiniteNode(ctx, node.left, pos, env),
|
|
208
|
+
evaluateFiniteNode(ctx, node.right, pos, env)
|
|
209
|
+
);
|
|
210
|
+
case "always": {
|
|
211
|
+
if (pos >= len) {
|
|
212
|
+
return "satisfied";
|
|
213
|
+
}
|
|
214
|
+
let result = "satisfied";
|
|
215
|
+
for (let step = pos; step < len; step++) {
|
|
216
|
+
result = andV(result, evaluateFiniteNode(ctx, node.child, step, env));
|
|
217
|
+
if (result === "violated") {
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
case "eventually": {
|
|
224
|
+
if (pos >= len) {
|
|
225
|
+
return "violated";
|
|
226
|
+
}
|
|
227
|
+
let result = "violated";
|
|
228
|
+
for (let step = pos; step < len; step++) {
|
|
229
|
+
result = orV(result, evaluateFiniteNode(ctx, node.child, step, env));
|
|
230
|
+
if (result === "satisfied") {
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
case "next":
|
|
237
|
+
return pos + 1 >= len ? "violated" : evaluateFiniteNode(ctx, node.child, pos + 1, env);
|
|
238
|
+
case "weakNext":
|
|
239
|
+
return pos + 1 >= len ? "satisfied" : evaluateFiniteNode(ctx, node.child, pos + 1, env);
|
|
240
|
+
case "until": {
|
|
241
|
+
if (pos >= len) {
|
|
242
|
+
return "violated";
|
|
243
|
+
}
|
|
244
|
+
let leftAccumulator = "satisfied";
|
|
245
|
+
for (let step = pos; step < len; step++) {
|
|
246
|
+
const rightVerdict = evaluateFiniteNode(ctx, node.right, step, env);
|
|
247
|
+
if (rightVerdict === "satisfied" && leftAccumulator === "satisfied") {
|
|
248
|
+
return "satisfied";
|
|
249
|
+
}
|
|
250
|
+
const leftVerdict = evaluateFiniteNode(ctx, node.left, step, env);
|
|
251
|
+
leftAccumulator = step === pos ? leftVerdict : andV(leftAccumulator, leftVerdict);
|
|
252
|
+
if (leftAccumulator === "violated") {
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return "violated";
|
|
257
|
+
}
|
|
258
|
+
case "release": {
|
|
259
|
+
if (pos >= len) {
|
|
260
|
+
return "satisfied";
|
|
261
|
+
}
|
|
262
|
+
let allRight = "satisfied";
|
|
263
|
+
for (let step = pos; step < len; step++) {
|
|
264
|
+
allRight = andV(allRight, evaluateFiniteNode(ctx, node.right, step, env));
|
|
265
|
+
const leftVerdict = evaluateFiniteNode(ctx, node.left, step, env);
|
|
266
|
+
if (leftVerdict === "satisfied" && allRight === "satisfied") {
|
|
267
|
+
return "satisfied";
|
|
268
|
+
}
|
|
269
|
+
if (allRight === "violated") {
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return allRight === "satisfied" ? "satisfied" : "violated";
|
|
274
|
+
}
|
|
275
|
+
case "once": {
|
|
276
|
+
if (pos >= len) {
|
|
277
|
+
return "violated";
|
|
278
|
+
}
|
|
279
|
+
for (let step = pos; step >= 0; step--) {
|
|
280
|
+
if (evaluateFiniteNode(ctx, node.child, step, env) === "satisfied") {
|
|
281
|
+
return "satisfied";
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return "violated";
|
|
285
|
+
}
|
|
286
|
+
case "historically": {
|
|
287
|
+
if (pos >= len) {
|
|
288
|
+
return "satisfied";
|
|
289
|
+
}
|
|
290
|
+
for (let step = 0; step <= pos; step++) {
|
|
291
|
+
if (evaluateFiniteNode(ctx, node.child, step, env) === "violated") {
|
|
292
|
+
return "violated";
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return "satisfied";
|
|
296
|
+
}
|
|
297
|
+
case "since": {
|
|
298
|
+
if (pos >= len) {
|
|
299
|
+
return "violated";
|
|
300
|
+
}
|
|
301
|
+
for (let witness = pos; witness >= 0; witness--) {
|
|
302
|
+
if (evaluateFiniteNode(ctx, node.right, witness, env) !== "satisfied") {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
let leftOk = "satisfied";
|
|
306
|
+
for (let step = witness + 1; step <= pos; step++) {
|
|
307
|
+
leftOk = andV(leftOk, evaluateFiniteNode(ctx, node.left, step, env));
|
|
308
|
+
if (leftOk === "violated") {
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (leftOk === "satisfied") {
|
|
313
|
+
return "satisfied";
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return "violated";
|
|
317
|
+
}
|
|
318
|
+
case "withinSteps": {
|
|
319
|
+
const upper = Math.min(pos + node.steps, len);
|
|
320
|
+
for (let step = pos; step < upper; step++) {
|
|
321
|
+
if (evaluateFiniteNode(ctx, node.child, step, env) === "satisfied") {
|
|
322
|
+
return "satisfied";
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return "violated";
|
|
326
|
+
}
|
|
327
|
+
case "withinMs": {
|
|
328
|
+
if (pos >= len) {
|
|
329
|
+
return "violated";
|
|
330
|
+
}
|
|
331
|
+
const startTs = getTimestamp(ctx.runtime, ctx.trace[pos]);
|
|
332
|
+
for (let step = pos; step < len; step++) {
|
|
333
|
+
const currentTs = getTimestamp(ctx.runtime, ctx.trace[step]);
|
|
334
|
+
if (currentTs - startTs > node.ms) {
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
if (evaluateFiniteNode(ctx, node.child, step, env) === "satisfied") {
|
|
338
|
+
return "satisfied";
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return "violated";
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/monitor/evaluate.ts
|
|
347
|
+
function evaluateFormula(doc, runtime, trace) {
|
|
348
|
+
return evaluateFiniteFormula(doc, runtime, trace);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/monitor/diagnostics.ts
|
|
352
|
+
function buildCounterexampleReport(doc, runtime, trace) {
|
|
353
|
+
const ctx = createFiniteEvalContext(doc, runtime, trace);
|
|
354
|
+
const env = /* @__PURE__ */ new Map();
|
|
355
|
+
const verdict = evaluateFiniteNode(ctx, doc.root, 0, env);
|
|
356
|
+
if (verdict !== "violated") {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
const failurePath = [];
|
|
360
|
+
collectFailurePath(ctx, doc.root, 0, env, failurePath);
|
|
361
|
+
return {
|
|
362
|
+
verdict: "violated",
|
|
363
|
+
failurePath,
|
|
364
|
+
traceSlice: trace.map((event, i) => ({ step: i + 1, event })),
|
|
365
|
+
summary: `Formula violated: ${print(doc)}`
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function collectFailurePath(ctx, nodeId, pos, env, path) {
|
|
369
|
+
const verdict = evaluateFiniteNode(ctx, nodeId, pos, env);
|
|
370
|
+
path.push({
|
|
371
|
+
nodeId,
|
|
372
|
+
activationId: toActivationId(nodeId, pos, env),
|
|
373
|
+
verdict,
|
|
374
|
+
step: pos
|
|
375
|
+
});
|
|
376
|
+
const node = ctx.doc.nodes[nodeId];
|
|
377
|
+
if (!node) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
switch (node.kind) {
|
|
381
|
+
case "literal":
|
|
382
|
+
case "predicate":
|
|
383
|
+
return;
|
|
384
|
+
case "when": {
|
|
385
|
+
if (pos >= ctx.trace.length) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const captured = env.get(node.captureName);
|
|
389
|
+
if (captured === void 0) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const selectorFn = ctx.runtime.selectors[node.selectorId];
|
|
393
|
+
if (!selectorFn) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const currentVal = selectorFn(ctx.trace[pos]);
|
|
397
|
+
if (!jsonEqual(captured, currentVal)) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
collectFailurePath(ctx, node.child, pos, env, path);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
case "capture": {
|
|
404
|
+
if (pos >= ctx.trace.length) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const selectorFn = ctx.runtime.selectors[node.selectorId];
|
|
408
|
+
if (!selectorFn) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const nextEnv = new Map(env);
|
|
412
|
+
nextEnv.set(node.captureName, selectorFn(ctx.trace[pos]));
|
|
413
|
+
collectFailurePath(ctx, node.child, pos, nextEnv, path);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
case "not":
|
|
417
|
+
collectFailurePath(ctx, node.child, pos, env, path);
|
|
418
|
+
return;
|
|
419
|
+
case "and":
|
|
420
|
+
case "or": {
|
|
421
|
+
const childId = pickBooleanChild(ctx, node, pos, env, verdict);
|
|
422
|
+
if (childId) {
|
|
423
|
+
collectFailurePath(ctx, childId, pos, env, path);
|
|
424
|
+
}
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
case "implies": {
|
|
428
|
+
const leftVerdict = evaluateFiniteNode(ctx, node.left, pos, env);
|
|
429
|
+
const rightVerdict = evaluateFiniteNode(ctx, node.right, pos, env);
|
|
430
|
+
if (verdict === "violated") {
|
|
431
|
+
collectFailurePath(ctx, node.right, pos, env, path);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (rightVerdict === "satisfied") {
|
|
435
|
+
collectFailurePath(ctx, node.right, pos, env, path);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
if (leftVerdict !== verdict || rightVerdict === "pending") {
|
|
439
|
+
collectFailurePath(ctx, node.left, pos, env, path);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
case "always": {
|
|
445
|
+
const childPos = verdict === "violated" ? findFirstPosition(ctx, node.child, pos, ctx.trace.length - 1, env, "violated") : pos < ctx.trace.length ? pos : null;
|
|
446
|
+
if (childPos !== null) {
|
|
447
|
+
collectFailurePath(ctx, node.child, childPos, env, path);
|
|
448
|
+
}
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
case "eventually": {
|
|
452
|
+
const childPos = verdict === "satisfied" ? findFirstPosition(ctx, node.child, pos, ctx.trace.length - 1, env, "satisfied") : findLastPosition(ctx, node.child, pos, ctx.trace.length - 1, env, "violated");
|
|
453
|
+
if (childPos !== null) {
|
|
454
|
+
collectFailurePath(ctx, node.child, childPos, env, path);
|
|
455
|
+
}
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
case "next":
|
|
459
|
+
case "weakNext":
|
|
460
|
+
if (pos + 1 < ctx.trace.length) {
|
|
461
|
+
collectFailurePath(ctx, node.child, pos + 1, env, path);
|
|
462
|
+
}
|
|
463
|
+
return;
|
|
464
|
+
case "until": {
|
|
465
|
+
const witness = findUntilFailureOrWitness(ctx, node, pos, env, verdict);
|
|
466
|
+
if (witness) {
|
|
467
|
+
collectFailurePath(ctx, witness.nodeId, witness.pos, env, path);
|
|
468
|
+
}
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
case "release": {
|
|
472
|
+
const witness = findReleaseFailureOrWitness(ctx, node, pos, env, verdict);
|
|
473
|
+
if (witness) {
|
|
474
|
+
collectFailurePath(ctx, witness.nodeId, witness.pos, env, path);
|
|
475
|
+
}
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
case "once": {
|
|
479
|
+
const childPos = verdict === "satisfied" ? findLastPosition(ctx, node.child, 0, pos, env, "satisfied") : pos < ctx.trace.length ? pos : null;
|
|
480
|
+
if (childPos !== null) {
|
|
481
|
+
collectFailurePath(ctx, node.child, childPos, env, path);
|
|
482
|
+
}
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
case "historically": {
|
|
486
|
+
const childPos = verdict === "violated" ? findFirstPosition(ctx, node.child, 0, pos, env, "violated") : pos < ctx.trace.length ? pos : null;
|
|
487
|
+
if (childPos !== null) {
|
|
488
|
+
collectFailurePath(ctx, node.child, childPos, env, path);
|
|
489
|
+
}
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
case "since": {
|
|
493
|
+
const witness = findSinceFailureOrWitness(ctx, node, pos, env, verdict);
|
|
494
|
+
if (witness) {
|
|
495
|
+
collectFailurePath(ctx, witness.nodeId, witness.pos, env, path);
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
case "withinSteps": {
|
|
500
|
+
const upper = Math.min(pos + node.steps - 1, ctx.trace.length - 1);
|
|
501
|
+
const childPos = verdict === "satisfied" ? findFirstPosition(ctx, node.child, pos, upper, env, "satisfied") : findLastPosition(ctx, node.child, pos, upper, env, "violated");
|
|
502
|
+
if (childPos !== null) {
|
|
503
|
+
collectFailurePath(ctx, node.child, childPos, env, path);
|
|
504
|
+
}
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
case "withinMs": {
|
|
508
|
+
if (pos >= ctx.trace.length) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const startTs = getTimestamp(ctx.runtime, ctx.trace[pos]);
|
|
512
|
+
let lastInBudget = null;
|
|
513
|
+
for (let i = pos; i < ctx.trace.length; i++) {
|
|
514
|
+
const currentTs = getTimestamp(ctx.runtime, ctx.trace[i]);
|
|
515
|
+
if (currentTs - startTs > node.ms) {
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
lastInBudget = i;
|
|
519
|
+
if (verdict === "satisfied" && evaluateFiniteNode(ctx, node.child, i, env) === "satisfied") {
|
|
520
|
+
collectFailurePath(ctx, node.child, i, env, path);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (verdict === "violated" && lastInBudget !== null) {
|
|
525
|
+
const childPos = findLastPosition(ctx, node.child, pos, lastInBudget, env, "violated");
|
|
526
|
+
if (childPos !== null) {
|
|
527
|
+
collectFailurePath(ctx, node.child, childPos, env, path);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
function pickBooleanChild(ctx, node, pos, env, verdict) {
|
|
534
|
+
for (const childId of node.children) {
|
|
535
|
+
const childVerdict = evaluateFiniteNode(ctx, childId, pos, env);
|
|
536
|
+
if (verdict === "violated" && childVerdict === "violated") {
|
|
537
|
+
return childId;
|
|
538
|
+
}
|
|
539
|
+
if (verdict === "satisfied" && childVerdict === "satisfied") {
|
|
540
|
+
return childId;
|
|
541
|
+
}
|
|
542
|
+
if (verdict === "pending" && childVerdict === "pending") {
|
|
543
|
+
return childId;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return node.children[0] ?? null;
|
|
547
|
+
}
|
|
548
|
+
function findUntilFailureOrWitness(ctx, node, pos, env, verdict) {
|
|
549
|
+
if (pos >= ctx.trace.length) {
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
let leftAcc = "satisfied";
|
|
553
|
+
for (let j = pos; j < ctx.trace.length; j++) {
|
|
554
|
+
const rightVerdict = evaluateFiniteNode(ctx, node.right, j, env);
|
|
555
|
+
if (rightVerdict === "satisfied" && leftAcc === "satisfied") {
|
|
556
|
+
return verdict === "satisfied" ? { nodeId: node.right, pos: j } : null;
|
|
557
|
+
}
|
|
558
|
+
const leftVerdict = evaluateFiniteNode(ctx, node.left, j, env);
|
|
559
|
+
if (verdict === "violated" && leftAcc === "satisfied" && leftVerdict === "violated") {
|
|
560
|
+
return { nodeId: node.left, pos: j };
|
|
561
|
+
}
|
|
562
|
+
leftAcc = j === pos ? leftVerdict : andV(leftAcc, leftVerdict);
|
|
563
|
+
if (leftAcc === "violated") {
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (verdict === "violated") {
|
|
568
|
+
const rightPos = findLastPosition(ctx, node.right, pos, ctx.trace.length - 1, env, "violated");
|
|
569
|
+
if (rightPos !== null) {
|
|
570
|
+
return { nodeId: node.right, pos: rightPos };
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
function findReleaseFailureOrWitness(ctx, node, pos, env, verdict) {
|
|
576
|
+
if (pos >= ctx.trace.length) {
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
let allRight = "satisfied";
|
|
580
|
+
for (let j = pos; j < ctx.trace.length; j++) {
|
|
581
|
+
const rightVerdict = evaluateFiniteNode(ctx, node.right, j, env);
|
|
582
|
+
if (verdict === "violated" && allRight === "satisfied" && rightVerdict === "violated") {
|
|
583
|
+
return { nodeId: node.right, pos: j };
|
|
584
|
+
}
|
|
585
|
+
allRight = andV(allRight, rightVerdict);
|
|
586
|
+
const leftVerdict = evaluateFiniteNode(ctx, node.left, j, env);
|
|
587
|
+
if (leftVerdict === "satisfied" && allRight === "satisfied") {
|
|
588
|
+
return verdict === "satisfied" ? { nodeId: node.left, pos: j } : null;
|
|
589
|
+
}
|
|
590
|
+
if (allRight === "violated") {
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
if (verdict === "satisfied" && pos < ctx.trace.length) {
|
|
595
|
+
return { nodeId: node.right, pos };
|
|
596
|
+
}
|
|
597
|
+
return null;
|
|
598
|
+
}
|
|
599
|
+
function findSinceFailureOrWitness(ctx, node, pos, env, verdict) {
|
|
600
|
+
if (pos >= ctx.trace.length) {
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
for (let j = pos; j >= 0; j--) {
|
|
604
|
+
const rightVerdict = evaluateFiniteNode(ctx, node.right, j, env);
|
|
605
|
+
if (rightVerdict === "satisfied") {
|
|
606
|
+
let leftOk = "satisfied";
|
|
607
|
+
for (let i = j + 1; i <= pos; i++) {
|
|
608
|
+
const leftVerdict = evaluateFiniteNode(ctx, node.left, i, env);
|
|
609
|
+
if (verdict === "violated" && leftVerdict === "violated") {
|
|
610
|
+
return { nodeId: node.left, pos: i };
|
|
611
|
+
}
|
|
612
|
+
leftOk = andV(leftOk, leftVerdict);
|
|
613
|
+
if (leftOk === "violated") {
|
|
614
|
+
break;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (leftOk === "satisfied") {
|
|
618
|
+
return verdict === "satisfied" ? { nodeId: node.right, pos: j } : null;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (verdict === "violated") {
|
|
623
|
+
const rightPos = findFirstPosition(ctx, node.right, 0, pos, env, "violated");
|
|
624
|
+
if (rightPos !== null) {
|
|
625
|
+
return { nodeId: node.right, pos: rightPos };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return null;
|
|
629
|
+
}
|
|
630
|
+
function findFirstPosition(ctx, nodeId, start, end, env, verdict) {
|
|
631
|
+
if (start > end) {
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
for (let pos = start; pos <= end; pos++) {
|
|
635
|
+
if (evaluateFiniteNode(ctx, nodeId, pos, env) === verdict) {
|
|
636
|
+
return pos;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
function findLastPosition(ctx, nodeId, start, end, env, verdict) {
|
|
642
|
+
if (start > end) {
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
for (let pos = end; pos >= start; pos--) {
|
|
646
|
+
if (evaluateFiniteNode(ctx, nodeId, pos, env) === verdict) {
|
|
647
|
+
return pos;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
652
|
+
function toActivationId(nodeId, pos, env) {
|
|
653
|
+
return activationId(`${nodeId}:${pos}:${encodeURIComponent(envKey(env))}`);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// src/monitor/run-oracle.ts
|
|
657
|
+
function runOracle(formula, runtime, trace) {
|
|
658
|
+
const doc = compile(formula);
|
|
659
|
+
const errors = validate(doc);
|
|
660
|
+
if (errors.length > 0) {
|
|
661
|
+
const messages = errors.map((e) => `${e.nodeId}: ${e.message}`).join("; ");
|
|
662
|
+
throw new Error(`Invalid formula: ${messages}`);
|
|
663
|
+
}
|
|
664
|
+
const verdict = evaluateFormula(doc, runtime, trace);
|
|
665
|
+
const report = verdict === "violated" ? buildCounterexampleReport(doc, runtime, trace) ?? {
|
|
666
|
+
verdict: "violated",
|
|
667
|
+
failurePath: [],
|
|
668
|
+
traceSlice: trace.map((event, i) => ({ step: i + 1, event })),
|
|
669
|
+
summary: `Formula violated: ${print(doc)}`
|
|
670
|
+
} : null;
|
|
671
|
+
return {
|
|
672
|
+
verdict,
|
|
673
|
+
steps: trace.length,
|
|
674
|
+
report
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
export {
|
|
679
|
+
assertWithinMsRuntimeSupport,
|
|
680
|
+
cacheKey,
|
|
681
|
+
resolveArg,
|
|
682
|
+
jsonEqual,
|
|
683
|
+
getTimestamp,
|
|
684
|
+
assertTimeSupportForTrace,
|
|
685
|
+
buildCounterexampleReport,
|
|
686
|
+
evaluateFormula,
|
|
687
|
+
runOracle
|
|
688
|
+
};
|
|
689
|
+
//# sourceMappingURL=chunk-EICHUHZH.js.map
|