@systemfsoftware/trace-spec 0.0.0 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @systemfsoftware/trace-spec
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - `Rel`, `Graph`, `FailureDump` and `Prop` functions that took their subject first can now also be called data-last inside `pipe`. Existing calls keep working.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies:
12
+ - @systemfsoftware/effect-spec-runtime@0.1.0
13
+
3
14
  ## 0.0.0
4
15
 
5
16
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -104,9 +104,18 @@ type TraceGraph = typeof TraceGraph.Type;
104
104
  declare namespace Graph_d_exports {
105
105
  export { AttributeValue, Attributes, GraphNode, SpanEvent, SpanLink, SpanRecord, Status, TraceGraph, byId, children, decode, descendants };
106
106
  }
107
- declare const byId: (graph: TraceGraph, spec: Span.Span) => ReadonlyArray<GraphNode>;
108
- declare const children: (graph: TraceGraph, node: GraphNode) => ReadonlyArray<GraphNode>;
109
- declare const descendants: (graph: TraceGraph, node: GraphNode) => ReadonlyArray<GraphNode>;
107
+ declare const byId: {
108
+ (spec: Span.Span): (graph: TraceGraph) => ReadonlyArray<GraphNode>;
109
+ (graph: TraceGraph, spec: Span.Span): ReadonlyArray<GraphNode>;
110
+ };
111
+ declare const children: {
112
+ (node: GraphNode): (graph: TraceGraph) => ReadonlyArray<GraphNode>;
113
+ (graph: TraceGraph, node: GraphNode): ReadonlyArray<GraphNode>;
114
+ };
115
+ declare const descendants: {
116
+ (node: GraphNode): (graph: TraceGraph) => ReadonlyArray<GraphNode>;
117
+ (graph: TraceGraph, node: GraphNode): ReadonlyArray<GraphNode>;
118
+ };
110
119
  /**
111
120
  * Decodes the recorded spans of one trace against a taxonomy, purely: a declared span
112
121
  * whose required attributes do not decode refuses with {@link ContractDecodeError}
@@ -114,7 +123,10 @@ declare const descendants: (graph: TraceGraph, node: GraphNode) => ReadonlyArray
114
123
  * the graph as recorded. Failure is a `Result`, so the phase that reads the trace cannot
115
124
  * fail the pipeline by accident.
116
125
  */
117
- declare const decode: (traceId: string, spans: ReadonlyArray<SpanRecord>, taxonomy: Taxonomy.Taxonomy) => Result.Result<TraceGraph, ContractDecodeError>;
126
+ declare const decode: {
127
+ (spans: ReadonlyArray<SpanRecord>, taxonomy: Taxonomy.Taxonomy): (traceId: string) => Result.Result<TraceGraph, ContractDecodeError>;
128
+ (traceId: string, spans: ReadonlyArray<SpanRecord>, taxonomy: Taxonomy.Taxonomy): Result.Result<TraceGraph, ContractDecodeError>;
129
+ };
118
130
  declare namespace Observation_service_d_exports {
119
131
  export { Collector, EmptyObservationError, Observation };
120
132
  }
@@ -156,22 +168,54 @@ interface Relation {
156
168
  declare const exists: <S extends Span.Span>(spec: S) => Relation;
157
169
  declare const absent: <S extends Span.Span>(spec: S) => Relation;
158
170
  declare const unique: <S extends Span.Span>(spec: S) => Relation;
159
- declare const child: (parent: Span.Span, childSpan: Span.Span) => Relation;
160
- declare const descendant: (parent: Span.Span, childSpan: Span.Span) => Relation;
161
- declare const order: (before: Span.Span, after: Span.Span) => Relation;
162
- declare const status: (spec: Span.Span, expected: Status) => Relation;
163
- declare const errorType: (spec: Span.Span, expected: string) => Relation;
164
- declare const attrs: <S extends Span.Span>(spec: S, partial: Partial<Span.AttrsOf<S>>) => Relation;
165
- declare const durationLessThan: (spec: Span.Span, millis: number) => Relation;
166
- declare const event: (spec: Span.Span, name: string) => Relation;
167
- declare const forall: (spec: Span.Span, predicate: (node: GraphNode) => boolean, detail: string) => Relation;
171
+ declare const child: {
172
+ (childSpan: Span.Span): (parent: Span.Span) => Relation;
173
+ (parent: Span.Span, childSpan: Span.Span): Relation;
174
+ };
175
+ declare const descendant: {
176
+ (childSpan: Span.Span): (parent: Span.Span) => Relation;
177
+ (parent: Span.Span, childSpan: Span.Span): Relation;
178
+ };
179
+ declare const order: {
180
+ (after: Span.Span): (before: Span.Span) => Relation;
181
+ (before: Span.Span, after: Span.Span): Relation;
182
+ };
183
+ declare const status: {
184
+ (expected: Status): (spec: Span.Span) => Relation;
185
+ (spec: Span.Span, expected: Status): Relation;
186
+ };
187
+ declare const errorType: {
188
+ (expected: string): (spec: Span.Span) => Relation;
189
+ (spec: Span.Span, expected: string): Relation;
190
+ };
191
+ declare const attrs: {
192
+ <S extends Span.Span>(partial: Partial<Span.AttrsOf<S>>): (spec: S) => Relation;
193
+ <S extends Span.Span>(spec: S, partial: Partial<Span.AttrsOf<S>>): Relation;
194
+ };
195
+ declare const durationLessThan: {
196
+ (millis: number): (spec: Span.Span) => Relation;
197
+ (spec: Span.Span, millis: number): Relation;
198
+ };
199
+ declare const event: {
200
+ (name: string): (spec: Span.Span) => Relation;
201
+ (spec: Span.Span, name: string): Relation;
202
+ };
203
+ declare const forall: {
204
+ (predicate: (node: GraphNode) => boolean, detail: string): (spec: Span.Span) => Relation;
205
+ (spec: Span.Span, predicate: (node: GraphNode) => boolean, detail: string): Relation;
206
+ };
168
207
  declare const soft: (self: Relation) => Relation;
169
208
  declare const not: (self: Relation) => Relation;
170
209
  declare const all: (...relations: ReadonlyArray<Relation>) => Relation;
171
210
  declare const any: (...relations: ReadonlyArray<Relation>) => Relation;
172
- declare const fromTaxonomy: (taxonomy: Taxonomy.Taxonomy, options: {
173
- readonly path: string;
174
- }) => Relation;
211
+ declare const fromTaxonomy: {
212
+ (options: {
213
+ readonly path: string;
214
+ }): (taxonomy: Taxonomy.Taxonomy) => Relation;
215
+ (taxonomy: Taxonomy.Taxonomy, options: {
216
+ readonly path: string;
217
+ }): Relation;
218
+ };
175
219
  declare namespace Stimulus_d_exports {
176
220
  export { Run, Stimulus, TraceContext, make$3 as make, traceContext };
177
221
  }
package/dist/index.mjs CHANGED
@@ -61,15 +61,16 @@ const renderNode = (spans, node, depth) => {
61
61
  ...childrenOf(spans, node.spanId).map((child) => renderNode(spans, child, depth + 1))
62
62
  ]].join("\n");
63
63
  };
64
- /**
65
- * The dump document: the trace it belongs to, the break that refused it, and the recorded
66
- * spans as the observation window saw them.
67
- */
68
- const document = (observed, report) => [
64
+ const documentImpl = (observed, report) => [
69
65
  `trace ${observed.traceId}`,
70
66
  report,
71
67
  ...observed.spans.map((node) => renderNode(observed.spans, node, 0))
72
68
  ].join("\n");
69
+ /**
70
+ * The dump document: the trace it belongs to, the break that refused it, and the recorded
71
+ * spans as the observation window saw them.
72
+ */
73
+ const document = dual(2, documentImpl);
73
74
  const sanitize = (value) => value.replace(/[^a-zA-Z0-9._-]+/g, "-");
74
75
  const fileNameOf = (request) => `${sanitize(request.name ?? request.traceId)}.${sanitize(request.conjunct)}.txt`;
75
76
  /**
@@ -156,12 +157,15 @@ var Graph_exports = /* @__PURE__ */ __exportAll({
156
157
  decode: () => decode,
157
158
  descendants: () => descendants
158
159
  });
159
- const byId = (graph, spec) => graph.nodes.filter((node) => node.name === spec.name);
160
- const children = (graph, node) => graph.nodes.filter((candidate) => candidate.parentSpanId === node.spanId);
161
- const descendants = (graph, node) => {
160
+ const byIdImpl = (graph, spec) => graph.nodes.filter((node) => node.name === spec.name);
161
+ const byId = dual(2, byIdImpl);
162
+ const childrenImpl = (graph, node) => graph.nodes.filter((candidate) => candidate.parentSpanId === node.spanId);
163
+ const children = dual(2, childrenImpl);
164
+ const descendantsImpl = (graph, node) => {
162
165
  const direct = children(graph, node);
163
166
  return [...direct, ...direct.flatMap((child) => descendants(graph, child))];
164
167
  };
168
+ const descendants = dual(2, descendantsImpl);
165
169
  const indexDeclarations = (taxonomy) => new Map(taxonomy.spans.map((span) => [span.name, span]));
166
170
  const keyOfPath = (path) => {
167
171
  const last = path.at(-1);
@@ -204,6 +208,10 @@ const graphOf = (traceId, nodes) => ({
204
208
  traceId,
205
209
  nodes
206
210
  });
211
+ const decodeImpl = (traceId, spans, taxonomy) => {
212
+ const declarations = indexDeclarations(taxonomy);
213
+ return Result.map(Result.all(spans.map((record) => declaredNodeOf(record, declarations))), (nodes) => graphOf(traceId, nodes));
214
+ };
207
215
  /**
208
216
  * Decodes the recorded spans of one trace against a taxonomy, purely: a declared span
209
217
  * whose required attributes do not decode refuses with {@link ContractDecodeError}
@@ -211,10 +219,7 @@ const graphOf = (traceId, nodes) => ({
211
219
  * the graph as recorded. Failure is a `Result`, so the phase that reads the trace cannot
212
220
  * fail the pipeline by accident.
213
221
  */
214
- const decode = (traceId, spans, taxonomy) => {
215
- const declarations = indexDeclarations(taxonomy);
216
- return Result.map(Result.all(spans.map((record) => declaredNodeOf(record, declarations))), (nodes) => graphOf(traceId, nodes));
217
- };
222
+ const decode = dual(3, decodeImpl);
218
223
  //#endregion
219
224
  //#region src/Observation.service.ts
220
225
  var Observation_service_exports = /* @__PURE__ */ __exportAll({
@@ -497,65 +502,73 @@ const reachedUnder = (graph, parent, childSpan, reach) => {
497
502
  const reached = reach(graph, matchedNodes(graph, parent));
498
503
  return matchedNodes(graph, childSpan).some((node) => reached.has(node.spanId));
499
504
  };
500
- const child = (parent, childSpan) => declared({
505
+ const childImpl = (parent, childSpan) => declared({
501
506
  id: `child(${parent.id},${childSpan.id})`,
502
507
  spans: [parent, childSpan],
503
508
  softenable: true,
504
509
  detail: `no ${childSpan.id} span is a direct child of a ${parent.id} span`,
505
510
  holds: (graph) => reachedUnder(graph, parent, childSpan, childIdsOf)
506
511
  });
507
- const descendant = (parent, childSpan) => declared({
512
+ const child = dual(2, childImpl);
513
+ const descendantImpl = (parent, childSpan) => declared({
508
514
  id: `descendant(${parent.id},${childSpan.id})`,
509
515
  spans: [parent, childSpan],
510
516
  softenable: true,
511
517
  detail: `no ${childSpan.id} span descends from a ${parent.id} span`,
512
518
  holds: (graph) => reachedUnder(graph, parent, childSpan, descendantIdsOf)
513
519
  });
514
- const order = (before, after) => declared({
520
+ const descendant = dual(2, descendantImpl);
521
+ const orderImpl = (before, after) => declared({
515
522
  id: `order(${before.id},${after.id})`,
516
523
  spans: [before, after],
517
524
  softenable: true,
518
525
  detail: `a ${after.id} span starts before every ${before.id} span`,
519
526
  holds: (graph) => matchedAll(matchedNodes(graph, after), (node) => startsAfterSome(matchedNodes(graph, before), node))
520
527
  });
521
- const status = (spec, expected) => declared({
528
+ const order = dual(2, orderImpl);
529
+ const statusImpl = (spec, expected) => declared({
522
530
  id: `status(${spec.id},${expected})`,
523
531
  spans: [spec],
524
532
  softenable: true,
525
533
  detail: `a ${spec.id} span is not ${expected}`,
526
534
  holds: holdsEveryOf(spec, (node) => node.status === expected)
527
535
  });
528
- const errorType = (spec, expected) => declared({
536
+ const status = dual(2, statusImpl);
537
+ const errorTypeImpl = (spec, expected) => declared({
529
538
  id: `errorType(${spec.id},${expected})`,
530
539
  spans: [spec],
531
540
  softenable: true,
532
541
  detail: `a ${spec.id} span carries a different error.type`,
533
542
  holds: holdsEveryOf(spec, (node) => node.errorType === expected)
534
543
  });
544
+ const errorType = dual(2, errorTypeImpl);
535
545
  const partialMatches = (attributes, partial) => Object.entries(partial).filter(([, value]) => value !== void 0).every(([key, value]) => Equal.equals(attributes[key], value));
536
- const attrs = (spec, partial) => declared({
546
+ const attrsImpl = (spec, partial) => declared({
537
547
  id: `attrs(${spec.id})`,
538
548
  spans: [spec],
539
549
  softenable: true,
540
550
  detail: `a ${spec.id} span carries a different declared attribute`,
541
551
  holds: holdsEveryOf(spec, (node) => partialMatches(node.attrs, partial))
542
552
  });
543
- const durationLessThan = (spec, millis) => declared({
553
+ const attrs = dual(2, attrsImpl);
554
+ const durationLessThanImpl = (spec, millis) => declared({
544
555
  id: `durationLessThan(${spec.id},${millis})`,
545
556
  spans: [spec],
546
557
  softenable: true,
547
558
  detail: `a ${spec.id} span exceeded ${millis}ms`,
548
559
  holds: holdsEveryOf(spec, (node) => node.durationMillis < millis)
549
560
  });
561
+ const durationLessThan = dual(2, durationLessThanImpl);
550
562
  const carriesEvent = (name) => (node) => node.events.some((event) => event.name === name);
551
- const event = (spec, name) => declared({
563
+ const eventImpl = (spec, name) => declared({
552
564
  id: `event(${spec.id},${name})`,
553
565
  spans: [spec],
554
566
  softenable: true,
555
567
  detail: `a ${spec.id} span carries no ${name} event`,
556
568
  holds: holdsEveryOf(spec, carriesEvent(name))
557
569
  });
558
- const forall = (spec, predicate, detail) => {
570
+ const event = dual(2, eventImpl);
571
+ const forallImpl = (spec, predicate, detail) => {
559
572
  const id = `forall(${spec.id})`;
560
573
  return relation({
561
574
  id,
@@ -572,6 +585,7 @@ const forall = (spec, predicate, detail) => {
572
585
  }
573
586
  });
574
587
  };
588
+ const forall = dual(3, forallImpl);
575
589
  const soft = (self) => self.softenable ? relation({
576
590
  id: self.id,
577
591
  soft: true,
@@ -667,12 +681,13 @@ const forbidsAt = (entry, path) => Option.match(entry.unless, {
667
681
  onSome: (tag) => tag !== path
668
682
  });
669
683
  const forbiddenOn = (path) => (entry) => forbidsAt(entry, path) ? [absent(entry.span)] : [];
670
- const fromTaxonomy = (taxonomy, options) => combined({
684
+ const fromTaxonomyImpl = (taxonomy, options) => combined({
671
685
  id: `fromTaxonomy(${taxonomy.id},${options.path})`,
672
686
  relations: [...taxonomy.edges.map(placementOf), ...taxonomy.forbidden.flatMap(forbiddenOn(options.path))],
673
687
  soft: false,
674
688
  softenable: false
675
689
  });
690
+ const fromTaxonomy = dual(2, fromTaxonomyImpl);
676
691
  //#endregion
677
692
  //#region src/Stimulus.ts
678
693
  var Stimulus_exports = /* @__PURE__ */ __exportAll({
@@ -724,19 +739,11 @@ const announce = (context, verdict, dumpPath) => Option.match(dumpMessageOf(verd
724
739
  onNone: () => Effect.void,
725
740
  onSome: (message) => annotate(context, message)
726
741
  });
727
- /**
728
- * The generated-case predicate for one case: a factory that runs the contract's cell with
729
- * the dump named after the case — so every failing draw overwrites one file and the last
730
- * failing draw is the shrunk counterexample the runner reports — and answers the verdict as
731
- * the boolean: `true` while the relation held, `false` on a break, falsifying the property.
732
- * Only infrastructure refusals — a failing behaviour, an undecodable span, an empty
733
- * observation — stay on the error channel. The scenario layer is built fresh per draw, so
734
- * each draw owns its observation window.
735
- */
736
- function predicate(title, contract, scenario) {
742
+ const predicateImpl = (title, contract, scenario) => {
737
743
  const checked = (input, context) => judge(contract, input, { dumpName: title }).pipe(Effect.tap((judgment) => announce(context, judgment.verdict, judgment.dumpPath)), Effect.map((judgment) => isHold(judgment.verdict)), Effect.provide(Layer.fresh(scenario)));
738
744
  return (input, context) => checked(input, context);
739
- }
745
+ };
746
+ const predicate = dual(3, predicateImpl);
740
747
  //#endregion
741
748
  //#region src/StimulusFailure.schema.ts
742
749
  var StimulusFailure = class extends Schema.TaggedError()("StimulusFailure", {
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.0.0",
4
+ "version": "0.1.0",
5
5
  "author": "Ryan Lee <drdgvhbh@gmail.com>",
6
6
  "repository": {
7
7
  "type": "git",
@@ -38,25 +38,25 @@
38
38
  "@opentelemetry/resources": "^2",
39
39
  "@opentelemetry/sdk-trace-base": "^2",
40
40
  "@opentelemetry/semantic-conventions": "^1.33",
41
- "@systemfsoftware/trace-taxonomy": "^0.0.0",
42
- "@systemfsoftware/effect-spec-runtime": "^0.0.0"
41
+ "@systemfsoftware/effect-spec-runtime": "^0.1.0",
42
+ "@systemfsoftware/trace-taxonomy": "^0.0.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@effect/platform-node": "4.0.0-rc.116",
46
46
  "@effect/vitest": "4.0.0-rc.116",
47
47
  "@systemfsoftware/arethetypeswrong-cli": "^4.2.0",
48
+ "@systemfsoftware/effect-gherkin-spec": "^4.3.0",
49
+ "@systemfsoftware/oxlint-config-recommended": "^2.0.0",
50
+ "@systemfsoftware/tsconfig": "^2.0.0",
51
+ "@systemfsoftware/tsdown-config": "^0.1.0",
52
+ "@systemfsoftware/vitest-config": "^0.1.0",
48
53
  "@types/node": "^26",
49
54
  "effect": "4.0.0-rc.116",
50
55
  "oxlint": "~1.82.0",
51
56
  "rimraf": "^6.1.3",
52
57
  "tsdown": "^0.23.0",
53
58
  "tstyche": "^7.2.5",
54
- "vitest": "^5",
55
- "@systemfsoftware/effect-gherkin-spec": "^4.2.3",
56
- "@systemfsoftware/oxlint-config-recommended": "^1.1.1",
57
- "@systemfsoftware/tsconfig": "^1.3.6",
58
- "@systemfsoftware/tsdown-config": "^0.1.0",
59
- "@systemfsoftware/vitest-config": "^0.1.0"
59
+ "vitest": "^5"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@effect/vitest": "4.0.0-rc.116",
@@ -69,7 +69,7 @@
69
69
  "scripts": {
70
70
  "clean": "rimraf dist",
71
71
  "build": "tsdown -l warn",
72
- "typecheck": "tsc --noEmit --incremental",
72
+ "typecheck": "tsc -b",
73
73
  "test": "vitest run",
74
74
  "test:types": "TSTYCHE_TYPESCRIPT_MODULE=tstyche-typescript tstyche",
75
75
  "lint": "f=${OXLINT_FORMAT:-${AGENT:+agent}}; oxlint . --format=${f:-default}",