@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.
Files changed (144) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +9 -5
  3. package/TECHNICAL-NOTE.md +17 -0
  4. package/dist/{chunk-3N3B5KHV.js → chunk-Z6D433R5.js} +8766 -6546
  5. package/dist/chunk-Z6D433R5.js.map +1 -0
  6. package/dist/cli.js +703 -160
  7. package/dist/cli.js.map +1 -1
  8. package/dist/index.d.ts +53 -14
  9. package/dist/index.js +2 -23
  10. package/dist/index.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/cli/doctor-event-quality.ts +371 -0
  13. package/src/cli/{002-doctor-lifecycle.ts → doctor-lifecycle.ts} +1 -1
  14. package/src/cli/{001-doctor-projection.ts → doctor-projection.ts} +1 -1
  15. package/src/cli/doctor.ts +9 -11
  16. package/src/cli.ts +6 -6
  17. package/src/db/{009-binding-fact-semantics.ts → binding-fact-semantics.ts} +2 -2
  18. package/src/db/{000-call-fact-repository.ts → call-fact-repository.ts} +12 -9
  19. package/src/db/{003-current-fact-semantics.ts → current-fact-semantics.ts} +8 -8
  20. package/src/db/event-fact-semantics.ts +347 -0
  21. package/src/db/event-surface-invalidation.ts +38 -0
  22. package/src/db/{002-fact-json-inventory.ts → fact-json-inventory.ts} +16 -0
  23. package/src/db/{001-fact-lifecycle.ts → fact-lifecycle.ts} +3 -3
  24. package/src/db/migrations.ts +12 -1
  25. package/src/db/{007-package-fact-semantics.ts → package-fact-semantics.ts} +6 -6
  26. package/src/db/{010-package-symbol-surface-semantics.ts → package-symbol-surface-semantics.ts} +2 -2
  27. package/src/db/{004-package-target-invalidation.ts → package-target-invalidation.ts} +80 -1
  28. package/src/db/{008-relative-fact-semantics.ts → relative-fact-semantics.ts} +3 -3
  29. package/src/db/{006-relative-symbol-resolution.ts → relative-symbol-resolution.ts} +1 -1
  30. package/src/db/repositories.ts +31 -5
  31. package/src/db/{005-schema-structure.ts → schema-structure.ts} +41 -1
  32. package/src/db/schema.ts +6 -2
  33. package/src/db/{011-symbol-call-semantics.ts → symbol-call-semantics.ts} +1 -1
  34. package/src/index.ts +3 -3
  35. package/src/indexer/repository-indexer.ts +50 -11
  36. package/src/indexer/workspace-indexer.ts +3 -3
  37. package/src/linker/{007-call-edge-insertion.ts → call-edge-insertion.ts} +2 -2
  38. package/src/linker/{002-call-evidence.ts → call-evidence.ts} +2 -2
  39. package/src/linker/cross-repo-linker.ts +30 -8
  40. package/src/linker/dynamic-edge-resolver.ts +1 -1
  41. package/src/linker/event-environment-link.ts +211 -0
  42. package/src/linker/event-shape-candidate-linker.ts +161 -0
  43. package/src/linker/{004-event-subscription-handler-linker.ts → event-subscription-handler-linker.ts} +124 -20
  44. package/src/linker/{006-event-template-link.ts → event-template-link.ts} +40 -6
  45. package/src/linker/external-http-target.ts +1 -1
  46. package/src/linker/helper-package-linker.ts +1 -1
  47. package/src/linker/{000-implementation-candidates.ts → implementation-candidates.ts} +1 -1
  48. package/src/linker/{001-implementation-evidence-projection.ts → implementation-evidence-projection.ts} +1 -1
  49. package/src/linker/odata-path-normalizer.ts +1 -1
  50. package/src/linker/{005-odata-path-structure.ts → odata-path-structure.ts} +1 -1
  51. package/src/linker/package-event-constant-resolver.ts +298 -0
  52. package/src/linker/{003-package-import-symbol-resolver.ts → package-import-symbol-resolver.ts} +3 -3
  53. package/src/linker/service-resolver.ts +2 -2
  54. package/src/output/{001-compact-json-output.ts → compact-json-output.ts} +1 -1
  55. package/src/output/table-output.ts +13 -1
  56. package/src/parsers/{006-binding-identity.ts → binding-identity.ts} +3 -3
  57. package/src/parsers/{011-binding-lexical-scope.ts → binding-lexical-scope.ts} +1 -1
  58. package/src/parsers/{021-binding-visibility.ts → binding-visibility.ts} +1 -1
  59. package/src/parsers/decorator-parser.ts +9 -53
  60. package/src/parsers/environment-declarations.ts +327 -0
  61. package/src/parsers/event-call-analysis.ts +242 -0
  62. package/src/parsers/event-environment-reference.ts +231 -0
  63. package/src/parsers/event-loop-registration.ts +132 -0
  64. package/src/parsers/event-name-import-resolution.ts +243 -0
  65. package/src/parsers/event-receiver-analysis.ts +404 -0
  66. package/src/parsers/{005-event-subscription-facts.ts → event-subscription-facts.ts} +6 -2
  67. package/src/parsers/generated-constants-parser.ts +80 -14
  68. package/src/parsers/{016-local-symbol-reference.ts → local-symbol-reference.ts} +2 -2
  69. package/src/parsers/operation-path-analysis.ts +1 -1
  70. package/src/parsers/{023-outbound-call-classifier.ts → outbound-call-classifier.ts} +30 -127
  71. package/src/parsers/outbound-call-parser.ts +15 -3
  72. package/src/parsers/{022-outbound-expression-analysis.ts → outbound-expression-analysis.ts} +4 -4
  73. package/src/parsers/{018-package-commonjs-syntax.ts → package-commonjs-syntax.ts} +1 -1
  74. package/src/parsers/{012-package-fact-contract.ts → package-fact-contract.ts} +3 -3
  75. package/src/parsers/{010-package-public-surface-analysis.ts → package-public-surface-analysis.ts} +2 -2
  76. package/src/parsers/{003-package-public-surface.ts → package-public-surface.ts} +3 -3
  77. package/src/parsers/{008-package-surface-publication.ts → package-surface-publication.ts} +1 -1
  78. package/src/parsers/{001-query-entity-resolution.ts → query-entity-resolution.ts} +1 -1
  79. package/src/parsers/{015-service-binding-collector.ts → service-binding-collector.ts} +3 -3
  80. package/src/parsers/{014-service-binding-helper-flow.ts → service-binding-helper-flow.ts} +2 -2
  81. package/src/parsers/service-binding-parser-helpers.ts +1 -1
  82. package/src/parsers/service-binding-parser.ts +2 -2
  83. package/src/parsers/{007-source-fact-reconciliation.ts → source-fact-reconciliation.ts} +3 -3
  84. package/src/parsers/{020-stable-local-value.ts → stable-local-value.ts} +32 -11
  85. package/src/parsers/string-constant-lookups.ts +358 -0
  86. package/src/parsers/{009-symbol-call-facts.ts → symbol-call-facts.ts} +3 -3
  87. package/src/parsers/{017-symbol-derived-contexts.ts → symbol-derived-contexts.ts} +2 -2
  88. package/src/parsers/symbol-parser.ts +6 -6
  89. package/src/trace/{021-compact-decision-normalization.ts → compact-decision-normalization.ts} +2 -2
  90. package/src/trace/{020-compact-field-projection.ts → compact-field-projection.ts} +3 -3
  91. package/src/trace/{024-compact-observation-decision.ts → compact-observation-decision.ts} +3 -3
  92. package/src/trace/{016-compact-projector.ts → compact-projector.ts} +4 -4
  93. package/src/trace/{018-compact-trace.ts → compact-trace.ts} +3 -3
  94. package/src/trace/{006-contextual-projection.ts → contextual-projection.ts} +1 -1
  95. package/src/trace/{008-contextual-runtime-state.ts → contextual-runtime-state.ts} +1 -1
  96. package/src/trace/{001-dynamic-identity.ts → dynamic-identity.ts} +2 -2
  97. package/src/trace/{003-dynamic-references.ts → dynamic-references.ts} +2 -2
  98. package/src/trace/dynamic-targets.ts +6 -6
  99. package/src/trace/{030-event-runtime-resolution.ts → event-runtime-resolution.ts} +26 -5
  100. package/src/trace/event-shape-candidate-trace.ts +172 -0
  101. package/src/trace/{011-event-subscriber-traversal.ts → event-subscriber-traversal.ts} +20 -8
  102. package/src/trace/evidence.ts +9 -2
  103. package/src/trace/implementation-hints.ts +2 -2
  104. package/src/trace/{005-implementation-selection.ts → implementation-selection.ts} +2 -2
  105. package/src/trace/{031-local-call-expansion.ts → local-call-expansion.ts} +3 -3
  106. package/src/trace/{009-selected-handler-provenance.ts → selected-handler-provenance.ts} +1 -1
  107. package/src/trace/selectors.ts +1 -1
  108. package/src/trace/{017-trace-context.ts → trace-context.ts} +2 -2
  109. package/src/trace/{015-trace-edge-recorder.ts → trace-edge-recorder.ts} +2 -2
  110. package/src/trace/{019-trace-edge-semantics.ts → trace-edge-semantics.ts} +3 -3
  111. package/src/trace/trace-engine.ts +10 -10
  112. package/src/trace/{022-trace-fact-preflight.ts → trace-fact-preflight.ts} +2 -2
  113. package/src/trace/{025-trace-implementation-scope.ts → trace-implementation-scope.ts} +1 -1
  114. package/src/trace/{028-trace-operation-execution.ts → trace-operation-execution.ts} +10 -10
  115. package/src/trace/{013-trace-root-scopes.ts → trace-root-scopes.ts} +3 -3
  116. package/src/trace/{027-trace-scope-execution.ts → trace-scope-execution.ts} +35 -43
  117. package/src/trace/{029-trace-start-implementation.ts → trace-start-implementation.ts} +7 -7
  118. package/src/trace/{026-trace-start-scope.ts → trace-start-scope.ts} +5 -5
  119. package/src/trace/{010-traversal-scope.ts → traversal-scope.ts} +1 -1
  120. package/src/types.ts +17 -1
  121. package/src/utils/event-skeleton.ts +207 -0
  122. package/src/version.ts +1 -1
  123. package/dist/chunk-3N3B5KHV.js.map +0 -1
  124. /package/src/cli/{000-clean.ts → clean.ts} +0 -0
  125. /package/src/cli/{003-doctor-package-resolution.ts → doctor-package-resolution.ts} +0 -0
  126. /package/src/cli/{001-index-summary.ts → index-summary.ts} +0 -0
  127. /package/src/db/{014-binding-helper-provenance.ts → binding-helper-provenance.ts} +0 -0
  128. /package/src/db/{012-binding-reference-proof.ts → binding-reference-proof.ts} +0 -0
  129. /package/src/db/{013-index-publication-failure.ts → index-publication-failure.ts} +0 -0
  130. /package/src/output/{000-stdout-policy.ts → stdout-policy.ts} +0 -0
  131. /package/src/parsers/{019-binding-assignment-targets.ts → binding-assignment-targets.ts} +0 -0
  132. /package/src/parsers/{000-direct-query-execution.ts → direct-query-execution.ts} +0 -0
  133. /package/src/parsers/{013-executable-body-eligibility.ts → executable-body-eligibility.ts} +0 -0
  134. /package/src/parsers/{004-fact-identity.ts → fact-identity.ts} +0 -0
  135. /package/src/parsers/{002-symbol-import-bindings.ts → symbol-import-bindings.ts} +0 -0
  136. /package/src/trace/{014-compact-contract.ts → compact-contract.ts} +0 -0
  137. /package/src/trace/{004-dynamic-candidate-sources.ts → dynamic-candidate-sources.ts} +0 -0
  138. /package/src/trace/{000-dynamic-target-types.ts → dynamic-target-types.ts} +0 -0
  139. /package/src/trace/{007-implementation-start-diagnostic.ts → implementation-start-diagnostic.ts} +0 -0
  140. /package/src/trace/{023-nested-event-scopes.ts → nested-event-scopes.ts} +0 -0
  141. /package/src/trace/{002-trace-diagnostics.ts → trace-diagnostics.ts} +0 -0
  142. /package/src/trace/{012-trace-graph-lookups.ts → trace-graph-lookups.ts} +0 -0
  143. /package/src/utils/{000-bounded-projection.ts → bounded-projection.ts} +0 -0
  144. /package/src/utils/{001-placeholders.ts → placeholders.ts} +0 -0
@@ -0,0 +1,358 @@
1
+ import ts from 'typescript';
2
+ import { stableLocalValueReference } from './stable-local-value.js';
3
+ import { lexicalIdentifierDeclaration } from './symbol-import-bindings.js';
4
+
5
+ export type StaticStringConstantKind =
6
+ | 'const_identifier'
7
+ | 'enum_member'
8
+ | 'const_object_property';
9
+
10
+ export interface StaticStringConstant {
11
+ key: string;
12
+ value: string;
13
+ kind: StaticStringConstantKind;
14
+ containerName?: string;
15
+ memberName?: string;
16
+ sourceFile: string;
17
+ declarationStartOffset: number;
18
+ declarationEndOffset: number;
19
+ valueStartOffset: number;
20
+ valueEndOffset: number;
21
+ exported: boolean;
22
+ stable: boolean;
23
+ }
24
+
25
+ export interface StaticStringRefusal {
26
+ key: string;
27
+ kind: StaticStringConstantKind;
28
+ containerName?: string;
29
+ memberName?: string;
30
+ sourceFile: string;
31
+ declarationStartOffset: number;
32
+ declarationEndOffset: number;
33
+ exported: boolean;
34
+ stable: boolean;
35
+ reason: 'event_name_constant_member_not_string'
36
+ | 'event_name_constant_container_mutable';
37
+ }
38
+
39
+ export interface StringConstantLookups {
40
+ identifiers: Map<string, StaticStringConstant>;
41
+ enumMembers: Map<string, StaticStringConstant>;
42
+ objectProperties: Map<string, StaticStringConstant>;
43
+ refusedMembers: Map<string, StaticStringRefusal>;
44
+ }
45
+
46
+ export type StaticStringLookupResult =
47
+ | { status: 'resolved'; constant: StaticStringConstant }
48
+ | { status: 'refused'; reason: string }
49
+ | { status: 'not_found' };
50
+
51
+ function unwrapExpression(expression: ts.Expression): ts.Expression {
52
+ if (ts.isParenthesizedExpression(expression)
53
+ || ts.isAsExpression(expression)
54
+ || ts.isSatisfiesExpression(expression)
55
+ || ts.isTypeAssertionExpression(expression))
56
+ return unwrapExpression(expression.expression);
57
+ return expression;
58
+ }
59
+
60
+ function stringValue(
61
+ expression: ts.Expression | undefined,
62
+ ): { value: string; node: ts.Expression } | undefined {
63
+ if (!expression) return undefined;
64
+ const value = unwrapExpression(expression);
65
+ return ts.isStringLiteralLike(value)
66
+ ? { value: value.text, node: value } : undefined;
67
+ }
68
+
69
+ function propertyName(name: ts.PropertyName): string | undefined {
70
+ return ts.isIdentifier(name) || ts.isStringLiteralLike(name)
71
+ || ts.isNumericLiteral(name) ? name.text : undefined;
72
+ }
73
+
74
+ function exportedNames(source: ts.SourceFile): Set<string> {
75
+ const names = new Set<string>();
76
+ for (const statement of source.statements) {
77
+ if (!ts.isExportDeclaration(statement) || statement.moduleSpecifier
78
+ || !statement.exportClause
79
+ || !ts.isNamedExports(statement.exportClause)) continue;
80
+ for (const element of statement.exportClause.elements)
81
+ names.add(element.propertyName?.text ?? element.name.text);
82
+ }
83
+ return names;
84
+ }
85
+
86
+ function hasExportModifier(node: ts.Node): boolean {
87
+ return ts.canHaveModifiers(node)
88
+ && Boolean(ts.getModifiers(node)?.some((modifier) =>
89
+ modifier.kind === ts.SyntaxKind.ExportKeyword));
90
+ }
91
+
92
+ function staticFact(
93
+ source: ts.SourceFile,
94
+ key: string,
95
+ value: { value: string; node: ts.Expression },
96
+ declaration: ts.Node,
97
+ fields: Pick<StaticStringConstant, 'kind' | 'exported' | 'stable'>
98
+ & Partial<Pick<StaticStringConstant, 'containerName' | 'memberName'>>,
99
+ ): StaticStringConstant {
100
+ return {
101
+ key,
102
+ value: value.value,
103
+ sourceFile: source.fileName,
104
+ declarationStartOffset: declaration.getStart(source),
105
+ declarationEndOffset: declaration.getEnd(),
106
+ valueStartOffset: value.node.getStart(source),
107
+ valueEndOffset: value.node.getEnd(),
108
+ ...fields,
109
+ };
110
+ }
111
+
112
+ function refusalFact(
113
+ source: ts.SourceFile,
114
+ key: string,
115
+ declaration: ts.Node,
116
+ fields: Pick<StaticStringRefusal,
117
+ 'kind' | 'exported' | 'stable' | 'reason'>
118
+ & Partial<Pick<StaticStringRefusal, 'containerName' | 'memberName'>>,
119
+ ): StaticStringRefusal {
120
+ return {
121
+ key,
122
+ sourceFile: source.fileName,
123
+ declarationStartOffset: declaration.getStart(source),
124
+ declarationEndOffset: declaration.getEnd(),
125
+ ...fields,
126
+ };
127
+ }
128
+
129
+ function collectEnum(
130
+ source: ts.SourceFile,
131
+ statement: ts.EnumDeclaration,
132
+ exports: Set<string>,
133
+ lookups: StringConstantLookups,
134
+ ): void {
135
+ const stable = stableLocalValueReference(source, statement.name);
136
+ const exported = hasExportModifier(statement)
137
+ || exports.has(statement.name.text);
138
+ for (const member of statement.members) {
139
+ const memberName = propertyName(member.name);
140
+ if (!memberName) continue;
141
+ const key = `${statement.name.text}.${memberName}`;
142
+ const value = stringValue(member.initializer);
143
+ if (!stable) lookups.refusedMembers.set(key, refusalFact(
144
+ source, key, member, {
145
+ kind: 'enum_member', containerName: statement.name.text,
146
+ memberName, exported, stable,
147
+ reason: 'event_name_constant_container_mutable',
148
+ },
149
+ ));
150
+ else if (!value) lookups.refusedMembers.set(key, refusalFact(
151
+ source, key, member, {
152
+ kind: 'enum_member', containerName: statement.name.text,
153
+ memberName, exported, stable,
154
+ reason: 'event_name_constant_member_not_string',
155
+ },
156
+ ));
157
+ else lookups.enumMembers.set(key, staticFact(
158
+ source, key, value, member, {
159
+ kind: 'enum_member',
160
+ containerName: statement.name.text,
161
+ memberName,
162
+ exported,
163
+ stable,
164
+ },
165
+ ));
166
+ }
167
+ }
168
+
169
+ function objectLiteral(
170
+ expression: ts.Expression,
171
+ ): ts.ObjectLiteralExpression | undefined {
172
+ const value = unwrapExpression(expression);
173
+ return ts.isObjectLiteralExpression(value) ? value : undefined;
174
+ }
175
+
176
+ function collectObject(
177
+ source: ts.SourceFile,
178
+ statement: ts.VariableStatement,
179
+ declaration: ts.VariableDeclaration,
180
+ exports: Set<string>,
181
+ lookups: StringConstantLookups,
182
+ ): void {
183
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) return;
184
+ const object = objectLiteral(declaration.initializer);
185
+ if (!object) return;
186
+ const stable = stableLocalValueReference(source, declaration.name);
187
+ const exported = hasExportModifier(statement)
188
+ || exports.has(declaration.name.text);
189
+ for (const property of object.properties) {
190
+ if (!ts.isPropertyAssignment(property)) continue;
191
+ const memberName = propertyName(property.name);
192
+ if (!memberName) continue;
193
+ const key = `${declaration.name.text}.${memberName}`;
194
+ const value = stringValue(property.initializer);
195
+ if (!stable) lookups.refusedMembers.set(key, refusalFact(
196
+ source, key, property, {
197
+ kind: 'const_object_property',
198
+ containerName: declaration.name.text, memberName,
199
+ exported, stable,
200
+ reason: 'event_name_constant_container_mutable',
201
+ },
202
+ ));
203
+ else if (!value) lookups.refusedMembers.set(key, refusalFact(
204
+ source, key, property, {
205
+ kind: 'const_object_property',
206
+ containerName: declaration.name.text, memberName,
207
+ exported, stable,
208
+ reason: 'event_name_constant_member_not_string',
209
+ },
210
+ ));
211
+ else lookups.objectProperties.set(key, staticFact(
212
+ source, key, value, property, {
213
+ kind: 'const_object_property',
214
+ containerName: declaration.name.text,
215
+ memberName,
216
+ exported,
217
+ stable,
218
+ },
219
+ ));
220
+ }
221
+ }
222
+
223
+ function collectIdentifier(
224
+ source: ts.SourceFile,
225
+ statement: ts.VariableStatement,
226
+ declaration: ts.VariableDeclaration,
227
+ exports: Set<string>,
228
+ lookups: StringConstantLookups,
229
+ ): void {
230
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) return;
231
+ const value = stringValue(declaration.initializer);
232
+ if (!value) return;
233
+ const key = declaration.name.text;
234
+ lookups.identifiers.set(key, staticFact(
235
+ source, key, value, declaration, {
236
+ kind: 'const_identifier',
237
+ exported: hasExportModifier(statement) || exports.has(key),
238
+ stable: true,
239
+ },
240
+ ));
241
+ }
242
+
243
+ export function collectStringConstantLookups(
244
+ source: ts.SourceFile,
245
+ ): StringConstantLookups {
246
+ const lookups: StringConstantLookups = {
247
+ identifiers: new Map(),
248
+ enumMembers: new Map(),
249
+ objectProperties: new Map(),
250
+ refusedMembers: new Map(),
251
+ };
252
+ const exports = exportedNames(source);
253
+ for (const statement of source.statements) {
254
+ if (ts.isEnumDeclaration(statement))
255
+ collectEnum(source, statement, exports, lookups);
256
+ if (!ts.isVariableStatement(statement)
257
+ || (statement.declarationList.flags & ts.NodeFlags.Const) === 0) continue;
258
+ for (const declaration of statement.declarationList.declarations) {
259
+ collectIdentifier(source, statement, declaration, exports, lookups);
260
+ collectObject(source, statement, declaration, exports, lookups);
261
+ }
262
+ }
263
+ return lookups;
264
+ }
265
+
266
+ export function resolveStringConstant(
267
+ expression: ts.Expression,
268
+ lookups: StringConstantLookups,
269
+ ): StaticStringLookupResult {
270
+ const value = unwrapExpression(expression);
271
+ if (ts.isIdentifier(value)) {
272
+ const constant = lookups.identifiers.get(value.text);
273
+ return constant && constantReferenceMatches(value, constant)
274
+ ? { status: 'resolved', constant } : { status: 'not_found' };
275
+ }
276
+ if (ts.isElementAccessExpression(value)
277
+ && ts.isIdentifier(value.expression)) {
278
+ const prefix = `${value.expression.text}.`;
279
+ const known = [
280
+ ...lookups.enumMembers.keys(),
281
+ ...lookups.objectProperties.keys(),
282
+ ...lookups.refusedMembers.keys(),
283
+ ].some((key) => key.startsWith(prefix));
284
+ return known && constantContainerMatches(
285
+ value.expression, lookups, prefix,
286
+ ) ? {
287
+ status: 'refused',
288
+ reason: 'event_name_constant_container_ambiguous',
289
+ } : { status: 'not_found' };
290
+ }
291
+ if (!ts.isPropertyAccessExpression(value)
292
+ || value.questionDotToken || !ts.isIdentifier(value.expression))
293
+ return { status: 'not_found' };
294
+ const key = `${value.expression.text}.${value.name.text}`;
295
+ const constant = lookups.enumMembers.get(key)
296
+ ?? lookups.objectProperties.get(key);
297
+ if (constant && constantReferenceMatches(value.expression, constant))
298
+ return { status: 'resolved', constant };
299
+ const reason = lookups.refusedMembers.get(key);
300
+ return reason && refusalReferenceMatches(value.expression, reason)
301
+ ? { status: 'refused', reason: reason.reason }
302
+ : constant || reason ? {
303
+ status: 'refused',
304
+ reason: 'event_name_constant_container_ambiguous',
305
+ } : { status: 'not_found' };
306
+ }
307
+
308
+ function declarationContains(
309
+ identifier: ts.Identifier,
310
+ startOffset: number,
311
+ endOffset: number,
312
+ ): boolean {
313
+ const declaration = lexicalIdentifierDeclaration(identifier);
314
+ if (!declaration) return false;
315
+ const owner = declaration.parent;
316
+ return owner.getSourceFile() === identifier.getSourceFile()
317
+ && owner.getStart(identifier.getSourceFile()) <= startOffset
318
+ && owner.getEnd() >= endOffset;
319
+ }
320
+
321
+ function constantReferenceMatches(
322
+ identifier: ts.Identifier,
323
+ constant: StaticStringConstant,
324
+ ): boolean {
325
+ return declarationContains(
326
+ identifier,
327
+ constant.declarationStartOffset,
328
+ constant.declarationEndOffset,
329
+ );
330
+ }
331
+
332
+ function refusalReferenceMatches(
333
+ identifier: ts.Identifier,
334
+ refusal: StaticStringRefusal,
335
+ ): boolean {
336
+ return declarationContains(
337
+ identifier,
338
+ refusal.declarationStartOffset,
339
+ refusal.declarationEndOffset,
340
+ );
341
+ }
342
+
343
+ function constantContainerMatches(
344
+ identifier: ts.Identifier,
345
+ lookups: StringConstantLookups,
346
+ prefix: string,
347
+ ): boolean {
348
+ const constants = [
349
+ ...lookups.enumMembers.values(),
350
+ ...lookups.objectProperties.values(),
351
+ ].filter((item) => item.key.startsWith(prefix));
352
+ const refusals = [...lookups.refusedMembers.values()]
353
+ .filter((item) => item.key.startsWith(prefix));
354
+ return [...constants, ...refusals].some((item) =>
355
+ declarationContains(
356
+ identifier, item.declarationStartOffset, item.declarationEndOffset,
357
+ ));
358
+ }
@@ -6,18 +6,18 @@ import type {
6
6
  import {
7
7
  executableSymbolCandidates,
8
8
  selectCallOwner,
9
- } from './004-fact-identity.js';
9
+ } from './fact-identity.js';
10
10
  import {
11
11
  derivedMemberImportReference,
12
12
  identifierMatchesDeclaration,
13
13
  symbolImportReference,
14
14
  type SymbolImportBinding,
15
15
  type SymbolImportReference,
16
- } from './002-symbol-import-bindings.js';
16
+ } from './symbol-import-bindings.js';
17
17
  import {
18
18
  localSymbolTarget,
19
19
  type LocalSymbolTargetIdentity,
20
- } from './016-local-symbol-reference.js';
20
+ } from './local-symbol-reference.js';
21
21
 
22
22
  export interface SymbolCallProxy {
23
23
  importSource: string;
@@ -3,12 +3,12 @@ import {
3
3
  symbolCallName,
4
4
  type SymbolCallProxy,
5
5
  type SymbolClassInstance,
6
- } from './009-symbol-call-facts.js';
6
+ } from './symbol-call-facts.js';
7
7
  import {
8
8
  identifierMatchesDeclaration,
9
9
  symbolImportReference,
10
10
  type SymbolImportBinding,
11
- } from './002-symbol-import-bindings.js';
11
+ } from './symbol-import-bindings.js';
12
12
 
13
13
  interface DerivedContextCollection {
14
14
  source: ts.SourceFile;
@@ -9,24 +9,24 @@ import {
9
9
  } from './outbound-call-parser.js';
10
10
  import type { RepositorySourceContext } from './ts-project.js';
11
11
  import { normalizePath } from '../utils/path-utils.js';
12
- import { reconcileEventSubscriptions } from './005-event-subscription-facts.js';
13
- import { reconcileSymbolCallOwners } from './007-source-fact-reconciliation.js';
12
+ import { reconcileEventSubscriptions } from './event-subscription-facts.js';
13
+ import { reconcileSymbolCallOwners } from './source-fact-reconciliation.js';
14
14
  import {
15
15
  collectSymbolImportBindings,
16
16
  type SymbolImportBinding,
17
- } from './002-symbol-import-bindings.js';
17
+ } from './symbol-import-bindings.js';
18
18
  import {
19
19
  collectSymbolCallFacts,
20
20
  symbolCallName,
21
21
  type SymbolCallProxy,
22
22
  type SymbolClassInstance,
23
- } from './009-symbol-call-facts.js';
23
+ } from './symbol-call-facts.js';
24
24
  import {
25
25
  executableBodyEligibility,
26
- } from './013-executable-body-eligibility.js';
26
+ } from './executable-body-eligibility.js';
27
27
  import {
28
28
  collectDerivedSymbolContexts,
29
- } from './017-symbol-derived-contexts.js';
29
+ } from './symbol-derived-contexts.js';
30
30
 
31
31
  function lineOf(source: ts.SourceFile, pos: number): number {
32
32
  return source.getLineAndCharacterOfPosition(pos).line + 1;
@@ -1,9 +1,9 @@
1
- import { compareBinary } from './010-traversal-scope.js';
1
+ import { compareBinary } from './traversal-scope.js';
2
2
  import type {
3
3
  CompactDecisionV1,
4
4
  CompactReferenceGroupV1,
5
5
  CompactStatus,
6
- } from './014-compact-contract.js';
6
+ } from './compact-contract.js';
7
7
 
8
8
  export const COMPACT_MISSING_NAME_LIMIT = 8;
9
9
  export const COMPACT_MISSING_NAME_MAX_LENGTH = 160;
@@ -4,7 +4,7 @@ import type {
4
4
  TraceOptions,
5
5
  TraceStart,
6
6
  } from '../types.js';
7
- import { compareBinary } from './010-traversal-scope.js';
7
+ import { compareBinary } from './traversal-scope.js';
8
8
  import type {
9
9
  CompactDecisionInput,
10
10
  CompactDecisionV1,
@@ -16,7 +16,7 @@ import type {
16
16
  CompactQueryV1,
17
17
  CompactStartV1,
18
18
  CompactStatusCountsV1,
19
- } from './014-compact-contract.js';
19
+ } from './compact-contract.js';
20
20
  import {
21
21
  compactMissingRemediation,
22
22
  isSafeCompactReferenceName,
@@ -24,7 +24,7 @@ import {
24
24
  projectCompactReferenceGroup,
25
25
  projectCompactMissingNames,
26
26
  type CompactMissingNameProjection,
27
- } from './021-compact-decision-normalization.js';
27
+ } from './compact-decision-normalization.js';
28
28
 
29
29
  const compactDiagnosticMessages: Readonly<Record<string, string>> = {
30
30
  schema_upgrade_required: 'The database schema must be upgraded before tracing.',
@@ -2,10 +2,10 @@ import type {
2
2
  CompactDecisionTargetInput,
3
3
  CompactDecisionV1,
4
4
  CompactEdgeObservation,
5
- } from './014-compact-contract.js';
6
- import { projectCompactDecision } from './020-compact-field-projection.js';
5
+ } from './compact-contract.js';
6
+ import { projectCompactDecision } from './compact-field-projection.js';
7
7
  import { normalizeCompactDecisionEquivalence } from
8
- './021-compact-decision-normalization.js';
8
+ './compact-decision-normalization.js';
9
9
 
10
10
  export interface CompactDecisionNode {
11
11
  key?: string;
@@ -1,6 +1,6 @@
1
1
  import type { Db } from '../db/connection.js';
2
2
  import { redactText } from '../utils/redaction.js';
3
- import { compareBinary as binaryCompare } from './010-traversal-scope.js';
3
+ import { compareBinary as binaryCompare } from './traversal-scope.js';
4
4
  import {
5
5
  type CompactDecisionTargetInput,
6
6
  type CompactProjectedDiagnostic,
@@ -17,16 +17,16 @@ import {
17
17
  type CompactSemanticEndpoint,
18
18
  type CompactSourceSite,
19
19
  type CompactStatus,
20
- } from './014-compact-contract.js';
20
+ } from './compact-contract.js';
21
21
  import {
22
22
  compactCompleteness, compactSafeCode, compactStatusCounts, compactStatusTotal,
23
23
  projectCompactDecisionTarget, projectCompactDiagnostics,
24
24
  projectCompactQuery, projectCompactStart,
25
- } from './020-compact-field-projection.js';
25
+ } from './compact-field-projection.js';
26
26
  import {
27
27
  projectObservationDecision,
28
28
  type CompactDecisionNode,
29
- } from './024-compact-observation-decision.js';
29
+ } from './compact-observation-decision.js';
30
30
 
31
31
  const REFERENCE_LIMIT = 5;
32
32
 
@@ -1,8 +1,8 @@
1
1
  import type { Db } from '../db/connection.js';
2
2
  import { CURRENT_SCHEMA_VERSION } from '../db/migrations.js';
3
- import type { CompactGraphV1, CompactSourceContext } from './014-compact-contract.js';
4
- import { CompactObservationCollector } from './014-compact-contract.js';
5
- import { projectCompactGraph } from './016-compact-projector.js';
3
+ import type { CompactGraphV1, CompactSourceContext } from './compact-contract.js';
4
+ import { CompactObservationCollector } from './compact-contract.js';
5
+ import { projectCompactGraph } from './compact-projector.js';
6
6
  import { traceWithObserver } from './trace-engine.js';
7
7
  import type { TraceOptions, TraceResult, TraceStart } from '../types.js';
8
8
 
@@ -1,4 +1,4 @@
1
- import { projectBounded } from '../utils/000-bounded-projection.js';
1
+ import { projectBounded } from '../utils/bounded-projection.js';
2
2
 
3
3
  export function boundedContextCandidates(values: unknown[]): {
4
4
  candidates: Array<Record<string, unknown>>;
@@ -1,7 +1,7 @@
1
1
  import type { Db } from '../db/connection.js';
2
2
  import { normalizeODataOperationInvocationPath } from '../linker/odata-path-normalizer.js';
3
3
  import { resolveOperation, type OperationResolution } from '../linker/service-resolver.js';
4
- import { boundedContextCandidates } from './006-contextual-projection.js';
4
+ import { boundedContextCandidates } from './contextual-projection.js';
5
5
 
6
6
  export interface ContextBinding {
7
7
  bindingId?: number;
@@ -1,10 +1,10 @@
1
1
  import type { Db } from '../db/connection.js';
2
- import { scanPlaceholders } from '../utils/001-placeholders.js';
2
+ import { scanPlaceholders } from '../utils/placeholders.js';
3
3
  import type {
4
4
  DynamicTargetCandidate,
5
5
  DynamicTemplates,
6
6
  DynamicVariableProvenance,
7
- } from './000-dynamic-target-types.js';
7
+ } from './dynamic-target-types.js';
8
8
 
9
9
  interface RouteImplementationEvidence {
10
10
  routeRepoId?: number;
@@ -2,8 +2,8 @@ import type { Db } from '../db/connection.js';
2
2
  import {
3
3
  projectBounded,
4
4
  type BoundedProjection,
5
- } from '../utils/000-bounded-projection.js';
6
- import type { DynamicVariableProvenance } from './000-dynamic-target-types.js';
5
+ } from '../utils/bounded-projection.js';
6
+ import type { DynamicVariableProvenance } from './dynamic-target-types.js';
7
7
 
8
8
  export interface DynamicReferenceRow {
9
9
  bindingId?: number;
@@ -7,25 +7,25 @@ import {
7
7
  import { normalizeODataOperationInvocationPath } from '../linker/odata-path-normalizer.js';
8
8
  import type { OperationTarget } from '../linker/service-resolver.js';
9
9
  import type { DynamicMode } from '../types.js';
10
- import { dynamicCandidateTargets } from './004-dynamic-candidate-sources.js';
11
- import { projectBounded } from '../utils/000-bounded-projection.js';
12
- import { uniqueIdentityDerivations } from './001-dynamic-identity.js';
10
+ import { dynamicCandidateTargets } from './dynamic-candidate-sources.js';
11
+ import { projectBounded } from '../utils/bounded-projection.js';
12
+ import { uniqueIdentityDerivations } from './dynamic-identity.js';
13
13
  import {
14
14
  dynamicReferenceProvenance,
15
15
  dynamicRoutingContext,
16
16
  type DynamicReferenceRow,
17
17
  type DynamicRoutingContext,
18
- } from './003-dynamic-references.js';
18
+ } from './dynamic-references.js';
19
19
  import type {
20
20
  DynamicTargetAnalysis,
21
21
  DynamicTargetCandidate,
22
22
  DynamicTemplates,
23
23
  DynamicVariableProvenance,
24
- } from './000-dynamic-target-types.js';
24
+ } from './dynamic-target-types.js';
25
25
  export type {
26
26
  DynamicTargetAnalysis,
27
27
  DynamicTargetCandidate,
28
- } from './000-dynamic-target-types.js';
28
+ } from './dynamic-target-types.js';
29
29
  type Templates = DynamicTemplates;
30
30
  type VariableProvenance = DynamicVariableProvenance;
31
31
  interface AnalysisInputs {
@@ -8,12 +8,18 @@ import {
8
8
  planEventSubscriberTransitions,
9
9
  type EventSubscriberTransitionQuery,
10
10
  type PlannedEventSubscriberTransition,
11
- } from './011-event-subscriber-traversal.js';
11
+ } from './event-subscriber-traversal.js';
12
12
  import type {
13
13
  TraversalScopeScheduler,
14
14
  TraversalScopeState,
15
- } from './010-traversal-scope.js';
15
+ } from './traversal-scope.js';
16
16
  import type { TraceGraphRow } from './evidence.js';
17
+ import {
18
+ eventMissingVariableNames,
19
+ eventTemplateVariables,
20
+ parseEventSkeletonFact,
21
+ type EventSkeletonFact,
22
+ } from '../utils/event-skeleton.js';
17
23
 
18
24
  export interface EventRuntimeResolution {
19
25
  row: TraceGraphRow;
@@ -37,6 +43,12 @@ function eventTemplate(evidence: Record<string, unknown>): string | undefined {
37
43
  ? resolution.original : undefined;
38
44
  }
39
45
 
46
+ function eventSkeleton(
47
+ evidence: Record<string, unknown>,
48
+ ): EventSkeletonFact | undefined {
49
+ return parseEventSkeletonFact(evidence.eventSkeleton);
50
+ }
51
+
40
52
  function missingReason(substitution: RuntimeSubstitution): string {
41
53
  return `Dynamic target requires runtime variable overrides: ${
42
54
  substitution.missing.join(', ')}`;
@@ -88,6 +100,10 @@ function eventEvidence(
88
100
  unresolvedReason,
89
101
  edgeType: row.edge_type,
90
102
  };
103
+ const skeleton = eventSkeleton(evidence);
104
+ const missing = eventMissingVariableNames(
105
+ skeleton, substitution.missing,
106
+ );
91
107
  return {
92
108
  ...evidence,
93
109
  runtimeSubstitutions: { eventName: substitution },
@@ -96,8 +112,10 @@ function eventEvidence(
96
112
  ),
97
113
  ...(substitution.supplied.length > 0
98
114
  ? { runtimeVariablesApplied: true } : {}),
99
- ...(substitution.missing.length > 0
100
- ? { missingRuntimeVariables: substitution.missing } : {}),
115
+ ...(missing.length > 0 ? {
116
+ missingRuntimeVariables: missing,
117
+ missingVariableCount: missing.length,
118
+ } : {}),
101
119
  effectiveResolution,
102
120
  linker: {
103
121
  status: effectiveResolution.status,
@@ -137,7 +155,10 @@ export function runtimeEventResolution(
137
155
  const template = eventTemplate(evidence);
138
156
  if (!template || row.to_kind === 'event' && variables === undefined)
139
157
  return undefined;
140
- const substitution = substituteVariables(template, variables ?? {});
158
+ const skeleton = eventSkeleton(evidence);
159
+ const substitution = substituteVariables(
160
+ template, eventTemplateVariables(skeleton, variables ?? {}),
161
+ );
141
162
  const effectiveRow = runtimeEventRow(
142
163
  row, evidence, substitution, template,
143
164
  );