@saptools/service-flow 0.1.65 → 0.1.67
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 +16 -0
- package/README.md +67 -11
- package/TECHNICAL-NOTE.md +41 -1
- package/dist/{chunk-OONNRIDL.js → chunk-ZQABU7MR.js} +3764 -643
- package/dist/chunk-ZQABU7MR.js.map +1 -0
- package/dist/cli.js +158 -295
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +196 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/002-doctor-lifecycle.ts +66 -0
- package/src/cli/doctor.ts +14 -27
- package/src/cli.ts +130 -102
- package/src/db/000-call-fact-repository.ts +537 -0
- package/src/db/001-fact-lifecycle.ts +111 -0
- package/src/db/migrations.ts +16 -1
- package/src/db/repositories.ts +1 -315
- package/src/db/schema.ts +4 -2
- package/src/index.ts +22 -0
- package/src/linker/004-event-subscription-handler-linker.ts +300 -0
- package/src/linker/cross-repo-linker.ts +23 -2
- package/src/output/001-compact-json-output.ts +6 -0
- package/src/parsers/imported-wrapper-parser.ts +4 -0
- package/src/parsers/outbound-call-parser.ts +11 -1
- package/src/parsers/symbol-parser.ts +7 -4
- package/src/trace/010-traversal-scope.ts +188 -0
- package/src/trace/011-event-subscriber-traversal.ts +366 -0
- package/src/trace/012-trace-graph-lookups.ts +74 -0
- package/src/trace/013-trace-root-scopes.ts +279 -0
- package/src/trace/014-compact-contract.ts +347 -0
- package/src/trace/015-trace-edge-recorder.ts +336 -0
- package/src/trace/016-compact-projector.ts +697 -0
- package/src/trace/017-trace-context.ts +378 -0
- package/src/trace/018-compact-trace.ts +87 -0
- package/src/trace/019-trace-edge-semantics.ts +328 -0
- package/src/trace/020-compact-field-projection.ts +387 -0
- package/src/trace/dynamic-branches.ts +35 -13
- package/src/trace/trace-engine.ts +271 -245
- package/src/types.ts +10 -0
- package/src/version.ts +1 -1
- package/dist/chunk-OONNRIDL.js.map +0 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import type { Db } from '../db/connection.js';
|
|
2
|
+
import { currentFactLifecycleDiagnostic } from '../db/001-fact-lifecycle.js';
|
|
3
|
+
import type { ContextBinding } from './008-contextual-runtime-state.js';
|
|
4
|
+
import {
|
|
5
|
+
resolveTraversalWorkspaceId,
|
|
6
|
+
type TraversalScopeScheduler,
|
|
7
|
+
type TraversalScopeState,
|
|
8
|
+
} from './010-traversal-scope.js';
|
|
9
|
+
|
|
10
|
+
export interface TraceQueueScope {
|
|
11
|
+
repoId?: number;
|
|
12
|
+
files?: Set<string>;
|
|
13
|
+
symbolIds?: Set<number>;
|
|
14
|
+
depth: number;
|
|
15
|
+
context: Map<string, ContextBinding>;
|
|
16
|
+
state: TraversalScopeState;
|
|
17
|
+
unownedOnly?: boolean;
|
|
18
|
+
rootObservationOnly?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface PendingTraceRootScope {
|
|
22
|
+
repoId: number;
|
|
23
|
+
files: Set<string>;
|
|
24
|
+
symbolIds: Set<number>;
|
|
25
|
+
unownedOnly: boolean;
|
|
26
|
+
rootObservationOnly: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface RootCallRow {
|
|
30
|
+
id: number;
|
|
31
|
+
repoId: number;
|
|
32
|
+
repoName: string;
|
|
33
|
+
workspaceId: number;
|
|
34
|
+
graphGeneration: number;
|
|
35
|
+
sourceSymbolId?: number | null;
|
|
36
|
+
sourceFile: string;
|
|
37
|
+
callType: string;
|
|
38
|
+
eventName?: string | null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface TraceRootPlan {
|
|
42
|
+
workspaceId?: number;
|
|
43
|
+
queue: TraceQueueScope[];
|
|
44
|
+
pendingRoots: PendingTraceRootScope[];
|
|
45
|
+
diagnostic?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createTraceRootPlan(
|
|
49
|
+
db: Db,
|
|
50
|
+
scheduler: TraversalScopeScheduler,
|
|
51
|
+
scope: {
|
|
52
|
+
repoId?: number;
|
|
53
|
+
files?: Set<string>;
|
|
54
|
+
symbolIds?: Set<number>;
|
|
55
|
+
selectorMatched: boolean;
|
|
56
|
+
},
|
|
57
|
+
requestedWorkspaceId: number | undefined,
|
|
58
|
+
includeAsync: boolean,
|
|
59
|
+
): TraceRootPlan {
|
|
60
|
+
const workspaceId = resolveTraversalWorkspaceId(
|
|
61
|
+
db, requestedWorkspaceId, scope.repoId,
|
|
62
|
+
);
|
|
63
|
+
if (workspaceId !== undefined) {
|
|
64
|
+
const lifecycle = currentFactLifecycleDiagnostic(db, workspaceId);
|
|
65
|
+
if (lifecycle) return {
|
|
66
|
+
workspaceId, queue: [], pendingRoots: [], diagnostic: lifecycle,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!scope.selectorMatched)
|
|
70
|
+
return { workspaceId, queue: [], pendingRoots: [] };
|
|
71
|
+
if (workspaceId === undefined) return {
|
|
72
|
+
workspaceId, queue: [], pendingRoots: [],
|
|
73
|
+
diagnostic: workspaceAmbiguityDiagnostic(db),
|
|
74
|
+
};
|
|
75
|
+
const pendingRoots = includeAsync
|
|
76
|
+
? rootScopes(db, workspaceId, scope) : undefined;
|
|
77
|
+
if (pendingRoots)
|
|
78
|
+
return { workspaceId, queue: [], pendingRoots };
|
|
79
|
+
return {
|
|
80
|
+
workspaceId,
|
|
81
|
+
queue: initialQueue(scheduler, workspaceId, scope),
|
|
82
|
+
pendingRoots: [],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function nextPendingRoot(
|
|
87
|
+
pendingRoots: PendingTraceRootScope[],
|
|
88
|
+
scheduler: TraversalScopeScheduler,
|
|
89
|
+
workspaceId: number,
|
|
90
|
+
): TraceQueueScope | undefined {
|
|
91
|
+
while (pendingRoots.length > 0) {
|
|
92
|
+
const root = pendingRoots.shift();
|
|
93
|
+
if (!root) return undefined;
|
|
94
|
+
const context = new Map<string, ContextBinding>();
|
|
95
|
+
const scheduled = scheduler.schedule({
|
|
96
|
+
workspaceId, repoId: root.repoId, files: root.files,
|
|
97
|
+
symbolIds: root.symbolIds, context,
|
|
98
|
+
});
|
|
99
|
+
if (scheduled.kind !== 'scheduled') continue;
|
|
100
|
+
return { ...root, depth: 1, context, state: scheduled.state };
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function claimPendingRoot(
|
|
106
|
+
pendingRoots: PendingTraceRootScope[],
|
|
107
|
+
target: {
|
|
108
|
+
repoId?: number;
|
|
109
|
+
files: ReadonlySet<string>;
|
|
110
|
+
symbolIds: ReadonlySet<number>;
|
|
111
|
+
},
|
|
112
|
+
): boolean {
|
|
113
|
+
const index = pendingRoots.findIndex((root) =>
|
|
114
|
+
target.repoId === root.repoId
|
|
115
|
+
&& !root.unownedOnly
|
|
116
|
+
&& setsEqual(root.files, target.files)
|
|
117
|
+
&& setsEqual(root.symbolIds, target.symbolIds));
|
|
118
|
+
if (index < 0) return false;
|
|
119
|
+
pendingRoots.splice(index, 1);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function enqueueCausalScope(
|
|
124
|
+
queue: TraceQueueScope[],
|
|
125
|
+
pendingRoots: PendingTraceRootScope[],
|
|
126
|
+
scope: TraceQueueScope,
|
|
127
|
+
): void {
|
|
128
|
+
if (scope.context.size === 0 && scope.files && scope.symbolIds)
|
|
129
|
+
claimPendingRoot(pendingRoots, {
|
|
130
|
+
repoId: scope.repoId, files: scope.files, symbolIds: scope.symbolIds,
|
|
131
|
+
});
|
|
132
|
+
queue.push(scope);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function initialQueue(
|
|
136
|
+
scheduler: TraversalScopeScheduler,
|
|
137
|
+
workspaceId: number,
|
|
138
|
+
scope: { repoId?: number; files?: Set<string>; symbolIds?: Set<number> },
|
|
139
|
+
): TraceQueueScope[] {
|
|
140
|
+
const context = new Map<string, ContextBinding>();
|
|
141
|
+
const scheduled = scheduler.schedule({
|
|
142
|
+
workspaceId, repoId: scope.repoId, files: scope.files,
|
|
143
|
+
symbolIds: scope.symbolIds, context,
|
|
144
|
+
});
|
|
145
|
+
return scheduled.kind === 'scheduled' ? [{
|
|
146
|
+
repoId: scope.repoId, files: scope.files, symbolIds: scope.symbolIds,
|
|
147
|
+
depth: 1, context, state: scheduled.state,
|
|
148
|
+
}] : [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function rootScopes(
|
|
152
|
+
db: Db,
|
|
153
|
+
workspaceId: number,
|
|
154
|
+
scope: { repoId?: number; files?: Set<string>; symbolIds?: Set<number> },
|
|
155
|
+
): PendingTraceRootScope[] | undefined {
|
|
156
|
+
if (scope.symbolIds && scope.symbolIds.size === 1) return undefined;
|
|
157
|
+
const calls = scopedRootCalls(db, workspaceId, scope);
|
|
158
|
+
if (!hasExactDispatch(db, calls)) return undefined;
|
|
159
|
+
if (scope.symbolIds && scope.symbolIds.size > 1)
|
|
160
|
+
return selectedSymbolRoots(db, workspaceId, scope.symbolIds);
|
|
161
|
+
return callOwnerRoots(calls);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function scopedRootCalls(
|
|
165
|
+
db: Db,
|
|
166
|
+
workspaceId: number,
|
|
167
|
+
scope: { repoId?: number; files?: Set<string>; symbolIds?: Set<number> },
|
|
168
|
+
): RootCallRow[] {
|
|
169
|
+
return rootCalls(db, workspaceId, scope.repoId, scope.files)
|
|
170
|
+
.filter((call) => !scope.symbolIds
|
|
171
|
+
|| (typeof call.sourceSymbolId === 'number'
|
|
172
|
+
&& scope.symbolIds.has(call.sourceSymbolId)));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function callOwnerRoots(
|
|
176
|
+
calls: RootCallRow[],
|
|
177
|
+
): PendingTraceRootScope[] | undefined {
|
|
178
|
+
const roots = new Map<string, PendingTraceRootScope>();
|
|
179
|
+
for (const call of calls) {
|
|
180
|
+
const [key, root] = callOwnerRoot(call);
|
|
181
|
+
if (roots.has(key)) continue;
|
|
182
|
+
roots.set(key, root);
|
|
183
|
+
}
|
|
184
|
+
return roots.size > 0 ? [...roots.values()] : undefined;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function callOwnerRoot(
|
|
188
|
+
call: RootCallRow,
|
|
189
|
+
): [string, PendingTraceRootScope] {
|
|
190
|
+
const symbolId = call.sourceSymbolId;
|
|
191
|
+
const owned = typeof symbolId === 'number';
|
|
192
|
+
const key = owned
|
|
193
|
+
? `symbol:${symbolId}` : `unowned:${call.repoId}:${call.sourceFile}`;
|
|
194
|
+
return [key, {
|
|
195
|
+
repoId: call.repoId,
|
|
196
|
+
files: new Set([call.sourceFile]),
|
|
197
|
+
symbolIds: owned ? new Set([symbolId]) : new Set(),
|
|
198
|
+
unownedOnly: !owned,
|
|
199
|
+
rootObservationOnly: true,
|
|
200
|
+
}];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function selectedSymbolRoots(
|
|
204
|
+
db: Db,
|
|
205
|
+
workspaceId: number,
|
|
206
|
+
symbolIds: Set<number>,
|
|
207
|
+
): PendingTraceRootScope[] {
|
|
208
|
+
const ids = [...symbolIds];
|
|
209
|
+
const rows = db.prepare(`SELECT s.id,s.repo_id repoId,s.source_file sourceFile
|
|
210
|
+
FROM symbols s JOIN repositories r ON r.id=s.repo_id
|
|
211
|
+
WHERE r.workspace_id=? AND s.id IN (${ids.map(() => '?').join(',')})
|
|
212
|
+
ORDER BY r.name COLLATE BINARY,r.id,s.source_file COLLATE BINARY,
|
|
213
|
+
s.start_offset,s.end_offset,s.id`).all(workspaceId, ...ids);
|
|
214
|
+
return rows.flatMap((row) => typeof row.id === 'number'
|
|
215
|
+
&& typeof row.repoId === 'number' && typeof row.sourceFile === 'string'
|
|
216
|
+
? [{ repoId: row.repoId, files: new Set([row.sourceFile]),
|
|
217
|
+
symbolIds: new Set([row.id]), unownedOnly: false,
|
|
218
|
+
rootObservationOnly: false }]
|
|
219
|
+
: []);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function setsEqual<T>(left: ReadonlySet<T>, right: ReadonlySet<T>): boolean {
|
|
223
|
+
if (left.size !== right.size) return false;
|
|
224
|
+
return [...left].every((value) => right.has(value));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function rootCalls(
|
|
228
|
+
db: Db,
|
|
229
|
+
workspaceId: number,
|
|
230
|
+
repoId: number | undefined,
|
|
231
|
+
files: Set<string> | undefined,
|
|
232
|
+
): RootCallRow[] {
|
|
233
|
+
const rows = db.prepare(`SELECT c.id,c.repo_id repoId,r.name repoName,
|
|
234
|
+
r.workspace_id workspaceId,r.graph_generation graphGeneration,
|
|
235
|
+
c.source_symbol_id sourceSymbolId,c.source_file sourceFile,
|
|
236
|
+
c.call_type callType,c.event_name_expr eventName
|
|
237
|
+
FROM outbound_calls c JOIN repositories r ON r.id=c.repo_id
|
|
238
|
+
WHERE r.workspace_id=? AND (? IS NULL OR c.repo_id=?)
|
|
239
|
+
ORDER BY r.name COLLATE BINARY,r.id,c.source_file COLLATE BINARY,
|
|
240
|
+
c.call_site_start_offset,c.call_site_end_offset,c.source_line,c.id`).all(
|
|
241
|
+
workspaceId, repoId, repoId,
|
|
242
|
+
) as unknown as RootCallRow[];
|
|
243
|
+
return files ? rows.filter((row) => files.has(row.sourceFile)) : rows;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function hasExactDispatch(db: Db, calls: RootCallRow[]): boolean {
|
|
247
|
+
const match = db.prepare(`SELECT 1 matched FROM graph_edges emitted
|
|
248
|
+
WHERE emitted.workspace_id=? AND emitted.generation=?
|
|
249
|
+
AND emitted.edge_type='HANDLER_EMITS_EVENT'
|
|
250
|
+
AND emitted.from_kind='call' AND emitted.from_id=?
|
|
251
|
+
AND EXISTS (SELECT 1 FROM graph_edges subscriber
|
|
252
|
+
WHERE subscriber.workspace_id=emitted.workspace_id
|
|
253
|
+
AND subscriber.generation=emitted.generation
|
|
254
|
+
AND subscriber.edge_type='EVENT_SUBSCRIPTION_HANDLED_BY'
|
|
255
|
+
AND subscriber.from_kind='event'
|
|
256
|
+
AND subscriber.from_id COLLATE BINARY=? COLLATE BINARY)
|
|
257
|
+
LIMIT 1`);
|
|
258
|
+
return calls.some((call) => call.callType === 'async_emit'
|
|
259
|
+
&& typeof call.eventName === 'string'
|
|
260
|
+
&& Boolean(match.get(call.workspaceId, call.graphGeneration,
|
|
261
|
+
String(call.id), call.eventName)));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function workspaceAmbiguityDiagnostic(db: Db): Record<string, unknown> {
|
|
265
|
+
const total = Number(db.prepare(`SELECT COUNT(DISTINCT w.id) count
|
|
266
|
+
FROM workspaces w JOIN repositories r ON r.workspace_id=w.id`).get()?.count ?? 0);
|
|
267
|
+
const workspaceIds = db.prepare(`SELECT DISTINCT w.id FROM workspaces w
|
|
268
|
+
JOIN repositories r ON r.workspace_id=w.id ORDER BY w.id LIMIT 5`).all()
|
|
269
|
+
.flatMap((row) => typeof row.id === 'number' ? [row.id] : []);
|
|
270
|
+
return {
|
|
271
|
+
severity: 'error', code: 'trace_workspace_ambiguous',
|
|
272
|
+
message: total > 1
|
|
273
|
+
? 'Trace spans multiple indexed workspaces; provide a workspace identity.'
|
|
274
|
+
: 'No indexed workspace could be selected for this trace.',
|
|
275
|
+
workspaceCount: total, workspaceIds,
|
|
276
|
+
omittedWorkspaceCount: Math.max(0, total - workspaceIds.length),
|
|
277
|
+
remediation: 'Pass TraceOptions.workspaceId or select a repository in one workspace.',
|
|
278
|
+
};
|
|
279
|
+
}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import type { Db } from '../db/connection.js';
|
|
2
|
+
import type {
|
|
3
|
+
DynamicMode,
|
|
4
|
+
TraceOptions,
|
|
5
|
+
TraceResult,
|
|
6
|
+
TraceStart,
|
|
7
|
+
} from '../types.js';
|
|
8
|
+
|
|
9
|
+
export type CompactStatus =
|
|
10
|
+
| 'resolved'
|
|
11
|
+
| 'terminal'
|
|
12
|
+
| 'inferred'
|
|
13
|
+
| 'dynamic'
|
|
14
|
+
| 'ambiguous'
|
|
15
|
+
| 'unresolved'
|
|
16
|
+
| 'cycle';
|
|
17
|
+
|
|
18
|
+
export type CompactEndpointSide = 'source' | 'target';
|
|
19
|
+
|
|
20
|
+
export type CompactSemanticEndpoint =
|
|
21
|
+
| { kind: 'operation'; operationId: number }
|
|
22
|
+
| { kind: 'symbol'; symbolId: number }
|
|
23
|
+
| { kind: 'handler_method'; handlerMethodId: number }
|
|
24
|
+
| { kind: 'event'; workspaceId: number; eventName: string }
|
|
25
|
+
| {
|
|
26
|
+
kind: 'target';
|
|
27
|
+
workspaceId: number;
|
|
28
|
+
repositoryId?: number;
|
|
29
|
+
targetKind: string;
|
|
30
|
+
targetId: string;
|
|
31
|
+
}
|
|
32
|
+
| {
|
|
33
|
+
kind: 'call_site';
|
|
34
|
+
workspaceId: number;
|
|
35
|
+
repositoryId: number;
|
|
36
|
+
repositoryName: string;
|
|
37
|
+
sourceFile: string;
|
|
38
|
+
sourceLine: number;
|
|
39
|
+
startOffset?: number;
|
|
40
|
+
endOffset?: number;
|
|
41
|
+
callId: number;
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
kind: 'scope';
|
|
45
|
+
workspaceId: number;
|
|
46
|
+
repositoryId?: number;
|
|
47
|
+
sourceFiles: string[];
|
|
48
|
+
symbolIds: number[];
|
|
49
|
+
structuralKey: string;
|
|
50
|
+
}
|
|
51
|
+
| {
|
|
52
|
+
kind: 'unavailable';
|
|
53
|
+
side: CompactEndpointSide;
|
|
54
|
+
endpointKind: string;
|
|
55
|
+
detailedEdgeIndex: number;
|
|
56
|
+
site?: CompactSourceSite;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type CompactRemediationCode =
|
|
60
|
+
| 'provide_runtime_variables'
|
|
61
|
+
| 'select_implementation'
|
|
62
|
+
| 'reindex_and_link'
|
|
63
|
+
| 'inspect_detailed_edge';
|
|
64
|
+
|
|
65
|
+
export interface CompactDecisionTargetInput {
|
|
66
|
+
kind: string;
|
|
67
|
+
id: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface CompactDecisionInput {
|
|
71
|
+
effectiveResolutionStatus?: string;
|
|
72
|
+
effectiveTarget?: CompactDecisionTargetInput;
|
|
73
|
+
persistedResolutionStatus?: string;
|
|
74
|
+
persistedTarget?: CompactDecisionTargetInput;
|
|
75
|
+
missingVariableNames?: string[];
|
|
76
|
+
missingVariableCount?: number;
|
|
77
|
+
dynamicMode?: DynamicMode;
|
|
78
|
+
candidateCount?: number;
|
|
79
|
+
viableCandidateCount?: number;
|
|
80
|
+
rejectedCandidateCount?: number;
|
|
81
|
+
omittedCandidateCount?: number;
|
|
82
|
+
implementationStrategy?: string;
|
|
83
|
+
implementationGuided?: boolean;
|
|
84
|
+
implementationContextual?: boolean;
|
|
85
|
+
reasonCode?: string;
|
|
86
|
+
eventMatchStrategy?: string;
|
|
87
|
+
dispatchCertainty?: string;
|
|
88
|
+
eventSubscriptionCount?: number;
|
|
89
|
+
associationStatus?: string;
|
|
90
|
+
associationBasis?: string;
|
|
91
|
+
eventScope?: string;
|
|
92
|
+
callRole?: string;
|
|
93
|
+
factOrigin?: string;
|
|
94
|
+
roleSiteMatchCount?: number;
|
|
95
|
+
bodyExpansion?: string;
|
|
96
|
+
remediationCode?: CompactRemediationCode;
|
|
97
|
+
remediationHintCount?: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface CompactReferenceInput {
|
|
101
|
+
graphEdgeIds?: Array<number | string>;
|
|
102
|
+
outboundCallIds?: Array<number | string>;
|
|
103
|
+
subscribeCallIds?: Array<number | string>;
|
|
104
|
+
symbolCallIds?: Array<number | string>;
|
|
105
|
+
operationIds?: Array<number | string>;
|
|
106
|
+
symbolIds?: Array<number | string>;
|
|
107
|
+
handlerMethodIds?: Array<number | string>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface CompactSourceSite {
|
|
111
|
+
repository?: string;
|
|
112
|
+
sourceFile?: string;
|
|
113
|
+
sourceLine?: number;
|
|
114
|
+
startOffset?: number;
|
|
115
|
+
endOffset?: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface CompactEdgeObservation {
|
|
119
|
+
ordinal: number;
|
|
120
|
+
step: number;
|
|
121
|
+
type: string;
|
|
122
|
+
source: CompactSemanticEndpoint;
|
|
123
|
+
target: CompactSemanticEndpoint;
|
|
124
|
+
status: CompactStatus;
|
|
125
|
+
confidence: number;
|
|
126
|
+
decision?: CompactDecisionInput;
|
|
127
|
+
refs?: CompactReferenceInput;
|
|
128
|
+
site?: CompactSourceSite;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface CompactTraceObserver {
|
|
132
|
+
record(observation: CompactEdgeObservation): void;
|
|
133
|
+
setWorkspaceId?(workspaceId: number | undefined): void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export class CompactObservationCollector implements CompactTraceObserver {
|
|
137
|
+
readonly observations: CompactEdgeObservation[] = [];
|
|
138
|
+
workspaceId?: number;
|
|
139
|
+
|
|
140
|
+
record(observation: CompactEdgeObservation): void {
|
|
141
|
+
this.observations.push(observation);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
setWorkspaceId(workspaceId: number | undefined): void {
|
|
145
|
+
this.workspaceId = workspaceId;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface CompactSourceContext {
|
|
150
|
+
schemaVersion: number;
|
|
151
|
+
analyzerVersion: string;
|
|
152
|
+
graphGeneration: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface CompactProjectionInput {
|
|
156
|
+
db: Db;
|
|
157
|
+
start: TraceStart;
|
|
158
|
+
options: TraceOptions;
|
|
159
|
+
source: CompactSourceContext;
|
|
160
|
+
trace: TraceResult;
|
|
161
|
+
observations: CompactEdgeObservation[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface CompactHintV1 {
|
|
165
|
+
servicePath: string | null;
|
|
166
|
+
operationPath: string | null;
|
|
167
|
+
packageName: string | null;
|
|
168
|
+
repositoryName: string | null;
|
|
169
|
+
candidateFamily: string | null;
|
|
170
|
+
implementationRepo: string | null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface CompactStartV1 {
|
|
174
|
+
repo: string | null;
|
|
175
|
+
servicePath: string | null;
|
|
176
|
+
operation: string | null;
|
|
177
|
+
operationPath: string | null;
|
|
178
|
+
handler: string | null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface CompactQueryV1 {
|
|
182
|
+
depth: number;
|
|
183
|
+
includeAsync: boolean;
|
|
184
|
+
includeDb: boolean;
|
|
185
|
+
includeExternal: boolean;
|
|
186
|
+
dynamicMode: DynamicMode;
|
|
187
|
+
maxDynamicCandidates: number;
|
|
188
|
+
suppliedVariableNames: string[];
|
|
189
|
+
runtimeValuesOmitted: true;
|
|
190
|
+
implementationRepo: string | null;
|
|
191
|
+
implementationHints: CompactHintV1[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface CompactReferenceGroupV1 {
|
|
195
|
+
values: Array<number | string>;
|
|
196
|
+
total: number;
|
|
197
|
+
shown: number;
|
|
198
|
+
omitted: number;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface CompactReferencesV1 {
|
|
202
|
+
graphEdgeIds?: CompactReferenceGroupV1;
|
|
203
|
+
outboundCallIds?: CompactReferenceGroupV1;
|
|
204
|
+
subscribeCallIds?: CompactReferenceGroupV1;
|
|
205
|
+
symbolCallIds?: CompactReferenceGroupV1;
|
|
206
|
+
operationIds?: CompactReferenceGroupV1;
|
|
207
|
+
symbolIds?: CompactReferenceGroupV1;
|
|
208
|
+
handlerMethodIds?: CompactReferenceGroupV1;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface CompactDecisionV1 {
|
|
212
|
+
effectiveResolutionStatus?: string;
|
|
213
|
+
effectiveTarget?: string;
|
|
214
|
+
persistedResolutionStatus?: string;
|
|
215
|
+
persistedTarget?: string;
|
|
216
|
+
missingVariableNames?: string[];
|
|
217
|
+
missingVariableCount?: number;
|
|
218
|
+
shownMissingVariableCount?: number;
|
|
219
|
+
omittedMissingVariableCount?: number;
|
|
220
|
+
dynamicMode?: DynamicMode;
|
|
221
|
+
candidateCount?: number;
|
|
222
|
+
viableCandidateCount?: number;
|
|
223
|
+
rejectedCandidateCount?: number;
|
|
224
|
+
omittedCandidateCount?: number;
|
|
225
|
+
implementationStrategy?: string;
|
|
226
|
+
implementationGuided?: boolean;
|
|
227
|
+
implementationContextual?: boolean;
|
|
228
|
+
eventMatchStrategy?: string;
|
|
229
|
+
dispatchCertainty?: string;
|
|
230
|
+
eventSubscriptionCount?: number;
|
|
231
|
+
associationStatus?: string;
|
|
232
|
+
associationBasis?: string;
|
|
233
|
+
eventScope?: string;
|
|
234
|
+
callRole?: string;
|
|
235
|
+
factOrigin?: string;
|
|
236
|
+
roleSiteMatchCount?: number;
|
|
237
|
+
bodyExpansion?: string;
|
|
238
|
+
reasonCode?: string;
|
|
239
|
+
remediationHint?: string;
|
|
240
|
+
omittedRemediationHintCount?: number;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface CompactEdgeDetailsV1 {
|
|
244
|
+
decision: CompactDecisionV1;
|
|
245
|
+
refs: CompactReferencesV1;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface CompactDiagnosticDetailsV1 {
|
|
249
|
+
reasonCode?: string;
|
|
250
|
+
missingVariableNames?: string[];
|
|
251
|
+
missingVariableCount?: number;
|
|
252
|
+
shownMissingVariableCount?: number;
|
|
253
|
+
omittedMissingVariableCount?: number;
|
|
254
|
+
candidateCount?: number;
|
|
255
|
+
viableCandidateCount?: number;
|
|
256
|
+
rejectedCandidateCount?: number;
|
|
257
|
+
remediationHint?: string;
|
|
258
|
+
omittedHintCount?: number;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface CompactProjectedDiagnostic {
|
|
262
|
+
index: number;
|
|
263
|
+
severity: 'error' | 'warning' | 'info';
|
|
264
|
+
code: string;
|
|
265
|
+
message: string;
|
|
266
|
+
file?: string;
|
|
267
|
+
line?: number;
|
|
268
|
+
details?: CompactDiagnosticDetailsV1;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export type CompactNodeRowV1 = [
|
|
272
|
+
id: string,
|
|
273
|
+
kind: string,
|
|
274
|
+
label: string,
|
|
275
|
+
repo: number | null,
|
|
276
|
+
file: number | null,
|
|
277
|
+
line: number | null,
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
export type CompactEdgeRowV1 = [
|
|
281
|
+
id: string,
|
|
282
|
+
traceOrdinals: number[],
|
|
283
|
+
step: number,
|
|
284
|
+
type: string,
|
|
285
|
+
from: string,
|
|
286
|
+
to: string,
|
|
287
|
+
status: CompactStatus,
|
|
288
|
+
confidence: number,
|
|
289
|
+
count: number,
|
|
290
|
+
details: CompactEdgeDetailsV1 | null,
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
export type CompactDiagnosticRowV1 = [
|
|
294
|
+
fullDiagnosticIndex: number,
|
|
295
|
+
severity: 'error' | 'warning' | 'info',
|
|
296
|
+
code: string,
|
|
297
|
+
message: string,
|
|
298
|
+
file: number | null,
|
|
299
|
+
line: number | null,
|
|
300
|
+
details: CompactDiagnosticDetailsV1 | null,
|
|
301
|
+
];
|
|
302
|
+
|
|
303
|
+
export interface CompactStatusCountsV1 {
|
|
304
|
+
resolved: number;
|
|
305
|
+
terminal: number;
|
|
306
|
+
inferred: number;
|
|
307
|
+
dynamic: number;
|
|
308
|
+
ambiguous: number;
|
|
309
|
+
unresolved: number;
|
|
310
|
+
cycle: number;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export interface CompactGraphV1 {
|
|
314
|
+
schema: 'service-flow/compact-graph@1';
|
|
315
|
+
start: CompactStartV1;
|
|
316
|
+
query: CompactQueryV1;
|
|
317
|
+
source: CompactSourceContext;
|
|
318
|
+
summary: {
|
|
319
|
+
completeness: 'complete' | 'partial' | 'blocked';
|
|
320
|
+
fullTraceNodes: number;
|
|
321
|
+
fullTraceEdges: number;
|
|
322
|
+
fullTraceDiagnostics: number;
|
|
323
|
+
nodes: number;
|
|
324
|
+
edges: number;
|
|
325
|
+
collapsedEdges: number;
|
|
326
|
+
statusCounts: CompactStatusCountsV1;
|
|
327
|
+
projection: {
|
|
328
|
+
evidence: 'summary-only';
|
|
329
|
+
syntheticEndpoints: number;
|
|
330
|
+
omittedUnreferencedFullNodes: number;
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
repos: string[];
|
|
334
|
+
files: string[];
|
|
335
|
+
nodeColumns: ['id', 'kind', 'label', 'repo', 'file', 'line'];
|
|
336
|
+
nodes: CompactNodeRowV1[];
|
|
337
|
+
edgeColumns: [
|
|
338
|
+
'id', 'traceOrdinals', 'step', 'type', 'from', 'to',
|
|
339
|
+
'status', 'confidence', 'count', 'details',
|
|
340
|
+
];
|
|
341
|
+
edges: CompactEdgeRowV1[];
|
|
342
|
+
diagnosticColumns: [
|
|
343
|
+
'fullDiagnosticIndex', 'severity', 'code', 'message',
|
|
344
|
+
'file', 'line', 'details',
|
|
345
|
+
];
|
|
346
|
+
diagnostics: CompactDiagnosticRowV1[];
|
|
347
|
+
}
|