@ryanstark24/sfgraph-core 1.4.0 → 1.6.0

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 (922) hide show
  1. package/dist/analyze/apex-platform.d.ts +23 -0
  2. package/dist/analyze/apex-platform.d.ts.map +1 -0
  3. package/dist/analyze/apex-platform.js +112 -0
  4. package/dist/analyze/apex-platform.js.map +1 -0
  5. package/dist/analyze/audit-graph.d.ts +34 -10
  6. package/dist/analyze/audit-graph.d.ts.map +1 -1
  7. package/dist/analyze/audit-graph.js +360 -39
  8. package/dist/analyze/audit-graph.js.map +1 -1
  9. package/dist/analyze/component-scope.d.ts +82 -0
  10. package/dist/analyze/component-scope.d.ts.map +1 -0
  11. package/dist/analyze/component-scope.js +207 -0
  12. package/dist/analyze/component-scope.js.map +1 -0
  13. package/dist/analyze/containment.d.ts +91 -0
  14. package/dist/analyze/containment.d.ts.map +1 -0
  15. package/dist/analyze/containment.js +175 -0
  16. package/dist/analyze/containment.js.map +1 -0
  17. package/dist/analyze/cross-org.d.ts +35 -0
  18. package/dist/analyze/cross-org.d.ts.map +1 -1
  19. package/dist/analyze/cross-org.js +102 -3
  20. package/dist/analyze/cross-org.js.map +1 -1
  21. package/dist/analyze/dead-code.d.ts +99 -3
  22. package/dist/analyze/dead-code.d.ts.map +1 -1
  23. package/dist/analyze/dead-code.js +282 -10
  24. package/dist/analyze/dead-code.js.map +1 -1
  25. package/dist/analyze/dependencies.d.ts +20 -1
  26. package/dist/analyze/dependencies.d.ts.map +1 -1
  27. package/dist/analyze/dependencies.js +96 -12
  28. package/dist/analyze/dependencies.js.map +1 -1
  29. package/dist/analyze/dependents.d.ts +111 -1
  30. package/dist/analyze/dependents.d.ts.map +1 -1
  31. package/dist/analyze/dependents.js +282 -20
  32. package/dist/analyze/dependents.js.map +1 -1
  33. package/dist/analyze/deployment-manifest/generate.d.ts +24 -0
  34. package/dist/analyze/deployment-manifest/generate.d.ts.map +1 -1
  35. package/dist/analyze/deployment-manifest/generate.js +40 -12
  36. package/dist/analyze/deployment-manifest/generate.js.map +1 -1
  37. package/dist/analyze/deployment-manifest/member-name-formatters.d.ts.map +1 -1
  38. package/dist/analyze/deployment-manifest/member-name-formatters.js +1 -0
  39. package/dist/analyze/deployment-manifest/member-name-formatters.js.map +1 -1
  40. package/dist/analyze/deployment-manifest/member-types.d.ts.map +1 -1
  41. package/dist/analyze/deployment-manifest/member-types.js +2 -0
  42. package/dist/analyze/deployment-manifest/member-types.js.map +1 -1
  43. package/dist/analyze/diff-seeds.d.ts +33 -0
  44. package/dist/analyze/diff-seeds.d.ts.map +1 -0
  45. package/dist/analyze/diff-seeds.js +299 -0
  46. package/dist/analyze/diff-seeds.js.map +1 -0
  47. package/dist/analyze/edge-filters.d.ts +25 -0
  48. package/dist/analyze/edge-filters.d.ts.map +1 -1
  49. package/dist/analyze/edge-filters.js +78 -2
  50. package/dist/analyze/edge-filters.js.map +1 -1
  51. package/dist/analyze/field-scope.d.ts +25 -0
  52. package/dist/analyze/field-scope.d.ts.map +1 -0
  53. package/dist/analyze/field-scope.js +94 -0
  54. package/dist/analyze/field-scope.js.map +1 -0
  55. package/dist/analyze/find-nodes.d.ts +48 -12
  56. package/dist/analyze/find-nodes.d.ts.map +1 -1
  57. package/dist/analyze/find-nodes.js +323 -12
  58. package/dist/analyze/find-nodes.js.map +1 -1
  59. package/dist/analyze/findings.d.ts.map +1 -1
  60. package/dist/analyze/findings.js +14 -0
  61. package/dist/analyze/findings.js.map +1 -1
  62. package/dist/analyze/git-diff.d.ts +27 -1
  63. package/dist/analyze/git-diff.d.ts.map +1 -1
  64. package/dist/analyze/git-diff.js +198 -26
  65. package/dist/analyze/git-diff.js.map +1 -1
  66. package/dist/analyze/governor.d.ts +25 -4
  67. package/dist/analyze/governor.d.ts.map +1 -1
  68. package/dist/analyze/governor.js +82 -18
  69. package/dist/analyze/governor.js.map +1 -1
  70. package/dist/analyze/index.d.ts +6 -0
  71. package/dist/analyze/index.d.ts.map +1 -1
  72. package/dist/analyze/index.js +6 -0
  73. package/dist/analyze/index.js.map +1 -1
  74. package/dist/analyze/path-to-qname.d.ts +9 -0
  75. package/dist/analyze/path-to-qname.d.ts.map +1 -1
  76. package/dist/analyze/path-to-qname.js +58 -15
  77. package/dist/analyze/path-to-qname.js.map +1 -1
  78. package/dist/analyze/populate.d.ts +40 -0
  79. package/dist/analyze/populate.d.ts.map +1 -1
  80. package/dist/analyze/populate.js +148 -48
  81. package/dist/analyze/populate.js.map +1 -1
  82. package/dist/analyze/pseudo-endpoints.d.ts +67 -0
  83. package/dist/analyze/pseudo-endpoints.d.ts.map +1 -0
  84. package/dist/analyze/pseudo-endpoints.js +78 -0
  85. package/dist/analyze/pseudo-endpoints.js.map +1 -0
  86. package/dist/analyze/security.d.ts +2 -0
  87. package/dist/analyze/security.d.ts.map +1 -1
  88. package/dist/analyze/security.js +44 -15
  89. package/dist/analyze/security.js.map +1 -1
  90. package/dist/analyze/test-coverage.d.ts +48 -0
  91. package/dist/analyze/test-coverage.d.ts.map +1 -1
  92. package/dist/analyze/test-coverage.js +72 -1
  93. package/dist/analyze/test-coverage.js.map +1 -1
  94. package/dist/analyze/wip-changed-files.d.ts +88 -0
  95. package/dist/analyze/wip-changed-files.d.ts.map +1 -0
  96. package/dist/analyze/wip-changed-files.js +422 -0
  97. package/dist/analyze/wip-changed-files.js.map +1 -0
  98. package/dist/analyze/wip-impact.d.ts +59 -0
  99. package/dist/analyze/wip-impact.d.ts.map +1 -1
  100. package/dist/analyze/wip-impact.js +199 -126
  101. package/dist/analyze/wip-impact.js.map +1 -1
  102. package/dist/domain/apex-platform.d.ts +10 -0
  103. package/dist/domain/apex-platform.d.ts.map +1 -0
  104. package/dist/domain/apex-platform.js +231 -0
  105. package/dist/domain/apex-platform.js.map +1 -0
  106. package/dist/domain/index.d.ts +2 -0
  107. package/dist/domain/index.d.ts.map +1 -1
  108. package/dist/domain/index.js +2 -0
  109. package/dist/domain/index.js.map +1 -1
  110. package/dist/domain/rel-types.d.ts +7 -0
  111. package/dist/domain/rel-types.d.ts.map +1 -1
  112. package/dist/domain/rel-types.js +7 -0
  113. package/dist/domain/rel-types.js.map +1 -1
  114. package/dist/domain/standard-sobjects.d.ts +20 -0
  115. package/dist/domain/standard-sobjects.d.ts.map +1 -0
  116. package/dist/domain/standard-sobjects.js +183 -0
  117. package/dist/domain/standard-sobjects.js.map +1 -0
  118. package/dist/embedding/cache.d.ts +41 -0
  119. package/dist/embedding/cache.d.ts.map +1 -0
  120. package/dist/embedding/cache.js +69 -0
  121. package/dist/embedding/cache.js.map +1 -0
  122. package/dist/embedding/embed.d.ts +59 -0
  123. package/dist/embedding/embed.d.ts.map +1 -1
  124. package/dist/embedding/embed.js +193 -28
  125. package/dist/embedding/embed.js.map +1 -1
  126. package/dist/embedding/index.d.ts +7 -0
  127. package/dist/embedding/index.d.ts.map +1 -1
  128. package/dist/embedding/index.js +4 -0
  129. package/dist/embedding/index.js.map +1 -1
  130. package/dist/embedding/pool.d.ts +66 -6
  131. package/dist/embedding/pool.d.ts.map +1 -1
  132. package/dist/embedding/pool.js +156 -6
  133. package/dist/embedding/pool.js.map +1 -1
  134. package/dist/embedding/queue.d.ts +166 -9
  135. package/dist/embedding/queue.d.ts.map +1 -1
  136. package/dist/embedding/queue.js +397 -39
  137. package/dist/embedding/queue.js.map +1 -1
  138. package/dist/embedding/tokenize.d.ts +18 -0
  139. package/dist/embedding/tokenize.d.ts.map +1 -0
  140. package/dist/embedding/tokenize.js +43 -0
  141. package/dist/embedding/tokenize.js.map +1 -0
  142. package/dist/embedding/worker.d.ts +0 -5
  143. package/dist/embedding/worker.d.ts.map +1 -1
  144. package/dist/embedding/worker.js +27 -4
  145. package/dist/embedding/worker.js.map +1 -1
  146. package/dist/extractors/filesystem/index.d.ts +21 -1
  147. package/dist/extractors/filesystem/index.d.ts.map +1 -1
  148. package/dist/extractors/filesystem/index.js +195 -38
  149. package/dist/extractors/filesystem/index.js.map +1 -1
  150. package/dist/extractors/filesystem/vlocity-datapacks.d.ts +27 -0
  151. package/dist/extractors/filesystem/vlocity-datapacks.d.ts.map +1 -0
  152. package/dist/extractors/filesystem/vlocity-datapacks.js +201 -0
  153. package/dist/extractors/filesystem/vlocity-datapacks.js.map +1 -0
  154. package/dist/extractors/interfaces/metadata-source.d.ts +29 -0
  155. package/dist/extractors/interfaces/metadata-source.d.ts.map +1 -1
  156. package/dist/extractors/live-org/bulk-retrieve.d.ts +37 -1
  157. package/dist/extractors/live-org/bulk-retrieve.d.ts.map +1 -1
  158. package/dist/extractors/live-org/bulk-retrieve.js +233 -50
  159. package/dist/extractors/live-org/bulk-retrieve.js.map +1 -1
  160. package/dist/extractors/live-org/capabilities.d.ts +15 -0
  161. package/dist/extractors/live-org/capabilities.d.ts.map +1 -1
  162. package/dist/extractors/live-org/capabilities.js +54 -9
  163. package/dist/extractors/live-org/capabilities.js.map +1 -1
  164. package/dist/extractors/live-org/extractors/apex.d.ts +12 -2
  165. package/dist/extractors/live-org/extractors/apex.d.ts.map +1 -1
  166. package/dist/extractors/live-org/extractors/apex.js +151 -80
  167. package/dist/extractors/live-org/extractors/apex.js.map +1 -1
  168. package/dist/extractors/live-org/extractors/custom-settings.d.ts +2 -1
  169. package/dist/extractors/live-org/extractors/custom-settings.d.ts.map +1 -1
  170. package/dist/extractors/live-org/extractors/custom-settings.js +19 -9
  171. package/dist/extractors/live-org/extractors/custom-settings.js.map +1 -1
  172. package/dist/extractors/live-org/extractors/flow.d.ts +2 -1
  173. package/dist/extractors/live-org/extractors/flow.d.ts.map +1 -1
  174. package/dist/extractors/live-org/extractors/flow.js +12 -3
  175. package/dist/extractors/live-org/extractors/flow.js.map +1 -1
  176. package/dist/extractors/live-org/extractors/generic-metadata.d.ts +23 -3
  177. package/dist/extractors/live-org/extractors/generic-metadata.d.ts.map +1 -1
  178. package/dist/extractors/live-org/extractors/generic-metadata.js +110 -25
  179. package/dist/extractors/live-org/extractors/generic-metadata.js.map +1 -1
  180. package/dist/extractors/live-org/extractors/integration.d.ts +2 -1
  181. package/dist/extractors/live-org/extractors/integration.d.ts.map +1 -1
  182. package/dist/extractors/live-org/extractors/integration.js +14 -5
  183. package/dist/extractors/live-org/extractors/integration.js.map +1 -1
  184. package/dist/extractors/live-org/extractors/lwc.d.ts +2 -1
  185. package/dist/extractors/live-org/extractors/lwc.d.ts.map +1 -1
  186. package/dist/extractors/live-org/extractors/lwc.js +14 -6
  187. package/dist/extractors/live-org/extractors/lwc.js.map +1 -1
  188. package/dist/extractors/live-org/extractors/object.d.ts +2 -11
  189. package/dist/extractors/live-org/extractors/object.d.ts.map +1 -1
  190. package/dist/extractors/live-org/extractors/object.js +127 -226
  191. package/dist/extractors/live-org/extractors/object.js.map +1 -1
  192. package/dist/extractors/live-org/extractors/omnistudio.d.ts +3 -0
  193. package/dist/extractors/live-org/extractors/omnistudio.d.ts.map +1 -1
  194. package/dist/extractors/live-org/extractors/omnistudio.js +57 -22
  195. package/dist/extractors/live-org/extractors/omnistudio.js.map +1 -1
  196. package/dist/extractors/live-org/extractors/security.d.ts +12 -1
  197. package/dist/extractors/live-org/extractors/security.d.ts.map +1 -1
  198. package/dist/extractors/live-org/extractors/security.js +29 -7
  199. package/dist/extractors/live-org/extractors/security.js.map +1 -1
  200. package/dist/extractors/live-org/rate-limit.d.ts +7 -1
  201. package/dist/extractors/live-org/rate-limit.d.ts.map +1 -1
  202. package/dist/extractors/live-org/rate-limit.js +53 -10
  203. package/dist/extractors/live-org/rate-limit.js.map +1 -1
  204. package/dist/extractors/live-org/retry.d.ts +136 -0
  205. package/dist/extractors/live-org/retry.d.ts.map +1 -0
  206. package/dist/extractors/live-org/retry.js +416 -0
  207. package/dist/extractors/live-org/retry.js.map +1 -0
  208. package/dist/extractors/live-org/vlocity/runner.d.ts +2 -1
  209. package/dist/extractors/live-org/vlocity/runner.d.ts.map +1 -1
  210. package/dist/extractors/live-org/vlocity/runner.js +95 -67
  211. package/dist/extractors/live-org/vlocity/runner.js.map +1 -1
  212. package/dist/extractors/vlocity-shared/row.d.ts +19 -0
  213. package/dist/extractors/vlocity-shared/row.d.ts.map +1 -0
  214. package/dist/extractors/vlocity-shared/row.js +69 -0
  215. package/dist/extractors/vlocity-shared/row.js.map +1 -0
  216. package/dist/index.d.ts +1 -0
  217. package/dist/index.d.ts.map +1 -1
  218. package/dist/index.js +2 -0
  219. package/dist/index.js.map +1 -1
  220. package/dist/ingest/delta.d.ts +70 -0
  221. package/dist/ingest/delta.d.ts.map +1 -0
  222. package/dist/ingest/delta.js +534 -0
  223. package/dist/ingest/delta.js.map +1 -0
  224. package/dist/ingest/detect-deletions-guard.d.ts +34 -0
  225. package/dist/ingest/detect-deletions-guard.d.ts.map +1 -1
  226. package/dist/ingest/detect-deletions-guard.js +59 -0
  227. package/dist/ingest/detect-deletions-guard.js.map +1 -1
  228. package/dist/ingest/index.d.ts +8 -1
  229. package/dist/ingest/index.d.ts.map +1 -1
  230. package/dist/ingest/index.js +4 -0
  231. package/dist/ingest/index.js.map +1 -1
  232. package/dist/ingest/live-ingest.d.ts +171 -7
  233. package/dist/ingest/live-ingest.d.ts.map +1 -1
  234. package/dist/ingest/live-ingest.js +1014 -249
  235. package/dist/ingest/live-ingest.js.map +1 -1
  236. package/dist/ingest/lock.d.ts +47 -0
  237. package/dist/ingest/lock.d.ts.map +1 -0
  238. package/dist/ingest/lock.js +222 -0
  239. package/dist/ingest/lock.js.map +1 -0
  240. package/dist/ingest/member-rows.d.ts +88 -0
  241. package/dist/ingest/member-rows.d.ts.map +1 -0
  242. package/dist/ingest/member-rows.js +152 -0
  243. package/dist/ingest/member-rows.js.map +1 -0
  244. package/dist/ingest/offline-org.d.ts +8 -0
  245. package/dist/ingest/offline-org.d.ts.map +1 -0
  246. package/dist/ingest/offline-org.js +41 -0
  247. package/dist/ingest/offline-org.js.map +1 -0
  248. package/dist/ingest/parse-member.d.ts +53 -0
  249. package/dist/ingest/parse-member.d.ts.map +1 -0
  250. package/dist/ingest/parse-member.js +276 -0
  251. package/dist/ingest/parse-member.js.map +1 -0
  252. package/dist/ingest/parse-pool.d.ts +139 -0
  253. package/dist/ingest/parse-pool.d.ts.map +1 -0
  254. package/dist/ingest/parse-pool.js +593 -0
  255. package/dist/ingest/parse-pool.js.map +1 -0
  256. package/dist/ingest/parse-worker.d.ts +3 -0
  257. package/dist/ingest/parse-worker.d.ts.map +1 -0
  258. package/dist/ingest/parse-worker.js +100 -0
  259. package/dist/ingest/parse-worker.js.map +1 -0
  260. package/dist/ingest/profile.d.ts +27 -0
  261. package/dist/ingest/profile.d.ts.map +1 -0
  262. package/dist/ingest/profile.js +48 -0
  263. package/dist/ingest/profile.js.map +1 -0
  264. package/dist/ingest/resolver-gates.d.ts +12 -0
  265. package/dist/ingest/resolver-gates.d.ts.map +1 -0
  266. package/dist/ingest/resolver-gates.js +53 -0
  267. package/dist/ingest/resolver-gates.js.map +1 -0
  268. package/dist/parsers/apex/arity-resolver.d.ts +16 -3
  269. package/dist/parsers/apex/arity-resolver.d.ts.map +1 -1
  270. package/dist/parsers/apex/arity-resolver.js +31 -2
  271. package/dist/parsers/apex/arity-resolver.js.map +1 -1
  272. package/dist/parsers/apex/ast-extractor.d.ts +4 -0
  273. package/dist/parsers/apex/ast-extractor.d.ts.map +1 -1
  274. package/dist/parsers/apex/ast-extractor.js +96 -29
  275. package/dist/parsers/apex/ast-extractor.js.map +1 -1
  276. package/dist/parsers/apex/class-refs.d.ts +78 -0
  277. package/dist/parsers/apex/class-refs.d.ts.map +1 -0
  278. package/dist/parsers/apex/class-refs.js +465 -0
  279. package/dist/parsers/apex/class-refs.js.map +1 -0
  280. package/dist/parsers/apex/class.d.ts +158 -0
  281. package/dist/parsers/apex/class.d.ts.map +1 -1
  282. package/dist/parsers/apex/class.js +1025 -183
  283. package/dist/parsers/apex/class.js.map +1 -1
  284. package/dist/parsers/apex/dynamic-soql.d.ts +52 -0
  285. package/dist/parsers/apex/dynamic-soql.d.ts.map +1 -0
  286. package/dist/parsers/apex/dynamic-soql.js +427 -0
  287. package/dist/parsers/apex/dynamic-soql.js.map +1 -0
  288. package/dist/parsers/apex/field-access.d.ts +65 -0
  289. package/dist/parsers/apex/field-access.d.ts.map +1 -0
  290. package/dist/parsers/apex/field-access.js +438 -0
  291. package/dist/parsers/apex/field-access.js.map +1 -0
  292. package/dist/parsers/apex/interface-ref-resolver.d.ts +32 -0
  293. package/dist/parsers/apex/interface-ref-resolver.d.ts.map +1 -0
  294. package/dist/parsers/apex/interface-ref-resolver.js +64 -0
  295. package/dist/parsers/apex/interface-ref-resolver.js.map +1 -0
  296. package/dist/parsers/apex/name-refs.d.ts +83 -0
  297. package/dist/parsers/apex/name-refs.d.ts.map +1 -0
  298. package/dist/parsers/apex/name-refs.js +465 -0
  299. package/dist/parsers/apex/name-refs.js.map +1 -0
  300. package/dist/parsers/apex/page-refs.d.ts +11 -0
  301. package/dist/parsers/apex/page-refs.d.ts.map +1 -0
  302. package/dist/parsers/apex/page-refs.js +34 -0
  303. package/dist/parsers/apex/page-refs.js.map +1 -0
  304. package/dist/parsers/apex/ref-resolver.d.ts +58 -0
  305. package/dist/parsers/apex/ref-resolver.d.ts.map +1 -0
  306. package/dist/parsers/apex/ref-resolver.js +348 -0
  307. package/dist/parsers/apex/ref-resolver.js.map +1 -0
  308. package/dist/parsers/apex/soql-fields.d.ts +75 -0
  309. package/dist/parsers/apex/soql-fields.d.ts.map +1 -0
  310. package/dist/parsers/apex/soql-fields.js +338 -0
  311. package/dist/parsers/apex/soql-fields.js.map +1 -0
  312. package/dist/parsers/apex/trigger.d.ts.map +1 -1
  313. package/dist/parsers/apex/trigger.js +90 -2
  314. package/dist/parsers/apex/trigger.js.map +1 -1
  315. package/dist/parsers/apex/vlocity-calls.d.ts +25 -0
  316. package/dist/parsers/apex/vlocity-calls.d.ts.map +1 -0
  317. package/dist/parsers/apex/vlocity-calls.js +225 -0
  318. package/dist/parsers/apex/vlocity-calls.js.map +1 -0
  319. package/dist/parsers/aura/bundle.d.ts +39 -0
  320. package/dist/parsers/aura/bundle.d.ts.map +1 -0
  321. package/dist/parsers/aura/bundle.js +269 -0
  322. package/dist/parsers/aura/bundle.js.map +1 -0
  323. package/dist/parsers/aura/embed-resolver.d.ts +17 -0
  324. package/dist/parsers/aura/embed-resolver.d.ts.map +1 -0
  325. package/dist/parsers/aura/embed-resolver.js +58 -0
  326. package/dist/parsers/aura/embed-resolver.js.map +1 -0
  327. package/dist/parsers/aura/index.d.ts +4 -0
  328. package/dist/parsers/aura/index.d.ts.map +1 -0
  329. package/dist/parsers/aura/index.js +6 -0
  330. package/dist/parsers/aura/index.js.map +1 -0
  331. package/dist/parsers/common.d.ts +9 -0
  332. package/dist/parsers/common.d.ts.map +1 -1
  333. package/dist/parsers/common.js +17 -0
  334. package/dist/parsers/common.js.map +1 -1
  335. package/dist/parsers/cross-flavor-resolver.js +8 -2
  336. package/dist/parsers/cross-flavor-resolver.js.map +1 -1
  337. package/dist/parsers/flow/invocable-resolver.d.ts.map +1 -1
  338. package/dist/parsers/flow/invocable-resolver.js +2 -0
  339. package/dist/parsers/flow/invocable-resolver.js.map +1 -1
  340. package/dist/parsers/flow/parser.d.ts +9 -0
  341. package/dist/parsers/flow/parser.d.ts.map +1 -1
  342. package/dist/parsers/flow/parser.js +327 -2
  343. package/dist/parsers/flow/parser.js.map +1 -1
  344. package/dist/parsers/flow/relationship-resolver.d.ts +34 -0
  345. package/dist/parsers/flow/relationship-resolver.d.ts.map +1 -0
  346. package/dist/parsers/flow/relationship-resolver.js +199 -0
  347. package/dist/parsers/flow/relationship-resolver.js.map +1 -0
  348. package/dist/parsers/generic/opaque-node-parser.d.ts +5 -1
  349. package/dist/parsers/generic/opaque-node-parser.d.ts.map +1 -1
  350. package/dist/parsers/generic/opaque-node-parser.js +37 -5
  351. package/dist/parsers/generic/opaque-node-parser.js.map +1 -1
  352. package/dist/parsers/generic/reflection-walker.d.ts +7 -0
  353. package/dist/parsers/generic/reflection-walker.d.ts.map +1 -1
  354. package/dist/parsers/generic/reflection-walker.js +37 -10
  355. package/dist/parsers/generic/reflection-walker.js.map +1 -1
  356. package/dist/parsers/hash-salts.d.ts +72 -0
  357. package/dist/parsers/hash-salts.d.ts.map +1 -0
  358. package/dist/parsers/hash-salts.js +91 -0
  359. package/dist/parsers/hash-salts.js.map +1 -0
  360. package/dist/parsers/index.d.ts +2 -0
  361. package/dist/parsers/index.d.ts.map +1 -1
  362. package/dist/parsers/index.js +2 -0
  363. package/dist/parsers/index.js.map +1 -1
  364. package/dist/parsers/lwc/bundle.d.ts +1 -0
  365. package/dist/parsers/lwc/bundle.d.ts.map +1 -1
  366. package/dist/parsers/lwc/bundle.js +37 -2
  367. package/dist/parsers/lwc/bundle.js.map +1 -1
  368. package/dist/parsers/lwc/field-key-resolver.d.ts +32 -0
  369. package/dist/parsers/lwc/field-key-resolver.d.ts.map +1 -0
  370. package/dist/parsers/lwc/field-key-resolver.js +92 -0
  371. package/dist/parsers/lwc/field-key-resolver.js.map +1 -0
  372. package/dist/parsers/lwc/html-visitor.d.ts +1 -1
  373. package/dist/parsers/lwc/html-visitor.d.ts.map +1 -1
  374. package/dist/parsers/lwc/html-visitor.js +78 -1
  375. package/dist/parsers/lwc/html-visitor.js.map +1 -1
  376. package/dist/parsers/lwc/js-visitor.d.ts +16 -0
  377. package/dist/parsers/lwc/js-visitor.d.ts.map +1 -1
  378. package/dist/parsers/lwc/js-visitor.js +348 -10
  379. package/dist/parsers/lwc/js-visitor.js.map +1 -1
  380. package/dist/parsers/lwc/omnidef.d.ts +10 -0
  381. package/dist/parsers/lwc/omnidef.d.ts.map +1 -0
  382. package/dist/parsers/lwc/omnidef.js +127 -0
  383. package/dist/parsers/lwc/omnidef.js.map +1 -0
  384. package/dist/parsers/lwc/xml-meta.d.ts.map +1 -1
  385. package/dist/parsers/lwc/xml-meta.js +16 -1
  386. package/dist/parsers/lwc/xml-meta.js.map +1 -1
  387. package/dist/parsers/object/formula-hop-resolver.d.ts +33 -0
  388. package/dist/parsers/object/formula-hop-resolver.d.ts.map +1 -0
  389. package/dist/parsers/object/formula-hop-resolver.js +60 -0
  390. package/dist/parsers/object/formula-hop-resolver.js.map +1 -0
  391. package/dist/parsers/object/formula-refs.d.ts +40 -0
  392. package/dist/parsers/object/formula-refs.d.ts.map +1 -0
  393. package/dist/parsers/object/formula-refs.js +129 -0
  394. package/dist/parsers/object/formula-refs.js.map +1 -0
  395. package/dist/parsers/object/object.d.ts +3 -0
  396. package/dist/parsers/object/object.d.ts.map +1 -1
  397. package/dist/parsers/object/object.js +53 -52
  398. package/dist/parsers/object/object.js.map +1 -1
  399. package/dist/parsers/omnistudio/data-transform.d.ts.map +1 -1
  400. package/dist/parsers/omnistudio/data-transform.js +2 -2
  401. package/dist/parsers/omnistudio/data-transform.js.map +1 -1
  402. package/dist/parsers/omnistudio/integration-procedure.d.ts.map +1 -1
  403. package/dist/parsers/omnistudio/integration-procedure.js +4 -5
  404. package/dist/parsers/omnistudio/integration-procedure.js.map +1 -1
  405. package/dist/parsers/omnistudio/overlap-detector.d.ts.map +1 -1
  406. package/dist/parsers/omnistudio/overlap-detector.js +27 -2
  407. package/dist/parsers/omnistudio/overlap-detector.js.map +1 -1
  408. package/dist/parsers/omnistudio/process.d.ts.map +1 -1
  409. package/dist/parsers/omnistudio/process.js +4 -5
  410. package/dist/parsers/omnistudio/process.js.map +1 -1
  411. package/dist/parsers/omnistudio/remote-refs.d.ts +11 -0
  412. package/dist/parsers/omnistudio/remote-refs.d.ts.map +1 -0
  413. package/dist/parsers/omnistudio/remote-refs.js +17 -0
  414. package/dist/parsers/omnistudio/remote-refs.js.map +1 -0
  415. package/dist/parsers/omnistudio/ui-card.d.ts.map +1 -1
  416. package/dist/parsers/omnistudio/ui-card.js +4 -5
  417. package/dist/parsers/omnistudio/ui-card.js.map +1 -1
  418. package/dist/parsers/resolver-prune.d.ts +14 -0
  419. package/dist/parsers/resolver-prune.d.ts.map +1 -0
  420. package/dist/parsers/resolver-prune.js +29 -0
  421. package/dist/parsers/resolver-prune.js.map +1 -0
  422. package/dist/parsers/rules/_engine.d.ts.map +1 -1
  423. package/dist/parsers/rules/_engine.js +4 -0
  424. package/dist/parsers/rules/_engine.js.map +1 -1
  425. package/dist/parsers/rules/_engine.ts +3 -0
  426. package/dist/parsers/rules/_loader.d.ts +8 -0
  427. package/dist/parsers/rules/_loader.d.ts.map +1 -1
  428. package/dist/parsers/rules/_loader.js +17 -0
  429. package/dist/parsers/rules/_loader.js.map +1 -1
  430. package/dist/parsers/rules/_loader.ts +19 -0
  431. package/dist/parsers/rules/_schema.d.ts +12 -12
  432. package/dist/parsers/rules/_selectors.d.ts +1 -0
  433. package/dist/parsers/rules/_selectors.d.ts.map +1 -1
  434. package/dist/parsers/rules/_selectors.js +6 -0
  435. package/dist/parsers/rules/_selectors.js.map +1 -1
  436. package/dist/parsers/rules/_selectors.ts +6 -0
  437. package/dist/parsers/rules/apex-component.yml +49 -4
  438. package/dist/parsers/rules/apex-page.yml +49 -4
  439. package/dist/parsers/rules/approval-process.yml +25 -5
  440. package/dist/parsers/rules/custom-metadata-type.yml +7 -7
  441. package/dist/parsers/rules/custom-tab.yml +41 -0
  442. package/dist/parsers/rules/lightning-page.yml +4 -2
  443. package/dist/parsers/rules/workflow.yml +30 -10
  444. package/dist/parsers/vf/refs.d.ts +39 -0
  445. package/dist/parsers/vf/refs.d.ts.map +1 -0
  446. package/dist/parsers/vf/refs.js +152 -0
  447. package/dist/parsers/vf/refs.js.map +1 -0
  448. package/dist/parsers/vlocity/apex-resolver.d.ts +21 -0
  449. package/dist/parsers/vlocity/apex-resolver.d.ts.map +1 -0
  450. package/dist/parsers/vlocity/apex-resolver.js +115 -0
  451. package/dist/parsers/vlocity/apex-resolver.js.map +1 -0
  452. package/dist/parsers/vlocity/common.d.ts +56 -1
  453. package/dist/parsers/vlocity/common.d.ts.map +1 -1
  454. package/dist/parsers/vlocity/common.js +275 -7
  455. package/dist/parsers/vlocity/common.js.map +1 -1
  456. package/dist/parsers/vlocity/data-raptor.d.ts +9 -0
  457. package/dist/parsers/vlocity/data-raptor.d.ts.map +1 -1
  458. package/dist/parsers/vlocity/data-raptor.js +133 -31
  459. package/dist/parsers/vlocity/data-raptor.js.map +1 -1
  460. package/dist/parsers/vlocity/datapack-refs.d.ts +22 -0
  461. package/dist/parsers/vlocity/datapack-refs.d.ts.map +1 -0
  462. package/dist/parsers/vlocity/datapack-refs.js +126 -0
  463. package/dist/parsers/vlocity/datapack-refs.js.map +1 -0
  464. package/dist/parsers/vlocity/dr-relationship-resolver.d.ts +26 -0
  465. package/dist/parsers/vlocity/dr-relationship-resolver.d.ts.map +1 -0
  466. package/dist/parsers/vlocity/dr-relationship-resolver.js +137 -0
  467. package/dist/parsers/vlocity/dr-relationship-resolver.js.map +1 -0
  468. package/dist/parsers/vlocity/integration-procedure.d.ts.map +1 -1
  469. package/dist/parsers/vlocity/integration-procedure.js +15 -48
  470. package/dist/parsers/vlocity/integration-procedure.js.map +1 -1
  471. package/dist/parsers/vlocity/name-match-resolver.d.ts +21 -0
  472. package/dist/parsers/vlocity/name-match-resolver.d.ts.map +1 -0
  473. package/dist/parsers/vlocity/name-match-resolver.js +97 -0
  474. package/dist/parsers/vlocity/name-match-resolver.js.map +1 -0
  475. package/dist/parsers/vlocity/omni-script.d.ts.map +1 -1
  476. package/dist/parsers/vlocity/omni-script.js +18 -32
  477. package/dist/parsers/vlocity/omni-script.js.map +1 -1
  478. package/dist/parsers/vlocity/vlocity-card.d.ts.map +1 -1
  479. package/dist/parsers/vlocity/vlocity-card.js +30 -36
  480. package/dist/parsers/vlocity/vlocity-card.js.map +1 -1
  481. package/dist/render/mermaid/dependency-graph.d.ts.map +1 -1
  482. package/dist/render/mermaid/dependency-graph.js +13 -1
  483. package/dist/render/mermaid/dependency-graph.js.map +1 -1
  484. package/dist/render/mermaid/diff.d.ts.map +1 -1
  485. package/dist/render/mermaid/diff.js +4 -2
  486. package/dist/render/mermaid/diff.js.map +1 -1
  487. package/dist/render/mermaid/shared.d.ts +7 -0
  488. package/dist/render/mermaid/shared.d.ts.map +1 -1
  489. package/dist/render/mermaid/shared.js +15 -6
  490. package/dist/render/mermaid/shared.js.map +1 -1
  491. package/dist/storage/index.d.ts +3 -3
  492. package/dist/storage/index.d.ts.map +1 -1
  493. package/dist/storage/index.js +2 -2
  494. package/dist/storage/index.js.map +1 -1
  495. package/dist/storage/interfaces.d.ts +155 -1
  496. package/dist/storage/interfaces.d.ts.map +1 -1
  497. package/dist/storage/sqlite/graph-store.d.ts +352 -3
  498. package/dist/storage/sqlite/graph-store.d.ts.map +1 -1
  499. package/dist/storage/sqlite/graph-store.js +1683 -74
  500. package/dist/storage/sqlite/graph-store.js.map +1 -1
  501. package/dist/storage/sqlite/migrations.d.ts +11 -0
  502. package/dist/storage/sqlite/migrations.d.ts.map +1 -1
  503. package/dist/storage/sqlite/migrations.js +226 -11
  504. package/dist/storage/sqlite/migrations.js.map +1 -1
  505. package/dist/storage/sqlite/snapshot-store.d.ts +79 -3
  506. package/dist/storage/sqlite/snapshot-store.d.ts.map +1 -1
  507. package/dist/storage/sqlite/snapshot-store.js +500 -100
  508. package/dist/storage/sqlite/snapshot-store.js.map +1 -1
  509. package/dist/storage/sqlite/snapshot-versions.d.ts +51 -0
  510. package/dist/storage/sqlite/snapshot-versions.d.ts.map +1 -0
  511. package/dist/storage/sqlite/snapshot-versions.js +209 -0
  512. package/dist/storage/sqlite/snapshot-versions.js.map +1 -0
  513. package/dist/storage/sqlite/vector-store.d.ts +12 -0
  514. package/dist/storage/sqlite/vector-store.d.ts.map +1 -1
  515. package/dist/storage/sqlite/vector-store.js +57 -14
  516. package/dist/storage/sqlite/vector-store.js.map +1 -1
  517. package/dist/util/process-owner.d.ts +35 -0
  518. package/dist/util/process-owner.d.ts.map +1 -0
  519. package/dist/util/process-owner.js +87 -0
  520. package/dist/util/process-owner.js.map +1 -0
  521. package/dist/util/worker-heap-cap.d.ts +10 -0
  522. package/dist/util/worker-heap-cap.d.ts.map +1 -0
  523. package/dist/util/worker-heap-cap.js +65 -0
  524. package/dist/util/worker-heap-cap.js.map +1 -0
  525. package/package.json +6 -7
  526. package/dist/analyze/__tests__/audit-graph.test.d.ts +0 -2
  527. package/dist/analyze/__tests__/audit-graph.test.d.ts.map +0 -1
  528. package/dist/analyze/__tests__/audit-graph.test.js +0 -201
  529. package/dist/analyze/__tests__/audit-graph.test.js.map +0 -1
  530. package/dist/analyze/__tests__/cross-org-two-store.test.d.ts +0 -2
  531. package/dist/analyze/__tests__/cross-org-two-store.test.d.ts.map +0 -1
  532. package/dist/analyze/__tests__/cross-org-two-store.test.js +0 -68
  533. package/dist/analyze/__tests__/cross-org-two-store.test.js.map +0 -1
  534. package/dist/analyze/__tests__/dead-code-confidence.test.d.ts +0 -2
  535. package/dist/analyze/__tests__/dead-code-confidence.test.d.ts.map +0 -1
  536. package/dist/analyze/__tests__/dead-code-confidence.test.js +0 -66
  537. package/dist/analyze/__tests__/dead-code-confidence.test.js.map +0 -1
  538. package/dist/analyze/__tests__/deployment-manifest.test.d.ts +0 -2
  539. package/dist/analyze/__tests__/deployment-manifest.test.d.ts.map +0 -1
  540. package/dist/analyze/__tests__/deployment-manifest.test.js +0 -66
  541. package/dist/analyze/__tests__/deployment-manifest.test.js.map +0 -1
  542. package/dist/analyze/__tests__/edge-filters.test.d.ts +0 -2
  543. package/dist/analyze/__tests__/edge-filters.test.d.ts.map +0 -1
  544. package/dist/analyze/__tests__/edge-filters.test.js +0 -66
  545. package/dist/analyze/__tests__/edge-filters.test.js.map +0 -1
  546. package/dist/analyze/__tests__/find-nodes.test.d.ts +0 -2
  547. package/dist/analyze/__tests__/find-nodes.test.d.ts.map +0 -1
  548. package/dist/analyze/__tests__/find-nodes.test.js +0 -129
  549. package/dist/analyze/__tests__/find-nodes.test.js.map +0 -1
  550. package/dist/analyze/__tests__/findings.test.d.ts +0 -2
  551. package/dist/analyze/__tests__/findings.test.d.ts.map +0 -1
  552. package/dist/analyze/__tests__/findings.test.js +0 -100
  553. package/dist/analyze/__tests__/findings.test.js.map +0 -1
  554. package/dist/analyze/__tests__/governor-risks-detection.test.d.ts +0 -2
  555. package/dist/analyze/__tests__/governor-risks-detection.test.d.ts.map +0 -1
  556. package/dist/analyze/__tests__/governor-risks-detection.test.js +0 -160
  557. package/dist/analyze/__tests__/governor-risks-detection.test.js.map +0 -1
  558. package/dist/analyze/__tests__/populate.test.d.ts +0 -2
  559. package/dist/analyze/__tests__/populate.test.d.ts.map +0 -1
  560. package/dist/analyze/__tests__/populate.test.js +0 -129
  561. package/dist/analyze/__tests__/populate.test.js.map +0 -1
  562. package/dist/analyze/__tests__/security-fls-filter.test.d.ts +0 -2
  563. package/dist/analyze/__tests__/security-fls-filter.test.d.ts.map +0 -1
  564. package/dist/analyze/__tests__/security-fls-filter.test.js +0 -23
  565. package/dist/analyze/__tests__/security-fls-filter.test.js.map +0 -1
  566. package/dist/analyze/__tests__/traversal-caps.test.d.ts +0 -2
  567. package/dist/analyze/__tests__/traversal-caps.test.d.ts.map +0 -1
  568. package/dist/analyze/__tests__/traversal-caps.test.js +0 -129
  569. package/dist/analyze/__tests__/traversal-caps.test.js.map +0 -1
  570. package/dist/analyze/__tests__/wip-impact.test.d.ts +0 -2
  571. package/dist/analyze/__tests__/wip-impact.test.d.ts.map +0 -1
  572. package/dist/analyze/__tests__/wip-impact.test.js +0 -134
  573. package/dist/analyze/__tests__/wip-impact.test.js.map +0 -1
  574. package/dist/embedding/__tests__/embed.test.d.ts +0 -2
  575. package/dist/embedding/__tests__/embed.test.d.ts.map +0 -1
  576. package/dist/embedding/__tests__/embed.test.js +0 -72
  577. package/dist/embedding/__tests__/embed.test.js.map +0 -1
  578. package/dist/embedding/__tests__/queue.test.d.ts +0 -2
  579. package/dist/embedding/__tests__/queue.test.d.ts.map +0 -1
  580. package/dist/embedding/__tests__/queue.test.js +0 -64
  581. package/dist/embedding/__tests__/queue.test.js.map +0 -1
  582. package/dist/extractors/__tests__/network-egress.test.d.ts +0 -2
  583. package/dist/extractors/__tests__/network-egress.test.d.ts.map +0 -1
  584. package/dist/extractors/__tests__/network-egress.test.js +0 -32
  585. package/dist/extractors/__tests__/network-egress.test.js.map +0 -1
  586. package/dist/extractors/filesystem/__tests__/filesystem.test.d.ts +0 -2
  587. package/dist/extractors/filesystem/__tests__/filesystem.test.d.ts.map +0 -1
  588. package/dist/extractors/filesystem/__tests__/filesystem.test.js +0 -96
  589. package/dist/extractors/filesystem/__tests__/filesystem.test.js.map +0 -1
  590. package/dist/extractors/live-org/__tests__/_jsforce-mock.d.ts +0 -38
  591. package/dist/extractors/live-org/__tests__/_jsforce-mock.d.ts.map +0 -1
  592. package/dist/extractors/live-org/__tests__/_jsforce-mock.js +0 -96
  593. package/dist/extractors/live-org/__tests__/_jsforce-mock.js.map +0 -1
  594. package/dist/extractors/live-org/__tests__/auth.test.d.ts +0 -2
  595. package/dist/extractors/live-org/__tests__/auth.test.d.ts.map +0 -1
  596. package/dist/extractors/live-org/__tests__/auth.test.js +0 -85
  597. package/dist/extractors/live-org/__tests__/auth.test.js.map +0 -1
  598. package/dist/extractors/live-org/__tests__/bulk-retrieve.test.d.ts +0 -2
  599. package/dist/extractors/live-org/__tests__/bulk-retrieve.test.d.ts.map +0 -1
  600. package/dist/extractors/live-org/__tests__/bulk-retrieve.test.js +0 -150
  601. package/dist/extractors/live-org/__tests__/bulk-retrieve.test.js.map +0 -1
  602. package/dist/extractors/live-org/__tests__/capabilities.test.d.ts +0 -2
  603. package/dist/extractors/live-org/__tests__/capabilities.test.d.ts.map +0 -1
  604. package/dist/extractors/live-org/__tests__/capabilities.test.js +0 -54
  605. package/dist/extractors/live-org/__tests__/capabilities.test.js.map +0 -1
  606. package/dist/extractors/live-org/__tests__/custom-settings.test.d.ts +0 -2
  607. package/dist/extractors/live-org/__tests__/custom-settings.test.d.ts.map +0 -1
  608. package/dist/extractors/live-org/__tests__/custom-settings.test.js +0 -79
  609. package/dist/extractors/live-org/__tests__/custom-settings.test.js.map +0 -1
  610. package/dist/extractors/live-org/__tests__/discovery.test.d.ts +0 -2
  611. package/dist/extractors/live-org/__tests__/discovery.test.d.ts.map +0 -1
  612. package/dist/extractors/live-org/__tests__/discovery.test.js +0 -55
  613. package/dist/extractors/live-org/__tests__/discovery.test.js.map +0 -1
  614. package/dist/extractors/live-org/__tests__/dispatch.test.d.ts +0 -2
  615. package/dist/extractors/live-org/__tests__/dispatch.test.d.ts.map +0 -1
  616. package/dist/extractors/live-org/__tests__/dispatch.test.js +0 -68
  617. package/dist/extractors/live-org/__tests__/dispatch.test.js.map +0 -1
  618. package/dist/extractors/live-org/__tests__/extractor-enrichment.test.d.ts +0 -2
  619. package/dist/extractors/live-org/__tests__/extractor-enrichment.test.d.ts.map +0 -1
  620. package/dist/extractors/live-org/__tests__/extractor-enrichment.test.js +0 -374
  621. package/dist/extractors/live-org/__tests__/extractor-enrichment.test.js.map +0 -1
  622. package/dist/extractors/live-org/__tests__/liveness.test.d.ts +0 -2
  623. package/dist/extractors/live-org/__tests__/liveness.test.d.ts.map +0 -1
  624. package/dist/extractors/live-org/__tests__/liveness.test.js +0 -148
  625. package/dist/extractors/live-org/__tests__/liveness.test.js.map +0 -1
  626. package/dist/extractors/live-org/__tests__/mcd-baseline.test.d.ts +0 -2
  627. package/dist/extractors/live-org/__tests__/mcd-baseline.test.d.ts.map +0 -1
  628. package/dist/extractors/live-org/__tests__/mcd-baseline.test.js +0 -177
  629. package/dist/extractors/live-org/__tests__/mcd-baseline.test.js.map +0 -1
  630. package/dist/extractors/live-org/__tests__/metadata-read-batch.test.d.ts +0 -2
  631. package/dist/extractors/live-org/__tests__/metadata-read-batch.test.d.ts.map +0 -1
  632. package/dist/extractors/live-org/__tests__/metadata-read-batch.test.js +0 -75
  633. package/dist/extractors/live-org/__tests__/metadata-read-batch.test.js.map +0 -1
  634. package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.d.ts +0 -2
  635. package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.d.ts.map +0 -1
  636. package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.js +0 -135
  637. package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.js.map +0 -1
  638. package/dist/extractors/live-org/__tests__/pools.test.d.ts +0 -2
  639. package/dist/extractors/live-org/__tests__/pools.test.d.ts.map +0 -1
  640. package/dist/extractors/live-org/__tests__/pools.test.js +0 -78
  641. package/dist/extractors/live-org/__tests__/pools.test.js.map +0 -1
  642. package/dist/extractors/live-org/__tests__/rate-limit.test.d.ts +0 -2
  643. package/dist/extractors/live-org/__tests__/rate-limit.test.d.ts.map +0 -1
  644. package/dist/extractors/live-org/__tests__/rate-limit.test.js +0 -73
  645. package/dist/extractors/live-org/__tests__/rate-limit.test.js.map +0 -1
  646. package/dist/extractors/live-org/__tests__/read-only-proxy.test.d.ts +0 -2
  647. package/dist/extractors/live-org/__tests__/read-only-proxy.test.d.ts.map +0 -1
  648. package/dist/extractors/live-org/__tests__/read-only-proxy.test.js +0 -376
  649. package/dist/extractors/live-org/__tests__/read-only-proxy.test.js.map +0 -1
  650. package/dist/extractors/live-org/__tests__/soql-rebatch.test.d.ts +0 -2
  651. package/dist/extractors/live-org/__tests__/soql-rebatch.test.d.ts.map +0 -1
  652. package/dist/extractors/live-org/__tests__/soql-rebatch.test.js +0 -118
  653. package/dist/extractors/live-org/__tests__/soql-rebatch.test.js.map +0 -1
  654. package/dist/extractors/live-org/__tests__/source-member.test.d.ts +0 -2
  655. package/dist/extractors/live-org/__tests__/source-member.test.d.ts.map +0 -1
  656. package/dist/extractors/live-org/__tests__/source-member.test.js +0 -84
  657. package/dist/extractors/live-org/__tests__/source-member.test.js.map +0 -1
  658. package/dist/extractors/live-org/__tests__/stop-waiting.test.d.ts +0 -2
  659. package/dist/extractors/live-org/__tests__/stop-waiting.test.d.ts.map +0 -1
  660. package/dist/extractors/live-org/__tests__/stop-waiting.test.js +0 -243
  661. package/dist/extractors/live-org/__tests__/stop-waiting.test.js.map +0 -1
  662. package/dist/extractors/live-org/__tests__/vlocity-runner.test.d.ts +0 -2
  663. package/dist/extractors/live-org/__tests__/vlocity-runner.test.d.ts.map +0 -1
  664. package/dist/extractors/live-org/__tests__/vlocity-runner.test.js +0 -115
  665. package/dist/extractors/live-org/__tests__/vlocity-runner.test.js.map +0 -1
  666. package/dist/extractors/live-org/__tests__/watchdog-budgets.test.d.ts +0 -2
  667. package/dist/extractors/live-org/__tests__/watchdog-budgets.test.d.ts.map +0 -1
  668. package/dist/extractors/live-org/__tests__/watchdog-budgets.test.js +0 -40
  669. package/dist/extractors/live-org/__tests__/watchdog-budgets.test.js.map +0 -1
  670. package/dist/extractors/live-org/__tests__/wedge-isolation.test.d.ts +0 -2
  671. package/dist/extractors/live-org/__tests__/wedge-isolation.test.d.ts.map +0 -1
  672. package/dist/extractors/live-org/__tests__/wedge-isolation.test.js +0 -270
  673. package/dist/extractors/live-org/__tests__/wedge-isolation.test.js.map +0 -1
  674. package/dist/extractors/live-org/extractors/__tests__/apex.test.d.ts +0 -2
  675. package/dist/extractors/live-org/extractors/__tests__/apex.test.d.ts.map +0 -1
  676. package/dist/extractors/live-org/extractors/__tests__/apex.test.js +0 -73
  677. package/dist/extractors/live-org/extractors/__tests__/apex.test.js.map +0 -1
  678. package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.d.ts +0 -2
  679. package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.d.ts.map +0 -1
  680. package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.js +0 -183
  681. package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.js.map +0 -1
  682. package/dist/ingest/__tests__/config-values.test.d.ts +0 -2
  683. package/dist/ingest/__tests__/config-values.test.d.ts.map +0 -1
  684. package/dist/ingest/__tests__/config-values.test.js +0 -65
  685. package/dist/ingest/__tests__/config-values.test.js.map +0 -1
  686. package/dist/ingest/__tests__/full-sync-deletion.test.d.ts +0 -2
  687. package/dist/ingest/__tests__/full-sync-deletion.test.d.ts.map +0 -1
  688. package/dist/ingest/__tests__/full-sync-deletion.test.js +0 -207
  689. package/dist/ingest/__tests__/full-sync-deletion.test.js.map +0 -1
  690. package/dist/ingest/__tests__/incremental-deletion.test.d.ts +0 -2
  691. package/dist/ingest/__tests__/incremental-deletion.test.d.ts.map +0 -1
  692. package/dist/ingest/__tests__/incremental-deletion.test.js +0 -92
  693. package/dist/ingest/__tests__/incremental-deletion.test.js.map +0 -1
  694. package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.d.ts +0 -10
  695. package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.d.ts.map +0 -1
  696. package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.js +0 -251
  697. package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.js.map +0 -1
  698. package/dist/ingest/__tests__/live-ingest.test.d.ts +0 -2
  699. package/dist/ingest/__tests__/live-ingest.test.d.ts.map +0 -1
  700. package/dist/ingest/__tests__/live-ingest.test.js +0 -155
  701. package/dist/ingest/__tests__/live-ingest.test.js.map +0 -1
  702. package/dist/ingest/__tests__/multi-org-orchestrator.test.d.ts +0 -2
  703. package/dist/ingest/__tests__/multi-org-orchestrator.test.d.ts.map +0 -1
  704. package/dist/ingest/__tests__/multi-org-orchestrator.test.js +0 -108
  705. package/dist/ingest/__tests__/multi-org-orchestrator.test.js.map +0 -1
  706. package/dist/ingest/__tests__/parser-dispatch.test.d.ts +0 -2
  707. package/dist/ingest/__tests__/parser-dispatch.test.d.ts.map +0 -1
  708. package/dist/ingest/__tests__/parser-dispatch.test.js +0 -55
  709. package/dist/ingest/__tests__/parser-dispatch.test.js.map +0 -1
  710. package/dist/ingest/__tests__/read-only-wrapping.test.d.ts +0 -2
  711. package/dist/ingest/__tests__/read-only-wrapping.test.d.ts.map +0 -1
  712. package/dist/ingest/__tests__/read-only-wrapping.test.js +0 -62
  713. package/dist/ingest/__tests__/read-only-wrapping.test.js.map +0 -1
  714. package/dist/ingest/__tests__/vlocity-dispatch-integration.test.d.ts +0 -2
  715. package/dist/ingest/__tests__/vlocity-dispatch-integration.test.d.ts.map +0 -1
  716. package/dist/ingest/__tests__/vlocity-dispatch-integration.test.js +0 -134
  717. package/dist/ingest/__tests__/vlocity-dispatch-integration.test.js.map +0 -1
  718. package/dist/parsers/__tests__/_harness.d.ts +0 -13
  719. package/dist/parsers/__tests__/_harness.d.ts.map +0 -1
  720. package/dist/parsers/__tests__/_harness.js +0 -84
  721. package/dist/parsers/__tests__/_harness.js.map +0 -1
  722. package/dist/parsers/__tests__/apex.golden.test.d.ts +0 -2
  723. package/dist/parsers/__tests__/apex.golden.test.d.ts.map +0 -1
  724. package/dist/parsers/__tests__/apex.golden.test.js +0 -28
  725. package/dist/parsers/__tests__/apex.golden.test.js.map +0 -1
  726. package/dist/parsers/__tests__/cross-flavor.test.d.ts +0 -2
  727. package/dist/parsers/__tests__/cross-flavor.test.d.ts.map +0 -1
  728. package/dist/parsers/__tests__/cross-flavor.test.js +0 -56
  729. package/dist/parsers/__tests__/cross-flavor.test.js.map +0 -1
  730. package/dist/parsers/__tests__/datatransform-structured.test.d.ts +0 -2
  731. package/dist/parsers/__tests__/datatransform-structured.test.d.ts.map +0 -1
  732. package/dist/parsers/__tests__/datatransform-structured.test.js +0 -147
  733. package/dist/parsers/__tests__/datatransform-structured.test.js.map +0 -1
  734. package/dist/parsers/__tests__/edge-provenance.test.d.ts +0 -2
  735. package/dist/parsers/__tests__/edge-provenance.test.d.ts.map +0 -1
  736. package/dist/parsers/__tests__/edge-provenance.test.js +0 -47
  737. package/dist/parsers/__tests__/edge-provenance.test.js.map +0 -1
  738. package/dist/parsers/__tests__/flow.golden.test.d.ts +0 -2
  739. package/dist/parsers/__tests__/flow.golden.test.d.ts.map +0 -1
  740. package/dist/parsers/__tests__/flow.golden.test.js +0 -17
  741. package/dist/parsers/__tests__/flow.golden.test.js.map +0 -1
  742. package/dist/parsers/__tests__/integration.golden.test.d.ts +0 -2
  743. package/dist/parsers/__tests__/integration.golden.test.d.ts.map +0 -1
  744. package/dist/parsers/__tests__/integration.golden.test.js +0 -31
  745. package/dist/parsers/__tests__/integration.golden.test.js.map +0 -1
  746. package/dist/parsers/__tests__/long-tail.golden.test.d.ts +0 -2
  747. package/dist/parsers/__tests__/long-tail.golden.test.d.ts.map +0 -1
  748. package/dist/parsers/__tests__/long-tail.golden.test.js +0 -115
  749. package/dist/parsers/__tests__/long-tail.golden.test.js.map +0 -1
  750. package/dist/parsers/__tests__/lwc-bindings.test.d.ts +0 -2
  751. package/dist/parsers/__tests__/lwc-bindings.test.d.ts.map +0 -1
  752. package/dist/parsers/__tests__/lwc-bindings.test.js +0 -149
  753. package/dist/parsers/__tests__/lwc-bindings.test.js.map +0 -1
  754. package/dist/parsers/__tests__/lwc.golden.test.d.ts +0 -2
  755. package/dist/parsers/__tests__/lwc.golden.test.d.ts.map +0 -1
  756. package/dist/parsers/__tests__/lwc.golden.test.js +0 -16
  757. package/dist/parsers/__tests__/lwc.golden.test.js.map +0 -1
  758. package/dist/parsers/__tests__/mcd-gap-fills.test.d.ts +0 -2
  759. package/dist/parsers/__tests__/mcd-gap-fills.test.d.ts.map +0 -1
  760. package/dist/parsers/__tests__/mcd-gap-fills.test.js +0 -75
  761. package/dist/parsers/__tests__/mcd-gap-fills.test.js.map +0 -1
  762. package/dist/parsers/__tests__/object-inline-fields.test.d.ts +0 -2
  763. package/dist/parsers/__tests__/object-inline-fields.test.d.ts.map +0 -1
  764. package/dist/parsers/__tests__/object-inline-fields.test.js +0 -115
  765. package/dist/parsers/__tests__/object-inline-fields.test.js.map +0 -1
  766. package/dist/parsers/__tests__/object.golden.test.d.ts +0 -2
  767. package/dist/parsers/__tests__/object.golden.test.d.ts.map +0 -1
  768. package/dist/parsers/__tests__/object.golden.test.js +0 -33
  769. package/dist/parsers/__tests__/object.golden.test.js.map +0 -1
  770. package/dist/parsers/__tests__/omnistudio-overlap.test.d.ts +0 -2
  771. package/dist/parsers/__tests__/omnistudio-overlap.test.d.ts.map +0 -1
  772. package/dist/parsers/__tests__/omnistudio-overlap.test.js +0 -163
  773. package/dist/parsers/__tests__/omnistudio-overlap.test.js.map +0 -1
  774. package/dist/parsers/__tests__/omnistudio.golden.test.d.ts +0 -2
  775. package/dist/parsers/__tests__/omnistudio.golden.test.d.ts.map +0 -1
  776. package/dist/parsers/__tests__/omnistudio.golden.test.js +0 -53
  777. package/dist/parsers/__tests__/omnistudio.golden.test.js.map +0 -1
  778. package/dist/parsers/__tests__/reflection-walker.test.d.ts +0 -2
  779. package/dist/parsers/__tests__/reflection-walker.test.d.ts.map +0 -1
  780. package/dist/parsers/__tests__/reflection-walker.test.js +0 -162
  781. package/dist/parsers/__tests__/reflection-walker.test.js.map +0 -1
  782. package/dist/parsers/__tests__/registry.test.d.ts +0 -2
  783. package/dist/parsers/__tests__/registry.test.d.ts.map +0 -1
  784. package/dist/parsers/__tests__/registry.test.js +0 -23
  785. package/dist/parsers/__tests__/registry.test.js.map +0 -1
  786. package/dist/parsers/__tests__/security.golden.test.d.ts +0 -2
  787. package/dist/parsers/__tests__/security.golden.test.d.ts.map +0 -1
  788. package/dist/parsers/__tests__/security.golden.test.js +0 -31
  789. package/dist/parsers/__tests__/security.golden.test.js.map +0 -1
  790. package/dist/parsers/__tests__/vlocity.golden.test.d.ts +0 -2
  791. package/dist/parsers/__tests__/vlocity.golden.test.d.ts.map +0 -1
  792. package/dist/parsers/__tests__/vlocity.golden.test.js +0 -105
  793. package/dist/parsers/__tests__/vlocity.golden.test.js.map +0 -1
  794. package/dist/parsers/__tests__/worker-pool.test.d.ts +0 -2
  795. package/dist/parsers/__tests__/worker-pool.test.d.ts.map +0 -1
  796. package/dist/parsers/__tests__/worker-pool.test.js +0 -48
  797. package/dist/parsers/__tests__/worker-pool.test.js.map +0 -1
  798. package/dist/parsers/apex/__tests__/arity-resolver.test.d.ts +0 -2
  799. package/dist/parsers/apex/__tests__/arity-resolver.test.d.ts.map +0 -1
  800. package/dist/parsers/apex/__tests__/arity-resolver.test.js +0 -135
  801. package/dist/parsers/apex/__tests__/arity-resolver.test.js.map +0 -1
  802. package/dist/parsers/apex/__tests__/ast-extractor.test.d.ts +0 -2
  803. package/dist/parsers/apex/__tests__/ast-extractor.test.d.ts.map +0 -1
  804. package/dist/parsers/apex/__tests__/ast-extractor.test.js +0 -206
  805. package/dist/parsers/apex/__tests__/ast-extractor.test.js.map +0 -1
  806. package/dist/parsers/apex/__tests__/empty-body.test.d.ts +0 -2
  807. package/dist/parsers/apex/__tests__/empty-body.test.d.ts.map +0 -1
  808. package/dist/parsers/apex/__tests__/empty-body.test.js +0 -40
  809. package/dist/parsers/apex/__tests__/empty-body.test.js.map +0 -1
  810. package/dist/parsers/apex/__tests__/is-test-attribute.test.d.ts +0 -2
  811. package/dist/parsers/apex/__tests__/is-test-attribute.test.d.ts.map +0 -1
  812. package/dist/parsers/apex/__tests__/is-test-attribute.test.js +0 -56
  813. package/dist/parsers/apex/__tests__/is-test-attribute.test.js.map +0 -1
  814. package/dist/parsers/apex/__tests__/regex-arg-count.test.d.ts +0 -2
  815. package/dist/parsers/apex/__tests__/regex-arg-count.test.d.ts.map +0 -1
  816. package/dist/parsers/apex/__tests__/regex-arg-count.test.js +0 -82
  817. package/dist/parsers/apex/__tests__/regex-arg-count.test.js.map +0 -1
  818. package/dist/parsers/apex/__tests__/regex-inloop.test.d.ts +0 -2
  819. package/dist/parsers/apex/__tests__/regex-inloop.test.d.ts.map +0 -1
  820. package/dist/parsers/apex/__tests__/regex-inloop.test.js +0 -70
  821. package/dist/parsers/apex/__tests__/regex-inloop.test.js.map +0 -1
  822. package/dist/parsers/flow/__tests__/invocable-resolver.test.d.ts +0 -2
  823. package/dist/parsers/flow/__tests__/invocable-resolver.test.d.ts.map +0 -1
  824. package/dist/parsers/flow/__tests__/invocable-resolver.test.js +0 -91
  825. package/dist/parsers/flow/__tests__/invocable-resolver.test.js.map +0 -1
  826. package/dist/parsers/rules/__tests__/applies-to.test.d.ts +0 -2
  827. package/dist/parsers/rules/__tests__/applies-to.test.d.ts.map +0 -1
  828. package/dist/parsers/rules/__tests__/applies-to.test.js +0 -31
  829. package/dist/parsers/rules/__tests__/applies-to.test.js.map +0 -1
  830. package/dist/parsers/rules/__tests__/applies-to.test.ts +0 -40
  831. package/dist/parsers/rules/__tests__/engine.test.d.ts +0 -2
  832. package/dist/parsers/rules/__tests__/engine.test.d.ts.map +0 -1
  833. package/dist/parsers/rules/__tests__/engine.test.js +0 -127
  834. package/dist/parsers/rules/__tests__/engine.test.js.map +0 -1
  835. package/dist/parsers/rules/__tests__/engine.test.ts +0 -138
  836. package/dist/parsers/rules/__tests__/loader.test.d.ts +0 -2
  837. package/dist/parsers/rules/__tests__/loader.test.d.ts.map +0 -1
  838. package/dist/parsers/rules/__tests__/loader.test.js +0 -31
  839. package/dist/parsers/rules/__tests__/loader.test.js.map +0 -1
  840. package/dist/parsers/rules/__tests__/loader.test.ts +0 -37
  841. package/dist/parsers/rules/__tests__/schema.test.d.ts +0 -2
  842. package/dist/parsers/rules/__tests__/schema.test.d.ts.map +0 -1
  843. package/dist/parsers/rules/__tests__/schema.test.js +0 -33
  844. package/dist/parsers/rules/__tests__/schema.test.js.map +0 -1
  845. package/dist/parsers/rules/__tests__/schema.test.ts +0 -37
  846. package/dist/parsers/rules/__tests__/selectors.test.d.ts +0 -2
  847. package/dist/parsers/rules/__tests__/selectors.test.d.ts.map +0 -1
  848. package/dist/parsers/rules/__tests__/selectors.test.js +0 -51
  849. package/dist/parsers/rules/__tests__/selectors.test.js.map +0 -1
  850. package/dist/parsers/rules/__tests__/selectors.test.ts +0 -62
  851. package/dist/render/__tests__/sarif.test.d.ts +0 -2
  852. package/dist/render/__tests__/sarif.test.d.ts.map +0 -1
  853. package/dist/render/__tests__/sarif.test.js +0 -126
  854. package/dist/render/__tests__/sarif.test.js.map +0 -1
  855. package/dist/render/mermaid/__tests__/mermaid.test.d.ts +0 -2
  856. package/dist/render/mermaid/__tests__/mermaid.test.d.ts.map +0 -1
  857. package/dist/render/mermaid/__tests__/mermaid.test.js +0 -74
  858. package/dist/render/mermaid/__tests__/mermaid.test.js.map +0 -1
  859. package/dist/storage/__tests__/analysis-tables-migration.test.d.ts +0 -2
  860. package/dist/storage/__tests__/analysis-tables-migration.test.d.ts.map +0 -1
  861. package/dist/storage/__tests__/analysis-tables-migration.test.js +0 -44
  862. package/dist/storage/__tests__/analysis-tables-migration.test.js.map +0 -1
  863. package/dist/storage/__tests__/graph-store.test.d.ts +0 -2
  864. package/dist/storage/__tests__/graph-store.test.d.ts.map +0 -1
  865. package/dist/storage/__tests__/graph-store.test.js +0 -145
  866. package/dist/storage/__tests__/graph-store.test.js.map +0 -1
  867. package/dist/storage/__tests__/identifier.test.d.ts +0 -2
  868. package/dist/storage/__tests__/identifier.test.d.ts.map +0 -1
  869. package/dist/storage/__tests__/identifier.test.js +0 -35
  870. package/dist/storage/__tests__/identifier.test.js.map +0 -1
  871. package/dist/storage/__tests__/load-better-sqlite3.test.d.ts +0 -2
  872. package/dist/storage/__tests__/load-better-sqlite3.test.d.ts.map +0 -1
  873. package/dist/storage/__tests__/load-better-sqlite3.test.js +0 -65
  874. package/dist/storage/__tests__/load-better-sqlite3.test.js.map +0 -1
  875. package/dist/storage/__tests__/migrations.test.d.ts +0 -2
  876. package/dist/storage/__tests__/migrations.test.d.ts.map +0 -1
  877. package/dist/storage/__tests__/migrations.test.js +0 -93
  878. package/dist/storage/__tests__/migrations.test.js.map +0 -1
  879. package/dist/storage/__tests__/perf-50k.test.d.ts +0 -2
  880. package/dist/storage/__tests__/perf-50k.test.d.ts.map +0 -1
  881. package/dist/storage/__tests__/perf-50k.test.js +0 -67
  882. package/dist/storage/__tests__/perf-50k.test.js.map +0 -1
  883. package/dist/storage/__tests__/rename-stability.test.d.ts +0 -2
  884. package/dist/storage/__tests__/rename-stability.test.d.ts.map +0 -1
  885. package/dist/storage/__tests__/rename-stability.test.js +0 -135
  886. package/dist/storage/__tests__/rename-stability.test.js.map +0 -1
  887. package/dist/storage/__tests__/snapshot-store.test.d.ts +0 -2
  888. package/dist/storage/__tests__/snapshot-store.test.d.ts.map +0 -1
  889. package/dist/storage/__tests__/snapshot-store.test.js +0 -117
  890. package/dist/storage/__tests__/snapshot-store.test.js.map +0 -1
  891. package/dist/storage/__tests__/snippets.test.d.ts +0 -2
  892. package/dist/storage/__tests__/snippets.test.d.ts.map +0 -1
  893. package/dist/storage/__tests__/snippets.test.js +0 -88
  894. package/dist/storage/__tests__/snippets.test.js.map +0 -1
  895. package/dist/storage/__tests__/sync-generation.test.d.ts +0 -2
  896. package/dist/storage/__tests__/sync-generation.test.d.ts.map +0 -1
  897. package/dist/storage/__tests__/sync-generation.test.js +0 -159
  898. package/dist/storage/__tests__/sync-generation.test.js.map +0 -1
  899. package/dist/storage/__tests__/vector-store-load-failure.test.d.ts +0 -2
  900. package/dist/storage/__tests__/vector-store-load-failure.test.d.ts.map +0 -1
  901. package/dist/storage/__tests__/vector-store-load-failure.test.js +0 -42
  902. package/dist/storage/__tests__/vector-store-load-failure.test.js.map +0 -1
  903. package/dist/storage/__tests__/vector-store.test.d.ts +0 -2
  904. package/dist/storage/__tests__/vector-store.test.d.ts.map +0 -1
  905. package/dist/storage/__tests__/vector-store.test.js +0 -87
  906. package/dist/storage/__tests__/vector-store.test.js.map +0 -1
  907. package/dist/telemetry/__tests__/event-schema.test.d.ts +0 -2
  908. package/dist/telemetry/__tests__/event-schema.test.d.ts.map +0 -1
  909. package/dist/telemetry/__tests__/event-schema.test.js +0 -56
  910. package/dist/telemetry/__tests__/event-schema.test.js.map +0 -1
  911. package/dist/telemetry/__tests__/machine-id.test.d.ts +0 -2
  912. package/dist/telemetry/__tests__/machine-id.test.d.ts.map +0 -1
  913. package/dist/telemetry/__tests__/machine-id.test.js +0 -33
  914. package/dist/telemetry/__tests__/machine-id.test.js.map +0 -1
  915. package/dist/telemetry/__tests__/pipeline.test.d.ts +0 -2
  916. package/dist/telemetry/__tests__/pipeline.test.d.ts.map +0 -1
  917. package/dist/telemetry/__tests__/pipeline.test.js +0 -68
  918. package/dist/telemetry/__tests__/pipeline.test.js.map +0 -1
  919. package/dist/telemetry/__tests__/sanitizer.test.d.ts +0 -2
  920. package/dist/telemetry/__tests__/sanitizer.test.d.ts.map +0 -1
  921. package/dist/telemetry/__tests__/sanitizer.test.js +0 -143
  922. package/dist/telemetry/__tests__/sanitizer.test.js.map +0 -1
@@ -1,21 +1,41 @@
1
+ import { existsSync, readFileSync } from "node:fs";
1
2
  import { asQualifiedName } from "@ryanstark24/sfgraph-shared";
2
3
  import { resolveApexMethodArity } from "../parsers/apex/arity-resolver.js";
4
+ import { retargetApexInterfaceRefs } from "../parsers/apex/interface-ref-resolver.js";
5
+ import { resolveAuraEmbeds } from "../parsers/aura/embed-resolver.js";
3
6
  import { resolveCrossFlavor } from "../parsers/cross-flavor-resolver.js";
4
7
  import { resolveFlowApexMethods } from "../parsers/flow/invocable-resolver.js";
5
- import { parserRegistry } from "../parsers/registry.js";
8
+ import { resolveFormulaRelationshipHops } from "../parsers/object/formula-hop-resolver.js";
6
9
  // Ensure all parsers are registered before we look them up.
7
10
  import "../parsers/index.js";
8
11
  import { auditDanglingEdges } from "../analyze/audit-graph.js";
9
12
  import { populateAnalysisTables } from "../analyze/populate.js";
10
- import { EmbeddingQueue } from "../embedding/index.js";
13
+ import { REL_TYPES } from "../domain/rel-types.js";
14
+ import { EmbeddingCache, EmbeddingPool, EmbeddingQueue, defaultEmbeddingWorkerUrl, hashEmbedText, } from "../embedding/index.js";
15
+ import { tokenizeIdentifier } from "../embedding/tokenize.js";
11
16
  import { resolveOrg } from "../extractors/live-org/auth.js";
12
17
  import { bulkRetrieve } from "../extractors/live-org/bulk-retrieve.js";
13
18
  import { probeCapabilities } from "../extractors/live-org/capabilities.js";
14
19
  import { startLivenessProbe } from "../extractors/live-org/liveness.js";
15
20
  import { dataPool, metadataPool, toolingPool } from "../extractors/live-org/rate-limit.js";
16
21
  import { iterChanges } from "../extractors/live-org/source-member.js";
22
+ // SourceMember MemberType -> the node LABEL the parsers actually store under,
23
+ // for the (rare) types whose label differs from the member type. The LWC parser
24
+ // labels nodes "LWC", not "LightningComponentBundle", so an obsolete-LWC delete
25
+ // keyed by the raw member type was a silent no-op. METADATA_CATEGORY is NOT
26
+ // usable here: its LWC/AURA values ARE the member-type strings, not the labels.
27
+ const MEMBER_TYPE_TO_NODE_LABEL = {
28
+ LightningComponentBundle: "LWC",
29
+ AuraDefinitionBundle: "AuraComponent",
30
+ };
17
31
  import { loadAllRules } from "../parsers/rules/_loader.js";
18
- import { evaluateDeletionGuard, resolveMaxDropRatio } from "./detect-deletions-guard.js";
32
+ import { evaluateDeletionGuard, isSkipProtected, resolveMaxDropRatio, skipProtection, } from "./detect-deletions-guard.js";
33
+ import { hasGoodPriorOwned, isParseFailureOnly, isQuarantinedFor, isQuarantinedRow, memberContentHash, memberFailureStamp, memberRowsGeneration, ownedQnames, quarantinedOutcome, } from "./member-rows.js";
34
+ import { OFFLINE_CAPS } from "./offline-org.js";
35
+ import { parseMember } from "./parse-member.js";
36
+ import { parsePool, resolveParseWorkers, } from "./parse-pool.js";
37
+ export { adaptParserInput } from "./parse-member.js";
38
+ import { createIngestProfiler } from "./profile.js";
19
39
  const NOOP_LOG = {
20
40
  debug: () => { },
21
41
  info: () => { },
@@ -25,23 +45,56 @@ const NOOP_LOG = {
25
45
  /** Print a consolidated end-of-run summary of metadata types that were
26
46
  * skipped during ingest, grouped by failure category, with a targeted
27
47
  * remediation block per category. */
28
- function printSkipSummary(report, orgAlias) {
48
+ /**
49
+ * Entries of the previous skip report at `path` (same org) whose label a
50
+ * scoped run did NOT re-run. Missing / malformed / other-org report: none.
51
+ * A `discovery` only-label re-runs every generic:* source (bulkRetrieve), so
52
+ * their entries are not carried either (review N3).
53
+ */
54
+ export function carriedOverSkips(path, orgId, reRun) {
55
+ try {
56
+ if (!existsSync(path))
57
+ return [];
58
+ const prev = JSON.parse(readFileSync(path, "utf8"));
59
+ if (prev.orgId !== undefined && prev.orgId !== orgId)
60
+ return [];
61
+ return (prev.skips ?? []).filter((s) => s &&
62
+ typeof s.label === "string" &&
63
+ !reRun.has(s.label) &&
64
+ !(reRun.has("discovery") && s.label.startsWith("generic:")));
65
+ }
66
+ catch {
67
+ return [];
68
+ }
69
+ }
70
+ /** A skip reason without a leading "<label>: " — source errors already name
71
+ * their source, which the summary bullet prints anyway. */
72
+ function bulletReason(s) {
73
+ return s.reason.startsWith(`${s.label}: `) ? s.reason.slice(s.label.length + 2) : s.reason;
74
+ }
75
+ export function printSkipSummary(report, orgAlias) {
29
76
  const byCategory = new Map();
30
77
  for (const s of report.skips) {
31
78
  const arr = byCategory.get(s.category) ?? [];
32
79
  arr.push({ label: s.label, reason: s.reason });
33
80
  byCategory.set(s.category, arr);
34
81
  }
35
- const total = report.skips.length;
82
+ const unreadableCount = byCategory.get("unreadable")?.length ?? 0;
83
+ const total = report.skips.length - unreadableCount;
36
84
  console.log("");
37
- console.log(`⚠ ${total} metadata ${total === 1 ? "type was" : "types were"} skipped during this ingest.`);
38
- console.log(" The rest of the graph completed successfully — these types are simply absent.");
85
+ if (total > 0) {
86
+ console.log(`⚠ ${total} metadata ${total === 1 ? "type was" : "types were"} skipped during this ingest.`);
87
+ console.log(" The rest of the graph completed successfully — these types are simply absent.");
88
+ }
89
+ if (unreadableCount > 0) {
90
+ console.log(`⚠ ${unreadableCount} metadata ${unreadableCount === 1 ? "type (or some of its members)" : "types (or some of their members)"} could not be read: the org refused them (unreadable — see below).`);
91
+ }
39
92
  if (byCategory.has("insufficient_access")) {
40
93
  const list = byCategory.get("insufficient_access") ?? [];
41
94
  console.log("");
42
95
  console.log(` Insufficient access (${list.length}):`);
43
96
  for (const s of list)
44
- console.log(` • ${s.label}: ${s.reason}`);
97
+ console.log(` • ${s.label}: ${bulletReason(s)}`);
45
98
  console.log("");
46
99
  console.log(" How to fix permanently:");
47
100
  console.log(" 1. Have an admin assign your user a permission set with:");
@@ -78,66 +131,47 @@ function printSkipSummary(report, orgAlias) {
78
131
  console.log("");
79
132
  console.log(` Network errors (${list.length}):`);
80
133
  for (const s of list)
81
- console.log(` • ${s.label}: ${s.reason}`);
134
+ console.log(` • ${s.label}: ${bulletReason(s)}`);
82
135
  console.log(" How to fix: check connectivity to your org and re-run.");
83
136
  }
137
+ if (byCategory.has("unreadable")) {
138
+ const list = byCategory.get("unreadable") ?? [];
139
+ console.log("");
140
+ console.log(` Unreadable (org refused; re-run with --retry-skipped to try again) (${list.length}):`);
141
+ for (const s of list)
142
+ console.log(` • ${s.label}: ${bulletReason(s)}`);
143
+ console.log(" The org rejected these reads as invalid, or returned the same error on");
144
+ console.log(" repeated reads, so they were not auto-retried in this run. To try again:");
145
+ console.log(` sfgraph ingest --org ${orgAlias} --retry-skipped`);
146
+ }
84
147
  if (byCategory.has("unknown")) {
85
148
  const list = byCategory.get("unknown") ?? [];
86
149
  console.log("");
87
150
  console.log(` Other (${list.length}):`);
88
151
  for (const s of list)
89
- console.log(` • ${s.label}: ${s.reason}`);
152
+ console.log(` • ${s.label}: ${bulletReason(s)}`);
90
153
  }
91
154
  console.log("");
92
155
  }
93
- /** Live-org Apex extractor wraps body in a `{body, metaXml}` JSON envelope
94
- * so we can forward Tooling-row ApiVersion/Status to the parser. Filesystem
95
- * extractor still passes raw body. Detect by trying JSON.parse — if it
96
- * yields an object with `body`, unwrap; otherwise treat as raw body. */
97
- function unwrapApexEnvelope(content) {
98
- if (!content)
99
- return { body: "" };
100
- if (content[0] !== "{")
101
- return { body: content };
102
- try {
103
- const parsed = JSON.parse(content);
104
- if (parsed && typeof parsed === "object" && typeof parsed.body === "string") {
105
- const out = { body: parsed.body };
106
- if (typeof parsed.metaXml === "string")
107
- out.metaXml = parsed.metaXml;
108
- return out;
109
- }
110
- }
111
- catch {
112
- /* fallthrough — raw body */
113
- }
114
- return { body: content };
115
- }
116
- /** Maps the Vlocity runner's emitted memberType (the bare VlocityDataPackType)
117
- * to the parser-registry key the four rich Vlocity parsers register under.
118
- * Only these four DataPack types have dedicated parsers; the other ~44 fall
119
- * through to the opaque node parser (node-only, by design). */
120
- const VLOCITY_MEMBER_TO_PARSER = {
121
- DataRaptor: "VlocityDataRaptor",
122
- VlocityDataRaptor: "VlocityDataRaptor",
123
- IntegrationProcedure: "VlocityIntegrationProcedure",
124
- VlocityIntegrationProcedure: "VlocityIntegrationProcedure",
125
- OmniScript: "VlocityOmniScript",
126
- VlocityOmniScript: "VlocityOmniScript",
127
- VlocityCard: "VlocityCard",
128
- };
129
156
  /**
130
157
  * Build the text embedded for a node's semantic vector. Beyond the
131
158
  * label/qname/description baseline, this folds in CONFIG VALUES so
132
159
  * `find_similar` matches on what a config artifact actually resolves to —
133
160
  * a Custom Metadata record's field values, a Custom Label's text, a Custom
134
161
  * Setting's rows. Without this, searching "endpoint for product push" can't
135
- * reach `End_Point_Urls.ProductPush_PLDT` because only its name was embedded.
162
+ * reach `Endpoint_Url.ProductPush_Acme` because only its name was embedded.
136
163
  * Exported for tests.
137
164
  */
138
165
  export function buildEmbedText(label, qname, attributes) {
139
166
  const a = attributes ?? {};
140
167
  const parts = [`${label}: ${qname}`];
168
+ // Word-split the identifier so semantic search matches on word boundaries
169
+ // (`account controller` → AccountController, `customer tier` → Customer_Tier__c).
170
+ // Only the name part after the label prefix; skip if it adds nothing.
171
+ const namePart = qname.includes(":") ? qname.slice(qname.indexOf(":") + 1) : qname;
172
+ const words = tokenizeIdentifier(namePart);
173
+ if (words && words !== namePart.toLowerCase())
174
+ parts.push(words);
141
175
  if (typeof a.description === "string" && a.description)
142
176
  parts.push(a.description);
143
177
  // Custom Metadata record field values: [{field,value}] | {field:value} | object.
@@ -173,6 +207,20 @@ export function buildEmbedText(label, qname, attributes) {
173
207
  }
174
208
  }
175
209
  }
210
+ // Structural attributes that make automation findable by WHAT it acts on:
211
+ // a trigger's object + DML events ("on Account before insert"), a Flow's
212
+ // process type ("AutoLaunchedFlow"/"Flow"). Gated by label — CustomField (and
213
+ // other nodes) also carry an `object` attribute (their parent SObject), and
214
+ // appending "on Account" to every field was pure noise in the embedding.
215
+ if (label === "ApexTrigger" && typeof a.object === "string" && a.object) {
216
+ const ev = Array.isArray(a.events)
217
+ ? a.events.filter((x) => typeof x === "string").join(" ")
218
+ : "";
219
+ parts.push(`on ${a.object}${ev ? ` ${ev}` : ""}`);
220
+ }
221
+ if (label === "Flow" && typeof a.processType === "string" && a.processType) {
222
+ parts.push(a.processType);
223
+ }
176
224
  return parts.join("\n");
177
225
  }
178
226
  function stringifyConfigVal(v) {
@@ -188,134 +236,6 @@ function stringifyConfigVal(v) {
188
236
  }
189
237
  return String(v);
190
238
  }
191
- /** Exported for tests — maps a RawMember to the registered parser's input shape. */
192
- export function adaptParserInput(ref, content) {
193
- switch (ref.memberType) {
194
- case "ApexClass": {
195
- const { body, metaXml } = unwrapApexEnvelope(content);
196
- return {
197
- type: "ApexClass",
198
- input: { className: ref.memberName, body, ...(metaXml ? { metaXml } : {}) },
199
- };
200
- }
201
- case "ApexTrigger": {
202
- const { body, metaXml } = unwrapApexEnvelope(content);
203
- return {
204
- type: "ApexTrigger",
205
- input: { triggerName: ref.memberName, body, ...(metaXml ? { metaXml } : {}) },
206
- };
207
- }
208
- case "LightningComponentBundle": {
209
- try {
210
- const parsed = JSON.parse(content || "{}");
211
- return {
212
- type: "LightningComponentBundle",
213
- input: { bundleName: parsed.bundleName ?? ref.memberName, files: parsed.files ?? {} },
214
- };
215
- }
216
- catch {
217
- return null;
218
- }
219
- }
220
- case "Flow":
221
- return { type: "Flow", input: { fullName: ref.memberName, xml: content } };
222
- case "CustomObject":
223
- return { type: "CustomObject", input: { apiName: ref.memberName, objectXml: content } };
224
- case "Profile":
225
- return { type: "Profile", input: { name: ref.memberName, xml: content } };
226
- case "PermissionSet":
227
- return { type: "PermissionSet", input: { name: ref.memberName, xml: content } };
228
- case "SharingRules":
229
- return { type: "SharingRules", input: { object: ref.memberName, xml: content } };
230
- case "NamedCredential":
231
- return { type: "NamedCredential", input: { name: ref.memberName, xml: content } };
232
- case "ExternalServiceRegistration":
233
- return { type: "ExternalServiceRegistration", input: { name: ref.memberName, xml: content } };
234
- case "OmniProcess":
235
- case "OmniUiCard":
236
- case "OmniDataTransform":
237
- case "OmniIntegrationProcedure": {
238
- let metadata = content;
239
- try {
240
- metadata = JSON.parse(content);
241
- }
242
- catch {
243
- /* keep raw */
244
- }
245
- return { type: ref.memberType, input: { name: ref.memberName, metadata } };
246
- }
247
- // The Vlocity runner emits the bare VlocityDataPackType as memberType
248
- // ("DataRaptor", "IntegrationProcedure", "OmniScript", "VlocityCard"),
249
- // but the four rich parsers register under "Vlocity"-prefixed type names
250
- // ("VlocityDataRaptor", …). Without this mapping the runner's members
251
- // never matched a case here and fell through to the opaque fallback —
252
- // shallow nodes with zero DR_/IP_/OS_ edges. Only "VlocityCard" happened
253
- // to align on both sides, which is why a real ingest produced VC edges
254
- // but no DataRaptor/IP/OmniScript lineage. The golden tests call the
255
- // parsers directly, so this runner→dispatch seam was never covered.
256
- // The legacy "Vlocity*"-prefixed keys are kept too in case any caller
257
- // (or a future filesystem source) emits them.
258
- case "DataRaptor":
259
- case "VlocityDataRaptor":
260
- case "IntegrationProcedure":
261
- case "VlocityIntegrationProcedure":
262
- case "OmniScript":
263
- case "VlocityOmniScript":
264
- case "VlocityCard": {
265
- let datapack = content;
266
- try {
267
- datapack = JSON.parse(content);
268
- }
269
- catch {
270
- /* keep raw */
271
- }
272
- return {
273
- type: VLOCITY_MEMBER_TO_PARSER[ref.memberType] ?? ref.memberType,
274
- input: { name: ref.memberName, datapack },
275
- };
276
- }
277
- default: {
278
- // Long-tail metadata types: route to a registered parser when one
279
- // exists (the 21 rule-based YAML parsers register under their raw
280
- // metadata type name, e.g. "Layout", "Dashboard"), otherwise fall
281
- // back to the opaque node parser so the member still becomes a
282
- // graph node. Before this fallback every generic-extractor member
283
- // was silently dropped here — extracted, logged as ✓, and never
284
- // merged — which left grant/reference edges dangling (e.g. 59k
285
- // GRANTS_TAB_ACCESS edges pointing at CustomTab nodes that were
286
- // never created).
287
- if (parserRegistry.for(ref.memberType)) {
288
- return { type: ref.memberType, input: genericRuleInput(ref.memberName, content) };
289
- }
290
- return {
291
- type: "OpaqueMetadata",
292
- input: { metadataType: ref.memberType, name: ref.memberName, raw: content },
293
- };
294
- }
295
- }
296
- }
297
- /**
298
- * Build the `{ name, xml, ...siblings }` input shape the rule-based parsers'
299
- * `xml-string` coercion expects. Filesystem sources hand us raw XML; the
300
- * live generic extractor hands us the JSON-serialized `metadata.read()`
301
- * object — whose keys mirror the parsed XML root, so they can be promoted
302
- * to sibling keys directly (coerceInput merges siblings into the record).
303
- */
304
- function genericRuleInput(name, content) {
305
- const s = (content ?? "").trimStart();
306
- if (s.startsWith("<"))
307
- return { name, xml: content };
308
- let parsed = {};
309
- try {
310
- const j = JSON.parse(s);
311
- if (j && typeof j === "object" && !Array.isArray(j))
312
- parsed = j;
313
- }
314
- catch {
315
- /* not JSON — leave record empty; the node still gets name + label */
316
- }
317
- return { xml: "", ...parsed, name };
318
- }
319
239
  export async function liveIngest(opts) {
320
240
  const logger = opts.logger ?? NOOP_LOG;
321
241
  // Load declarative rule parsers (idempotent).
@@ -352,28 +272,40 @@ export async function liveIngest(opts) {
352
272
  catch (e) {
353
273
  logger.warn("live-ingest: markSyncStarted failed", { err: e.message });
354
274
  }
275
+ // Opt-in profiling (SFGRAPH_INGEST_PROFILE=<file>); no-op otherwise.
276
+ // Created before the try so the finally can flush on failure too.
277
+ const profiler = createIngestProfiler();
278
+ // Embedding resources, owned here so the finally can release them on any path.
279
+ let embedQueue = null;
280
+ let ownedEmbedder = null;
281
+ let embedCache = null;
355
282
  // W1.5-08: the rest of the ingest runs inside this try so a thrown
356
283
  // exception still flips `sync_in_progress` back to 0 via markSyncFailed.
357
284
  // Per-resolver try/catch isolation inside bulkRetrieve / live-ingest is
358
285
  // preserved — this wrapper only catches exceptions that escape *all* of
359
286
  // those inner handlers (i.e. genuinely fatal failures).
360
287
  try {
361
- const caps = await probeCapabilities(resolved.conn);
288
+ const caps = opts.metadataSource ? OFFLINE_CAPS : await probeCapabilities(resolved.conn);
362
289
  logger.info("live-ingest: probed capabilities", { caps });
363
290
  // Discovery is also invoked implicitly inside bulkRetrieve, but logging the
364
291
  // type-count up-front gives operators a quick coverage signal.
365
- try {
366
- const { discoverMetadataTypes } = await import("../extractors/live-org/discovery.js");
367
- const discovered = await discoverMetadataTypes(resolved.conn, apiVersion);
368
- logger.info("live-ingest: discovered metadata types", { count: discovered.length });
369
- }
370
- catch (e) {
371
- logger.warn("live-ingest: metadata.describe failed", { err: e.message });
292
+ if (!opts.metadataSource) {
293
+ try {
294
+ const { discoverMetadataTypes } = await import("../extractors/live-org/discovery.js");
295
+ const discovered = await discoverMetadataTypes(resolved.conn, apiVersion);
296
+ logger.info("live-ingest: discovered metadata types", { count: discovered.length });
297
+ }
298
+ catch (e) {
299
+ logger.warn("live-ingest: metadata.describe failed", { err: e.message });
300
+ }
372
301
  }
373
302
  const existing = graph.getOrg(resolved.orgId);
374
303
  const requestedMode = opts.mode ?? "auto";
375
304
  let mode;
376
- if (requestedMode === "auto") {
305
+ if (opts.metadataSource) {
306
+ mode = "full";
307
+ }
308
+ else if (requestedMode === "auto") {
377
309
  mode = existing?.lastSyncedAt && caps.sourceTracking ? "incremental" : "full";
378
310
  }
379
311
  else {
@@ -390,6 +322,11 @@ export async function liveIngest(opts) {
390
322
  let membersProcessed = 0;
391
323
  let parseErrors = 0;
392
324
  let deletions = 0;
325
+ // Incremental detects changed/added members but cannot fetch their content
326
+ // yet, so it skips them. If we then advanced the watermark past them, the
327
+ // next incremental would start AFTER those changes and never see them —
328
+ // silent permanent data loss. Track the count so we can HOLD the watermark.
329
+ let incrementalUnfetched = 0;
393
330
  // Set in the full-sync branch if the bulkRetrieve stream itself throws.
394
331
  // Detect-deletions reads it post-fan-out to bail out instead of mass-
395
332
  // wiping nodes that were never visited due to the abort.
@@ -410,18 +347,125 @@ export async function liveIngest(opts) {
410
347
  // the legacy `${label}: ${reason}` strings from skipReport.skips into the
411
348
  // final LiveIngestResult.warnings array. See bulk-retrieve.ts WedgeCoordinator.
412
349
  const wedgeWarnings = [];
350
+ // Task 10 rebuild fast path. On a full ingest into an org whose graph is
351
+ // empty at start, run the fan-out inside the store's bulk-load window:
352
+ // deferred secondary indexes, synchronous=OFF, one transaction per 2,000
353
+ // members, and no per-member delete probes for keys not yet written (the
354
+ // store tracks what this run wrote, so repeats are still reconciled and
355
+ // the graph is identical to the slow path). SFGRAPH_DISABLE_FASTPATH=1
356
+ // forces the per-member path (used by the same-output test and gate).
357
+ const fastPathDisabled = process.env.SFGRAPH_DISABLE_FASTPATH === "1";
358
+ const graphEmptyAtStart = !fastPathDisabled &&
359
+ mode === "full" &&
360
+ opts.rebuild !== false &&
361
+ typeof graph.beginBulk === "function" &&
362
+ typeof graph.endBulk === "function" &&
363
+ typeof graph.isOrgEmpty === "function" &&
364
+ graph.isOrgEmpty(resolved.orgId);
365
+ // A vector store on its own connection would hit SQLITE_BUSY behind the
366
+ // held bulk transaction, so keep per-member commits in that case.
367
+ const vectorDb = opts.vectorStore?.db;
368
+ const graphDb = graph.db;
369
+ const sharedConnection = vectorDb === undefined || vectorDb === graphDb;
370
+ // Every other full ingest (a normal sync, a delta's merge) writes into a
371
+ // graph that MCP servers may be reading, so the bulk window's relaxed
372
+ // pragmas and dropped indexes are not an option. It still groups members
373
+ // into plain transactions (store.beginBatch: BEGIN IMMEDIATE, committed
374
+ // only between members, at most ~200 ms each), which removes most of the
375
+ // per-member commit cost. Same SQLITE_BUSY rule as the bulk window: a
376
+ // vector store on its own connection keeps per-member commits.
377
+ const batchWrites = !fastPathDisabled &&
378
+ !graphEmptyAtStart &&
379
+ mode === "full" &&
380
+ sharedConnection &&
381
+ typeof graph.beginBatch === "function" &&
382
+ typeof graph.endBatch === "function";
383
+ let bulkOpen = false;
384
+ let batchOpen = false;
385
+ let bulkFailure = null;
386
+ const openBulk = () => {
387
+ if (graphEmptyAtStart && !bulkOpen) {
388
+ graph.beginBulk?.({
389
+ freshOrgId: resolved.orgId,
390
+ ...(sharedConnection ? {} : { batchTransactions: false }),
391
+ });
392
+ bulkOpen = true;
393
+ }
394
+ else if (batchWrites && !batchOpen) {
395
+ try {
396
+ graph.beginBatch?.();
397
+ batchOpen = true;
398
+ }
399
+ catch (e) {
400
+ // e.g. the caller holds a transaction: keep per-member commits.
401
+ logger.debug("live-ingest: write batching unavailable", { err: e.message });
402
+ }
403
+ }
404
+ };
405
+ const closeBulk = () => {
406
+ if (batchOpen) {
407
+ batchOpen = false;
408
+ graph.endBatch?.();
409
+ }
410
+ if (!bulkOpen)
411
+ return;
412
+ bulkOpen = false;
413
+ graph.endBulk?.();
414
+ };
413
415
  const parseCtxBase = {
414
416
  orgId: resolved.orgId,
415
417
  parseTimestamp: new Date(now).toISOString(),
416
418
  namespace: null,
417
419
  logger,
418
420
  };
419
- const embedQueue = opts.vectorStore
420
- ? new EmbeddingQueue({
421
+ // Task 11a: embeddings run off the graph-ready path. Inference happens in
422
+ // a worker thread (compiled builds) or an injected embedder, with up to 4
423
+ // batches in flight to keep it fed. The queue is HELD until graph ready:
424
+ // texts buffer (bounded by backpressure, which still forces batches out)
425
+ // and no inference competes for CPU with the graph build — measured, an
426
+ // overlapping worker slowed fan-out by ~45%. A persistent text → vector
427
+ // cache makes --rebuild skip the model for unchanged texts. The org is flagged `embeddings_pending` until every
428
+ // vector is written, so find_similar can fall back to text search and the
429
+ // next ingest can fill whatever a no-wait / failed run left behind. The
430
+ // flag is set lazily, when the queue first has real vector work (a text
431
+ // past the unchanged check at dispatch, or live work abandoned), so a
432
+ // re-sync with nothing to embed keeps find_similar's vector leg on.
433
+ let embedError = null;
434
+ let wasEmbeddingsPending = false;
435
+ if (opts.vectorStore) {
436
+ const workerUrl = opts.embedder ? null : defaultEmbeddingWorkerUrl();
437
+ ownedEmbedder = opts.embedder ? null : workerUrl ? new EmbeddingPool({ workerUrl }) : null;
438
+ const embedder = opts.embedder ?? ownedEmbedder;
439
+ if (opts.embeddingCacheFile) {
440
+ try {
441
+ embedCache = EmbeddingCache.open(opts.embeddingCacheFile);
442
+ }
443
+ catch (e) {
444
+ logger.warn("live-ingest: embedding cache unavailable", { err: e.message });
445
+ }
446
+ }
447
+ wasEmbeddingsPending = graph.getEmbeddingStatus?.(resolved.orgId)?.pending ?? false;
448
+ const maxPendingChars = Number.parseInt(process.env.SFGRAPH_EMBED_MAX_PENDING_CHARS ?? "", 10);
449
+ embedQueue = new EmbeddingQueue({
421
450
  vectorStore: opts.vectorStore,
422
- onError: (err) => logger.warn("live-ingest: embedding batch failed", { err: err.message }),
423
- })
424
- : null;
451
+ hold: true,
452
+ ...(maxPendingChars > 0 ? { maxPendingChars } : {}),
453
+ onWork: () => {
454
+ if (!wasEmbeddingsPending)
455
+ graph.setEmbeddingsPending?.(resolved.orgId, true);
456
+ },
457
+ onCacheError: (err) => {
458
+ logger.warn("live-ingest: embedding cache write failed", { err: err.message });
459
+ },
460
+ ...(embedder ? { embed: (t) => embedder.embed(t), maxInFlight: 4 } : {}),
461
+ ...(embedCache ? { cache: embedCache } : {}),
462
+ onError: (err) => {
463
+ if (!embedError)
464
+ embedError = err;
465
+ logger.warn("live-ingest: embedding batch failed", { err: err.message });
466
+ },
467
+ });
468
+ }
425
469
  const handleParsed = (parsed) => {
426
470
  if (parsed.nodes.length) {
427
471
  graph.mergeNodes(parsed.nodes);
@@ -437,8 +481,29 @@ export async function liveIngest(opts) {
437
481
  bucket.add(qn);
438
482
  }
439
483
  }
440
- if (parsed.edges.length)
441
- graph.mergeEdges(parsed.edges);
484
+ // A parser's ParseResult is the COMPLETE authoritative outgoing-edge set
485
+ // for the member it parsed, so reconcile: prune any prior outgoing edge
486
+ // from these sources that the member no longer emits (fixes "immortal
487
+ // edges" — a SOQL/DML/CALLS that lingered after the code dropped it on a
488
+ // non-rebuild re-sync). Resolver post-passes (arity / overlap / reflection)
489
+ // re-add their cross-cutting edges afterward, so this is safe.
490
+ // N-5: a method the member still emits but that now has NO outgoing
491
+ // edge (its only call was removed) is not a source in `parsed.edges`,
492
+ // so it is named explicitly and its stale edges are pruned too.
493
+ const methodSrcs = [];
494
+ for (const n of parsed.nodes) {
495
+ if (n.label === "ApexMethod" || n.label === "TestMethod") {
496
+ methodSrcs.push(String(n.qualifiedName));
497
+ }
498
+ }
499
+ if (parsed.edges.length || methodSrcs.length) {
500
+ graph.mergeEdges(parsed.edges, {
501
+ reconcileSources: true,
502
+ ...(methodSrcs.length
503
+ ? { reconcileExtraSrcs: { orgId: resolved.orgId, qnames: methodSrcs } }
504
+ : {}),
505
+ });
506
+ }
442
507
  if (parsed.snippets?.length) {
443
508
  graph.transaction(() => {
444
509
  for (const s of parsed.snippets ?? []) {
@@ -446,52 +511,117 @@ export async function liveIngest(opts) {
446
511
  }
447
512
  });
448
513
  }
449
- if (embedQueue) {
514
+ // Fold the stored source snippet into the search text for code nodes so
515
+ // search matches on what the code DOES, not just its name/attrs. (The
516
+ // snippet text lives in parsed.snippets, not on the node.) Bounded to a
517
+ // few KB — MiniLM truncates to its token window anyway, and we keep the
518
+ // structured buildEmbedText prefix first so identity stays dominant. The
519
+ // SAME text feeds both the vector index and the FTS keyword index; FTS is
520
+ // populated regardless of embedQueue so it works as the embedder-down
521
+ // fallback leg of hybrid search.
522
+ if (parsed.nodes.length) {
523
+ const snippetByQname = new Map();
524
+ for (const s of parsed.snippets ?? []) {
525
+ snippetByQname.set(String(s.qualifiedName), s.sourceText);
526
+ }
450
527
  for (const n of parsed.nodes) {
451
- embedQueue.push({
452
- qname: String(n.qualifiedName),
453
- text: buildEmbedText(n.label, String(n.qualifiedName), n.attributes),
454
- orgId: String(n.orgId),
455
- label: n.label,
528
+ const qn = String(n.qualifiedName);
529
+ let text = buildEmbedText(n.label, qn, n.attributes);
530
+ const snippet = snippetByQname.get(qn);
531
+ if (snippet)
532
+ text += `\n${snippet.slice(0, 4000)}`;
533
+ graph.upsertNodeFts(n.orgId, n.qualifiedName, n.label, text);
534
+ if (embedQueue) {
535
+ embedQueue.push({ qname: qn, text, orgId: String(n.orgId), label: n.label });
536
+ }
537
+ }
538
+ }
539
+ };
540
+ // Purge a deleted node's vector so it stops surfacing as a phantom
541
+ // find_similar hit. The vec0 table lives in the VectorStore (not the graph
542
+ // store); feature-detect since lightweight sinks may not implement delete.
543
+ const purgeNodeVector = (qname) => {
544
+ const sink = opts.vectorStore;
545
+ if (sink && typeof sink.deleteNodeVector === "function") {
546
+ try {
547
+ sink.deleteNodeVector(resolved.orgId, qname);
548
+ }
549
+ catch (e) {
550
+ logger.warn("live-ingest: vector purge failed", {
551
+ qname: String(qname),
552
+ err: e.message,
456
553
  });
457
554
  }
458
555
  }
459
556
  };
460
557
  const debugProcess = process.env.SFGRAPH_DEBUG_INGEST === "1";
461
- const processOne = async (ref, content) => {
558
+ // Per-member timings, filled by applyMember (parse vs. store write) and
559
+ // consumed by the member loop. Reset on every call. These are shared
560
+ // closure state: applyMember must NOT be called concurrently.
561
+ let lastParseMs = 0;
562
+ let lastWriteMs = 0;
563
+ // Apply one member's parse outcome to the graph (or delete an obsolete
564
+ // member). Always on the main thread, in member order: the parse may have
565
+ // run in a worker (parsePool), the writes never do.
566
+ const applyMember = (ref, outcome) => {
462
567
  const qnameForLog = `${ref.memberType}:${ref.memberName}`;
568
+ lastParseMs = 0;
569
+ lastWriteMs = 0;
463
570
  if (ref.obsolete) {
464
- // Build the qualified name same way parsers would: best-effort by member name.
465
- const qname = asQualifiedName(`${ref.memberType}:${ref.memberName}`);
571
+ // Build the qname with the node's LABEL, not the raw SourceMember type:
572
+ // e.g. LightningComponentBundle is stored as `LWC:<name>`, so the old
573
+ // `${memberType}:${name}` never matched and LWC deletes were silent
574
+ // no-ops. Fall back to memberType when no mapping exists.
575
+ const label = MEMBER_TYPE_TO_NODE_LABEL[ref.memberType] ?? ref.memberType;
576
+ const qname = asQualifiedName(`${label}:${ref.memberName}`);
466
577
  if (debugProcess)
467
578
  console.log(`ingest: [trace] delete ← ${qnameForLog}`);
579
+ // Cascade to contained children (a class/trigger owns ApexMethod /
580
+ // TestMethod nodes via CONTAINS_METHOD). Deleting only the parent left
581
+ // the method nodes — and their edges/snippets/vectors — orphaned.
582
+ for (const e of graph.listEdgesFrom(resolved.orgId, qname, REL_TYPES.CONTAINS_METHOD)) {
583
+ const child = e.dstQualifiedName;
584
+ graph.deleteEdgesFor(resolved.orgId, child);
585
+ graph.deleteNode(resolved.orgId, child);
586
+ purgeNodeVector(child);
587
+ }
468
588
  graph.deleteEdgesFor(resolved.orgId, qname);
469
589
  graph.deleteNode(resolved.orgId, qname);
590
+ purgeNodeVector(qname);
470
591
  if (debugProcess)
471
592
  console.log(`ingest: [trace] delete ✓ ${qnameForLog}`);
472
593
  deletions += 1;
473
594
  return;
474
595
  }
475
- const adapted = adaptParserInput(ref, content);
476
- if (!adapted)
477
- return;
478
- const parser = parserRegistry.for(adapted.type);
479
- if (!parser)
596
+ // Building the parser input threw: surfaces to the member loop's catch.
597
+ if (outcome.kind === "error" && outcome.phase === "adapt")
598
+ throw new Error(outcome.message);
599
+ if (outcome.kind === "skip")
480
600
  return;
601
+ // Emitted when the result is applied (in member order); the parse itself
602
+ // may have run earlier in a worker.
603
+ if (debugProcess)
604
+ console.log(`ingest: [trace] parse ← ${qnameForLog}`);
605
+ lastParseMs = outcome.parseMs;
481
606
  try {
482
- const ctx = {
483
- ...parseCtxBase,
484
- sourceUri: ref.sourceUri,
485
- namespace: ref.namespace ?? null,
486
- };
487
- if (debugProcess)
488
- console.log(`ingest: [trace] parse ← ${qnameForLog}`);
489
- const result = await parser.parse(adapted.input, ctx);
607
+ if (outcome.kind === "error") {
608
+ const err = new Error(outcome.message);
609
+ if (outcome.stack)
610
+ err.stack = outcome.stack;
611
+ throw err;
612
+ }
613
+ const result = outcome.result;
490
614
  if (debugProcess)
491
615
  console.log(`ingest: [trace] parse ✓ ${qnameForLog} (nodes=${result.nodes.length} edges=${result.edges.length})`);
492
616
  if (debugProcess)
493
617
  console.log(`ingest: [trace] graph-merge ← ${qnameForLog}`);
494
- handleParsed(result);
618
+ const tWrite = performance.now();
619
+ try {
620
+ handleParsed(result);
621
+ }
622
+ finally {
623
+ lastWriteMs = performance.now() - tWrite;
624
+ }
495
625
  if (debugProcess)
496
626
  console.log(`ingest: [trace] graph-merge ✓ ${qnameForLog}`);
497
627
  membersProcessed += 1;
@@ -508,13 +638,161 @@ export async function liveIngest(opts) {
508
638
  }
509
639
  }
510
640
  };
641
+ // Task 11c: member rows (delta ingest's record of what each member owns)
642
+ // and the ghost sweep, on a full ingest of a metadataSource. The rows are
643
+ // cleared now and rewritten only once the ingest completes, so an
644
+ // interrupted run leaves no rows and the next delta falls back to a full
645
+ // rebuild. The ghost sweep deletes what a member owned last run that no
646
+ // member owns now (a deleted / renamed file), before the resolvers run.
647
+ if (opts.delta && (!opts.metadataSource || mode !== "full")) {
648
+ throw new Error("liveIngest: delta hooks need a metadataSource and mode 'full'");
649
+ }
650
+ const deltaHooks = opts.delta;
651
+ const priorRows = !deltaHooks &&
652
+ opts.metadataSource &&
653
+ mode === "full" &&
654
+ graph.listMemberRows &&
655
+ graph.replaceMemberRows
656
+ ? graph.listMemberRows(resolved.orgId)
657
+ : null;
658
+ if (priorRows && priorRows.length > 0)
659
+ graph.clearMemberRows?.(resolved.orgId);
660
+ const memberRows = priorRows ? new Map() : null;
661
+ const priorRowByKey = new Map((priorRows ?? []).map((r) => [r.key, r]));
662
+ const keptPrior = [];
663
+ // T15 N5-1: members quarantined by earlier runs (workers kept failing on
664
+ // that exact content) are not parsed again until their content changes.
665
+ const quarantinedKeys = new Set((priorRows ?? []).filter((r) => isQuarantinedRow(r)).map((r) => r.key));
666
+ const quarantinePreset = (m) => quarantinedKeys.has(m.ref.sourceUri) &&
667
+ isQuarantinedFor(priorRowByKey.get(m.ref.sourceUri), memberContentHash(m.content))
668
+ ? quarantinedOutcome()
669
+ : undefined;
670
+ const recordMemberRow = (member, outcome, errored) => {
671
+ if (!memberRows)
672
+ return;
673
+ const key = member.ref.sourceUri;
674
+ const prior = priorRowByKey.get(key);
675
+ const owned = outcome.kind === "parsed" ? ownedQnames(outcome.result) : [];
676
+ if (errored || (isParseFailureOnly(owned) && hasGoodPriorOwned(prior))) {
677
+ // Keep what it owned (its nodes are not re-emitted, nor swept). A
678
+ // member that parsed to ParseError only (N2-1) or whose parse threw
679
+ // records the hash of its broken content and is skipped until it
680
+ // changes; one whose merge failed is retried by every delta.
681
+ if (hasGoodPriorOwned(prior))
682
+ keptPrior.push(key);
683
+ memberRows.set(key, {
684
+ key,
685
+ ...memberFailureStamp(member, outcome, errored, prior),
686
+ owned: [...new Set([...(prior?.owned ?? []), ...owned])],
687
+ });
688
+ return;
689
+ }
690
+ memberRows.set(key, {
691
+ key,
692
+ fingerprint: member.fingerprint ?? "",
693
+ hash: memberContentHash(member.content),
694
+ owned,
695
+ });
696
+ };
697
+ const finishMemberRows = () => {
698
+ if (!memberRows || !priorRows)
699
+ return;
700
+ if (streamAborted) {
701
+ memberRows.clear();
702
+ return;
703
+ }
704
+ if (priorRows.length === 0)
705
+ return;
706
+ // Members the source indexed but could not load (unreadable, malformed)
707
+ // keep their previous graph and row (retried by the next delta).
708
+ const unloaded = opts.metadataSource?.unloadedKeys?.();
709
+ if (unloaded) {
710
+ for (const r of priorRows) {
711
+ if (!unloaded.has(r.key) || memberRows.has(r.key))
712
+ continue;
713
+ memberRows.set(r.key, { ...r, fingerprint: "" });
714
+ keptPrior.push(r.key);
715
+ }
716
+ }
717
+ if (keptPrior.length > 0) {
718
+ wedgeWarnings.push(`wedge:ingest:kept-prior:members=${keptPrior.length}`);
719
+ logger.warn("live-ingest: unreadable / unparseable members keep their previous graph", {
720
+ members: keptPrior.slice(0, 20),
721
+ });
722
+ }
723
+ if (memberRows.size === 0) {
724
+ // Same guard as detect-deletions' empty-stream refusal: a source that
725
+ // yielded no members at all (wrong path, unreadable tree) must not
726
+ // wipe the graph. No rows are written, so the next delta rebuilds.
727
+ wedgeWarnings.push(`wedge:ghost-sweep:refuse:reason=empty-stream:priorMembers=${priorRows.length}`);
728
+ logger.warn("live-ingest: ghost sweep refused (the source yielded no members)", {
729
+ priorMembers: priorRows.length,
730
+ });
731
+ return;
732
+ }
733
+ // Qnames match case-insensitively (the store's NOCASE): `ApexClass:Util`
734
+ // re-emitted as `ApexClass:UTIL` is the same node, not a ghost.
735
+ const ownedNow = new Set();
736
+ for (const r of memberRows.values())
737
+ for (const q of r.owned)
738
+ ownedNow.add(q.toLowerCase());
739
+ const ghosts = [];
740
+ for (const r of priorRows) {
741
+ for (const q of r.owned)
742
+ if (!ownedNow.has(q.toLowerCase()))
743
+ ghosts.push(q);
744
+ }
745
+ if (ghosts.length === 0)
746
+ return;
747
+ let removed = 0;
748
+ graph.transaction(() => {
749
+ graph.deleteEdgesFrom?.(resolved.orgId, ghosts);
750
+ graph.deleteReflectionEdges?.(resolved.orgId, { dsts: ghosts });
751
+ for (const q of new Set(ghosts)) {
752
+ const qn = asQualifiedName(q);
753
+ if (!graph.getNode(resolved.orgId, qn))
754
+ continue;
755
+ graph.deleteNode(resolved.orgId, qn);
756
+ purgeNodeVector(qn);
757
+ removed += 1;
758
+ }
759
+ });
760
+ deletions += removed;
761
+ if (removed > 0)
762
+ logger.info("live-ingest: ghost sweep removed nodes of vanished members", { removed });
763
+ };
764
+ // Serial parse + apply (incremental deletions).
765
+ const processOne = async (ref, content) => {
766
+ const outcome = ref.obsolete
767
+ ? { kind: "skip", parseMs: 0 }
768
+ : await parseMember(ref, content, parseCtxBase, logger);
769
+ applyMember(ref, outcome);
770
+ };
511
771
  if (mode === "incremental") {
512
772
  const sinceIso = existing?.lastSyncedAt
513
773
  ? new Date(existing.lastSyncedAt).toISOString()
514
774
  : new Date(now - 24 * 3600 * 1000).toISOString();
775
+ // Incremental applies DELETIONS (obsolete members need no content) but
776
+ // does NOT re-parse changed/added members: their content is not fetched
777
+ // here, and calling processOne(ref, "") would overwrite real node
778
+ // attributes with empty-parse garbage and emit no edges — actively
779
+ // degrading the graph. Until per-member content fetch lands, changed
780
+ // members are counted and the user is told to run a full ingest to
781
+ // refresh them. (Deletions are still valuable and safe.)
782
+ let changedNotApplied = 0;
515
783
  for await (const ref of iterChanges(resolved.conn, resolved.orgId, sinceIso)) {
516
- // For incremental, content is best fetched on-demand; for deletions we skip content.
517
- await processOne(ref, "");
784
+ if (ref.obsolete) {
785
+ await processOne(ref, "");
786
+ }
787
+ else {
788
+ changedNotApplied += 1;
789
+ }
790
+ }
791
+ incrementalUnfetched = changedNotApplied;
792
+ if (changedNotApplied > 0) {
793
+ const msg = `incremental: ${changedNotApplied} changed/added member(s) detected but NOT refreshed (content fetch not implemented for incremental). The sync watermark is being HELD so the next run re-detects them. Run \`sfgraph ingest --org ${resolved.alias} --rebuild\` (or --mode full) to capture them.`;
794
+ logger.warn(msg);
795
+ wedgeWarnings.push(`incremental:contentNotFetched:count=${changedNotApplied}`);
518
796
  }
519
797
  }
520
798
  else {
@@ -537,7 +815,8 @@ export async function liveIngest(opts) {
537
815
  // different edge tables rather than competing for the same row, but
538
816
  // the pre-fan-out ordering preserves the "parsed wins" guarantee for
539
817
  // the (rare) case where a parser does emit REFERENCES.
540
- if (!opts.disableMcdBaseline) {
818
+ openBulk();
819
+ if (!opts.disableMcdBaseline && !opts.metadataSource) {
541
820
  try {
542
821
  const { runMcdBaseline } = await import("../extractors/live-org/extractors/mcd-baseline.js");
543
822
  const mcdCtx = {
@@ -614,7 +893,7 @@ export async function liveIngest(opts) {
614
893
  // benefit. The probe's job is observability, not control flow.
615
894
  // Disable via SFGRAPH_NO_LIVENESS_PROBE=1 for hermetic test runs
616
895
  // where the mock connection has no identity() implementation.
617
- if (process.env.SFGRAPH_NO_LIVENESS_PROBE !== "1") {
896
+ if (process.env.SFGRAPH_NO_LIVENESS_PROBE !== "1" && !opts.metadataSource) {
618
897
  livenessProbe = startLivenessProbe(resolved.conn);
619
898
  }
620
899
  // Wall-clock heartbeat — always on. Without this, silent phases (where
@@ -667,6 +946,17 @@ export async function liveIngest(opts) {
667
946
  console.error(`ingest: [debug] received ${sig} after ${Math.round((Date.now() - fanOutStart) / 1000)}s — processed=${progressCount} lastSource=${lastMemberLabel}`);
668
947
  console.error(new Error(`signal:${sig}`).stack);
669
948
  process.exitCode = 130;
949
+ // rel-08: a breadcrumb only — never swallow the signal. Drop the
950
+ // debug handlers; if nothing else handles it (an embedding host
951
+ // or the CLI would), re-raise so the default action terminates.
952
+ // Review minor 12: on the library path the default action kills
953
+ // the process without the finally blocks, so the ingest lock file
954
+ // and sync_in_progress stay behind; the next run reclaims both
955
+ // through the dead-owner (stale pid) check (rel-02).
956
+ for (const h of installedSignalHandlers.splice(0))
957
+ process.off(h.sig, h.fn);
958
+ if (process.listenerCount(sig) === 0)
959
+ process.kill(process.pid, sig);
670
960
  };
671
961
  const onUsr2 = () => {
672
962
  const mem = process.memoryUsage();
@@ -679,21 +969,65 @@ export async function liveIngest(opts) {
679
969
  process.on(h.sig, h.fn);
680
970
  }
681
971
  try {
682
- for await (const member of bulkRetrieve(resolved.conn, caps, resolved.orgId, {
683
- skipReport,
684
- warnings: wedgeWarnings,
685
- ...(opts.onlyLabels ? { onlyLabels: opts.onlyLabels } : {}),
686
- // The bulk-retrieve flag name follows the same convention as
687
- // the bulk-retrieve's other opts; semantically it's "do the
688
- // retrieve()" which is now on by default. Caller-side disable
689
- // routes through this same boolean inverted.
690
- ...(opts.disableOmnistudioRetrieve ? {} : { enableOmnistudioRetrieve: true }),
691
- // jsforce attaches the version it negotiated on conn.version; fall
692
- // back to a sensible recent release if absent (mocks, etc.)
693
- apiVersion: resolved.conn.version ?? "60.0",
694
- })) {
972
+ const memberStream = deltaHooks
973
+ ? deltaHooks.members
974
+ : opts.metadataSource
975
+ ? opts.metadataSource.iter()
976
+ : bulkRetrieve(resolved.conn, caps, resolved.orgId, {
977
+ skipReport,
978
+ warnings: wedgeWarnings,
979
+ ...(opts.onlyLabels ? { onlyLabels: opts.onlyLabels } : {}),
980
+ ...(opts.explicitOnlyLabels ? { explicitOnlyLabels: true } : {}),
981
+ // The bulk-retrieve flag name follows the same convention as
982
+ // the bulk-retrieve's other opts; semantically it's "do the
983
+ // retrieve()" which is now on by default. Caller-side disable
984
+ // routes through this same boolean inverted.
985
+ ...(opts.disableOmnistudioRetrieve ? {} : { enableOmnistudioRetrieve: true }),
986
+ // jsforce attaches the version it negotiated on conn.version; fall
987
+ // back to a sensible recent release if absent (mocks, etc.)
988
+ apiVersion: resolved.conn.version ?? "60.0",
989
+ });
990
+ const tFanout = performance.now();
991
+ // Task 11b: parse in worker threads (SFGRAPH_PARSE_WORKERS, default
992
+ // min(4, availableParallelism - 1); 0 = main thread), apply in member
993
+ // order here.
994
+ const parseStats = opts.parsePool?.stats ?? {
995
+ workers: 0,
996
+ pooled: 0,
997
+ inProcess: 0,
998
+ fallbacks: 0,
999
+ crashes: 0,
1000
+ oomFallbacks: 0,
1001
+ };
1002
+ const parsed = parsePool(memberStream, {
1003
+ orgId: parseCtxBase.orgId,
1004
+ parseTimestamp: parseCtxBase.parseTimestamp,
1005
+ logger,
1006
+ workers: opts.parsePool?.workers ?? resolveParseWorkers(),
1007
+ ...(opts.parsePool?.workerUrl !== undefined
1008
+ ? { workerUrl: opts.parsePool.workerUrl }
1009
+ : {}),
1010
+ ...(opts.parsePool?.minMembers !== undefined
1011
+ ? { minMembers: opts.parsePool.minMembers }
1012
+ : {}),
1013
+ stats: parseStats,
1014
+ ...(quarantinedKeys.size > 0 ? { preset: quarantinePreset } : {}),
1015
+ });
1016
+ for await (const { member, outcome } of parsed) {
1017
+ const errorsBefore = parseErrors;
1018
+ if (batchOpen)
1019
+ graph.batchMemberStart?.();
695
1020
  try {
696
- await processOne(member.ref, member.content);
1021
+ applyMember(member.ref, outcome);
1022
+ if (profiler.enabled) {
1023
+ profiler.member({
1024
+ qname: `${member.ref.memberType}:${member.ref.memberName}`,
1025
+ label: member.ref.memberType,
1026
+ bytes: member.content.length,
1027
+ parseMs: lastParseMs,
1028
+ writeMs: lastWriteMs,
1029
+ });
1030
+ }
697
1031
  }
698
1032
  catch (e) {
699
1033
  parseErrors += 1;
@@ -702,6 +1036,33 @@ export async function liveIngest(opts) {
702
1036
  error: e.message,
703
1037
  });
704
1038
  }
1039
+ // Task 11c: member rows (what each member owns) for delta ingest.
1040
+ const errored = outcome.kind === "error" || parseErrors > errorsBefore;
1041
+ if (deltaHooks)
1042
+ deltaHooks.onMember(member, outcome, errored);
1043
+ else if (memberRows && member.fingerprint !== undefined) {
1044
+ recordMemberRow(member, outcome, errored);
1045
+ }
1046
+ if (bulkOpen || batchOpen) {
1047
+ // Outside the per-member catch: if SQLite rolled back the bulk
1048
+ // transaction (SQLITE_FULL / IOERR / NOMEM), up to 2,000 earlier
1049
+ // members are gone, so the ingest must fail, not count one error.
1050
+ // The same holds for a live-graph batch.
1051
+ try {
1052
+ if (bulkOpen)
1053
+ graph.bulkMemberDone?.();
1054
+ else
1055
+ graph.batchMemberDone?.();
1056
+ }
1057
+ catch (e) {
1058
+ bulkFailure = e;
1059
+ break;
1060
+ }
1061
+ }
1062
+ // Backpressure: past the queued-text bound, wait for forced
1063
+ // batches to drain (the only inference during fan-out).
1064
+ if (embedQueue?.overCapacity)
1065
+ await embedQueue.waitForCapacity();
705
1066
  progressCount += 1;
706
1067
  lastActivityAt = Date.now();
707
1068
  lastMemberLabel = `${member.ref.memberType}:${member.ref.memberName}`;
@@ -719,6 +1080,9 @@ export async function liveIngest(opts) {
719
1080
  gs.checkpoint();
720
1081
  }
721
1082
  }
1083
+ profiler.phase("fanout", performance.now() - tFanout);
1084
+ // Always printed (serial too) so bench runs can record the counts.
1085
+ console.log(`ingest: parse pool: ${parseStats.workers} workers, ${parseStats.pooled} parsed in workers, ${parseStats.inProcess} on main (${parseStats.fallbacks} fallbacks, ${parseStats.crashes} worker crashes, ${parseStats.oomFallbacks ?? 0} heap-cap re-parses)`);
722
1086
  console.log(`ingest: fan-out complete (${progressCount} members in ${Math.round((Date.now() - fanOutStart) / 1000)}s)`);
723
1087
  const gs = graph;
724
1088
  if (typeof gs.checkpoint === "function")
@@ -731,6 +1095,8 @@ export async function liveIngest(opts) {
731
1095
  logger.warn("live-ingest: bulkRetrieve stream aborted", {
732
1096
  error: e.message,
733
1097
  });
1098
+ // Never a silent partial ingest: the abort is in the result's warnings.
1099
+ wedgeWarnings.push(`stream:aborted:${String(e.message).slice(0, 200)}`);
734
1100
  }
735
1101
  }
736
1102
  finally {
@@ -741,6 +1107,31 @@ export async function liveIngest(opts) {
741
1107
  livenessProbe?.stop();
742
1108
  for (const h of installedSignalHandlers)
743
1109
  process.off(h.sig, h.fn);
1110
+ // Commit the last bulk batch and rebuild the deferred indexes before
1111
+ // any post-pass reads the graph.
1112
+ const tEndBulk = performance.now();
1113
+ closeBulk();
1114
+ if (graphEmptyAtStart)
1115
+ profiler.phase("endBulk", performance.now() - tEndBulk);
1116
+ }
1117
+ if (bulkFailure)
1118
+ throw bulkFailure;
1119
+ if (deltaHooks) {
1120
+ // A partial stream must not be finalized as a delta: fail, keeping
1121
+ // the pending marker, so the next delta replays it.
1122
+ if (streamAborted)
1123
+ throw new Error("delta: member stream aborted");
1124
+ deltaHooks.afterMerge();
1125
+ }
1126
+ else if (memberRows) {
1127
+ finishMemberRows();
1128
+ }
1129
+ // A scoped run (auto-retry pass, --retry-skipped, --only) re-ran only
1130
+ // `onlyLabels`: carry the previous report's entries for every OTHER
1131
+ // label forward, so unreadable / insufficient_access entries it did
1132
+ // not touch stay in the report, the summary and the warnings (I2).
1133
+ if (opts.onlyLabels && opts.skipReportPath) {
1134
+ skipReport.skips.push(...carriedOverSkips(opts.skipReportPath, resolved.orgId, opts.onlyLabels));
744
1135
  }
745
1136
  // End-of-run skip summary. Grouped by category so the remediation is
746
1137
  // targeted to the specific class of failure.
@@ -762,19 +1153,16 @@ export async function liveIngest(opts) {
762
1153
  }
763
1154
  }
764
1155
  }
765
- if (embedQueue) {
766
- try {
767
- await embedQueue.drain();
768
- }
769
- catch (e) {
770
- logger.warn("live-ingest: embed drain failed", { err: e.message });
771
- }
772
- }
1156
+ // Mark the end of input (the held queue still runs nothing until graph ready).
1157
+ embedQueue?.startDrain();
773
1158
  // Full-sync deletion detection: compute previously-known minus touched and
774
1159
  // delete the difference. Skipped on incremental (SourceMember handles it),
775
1160
  // skipped if any parse error occurred this run (avoid mass-wipe on
776
1161
  // transient SF errors).
777
- if (opts.detectDeletions && mode === "full") {
1162
+ // Fast path: an org that was empty at start has no stale qnames — every
1163
+ // persisted node was touched by this run — so the sweep (and its
1164
+ // deleteEdgesFor calls) would be a no-op; skip it.
1165
+ if (opts.detectDeletions && !opts.metadataSource && mode === "full" && !graphEmptyAtStart) {
778
1166
  if (streamAborted) {
779
1167
  logger.warn("live-ingest: detect-deletions skipped because bulkRetrieve stream aborted — touchedQnames is incomplete and a full deletion sweep would wrongly wipe untouched-but-still-present nodes");
780
1168
  }
@@ -790,7 +1178,18 @@ export async function liveIngest(opts) {
790
1178
  // compounds with the W1.5-01/02 wedge cascade). Now we evaluate the
791
1179
  // guard per label and refuse when the implied drop is suspicious.
792
1180
  const maxDropRatio = resolveMaxDropRatio(process.env.SFGRAPH_DETECT_DELETIONS_MAX_DROP_RATIO);
793
- const labels = graph.listAllLabels();
1181
+ // Task 11c: a node from a source this run skipped (or carried a
1182
+ // skip for) is never "stale" — the source touched nothing.
1183
+ const protection = skipProtection(skipReport.skips);
1184
+ if (protection.refuseAll) {
1185
+ const warning = `wedge:detect-deletions:refuse:label=*:reason=skipped-source:skips=${protection.unknownLabels.join(",")}`;
1186
+ wedgeWarnings.push(warning);
1187
+ logger.warn("live-ingest: detect-deletions refused (a skipped source has no type mapping)", {
1188
+ skips: protection.unknownLabels,
1189
+ });
1190
+ }
1191
+ const labels = protection.refuseAll ? [] : graph.listAllLabels();
1192
+ let protectedCount = 0;
794
1193
  for (const label of labels) {
795
1194
  const priorCount = graph.countNodesByLabel(resolved.orgId, label);
796
1195
  const touchedCount = touchedQnamesByLabel.get(label)?.size ?? 0;
@@ -818,8 +1217,13 @@ export async function liveIngest(opts) {
818
1217
  const q = String(node.qualifiedName);
819
1218
  if (touchedSet?.has(q))
820
1219
  continue;
1220
+ if (isSkipProtected(protection, node)) {
1221
+ protectedCount += 1;
1222
+ continue;
1223
+ }
821
1224
  graph.deleteEdgesFor(resolved.orgId, asQualifiedName(q));
822
1225
  graph.deleteNode(resolved.orgId, asQualifiedName(q));
1226
+ purgeNodeVector(asQualifiedName(q));
823
1227
  deletions += 1;
824
1228
  labelDeletions += 1;
825
1229
  }
@@ -830,12 +1234,50 @@ export async function liveIngest(opts) {
830
1234
  });
831
1235
  }
832
1236
  }
1237
+ if (protectedCount > 0) {
1238
+ logger.info("live-ingest: detect-deletions kept nodes of skipped sources", {
1239
+ count: protectedCount,
1240
+ });
1241
+ }
833
1242
  }
834
1243
  catch (e) {
835
1244
  logger.warn("live-ingest: detect-deletions failed", { err: e.message });
836
1245
  }
837
1246
  }
838
1247
  }
1248
+ // Backfill: an earlier run returned before its vectors were all written
1249
+ // (--no-wait-embeddings, a worker crash, a kill). Every embedded text is
1250
+ // also stored verbatim as the node's FTS body, so re-queue the docs this
1251
+ // run did not touch whose stored vector is missing or stale.
1252
+ let backfilled = 0;
1253
+ if (embedQueue && wasEmbeddingsPending && graph.listFtsDocs) {
1254
+ const sink = opts.vectorStore;
1255
+ try {
1256
+ for (const doc of graph.listFtsDocs(resolved.orgId)) {
1257
+ if (touchedQnames.has(doc.qname))
1258
+ continue;
1259
+ const stored = sink?.getContentHash?.(resolved.orgId, asQualifiedName(doc.qname));
1260
+ if (stored && stored === hashEmbedText(doc.body))
1261
+ continue;
1262
+ embedQueue.push({
1263
+ qname: doc.qname,
1264
+ text: doc.body,
1265
+ orgId: String(resolved.orgId),
1266
+ label: doc.label,
1267
+ });
1268
+ backfilled += 1;
1269
+ if (embedQueue.overCapacity)
1270
+ await embedQueue.waitForCapacity();
1271
+ }
1272
+ }
1273
+ catch (e) {
1274
+ logger.warn("live-ingest: embedding backfill failed", { err: e.message });
1275
+ }
1276
+ if (backfilled > 0) {
1277
+ logger.info("live-ingest: re-queued pending embeddings", { backfilled });
1278
+ }
1279
+ embedQueue.startDrain();
1280
+ }
839
1281
  // -----------------------------------------------------------------------
840
1282
  // Post-merge resolver passes. Each step is isolated in try/catch so a
841
1283
  // single resolver bug never breaks ingest — it just reports zero work done.
@@ -843,14 +1285,30 @@ export async function liveIngest(opts) {
843
1285
  let crossFlavorEdges = 0;
844
1286
  let arityResolved = 0;
845
1287
  let flowMethodsResolved = 0;
1288
+ let vlocityApexResult;
1289
+ let drRelationshipsResult;
846
1290
  let danglingEdges = 0;
847
1291
  let overlapResult = { matched: 0, diverged: 0, empty: 0, annotated: 0 };
848
1292
  let reflectionEdges = 0;
1293
+ // T15 I-2: post-merge steps that threw. A full ingest only warns; a delta
1294
+ // must not finalize (see below).
1295
+ const postFailures = [];
849
1296
  // Synth a ParseContext for post-passes that need to mint edges/nodes.
850
1297
  const postCtx = {
851
1298
  ...parseCtxBase,
852
1299
  sourceUri: "post-merge://resolver",
853
1300
  };
1301
+ // review I4: re-target Aura `<c:name>` embeds at the bundles that exist.
1302
+ try {
1303
+ const auraEmbeds = resolveAuraEmbeds(graph, resolved.orgId);
1304
+ if (auraEmbeds.retargeted > 0) {
1305
+ logger.info("live-ingest: aura embed resolver re-targeted embeds", { ...auraEmbeds });
1306
+ }
1307
+ }
1308
+ catch (e) {
1309
+ postFailures.push("aura embed resolver");
1310
+ logger.warn("live-ingest: aura embed resolver failed", { err: e.message });
1311
+ }
854
1312
  if (!opts.disableCrossFlavor) {
855
1313
  try {
856
1314
  crossFlavorEdges = resolveCrossFlavor(graph, {
@@ -865,6 +1323,7 @@ export async function liveIngest(opts) {
865
1323
  }
866
1324
  }
867
1325
  catch (e) {
1326
+ postFailures.push("cross-flavor resolver");
868
1327
  logger.warn("live-ingest: cross-flavor resolver failed", { err: e.message });
869
1328
  }
870
1329
  }
@@ -889,12 +1348,14 @@ export async function liveIngest(opts) {
889
1348
  }
890
1349
  }
891
1350
  catch (e) {
1351
+ postFailures.push("omnistudio overlap detector");
892
1352
  logger.warn("live-ingest: omnistudio overlap detector failed", {
893
1353
  err: e.message,
894
1354
  });
895
1355
  }
896
1356
  }
897
1357
  if (!opts.disableFlowInvocableResolve) {
1358
+ const tPhase = performance.now();
898
1359
  try {
899
1360
  const flowResult = resolveFlowApexMethods(graph, resolved.orgId, postCtx);
900
1361
  flowMethodsResolved = flowResult.resolved;
@@ -908,14 +1369,134 @@ export async function liveIngest(opts) {
908
1369
  }
909
1370
  }
910
1371
  catch (e) {
1372
+ postFailures.push("flow→apex resolver");
911
1373
  logger.warn("live-ingest: flow→apex resolver failed", { err: e.message });
912
1374
  }
1375
+ profiler.phase("resolver:flow-apex", performance.now() - tPhase);
1376
+ }
1377
+ if (!opts.disableVlocityApexResolve) {
1378
+ const tPhase = performance.now();
1379
+ try {
1380
+ const { resolveVlocityApex } = await import("../parsers/vlocity/apex-resolver.js");
1381
+ vlocityApexResult = resolveVlocityApex(graph, resolved.orgId, postCtx);
1382
+ if (vlocityApexResult.scanned > 0)
1383
+ logger.info("live-ingest: vlocity→apex resolver", vlocityApexResult);
1384
+ }
1385
+ catch (e) {
1386
+ postFailures.push("vlocity-apex-resolver");
1387
+ logger.warn(`vlocity-apex-resolver:failed:${e.message}`);
1388
+ wedgeWarnings.push(`vlocity-apex-resolver:failed:${e.message}`);
1389
+ }
1390
+ profiler.phase("resolver:vlocity-apex", performance.now() - tPhase);
1391
+ }
1392
+ if (!opts.disableDrRelationshipResolve) {
1393
+ const tPhase = performance.now();
1394
+ try {
1395
+ const { resolveDataRaptorRelationships } = await import("../parsers/vlocity/dr-relationship-resolver.js");
1396
+ drRelationshipsResult = resolveDataRaptorRelationships(graph, resolved.orgId, postCtx);
1397
+ if (drRelationshipsResult.scanned > 0)
1398
+ logger.info("live-ingest: dataraptor relationship-path resolver", drRelationshipsResult);
1399
+ }
1400
+ catch (e) {
1401
+ postFailures.push("dr-relationship-resolver");
1402
+ logger.warn(`dr-relationship-resolver:failed:${e.message}`);
1403
+ wedgeWarnings.push(`dr-relationship-resolver:failed:${e.message}`);
1404
+ }
1405
+ profiler.phase("resolver:dr-relationship", performance.now() - tPhase);
1406
+ }
1407
+ if (!opts.disableFlowRelationshipResolve) {
1408
+ const tPhase = performance.now();
1409
+ try {
1410
+ const { resolveFlowRelationshipPaths } = await import("../parsers/flow/relationship-resolver.js");
1411
+ const fr = resolveFlowRelationshipPaths(graph, resolved.orgId, postCtx);
1412
+ if (fr.scanned > 0)
1413
+ logger.info("live-ingest: flow relationship-path resolver", { ...fr });
1414
+ }
1415
+ catch (e) {
1416
+ postFailures.push("flow-relationship-resolver");
1417
+ logger.warn(`flow-relationship-resolver:failed:${e.message}`);
1418
+ wedgeWarnings.push(`flow-relationship-resolver:failed:${e.message}`);
1419
+ }
1420
+ profiler.phase("resolver:flow-relationship", performance.now() - tPhase);
1421
+ }
1422
+ if (!opts.disableLwcFieldKeyResolve) {
1423
+ const tPhase = performance.now();
1424
+ try {
1425
+ const { resolveLwcFieldKeys } = await import("../parsers/lwc/field-key-resolver.js");
1426
+ const r = resolveLwcFieldKeys(graph, resolved.orgId, postCtx);
1427
+ if (r.scanned > 0)
1428
+ logger.info("live-ingest: lwc field-key resolver", { ...r });
1429
+ }
1430
+ catch (e) {
1431
+ postFailures.push("lwc-field-key-resolver");
1432
+ logger.warn(`lwc-field-key-resolver:failed:${e.message}`);
1433
+ wedgeWarnings.push(`lwc-field-key-resolver:failed:${e.message}`);
1434
+ }
1435
+ profiler.phase("resolver:lwc-field-key", performance.now() - tPhase);
1436
+ }
1437
+ if (!opts.disableVlocityNameMatchResolve) {
1438
+ const tPhase = performance.now();
1439
+ try {
1440
+ const { resolveVlocityNameMatches } = await import("../parsers/vlocity/name-match-resolver.js");
1441
+ const nm = resolveVlocityNameMatches(graph, resolved.orgId, postCtx);
1442
+ if (nm.scanned > 0)
1443
+ logger.info("live-ingest: vlocity name-match resolver", { ...nm });
1444
+ }
1445
+ catch (e) {
1446
+ postFailures.push("vlocity-name-match-resolver");
1447
+ logger.warn(`vlocity-name-match-resolver:failed:${e.message}`);
1448
+ wedgeWarnings.push(`vlocity-name-match-resolver:failed:${e.message}`);
1449
+ }
1450
+ profiler.phase("resolver:vlocity-name-match", performance.now() - tPhase);
1451
+ }
1452
+ if (!opts.disableApexRefResolve) {
1453
+ const tPhase = performance.now();
1454
+ try {
1455
+ const { resolveApexReferences } = await import("../parsers/apex/ref-resolver.js");
1456
+ const { apexRefNoWorkResult } = await import("./resolver-gates.js");
1457
+ // Skip its whole-graph reads when it provably has no input and no
1458
+ // earlier output to prune (same result object it would return).
1459
+ const ar = apexRefNoWorkResult(graph, resolved.orgId) ??
1460
+ resolveApexReferences(graph, resolved.orgId, postCtx);
1461
+ if (ar.edgesEmitted > 0 || ar.pathsUnresolved > 0 || ar.dynamicSoqlFieldsSkipped > 0)
1462
+ logger.info("live-ingest: apex ref resolver", { ...ar });
1463
+ }
1464
+ catch (e) {
1465
+ postFailures.push("apex-ref-resolver");
1466
+ logger.warn(`apex-ref-resolver:failed:${e.message}`);
1467
+ wedgeWarnings.push(`apex-ref-resolver:failed:${e.message}`);
1468
+ }
1469
+ profiler.phase("resolver:apex-ref", performance.now() - tPhase);
1470
+ }
1471
+ // `ApexClass:X` references to an interface X (no class X): move them onto
1472
+ // `ApexInterface:X`. Before arity, which then sees interface method calls
1473
+ // under their real owner.
1474
+ let interfaceRefsRetargeted = 0;
1475
+ if (!opts.disableInterfaceRetarget) {
1476
+ const tPhase = performance.now();
1477
+ try {
1478
+ const names = deltaHooks?.retargetInterfaceNames();
1479
+ interfaceRefsRetargeted = retargetApexInterfaceRefs(graph, resolved.orgId, names ? { interfaceNames: names } : {});
1480
+ if (interfaceRefsRetargeted > 0) {
1481
+ logger.info("live-ingest: apex interface references retargeted", {
1482
+ interfaceRefsRetargeted,
1483
+ });
1484
+ }
1485
+ }
1486
+ catch (e) {
1487
+ postFailures.push("apex interface retarget");
1488
+ logger.warn("live-ingest: apex interface retarget failed", { err: e.message });
1489
+ }
1490
+ profiler.phase("resolver:interface-retarget", performance.now() - tPhase);
913
1491
  }
914
1492
  if (!opts.disableArityResolve) {
1493
+ const tPhase = performance.now();
915
1494
  try {
1495
+ const scope = deltaHooks?.arityScope();
916
1496
  const arityResult = resolveApexMethodArity(graph, {
917
1497
  orgId: resolved.orgId,
918
1498
  ctx: postCtx,
1499
+ ...(scope ? { scope } : {}),
919
1500
  });
920
1501
  arityResolved = arityResult.resolved;
921
1502
  if (arityResult.scanned > 0) {
@@ -929,18 +1510,39 @@ export async function liveIngest(opts) {
929
1510
  }
930
1511
  }
931
1512
  catch (e) {
1513
+ postFailures.push("apex arity resolver");
932
1514
  logger.warn("live-ingest: apex arity resolver failed", { err: e.message });
933
1515
  }
1516
+ profiler.phase("resolver:arity", performance.now() - tPhase);
1517
+ }
1518
+ // A formula's second-hop field guess moves onto the CustomField that
1519
+ // declares that relationshipName.
1520
+ if (!opts.disableFormulaHopResolve) {
1521
+ const tPhase = performance.now();
1522
+ try {
1523
+ const sources = deltaHooks?.hopSources();
1524
+ const hop = resolveFormulaRelationshipHops(graph, resolved.orgId, sources ? { sources } : {});
1525
+ if (hop.moved > 0)
1526
+ logger.info("live-ingest: formula relationship hops resolved", { ...hop });
1527
+ }
1528
+ catch (e) {
1529
+ postFailures.push("formula hop resolver");
1530
+ logger.warn("live-ingest: formula hop resolver failed", { err: e.message });
1531
+ }
1532
+ profiler.phase("resolver:formula-hop", performance.now() - tPhase);
934
1533
  }
935
1534
  // Reflection walker: runs BEFORE the dangling-edge audit so any
936
1535
  // REFERENCES edges it emits are validated by the audit alongside
937
1536
  // parser-emitted edges. Default on; disable via disableReflectionWalker.
938
1537
  if (!opts.disableReflectionWalker) {
1538
+ const tPhase = performance.now();
939
1539
  try {
940
1540
  const { walkBlobsForReferences } = await import("../parsers/generic/reflection-walker.js");
1541
+ const sourceQnames = deltaHooks?.reflectionSources();
941
1542
  const reflectionResult = walkBlobsForReferences(graph, {
942
1543
  orgId: resolved.orgId,
943
1544
  ctx: postCtx,
1545
+ ...(sourceQnames ? { sourceQnames } : {}),
944
1546
  });
945
1547
  reflectionEdges = reflectionResult.edgesEmitted;
946
1548
  if (reflectionEdges > 0) {
@@ -953,12 +1555,16 @@ export async function liveIngest(opts) {
953
1555
  }
954
1556
  }
955
1557
  catch (e) {
1558
+ postFailures.push("reflection walker");
956
1559
  logger.warn("live-ingest: reflection walker failed", {
957
1560
  err: e.message,
958
1561
  });
959
1562
  }
1563
+ profiler.phase("resolver:reflection", performance.now() - tPhase);
960
1564
  }
961
- if (!opts.disableAudit) {
1565
+ // The audit only reports (it changes nothing): a delta skips it.
1566
+ if (!opts.disableAudit && !deltaHooks) {
1567
+ const tPhase = performance.now();
962
1568
  try {
963
1569
  const auditResult = auditDanglingEdges(graph, resolved.orgId, { sampleSize: 25 });
964
1570
  danglingEdges = auditResult.danglingCount;
@@ -974,29 +1580,151 @@ export async function liveIngest(opts) {
974
1580
  }
975
1581
  }
976
1582
  catch (e) {
1583
+ postFailures.push("graph audit");
977
1584
  logger.warn("live-ingest: graph audit failed", { err: e.message });
978
1585
  }
1586
+ profiler.phase("audit", performance.now() - tPhase);
979
1587
  }
980
1588
  const completedIso = new Date().toISOString();
1589
+ // N4: when incremental skipped changed members it couldn't fetch, do NOT
1590
+ // advance the watermark past them — hold it at the prior value so the next
1591
+ // incremental re-detects (and keeps warning about) those changes instead of
1592
+ // stepping over them forever. generation still increments / in-progress
1593
+ // still clears (markSyncComplete does both regardless of the timestamp).
1594
+ const holdWatermark = incrementalUnfetched > 0 && existing?.lastSyncedAt != null;
1595
+ const watermarkIso = holdWatermark
1596
+ ? new Date(existing.lastSyncedAt).toISOString()
1597
+ : completedIso;
1598
+ // N-1: the held queue has not dispatched yet, so its lazy `onWork` flag
1599
+ // may not be set. Make `embeddings_pending` durable BEFORE the sync is
1600
+ // marked complete: a crash between here and the drain must leave the
1601
+ // next ingest knowing vectors are missing (it backfills them).
1602
+ if (embedQueue && !wasEmbeddingsPending && embedQueue.hasVectorWork()) {
1603
+ try {
1604
+ graph.setEmbeddingsPending?.(resolved.orgId, true);
1605
+ }
1606
+ catch (e) {
1607
+ logger.warn("live-ingest: setEmbeddingsPending failed", { err: e.message });
1608
+ }
1609
+ }
1610
+ const populate = async () => {
1611
+ if (!opts.analysisDb)
1612
+ return;
1613
+ const tDead = performance.now();
1614
+ try {
1615
+ await populateAnalysisTables(graph, resolved.orgId, opts.analysisDb);
1616
+ }
1617
+ catch (e) {
1618
+ postFailures.push("populate analysis tables");
1619
+ logger.warn("live-ingest: populate analysis tables failed", {
1620
+ err: e.message,
1621
+ });
1622
+ }
1623
+ profiler.phase("deadcode", performance.now() - tDead);
1624
+ };
1625
+ // T15 I-2: a delta whose resolver or dead-code pass failed is not a clean
1626
+ // sync. Populate runs before the sync is marked complete, and any failure
1627
+ // throws here: the pending marker and member rows stay as they were, so the
1628
+ // next delta replays the touched members with every resolver at full scope
1629
+ // (the outer catch marks the sync failed; the generation does not move).
1630
+ if (deltaHooks) {
1631
+ await populate();
1632
+ if (postFailures.length > 0) {
1633
+ throw new Error(`delta: post-merge step(s) failed (${postFailures.join(", ")}); not finalized, the next delta re-derives at full scope`);
1634
+ }
1635
+ }
981
1636
  try {
982
1637
  // W1.5-08: markSyncComplete subsumes the old touchSync — it updates
983
1638
  // last_synced_at AND increments sync_generation AND clears the
984
1639
  // in-progress flag, atomically in one transaction.
985
- graph.markSyncComplete(resolved.orgId, completedIso);
1640
+ graph.markSyncComplete(resolved.orgId, watermarkIso);
986
1641
  }
987
1642
  catch (e) {
988
1643
  logger.warn("live-ingest: markSyncComplete failed", { err: e.message });
989
1644
  }
990
- if (opts.analysisDb) {
1645
+ opts.onPhase?.("sync-complete");
1646
+ if (!deltaHooks)
1647
+ await populate();
1648
+ // Task 11c: the ingest is complete; record what each member owns.
1649
+ if (deltaHooks)
1650
+ deltaHooks.finalize();
1651
+ else if (memberRows && !streamAborted) {
991
1652
  try {
992
- await populateAnalysisTables(graph, resolved.orgId, opts.analysisDb);
1653
+ graph.replaceMemberRows?.(resolved.orgId, [...memberRows.values()], memberRowsGeneration());
993
1654
  }
994
1655
  catch (e) {
995
- logger.warn("live-ingest: populate analysis tables failed", {
996
- err: e.message,
997
- });
1656
+ logger.warn("live-ingest: member rows write failed", { err: e.message });
998
1657
  }
999
1658
  }
1659
+ // T15 N5-1: surface members skipped after repeated parse-worker failures.
1660
+ const parseQuarantined = deltaHooks
1661
+ ? (deltaHooks.quarantinedCount?.() ?? 0)
1662
+ : memberRows
1663
+ ? [...memberRows.values()].filter((r) => isQuarantinedRow(r)).length
1664
+ : 0;
1665
+ if (parseQuarantined > 0) {
1666
+ logger.warn("live-ingest: members skipped after repeated parse-worker failures (until their content changes)", { count: parseQuarantined });
1667
+ }
1668
+ // Graph ready: merges, resolvers and the dead-code cache are done. Only
1669
+ // embeddings may still be in flight.
1670
+ const graphReadyMs = Date.now() - startedAt;
1671
+ console.log(`graph ready in ${(graphReadyMs / 1000).toFixed(1)}s`);
1672
+ profiler.phase("graph-ready", graphReadyMs, true);
1673
+ let embeddings;
1674
+ if (embedQueue) {
1675
+ const q = embedQueue;
1676
+ let pendingLeft = 0;
1677
+ if (opts.waitEmbeddings === false) {
1678
+ // Cache hits are cheap: write them before returning, so a warm no-wait
1679
+ // run still completes its vectors. Only model work is deferred.
1680
+ try {
1681
+ q.flushCached();
1682
+ }
1683
+ catch (e) {
1684
+ // Items may have been dropped mid-flush: keep the flag set.
1685
+ if (!embedError)
1686
+ embedError = e;
1687
+ logger.warn("live-ingest: cached vector flush failed", { err: e.message });
1688
+ }
1689
+ pendingLeft = q.abandon() + q.stats.failed;
1690
+ const err = embedError;
1691
+ if (pendingLeft > 0 || err) {
1692
+ console.log(`embeddings deferred: ${pendingLeft} texts pending (cached vectors written: ${q.stats.cached}); find_similar uses text search until an ingest that waits for embeddings fills them`);
1693
+ }
1694
+ else {
1695
+ graph.setEmbeddingsPending?.(resolved.orgId, false);
1696
+ }
1697
+ }
1698
+ else {
1699
+ try {
1700
+ // drain() releases the held queue.
1701
+ await q.drain();
1702
+ }
1703
+ catch (e) {
1704
+ if (!embedError)
1705
+ embedError = e;
1706
+ }
1707
+ const doneMs = Date.now() - startedAt;
1708
+ const err = embedError;
1709
+ if (err) {
1710
+ pendingLeft = q.stats.failed;
1711
+ console.error(`embeddings failed: ${err.message} — ${q.stats.failed} texts left unembedded; they will be filled on the next ingest`);
1712
+ }
1713
+ else {
1714
+ graph.setEmbeddingsPending?.(resolved.orgId, false);
1715
+ console.log(`embeddings done in ${(doneMs / 1000).toFixed(1)}s (cached ${q.stats.cached} / computed ${q.stats.computed})`);
1716
+ }
1717
+ profiler.phase("embeddings", doneMs, true);
1718
+ }
1719
+ const err = embedError;
1720
+ embeddings = {
1721
+ ...q.stats,
1722
+ pending: pendingLeft,
1723
+ backfilled,
1724
+ doneMs: Date.now() - startedAt,
1725
+ ...(err ? { error: err.message } : {}),
1726
+ };
1727
+ }
1000
1728
  if (opts.snapshotStore) {
1001
1729
  try {
1002
1730
  opts.snapshotStore.prune(resolved.orgId, opts.snapshotRetentionDays ?? 30);
@@ -1015,7 +1743,11 @@ export async function liveIngest(opts) {
1015
1743
  durationMs: Date.now() - startedAt,
1016
1744
  crossFlavorEdges,
1017
1745
  arityResolved,
1746
+ parseQuarantined,
1747
+ interfaceRefsRetargeted,
1018
1748
  flowMethodsResolved,
1749
+ vlocityApex: vlocityApexResult,
1750
+ drRelationships: drRelationshipsResult,
1019
1751
  danglingEdges,
1020
1752
  reflectionEdges,
1021
1753
  overlap: overlapResult,
@@ -1026,9 +1758,27 @@ export async function liveIngest(opts) {
1026
1758
  // with Phase 1's structured-warnings refactor (W1-01).
1027
1759
  ...wedgeWarnings,
1028
1760
  ],
1761
+ graphReadyMs,
1762
+ ...(streamAborted ? { streamAborted: true } : {}),
1763
+ ...(embeddings ? { embeddings } : {}),
1029
1764
  };
1030
1765
  }
1031
1766
  catch (e) {
1767
+ embedQueue?.abandon();
1768
+ // Never leave a bulk window (open transaction, dropped indexes) or a
1769
+ // batch window (open transaction) behind.
1770
+ try {
1771
+ graph.endBatch?.();
1772
+ }
1773
+ catch {
1774
+ /* best-effort */
1775
+ }
1776
+ try {
1777
+ graph.endBulk?.();
1778
+ }
1779
+ catch {
1780
+ /* best-effort */
1781
+ }
1032
1782
  // W1.5-08: ingest threw before reaching markSyncComplete. Flip
1033
1783
  // sync_in_progress back to 0 (and clear sync_started_at) so concurrent
1034
1784
  // MCP readers don't see an orphaned in_progress flag forever. Generation
@@ -1045,5 +1795,20 @@ export async function liveIngest(opts) {
1045
1795
  }
1046
1796
  throw e;
1047
1797
  }
1798
+ finally {
1799
+ profiler.close();
1800
+ try {
1801
+ await ownedEmbedder?.close();
1802
+ }
1803
+ catch {
1804
+ /* best-effort */
1805
+ }
1806
+ try {
1807
+ embedCache?.close();
1808
+ }
1809
+ catch {
1810
+ /* best-effort */
1811
+ }
1812
+ }
1048
1813
  }
1049
1814
  //# sourceMappingURL=live-ingest.js.map