gitnexus 1.6.10-rc.99 → 1.6.10

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 (775) hide show
  1. package/README.md +177 -18
  2. package/dist/_shared/graph/types.d.ts +21 -2
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +3 -3
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/index.js +1 -1
  7. package/dist/_shared/index.js.map +1 -1
  8. package/dist/_shared/integrations/circuit-breaker.d.ts.map +1 -1
  9. package/dist/_shared/integrations/circuit-breaker.js.map +1 -1
  10. package/dist/_shared/integrations/resilient-fetch.d.ts +16 -0
  11. package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
  12. package/dist/_shared/integrations/resilient-fetch.js +19 -7
  13. package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
  14. package/dist/_shared/language-detection.d.ts.map +1 -1
  15. package/dist/_shared/lbug/schema-constants.d.ts +2 -2
  16. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  17. package/dist/_shared/lbug/schema-constants.js +3 -0
  18. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  19. package/dist/_shared/scope-resolution/evidence-weights.d.ts.map +1 -1
  20. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +5 -0
  21. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
  22. package/dist/_shared/scope-resolution/finalize-algorithm.js +315 -36
  23. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  24. package/dist/_shared/scope-resolution/reference-site.d.ts +115 -0
  25. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
  26. package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -1
  27. package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -1
  28. package/dist/_shared/scope-resolution/registries/lookup-core.js +58 -2
  29. package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
  30. package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -1
  31. package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
  32. package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
  33. package/dist/_shared/scope-resolution/symbol-definition.d.ts +47 -0
  34. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  35. package/dist/_shared/scope-resolution/types.d.ts +278 -3
  36. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  37. package/dist/cli/ai-context.d.ts +3 -2
  38. package/dist/cli/ai-context.js +71 -16
  39. package/dist/cli/analyze-config.d.ts +1 -1
  40. package/dist/cli/analyze-options.d.ts +131 -0
  41. package/dist/cli/analyze-options.js +1 -0
  42. package/dist/cli/analyze.d.ts +21 -113
  43. package/dist/cli/analyze.js +172 -29
  44. package/dist/cli/cli-message.d.ts +1 -1
  45. package/dist/cli/detect-changes-format.js +19 -2
  46. package/dist/cli/doctor.d.ts +12 -0
  47. package/dist/cli/doctor.js +32 -5
  48. package/dist/cli/editor-targets.js +6 -0
  49. package/dist/cli/eval-server.js +2 -1
  50. package/dist/cli/format-symbol.d.ts +15 -0
  51. package/dist/cli/format-symbol.js +17 -0
  52. package/dist/cli/generated-skill.d.ts +17 -0
  53. package/dist/cli/generated-skill.js +1 -0
  54. package/dist/cli/group.js +229 -21
  55. package/dist/cli/help-i18n.js +1 -2
  56. package/dist/cli/i18n/en.d.ts +11 -9
  57. package/dist/cli/i18n/en.js +13 -9
  58. package/dist/cli/i18n/resources.d.ts +15 -11
  59. package/dist/cli/i18n/zh-CN.d.ts +4 -2
  60. package/dist/cli/i18n/zh-CN.js +11 -9
  61. package/dist/cli/index.js +8 -4
  62. package/dist/cli/resolve-invocation.d.ts +7 -3
  63. package/dist/cli/resolve-invocation.js +7 -3
  64. package/dist/cli/setup.js +4 -3
  65. package/dist/cli/skill-gen.d.ts +1 -6
  66. package/dist/cli/tool.d.ts +1 -0
  67. package/dist/cli/tool.js +74 -17
  68. package/dist/cli/wiki.js +53 -10
  69. package/dist/config/ignore-service.d.ts +2 -0
  70. package/dist/config/ignore-service.js +54 -13
  71. package/dist/core/analyzer-identity.d.ts +80 -0
  72. package/dist/core/analyzer-identity.js +364 -26
  73. package/dist/core/augmentation/engine.js +86 -71
  74. package/dist/core/embedding-checkpoint.d.ts +143 -0
  75. package/dist/core/embedding-checkpoint.js +221 -0
  76. package/dist/core/embedding-count.d.ts +61 -0
  77. package/dist/core/embedding-count.js +69 -0
  78. package/dist/core/embeddings/ast-utils.js +9 -1
  79. package/dist/core/embeddings/embedding-pipeline.d.ts +8 -0
  80. package/dist/core/embeddings/embedding-pipeline.js +253 -14
  81. package/dist/core/embeddings/http-client.d.ts +5 -0
  82. package/dist/core/embeddings/http-client.js +142 -27
  83. package/dist/core/graph/graph.js +3 -0
  84. package/dist/core/graph/import-cycles.d.ts +194 -3
  85. package/dist/core/graph/import-cycles.js +522 -73
  86. package/dist/core/graph/types.d.ts +18 -0
  87. package/dist/core/group/bridge-db.d.ts +204 -1
  88. package/dist/core/group/bridge-db.js +401 -28
  89. package/dist/core/group/completeness.d.ts +130 -0
  90. package/dist/core/group/completeness.js +83 -0
  91. package/dist/core/group/config-parser.js +0 -5
  92. package/dist/core/group/cross-impact.d.ts +46 -1
  93. package/dist/core/group/cross-impact.js +220 -19
  94. package/dist/core/group/cross-trace.d.ts +32 -11
  95. package/dist/core/group/cross-trace.js +114 -20
  96. package/dist/core/group/extractors/http-patterns/java.js +278 -22
  97. package/dist/core/group/extractors/http-patterns/node.js +332 -216
  98. package/dist/core/group/extractors/http-patterns/types.d.ts +8 -0
  99. package/dist/core/group/extractors/http-route-extractor.d.ts +1 -0
  100. package/dist/core/group/extractors/http-route-extractor.js +122 -48
  101. package/dist/core/group/extractors/include-extractor.js +20 -2
  102. package/dist/core/group/extractors/manifest-extractor.d.ts +1 -1
  103. package/dist/core/group/extractors/manifest-extractor.js +7 -7
  104. package/dist/core/group/extractors/python-workspace-extractor.js +5 -2
  105. package/dist/core/group/group-lock.d.ts +31 -0
  106. package/dist/core/group/group-lock.js +166 -0
  107. package/dist/core/group/service.js +297 -16
  108. package/dist/core/group/storage.d.ts +3 -0
  109. package/dist/core/group/storage.js +7 -39
  110. package/dist/core/group/sync.d.ts +49 -3
  111. package/dist/core/group/sync.js +0 -0
  112. package/dist/core/group/types.d.ts +183 -8
  113. package/dist/core/group/types.js +28 -1
  114. package/dist/core/incremental/subgraph-extract.d.ts +9 -6
  115. package/dist/core/incremental/subgraph-extract.js +33 -10
  116. package/dist/core/index-freshness.d.ts +77 -2
  117. package/dist/core/index-freshness.js +109 -2
  118. package/dist/core/ingestion/call-processor.d.ts +13 -1
  119. package/dist/core/ingestion/call-processor.js +110 -3
  120. package/dist/core/ingestion/cfg/callee-cell-format.d.ts +42 -0
  121. package/dist/core/ingestion/cfg/callee-cell-format.js +42 -0
  122. package/dist/core/ingestion/cfg/emit.d.ts +8 -23
  123. package/dist/core/ingestion/cfg/emit.js +9 -23
  124. package/dist/core/ingestion/class-extractors/configs/go.js +10 -5
  125. package/dist/core/ingestion/cluster-enricher.js +8 -4
  126. package/dist/core/ingestion/community-processor.d.ts +21 -3
  127. package/dist/core/ingestion/community-processor.js +81 -82
  128. package/dist/core/ingestion/di-extractors/index.d.ts +9 -33
  129. package/dist/core/ingestion/di-extractors/spring.d.ts +1 -1
  130. package/dist/core/ingestion/di-extractors/spring.js +8 -1
  131. package/dist/core/ingestion/di-extractors/types.d.ts +60 -0
  132. package/dist/core/ingestion/di-extractors/types.js +15 -0
  133. package/dist/core/ingestion/filesystem-walker.js +30 -14
  134. package/dist/core/ingestion/finalize-orchestrator.js +1 -0
  135. package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +6 -0
  136. package/dist/core/ingestion/frameworks/spring/analysis-features.js +35 -1
  137. package/dist/core/ingestion/frameworks/spring/annotation-arguments.d.ts +13 -0
  138. package/dist/core/ingestion/frameworks/spring/annotation-arguments.js +227 -0
  139. package/dist/core/ingestion/frameworks/spring/aop-candidates.d.ts +15 -0
  140. package/dist/core/ingestion/frameworks/spring/aop-candidates.js +85 -0
  141. package/dist/core/ingestion/frameworks/spring/aop.d.ts +118 -0
  142. package/dist/core/ingestion/frameworks/spring/aop.js +476 -0
  143. package/dist/core/ingestion/frameworks/spring/auto-configuration.d.ts +8 -0
  144. package/dist/core/ingestion/frameworks/spring/auto-configuration.js +16 -0
  145. package/dist/core/ingestion/frameworks/spring/bean-catalog.js +1 -0
  146. package/dist/core/ingestion/frameworks/spring/bean-factories.d.ts +33 -0
  147. package/dist/core/ingestion/frameworks/spring/bean-factories.js +65 -0
  148. package/dist/core/ingestion/frameworks/spring/conditionals.d.ts +25 -0
  149. package/dist/core/ingestion/frameworks/spring/conditionals.js +319 -0
  150. package/dist/core/ingestion/frameworks/spring/di-metadata.d.ts +3 -0
  151. package/dist/core/ingestion/frameworks/spring/di-metadata.js +162 -13
  152. package/dist/core/ingestion/frameworks/spring/non-http-handlers.d.ts +28 -0
  153. package/dist/core/ingestion/frameworks/spring/non-http-handlers.js +152 -0
  154. package/dist/core/ingestion/frameworks/spring/resource-injection.d.ts +5 -0
  155. package/dist/core/ingestion/frameworks/spring/resource-injection.js +91 -0
  156. package/dist/core/ingestion/import-resolvers/configs/csharp.js +5 -1
  157. package/dist/core/ingestion/import-resolvers/configs/swift.js +13 -0
  158. package/dist/core/ingestion/import-resolvers/csharp.d.ts +9 -1
  159. package/dist/core/ingestion/import-resolvers/csharp.js +234 -27
  160. package/dist/core/ingestion/import-resolvers/go.d.ts +11 -1
  161. package/dist/core/ingestion/import-resolvers/go.js +44 -17
  162. package/dist/core/ingestion/import-resolvers/jvm.d.ts +2 -2
  163. package/dist/core/ingestion/import-resolvers/node-workspace-packages.d.ts +90 -0
  164. package/dist/core/ingestion/import-resolvers/node-workspace-packages.js +429 -0
  165. package/dist/core/ingestion/import-resolvers/package-dir-index.d.ts +124 -0
  166. package/dist/core/ingestion/import-resolvers/package-dir-index.js +223 -0
  167. package/dist/core/ingestion/import-resolvers/pass-cache.d.ts +50 -0
  168. package/dist/core/ingestion/import-resolvers/pass-cache.js +60 -0
  169. package/dist/core/ingestion/import-resolvers/per-file-set.d.ts +71 -0
  170. package/dist/core/ingestion/import-resolvers/per-file-set.js +11 -0
  171. package/dist/core/ingestion/import-resolvers/php.d.ts +1 -1
  172. package/dist/core/ingestion/import-resolvers/php.js +65 -19
  173. package/dist/core/ingestion/import-resolvers/python-file-index.d.ts +201 -0
  174. package/dist/core/ingestion/import-resolvers/python-file-index.js +302 -0
  175. package/dist/core/ingestion/import-resolvers/python.js +25 -6
  176. package/dist/core/ingestion/import-resolvers/ruby.d.ts +1 -1
  177. package/dist/core/ingestion/import-resolvers/rust.d.ts +2 -2
  178. package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
  179. package/dist/core/ingestion/import-resolvers/types.d.ts +1 -12
  180. package/dist/core/ingestion/import-resolvers/utils.d.ts +65 -6
  181. package/dist/core/ingestion/import-resolvers/utils.js +215 -36
  182. package/dist/core/ingestion/import-resolvers/workspace-file-index.d.ts +72 -0
  183. package/dist/core/ingestion/import-resolvers/workspace-file-index.js +58 -0
  184. package/dist/core/ingestion/language-config.d.ts +29 -1
  185. package/dist/core/ingestion/language-config.js +110 -35
  186. package/dist/core/ingestion/language-provider.d.ts +209 -7
  187. package/dist/core/ingestion/language-provider.js +37 -0
  188. package/dist/core/ingestion/languages/c/captures.js +7 -0
  189. package/dist/core/ingestion/languages/c/import-target.js +12 -16
  190. package/dist/core/ingestion/languages/c/scope-resolver.js +20 -19
  191. package/dist/core/ingestion/languages/c/static-linkage.js +12 -16
  192. package/dist/core/ingestion/languages/c-cpp.js +13 -0
  193. package/dist/core/ingestion/languages/cobol/scope-resolver.js +27 -20
  194. package/dist/core/ingestion/languages/cobol.js +13 -0
  195. package/dist/core/ingestion/languages/cpp/adl.d.ts +2 -2
  196. package/dist/core/ingestion/languages/cpp/adl.js +67 -44
  197. package/dist/core/ingestion/languages/cpp/captures.js +14 -2
  198. package/dist/core/ingestion/languages/cpp/file-local-linkage.js +11 -15
  199. package/dist/core/ingestion/languages/cpp/inline-namespaces.d.ts +28 -8
  200. package/dist/core/ingestion/languages/cpp/inline-namespaces.js +242 -68
  201. package/dist/core/ingestion/languages/cpp/interpret.d.ts +2 -0
  202. package/dist/core/ingestion/languages/cpp/interpret.js +126 -6
  203. package/dist/core/ingestion/languages/cpp/query.js +106 -0
  204. package/dist/core/ingestion/languages/cpp/scope-resolver.js +48 -20
  205. package/dist/core/ingestion/languages/csharp/accessor-unwrap.d.ts +2 -15
  206. package/dist/core/ingestion/languages/csharp/accessor-unwrap.js +18 -10
  207. package/dist/core/ingestion/languages/csharp/captures.js +19 -0
  208. package/dist/core/ingestion/languages/csharp/import-target.js +46 -72
  209. package/dist/core/ingestion/languages/csharp/namespace-siblings.js +5 -1
  210. package/dist/core/ingestion/languages/csharp/query.js +25 -5
  211. package/dist/core/ingestion/languages/csharp/scope-resolver.js +75 -2
  212. package/dist/core/ingestion/languages/dart/captures.d.ts +10 -0
  213. package/dist/core/ingestion/languages/dart/captures.js +598 -16
  214. package/dist/core/ingestion/languages/dart/import-target.js +32 -9
  215. package/dist/core/ingestion/languages/dart/index.d.ts +1 -1
  216. package/dist/core/ingestion/languages/dart/index.js +1 -1
  217. package/dist/core/ingestion/languages/dart/query.js +98 -1
  218. package/dist/core/ingestion/languages/dart/scope-resolver.js +14 -3
  219. package/dist/core/ingestion/languages/dart/simple-hooks.js +9 -0
  220. package/dist/core/ingestion/languages/dart.js +6 -1
  221. package/dist/core/ingestion/languages/go/captures.js +108 -3
  222. package/dist/core/ingestion/languages/go/generic-type-parameters.d.ts +31 -0
  223. package/dist/core/ingestion/languages/go/generic-type-parameters.js +140 -0
  224. package/dist/core/ingestion/languages/go/import-target.d.ts +3 -10
  225. package/dist/core/ingestion/languages/go/import-target.js +34 -30
  226. package/dist/core/ingestion/languages/go/index.d.ts +1 -1
  227. package/dist/core/ingestion/languages/go/interface-impls.d.ts +9 -1
  228. package/dist/core/ingestion/languages/go/interface-impls.js +693 -87
  229. package/dist/core/ingestion/languages/go/interpret.d.ts +2 -0
  230. package/dist/core/ingestion/languages/go/interpret.js +22 -8
  231. package/dist/core/ingestion/languages/go/method-owners.js +31 -12
  232. package/dist/core/ingestion/languages/go/package-clause.d.ts +46 -0
  233. package/dist/core/ingestion/languages/go/package-clause.js +75 -0
  234. package/dist/core/ingestion/languages/go/package-siblings.js +7 -11
  235. package/dist/core/ingestion/languages/go/query.js +56 -3
  236. package/dist/core/ingestion/languages/go/scope-resolver.js +39 -0
  237. package/dist/core/ingestion/languages/go.js +9 -0
  238. package/dist/core/ingestion/languages/java/analysis-features.d.ts +4 -0
  239. package/dist/core/ingestion/languages/java/analysis-features.js +12 -0
  240. package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +12 -0
  241. package/dist/core/ingestion/languages/java/capture-side-channel.js +48 -0
  242. package/dist/core/ingestion/languages/java/captures.js +77 -32
  243. package/dist/core/ingestion/languages/java/import-target.d.ts +49 -9
  244. package/dist/core/ingestion/languages/java/import-target.js +68 -88
  245. package/dist/core/ingestion/languages/java/interpret.js +3 -2
  246. package/dist/core/ingestion/languages/java/module-resolution.d.ts +62 -0
  247. package/dist/core/ingestion/languages/java/module-resolution.js +142 -0
  248. package/dist/core/ingestion/languages/java/query.js +15 -3
  249. package/dist/core/ingestion/languages/java/record-components.d.ts +14 -0
  250. package/dist/core/ingestion/languages/java/record-components.js +185 -0
  251. package/dist/core/ingestion/languages/java/scope-resolver.js +10 -2
  252. package/dist/core/ingestion/languages/java/spring-aop.d.ts +12 -0
  253. package/dist/core/ingestion/languages/java/spring-aop.js +49 -0
  254. package/dist/core/ingestion/languages/java/spring-conditionals.d.ts +11 -0
  255. package/dist/core/ingestion/languages/java/spring-conditionals.js +48 -0
  256. package/dist/core/ingestion/languages/java/spring-di.d.ts +4 -1
  257. package/dist/core/ingestion/languages/java/spring-di.js +41 -9
  258. package/dist/core/ingestion/languages/java/spring-non-http-handlers.d.ts +7 -0
  259. package/dist/core/ingestion/languages/java/spring-non-http-handlers.js +32 -0
  260. package/dist/core/ingestion/languages/java.js +94 -3
  261. package/dist/core/ingestion/languages/javascript/captures.d.ts +6 -1
  262. package/dist/core/ingestion/languages/javascript/captures.js +262 -4
  263. package/dist/core/ingestion/languages/javascript/import-target.d.ts +17 -21
  264. package/dist/core/ingestion/languages/javascript/import-target.js +24 -41
  265. package/dist/core/ingestion/languages/javascript/index.d.ts +54 -5
  266. package/dist/core/ingestion/languages/javascript/index.js +54 -5
  267. package/dist/core/ingestion/languages/javascript/query.d.ts +1 -0
  268. package/dist/core/ingestion/languages/javascript/query.js +211 -5
  269. package/dist/core/ingestion/languages/javascript/scope-resolver.js +12 -0
  270. package/dist/core/ingestion/languages/javascript/simple-hooks.js +2 -1
  271. package/dist/core/ingestion/languages/jvm/package-siblings.js +77 -9
  272. package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +15 -0
  273. package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +48 -0
  274. package/dist/core/ingestion/languages/kotlin/captures.js +43 -1
  275. package/dist/core/ingestion/languages/kotlin/import-target.d.ts +8 -1
  276. package/dist/core/ingestion/languages/kotlin/import-target.js +20 -123
  277. package/dist/core/ingestion/languages/kotlin/index.d.ts +1 -0
  278. package/dist/core/ingestion/languages/kotlin/index.js +1 -0
  279. package/dist/core/ingestion/languages/kotlin/module-resolution.d.ts +22 -0
  280. package/dist/core/ingestion/languages/kotlin/module-resolution.js +108 -0
  281. package/dist/core/ingestion/languages/kotlin/query.js +28 -2
  282. package/dist/core/ingestion/languages/kotlin/scope-resolver.js +23 -2
  283. package/dist/core/ingestion/languages/kotlin/spring-aop.d.ts +12 -0
  284. package/dist/core/ingestion/languages/kotlin/spring-aop.js +64 -0
  285. package/dist/core/ingestion/languages/kotlin/spring-conditionals.d.ts +12 -0
  286. package/dist/core/ingestion/languages/kotlin/spring-conditionals.js +49 -0
  287. package/dist/core/ingestion/languages/kotlin/spring-di.d.ts +2 -0
  288. package/dist/core/ingestion/languages/kotlin/spring-di.js +60 -11
  289. package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.d.ts +10 -0
  290. package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.js +41 -0
  291. package/dist/core/ingestion/languages/php/captures.d.ts +5 -0
  292. package/dist/core/ingestion/languages/php/captures.js +319 -51
  293. package/dist/core/ingestion/languages/php/import-target.d.ts +3 -4
  294. package/dist/core/ingestion/languages/php/import-target.js +192 -62
  295. package/dist/core/ingestion/languages/php/query.js +31 -0
  296. package/dist/core/ingestion/languages/python/arity-metadata.d.ts +1 -0
  297. package/dist/core/ingestion/languages/python/arity-metadata.js +1 -0
  298. package/dist/core/ingestion/languages/python/captures.js +29 -0
  299. package/dist/core/ingestion/languages/python/import-decomposer.js +22 -1
  300. package/dist/core/ingestion/languages/python/import-target.d.ts +42 -1
  301. package/dist/core/ingestion/languages/python/import-target.js +277 -91
  302. package/dist/core/ingestion/languages/python/index.d.ts +1 -1
  303. package/dist/core/ingestion/languages/python/index.js +1 -1
  304. package/dist/core/ingestion/languages/python/interpret.d.ts +52 -0
  305. package/dist/core/ingestion/languages/python/interpret.js +249 -7
  306. package/dist/core/ingestion/languages/python/query.js +9 -0
  307. package/dist/core/ingestion/languages/python/receiver-binding.d.ts +8 -6
  308. package/dist/core/ingestion/languages/python/receiver-binding.js +108 -12
  309. package/dist/core/ingestion/languages/python/scope-resolver.js +27 -4
  310. package/dist/core/ingestion/languages/python/simple-hooks.js +2 -8
  311. package/dist/core/ingestion/languages/python.js +13 -0
  312. package/dist/core/ingestion/languages/ruby/captures.js +158 -0
  313. package/dist/core/ingestion/languages/ruby/import-target.js +7 -5
  314. package/dist/core/ingestion/languages/ruby/query.js +93 -0
  315. package/dist/core/ingestion/languages/ruby/scope-resolver.js +2 -0
  316. package/dist/core/ingestion/languages/ruby/simple-hooks.d.ts +1 -1
  317. package/dist/core/ingestion/languages/ruby/simple-hooks.js +22 -1
  318. package/dist/core/ingestion/languages/rust/captures.js +39 -1
  319. package/dist/core/ingestion/languages/rust/method-owners.js +11 -1
  320. package/dist/core/ingestion/languages/rust/module-path.d.ts +126 -0
  321. package/dist/core/ingestion/languages/rust/module-path.js +214 -0
  322. package/dist/core/ingestion/languages/rust/qualified-call.d.ts +41 -0
  323. package/dist/core/ingestion/languages/rust/qualified-call.js +481 -0
  324. package/dist/core/ingestion/languages/rust/query.js +39 -6
  325. package/dist/core/ingestion/languages/rust/scope-resolver.js +21 -2
  326. package/dist/core/ingestion/languages/rust.js +17 -0
  327. package/dist/core/ingestion/languages/swift/captures.js +87 -3
  328. package/dist/core/ingestion/languages/swift/conditional-directive-preprocess.d.ts +48 -0
  329. package/dist/core/ingestion/languages/swift/conditional-directive-preprocess.js +253 -0
  330. package/dist/core/ingestion/languages/swift/import-target.js +4 -9
  331. package/dist/core/ingestion/languages/swift/query.js +17 -0
  332. package/dist/core/ingestion/languages/swift/receiver-binding.d.ts +8 -0
  333. package/dist/core/ingestion/languages/swift/receiver-binding.js +6 -2
  334. package/dist/core/ingestion/languages/swift.js +2 -0
  335. package/dist/core/ingestion/languages/typescript/captures.d.ts +90 -1
  336. package/dist/core/ingestion/languages/typescript/captures.js +267 -5
  337. package/dist/core/ingestion/languages/typescript/cjs-export-assignment.d.ts +134 -0
  338. package/dist/core/ingestion/languages/typescript/cjs-export-assignment.js +523 -0
  339. package/dist/core/ingestion/languages/typescript/cjs-module-exports.d.ts +54 -0
  340. package/dist/core/ingestion/languages/typescript/cjs-module-exports.js +191 -0
  341. package/dist/core/ingestion/languages/typescript/convex-endpoint-metadata.d.ts +7 -0
  342. package/dist/core/ingestion/languages/typescript/convex-endpoint-metadata.js +92 -0
  343. package/dist/core/ingestion/languages/typescript/file-candidates.d.ts +29 -0
  344. package/dist/core/ingestion/languages/typescript/file-candidates.js +70 -0
  345. package/dist/core/ingestion/languages/typescript/import-decomposer.d.ts +28 -1
  346. package/dist/core/ingestion/languages/typescript/import-decomposer.js +125 -10
  347. package/dist/core/ingestion/languages/typescript/import-target.d.ts +25 -37
  348. package/dist/core/ingestion/languages/typescript/import-target.js +24 -26
  349. package/dist/core/ingestion/languages/typescript/interpret.d.ts +21 -1
  350. package/dist/core/ingestion/languages/typescript/interpret.js +45 -5
  351. package/dist/core/ingestion/languages/typescript/module-resolution.d.ts +48 -0
  352. package/dist/core/ingestion/languages/typescript/module-resolution.js +171 -0
  353. package/dist/core/ingestion/languages/typescript/query.d.ts +1 -0
  354. package/dist/core/ingestion/languages/typescript/query.js +303 -14
  355. package/dist/core/ingestion/languages/typescript/receiver-binding.d.ts +17 -0
  356. package/dist/core/ingestion/languages/typescript/receiver-binding.js +27 -0
  357. package/dist/core/ingestion/languages/typescript/scope-resolver.js +27 -40
  358. package/dist/core/ingestion/languages/typescript/simple-hooks.d.ts +0 -10
  359. package/dist/core/ingestion/languages/typescript/simple-hooks.js +22 -22
  360. package/dist/core/ingestion/languages/typescript/tsconfig.d.ts +59 -0
  361. package/dist/core/ingestion/languages/typescript/tsconfig.js +292 -0
  362. package/dist/core/ingestion/languages/typescript.js +93 -2
  363. package/dist/core/ingestion/languages/vue/import-target.d.ts +6 -22
  364. package/dist/core/ingestion/languages/vue/import-target.js +11 -47
  365. package/dist/core/ingestion/languages/vue/scope-resolver.js +4 -2
  366. package/dist/core/ingestion/local-symbol-pruner.js +11 -11
  367. package/dist/core/ingestion/method-extractors/configs/csharp.js +1 -0
  368. package/dist/core/ingestion/method-extractors/generic.js +1 -0
  369. package/dist/core/ingestion/method-types.d.ts +16 -0
  370. package/dist/core/ingestion/pipeline-phases/di.d.ts +1 -1
  371. package/dist/core/ingestion/pipeline-phases/di.js +136 -21
  372. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  373. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  374. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +15 -0
  375. package/dist/core/ingestion/pipeline-phases/parse-impl.js +154 -4
  376. package/dist/core/ingestion/pipeline-phases/parse.js +5 -0
  377. package/dist/core/ingestion/pipeline-phases/processes.d.ts +3 -2
  378. package/dist/core/ingestion/pipeline-phases/processes.js +91 -6
  379. package/dist/core/ingestion/pipeline-phases/routes.js +116 -25
  380. package/dist/core/ingestion/pipeline-phases/spring-aop.d.ts +34 -0
  381. package/dist/core/ingestion/pipeline-phases/spring-aop.js +439 -0
  382. package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.d.ts +34 -0
  383. package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.js +255 -0
  384. package/dist/core/ingestion/pipeline-phases/types.d.ts +7 -0
  385. package/dist/core/ingestion/pipeline.d.ts +26 -2
  386. package/dist/core/ingestion/pipeline.js +60 -11
  387. package/dist/core/ingestion/process-processor.d.ts +109 -2
  388. package/dist/core/ingestion/process-processor.js +464 -52
  389. package/dist/core/ingestion/resolve-references.d.ts +6 -1
  390. package/dist/core/ingestion/resolve-references.js +66 -6
  391. package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +8 -2
  392. package/dist/core/ingestion/route-extractors/constant-resolver.js +11 -7
  393. package/dist/core/ingestion/route-extractors/data-route-table.d.ts +40 -0
  394. package/dist/core/ingestion/route-extractors/data-route-table.js +876 -0
  395. package/dist/core/ingestion/route-extractors/dispatch-guard.d.ts +96 -0
  396. package/dist/core/ingestion/route-extractors/dispatch-guard.js +1184 -0
  397. package/dist/core/ingestion/route-extractors/java-const-resolver.d.ts +114 -0
  398. package/dist/core/ingestion/route-extractors/java-const-resolver.js +569 -0
  399. package/dist/core/ingestion/route-extractors/js-const-resolver.d.ts +192 -0
  400. package/dist/core/ingestion/route-extractors/js-const-resolver.js +1033 -0
  401. package/dist/core/ingestion/route-extractors/nest.d.ts +53 -0
  402. package/dist/core/ingestion/route-extractors/nest.js +523 -0
  403. package/dist/core/ingestion/route-extractors/spring-shared.d.ts +11 -0
  404. package/dist/core/ingestion/route-extractors/spring-shared.js +89 -0
  405. package/dist/core/ingestion/route-extractors/spring.js +214 -29
  406. package/dist/core/ingestion/scope-extractor-bridge.js +9 -1
  407. package/dist/core/ingestion/scope-extractor.d.ts +22 -7
  408. package/dist/core/ingestion/scope-extractor.js +309 -15
  409. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +311 -21
  410. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +16 -5
  411. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -0
  412. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +47 -0
  413. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +20 -15
  414. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +280 -42
  415. package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.d.ts +123 -0
  416. package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +171 -17
  417. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.d.ts +58 -1
  418. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +137 -34
  419. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +30 -1
  420. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +39 -1
  421. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +18 -1
  422. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +113 -18
  423. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +107 -5
  424. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +590 -33
  425. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +3 -0
  426. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +101 -41
  427. package/dist/core/ingestion/scope-resolution/passes/imported-value-refs.d.ts +34 -0
  428. package/dist/core/ingestion/scope-resolution/passes/imported-value-refs.js +62 -0
  429. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +5 -1
  430. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +8 -1
  431. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +105 -5
  432. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +931 -92
  433. package/dist/core/ingestion/scope-resolution/passes/return-shape-members.d.ts +58 -0
  434. package/dist/core/ingestion/scope-resolution/passes/return-shape-members.js +458 -0
  435. package/dist/core/ingestion/scope-resolution/passes/unique-name-properties.d.ts +180 -0
  436. package/dist/core/ingestion/scope-resolution/passes/unique-name-properties.js +418 -0
  437. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +29 -0
  438. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +57 -0
  439. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +55 -1
  440. package/dist/core/ingestion/scope-resolution/pipeline/run.js +241 -19
  441. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +112 -2
  442. package/dist/core/ingestion/scope-resolution/resolution-outcome.js +38 -1
  443. package/dist/core/ingestion/scope-resolution/scope/namespace-targets.d.ts +25 -3
  444. package/dist/core/ingestion/scope-resolution/scope/namespace-targets.js +36 -16
  445. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +210 -9
  446. package/dist/core/ingestion/scope-resolution/scope/walkers.js +905 -22
  447. package/dist/core/ingestion/scope-resolution/summary-maps.d.ts +28 -0
  448. package/dist/core/ingestion/scope-resolution/summary-maps.js +50 -0
  449. package/dist/core/ingestion/scope-resolution/undecided-satisfaction.d.ts +55 -0
  450. package/dist/core/ingestion/scope-resolution/undecided-satisfaction.js +37 -0
  451. package/dist/core/ingestion/scope-resolution/unresolved-receivers.d.ts +109 -0
  452. package/dist/core/ingestion/scope-resolution/unresolved-receivers.js +204 -0
  453. package/dist/core/ingestion/scope-resolution/utils/definition-id.d.ts +13 -0
  454. package/dist/core/ingestion/scope-resolution/utils/definition-id.js +19 -0
  455. package/dist/core/ingestion/scope-resolution/utils/generic-instantiation.d.ts +171 -0
  456. package/dist/core/ingestion/scope-resolution/utils/generic-instantiation.js +218 -0
  457. package/dist/core/ingestion/scope-resolution/workspace-index-types.d.ts +34 -0
  458. package/dist/core/ingestion/scope-resolution/workspace-index-types.js +15 -0
  459. package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +7 -20
  460. package/dist/core/ingestion/tree-sitter-queries.d.ts +11 -11
  461. package/dist/core/ingestion/tree-sitter-queries.js +678 -4
  462. package/dist/core/ingestion/type-env.js +11 -7
  463. package/dist/core/ingestion/type-extractors/shared.d.ts +17 -0
  464. package/dist/core/ingestion/type-extractors/shared.js +16 -0
  465. package/dist/core/ingestion/type-extractors/types.d.ts +12 -0
  466. package/dist/core/ingestion/type-extractors/typescript.d.ts +20 -0
  467. package/dist/core/ingestion/type-extractors/typescript.js +26 -0
  468. package/dist/core/ingestion/utils/ast-helpers.d.ts +297 -15
  469. package/dist/core/ingestion/utils/ast-helpers.js +578 -46
  470. package/dist/core/ingestion/utils/call-analysis.d.ts +27 -22
  471. package/dist/core/ingestion/utils/call-analysis.js +202 -7
  472. package/dist/core/ingestion/utils/callable-flow-captures.d.ts +59 -0
  473. package/dist/core/ingestion/utils/callable-flow-captures.js +51 -1
  474. package/dist/core/ingestion/utils/callable-labels.d.ts +25 -0
  475. package/dist/core/ingestion/utils/callable-labels.js +31 -0
  476. package/dist/core/ingestion/utils/effective-ram.d.ts +40 -0
  477. package/dist/core/ingestion/utils/effective-ram.js +58 -0
  478. package/dist/core/ingestion/utils/line-base.d.ts +14 -0
  479. package/dist/core/ingestion/utils/line-base.js +14 -0
  480. package/dist/core/ingestion/utils/method-props.d.ts +27 -4
  481. package/dist/core/ingestion/utils/method-props.js +29 -4
  482. package/dist/core/ingestion/utils/receiver-chain-captures.d.ts +31 -0
  483. package/dist/core/ingestion/utils/receiver-chain-captures.js +57 -0
  484. package/dist/core/ingestion/utils/receiver-chain-codec.d.ts +89 -0
  485. package/dist/core/ingestion/utils/receiver-chain-codec.js +182 -0
  486. package/dist/core/ingestion/utils/scope-tree-walk.d.ts +22 -0
  487. package/dist/core/ingestion/utils/scope-tree-walk.js +33 -0
  488. package/dist/core/ingestion/utils/template-arguments.d.ts +96 -0
  489. package/dist/core/ingestion/utils/template-arguments.js +196 -0
  490. package/dist/core/ingestion/utils/type-parameters.d.ts +49 -0
  491. package/dist/core/ingestion/utils/type-parameters.js +206 -0
  492. package/dist/core/ingestion/workers/callable-id.d.ts +80 -0
  493. package/dist/core/ingestion/workers/callable-id.js +125 -0
  494. package/dist/core/ingestion/workers/parse-worker.d.ts +14 -1
  495. package/dist/core/ingestion/workers/parse-worker.js +493 -54
  496. package/dist/core/ingestion/workers/worker-pool.d.ts +20 -27
  497. package/dist/core/ingestion/workers/worker-pool.js +91 -3
  498. package/dist/core/lbug/csv-generator.d.ts +27 -0
  499. package/dist/core/lbug/csv-generator.js +72 -17
  500. package/dist/core/lbug/extension-load-error.js +13 -2
  501. package/dist/core/lbug/extension-loader.d.ts +29 -0
  502. package/dist/core/lbug/extension-loader.js +31 -6
  503. package/dist/core/lbug/graph-emit-sink.d.ts +264 -0
  504. package/dist/core/lbug/graph-emit-sink.js +581 -0
  505. package/dist/core/lbug/lbug-adapter.d.ts +290 -11
  506. package/dist/core/lbug/lbug-adapter.js +652 -69
  507. package/dist/core/lbug/native-check.d.ts +21 -0
  508. package/dist/core/lbug/native-check.js +248 -32
  509. package/dist/core/lbug/pdg-emit-sink.d.ts +13 -4
  510. package/dist/core/lbug/pdg-emit-sink.js +21 -111
  511. package/dist/core/lbug/pool-adapter.d.ts +9 -0
  512. package/dist/core/lbug/pool-adapter.js +164 -14
  513. package/dist/core/lbug/query-batch.d.ts +75 -0
  514. package/dist/core/lbug/query-batch.js +102 -0
  515. package/dist/core/lbug/rel-pair-routing.d.ts +160 -2
  516. package/dist/core/lbug/rel-pair-routing.js +228 -10
  517. package/dist/core/lbug/schema.d.ts +163 -4
  518. package/dist/core/lbug/schema.js +404 -159
  519. package/dist/core/lbug/sync-csv-writer.d.ts +47 -0
  520. package/dist/core/lbug/sync-csv-writer.js +108 -0
  521. package/dist/core/run-analyze.d.ts +147 -0
  522. package/dist/core/run-analyze.js +1215 -179
  523. package/dist/core/search/bm25-index.d.ts +11 -0
  524. package/dist/core/search/bm25-index.js +60 -26
  525. package/dist/core/search/fts-indexes.d.ts +150 -9
  526. package/dist/core/search/fts-indexes.js +241 -23
  527. package/dist/core/wiki/graph-queries.js +145 -112
  528. package/dist/core/wiki/llm-client.d.ts +29 -3
  529. package/dist/core/wiki/llm-client.js +47 -12
  530. package/dist/core/wiki/prompts.d.ts +19 -0
  531. package/dist/core/wiki/prompts.js +20 -1
  532. package/dist/lib/utils.d.ts +113 -0
  533. package/dist/lib/utils.js +185 -0
  534. package/dist/mcp/local/aop-metadata.d.ts +77 -0
  535. package/dist/mcp/local/aop-metadata.js +227 -0
  536. package/dist/mcp/local/bean-metadata.d.ts +2 -1
  537. package/dist/mcp/local/bean-metadata.js +22 -1
  538. package/dist/mcp/local/convex-metadata.d.ts +8 -0
  539. package/dist/mcp/local/convex-metadata.js +45 -0
  540. package/dist/mcp/local/local-backend.d.ts +174 -11
  541. package/dist/mcp/local/local-backend.js +1678 -331
  542. package/dist/mcp/local/path-predicate.d.ts +19 -0
  543. package/dist/mcp/local/path-predicate.js +21 -0
  544. package/dist/mcp/local/pdg-impact.d.ts +132 -10
  545. package/dist/mcp/local/pdg-impact.js +391 -98
  546. package/dist/mcp/repository-policy.d.ts +1 -0
  547. package/dist/mcp/repository-policy.js +5 -0
  548. package/dist/mcp/resources.js +26 -4
  549. package/dist/mcp/server.js +23 -13
  550. package/dist/mcp/tools.d.ts +8 -0
  551. package/dist/mcp/tools.js +76 -23
  552. package/dist/server/analyze-job.d.ts +37 -2
  553. package/dist/server/analyze-job.js +13 -2
  554. package/dist/server/analyze-launch.d.ts +1 -1
  555. package/dist/server/analyze-launch.js +79 -10
  556. package/dist/server/analyze-worker-core.d.ts +1 -1
  557. package/dist/server/analyze-worker-core.js +10 -1
  558. package/dist/server/analyze-worker-ipc.d.ts +1 -1
  559. package/dist/server/analyze-worker-ipc.js +4 -0
  560. package/dist/server/analyze-worker-protocol.d.ts +59 -0
  561. package/dist/server/analyze-worker-protocol.js +1 -0
  562. package/dist/server/analyze-worker.d.ts +1 -17
  563. package/dist/server/api.d.ts +2 -11
  564. package/dist/server/api.js +164 -163
  565. package/dist/server/embed-run-outcome.d.ts +89 -0
  566. package/dist/server/embed-run-outcome.js +88 -0
  567. package/dist/server/git-clone.js +6 -2
  568. package/dist/server/middleware.d.ts +116 -9
  569. package/dist/server/middleware.js +291 -22
  570. package/dist/server/sse-progress.d.ts +41 -0
  571. package/dist/server/sse-progress.js +125 -0
  572. package/dist/storage/branch-index.d.ts +11 -6
  573. package/dist/storage/branch-index.js +15 -7
  574. package/dist/storage/file-hash.js +2 -2
  575. package/dist/storage/fs-atomic.d.ts +25 -0
  576. package/dist/storage/fs-atomic.js +42 -0
  577. package/dist/storage/git.d.ts +131 -0
  578. package/dist/storage/git.js +236 -2
  579. package/dist/storage/index-lock.d.ts +102 -0
  580. package/dist/storage/index-lock.js +660 -0
  581. package/dist/storage/parse-cache.js +588 -6
  582. package/dist/storage/parsedfile-store.js +76 -6
  583. package/dist/storage/repo-manager.d.ts +54 -441
  584. package/dist/storage/repo-manager.js +312 -221
  585. package/dist/storage/repo-meta.d.ts +530 -0
  586. package/dist/storage/repo-meta.js +100 -0
  587. package/dist/types/pipeline.d.ts +37 -0
  588. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +1 -1
  589. package/hooks/claude/gitnexus-hook.cjs +1 -1
  590. package/hooks/claude/resolve-analyze-cmd.cjs +80 -13
  591. package/package.json +11 -2
  592. package/scripts/cross-platform-shard.ts +153 -0
  593. package/scripts/cross-platform-tests.ts +122 -0
  594. package/scripts/run-cross-platform.ts +16 -5
  595. package/skills/gitnexus-cli.md +3 -3
  596. package/skills/gitnexus-debugging.md +37 -7
  597. package/skills/gitnexus-exploring.md +26 -4
  598. package/skills/gitnexus-impact-analysis.md +71 -10
  599. package/skills/gitnexus-plan/README.md +11 -6
  600. package/skills/gitnexus-plan/references/evidence-provenance.md +49 -12
  601. package/skills/gitnexus-plan/scripts/evidence-provenance.mjs +654 -372
  602. package/skills/gitnexus-refactoring.md +48 -5
  603. package/skills/gitnexus-review/SKILL.md +12 -6
  604. package/skills/gitnexus-review/ci-personas/ci-adversarial-lens.md +1 -1
  605. package/skills/gitnexus-review/ci-personas/ci-blast-radius-lens.md +1 -1
  606. package/skills/gitnexus-review/ci-personas/ci-correctness-lens.md +1 -1
  607. package/skills/gitnexus-review/ci-personas/ci-coverage-lens.md +1 -1
  608. package/skills/gitnexus-review/ci-personas/ci-critic-lens.md +1 -1
  609. package/skills/gitnexus-review/ci-personas/ci-security-lens.md +1 -1
  610. package/skills/gitnexus-taint-analysis.md +13 -7
  611. package/skills/gitnexus-work/SKILL.md +4 -1
  612. package/skills/gitnexus-work/references/evidence-provenance.md +49 -12
  613. package/skills/gitnexus-work/scripts/evidence-provenance.mjs +654 -372
  614. package/vendor/leiden/utils.cjs +28 -1
  615. package/web/assets/ProcessFlowModal-Badh2Pbg.js +24 -0
  616. package/web/assets/{__vite-browser-external-bMKyYQkO.js → __vite-browser-external-COxE8F0G.js} +1 -1
  617. package/web/assets/abnfDiagram-QNN2D4NM-Cq2djWWe.js +1 -0
  618. package/web/assets/agent-Dr4l5EOp.js +662 -0
  619. package/web/assets/architecture-TIHT7OUA-V6N4J3SY-fTePvLoe.js +1 -0
  620. package/web/assets/architectureDiagram-OT7VKSJ7-mKEXxkeF.js +36 -0
  621. package/web/assets/{blockDiagram-7IZFK4PR-DBefcjof.js → blockDiagram-54WLDVWM-Dg_hrRWE.js} +4 -4
  622. package/web/assets/{c4Diagram-Y2BXMSZH-EjWnjEJl.js → c4Diagram-X2LASM7V-CnhoT4aV.js} +2 -2
  623. package/web/assets/chunk-224SPVON-B8gxtXpy.js +1 -0
  624. package/web/assets/chunk-2AEHWXPW-CV4r6-1I.js +127 -0
  625. package/web/assets/chunk-2SREHG4O-Dip42xOq.js +1 -0
  626. package/web/assets/chunk-4RFN2BYJ-DHHWuC-n.js +1 -0
  627. package/web/assets/chunk-66DQ2XMT-CM0xjFAN.js +1 -0
  628. package/web/assets/chunk-6BELYETK-ChsYtfHW.js +1 -0
  629. package/web/assets/{chunk-LII3EMHJ-BL6lKJ_P.js → chunk-6L755F7B-CMhLBxi2.js} +1 -1
  630. package/web/assets/{chunk-QA3QBVWF-DVXPOIxe.js → chunk-7CWYLC5S-DRgGkkpF.js} +1 -1
  631. package/web/assets/{chunk-ZXARS5L4-C3v-4Fsw.js → chunk-A7VWPJGB-B4O3oQdQ.js} +1 -1
  632. package/web/assets/chunk-BI6VK774-D0oaWk8V.js +1 -0
  633. package/web/assets/chunk-D6VWDJW2-BxcBdZ9c.js +2 -0
  634. package/web/assets/chunk-DMV4VAQV-Bn6WXDSX.js +4 -0
  635. package/web/assets/chunk-E5QJAATJ-dh-5CtIV.js +2 -0
  636. package/web/assets/chunk-EQFTRU2I-1ix7TzW9.js +2 -0
  637. package/web/assets/chunk-FWYVLQTC-BgDItRzJ.js +1 -0
  638. package/web/assets/chunk-HNC4WDU7-DoU3KnA7.js +1 -0
  639. package/web/assets/chunk-L5GCOVLC-CE2w8Nm_.js +161 -0
  640. package/web/assets/chunk-LAHSG3N2-Bz4hcn0N.js +321 -0
  641. package/web/assets/chunk-LORZLZWG-B57uGw2N.js +88 -0
  642. package/web/assets/chunk-NLANEA3F-XpH_NPA5.js +62 -0
  643. package/web/assets/chunk-NV3KIAZN-5yvcpMiu.js +1 -0
  644. package/web/assets/chunk-OIYT25JQ-CQ6KOZGX.js +1 -0
  645. package/web/assets/chunk-PE7DX7ZZ-CCvRVj43.js +10 -0
  646. package/web/assets/chunk-Q67WD55A-BWCH2SVz.js +156 -0
  647. package/web/assets/chunk-RRFMTAIC-CMN0wcYA.js +1 -0
  648. package/web/assets/{chunk-RLI5ZMPA-CkXZ0y0U.js → chunk-SATU7PGQ-B1zhgOvc.js} +1 -1
  649. package/web/assets/chunk-STOV2HOB-GnExfzIX.js +1 -0
  650. package/web/assets/{chunk-INKRHTLW-Ckl3_KkO.js → chunk-SZD42YQK-ijyKKVr1.js} +21 -21
  651. package/web/assets/{chunk-LCXTWHL2-C162wE5z.js → chunk-TFPGFQPA-Dj6a-0pC.js} +3 -3
  652. package/web/assets/chunk-TGVD4F4B-BMc31Gj2.js +2 -0
  653. package/web/assets/chunk-TZUXEDM2-B7p9AcTw.js +1 -0
  654. package/web/assets/chunk-UAT7B5JY-DW-A_fpI.js +1 -0
  655. package/web/assets/{chunk-6764PJDD-C7xxk063.js → chunk-VE5CLXGZ-C1vB7wpY.js} +1 -1
  656. package/web/assets/{chunk-RG4AUYOV-ZNgyLFq6.js → chunk-VJFVEZTB-CX66F2ep.js} +3 -3
  657. package/web/assets/chunk-VY5UBI4V-yxPQAWxw.js +1 -0
  658. package/web/assets/chunk-WJBAP47W-BckNkuEN.js +1 -0
  659. package/web/assets/chunk-XNMVGMAZ-Cg_LnPtj.js +1 -0
  660. package/web/assets/classDiagram-VPOSVPXH-BjOiXA_C.js +1 -0
  661. package/web/assets/classDiagram-v2-5VFNUXQA-BjOiXA_C.js +1 -0
  662. package/web/assets/{cose-bilkent-UX7MHV2Q-BmnZ7Mvj.js → cose-bilkent-RZA4XIPR-BHpK4Crp.js} +1 -1
  663. package/web/assets/cynefin-VYW2F7L2-2VAHYKR6-DAsF6GZv.js +1 -0
  664. package/web/assets/cynefinDiagram-TR7LZUCG-C3Iar9lZ.js +62 -0
  665. package/web/assets/dagre-K64A6Z3X-CUwi79mA.js +4 -0
  666. package/web/assets/diagram-2TLGJV2N-C2F5Nfym.js +30 -0
  667. package/web/assets/diagram-JCD7PQ7C-DC5-9FRr.js +24 -0
  668. package/web/assets/{diagram-HNR7UZ2L-DVRltWbL.js → diagram-KFBZAVDW-Dfmf_4ti.js} +3 -3
  669. package/web/assets/diagram-L7DVE3PN-GIRyVUtt.js +41 -0
  670. package/web/assets/diagram-YP3FGXHI-CyNFYtkd.js +24 -0
  671. package/web/assets/ebnfDiagram-DRHRQJWO-D8_CI4ZF.js +1 -0
  672. package/web/assets/erDiagram-SZLJLQMB-CohQjznC.js +85 -0
  673. package/web/assets/error-D9MtuG9s.js +1 -0
  674. package/web/assets/eventmodeling-45OFAUF4-AOUJWSLX-BvTc6iQi.js +1 -0
  675. package/web/assets/flowDiagram-BWE6NHOH-B6RnEvD9.js +1 -0
  676. package/web/assets/ganttDiagram-2QTCJSNI-Cks_mEcF.js +292 -0
  677. package/web/assets/gitGraph-TEB2WS4Q-U5VWYIBC-Dy7CCSZ5.js +1 -0
  678. package/web/assets/gitGraphDiagram-VVZAVV5G-CG41cIVc.js +106 -0
  679. package/web/assets/{index-D7mTFcvQ.js → index-2zdvEdzg.js} +51 -51
  680. package/web/assets/index-CJDpyH-n.css +2 -0
  681. package/web/assets/info-DKCQHKI2-DX6KST54-BLJg1ikX.js +1 -0
  682. package/web/assets/infoDiagram-FY4PZKRE-BJ3vPVwW.js +2 -0
  683. package/web/assets/{ishikawaDiagram-BNXS4ZKH-XpjJRU9h.js → ishikawaDiagram-4JDSWWDM-DmqWtjkl.js} +2 -2
  684. package/web/assets/{journeyDiagram-M6C3CM3L-C6wjooas.js → journeyDiagram-QUS3FAKT-XAzVzrQW.js} +3 -3
  685. package/web/assets/{kanban-definition-75IXJCU3-5_UVY79g.js → kanban-definition-D4L7SQKK-YurRnmYn.js} +6 -6
  686. package/web/assets/katex-C5OPUE3Q-Bnbavtmu.js +257 -0
  687. package/web/assets/{mindmap-definition-2TDM6QVE-8xDLzk2e.js → mindmap-definition-66QP5TD6-ChrWWnil.js} +5 -5
  688. package/web/assets/node.browser-U-KyT5AW.js +1 -0
  689. package/web/assets/packet-7NZHBO7P-5WG45QPS-KUxcuvaA.js +1 -0
  690. package/web/assets/pegDiagram-YKIO5C6U-QGeQLEq2.js +1 -0
  691. package/web/assets/pie-RZYD4A2V-2OCZ2VTD-DPs08kJY.js +1 -0
  692. package/web/assets/pieDiagram-YPY3TKG5-BuT3MYzm.js +39 -0
  693. package/web/assets/{quadrantDiagram-VICAPDV7-DR54jOeR.js → quadrantDiagram-VO5QLCXA-B7098wSc.js} +3 -3
  694. package/web/assets/radar-I7S5WNFK-EPLSA35B-w5F0K3a7.js +1 -0
  695. package/web/assets/railroad-3IZDKUUU-PWFQV6Y6-Bu668yqY.js +1 -0
  696. package/web/assets/railroad-abnf-AHOZXSZD-JYYJX3BS-B6ghpETS.js +1 -0
  697. package/web/assets/railroad-ebnf-EBAXGLYW-RBZ4ONAP-D-XmHh3M.js +1 -0
  698. package/web/assets/railroad-peg-LSFZ7HO6-KHNPXGPG-mhkrhzEn.js +1 -0
  699. package/web/assets/railroadDiagram-M77LTMSB-AXu4vxk_.js +1 -0
  700. package/web/assets/{requirementDiagram-JXO7QTGE-PEkg7sKC.js → requirementDiagram-RASO5HTO-B-l8InpK.js} +4 -4
  701. package/web/assets/{sankeyDiagram-URQDO5SZ-DDWEtjcs.js → sankeyDiagram-F32LOJ6L-Kd7zjJgX.js} +3 -3
  702. package/web/assets/{sequenceDiagram-VS2MUI6T-Bv-uwANx.js → sequenceDiagram-URATNSBD-BlcdY9DS.js} +7 -7
  703. package/web/assets/sizeCapture-5GORAGP4-BEqQzsxs.js +1 -0
  704. package/web/assets/src-C5sx_gMp.js +1 -0
  705. package/web/assets/stateDiagram-DODFXNG5-DTdHc-fF.js +1 -0
  706. package/web/assets/stateDiagram-v2-JNMM5JRA-DioNLDDo.js +1 -0
  707. package/web/assets/swimlanes-OSWOYLSK-CA0ofdwY.js +2 -0
  708. package/web/assets/swimlanesDiagram-RHGX2RDE-PkwUdckC.js +8 -0
  709. package/web/assets/{timeline-definition-O6YCAMPW-Qmsuo7qS.js → timeline-definition-WJXWRH4I-DUfp1R3E.js} +3 -3
  710. package/web/assets/treeView-QDETBFTQ-EHYTSQNO-C5lpBgPm.js +1 -0
  711. package/web/assets/treemap-6X3UGDF4-CCWCF7EK-BB0ZyO-B.js +1 -0
  712. package/web/assets/vennDiagram-K3VCMQLI-Bj-FN-XS.js +34 -0
  713. package/web/assets/wardley-OPB4EBWU-6OWERDVT-CEA3Nq0j.js +1 -0
  714. package/web/assets/wardleyDiagram-XK6FUAWV-CVV0dHFr.js +78 -0
  715. package/web/assets/xychartDiagram-5VRUVLCW-CK_rbSWE.js +7 -0
  716. package/web/index.html +16 -15
  717. package/dist/core/ingestion/languages/python/index-stats.d.ts +0 -18
  718. package/dist/core/ingestion/languages/python/index-stats.js +0 -25
  719. package/web/assets/ProcessFlowModal-CwkpVkv-.js +0 -22
  720. package/web/assets/agent-Ds-lkZjX.js +0 -626
  721. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BVWFvYz2.js +0 -1
  722. package/web/assets/architectureDiagram-UL44E2DR-CmG3uPWf.js +0 -36
  723. package/web/assets/chunk-2T2R6R2M-Bb6Sy3_j.js +0 -4
  724. package/web/assets/chunk-2UTLFMKG-CXlhF3Pt.js +0 -1
  725. package/web/assets/chunk-3SSMPTDK-rPsRM1x0.js +0 -321
  726. package/web/assets/chunk-4R4BOZG6-Be_F0JoX.js +0 -159
  727. package/web/assets/chunk-67TQ5CYL-CA7OhIEf.js +0 -124
  728. package/web/assets/chunk-7J6CGLKN-BlKwgXKs.js +0 -10
  729. package/web/assets/chunk-C62D2QBJ-3gdL8EKc.js +0 -1
  730. package/web/assets/chunk-CEXFNPSA-CjwtMDkc.js +0 -1
  731. package/web/assets/chunk-J5EP6P6S-L19oz55R.js +0 -1
  732. package/web/assets/chunk-KGFNY3KK-BZeP-55u.js +0 -62
  733. package/web/assets/chunk-KGYTTC2M-zm6n242I.js +0 -1
  734. package/web/assets/chunk-KNLZD3CH-BGlP6X9R.js +0 -1
  735. package/web/assets/chunk-LRIF4GLE-n59lhprL.js +0 -1
  736. package/web/assets/chunk-RERM46MO-B5dAdWpP.js +0 -1
  737. package/web/assets/chunk-RKZBBQEN-MyIQbGgD.js +0 -1
  738. package/web/assets/chunk-T2UQINTJ-BEyXhZWe.js +0 -1
  739. package/web/assets/chunk-UP6H54XL-BG-n7qDp.js +0 -1
  740. package/web/assets/chunk-UXSXWOXI-CW1_r5cS.js +0 -1
  741. package/web/assets/chunk-UY5QBCOK-ByqTVLvh.js +0 -1
  742. package/web/assets/chunk-VU6ZFW4Y-BLeasdkU.js +0 -2
  743. package/web/assets/classDiagram-KGZ6W3CR-olpO3fMe.js +0 -1
  744. package/web/assets/classDiagram-v2-72OJOZXJ-olpO3fMe.js +0 -1
  745. package/web/assets/dagre-ND4H6XIP-CY4iIF7v.js +0 -4
  746. package/web/assets/diagram-3NCE3AQN-CO6QpzEE.js +0 -43
  747. package/web/assets/diagram-GF46GFSD-B2atbzmU.js +0 -24
  748. package/web/assets/diagram-QXG6HAR7-DR6AHD2h.js +0 -24
  749. package/web/assets/diagram-WEQXMOUZ-DkpoMwTL.js +0 -10
  750. package/web/assets/erDiagram-L5TCEMPS-n8g_90bc.js +0 -85
  751. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-CgFBM7e-.js +0 -1
  752. package/web/assets/flowDiagram-H6V6AXG4-SGMDiCkB.js +0 -162
  753. package/web/assets/ganttDiagram-JCBTUEKG-Cb3UBqRS.js +0 -292
  754. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DCJv7SII.js +0 -1
  755. package/web/assets/gitGraphDiagram-S2ZK5IYY-Bs9CR7tq.js +0 -106
  756. package/web/assets/index-CX_fADmQ.css +0 -2
  757. package/web/assets/info-J43DQDTF-KCYPFFUO-BfNy-9Nd.js +0 -1
  758. package/web/assets/infoDiagram-3YFTVSEB-T368on4D.js +0 -2
  759. package/web/assets/katex-K3KEBU37-qRQBy-EZ.js +0 -261
  760. package/web/assets/node-Ct_zna8U.js +0 -8
  761. package/web/assets/packet-YPE3B663-LP52Z2RK-D4qkeG9k.js +0 -1
  762. package/web/assets/pie-LRSECV5Y-TCRJHUBD-B_yMKyQa.js +0 -1
  763. package/web/assets/pieDiagram-CU6KROY3-Bv4LpAbr.js +0 -30
  764. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DeD6yN_0.js +0 -1
  765. package/web/assets/sdk-CzHHH8tD.js +0 -37
  766. package/web/assets/src-Cv1eWg0o.js +0 -1
  767. package/web/assets/stateDiagram-7D4R322I-DVNjmkEq.js +0 -1
  768. package/web/assets/stateDiagram-v2-36443NZ5-CyN4Fh7_.js +0 -1
  769. package/web/assets/treeView-BLDUP644-QA4HXRO3-CDuSYnd4.js +0 -1
  770. package/web/assets/treemap-LRROVOQU-LLAWBHMP-imazucyJ.js +0 -1
  771. package/web/assets/vennDiagram-MWXL3ELB-BD1iK1SX.js +0 -34
  772. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-DqrT9tB8.js +0 -1
  773. package/web/assets/wardleyDiagram-CUQ6CDDI-D6TzLVob.js +0 -78
  774. package/web/assets/xychartDiagram-N2JHSOCM-CoZ_Tits.js +0 -7
  775. /package/web/assets/{chunk-7W6UQGC5-pyKGssV3.js → chunk-LIEV3EAG-pyKGssV3.js} +0 -0
@@ -8,14 +8,18 @@
8
8
  *
9
9
  * 1. **super branch** — `provider.isSuperReceiver(receiverName)` →
10
10
  * MRO walk skipping self
11
- * 2. **Case 0 (compound)** — receiver has `.` or `(` → compound resolver
11
+ * 2. **Case 0 (compound)** — receiver has `.` or `(` → compound resolver.
12
+ * Also emits the interface-dispatch fan-out when the folded receiver type
13
+ * is an Interface (#2829) — see Case 4, which does the same.
12
14
  * 3. **Case 0.5 (implicit `this` receiver)** — GATED: fires only when
13
15
  * the language sets `resolveThisViaEnclosingClass === true` AND the
14
16
  * receiver is literally `this` → enclosing-class + MRO chain walk
15
17
  * with C++ member-name-hiding semantics. Languages that leave the
16
18
  * toggle unset skip this case entirely; their `this` sites fall
17
19
  * through to Case 4 via the synthesized `this` typeBinding (which
18
- * also emits interface-dispatch fan-out that this case does not).
20
+ * emits the interface-dispatch fan-out that this case does not —
21
+ * as do Cases 0 since #2829 and 3b since #2832; Case 0.5 remains
22
+ * the only fold-or-walk case without it).
19
23
  * 4. **Case 1 (namespace)** — receiver in `namespaceTargets` → exported def
20
24
  * 5. **Case 2 (class-name / static receiver)** — receiver resolves to a
21
25
  * class-like binding (Class/Interface/Struct/Record/Enum/Trait) → MRO
@@ -25,7 +29,9 @@
25
29
  * 6. **Case 3 (dotted typeBinding for namespace prefix)** —
26
30
  * `typeRef.rawName` like `models.User`
27
31
  * 7. **Case 3b (chain-typebinding)** — `typeRef.rawName` has a dot
28
- * but not a namespace prefix → compound resolver
32
+ * but not a namespace prefix → compound resolver. Also emits the
33
+ * interface-dispatch fan-out when the folded receiver type is an
34
+ * Interface (#2832) — same call Cases 0 and 4 make.
29
35
  * 8. **Case 4 (simple typeBinding)** — `typeRef.rawName` has no dot →
30
36
  * MRO walk + `findOwnedMember`
31
37
  * 9. **Case 5 (value-receiver bridge)** — receiver is a `Const`/`Variable`
@@ -33,6 +39,15 @@
33
39
  * (object-literal services). Last-resort fallback for lowercase
34
40
  * receivers with no class-like or type-binding match. Mirrors
35
41
  * the legacy DAG bridge in `call-processor.ts`.
42
+ * 10. **Case 6 (class-level member receiver)** — `Holder.repo.save(u)`,
43
+ * where the receiver's head is a CLASS and the one hop past it is a
44
+ * class-level (`isStatic`) field. Types the receiver from that field
45
+ * DEF's declared type rather than from a `typeBindings` entry, which
46
+ * is the thing a per-scope binding map cannot hold for a class that
47
+ * declares both a static and an instance member of one name. Gated on
48
+ * Case 0 having declined the same receiver, so it only ever adds an
49
+ * edge where there was none. Emits the interface-dispatch fan-out
50
+ * alongside Cases 0, 3b and 4.
36
51
  *
37
52
  * Reordering or merging cases changes resolution semantics.
38
53
  *
@@ -44,55 +59,134 @@
44
59
  * resolved to a wrong target.
45
60
  */
46
61
  import { collectNamespaceTargets } from '../scope/namespace-targets.js';
47
- import { findClassBindingInScope, findEnclosingClassDef, findExportedDef, findOwnedMember, findReceiverTypeBinding, findValueBindingInScope, isClassLike, } from '../scope/walkers.js';
62
+ import { bindsTypeParameter, findClassBindingInScope, findEnclosingClassDef, isReceiverOwnedButUnbound, findExportedDef, findOwnedMember, findReceiverTypeBinding, findValueBindingInScope, isClassLike, isNamespaceNameShadowed, resolveClassBindingForName, } from '../scope/walkers.js';
48
63
  import { tryEmitEdge, tryEmitEdgeWithExplicitTargetId, } from '../graph-bridge/edges.js';
49
- import { resolveCompoundReceiverClass } from '../passes/compound-receiver.js';
64
+ import { resolveCompoundReceiverClass, resolveCompoundReceiverTyped, } from '../passes/compound-receiver.js';
65
+ import { erasedTypeApplication, typeApplicationArguments } from '../../utils/template-arguments.js';
66
+ import { heritageTypeArgumentsKey, stepHeritageInstantiation, } from '../utils/generic-instantiation.js';
50
67
  import { resolveDefGraphId } from '../graph-bridge/ids.js';
51
68
  import { narrowOverloadCandidates, isOverloadAmbiguousAfterNormalization, } from './overload-narrowing.js';
52
- import { extractTemplateArguments, stripTemplateArguments, } from '../../utils/template-arguments.js';
53
- function normalizeTemplateArgToken(value) {
54
- return value.replace(/\s+/g, '');
69
+ import { classifyReceiverShape } from '../resolution-outcome.js';
70
+ import { decodeReceiverChain } from '../../utils/receiver-chain-codec.js';
71
+ /** A bare, undecorated identifier and nothing else — see {@link isBareTypeName}. */
72
+ const BARE_TYPE_NAME_RE = /^[A-Za-z_$][\w$]*$/;
73
+ /**
74
+ * A type name a built-in test may be asked about: a bare, undecorated
75
+ * identifier and nothing else.
76
+ *
77
+ * `Promise<User>`, `[]Repo` and `Option<Repo>` all name a built-in CONTAINER
78
+ * whose ELEMENT is very often in-program, and an await/index/unwrap step is
79
+ * exactly how a receiver chain reaches that element. Answering "external"
80
+ * because the outer spelling matched a built-in would relabel a real in-program
81
+ * drop, which is the failure this whole function exists to stop. A decorated or
82
+ * dotted spelling is likewise not a built-in name, it merely contains one.
83
+ */
84
+ function isBareTypeName(rawName) {
85
+ return BARE_TYPE_NAME_RE.test(rawName);
55
86
  }
56
- function resolveClassBindingForName(scopeId, rawClassName, scopes) {
57
- const direct = findClassBindingInScope(scopeId, rawClassName, scopes);
58
- if (direct !== undefined)
59
- return direct;
60
- if (!rawClassName.includes('<'))
61
- return undefined;
62
- const baseName = stripTemplateArguments(rawClassName).replace(/\s+/g, '');
63
- if (baseName.length === 0)
64
- return undefined;
65
- const wantedArgs = extractTemplateArguments(rawClassName)?.map(normalizeTemplateArgToken);
66
- if (wantedArgs !== undefined && wantedArgs.length > 0) {
67
- // qualifiedNames is a Map and may not contain the stripped base name at all
68
- // (e.g., unresolved type binding or only template-qualified entries), so
69
- // default to [] before checking `.length`.
70
- const qnameIds = scopes.qualifiedNames.get(baseName) ?? [];
71
- if (qnameIds.length === 0) {
72
- return findClassBindingInScope(scopeId, baseName, scopes);
87
+ /**
88
+ * Is this dropped receiver rooted inside the analyzed program?
89
+ *
90
+ * Asks of the receiver's BASE — the leftmost name the chain hangs off — what
91
+ * this index can DEMONSTRATE. Three answers, and the asymmetry between them is
92
+ * the whole point:
93
+ *
94
+ * - `in-program` — the base's declared type resolves here, or the base itself is
95
+ * a class, a qualified name, or a value this program declares. A real edge was
96
+ * lost; the hedge must fire.
97
+ * - `external` — POSITIVE evidence that the target is outside: the language
98
+ * itself names the base (or its bare declared type) a built-in. `console.log`,
99
+ * `fetch(...)`, `JSON.stringify` reach code no index contains, so there is no
100
+ * node an edge could have pointed at and nothing was lost.
101
+ * - `unknown` — everything else. An absence of evidence is NOT evidence of
102
+ * externality: an unannotated parameter (`function f(svc) { svc.a().b(); }`)
103
+ * is recorded nowhere in the scope model at all, and calling that "external"
104
+ * published `epistemic: 'exact'` over a genuinely missing in-program caller —
105
+ * strictly worse than hedging, because it is a confident wrong answer rather
106
+ * than an admitted gap. `unknown` counts WITH `in-program` in
107
+ * `summarizeUnresolvedReceivers`, which is the safe direction.
108
+ *
109
+ * Uses the AST-derived chain base when one was minted, and falls back to the
110
+ * head of the receiver text otherwise — never a regex over the source line.
111
+ *
112
+ * Exported for the unit tests that pin the three-way split; the pass is its only
113
+ * production caller.
114
+ */
115
+ export function classifyReceiverOrigin(decoded, inScope, receiverName, scopes, options = {}) {
116
+ // The chain's base is authoritative. Without one, take the head of the
117
+ // receiver text up to the first member/call punctuation.
118
+ const base = decoded?.baseReceiverName ?? /^[A-Za-z_$][\w$]*/.exec(receiverName)?.[0];
119
+ if (base === undefined || base.length === 0)
120
+ return 'unknown';
121
+ const strip = options.stripTypePreservingDecoration;
122
+ const isBuiltIn = options.isBuiltInName;
123
+ // The base's declared TYPE, when it has one, is the strongest signal about
124
+ // where the member lives: `inputs.stream()` has an in-program base bound to
125
+ // `List<String>`, whose `stream` is in the JDK.
126
+ const binding = findReceiverTypeBinding(inScope, base, scopes);
127
+ if (binding !== undefined) {
128
+ // `resolveClassBindingForName`, not a bare lookup: it also strips template
129
+ // arguments, so an in-program generic base (`Box<String> b; b.open()`)
130
+ // resolves instead of being mislabelled and dropped from the hedge.
131
+ if (resolveClassBindingForName(binding.declaredAtScope, binding.rawName, scopes, strip) !==
132
+ undefined) {
133
+ return 'in-program';
73
134
  }
74
- const matches = [];
75
- for (const id of qnameIds) {
76
- const def = scopes.defs.get(id);
77
- if (def === undefined || !isClassLike(def.type))
78
- continue;
79
- const defArgs = def.templateArguments?.map(normalizeTemplateArgToken);
80
- if (defArgs !== undefined &&
81
- defArgs.length === wantedArgs.length &&
82
- defArgs.every((value, i) => value === wantedArgs[i])) {
83
- matches.push(def);
84
- }
135
+ // The declared type is not one this index contains. That is only proof of
136
+ // externality when the language itself names it — otherwise the type merely
137
+ // failed to resolve (an alias, an inferred callable, a generic parameter),
138
+ // and we fall through to ask what the index knows about the base itself.
139
+ if (isBareTypeName(binding.rawName) && isBuiltIn?.(binding.rawName) === true) {
140
+ return 'external';
85
141
  }
86
- if (matches.length === 1)
87
- return matches[0];
88
- // Scope extractor only records class definitions with bodies in C++, so
89
- // forward declarations are not expected here. Keep fallback behavior for
90
- // safety in non-ODR or mixed-language edge cases.
91
142
  }
92
- return findClassBindingInScope(scopeId, baseName, scopes);
143
+ // Anything else this index knows by that name (namespace, module, free fn).
144
+ // O(1), so it goes ahead of the scope-chain walks below: all three checks are
145
+ // arms of the same `in-program` disjunction and none has a side effect, so
146
+ // answering from the index first is free and changes no verdict.
147
+ if (scopes.qualifiedNames.has(base))
148
+ return 'in-program';
149
+ // A type the program declares, used as a static receiver.
150
+ if (findClassBindingInScope(inScope, base, scopes, strip) !== undefined)
151
+ return 'in-program';
152
+ // A VALUE the program declares — an object-literal service, a local whose
153
+ // initializer we could not type (`const loc = makeIt(); loc.getUser().save()`),
154
+ // a field. The type channel had nothing usable to say about these, but the
155
+ // program demonstrably declares the name, so the lost edge is in-program and
156
+ // failing to type it is a resolver defect. This is the channel Case 5 already
157
+ // dispatches on; consulting it here keeps the diagnostic honest about the
158
+ // same population.
159
+ if (findValueBindingInScope(inScope, base, scopes) !== undefined)
160
+ return 'in-program';
161
+ // Positive external evidence, and the only kind reachable from this pass.
162
+ if (isBuiltIn?.(base) === true)
163
+ return 'external';
164
+ return 'unknown';
93
165
  }
166
+ /**
167
+ * Upper bound on how many implementors ONE interface member may fan out to at a
168
+ * single call site (#2829).
169
+ *
170
+ * Mirrors `MAX_PROPERTY_DISPATCH_FANOUT` in `property-dispatch.ts`, deliberately
171
+ * including its reporting half: a bare cap would silently discard valid dispatch
172
+ * targets, which is the same false-safe silence #2813 was filed about. The
173
+ * default matches that sibling's 32 — the fan-out is a per-call-site product, so
174
+ * an interface with hundreds of implementors (mock proliferation is the usual
175
+ * cause) multiplies the graph without adding information a reader can act on.
176
+ *
177
+ * Override with `GITNEXUS_MAX_INTERFACE_DISPATCH_FANOUT` for a repo with
178
+ * legitimately high implementor counts.
179
+ */
180
+ export const MAX_INTERFACE_DISPATCH_FANOUT = (() => {
181
+ const env = Number(process.env.GITNEXUS_MAX_INTERFACE_DISPATCH_FANOUT);
182
+ return Number.isInteger(env) && env >= 1 ? env : 32;
183
+ })();
184
+ /** Bound on the sample of over-cap interface members kept for the warning. */
185
+ const MAX_REPORTED_SKIPPED_INTERFACES = 20;
94
186
  export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, handledSites, provider, index, model, options = {}) {
95
187
  let emitted = 0;
188
+ let dispatchFanoutSkipped = 0;
189
+ const dispatchFanoutSkippedNames = [];
96
190
  // Per-pass dedup so the multiple cases don't double-emit if two of
97
191
  // them resolve the same site to the same target. NEVER pre-seed
98
192
  // from the reference index — see Contract Invariant I5.
@@ -102,66 +196,394 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
102
196
  const hoistTypeBindingsToModule = provider.hoistTypeBindingsToModule === true;
103
197
  const compoundOpts = {
104
198
  fieldFallback,
105
- unwrapCollectionAccessor: provider.unwrapCollectionAccessor,
199
+ elementTypeOf: provider.elementTypeOf,
106
200
  hoistTypeBindingsToModule,
107
201
  stripReceiverCastExpressions: provider.stripReceiverCastExpressions === true,
202
+ constructionSyntax: provider.constructionSyntax,
203
+ stripTypePreservingDecoration: provider.stripTypePreservingDecoration,
204
+ resolveThisViaEnclosingClass: provider.resolveThisViaEnclosingClass,
205
+ };
206
+ // Loop-invariant: both hooks come off the pass arguments, so the options bag
207
+ // for `classifyReceiverOrigin` is built once here rather than per dropped site.
208
+ const receiverOriginOpts = {
209
+ stripTypePreservingDecoration: provider.stripTypePreservingDecoration,
210
+ isBuiltInName: options.isBuiltInName,
108
211
  };
109
- // Build an interface → implementors map from IMPLEMENTS edges.
110
- // Maps Interface graph-id → list of implementor class scope-def-ids.
111
- // We translate graph-ids back to scope-resolution DefIds via
112
- // `parsedFiles.localDefs` lookup so downstream `findOwnedMember`
113
- // (which keys by DefId) can find the implementor's members.
114
- const graphIdToClassDef = new Map();
212
+ // Maps class-like graph ids back to ALL scope definitions that resolved to
213
+ // them. Same-file partial declarations share one graph id but keep distinct
214
+ // DefIds, and `pickOverload` keys member lookup by those DefIds. Preserving
215
+ // every part makes dispatch independent of declaration order.
216
+ const graphIdToClassDefs = new Map();
217
+ // The same correspondence read the other way, so the dispatch walk can name a
218
+ // heritage EDGE (which is keyed by graph ids) from the two DEFS it holds.
219
+ const classGraphIdByDefId = new Map();
220
+ /**
221
+ * Does THIS language record generic type parameters (#2912)?
222
+ *
223
+ * `SymbolDefinition.typeParameters` is absent both for a non-generic
224
+ * declaration and for every declaration in a language whose captures do not
225
+ * emit `@declaration.type-parameters`, and instantiation filtering needs the
226
+ * two told apart: in the second case a heritage argument `T` is a type
227
+ * VARIABLE that would otherwise read as a concrete type named "T", and
228
+ * `class Box<T> : IValidator<T>` would be pruned out of every instantiation.
229
+ *
230
+ * Evidence rather than a declared capability, because the evidence is exactly
231
+ * as good and costs nothing: one run resolves one language (`phase.ts` loops
232
+ * per language), so a single generic declaration anywhere in it proves the
233
+ * captures record parameters. A run where none exists cannot be harmed by the
234
+ * answer — with no generic declaration there is no type variable to mistake.
235
+ */
236
+ let languageCapturesTypeParameters = false;
115
237
  for (const parsed of parsedFiles) {
116
238
  for (const def of parsed.localDefs) {
117
- if (def.type !== 'Class' && def.type !== 'Struct' && def.type !== 'Interface')
239
+ if (!isClassLike(def.type))
118
240
  continue;
119
241
  const graphId = resolveDefGraphId(parsed.filePath, def, nodeLookup);
120
- if (graphId !== undefined)
121
- graphIdToClassDef.set(graphId, def);
242
+ if (graphId === undefined)
243
+ continue;
244
+ let defs = graphIdToClassDefs.get(graphId);
245
+ if (defs === undefined) {
246
+ defs = [];
247
+ graphIdToClassDefs.set(graphId, defs);
248
+ }
249
+ defs.push(def);
250
+ classGraphIdByDefId.set(def.nodeId, graphId);
251
+ if (def.typeParameters !== undefined && def.typeParameters.length > 0) {
252
+ languageCapturesTypeParameters = true;
253
+ }
122
254
  }
123
255
  }
124
- const implementorsByInterfaceDefId = new Map();
125
- for (const rel of graph.iterRelationshipsByType('IMPLEMENTS')) {
126
- const ifaceDef = graphIdToClassDef.get(rel.targetId);
127
- const implDef = graphIdToClassDef.get(rel.sourceId);
128
- if (ifaceDef === undefined || implDef === undefined)
129
- continue;
130
- let list = implementorsByInterfaceDefId.get(ifaceDef.nodeId);
256
+ // Direct subtypes of a type, keyed by the SUPERtype's def id.
257
+ //
258
+ // Built from IMPLEMENTS **and** EXTENDS (#2829). IMPLEMENTS alone is not the
259
+ // set of implementations: `preEmitInheritanceEdges` classifies heritage by the
260
+ // TARGET's kind, so `interface B extends A` is stored as `B IMPLEMENTS A` and
261
+ // an INTERFACE lands in A's list; and a concrete class reaches its interface
262
+ // through `class C extends AbstractBase` (EXTENDS) + `AbstractBase implements
263
+ // I` (IMPLEMENTS), so it is two hops away and invisible to a depth-1 walk.
264
+ // Both shapes previously ended the fan-out on a bodiless declaration while the
265
+ // only executable target got no edge at all.
266
+ const subtypesBySupertypeDefId = new Map();
267
+ const addSubtype = (superId, sub) => {
268
+ let list = subtypesBySupertypeDefId.get(superId);
131
269
  if (list === undefined) {
132
270
  list = [];
133
- implementorsByInterfaceDefId.set(ifaceDef.nodeId, list);
271
+ subtypesBySupertypeDefId.set(superId, list);
272
+ }
273
+ list.push(sub);
274
+ };
275
+ for (const relType of ['IMPLEMENTS', 'EXTENDS']) {
276
+ for (const rel of graph.iterRelationshipsByType(relType)) {
277
+ const superDefs = graphIdToClassDefs.get(rel.targetId);
278
+ const subDefs = graphIdToClassDefs.get(rel.sourceId);
279
+ if (superDefs === undefined || subDefs === undefined)
280
+ continue;
281
+ for (const superDef of superDefs) {
282
+ for (const subDef of subDefs)
283
+ addSubtype(superDef.nodeId, subDef);
284
+ }
134
285
  }
135
- list.push(implDef);
136
286
  }
137
- /** Emit secondary CALLS edges with reason='interface-dispatch'
138
- * when the primary receiver-typed edge targeted an Interface's
139
- * method. Each implementing class's same-named method gets a
140
- * secondary edge (excluding the primary target itself). */
141
- const emitInterfaceDispatchFor = (ownerDef, memberName, primaryMemberDef, site, confidence, calleeCapture) => {
287
+ /**
288
+ * Is this member a bodiless DECLARATION rather than an implementation?
289
+ *
290
+ * An interface method, and an `abstract` method on an abstract base, are
291
+ * both declarations: dispatching to them names something with no body while
292
+ * the executable target sits further down the hierarchy. `isAbstract` lives
293
+ * on the graph NODE (the structure phase sets it), not on `SymbolDefinition`,
294
+ * so this resolves the def to its node. A def that cannot be resolved is
295
+ * treated as NOT abstract — the fail-open direction, matching how the rest of
296
+ * this pass treats an unresolvable lookup.
297
+ */
298
+ const isDeclarationOnly = (def) => {
299
+ const graphId = resolveDefGraphId(def.filePath, def, nodeLookup);
300
+ if (graphId === undefined)
301
+ return false;
302
+ return graph.getNode(graphId)?.properties.isAbstract === true;
303
+ };
304
+ /**
305
+ * Can an INSTANCE-typed receiver reach this member? A static member cannot be,
306
+ * ever — `class C implements I { static save() {} }` does not satisfy `I`
307
+ * (TypeScript rejects it outright as TS2420, "Property 'save' is missing"), so
308
+ * an edge to it from an `I`-typed receiver names a target no dispatch can
309
+ * produce. Every comparable tool draws the same line: tsserver partitions
310
+ * static from instance results, clangd gates on `isVirtual()` (C++ forbids
311
+ * virtual statics), jdtls filters abstract-or-static, and class-hierarchy
312
+ * analysis expands only VIRTUAL call sites — a static call already has exactly
313
+ * one target and needs no fan-out.
314
+ *
315
+ * Two sources answer this, and the order matters:
316
+ *
317
+ * 1. `provider.isStaticOnly` when the language declares it. It is the
318
+ * precise answer, because a language that needs the distinction defines
319
+ * it exactly — Kotlin marks only COMPANION-promoted defs, so a Kotlin
320
+ * `object Impl : Iface { override fun handle() }` is correctly kept: an
321
+ * `object` is a singleton INSTANCE and its members really are reachable
322
+ * through an `Iface`-typed receiver.
323
+ * 2. Otherwise the graph node's `isStatic`. For every language that does not
324
+ * declare the hook, that flag comes from the member's own modifier (or,
325
+ * for Ruby, from `singleton_class` — `def self.foo`, which is likewise
326
+ * unreachable through an instance), so it means what we need here.
327
+ *
328
+ * Getting that order wrong is a live regression, not a hypothetical: the
329
+ * method extractor derives `isStatic` from the OWNER type as well as the
330
+ * member (`method-extractors/generic.ts`, `staticOwnerTypes`), and the JVM
331
+ * config lists `object_declaration`. Reading the flag first would delete
332
+ * Kotlin object implementations from the fan-out. A language that needs
333
+ * precision declares the hook; that is the upgrade path.
334
+ *
335
+ * Unresolvable defs fail open (treated as reachable), matching
336
+ * `isDeclarationOnly` and the rest of this pass.
337
+ */
338
+ const isUnreachableByInstanceDispatch = (def) => {
339
+ const staticOnly = provider.isStaticOnly;
340
+ if (staticOnly !== undefined)
341
+ return staticOnly(def) === true;
342
+ const graphId = resolveDefGraphId(def.filePath, def, nodeLookup);
343
+ if (graphId === undefined)
344
+ return false;
345
+ return graph.getNode(graphId)?.properties.isStatic === true;
346
+ };
347
+ /**
348
+ * What does this written type argument NAME, as seen from `scopeId` (#2912)?
349
+ *
350
+ * The scope is load-bearing: a heritage argument is resolved from the
351
+ * declaring class's own scope and a receiver argument from the call site's,
352
+ * because a name means what it means where it was WRITTEN. Resolving both
353
+ * makes `Models.User` and an imported `User` one type, which a string
354
+ * comparison could only get wrong.
355
+ *
356
+ * Neither answer is an error: a name that binds nothing and is not built in
357
+ * comes back ungrounded, which the matcher reads as "unknown" and keeps.
358
+ *
359
+ * A TYPE PARAMETER is reported as such rather than left to the ungrounded
360
+ * path, because `resolveClassBindingForName` answers a bounded one with its
361
+ * BOUND's declaration — grounded, and the wrong thing to compare.
362
+ */
363
+ const groundTypeArgument = (name, scopeId) => {
364
+ const def = scopeId === undefined ? undefined : resolveClassBindingForName(scopeId, name, scopes);
365
+ return {
366
+ ...(def !== undefined ? { definitionId: def.nodeId } : {}),
367
+ builtIn: options.isBuiltInName?.(name) === true,
368
+ ...(scopeId !== undefined && bindsTypeParameter(scopeId, name, scopes)
369
+ ? { typeVariable: true }
370
+ : {}),
371
+ };
372
+ };
373
+ /**
374
+ * Emit secondary CALLS edges with reason='interface-dispatch' when the primary
375
+ * receiver-typed edge targeted an Interface's method.
376
+ *
377
+ * Walks the SUBTYPE CLOSURE of the interface rather than its direct
378
+ * implementors (#2829). Two shapes made the depth-1 walk both wrong and
379
+ * incomplete, each reproduced in plain Java:
380
+ *
381
+ * interface ReadCloser extends Reader { int read(String p); } // re-declares
382
+ * abstract class AbstractHandler implements Handler { public abstract void handle(String s); }
383
+ *
384
+ * In both, the depth-1 list contains a type whose `read`/`handle` is a bodiless
385
+ * declaration, so the fan-out emitted an edge to *that* — while the only class
386
+ * with a body (`FileRC`, `RealHandler`) is one hop further down and received
387
+ * nothing at all. Descending and skipping declarations fixes both directions
388
+ * at once: the wrong edge disappears and the real implementation gains one.
389
+ *
390
+ * Descent continues THROUGH a type that supplied a concrete member, because an
391
+ * override further down is an equally real runtime target — dispatch is an
392
+ * over-approximation by design, and stopping early would silently prefer the
393
+ * base.
394
+ *
395
+ * The closure is walked carrying the receiver's generic INSTANTIATION (#2912).
396
+ * `IValidator<string>` and `IValidator<int>` are one declaration and therefore
397
+ * one subtype list, so without the substitution a `IValidator<string>` call
398
+ * reaches `IntValidator.Check(int)` — a target no dispatch can produce. Each
399
+ * hop unifies the arguments the subtype wrote against the ones the supertype
400
+ * is known to hold; an incompatible hop is skipped BEFORE the visit is
401
+ * recorded, so a type reachable by a second, compatible path still gets its
402
+ * edge, and skipped WITHOUT descending, because its own subtypes inherit the
403
+ * mismatch.
404
+ * Every uncertainty keeps the target — see `generic-instantiation.ts`.
405
+ */
406
+ const emitInterfaceDispatchFor = (ownerDef, memberName, primaryMemberDef, site, confidence, calleeCapture,
407
+ /** The receiver's declared type AS WRITTEN (`IValidator<string>`), or
408
+ * `undefined` where the case could not recover it — which restores the
409
+ * unfiltered fan-out for that site rather than guessing.
410
+ *
411
+ * The SPELLING rather than the parsed arguments, so the parse happens after
412
+ * the two gates below rather than at every resolved receiver site: all five
413
+ * cases call this unconditionally, and the overwhelming majority of
414
+ * receivers are concrete classes that return at the first line. */
415
+ receiverTypeSpelling) => {
142
416
  if (ownerDef.type !== 'Interface')
143
417
  return 0;
144
- const impls = implementorsByInterfaceDefId.get(ownerDef.nodeId);
145
- if (impls === undefined)
418
+ if (subtypesBySupertypeDefId.get(ownerDef.nodeId) === undefined)
146
419
  return 0;
147
- let n = 0;
148
- for (const implDef of impls) {
149
- const implMember = pickOverload(implDef.nodeId, memberName, site, model, provider);
150
- if (implMember === undefined ||
151
- implMember === OVERLOAD_AMBIGUOUS ||
152
- implMember.isDeleted === true) {
153
- continue;
420
+ const receiverTypeArguments = receiverTypeSpelling === undefined
421
+ ? undefined
422
+ : typeApplicationArguments(receiverTypeSpelling);
423
+ // Captures only `site`, so it is built once per SITE rather than once per
424
+ // subtype visited. Its partner below cannot be: it is keyed by the subtype.
425
+ const resolveSupertypeArgument = (name) => groundTypeArgument(name, site.inScope);
426
+ const targetByMemberId = new Map();
427
+ const bestIncomingCount = new Map([[ownerDef.nodeId, 0]]);
428
+ const queue = [
429
+ {
430
+ typeId: ownerDef.nodeId,
431
+ ancestorImplementationCount: 0,
432
+ typeArguments: receiverTypeArguments,
433
+ },
434
+ ];
435
+ let head = 0;
436
+ let discoveryOrder = 0;
437
+ while (head < queue.length) {
438
+ const current = queue[head++];
439
+ // The whole instantiation apparatus hangs off ONE question: is the
440
+ // supertype's own instantiation known? It is not for a non-generic
441
+ // receiver, nor for any language that captures no heritage arguments, so
442
+ // those walks skip every lookup below and emit exactly what they did
443
+ // before #2912.
444
+ const superGraphId = current.typeArguments === undefined ? undefined : classGraphIdByDefId.get(current.typeId);
445
+ for (const subDef of subtypesBySupertypeDefId.get(current.typeId) ?? []) {
446
+ const previousIncomingCount = bestIncomingCount.get(subDef.nodeId);
447
+ if (previousIncomingCount !== undefined &&
448
+ previousIncomingCount <= current.ancestorImplementationCount) {
449
+ continue;
450
+ }
451
+ // What THIS heritage clause instantiated its base with. `superGraphId`
452
+ // already answers "is the supertype's instantiation known?", so it gates
453
+ // the whole lookup once instead of being re-asked at each step below.
454
+ let subtypeArguments;
455
+ if (superGraphId !== undefined) {
456
+ const subGraphId = classGraphIdByDefId.get(subDef.nodeId);
457
+ const heritageArguments = subGraphId === undefined
458
+ ? undefined
459
+ : options.heritageTypeArguments?.get(heritageTypeArgumentsKey(subGraphId, superGraphId));
460
+ if (heritageArguments !== undefined) {
461
+ const subtypeScopeId = index.classScopeByDefId.get(subDef.nodeId)?.id;
462
+ const step = stepHeritageInstantiation({
463
+ supertypeArguments: current.typeArguments,
464
+ heritageArguments,
465
+ subtypeParameters: subDef.typeParameters,
466
+ // The "this subtype declares parameters" disjunct an earlier
467
+ // revision carried here could never decide: `subDef` comes out of
468
+ // the same loop that sets this flag, from exactly these defs, so a
469
+ // subtype with parameters has already set it.
470
+ subtypeParametersComplete: languageCapturesTypeParameters,
471
+ resolveSupertypeArgument,
472
+ resolveHeritageArgument: (name) => groundTypeArgument(name, subtypeScopeId),
473
+ normalize: provider.normalizeTypeArgument,
474
+ });
475
+ // Skipped BEFORE the visit is recorded, so a type reachable by a
476
+ // second, compatible path still gets its edge; and without
477
+ // descending, because its own subtypes inherit the mismatch.
478
+ if (!step.compatible)
479
+ continue;
480
+ subtypeArguments = step.subtypeArguments;
481
+ }
482
+ }
483
+ bestIncomingCount.set(subDef.nodeId, current.ancestorImplementationCount);
484
+ const implMember = pickOverload(subDef.nodeId, memberName, site, model, provider);
485
+ let descendantImplementationCount = current.ancestorImplementationCount;
486
+ if (implMember !== undefined &&
487
+ implMember !== OVERLOAD_AMBIGUOUS &&
488
+ implMember.isDeleted !== true &&
489
+ implMember.nodeId !== primaryMemberDef.nodeId &&
490
+ !isDeclarationOnly(implMember) &&
491
+ !isUnreachableByInstanceDispatch(implMember)) {
492
+ const existing = targetByMemberId.get(implMember.nodeId);
493
+ const syntheticOwnerPriority = subDef.isSynthetic === true ? 1 : 0;
494
+ if (existing === undefined ||
495
+ syntheticOwnerPriority < existing.syntheticOwnerPriority ||
496
+ (syntheticOwnerPriority === existing.syntheticOwnerPriority &&
497
+ current.ancestorImplementationCount < existing.ancestorImplementationCount)) {
498
+ targetByMemberId.set(implMember.nodeId, {
499
+ member: implMember,
500
+ syntheticOwnerPriority,
501
+ ancestorImplementationCount: current.ancestorImplementationCount,
502
+ discoveryOrder: existing?.discoveryOrder ?? discoveryOrder++,
503
+ });
504
+ }
505
+ descendantImplementationCount++;
506
+ }
507
+ queue.push({
508
+ typeId: subDef.nodeId,
509
+ ancestorImplementationCount: descendantImplementationCount,
510
+ typeArguments: subtypeArguments,
511
+ });
154
512
  }
155
- if (implMember.nodeId === primaryMemberDef.nodeId)
156
- continue;
513
+ }
514
+ const targets = [...targetByMemberId.values()]
515
+ .sort((left, right) => left.syntheticOwnerPriority - right.syntheticOwnerPriority ||
516
+ left.ancestorImplementationCount - right.ancestorImplementationCount ||
517
+ left.discoveryOrder - right.discoveryOrder)
518
+ .map((target) => target.member);
519
+ // Bounded, and NEVER silently (#2829). An interface with a very large
520
+ // implementor set multiplies edges by every call site — Go, TypeScript and
521
+ // Kotlin do not set `collapseMemberCallsByCallerTarget`, so the product is
522
+ // per SITE. Truncating without saying so would recreate the false-safe
523
+ // silence this whole issue is about, which is why the sibling
524
+ // `MAX_PROPERTY_DISPATCH_FANOUT` reports its dropped keys too.
525
+ if (targets.length > MAX_INTERFACE_DISPATCH_FANOUT) {
526
+ dispatchFanoutSkipped += targets.length - MAX_INTERFACE_DISPATCH_FANOUT;
527
+ if (dispatchFanoutSkippedNames.length < MAX_REPORTED_SKIPPED_INTERFACES) {
528
+ const dropped = targets
529
+ .slice(MAX_INTERFACE_DISPATCH_FANOUT, MAX_INTERFACE_DISPATCH_FANOUT + 5)
530
+ .map((target) => target.qualifiedName ?? target.nodeId);
531
+ const omitted = targets.length - MAX_INTERFACE_DISPATCH_FANOUT - dropped.length;
532
+ dispatchFanoutSkippedNames.push(`${ownerDef.qualifiedName ?? ownerDef.nodeId}.${memberName} (${targets.length} targets; ` +
533
+ `dropped: ${dropped.join(', ')}${omitted > 0 ? `, +${omitted} more` : ''})`);
534
+ }
535
+ targets.length = MAX_INTERFACE_DISPATCH_FANOUT;
536
+ }
537
+ let n = 0;
538
+ for (const implMember of targets) {
157
539
  const ok = tryEmitEdge(graph, scopes, nodeLookup, site, implMember, 'interface-dispatch', seen, confidence, collapse, calleeCapture);
158
540
  if (ok)
159
541
  n++;
160
542
  }
161
543
  return n;
162
544
  };
545
+ /**
546
+ * Declared type of the CLASS-LEVEL field named `fieldName` on `ownerId`, or
547
+ * `undefined` when the owner declares no such field, declares only an
548
+ * instance one, or declares one whose type was never captured.
549
+ *
550
+ * Both facts live on the graph NODE rather than on `SymbolDefinition` —
551
+ * `isStatic` is set by the structure phase and `declaredType` by the field
552
+ * extractor — which is the same place {@link isUnreachableByInstanceDispatch}
553
+ * reads `isStatic` from, so this introduces no new dependency.
554
+ *
555
+ * `isStatic === true` is required, not merely preferred. The receiver that
556
+ * asks this question resolved its head to the CLASS, so an instance field of
557
+ * that name is not reachable through it and answering with the instance
558
+ * field's type would type the receiver as something the source cannot
559
+ * denote. A def that resolves to no node, or a node with no captured type,
560
+ * answers `undefined` — the declining direction, matching how the rest of
561
+ * this pass treats an unresolvable lookup.
562
+ */
563
+ const declaredTypeOfClassLevelField = (ownerId, fieldName) => {
564
+ for (const candidate of model.fields.lookupAllByOwner(ownerId, fieldName)) {
565
+ const graphId = resolveDefGraphId(candidate.filePath, candidate, nodeLookup);
566
+ if (graphId === undefined)
567
+ continue;
568
+ const properties = graph.getNode(graphId)?.properties;
569
+ if (properties?.isStatic !== true)
570
+ continue;
571
+ const declaredType = properties.declaredType;
572
+ if (typeof declaredType !== 'string')
573
+ continue;
574
+ const trimmed = declaredType.trim();
575
+ if (trimmed.length === 0)
576
+ continue;
577
+ return trimmed;
578
+ }
579
+ return undefined;
580
+ };
163
581
  for (const parsed of parsedFiles) {
164
- const namespaceTargets = collectNamespaceTargets(parsed, scopes);
582
+ const namespaceTargets = collectNamespaceTargets(parsed, scopes, {
583
+ receiverPaths: provider.namespaceReceiverPaths,
584
+ moduleFileExists: (filePath) => index.moduleScopeByFile.has(filePath),
585
+ });
586
+ const fileCompoundOpts = { ...compoundOpts, namespaceTargets };
165
587
  // Per-file resolved-callee-id capture context (#2227 U2). Built once per
166
588
  // file; `undefined` when the sink is absent (pdg off) so the `tryEmitEdge`
167
589
  // capture is a no-op and emission stays byte-identical (R4).
@@ -176,6 +598,27 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
176
598
  const receiverName = site.explicitReceiver.name;
177
599
  const memberName = site.name;
178
600
  const siteKey = `${parsed.filePath}:${site.atRange.startLine}:${site.atRange.startCol}`;
601
+ // ── owned-but-unbound receiver ───────────────────────────────
602
+ // The language declared this scope REBINDS the receiver and gave
603
+ // it no type — a JS/TS ordinary `function`, whose `this` comes
604
+ // from the call site (#2701). No enclosing type can be its type,
605
+ // so this is a definitive negative, not a miss: suppress the site
606
+ // instead of letting the receiver-blind lexical fallback in
607
+ // `lookupCore` match the enclosing class's member by name.
608
+ // No-op for every language that leaves `Scope.ownsReceivers` unset.
609
+ if (isReceiverOwnedButUnbound(site.inScope, receiverName, scopes)) {
610
+ options.recordResolutionOutcome?.({
611
+ kind: 'suppressed',
612
+ phase: 'receiver-bound-calls',
613
+ filePath: parsed.filePath,
614
+ name: site.name,
615
+ range: site.atRange,
616
+ reason: 'receiver-owned-but-unbound',
617
+ candidateIds: [],
618
+ });
619
+ handledSites.add(siteKey);
620
+ continue;
621
+ }
179
622
  // ── super branch ─────────────────────────────────────────────
180
623
  // Languages with caller-context-dependent super classification
181
624
  // (C++) define `isSuperReceiverInContext`; we prefer it. Simple
@@ -249,9 +692,32 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
249
692
  }
250
693
  }
251
694
  // ── Case 0: compound receiver ────────────────────────────────
252
- if (receiverName.includes('.') || receiverName.includes('(')) {
253
- const currentClass = resolveCompoundReceiverClass(receiverName, site.inScope, scopes, index, compoundOpts);
254
- if (currentClass !== undefined) {
695
+ // #2744: remember a compound receiver we could not type. Reported at
696
+ // the end of the site loop, not here — a later case may still resolve
697
+ // the site, and only a site that survives every case is a real drop.
698
+ let compoundReceiverUnresolved = false;
699
+ // The punctuation test is a C-family heuristic and it is the reason
700
+ // `repos[0].save()` is INVISIBLE in all 14 languages: a subscript receiver
701
+ // contains neither `.` nor `(`, so this case never fired, the fold was
702
+ // never consulted, and no drop was recorded either — the call vanished
703
+ // with the instrument blind to it. PHP `->` and `::` receivers are lost
704
+ // the same way.
705
+ //
706
+ // A minted receiver chain is the STRUCTURAL answer to the same question:
707
+ // the capture layer walked the real AST and found the receiver is an
708
+ // expression, whatever punctuation it happens to be spelled with. Trusting
709
+ // that instead of the text is the substitution this whole line of work
710
+ // exists to make.
711
+ if (receiverName.includes('.') ||
712
+ receiverName.includes('(') ||
713
+ site.receiverChain !== undefined) {
714
+ const resolved = resolveCompoundReceiverTyped(receiverName, site.inScope, scopes, index,
715
+ // Group A: the receiver IS this site's expression, so the site's
716
+ // captured chain describes it and the structural fold applies.
717
+ { ...fileCompoundOpts, receiverChain: site.receiverChain });
718
+ const currentClass = resolved?.def;
719
+ compoundReceiverUnresolved = currentClass === undefined;
720
+ if (resolved !== undefined && currentClass !== undefined) {
255
721
  const chain = [currentClass.nodeId, ...scopes.methodDispatch.mroFor(currentClass.nodeId)];
256
722
  let memberDef;
257
723
  let ambiguousOwnerId;
@@ -294,6 +760,45 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
294
760
  const ok = tryEmitEdge(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen, 0.85, collapse, calleeCapture);
295
761
  if (ok)
296
762
  emitted++;
763
+ // Interface dispatch, exactly as Case 4 does it (#2813). When the
764
+ // folded receiver type is an Interface, the primary edge above
765
+ // lands on the interface's own method DECLARATION; these secondary
766
+ // edges are what reach the implementations.
767
+ //
768
+ // Case 4 had this and Case 0 did not, which made the gap a property
769
+ // of receiver SYNTAX rather than of types: a struct-field receiver
770
+ // (`s.orderRepo`) contains a dot, so it always takes Case 0, while
771
+ // the same interface reached through a local or parameter is a bare
772
+ // name and reaches Case 4. Field-held interfaces — dependency
773
+ // injection, in other words — were the half that silently lost every
774
+ // implementation edge.
775
+ //
776
+ // `currentClass` is the receiver's own folded type, matching what
777
+ // Case 4 passes. `emitInterfaceDispatchFor` self-gates on
778
+ // `ownerDef.type !== 'Interface'`, so this is inert for every
779
+ // concrete receiver and needs no language check of its own — a
780
+ // member whose owner resolved to a Struct emits nothing extra.
781
+ //
782
+ // Confidence mirrors THIS case's own primary emit above — the 0.85
783
+ // literal — so a site's dispatch edges never claim more certainty
784
+ // than the edge they hang off.
785
+ //
786
+ // Case 4 passes a site.kind-dependent value instead (1.0 for
787
+ // read/write, `:1399-1405`) because ITS primary varies the same way.
788
+ // Case 0 does branch on `site.kind` when picking the member
789
+ // (`:713-716`), it simply does not vary reason/confidence with it,
790
+ // so there is no 1.0 arm here to mirror. That leaves a read/write
791
+ // ACCESSES through a compound receiver at 0.85 while the same access
792
+ // through a bare name is 1.0 — a PRE-EXISTING difference between the
793
+ // two cases' primaries, not something this fan-out introduces.
794
+ // Deliberately not "fixed" here: changing Case 0's primary
795
+ // confidence is a separate behavioural change affecting every
796
+ // language, and is out of scope for #2813.
797
+ //
798
+ // The instantiation the FOLD typed this receiver from — the
799
+ // declared spelling of `this.repo` / `svc.get().repo`, which the
800
+ // folded class alone no longer carries (#2912).
801
+ emitted += emitInterfaceDispatchFor(currentClass, memberName, memberDef, site, 0.85, calleeCapture, resolved.declaredSpelling);
297
802
  // Always mark handled when the site was resolved, even
298
803
  // if the edge was deduplicated (collapse mode), so
299
804
  // `emitReferencesViaLookup` doesn't re-emit from the
@@ -428,7 +933,23 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
428
933
  }
429
934
  }
430
935
  // ── Case 1: namespace receiver ───────────────────────────────
431
- const targetFiles = namespaceTargets.get(receiverName);
936
+ // `namespaceTargets` is collected per FILE, so a local declaration that
937
+ // shadows the import must suppress it — `def f(pkg): pkg.db.query()`
938
+ // calls a method on the PARAMETER, and resolving it through the import
939
+ // emits a wrong edge, not a missing one. The compound-receiver
940
+ // construction path has applied this guard since #2770; Case 1 never did,
941
+ // for dotted and single-segment receivers alike.
942
+ // Map lookup FIRST: it is an O(1) miss for almost every site, and the
943
+ // guard is a scope-chain walk (a Set allocation plus a linear `ownedDefs`
944
+ // scan per level). Guarding before looking up would charge that walk to
945
+ // every explicit-receiver site in every language, for a candidate set
946
+ // that is usually empty. Mirrors the order the compound-receiver
947
+ // construction path already uses.
948
+ const namespaceCandidates = namespaceTargets.get(receiverName);
949
+ const targetFiles = namespaceCandidates !== undefined &&
950
+ !isNamespaceNameShadowed(receiverName, site.inScope, scopes)
951
+ ? namespaceCandidates
952
+ : undefined;
432
953
  if (targetFiles !== undefined && provider.resolveQualifiedReceiverMember === undefined) {
433
954
  let found = false;
434
955
  for (const targetFile of targetFiles) {
@@ -596,11 +1117,15 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
596
1117
  // already contain `()` (Ruby member-call-return captures),
597
1118
  // pass through directly — the compound resolver handles the
598
1119
  // full expression including the call syntax.
599
- let ownerDef = resolveCompoundReceiverClass(typeRef.rawName, typeRef.declaredAtScope, scopes, index, compoundOpts);
600
- if (ownerDef === undefined && !typeRef.rawName.includes('(')) {
601
- ownerDef = resolveCompoundReceiverClass(typeRef.rawName + '()', typeRef.declaredAtScope, scopes, index, compoundOpts);
1120
+ // Each attempt carries its OWN spelling: the retry below used to reuse a
1121
+ // recorder reset once, before the first call, so a spelling reported by
1122
+ // the attempt that FAILED could be read as the retry's.
1123
+ let resolved = resolveCompoundReceiverTyped(typeRef.rawName, typeRef.declaredAtScope, scopes, index, fileCompoundOpts);
1124
+ if (resolved === undefined && !typeRef.rawName.includes('(')) {
1125
+ resolved = resolveCompoundReceiverTyped(typeRef.rawName + '()', typeRef.declaredAtScope, scopes, index, fileCompoundOpts);
602
1126
  }
603
- if (ownerDef !== undefined) {
1127
+ const ownerDef = resolved?.def;
1128
+ if (resolved !== undefined && ownerDef !== undefined) {
604
1129
  const chain = [ownerDef.nodeId, ...scopes.methodDispatch.mroFor(ownerDef.nodeId)];
605
1130
  let memberDef;
606
1131
  let ambiguousOwnerId;
@@ -639,6 +1164,44 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
639
1164
  const ok = tryEmitEdge(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen, 0.85, collapse, calleeCapture);
640
1165
  if (ok)
641
1166
  emitted++;
1167
+ // Interface dispatch, exactly as Cases 0 and 4 do it (#2832). Case
1168
+ // 3b folds a chain to a receiver type through the SAME
1169
+ // `resolveCompoundReceiverClass` call and the same MRO walk Case 0
1170
+ // uses, so when that fold lands on an Interface the primary edge
1171
+ // above names the interface's own bodiless DECLARATION and nothing
1172
+ // reaches the implementations.
1173
+ //
1174
+ // Leaving 3b out made the fan-out a property of how the receiver
1175
+ // was SPELLED rather than of what it resolved to: `d.repo.save()`
1176
+ // took Case 0 and fanned out, while binding the identical field to
1177
+ // a local first (`const r = d.repo; r.save()`) took Case 3b and
1178
+ // did not. #2829 closed that gap for Case 0 and left this half of
1179
+ // it open (#2832).
1180
+ //
1181
+ // `ownerDef` is the receiver's own folded type — matching Case 0's
1182
+ // `currentClass` and Case 4's `ownerDef` — NOT the owner of the
1183
+ // member the MRO walk settled on. That distinction matters: a
1184
+ // receiver that folds to a concrete class merely INHERITING an
1185
+ // interface method must not fan out, because its runtime type is
1186
+ // that class. `emitInterfaceDispatchFor` self-gates on
1187
+ // `ownerDef.type !== 'Interface'`, so this is inert for every
1188
+ // concrete receiver and needs no language check of its own.
1189
+ //
1190
+ // That gate is deliberately narrower than "the primary landed on
1191
+ // something bodiless": a chain folding to an ABSTRACT class also
1192
+ // dead-ends on a declaration-only member and does NOT fan out
1193
+ // here. Widening it to `|| isDeclarationOnly(memberDef)` would
1194
+ // cover that, but it changes Cases 0 and 4 identically and for
1195
+ // every language, so it is not #2832's to make.
1196
+ //
1197
+ // Confidence mirrors THIS case's own primary emit above — the 0.85
1198
+ // literal — so a site's dispatch edges never claim more certainty
1199
+ // than the edge they hang off. Case 4 passes a site.kind-dependent
1200
+ // value instead because ITS primary varies that way; Case 3b's
1201
+ // primary, like Case 0's, does not, so there is no 1.0 arm here to
1202
+ // mirror.
1203
+ // Same fold, same recovered spelling as Case 0.
1204
+ emitted += emitInterfaceDispatchFor(ownerDef, memberName, memberDef, site, 0.85, calleeCapture, resolved.declaredSpelling);
642
1205
  // Always mark handled when the site was resolved, even
643
1206
  // if the edge was deduplicated (collapse mode), so
644
1207
  // `emitReferencesViaLookup` doesn't re-emit from the
@@ -650,13 +1213,27 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
650
1213
  }
651
1214
  // ── Case 4: simple typeBinding (`u: U`) ──────────────────────
652
1215
  if (typeRef !== undefined && !typeRef.rawName.includes('.')) {
653
- let ownerDef = resolveClassBindingForName(site.inScope, typeRef.rawName, scopes);
1216
+ // A `rawName` the capture layer reduced from a type application is
1217
+ // resolved through the application it was written as, so the erasure
1218
+ // takes the GROUNDED route rather than binding whatever the workspace
1219
+ // declares under that base name — see {@link erasedTypeApplication}.
1220
+ const typeApplication = erasedTypeApplication(typeRef);
1221
+ let ownerDef = resolveClassBindingForName(site.inScope, typeApplication ?? typeRef.rawName, scopes);
654
1222
  // `findClassBindingInScope(..., typeRef.rawName)` only works when
655
1223
  // rawName is itself a class symbol reachable through scope bindings.
656
1224
  // For languages with namespace-style imports (Go), imported types
657
1225
  // don't create bindings. Fall back to QualifiedNameIndex — single-
658
1226
  // match wins; ambiguous/missing falls through.
659
- if (ownerDef === undefined) {
1227
+ //
1228
+ // NOT for an erased base name. This fallback consults no scope, no
1229
+ // import and no module: it binds any name with exactly one workspace
1230
+ // definition. That is a defensible last resort for a name the source
1231
+ // WROTE — the file named it, so the only question is which declaration
1232
+ // it meant — and is not defensible for a name the capture layer
1233
+ // MANUFACTURED by erasing type arguments, where the file may never
1234
+ // have named it at all. The lookup above already answered that case on
1235
+ // grounds; re-asking it here without any would undo them.
1236
+ if (ownerDef === undefined && typeApplication === undefined) {
660
1237
  const qnameIds = scopes.qualifiedNames.get(typeRef.rawName);
661
1238
  if (qnameIds.length === 1) {
662
1239
  const qdef = scopes.defs.get(qnameIds[0]);
@@ -667,8 +1244,52 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
667
1244
  // Map for-of tuple bindings (`__MAP_TUPLE_i__:mapId`), callable
668
1245
  // aliases (`getUser` → User), and other compound-friendly shapes
669
1246
  // need the compound resolver keyed by the receiver identifier.
670
- if (ownerDef === undefined) {
671
- ownerDef = resolveCompoundReceiverClass(receiverName, site.inScope, scopes, index, compoundOpts);
1247
+ //
1248
+ // Not asked for a receiver whose declared type IS an erased type
1249
+ // application the grounded lookup just refused. Those shapes are
1250
+ // alternatives to a declared type, not readings of one: this receiver
1251
+ // HAS a declared type, the question "which class does its base name
1252
+ // denote here" was already put and answered "cannot tell", and the
1253
+ // compound resolver reaches the same base name through its own
1254
+ // scope-free routes (its bare-identifier step re-runs the lookup on
1255
+ // `rawName`; its callable-alias step retries the same name as a
1256
+ // construction). Asking again by a route that cannot see the grounds
1257
+ // would make the refusal decorative.
1258
+ if (ownerDef === undefined && typeApplication === undefined) {
1259
+ ownerDef = resolveCompoundReceiverClass(receiverName, site.inScope, scopes, index,
1260
+ // Group A, same reasoning as Case 0 above.
1261
+ { ...fileCompoundOpts, receiverChain: site.receiverChain });
1262
+ }
1263
+ // The receiver has a declared type, that type is a type APPLICATION,
1264
+ // and its base name could not be connected to any declaration this
1265
+ // file can see. The site is DROPPED, and dropped deliberately, so it
1266
+ // must be marked handled: `emitReferencesViaLookup` would otherwise
1267
+ // re-emit the very target the grounds refused, because the pre-resolved
1268
+ // reference index answers a name with the single workspace definition
1269
+ // that carries it and knows nothing about erasure. That is exactly why
1270
+ // the static-only filter above marks handled too — a refusal this pass
1271
+ // makes is not a refusal until the fallback emitter is told.
1272
+ //
1273
+ // Recorded as `receiver-unresolved` rather than silently: the receiver's
1274
+ // TYPE could not be established, which is the reason's own definition,
1275
+ // and a consumer counting resolver gaps must see this drop rather than
1276
+ // read the absence as a resolved site. No `receiverOrigin` — the base
1277
+ // name resolving in the index is precisely the evidence just rejected,
1278
+ // so claiming `in-program` from it would relaunder the fabrication as a
1279
+ // diagnostic, and the absent field hedges (the safe direction).
1280
+ if (ownerDef === undefined && typeApplication !== undefined) {
1281
+ options.recordResolutionOutcome?.({
1282
+ kind: 'suppressed',
1283
+ reason: 'receiver-unresolved',
1284
+ candidateIds: [],
1285
+ phase: 'receiver-bound-calls',
1286
+ filePath: parsed.filePath,
1287
+ name: site.name,
1288
+ range: site.atRange,
1289
+ siteKind: site.kind,
1290
+ });
1291
+ handledSites.add(siteKey);
1292
+ continue;
672
1293
  }
673
1294
  if (ownerDef !== undefined) {
674
1295
  const languageResolution = provider.resolveReceiverMember?.(ownerDef, memberName, site, scopes, model);
@@ -793,7 +1414,13 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
793
1414
  // Interface dispatch: when the primary owner is an
794
1415
  // Interface, emit secondary CALLS edges to every
795
1416
  // implementing class's same-named method.
796
- emitted += emitInterfaceDispatchFor(ownerDef, memberName, memberDef, site, confidence, calleeCapture);
1417
+ //
1418
+ // This case is the one that KNOWS the instantiation: the receiver
1419
+ // has a declared type, and `typeApplication` is that type restored
1420
+ // to its written `Base<Args>` spelling (`rawName` is the erasure).
1421
+ // A language whose `rawName` was never erased carries the arguments
1422
+ // itself, so both spellings are read (#2912).
1423
+ emitted += emitInterfaceDispatchFor(ownerDef, memberName, memberDef, site, confidence, calleeCapture, typeApplication ?? typeRef.rawName);
797
1424
  // Always mark handled when the site was resolved, even
798
1425
  // if the edge was deduplicated (collapse mode), so
799
1426
  // `emitReferencesViaLookup` doesn't re-emit from the
@@ -864,10 +1491,222 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
864
1491
  continue;
865
1492
  }
866
1493
  }
1494
+ // ── Case 6: class-level (static) member receiver ─────────────
1495
+ // `Holder.repo.save(u)` — the receiver `Holder.repo` reaches a value
1496
+ // through a CLASS-LEVEL member. Both routes that type a compound
1497
+ // receiver (the structural fold and the text cascade) read the same
1498
+ // place for the `repo` hop: the owning class scope's `typeBindings`.
1499
+ // A scope has ONE `typeBindings` map with no static/instance split, so
1500
+ // a language that declares both `p` and `static p` cannot record both
1501
+ // — and at least two resolve that collision by not recording the
1502
+ // static one at all, leaving `Holder.repo` with nothing to type
1503
+ // against. A language that nests its class-level members in a scope of
1504
+ // their own (a companion/singleton body) lands in the same place from
1505
+ // the other direction: the binding exists, but not in the scope keyed
1506
+ // by the class the receiver names. Both were MEASURED as emitting no
1507
+ // edge at all, generic field and non-generic control alike.
1508
+ //
1509
+ // The definition side does not have that ambiguity: a class-level
1510
+ // member and an instance member of one name are two distinct defs, and
1511
+ // the graph node carries both `isStatic` and the member's declared
1512
+ // type. So this case types the receiver off the DEF rather than off a
1513
+ // typeBinding, and needs no scope-tree change to do it.
1514
+ //
1515
+ // ── WHY THIS CANNOT MINT A STATIC-TARGETED EDGE ────────────────────
1516
+ //
1517
+ // `Holder.repo` is a static FIELD whose TYPE is `Repo`; the value it
1518
+ // holds is an INSTANCE. So "reached through a class-level member" says
1519
+ // nothing about the target: `save` is looked up with the ordinary
1520
+ // `pickFirstNonStaticOnly` instance walk that Cases 0/3b/4 use, and a
1521
+ // static-only `save` is skipped exactly as it is there. A genuine
1522
+ // static CALL (`Repo.create()`) never arrives here — its receiver is a
1523
+ // bare class name with no dot, which Case 2 owns and this case's
1524
+ // two-part receiver requirement excludes.
1525
+ //
1526
+ // The `isStatic === true` requirement on the FIELD is the load-bearing
1527
+ // guard in the other direction: the head resolved to the class itself,
1528
+ // so only a class-level member is reachable through it, and an
1529
+ // instance field of the same name must not be substituted. That is a
1530
+ // POSITIVE selection among the defs that exist, never a filter that
1531
+ // deletes otherwise-valid targets — the distinction that matters for a
1532
+ // language whose singleton/companion members all carry `isStatic` from
1533
+ // their OWNER type, where the flag being set is precisely what makes
1534
+ // reaching them through the type name correct.
1535
+ //
1536
+ // Runs LAST, and only for a receiver Case 0 already declined
1537
+ // (`compoundReceiverUnresolved`): a site any earlier case resolved
1538
+ // keeps that answer, so this can only turn a missing edge into an edge
1539
+ // and never retarget an existing one. Contract Invariant I4 holds —
1540
+ // nothing above moved.
1541
+ if (compoundReceiverUnresolved) {
1542
+ const staticMemberReceiver = splitClassLevelMemberReceiver(receiverName, site.receiverChain);
1543
+ const headClass = staticMemberReceiver === undefined
1544
+ ? undefined
1545
+ : findClassBindingInScope(site.inScope, staticMemberReceiver.headName, scopes);
1546
+ // The head must be the CLASS ITSELF, not a value that happens to
1547
+ // share its name — the same `currentIsClassConstant` test the text
1548
+ // cascade makes before it treats a head as a class constant. A head
1549
+ // with a type binding is an instance and its members are typed by
1550
+ // the routes above.
1551
+ if (staticMemberReceiver !== undefined &&
1552
+ headClass !== undefined &&
1553
+ findReceiverTypeBinding(site.inScope, staticMemberReceiver.headName, scopes) === undefined) {
1554
+ // MRO walk, so a class-level member declared on an ancestor is
1555
+ // reachable through a subclass name where the language allows it.
1556
+ // First owner that declares one wins, matching every other walk in
1557
+ // this pass.
1558
+ let fieldOwnerId;
1559
+ let fieldDeclaredType;
1560
+ for (const ownerId of [
1561
+ headClass.nodeId,
1562
+ ...scopes.methodDispatch.mroFor(headClass.nodeId),
1563
+ ]) {
1564
+ const declared = declaredTypeOfClassLevelField(ownerId, staticMemberReceiver.memberName);
1565
+ if (declared === undefined)
1566
+ continue;
1567
+ fieldOwnerId = ownerId;
1568
+ fieldDeclaredType = declared;
1569
+ break;
1570
+ }
1571
+ // Resolve the declared type from where it was WRITTEN — the
1572
+ // declaring class's own scope — not from the call site. A caller
1573
+ // in another file need not have the field's type in scope at all,
1574
+ // and resolving `Repo` against the caller's bindings would either
1575
+ // miss or, worse, find an unrelated same-named class.
1576
+ const declaringScope = fieldOwnerId === undefined ? undefined : index.classScopeByDefId.get(fieldOwnerId)?.id;
1577
+ const receiverClass = declaringScope === undefined || fieldDeclaredType === undefined
1578
+ ? undefined
1579
+ : resolveClassBindingForName(declaringScope, fieldDeclaredType, scopes, provider.stripTypePreservingDecoration);
1580
+ if (receiverClass !== undefined) {
1581
+ const chain = [
1582
+ receiverClass.nodeId,
1583
+ ...scopes.methodDispatch.mroFor(receiverClass.nodeId),
1584
+ ];
1585
+ let memberDef;
1586
+ let ambiguousOwnerId;
1587
+ for (const ownerId of chain) {
1588
+ const picked = pickFirstNonStaticOnly(ownerId, memberName, site, model, provider);
1589
+ if (picked === OVERLOAD_AMBIGUOUS) {
1590
+ ambiguousOwnerId = ownerId;
1591
+ break;
1592
+ }
1593
+ // Same skip-and-walk-on as Case 4: a static-only candidate at
1594
+ // this owner must not block an ancestor's instance member.
1595
+ if (picked === STATIC_ONLY_FILTERED || picked === undefined)
1596
+ continue;
1597
+ memberDef = picked;
1598
+ break;
1599
+ }
1600
+ if (ambiguousOwnerId !== undefined) {
1601
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ambiguousOwnerId, memberName, model, provider);
1602
+ handledSites.add(siteKey);
1603
+ continue;
1604
+ }
1605
+ if (memberDef !== undefined) {
1606
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
1607
+ handledSites.add(siteKey);
1608
+ continue;
1609
+ }
1610
+ const reason = site.kind === 'write' || site.kind === 'read'
1611
+ ? site.kind
1612
+ : memberDef.filePath !== parsed.filePath
1613
+ ? 'import-resolved'
1614
+ : 'global';
1615
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
1616
+ const ok = tryEmitEdge(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse, calleeCapture);
1617
+ if (ok)
1618
+ emitted++;
1619
+ // The receiver's declared type can be an Interface exactly as
1620
+ // in Cases 0/3b/4 — an interface-typed static field is the
1621
+ // canonical service-locator shape — so it fans out the same
1622
+ // way. Omitting it would make the static spelling emit fewer
1623
+ // targets than the identical instance field, which is the very
1624
+ // spelling-dependence #2829/#2842 closed elsewhere.
1625
+ // The field's DECLARED type is the spelling the source wrote, so
1626
+ // its arguments are available here exactly as in Case 4 (#2912).
1627
+ emitted += emitInterfaceDispatchFor(receiverClass, memberName, memberDef, site, confidence, calleeCapture, fieldDeclaredType);
1628
+ handledSites.add(siteKey);
1629
+ continue;
1630
+ }
1631
+ }
1632
+ }
1633
+ }
1634
+ // #2744: the site survived every case with a compound receiver we could
1635
+ // not type, so the call is dropped with no candidate. Record it here —
1636
+ // after the cases, so a site a later case resolved is never reported —
1637
+ // keyed by the MEMBER name, which is the only thing still known about a
1638
+ // dropped site (its callee is unknown by definition, so the drop cannot
1639
+ // be attributed to any target symbol).
1640
+ if (compoundReceiverUnresolved && !handledSites.has(siteKey)) {
1641
+ // Decoded once: both the shape census and the origin classifier read the
1642
+ // same chain, and this is inside the drop guard so a resolved site pays
1643
+ // nothing.
1644
+ const decodedChain = decodeReceiverChain(site.receiverChain);
1645
+ options.recordResolutionOutcome?.({
1646
+ kind: 'suppressed',
1647
+ reason: 'receiver-unresolved',
1648
+ candidateIds: [],
1649
+ phase: 'receiver-bound-calls',
1650
+ filePath: parsed.filePath,
1651
+ name: site.name,
1652
+ range: site.atRange,
1653
+ // The gate above tests the receiver's punctuation, not the site's
1654
+ // kind, so property reads and writes with a compound receiver are
1655
+ // recorded here too. Carry the kind so a consumer can separate a
1656
+ // dropped CALL from a dropped property access.
1657
+ siteKind: site.kind,
1658
+ // Structural, from the AST-derived chain the emitter minted — never
1659
+ // re-derived from the source line.
1660
+ // `decodeReceiverChain` opens with a non-string guard, so the
1661
+ // undefined case needs no ternary here.
1662
+ receiverShape: classifyReceiverShape(decodedChain),
1663
+ // Whether anything was actually lost. An external target has no node
1664
+ // to point at, so its absence is completeness, not uncertainty — but
1665
+ // ONLY a positive built-in match may say so. Everything the index
1666
+ // cannot demonstrate stays `unknown` and keeps hedging.
1667
+ receiverOrigin: classifyReceiverOrigin(decodedChain, site.inScope, receiverName, scopes, receiverOriginOpts),
1668
+ });
1669
+ }
867
1670
  }
868
1671
  }
869
- return emitted;
1672
+ return { emitted, dispatchFanoutSkipped, dispatchFanoutSkippedNames };
1673
+ }
1674
+ /**
1675
+ * Split a receiver into `Head` + one member hop, or decline.
1676
+ *
1677
+ * The STRUCTURE decides when the capture layer minted a chain: exactly one
1678
+ * step, and that step a FIELD. A `call` step is a different shape entirely
1679
+ * (`Holder.make().save()` — the value comes from a return type, which the
1680
+ * routes above already own), and an `await`/`index` step transforms the value
1681
+ * in a way a field's declared type does not describe.
1682
+ *
1683
+ * Without a chain the receiver TEXT answers, and only in the one spelling that
1684
+ * cannot be read two ways: two bare identifiers around a single dot. Anything
1685
+ * carrying a call, a subscript, a second dot or a decoration declines rather
1686
+ * than being parsed here — re-deriving structure from text is what the chain
1687
+ * exists to replace, and a second, looser text parser beside the cascade's own
1688
+ * would drift from it.
1689
+ */
1690
+ function splitClassLevelMemberReceiver(receiverText, receiverChain) {
1691
+ const decoded = decodeReceiverChain(receiverChain);
1692
+ if (decoded !== undefined) {
1693
+ if (decoded.truncated || decoded.steps.length !== 1)
1694
+ return undefined;
1695
+ const step = decoded.steps[0];
1696
+ if (step === undefined || step.kind !== 'field')
1697
+ return undefined;
1698
+ return { headName: decoded.baseReceiverName, memberName: step.name };
1699
+ }
1700
+ const match = TWO_PART_RECEIVER_RE.exec(receiverText);
1701
+ if (match === null)
1702
+ return undefined;
1703
+ const [, headName, memberName] = match;
1704
+ if (headName === undefined || memberName === undefined)
1705
+ return undefined;
1706
+ return { headName, memberName };
870
1707
  }
1708
+ /** `Holder.repo` and nothing looser — see {@link splitClassLevelMemberReceiver}. */
1709
+ const TWO_PART_RECEIVER_RE = /^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/;
871
1710
  /** Resolve a member by name on a class def, narrowing by argument
872
1711
  * types when multiple overloads share the name. Falls back to the
873
1712
  * first-seen def (legacy `findOwnedMember` semantics) when there's