Diagram Fidelity
Diagram fidelity measures whether the analyzer can represent a program without unresolved or ambiguous nodes. A score helps you track coverage. The exact field gives CI a strict pass or fail result.
Run the Check
Section titled “Run the Check”import { analysis, computeDiagramFidelity, formatDiagramFidelity,} from "effect-analyzer"import { Effect } from "effect"
const ir = await Effect.runPromise( analysis.file("./src/transfer.ts").single,)
const report = computeDiagramFidelity(ir)console.log(formatDiagramFidelity(report))DiagramFidelityReport contains:
| Field | Meaning |
|---|---|
exact |
true when the report contains no issues |
score |
Percentage of IR nodes without a fidelity penalty |
totalNodes |
Number of nodes in the deep IR tree |
exactRuntimeNodes |
Span-backed nodes with a unique runtime identity |
staticOnlyNodes |
Nodes that have no runtime span identity |
ambiguousRuntimeNodes |
Nodes that share a span path |
unresolvedNodes |
Unknown, opaque, or dynamic-span nodes |
issues |
Located findings with a suggested source change |
Issue Types
Section titled “Issue Types”| Issue | Cause | Source change |
|---|---|---|
unknown-node |
The analyzer cannot resolve an expression | Use a supported Effect v4 operation or extract a named Effect.fn |
opaque-node |
The analyzer treats a boundary as opaque | Extract diagram-relevant work or add an explicit span |
dynamic-span-name |
Code computes the Effect.withSpan name |
Use a string literal and store dynamic values in span attributes |
duplicate-span-path |
Two nodes produce the same nested span path | Give sibling spans distinct names |
Enforce Fidelity in CI
Section titled “Enforce Fidelity in CI”npx effect-analyze ./src --assert-diagram-fidelityThe command checks one file or each analyzed program in a directory. It prints the findings and exits with code 1 when any report has exact: false.
Match Runtime Spans
Section titled “Match Runtime Spans”The analyzer joins runtime spans to static nodes by their nested path. These two spans form the path transfer > debit:
const program = Effect.gen(function* () { yield* debit}).pipe( Effect.withSpan("debit"), Effect.withSpan("transfer"),)Keep names literal and give sibling spans different names. Put request IDs, account IDs, and other runtime values in span attributes.
A captured trace usually starts above the analyzed program, in an HTTP handler or a job runner the analyzed file never mentions. The analyzer matches the full path first, then the longest path suffix that identifies a single node, so those outer spans still resolve everything nested beneath them.
Effect v4 spans
Section titled “Effect v4 spans”import { renderMermaidWithRuntimeTrace, traceFromEffectSpans,} from "effect-analyzer"
const trace = traceFromEffectSpans(effectSpans)const overlay = renderMermaidWithRuntimeTrace(ir, trace)OpenTelemetry spans
Section titled “OpenTelemetry spans”import { renderMermaidWithRuntimeTrace, traceFromOpenTelemetry,} from "effect-analyzer"
const trace = traceFromOpenTelemetry(readableSpans)const overlay = renderMermaidWithRuntimeTrace(ir, trace)Span-tree JSON
Section titled “Span-tree JSON”Tracing tools that export a trace as a nested tree of spans go through traceFromSpanTree(). Each node carries a spanId, a name, a status of ok, error or unset, an optional durationMs, an optional running flag, and its children:
import { renderMermaidWithRuntimeTrace, traceFromSpanTree,} from "effect-analyzer"
const trace = traceFromSpanTree(JSON.parse(exportedTrace))const overlay = renderMermaidWithRuntimeTrace(ir, trace)The CLI reads that same shape from a file:
npx effect-analyze ./src/transfer.ts --format mermaid --runtime-trace ./trace.jsonThe diagram is followed by a comment line counting how the spans matched, so a reviewer or an agent can weigh the colors:
%% runtime overlay: 5 matched, 1 matched by suffix, 0 unmatched, 0 ambiguousRuntimeOverlayResult returns the Mermaid source and four span-ID lists:
| Field | Meaning |
|---|---|
matchedSpanIds |
The full trace path identifies one static node |
suffixMatchedSpanIds |
A path suffix identifies one static node, after dropping outer spans |
unmatchedSpanIds |
The trace path identifies no static node |
ambiguousSpanIds |
The trace path identifies more than one static node |
The renderer colors successful spans green, failed spans red, and running spans amber.