@ontrails/trails 1.0.0-beta.30 → 1.0.0-beta.39

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.
@@ -14,7 +14,8 @@ const releaseSmokeInputSchema = z.object({
14
14
  });
15
15
 
16
16
  const releaseSmokeCheckResultSchema = z.object({
17
- check: z.enum(['packed-artifacts', 'wayfinder-dogfood']),
17
+ check: z.enum(['lock-roundtrip', 'packed-artifacts', 'wayfinder-dogfood']),
18
+ lockCount: z.number().optional(),
18
19
  message: z.string(),
19
20
  packageCount: z.number().optional(),
20
21
  passed: z.literal(true),
@@ -44,7 +44,7 @@ export const reviseTrail = trail('revise', {
44
44
  }),
45
45
  intent: 'write',
46
46
  output: z.object({
47
- file: z.string(),
47
+ filePath: z.string(),
48
48
  trailId: z.string(),
49
49
  updated: z.boolean(),
50
50
  warnings: z.array(z.string()).optional(),
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { basename, extname, join } from 'node:path';
9
9
 
10
- import type { CliCommandAliasInput, Topo } from '@ontrails/core';
10
+ import type { Topo } from '@ontrails/core';
11
11
  import {
12
12
  deriveSafePath,
13
13
  NotFoundError,
@@ -15,7 +15,12 @@ import {
15
15
  trail,
16
16
  ValidationError,
17
17
  } from '@ontrails/core';
18
- import type { DiffEntry, DiffResult, TopoGraph } from '@ontrails/topographer';
18
+ import type {
19
+ DiffEntry,
20
+ DiffResult,
21
+ TopoGraph,
22
+ TopoGraphOverlayRegistration,
23
+ } from '@ontrails/topographer';
19
24
  import {
20
25
  createTopoStore,
21
26
  deriveTopoGraphDiff,
@@ -30,12 +35,12 @@ import { writeIsolatedExampleJsonFile } from '../local-state-io.js';
30
35
 
31
36
  import { withFreshAppLease, withOperatorRootDir } from './operator-context.js';
32
37
  import {
33
- buildCurrentTopoBrief,
34
- buildCurrentTopoList,
35
- buildCurrentTopoMatches,
36
- buildCurrentTrailDetail,
37
- buildCurrentResourceDetail,
38
- buildCurrentSignalDetail,
38
+ deriveCurrentTopoBrief,
39
+ deriveCurrentTopoList,
40
+ deriveCurrentTopoMatches,
41
+ deriveCurrentTrailDetail,
42
+ deriveCurrentResourceDetail,
43
+ deriveCurrentSignalDetail,
39
44
  readSurfaceLayerNamesFromContext,
40
45
  } from './topo-read-support.js';
41
46
  import {
@@ -506,13 +511,11 @@ const buildSurveyLookup = (
506
511
  app: Topo,
507
512
  entityId: string,
508
513
  rootDir: string,
509
- cliAliases:
510
- | Readonly<Record<string, readonly CliCommandAliasInput[]>>
511
- | undefined,
514
+ overlays: readonly TopoGraphOverlayRegistration[] | undefined,
512
515
  surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
513
516
  ): Result<object, Error> => {
514
- const matches = buildCurrentTopoMatches(app, entityId, {
515
- cliAliases,
517
+ const matches = deriveCurrentTopoMatches(app, entityId, {
518
+ overlays,
516
519
  rootDir,
517
520
  surfaceLayerNames,
518
521
  });
@@ -523,13 +526,11 @@ const buildSurveyTrailDetail = (
523
526
  app: Topo,
524
527
  id: string,
525
528
  rootDir: string,
526
- cliAliases:
527
- | Readonly<Record<string, readonly CliCommandAliasInput[]>>
528
- | undefined,
529
+ overlays: readonly TopoGraphOverlayRegistration[] | undefined,
529
530
  surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
530
531
  ): Result<object, Error> => {
531
- const detail = buildCurrentTrailDetail(app, id, {
532
- cliAliases,
532
+ const detail = deriveCurrentTrailDetail(app, id, {
533
+ overlays,
533
534
  rootDir,
534
535
  surfaceLayerNames,
535
536
  });
@@ -543,7 +544,7 @@ const buildSurveyResourceDetail = (
543
544
  id: string,
544
545
  rootDir: string
545
546
  ): Result<object, Error> => {
546
- const detail = buildCurrentResourceDetail(app, id, { rootDir });
547
+ const detail = deriveCurrentResourceDetail(app, id, { rootDir });
547
548
  return detail === undefined
548
549
  ? Result.err(new NotFoundError(`Resource not found: ${id}`))
549
550
  : Result.ok(detail);
@@ -554,7 +555,7 @@ const buildSurveySignalDetail = (
554
555
  id: string,
555
556
  rootDir: string
556
557
  ): Result<object, Error> => {
557
- const detail = buildCurrentSignalDetail(app, id, { rootDir });
558
+ const detail = deriveCurrentSignalDetail(app, id, { rootDir });
558
559
  return detail === undefined
559
560
  ? Result.err(new NotFoundError(`Signal not found: ${id}`))
560
561
  : Result.ok(detail);
@@ -581,26 +582,18 @@ type SurveyHandler = (
581
582
  app: Topo,
582
583
  input: SurveyInput,
583
584
  rootDir: string,
584
- cliAliases:
585
- | Readonly<Record<string, readonly CliCommandAliasInput[]>>
586
- | undefined,
585
+ overlays: readonly TopoGraphOverlayRegistration[] | undefined,
587
586
  surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
588
587
  ) => Result<object, Error> | Promise<Result<object, Error>>;
589
588
 
590
589
  /** Handlers keyed by survey mode. */
591
590
  const surveyHandlers: Record<SurveyMode, SurveyHandler> = {
592
- lookup: (app, input, rootDir, cliAliases, surfaceLayerNames) =>
591
+ lookup: (app, input, rootDir, overlays, surfaceLayerNames) =>
593
592
  input.id === undefined || input.id === ''
594
593
  ? Result.err(new ValidationError('Survey lookup requires an id'))
595
- : buildSurveyLookup(
596
- app,
597
- input.id,
598
- rootDir,
599
- cliAliases,
600
- surfaceLayerNames
601
- ),
594
+ : buildSurveyLookup(app, input.id, rootDir, overlays, surfaceLayerNames),
602
595
  overview: (app, _input, rootDir) =>
603
- Result.ok(buildCurrentTopoList(app, { rootDir })),
596
+ Result.ok(deriveCurrentTopoList(app, { rootDir })),
604
597
  };
605
598
 
606
599
  const envelopeSurveyValue = (
@@ -613,9 +606,7 @@ const dispatchSurvey = async (
613
606
  app: Topo,
614
607
  input: SurveyInput,
615
608
  rootDir: string,
616
- cliAliases:
617
- | Readonly<Record<string, readonly CliCommandAliasInput[]>>
618
- | undefined,
609
+ overlays: readonly TopoGraphOverlayRegistration[] | undefined,
619
610
  surfaceLayerNames?: Partial<SurfaceLayerNames> | undefined
620
611
  ): Promise<Result<SurveyEnvelope, Error>> => {
621
612
  const mode = deriveSurveyMode(input);
@@ -624,7 +615,7 @@ const dispatchSurvey = async (
624
615
  app,
625
616
  input,
626
617
  rootDir,
627
- cliAliases,
618
+ overlays,
628
619
  surfaceLayerNames
629
620
  );
630
621
  if (result.isErr()) {
@@ -644,13 +635,11 @@ const withFreshSurveyApp = async <T>(
644
635
  rootDir: string,
645
636
  consume: (
646
637
  app: Topo,
647
- cliAliases:
648
- | Readonly<Record<string, readonly CliCommandAliasInput[]>>
649
- | undefined
638
+ overlays: readonly TopoGraphOverlayRegistration[] | undefined
650
639
  ) => Promise<Result<T, Error>> | Result<T, Error>
651
640
  ): Promise<Result<T, Error>> =>
652
641
  withFreshAppLease(input.module, rootDir, (lease) =>
653
- consume(lease.app, lease.cliAliases)
642
+ consume(lease.app, lease.overlays)
654
643
  );
655
644
 
656
645
  const withResolvedSurveyApp = async <T>(
@@ -662,14 +651,12 @@ const withResolvedSurveyApp = async <T>(
662
651
  consume: (
663
652
  app: Topo,
664
653
  rootDir: string,
665
- cliAliases:
666
- | Readonly<Record<string, readonly CliCommandAliasInput[]>>
667
- | undefined
654
+ overlays: readonly TopoGraphOverlayRegistration[] | undefined
668
655
  ) => Promise<Result<T, Error>> | Result<T, Error>
669
656
  ): Promise<Result<T, Error>> =>
670
657
  withOperatorRootDir(input, { cwd }, (rootDir) =>
671
- withFreshSurveyApp(input, rootDir, (app, cliAliases) =>
672
- consume(app, rootDir, cliAliases)
658
+ withFreshSurveyApp(input, rootDir, (app, overlays) =>
659
+ consume(app, rootDir, overlays)
673
660
  )
674
661
  );
675
662
 
@@ -743,12 +730,12 @@ const surveyMatchOutput = z.discriminatedUnion('kind', [
743
730
  export const surveyTrail = trail('survey', {
744
731
  args: ['id'],
745
732
  blaze: async (input, ctx) =>
746
- withResolvedSurveyApp(input, ctx.cwd, (app, rootDir, cliAliases) =>
733
+ withResolvedSurveyApp(input, ctx.cwd, (app, rootDir, overlays) =>
747
734
  dispatchSurvey(
748
735
  app,
749
736
  input,
750
737
  rootDir,
751
- cliAliases,
738
+ overlays,
752
739
  readSurfaceLayerNamesFromContext(ctx)
753
740
  )
754
741
  ),
@@ -824,7 +811,7 @@ export const surveyTrail = trail('survey', {
824
811
  export const surveyBriefTrail = trail('survey.brief', {
825
812
  blaze: async (input, ctx) =>
826
813
  withResolvedSurveyApp(input, ctx.cwd, (app, rootDir) =>
827
- Result.ok(buildCurrentTopoBrief(app, { rootDir }))
814
+ Result.ok(deriveCurrentTopoBrief(app, { rootDir }))
828
815
  ),
829
816
  description: 'Summarize topo capabilities',
830
817
  examples: [
@@ -904,12 +891,12 @@ export const surveyDiffTrail = trail('survey.diff', {
904
891
  export const surveyTrailDetailTrail = trail('survey.trail', {
905
892
  args: ['id'],
906
893
  blaze: async (input, ctx) =>
907
- withResolvedSurveyApp(input, ctx.cwd, (app, rootDir, cliAliases) =>
894
+ withResolvedSurveyApp(input, ctx.cwd, (app, rootDir, overlays) =>
908
895
  buildSurveyTrailDetail(
909
896
  app,
910
897
  input.id,
911
898
  rootDir,
912
- cliAliases,
899
+ overlays,
913
900
  readSurfaceLayerNamesFromContext(ctx)
914
901
  )
915
902
  ),
@@ -1,385 +1,14 @@
1
- import type {
2
- ActivationEntry,
3
- ActivationSource,
4
- ActivationSourceProjection,
5
- AnyTrail,
6
- Topo,
7
- } from '@ontrails/core';
8
- import {
9
- activationSourceKey,
10
- projectActivationSourceDeclaration,
11
- } from '@ontrails/core';
12
-
13
- export interface ActivationChainReport {
14
- readonly consumer: string;
15
- readonly producer: string;
16
- readonly signal: string;
17
- }
18
-
19
- type JsonSchemaReport = Readonly<Record<string, unknown>>;
20
-
21
- export interface ActivationSourceReport extends ActivationSourceProjection {
22
- readonly cron?: string | undefined;
23
- readonly hasParse?: true | undefined;
24
- readonly hasPayloadSchema?: true | undefined;
25
- readonly hasVerify?: true | undefined;
26
- readonly id: string;
27
- readonly input?: unknown;
28
- readonly inputSchema?: JsonSchemaReport | undefined;
29
- readonly kind: string;
30
- readonly key: string;
31
- readonly meta?: Readonly<Record<string, unknown>> | undefined;
32
- readonly method?: string | undefined;
33
- readonly parseOutputSchema?: JsonSchemaReport | undefined;
34
- readonly path?: string | undefined;
35
- readonly payloadSchema?: JsonSchemaReport | undefined;
36
- readonly timezone?: string | undefined;
37
- }
38
-
39
- export interface ActivationEdgeReport extends Readonly<
40
- Record<string, unknown>
41
- > {
42
- readonly hasWhere: boolean;
43
- readonly sourceId: string;
44
- readonly sourceKey: string;
45
- readonly sourceKind: string;
46
- readonly trailId: string;
47
- readonly where?: { readonly predicate: true } | undefined;
48
- }
49
-
50
- export interface SignalActivationRelations {
51
- readonly consumers: readonly string[];
52
- readonly producers: readonly string[];
53
- }
54
-
55
- export interface TrailActivationReport {
56
- readonly activatedBy: readonly string[];
57
- readonly activates: readonly string[];
58
- readonly chains: readonly ActivationChainReport[];
59
- readonly edges: readonly ActivationEdgeReport[];
60
- readonly fires: readonly string[];
61
- readonly on: readonly string[];
62
- readonly sources: readonly ActivationSourceReport[];
63
- }
64
-
65
- export interface ActivationOverviewReport {
66
- readonly chainCount: number;
67
- readonly chains: readonly ActivationChainReport[];
68
- readonly edgeCount: number;
69
- readonly edges: readonly ActivationEdgeReport[];
70
- readonly signalIds: readonly string[];
71
- readonly sourceCount: number;
72
- readonly sourceKeys: readonly string[];
73
- readonly trailIds: readonly string[];
74
- }
75
-
76
- export interface ActivationGraphReport {
77
- readonly overview: ActivationOverviewReport;
78
- readonly signals: ReadonlyMap<string, SignalActivationRelations>;
79
- readonly sources: ReadonlyMap<string, ActivationSourceReport>;
80
- readonly trails: ReadonlyMap<string, TrailActivationReport>;
81
- }
82
-
83
- interface MutableSignalRelations {
84
- readonly consumers: Set<string>;
85
- readonly producers: Set<string>;
86
- }
87
-
88
- interface MutableTrailActivation {
89
- readonly activatedBy: Set<string>;
90
- readonly activates: Set<string>;
91
- readonly chains: ActivationChainReport[];
92
- readonly fires: readonly string[];
93
- readonly on: readonly string[];
94
- }
95
-
96
- const canonicalLeaf = (value: unknown): unknown => {
97
- switch (typeof value) {
98
- case 'bigint': {
99
- return value.toString();
100
- }
101
- case 'function': {
102
- return `[Function:${value.name || 'anonymous'}]`;
103
- }
104
- case 'symbol': {
105
- return `[Symbol:${value.description ?? ''}]`;
106
- }
107
- case 'undefined': {
108
- return '[Undefined]';
109
- }
110
- default: {
111
- return value;
112
- }
113
- }
114
- };
115
-
116
- const canonicalize = (value: unknown): unknown => {
117
- if (Array.isArray(value)) {
118
- return value.map(canonicalize);
119
- }
120
- if (value instanceof Date) {
121
- return value.toISOString();
122
- }
123
- if (value instanceof RegExp) {
124
- return value.toString();
125
- }
126
- if (value !== null && typeof value === 'object') {
127
- const sorted: Record<string, unknown> = {};
128
- for (const key of Object.keys(value).toSorted()) {
129
- const next = (value as Record<string, unknown>)[key];
130
- sorted[key] = next === undefined ? '[Undefined]' : canonicalize(next);
131
- }
132
- return sorted;
133
- }
134
- return canonicalLeaf(value);
135
- };
136
-
137
- const sortKeys = <T extends Record<string, unknown>>(value: T): T => {
138
- const sorted: Record<string, unknown> = {};
139
- for (const key of Object.keys(value).toSorted()) {
140
- sorted[key] = value[key];
141
- }
142
- return sorted as T;
143
- };
144
-
145
- const compareChains = (
146
- a: ActivationChainReport,
147
- b: ActivationChainReport
148
- ): number =>
149
- a.producer.localeCompare(b.producer) ||
150
- a.signal.localeCompare(b.signal) ||
151
- a.consumer.localeCompare(b.consumer);
152
-
153
- const sortedUnique = (values: Iterable<string>): readonly string[] =>
154
- [...new Set(values)].toSorted();
155
-
156
- const projectActivationSource = (
157
- source: ActivationSource
158
- ): ActivationSourceReport =>
159
- projectActivationSourceDeclaration(source) as ActivationSourceReport;
160
-
161
- const projectActivationEdge = (
162
- trailId: string,
163
- activation: ActivationEntry
164
- ): ActivationEdgeReport => {
165
- const sourceKey = activationSourceKey(activation.source);
166
- const edge: Record<string, unknown> = {
167
- hasWhere: activation.where !== undefined,
168
- sourceId: activation.source.id,
169
- sourceKey,
170
- sourceKind: activation.source.kind,
171
- trailId,
172
- };
173
-
174
- if (activation.meta !== undefined) {
175
- edge['meta'] = canonicalize(activation.meta);
176
- }
177
- if (activation.where !== undefined) {
178
- edge['where'] = { predicate: true };
179
- }
180
-
181
- return sortKeys(edge) as ActivationEdgeReport;
182
- };
183
-
184
- const collectActivationSourceCatalog = (
185
- trails: readonly AnyTrail[]
186
- ): readonly ActivationSourceReport[] => {
187
- const sources = new Map<string, ActivationSourceReport>();
188
- for (const trail of trails) {
189
- for (const activation of trail.activationSources) {
190
- const projected = projectActivationSource(activation.source);
191
- sources.set(projected.key, projected);
192
- }
193
- }
194
- return [...sources.values()].toSorted((a, b) => a.key.localeCompare(b.key));
195
- };
196
-
197
- const collectActivationEdges = (
198
- trails: readonly AnyTrail[]
199
- ): readonly ActivationEdgeReport[] => {
200
- const edges = new Map<string, ActivationEdgeReport>();
201
- for (const trail of trails) {
202
- for (const activation of trail.activationSources) {
203
- const edge = projectActivationEdge(trail.id, activation);
204
- const key = `${edge.sourceKey}\0${edge.trailId}`;
205
- const previous = edges.get(key);
206
- edges.set(
207
- key,
208
- previous === undefined || (!previous.hasWhere && edge.hasWhere)
209
- ? edge
210
- : previous
211
- );
212
- }
213
- }
214
-
215
- return [...edges.values()].toSorted(
216
- (a, b) =>
217
- a.sourceKey.localeCompare(b.sourceKey) ||
218
- a.trailId.localeCompare(b.trailId)
219
- );
220
- };
221
-
222
- const getSignalRelations = (
223
- relations: Map<string, MutableSignalRelations>,
224
- signalId: string
225
- ): MutableSignalRelations => {
226
- const existing = relations.get(signalId);
227
- if (existing !== undefined) {
228
- return existing;
229
- }
230
-
231
- const created = {
232
- consumers: new Set<string>(),
233
- producers: new Set<string>(),
234
- };
235
- relations.set(signalId, created);
236
- return created;
237
- };
238
-
239
- const getTrailActivation = (
240
- trails: Map<string, MutableTrailActivation>,
241
- trail: AnyTrail
242
- ): MutableTrailActivation => {
243
- const existing = trails.get(trail.id);
244
- if (existing !== undefined) {
245
- return existing;
246
- }
247
-
248
- const created = {
249
- activatedBy: new Set<string>(),
250
- activates: new Set<string>(),
251
- chains: [],
252
- fires: sortedUnique(trail.fires),
253
- on: sortedUnique(trail.on),
254
- };
255
- trails.set(trail.id, created);
256
- return created;
257
- };
258
-
259
- export const deriveDeclaredTrailActivation = (
260
- trail: AnyTrail
261
- ): TrailActivationReport => {
262
- const sources = collectActivationSourceCatalog([trail]);
263
- return {
264
- activatedBy: [],
265
- activates: [],
266
- chains: [],
267
- edges: collectActivationEdges([trail]),
268
- fires: sortedUnique(trail.fires),
269
- on: sortedUnique(trail.on),
270
- sources,
271
- };
272
- };
273
-
274
- export const deriveSignalActivationRelations = (
275
- app: Topo,
276
- signalId: string
277
- ): SignalActivationRelations => {
278
- const consumers: string[] = [];
279
- const producers: string[] = [];
280
-
281
- for (const trail of app.list()) {
282
- if (trail.fires.includes(signalId)) {
283
- producers.push(trail.id);
284
- }
285
- if (trail.on.includes(signalId)) {
286
- consumers.push(trail.id);
287
- }
288
- }
289
-
290
- return {
291
- consumers: sortedUnique(consumers),
292
- producers: sortedUnique(producers),
293
- };
294
- };
295
-
296
- export const deriveActivationGraph = (app: Topo): ActivationGraphReport => {
297
- const signalRelations = new Map<string, MutableSignalRelations>();
298
- const trailActivations = new Map<string, MutableTrailActivation>();
299
- const trails = app.list();
300
- const sources = collectActivationSourceCatalog(trails);
301
- const edges = collectActivationEdges(trails);
302
-
303
- for (const signal of app.listSignals()) {
304
- getSignalRelations(signalRelations, signal.id);
305
- }
306
-
307
- for (const trail of trails) {
308
- const trailActivation = getTrailActivation(trailActivations, trail);
309
- for (const signalId of trailActivation.fires) {
310
- getSignalRelations(signalRelations, signalId).producers.add(trail.id);
311
- }
312
- for (const signalId of trailActivation.on) {
313
- getSignalRelations(signalRelations, signalId).consumers.add(trail.id);
314
- }
315
- }
316
-
317
- const chains: ActivationChainReport[] = [];
318
- for (const [signal, related] of signalRelations) {
319
- for (const producer of related.producers) {
320
- const producerActivation = trailActivations.get(producer);
321
- for (const consumer of related.consumers) {
322
- const chain = { consumer, producer, signal };
323
- chains.push(chain);
324
- producerActivation?.activates.add(consumer);
325
- producerActivation?.chains.push(chain);
326
- const consumerActivation = trailActivations.get(consumer);
327
- consumerActivation?.activatedBy.add(producer);
328
- if (consumerActivation !== producerActivation) {
329
- consumerActivation?.chains.push(chain);
330
- }
331
- }
332
- }
333
- }
334
-
335
- chains.sort(compareChains);
336
- const activeTrailIds = sortedUnique([
337
- ...[...trailActivations.entries()].flatMap(([trailId, trail]) =>
338
- trail.fires.length > 0 || trail.on.length > 0
339
- ? [trailId, ...trail.activatedBy, ...trail.activates]
340
- : []
341
- ),
342
- ...edges.map((edge) => edge.trailId),
343
- ]);
344
-
345
- return {
346
- overview: {
347
- chainCount: chains.length,
348
- chains,
349
- edgeCount: edges.length,
350
- edges,
351
- signalIds: [...signalRelations.keys()].toSorted(),
352
- sourceCount: sources.length,
353
- sourceKeys: sources.map((source) => source.key),
354
- trailIds: activeTrailIds,
355
- },
356
- signals: new Map(
357
- [...signalRelations.entries()].map(([id, relations]) => [
358
- id,
359
- {
360
- consumers: sortedUnique(relations.consumers),
361
- producers: sortedUnique(relations.producers),
362
- },
363
- ])
364
- ),
365
- sources: new Map(sources.map((source) => [source.key, source])),
366
- trails: new Map(
367
- [...trailActivations.entries()].map(([id, activation]) => [
368
- id,
369
- {
370
- activatedBy: sortedUnique(activation.activatedBy),
371
- activates: sortedUnique(activation.activates),
372
- chains: activation.chains.toSorted(compareChains),
373
- edges: edges.filter((edge) => edge.trailId === id),
374
- fires: activation.fires,
375
- on: activation.on,
376
- sources: sources.filter((source) =>
377
- edges.some(
378
- (edge) => edge.trailId === id && edge.sourceKey === source.key
379
- )
380
- ),
381
- },
382
- ])
383
- ),
384
- };
385
- };
1
+ export {
2
+ deriveActivationGraph,
3
+ deriveDeclaredTrailActivation,
4
+ deriveSignalActivationRelations,
5
+ } from '@ontrails/topographer';
6
+ export type {
7
+ ActivationChainReport,
8
+ ActivationEdgeReport,
9
+ ActivationGraphReport,
10
+ ActivationOverviewReport,
11
+ ActivationSourceReport,
12
+ SignalActivationRelations,
13
+ TrailActivationReport,
14
+ } from '@ontrails/topographer';