@kaelio/ktx 0.5.0 → 0.7.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 (875) hide show
  1. package/assets/python/{kaelio_ktx-0.5.0-py3-none-any.whl → kaelio_ktx-0.7.0-py3-none-any.whl} +0 -0
  2. package/assets/python/manifest.json +4 -4
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/clack.d.ts +8 -0
  5. package/dist/clack.js +14 -0
  6. package/dist/connection.js +2 -9
  7. package/dist/connectors/bigquery/connector.d.ts +6 -1
  8. package/dist/connectors/bigquery/connector.js +38 -9
  9. package/dist/connectors/bigquery/dialect.d.ts +11 -9
  10. package/dist/connectors/bigquery/dialect.js +25 -45
  11. package/dist/connectors/clickhouse/connector.d.ts +5 -0
  12. package/dist/connectors/clickhouse/connector.js +36 -3
  13. package/dist/connectors/clickhouse/dialect.d.ts +11 -12
  14. package/dist/connectors/clickhouse/dialect.js +25 -100
  15. package/dist/connectors/mysql/connector.d.ts +7 -1
  16. package/dist/connectors/mysql/connector.js +67 -9
  17. package/dist/connectors/mysql/dialect.d.ts +11 -9
  18. package/dist/connectors/mysql/dialect.js +25 -43
  19. package/dist/connectors/postgres/connector.d.ts +6 -0
  20. package/dist/connectors/postgres/connector.js +67 -12
  21. package/dist/connectors/postgres/dialect.d.ts +11 -9
  22. package/dist/connectors/postgres/dialect.js +26 -35
  23. package/dist/connectors/snowflake/connector.d.ts +8 -3
  24. package/dist/connectors/snowflake/connector.js +39 -20
  25. package/dist/connectors/snowflake/dialect.d.ts +11 -9
  26. package/dist/connectors/snowflake/dialect.js +25 -24
  27. package/dist/connectors/sqlite/connector.d.ts +3 -1
  28. package/dist/connectors/sqlite/connector.js +23 -3
  29. package/dist/connectors/sqlite/dialect.d.ts +11 -9
  30. package/dist/connectors/sqlite/dialect.js +25 -29
  31. package/dist/connectors/sqlserver/connector.d.ts +6 -0
  32. package/dist/connectors/sqlserver/connector.js +56 -9
  33. package/dist/connectors/sqlserver/dialect.d.ts +11 -10
  34. package/dist/connectors/sqlserver/dialect.js +24 -40
  35. package/dist/context/connections/connection-type.d.ts +1 -1
  36. package/dist/context/connections/dialect-helpers.d.ts +9 -0
  37. package/dist/context/connections/dialect-helpers.js +67 -0
  38. package/dist/context/connections/dialects.d.ts +23 -5
  39. package/dist/context/connections/dialects.js +18 -56
  40. package/dist/context/connections/drivers.d.ts +23 -0
  41. package/dist/context/connections/drivers.js +171 -0
  42. package/dist/context/connections/local-query-executor.js +25 -7
  43. package/dist/context/connections/local-warehouse-descriptor.js +0 -2
  44. package/dist/context/connections/postgres-query-executor.js +1 -1
  45. package/dist/context/connections/sqlite-query-executor.js +1 -1
  46. package/dist/context/ingest/adapters/historic-sql/chunk-unified.js +1 -1
  47. package/dist/context/ingest/adapters/historic-sql/connection-dialect.js +11 -7
  48. package/dist/context/ingest/adapters/historic-sql/evidence-tool.d.ts +1 -1
  49. package/dist/context/ingest/adapters/historic-sql/evidence-tool.js +8 -5
  50. package/dist/context/ingest/adapters/historic-sql/evidence.d.ts +4 -4
  51. package/dist/context/ingest/adapters/historic-sql/evidence.js +2 -2
  52. package/dist/context/ingest/adapters/historic-sql/projection.js +5 -2
  53. package/dist/context/ingest/adapters/live-database/daemon-introspection.js +1 -1
  54. package/dist/context/ingest/adapters/live-database/stage.d.ts +2 -0
  55. package/dist/context/ingest/adapters/live-database/stage.js +9 -0
  56. package/dist/context/ingest/adapters/looker/mapping.d.ts +0 -3
  57. package/dist/context/ingest/adapters/looker/mapping.js +0 -3
  58. package/dist/context/ingest/adapters/looker/types.d.ts +1 -1
  59. package/dist/context/ingest/historic-sql-probes/bigquery-runner.d.ts +34 -0
  60. package/dist/context/ingest/historic-sql-probes/bigquery-runner.js +99 -0
  61. package/dist/context/ingest/historic-sql-probes/postgres-runner.d.ts +26 -0
  62. package/dist/context/ingest/historic-sql-probes/postgres-runner.js +76 -0
  63. package/dist/context/ingest/historic-sql-probes/snowflake-runner.d.ts +29 -0
  64. package/dist/context/ingest/historic-sql-probes/snowflake-runner.js +62 -0
  65. package/dist/context/ingest/historic-sql-probes.d.ts +46 -0
  66. package/dist/context/ingest/historic-sql-probes.js +62 -0
  67. package/dist/context/ingest/local-adapters.js +0 -1
  68. package/dist/context/ingest/local-ingest.js +1 -1
  69. package/dist/context/llm/claude-code-runtime.js +16 -1
  70. package/dist/context/mcp/context-tools.js +11 -48
  71. package/dist/context/mcp/local-project-ports.js +0 -3
  72. package/dist/context/project/config.d.ts +0 -8
  73. package/dist/context/project/driver-schemas.d.ts +0 -4
  74. package/dist/context/project/driver-schemas.js +0 -2
  75. package/dist/context/scan/constraint-discovery.d.ts +19 -0
  76. package/dist/context/scan/constraint-discovery.js +23 -0
  77. package/dist/context/scan/enabled-tables.d.ts +4 -5
  78. package/dist/context/scan/enabled-tables.js +4 -18
  79. package/dist/context/scan/entity-details.js +14 -44
  80. package/dist/context/scan/local-enrichment.js +13 -1
  81. package/dist/context/scan/local-scan.js +5 -4
  82. package/dist/context/scan/local-structural-artifacts.js +51 -0
  83. package/dist/context/scan/relationship-benchmarks.js +9 -6
  84. package/dist/context/scan/relationship-composite-candidates.d.ts +3 -2
  85. package/dist/context/scan/relationship-composite-candidates.js +21 -33
  86. package/dist/context/scan/relationship-discovery.d.ts +3 -2
  87. package/dist/context/scan/relationship-discovery.js +4 -4
  88. package/dist/context/scan/relationship-profiling.d.ts +2 -3
  89. package/dist/context/scan/relationship-profiling.js +25 -94
  90. package/dist/context/scan/relationship-validation.d.ts +3 -2
  91. package/dist/context/scan/relationship-validation.js +12 -22
  92. package/dist/context/scan/table-ref.d.ts +1 -2
  93. package/dist/context/scan/table-ref.js +3 -4
  94. package/dist/context/scan/types.d.ts +6 -2
  95. package/dist/context/scan/warehouse-catalog.js +31 -48
  96. package/dist/context/sl/local-query.js +0 -3
  97. package/dist/context/sl/local-sl.js +0 -13
  98. package/dist/context/sl/semantic-layer.service.js +1 -4
  99. package/dist/context/tools/context-candidate-write.tool.d.ts +2 -2
  100. package/dist/context-build-view.js +1 -1
  101. package/dist/database-tree-picker.js +14 -7
  102. package/dist/error-message.d.ts +1 -0
  103. package/dist/error-message.js +29 -0
  104. package/dist/ingest-depth.js +0 -1
  105. package/dist/ingest.js +2 -2
  106. package/dist/llm/embedding-health.js +2 -2
  107. package/dist/local-scan-connectors.js +13 -56
  108. package/dist/managed-local-embeddings.js +2 -1
  109. package/dist/managed-python-daemon.d.ts +5 -0
  110. package/dist/managed-python-daemon.js +29 -9
  111. package/dist/managed-python-http.js +2 -1
  112. package/dist/public-ingest.js +1 -6
  113. package/dist/runtime-requirements.js +2 -2
  114. package/dist/setup-agents.d.ts +1 -1
  115. package/dist/setup-agents.js +16 -74
  116. package/dist/setup-context.js +2 -1
  117. package/dist/setup-databases.d.ts +3 -13
  118. package/dist/setup-databases.js +141 -313
  119. package/dist/setup-embeddings.js +10 -2
  120. package/dist/setup-project.d.ts +0 -8
  121. package/dist/setup-project.js +3 -27
  122. package/dist/setup-runtime.js +2 -1
  123. package/dist/setup-sources.js +2 -1
  124. package/dist/setup.js +11 -18
  125. package/dist/skills/historic_sql_patterns/SKILL.md +1 -3
  126. package/dist/skills/historic_sql_table_digest/SKILL.md +0 -1
  127. package/dist/skills/sl/SKILL.md +2 -2
  128. package/dist/sql.js +0 -4
  129. package/dist/status-project.d.ts +3 -18
  130. package/dist/status-project.js +42 -216
  131. package/dist/telemetry/events.d.ts +1 -1
  132. package/dist/telemetry/index.js +8 -3
  133. package/dist/tree-picker-state.d.ts +2 -2
  134. package/dist/tree-picker-state.js +29 -13
  135. package/dist/tree-picker-tui.d.ts +3 -1
  136. package/dist/tree-picker-tui.js +20 -32
  137. package/package.json +6 -6
  138. package/dist/admin-reindex.test.d.ts +0 -1
  139. package/dist/admin-reindex.test.js +0 -119
  140. package/dist/admin.test.d.ts +0 -1
  141. package/dist/admin.test.js +0 -201
  142. package/dist/cli-program-telemetry.test.d.ts +0 -1
  143. package/dist/cli-program-telemetry.test.js +0 -89
  144. package/dist/cli-program.test.d.ts +0 -1
  145. package/dist/cli-program.test.js +0 -71
  146. package/dist/command-tree.test.d.ts +0 -1
  147. package/dist/command-tree.test.js +0 -126
  148. package/dist/commands/mcp-commands.test.d.ts +0 -1
  149. package/dist/commands/mcp-commands.test.js +0 -111
  150. package/dist/commands/sql-commands.test.d.ts +0 -1
  151. package/dist/commands/sql-commands.test.js +0 -68
  152. package/dist/connection.test.d.ts +0 -1
  153. package/dist/connection.test.js +0 -426
  154. package/dist/connectors/bigquery/connector.test.d.ts +0 -1
  155. package/dist/connectors/bigquery/connector.test.js +0 -363
  156. package/dist/connectors/bigquery/dialect.test.d.ts +0 -1
  157. package/dist/connectors/bigquery/dialect.test.js +0 -36
  158. package/dist/connectors/clickhouse/connector.test.d.ts +0 -1
  159. package/dist/connectors/clickhouse/connector.test.js +0 -342
  160. package/dist/connectors/clickhouse/dialect.test.d.ts +0 -1
  161. package/dist/connectors/clickhouse/dialect.test.js +0 -36
  162. package/dist/connectors/mysql/connector.test.d.ts +0 -1
  163. package/dist/connectors/mysql/connector.test.js +0 -365
  164. package/dist/connectors/mysql/dialect.test.d.ts +0 -1
  165. package/dist/connectors/mysql/dialect.test.js +0 -36
  166. package/dist/connectors/postgres/connector.test.d.ts +0 -1
  167. package/dist/connectors/postgres/connector.test.js +0 -391
  168. package/dist/connectors/postgres/dialect.test.d.ts +0 -1
  169. package/dist/connectors/postgres/dialect.test.js +0 -37
  170. package/dist/connectors/postgres/historic-sql-query-client.test.d.ts +0 -1
  171. package/dist/connectors/postgres/historic-sql-query-client.test.js +0 -45
  172. package/dist/connectors/snowflake/connector.test.d.ts +0 -1
  173. package/dist/connectors/snowflake/connector.test.js +0 -462
  174. package/dist/connectors/snowflake/dialect.test.d.ts +0 -1
  175. package/dist/connectors/snowflake/dialect.test.js +0 -34
  176. package/dist/connectors/snowflake/identifiers.test.d.ts +0 -1
  177. package/dist/connectors/snowflake/identifiers.test.js +0 -12
  178. package/dist/connectors/snowflake/sdk-logger.test.d.ts +0 -1
  179. package/dist/connectors/snowflake/sdk-logger.test.js +0 -47
  180. package/dist/connectors/sqlite/connector.test.d.ts +0 -1
  181. package/dist/connectors/sqlite/connector.test.js +0 -207
  182. package/dist/connectors/sqlite/dialect.test.d.ts +0 -1
  183. package/dist/connectors/sqlite/dialect.test.js +0 -23
  184. package/dist/connectors/sqlserver/connector.test.d.ts +0 -1
  185. package/dist/connectors/sqlserver/connector.test.js +0 -313
  186. package/dist/connectors/sqlserver/dialect.test.d.ts +0 -1
  187. package/dist/connectors/sqlserver/dialect.test.js +0 -36
  188. package/dist/context/connections/bigquery-identifiers.test.d.ts +0 -1
  189. package/dist/context/connections/bigquery-identifiers.test.js +0 -13
  190. package/dist/context/connections/dialects.test.d.ts +0 -1
  191. package/dist/context/connections/dialects.test.js +0 -24
  192. package/dist/context/connections/local-query-executor.test.d.ts +0 -1
  193. package/dist/context/connections/local-query-executor.test.js +0 -48
  194. package/dist/context/connections/local-warehouse-descriptor.test.d.ts +0 -1
  195. package/dist/context/connections/local-warehouse-descriptor.test.js +0 -53
  196. package/dist/context/connections/notion-config.test.d.ts +0 -1
  197. package/dist/context/connections/notion-config.test.js +0 -121
  198. package/dist/context/connections/postgres-query-executor.test.d.ts +0 -1
  199. package/dist/context/connections/postgres-query-executor.test.js +0 -91
  200. package/dist/context/connections/read-only-sql.test.d.ts +0 -1
  201. package/dist/context/connections/read-only-sql.test.js +0 -20
  202. package/dist/context/connections/sqlite-query-executor.test.d.ts +0 -1
  203. package/dist/context/connections/sqlite-query-executor.test.js +0 -113
  204. package/dist/context/core/config-reference.test.d.ts +0 -1
  205. package/dist/context/core/config-reference.test.js +0 -27
  206. package/dist/context/core/git.service.assert-worktree-clean.test.d.ts +0 -1
  207. package/dist/context/core/git.service.assert-worktree-clean.test.js +0 -62
  208. package/dist/context/core/git.service.delete-directories.test.d.ts +0 -1
  209. package/dist/context/core/git.service.delete-directories.test.js +0 -61
  210. package/dist/context/core/git.service.patch.test.d.ts +0 -1
  211. package/dist/context/core/git.service.patch.test.js +0 -40
  212. package/dist/context/core/git.service.reset-hard.test.d.ts +0 -1
  213. package/dist/context/core/git.service.reset-hard.test.js +0 -47
  214. package/dist/context/core/git.service.test.d.ts +0 -1
  215. package/dist/context/core/git.service.test.js +0 -357
  216. package/dist/context/core/session-worktree.service.test.d.ts +0 -1
  217. package/dist/context/core/session-worktree.service.test.js +0 -97
  218. package/dist/context/daemon/semantic-layer-compute.test.d.ts +0 -1
  219. package/dist/context/daemon/semantic-layer-compute.test.js +0 -305
  220. package/dist/context/index-sync/reindex.test.d.ts +0 -1
  221. package/dist/context/index-sync/reindex.test.js +0 -139
  222. package/dist/context/ingest/action-identity.test.d.ts +0 -1
  223. package/dist/context/ingest/action-identity.test.js +0 -19
  224. package/dist/context/ingest/adapters/dbt/chunk.test.d.ts +0 -1
  225. package/dist/context/ingest/adapters/dbt/chunk.test.js +0 -30
  226. package/dist/context/ingest/adapters/dbt/dbt.adapter.test.d.ts +0 -1
  227. package/dist/context/ingest/adapters/dbt/dbt.adapter.test.js +0 -43
  228. package/dist/context/ingest/adapters/dbt/fetch.test.d.ts +0 -1
  229. package/dist/context/ingest/adapters/dbt/fetch.test.js +0 -30
  230. package/dist/context/ingest/adapters/dbt/parse.test.d.ts +0 -1
  231. package/dist/context/ingest/adapters/dbt/parse.test.js +0 -7
  232. package/dist/context/ingest/adapters/dbt-descriptions/parse-schema.test.d.ts +0 -1
  233. package/dist/context/ingest/adapters/dbt-descriptions/parse-schema.test.js +0 -195
  234. package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.test.d.ts +0 -1
  235. package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.test.js +0 -121
  236. package/dist/context/ingest/adapters/historic-sql/buckets.test.d.ts +0 -1
  237. package/dist/context/ingest/adapters/historic-sql/buckets.test.js +0 -49
  238. package/dist/context/ingest/adapters/historic-sql/chunk-unified.test.d.ts +0 -1
  239. package/dist/context/ingest/adapters/historic-sql/chunk-unified.test.js +0 -160
  240. package/dist/context/ingest/adapters/historic-sql/detect.test.d.ts +0 -1
  241. package/dist/context/ingest/adapters/historic-sql/detect.test.js +0 -48
  242. package/dist/context/ingest/adapters/historic-sql/evidence-tool.test.d.ts +0 -1
  243. package/dist/context/ingest/adapters/historic-sql/evidence-tool.test.js +0 -67
  244. package/dist/context/ingest/adapters/historic-sql/evidence.test.d.ts +0 -1
  245. package/dist/context/ingest/adapters/historic-sql/evidence.test.js +0 -43
  246. package/dist/context/ingest/adapters/historic-sql/historic-sql.adapter.test.d.ts +0 -1
  247. package/dist/context/ingest/adapters/historic-sql/historic-sql.adapter.test.js +0 -98
  248. package/dist/context/ingest/adapters/historic-sql/local-ingest-acceptance.test.d.ts +0 -1
  249. package/dist/context/ingest/adapters/historic-sql/local-ingest-acceptance.test.js +0 -235
  250. package/dist/context/ingest/adapters/historic-sql/pattern-inputs.test.d.ts +0 -1
  251. package/dist/context/ingest/adapters/historic-sql/pattern-inputs.test.js +0 -68
  252. package/dist/context/ingest/adapters/historic-sql/postgres-pgss-reader.test.d.ts +0 -1
  253. package/dist/context/ingest/adapters/historic-sql/postgres-pgss-reader.test.js +0 -205
  254. package/dist/context/ingest/adapters/historic-sql/projection.test.d.ts +0 -1
  255. package/dist/context/ingest/adapters/historic-sql/projection.test.js +0 -392
  256. package/dist/context/ingest/adapters/historic-sql/redaction.test.d.ts +0 -1
  257. package/dist/context/ingest/adapters/historic-sql/redaction.test.js +0 -22
  258. package/dist/context/ingest/adapters/historic-sql/skill-schemas.test.d.ts +0 -1
  259. package/dist/context/ingest/adapters/historic-sql/skill-schemas.test.js +0 -62
  260. package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.test.d.ts +0 -1
  261. package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.test.js +0 -117
  262. package/dist/context/ingest/adapters/historic-sql/stage-unified.test.d.ts +0 -1
  263. package/dist/context/ingest/adapters/historic-sql/stage-unified.test.js +0 -405
  264. package/dist/context/ingest/adapters/historic-sql/types.test.d.ts +0 -1
  265. package/dist/context/ingest/adapters/historic-sql/types.test.js +0 -87
  266. package/dist/context/ingest/adapters/live-database/chunk.test.d.ts +0 -1
  267. package/dist/context/ingest/adapters/live-database/chunk.test.js +0 -95
  268. package/dist/context/ingest/adapters/live-database/daemon-introspection.test.d.ts +0 -1
  269. package/dist/context/ingest/adapters/live-database/daemon-introspection.test.js +0 -241
  270. package/dist/context/ingest/adapters/live-database/live-database.adapter.test.d.ts +0 -1
  271. package/dist/context/ingest/adapters/live-database/live-database.adapter.test.js +0 -105
  272. package/dist/context/ingest/adapters/live-database/manifest.test.d.ts +0 -1
  273. package/dist/context/ingest/adapters/live-database/manifest.test.js +0 -291
  274. package/dist/context/ingest/adapters/live-database/stage.test.d.ts +0 -1
  275. package/dist/context/ingest/adapters/live-database/stage.test.js +0 -133
  276. package/dist/context/ingest/adapters/looker/chunk.test.d.ts +0 -1
  277. package/dist/context/ingest/adapters/looker/chunk.test.js +0 -142
  278. package/dist/context/ingest/adapters/looker/client-boundary.test.d.ts +0 -1
  279. package/dist/context/ingest/adapters/looker/client-boundary.test.js +0 -12
  280. package/dist/context/ingest/adapters/looker/client.test.d.ts +0 -1
  281. package/dist/context/ingest/adapters/looker/client.test.js +0 -407
  282. package/dist/context/ingest/adapters/looker/daemon-table-identifier-parser.test.d.ts +0 -1
  283. package/dist/context/ingest/adapters/looker/daemon-table-identifier-parser.test.js +0 -40
  284. package/dist/context/ingest/adapters/looker/detect.test.d.ts +0 -1
  285. package/dist/context/ingest/adapters/looker/detect.test.js +0 -39
  286. package/dist/context/ingest/adapters/looker/evidence-documents.test.d.ts +0 -1
  287. package/dist/context/ingest/adapters/looker/evidence-documents.test.js +0 -178
  288. package/dist/context/ingest/adapters/looker/factory.test.d.ts +0 -1
  289. package/dist/context/ingest/adapters/looker/factory.test.js +0 -55
  290. package/dist/context/ingest/adapters/looker/fetch-report.test.d.ts +0 -1
  291. package/dist/context/ingest/adapters/looker/fetch-report.test.js +0 -71
  292. package/dist/context/ingest/adapters/looker/fetch.test.d.ts +0 -1
  293. package/dist/context/ingest/adapters/looker/fetch.test.js +0 -592
  294. package/dist/context/ingest/adapters/looker/local-runtime-store.test.d.ts +0 -1
  295. package/dist/context/ingest/adapters/looker/local-runtime-store.test.js +0 -106
  296. package/dist/context/ingest/adapters/looker/looker.adapter.test.d.ts +0 -1
  297. package/dist/context/ingest/adapters/looker/looker.adapter.test.js +0 -99
  298. package/dist/context/ingest/adapters/looker/mapping.test.d.ts +0 -1
  299. package/dist/context/ingest/adapters/looker/mapping.test.js +0 -334
  300. package/dist/context/ingest/adapters/looker/reconcile.test.d.ts +0 -1
  301. package/dist/context/ingest/adapters/looker/reconcile.test.js +0 -12
  302. package/dist/context/ingest/adapters/looker/scope.test.d.ts +0 -1
  303. package/dist/context/ingest/adapters/looker/scope.test.js +0 -84
  304. package/dist/context/ingest/adapters/looker/target-connections.test.d.ts +0 -1
  305. package/dist/context/ingest/adapters/looker/target-connections.test.js +0 -71
  306. package/dist/context/ingest/adapters/looker/tools/looker-query-to-sl.tool.test.d.ts +0 -1
  307. package/dist/context/ingest/adapters/looker/tools/looker-query-to-sl.tool.test.js +0 -211
  308. package/dist/context/ingest/adapters/looker/types.test.d.ts +0 -1
  309. package/dist/context/ingest/adapters/looker/types.test.js +0 -261
  310. package/dist/context/ingest/adapters/lookml/chunk.test.d.ts +0 -1
  311. package/dist/context/ingest/adapters/lookml/chunk.test.js +0 -213
  312. package/dist/context/ingest/adapters/lookml/detect.test.d.ts +0 -1
  313. package/dist/context/ingest/adapters/lookml/detect.test.js +0 -37
  314. package/dist/context/ingest/adapters/lookml/fetch-report.test.d.ts +0 -1
  315. package/dist/context/ingest/adapters/lookml/fetch-report.test.js +0 -82
  316. package/dist/context/ingest/adapters/lookml/fetch.test.d.ts +0 -1
  317. package/dist/context/ingest/adapters/lookml/fetch.test.js +0 -121
  318. package/dist/context/ingest/adapters/lookml/graph.test.d.ts +0 -1
  319. package/dist/context/ingest/adapters/lookml/graph.test.js +0 -105
  320. package/dist/context/ingest/adapters/lookml/lookml.adapter.test.d.ts +0 -1
  321. package/dist/context/ingest/adapters/lookml/lookml.adapter.test.js +0 -49
  322. package/dist/context/ingest/adapters/lookml/parse.test.d.ts +0 -1
  323. package/dist/context/ingest/adapters/lookml/parse.test.js +0 -118
  324. package/dist/context/ingest/adapters/lookml/pull-config.test.d.ts +0 -1
  325. package/dist/context/ingest/adapters/lookml/pull-config.test.js +0 -128
  326. package/dist/context/ingest/adapters/metabase/card-references.test.d.ts +0 -1
  327. package/dist/context/ingest/adapters/metabase/card-references.test.js +0 -36
  328. package/dist/context/ingest/adapters/metabase/chunk.test.d.ts +0 -1
  329. package/dist/context/ingest/adapters/metabase/chunk.test.js +0 -299
  330. package/dist/context/ingest/adapters/metabase/client-boundary.test.d.ts +0 -1
  331. package/dist/context/ingest/adapters/metabase/client-boundary.test.js +0 -38
  332. package/dist/context/ingest/adapters/metabase/client-port.test.d.ts +0 -1
  333. package/dist/context/ingest/adapters/metabase/client-port.test.js +0 -86
  334. package/dist/context/ingest/adapters/metabase/client.test.d.ts +0 -1
  335. package/dist/context/ingest/adapters/metabase/client.test.js +0 -377
  336. package/dist/context/ingest/adapters/metabase/detect.test.d.ts +0 -1
  337. package/dist/context/ingest/adapters/metabase/detect.test.js +0 -42
  338. package/dist/context/ingest/adapters/metabase/fanout-planner.test.d.ts +0 -1
  339. package/dist/context/ingest/adapters/metabase/fanout-planner.test.js +0 -44
  340. package/dist/context/ingest/adapters/metabase/fetch-scope.test.d.ts +0 -1
  341. package/dist/context/ingest/adapters/metabase/fetch-scope.test.js +0 -124
  342. package/dist/context/ingest/adapters/metabase/fetch.test.d.ts +0 -1
  343. package/dist/context/ingest/adapters/metabase/fetch.test.js +0 -557
  344. package/dist/context/ingest/adapters/metabase/local-metabase.adapter.test.d.ts +0 -1
  345. package/dist/context/ingest/adapters/metabase/local-metabase.adapter.test.js +0 -56
  346. package/dist/context/ingest/adapters/metabase/local-source-state-store.test.d.ts +0 -1
  347. package/dist/context/ingest/adapters/metabase/local-source-state-store.test.js +0 -99
  348. package/dist/context/ingest/adapters/metabase/mapping.test.d.ts +0 -1
  349. package/dist/context/ingest/adapters/metabase/mapping.test.js +0 -215
  350. package/dist/context/ingest/adapters/metabase/metabase.adapter.test.d.ts +0 -1
  351. package/dist/context/ingest/adapters/metabase/metabase.adapter.test.js +0 -129
  352. package/dist/context/ingest/adapters/metabase/serialize-card.test.d.ts +0 -1
  353. package/dist/context/ingest/adapters/metabase/serialize-card.test.js +0 -205
  354. package/dist/context/ingest/adapters/metabase/types.test.d.ts +0 -1
  355. package/dist/context/ingest/adapters/metabase/types.test.js +0 -75
  356. package/dist/context/ingest/adapters/metricflow/chunk.test.d.ts +0 -1
  357. package/dist/context/ingest/adapters/metricflow/chunk.test.js +0 -114
  358. package/dist/context/ingest/adapters/metricflow/deep-parse.test.d.ts +0 -1
  359. package/dist/context/ingest/adapters/metricflow/deep-parse.test.js +0 -1139
  360. package/dist/context/ingest/adapters/metricflow/detect.test.d.ts +0 -1
  361. package/dist/context/ingest/adapters/metricflow/detect.test.js +0 -43
  362. package/dist/context/ingest/adapters/metricflow/fetch.test.d.ts +0 -1
  363. package/dist/context/ingest/adapters/metricflow/fetch.test.js +0 -97
  364. package/dist/context/ingest/adapters/metricflow/graph.test.d.ts +0 -1
  365. package/dist/context/ingest/adapters/metricflow/graph.test.js +0 -245
  366. package/dist/context/ingest/adapters/metricflow/import-semantic-models.test.d.ts +0 -1
  367. package/dist/context/ingest/adapters/metricflow/import-semantic-models.test.js +0 -318
  368. package/dist/context/ingest/adapters/metricflow/metricflow.adapter.test.d.ts +0 -1
  369. package/dist/context/ingest/adapters/metricflow/metricflow.adapter.test.js +0 -212
  370. package/dist/context/ingest/adapters/metricflow/parse.test.d.ts +0 -1
  371. package/dist/context/ingest/adapters/metricflow/parse.test.js +0 -171
  372. package/dist/context/ingest/adapters/metricflow/pull-config.test.d.ts +0 -1
  373. package/dist/context/ingest/adapters/metricflow/pull-config.test.js +0 -57
  374. package/dist/context/ingest/adapters/metricflow/semantic-models.test.d.ts +0 -1
  375. package/dist/context/ingest/adapters/metricflow/semantic-models.test.js +0 -204
  376. package/dist/context/ingest/adapters/notion/cluster.test.d.ts +0 -1
  377. package/dist/context/ingest/adapters/notion/cluster.test.js +0 -123
  378. package/dist/context/ingest/adapters/notion/fetch.test.d.ts +0 -1
  379. package/dist/context/ingest/adapters/notion/fetch.test.js +0 -358
  380. package/dist/context/ingest/adapters/notion/local-state-store.test.d.ts +0 -1
  381. package/dist/context/ingest/adapters/notion/local-state-store.test.js +0 -29
  382. package/dist/context/ingest/adapters/notion/normalize.test.d.ts +0 -1
  383. package/dist/context/ingest/adapters/notion/normalize.test.js +0 -64
  384. package/dist/context/ingest/adapters/notion/notion-client.test.d.ts +0 -1
  385. package/dist/context/ingest/adapters/notion/notion-client.test.js +0 -49
  386. package/dist/context/ingest/adapters/notion/notion.adapter.test.d.ts +0 -1
  387. package/dist/context/ingest/adapters/notion/notion.adapter.test.js +0 -315
  388. package/dist/context/ingest/artifact-gates.test.d.ts +0 -1
  389. package/dist/context/ingest/artifact-gates.test.js +0 -167
  390. package/dist/context/ingest/canonical-pins.test.d.ts +0 -1
  391. package/dist/context/ingest/canonical-pins.test.js +0 -66
  392. package/dist/context/ingest/clustering/kmeans.test.d.ts +0 -1
  393. package/dist/context/ingest/clustering/kmeans.test.js +0 -61
  394. package/dist/context/ingest/context-candidates/candidate-dedup.service.test.d.ts +0 -1
  395. package/dist/context/ingest/context-candidates/candidate-dedup.service.test.js +0 -216
  396. package/dist/context/ingest/context-candidates/context-candidate-carryforward.service.test.d.ts +0 -1
  397. package/dist/context/ingest/context-candidates/context-candidate-carryforward.service.test.js +0 -161
  398. package/dist/context/ingest/context-candidates/curator-pagination.service.test.d.ts +0 -1
  399. package/dist/context/ingest/context-candidates/curator-pagination.service.test.js +0 -168
  400. package/dist/context/ingest/context-candidates/embedding-text.test.d.ts +0 -1
  401. package/dist/context/ingest/context-candidates/embedding-text.test.js +0 -10
  402. package/dist/context/ingest/context-candidates/store.test.d.ts +0 -1
  403. package/dist/context/ingest/context-candidates/store.test.js +0 -67
  404. package/dist/context/ingest/context-evidence/context-evidence-index.service.test.d.ts +0 -1
  405. package/dist/context/ingest/context-evidence/context-evidence-index.service.test.js +0 -374
  406. package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.test.d.ts +0 -1
  407. package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.test.js +0 -416
  408. package/dist/context/ingest/context-evidence/store.test.d.ts +0 -1
  409. package/dist/context/ingest/context-evidence/store.test.js +0 -55
  410. package/dist/context/ingest/dbt-shared/project-vars.test.d.ts +0 -1
  411. package/dist/context/ingest/dbt-shared/project-vars.test.js +0 -90
  412. package/dist/context/ingest/dbt-shared/schema-files.test.d.ts +0 -1
  413. package/dist/context/ingest/dbt-shared/schema-files.test.js +0 -35
  414. package/dist/context/ingest/diff-set.service.test.d.ts +0 -1
  415. package/dist/context/ingest/diff-set.service.test.js +0 -132
  416. package/dist/context/ingest/final-gate-repair.test.d.ts +0 -1
  417. package/dist/context/ingest/final-gate-repair.test.js +0 -109
  418. package/dist/context/ingest/finalization-scope.test.d.ts +0 -1
  419. package/dist/context/ingest/finalization-scope.test.js +0 -114
  420. package/dist/context/ingest/ingest-bundle.runner.isolated-diff.test.d.ts +0 -1
  421. package/dist/context/ingest/ingest-bundle.runner.isolated-diff.test.js +0 -1928
  422. package/dist/context/ingest/ingest-bundle.runner.test.d.ts +0 -1
  423. package/dist/context/ingest/ingest-bundle.runner.test.js +0 -1899
  424. package/dist/context/ingest/ingest-prompts.test.d.ts +0 -1
  425. package/dist/context/ingest/ingest-prompts.test.js +0 -32
  426. package/dist/context/ingest/ingest-runtime-assets.test.d.ts +0 -1
  427. package/dist/context/ingest/ingest-runtime-assets.test.js +0 -89
  428. package/dist/context/ingest/ingest-trace.test.d.ts +0 -1
  429. package/dist/context/ingest/ingest-trace.test.js +0 -76
  430. package/dist/context/ingest/isolated-diff/git-patch.test.d.ts +0 -1
  431. package/dist/context/ingest/isolated-diff/git-patch.test.js +0 -76
  432. package/dist/context/ingest/isolated-diff/patch-integrator.test.d.ts +0 -1
  433. package/dist/context/ingest/isolated-diff/patch-integrator.test.js +0 -369
  434. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.test.d.ts +0 -1
  435. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.test.js +0 -101
  436. package/dist/context/ingest/isolated-diff/work-unit-executor.test.d.ts +0 -1
  437. package/dist/context/ingest/isolated-diff/work-unit-executor.test.js +0 -137
  438. package/dist/context/ingest/local-adapters.test.d.ts +0 -1
  439. package/dist/context/ingest/local-adapters.test.js +0 -612
  440. package/dist/context/ingest/local-bundle-ingest.test.d.ts +0 -1
  441. package/dist/context/ingest/local-bundle-ingest.test.js +0 -794
  442. package/dist/context/ingest/local-bundle-runtime.test.d.ts +0 -1
  443. package/dist/context/ingest/local-bundle-runtime.test.js +0 -240
  444. package/dist/context/ingest/local-embedding-provider.integration.test.d.ts +0 -1
  445. package/dist/context/ingest/local-embedding-provider.integration.test.js +0 -139
  446. package/dist/context/ingest/local-mapping-reconcile.test.d.ts +0 -1
  447. package/dist/context/ingest/local-mapping-reconcile.test.js +0 -61
  448. package/dist/context/ingest/local-metabase-ingest.test.d.ts +0 -1
  449. package/dist/context/ingest/local-metabase-ingest.test.js +0 -227
  450. package/dist/context/ingest/local-stage-ingest.test.d.ts +0 -1
  451. package/dist/context/ingest/local-stage-ingest.test.js +0 -581
  452. package/dist/context/ingest/memory-flow/acceptance-fixtures.d.ts +0 -6
  453. package/dist/context/ingest/memory-flow/acceptance-fixtures.js +0 -155
  454. package/dist/context/ingest/memory-flow/acceptance.test.d.ts +0 -1
  455. package/dist/context/ingest/memory-flow/acceptance.test.js +0 -43
  456. package/dist/context/ingest/memory-flow/events.test.d.ts +0 -1
  457. package/dist/context/ingest/memory-flow/events.test.js +0 -319
  458. package/dist/context/ingest/memory-flow/interaction.test.d.ts +0 -1
  459. package/dist/context/ingest/memory-flow/interaction.test.js +0 -264
  460. package/dist/context/ingest/memory-flow/interactive-render.test.d.ts +0 -1
  461. package/dist/context/ingest/memory-flow/interactive-render.test.js +0 -160
  462. package/dist/context/ingest/memory-flow/live-buffer.test.d.ts +0 -1
  463. package/dist/context/ingest/memory-flow/live-buffer.test.js +0 -77
  464. package/dist/context/ingest/memory-flow/render.test.d.ts +0 -1
  465. package/dist/context/ingest/memory-flow/render.test.js +0 -105
  466. package/dist/context/ingest/memory-flow/schema.test.d.ts +0 -1
  467. package/dist/context/ingest/memory-flow/schema.test.js +0 -147
  468. package/dist/context/ingest/memory-flow/summary.test.d.ts +0 -1
  469. package/dist/context/ingest/memory-flow/summary.test.js +0 -130
  470. package/dist/context/ingest/memory-flow/view-model.test.d.ts +0 -1
  471. package/dist/context/ingest/memory-flow/view-model.test.js +0 -397
  472. package/dist/context/ingest/memory-flow/visuals.test.d.ts +0 -1
  473. package/dist/context/ingest/memory-flow/visuals.test.js +0 -49
  474. package/dist/context/ingest/page-triage/page-triage.service.test.d.ts +0 -1
  475. package/dist/context/ingest/page-triage/page-triage.service.test.js +0 -311
  476. package/dist/context/ingest/raw-sources-paths.test.d.ts +0 -1
  477. package/dist/context/ingest/raw-sources-paths.test.js +0 -18
  478. package/dist/context/ingest/repo-fetch.test.d.ts +0 -1
  479. package/dist/context/ingest/repo-fetch.test.js +0 -168
  480. package/dist/context/ingest/report-snapshot.test.d.ts +0 -1
  481. package/dist/context/ingest/report-snapshot.test.js +0 -329
  482. package/dist/context/ingest/semantic-layer-target-policy.test.d.ts +0 -1
  483. package/dist/context/ingest/semantic-layer-target-policy.test.js +0 -25
  484. package/dist/context/ingest/source-adapter-registry.test.d.ts +0 -1
  485. package/dist/context/ingest/source-adapter-registry.test.js +0 -35
  486. package/dist/context/ingest/sqlite-bundle-ingest-store.test.d.ts +0 -1
  487. package/dist/context/ingest/sqlite-bundle-ingest-store.test.js +0 -517
  488. package/dist/context/ingest/sqlite-local-ingest-store.test.d.ts +0 -1
  489. package/dist/context/ingest/sqlite-local-ingest-store.test.js +0 -143
  490. package/dist/context/ingest/stages/build-reconcile-context.context-candidates.test.d.ts +0 -1
  491. package/dist/context/ingest/stages/build-reconcile-context.context-candidates.test.js +0 -102
  492. package/dist/context/ingest/stages/build-reconcile-context.test.d.ts +0 -1
  493. package/dist/context/ingest/stages/build-reconcile-context.test.js +0 -141
  494. package/dist/context/ingest/stages/build-wu-context.test.d.ts +0 -1
  495. package/dist/context/ingest/stages/build-wu-context.test.js +0 -196
  496. package/dist/context/ingest/stages/stage-1-stage-raw-files.test.d.ts +0 -1
  497. package/dist/context/ingest/stages/stage-1-stage-raw-files.test.js +0 -54
  498. package/dist/context/ingest/stages/stage-3-work-units.test.d.ts +0 -1
  499. package/dist/context/ingest/stages/stage-3-work-units.test.js +0 -175
  500. package/dist/context/ingest/stages/stage-4-reconciliation.test.d.ts +0 -1
  501. package/dist/context/ingest/stages/stage-4-reconciliation.test.js +0 -144
  502. package/dist/context/ingest/stages/validate-wu-sources.test.d.ts +0 -1
  503. package/dist/context/ingest/stages/validate-wu-sources.test.js +0 -27
  504. package/dist/context/ingest/tools/emit-reconciliation-records.tool.test.d.ts +0 -1
  505. package/dist/context/ingest/tools/emit-reconciliation-records.tool.test.js +0 -237
  506. package/dist/context/ingest/tools/eviction-list.tool.test.d.ts +0 -1
  507. package/dist/context/ingest/tools/eviction-list.tool.test.js +0 -44
  508. package/dist/context/ingest/tools/read-raw-file.tool.test.d.ts +0 -1
  509. package/dist/context/ingest/tools/read-raw-file.tool.test.js +0 -45
  510. package/dist/context/ingest/tools/read-raw-span.tool.test.d.ts +0 -1
  511. package/dist/context/ingest/tools/read-raw-span.tool.test.js +0 -34
  512. package/dist/context/ingest/tools/stage-diff.tool.test.d.ts +0 -1
  513. package/dist/context/ingest/tools/stage-diff.tool.test.js +0 -112
  514. package/dist/context/ingest/tools/stage-list.tool.test.d.ts +0 -1
  515. package/dist/context/ingest/tools/stage-list.tool.test.js +0 -58
  516. package/dist/context/ingest/tools/tool-transcript-summary.test.d.ts +0 -1
  517. package/dist/context/ingest/tools/tool-transcript-summary.test.js +0 -141
  518. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.test.d.ts +0 -1
  519. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.test.js +0 -107
  520. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.test.d.ts +0 -1
  521. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.test.js +0 -146
  522. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.test.d.ts +0 -1
  523. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.test.js +0 -50
  524. package/dist/context/ingest/wiki-body-refs.test.d.ts +0 -1
  525. package/dist/context/ingest/wiki-body-refs.test.js +0 -138
  526. package/dist/context/ingest/wiki-sl-ref-repair.test.d.ts +0 -1
  527. package/dist/context/ingest/wiki-sl-ref-repair.test.js +0 -81
  528. package/dist/context/llm/ai-sdk-runtime.test.d.ts +0 -1
  529. package/dist/context/llm/ai-sdk-runtime.test.js +0 -308
  530. package/dist/context/llm/claude-code-env.test.d.ts +0 -1
  531. package/dist/context/llm/claude-code-env.test.js +0 -17
  532. package/dist/context/llm/claude-code-models.test.d.ts +0 -1
  533. package/dist/context/llm/claude-code-models.test.js +0 -15
  534. package/dist/context/llm/claude-code-runtime.test.d.ts +0 -1
  535. package/dist/context/llm/claude-code-runtime.test.js +0 -434
  536. package/dist/context/llm/debug-request-recorder.test.d.ts +0 -1
  537. package/dist/context/llm/debug-request-recorder.test.js +0 -112
  538. package/dist/context/llm/embedding-port.test.d.ts +0 -1
  539. package/dist/context/llm/embedding-port.test.js +0 -34
  540. package/dist/context/llm/local-config.test.d.ts +0 -1
  541. package/dist/context/llm/local-config.test.js +0 -164
  542. package/dist/context/llm/runtime-local-config.test.d.ts +0 -1
  543. package/dist/context/llm/runtime-local-config.test.js +0 -17
  544. package/dist/context/llm/runtime-tools.test.d.ts +0 -1
  545. package/dist/context/llm/runtime-tools.test.js +0 -36
  546. package/dist/context/mcp/local-project-ports.test.d.ts +0 -1
  547. package/dist/context/mcp/local-project-ports.test.js +0 -689
  548. package/dist/context/mcp/server.test.d.ts +0 -1
  549. package/dist/context/mcp/server.test.js +0 -902
  550. package/dist/context/memory/local-memory.test.d.ts +0 -1
  551. package/dist/context/memory/local-memory.test.js +0 -173
  552. package/dist/context/memory/memory-agent.service.ingest.test.d.ts +0 -1
  553. package/dist/context/memory/memory-agent.service.ingest.test.js +0 -355
  554. package/dist/context/memory/memory-agent.service.test.d.ts +0 -1
  555. package/dist/context/memory/memory-agent.service.test.js +0 -413
  556. package/dist/context/memory/memory-runs.test.d.ts +0 -1
  557. package/dist/context/memory/memory-runs.test.js +0 -158
  558. package/dist/context/memory/memory-runtime-assets.test.d.ts +0 -1
  559. package/dist/context/memory/memory-runtime-assets.test.js +0 -162
  560. package/dist/context/project/config.test.d.ts +0 -1
  561. package/dist/context/project/config.test.js +0 -467
  562. package/dist/context/project/driver-schemas.test.d.ts +0 -1
  563. package/dist/context/project/driver-schemas.test.js +0 -125
  564. package/dist/context/project/local-git-file-store.test.d.ts +0 -1
  565. package/dist/context/project/local-git-file-store.test.js +0 -71
  566. package/dist/context/project/mappings-yaml-schema.test.d.ts +0 -1
  567. package/dist/context/project/mappings-yaml-schema.test.js +0 -79
  568. package/dist/context/project/project.test.d.ts +0 -1
  569. package/dist/context/project/project.test.js +0 -55
  570. package/dist/context/project/setup-config.test.d.ts +0 -1
  571. package/dist/context/project/setup-config.test.js +0 -38
  572. package/dist/context/prompts/prompt.service.test.d.ts +0 -1
  573. package/dist/context/prompts/prompt.service.test.js +0 -43
  574. package/dist/context/scan/credentials.test.d.ts +0 -1
  575. package/dist/context/scan/credentials.test.js +0 -162
  576. package/dist/context/scan/data-dictionary.test.d.ts +0 -1
  577. package/dist/context/scan/data-dictionary.test.js +0 -92
  578. package/dist/context/scan/description-generation.test.d.ts +0 -1
  579. package/dist/context/scan/description-generation.test.js +0 -693
  580. package/dist/context/scan/embedding-text.test.d.ts +0 -1
  581. package/dist/context/scan/embedding-text.test.js +0 -36
  582. package/dist/context/scan/enrichment-state.test.d.ts +0 -1
  583. package/dist/context/scan/enrichment-state.test.js +0 -147
  584. package/dist/context/scan/enrichment-summary.test.d.ts +0 -1
  585. package/dist/context/scan/enrichment-summary.test.js +0 -34
  586. package/dist/context/scan/enrichment-types.test.d.ts +0 -1
  587. package/dist/context/scan/enrichment-types.test.js +0 -141
  588. package/dist/context/scan/entity-details.test.d.ts +0 -1
  589. package/dist/context/scan/entity-details.test.js +0 -234
  590. package/dist/context/scan/local-enrichment-artifacts.test.d.ts +0 -1
  591. package/dist/context/scan/local-enrichment-artifacts.test.js +0 -771
  592. package/dist/context/scan/local-enrichment.test.d.ts +0 -1
  593. package/dist/context/scan/local-enrichment.test.js +0 -765
  594. package/dist/context/scan/local-scan.test.d.ts +0 -1
  595. package/dist/context/scan/local-scan.test.js +0 -1663
  596. package/dist/context/scan/local-structural-artifacts.test.d.ts +0 -1
  597. package/dist/context/scan/local-structural-artifacts.test.js +0 -144
  598. package/dist/context/scan/relationship-benchmark-report.test.d.ts +0 -1
  599. package/dist/context/scan/relationship-benchmark-report.test.js +0 -389
  600. package/dist/context/scan/relationship-benchmarks.test.d.ts +0 -1
  601. package/dist/context/scan/relationship-benchmarks.test.js +0 -1072
  602. package/dist/context/scan/relationship-budget.test.d.ts +0 -1
  603. package/dist/context/scan/relationship-budget.test.js +0 -71
  604. package/dist/context/scan/relationship-candidates.test.d.ts +0 -1
  605. package/dist/context/scan/relationship-candidates.test.js +0 -747
  606. package/dist/context/scan/relationship-composite-candidates.test.d.ts +0 -1
  607. package/dist/context/scan/relationship-composite-candidates.test.js +0 -69
  608. package/dist/context/scan/relationship-diagnostics.test.d.ts +0 -1
  609. package/dist/context/scan/relationship-diagnostics.test.js +0 -333
  610. package/dist/context/scan/relationship-discovery.test.d.ts +0 -1
  611. package/dist/context/scan/relationship-discovery.test.js +0 -618
  612. package/dist/context/scan/relationship-formal-metadata.test.d.ts +0 -1
  613. package/dist/context/scan/relationship-formal-metadata.test.js +0 -125
  614. package/dist/context/scan/relationship-graph-resolver.test.d.ts +0 -1
  615. package/dist/context/scan/relationship-graph-resolver.test.js +0 -604
  616. package/dist/context/scan/relationship-llm-proposal.test.d.ts +0 -1
  617. package/dist/context/scan/relationship-llm-proposal.test.js +0 -197
  618. package/dist/context/scan/relationship-locality.test.d.ts +0 -1
  619. package/dist/context/scan/relationship-locality.test.js +0 -128
  620. package/dist/context/scan/relationship-name-similarity.test.d.ts +0 -1
  621. package/dist/context/scan/relationship-name-similarity.test.js +0 -68
  622. package/dist/context/scan/relationship-profiling.test.d.ts +0 -1
  623. package/dist/context/scan/relationship-profiling.test.js +0 -392
  624. package/dist/context/scan/relationship-scoring.test.d.ts +0 -1
  625. package/dist/context/scan/relationship-scoring.test.js +0 -86
  626. package/dist/context/scan/relationship-validation.test.d.ts +0 -1
  627. package/dist/context/scan/relationship-validation.test.js +0 -455
  628. package/dist/context/scan/table-ref.test.d.ts +0 -1
  629. package/dist/context/scan/table-ref.test.js +0 -53
  630. package/dist/context/scan/type-normalization.test.d.ts +0 -1
  631. package/dist/context/scan/type-normalization.test.js +0 -21
  632. package/dist/context/scan/types.test.d.ts +0 -1
  633. package/dist/context/scan/types.test.js +0 -206
  634. package/dist/context/scan/warehouse-catalog.test.d.ts +0 -1
  635. package/dist/context/scan/warehouse-catalog.test.js +0 -158
  636. package/dist/context/search/backend-conformance.test-utils.d.ts +0 -39
  637. package/dist/context/search/backend-conformance.test-utils.js +0 -88
  638. package/dist/context/search/backend-conformance.test-utils.test.d.ts +0 -1
  639. package/dist/context/search/backend-conformance.test-utils.test.js +0 -408
  640. package/dist/context/search/discover.test.d.ts +0 -1
  641. package/dist/context/search/discover.test.js +0 -197
  642. package/dist/context/search/hybrid-search-core.test.d.ts +0 -1
  643. package/dist/context/search/hybrid-search-core.test.js +0 -113
  644. package/dist/context/search/pglite-owner-process.test.d.ts +0 -1
  645. package/dist/context/search/pglite-owner-process.test.js +0 -273
  646. package/dist/context/search/pglite-runtime-boundary.test.d.ts +0 -1
  647. package/dist/context/search/pglite-runtime-boundary.test.js +0 -40
  648. package/dist/context/search/pglite-spike.test.d.ts +0 -1
  649. package/dist/context/search/pglite-spike.test.js +0 -249
  650. package/dist/context/search/query.test.d.ts +0 -1
  651. package/dist/context/search/query.test.js +0 -23
  652. package/dist/context/search/rrf.test.d.ts +0 -1
  653. package/dist/context/search/rrf.test.js +0 -47
  654. package/dist/context/skills/skills-registry.service.test.d.ts +0 -1
  655. package/dist/context/skills/skills-registry.service.test.js +0 -161
  656. package/dist/context/sl/dictionary-search.test.d.ts +0 -1
  657. package/dist/context/sl/dictionary-search.test.js +0 -204
  658. package/dist/context/sl/local-query.test.d.ts +0 -1
  659. package/dist/context/sl/local-query.test.js +0 -283
  660. package/dist/context/sl/local-sl.test.d.ts +0 -1
  661. package/dist/context/sl/local-sl.test.js +0 -334
  662. package/dist/context/sl/pglite-sl-search-prototype.test.d.ts +0 -1
  663. package/dist/context/sl/pglite-sl-search-prototype.test.js +0 -240
  664. package/dist/context/sl/schemas.contract.test.d.ts +0 -1
  665. package/dist/context/sl/schemas.contract.test.js +0 -62
  666. package/dist/context/sl/semantic-layer.service.test.d.ts +0 -1
  667. package/dist/context/sl/semantic-layer.service.test.js +0 -1107
  668. package/dist/context/sl/sl-dictionary-profile.test.d.ts +0 -1
  669. package/dist/context/sl/sl-dictionary-profile.test.js +0 -88
  670. package/dist/context/sl/sl-search.service.test.d.ts +0 -1
  671. package/dist/context/sl/sl-search.service.test.js +0 -256
  672. package/dist/context/sl/sqlite-sl-sources-index.test.d.ts +0 -1
  673. package/dist/context/sl/sqlite-sl-sources-index.test.js +0 -175
  674. package/dist/context/sl/tools/connection-id-schema.test.d.ts +0 -1
  675. package/dist/context/sl/tools/connection-id-schema.test.js +0 -14
  676. package/dist/context/sl/tools/sl-discover.tool.test.d.ts +0 -1
  677. package/dist/context/sl/tools/sl-discover.tool.test.js +0 -72
  678. package/dist/context/sl/tools/sl-edit-source.tool.test.d.ts +0 -1
  679. package/dist/context/sl/tools/sl-edit-source.tool.test.js +0 -184
  680. package/dist/context/sl/tools/sl-read-source.tool.session.test.d.ts +0 -1
  681. package/dist/context/sl/tools/sl-read-source.tool.session.test.js +0 -55
  682. package/dist/context/sl/tools/sl-rollback.tool.test.d.ts +0 -1
  683. package/dist/context/sl/tools/sl-rollback.tool.test.js +0 -57
  684. package/dist/context/sl/tools/sl-validate.tool.test.d.ts +0 -1
  685. package/dist/context/sl/tools/sl-validate.tool.test.js +0 -54
  686. package/dist/context/sl/tools/sl-warehouse-validation.test.d.ts +0 -1
  687. package/dist/context/sl/tools/sl-warehouse-validation.test.js +0 -136
  688. package/dist/context/sl/tools/sl-write-source.tool.test.d.ts +0 -1
  689. package/dist/context/sl/tools/sl-write-source.tool.test.js +0 -307
  690. package/dist/context/sql-analysis/http-sql-analysis-port.test.d.ts +0 -1
  691. package/dist/context/sql-analysis/http-sql-analysis-port.test.js +0 -147
  692. package/dist/context/test/make-local-git-repo.d.ts +0 -10
  693. package/dist/context/test/make-local-git-repo.js +0 -34
  694. package/dist/context/tools/context-evidence-tools.test.d.ts +0 -1
  695. package/dist/context/tools/context-evidence-tools.test.js +0 -486
  696. package/dist/context/tools/touched-sl-sources.test.d.ts +0 -1
  697. package/dist/context/tools/touched-sl-sources.test.js +0 -31
  698. package/dist/context/wiki/knowledge-wiki.service.test.d.ts +0 -1
  699. package/dist/context/wiki/knowledge-wiki.service.test.js +0 -205
  700. package/dist/context/wiki/local-knowledge.test.d.ts +0 -1
  701. package/dist/context/wiki/local-knowledge.test.js +0 -270
  702. package/dist/context/wiki/sqlite-knowledge-index.test.d.ts +0 -1
  703. package/dist/context/wiki/sqlite-knowledge-index.test.js +0 -129
  704. package/dist/context/wiki/tools/wiki-list-tags.tool.test.d.ts +0 -1
  705. package/dist/context/wiki/tools/wiki-list-tags.tool.test.js +0 -35
  706. package/dist/context/wiki/tools/wiki-read.tool.test.d.ts +0 -1
  707. package/dist/context/wiki/tools/wiki-read.tool.test.js +0 -66
  708. package/dist/context/wiki/tools/wiki-remove.tool.test.d.ts +0 -1
  709. package/dist/context/wiki/tools/wiki-remove.tool.test.js +0 -95
  710. package/dist/context/wiki/tools/wiki-search.tool.test.d.ts +0 -1
  711. package/dist/context/wiki/tools/wiki-search.tool.test.js +0 -35
  712. package/dist/context/wiki/tools/wiki-write.tool.test.d.ts +0 -1
  713. package/dist/context/wiki/tools/wiki-write.tool.test.js +0 -264
  714. package/dist/context/wiki/wiki-ref-validation.test.d.ts +0 -1
  715. package/dist/context/wiki/wiki-ref-validation.test.js +0 -64
  716. package/dist/context-build-view.test.d.ts +0 -1
  717. package/dist/context-build-view.test.js +0 -942
  718. package/dist/database-tree-picker.test.d.ts +0 -1
  719. package/dist/database-tree-picker.test.js +0 -188
  720. package/dist/demo-assets.test.d.ts +0 -1
  721. package/dist/demo-assets.test.js +0 -121
  722. package/dist/demo-metrics.test.d.ts +0 -1
  723. package/dist/demo-metrics.test.js +0 -108
  724. package/dist/doctor.test.d.ts +0 -1
  725. package/dist/doctor.test.js +0 -596
  726. package/dist/embedding-resolution.test.d.ts +0 -1
  727. package/dist/embedding-resolution.test.js +0 -132
  728. package/dist/example-smoke.test.d.ts +0 -1
  729. package/dist/example-smoke.test.js +0 -83
  730. package/dist/index.test.d.ts +0 -1
  731. package/dist/index.test.js +0 -1300
  732. package/dist/ingest-query-executor.test.d.ts +0 -1
  733. package/dist/ingest-query-executor.test.js +0 -71
  734. package/dist/ingest-report-file.test.d.ts +0 -1
  735. package/dist/ingest-report-file.test.js +0 -63
  736. package/dist/ingest-viz.test.d.ts +0 -1
  737. package/dist/ingest-viz.test.js +0 -691
  738. package/dist/ingest.test-utils.d.ts +0 -126
  739. package/dist/ingest.test-utils.js +0 -629
  740. package/dist/ingest.test.d.ts +0 -1
  741. package/dist/ingest.test.js +0 -1568
  742. package/dist/io/logger.test.d.ts +0 -1
  743. package/dist/io/logger.test.js +0 -55
  744. package/dist/io/mode.test.d.ts +0 -1
  745. package/dist/io/mode.test.js +0 -48
  746. package/dist/io/print-list.test.d.ts +0 -1
  747. package/dist/io/print-list.test.js +0 -277
  748. package/dist/knowledge.test.d.ts +0 -1
  749. package/dist/knowledge.test.js +0 -198
  750. package/dist/llm/embedding-health.test.d.ts +0 -1
  751. package/dist/llm/embedding-health.test.js +0 -72
  752. package/dist/llm/embedding-provider.test.d.ts +0 -1
  753. package/dist/llm/embedding-provider.test.js +0 -84
  754. package/dist/llm/message-builder.test.d.ts +0 -1
  755. package/dist/llm/message-builder.test.js +0 -127
  756. package/dist/llm/model-health.test.d.ts +0 -1
  757. package/dist/llm/model-health.test.js +0 -55
  758. package/dist/llm/model-provider.test.d.ts +0 -1
  759. package/dist/llm/model-provider.test.js +0 -246
  760. package/dist/llm/repair.test.d.ts +0 -1
  761. package/dist/llm/repair.test.js +0 -78
  762. package/dist/local-adapters.test.d.ts +0 -1
  763. package/dist/local-adapters.test.js +0 -166
  764. package/dist/local-scan-connectors.test.d.ts +0 -1
  765. package/dist/local-scan-connectors.test.js +0 -92
  766. package/dist/managed-local-embeddings.test.d.ts +0 -1
  767. package/dist/managed-local-embeddings.test.js +0 -229
  768. package/dist/managed-mcp-daemon.test.d.ts +0 -1
  769. package/dist/managed-mcp-daemon.test.js +0 -187
  770. package/dist/managed-python-command.test.d.ts +0 -1
  771. package/dist/managed-python-command.test.js +0 -262
  772. package/dist/managed-python-daemon.test.d.ts +0 -1
  773. package/dist/managed-python-daemon.test.js +0 -360
  774. package/dist/managed-python-http.test.d.ts +0 -1
  775. package/dist/managed-python-http.test.js +0 -177
  776. package/dist/managed-python-runtime.test.d.ts +0 -1
  777. package/dist/managed-python-runtime.test.js +0 -426
  778. package/dist/mcp-http-server.test.d.ts +0 -1
  779. package/dist/mcp-http-server.test.js +0 -209
  780. package/dist/mcp-server-factory.test.d.ts +0 -1
  781. package/dist/mcp-server-factory.test.js +0 -142
  782. package/dist/memory-flow-interactive.test.d.ts +0 -1
  783. package/dist/memory-flow-interactive.test.js +0 -109
  784. package/dist/memory-flow-tui.test.d.ts +0 -1
  785. package/dist/memory-flow-tui.test.js +0 -247
  786. package/dist/next-steps.test.d.ts +0 -1
  787. package/dist/next-steps.test.js +0 -77
  788. package/dist/notion-page-picker.test.d.ts +0 -1
  789. package/dist/notion-page-picker.test.js +0 -244
  790. package/dist/print-command-tree.test.d.ts +0 -1
  791. package/dist/print-command-tree.test.js +0 -37
  792. package/dist/project-dir.test.d.ts +0 -1
  793. package/dist/project-dir.test.js +0 -124
  794. package/dist/project-resolver.test.d.ts +0 -1
  795. package/dist/project-resolver.test.js +0 -49
  796. package/dist/prompt-navigation.test.d.ts +0 -1
  797. package/dist/prompt-navigation.test.js +0 -33
  798. package/dist/proxy-env.test.d.ts +0 -1
  799. package/dist/proxy-env.test.js +0 -17
  800. package/dist/public-ingest-copy.test.d.ts +0 -1
  801. package/dist/public-ingest-copy.test.js +0 -24
  802. package/dist/public-ingest.test.d.ts +0 -1
  803. package/dist/public-ingest.test.js +0 -891
  804. package/dist/runtime-requirements.test.d.ts +0 -1
  805. package/dist/runtime-requirements.test.js +0 -73
  806. package/dist/runtime.test.d.ts +0 -1
  807. package/dist/runtime.test.js +0 -381
  808. package/dist/scan.test.d.ts +0 -1
  809. package/dist/scan.test.js +0 -1123
  810. package/dist/setup-agents.test.d.ts +0 -1
  811. package/dist/setup-agents.test.js +0 -1028
  812. package/dist/setup-context.test.d.ts +0 -1
  813. package/dist/setup-context.test.js +0 -491
  814. package/dist/setup-databases.test.d.ts +0 -1
  815. package/dist/setup-databases.test.js +0 -2101
  816. package/dist/setup-demo-tour.test.d.ts +0 -1
  817. package/dist/setup-demo-tour.test.js +0 -221
  818. package/dist/setup-embeddings.test.d.ts +0 -1
  819. package/dist/setup-embeddings.test.js +0 -436
  820. package/dist/setup-interrupt.test.d.ts +0 -1
  821. package/dist/setup-interrupt.test.js +0 -77
  822. package/dist/setup-models.test.d.ts +0 -1
  823. package/dist/setup-models.test.js +0 -885
  824. package/dist/setup-project.test.d.ts +0 -1
  825. package/dist/setup-project.test.js +0 -209
  826. package/dist/setup-prompts.test.d.ts +0 -1
  827. package/dist/setup-prompts.test.js +0 -208
  828. package/dist/setup-ready-menu.test.d.ts +0 -1
  829. package/dist/setup-ready-menu.test.js +0 -44
  830. package/dist/setup-runtime.test.d.ts +0 -1
  831. package/dist/setup-runtime.test.js +0 -111
  832. package/dist/setup-secrets.test.d.ts +0 -1
  833. package/dist/setup-secrets.test.js +0 -30
  834. package/dist/setup-sources-notion.test.d.ts +0 -1
  835. package/dist/setup-sources-notion.test.js +0 -109
  836. package/dist/setup-sources.test.d.ts +0 -1
  837. package/dist/setup-sources.test.js +0 -1303
  838. package/dist/setup.test.d.ts +0 -1
  839. package/dist/setup.test.js +0 -1825
  840. package/dist/sl.test.d.ts +0 -1
  841. package/dist/sl.test.js +0 -567
  842. package/dist/source-mapping.test.d.ts +0 -1
  843. package/dist/source-mapping.test.js +0 -65
  844. package/dist/sql.test.d.ts +0 -1
  845. package/dist/sql.test.js +0 -253
  846. package/dist/standalone-smoke.test.d.ts +0 -1
  847. package/dist/standalone-smoke.test.js +0 -250
  848. package/dist/status-project.test.d.ts +0 -1
  849. package/dist/status-project.test.js +0 -502
  850. package/dist/telemetry/command-hook.test.d.ts +0 -1
  851. package/dist/telemetry/command-hook.test.js +0 -31
  852. package/dist/telemetry/demo-detect.test.d.ts +0 -1
  853. package/dist/telemetry/demo-detect.test.js +0 -22
  854. package/dist/telemetry/emitter.test.d.ts +0 -1
  855. package/dist/telemetry/emitter.test.js +0 -103
  856. package/dist/telemetry/events.snapshot.test.d.ts +0 -1
  857. package/dist/telemetry/events.snapshot.test.js +0 -135
  858. package/dist/telemetry/events.test.d.ts +0 -1
  859. package/dist/telemetry/events.test.js +0 -136
  860. package/dist/telemetry/identity.test.d.ts +0 -1
  861. package/dist/telemetry/identity.test.js +0 -148
  862. package/dist/telemetry/project-snapshot.test.d.ts +0 -1
  863. package/dist/telemetry/project-snapshot.test.js +0 -71
  864. package/dist/telemetry/schema-writer.test.d.ts +0 -1
  865. package/dist/telemetry/schema-writer.test.js +0 -23
  866. package/dist/telemetry/scrubber.test.d.ts +0 -1
  867. package/dist/telemetry/scrubber.test.js +0 -21
  868. package/dist/text-ingest.test.d.ts +0 -1
  869. package/dist/text-ingest.test.js +0 -247
  870. package/dist/tree-picker-state.test.d.ts +0 -1
  871. package/dist/tree-picker-state.test.js +0 -303
  872. package/dist/tree-picker-tui.test.d.ts +0 -1
  873. package/dist/tree-picker-tui.test.js +0 -248
  874. package/dist/viz-fallback.test.d.ts +0 -1
  875. package/dist/viz-fallback.test.js +0 -77
@@ -1,1663 +0,0 @@
1
- import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
- import YAML from 'yaml';
6
- import { initKtxProject, loadKtxProject } from '../../context/project/project.js';
7
- import { resolveEnabledTables } from './enabled-tables.js';
8
- import { getLocalScanReport, getLocalScanStatus, runLocalScan } from './local-scan.js';
9
- import { tableRefKey, tableRefSet } from './table-ref.js';
10
- function relationshipSqlResult(input, options = {}) {
11
- if (input.sql.includes('child_values')) {
12
- if (options.throwOnCoverage) {
13
- throw new Error('validation failed for postgres://reader:secret@example.test/db'); // pragma: allowlist secret
14
- }
15
- return {
16
- headers: ['child_distinct', 'parent_distinct', 'overlap', 'violation_count'],
17
- rows: [[100, 100, 99, 0]],
18
- totalRows: 1,
19
- rowCount: 1,
20
- };
21
- }
22
- if (input.sql.includes(' AS column_name')) {
23
- const tableRowCount = input.sql.includes('orders') || input.sql.includes('users') ? 1000 : 100;
24
- const columnNames = Array.from(input.sql.matchAll(/'([^']+)' AS column_name/g), (match) => match[1]);
25
- return {
26
- headers: [
27
- 'column_name',
28
- 'table_row_count',
29
- 'row_count',
30
- 'null_count',
31
- 'distinct_count',
32
- 'min_text_length',
33
- 'max_text_length',
34
- 'sample_values',
35
- ],
36
- rows: columnNames.map((columnName) => [
37
- columnName,
38
- tableRowCount,
39
- tableRowCount,
40
- 0,
41
- columnName === 'id' ? tableRowCount : 100,
42
- 1,
43
- 3,
44
- '1\u001f2',
45
- ]),
46
- totalRows: columnNames.length,
47
- rowCount: columnNames.length,
48
- };
49
- }
50
- if (input.sql.includes('COUNT(*) AS row_count') && !input.sql.includes('COUNT(DISTINCT')) {
51
- return {
52
- headers: ['row_count'],
53
- rows: [[input.sql.includes('orders') ? 1000 : 100]],
54
- totalRows: 1,
55
- rowCount: 1,
56
- };
57
- }
58
- if (input.sql.includes('COUNT(DISTINCT')) {
59
- return {
60
- headers: ['row_count', 'null_count', 'distinct_count', 'min_text_length', 'max_text_length'],
61
- rows: [[input.sql.includes('orders') ? 1000 : 100, 0, input.sql.includes('orders') ? 100 : 100, 1, 3]],
62
- totalRows: 1,
63
- rowCount: 1,
64
- };
65
- }
66
- if (input.sql.includes(' AS value')) {
67
- return {
68
- headers: ['value'],
69
- rows: [[1], [2]],
70
- totalRows: 2,
71
- rowCount: 2,
72
- };
73
- }
74
- throw new Error(`Unexpected relationship SQL: ${input.sql}`);
75
- }
76
- function deterministicLlmRuntime() {
77
- return {
78
- generateText: vi.fn(async (input) => `Deterministic description for ${input.prompt.slice(0, 64).trim() || 'data source'}`),
79
- generateObject: vi.fn(async () => ({ pkCandidates: [], fkCandidates: [] })),
80
- runAgentLoop: vi.fn(),
81
- };
82
- }
83
- async function writeLiveDatabaseConfig(projectDir) {
84
- await writeFile(join(projectDir, 'ktx.yaml'), [
85
- 'connections:',
86
- ' warehouse:',
87
- ' driver: postgres',
88
- ' url: env:DATABASE_URL',
89
- 'ingest:',
90
- ' adapters:',
91
- ' - live-database',
92
- '',
93
- ].join('\n'), 'utf-8');
94
- }
95
- async function writeDatabaseConfigWithoutIngestAdapters(projectDir) {
96
- await writeFile(join(projectDir, 'ktx.yaml'), [
97
- 'connections:',
98
- ' warehouse:',
99
- ' driver: postgres',
100
- ' url: env:DATABASE_URL',
101
- ' readonly: true',
102
- '',
103
- ].join('\n'), 'utf-8');
104
- }
105
- function defaultFetchSnapshot(options = {}) {
106
- return {
107
- connectionId: 'warehouse',
108
- driver: 'postgres',
109
- extractedAt: options.extractedAt?.() ?? '2026-04-29T09:00:00.000Z',
110
- scope: { schemas: ['public'] },
111
- metadata: {},
112
- tables: [
113
- {
114
- name: 'orders',
115
- catalog: null,
116
- db: 'public',
117
- kind: 'table',
118
- comment: null,
119
- estimatedRows: null,
120
- columns: [
121
- {
122
- name: 'id',
123
- nativeType: 'integer',
124
- normalizedType: 'integer',
125
- dimensionType: 'number',
126
- nullable: false,
127
- primaryKey: true,
128
- comment: null,
129
- },
130
- ],
131
- foreignKeys: [],
132
- },
133
- ],
134
- };
135
- }
136
- function fetchOnlyAdapter(options = {}) {
137
- const scanSnapshot = options.snapshot
138
- ? { ...options.snapshot, ...(options.extractedAt ? { extractedAt: options.extractedAt() } : {}) }
139
- : defaultFetchSnapshot(options);
140
- return {
141
- source: 'live-database',
142
- skillNames: ['live_database_ingest'],
143
- async fetch(_pullConfig, stagedDir) {
144
- await mkdir(join(stagedDir, 'tables'), { recursive: true });
145
- await writeFile(join(stagedDir, 'connection.json'), `${JSON.stringify({
146
- connectionId: scanSnapshot.connectionId,
147
- driver: scanSnapshot.driver,
148
- extractedAt: scanSnapshot.extractedAt,
149
- scope: scanSnapshot.scope,
150
- metadata: scanSnapshot.metadata,
151
- })}\n`, 'utf-8');
152
- await writeFile(join(stagedDir, 'foreign-keys.json'), '{"foreignKeys":[]}\n', 'utf-8');
153
- for (const table of scanSnapshot.tables) {
154
- await writeFile(join(stagedDir, 'tables', `${table.name}.json`), `${JSON.stringify(table)}\n`, 'utf-8');
155
- }
156
- },
157
- async detect() {
158
- return true;
159
- },
160
- async chunk() {
161
- return {
162
- workUnits: scanSnapshot.tables.map((table) => ({
163
- unitKey: `live-database-${table.db ?? 'default'}-${table.name}`,
164
- rawFiles: [`tables/${table.name}.json`],
165
- dependencyPaths: ['connection.json', 'foreign-keys.json'],
166
- peerFileIndex: [],
167
- })),
168
- };
169
- },
170
- };
171
- }
172
- function nativeScanSnapshot() {
173
- return {
174
- connectionId: 'warehouse',
175
- driver: 'postgres',
176
- extractedAt: '2026-04-29T09:00:00.000Z',
177
- scope: { schemas: ['public'] },
178
- metadata: {},
179
- tables: [
180
- {
181
- catalog: null,
182
- db: 'public',
183
- name: 'orders',
184
- kind: 'table',
185
- comment: 'Orders',
186
- estimatedRows: 1,
187
- foreignKeys: [],
188
- columns: [
189
- {
190
- name: 'id',
191
- nativeType: 'integer',
192
- normalizedType: 'integer',
193
- dimensionType: 'number',
194
- nullable: false,
195
- primaryKey: true,
196
- comment: 'Order id',
197
- },
198
- ],
199
- },
200
- ],
201
- };
202
- }
203
- function nativeScanConnector(options = {}) {
204
- return {
205
- id: 'test:warehouse',
206
- driver: 'postgres',
207
- capabilities: {
208
- structuralIntrospection: true,
209
- tableSampling: true,
210
- columnSampling: true,
211
- columnStats: false,
212
- readOnlySql: false,
213
- nestedAnalysis: false,
214
- eventStreamDiscovery: false,
215
- formalForeignKeys: false,
216
- estimatedRowCounts: false,
217
- },
218
- introspect: vi.fn(async () => nativeScanSnapshot()),
219
- sampleTable: vi.fn(async () => ({ headers: ['id'], rows: [[1]], totalRows: 1 })),
220
- sampleColumn: vi.fn(async () => ({ values: ['1'], nullCount: 0, distinctCount: 1 })),
221
- ...(options.cleanup ? { cleanup: options.cleanup } : {}),
222
- };
223
- }
224
- describe('local scan', () => {
225
- let tempDir;
226
- let project;
227
- beforeEach(async () => {
228
- tempDir = await mkdtemp(join(tmpdir(), 'ktx-local-scan-'));
229
- const projectDir = join(tempDir, 'project');
230
- await initKtxProject({ projectDir });
231
- await writeLiveDatabaseConfig(projectDir);
232
- project = await loadKtxProject({ projectDir });
233
- });
234
- afterEach(async () => {
235
- await rm(tempDir, { recursive: true, force: true });
236
- });
237
- it('runs a structural live-database scan and writes a durable scan report', async () => {
238
- const result = await runLocalScan({
239
- project,
240
- adapters: [fetchOnlyAdapter()],
241
- connectionId: 'warehouse',
242
- jobId: 'scan-run-1',
243
- now: () => new Date('2026-04-29T09:00:00.000Z'),
244
- });
245
- expect(result.report).toMatchObject({
246
- connectionId: 'warehouse',
247
- driver: 'postgres',
248
- runId: 'scan-run-1',
249
- syncId: '2026-04-29-090000-scan-run-1',
250
- trigger: 'cli',
251
- mode: 'structural',
252
- dryRun: false,
253
- artifactPaths: {
254
- rawSourcesDir: 'raw-sources/warehouse/live-database/2026-04-29-090000-scan-run-1',
255
- reportPath: 'raw-sources/warehouse/live-database/2026-04-29-090000-scan-run-1/scan-report.json',
256
- manifestShards: ['semantic-layer/warehouse/_schema/public.yaml'],
257
- enrichmentArtifacts: [],
258
- },
259
- diffSummary: {
260
- tablesAdded: 1,
261
- tablesModified: 0,
262
- tablesDeleted: 0,
263
- tablesUnchanged: 0,
264
- columnsAdded: 0,
265
- columnsModified: 0,
266
- columnsDeleted: 0,
267
- },
268
- manifestShardsWritten: 1,
269
- relationships: { accepted: 0, review: 0, rejected: 0, skipped: 0 },
270
- });
271
- await expect(readFile(join(project.projectDir, 'raw-sources/warehouse/live-database/2026-04-29-090000-scan-run-1/scan-report.json'), 'utf-8')).resolves.toContain('"runId": "scan-run-1"');
272
- const structuralManifest = await readFile(join(project.projectDir, 'semantic-layer/warehouse/_schema/public.yaml'), 'utf-8');
273
- expect(structuralManifest).toContain('orders:');
274
- expect(structuralManifest).toContain('table: public.orders');
275
- expect(structuralManifest).toContain('name: id');
276
- expect(structuralManifest).not.toContain('ai:');
277
- await expect(getLocalScanStatus(project, 'scan-run-1')).resolves.toMatchObject({
278
- runId: 'scan-run-1',
279
- status: 'done',
280
- done: true,
281
- connectionId: 'warehouse',
282
- mode: 'structural',
283
- reportPath: 'raw-sources/warehouse/live-database/2026-04-29-090000-scan-run-1/scan-report.json',
284
- });
285
- await expect(getLocalScanReport(project, 'scan-run-1')).resolves.toMatchObject({
286
- runId: 'scan-run-1',
287
- connectionId: 'warehouse',
288
- });
289
- });
290
- it('passes enabled_tables as fetch context tableScope and does not post-filter staged snapshots', async () => {
291
- project.config.connections.warehouse = {
292
- ...project.config.connections.warehouse,
293
- enabled_tables: ['public.orders'],
294
- };
295
- let capturedTableScope;
296
- const adapter = {
297
- source: 'live-database',
298
- skillNames: ['live_database_ingest'],
299
- async fetch(_pullConfig, stagedDir, ctx) {
300
- capturedTableScope = ctx.tableScope;
301
- await mkdir(join(stagedDir, 'tables'), { recursive: true });
302
- await writeFile(join(stagedDir, 'connection.json'), '{"connectionId":"warehouse","driver":"postgres","scope":{"schemas":["public"]},"metadata":{}}\n', 'utf-8');
303
- await writeFile(join(stagedDir, 'foreign-keys.json'), '{"foreignKeys":[]}\n', 'utf-8');
304
- await writeFile(join(stagedDir, 'tables', 'customers.json'), '{"name":"customers","catalog":null,"db":"public","kind":"table","comment":null,"estimatedRows":100,"columns":[{"name":"id","nativeType":"integer","normalizedType":"integer","dimensionType":"number","nullable":false,"primaryKey":true,"comment":null}],"foreignKeys":[]}\n', 'utf-8');
305
- await writeFile(join(stagedDir, 'tables', 'orders.json'), '{"name":"orders","catalog":null,"db":"public","kind":"table","comment":null,"estimatedRows":1000,"columns":[{"name":"id","nativeType":"integer","normalizedType":"integer","dimensionType":"number","nullable":false,"primaryKey":true,"comment":null}],"foreignKeys":[]}\n', 'utf-8');
306
- },
307
- async detect() {
308
- return true;
309
- },
310
- async chunk() {
311
- return {
312
- workUnits: [
313
- {
314
- unitKey: 'live-database-public-customers',
315
- rawFiles: ['tables/customers.json'],
316
- dependencyPaths: ['connection.json', 'foreign-keys.json'],
317
- peerFileIndex: [],
318
- },
319
- {
320
- unitKey: 'live-database-public-orders',
321
- rawFiles: ['tables/orders.json'],
322
- dependencyPaths: ['connection.json', 'foreign-keys.json'],
323
- peerFileIndex: [],
324
- },
325
- ],
326
- };
327
- },
328
- };
329
- const result = await runLocalScan({
330
- project,
331
- adapters: [adapter],
332
- connectionId: 'warehouse',
333
- jobId: 'scan-strict-scope-fetch',
334
- now: () => new Date('2026-05-22T00:00:00.000Z'),
335
- });
336
- expect([...(capturedTableScope ?? [])]).toEqual([...tableRefSet([{ catalog: null, db: 'public', name: 'orders' }])]);
337
- expect(result.report.diffSummary.tablesAdded).toBe(2);
338
- const structuralManifest = await readFile(join(project.projectDir, 'semantic-layer/warehouse/_schema/public.yaml'), 'utf-8');
339
- expect(structuralManifest).toContain('customers:');
340
- expect(structuralManifest).toContain('orders:');
341
- });
342
- it('runs a structural database scan when live-database is not listed in ktx.yaml', async () => {
343
- await writeDatabaseConfigWithoutIngestAdapters(project.projectDir);
344
- project = await loadKtxProject({ projectDir: project.projectDir });
345
- const result = await runLocalScan({
346
- project,
347
- adapters: [fetchOnlyAdapter()],
348
- connectionId: 'warehouse',
349
- jobId: 'scan-run-without-public-adapter',
350
- now: () => new Date('2026-04-29T09:10:00.000Z'),
351
- });
352
- expect(result.report).toMatchObject({
353
- connectionId: 'warehouse',
354
- runId: 'scan-run-without-public-adapter',
355
- artifactPaths: {
356
- reportPath: 'raw-sources/warehouse/live-database/2026-04-29-091000-scan-run-without-public-adapter/scan-report.json',
357
- },
358
- });
359
- });
360
- it('threads the structural snapshot into enrichment without connector re-introspection', async () => {
361
- project.config.scan.enrichment = { mode: 'deterministic' };
362
- const connector = nativeScanConnector();
363
- const introspect = vi.mocked(connector.introspect);
364
- const result = await runLocalScan({
365
- project,
366
- adapters: [fetchOnlyAdapter()],
367
- connectionId: 'warehouse',
368
- mode: 'enriched',
369
- connector,
370
- jobId: 'scan-enrichment-snapshot-threading',
371
- now: () => new Date('2026-04-29T09:11:00.000Z'),
372
- });
373
- expect(result.report.enrichment.tableDescriptions).toBe('completed');
374
- expect(introspect).not.toHaveBeenCalled();
375
- });
376
- it('cleans up a scan connector constructed by local scan', async () => {
377
- const cleanup = vi.fn(async () => undefined);
378
- await runLocalScan({
379
- project,
380
- adapters: [fetchOnlyAdapter()],
381
- connectionId: 'warehouse',
382
- mode: 'relationships',
383
- detectRelationships: true,
384
- createConnector: vi.fn(async () => nativeScanConnector({ cleanup })),
385
- jobId: 'scan-owned-connector-cleanup',
386
- now: () => new Date('2026-04-29T09:13:00.000Z'),
387
- });
388
- expect(cleanup).toHaveBeenCalledTimes(1);
389
- });
390
- it('does not clean up a caller-supplied scan connector', async () => {
391
- const cleanup = vi.fn(async () => undefined);
392
- await runLocalScan({
393
- project,
394
- adapters: [fetchOnlyAdapter()],
395
- connectionId: 'warehouse',
396
- mode: 'relationships',
397
- detectRelationships: true,
398
- connector: nativeScanConnector({ cleanup }),
399
- jobId: 'scan-supplied-connector-cleanup',
400
- now: () => new Date('2026-04-29T09:13:30.000Z'),
401
- });
402
- expect(cleanup).not.toHaveBeenCalled();
403
- });
404
- it('reuses scan report and raw-source paths when the same local scan run id is retried', async () => {
405
- const first = await runLocalScan({
406
- project,
407
- adapters: [fetchOnlyAdapter()],
408
- connectionId: 'warehouse',
409
- jobId: 'scan-idempotent-run',
410
- now: () => new Date('2026-04-29T09:20:00.000Z'),
411
- });
412
- const retry = await runLocalScan({
413
- project,
414
- adapters: [fetchOnlyAdapter()],
415
- connectionId: 'warehouse',
416
- jobId: 'scan-idempotent-run',
417
- now: () => new Date('2026-04-29T10:20:00.000Z'),
418
- });
419
- expect(retry.runId).toBe(first.runId);
420
- expect(retry.syncId).toBe(first.syncId);
421
- expect(retry.report.artifactPaths.rawSourcesDir).toBe(first.report.artifactPaths.rawSourcesDir);
422
- expect(retry.report.artifactPaths.reportPath).toBe(first.report.artifactPaths.reportPath);
423
- expect(retry.report.artifactPaths.manifestShards).toEqual(first.report.artifactPaths.manifestShards);
424
- const status = await getLocalScanStatus(project, 'scan-idempotent-run');
425
- expect(status?.syncId).toBe(first.syncId);
426
- expect(status?.reportPath).toBe(first.report.artifactPaths.reportPath);
427
- const files = await project.fileStore.listFiles('raw-sources/warehouse/live-database');
428
- expect(files.files.every((file) => file.includes('2026-04-29-092000-scan-idempotent-run'))).toBe(true);
429
- expect(files.files.some((file) => file.includes('2026-04-29-102000-scan-idempotent-run'))).toBe(false);
430
- });
431
- it('reuses existing scan artifacts without writing when a new scan run has unchanged input', async () => {
432
- let extractedAt = '2026-04-29T09:25:00.000Z';
433
- const adapter = fetchOnlyAdapter({ extractedAt: () => extractedAt });
434
- const first = await runLocalScan({
435
- project,
436
- adapters: [adapter],
437
- connectionId: 'warehouse',
438
- jobId: 'scan-idempotent-new-run-1',
439
- now: () => new Date('2026-04-29T09:25:00.000Z'),
440
- });
441
- const writeSpy = vi.spyOn(project.fileStore, 'writeFile');
442
- const commitSpy = vi.spyOn(project.git, 'commitFiles');
443
- extractedAt = '2026-04-29T10:25:00.000Z';
444
- const second = await runLocalScan({
445
- project,
446
- adapters: [adapter],
447
- connectionId: 'warehouse',
448
- jobId: 'scan-idempotent-new-run-2',
449
- now: () => new Date('2026-04-29T10:25:00.000Z'),
450
- });
451
- expect(second.runId).toBe('scan-idempotent-new-run-2');
452
- expect(second.syncId).toBe(first.syncId);
453
- expect(second.report.runId).toBe('scan-idempotent-new-run-2');
454
- expect(second.report.artifactPaths.rawSourcesDir).toBe(first.report.artifactPaths.rawSourcesDir);
455
- expect(second.report.artifactPaths.reportPath).toBe(first.report.artifactPaths.reportPath);
456
- expect(second.report.artifactPaths.manifestShards).toEqual(first.report.artifactPaths.manifestShards);
457
- expect(second.report.diffSummary).toMatchObject({
458
- tablesAdded: 0,
459
- tablesModified: 0,
460
- tablesDeleted: 0,
461
- tablesUnchanged: 1,
462
- });
463
- expect(writeSpy).not.toHaveBeenCalled();
464
- expect(commitSpy).not.toHaveBeenCalled();
465
- await expect(getLocalScanReport(project, 'scan-idempotent-new-run-2')).resolves.toMatchObject({
466
- runId: 'scan-idempotent-new-run-2',
467
- syncId: first.syncId,
468
- diffSummary: {
469
- tablesAdded: 0,
470
- tablesModified: 0,
471
- tablesDeleted: 0,
472
- tablesUnchanged: 1,
473
- columnsAdded: 0,
474
- columnsModified: 0,
475
- columnsDeleted: 0,
476
- },
477
- });
478
- const files = await project.fileStore.listFiles('raw-sources/warehouse/live-database');
479
- expect(files.files.every((file) => file.includes(first.syncId))).toBe(true);
480
- writeSpy.mockRestore();
481
- commitSpy.mockRestore();
482
- });
483
- it('returns an in-memory dry-run report without persisting scan status or report files', async () => {
484
- const result = await runLocalScan({
485
- project,
486
- adapters: [fetchOnlyAdapter()],
487
- connectionId: 'warehouse',
488
- jobId: 'scan-dry-run-1',
489
- now: () => new Date('2026-04-29T09:05:00.000Z'),
490
- dryRun: true,
491
- });
492
- expect(result.report).toMatchObject({
493
- runId: 'scan-dry-run-1',
494
- dryRun: true,
495
- artifactPaths: {
496
- rawSourcesDir: null,
497
- reportPath: null,
498
- manifestShards: [],
499
- enrichmentArtifacts: [],
500
- },
501
- });
502
- await expect(getLocalScanStatus(project, 'scan-dry-run-1')).resolves.toBeNull();
503
- await expect(getLocalScanReport(project, 'scan-dry-run-1')).resolves.toBeNull();
504
- });
505
- it('runs relationship scans through a native scan connector and records relationship summary', async () => {
506
- const connector = {
507
- id: 'test:warehouse',
508
- driver: 'postgres',
509
- capabilities: {
510
- structuralIntrospection: true,
511
- tableSampling: false,
512
- columnSampling: false,
513
- columnStats: false,
514
- readOnlySql: false,
515
- nestedAnalysis: false,
516
- eventStreamDiscovery: false,
517
- formalForeignKeys: false,
518
- estimatedRowCounts: false,
519
- },
520
- async introspect() {
521
- return {
522
- connectionId: 'warehouse',
523
- driver: 'postgres',
524
- extractedAt: '2026-04-29T09:00:00.000Z',
525
- scope: { schemas: ['public'] },
526
- metadata: {},
527
- tables: [
528
- {
529
- catalog: null,
530
- db: 'public',
531
- name: 'customers',
532
- kind: 'table',
533
- comment: null,
534
- estimatedRows: null,
535
- foreignKeys: [],
536
- columns: [
537
- {
538
- name: 'id',
539
- nativeType: 'integer',
540
- normalizedType: 'integer',
541
- dimensionType: 'number',
542
- nullable: false,
543
- primaryKey: true,
544
- comment: null,
545
- },
546
- ],
547
- },
548
- {
549
- catalog: null,
550
- db: 'public',
551
- name: 'orders',
552
- kind: 'table',
553
- comment: null,
554
- estimatedRows: null,
555
- foreignKeys: [],
556
- columns: [
557
- {
558
- name: 'customer_id',
559
- nativeType: 'integer',
560
- normalizedType: 'integer',
561
- dimensionType: 'number',
562
- nullable: false,
563
- primaryKey: false,
564
- comment: null,
565
- },
566
- ],
567
- },
568
- ],
569
- };
570
- },
571
- };
572
- const adapter = fetchOnlyAdapter({ snapshot: await connector.introspect() });
573
- const result = await runLocalScan({
574
- project,
575
- adapters: [adapter],
576
- connectionId: 'warehouse',
577
- mode: 'relationships',
578
- detectRelationships: true,
579
- connector,
580
- jobId: 'scan-relationships-1',
581
- now: () => new Date('2026-04-29T09:10:00.000Z'),
582
- });
583
- expect(result.report.mode).toBe('relationships');
584
- expect(result.report.enrichment.deterministicRelationships).toBe('completed');
585
- expect(result.report.relationships).toEqual({ accepted: 0, review: 1, rejected: 0, skipped: 0 });
586
- });
587
- it('records standalone statistical validation results in the scan report', async () => {
588
- const connector = {
589
- id: 'test:warehouse',
590
- driver: 'postgres',
591
- capabilities: {
592
- structuralIntrospection: true,
593
- tableSampling: false,
594
- columnSampling: false,
595
- columnStats: true,
596
- readOnlySql: true,
597
- nestedAnalysis: false,
598
- eventStreamDiscovery: false,
599
- formalForeignKeys: false,
600
- estimatedRowCounts: true,
601
- },
602
- async introspect() {
603
- return {
604
- connectionId: 'warehouse',
605
- driver: 'postgres',
606
- extractedAt: '2026-04-29T09:00:00.000Z',
607
- scope: { schemas: ['public'] },
608
- metadata: {},
609
- tables: [
610
- {
611
- catalog: null,
612
- db: 'public',
613
- name: 'customers',
614
- kind: 'table',
615
- comment: null,
616
- estimatedRows: 100,
617
- foreignKeys: [],
618
- columns: [
619
- {
620
- name: 'id',
621
- nativeType: 'integer',
622
- normalizedType: 'integer',
623
- dimensionType: 'number',
624
- nullable: false,
625
- primaryKey: true,
626
- comment: null,
627
- },
628
- ],
629
- },
630
- {
631
- catalog: null,
632
- db: 'public',
633
- name: 'orders',
634
- kind: 'table',
635
- comment: null,
636
- estimatedRows: 1000,
637
- foreignKeys: [],
638
- columns: [
639
- {
640
- name: 'customer_id',
641
- nativeType: 'integer',
642
- normalizedType: 'integer',
643
- dimensionType: 'number',
644
- nullable: false,
645
- primaryKey: false,
646
- comment: null,
647
- },
648
- ],
649
- },
650
- ],
651
- };
652
- },
653
- async executeReadOnly(input) {
654
- return relationshipSqlResult(input);
655
- },
656
- };
657
- const adapter = fetchOnlyAdapter({ snapshot: await connector.introspect() });
658
- const result = await runLocalScan({
659
- project,
660
- adapters: [adapter],
661
- connectionId: 'warehouse',
662
- mode: 'relationships',
663
- detectRelationships: true,
664
- connector,
665
- jobId: 'scan-statistical-relationships-1',
666
- now: () => new Date('2026-04-29T09:12:00.000Z'),
667
- });
668
- expect(result.report.enrichment.statisticalValidation).toBe('completed');
669
- expect(result.report.relationships).toEqual({ accepted: 1, review: 0, rejected: 0, skipped: 0 });
670
- expect(result.report.warnings).toEqual([]);
671
- });
672
- it('keeps prototype connector methods when enabled_tables is configured', async () => {
673
- project.config.connections.warehouse = {
674
- ...project.config.connections.warehouse,
675
- enabled_tables: ['public.customers', 'public.orders'],
676
- };
677
- const scopedAdapter = {
678
- source: 'live-database',
679
- skillNames: ['live_database_ingest'],
680
- async fetch(_pullConfig, stagedDir) {
681
- await mkdir(join(stagedDir, 'tables'), { recursive: true });
682
- await writeFile(join(stagedDir, 'connection.json'), '{"connectionId":"warehouse","driver":"postgres","scope":{"schemas":["public"]},"metadata":{}}\n', 'utf-8');
683
- await writeFile(join(stagedDir, 'foreign-keys.json'), '{"foreignKeys":[]}\n', 'utf-8');
684
- await writeFile(join(stagedDir, 'tables', 'customers.json'), '{"name":"customers","catalog":null,"db":"public","kind":"table","comment":null,"estimatedRows":100,"columns":[{"name":"id","nativeType":"integer","normalizedType":"integer","dimensionType":"number","nullable":false,"primaryKey":true,"comment":null}],"foreignKeys":[]}\n', 'utf-8');
685
- await writeFile(join(stagedDir, 'tables', 'orders.json'), '{"name":"orders","catalog":null,"db":"public","kind":"table","comment":null,"estimatedRows":1000,"columns":[{"name":"customer_id","nativeType":"integer","normalizedType":"integer","dimensionType":"number","nullable":false,"primaryKey":false,"comment":null}],"foreignKeys":[]}\n', 'utf-8');
686
- },
687
- async detect() {
688
- return true;
689
- },
690
- async chunk() {
691
- return {
692
- workUnits: [
693
- {
694
- unitKey: 'live-database-public-customers',
695
- rawFiles: ['tables/customers.json'],
696
- dependencyPaths: ['connection.json', 'foreign-keys.json'],
697
- peerFileIndex: [],
698
- },
699
- {
700
- unitKey: 'live-database-public-orders',
701
- rawFiles: ['tables/orders.json'],
702
- dependencyPaths: ['connection.json', 'foreign-keys.json'],
703
- peerFileIndex: [],
704
- },
705
- ],
706
- };
707
- },
708
- };
709
- class FakeClassConnector {
710
- id = 'test:warehouse';
711
- driver = 'postgres';
712
- capabilities = {
713
- structuralIntrospection: true,
714
- tableSampling: false,
715
- columnSampling: false,
716
- columnStats: true,
717
- readOnlySql: true,
718
- nestedAnalysis: false,
719
- eventStreamDiscovery: false,
720
- formalForeignKeys: false,
721
- estimatedRowCounts: true,
722
- };
723
- async introspect() {
724
- return {
725
- connectionId: 'warehouse',
726
- driver: 'postgres',
727
- extractedAt: '2026-05-22T00:00:00.000Z',
728
- scope: { schemas: ['public'] },
729
- metadata: {},
730
- tables: [
731
- {
732
- catalog: null,
733
- db: 'public',
734
- name: 'customers',
735
- kind: 'table',
736
- comment: null,
737
- estimatedRows: 100,
738
- foreignKeys: [],
739
- columns: [
740
- {
741
- name: 'id',
742
- nativeType: 'integer',
743
- normalizedType: 'integer',
744
- dimensionType: 'number',
745
- nullable: false,
746
- primaryKey: true,
747
- comment: null,
748
- },
749
- ],
750
- },
751
- {
752
- catalog: null,
753
- db: 'public',
754
- name: 'orders',
755
- kind: 'table',
756
- comment: null,
757
- estimatedRows: 1000,
758
- foreignKeys: [],
759
- columns: [
760
- {
761
- name: 'customer_id',
762
- nativeType: 'integer',
763
- normalizedType: 'integer',
764
- dimensionType: 'number',
765
- nullable: false,
766
- primaryKey: false,
767
- comment: null,
768
- },
769
- ],
770
- },
771
- ],
772
- };
773
- }
774
- async executeReadOnly(input) {
775
- return relationshipSqlResult(input);
776
- }
777
- }
778
- const result = await runLocalScan({
779
- project,
780
- adapters: [scopedAdapter],
781
- connectionId: 'warehouse',
782
- mode: 'relationships',
783
- detectRelationships: true,
784
- connector: new FakeClassConnector(),
785
- jobId: 'scan-prototype-connector-scope',
786
- now: () => new Date('2026-05-22T00:00:00.000Z'),
787
- });
788
- expect(result.report.relationships.accepted).toBe(1);
789
- expect(result.report.warnings).toEqual([]);
790
- });
791
- it('threads scan relationship settings into relationship-only local scans', async () => {
792
- project.config.scan.enrichment = { mode: 'deterministic' };
793
- project.config.scan.relationships = {
794
- ...project.config.scan.relationships,
795
- llmProposals: false,
796
- maxLlmTablesPerBatch: 7,
797
- };
798
- const generateObject = vi.fn(async () => ({ pkCandidates: [], fkCandidates: [] }));
799
- const connector = {
800
- id: 'test:warehouse',
801
- driver: 'postgres',
802
- capabilities: {
803
- structuralIntrospection: true,
804
- tableSampling: false,
805
- columnSampling: false,
806
- columnStats: true,
807
- readOnlySql: true,
808
- nestedAnalysis: false,
809
- eventStreamDiscovery: false,
810
- formalForeignKeys: false,
811
- estimatedRowCounts: true,
812
- },
813
- async introspect() {
814
- return {
815
- connectionId: 'warehouse',
816
- driver: 'postgres',
817
- extractedAt: '2026-04-29T09:30:00.000Z',
818
- scope: { schemas: ['public'] },
819
- metadata: {},
820
- tables: [
821
- {
822
- catalog: null,
823
- db: 'public',
824
- name: 'customers',
825
- kind: 'table',
826
- comment: null,
827
- estimatedRows: null,
828
- foreignKeys: [],
829
- columns: [
830
- {
831
- name: 'id',
832
- nativeType: 'integer',
833
- normalizedType: 'integer',
834
- dimensionType: 'number',
835
- nullable: false,
836
- primaryKey: false,
837
- comment: null,
838
- },
839
- ],
840
- },
841
- {
842
- catalog: null,
843
- db: 'public',
844
- name: 'orders',
845
- kind: 'table',
846
- comment: null,
847
- estimatedRows: null,
848
- foreignKeys: [],
849
- columns: [
850
- {
851
- name: 'customer_id',
852
- nativeType: 'integer',
853
- normalizedType: 'integer',
854
- dimensionType: 'number',
855
- nullable: false,
856
- primaryKey: false,
857
- comment: null,
858
- },
859
- ],
860
- },
861
- ],
862
- };
863
- },
864
- async executeReadOnly(input) {
865
- return relationshipSqlResult(input);
866
- },
867
- };
868
- const adapter = fetchOnlyAdapter({ snapshot: await connector.introspect() });
869
- const result = await runLocalScan({
870
- project,
871
- adapters: [adapter],
872
- connectionId: 'warehouse',
873
- mode: 'relationships',
874
- detectRelationships: true,
875
- connector,
876
- enrichmentProviders: {
877
- llmRuntime: {
878
- ...deterministicLlmRuntime(),
879
- generateObject: generateObject,
880
- },
881
- embedding: {
882
- dimensions: 8,
883
- maxBatchSize: 64,
884
- async embedBatch() {
885
- return [];
886
- },
887
- },
888
- },
889
- jobId: 'scan-relationships-llm-disabled-1',
890
- now: () => new Date('2026-04-29T09:30:00.000Z'),
891
- });
892
- expect(result.report.relationships.accepted).toBe(1);
893
- expect(result.report.enrichment.llmRelationshipValidation).toBe('skipped');
894
- expect(generateObject).not.toHaveBeenCalled();
895
- });
896
- it('accepts no-declared-constraint relationships and writes relationship artifacts', async () => {
897
- const connector = {
898
- id: 'test:warehouse',
899
- driver: 'postgres',
900
- capabilities: {
901
- structuralIntrospection: true,
902
- tableSampling: false,
903
- columnSampling: false,
904
- columnStats: true,
905
- readOnlySql: true,
906
- nestedAnalysis: false,
907
- eventStreamDiscovery: false,
908
- formalForeignKeys: false,
909
- estimatedRowCounts: true,
910
- },
911
- async introspect() {
912
- return {
913
- connectionId: 'warehouse',
914
- driver: 'postgres',
915
- extractedAt: '2026-05-07T09:00:00.000Z',
916
- scope: {},
917
- metadata: {},
918
- tables: [
919
- {
920
- catalog: null,
921
- db: null,
922
- name: 'accounts',
923
- kind: 'table',
924
- comment: null,
925
- estimatedRows: 2,
926
- foreignKeys: [],
927
- columns: [
928
- {
929
- name: 'id',
930
- nativeType: 'integer',
931
- normalizedType: 'integer',
932
- dimensionType: 'number',
933
- nullable: false,
934
- primaryKey: false,
935
- comment: null,
936
- },
937
- ],
938
- },
939
- {
940
- catalog: null,
941
- db: null,
942
- name: 'orders',
943
- kind: 'table',
944
- comment: null,
945
- estimatedRows: 3,
946
- foreignKeys: [],
947
- columns: [
948
- {
949
- name: 'id',
950
- nativeType: 'integer',
951
- normalizedType: 'integer',
952
- dimensionType: 'number',
953
- nullable: false,
954
- primaryKey: false,
955
- comment: null,
956
- },
957
- {
958
- name: 'account_id',
959
- nativeType: 'integer',
960
- normalizedType: 'integer',
961
- dimensionType: 'number',
962
- nullable: false,
963
- primaryKey: false,
964
- comment: null,
965
- },
966
- ],
967
- },
968
- ],
969
- };
970
- },
971
- async executeReadOnly(input) {
972
- return relationshipSqlResult(input);
973
- },
974
- };
975
- const adapter = fetchOnlyAdapter({ snapshot: await connector.introspect() });
976
- const result = await runLocalScan({
977
- project,
978
- adapters: [adapter],
979
- connectionId: 'warehouse',
980
- mode: 'relationships',
981
- detectRelationships: true,
982
- connector,
983
- jobId: 'scan-relationship-discovery',
984
- now: () => new Date('2026-05-07T09:12:00.000Z'),
985
- });
986
- expect(result.report.relationships).toEqual({ accepted: 1, review: 0, rejected: 0, skipped: 0 });
987
- const enrichmentRoot = `raw-sources/warehouse/live-database/${result.report.syncId}/enrichment`;
988
- expect(result.report.artifactPaths.enrichmentArtifacts).toEqual([
989
- `${enrichmentRoot}/relationships.json`,
990
- `${enrichmentRoot}/relationship-profile.json`,
991
- `${enrichmentRoot}/relationship-diagnostics.json`,
992
- ]);
993
- const diagnostics = JSON.parse((await project.fileStore.readFile(`${enrichmentRoot}/relationship-diagnostics.json`)).content);
994
- expect(diagnostics.summary).toEqual({ accepted: 1, review: 0, rejected: 0, skipped: 0 });
995
- expect(diagnostics.noAcceptedReason).toBeNull();
996
- const manifestPath = result.report.artifactPaths.manifestShards[0];
997
- if (!manifestPath) {
998
- throw new Error('Expected manifest shard path');
999
- }
1000
- const manifest = YAML.parse((await project.fileStore.readFile(manifestPath)).content);
1001
- expect(manifest.tables.orders.joins).toEqual(expect.arrayContaining([
1002
- expect.objectContaining({
1003
- to: 'accounts',
1004
- on: 'orders.account_id = accounts.id',
1005
- source: 'inferred',
1006
- }),
1007
- ]));
1008
- });
1009
- it('runs enriched relationship discovery without scan enrichment backend', async () => {
1010
- const connector = {
1011
- id: 'test:warehouse',
1012
- driver: 'postgres',
1013
- capabilities: {
1014
- structuralIntrospection: true,
1015
- tableSampling: false,
1016
- columnSampling: false,
1017
- columnStats: true,
1018
- readOnlySql: true,
1019
- nestedAnalysis: false,
1020
- eventStreamDiscovery: false,
1021
- formalForeignKeys: false,
1022
- estimatedRowCounts: true,
1023
- },
1024
- async introspect() {
1025
- return {
1026
- connectionId: 'warehouse',
1027
- driver: 'postgres',
1028
- extractedAt: '2026-05-07T09:00:00.000Z',
1029
- scope: {},
1030
- metadata: {},
1031
- tables: [
1032
- {
1033
- catalog: null,
1034
- db: null,
1035
- name: 'accounts',
1036
- kind: 'table',
1037
- comment: null,
1038
- estimatedRows: 2,
1039
- foreignKeys: [],
1040
- columns: [
1041
- {
1042
- name: 'id',
1043
- nativeType: 'integer',
1044
- normalizedType: 'integer',
1045
- dimensionType: 'number',
1046
- nullable: false,
1047
- primaryKey: false,
1048
- comment: null,
1049
- },
1050
- ],
1051
- },
1052
- {
1053
- catalog: null,
1054
- db: null,
1055
- name: 'orders',
1056
- kind: 'table',
1057
- comment: null,
1058
- estimatedRows: 3,
1059
- foreignKeys: [],
1060
- columns: [
1061
- {
1062
- name: 'id',
1063
- nativeType: 'integer',
1064
- normalizedType: 'integer',
1065
- dimensionType: 'number',
1066
- nullable: false,
1067
- primaryKey: false,
1068
- comment: null,
1069
- },
1070
- {
1071
- name: 'account_id',
1072
- nativeType: 'integer',
1073
- normalizedType: 'integer',
1074
- dimensionType: 'number',
1075
- nullable: false,
1076
- primaryKey: false,
1077
- comment: null,
1078
- },
1079
- ],
1080
- },
1081
- ],
1082
- };
1083
- },
1084
- async executeReadOnly(input) {
1085
- return relationshipSqlResult(input);
1086
- },
1087
- };
1088
- const adapter = fetchOnlyAdapter({ snapshot: await connector.introspect() });
1089
- const result = await runLocalScan({
1090
- project,
1091
- adapters: [adapter],
1092
- connectionId: 'warehouse',
1093
- mode: 'enriched',
1094
- connector,
1095
- jobId: 'scan-providerless-enriched-relationship-discovery',
1096
- now: () => new Date('2026-05-07T09:14:00.000Z'),
1097
- });
1098
- expect(result.report.mode).toBe('enriched');
1099
- expect(result.report.enrichment).toEqual({
1100
- dataDictionary: 'skipped',
1101
- tableDescriptions: 'skipped',
1102
- columnDescriptions: 'skipped',
1103
- embeddings: 'skipped',
1104
- deterministicRelationships: 'completed',
1105
- llmRelationshipValidation: 'skipped',
1106
- statisticalValidation: 'completed',
1107
- });
1108
- expect(result.report.relationships).toEqual({ accepted: 1, review: 0, rejected: 0, skipped: 0 });
1109
- expect(result.report.warnings).toContainEqual({
1110
- code: 'scan_enrichment_backend_not_configured',
1111
- message: 'Skipping description and embedding enrichment because scan.enrichment.mode is not configured; relationship discovery still ran.',
1112
- recoverable: true,
1113
- metadata: {
1114
- skippedStages: ['descriptions', 'embeddings'],
1115
- relationshipDetection: true,
1116
- },
1117
- });
1118
- const enrichmentRoot = `raw-sources/warehouse/live-database/${result.report.syncId}/enrichment`;
1119
- expect(result.report.artifactPaths.enrichmentArtifacts).toEqual(expect.arrayContaining([
1120
- `${enrichmentRoot}/relationships.json`,
1121
- `${enrichmentRoot}/relationship-profile.json`,
1122
- `${enrichmentRoot}/relationship-diagnostics.json`,
1123
- ]));
1124
- const manifestPath = result.report.artifactPaths.manifestShards[0];
1125
- if (!manifestPath) {
1126
- throw new Error('Expected manifest shard path');
1127
- }
1128
- const manifest = YAML.parse((await project.fileStore.readFile(manifestPath)).content);
1129
- expect(manifest.tables.orders.joins).toEqual(expect.arrayContaining([
1130
- expect.objectContaining({
1131
- to: 'accounts',
1132
- on: 'orders.account_id = accounts.id',
1133
- source: 'inferred',
1134
- }),
1135
- ]));
1136
- });
1137
- it('redacts credential-like warning messages before persisting local scan reports', async () => {
1138
- const connector = {
1139
- id: 'test:warehouse',
1140
- driver: 'postgres',
1141
- capabilities: {
1142
- structuralIntrospection: true,
1143
- tableSampling: false,
1144
- columnSampling: false,
1145
- columnStats: true,
1146
- readOnlySql: true,
1147
- nestedAnalysis: false,
1148
- eventStreamDiscovery: false,
1149
- formalForeignKeys: false,
1150
- estimatedRowCounts: true,
1151
- },
1152
- async introspect() {
1153
- return {
1154
- connectionId: 'warehouse',
1155
- driver: 'postgres',
1156
- extractedAt: '2026-04-29T09:00:00.000Z',
1157
- scope: { schemas: ['public'] },
1158
- metadata: {},
1159
- tables: [
1160
- {
1161
- catalog: null,
1162
- db: 'public',
1163
- name: 'customers',
1164
- kind: 'table',
1165
- comment: null,
1166
- estimatedRows: 100,
1167
- foreignKeys: [],
1168
- columns: [
1169
- {
1170
- name: 'id',
1171
- nativeType: 'integer',
1172
- normalizedType: 'integer',
1173
- dimensionType: 'number',
1174
- nullable: false,
1175
- primaryKey: true,
1176
- comment: null,
1177
- },
1178
- ],
1179
- },
1180
- {
1181
- catalog: null,
1182
- db: 'public',
1183
- name: 'orders',
1184
- kind: 'table',
1185
- comment: null,
1186
- estimatedRows: 1000,
1187
- foreignKeys: [],
1188
- columns: [
1189
- {
1190
- name: 'customer_id',
1191
- nativeType: 'integer',
1192
- normalizedType: 'integer',
1193
- dimensionType: 'number',
1194
- nullable: false,
1195
- primaryKey: false,
1196
- comment: null,
1197
- },
1198
- ],
1199
- },
1200
- ],
1201
- };
1202
- },
1203
- async executeReadOnly(input) {
1204
- return relationshipSqlResult(input, { throwOnCoverage: true });
1205
- },
1206
- };
1207
- const adapter = fetchOnlyAdapter({ snapshot: await connector.introspect() });
1208
- const result = await runLocalScan({
1209
- project,
1210
- adapters: [adapter],
1211
- connectionId: 'warehouse',
1212
- mode: 'relationships',
1213
- detectRelationships: true,
1214
- connector,
1215
- jobId: 'scan-redacted-warning-1',
1216
- now: () => new Date('2026-04-29T09:14:00.000Z'),
1217
- });
1218
- expect(result.report.warnings[0]?.message).toContain('postgres://reader:<redacted>@example.test/db');
1219
- expect(result.report.warnings[0]?.message).not.toContain('postgres://reader:secret@example.test/db');
1220
- const reportPath = result.report.artifactPaths.reportPath;
1221
- if (!reportPath) {
1222
- throw new Error('Expected local scan report path');
1223
- }
1224
- const persistedReport = await readFile(join(project.projectDir, reportPath), 'utf-8');
1225
- expect(persistedReport).toContain('postgres://reader:<redacted>@example.test/db');
1226
- expect(persistedReport).not.toContain('postgres://reader:secret@example.test/db'); // pragma: allowlist secret
1227
- });
1228
- it('runs enriched scans when deterministic standalone enrichment is configured without embeddings', async () => {
1229
- await writeFile(join(project.projectDir, 'ktx.yaml'), [
1230
- 'connections:',
1231
- ' warehouse:',
1232
- ' driver: postgres',
1233
- ' url: env:DATABASE_URL',
1234
- 'ingest:',
1235
- ' adapters:',
1236
- ' - live-database',
1237
- 'scan:',
1238
- ' enrichment:',
1239
- ' mode: deterministic',
1240
- '',
1241
- ].join('\n'), 'utf-8');
1242
- project = await loadKtxProject({ projectDir: project.projectDir });
1243
- const connector = {
1244
- id: 'test:warehouse',
1245
- driver: 'postgres',
1246
- capabilities: {
1247
- structuralIntrospection: true,
1248
- tableSampling: true,
1249
- columnSampling: true,
1250
- columnStats: false,
1251
- readOnlySql: false,
1252
- nestedAnalysis: false,
1253
- eventStreamDiscovery: false,
1254
- formalForeignKeys: false,
1255
- estimatedRowCounts: false,
1256
- },
1257
- async introspect() {
1258
- return {
1259
- connectionId: 'warehouse',
1260
- driver: 'postgres',
1261
- extractedAt: '2026-04-29T09:00:00.000Z',
1262
- scope: { schemas: ['public'] },
1263
- metadata: {},
1264
- tables: [
1265
- {
1266
- catalog: null,
1267
- db: 'public',
1268
- name: 'orders',
1269
- kind: 'table',
1270
- comment: 'Orders',
1271
- estimatedRows: 1,
1272
- foreignKeys: [],
1273
- columns: [
1274
- {
1275
- name: 'id',
1276
- nativeType: 'integer',
1277
- normalizedType: 'integer',
1278
- dimensionType: 'number',
1279
- nullable: false,
1280
- primaryKey: true,
1281
- comment: 'Order id',
1282
- },
1283
- ],
1284
- },
1285
- ],
1286
- };
1287
- },
1288
- async sampleTable() {
1289
- return { headers: ['id'], rows: [[1]], totalRows: 1 };
1290
- },
1291
- async sampleColumn() {
1292
- return { values: ['1'], nullCount: 0, distinctCount: 1 };
1293
- },
1294
- };
1295
- const result = await runLocalScan({
1296
- project,
1297
- adapters: [fetchOnlyAdapter()],
1298
- connectionId: 'warehouse',
1299
- mode: 'enriched',
1300
- connector,
1301
- jobId: 'scan-enriched-1',
1302
- now: () => new Date('2026-04-29T09:15:00.000Z'),
1303
- });
1304
- expect(result.report.mode).toBe('enriched');
1305
- expect(result.report.enrichment.tableDescriptions).toBe('completed');
1306
- expect(result.report.enrichment.columnDescriptions).toBe('completed');
1307
- expect(result.report.enrichment.embeddings).toBe('skipped');
1308
- expect(result.report.artifactPaths.enrichmentArtifacts).toEqual([
1309
- 'raw-sources/warehouse/live-database/2026-04-29-091500-scan-enriched-1/enrichment/descriptions.json',
1310
- 'raw-sources/warehouse/live-database/2026-04-29-091500-scan-enriched-1/enrichment/relationships.json',
1311
- 'raw-sources/warehouse/live-database/2026-04-29-091500-scan-enriched-1/enrichment/relationship-profile.json',
1312
- 'raw-sources/warehouse/live-database/2026-04-29-091500-scan-enriched-1/enrichment/relationship-diagnostics.json',
1313
- ]);
1314
- expect(result.report.artifactPaths.manifestShards).toEqual(['semantic-layer/warehouse/_schema/public.yaml']);
1315
- expect(result.report.manifestShardsWritten).toBe(1);
1316
- await expect(readFile(join(project.projectDir, 'raw-sources/warehouse/live-database/2026-04-29-091500-scan-enriched-1/enrichment/descriptions.json'), 'utf-8')).resolves.toContain('Deterministic description');
1317
- const manifestRaw = await readFile(join(project.projectDir, 'semantic-layer/warehouse/_schema/public.yaml'), 'utf-8');
1318
- expect(manifestRaw).toContain('ai: |-');
1319
- expect(manifestRaw).toContain('Deterministic description');
1320
- });
1321
- it('persists structural artifacts and a recoverable warning when standalone enrichment execution fails', async () => {
1322
- const connector = {
1323
- id: 'test:warehouse',
1324
- driver: 'postgres',
1325
- capabilities: {
1326
- structuralIntrospection: true,
1327
- tableSampling: true,
1328
- columnSampling: true,
1329
- columnStats: false,
1330
- readOnlySql: false,
1331
- nestedAnalysis: false,
1332
- eventStreamDiscovery: false,
1333
- formalForeignKeys: false,
1334
- estimatedRowCounts: false,
1335
- },
1336
- async introspect() {
1337
- return {
1338
- connectionId: 'warehouse',
1339
- driver: 'postgres',
1340
- extractedAt: '2026-04-29T09:00:00.000Z',
1341
- scope: { schemas: ['public'] },
1342
- metadata: {},
1343
- tables: [
1344
- {
1345
- catalog: null,
1346
- db: 'public',
1347
- name: 'orders',
1348
- kind: 'table',
1349
- comment: 'Orders',
1350
- estimatedRows: 1,
1351
- foreignKeys: [],
1352
- columns: [
1353
- {
1354
- name: 'id',
1355
- nativeType: 'integer',
1356
- normalizedType: 'integer',
1357
- dimensionType: 'number',
1358
- nullable: false,
1359
- primaryKey: true,
1360
- comment: 'Order id',
1361
- },
1362
- ],
1363
- },
1364
- ],
1365
- };
1366
- },
1367
- async sampleTable() {
1368
- return { headers: ['id'], rows: [[1]], totalRows: 1 };
1369
- },
1370
- async sampleColumn() {
1371
- return { values: ['1'], nullCount: 0, distinctCount: 1 };
1372
- },
1373
- };
1374
- const result = await runLocalScan({
1375
- project,
1376
- adapters: [fetchOnlyAdapter()],
1377
- connectionId: 'warehouse',
1378
- mode: 'enriched',
1379
- connector,
1380
- enrichmentProviders: {
1381
- llmRuntime: deterministicLlmRuntime(),
1382
- embedding: {
1383
- dimensions: 8,
1384
- maxBatchSize: 64,
1385
- async embedBatch() {
1386
- throw new Error('embedding service timed out');
1387
- },
1388
- },
1389
- },
1390
- jobId: 'scan-enrichment-fails-1',
1391
- now: () => new Date('2026-04-29T09:18:00.000Z'),
1392
- });
1393
- expect(result.report.mode).toBe('enriched');
1394
- expect(result.report.enrichment).toEqual({
1395
- dataDictionary: 'failed',
1396
- tableDescriptions: 'failed',
1397
- columnDescriptions: 'failed',
1398
- embeddings: 'failed',
1399
- deterministicRelationships: 'failed',
1400
- llmRelationshipValidation: 'failed',
1401
- statisticalValidation: 'failed',
1402
- });
1403
- expect(result.report.warnings).toEqual([
1404
- {
1405
- code: 'enrichment_failed',
1406
- message: 'KTX scan enrichment failed after structural scan completed: embedding service timed out',
1407
- recoverable: true,
1408
- metadata: {
1409
- mode: 'enriched',
1410
- detectRelationships: false,
1411
- },
1412
- },
1413
- ]);
1414
- expect(result.report.artifactPaths.enrichmentArtifacts).toEqual([]);
1415
- expect(result.report.artifactPaths.manifestShards).toEqual(['semantic-layer/warehouse/_schema/public.yaml']);
1416
- const manifestRaw = await readFile(join(project.projectDir, 'semantic-layer/warehouse/_schema/public.yaml'), 'utf-8');
1417
- expect(manifestRaw).toContain('orders:');
1418
- expect(manifestRaw).toContain('table: public.orders');
1419
- expect(manifestRaw).not.toContain('ai: Generated description');
1420
- const reportPath = result.report.artifactPaths.reportPath;
1421
- if (!reportPath) {
1422
- throw new Error('Expected local scan report path');
1423
- }
1424
- const persistedReport = await readFile(join(project.projectDir, reportPath), 'utf-8');
1425
- expect(persistedReport).toContain('"code": "enrichment_failed"');
1426
- expect(persistedReport).toContain('embedding service timed out');
1427
- });
1428
- it('resumes completed local enrichment stages when an enriched scan run is retried', async () => {
1429
- let embeddingAttempts = 0;
1430
- const connector = {
1431
- id: 'test:warehouse',
1432
- driver: 'postgres',
1433
- capabilities: {
1434
- structuralIntrospection: true,
1435
- tableSampling: true,
1436
- columnSampling: true,
1437
- columnStats: true,
1438
- readOnlySql: false,
1439
- nestedAnalysis: false,
1440
- eventStreamDiscovery: false,
1441
- formalForeignKeys: false,
1442
- estimatedRowCounts: false,
1443
- },
1444
- async introspect() {
1445
- return {
1446
- connectionId: 'warehouse',
1447
- driver: 'postgres',
1448
- extractedAt: '2026-04-29T09:21:00.000Z',
1449
- scope: { schemas: ['public'] },
1450
- metadata: {},
1451
- tables: [
1452
- {
1453
- catalog: null,
1454
- db: 'public',
1455
- name: 'orders',
1456
- kind: 'table',
1457
- comment: 'Orders',
1458
- estimatedRows: 1,
1459
- foreignKeys: [],
1460
- columns: [
1461
- {
1462
- name: 'id',
1463
- nativeType: 'integer',
1464
- normalizedType: 'integer',
1465
- dimensionType: 'number',
1466
- nullable: false,
1467
- primaryKey: true,
1468
- comment: 'Order id',
1469
- },
1470
- ],
1471
- },
1472
- ],
1473
- };
1474
- },
1475
- async sampleTable() {
1476
- return { headers: ['id'], rows: [[1]], totalRows: 1 };
1477
- },
1478
- async sampleColumn() {
1479
- return { values: ['1'], nullCount: 0, distinctCount: 1 };
1480
- },
1481
- };
1482
- const llmRuntime = deterministicLlmRuntime();
1483
- const adapter = fetchOnlyAdapter({ snapshot: await connector.introspect() });
1484
- const first = await runLocalScan({
1485
- project,
1486
- adapters: [adapter],
1487
- connectionId: 'warehouse',
1488
- mode: 'enriched',
1489
- connector,
1490
- enrichmentProviders: {
1491
- llmRuntime,
1492
- embedding: {
1493
- dimensions: 8,
1494
- maxBatchSize: 64,
1495
- async embedBatch() {
1496
- embeddingAttempts += 1;
1497
- throw new Error('embedding service timed out once');
1498
- },
1499
- },
1500
- },
1501
- jobId: 'scan-enrichment-resume-1',
1502
- now: () => new Date('2026-04-29T09:21:00.000Z'),
1503
- });
1504
- expect(first.report.enrichmentState).toEqual({
1505
- resumedStages: [],
1506
- completedStages: ['descriptions'],
1507
- failedStages: ['embeddings'],
1508
- });
1509
- expect(first.report.enrichment.embeddings).toBe('failed');
1510
- const generateObject = vi.spyOn(llmRuntime, 'generateObject');
1511
- const retry = await runLocalScan({
1512
- project,
1513
- adapters: [adapter],
1514
- connectionId: 'warehouse',
1515
- mode: 'enriched',
1516
- connector,
1517
- enrichmentProviders: {
1518
- llmRuntime,
1519
- embedding: {
1520
- dimensions: 8,
1521
- maxBatchSize: 64,
1522
- async embedBatch(texts) {
1523
- embeddingAttempts += 1;
1524
- return texts.map(() => [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]);
1525
- },
1526
- },
1527
- },
1528
- jobId: 'scan-enrichment-resume-1',
1529
- now: () => new Date('2026-04-29T09:22:00.000Z'),
1530
- });
1531
- expect(retry.syncId).toBe(first.syncId);
1532
- expect(retry.report.enrichmentState).toEqual({
1533
- resumedStages: ['descriptions'],
1534
- completedStages: ['descriptions', 'embeddings', 'relationships'],
1535
- failedStages: [],
1536
- });
1537
- expect(retry.report.enrichment.embeddings).toBe('completed');
1538
- expect(generateObject).toHaveBeenCalledWith(expect.objectContaining({ role: 'candidateExtraction' }));
1539
- expect(embeddingAttempts).toBe(2);
1540
- const reportPath = retry.report.artifactPaths.reportPath;
1541
- if (!reportPath) {
1542
- throw new Error('Expected local scan report path');
1543
- }
1544
- const persistedReport = await readFile(join(project.projectDir, reportPath), 'utf-8');
1545
- expect(persistedReport).toContain('"resumedStages": [');
1546
- expect(persistedReport).toContain('"descriptions"');
1547
- });
1548
- it('accepts sqlite as a native standalone scan driver when the host supplies a live-database adapter', async () => {
1549
- await writeFile(join(project.projectDir, 'ktx.yaml'), [
1550
- 'connections:',
1551
- ' warehouse:',
1552
- ' driver: sqlite',
1553
- ' path: warehouse.db',
1554
- 'ingest:',
1555
- ' adapters:',
1556
- ' - live-database',
1557
- '',
1558
- ].join('\n'), 'utf-8');
1559
- project = await loadKtxProject({ projectDir: project.projectDir });
1560
- const result = await runLocalScan({
1561
- project,
1562
- adapters: [fetchOnlyAdapter()],
1563
- connectionId: 'warehouse',
1564
- jobId: 'scan-run-sqlite',
1565
- now: () => new Date('2026-04-29T11:00:00.000Z'),
1566
- });
1567
- expect(result.report.driver).toBe('sqlite');
1568
- expect(result.report.artifactPaths.reportPath).toBe('raw-sources/warehouse/live-database/2026-04-29-110000-scan-run-sqlite/scan-report.json');
1569
- });
1570
- it('accepts mysql as a native standalone scan driver when the host supplies a live-database adapter', async () => {
1571
- await writeFile(join(project.projectDir, 'ktx.yaml'), [
1572
- 'connections:',
1573
- ' warehouse:',
1574
- ' driver: mysql',
1575
- ' url: env:MYSQL_URL',
1576
- 'ingest:',
1577
- ' adapters:',
1578
- ' - live-database',
1579
- '',
1580
- ].join('\n'), 'utf-8');
1581
- project = await loadKtxProject({ projectDir: project.projectDir });
1582
- const result = await runLocalScan({
1583
- project,
1584
- adapters: [fetchOnlyAdapter()],
1585
- connectionId: 'warehouse',
1586
- jobId: 'scan-run-mysql',
1587
- now: () => new Date('2026-04-29T13:00:00.000Z'),
1588
- });
1589
- expect(result.report.driver).toBe('mysql');
1590
- expect(result.report.artifactPaths.reportPath).toBe('raw-sources/warehouse/live-database/2026-04-29-130000-scan-run-mysql/scan-report.json');
1591
- });
1592
- it('accepts clickhouse as a native standalone scan driver when the host supplies a live-database adapter', async () => {
1593
- await writeFile(join(project.projectDir, 'ktx.yaml'), [
1594
- 'connections:',
1595
- ' warehouse:',
1596
- ' driver: clickhouse',
1597
- ' host: env:CLICKHOUSE_HOST',
1598
- ' database: analytics',
1599
- ' username: reader',
1600
- ' password: env:CLICKHOUSE_PASSWORD',
1601
- 'ingest:',
1602
- ' adapters:',
1603
- ' - live-database',
1604
- '',
1605
- ].join('\n'), 'utf-8');
1606
- project = await loadKtxProject({ projectDir: project.projectDir });
1607
- const result = await runLocalScan({
1608
- project,
1609
- adapters: [fetchOnlyAdapter()],
1610
- connectionId: 'warehouse',
1611
- jobId: 'scan-run-clickhouse',
1612
- now: () => new Date('2026-04-29T15:00:00.000Z'),
1613
- });
1614
- expect(result.report.driver).toBe('clickhouse');
1615
- expect(result.report.artifactPaths.reportPath).toBe('raw-sources/warehouse/live-database/2026-04-29-150000-scan-run-clickhouse/scan-report.json');
1616
- });
1617
- it('accepts sqlserver as a native standalone scan driver when the host supplies a live-database adapter', async () => {
1618
- await writeFile(join(project.projectDir, 'ktx.yaml'), [
1619
- 'connections:',
1620
- ' warehouse:',
1621
- ' driver: sqlserver',
1622
- ' host: env:SQLSERVER_HOST',
1623
- ' database: analytics',
1624
- ' username: reader',
1625
- ' schema: dbo',
1626
- 'ingest:',
1627
- ' adapters:',
1628
- ' - live-database',
1629
- '',
1630
- ].join('\n'), 'utf-8');
1631
- project = await loadKtxProject({ projectDir: project.projectDir });
1632
- const result = await runLocalScan({
1633
- project,
1634
- adapters: [fetchOnlyAdapter()],
1635
- connectionId: 'warehouse',
1636
- jobId: 'scan-run-sqlserver',
1637
- now: () => new Date('2026-04-29T16:00:00.000Z'),
1638
- });
1639
- expect(result.report.driver).toBe('sqlserver');
1640
- expect(result.report.artifactPaths.reportPath).toBe('raw-sources/warehouse/live-database/2026-04-29-160000-scan-run-sqlserver/scan-report.json');
1641
- });
1642
- });
1643
- describe('resolveEnabledTables', () => {
1644
- it('returns null when no enabled_tables field', () => {
1645
- expect(resolveEnabledTables({ driver: 'postgres' })).toBeNull();
1646
- });
1647
- it('returns null for empty array', () => {
1648
- expect(resolveEnabledTables({ driver: 'postgres', enabled_tables: [] })).toBeNull();
1649
- });
1650
- it('returns a canonical set of enabled table refs', () => {
1651
- const result = resolveEnabledTables({
1652
- driver: 'postgres',
1653
- enabled_tables: ['public.users', 'public.orders'],
1654
- });
1655
- expect(result).toBeInstanceOf(Set);
1656
- expect(result.size).toBe(2);
1657
- expect(result.has(tableRefKey({ catalog: null, db: 'public', name: 'users' }))).toBe(true);
1658
- expect(result.has(tableRefKey({ catalog: null, db: 'public', name: 'orders' }))).toBe(true);
1659
- });
1660
- it('returns null for undefined connection', () => {
1661
- expect(resolveEnabledTables(undefined)).toBeNull();
1662
- });
1663
- });