@systemfsoftware/trace-spec 0.5.1 → 0.5.2
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/CHANGELOG.md +7 -0
- package/dist/index.d.ts +9 -7
- package/dist/index.mjs +480 -207
- package/package.json +15 -6
package/CHANGELOG.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Context, Duration, Effect, FileSystem, Layer,
|
|
1
|
+
import { Context, Duration, Effect, FileSystem, Layer, Option, Schema } from "effect";
|
|
2
2
|
import { Pipeable } from "effect/Pipeable";
|
|
3
3
|
import { Span, Taxonomy } from "@systemfsoftware/trace-taxonomy";
|
|
4
|
+
import * as Result$1 from "effect/Result";
|
|
4
5
|
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
5
|
-
import * as OtelTracer from "@effect/opentelemetry/OtelTracer";
|
|
6
6
|
import { Blueprint, Handle } from "@systemfsoftware/effect-cell-types";
|
|
7
|
+
import * as OtelTracer from "@effect/opentelemetry/OtelTracer";
|
|
7
8
|
import { BasicTracerProvider, ReadableSpan } from "@opentelemetry/sdk-trace-base";
|
|
8
9
|
import { Suite } from "@systemfsoftware/effect-spec-runtime";
|
|
9
10
|
import { Asserted, Check, Expect } from "@systemfsoftware/vitest";
|
|
@@ -126,9 +127,7 @@ declare const TraceGraph: Schema.Struct<{
|
|
|
126
127
|
}>>;
|
|
127
128
|
}>;
|
|
128
129
|
type TraceGraph = typeof TraceGraph.Type;
|
|
129
|
-
|
|
130
|
-
export { AttributeValue, Attributes, GraphNode, SpanEvent, SpanLink, SpanRecord, Status, TraceGraph, byId, children, decode, descendants };
|
|
131
|
-
}
|
|
130
|
+
type GraphDecoded = Result$1.Result<TraceGraph, ContractDecodeError>;
|
|
132
131
|
declare const byId: {
|
|
133
132
|
(spec: Span.Span): (graph: TraceGraph) => ReadonlyArray<GraphNode>;
|
|
134
133
|
(graph: TraceGraph, spec: Span.Span): ReadonlyArray<GraphNode>;
|
|
@@ -149,9 +148,12 @@ declare const descendants: {
|
|
|
149
148
|
* fail the pipeline by accident.
|
|
150
149
|
*/
|
|
151
150
|
declare const decode: {
|
|
152
|
-
(spans: ReadonlyArray<SpanRecord>, taxonomy: Taxonomy.Taxonomy): (traceId: string) =>
|
|
153
|
-
(traceId: string, spans: ReadonlyArray<SpanRecord>, taxonomy: Taxonomy.Taxonomy):
|
|
151
|
+
(spans: ReadonlyArray<SpanRecord>, taxonomy: Taxonomy.Taxonomy): (traceId: string) => GraphDecoded;
|
|
152
|
+
(traceId: string, spans: ReadonlyArray<SpanRecord>, taxonomy: Taxonomy.Taxonomy): GraphDecoded;
|
|
154
153
|
};
|
|
154
|
+
declare namespace Graph_d_exports {
|
|
155
|
+
export { AttributeValue, Attributes, GraphDecoded, GraphNode, SpanEvent, SpanLink, SpanRecord, Status, TraceGraph, byId, children, decode, descendants };
|
|
156
|
+
}
|
|
155
157
|
//#endregion
|
|
156
158
|
//#region src/TransportObservationError.schema.d.ts
|
|
157
159
|
declare const TransportObservationError_base: Schema.Class<TransportObservationError, Schema.TaggedStruct<"TransportObservationError", {
|
package/dist/index.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { callFrameOutside, withRaisingFrame } from "@systemfsoftware/vitest/failure";
|
|
3
3
|
import { Array as Array$1, Cause, Clock, Context, Duration, Effect, Encoding, Equal, FileSystem, Layer, Match, Option, Predicate, Random, Ref, Result, Schema, SchemaGetter, SchemaTransformation } from "effect";
|
|
4
|
-
import { dual } from "effect/Function";
|
|
4
|
+
import { absurd, dual } from "effect/Function";
|
|
5
5
|
import { Prototype } from "effect/Pipeable";
|
|
6
6
|
import "effect/PlatformError";
|
|
7
7
|
import "@systemfsoftware/trace-taxonomy";
|
|
8
8
|
import "effect/Array";
|
|
9
|
-
import "effect/Result";
|
|
9
|
+
import * as Result$1 from "effect/Result";
|
|
10
10
|
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
11
11
|
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
12
12
|
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
13
|
+
import { Blueprint, Handle, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
13
14
|
import * as OtelTracer from "@effect/opentelemetry/OtelTracer";
|
|
14
15
|
import * as OtelResource from "@effect/opentelemetry/Resource";
|
|
15
|
-
import { Blueprint, Handle } from "@systemfsoftware/effect-cell-types";
|
|
16
16
|
import { SpanStatusCode } from "@opentelemetry/api";
|
|
17
17
|
import { AlwaysOnSampler, BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
|
|
18
18
|
import { Suite, TaskRef } from "@systemfsoftware/effect-spec-runtime";
|
|
@@ -46,64 +46,6 @@ var EmptyObservationError = class extends Schema.TaggedError()("EmptyObservation
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
//#endregion
|
|
49
|
-
//#region src/Verdict.schema.ts
|
|
50
|
-
const Hold = Schema.TaggedStruct("Hold", {
|
|
51
|
-
conjunct: Schema.String,
|
|
52
|
-
inspected: Schema.Array(Schema.String)
|
|
53
|
-
});
|
|
54
|
-
const Break = Schema.TaggedStruct("Break", {
|
|
55
|
-
conjunct: Schema.String,
|
|
56
|
-
inspected: Schema.Array(Schema.String),
|
|
57
|
-
detail: Schema.String
|
|
58
|
-
});
|
|
59
|
-
const Verdict = Schema.Union([Hold, Break]);
|
|
60
|
-
//#endregion
|
|
61
|
-
//#region src/FailureDump.ts
|
|
62
|
-
const DEFAULT_DIRECTORY = "artifacts/traces";
|
|
63
|
-
const isBreak$1 = Schema.is(Break);
|
|
64
|
-
/**
|
|
65
|
-
* The rendered evidence a break carries; a held verdict leaves nothing to write.
|
|
66
|
-
*/
|
|
67
|
-
const report = (verdict) => Option.map(Option.liftPredicate(verdict, isBreak$1), renderBreach);
|
|
68
|
-
const renderValue = (value) => JSON.stringify(value);
|
|
69
|
-
const renderEntries = (entries) => [...entries].map(([key, value]) => `${key}=${renderValue(value)}`).join(" ");
|
|
70
|
-
const indentOf = (depth) => " ".repeat(depth);
|
|
71
|
-
const renderBreach = (breach) => `break ${breach.conjunct} inspected=[${breach.inspected.join(", ")}]\n${indentOf(1)}${breach.detail}`;
|
|
72
|
-
const childrenOf = (spans, spanId) => spans.filter((span) => span.parentSpanId === spanId);
|
|
73
|
-
const renderNode = (spans, node, depth) => {
|
|
74
|
-
return [`${indentOf(depth)}${node.name} (${node.spanId}) status=${node.status} error.type=${String(node.errorType)} duration=${node.durationMillis}ms`, ...[
|
|
75
|
-
`${indentOf(depth)} attrs: ${renderEntries(Object.entries(node.attributes))}`,
|
|
76
|
-
...node.events.map((event) => `${indentOf(depth)} event ${event.name} ${renderEntries(Object.entries(event.attributes))}`),
|
|
77
|
-
...node.links.map((link) => `${indentOf(depth)} link ${link.traceId}/${link.spanId}`),
|
|
78
|
-
...childrenOf(spans, node.spanId).map((child) => renderNode(spans, child, depth + 1))
|
|
79
|
-
]].join("\n");
|
|
80
|
-
};
|
|
81
|
-
const documentImpl = (observed, report) => [
|
|
82
|
-
`trace ${observed.traceId}`,
|
|
83
|
-
report,
|
|
84
|
-
...observed.spans.map((node) => renderNode(observed.spans, node, 0))
|
|
85
|
-
].join("\n");
|
|
86
|
-
/**
|
|
87
|
-
* The dump document: the trace it belongs to, the break that refused it, and the recorded
|
|
88
|
-
* spans as the observation window saw them.
|
|
89
|
-
*/
|
|
90
|
-
const document = dual(2, documentImpl);
|
|
91
|
-
const sanitize = (value) => value.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
92
|
-
const fileNameOf = (request) => `${sanitize(request.name ?? request.traceId)}.${sanitize(request.conjunct)}.txt`;
|
|
93
|
-
/**
|
|
94
|
-
* Writes the dump under the artifacts directory and answers with its path. The file is
|
|
95
|
-
* named after the request's name when one is given — a generated case names its dump after
|
|
96
|
-
* itself, so every failing draw overwrites one file and the last write is the reported
|
|
97
|
-
* counterexample.
|
|
98
|
-
*/
|
|
99
|
-
const write = (request) => Effect.gen(function* () {
|
|
100
|
-
const fs = yield* FileSystem.FileSystem;
|
|
101
|
-
yield* fs.makeDirectory(DEFAULT_DIRECTORY, { recursive: true });
|
|
102
|
-
const path = `${DEFAULT_DIRECTORY}/${fileNameOf(request)}`;
|
|
103
|
-
yield* fs.writeFileString(path, document(request, request.report));
|
|
104
|
-
return path;
|
|
105
|
-
});
|
|
106
|
-
//#endregion
|
|
107
49
|
//#region src/TraceGraph.schema.ts
|
|
108
50
|
const Status = Schema.Literals([
|
|
109
51
|
"ok",
|
|
@@ -159,22 +101,6 @@ const TraceGraph = Schema.Struct({
|
|
|
159
101
|
traceId: Schema.String,
|
|
160
102
|
nodes: Schema.Array(GraphNode)
|
|
161
103
|
});
|
|
162
|
-
//#endregion
|
|
163
|
-
//#region src/Graph.ts
|
|
164
|
-
var Graph_exports = /* @__PURE__ */ __exportAll({
|
|
165
|
-
AttributeValue: () => AttributeValue,
|
|
166
|
-
Attributes: () => Attributes,
|
|
167
|
-
GraphNode: () => GraphNode,
|
|
168
|
-
SpanEvent: () => SpanEvent,
|
|
169
|
-
SpanLink: () => SpanLink,
|
|
170
|
-
SpanRecord: () => SpanRecord,
|
|
171
|
-
Status: () => Status,
|
|
172
|
-
TraceGraph: () => TraceGraph,
|
|
173
|
-
byId: () => byId,
|
|
174
|
-
children: () => children,
|
|
175
|
-
decode: () => decode,
|
|
176
|
-
descendants: () => descendants
|
|
177
|
-
});
|
|
178
104
|
const byIdImpl = (graph, spec) => graph.nodes.filter((node) => node.name === spec.name);
|
|
179
105
|
const byId = dual(2, byIdImpl);
|
|
180
106
|
const childrenImpl = (graph, node) => graph.nodes.filter((candidate) => candidate.parentSpanId === node.spanId);
|
|
@@ -204,7 +130,7 @@ const decodeFailure = (spec, record, detail, attribute) => ContractDecodeError.m
|
|
|
204
130
|
attribute: attribute ?? "*",
|
|
205
131
|
detail
|
|
206
132
|
});
|
|
207
|
-
const decodeAttrs = (spec, record) => Result.mapError(Schema.decodeResult(Schema.toType(spec.attrs))(record.attributes), (error) => decodeFailure(spec, record, error.message, attributeNameOf(error.issue)));
|
|
133
|
+
const decodeAttrs = (spec, record) => Result$1.mapError(Schema.decodeResult(Schema.toType(spec.attrs))(record.attributes), (error) => decodeFailure(spec, record, error.message, attributeNameOf(error.issue)));
|
|
208
134
|
const nodeOf = (record, attrs) => ({
|
|
209
135
|
spanId: record.spanId,
|
|
210
136
|
parentSpanId: record.parentSpanId,
|
|
@@ -217,10 +143,10 @@ const nodeOf = (record, attrs) => ({
|
|
|
217
143
|
events: record.events,
|
|
218
144
|
links: record.links
|
|
219
145
|
});
|
|
220
|
-
const decodedNodeOf = (record, spec) => Result.map(decodeAttrs(spec, record), (attrs) => nodeOf(record, attrs));
|
|
146
|
+
const decodedNodeOf = (record, spec) => Result$1.map(decodeAttrs(spec, record), (attrs) => nodeOf(record, attrs));
|
|
221
147
|
const declaredNodeOf = (record, declarations) => {
|
|
222
148
|
const spec = declarations.get(record.name);
|
|
223
|
-
return spec === void 0 ? Result.succeed(nodeOf(record, record.attributes)) : decodedNodeOf(record, spec);
|
|
149
|
+
return spec === void 0 ? Result$1.succeed(nodeOf(record, record.attributes)) : decodedNodeOf(record, spec);
|
|
224
150
|
};
|
|
225
151
|
const graphOf = (traceId, nodes) => ({
|
|
226
152
|
traceId,
|
|
@@ -228,7 +154,7 @@ const graphOf = (traceId, nodes) => ({
|
|
|
228
154
|
});
|
|
229
155
|
const decodeImpl = (traceId, spans, taxonomy) => {
|
|
230
156
|
const declarations = indexDeclarations(taxonomy);
|
|
231
|
-
return Result.map(Result.all(spans.map((record) => declaredNodeOf(record, declarations))), (nodes) => graphOf(traceId, nodes));
|
|
157
|
+
return Result$1.map(Result$1.all(spans.map((record) => declaredNodeOf(record, declarations))), (nodes) => graphOf(traceId, nodes));
|
|
232
158
|
};
|
|
233
159
|
/**
|
|
234
160
|
* Decodes the recorded spans of one trace against a taxonomy, purely: a declared span
|
|
@@ -238,6 +164,56 @@ const decodeImpl = (traceId, spans, taxonomy) => {
|
|
|
238
164
|
* fail the pipeline by accident.
|
|
239
165
|
*/
|
|
240
166
|
const decode = dual(3, decodeImpl);
|
|
167
|
+
Schema.Struct({
|
|
168
|
+
traceId: Schema.String,
|
|
169
|
+
spans: Schema.Array(SpanRecord)
|
|
170
|
+
});
|
|
171
|
+
const renderValue = (value) => JSON.stringify(value);
|
|
172
|
+
const renderEntries = (entries) => [...entries].map(([key, value]) => `${key}=${renderValue(value)}`).join(" ");
|
|
173
|
+
const indentOf$1 = (depth) => " ".repeat(depth);
|
|
174
|
+
const childrenOf = (spans, spanId) => spans.filter((span) => span.parentSpanId === spanId);
|
|
175
|
+
const renderNode = (spans, node, depth) => {
|
|
176
|
+
return [`${indentOf$1(depth)}${node.name} (${node.spanId}) status=${node.status} error.type=${String(node.errorType)} duration=${node.durationMillis}ms`, ...[
|
|
177
|
+
`${indentOf$1(depth)} attrs: ${renderEntries(Object.entries(node.attributes))}`,
|
|
178
|
+
...node.events.map((event) => `${indentOf$1(depth)} event ${event.name} ${renderEntries(Object.entries(event.attributes))}`),
|
|
179
|
+
...node.links.map((link) => `${indentOf$1(depth)} link ${link.traceId}/${link.spanId}`),
|
|
180
|
+
...childrenOf(spans, node.spanId).map((child) => renderNode(spans, child, depth + 1))
|
|
181
|
+
]].join("\n");
|
|
182
|
+
};
|
|
183
|
+
const documentImpl = (observed, report) => [
|
|
184
|
+
`trace ${observed.traceId}`,
|
|
185
|
+
report,
|
|
186
|
+
...observed.spans.map((node) => renderNode(observed.spans, node, 0))
|
|
187
|
+
].join("\n");
|
|
188
|
+
const document = dual(2, documentImpl);
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/FailureDump.ts
|
|
191
|
+
const DEFAULT_DIRECTORY = "artifacts/traces";
|
|
192
|
+
const sanitize = (value) => value.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
193
|
+
const fileNameOf = (request) => `${sanitize(request.name ?? request.traceId)}.${sanitize(request.conjunct)}.txt`;
|
|
194
|
+
const write = (request) => Effect.gen(function* () {
|
|
195
|
+
const fs = yield* FileSystem.FileSystem;
|
|
196
|
+
yield* fs.makeDirectory(DEFAULT_DIRECTORY, { recursive: true });
|
|
197
|
+
const path = `${DEFAULT_DIRECTORY}/${fileNameOf(request)}`;
|
|
198
|
+
yield* fs.writeFileString(path, document(request, request.report));
|
|
199
|
+
return path;
|
|
200
|
+
});
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region src/Graph.ts
|
|
203
|
+
var Graph_exports = /* @__PURE__ */ __exportAll({
|
|
204
|
+
AttributeValue: () => AttributeValue,
|
|
205
|
+
Attributes: () => Attributes,
|
|
206
|
+
GraphNode: () => GraphNode,
|
|
207
|
+
SpanEvent: () => SpanEvent,
|
|
208
|
+
SpanLink: () => SpanLink,
|
|
209
|
+
SpanRecord: () => SpanRecord,
|
|
210
|
+
Status: () => Status,
|
|
211
|
+
TraceGraph: () => TraceGraph,
|
|
212
|
+
byId: () => byId,
|
|
213
|
+
children: () => children,
|
|
214
|
+
decode: () => decode,
|
|
215
|
+
descendants: () => descendants
|
|
216
|
+
});
|
|
241
217
|
//#endregion
|
|
242
218
|
//#region src/IncompleteObservationError.schema.ts
|
|
243
219
|
const SpanCount = Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0, { message: "a span count is a non-negative integer" })));
|
|
@@ -271,6 +247,22 @@ var Observation_service_exports = /* @__PURE__ */ __exportAll({
|
|
|
271
247
|
});
|
|
272
248
|
var Observation = class extends Context.Service()("@systemfsoftware/trace-spec/Observation") {};
|
|
273
249
|
//#endregion
|
|
250
|
+
//#region src/Verdict.schema.ts
|
|
251
|
+
const Hold = Schema.TaggedStruct("Hold", {
|
|
252
|
+
conjunct: Schema.String,
|
|
253
|
+
inspected: Schema.Array(Schema.String)
|
|
254
|
+
});
|
|
255
|
+
const Break = Schema.TaggedStruct("Break", {
|
|
256
|
+
conjunct: Schema.String,
|
|
257
|
+
inspected: Schema.Array(Schema.String),
|
|
258
|
+
detail: Schema.String
|
|
259
|
+
});
|
|
260
|
+
const Verdict = Schema.Union([Hold, Break]);
|
|
261
|
+
const isBreak = Schema.is(Break);
|
|
262
|
+
const indentOf = (depth) => " ".repeat(depth);
|
|
263
|
+
const renderBreach = (breach) => `break ${breach.conjunct} inspected=[${breach.inspected.join(", ")}]\n${indentOf(1)}${breach.detail}`;
|
|
264
|
+
const report = (verdict) => Option.map(Option.liftPredicate(verdict, isBreak), renderBreach);
|
|
265
|
+
//#endregion
|
|
274
266
|
//#region src/Contract.ts
|
|
275
267
|
var Contract_exports = /* @__PURE__ */ __exportAll({
|
|
276
268
|
BreakFailure: () => BreakFailure,
|
|
@@ -280,7 +272,7 @@ var Contract_exports = /* @__PURE__ */ __exportAll({
|
|
|
280
272
|
TransportObservationError: () => TransportObservationError,
|
|
281
273
|
TypeId: () => TypeId$3,
|
|
282
274
|
check: () => check,
|
|
283
|
-
holds: () => holds,
|
|
275
|
+
holds: () => holds$1,
|
|
284
276
|
judge: () => judge,
|
|
285
277
|
of: () => of,
|
|
286
278
|
stimulate: () => stimulate,
|
|
@@ -312,14 +304,14 @@ const of = (taxonomy) => ({
|
|
|
312
304
|
const stimulateDual = (self, stimulus) => stimulatedOf(self.taxonomy, stimulus);
|
|
313
305
|
const stimulate = dual(2, stimulateDual);
|
|
314
306
|
const holdsDual = (self, relation) => contractOf(self.taxonomy, self.stimulus, relation);
|
|
315
|
-
const holds = dual(2, holdsDual);
|
|
307
|
+
const holds$1 = dual(2, holdsDual);
|
|
316
308
|
const isContract = (value) => Predicate.hasProperty(value, TypeId$3);
|
|
317
309
|
const dumpOf = (observed, verdict, options) => Option.match(report(verdict), {
|
|
318
310
|
onNone: () => Effect.succeed(null),
|
|
319
|
-
onSome: (
|
|
311
|
+
onSome: (rendered) => Effect.map(Effect.option(write({
|
|
320
312
|
...observed,
|
|
321
313
|
conjunct: verdict.conjunct,
|
|
322
|
-
report,
|
|
314
|
+
report: rendered,
|
|
323
315
|
name: options?.dumpName
|
|
324
316
|
})), Option.getOrNull)
|
|
325
317
|
});
|
|
@@ -355,8 +347,8 @@ const reportOf = (relationId, judgment) => Match.value(judgment.verdict).pipe(Ma
|
|
|
355
347
|
].join("\n")
|
|
356
348
|
})), Match.exhaustive);
|
|
357
349
|
const verdictCheckWith = (self, expect, judgment, frame) => {
|
|
358
|
-
const
|
|
359
|
-
return
|
|
350
|
+
const finding = reportOf(self.relation.id, judgment);
|
|
351
|
+
return finding.verdict === "Break" ? Effect.die(withRaisingFrame(failureOfReport(finding), frame)) : expect(finding, finding.report).toEqual(held);
|
|
360
352
|
};
|
|
361
353
|
const verdictCheckImpl = (self, expect, judgment) => verdictCheckWith(self, expect, judgment, callFrame());
|
|
362
354
|
/**
|
|
@@ -374,6 +366,50 @@ const checkDual = (self, expect, input, options) => {
|
|
|
374
366
|
*/
|
|
375
367
|
const check = dual((args) => isContract(args[0]), checkDual);
|
|
376
368
|
//#endregion
|
|
369
|
+
//#region src/drivers/judge-tempo-answer.workflow.ts
|
|
370
|
+
const JudgeTempoAnswerTypeId = Symbol.for("@systemfsoftware/trace-spec/JudgeTempoAnswer");
|
|
371
|
+
var TempoBodyDecoded = class extends Schema.TaggedClass()("TempoBodyDecoded", {
|
|
372
|
+
spans: Schema.Array(SpanRecord),
|
|
373
|
+
status: Schema.optional(Schema.String)
|
|
374
|
+
}) {};
|
|
375
|
+
var TempoBodyUndecodable = class extends Schema.TaggedClass()("TempoBodyUndecodable", { detail: Schema.String }) {};
|
|
376
|
+
const TempoBody = Schema.Union([TempoBodyDecoded, TempoBodyUndecodable]);
|
|
377
|
+
var TempoAnswerComplete = class extends Schema.TaggedClass()("TempoAnswerComplete", { spans: Schema.Array(SpanRecord) }) {
|
|
378
|
+
[JudgeTempoAnswerTypeId] = JudgeTempoAnswerTypeId;
|
|
379
|
+
};
|
|
380
|
+
var TempoAnswerIncomplete = class extends Schema.TaggedClass()("TempoAnswerIncomplete", {
|
|
381
|
+
status: Schema.String,
|
|
382
|
+
spanCount: Schema.Int
|
|
383
|
+
}) {
|
|
384
|
+
[JudgeTempoAnswerTypeId] = JudgeTempoAnswerTypeId;
|
|
385
|
+
};
|
|
386
|
+
var TempoAnswerUndecodable = class extends Schema.TaggedClass()("TempoAnswerUndecodable", { detail: Schema.String }) {
|
|
387
|
+
[JudgeTempoAnswerTypeId] = JudgeTempoAnswerTypeId;
|
|
388
|
+
};
|
|
389
|
+
const TempoAnswerDecision = Schema.Union([
|
|
390
|
+
TempoAnswerComplete,
|
|
391
|
+
TempoAnswerIncomplete,
|
|
392
|
+
TempoAnswerUndecodable
|
|
393
|
+
]);
|
|
394
|
+
var JudgeTempoAnswer = class extends Schema.TaggedClass()("JudgeTempoAnswer", { body: TempoBody }) {
|
|
395
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
396
|
+
};
|
|
397
|
+
const isComplete = (status) => Option.match(status, {
|
|
398
|
+
onNone: () => true,
|
|
399
|
+
onSome: (marked) => marked === "COMPLETE"
|
|
400
|
+
});
|
|
401
|
+
const classify$1 = (spans, status) => Match.value(isComplete(status)).pipe(Match.when(true, () => new TempoAnswerComplete({ spans })), Match.when(false, () => new TempoAnswerIncomplete({
|
|
402
|
+
status: Option.getOrElse(status, () => "INCOMPLETE"),
|
|
403
|
+
spanCount: spans.length
|
|
404
|
+
})), Match.exhaustive);
|
|
405
|
+
const decide$5 = (command) => Result$1.succeed(Match.value(command.body).pipe(Match.tag("TempoBodyDecoded", (decoded) => classify$1(decoded.spans, Option.fromUndefinedOr(decoded.status))), Match.tag("TempoBodyUndecodable", (undecodable) => new TempoAnswerUndecodable({ detail: undecodable.detail })), Match.exhaustive));
|
|
406
|
+
const judgeTempoAnswer = Workflow.make({
|
|
407
|
+
command: JudgeTempoAnswer,
|
|
408
|
+
decision: TempoAnswerDecision,
|
|
409
|
+
error: Schema.Never,
|
|
410
|
+
decide: decide$5
|
|
411
|
+
});
|
|
412
|
+
//#endregion
|
|
377
413
|
//#region src/drivers/tempo-trace.schema.ts
|
|
378
414
|
/** Proto bytes (base64 on the wire) as the lowercase hex ids traces are addressed by. */
|
|
379
415
|
const HexId = Schema.Uint8ArrayFromBase64.pipe(Schema.decodeTo(Schema.String, {
|
|
@@ -550,32 +586,27 @@ var tempo_trace_store_exports = /* @__PURE__ */ __exportAll({ source: () => sour
|
|
|
550
586
|
*/
|
|
551
587
|
const parseBody = Schema.decodeResult(Schema.fromJsonString(TempoV2TraceResponse));
|
|
552
588
|
const orEmpty = (values) => values ?? [];
|
|
553
|
-
const
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
589
|
+
const spansOf = (response) => orEmpty(response.trace.resourceSpans).flatMap((resourceSpans) => orEmpty(resourceSpans.scopeSpans).flatMap((scopeSpans) => orEmpty(scopeSpans.spans)));
|
|
590
|
+
const bodyOf = (decoded) => Result.match(decoded, {
|
|
591
|
+
onFailure: (error) => new TempoBodyUndecodable({ detail: error.message }),
|
|
592
|
+
onSuccess: (response) => new TempoBodyDecoded({
|
|
593
|
+
spans: spansOf(response),
|
|
594
|
+
status: response.status
|
|
595
|
+
})
|
|
596
|
+
});
|
|
557
597
|
const transportFailureOf = (traceId, url, cause) => new TransportObservationError({
|
|
558
598
|
traceId,
|
|
559
599
|
source: url,
|
|
560
600
|
detail: cause
|
|
561
601
|
});
|
|
562
602
|
const refusedOf = (traceId, url, error) => transportFailureOf(traceId, url, error.message);
|
|
563
|
-
const undecodableOf = (traceId, url,
|
|
603
|
+
const undecodableOf = (traceId, url, detail) => transportFailureOf(traceId, url, `undecodable trace body: ${detail}`);
|
|
564
604
|
const incompleteOf = (traceId, status, spanCount) => new IncompleteObservationError({
|
|
565
605
|
traceId,
|
|
566
606
|
spanCount,
|
|
567
607
|
detail: `the store answered ${status}: waiting cannot complete the trace`
|
|
568
608
|
});
|
|
569
|
-
const
|
|
570
|
-
const markedOf = (response) => response.status ?? "INCOMPLETE";
|
|
571
|
-
const recordsOf$1 = (traceId, response) => {
|
|
572
|
-
const spans = spansOf(response);
|
|
573
|
-
return isComplete(response.status) ? Effect.succeed(spans) : Effect.fail(incompleteOf(traceId, markedOf(response), spans.length));
|
|
574
|
-
};
|
|
575
|
-
const readTrace = (traceId, url, body) => {
|
|
576
|
-
const decoded = parseBody(body);
|
|
577
|
-
return Result.isFailure(decoded) ? Effect.fail(undecodableOf(traceId, url, decoded.failure)) : recordsOf$1(traceId, decoded.success);
|
|
578
|
-
};
|
|
609
|
+
const readTrace = (traceId, url, body) => Effect.flatMap(Effect.fromResult(judgeTempoAnswer(new JudgeTempoAnswer({ body: bodyOf(parseBody(body)) }))), (decision) => Match.value(decision).pipe(Match.tag("TempoAnswerComplete", (complete) => Effect.succeed(complete.spans)), Match.tag("TempoAnswerIncomplete", (incomplete) => Effect.fail(incompleteOf(traceId, incomplete.status, incomplete.spanCount))), Match.tag("TempoAnswerUndecodable", (undecodable) => Effect.fail(undecodableOf(traceId, url, undecodable.detail))), Match.exhaustive));
|
|
579
610
|
/** One read against one Tempo endpoint. Its only requirement is the caller's HTTP client. */
|
|
580
611
|
const source = (options) => {
|
|
581
612
|
const urlOf = (traceId) => `${options.baseUrl}/api/v2/traces/${traceId}`;
|
|
@@ -713,6 +744,199 @@ const ObservationWindows = Blueprint.make()(TypeId$1).steps({
|
|
|
713
744
|
});
|
|
714
745
|
const make$2 = (serviceName) => ObservationWindows.of(ObservationWindowSpec.make({ serviceName }));
|
|
715
746
|
//#endregion
|
|
747
|
+
//#region src/combine-any-relations.workflow.ts
|
|
748
|
+
const CombineAnyRelationsTypeId = Symbol.for("@systemfsoftware/trace-spec/CombineAnyRelations");
|
|
749
|
+
/** At least one relation held, so the disjunction holds over every inspected span. */
|
|
750
|
+
var AnyRelationHeld = class extends Schema.TaggedClass()("AnyRelationHeld", {
|
|
751
|
+
conjunct: Schema.String,
|
|
752
|
+
inspected: Schema.Array(Schema.String)
|
|
753
|
+
}) {
|
|
754
|
+
[CombineAnyRelationsTypeId] = CombineAnyRelationsTypeId;
|
|
755
|
+
};
|
|
756
|
+
/** No relation held: every conjunct is named in the break. */
|
|
757
|
+
var NoRelationHeld = class extends Schema.TaggedClass()("NoRelationHeld", {
|
|
758
|
+
conjunct: Schema.String,
|
|
759
|
+
inspected: Schema.Array(Schema.String),
|
|
760
|
+
detail: Schema.String
|
|
761
|
+
}) {
|
|
762
|
+
[CombineAnyRelationsTypeId] = CombineAnyRelationsTypeId;
|
|
763
|
+
};
|
|
764
|
+
const CombineAnyRelationsDecision = Schema.Union([AnyRelationHeld, NoRelationHeld]);
|
|
765
|
+
var CombineAnyRelations = class extends Schema.TaggedClass()("CombineAnyRelations", {
|
|
766
|
+
conjunct: Schema.String,
|
|
767
|
+
verdicts: Schema.Array(Verdict)
|
|
768
|
+
}) {
|
|
769
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
770
|
+
};
|
|
771
|
+
const holds = (verdict) => Match.value(verdict).pipe(Match.tag("Hold", () => true), Match.tag("Break", () => false), Match.exhaustive);
|
|
772
|
+
const inspectedOf$1 = (verdicts) => Array$1.flatMap(verdicts, (verdict) => verdict.inspected);
|
|
773
|
+
const namedConjuncts = (verdicts) => Array$1.join(Array$1.map(verdicts, (verdict) => verdict.conjunct), ", ");
|
|
774
|
+
const decide$4 = (command) => Result$1.succeed(Match.value(Array$1.some(command.verdicts, holds)).pipe(Match.when(true, () => new AnyRelationHeld({
|
|
775
|
+
conjunct: command.conjunct,
|
|
776
|
+
inspected: inspectedOf$1(command.verdicts)
|
|
777
|
+
})), Match.when(false, () => new NoRelationHeld({
|
|
778
|
+
conjunct: command.conjunct,
|
|
779
|
+
inspected: inspectedOf$1(command.verdicts),
|
|
780
|
+
detail: namedConjuncts(command.verdicts)
|
|
781
|
+
})), Match.exhaustive));
|
|
782
|
+
/** `any(...)`: holds as soon as one relation holds, and otherwise breaks naming every conjunct. */
|
|
783
|
+
const combineAnyRelations = Workflow.make({
|
|
784
|
+
command: CombineAnyRelations,
|
|
785
|
+
decision: CombineAnyRelationsDecision,
|
|
786
|
+
error: Schema.Never,
|
|
787
|
+
decide: decide$4
|
|
788
|
+
});
|
|
789
|
+
//#endregion
|
|
790
|
+
//#region src/combine-relation-verdicts.workflow.ts
|
|
791
|
+
const CombineRelationVerdictsTypeId = Symbol.for("@systemfsoftware/trace-spec/CombineRelationVerdicts");
|
|
792
|
+
const EvaluatedRelation = Schema.Struct({
|
|
793
|
+
verdict: Verdict,
|
|
794
|
+
soft: Schema.Boolean
|
|
795
|
+
});
|
|
796
|
+
var FirstHardBreak = class extends Schema.TaggedClass()("FirstHardBreak", {
|
|
797
|
+
conjunct: Schema.String,
|
|
798
|
+
inspected: Schema.Array(Schema.String),
|
|
799
|
+
detail: Schema.String
|
|
800
|
+
}) {
|
|
801
|
+
[CombineRelationVerdictsTypeId] = CombineRelationVerdictsTypeId;
|
|
802
|
+
};
|
|
803
|
+
var AggregatedSoftBreak = class extends Schema.TaggedClass()("AggregatedSoftBreak", {
|
|
804
|
+
conjunct: Schema.String,
|
|
805
|
+
inspected: Schema.Array(Schema.String),
|
|
806
|
+
detail: Schema.String
|
|
807
|
+
}) {
|
|
808
|
+
[CombineRelationVerdictsTypeId] = CombineRelationVerdictsTypeId;
|
|
809
|
+
};
|
|
810
|
+
var EveryRelationHeld = class extends Schema.TaggedClass()("EveryRelationHeld", {
|
|
811
|
+
conjunct: Schema.String,
|
|
812
|
+
inspected: Schema.Array(Schema.String)
|
|
813
|
+
}) {
|
|
814
|
+
[CombineRelationVerdictsTypeId] = CombineRelationVerdictsTypeId;
|
|
815
|
+
};
|
|
816
|
+
const CombineRelationVerdictsDecision = Schema.Union([
|
|
817
|
+
FirstHardBreak,
|
|
818
|
+
AggregatedSoftBreak,
|
|
819
|
+
EveryRelationHeld
|
|
820
|
+
]);
|
|
821
|
+
var CombineRelationVerdicts = class extends Schema.TaggedClass()("CombineRelationVerdicts", {
|
|
822
|
+
conjunct: Schema.String,
|
|
823
|
+
verdicts: Schema.Array(EvaluatedRelation)
|
|
824
|
+
}) {
|
|
825
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
826
|
+
};
|
|
827
|
+
const asBreak = (entry) => Match.value(entry.verdict).pipe(Match.tag("Break", (breach) => Option.some(breach)), Match.tag("Hold", () => Option.none()), Match.exhaustive);
|
|
828
|
+
const breaksIn = (entries) => Array$1.flatMap(entries, (entry) => Option.match(asBreak(entry), {
|
|
829
|
+
onNone: () => [],
|
|
830
|
+
onSome: (breach) => [breach]
|
|
831
|
+
}));
|
|
832
|
+
const firstHardBreak = (verdicts) => Array$1.head(breaksIn(Array$1.filter(verdicts, (entry) => !entry.soft)));
|
|
833
|
+
const softBreaks = (verdicts) => breaksIn(Array$1.filter(verdicts, (entry) => entry.soft));
|
|
834
|
+
const aggregateSoft = (command) => {
|
|
835
|
+
const breaks = softBreaks(command.verdicts);
|
|
836
|
+
return Option.match(Array$1.head(breaks), {
|
|
837
|
+
onNone: () => new EveryRelationHeld({
|
|
838
|
+
conjunct: command.conjunct,
|
|
839
|
+
inspected: []
|
|
840
|
+
}),
|
|
841
|
+
onSome: () => new AggregatedSoftBreak({
|
|
842
|
+
conjunct: command.conjunct,
|
|
843
|
+
inspected: Array$1.flatMap(breaks, (breach) => breach.inspected),
|
|
844
|
+
detail: Array$1.join(Array$1.map(breaks, (breach) => breach.conjunct), ", ")
|
|
845
|
+
})
|
|
846
|
+
});
|
|
847
|
+
};
|
|
848
|
+
const decide$3 = (command) => Result$1.succeed(Option.match(firstHardBreak(command.verdicts), {
|
|
849
|
+
onNone: () => aggregateSoft(command),
|
|
850
|
+
onSome: (winner) => new FirstHardBreak({
|
|
851
|
+
conjunct: winner.conjunct,
|
|
852
|
+
inspected: winner.inspected,
|
|
853
|
+
detail: winner.detail
|
|
854
|
+
})
|
|
855
|
+
}));
|
|
856
|
+
const combineRelationVerdicts = Workflow.make({
|
|
857
|
+
command: CombineRelationVerdicts,
|
|
858
|
+
decision: CombineRelationVerdictsDecision,
|
|
859
|
+
error: Schema.Never,
|
|
860
|
+
decide: decide$3
|
|
861
|
+
});
|
|
862
|
+
//#endregion
|
|
863
|
+
//#region src/judge-edge-placement.workflow.ts
|
|
864
|
+
const JudgeEdgePlacementTypeId = Symbol.for("@systemfsoftware/trace-spec/JudgeEdgePlacement");
|
|
865
|
+
var EdgePlacementHeld = class extends Schema.TaggedClass()("EdgePlacementHeld", {
|
|
866
|
+
conjunct: Schema.String,
|
|
867
|
+
inspected: Schema.Array(Schema.String)
|
|
868
|
+
}) {
|
|
869
|
+
[JudgeEdgePlacementTypeId] = JudgeEdgePlacementTypeId;
|
|
870
|
+
};
|
|
871
|
+
var EdgePlacementBroken = class extends Schema.TaggedClass()("EdgePlacementBroken", {
|
|
872
|
+
conjunct: Schema.String,
|
|
873
|
+
inspected: Schema.Array(Schema.String),
|
|
874
|
+
detail: Schema.String
|
|
875
|
+
}) {
|
|
876
|
+
[JudgeEdgePlacementTypeId] = JudgeEdgePlacementTypeId;
|
|
877
|
+
};
|
|
878
|
+
const JudgeEdgePlacementDecision = Schema.Union([EdgePlacementHeld, EdgePlacementBroken]);
|
|
879
|
+
var JudgeEdgePlacement = class extends Schema.TaggedClass()("JudgeEdgePlacement", {
|
|
880
|
+
conjunct: Schema.String,
|
|
881
|
+
placed: Schema.Array(Schema.String),
|
|
882
|
+
reached: Schema.Array(Schema.String),
|
|
883
|
+
detail: Schema.String
|
|
884
|
+
}) {
|
|
885
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
886
|
+
};
|
|
887
|
+
const everyPlaced = (placed, reached) => Array$1.every(placed, (spanId) => Array$1.some(reached, (candidate) => candidate === spanId));
|
|
888
|
+
const decide$2 = (command) => Result$1.succeed(Match.value(everyPlaced(command.placed, command.reached)).pipe(Match.when(true, () => new EdgePlacementHeld({
|
|
889
|
+
conjunct: command.conjunct,
|
|
890
|
+
inspected: command.placed
|
|
891
|
+
})), Match.when(false, () => new EdgePlacementBroken({
|
|
892
|
+
conjunct: command.conjunct,
|
|
893
|
+
inspected: command.placed,
|
|
894
|
+
detail: command.detail
|
|
895
|
+
})), Match.exhaustive));
|
|
896
|
+
const judgeEdgePlacement = Workflow.make({
|
|
897
|
+
command: JudgeEdgePlacement,
|
|
898
|
+
decision: JudgeEdgePlacementDecision,
|
|
899
|
+
error: Schema.Never,
|
|
900
|
+
decide: decide$2
|
|
901
|
+
});
|
|
902
|
+
//#endregion
|
|
903
|
+
//#region src/negate-relation-verdict.workflow.ts
|
|
904
|
+
const NegateRelationVerdictTypeId = Symbol.for("@systemfsoftware/trace-spec/NegateRelationVerdict");
|
|
905
|
+
var HoldNegated = class extends Schema.TaggedClass()("HoldNegated", {
|
|
906
|
+
conjunct: Schema.String,
|
|
907
|
+
inspected: Schema.Array(Schema.String),
|
|
908
|
+
detail: Schema.String
|
|
909
|
+
}) {
|
|
910
|
+
[NegateRelationVerdictTypeId] = NegateRelationVerdictTypeId;
|
|
911
|
+
};
|
|
912
|
+
var BreakNegated = class extends Schema.TaggedClass()("BreakNegated", {
|
|
913
|
+
conjunct: Schema.String,
|
|
914
|
+
inspected: Schema.Array(Schema.String)
|
|
915
|
+
}) {
|
|
916
|
+
[NegateRelationVerdictTypeId] = NegateRelationVerdictTypeId;
|
|
917
|
+
};
|
|
918
|
+
const NegateRelationVerdictDecision = Schema.Union([HoldNegated, BreakNegated]);
|
|
919
|
+
var NegateRelationVerdict = class extends Schema.TaggedClass()("NegateRelationVerdict", {
|
|
920
|
+
conjunct: Schema.String,
|
|
921
|
+
verdict: Verdict
|
|
922
|
+
}) {
|
|
923
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
924
|
+
};
|
|
925
|
+
const decide$1 = (command) => Result$1.succeed(Match.value(command.verdict).pipe(Match.tag("Hold", (held) => new HoldNegated({
|
|
926
|
+
conjunct: command.conjunct,
|
|
927
|
+
inspected: held.inspected,
|
|
928
|
+
detail: `${held.conjunct} held`
|
|
929
|
+
})), Match.tag("Break", (breach) => new BreakNegated({
|
|
930
|
+
conjunct: command.conjunct,
|
|
931
|
+
inspected: breach.inspected
|
|
932
|
+
})), Match.exhaustive));
|
|
933
|
+
const negateRelationVerdict = Workflow.make({
|
|
934
|
+
command: NegateRelationVerdict,
|
|
935
|
+
decision: NegateRelationVerdictDecision,
|
|
936
|
+
error: Schema.Never,
|
|
937
|
+
decide: decide$1
|
|
938
|
+
});
|
|
939
|
+
//#endregion
|
|
716
940
|
//#region src/Rel.ts
|
|
717
941
|
var Rel_exports = /* @__PURE__ */ __exportAll({
|
|
718
942
|
Break: () => Break,
|
|
@@ -736,6 +960,10 @@ var Rel_exports = /* @__PURE__ */ __exportAll({
|
|
|
736
960
|
status: () => status,
|
|
737
961
|
unique: () => unique
|
|
738
962
|
});
|
|
963
|
+
const decisionOf = (result) => Result.match(result, {
|
|
964
|
+
onFailure: (unreachable) => absurd(unreachable),
|
|
965
|
+
onSuccess: (decision) => decision
|
|
966
|
+
});
|
|
739
967
|
const relation = (parts) => Object.assign((graph) => parts.evaluate(graph), {
|
|
740
968
|
id: parts.id,
|
|
741
969
|
soft: parts.soft,
|
|
@@ -744,9 +972,7 @@ const relation = (parts) => Object.assign((graph) => parts.evaluate(graph), {
|
|
|
744
972
|
const matchedNodes = (graph, spec) => byId(graph, spec);
|
|
745
973
|
const inspectedOf = (nodes) => nodes.map((node) => node.spanId);
|
|
746
974
|
const matchedAll = (items, predicate) => items.length > 0 && items.every(predicate);
|
|
747
|
-
const
|
|
748
|
-
const isHold$1 = (verdict) => Schema.is(Hold)(verdict);
|
|
749
|
-
const verdictOf$1 = (options) => options.holds ? Hold.make({
|
|
975
|
+
const verdictOf = (options) => options.holds ? Hold.make({
|
|
750
976
|
conjunct: options.id,
|
|
751
977
|
inspected: options.inspected
|
|
752
978
|
}) : Break.make({
|
|
@@ -760,7 +986,7 @@ const declared$1 = (declaration) => relation({
|
|
|
760
986
|
softenable: declaration.softenable,
|
|
761
987
|
evaluate: (graph) => {
|
|
762
988
|
const inspected = declaration.spans.flatMap((span) => inspectedOf(byId(graph, span)));
|
|
763
|
-
return verdictOf
|
|
989
|
+
return verdictOf({
|
|
764
990
|
id: declaration.id,
|
|
765
991
|
inspected,
|
|
766
992
|
holds: declaration.holds(graph),
|
|
@@ -873,7 +1099,7 @@ const forallImpl = (spec, predicate, detail) => {
|
|
|
873
1099
|
softenable: true,
|
|
874
1100
|
evaluate: (graph) => {
|
|
875
1101
|
const nodes = matchedNodes(graph, spec);
|
|
876
|
-
return verdictOf
|
|
1102
|
+
return verdictOf({
|
|
877
1103
|
id,
|
|
878
1104
|
inspected: inspectedOf(nodes),
|
|
879
1105
|
holds: matchedAll(nodes, predicate),
|
|
@@ -889,13 +1115,16 @@ const soft = (self) => self.softenable ? relation({
|
|
|
889
1115
|
softenable: true,
|
|
890
1116
|
evaluate: (graph) => self(graph)
|
|
891
1117
|
}) : self;
|
|
892
|
-
const negatedVerdict = (id, inner) => Match.value(
|
|
1118
|
+
const negatedVerdict = (id, inner) => Match.value(decisionOf(negateRelationVerdict(new NegateRelationVerdict({
|
|
893
1119
|
conjunct: id,
|
|
1120
|
+
verdict: inner
|
|
1121
|
+
})))).pipe(Match.tag("HoldNegated", (held) => Break.make({
|
|
1122
|
+
conjunct: held.conjunct,
|
|
894
1123
|
inspected: held.inspected,
|
|
895
|
-
detail:
|
|
896
|
-
})), Match.tag("
|
|
897
|
-
conjunct:
|
|
898
|
-
inspected:
|
|
1124
|
+
detail: held.detail
|
|
1125
|
+
})), Match.tag("BreakNegated", (broken) => Hold.make({
|
|
1126
|
+
conjunct: broken.conjunct,
|
|
1127
|
+
inspected: broken.inspected
|
|
899
1128
|
})), Match.exhaustive);
|
|
900
1129
|
const not = (self) => {
|
|
901
1130
|
const id = `not(${self.id})`;
|
|
@@ -906,24 +1135,29 @@ const not = (self) => {
|
|
|
906
1135
|
evaluate: (graph) => negatedVerdict(id, self(graph))
|
|
907
1136
|
});
|
|
908
1137
|
};
|
|
909
|
-
const
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
})
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
|
|
1138
|
+
const combinationOf = (conjunct, relations, graph) => Match.value(decisionOf(combineRelationVerdicts(new CombineRelationVerdicts({
|
|
1139
|
+
conjunct,
|
|
1140
|
+
verdicts: relations.map((relation) => ({
|
|
1141
|
+
verdict: relation(graph),
|
|
1142
|
+
soft: relation.soft
|
|
1143
|
+
}))
|
|
1144
|
+
})))).pipe(Match.tag("FirstHardBreak", (winner) => Break.make({
|
|
1145
|
+
conjunct: winner.conjunct,
|
|
1146
|
+
inspected: winner.inspected,
|
|
1147
|
+
detail: winner.detail
|
|
1148
|
+
})), Match.tag("AggregatedSoftBreak", (aggregated) => Break.make({
|
|
1149
|
+
conjunct: aggregated.conjunct,
|
|
1150
|
+
inspected: aggregated.inspected,
|
|
1151
|
+
detail: aggregated.detail
|
|
1152
|
+
})), Match.tag("EveryRelationHeld", (held) => Hold.make({
|
|
1153
|
+
conjunct: held.conjunct,
|
|
1154
|
+
inspected: held.inspected
|
|
1155
|
+
})), Match.exhaustive);
|
|
922
1156
|
const combined = (options) => relation({
|
|
923
1157
|
id: options.id,
|
|
924
1158
|
soft: options.soft,
|
|
925
1159
|
softenable: options.softenable,
|
|
926
|
-
evaluate: (graph) =>
|
|
1160
|
+
evaluate: (graph) => combinationOf(options.id, options.relations, graph)
|
|
927
1161
|
});
|
|
928
1162
|
const all = (...relations) => combined({
|
|
929
1163
|
id: `all(${relations.map((relation) => relation.id).join(", ")})`,
|
|
@@ -931,30 +1165,43 @@ const all = (...relations) => combined({
|
|
|
931
1165
|
soft: relations.every((relation) => relation.soft),
|
|
932
1166
|
softenable: true
|
|
933
1167
|
});
|
|
1168
|
+
const disjunctionOf = (conjunct, verdicts) => Match.value(decisionOf(combineAnyRelations(new CombineAnyRelations({
|
|
1169
|
+
conjunct,
|
|
1170
|
+
verdicts
|
|
1171
|
+
})))).pipe(Match.tag("AnyRelationHeld", (held) => Hold.make({
|
|
1172
|
+
conjunct: held.conjunct,
|
|
1173
|
+
inspected: held.inspected
|
|
1174
|
+
})), Match.tag("NoRelationHeld", (broken) => Break.make({
|
|
1175
|
+
conjunct: broken.conjunct,
|
|
1176
|
+
inspected: broken.inspected,
|
|
1177
|
+
detail: broken.detail
|
|
1178
|
+
})), Match.exhaustive);
|
|
934
1179
|
const any = (...relations) => {
|
|
935
1180
|
const id = `any(${relations.map((relation) => relation.id).join(", ")})`;
|
|
936
1181
|
return relation({
|
|
937
1182
|
id,
|
|
938
1183
|
soft: false,
|
|
939
1184
|
softenable: false,
|
|
940
|
-
evaluate: (graph) =>
|
|
941
|
-
const verdicts = relations.map((relation) => relation(graph));
|
|
942
|
-
const inspected = verdicts.flatMap((verdict) => verdict.inspected);
|
|
943
|
-
return verdicts.some(isHold$1) ? Hold.make({
|
|
944
|
-
conjunct: id,
|
|
945
|
-
inspected
|
|
946
|
-
}) : Break.make({
|
|
947
|
-
conjunct: id,
|
|
948
|
-
inspected,
|
|
949
|
-
detail: verdicts.map((verdict) => verdict.conjunct).join(", ")
|
|
950
|
-
});
|
|
951
|
-
}
|
|
1185
|
+
evaluate: (graph) => disjunctionOf(id, relations.map((relation) => relation(graph)))
|
|
952
1186
|
});
|
|
953
1187
|
};
|
|
954
1188
|
const REACH_BY_RELATION = {
|
|
955
1189
|
child: childIdsOf,
|
|
956
1190
|
descendant: descendantIdsOf
|
|
957
1191
|
};
|
|
1192
|
+
const placementVerdictOf = (conjunct, placed, reached, detail) => Match.value(decisionOf(judgeEdgePlacement(new JudgeEdgePlacement({
|
|
1193
|
+
conjunct,
|
|
1194
|
+
placed,
|
|
1195
|
+
reached: [...reached],
|
|
1196
|
+
detail
|
|
1197
|
+
})))).pipe(Match.tag("EdgePlacementHeld", (held) => Hold.make({
|
|
1198
|
+
conjunct: held.conjunct,
|
|
1199
|
+
inspected: held.inspected
|
|
1200
|
+
})), Match.tag("EdgePlacementBroken", (broken) => Break.make({
|
|
1201
|
+
conjunct: broken.conjunct,
|
|
1202
|
+
inspected: broken.inspected,
|
|
1203
|
+
detail: broken.detail
|
|
1204
|
+
})), Match.exhaustive);
|
|
958
1205
|
const placementOf = (edge) => {
|
|
959
1206
|
const id = `placement(${edge.relation}:${edge.parent.id},${edge.child.id})`;
|
|
960
1207
|
return relation({
|
|
@@ -962,14 +1209,9 @@ const placementOf = (edge) => {
|
|
|
962
1209
|
soft: false,
|
|
963
1210
|
softenable: false,
|
|
964
1211
|
evaluate: (graph) => {
|
|
965
|
-
const placed = matchedNodes(graph, edge.child);
|
|
1212
|
+
const placed = inspectedOf(matchedNodes(graph, edge.child));
|
|
966
1213
|
const reached = REACH_BY_RELATION[edge.relation](graph, matchedNodes(graph, edge.parent));
|
|
967
|
-
return
|
|
968
|
-
id,
|
|
969
|
-
inspected: inspectedOf(placed),
|
|
970
|
-
holds: placed.every((node) => reached.has(node.spanId)),
|
|
971
|
-
detail: `a ${edge.child.id} span is not a ${edge.relation} of any ${edge.parent.id} span`
|
|
972
|
-
});
|
|
1214
|
+
return placementVerdictOf(id, placed, reached, `a ${edge.child.id} span is not a ${edge.relation} of any ${edge.parent.id} span`);
|
|
973
1215
|
}
|
|
974
1216
|
});
|
|
975
1217
|
};
|
|
@@ -986,44 +1228,87 @@ const fromTaxonomyImpl = (taxonomy, options) => combined({
|
|
|
986
1228
|
});
|
|
987
1229
|
const fromTaxonomy = dual(2, fromTaxonomyImpl);
|
|
988
1230
|
//#endregion
|
|
1231
|
+
//#region src/settle-remote-read.workflow.ts
|
|
1232
|
+
const SettleRemoteReadTypeId = Symbol.for("@systemfsoftware/trace-spec/SettleRemoteRead");
|
|
1233
|
+
const ObservedSpans = Schema.Struct({
|
|
1234
|
+
spans: Schema.Array(SpanRecord),
|
|
1235
|
+
addedAtMillis: Schema.Finite
|
|
1236
|
+
});
|
|
1237
|
+
var ReadSettled = class extends Schema.TaggedClass()("ReadSettled", { observation: ObservedSpans }) {
|
|
1238
|
+
[SettleRemoteReadTypeId] = SettleRemoteReadTypeId;
|
|
1239
|
+
};
|
|
1240
|
+
var ReadAbsent = class extends Schema.TaggedClass()("ReadAbsent", { observation: ObservedSpans }) {
|
|
1241
|
+
[SettleRemoteReadTypeId] = SettleRemoteReadTypeId;
|
|
1242
|
+
};
|
|
1243
|
+
var ReadUnfinished = class extends Schema.TaggedClass()("ReadUnfinished", { observation: ObservedSpans }) {
|
|
1244
|
+
[SettleRemoteReadTypeId] = SettleRemoteReadTypeId;
|
|
1245
|
+
};
|
|
1246
|
+
var ReadStillGrowing = class extends Schema.TaggedClass()("ReadStillGrowing", { observation: ObservedSpans }) {
|
|
1247
|
+
[SettleRemoteReadTypeId] = SettleRemoteReadTypeId;
|
|
1248
|
+
};
|
|
1249
|
+
const SettleRemoteReadDecision = Schema.Union([
|
|
1250
|
+
ReadSettled,
|
|
1251
|
+
ReadAbsent,
|
|
1252
|
+
ReadUnfinished,
|
|
1253
|
+
ReadStillGrowing
|
|
1254
|
+
]);
|
|
1255
|
+
var SettleRemoteRead = class extends Schema.TaggedClass()("SettleRemoteRead", {
|
|
1256
|
+
observed: ObservedSpans,
|
|
1257
|
+
read: Schema.Array(SpanRecord),
|
|
1258
|
+
elapsedMillis: Schema.Finite,
|
|
1259
|
+
settleMillis: Schema.Finite,
|
|
1260
|
+
timeoutMillis: Schema.Finite
|
|
1261
|
+
}) {
|
|
1262
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
1263
|
+
};
|
|
1264
|
+
const sameId = (left, right) => left.spanId === right.spanId;
|
|
1265
|
+
const firstOfEachId = (read) => Array$1.dedupeWith(read, sameId);
|
|
1266
|
+
const freshOf = (observed, read) => Array$1.filter(firstOfEachId(read), (span) => Array$1.every(observed.spans, (seen) => seen.spanId !== span.spanId));
|
|
1267
|
+
const absorbed = (observed, read, elapsedMillis) => {
|
|
1268
|
+
const fresh = freshOf(observed, read);
|
|
1269
|
+
return Option.match(Array$1.head(fresh), {
|
|
1270
|
+
onNone: () => observed,
|
|
1271
|
+
onSome: () => ({
|
|
1272
|
+
spans: [...observed.spans, ...fresh],
|
|
1273
|
+
addedAtMillis: elapsedMillis
|
|
1274
|
+
})
|
|
1275
|
+
});
|
|
1276
|
+
};
|
|
1277
|
+
const quietForLongEnough = (observed, elapsedMillis, settleMillis) => Array$1.every([observed.spans.length > 0, elapsedMillis - observed.addedAtMillis >= settleMillis], Boolean);
|
|
1278
|
+
const classify = (observation, elapsedMillis, settleMillis, timeoutMillis) => Match.value(quietForLongEnough(observation, elapsedMillis, settleMillis)).pipe(Match.when(true, () => new ReadSettled({ observation })), Match.when(false, () => Match.value(elapsedMillis >= timeoutMillis).pipe(Match.when(true, () => Match.value(observation.spans.length === 0).pipe(Match.when(true, () => new ReadAbsent({ observation })), Match.when(false, () => new ReadUnfinished({ observation })), Match.exhaustive)), Match.when(false, () => new ReadStillGrowing({ observation })), Match.exhaustive)), Match.exhaustive);
|
|
1279
|
+
const decide = (command) => Result$1.succeed(classify(absorbed(command.observed, command.read, command.elapsedMillis), command.elapsedMillis, command.settleMillis, command.timeoutMillis));
|
|
1280
|
+
const settleRemoteRead = Workflow.make({
|
|
1281
|
+
command: SettleRemoteRead,
|
|
1282
|
+
decision: SettleRemoteReadDecision,
|
|
1283
|
+
error: Schema.Never,
|
|
1284
|
+
decide
|
|
1285
|
+
});
|
|
1286
|
+
//#endregion
|
|
989
1287
|
//#region src/RemoteObservation.ts
|
|
990
1288
|
var RemoteObservation_exports = /* @__PURE__ */ __exportAll({ layer: () => layer });
|
|
991
1289
|
const NEVER_READ = {
|
|
992
1290
|
spans: [],
|
|
993
1291
|
addedAtMillis: 0
|
|
994
1292
|
};
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
const freshOf = (settlement, read) => {
|
|
1000
|
-
const known = idsOf(settlement.spans);
|
|
1001
|
-
return firstOfEachId(read).filter((span) => !known.has(span.spanId));
|
|
1002
|
-
};
|
|
1003
|
-
const absorbed = (settlement, read, elapsedMillis) => {
|
|
1004
|
-
const fresh = freshOf(settlement, read);
|
|
1005
|
-
return fresh.length === 0 ? settlement : {
|
|
1006
|
-
spans: [...settlement.spans, ...fresh],
|
|
1007
|
-
addedAtMillis: elapsedMillis
|
|
1008
|
-
};
|
|
1009
|
-
};
|
|
1010
|
-
const quietForLongEnough = (settlement, elapsedMillis, windows) => settlement.spans.length > 0 && elapsedMillis - settlement.addedAtMillis >= windows.settleMillis;
|
|
1293
|
+
const settlementOf = (command) => Result.match(settleRemoteRead(command), {
|
|
1294
|
+
onFailure: (unreachable) => absurd(unreachable),
|
|
1295
|
+
onSuccess: (decision) => decision
|
|
1296
|
+
});
|
|
1011
1297
|
const pastDeadline = (elapsedMillis, windows) => elapsedMillis >= windows.timeoutMillis;
|
|
1012
1298
|
const settledVerdict = (spans) => Option.some(Result.succeed(spans));
|
|
1013
1299
|
const refusedVerdict = (refusal) => Option.some(Result.fail(refusal));
|
|
1014
|
-
const
|
|
1015
|
-
quiet: quietForLongEnough(settlement, elapsedMillis, windows),
|
|
1016
|
-
vacant: settlement.spans.length === 0,
|
|
1017
|
-
late: pastDeadline(elapsedMillis, windows)
|
|
1018
|
-
}).pipe(Match.when({ quiet: true }, () => settledVerdict(settlement.spans)), Match.when({
|
|
1019
|
-
vacant: true,
|
|
1020
|
-
late: true
|
|
1021
|
-
}, () => refusedVerdict("absent")), Match.when({ late: true }, () => refusedVerdict("unfinished")), Match.orElse(() => Option.none()));
|
|
1300
|
+
const verdictOfOutcome = (outcome) => Match.value(outcome).pipe(Match.tag("ReadSettled", (settled) => settledVerdict(settled.observation.spans)), Match.tag("ReadAbsent", () => refusedVerdict("absent")), Match.tag("ReadUnfinished", () => refusedVerdict("unfinished")), Match.tag("ReadStillGrowing", () => Option.none()), Match.exhaustive);
|
|
1022
1301
|
const settleStep = (settlement, read, elapsedMillis, windows) => {
|
|
1023
|
-
const
|
|
1302
|
+
const outcome = settlementOf(new SettleRemoteRead({
|
|
1303
|
+
observed: settlement,
|
|
1304
|
+
read,
|
|
1305
|
+
elapsedMillis,
|
|
1306
|
+
settleMillis: windows.settleMillis,
|
|
1307
|
+
timeoutMillis: windows.timeoutMillis
|
|
1308
|
+
}));
|
|
1024
1309
|
return {
|
|
1025
|
-
settlement:
|
|
1026
|
-
verdict:
|
|
1310
|
+
settlement: outcome.observation,
|
|
1311
|
+
verdict: verdictOfOutcome(outcome)
|
|
1027
1312
|
};
|
|
1028
1313
|
};
|
|
1029
1314
|
const lateRefusal = (settlement) => settlement.spans.length === 0 ? "absent" : "unfinished";
|
|
@@ -1147,6 +1432,17 @@ const HarnessFailure = Schema.Union([
|
|
|
1147
1432
|
TransportObservationError
|
|
1148
1433
|
]);
|
|
1149
1434
|
//#endregion
|
|
1435
|
+
//#region src/StimulusFailure.schema.ts
|
|
1436
|
+
const firstLine = (text) => text.split("\n")[0] ?? "";
|
|
1437
|
+
var StimulusFailure = class extends Schema.TaggedError()("StimulusFailure", {
|
|
1438
|
+
stimulus: Schema.String,
|
|
1439
|
+
detail: Schema.String
|
|
1440
|
+
}) {
|
|
1441
|
+
get message() {
|
|
1442
|
+
return `The stimulus "${this.stimulus}" failed: ${firstLine(this.detail)}`;
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1445
|
+
//#endregion
|
|
1150
1446
|
//#region src/TaskAnnounce.ts
|
|
1151
1447
|
const forget = (annotation) => {
|
|
1152
1448
|
Promise.resolve(annotation);
|
|
@@ -1169,40 +1465,6 @@ const announceDump = (judged) => Option.match(dumpMessageOf(judged), {
|
|
|
1169
1465
|
onSome: (message) => record(message, "info")
|
|
1170
1466
|
});
|
|
1171
1467
|
//#endregion
|
|
1172
|
-
//#region src/Prop.ts
|
|
1173
|
-
const isHold = Schema.is(Hold);
|
|
1174
|
-
/**
|
|
1175
|
-
* The contract with its stimulus replaced by the function the property was handed: the impostor gate
|
|
1176
|
-
* swaps in a constant fake, so the judgement must reach the stimulus through the argument, never the
|
|
1177
|
-
* closure.
|
|
1178
|
-
*/
|
|
1179
|
-
const judgedOver = (contract, subject) => ({
|
|
1180
|
-
...contract,
|
|
1181
|
-
stimulus: subject
|
|
1182
|
-
});
|
|
1183
|
-
/**
|
|
1184
|
-
* The run must be the run of the generated input: a stimulus that ignores its input and answers with one
|
|
1185
|
-
* frozen run satisfies every relation about that run, so the input pin is what refutes it.
|
|
1186
|
-
*/
|
|
1187
|
-
const consumedInput = (judgment, input) => judgment.run.input === input;
|
|
1188
|
-
const predicateImpl = (title, contract, scenario, shared) => {
|
|
1189
|
-
const provided = scenario.pipe(Layer.provideMerge(shared));
|
|
1190
|
-
const checked = (subject, input) => judge(judgedOver(contract, subject), input, { dumpName: title }).pipe(Effect.tap(announceDump), Effect.map((judgment) => isHold(judgment.verdict) && consumedInput(judgment, input)), Effect.provide(Layer.fresh(provided)));
|
|
1191
|
-
return (subject, input) => checked(subject, input);
|
|
1192
|
-
};
|
|
1193
|
-
const predicate = dual(4, predicateImpl);
|
|
1194
|
-
//#endregion
|
|
1195
|
-
//#region src/StimulusFailure.schema.ts
|
|
1196
|
-
const firstLine = (text) => text.split("\n")[0] ?? "";
|
|
1197
|
-
var StimulusFailure = class extends Schema.TaggedError()("StimulusFailure", {
|
|
1198
|
-
stimulus: Schema.String,
|
|
1199
|
-
detail: Schema.String
|
|
1200
|
-
}) {
|
|
1201
|
-
get message() {
|
|
1202
|
-
return `The stimulus "${this.stimulus}" failed: ${firstLine(this.detail)}`;
|
|
1203
|
-
}
|
|
1204
|
-
};
|
|
1205
|
-
//#endregion
|
|
1206
1468
|
//#region src/Suite.ts
|
|
1207
1469
|
var Suite_exports = /* @__PURE__ */ __exportAll({
|
|
1208
1470
|
StimulusFailure: () => StimulusFailure,
|
|
@@ -1230,6 +1492,17 @@ const caseFailureOf = (stimulus, salt) => (failure) => isHarnessFailure(failure)
|
|
|
1230
1492
|
detail: `${Cause.pretty(Cause.fail(failure))}\nrandom salt: ${salt}`
|
|
1231
1493
|
});
|
|
1232
1494
|
const caseBody = (expect, contract, input, salt) => judge(contract, input).pipe(Effect.tap(announceDump), Effect.flatMap((judgment) => verdictCheck(contract, expect, judgment)), Effect.mapError(caseFailureOf(contract.stimulus.name, salt)));
|
|
1495
|
+
const isHold = Schema.is(Hold);
|
|
1496
|
+
const judgedOver = (contract, subject) => ({
|
|
1497
|
+
...contract,
|
|
1498
|
+
stimulus: subject
|
|
1499
|
+
});
|
|
1500
|
+
const consumedInput = (judgment, input) => judgment.run.input === input;
|
|
1501
|
+
const casePredicate = (title, contract, scenario, shared) => {
|
|
1502
|
+
const provided = scenario.pipe(Layer.provideMerge(shared));
|
|
1503
|
+
const checked = (subject, input) => judge(judgedOver(contract, subject), input, { dumpName: title }).pipe(Effect.tap(announceDump), Effect.map((judgment) => isHold(judgment.verdict) && consumedInput(judgment, input)), Effect.provide(Layer.fresh(provided)));
|
|
1504
|
+
return (subject, input) => checked(subject, input);
|
|
1505
|
+
};
|
|
1233
1506
|
const caseTools = (register, propIt, scenario, shared) => {
|
|
1234
1507
|
const Case = (name, contract, input) => {
|
|
1235
1508
|
const salt = saltOf();
|
|
@@ -1240,7 +1513,7 @@ const caseTools = (register, propIt, scenario, shared) => {
|
|
|
1240
1513
|
propIt.effect.prop(name, {
|
|
1241
1514
|
of: [arbitrary],
|
|
1242
1515
|
subject: contract.stimulus
|
|
1243
|
-
}, (subject, values) =>
|
|
1516
|
+
}, (subject, values) => casePredicate(name, contract, scenario, shared)(subject, values[0]).pipe(Random.withSeed(salt)));
|
|
1244
1517
|
};
|
|
1245
1518
|
return { Case };
|
|
1246
1519
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@systemfsoftware/trace-spec",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.2",
|
|
5
5
|
"author": "Ryan Lee <drdgvhbh@gmail.com>",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -39,18 +39,25 @@
|
|
|
39
39
|
"@opentelemetry/sdk-trace-base": "^2",
|
|
40
40
|
"@opentelemetry/semantic-conventions": "^1.33",
|
|
41
41
|
"@systemfsoftware/effect-cell-types": "^11.0.0",
|
|
42
|
-
"@systemfsoftware/effect-spec-runtime": "^0.3.
|
|
42
|
+
"@systemfsoftware/effect-spec-runtime": "^0.3.2",
|
|
43
43
|
"@systemfsoftware/trace-taxonomy": "^0.0.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@effect/platform-node": "4.0.0-rc.117",
|
|
47
47
|
"@systemfsoftware/arethetypeswrong-cli": "^4.2.0",
|
|
48
48
|
"@systemfsoftware/conformance-spec": "^0.2.0",
|
|
49
|
-
"@systemfsoftware/effect-gherkin-spec": "^6.0.
|
|
50
|
-
"@systemfsoftware/oxlint-config-recommended": "^3.
|
|
49
|
+
"@systemfsoftware/effect-gherkin-spec": "^6.0.1",
|
|
50
|
+
"@systemfsoftware/oxlint-config-recommended": "^3.3.0",
|
|
51
|
+
"@systemfsoftware/stryker-config": "^0.1.0",
|
|
52
|
+
"@systemfsoftware/stryker-ignorer-effect-schema-declarations": "latest",
|
|
53
|
+
"@systemfsoftware/stryker-ignorer-in-source-vitest-block": "latest",
|
|
54
|
+
"@systemfsoftware/stryker-js": "latest",
|
|
55
|
+
"@systemfsoftware/stryker-js-typescript-checker": "latest",
|
|
56
|
+
"@systemfsoftware/stryker-js-vitest-runner": "latest",
|
|
57
|
+
"@systemfsoftware/stryker-test-contribution": "latest",
|
|
51
58
|
"@systemfsoftware/tsconfig": "^2.0.1",
|
|
52
59
|
"@systemfsoftware/tsdown-config": "^0.1.0",
|
|
53
|
-
"@systemfsoftware/vitest": "^0.
|
|
60
|
+
"@systemfsoftware/vitest": "^0.3.0",
|
|
54
61
|
"@systemfsoftware/vitest-config": "^0.1.0",
|
|
55
62
|
"@types/node": "^26",
|
|
56
63
|
"effect": "4.0.0-rc.117",
|
|
@@ -61,7 +68,7 @@
|
|
|
61
68
|
"vitest": "^5"
|
|
62
69
|
},
|
|
63
70
|
"peerDependencies": {
|
|
64
|
-
"@systemfsoftware/vitest": "^0.
|
|
71
|
+
"@systemfsoftware/vitest": "^0.3.0",
|
|
65
72
|
"effect": "4.0.0-rc.117",
|
|
66
73
|
"vitest": "^5"
|
|
67
74
|
},
|
|
@@ -74,6 +81,8 @@
|
|
|
74
81
|
"build": "tsdown -l warn",
|
|
75
82
|
"typecheck": "tsc -b",
|
|
76
83
|
"test": "vitest run",
|
|
84
|
+
"mutation": "stryker run",
|
|
85
|
+
"mutation:full": "stryker run --force",
|
|
77
86
|
"test:types": "TSTYCHE_TYPESCRIPT_MODULE=tstyche-typescript tstyche",
|
|
78
87
|
"lint": "f=${OXLINT_FORMAT:-${AGENT:+agent}}; oxlint . --format=${f:-default}",
|
|
79
88
|
"attw": "attw --pack ."
|