@saptools/service-flow 0.1.69 → 0.1.72
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 +17 -0
- package/README.md +9 -5
- package/TECHNICAL-NOTE.md +17 -0
- package/dist/{chunk-3N3B5KHV.js → chunk-Z6D433R5.js} +8766 -6546
- package/dist/chunk-Z6D433R5.js.map +1 -0
- package/dist/cli.js +703 -160
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +53 -14
- package/dist/index.js +2 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/doctor-event-quality.ts +371 -0
- package/src/cli/{002-doctor-lifecycle.ts → doctor-lifecycle.ts} +1 -1
- package/src/cli/{001-doctor-projection.ts → doctor-projection.ts} +1 -1
- package/src/cli/doctor.ts +9 -11
- package/src/cli.ts +6 -6
- package/src/db/{009-binding-fact-semantics.ts → binding-fact-semantics.ts} +2 -2
- package/src/db/{000-call-fact-repository.ts → call-fact-repository.ts} +12 -9
- package/src/db/{003-current-fact-semantics.ts → current-fact-semantics.ts} +8 -8
- package/src/db/event-fact-semantics.ts +347 -0
- package/src/db/event-surface-invalidation.ts +38 -0
- package/src/db/{002-fact-json-inventory.ts → fact-json-inventory.ts} +16 -0
- package/src/db/{001-fact-lifecycle.ts → fact-lifecycle.ts} +3 -3
- package/src/db/migrations.ts +12 -1
- package/src/db/{007-package-fact-semantics.ts → package-fact-semantics.ts} +6 -6
- package/src/db/{010-package-symbol-surface-semantics.ts → package-symbol-surface-semantics.ts} +2 -2
- package/src/db/{004-package-target-invalidation.ts → package-target-invalidation.ts} +80 -1
- package/src/db/{008-relative-fact-semantics.ts → relative-fact-semantics.ts} +3 -3
- package/src/db/{006-relative-symbol-resolution.ts → relative-symbol-resolution.ts} +1 -1
- package/src/db/repositories.ts +31 -5
- package/src/db/{005-schema-structure.ts → schema-structure.ts} +41 -1
- package/src/db/schema.ts +6 -2
- package/src/db/{011-symbol-call-semantics.ts → symbol-call-semantics.ts} +1 -1
- package/src/index.ts +3 -3
- package/src/indexer/repository-indexer.ts +50 -11
- package/src/indexer/workspace-indexer.ts +3 -3
- package/src/linker/{007-call-edge-insertion.ts → call-edge-insertion.ts} +2 -2
- package/src/linker/{002-call-evidence.ts → call-evidence.ts} +2 -2
- package/src/linker/cross-repo-linker.ts +30 -8
- package/src/linker/dynamic-edge-resolver.ts +1 -1
- package/src/linker/event-environment-link.ts +211 -0
- package/src/linker/event-shape-candidate-linker.ts +161 -0
- package/src/linker/{004-event-subscription-handler-linker.ts → event-subscription-handler-linker.ts} +124 -20
- package/src/linker/{006-event-template-link.ts → event-template-link.ts} +40 -6
- package/src/linker/external-http-target.ts +1 -1
- package/src/linker/helper-package-linker.ts +1 -1
- package/src/linker/{000-implementation-candidates.ts → implementation-candidates.ts} +1 -1
- package/src/linker/{001-implementation-evidence-projection.ts → implementation-evidence-projection.ts} +1 -1
- package/src/linker/odata-path-normalizer.ts +1 -1
- package/src/linker/{005-odata-path-structure.ts → odata-path-structure.ts} +1 -1
- package/src/linker/package-event-constant-resolver.ts +298 -0
- package/src/linker/{003-package-import-symbol-resolver.ts → package-import-symbol-resolver.ts} +3 -3
- package/src/linker/service-resolver.ts +2 -2
- package/src/output/{001-compact-json-output.ts → compact-json-output.ts} +1 -1
- package/src/output/table-output.ts +13 -1
- package/src/parsers/{006-binding-identity.ts → binding-identity.ts} +3 -3
- package/src/parsers/{011-binding-lexical-scope.ts → binding-lexical-scope.ts} +1 -1
- package/src/parsers/{021-binding-visibility.ts → binding-visibility.ts} +1 -1
- package/src/parsers/decorator-parser.ts +9 -53
- package/src/parsers/environment-declarations.ts +327 -0
- package/src/parsers/event-call-analysis.ts +242 -0
- package/src/parsers/event-environment-reference.ts +231 -0
- package/src/parsers/event-loop-registration.ts +132 -0
- package/src/parsers/event-name-import-resolution.ts +243 -0
- package/src/parsers/event-receiver-analysis.ts +404 -0
- package/src/parsers/{005-event-subscription-facts.ts → event-subscription-facts.ts} +6 -2
- package/src/parsers/generated-constants-parser.ts +80 -14
- package/src/parsers/{016-local-symbol-reference.ts → local-symbol-reference.ts} +2 -2
- package/src/parsers/operation-path-analysis.ts +1 -1
- package/src/parsers/{023-outbound-call-classifier.ts → outbound-call-classifier.ts} +30 -127
- package/src/parsers/outbound-call-parser.ts +15 -3
- package/src/parsers/{022-outbound-expression-analysis.ts → outbound-expression-analysis.ts} +4 -4
- package/src/parsers/{018-package-commonjs-syntax.ts → package-commonjs-syntax.ts} +1 -1
- package/src/parsers/{012-package-fact-contract.ts → package-fact-contract.ts} +3 -3
- package/src/parsers/{010-package-public-surface-analysis.ts → package-public-surface-analysis.ts} +2 -2
- package/src/parsers/{003-package-public-surface.ts → package-public-surface.ts} +3 -3
- package/src/parsers/{008-package-surface-publication.ts → package-surface-publication.ts} +1 -1
- package/src/parsers/{001-query-entity-resolution.ts → query-entity-resolution.ts} +1 -1
- package/src/parsers/{015-service-binding-collector.ts → service-binding-collector.ts} +3 -3
- package/src/parsers/{014-service-binding-helper-flow.ts → service-binding-helper-flow.ts} +2 -2
- package/src/parsers/service-binding-parser-helpers.ts +1 -1
- package/src/parsers/service-binding-parser.ts +2 -2
- package/src/parsers/{007-source-fact-reconciliation.ts → source-fact-reconciliation.ts} +3 -3
- package/src/parsers/{020-stable-local-value.ts → stable-local-value.ts} +32 -11
- package/src/parsers/string-constant-lookups.ts +358 -0
- package/src/parsers/{009-symbol-call-facts.ts → symbol-call-facts.ts} +3 -3
- package/src/parsers/{017-symbol-derived-contexts.ts → symbol-derived-contexts.ts} +2 -2
- package/src/parsers/symbol-parser.ts +6 -6
- package/src/trace/{021-compact-decision-normalization.ts → compact-decision-normalization.ts} +2 -2
- package/src/trace/{020-compact-field-projection.ts → compact-field-projection.ts} +3 -3
- package/src/trace/{024-compact-observation-decision.ts → compact-observation-decision.ts} +3 -3
- package/src/trace/{016-compact-projector.ts → compact-projector.ts} +4 -4
- package/src/trace/{018-compact-trace.ts → compact-trace.ts} +3 -3
- package/src/trace/{006-contextual-projection.ts → contextual-projection.ts} +1 -1
- package/src/trace/{008-contextual-runtime-state.ts → contextual-runtime-state.ts} +1 -1
- package/src/trace/{001-dynamic-identity.ts → dynamic-identity.ts} +2 -2
- package/src/trace/{003-dynamic-references.ts → dynamic-references.ts} +2 -2
- package/src/trace/dynamic-targets.ts +6 -6
- package/src/trace/{030-event-runtime-resolution.ts → event-runtime-resolution.ts} +26 -5
- package/src/trace/event-shape-candidate-trace.ts +172 -0
- package/src/trace/{011-event-subscriber-traversal.ts → event-subscriber-traversal.ts} +20 -8
- package/src/trace/evidence.ts +9 -2
- package/src/trace/implementation-hints.ts +2 -2
- package/src/trace/{005-implementation-selection.ts → implementation-selection.ts} +2 -2
- package/src/trace/{031-local-call-expansion.ts → local-call-expansion.ts} +3 -3
- package/src/trace/{009-selected-handler-provenance.ts → selected-handler-provenance.ts} +1 -1
- package/src/trace/selectors.ts +1 -1
- package/src/trace/{017-trace-context.ts → trace-context.ts} +2 -2
- package/src/trace/{015-trace-edge-recorder.ts → trace-edge-recorder.ts} +2 -2
- package/src/trace/{019-trace-edge-semantics.ts → trace-edge-semantics.ts} +3 -3
- package/src/trace/trace-engine.ts +10 -10
- package/src/trace/{022-trace-fact-preflight.ts → trace-fact-preflight.ts} +2 -2
- package/src/trace/{025-trace-implementation-scope.ts → trace-implementation-scope.ts} +1 -1
- package/src/trace/{028-trace-operation-execution.ts → trace-operation-execution.ts} +10 -10
- package/src/trace/{013-trace-root-scopes.ts → trace-root-scopes.ts} +3 -3
- package/src/trace/{027-trace-scope-execution.ts → trace-scope-execution.ts} +35 -43
- package/src/trace/{029-trace-start-implementation.ts → trace-start-implementation.ts} +7 -7
- package/src/trace/{026-trace-start-scope.ts → trace-start-scope.ts} +5 -5
- package/src/trace/{010-traversal-scope.ts → traversal-scope.ts} +1 -1
- package/src/types.ts +17 -1
- package/src/utils/event-skeleton.ts +207 -0
- package/src/version.ts +1 -1
- package/dist/chunk-3N3B5KHV.js.map +0 -1
- /package/src/cli/{000-clean.ts → clean.ts} +0 -0
- /package/src/cli/{003-doctor-package-resolution.ts → doctor-package-resolution.ts} +0 -0
- /package/src/cli/{001-index-summary.ts → index-summary.ts} +0 -0
- /package/src/db/{014-binding-helper-provenance.ts → binding-helper-provenance.ts} +0 -0
- /package/src/db/{012-binding-reference-proof.ts → binding-reference-proof.ts} +0 -0
- /package/src/db/{013-index-publication-failure.ts → index-publication-failure.ts} +0 -0
- /package/src/output/{000-stdout-policy.ts → stdout-policy.ts} +0 -0
- /package/src/parsers/{019-binding-assignment-targets.ts → binding-assignment-targets.ts} +0 -0
- /package/src/parsers/{000-direct-query-execution.ts → direct-query-execution.ts} +0 -0
- /package/src/parsers/{013-executable-body-eligibility.ts → executable-body-eligibility.ts} +0 -0
- /package/src/parsers/{004-fact-identity.ts → fact-identity.ts} +0 -0
- /package/src/parsers/{002-symbol-import-bindings.ts → symbol-import-bindings.ts} +0 -0
- /package/src/trace/{014-compact-contract.ts → compact-contract.ts} +0 -0
- /package/src/trace/{004-dynamic-candidate-sources.ts → dynamic-candidate-sources.ts} +0 -0
- /package/src/trace/{000-dynamic-target-types.ts → dynamic-target-types.ts} +0 -0
- /package/src/trace/{007-implementation-start-diagnostic.ts → implementation-start-diagnostic.ts} +0 -0
- /package/src/trace/{023-nested-event-scopes.ts → nested-event-scopes.ts} +0 -0
- /package/src/trace/{002-trace-diagnostics.ts → trace-diagnostics.ts} +0 -0
- /package/src/trace/{012-trace-graph-lookups.ts → trace-graph-lookups.ts} +0 -0
- /package/src/utils/{000-bounded-projection.ts → bounded-projection.ts} +0 -0
- /package/src/utils/{001-placeholders.ts → placeholders.ts} +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { Db } from '../db/connection.js';
|
|
2
|
+
import type { TraceOptions } from '../types.js';
|
|
3
|
+
import {
|
|
4
|
+
operationNode,
|
|
5
|
+
symbolNode,
|
|
6
|
+
type TraceGraphEdgeRow,
|
|
7
|
+
} from './trace-graph-lookups.js';
|
|
8
|
+
import type { TraceGraphRow } from './evidence.js';
|
|
9
|
+
import {
|
|
10
|
+
eventMissingVariableNames,
|
|
11
|
+
eventTemplateVariables,
|
|
12
|
+
parseEventSkeletonFact,
|
|
13
|
+
} from '../utils/event-skeleton.js';
|
|
14
|
+
|
|
15
|
+
const defaultEventShapeCandidateCap = 5;
|
|
16
|
+
const maximumEventShapeCandidateCap = 50;
|
|
17
|
+
|
|
18
|
+
function candidateCap(options: TraceOptions): number {
|
|
19
|
+
const value = options.maxDynamicCandidates
|
|
20
|
+
?? defaultEventShapeCandidateCap;
|
|
21
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
22
|
+
return defaultEventShapeCandidateCap;
|
|
23
|
+
return Math.min(value, maximumEventShapeCandidateCap);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function withCandidateCounts(
|
|
27
|
+
row: TraceGraphEdgeRow,
|
|
28
|
+
total: number,
|
|
29
|
+
shown: number,
|
|
30
|
+
): TraceGraphEdgeRow {
|
|
31
|
+
let evidence: Record<string, unknown> = {};
|
|
32
|
+
try {
|
|
33
|
+
const parsed: unknown = JSON.parse(row.evidence_json);
|
|
34
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
35
|
+
evidence = parsed as Record<string, unknown>;
|
|
36
|
+
} catch {
|
|
37
|
+
evidence = {};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
...row,
|
|
41
|
+
evidence_json: JSON.stringify({
|
|
42
|
+
...evidence,
|
|
43
|
+
eventShapeCandidateCount: total,
|
|
44
|
+
shownEventShapeCandidateCount: shown,
|
|
45
|
+
omittedEventShapeCandidateCount: Math.max(0, total - shown),
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function visibleEventShapeRows(
|
|
51
|
+
rows: readonly TraceGraphEdgeRow[],
|
|
52
|
+
options: TraceOptions,
|
|
53
|
+
): TraceGraphEdgeRow[] {
|
|
54
|
+
const regular = rows.filter((row) =>
|
|
55
|
+
row.edge_type !== 'EVENT_SHAPE_CANDIDATE_SUBSCRIBER');
|
|
56
|
+
if ((options.dynamicMode ?? 'strict') !== 'candidates') return regular;
|
|
57
|
+
const candidates = rows.filter((row) =>
|
|
58
|
+
row.edge_type === 'EVENT_SHAPE_CANDIDATE_SUBSCRIBER');
|
|
59
|
+
const shown = candidates.slice(0, candidateCap(options));
|
|
60
|
+
return [
|
|
61
|
+
...regular,
|
|
62
|
+
...shown.map((row) =>
|
|
63
|
+
withCandidateCounts(row, candidates.length, shown.length)),
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function outboundTraceEdgeType(
|
|
68
|
+
call: { call_type: string },
|
|
69
|
+
row: { edge_type: string; to_kind: string },
|
|
70
|
+
): string {
|
|
71
|
+
if (row.edge_type === 'EVENT_SHAPE_CANDIDATE_SUBSCRIBER')
|
|
72
|
+
return 'event_shape_candidate_subscriber';
|
|
73
|
+
if (row.to_kind === 'operation'
|
|
74
|
+
&& row.edge_type === 'REMOTE_CALL_RESOLVES_TO_OPERATION')
|
|
75
|
+
return 'remote_action';
|
|
76
|
+
if (row.to_kind === 'operation'
|
|
77
|
+
&& row.edge_type === 'LOCAL_CALL_RESOLVES_TO_OPERATION')
|
|
78
|
+
return 'local_service_call';
|
|
79
|
+
return call.call_type;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function outboundTraceTargetNode(
|
|
83
|
+
db: Db,
|
|
84
|
+
id: string,
|
|
85
|
+
row: TraceGraphRow,
|
|
86
|
+
): Record<string, unknown> {
|
|
87
|
+
const operation = row.to_kind === 'operation'
|
|
88
|
+
? operationNode(db, row.to_id) : undefined;
|
|
89
|
+
const candidate = row.edge_type === 'EVENT_SHAPE_CANDIDATE_SUBSCRIBER'
|
|
90
|
+
? symbolNode(db, Number(row.to_id)) : undefined;
|
|
91
|
+
return operation ?? candidate ?? {
|
|
92
|
+
id,
|
|
93
|
+
kind: row.to_kind,
|
|
94
|
+
label: row.to_kind === 'db_entity'
|
|
95
|
+
? `Entity: ${row.to_id || 'unknown'}` : row.to_id,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function stringArray(value: unknown): string[] {
|
|
100
|
+
return Array.isArray(value)
|
|
101
|
+
? value.filter((item): item is string => typeof item === 'string') : [];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function subscriberSkeletons(
|
|
105
|
+
db: Db,
|
|
106
|
+
workspaceId: number,
|
|
107
|
+
publishCallId: number,
|
|
108
|
+
): unknown[] {
|
|
109
|
+
return db.prepare(`SELECT subscription.event_skeleton_json skeleton
|
|
110
|
+
FROM outbound_calls publication
|
|
111
|
+
JOIN repositories publication_repo ON publication_repo.id=publication.repo_id
|
|
112
|
+
JOIN outbound_calls subscription
|
|
113
|
+
ON subscription.call_type='async_subscribe'
|
|
114
|
+
AND subscription.event_skeleton_signature
|
|
115
|
+
=publication.event_skeleton_signature
|
|
116
|
+
JOIN repositories subscription_repo
|
|
117
|
+
ON subscription_repo.id=subscription.repo_id
|
|
118
|
+
AND subscription_repo.workspace_id=publication_repo.workspace_id
|
|
119
|
+
WHERE publication.id=? AND publication_repo.workspace_id=?
|
|
120
|
+
AND publication.event_skeleton_signature IS NOT NULL
|
|
121
|
+
ORDER BY subscription_repo.name COLLATE BINARY,
|
|
122
|
+
subscription.repo_id,subscription.source_file COLLATE BINARY,
|
|
123
|
+
subscription.call_site_start_offset,subscription.id`).all(
|
|
124
|
+
publishCallId, workspaceId,
|
|
125
|
+
).map((row) => row.skeleton);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function eventShapeMissingVariableEvidence(
|
|
129
|
+
db: Db,
|
|
130
|
+
workspaceId: number,
|
|
131
|
+
publishCallId: number,
|
|
132
|
+
evidence: Record<string, unknown>,
|
|
133
|
+
variables: Record<string, string> | undefined,
|
|
134
|
+
): Record<string, unknown> {
|
|
135
|
+
const current = stringArray(evidence.missingRuntimeVariables);
|
|
136
|
+
if (current.length === 0) return evidence;
|
|
137
|
+
const names = new Set(current);
|
|
138
|
+
let matchingSubscriptions = 0;
|
|
139
|
+
for (const value of subscriberSkeletons(db, workspaceId, publishCallId)) {
|
|
140
|
+
const skeleton = parseEventSkeletonFact(value);
|
|
141
|
+
if (!skeleton?.candidateEligible) continue;
|
|
142
|
+
matchingSubscriptions += 1;
|
|
143
|
+
const expanded = eventTemplateVariables(skeleton, variables ?? {});
|
|
144
|
+
const missing = skeleton.sourceKeys.filter((key) =>
|
|
145
|
+
!Object.hasOwn(expanded, key));
|
|
146
|
+
for (const name of eventMissingVariableNames(skeleton, missing))
|
|
147
|
+
names.add(name);
|
|
148
|
+
}
|
|
149
|
+
const missing = [...names].sort((left, right) =>
|
|
150
|
+
left < right ? -1 : left > right ? 1 : 0);
|
|
151
|
+
return {
|
|
152
|
+
...evidence,
|
|
153
|
+
missingRuntimeVariables: missing,
|
|
154
|
+
missingVariableCount: missing.length,
|
|
155
|
+
eventShapeMatchingSubscriptionCount: matchingSubscriptions,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function eventShapeRuntimeEvidence(
|
|
160
|
+
db: Db,
|
|
161
|
+
workspaceId: number,
|
|
162
|
+
callId: number,
|
|
163
|
+
callType: string,
|
|
164
|
+
evidence: Record<string, unknown>,
|
|
165
|
+
variables: Record<string, string> | undefined,
|
|
166
|
+
): Record<string, unknown> {
|
|
167
|
+
return callType === 'async_emit'
|
|
168
|
+
? eventShapeMissingVariableEvidence(
|
|
169
|
+
db, workspaceId, callId, evidence, variables,
|
|
170
|
+
)
|
|
171
|
+
: evidence;
|
|
172
|
+
}
|
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
compareBinary,
|
|
8
8
|
type TraversalScopeScheduler,
|
|
9
9
|
type TraversalScopeState,
|
|
10
|
-
} from './
|
|
10
|
+
} from './traversal-scope.js';
|
|
11
|
+
import {
|
|
12
|
+
eventTemplateVariables,
|
|
13
|
+
parseEventSkeletonFact,
|
|
14
|
+
} from '../utils/event-skeleton.js';
|
|
11
15
|
|
|
12
16
|
export type EventSubscriberTransitionStatus =
|
|
13
17
|
| 'resolved'
|
|
@@ -96,7 +100,8 @@ export function planEventSubscriberTransitions(
|
|
|
96
100
|
): PlannedEventSubscriberTransition[] {
|
|
97
101
|
return loadEventSubscriberTransitions(db, query).map((transition) => {
|
|
98
102
|
const handler = transition.handler;
|
|
99
|
-
if (
|
|
103
|
+
if (transition.status !== 'resolved' || !handler)
|
|
104
|
+
return plannedTransition(transition, 'not_resolved');
|
|
100
105
|
if (depth >= maxDepth)
|
|
101
106
|
return plannedTransition(transition, 'depth_limited');
|
|
102
107
|
const state = scheduler.schedule({
|
|
@@ -245,13 +250,15 @@ function eventRowForQuery(
|
|
|
245
250
|
row: Record<string, unknown>,
|
|
246
251
|
query: EventSubscriberTransitionQuery,
|
|
247
252
|
): Record<string, unknown> | undefined {
|
|
253
|
+
const exact = exactPersistedEventRow(row, query);
|
|
254
|
+
if (exact) return exact;
|
|
248
255
|
const variables = query.vars;
|
|
249
|
-
if (variables === undefined) return
|
|
256
|
+
if (variables === undefined) return undefined;
|
|
250
257
|
const evidence = parseEvidence(row.evidenceJson);
|
|
251
258
|
const resolution = isRecord(evidence.eventTemplateResolution)
|
|
252
259
|
? evidence.eventTemplateResolution : {};
|
|
253
260
|
if (typeof resolution.original !== 'string')
|
|
254
|
-
return
|
|
261
|
+
return undefined;
|
|
255
262
|
return runtimeMatchedEventRow(
|
|
256
263
|
row, query, evidence, resolution.original, variables,
|
|
257
264
|
);
|
|
@@ -272,7 +279,10 @@ function runtimeMatchedEventRow(
|
|
|
272
279
|
template: string,
|
|
273
280
|
variables: Record<string, string>,
|
|
274
281
|
): Record<string, unknown> | undefined {
|
|
275
|
-
const
|
|
282
|
+
const skeleton = parseEventSkeletonFact(evidence.eventSkeleton);
|
|
283
|
+
const substitution = substituteVariables(
|
|
284
|
+
template, eventTemplateVariables(skeleton, variables),
|
|
285
|
+
);
|
|
276
286
|
if (substitution.missing.length > 0
|
|
277
287
|
|| substitution.effective !== query.eventName) return undefined;
|
|
278
288
|
const resolvedAssociation = evidence.associationStatus === 'resolved';
|
|
@@ -295,8 +305,7 @@ export function eventSubscriberMissingVariables(
|
|
|
295
305
|
db: Db,
|
|
296
306
|
query: EventSubscriberTransitionQuery,
|
|
297
307
|
): string[] {
|
|
298
|
-
|
|
299
|
-
const variables = query.vars;
|
|
308
|
+
const variables = query.vars ?? {};
|
|
300
309
|
const rows = db.prepare(`SELECT ge.from_id eventName,
|
|
301
310
|
ge.evidence_json evidenceJson FROM graph_edges ge
|
|
302
311
|
WHERE ge.workspace_id=? AND ge.generation=?
|
|
@@ -311,7 +320,10 @@ export function eventSubscriberMissingVariables(
|
|
|
311
320
|
const template = typeof resolution.original === 'string'
|
|
312
321
|
? resolution.original : undefined;
|
|
313
322
|
if (!template) return [];
|
|
314
|
-
const
|
|
323
|
+
const skeleton = parseEventSkeletonFact(evidence.eventSkeleton);
|
|
324
|
+
const substitution = substituteVariables(
|
|
325
|
+
template, eventTemplateVariables(skeleton, variables),
|
|
326
|
+
);
|
|
315
327
|
if (substitution.missing.length === 0
|
|
316
328
|
|| matchRuntimeTemplate(
|
|
317
329
|
substitution.effective, query.eventName,
|
package/src/trace/evidence.ts
CHANGED
|
@@ -4,12 +4,12 @@ import { normalizeODataOperationInvocationPath } from '../linker/odata-path-norm
|
|
|
4
4
|
import { resolveOperation, type OperationTarget } from '../linker/service-resolver.js';
|
|
5
5
|
import type { DynamicMode } from '../types.js';
|
|
6
6
|
import { analyzeDynamicTargetCandidates, type DynamicTargetAnalysis, type DynamicTargetCandidate } from './dynamic-targets.js';
|
|
7
|
-
import { boundCandidateLikeEvidence } from '../utils/
|
|
7
|
+
import { boundCandidateLikeEvidence } from '../utils/bounded-projection.js';
|
|
8
8
|
import {
|
|
9
9
|
dynamicMissingReason,
|
|
10
10
|
isStructuralContextualBlocker,
|
|
11
11
|
type ContextualRuntimeState,
|
|
12
|
-
} from './
|
|
12
|
+
} from './contextual-runtime-state.js';
|
|
13
13
|
|
|
14
14
|
export interface TraceGraphRow extends Record<string, unknown> {
|
|
15
15
|
id: number;
|
|
@@ -262,6 +262,8 @@ function runtimeDiagnosticTotals(
|
|
|
262
262
|
const effective = parseObject(edge.evidence.effectiveResolution);
|
|
263
263
|
if (!['dynamic', 'unresolved', 'ambiguous'].includes(String(effective.status ?? '')))
|
|
264
264
|
continue;
|
|
265
|
+
for (const key of stringArray(edge.evidence.missingRuntimeVariables))
|
|
266
|
+
missing.add(key);
|
|
265
267
|
const substitutions = edge.evidence.runtimeSubstitutions;
|
|
266
268
|
if (!substitutions || typeof substitutions !== 'object' || Array.isArray(substitutions)) continue;
|
|
267
269
|
for (const value of Object.values(substitutions as Record<string, RuntimeSubstitution>))
|
|
@@ -648,6 +650,11 @@ function stringValue(value: unknown): string | undefined {
|
|
|
648
650
|
return typeof value === 'string' ? value : undefined;
|
|
649
651
|
}
|
|
650
652
|
|
|
653
|
+
function stringArray(value: unknown): string[] {
|
|
654
|
+
return Array.isArray(value)
|
|
655
|
+
? value.filter((item): item is string => typeof item === 'string') : [];
|
|
656
|
+
}
|
|
657
|
+
|
|
651
658
|
function numeric(value: unknown): number {
|
|
652
659
|
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
|
|
653
660
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ImplementationHint } from '../types.js';
|
|
2
|
-
import { projectBounded } from '../utils/
|
|
3
|
-
import { compareBinary } from './
|
|
2
|
+
import { projectBounded } from '../utils/bounded-projection.js';
|
|
3
|
+
import { compareBinary } from './traversal-scope.js';
|
|
4
4
|
|
|
5
5
|
interface Candidate {
|
|
6
6
|
accepted?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
|
-
import { canonicalImplementationEvidence } from '../linker/
|
|
2
|
+
import { canonicalImplementationEvidence } from '../linker/implementation-candidates.js';
|
|
3
3
|
import type { ImplementationHint } from '../types.js';
|
|
4
|
-
import { projectBounded } from '../utils/
|
|
4
|
+
import { projectBounded } from '../utils/bounded-projection.js';
|
|
5
5
|
import {
|
|
6
6
|
selectImplementation,
|
|
7
7
|
type ImplementationSelection,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
2
|
import {
|
|
3
3
|
type ContextBinding,
|
|
4
|
-
} from './
|
|
4
|
+
} from './contextual-runtime-state.js';
|
|
5
5
|
import {
|
|
6
6
|
type TraversalScheduleDecision,
|
|
7
7
|
type TraversalScopeScheduler,
|
|
8
8
|
type TraversalScopeState,
|
|
9
|
-
} from './
|
|
10
|
-
import { contextForSymbolCall } from './
|
|
9
|
+
} from './traversal-scope.js';
|
|
10
|
+
import { contextForSymbolCall } from './trace-context.js';
|
|
11
11
|
|
|
12
12
|
export interface LocalCallExpansion {
|
|
13
13
|
repoId: number;
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
selectedHandlerProvenance,
|
|
4
4
|
type SelectedHandlerProvenance,
|
|
5
5
|
type SelectedHandlerSource,
|
|
6
|
-
} from '../linker/
|
|
6
|
+
} from '../linker/implementation-evidence-projection.js';
|
|
7
7
|
|
|
8
8
|
export interface HandlerMethodNode extends Record<string, unknown> {
|
|
9
9
|
id: string;
|
package/src/trace/selectors.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
2
|
import { extractPlaceholders } from '../linker/dynamic-edge-resolver.js';
|
|
3
|
-
import { boundCandidateLikeEvidence } from '../utils/
|
|
4
|
-
import type { ContextBinding } from './
|
|
3
|
+
import { boundCandidateLikeEvidence } from '../utils/bounded-projection.js';
|
|
4
|
+
import type { ContextBinding } from './contextual-runtime-state.js';
|
|
5
5
|
|
|
6
6
|
export interface TraceContextCall extends Record<string, unknown> {
|
|
7
7
|
service_binding_id?: number;
|
|
@@ -7,13 +7,13 @@ import type {
|
|
|
7
7
|
CompactSourceSite,
|
|
8
8
|
CompactStatus,
|
|
9
9
|
CompactTraceObserver,
|
|
10
|
-
} from './
|
|
10
|
+
} from './compact-contract.js';
|
|
11
11
|
import { implementationHintSuggestionProjection } from
|
|
12
12
|
'./implementation-hints.js';
|
|
13
13
|
import {
|
|
14
14
|
isSafeCompactReferenceName,
|
|
15
15
|
projectCompactReferenceGroup,
|
|
16
|
-
} from './
|
|
16
|
+
} from './compact-decision-normalization.js';
|
|
17
17
|
|
|
18
18
|
export interface TraceEdgeSemantics {
|
|
19
19
|
source: CompactSemanticEndpoint;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TraceEdge } from '../types.js';
|
|
2
|
-
import type { CompactSemanticEndpoint, CompactStatus } from './
|
|
2
|
+
import type { CompactSemanticEndpoint, CompactStatus } from './compact-contract.js';
|
|
3
3
|
import {
|
|
4
4
|
compactDecisionFromEvidence,
|
|
5
5
|
compactEvidenceReasonCode,
|
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
type SemanticCallRow,
|
|
18
18
|
type SemanticTargetRow,
|
|
19
19
|
type TraceEdgeRecorder,
|
|
20
|
-
} from './
|
|
21
|
-
import type { PlannedEventSubscriberTransition } from './
|
|
20
|
+
} from './trace-edge-recorder.js';
|
|
21
|
+
import type { PlannedEventSubscriberTransition } from './event-subscriber-traversal.js';
|
|
22
22
|
import type { DynamicCandidateBranch } from './dynamic-branches.js';
|
|
23
23
|
|
|
24
24
|
interface ImplementationObservation {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
|
-
import { schemaLifecycleDiagnostic } from '../db/
|
|
2
|
+
import { schemaLifecycleDiagnostic } from '../db/fact-lifecycle.js';
|
|
3
3
|
import type {
|
|
4
4
|
TraceEdge,
|
|
5
5
|
TraceOptions,
|
|
@@ -13,21 +13,21 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
loadTraceDiagnostics,
|
|
15
15
|
prependTraceDiagnostic,
|
|
16
|
-
} from './
|
|
17
|
-
import { TraversalScopeScheduler } from './
|
|
18
|
-
import { createTraceRootPlan } from './
|
|
19
|
-
import type { CompactTraceObserver } from './
|
|
20
|
-
import { TraceEdgeRecorder } from './
|
|
21
|
-
import type { ImplementationHintOptions } from './
|
|
16
|
+
} from './trace-diagnostics.js';
|
|
17
|
+
import { TraversalScopeScheduler } from './traversal-scope.js';
|
|
18
|
+
import { createTraceRootPlan } from './trace-root-scopes.js';
|
|
19
|
+
import type { CompactTraceObserver } from './compact-contract.js';
|
|
20
|
+
import { TraceEdgeRecorder } from './trace-edge-recorder.js';
|
|
21
|
+
import type { ImplementationHintOptions } from './trace-implementation-scope.js';
|
|
22
22
|
import {
|
|
23
23
|
resolveTraceStartScope,
|
|
24
24
|
type TraceStartScope,
|
|
25
|
-
} from './
|
|
25
|
+
} from './trace-start-scope.js';
|
|
26
26
|
import {
|
|
27
27
|
executeTraceScopes,
|
|
28
28
|
type TraceExecutionRuntime,
|
|
29
|
-
} from './
|
|
30
|
-
import { recordTraceStartImplementation } from './
|
|
29
|
+
} from './trace-scope-execution.js';
|
|
30
|
+
import { recordTraceStartImplementation } from './trace-start-implementation.js';
|
|
31
31
|
import { selectorNotFoundDiagnostic } from './selectors.js';
|
|
32
32
|
|
|
33
33
|
const compactObserverKey = Symbol('service-flow.compact-trace-observer');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
|
-
import { currentFactLifecycleDiagnostic } from '../db/
|
|
3
|
-
import { resolveTraversalWorkspaceId } from './
|
|
2
|
+
import { currentFactLifecycleDiagnostic } from '../db/fact-lifecycle.js';
|
|
3
|
+
import { resolveTraversalWorkspaceId } from './traversal-scope.js';
|
|
4
4
|
|
|
5
5
|
function workspaceScopeIsAmbiguous(db: Db): boolean {
|
|
6
6
|
const rows = db.prepare(`SELECT DISTINCT workspace_id workspaceId
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
2
|
import type { ImplementationHint } from '../types.js';
|
|
3
|
-
import type { TraceGraphEdgeRow } from './
|
|
3
|
+
import type { TraceGraphEdgeRow } from './trace-graph-lookups.js';
|
|
4
4
|
|
|
5
5
|
export interface ImplementationHintOptions {
|
|
6
6
|
implementationRepo?: string;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
2
|
import type { TraceEdge } from '../types.js';
|
|
3
3
|
import { implementationHintDiagnostic } from './implementation-hints.js';
|
|
4
|
-
import { contextualImplementationSelection } from './
|
|
5
|
-
import type { ContextBinding } from './
|
|
4
|
+
import { contextualImplementationSelection } from './implementation-selection.js';
|
|
5
|
+
import type { ContextBinding } from './contextual-runtime-state.js';
|
|
6
6
|
import {
|
|
7
7
|
handlerMethodNode,
|
|
8
8
|
withSelectedHandlerProvenance,
|
|
9
9
|
type SelectedHandlerEvidence,
|
|
10
|
-
} from './
|
|
11
|
-
import type { TraversalScopeState } from './
|
|
12
|
-
import type { TraceGraphEdgeRow } from './
|
|
10
|
+
} from './selected-handler-provenance.js';
|
|
11
|
+
import type { TraversalScopeState } from './traversal-scope.js';
|
|
12
|
+
import type { TraceGraphEdgeRow } from './trace-graph-lookups.js';
|
|
13
13
|
import {
|
|
14
14
|
enqueueCausalScope,
|
|
15
15
|
type TraceQueueScope,
|
|
16
|
-
} from './
|
|
17
|
-
import { parseTraceEvidence } from './
|
|
16
|
+
} from './trace-root-scopes.js';
|
|
17
|
+
import { parseTraceEvidence } from './trace-context.js';
|
|
18
18
|
import {
|
|
19
19
|
recordCycleObservation,
|
|
20
20
|
recordImplementationObservation,
|
|
21
|
-
} from './
|
|
21
|
+
} from './trace-edge-semantics.js';
|
|
22
22
|
import {
|
|
23
23
|
handlerFilesForOperation,
|
|
24
24
|
handlerScope,
|
|
25
25
|
implementationScope,
|
|
26
|
-
} from './
|
|
26
|
+
} from './trace-implementation-scope.js';
|
|
27
27
|
import type {
|
|
28
28
|
CallRow,
|
|
29
29
|
EffectiveOutbound,
|
|
30
30
|
TraceExecutionRuntime,
|
|
31
|
-
} from './
|
|
31
|
+
} from './trace-scope-execution.js';
|
|
32
32
|
|
|
33
33
|
interface OperationSelection {
|
|
34
34
|
implementation: ReturnType<typeof implementationScope>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
|
-
import { currentFactLifecycleDiagnostic } from '../db/
|
|
3
|
-
import type { ContextBinding } from './
|
|
2
|
+
import { currentFactLifecycleDiagnostic } from '../db/fact-lifecycle.js';
|
|
3
|
+
import type { ContextBinding } from './contextual-runtime-state.js';
|
|
4
4
|
import {
|
|
5
5
|
resolveTraversalWorkspaceId,
|
|
6
6
|
type TraversalScopeScheduler,
|
|
7
7
|
type TraversalScopeState,
|
|
8
|
-
} from './
|
|
8
|
+
} from './traversal-scope.js';
|
|
9
9
|
|
|
10
10
|
export interface TraceQueueScope {
|
|
11
11
|
repoId?: number;
|
|
@@ -12,32 +12,31 @@ import {
|
|
|
12
12
|
type ContextBinding,
|
|
13
13
|
type ContextualGraphRow,
|
|
14
14
|
type ContextualRuntimeResolution,
|
|
15
|
-
} from './
|
|
15
|
+
} from './contextual-runtime-state.js';
|
|
16
16
|
import {
|
|
17
17
|
TraversalScopeScheduler,
|
|
18
18
|
type TraversalScopeState,
|
|
19
|
-
} from './
|
|
20
|
-
import type { PlannedEventSubscriberTransition } from './
|
|
19
|
+
} from './traversal-scope.js';
|
|
20
|
+
import type { PlannedEventSubscriberTransition } from './event-subscriber-traversal.js';
|
|
21
21
|
import {
|
|
22
22
|
graphForCalls,
|
|
23
|
-
operationNode,
|
|
24
23
|
symbolNode,
|
|
25
24
|
type TraceGraphEdgeRow,
|
|
26
|
-
} from './
|
|
25
|
+
} from './trace-graph-lookups.js';
|
|
27
26
|
import {
|
|
28
27
|
enqueueCausalScope,
|
|
29
28
|
nextPendingRoot,
|
|
30
29
|
type PendingTraceRootScope,
|
|
31
30
|
type TraceQueueScope,
|
|
32
|
-
} from './
|
|
33
|
-
import type { CompactSemanticEndpoint } from './
|
|
34
|
-
import { TraceEdgeRecorder } from './
|
|
31
|
+
} from './trace-root-scopes.js';
|
|
32
|
+
import type { CompactSemanticEndpoint } from './compact-contract.js';
|
|
33
|
+
import { TraceEdgeRecorder } from './trace-edge-recorder.js';
|
|
35
34
|
import {
|
|
36
35
|
knownBindingsForCalls,
|
|
37
36
|
knownBindingsForScope,
|
|
38
37
|
parseTraceEvidence,
|
|
39
38
|
receiverFromTraceEvidence,
|
|
40
|
-
} from './
|
|
39
|
+
} from './trace-context.js';
|
|
41
40
|
import {
|
|
42
41
|
recordCycleObservation,
|
|
43
42
|
recordDynamicBranchObservation,
|
|
@@ -45,12 +44,18 @@ import {
|
|
|
45
44
|
recordEventCycleObservation,
|
|
46
45
|
recordLocalCallObservation,
|
|
47
46
|
recordOutboundObservation,
|
|
48
|
-
} from './
|
|
49
|
-
import { outboundScopeSymbolIds } from './
|
|
50
|
-
import type { ImplementationHintOptions } from './
|
|
51
|
-
import { processOperationTarget } from './
|
|
52
|
-
import { runtimeEventResolution, runtimeEventSubscriberPlans } from './
|
|
53
|
-
import { planLocalCallExpansion } from './
|
|
47
|
+
} from './trace-edge-semantics.js';
|
|
48
|
+
import { outboundScopeSymbolIds } from './nested-event-scopes.js';
|
|
49
|
+
import type { ImplementationHintOptions } from './trace-implementation-scope.js';
|
|
50
|
+
import { processOperationTarget } from './trace-operation-execution.js';
|
|
51
|
+
import { runtimeEventResolution, runtimeEventSubscriberPlans } from './event-runtime-resolution.js';
|
|
52
|
+
import { planLocalCallExpansion } from './local-call-expansion.js';
|
|
53
|
+
import {
|
|
54
|
+
eventShapeRuntimeEvidence,
|
|
55
|
+
outboundTraceEdgeType,
|
|
56
|
+
outboundTraceTargetNode,
|
|
57
|
+
visibleEventShapeRows,
|
|
58
|
+
} from './event-shape-candidate-trace.js';
|
|
54
59
|
|
|
55
60
|
export interface CallRow extends Record<string, unknown> {
|
|
56
61
|
id: number;
|
|
@@ -90,16 +95,6 @@ export interface TraceExecutionRuntime {
|
|
|
90
95
|
recorder: TraceEdgeRecorder;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
|
-
function traceEdgeType(call: CallRow, row: TraceGraphRow): string {
|
|
94
|
-
if (row.to_kind === 'operation'
|
|
95
|
-
&& row.edge_type === 'REMOTE_CALL_RESOLVES_TO_OPERATION')
|
|
96
|
-
return 'remote_action';
|
|
97
|
-
if (row.to_kind === 'operation'
|
|
98
|
-
&& row.edge_type === 'LOCAL_CALL_RESOLVES_TO_OPERATION')
|
|
99
|
-
return 'local_service_call';
|
|
100
|
-
return String(call.call_type);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
98
|
function includeCall(type: string, options: TraceOptions): boolean {
|
|
104
99
|
if (!options.includeDb && type === 'local_db_query') return false;
|
|
105
100
|
if (!options.includeExternal && type === 'external_http') return false;
|
|
@@ -339,7 +334,9 @@ function processOutboundCall(
|
|
|
339
334
|
const contextual = contextualRuntimeResolution(
|
|
340
335
|
runtime.db, call, bindings.get(receiver), call.workspaceId, persistedRows,
|
|
341
336
|
);
|
|
342
|
-
const rows = contextual.row
|
|
337
|
+
const rows = contextual.row
|
|
338
|
+
? [contextual.row]
|
|
339
|
+
: visibleEventShapeRows(persistedRows, runtime.options);
|
|
343
340
|
for (const row of rows)
|
|
344
341
|
processOutboundRow(runtime, current, call, { ...row }, contextual);
|
|
345
342
|
}
|
|
@@ -385,16 +382,23 @@ function recordEffectiveOutbound(
|
|
|
385
382
|
): EffectiveOutbound {
|
|
386
383
|
const persisted = parseTraceEvidence(row.evidence_json);
|
|
387
384
|
const raw = baseTraceEvidence(row, call, persisted, contextual.evidence);
|
|
388
|
-
const
|
|
385
|
+
const resolved = runtimeEventResolution(row, raw, runtime.options.vars)
|
|
389
386
|
?? runtimeResolution(runtime.db, row, raw, {
|
|
390
387
|
vars: runtime.options.vars,
|
|
391
388
|
dynamicMode: runtime.options.dynamicMode ?? 'strict',
|
|
392
389
|
maxDynamicCandidates: runtime.options.maxDynamicCandidates,
|
|
393
390
|
}, call.workspaceId, contextual.state);
|
|
391
|
+
const effective = {
|
|
392
|
+
...resolved,
|
|
393
|
+
evidence: eventShapeRuntimeEvidence(
|
|
394
|
+
runtime.db, call.workspaceId, call.id, call.call_type,
|
|
395
|
+
resolved.evidence, runtime.options.vars,
|
|
396
|
+
),
|
|
397
|
+
};
|
|
394
398
|
const target = `${effective.row.to_kind}:${effective.row.to_id}`;
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
399
|
+
runtime.nodes.set(
|
|
400
|
+
target, outboundTraceTargetNode(runtime.db, target, effective.row),
|
|
401
|
+
);
|
|
398
402
|
const to = edgeTarget(effective.row, effective.evidence);
|
|
399
403
|
const edge = outboundTraceEdge(
|
|
400
404
|
current.depth, call, effective.row, to,
|
|
@@ -418,18 +422,6 @@ function recordEffectiveOutbound(
|
|
|
418
422
|
};
|
|
419
423
|
}
|
|
420
424
|
|
|
421
|
-
function targetNode(
|
|
422
|
-
id: string,
|
|
423
|
-
row: TraceGraphRow,
|
|
424
|
-
): Record<string, unknown> {
|
|
425
|
-
return {
|
|
426
|
-
id,
|
|
427
|
-
kind: row.to_kind,
|
|
428
|
-
label: row.to_kind === 'db_entity'
|
|
429
|
-
? `Entity: ${row.to_id || 'unknown'}` : row.to_id,
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
|
|
433
425
|
function outboundTraceEdge(
|
|
434
426
|
depth: number,
|
|
435
427
|
call: CallRow,
|
|
@@ -440,7 +432,7 @@ function outboundTraceEdge(
|
|
|
440
432
|
): TraceEdge {
|
|
441
433
|
return {
|
|
442
434
|
step: depth,
|
|
443
|
-
type:
|
|
435
|
+
type: outboundTraceEdgeType(call, row),
|
|
444
436
|
from: `${call.repoName}:${call.source_file}:${call.source_line}`,
|
|
445
437
|
to,
|
|
446
438
|
evidence,
|