@saptools/service-flow 0.1.67 → 0.1.68
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 +10 -0
- package/README.md +20 -8
- package/TECHNICAL-NOTE.md +27 -0
- package/dist/{chunk-ZQABU7MR.js → chunk-AEM4JY22.js} +12676 -6714
- package/dist/chunk-AEM4JY22.js.map +1 -0
- package/dist/cli.js +2325 -413
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +61 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/003-doctor-package-resolution.ts +68 -0
- package/src/cli/doctor.ts +25 -14
- package/src/db/000-call-fact-repository.ts +475 -342
- package/src/db/001-fact-lifecycle.ts +60 -30
- package/src/db/002-fact-json-inventory.ts +169 -0
- package/src/db/003-current-fact-semantics.ts +698 -0
- package/src/db/004-package-target-invalidation.ts +173 -0
- package/src/db/005-schema-structure.ts +201 -0
- package/src/db/006-relative-symbol-resolution.ts +443 -0
- package/src/db/007-package-fact-semantics.ts +573 -0
- package/src/db/008-relative-fact-semantics.ts +207 -0
- package/src/db/009-binding-fact-semantics.ts +347 -0
- package/src/db/010-package-symbol-surface-semantics.ts +320 -0
- package/src/db/011-symbol-call-semantics.ts +144 -0
- package/src/db/012-binding-reference-proof.ts +264 -0
- package/src/db/migrations.ts +16 -3
- package/src/db/repositories.ts +113 -6
- package/src/db/schema.ts +4 -2
- package/src/index.ts +12 -0
- package/src/indexer/repository-indexer.ts +72 -11
- package/src/indexer/workspace-indexer.ts +123 -32
- package/src/linker/003-package-import-symbol-resolver.ts +363 -131
- package/src/linker/004-event-subscription-handler-linker.ts +2 -0
- package/src/linker/005-odata-path-structure.ts +371 -0
- package/src/linker/cross-repo-linker.ts +2 -1
- package/src/linker/odata-path-normalizer.ts +273 -180
- package/src/linker/service-resolver.ts +197 -77
- package/src/parsers/002-symbol-import-bindings.ts +516 -0
- package/src/parsers/003-package-public-surface.ts +661 -0
- package/src/parsers/004-fact-identity.ts +108 -0
- package/src/parsers/005-event-subscription-facts.ts +281 -0
- package/src/parsers/006-binding-identity.ts +343 -0
- package/src/parsers/007-source-fact-reconciliation.ts +105 -0
- package/src/parsers/008-package-surface-publication.ts +82 -0
- package/src/parsers/009-symbol-call-facts.ts +528 -0
- package/src/parsers/010-package-public-surface-analysis.ts +352 -0
- package/src/parsers/011-binding-lexical-scope.ts +583 -0
- package/src/parsers/012-package-fact-contract.ts +306 -0
- package/src/parsers/013-executable-body-eligibility.ts +35 -0
- package/src/parsers/014-service-binding-helper-flow.ts +240 -0
- package/src/parsers/015-service-binding-collector.ts +693 -0
- package/src/parsers/016-local-symbol-reference.ts +261 -0
- package/src/parsers/017-symbol-derived-contexts.ts +268 -0
- package/src/parsers/018-package-commonjs-syntax.ts +142 -0
- package/src/parsers/019-binding-assignment-targets.ts +76 -0
- package/src/parsers/020-stable-local-value.ts +217 -0
- package/src/parsers/021-binding-visibility.ts +152 -0
- package/src/parsers/operation-path-analysis.ts +6 -1
- package/src/parsers/outbound-call-parser.ts +19 -6
- package/src/parsers/package-json-parser.ts +45 -3
- package/src/parsers/service-binding-parser-helpers.ts +86 -15
- package/src/parsers/service-binding-parser.ts +147 -597
- package/src/parsers/symbol-parser.ts +482 -353
- package/src/trace/002-trace-diagnostics.ts +36 -1
- package/src/trace/016-compact-projector.ts +16 -17
- package/src/trace/020-compact-field-projection.ts +48 -37
- package/src/trace/021-compact-decision-normalization.ts +105 -0
- package/src/trace/022-trace-fact-preflight.ts +21 -0
- package/src/trace/023-nested-event-scopes.ts +23 -0
- package/src/trace/024-compact-observation-decision.ts +76 -0
- package/src/trace/025-trace-implementation-scope.ts +123 -0
- package/src/trace/026-trace-start-scope.ts +335 -0
- package/src/trace/027-trace-scope-execution.ts +566 -0
- package/src/trace/028-trace-operation-execution.ts +336 -0
- package/src/trace/029-trace-start-implementation.ts +172 -0
- package/src/trace/trace-engine.ts +122 -624
- package/src/types.ts +56 -0
- package/src/utils/001-placeholders.ts +188 -10
- package/src/version.ts +1 -1
- package/dist/chunk-ZQABU7MR.js.map +0 -1
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import type { Db } from '../db/connection.js';
|
|
2
|
+
import type { TraceEdge } from '../types.js';
|
|
3
|
+
import { implementationHintDiagnostic } from './implementation-hints.js';
|
|
4
|
+
import { contextualImplementationSelection } from './005-implementation-selection.js';
|
|
5
|
+
import type { ContextBinding } from './008-contextual-runtime-state.js';
|
|
6
|
+
import {
|
|
7
|
+
handlerMethodNode,
|
|
8
|
+
withSelectedHandlerProvenance,
|
|
9
|
+
type SelectedHandlerEvidence,
|
|
10
|
+
} from './009-selected-handler-provenance.js';
|
|
11
|
+
import type { TraversalScopeState } from './010-traversal-scope.js';
|
|
12
|
+
import type { TraceGraphEdgeRow } from './012-trace-graph-lookups.js';
|
|
13
|
+
import {
|
|
14
|
+
enqueueCausalScope,
|
|
15
|
+
type TraceQueueScope,
|
|
16
|
+
} from './013-trace-root-scopes.js';
|
|
17
|
+
import { parseTraceEvidence } from './017-trace-context.js';
|
|
18
|
+
import {
|
|
19
|
+
recordCycleObservation,
|
|
20
|
+
recordImplementationObservation,
|
|
21
|
+
} from './019-trace-edge-semantics.js';
|
|
22
|
+
import {
|
|
23
|
+
handlerFilesForOperation,
|
|
24
|
+
handlerScope,
|
|
25
|
+
implementationScope,
|
|
26
|
+
} from './025-trace-implementation-scope.js';
|
|
27
|
+
import type {
|
|
28
|
+
CallRow,
|
|
29
|
+
EffectiveOutbound,
|
|
30
|
+
TraceExecutionRuntime,
|
|
31
|
+
} from './027-trace-scope-execution.js';
|
|
32
|
+
|
|
33
|
+
interface OperationSelection {
|
|
34
|
+
implementation: ReturnType<typeof implementationScope>;
|
|
35
|
+
contextMethodId?: string;
|
|
36
|
+
selectedHandlerAvailable: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function processOperationTarget(
|
|
40
|
+
runtime: TraceExecutionRuntime,
|
|
41
|
+
current: TraceQueueScope,
|
|
42
|
+
call: CallRow,
|
|
43
|
+
effective: EffectiveOutbound,
|
|
44
|
+
): void {
|
|
45
|
+
const selection = selectOperation(runtime, current, effective);
|
|
46
|
+
if (current.depth >= runtime.maxDepth) return;
|
|
47
|
+
scheduleOperation(runtime, current, call, effective, selection);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function selectOperation(
|
|
51
|
+
runtime: TraceExecutionRuntime,
|
|
52
|
+
current: TraceQueueScope,
|
|
53
|
+
effective: EffectiveOutbound,
|
|
54
|
+
): OperationSelection {
|
|
55
|
+
const implementation = implementationScope(
|
|
56
|
+
runtime.db, effective.row.to_id,
|
|
57
|
+
);
|
|
58
|
+
const context = contextualImplementationSelection(
|
|
59
|
+
runtime.db, implementation.edge, effective.row.to_id,
|
|
60
|
+
current.repoId, effective.evidence, runtime.hintOptions,
|
|
61
|
+
);
|
|
62
|
+
const available = implementation.edge
|
|
63
|
+
? recordOperationImplementation(runtime, current, effective,
|
|
64
|
+
implementation.edge, context)
|
|
65
|
+
: true;
|
|
66
|
+
return {
|
|
67
|
+
implementation,
|
|
68
|
+
contextMethodId: context.methodId,
|
|
69
|
+
selectedHandlerAvailable: available,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function recordOperationImplementation(
|
|
74
|
+
runtime: TraceExecutionRuntime,
|
|
75
|
+
current: TraceQueueScope,
|
|
76
|
+
effective: EffectiveOutbound,
|
|
77
|
+
edge: TraceGraphEdgeRow,
|
|
78
|
+
context: ReturnType<typeof contextualImplementationSelection>,
|
|
79
|
+
): boolean {
|
|
80
|
+
const evidence = parseTraceEvidence(edge.evidence_json);
|
|
81
|
+
const hintDiagnostic = implementationHintDiagnostic(context, evidence);
|
|
82
|
+
if (hintDiagnostic) runtime.diagnostics.unshift(hintDiagnostic);
|
|
83
|
+
const methodId = edge.status === 'resolved' ? edge.to_id : context.methodId;
|
|
84
|
+
const selectionEvidence = contextualSelectionEvidence(evidence, context);
|
|
85
|
+
const selected = methodId
|
|
86
|
+
? withSelectedHandlerProvenance(
|
|
87
|
+
selectionEvidence, methodId, handlerMethodNode(runtime.db, methodId),
|
|
88
|
+
)
|
|
89
|
+
: { evidence: selectionEvidence };
|
|
90
|
+
recordSelectedOperation(
|
|
91
|
+
runtime, current, effective, edge, context, methodId, selected,
|
|
92
|
+
);
|
|
93
|
+
return !selected.unresolvedReason;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function recordSelectedOperation(
|
|
97
|
+
runtime: TraceExecutionRuntime,
|
|
98
|
+
current: TraceQueueScope,
|
|
99
|
+
effective: EffectiveOutbound,
|
|
100
|
+
edge: TraceGraphEdgeRow,
|
|
101
|
+
context: ReturnType<typeof contextualImplementationSelection>,
|
|
102
|
+
methodId: string | undefined,
|
|
103
|
+
selected: SelectedHandlerEvidence,
|
|
104
|
+
): void {
|
|
105
|
+
retainSelectedHandler(runtime, selected);
|
|
106
|
+
const unresolvedReason = operationUnresolvedReason(edge, context, selected);
|
|
107
|
+
const traceEdge = implementationTraceEdge(
|
|
108
|
+
current.depth, effective.to, edge, selected, unresolvedReason,
|
|
109
|
+
);
|
|
110
|
+
const scope = methodId ? handlerScope(runtime.db, methodId) : undefined;
|
|
111
|
+
recordImplementationObservation(runtime.recorder, traceEdge, {
|
|
112
|
+
operationId: effective.row.to_id,
|
|
113
|
+
handlerMethodId: methodId,
|
|
114
|
+
handlerSymbolId: scope?.symbolId,
|
|
115
|
+
graphEdgeId: edge.id,
|
|
116
|
+
persistedStatus: edge.status,
|
|
117
|
+
persistedTargetKind: edge.to_kind,
|
|
118
|
+
persistedTargetId: edge.to_id,
|
|
119
|
+
effectiveStatus: context.methodId ? 'resolved' : String(edge.status),
|
|
120
|
+
strategy: implementationStrategy(context),
|
|
121
|
+
guided: context.evidence.guided === true,
|
|
122
|
+
contextual: contextualSelection(context),
|
|
123
|
+
unresolvedReason,
|
|
124
|
+
evidence: selected.evidence,
|
|
125
|
+
site: effective.evidence,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function retainSelectedHandler(
|
|
130
|
+
runtime: TraceExecutionRuntime,
|
|
131
|
+
selected: SelectedHandlerEvidence,
|
|
132
|
+
): void {
|
|
133
|
+
if (selected.diagnostic) runtime.diagnostics.unshift(selected.diagnostic);
|
|
134
|
+
if (selected.handler)
|
|
135
|
+
runtime.nodes.set(String(selected.handler.id), selected.handler);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function operationUnresolvedReason(
|
|
139
|
+
edge: TraceGraphEdgeRow,
|
|
140
|
+
context: ReturnType<typeof contextualImplementationSelection>,
|
|
141
|
+
selected: SelectedHandlerEvidence,
|
|
142
|
+
): string | undefined {
|
|
143
|
+
if (selected.unresolvedReason) return selected.unresolvedReason;
|
|
144
|
+
if (edge.status === 'resolved' || context.methodId) return undefined;
|
|
145
|
+
return String(edge.unresolved_reason ?? edge.status);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function contextualSelection(
|
|
149
|
+
context: ReturnType<typeof contextualImplementationSelection>,
|
|
150
|
+
): boolean {
|
|
151
|
+
return Boolean(context.methodId)
|
|
152
|
+
&& context.evidence.strategy !== 'implementation_repo_hint';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function implementationStrategy(
|
|
156
|
+
context: ReturnType<typeof contextualImplementationSelection>,
|
|
157
|
+
): string {
|
|
158
|
+
return String(context.evidence.strategy
|
|
159
|
+
?? (context.methodId
|
|
160
|
+
? 'contextual_implementation_selection' : 'indexed_operation_graph'));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function contextualSelectionEvidence(
|
|
164
|
+
evidence: Record<string, unknown>,
|
|
165
|
+
context: ReturnType<typeof contextualImplementationSelection>,
|
|
166
|
+
): Record<string, unknown> {
|
|
167
|
+
return context.methodId ? {
|
|
168
|
+
...evidence,
|
|
169
|
+
contextualImplementationSelected:
|
|
170
|
+
context.evidence.strategy !== 'implementation_repo_hint',
|
|
171
|
+
contextualImplementation: context.evidence,
|
|
172
|
+
implementationSelection: context.evidence,
|
|
173
|
+
} : {
|
|
174
|
+
...evidence,
|
|
175
|
+
contextualImplementation: context.evidence,
|
|
176
|
+
implementationSelection: context.evidence,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function implementationTraceEdge(
|
|
181
|
+
depth: number,
|
|
182
|
+
from: string,
|
|
183
|
+
edge: TraceGraphEdgeRow,
|
|
184
|
+
selected: SelectedHandlerEvidence,
|
|
185
|
+
unresolvedReason: string | undefined,
|
|
186
|
+
): TraceEdge {
|
|
187
|
+
return {
|
|
188
|
+
step: depth,
|
|
189
|
+
type: 'operation_implemented_by_handler',
|
|
190
|
+
from,
|
|
191
|
+
to: selected.handler?.label
|
|
192
|
+
? String(selected.handler.label) : `${edge.to_kind}:${edge.to_id}`,
|
|
193
|
+
evidence: selected.evidence,
|
|
194
|
+
confidence: Number(edge.confidence ?? 0),
|
|
195
|
+
unresolvedReason,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function scheduleOperation(
|
|
200
|
+
runtime: TraceExecutionRuntime,
|
|
201
|
+
current: TraceQueueScope,
|
|
202
|
+
call: CallRow,
|
|
203
|
+
effective: EffectiveOutbound,
|
|
204
|
+
selection: OperationSelection,
|
|
205
|
+
): void {
|
|
206
|
+
const contextScope = operationContextScope(runtime.db, selection);
|
|
207
|
+
const files = operationFiles(runtime.db, effective, selection, contextScope);
|
|
208
|
+
const symbols = operationSymbols(selection, contextScope);
|
|
209
|
+
if (!operationCanSchedule(selection, contextScope, files)) return;
|
|
210
|
+
scheduleOperationScope(
|
|
211
|
+
runtime, current, call, effective, selection, contextScope, files, symbols,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function operationContextScope(
|
|
216
|
+
db: Db,
|
|
217
|
+
selection: OperationSelection,
|
|
218
|
+
): ReturnType<typeof handlerScope> {
|
|
219
|
+
return selection.contextMethodId
|
|
220
|
+
? handlerScope(db, selection.contextMethodId) : undefined;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function operationFiles(
|
|
224
|
+
db: Db,
|
|
225
|
+
effective: EffectiveOutbound,
|
|
226
|
+
selection: OperationSelection,
|
|
227
|
+
contextScope: ReturnType<typeof handlerScope>,
|
|
228
|
+
): Set<string> {
|
|
229
|
+
if (contextScope) return contextScope.files;
|
|
230
|
+
if (selection.implementation.files.size > 0)
|
|
231
|
+
return selection.implementation.files;
|
|
232
|
+
return handlerFilesForOperation(db, effective.row.to_id);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function operationSymbols(
|
|
236
|
+
selection: OperationSelection,
|
|
237
|
+
contextScope: ReturnType<typeof handlerScope>,
|
|
238
|
+
): Set<number> | undefined {
|
|
239
|
+
if (contextScope?.symbolId) return new Set([contextScope.symbolId]);
|
|
240
|
+
const symbolId = selection.implementation.symbolId;
|
|
241
|
+
return symbolId ? new Set([symbolId]) : undefined;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function operationCanSchedule(
|
|
245
|
+
selection: OperationSelection,
|
|
246
|
+
contextScope: ReturnType<typeof handlerScope>,
|
|
247
|
+
files: ReadonlySet<string>,
|
|
248
|
+
): boolean {
|
|
249
|
+
if (!selection.selectedHandlerAvailable || files.size === 0) return false;
|
|
250
|
+
const edge = selection.implementation.edge;
|
|
251
|
+
if (!edge) return false;
|
|
252
|
+
return edge.status === 'resolved' || contextScope !== undefined;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function scheduleOperationScope(
|
|
256
|
+
runtime: TraceExecutionRuntime,
|
|
257
|
+
current: TraceQueueScope,
|
|
258
|
+
call: CallRow,
|
|
259
|
+
effective: EffectiveOutbound,
|
|
260
|
+
selection: OperationSelection,
|
|
261
|
+
contextScope: ReturnType<typeof handlerScope>,
|
|
262
|
+
files: Set<string>,
|
|
263
|
+
symbols: Set<number> | undefined,
|
|
264
|
+
): void {
|
|
265
|
+
const repoId = contextScope?.repoId ?? selection.implementation.repoId
|
|
266
|
+
?? operationRepositoryId(runtime.db, effective.row.to_id);
|
|
267
|
+
const context = new Map<string, ContextBinding>();
|
|
268
|
+
const scheduling = runtime.scheduler.schedule({
|
|
269
|
+
workspaceId: runtime.workspaceId ?? call.workspaceId,
|
|
270
|
+
repoId,
|
|
271
|
+
files,
|
|
272
|
+
symbolIds: symbols,
|
|
273
|
+
context,
|
|
274
|
+
}, current.state);
|
|
275
|
+
if (scheduling.kind === 'cycle')
|
|
276
|
+
recordOperationCycle(
|
|
277
|
+
runtime, current, call, effective, scheduling.state,
|
|
278
|
+
repoId, files, symbols,
|
|
279
|
+
);
|
|
280
|
+
if (scheduling.kind === 'scheduled')
|
|
281
|
+
enqueueCausalScope(runtime.queue, runtime.pendingRoots, {
|
|
282
|
+
repoId,
|
|
283
|
+
files,
|
|
284
|
+
symbolIds: symbols,
|
|
285
|
+
depth: current.depth + 1,
|
|
286
|
+
context,
|
|
287
|
+
state: scheduling.state,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function operationRepositoryId(
|
|
292
|
+
db: Db,
|
|
293
|
+
operationId: string,
|
|
294
|
+
): number | undefined {
|
|
295
|
+
return db.prepare(`SELECT s.repo_id repoId
|
|
296
|
+
FROM cds_operations o JOIN cds_services s ON s.id=o.service_id
|
|
297
|
+
WHERE o.id=?`).get(operationId)?.repoId as number | undefined;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function recordOperationCycle(
|
|
301
|
+
runtime: TraceExecutionRuntime,
|
|
302
|
+
current: TraceQueueScope,
|
|
303
|
+
call: CallRow,
|
|
304
|
+
effective: EffectiveOutbound,
|
|
305
|
+
state: TraversalScopeState,
|
|
306
|
+
repoId: number | undefined,
|
|
307
|
+
files: Set<string>,
|
|
308
|
+
symbols: Set<number> | undefined,
|
|
309
|
+
): void {
|
|
310
|
+
const evidence = {
|
|
311
|
+
...effective.evidence,
|
|
312
|
+
cycle: true,
|
|
313
|
+
cycleReason: 'structural_ancestry_cycle',
|
|
314
|
+
};
|
|
315
|
+
const edge: TraceEdge = {
|
|
316
|
+
step: current.depth,
|
|
317
|
+
type: 'cycle',
|
|
318
|
+
from: effective.to,
|
|
319
|
+
to: state.structuralKey,
|
|
320
|
+
evidence,
|
|
321
|
+
confidence: 1,
|
|
322
|
+
unresolvedReason:
|
|
323
|
+
'Cycle detected in structural ancestry; downstream scope was not expanded',
|
|
324
|
+
};
|
|
325
|
+
recordCycleObservation(runtime.recorder, edge, effective.semantic.target, {
|
|
326
|
+
workspaceId: effective.semanticWorkspaceId,
|
|
327
|
+
repositoryId: repoId,
|
|
328
|
+
sourceFiles: files,
|
|
329
|
+
symbolIds: symbols,
|
|
330
|
+
structuralKey: state.structuralKey,
|
|
331
|
+
}, {
|
|
332
|
+
graphEdgeId: effective.evidence.persistedGraphEdgeId,
|
|
333
|
+
outboundCallId: call.id,
|
|
334
|
+
operationId: effective.row.to_id,
|
|
335
|
+
}, call);
|
|
336
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { Db } from '../db/connection.js';
|
|
2
|
+
import type { TraceEdge } from '../types.js';
|
|
3
|
+
import { hintedImplementationSelection } from './005-implementation-selection.js';
|
|
4
|
+
import {
|
|
5
|
+
handlerMethodNode,
|
|
6
|
+
withSelectedHandlerProvenance,
|
|
7
|
+
type SelectedHandlerEvidence,
|
|
8
|
+
} from './009-selected-handler-provenance.js';
|
|
9
|
+
import {
|
|
10
|
+
operationNode,
|
|
11
|
+
type TraceGraphEdgeRow,
|
|
12
|
+
} from './012-trace-graph-lookups.js';
|
|
13
|
+
import { parseTraceEvidence } from './017-trace-context.js';
|
|
14
|
+
import { recordImplementationObservation } from './019-trace-edge-semantics.js';
|
|
15
|
+
import {
|
|
16
|
+
handlerScope,
|
|
17
|
+
implementationScope,
|
|
18
|
+
} from './025-trace-implementation-scope.js';
|
|
19
|
+
import type { TraceExecutionRuntime } from './027-trace-scope-execution.js';
|
|
20
|
+
|
|
21
|
+
interface StartImplementationSelection {
|
|
22
|
+
edge: TraceGraphEdgeRow;
|
|
23
|
+
operationNode?: Record<string, unknown>;
|
|
24
|
+
selectedMethodId?: string;
|
|
25
|
+
selected: SelectedHandlerEvidence;
|
|
26
|
+
selectedSymbolId?: number;
|
|
27
|
+
effectiveStatus: string;
|
|
28
|
+
strategy: string;
|
|
29
|
+
guided: boolean;
|
|
30
|
+
unresolvedReason?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function selectedStartImplementation(
|
|
34
|
+
runtime: TraceExecutionRuntime,
|
|
35
|
+
operationId: string,
|
|
36
|
+
): StartImplementationSelection | undefined {
|
|
37
|
+
const operation = operationNode(runtime.db, operationId);
|
|
38
|
+
if (operation) runtime.nodes.set(String(operation.id), operation);
|
|
39
|
+
const implementation = implementationScope(runtime.db, operationId);
|
|
40
|
+
const startSelection = hintedImplementationSelection(
|
|
41
|
+
runtime.db, implementation.edge, operationId, runtime.hintOptions,
|
|
42
|
+
);
|
|
43
|
+
const edge = implementation.edge;
|
|
44
|
+
if (!edge) return undefined;
|
|
45
|
+
const selectedMethodId = startSelectedMethod(edge, startSelection.methodId);
|
|
46
|
+
if (!selectedMethodId && edge.status !== 'resolved') return undefined;
|
|
47
|
+
const evidence = startImplementationEvidence(
|
|
48
|
+
edge, operationId, selectedMethodId, startSelection,
|
|
49
|
+
);
|
|
50
|
+
const selected = startSelectedHandler(
|
|
51
|
+
runtime.db, evidence, selectedMethodId,
|
|
52
|
+
);
|
|
53
|
+
const scope = selectedMethodId
|
|
54
|
+
? handlerScope(runtime.db, selectedMethodId) : undefined;
|
|
55
|
+
return {
|
|
56
|
+
edge, operationNode: operation, selectedMethodId, selected,
|
|
57
|
+
selectedSymbolId: scope?.symbolId,
|
|
58
|
+
effectiveStatus: startEffectiveStatus(edge, startSelection.methodId),
|
|
59
|
+
strategy: startStrategy(startSelection.evidence.strategy),
|
|
60
|
+
guided: startSelection.evidence.guided === true,
|
|
61
|
+
unresolvedReason: startUnresolvedReason(
|
|
62
|
+
edge, selected, startSelection.methodId,
|
|
63
|
+
),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function startSelectedMethod(
|
|
68
|
+
edge: TraceGraphEdgeRow,
|
|
69
|
+
hintedMethodId: string | undefined,
|
|
70
|
+
): string | undefined {
|
|
71
|
+
return edge.status === 'resolved' ? edge.to_id : hintedMethodId;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function startSelectedHandler(
|
|
75
|
+
db: Db,
|
|
76
|
+
evidence: Record<string, unknown>,
|
|
77
|
+
methodId: string | undefined,
|
|
78
|
+
): SelectedHandlerEvidence {
|
|
79
|
+
if (!methodId) return { evidence };
|
|
80
|
+
return withSelectedHandlerProvenance(
|
|
81
|
+
evidence, methodId, handlerMethodNode(db, methodId),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function startEffectiveStatus(
|
|
86
|
+
edge: TraceGraphEdgeRow,
|
|
87
|
+
hintedMethodId: string | undefined,
|
|
88
|
+
): string {
|
|
89
|
+
return hintedMethodId ? 'resolved' : String(edge.status ?? 'unresolved');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function startStrategy(value: unknown): string {
|
|
93
|
+
return typeof value === 'string' ? value : 'indexed_operation_graph';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function startUnresolvedReason(
|
|
97
|
+
edge: TraceGraphEdgeRow,
|
|
98
|
+
selected: SelectedHandlerEvidence,
|
|
99
|
+
hintedMethodId: string | undefined,
|
|
100
|
+
): string | undefined {
|
|
101
|
+
if (selected.unresolvedReason) return selected.unresolvedReason;
|
|
102
|
+
if (edge.status === 'resolved' || hintedMethodId) return undefined;
|
|
103
|
+
return String(edge.unresolved_reason ?? edge.status);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function startImplementationEvidence(
|
|
107
|
+
edge: TraceGraphEdgeRow,
|
|
108
|
+
operationId: string,
|
|
109
|
+
selectedMethodId: string | undefined,
|
|
110
|
+
selection: ReturnType<typeof hintedImplementationSelection>,
|
|
111
|
+
): Record<string, unknown> {
|
|
112
|
+
return {
|
|
113
|
+
...parseTraceEvidence(edge.evidence_json),
|
|
114
|
+
startResolution: {
|
|
115
|
+
strategy: 'indexed_operation_graph',
|
|
116
|
+
matchedOperationId: operationId,
|
|
117
|
+
implementationEdgeId: edge.id,
|
|
118
|
+
implementationStatus: edge.status,
|
|
119
|
+
selectedHandlerMethodId: selectedMethodId,
|
|
120
|
+
},
|
|
121
|
+
implementationSelection: selection.methodId
|
|
122
|
+
? selection.evidence : undefined,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function recordTraceStartImplementation(
|
|
127
|
+
runtime: TraceExecutionRuntime,
|
|
128
|
+
operationId: string,
|
|
129
|
+
): void {
|
|
130
|
+
const selection = selectedStartImplementation(runtime, operationId);
|
|
131
|
+
if (!selection) return;
|
|
132
|
+
const selected = selection.selected;
|
|
133
|
+
if (selected.diagnostic)
|
|
134
|
+
runtime.diagnostics.unshift(selected.diagnostic);
|
|
135
|
+
if (selected.handler)
|
|
136
|
+
runtime.nodes.set(String(selected.handler.id), selected.handler);
|
|
137
|
+
const edge = startImplementationTraceEdge(operationId, selection);
|
|
138
|
+
recordImplementationObservation(runtime.recorder, edge, {
|
|
139
|
+
operationId,
|
|
140
|
+
handlerMethodId: selection.selectedMethodId,
|
|
141
|
+
handlerSymbolId: selection.selectedSymbolId,
|
|
142
|
+
graphEdgeId: selection.edge.id,
|
|
143
|
+
persistedStatus: selection.edge.status,
|
|
144
|
+
persistedTargetKind: selection.edge.to_kind,
|
|
145
|
+
persistedTargetId: selection.edge.to_id,
|
|
146
|
+
effectiveStatus: selection.effectiveStatus,
|
|
147
|
+
strategy: selection.strategy,
|
|
148
|
+
guided: selection.guided,
|
|
149
|
+
unresolvedReason: selection.unresolvedReason,
|
|
150
|
+
evidence: selected.evidence,
|
|
151
|
+
site: selection.operationNode ?? {},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function startImplementationTraceEdge(
|
|
156
|
+
operationId: string,
|
|
157
|
+
selection: StartImplementationSelection,
|
|
158
|
+
): TraceEdge {
|
|
159
|
+
const selected = selection.selected;
|
|
160
|
+
return {
|
|
161
|
+
step: 1,
|
|
162
|
+
type: 'operation_implemented_by_handler',
|
|
163
|
+
from: selection.operationNode?.label
|
|
164
|
+
? String(selection.operationNode.label) : `operation:${operationId}`,
|
|
165
|
+
to: selected.handler?.label
|
|
166
|
+
? String(selected.handler.label)
|
|
167
|
+
: `${selection.edge.to_kind}:${selection.edge.to_id}`,
|
|
168
|
+
evidence: selected.evidence,
|
|
169
|
+
confidence: Number(selection.edge.confidence ?? 0),
|
|
170
|
+
unresolvedReason: selection.unresolvedReason,
|
|
171
|
+
};
|
|
172
|
+
}
|