sql-code-graph 1.5.1__tar.gz → 1.33.0__tar.gz

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 (581) hide show
  1. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.claude/agents/architect-planner.md +28 -7
  2. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.claude/agents/developer.md +69 -0
  3. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.claude/agents/sprint-planner.md +5 -0
  4. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.github/workflows/release.yml +9 -0
  5. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.gitignore +2 -0
  6. sql_code_graph-1.33.0/ARCHITECTURE_REVIEW.md +364 -0
  7. sql_code_graph-1.5.1/ARCHITECTURE_REVIEW.md → sql_code_graph-1.33.0/ARCHITECTURE_REVIEW_ARCHIVE.md +10 -1
  8. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/CHANGELOG.md +34 -1
  9. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/CLAUDE.md +38 -11
  10. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/PKG-INFO +60 -12
  11. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/README.md +59 -11
  12. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/docs/cli.md +128 -13
  13. sql_code_graph-1.33.0/docs/getting-started.md +392 -0
  14. sql_code_graph-1.33.0/docs/releasing-pypi.md +112 -0
  15. sql_code_graph-1.33.0/plan/measurements/pr2_catalog_load_eval.json +81 -0
  16. sql_code_graph-1.33.0/plan/measurements/pr3_repo_native_plateau.json +52 -0
  17. sql_code_graph-1.33.0/plan/measurements/pr4_transform_kinds.json +55 -0
  18. sql_code_graph-1.33.0/plan/measurements/pr5_extraction_recall_taxonomy.json +118 -0
  19. sql_code_graph-1.33.0/plan/measurements/sprint_08_changelogs_fullindex.json +37 -0
  20. sql_code_graph-1.33.0/plan/measurements/sprint_08_fullcorpus_index.json +37 -0
  21. sql_code_graph-1.33.0/plan/metrics/gain_1.29.0_05c6943.json +1 -0
  22. sql_code_graph-1.33.0/plan/metrics/gain_1.30.0_2c8ac25.json +29 -0
  23. sql_code_graph-1.33.0/plan/metrics/gain_1.30.1_26271fc.json +30 -0
  24. sql_code_graph-1.33.0/plan/metrics/gain_1.31.0_a40c837.json +30 -0
  25. sql_code_graph-1.33.0/plan/metrics/gain_1.32.0_c1bec3c.json +30 -0
  26. {sql_code_graph-1.5.1/plan/measurements → sql_code_graph-1.33.0/plan/metrics}/sprint_08_changelogs_fullindex.json +6 -6
  27. {sql_code_graph-1.5.1/plan/measurements → sql_code_graph-1.33.0/plan/metrics}/sprint_08_fullcorpus_index.json +13 -13
  28. sql_code_graph-1.33.0/plan/reports/column_coverage_diagnostic.md +220 -0
  29. sql_code_graph-1.33.0/plan/reports/column_coverage_findings.md +235 -0
  30. sql_code_graph-1.33.0/plan/reports/dwh_graph_analysis.md +245 -0
  31. sql_code_graph-1.33.0/plan/reports/dwh_positional_insert_column_blindspot.md +215 -0
  32. sql_code_graph-1.33.0/plan/reports/feature_acceptance_dwh.md +380 -0
  33. sql_code_graph-1.33.0/plan/reports/graph_health_sprint_postmortem.md +85 -0
  34. sql_code_graph-1.33.0/plan/reports/island_lever_live_verification.md +170 -0
  35. sql_code_graph-1.33.0/plan/reports/issue38_pr2_live_acceptance.md +127 -0
  36. sql_code_graph-1.33.0/plan/reports/issue38_pr3_live_acceptance.md +75 -0
  37. sql_code_graph-1.33.0/plan/reports/lineage_identity_sprint_postmortem.md +237 -0
  38. sql_code_graph-1.33.0/plan/reports/pr_impact_followups_2026-06-14.md +53 -0
  39. sql_code_graph-1.33.0/plan/reports/v1_14_dialect_query_config_postmortem.md +93 -0
  40. sql_code_graph-1.33.0/plan/research/coverage_parse_failure_diagnosis.md +138 -0
  41. sql_code_graph-1.33.0/plan/research/observed_usage_overlay_query_history_tableau.md +550 -0
  42. sql_code_graph-1.33.0/plan/research/sql_only_coverage_lever_post_pr2.md +344 -0
  43. sql_code_graph-1.33.0/plan/sprints/ci_tests_pool_flake_fix.md +257 -0
  44. sql_code_graph-1.33.0/plan/sprints/column_lineage_recall_metric.md +304 -0
  45. sql_code_graph-1.33.0/plan/sprints/coverage_p1_p3_p4.md +653 -0
  46. sql_code_graph-1.33.0/plan/sprints/coverage_p1_p5_metric.md +595 -0
  47. sql_code_graph-1.33.0/plan/sprints/coverage_parse_failures.md +522 -0
  48. sql_code_graph-1.33.0/plan/sprints/e8_dual_emission.md +155 -0
  49. sql_code_graph-1.33.0/plan/sprints/fix_backward_self_heal_index_at_sha.md +404 -0
  50. sql_code_graph-1.33.0/plan/sprints/gain_coverage_metrics.md +402 -0
  51. sql_code_graph-1.33.0/plan/sprints/graph_health_catalog_and_metrics.md +640 -0
  52. sql_code_graph-1.33.0/plan/sprints/issue-38-residual-source-extraction.md +391 -0
  53. sql_code_graph-1.33.0/plan/sprints/issue-38-selects-from-island-lever.md +600 -0
  54. sql_code_graph-1.33.0/plan/sprints/mcp_server_self_healing.md +546 -0
  55. sql_code_graph-1.33.0/plan/sprints/positional_insert_clone_blindspot.md +885 -0
  56. sql_code_graph-1.33.0/plan/sprints/sprint_lineage_identity_and_session_context.md +423 -0
  57. sql_code_graph-1.33.0/plan/sprints/sprint_postmortem_fixes.md +560 -0
  58. sql_code_graph-1.33.0/plan/sprints/temp_table_namespacing.md +674 -0
  59. sql_code_graph-1.33.0/plan/sprints/unfilled_table_impact.md +2023 -0
  60. sql_code_graph-1.33.0/plan/sprints/v1.14.0_dialect_and_query_config_fixes.md +750 -0
  61. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/pyproject.toml +2 -1
  62. sql_code_graph-1.33.0/scripts/column_coverage_check.py +356 -0
  63. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/__init__.py +1 -1
  64. sql_code_graph-1.33.0/src/sqlcg/cli/commands/analyze.py +750 -0
  65. sql_code_graph-1.33.0/src/sqlcg/cli/commands/catalog.py +313 -0
  66. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/db.py +23 -2
  67. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/find.py +3 -3
  68. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/gain.py +42 -14
  69. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/git.py +22 -3
  70. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/index.py +70 -33
  71. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/install.py +4 -1
  72. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/mcp.py +94 -20
  73. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/reindex.py +134 -2
  74. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/watch.py +10 -2
  75. sql_code_graph-1.33.0/src/sqlcg/cli/coverage.py +966 -0
  76. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/main.py +2 -0
  77. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/config.py +158 -4
  78. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/duckdb_backend.py +255 -32
  79. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/freshness.py +46 -2
  80. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/graph_db.py +49 -7
  81. sql_code_graph-1.33.0/src/sqlcg/core/noise_match.py +125 -0
  82. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/queries.py +3 -0
  83. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/queries.sql +62 -3
  84. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/schema.cypher +2 -1
  85. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/schema.py +1 -1
  86. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/error_classify.py +47 -1
  87. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/git_delta.py +18 -0
  88. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/indexer.py +681 -30
  89. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/pool.py +12 -2
  90. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/walker.py +2 -2
  91. sql_code_graph-1.33.0/src/sqlcg/lineage/aggregator.py +256 -0
  92. sql_code_graph-1.33.0/src/sqlcg/parsers/ansi_parser.py +812 -0
  93. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/parsers/base.py +722 -68
  94. sql_code_graph-1.33.0/src/sqlcg/parsers/snowflake_parser.py +976 -0
  95. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/models.py +202 -0
  96. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/noise_filter.py +26 -34
  97. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/read_client.py +59 -2
  98. sql_code_graph-1.33.0/src/sqlcg/server/selfheal.py +209 -0
  99. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/server.py +267 -10
  100. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/skill.py +12 -1
  101. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/tools.py +1084 -83
  102. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/writer.py +12 -14
  103. sql_code_graph-1.33.0/src/sqlcg/utils/ignore.py +52 -0
  104. sql_code_graph-1.33.0/tests/conftest.py +41 -0
  105. sql_code_graph-1.33.0/tests/e2e/test_empty_impact_cli_e2e.py +161 -0
  106. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_golden_lineage.py +190 -31
  107. sql_code_graph-1.33.0/tests/e2e/test_pr_impact_cli_e2e.py +235 -0
  108. sql_code_graph-1.33.0/tests/e2e/test_selfheal_e2e.py +394 -0
  109. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/duckdb_parity/kuzu_reference.json +1 -1
  110. sql_code_graph-1.33.0/tests/integration/snowflake/test_qualify_bare_tables_command_guard_integration.py +179 -0
  111. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_T35_external_consumers.py +12 -4
  112. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_anchor_tools.py +14 -4
  113. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_backfill_impact_consistency.py +102 -27
  114. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_bare_column_cte_lineage.py +41 -11
  115. sql_code_graph-1.33.0/tests/integration/test_catalog_kind_upgrade.py +323 -0
  116. sql_code_graph-1.33.0/tests/integration/test_catalog_load_integration.py +528 -0
  117. sql_code_graph-1.33.0/tests/integration/test_cli_index_clear_before_rebuild.py +210 -0
  118. sql_code_graph-1.33.0/tests/integration/test_column_coverage_patterns.py +858 -0
  119. sql_code_graph-1.33.0/tests/integration/test_coverage_metrics_integration.py +702 -0
  120. sql_code_graph-1.33.0/tests/integration/test_cte_key_namespacing_integration.py +252 -0
  121. sql_code_graph-1.33.0/tests/integration/test_empty_impact_blast_radius.py +490 -0
  122. sql_code_graph-1.33.0/tests/integration/test_empty_index_rollback_guard.py +235 -0
  123. sql_code_graph-1.33.0/tests/integration/test_gating_join_retrofit.py +317 -0
  124. sql_code_graph-1.33.0/tests/integration/test_identity_counters_integration.py +281 -0
  125. sql_code_graph-1.33.0/tests/integration/test_index_degraded_files_metric.py +148 -0
  126. sql_code_graph-1.33.0/tests/integration/test_index_filter_node_exclusion.py +264 -0
  127. sql_code_graph-1.33.0/tests/integration/test_issue38_cte_insert_regression.py +185 -0
  128. sql_code_graph-1.33.0/tests/integration/test_key_normalization_chokepoint.py +200 -0
  129. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_parse_diagnostics.py +10 -3
  130. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_pr2_source_location.py +5 -2
  131. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_pr3_kind_tagging.py +57 -16
  132. sql_code_graph-1.33.0/tests/integration/test_pr_impact_integration.py +585 -0
  133. sql_code_graph-1.33.0/tests/integration/test_qualify_failed_persist.py +175 -0
  134. sql_code_graph-1.33.0/tests/integration/test_repo_relative_cte_namespaces.py +161 -0
  135. sql_code_graph-1.33.0/tests/integration/test_resolvable_write_col_edges_integration.py +220 -0
  136. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_resync.py +127 -0
  137. sql_code_graph-1.33.0/tests/integration/test_selects_from_completeness.py +405 -0
  138. sql_code_graph-1.33.0/tests/integration/test_selects_from_cte_body_source.py +320 -0
  139. sql_code_graph-1.33.0/tests/integration/test_selects_from_subscope_source.py +389 -0
  140. sql_code_graph-1.33.0/tests/integration/test_skip_counts_integration.py +252 -0
  141. sql_code_graph-1.33.0/tests/integration/test_temp_table_namespacing.py +853 -0
  142. sql_code_graph-1.33.0/tests/integration/test_tool_version_stamp_integration.py +164 -0
  143. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_union_cte_star_recall_guard.py +62 -16
  144. sql_code_graph-1.33.0/tests/integration/test_usage_derived_catalog.py +311 -0
  145. sql_code_graph-1.33.0/tests/integration/test_use_schema_session_context_integration.py +141 -0
  146. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_user_surface_recall_guard.py +49 -56
  147. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_v141_surface_guards.py +21 -6
  148. sql_code_graph-1.33.0/tests/integration/test_v1_14_0_dialect_and_query_config_fixes.py +771 -0
  149. sql_code_graph-1.33.0/tests/integration/test_view_kind_in_graph.py +39 -0
  150. sql_code_graph-1.33.0/tests/integration/test_write_memory_ceiling.py +201 -0
  151. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E12/test_e12.py +1 -1
  152. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E16/test_e16.py +2 -2
  153. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E27/test_e27.py +1 -1
  154. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/test_plan_review_gates.py +3 -3
  155. sql_code_graph-1.33.0/tests/unit/snowflake/test_qualify_bare_tables_command_guard.py +173 -0
  156. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_F2_install_skill.py +10 -4
  157. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_F2_skill_render.py +19 -10
  158. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_F2_uninstall_skill.py +1 -1
  159. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_analyze_case_fold.py +65 -30
  160. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_base_parser.py +22 -15
  161. sql_code_graph-1.33.0/tests/unit/test_catalog_csv_parsing.py +392 -0
  162. sql_code_graph-1.33.0/tests/unit/test_catalog_missing_warning.py +219 -0
  163. sql_code_graph-1.33.0/tests/unit/test_cli_doc_flag_staleness.py +283 -0
  164. sql_code_graph-1.33.0/tests/unit/test_clone_positional_insert_blindspot.py +279 -0
  165. sql_code_graph-1.33.0/tests/unit/test_coverage_metrics.py +360 -0
  166. sql_code_graph-1.33.0/tests/unit/test_cte_key_namespacing.py +251 -0
  167. sql_code_graph-1.33.0/tests/unit/test_cte_source_gap_metric.py +273 -0
  168. sql_code_graph-1.33.0/tests/unit/test_db_info_coverage.py +111 -0
  169. sql_code_graph-1.33.0/tests/unit/test_db_path_isolation_fixture.py +60 -0
  170. sql_code_graph-1.33.0/tests/unit/test_doc_links.py +83 -0
  171. sql_code_graph-1.33.0/tests/unit/test_doc_markdown_link_existence.py +151 -0
  172. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_duckdb_backend.py +39 -0
  173. sql_code_graph-1.33.0/tests/unit/test_e5_view_alias_resolution.py +189 -0
  174. sql_code_graph-1.33.0/tests/unit/test_e8_dual_emission.py +299 -0
  175. sql_code_graph-1.33.0/tests/unit/test_e8_temp_chain_key_mismatch.py +365 -0
  176. sql_code_graph-1.33.0/tests/unit/test_empty_propagation_unit.py +328 -0
  177. sql_code_graph-1.33.0/tests/unit/test_extract_select_output_columns.py +169 -0
  178. sql_code_graph-1.33.0/tests/unit/test_file_ignore_defaults.py +115 -0
  179. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_find_cmd.py +24 -8
  180. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_firstuser_findings.py +19 -3
  181. sql_code_graph-1.33.0/tests/unit/test_gain_coverage.py +168 -0
  182. sql_code_graph-1.33.0/tests/unit/test_gating_join_field_docstrings.py +66 -0
  183. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_git_delta.py +23 -0
  184. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_git_hooks.py +81 -0
  185. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_graph_backend.py +3 -0
  186. sql_code_graph-1.33.0/tests/unit/test_has_column_precedence_upsert.py +162 -0
  187. sql_code_graph-1.33.0/tests/unit/test_hook_reindex_detach.py +481 -0
  188. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_hygiene_config_warning.py +15 -4
  189. sql_code_graph-1.33.0/tests/unit/test_identity_counters.py +295 -0
  190. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_include_working_tree.py +4 -1
  191. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_index_cmd.py +20 -2
  192. sql_code_graph-1.33.0/tests/unit/test_index_filter_config.py +76 -0
  193. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_index_flags.py +16 -2
  194. sql_code_graph-1.33.0/tests/unit/test_index_summary_degraded_metric.py +329 -0
  195. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_install.py +8 -1
  196. sql_code_graph-1.33.0/tests/unit/test_issue_63_readonly_lock.py +153 -0
  197. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_mcp_control.py +151 -14
  198. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_noise_filter.py +10 -3
  199. sql_code_graph-1.33.0/tests/unit/test_normalize_keys.py +353 -0
  200. sql_code_graph-1.33.0/tests/unit/test_parse_failed_classification.py +174 -0
  201. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_perf_scaling_guard.py +86 -2
  202. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_pr07_observability.py +35 -10
  203. sql_code_graph-1.33.0/tests/unit/test_pr6_execute_immediate_unwrap.py +197 -0
  204. sql_code_graph-1.33.0/tests/unit/test_pr_impact_unit.py +499 -0
  205. sql_code_graph-1.33.0/tests/unit/test_qualify_failed_unit.py +157 -0
  206. sql_code_graph-1.33.0/tests/unit/test_repo_relative_cte_namespaces.py +247 -0
  207. sql_code_graph-1.33.0/tests/unit/test_resolvable_write_col_edges_unit.py +261 -0
  208. sql_code_graph-1.33.0/tests/unit/test_selects_from_completeness_unit.py +159 -0
  209. sql_code_graph-1.33.0/tests/unit/test_selfheal_detector.py +162 -0
  210. sql_code_graph-1.33.0/tests/unit/test_selfheal_pr1_messages.py +133 -0
  211. sql_code_graph-1.33.0/tests/unit/test_selfheal_reexec.py +357 -0
  212. sql_code_graph-1.33.0/tests/unit/test_selfheal_watcher.py +280 -0
  213. sql_code_graph-1.33.0/tests/unit/test_skip_counts_persistence.py +162 -0
  214. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_star_schema_unit.py +10 -5
  215. sql_code_graph-1.33.0/tests/unit/test_temp_table_namespacing.py +797 -0
  216. sql_code_graph-1.33.0/tests/unit/test_tool_version_stamp.py +405 -0
  217. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_tools_hints.py +22 -6
  218. sql_code_graph-1.33.0/tests/unit/test_transform_kind_classification.py +265 -0
  219. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_uninstall.py +67 -6
  220. sql_code_graph-1.33.0/tests/unit/test_unknown_sentinel_skip.py +184 -0
  221. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_upsert_batch_invariant.py +60 -0
  222. sql_code_graph-1.33.0/tests/unit/test_use_schema_session_context.py +446 -0
  223. sql_code_graph-1.33.0/tests/unit/test_view_classification.py +82 -0
  224. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_walker.py +66 -0
  225. sql_code_graph-1.33.0/tests/unit/test_worker_error_classification.py +101 -0
  226. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/uv.lock +1 -1
  227. sql_code_graph-1.5.1/src/sqlcg/cli/commands/analyze.py +0 -345
  228. sql_code_graph-1.5.1/src/sqlcg/lineage/aggregator.py +0 -86
  229. sql_code_graph-1.5.1/src/sqlcg/parsers/ansi_parser.py +0 -462
  230. sql_code_graph-1.5.1/src/sqlcg/parsers/snowflake_parser.py +0 -351
  231. sql_code_graph-1.5.1/src/sqlcg/utils/ignore.py +0 -38
  232. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.claude/agents/api-documenter.md +0 -0
  233. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.claude/agents/architect-reviewer.md +0 -0
  234. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.claude/agents/code-reviewer.md +0 -0
  235. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.claude/agents/plan-reviewer.md +0 -0
  236. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  237. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  238. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  239. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.github/workflows/benchmark.yml +0 -0
  240. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.github/workflows/e2e-tests.yml +0 -0
  241. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.github/workflows/test.yml +0 -0
  242. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.pre-commit-config.yaml +0 -0
  243. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/.sqlcgignore +0 -0
  244. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/docs/AIRBNB_PARSE_REPORT.md +0 -0
  245. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/e2e_firstuser_report.md +0 -0
  246. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/e2e_run_20260528_101413.output +0 -0
  247. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/main.py +0 -0
  248. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/plan/WORKFLOW.md +0 -0
  249. {sql_code_graph-1.5.1/plan/measurements → sql_code_graph-1.33.0/plan/metrics}/schema_comparison_with_schema.json +0 -0
  250. {sql_code_graph-1.5.1/plan/measurements → sql_code_graph-1.33.0/plan/metrics}/schema_comparison_without_schema.json +0 -0
  251. {sql_code_graph-1.5.1/plan/measurements → sql_code_graph-1.33.0/plan/metrics}/sprint_pool_300s_plan.json +0 -0
  252. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/reports}/sprint_03_v0.3.1_postmortem.md +0 -0
  253. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/reports}/sprint_3.1_postmortem.md +0 -0
  254. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/research}/blueprint.md +0 -0
  255. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/research}/investigation_e5_e4.md +0 -0
  256. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/research}/parse_diagnostics.md +0 -0
  257. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/research}/parsing_errors_experiment.md +0 -0
  258. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/research}/snowflake_en_test_suite.md +0 -0
  259. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/research}/sqlcg.md +0 -0
  260. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/bundle_claude_skill.md +0 -0
  261. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/diff-impact-producer-file.md +0 -0
  262. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/feature_34_unused_presentation_segregation.md +0 -0
  263. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/feature_35_external_downstream_injection.md +0 -0
  264. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/feature_F2_bundle_claude_skill.md +0 -0
  265. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/feature_kuzu_to_duckdb_migration.md +0 -0
  266. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/fix_downstream_sink_location.md +0 -0
  267. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/fix_dynamic_table_parsing.md +0 -0
  268. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/fix_expand_qualify_perf.md +0 -0
  269. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/fix_firstuser_findings.md +0 -0
  270. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/fix_issue29_live_test_followups.md +0 -0
  271. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/fix_schema_case_mismatch.md +0 -0
  272. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/hygiene_config_path_and_survivors.md +0 -0
  273. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/issue-38-backfill-cte-bridge.md +0 -0
  274. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/living_codebase_resync.md +0 -0
  275. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_01.md +0 -0
  276. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_01_deployment_pypi.md +0 -0
  277. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_02.md +0 -0
  278. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_02_v0.3.0_core.md +0 -0
  279. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_03.md +0 -0
  280. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_04_column_lineage.md +0 -0
  281. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_04_column_lineage_fix.md +0 -0
  282. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_05_star_resolution.md +0 -0
  283. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_06_lineage_coverage.md +0 -0
  284. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_07_open_ecodes.md +0 -0
  285. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_07_perf_and_live_test.md +0 -0
  286. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_08_perf_upsert.md +0 -0
  287. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_09_lineage_coverage.md +0 -0
  288. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_10_anchor_tools.md +0 -0
  289. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_11_v1.0.2_bugfix.md +0 -0
  290. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_12_v1.1.0.md +0 -0
  291. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/sprint_13_v1.1.0_cluster_b.md +0 -0
  292. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/trust_layer.md +0 -0
  293. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/v1.1.0_cluster_b_provenance_trust.md +0 -0
  294. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/v1.1.0_live_graph_freshness.md +0 -0
  295. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/v1.1.1_batch_upsert_perf.md +0 -0
  296. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/v1_1_2_bugfix.md +0 -0
  297. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/v1_1_3_union_cte_star.md +0 -0
  298. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/v1_2_0_read_proxy.md +0 -0
  299. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/v1_2_1_bugfix.md +0 -0
  300. {sql_code_graph-1.5.1/plan → sql_code_graph-1.33.0/plan/sprints}/version-parity-and-restart.md +0 -0
  301. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/profile.html +0 -0
  302. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/pyrightconfig.json +0 -0
  303. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/scripts/collect_parse_errors.py +0 -0
  304. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/scripts/generate_cli_docs.sh +0 -0
  305. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/__main__.py +0 -0
  306. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/__init__.py +0 -0
  307. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/__init__.py +0 -0
  308. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/report.py +0 -0
  309. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/cli/commands/uninstall.py +0 -0
  310. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/__init__.py +0 -0
  311. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/jobs.py +0 -0
  312. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/core/queries.cypher +0 -0
  313. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/__init__.py +0 -0
  314. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/dbt_adapter.py +0 -0
  315. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/indexer/watcher.py +0 -0
  316. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/lineage/__init__.py +0 -0
  317. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/lineage/schema_resolver.py +0 -0
  318. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/metrics/__init__.py +0 -0
  319. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/metrics/store.py +0 -0
  320. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/parsers/__init__.py +0 -0
  321. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/parsers/bigquery_parser.py +0 -0
  322. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/parsers/postgres_parser.py +0 -0
  323. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/parsers/registry.py +0 -0
  324. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/parsers/tsql_parser.py +0 -0
  325. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/__init__.py +0 -0
  326. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/control.py +0 -0
  327. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/server/exceptions.py +0 -0
  328. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/utils/__init__.py +0 -0
  329. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/utils/hashing.py +0 -0
  330. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/src/sqlcg/utils/logging.py +0 -0
  331. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/__init__.py +0 -0
  332. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/__init__.py +0 -0
  333. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/adversarial/200_join.sql +0 -0
  334. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/adversarial/500_union.sql +0 -0
  335. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/bench_indexer.py +0 -0
  336. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/conftest.py +0 -0
  337. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
  338. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
  339. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
  340. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
  341. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
  342. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
  343. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
  344. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
  345. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
  346. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
  347. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/tpch/q01.sql +0 -0
  348. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/tpch/q02.sql +0 -0
  349. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/tpch/q03.sql +0 -0
  350. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/tpch/q04.sql +0 -0
  351. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/benchmarks/tpch/q05.sql +0 -0
  352. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/__init__.py +0 -0
  353. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/conftest.py +0 -0
  354. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
  355. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_airbnb_e2e.py +0 -0
  356. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_cli_index.py +0 -0
  357. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_git_hook_install.py +0 -0
  358. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_mcp_lifecycle.py +0 -0
  359. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_mcp_tools.py +0 -0
  360. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
  361. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_star_resolution_e2e.py +0 -0
  362. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/e2e/test_watch.py +0 -0
  363. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
  364. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
  365. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
  366. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
  367. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
  368. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/raw_listings.sql +0 -0
  369. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
  370. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/src_hosts.sql +0 -0
  371. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/src_listings.sql +0 -0
  372. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/airbnb/src_reviews.sql +0 -0
  373. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/bigquery/.gitkeep +0 -0
  374. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/jaffle_shop/customers.sql +0 -0
  375. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/jaffle_shop/orders.sql +0 -0
  376. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
  377. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/snowflake/base_tables.sql +0 -0
  378. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/snowflake/reports.sql +0 -0
  379. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/snowflake/views.sql +0 -0
  380. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
  381. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
  382. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
  383. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/star_corpus/etl_star.sql +0 -0
  384. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/synthetic/base_tables.sql +0 -0
  385. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/synthetic/reports.sql +0 -0
  386. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/fixtures/synthetic/views.sql +0 -0
  387. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/__init__.py +0 -0
  388. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/snowflake/__init__.py +0 -0
  389. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/snowflake/test_insert_select.py +0 -0
  390. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_T34_presentation_segregation.py +0 -0
  391. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_analyze_case_fold.py +0 -0
  392. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_bulk_upsert.py +0 -0
  393. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_case_split_seed_regression.py +0 -0
  394. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_column_lineage_e2e.py +0 -0
  395. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_cross_file_lineage.py +0 -0
  396. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_cte_recall_guard.py +0 -0
  397. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_cte_schema_alias_guard.py +0 -0
  398. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_cte_source_node_invariant.py +0 -0
  399. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_dialect_auto_resolution.py +0 -0
  400. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_dialect_matrix.py +0 -0
  401. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_duckdb_parity.py +0 -0
  402. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
  403. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_freshness_mcp.py +0 -0
  404. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
  405. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_indexer_batching.py +0 -0
  406. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_indexer_commits.py +0 -0
  407. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_indexer_to_graph.py +0 -0
  408. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_live_anchors.py +0 -0
  409. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_mvcc_rebuild.py +0 -0
  410. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_pr1_confidence_reason.py +0 -0
  411. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_read_via_server.py +0 -0
  412. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_readonly_under_lock.py +0 -0
  413. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_reindex_via_server.py +0 -0
  414. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_single_writer_queue.py +0 -0
  415. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_star_resolution.py +0 -0
  416. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/integration/test_temp_table_lineage.py +0 -0
  417. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/perf/__init__.py +0 -0
  418. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/perf/test_perf.py +0 -0
  419. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E10/__init__.py +0 -0
  420. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E11/__init__.py +0 -0
  421. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E12/__init__.py +0 -0
  422. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E12/e12_json_path.sql +0 -0
  423. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
  424. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E13/__init__.py +0 -0
  425. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E14/__init__.py +0 -0
  426. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E15/__init__.py +0 -0
  427. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E16/__init__.py +0 -0
  428. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E16/e16_merge.sql +0 -0
  429. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
  430. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E17/__init__.py +0 -0
  431. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E18/__init__.py +0 -0
  432. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E18/e18_decode.sql +0 -0
  433. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
  434. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E18/e18_nvl2.sql +0 -0
  435. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E18/test_e18.py +0 -0
  436. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E19/__init__.py +0 -0
  437. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E2/__init__.py +0 -0
  438. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
  439. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E2/e2_function_alias.sql +0 -0
  440. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
  441. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E2/test_e2.py +0 -0
  442. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E20/__init__.py +0 -0
  443. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E21/__init__.py +0 -0
  444. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
  445. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
  446. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E21/test_e21.py +0 -0
  447. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E22/__init__.py +0 -0
  448. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E23/__init__.py +0 -0
  449. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
  450. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
  451. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E23/test_e23.py +0 -0
  452. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E24/__init__.py +0 -0
  453. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E25/__init__.py +0 -0
  454. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E25/e25_cross_db.sql +0 -0
  455. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E25/e25_two_part.sql +0 -0
  456. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E25/test_e25.py +0 -0
  457. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E25/test_e25_full_id.py +0 -0
  458. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E26/__init__.py +0 -0
  459. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E27/__init__.py +0 -0
  460. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
  461. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E27/e27_udf.sql +0 -0
  462. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E28/__init__.py +0 -0
  463. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E29/__init__.py +0 -0
  464. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E3/__init__.py +0 -0
  465. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E3/e3_alter_table.sql +0 -0
  466. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
  467. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
  468. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E3/test_e3.py +0 -0
  469. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E30/__init__.py +0 -0
  470. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E31/__init__.py +0 -0
  471. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E32/__init__.py +0 -0
  472. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E33/__init__.py +0 -0
  473. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E34/__init__.py +0 -0
  474. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E35/__init__.py +0 -0
  475. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E36/__init__.py +0 -0
  476. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
  477. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E36/e36_temp_table.sql +0 -0
  478. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E36/test_e36.py +0 -0
  479. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E36/test_e36_xfile.py +0 -0
  480. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E37/__init__.py +0 -0
  481. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E38/__init__.py +0 -0
  482. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E4/__init__.py +0 -0
  483. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
  484. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
  485. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
  486. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E4/e4_unpivot.sql +0 -0
  487. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E4/test_e4.py +0 -0
  488. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E5/__init__.py +0 -0
  489. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
  490. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
  491. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
  492. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E5/test_e5.py +0 -0
  493. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
  494. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E8/__init__.py +0 -0
  495. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
  496. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
  497. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E8/e8_uuid.sql +0 -0
  498. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E8/test_e8.py +0 -0
  499. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E9/__init__.py +0 -0
  500. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_aggregates/__init__.py +0 -0
  501. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
  502. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
  503. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
  504. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
  505. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_date_functions/__init__.py +0 -0
  506. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
  507. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
  508. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
  509. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
  510. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
  511. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/README.md +0 -0
  512. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/__init__.py +0 -0
  513. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/anchors/__init__.py +0 -0
  514. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/anchors/fixture_etl.sql +0 -0
  515. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
  516. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
  517. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/anchors/fixture_source.sql +0 -0
  518. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
  519. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
  520. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/snowflake/conftest.py +0 -0
  521. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/__init__.py +0 -0
  522. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/snowflake/__init__.py +0 -0
  523. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/snowflake/test_scripting_noise.py +0 -0
  524. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
  525. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_BugC_hook_upgrade.py +0 -0
  526. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_T09_01_qualify_once.py +0 -0
  527. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_T09_02_ddl_skip.py +0 -0
  528. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
  529. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_T09_06_log_verbosity.py +0 -0
  530. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_T35_config_external_consumers.py +0 -0
  531. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_aggregator.py +0 -0
  532. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_aggregator_skip.py +0 -0
  533. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_branch_monitor.py +0 -0
  534. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_bulk_upsert_invariant.py +0 -0
  535. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_canonical_target_resolution.py +0 -0
  536. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_cli.py +0 -0
  537. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_cli_help.py +0 -0
  538. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_closure_depth.py +0 -0
  539. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_column_lineage_wiring.py +0 -0
  540. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_config.py +0 -0
  541. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_data_models.py +0 -0
  542. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_db_info.py +0 -0
  543. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_dominant_cause.py +0 -0
  544. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_duckdb_backend_shared.py +0 -0
  545. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_freshness_helper.py +0 -0
  546. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_gain_ratio.py +0 -0
  547. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_git_hooks_notify.py +0 -0
  548. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_graph_completeness_invariant.py +0 -0
  549. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_hard_kill_pool.py +0 -0
  550. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_index_progress.py +0 -0
  551. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_indexer_progress.py +0 -0
  552. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_indexer_quality.py +0 -0
  553. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_install_message.py +0 -0
  554. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_jobs.py +0 -0
  555. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_judgement.py +0 -0
  556. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_lineage_conversion.py +0 -0
  557. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_literal_column_skip.py +0 -0
  558. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_mcp_best_practices.py +0 -0
  559. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_mcp_stdio_smoke.py +0 -0
  560. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_metrics.py +0 -0
  561. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_parse_file_dependency_filter.py +0 -0
  562. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_parse_quality.py +0 -0
  563. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_parser.py +0 -0
  564. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_queries_loader.py +0 -0
  565. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_read_client.py +0 -0
  566. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
  567. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_schema_resolver.py +0 -0
  568. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_server.py +0 -0
  569. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
  570. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_sprint_06_t04_t05.py +0 -0
  571. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_star_resolution_unit.py +0 -0
  572. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_submit_feedback.py +0 -0
  573. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_subprocess_isolate.py +0 -0
  574. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_t02_expression_name_extraction.py +0 -0
  575. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_t03_ddl_skip.py +0 -0
  576. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_timeout_cancel.py +0 -0
  577. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_tools_warnings.py +0 -0
  578. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_unqualified_fallback.py +0 -0
  579. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_version_parity.py +0 -0
  580. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_watcher.py +0 -0
  581. {sql_code_graph-1.5.1 → sql_code_graph-1.33.0}/tests/unit/test_writer_queue.py +0 -0
@@ -91,6 +91,12 @@ Before starting work, call `list_graph_stats_tool` once.
91
91
  - Unit tests: ...
92
92
  - Integration tests: ...
93
93
 
94
+ > Describe each test by the **behavior** it verifies, never by a task/case code
95
+ > (`TC1`, `T-03`, …). The developer names tests `test_<unit>_<scenario>_<expected>`
96
+ > and links this plan in the docstring — see *Test naming* in
97
+ > [`developer.md`](.claude/agents/developer.md). Do not seed opaque codes the
98
+ > developer will copy into test names.
99
+
94
100
  ## Acceptance Criteria
95
101
  - [ ] Criterion 1
96
102
  - [ ] Criterion 2
@@ -139,14 +145,29 @@ code-reviewer's job).
139
145
 
140
146
  Steps:
141
147
 
142
- 1. Read `git diff main...HEAD` and the plan side-by-side.
143
- 2. For each implementation step in the plan, verify it was addressed.
144
- 3. Append a `## Plan Compliance YYYY-MM-DD` section to `plan/<feature>.md`:
145
- - `PASS` — all steps implemented as planned (deviations are documented)
148
+ 1. Read `git diff main...HEAD` and the plan side-by-side. **The developer's
149
+ handoff/PR body is a claim, not evidence never quote it as verification.**
150
+ Presence of code that "looks like" a step is not compliance; trace what the
151
+ code DOES.
152
+ 2. For each implementation step in the plan, verify it was addressed and record
153
+ the **evidence**: the diff file:line that implements it, and the test that
154
+ pins it. A step with no citable diff hunk or no pinning test is not PASS.
155
+ 3. For each plan **acceptance criterion**, run its test yourself (or execute the
156
+ criterion's repro directly) and record the observed output. Check the test
157
+ asserts the criterion itself, not adjacent behavior — and that fixtures model
158
+ the live configuration the criterion will face (schema aliases, USE SCHEMA
159
+ context, real-corpus statement shapes), not a minimal idealized case. A
160
+ criterion whose test passes on a fixture that cannot exhibit the failure mode
161
+ is UNVERIFIED, not PASS (this is how the v1.21.0 dual-write shipped green).
162
+ 4. Append a `## Plan Compliance — YYYY-MM-DD` section to `plan/<feature>.md`,
163
+ one row per step/criterion: PASS with evidence (diff hunk + test + observed
164
+ output), FAIL with reason, or UNVERIFIED with what's missing.
165
+ - `PASS` — every row PASS (deviations are documented)
146
166
  - `FAIL — <step>: <reason>` — a step was skipped or implemented contrary
147
- to the plan
148
- 4. Commit the compliance result.
149
- 5. If `FAIL`, tell the developer what to fix before code review starts.
167
+ to the plan; UNVERIFIED rows also block an overall PASS
168
+ 5. Commit the compliance result.
169
+ 6. If `FAIL` (or any UNVERIFIED), tell the developer what to fix before code
170
+ review starts.
150
171
 
151
172
  ## MUST NOT
152
173
 
@@ -78,6 +78,24 @@ Before starting work, call `list_graph_stats_tool` once.
78
78
  13. Say **"finished"** — this signals the idle architect-planner to perform the
79
79
  plan-compliance check before the PR moves to code review.
80
80
 
81
+ ## Report facts, not verdicts
82
+
83
+ Your handoff, PR body, and final report state **what is** — never whether it
84
+ satisfies the plan. That judgment belongs to the compliance check and the
85
+ shepherd, who verify against the diff, not your summary.
86
+
87
+ - DO report: files changed with file:line, exact test counts (collected/passed/
88
+ failed/skipped), commands run with their observable output, deviations with
89
+ their mechanism, anything NOT done or NOT verified.
90
+ - DO NOT write: "implemented as planned", "all acceptance criteria met",
91
+ "no deviations" as a conclusion you reasoned to, "plan compliant", or any
92
+ equivalent verdict. If you believe a criterion is met, cite the test name and
93
+ its asserted output instead — the evidence, not the judgment.
94
+ - A claim of "pre-existing failure" requires proof in the report: the exact
95
+ command run on clean master and its output. No proof → don't make the claim.
96
+ - Never record decisions in progress.txt that were not explicitly made by the
97
+ user or the shepherd in this session.
98
+
81
99
  ## PR Review Iteration
82
100
 
83
101
  When addressing review comments:
@@ -115,6 +133,57 @@ Run through this before marking work done:
115
133
  feature produces observable output (e.g., non-empty list, specific field value). Tests
116
134
  that only cover exception handling or log messages are insufficient on their own.
117
135
 
136
+ ## Test naming — describe behavior, link the doc
137
+
138
+ Tests are read far more often than the plan that spawned them. A name like
139
+ `test_tc2_*` or `test_T35_DOWN_1_*` is meaningless once the sprint closes — the
140
+ reader has to go find the plan to learn what broke. Use a name that stands on its
141
+ own and a docstring that links the governing doc.
142
+
143
+ **Convention (standard three-part name — nothing to install):**
144
+
145
+ ```
146
+ test_<unit>_<scenario>_<expected>
147
+ ```
148
+
149
+ **Forbidden: opaque plan-internal codes in the test name.** These families are all
150
+ ephemeral identifiers that mean nothing outside their plan — never use them as the
151
+ name:
152
+
153
+ | Family | Example | Origin |
154
+ |--------|---------|--------|
155
+ | `TC<n>` | `test_tc6b_*` | "test case" numbers in a plan |
156
+ | `T<nn>` task IDs | `test_T01_*`, `test_T09_06_*` | sprint task IDs |
157
+ | `T34`/`T35` (+ `CFG`/`DIFF`/`DOWN`/`IDX` sub-codes) | `test_T35_DOWN_1_*` | feature task IDs |
158
+ | `F<n>` feature IDs | `test_F2_*` | feature IDs |
159
+ | `gap<n>` / `issue<n>` | `test_gap3_*`, `test_issue38_*` | blueprint-gap / issue numbers |
160
+
161
+ The code goes in the **docstring**, not the name. Link the plan doc (markdown link,
162
+ real path — see the link convention in `ARCHITECTURE_REVIEW.md`) so the reader can
163
+ jump to the rationale:
164
+
165
+ ```python
166
+ def test_filtered_surface_recall_physical_sources(indexed_db):
167
+ """Physical source tables survive the default analyze filter.
168
+
169
+ Guards the #40 user-surface recall plan
170
+ ([plan doc](plan/sprints/v1_2_1_bugfix.md)).
171
+ """
172
+ ```
173
+
174
+ **Two exceptions** (these codes are durable, documented vocabulary — keep the code,
175
+ just add the doc-link docstring):
176
+ - The **`E{n}` lineage-failure taxonomy** (`test_e27_*` etc.) — `E{n}` *is* the
177
+ shared name; renaming it loses meaning. Link the taxonomy doc in the docstring.
178
+ - **CLAUDE.md-pinned regression guards** (`test_T09_01_qualify_once.py`,
179
+ `*_invariant.py`) are referenced *by filename* in `CLAUDE.md`. Do not rename the
180
+ file without updating CLAUDE.md in lockstep; prefer leaving the filename and giving
181
+ the test functions behavioral names + docstrings.
182
+
183
+ **Rename-on-touch, not big-bang.** Do not open a PR that mass-renames existing tests.
184
+ When you next implement in or edit a test (or its area), bring the tests you touch up
185
+ to this convention as part of that change. New tests follow it from the start.
186
+
118
187
  ## Performance invariants — MUST preserve
119
188
 
120
189
  `src/sqlcg/parsers/base.py` contains hard-won performance fixes. Before touching this
@@ -168,6 +168,11 @@ critical finding before shipping. Place it in `## Test Strategy` under
168
168
  - Include a failure message that names the original regression
169
169
  (e.g., `"Column lineage edges must be non-zero — guards against v0.3.0 regression"`)
170
170
 
171
+ > Refer to tests by the **behavior** they verify, not by a task/case code (`TC1`,
172
+ > `T-03`, …). The developer names tests `test_<unit>_<scenario>_<expected>` and links
173
+ > the plan in the docstring — see *Test naming* in
174
+ > [`developer.md`](.claude/agents/developer.md). Don't seed codes into "Tests to add".
175
+
171
176
  ## Sprint-Level Acceptance Criteria — Always Required
172
177
 
173
178
  End every plan with `## Acceptance Criteria (sprint-level)` — a checklist of
@@ -4,6 +4,11 @@ on:
4
4
  push:
5
5
  tags: ["v*"]
6
6
  workflow_dispatch:
7
+ inputs:
8
+ ref:
9
+ description: "Tag or commit to build and publish (e.g. v1.6.0). Leave blank to use the current HEAD of the default branch."
10
+ required: false
11
+ default: ""
7
12
 
8
13
  permissions:
9
14
  contents: write
@@ -14,6 +19,8 @@ jobs:
14
19
  runs-on: ubuntu-latest
15
20
  steps:
16
21
  - uses: actions/checkout@v4
22
+ with:
23
+ ref: ${{ github.event.inputs.ref || github.ref }}
17
24
  - uses: astral-sh/setup-uv@v4
18
25
  - run: uv sync --all-extras
19
26
  - run: uv run pytest tests/unit tests/integration -v --tb=short
@@ -26,6 +33,8 @@ jobs:
26
33
  environment: pypi
27
34
  steps:
28
35
  - uses: actions/checkout@v4
36
+ with:
37
+ ref: ${{ github.event.inputs.ref || github.ref }}
29
38
  - uses: astral-sh/setup-uv@v4
30
39
  - run: uv build
31
40
  - uses: pypa/gh-action-pypi-publish@release/v1
@@ -65,6 +65,8 @@ tests/e2e/test_dwh_schema_e2e.py
65
65
  .claude/progress.txt
66
66
  columns.csv
67
67
  results_*.json
68
+ # Large scratch data export (811k rows) — never commit
69
+ anomaly.csv
68
70
 
69
71
  # Local-only golden lineage ground truth — names private DWH columns
70
72
  tests/e2e/golden_lineage.yaml
@@ -0,0 +1,364 @@
1
+ # Architecture Review — sql-code-graph (`sqlcg`)
2
+
3
+ **Current as of:** v1.25.0 · DuckDB backend · Python 3.12
4
+ **Status:** living document — describes the system as it stands today.
5
+ **History:** the pre-1.4 blueprint review, PR/issue reviews, and every sprint
6
+ postmortem (§1–20 + the Kuzu→DuckDB migration review) are preserved verbatim in
7
+ [`ARCHITECTURE_REVIEW_ARCHIVE.md`](ARCHITECTURE_REVIEW_ARCHIVE.md). This file was
8
+ overhauled on 2026-06-08 to drop content made stale by the DuckDB migration and the
9
+ v1.x releases. See [§8 History](#8-history) for the timeline.
10
+
11
+ > **Link convention.** Links here use real repo paths (e.g.
12
+ > [`base.py`](src/sqlcg/parsers/base.py)) so a rename breaks the link *visibly*. The
13
+ > guard test [`test_doc_links.py`](tests/unit/test_doc_links.py) fails CI if any link
14
+ > in a maintained doc points at a missing file.
15
+
16
+ ---
17
+
18
+ ## 1. What `sqlcg` is
19
+
20
+ `sqlcg` indexes a corpus of `.sql` files into an embedded **DuckDB** graph and answers
21
+ **lineage** questions over it — "what feeds this column?", "what breaks if I change this
22
+ table?", "which views are downstream?". It parses SQL with `sqlglot`, persists tables /
23
+ columns / queries / lineage edges as graph nodes and relationships, and exposes the graph
24
+ two ways: a `typer` **CLI** (`sqlcg …`) and an **MCP server** for use from Claude.
25
+
26
+ It targets both ends of a scale spectrum — a ~20-file ETL repo and a 1,000–1,600 file
27
+ data warehouse — from the same zero-config `sqlcg index ./sql` entry point. The scale
28
+ rules and performance budget live in [`CLAUDE.md`](CLAUDE.md); the invariants that enforce
29
+ them are summarised in [§4](#4-performance-invariants).
30
+
31
+ ---
32
+
33
+ ## 2. Component map
34
+
35
+ ```mermaid
36
+ flowchart TD
37
+ subgraph entry[Entry points]
38
+ CLI["CLI — typer<br/>cli/main.py"]
39
+ MCP["MCP server — FastMCP<br/>server/server.py + tools.py"]
40
+ end
41
+
42
+ subgraph index[Indexing pipeline]
43
+ WALK["walker — find .sql"]
44
+ POOL["pool — spawn workers<br/>+ hard-kill timeouts"]
45
+ PARSE["parsers — sqlglot<br/>per dialect"]
46
+ AGG["aggregator — 2-pass<br/>cross-file lineage"]
47
+ IDX["indexer — orchestrate<br/>+ batched bulk upsert"]
48
+ end
49
+
50
+ subgraph store[Graph store]
51
+ BACKEND[("DuckDBBackend<br/>7 node / 12 edge tables")]
52
+ end
53
+
54
+ subgraph readpath[Read / query]
55
+ ANALYZE["analyze / find queries<br/>recursive-CTE traversal"]
56
+ end
57
+
58
+ subgraph live[Liveness]
59
+ FRESH["freshness — indexed vs HEAD"]
60
+ WRITER["writer — single-writer drain"]
61
+ JOBS["jobs / watcher — file events"]
62
+ end
63
+
64
+ CLI --> IDX
65
+ CLI --> ANALYZE
66
+ MCP --> ANALYZE
67
+ MCP --> WRITER --> IDX
68
+ IDX --> WALK --> POOL --> PARSE --> AGG --> IDX
69
+ IDX --> BACKEND
70
+ ANALYZE --> BACKEND
71
+ FRESH -.-> BACKEND
72
+ JOBS --> WRITER
73
+ ```
74
+
75
+ **Read path** (`analyze`, `find`, most MCP tools) and **write path** (`index`, `reindex`)
76
+ both go through `DuckDBBackend`. When the MCP server is running, the CLI routes reads to it
77
+ ([`read_client.py`](src/sqlcg/server/read_client.py)) and serialises all writes through a
78
+ single-writer drain ([`writer.py`](src/sqlcg/server/writer.py)) so there is exactly one
79
+ writer per database.
80
+
81
+ ### 2.1 Responsibilities
82
+
83
+ | Module | Job |
84
+ |---|---|
85
+ | [`cli/main.py`](src/sqlcg/cli/main.py) + [`cli/commands/`](src/sqlcg/cli/commands) | Typer CLI. Commands: `index`, `reindex`, `watch`, `report`, `gain`, `install`, `uninstall`; groups `db` (`init`/`reset`/`info`/`list-repos`), `find` (`table`/`column`/`pattern`), `analyze` (`upstream`/`downstream`/`impact`/`failures`/`unused`), `mcp`, `git` (`install-hooks`). |
86
+ | [`server/server.py`](src/sqlcg/server/server.py) | FastMCP instance + stdio entry. Constructs `mcp` at module scope (after the stdout→stderr guard) so [`tools.py`](src/sqlcg/server/tools.py) can register tools onto it. |
87
+ | [`server/tools.py`](src/sqlcg/server/tools.py) | The 18 MCP tools — `trace_column_lineage`, `get_upstream_dependencies`, `get_downstream_dependencies`, `diff_impact`, `find_table_usages`, `find_definition`, `search_sql_pattern`, `analyze_unused`, `get_hub_ranking`, `index_repo`, `execute_sql`, `get_empty_propagation`, `get_pr_impact`, etc. |
88
+ | [`server/writer.py`](src/sqlcg/server/writer.py) | Single-writer queue + drain task. The drain holds `backend_lock` and runs the indexer op directly — the sole backend writer. |
89
+ | [`server/read_client.py`](src/sqlcg/server/read_client.py) | Routes CLI read commands through the live server socket when one is running. |
90
+ | [`server/control.py`](src/sqlcg/server/control.py) | `.pid` / `.sock` control files for server discovery, status, and stop — keyed off the db path. |
91
+ | [`server/models.py`](src/sqlcg/server/models.py) · [`server/exceptions.py`](src/sqlcg/server/exceptions.py) | Pydantic return types for tools; the tool error hierarchy. |
92
+ | [`server/noise_filter.py`](src/sqlcg/server/noise_filter.py) | Filters backup tables and schema-alias mirrors out of user-facing surfaces. |
93
+ | [`server/skill.py`](src/sqlcg/server/skill.py) | Pure renderer for the bundled Claude skill (`SKILL.md`); the installer writes its output to disk. |
94
+ | [`indexer/indexer.py`](src/sqlcg/indexer/indexer.py) | Orchestrates parse → persist. Two-pass index, batched bulk upsert (`_flush_row_batch`), atomic SHA stamping. |
95
+ | [`indexer/walker.py`](src/sqlcg/indexer/walker.py) | Walks the corpus for `.sql` files honouring ignore patterns. |
96
+ | [`indexer/pool.py`](src/sqlcg/indexer/pool.py) | Spawn-mode worker pool; each worker holds pass-1/pass-2 parsers. Per-task hard-kill timeout + respawn (what `concurrent.futures` can't do). |
97
+ | [`indexer/dbt_adapter.py`](src/sqlcg/indexer/dbt_adapter.py) | Enriches `SchemaResolver` from a dbt `manifest.json`. |
98
+ | [`indexer/git_delta.py`](src/sqlcg/indexer/git_delta.py) | Computes the changed-file set between two git SHAs for incremental reindex. |
99
+ | [`indexer/watcher.py`](src/sqlcg/indexer/watcher.py) | `watchdog` file-event source for `sqlcg watch`. |
100
+ | [`indexer/error_classify.py`](src/sqlcg/indexer/error_classify.py) | Maps lineage-extraction failures to the `E{n}` taxonomy for measurement/reporting. |
101
+ | [`lineage/aggregator.py`](src/sqlcg/lineage/aggregator.py) | `CrossFileAggregator` — pass-1 source harvest, pass-2 cross-file lineage resolution. |
102
+ | [`lineage/schema_resolver.py`](src/sqlcg/lineage/schema_resolver.py) | `SchemaResolver` — table/view/column resolution with a lock-guarded cache. One instance per re-index job (never shared across threads). |
103
+ | [`parsers/base.py`](src/sqlcg/parsers/base.py) | Base data models + abstract parser; column-lineage extraction via `sg_lineage`. **Hot path — see [§4](#4-performance-invariants).** |
104
+ | [`parsers/registry.py`](src/sqlcg/parsers/registry.py) | Dialect → parser factory. |
105
+ | [`parsers/{ansi,snowflake,bigquery,postgres,tsql}_parser.py`](src/sqlcg/parsers) | Per-dialect parsers; Snowflake carries the scripting-block / gap handlers. |
106
+ | [`core/duckdb_backend.py`](src/sqlcg/core/duckdb_backend.py) | `DuckDBBackend` — the graph store. 7 node + 12 edge tables, bulk upsert via `unnest`, reentrant `transaction()`, `run_read`, recursive-CTE traversal SQL. |
107
+ | [`core/graph_db.py`](src/sqlcg/core/graph_db.py) | `GraphBackend` ABC. Single-impl today (see [§5](#5-active-findings)); kept for the v2 second-source path. |
108
+ | [`core/schema.py`](src/sqlcg/core/schema.py) | Node/edge labels + `SCHEMA_VERSION` (the schema gate). |
109
+ | [`core/queries.py`](src/sqlcg/core/queries.py) | Loader for query strings in `queries.sql`. |
110
+ | [`core/config.py`](src/sqlcg/core/config.py) | `DbConfig.from_env()` — resolves the db path and settings. |
111
+ | [`core/freshness.py`](src/sqlcg/core/freshness.py) | Backend-free indexed-SHA-vs-HEAD delta; unit-testable with only a git repo. |
112
+ | [`core/jobs.py`](src/sqlcg/core/jobs.py) | Watch job manager — debounced reindex on file-change events. |
113
+ | [`metrics/store.py`](src/sqlcg/metrics/store.py) | SQLite metrics store; opt-out via `SQLCG_METRICS=0`. |
114
+
115
+ ---
116
+
117
+ ## 3. Key flows
118
+
119
+ ### 3.1 Indexing (`sqlcg index`)
120
+ [`walker`](src/sqlcg/indexer/walker.py) enumerates `.sql` files →
121
+ [`pool`](src/sqlcg/indexer/pool.py) farms them to spawn workers → each
122
+ [`parser`](src/sqlcg/parsers/base.py) produces tables/columns/queries and per-statement
123
+ column lineage. The [`aggregator`](src/sqlcg/lineage/aggregator.py) runs **two passes**:
124
+ pass-1 harvests CTE/CTAS bodies and DDL into the `SchemaResolver`; pass-2 reparses with a
125
+ `dependency_filter` to resolve cross-file lineage. [`indexer`](src/sqlcg/indexer/indexer.py)
126
+ accumulates rows across a batch and issues **one bulk upsert per node/edge label per batch**
127
+ into [`DuckDBBackend`](src/sqlcg/core/duckdb_backend.py), stamping the indexed SHA inside the
128
+ same transaction.
129
+
130
+ ### 3.2 Query / lineage (`sqlcg analyze`, MCP tools)
131
+ Lineage traversal is a recursive CTE in DuckDB with a depth cap + path-based cycle guard.
132
+ A kind-filter (`WHERE kind IS NULL OR kind IN ('table','external')`) keeps CTE/derived
133
+ scratch nodes out of user-facing surfaces. Up/down direction differ only in which
134
+ `COLUMN_LINEAGE` edge endpoint binds the result's `file:line`.
135
+
136
+ > **Mental model — CTE/derived edges are structural, not coverage gaps.** For
137
+ > `INSERT INTO t (cols) WITH cte … SELECT … FROM cte`, the parser emits two *different,
138
+ > both-correct* edge families: (1) **CTE chain edges** where the CTE node is the `dst`
139
+ > (`src.x → cte.col`, from the CTE-projection block) and (2) **positional edges** where the
140
+ > CTE is the `src` and the real target is the `dst` (`cte.col → t.col`, from the `#25`
141
+ > block). Multi-hop **upstream** traversal walks *both* to chain `t.col ← cte.col ← src.x`.
142
+ > A `kind='cte'`/`kind='derived'` node is a scratch intermediate, never persistent schema,
143
+ > so it can **never** carry a `HAS_COLUMN` row — but it is *required* in the edge set for
144
+ > traversal. Suppressing family (1) (an earlier "P1 de-leak" attempt) dead-ends upstream
145
+ > traversal at the CTE node and was reverted; the canary is
146
+ > [`test_analyze_case_fold`](tests/integration/test_analyze_case_fold.py)
147
+ > (`test_uppercase_upstream_anchor_returns_same_ids_as_lowercase`).
148
+
149
+ > **Coverage-metric formula — edge health is scoped to real-table destinations.** The
150
+ > `edge_health` and `blindspot` metrics in [`coverage.py`](src/sqlcg/cli/coverage.py)
151
+ > count a `COLUMN_LINEAGE` edge as "good" only when its stripped dst table has a
152
+ > `HAS_COLUMN` entry. Because CTE/derived dst edges can never be catalogued (above), they
153
+ > are **excluded from both numerator and denominator** via
154
+ > `WHERE EXISTS (SELECT 1 FROM "SqlTable" t WHERE t.qualified = <dst_table strip> AND
155
+ > t.kind NOT IN ('cte','derived'))`. This mirrors the analyze-surface kind-filter: scratch
156
+ > nodes are scored out of coverage exactly as they are filtered out of user surfaces.
157
+ > Counting them (the pre-2026-06 formula) made ≥95 % edge health mathematically impossible
158
+ > — ~29 % of all edges legitimately point at CTE/derived intermediates.
159
+
160
+ ### 3.2b INFORMATION_SCHEMA catalog enrichment (PR 2, 2026-06-10)
161
+
162
+ **Why the 2026-05 prohibition is lifted.** The 2026-05 removal of INFORMATION_SCHEMA
163
+ CSV ingestion was based on a "zero edge delta" measurement — true but wrong-axis: schema
164
+ never creates edges, it makes edge *targets resolvable* (`HAS_COLUMN`). The strict
165
+ column-level health metric that shows the win didn't exist until v1.6.1 (PR 1).
166
+
167
+ Measured root cause (2026-06-10, DWH, ~69k edges): 94 % of all bad edges (18,244/19,438)
168
+ come from ETL files writing to tables whose DDL lives in Liquibase **XML** changelogs
169
+ (not indexed). An INFORMATION_SCHEMA export covers those tables directly, falsifying
170
+ wrong positional guesses (contradicted bucket) rather than hiding them.
171
+
172
+ **Design rule (replaces the old prohibition):**
173
+ - `sqlcg catalog load <csv>` loads `INFORMATION_SCHEMA.COLUMNS` into the graph as
174
+ `HAS_COLUMN(source='information_schema')` rows **post-index** (never at parse time).
175
+ - Precedence: `ddl > information_schema > usage` — enforced in `upsert_edges_bulk`
176
+ via `ON CONFLICT (src_key, dst_key) DO UPDATE SET source = CASE … END`.
177
+ - **Parse-time schema feeding remains forbidden.** Passing `schema_sources` into
178
+ `exp.expand()` or `qualify()` is still prohibited (the hot-loop path that measured
179
+ zero and regressed performance in 2026-05).
180
+ - Per-file reindex (`delete_nodes_for_file`) is **source-aware**: only `ddl`/NULL rows
181
+ are deleted; `information_schema` and `usage` rows survive incremental reindex.
182
+ - Config persistence: `[sqlcg.catalog] path = "..."` in `.sqlcg.toml` causes
183
+ `index_repo` to re-apply the catalog at the end of every full rebuild (zero parse-time
184
+ cost, one-shot bulk upsert outside all hot loops).
185
+
186
+ ### 3.3 MCP server + single-writer model
187
+ [`server.py`](src/sqlcg/server/server.py) runs FastMCP over stdio. Writes (`index`,
188
+ `reindex`) are enqueued and drained by [`writer.py`](src/sqlcg/server/writer.py) under
189
+ `backend_lock` — one writer per db. The full-rebuild drain wraps `clear_all_tables()` +
190
+ `index_repo()` in one reentrant transaction, so a mid-rebuild failure rolls back to the
191
+ prior graph. Reads currently share that lock (see [§5](#5-active-findings)).
192
+
193
+ ### 3.4 Freshness / reindex / watch
194
+ [`freshness`](src/sqlcg/core/freshness.py) compares the stored `indexed_sha` to git HEAD;
195
+ [`git_delta`](src/sqlcg/indexer/git_delta.py) yields the changed files; `reindex` /
196
+ [`jobs`](src/sqlcg/core/jobs.py) + [`watcher`](src/sqlcg/indexer/watcher.py) drive
197
+ incremental updates (`git install-hooks` wires this to commits).
198
+
199
+ ---
200
+
201
+ ## 4. Performance invariants
202
+
203
+ These are **not duplicated here** — the canonical table (parser hot-path rules, bulk-upsert
204
+ and batch-flush invariants, the named regressions each guards) lives in
205
+ [`CLAUDE.md`](CLAUDE.md) under *Performance invariants — DO NOT REMOVE OR SIMPLIFY*. They
206
+ are pinned by [`test_perf_scaling_guard.py`](tests/unit/test_perf_scaling_guard.py),
207
+ [`test_bulk_upsert_invariant.py`](tests/unit/test_bulk_upsert_invariant.py),
208
+ [`test_upsert_batch_invariant.py`](tests/unit/test_upsert_batch_invariant.py), and
209
+ [`test_T09_01_qualify_once.py`](tests/unit/test_T09_01_qualify_once.py). Any refactor of
210
+ [`base.py`](src/sqlcg/parsers/base.py) or [`indexer.py`](src/sqlcg/indexer/indexer.py) must
211
+ keep them green.
212
+
213
+ ---
214
+
215
+ ## 5. Active findings
216
+
217
+ Only genuinely-open items live here. Resolved findings and their reasoning are in the
218
+ [archive](ARCHITECTURE_REVIEW_ARCHIVE.md).
219
+
220
+ | # | Sev | Finding | Where | Plan |
221
+ |---|-----|---------|-------|------|
222
+ | F1 | LOW | **Scratch-object leak into the default `analyze` surface.** ~22% of `kind='table'` nodes carry `tmp_*`/`temp_*` prefixes and leak into filtered output. Fix belongs at **classification time** (emit `kind='derived'` for TEMP/TRANSIENT CTAS targets), never in the name-blind filter. | [`aggregator.py`](src/sqlcg/lineage/aggregator.py) `_build_file_rows`, [`analyze.py`](src/sqlcg/cli/commands/analyze.py) | none yet |
223
+ | F2 | LOW | **RESOLVED (v1.28.2, PR #119+#120)** `run_read` now uses `self._conn.cursor()` for a per-call snapshot; the read dispatch path in `server.py` no longer acquires `backend_lock`. Reads during a rebuild see the last committed graph immediately. Drain (writer.py:330) still holds `backend_lock` for the full write transaction. Proven by `test_write_memory_ceiling.py` Scenario A (read returns in <1 s with non-empty result while write transaction open). | [`duckdb_backend.py`](src/sqlcg/core/duckdb_backend.py) `run_read`, [`server.py`](src/sqlcg/server/server.py) `query` op | sprint_backlog_q2_bugfix §PR-E |
224
+ | F3 | LOW | **RESOLVED (v1.28.2, PR #119+#120)** 1,600-file write-memory ceiling measured and verified. Peak RSS in a dedicated subprocess (1,600 minimal SQL fixtures, batch_size=50): **0.154 GiB (165 MB)** — well under the 3.8 GiB gate. Pinned by [`test_write_memory_ceiling.py`](tests/integration/test_write_memory_ceiling.py) Scenario B. | [`indexer.py`](src/sqlcg/indexer/indexer.py), [`duckdb_backend.py`](src/sqlcg/core/duckdb_backend.py) | sprint_backlog_q2_bugfix §PR-E |
225
+ | F4 | LOW | **Single-impl ABC + stale Cypher/Kuzu docstrings.** `GraphBackend` adds indirection without polymorphism now; `clear_all_tables` is a `NotImplementedError`-default on the ABC; a docstring still says "skipped by KuzuDB's MERGE semantics". De-Cypher the docstrings and relocate `clear_all_tables` off the ABC, or collapse the ABC if v2 ACCESS_HISTORY is shelved. | [`graph_db.py`](src/sqlcg/core/graph_db.py) | none yet |
226
+ | F5 | LOW | **TC6b guard reconstructs the query.** The terminal-sink test rebuilds the downstream Cypher/SQL string instead of running `analyze downstream` end-to-end, so it can drift from the shipped query. Replace with a `CliRunner`-based guard. | [`test_user_surface_recall_guard.py`](tests/integration/test_user_surface_recall_guard.py) | none yet |
227
+ | F6 | LOW | **Dead `_set_backend_lock` stub.** Defined but never called (the escalation plumbing it belonged to was deleted in the DuckDB migration). Violates the CLAUDE.md "every new method has a grep-confirmed call site" rule — remove it. | [`tools.py`](src/sqlcg/server/tools.py) | none yet |
228
+ | F7 | MED | **95 % edge-health milestone is ~30 points short after P1/P3/P4.** With the scoped metric (CTE/derived excluded) the DWH baseline is ≈41 %; P3 (+6,045 edges) + P4 lift it to ≈55–65 %. Reaching ≥95 % needs catalogs for ~566 residual **real-table** blindspots — the P2 cohort (temp / cross-file / unseen-DDL tables) and the deferred P5 `USE SCHEMA` bare-name group (956 tables). **RESOLVED (GitHub #124, PR fix/coverage-metric-baselining)**: 95 % numeric gate dropped; coverage is now reported as an observed metric with no pass/fail target. BQ-2 is the follow-up sprint. | [`coverage.py`](src/sqlcg/cli/coverage.py), [`base.py`](src/sqlcg/parsers/base.py) | [coverage_p1_p3_p4](plan/sprints/coverage_p1_p3_p4.md) §95 % Feasibility Analysis |
229
+ | F8 | MED | **Index-summary metric undercount masks coverage gaps.** End-of-`sqlcg index` prints "1 failed" while 410 files carry `parse_failed=True` in the live DWH (1,335 files indexed, v1.25.0). The printed count reflects only the final-phase summary, not the full parse-failure population. Users and agents see a misleadingly-healthy finish line. Being addressed in the coverage sprint. | [`indexer.py`](src/sqlcg/indexer/indexer.py) summary path | `plan/sprints/coverage_parse_failures.md` (pending creation) |
230
+ | F9 | LOW | **`pr-impact` rename suppression renders no "verify consumers updated" label.** The help text promises a dedicated labelled section when a rename is detected with consumers updated; the actual output emits only "No genuine lost producers detected" with no rename callout. Suppression logic is correct; the label is missing. | [`server/tools.py`](src/sqlcg/server/tools.py) `get_pr_impact` | none yet |
231
+ | F10 | LOW | **`git install-hooks` embeds venv path, not user-installed binary.** Hooks installed via `sqlcg git install-hooks` point at `.venv/bin/sqlcg`, not `~/.local/bin/sqlcg`. If the project venv is rebuilt or deleted, the hooks become stale silently while the user-installed PyPI copy is current. Observed live on v1.25.0 (both pointed at 1.25.0 coincidentally — but this is a version-skew surface). | [`indexer/`](src/sqlcg/indexer/) install path | none yet |
232
+ | F11 | LOW | **`mcp restart` is stop-only by design but misnamed.** The command stops the server and instructs the user to reconnect via `/mcp`; it does NOT restart the server process. For a stdio MCP server this is architecturally correct (the client owns the lifecycle), but the name and the live-verify expectation are contradicted by the observed behaviour. Either rename to `mcp stop` or document prominently in `--help` that the client must reconnect. Honest reframe shipped in v1.20.0; the naming gap remains. | [`server/control.py`](src/sqlcg/server/control.py), [`cli/commands/`](src/sqlcg/cli/commands) | none yet |
233
+ | F12 | MED | **`pr-impact` requires graph to be indexed at base-ref; not self-healing.** Each `pr-impact --base X` run leaves the graph indexed at HEAD. A second run fails with a hint to manually reindex. Worse, the installed git post-checkout/post-merge hooks fire a background `sqlcg reindex` on every branch switch, racing `pr-impact` off the base. Reproduced on the live DWH (2026-06-13). Working protocol: chain `reindex --from <current_sha> --to <base>` immediately before `pr-impact`. A self-healing reindex-to-base step inside `pr-impact` itself is the right fix. | [`server/tools.py`](src/sqlcg/server/tools.py) `get_pr_impact`, [`indexer/git_delta.py`](src/sqlcg/indexer/git_delta.py) | backlog (deferred post data-loss-impact sprint) |
234
+
235
+ ---
236
+
237
+ ## 6. DWH graph topology insights (2026-06-13, v1.25.0)
238
+
239
+ Source: [`plan/reports/dwh_graph_analysis.md`](plan/reports/dwh_graph_analysis.md) —
240
+ full tables, method, and candidate lists live there; this section captures the
241
+ actionable architectural findings only.
242
+
243
+ Graph: **2,030 nodes · 2,930 directed edges** (table-level, noise-filtered), built from
244
+ 1,335 files, 52,514 column-lineage edges (schema v8, DWH corpus, 2026-06-13).
245
+
246
+ ### 6.1 Centrality — VALIDATED
247
+
248
+ Ground-truth check: `ba.wtdh_artikel` (degree rank #3, total=107) and
249
+ `ba.wtfe_verkoopinfo` (rank #6, total=57) independently reproduced as top hubs.
250
+ **Out-degree / total-degree is the right blast-radius metric** — it answers "what breaks
251
+ the most downstream if this table is wrong". PageRank is the wrong metric here: it ranks
252
+ hubs low because they are *sources*, not sinks.
253
+
254
+ The warehouse is anchored on five conformed dimensions (store, banner, article, date,
255
+ week) and one dominant fact hub (verkoopinfo) — exactly the expected retail star-schema
256
+ shape.
257
+
258
+ **Surprising high-centrality tables** (not obvious from name alone):
259
+ `da.ttint_verkooptransactie` (PageRank #4 — a quiet integration staging table is the
260
+ single biggest convergence point with in=25), `ba.wtfe_korting` (PageRank #1 — discount
261
+ logic far more central than its name suggests), `ba.wtfi_axi_ail` +
262
+ `ba.wtfe_artikel_inteken_lijst` (intake-list pipeline dense hub, not a leaf report).
263
+
264
+ ### 6.2 Named single-points-of-failure (high betweenness bridges)
265
+
266
+ These four permanent tables sit on the most shortest-paths; an outage in any of them
267
+ **fragments lineage across subject areas**. Directly actionable for outage planning.
268
+
269
+ | Table | Betweenness | Role |
270
+ |---|---|---|
271
+ | `ba.wtfe_verkoopinfo` | 0.00372 | #1 bridge AND top hub (sales fact) |
272
+ | `da.ttint_verkooptransactie` | 0.00340 | Transaction integration bridge (in=25 → upstream of sales + promotions) |
273
+ | `ba.wtfe_promotie_artikel_bouwmarkt` | 0.00175 | Bridges promotions ↔ sales ↔ store |
274
+ | `ba.wtfv_voorraad_dagstand` | 0.00120 | Inventory daily-snapshot bridge |
275
+
276
+ Betweenness floats are meaningful only as a ranking; computed on the 2,030-node
277
+ filtered DiGraph.
278
+
279
+ ### 6.3 Communities
280
+
281
+ 171 communities, modularity **0.763** (strong, well-separated). Communities map
282
+ cleanly onto retail subject areas. Two notable anomalies:
283
+
284
+ - `ba.wtfe_loyalty` sits in the **Webshop** community (#32), not a
285
+ customer/CRM community — candidate for a real coupling or mis-placement.
286
+ - **HR/workforce fused into the Store community (#4)** — staffing data has no independent
287
+ lineage island; it only exists hanging off the store dimension.
288
+
289
+ Cross-community bridge edges concentrate on the same four betweenness tables (§6.2) —
290
+ confirming that any refactor touching those tables has the widest blast radius.
291
+
292
+ ### 6.4 Orphan / satellite belt
293
+
294
+ ~4,417 SqlTable nodes have zero table-level lineage edges. The headline is **not
295
+ "4,000 dead tables"**: that population is dominated by parse-failure coverage gaps
296
+ (410 parse-failed files) + targetless write queries (1,090 of 2,349) + downstream
297
+ export mirrors (`ia_*` schemas) — not genuinely standalone business tables. Only ~57
298
+ clean-parse standalone DDL tables are confidently business isolates.
299
+
300
+ This orphan belt is the main driver of the coverage sprint (F8 +
301
+ `plan/sprints/coverage_parse_failures.md` — being produced separately).
302
+
303
+ ### 6.5 Tier-2 "refactor advisor" candidate (feature opportunity)
304
+
305
+ The `wtfv_`/`wtfs_` prefix-split pattern surfaces as a recurring topology signal: 7
306
+ ranked candidate groups where a fact-view and a fact-snapshot table share J=1.0 leaf
307
+ sets and 8–71 shared columns (see the full table in
308
+ [`plan/reports/dwh_graph_analysis.md`](plan/reports/dwh_graph_analysis.md) §Lens 4).
309
+ The strongest candidate is the `*voorraad_dagstand*` inventory family (3 tables, J=1.0,
310
+ 33 shared leaves, 33–71 shared columns).
311
+
312
+ **This is a topology + column-name hypothesis, NOT a confirmed refactor recommendation.**
313
+ The `manus_export` false positive (J=1.0, 50 shared leaves, only 5 shared columns of 84)
314
+ proves same inputs ≠ same logic. Confirming evidence a tier-2 pass needs before any
315
+ prescriptive recommendation:
316
+
317
+ - **(a) SQL-expression comparison** — prove the *logic* (not just the inputs) is duplicated.
318
+ Compare actual SELECT projections / WHERE / join logic per `SqlQuery.sql`.
319
+ - **(b) Shared grain / PK** — a conformed hub is only legal if the candidates share a
320
+ grain. PK/grain metadata is **not in the graph today**.
321
+
322
+ Record as a feature opportunity. Do not implement until (a) and (b) are available.
323
+
324
+ ---
325
+
326
+ ## 7. Deferred / roadmap
327
+
328
+ - **Coverage sprint — parse-failure diagnosis (active).** 410/1,335 files
329
+ parse-failed on the live DWH, dominated by error classes **E5 (217)** and **E8 (184)**;
330
+ only 1 timeout. This is the dominant driver of the satellite/orphan belt (§6.4) and the
331
+ F7/F8 findings. Diagnosis: [`plan/research/coverage_parse_failure_diagnosis.md`](plan/research/coverage_parse_failure_diagnosis.md);
332
+ sprint plan: `plan/sprints/coverage_parse_failures.md` (being produced separately).
333
+ - **v2 — Snowflake `ACCESS_HISTORY` as a second lineage source.** Fuse query-history lineage
334
+ to *enrich* (not replace) static parsing. This is the main reason the `GraphBackend` ABC
335
+ (F4) is kept rather than collapsed.
336
+ - **ETL session-context limits (fundamental).** Cross-session temp tables, `COPY INTO`
337
+ column mapping, and dynamic `IDENTIFIER()` references are static-analysis limits — they
338
+ need runtime information. Intra-file temp-table chains resolve via pass-1 DDL sniffing;
339
+ cross-file/cross-session chains do not. Full analysis in the
340
+ [archive §6](ARCHITECTURE_REVIEW_ARCHIVE.md).
341
+ - **Incremental reindex** (vs. full rebuild) — the real fix for F2/F3's lock-duration and
342
+ memory pressure; explicitly deferred during the DuckDB migration.
343
+ - **PyPI publish pipeline — batch-push root cause resolved; re-publish backlog pending.**
344
+ PyPI is stuck at v1.5.1 because tags v1.6.0–v1.14.2 were pushed as a batch (GitHub
345
+ Actions silently drops triggers for all but ~3 tags in a single push). The v1.14.2
346
+ `workflow_dispatch` run also failed its `test` gate. A `workflow_dispatch` re-publish
347
+ path exists (`docs/releasing-pypi.md`); actual tagging and per-tag republishing are
348
+ user-gated. v1.15.0–v1.25.x are not yet tagged or published.
349
+
350
+ ---
351
+
352
+ ## 8. History
353
+
354
+ Earlier content is preserved verbatim in
355
+ [`ARCHITECTURE_REVIEW_ARCHIVE.md`](ARCHITECTURE_REVIEW_ARCHIVE.md). Detailed per-release
356
+ plans live in [`plan/`](plan) (a frozen historical archive — see
357
+ [`plan/WORKFLOW.md`](plan/WORKFLOW.md) for the agent pipeline that produced them).
358
+
359
+ | Era | What it covered |
360
+ |---|---|
361
+ | Pre-1.4 blueprint review (archive §1–7) | Original design review, ETL-lineage gap analysis, open questions. |
362
+ | PR/issue reviews (archive §8, §10) | PR #1 inline comments; issues #5/#6 LLM-experience feedback. |
363
+ | v0.3–v1.3 sprint postmortems (archive §11–20) | Column-lineage diagnostics, the `E{n}` taxonomy, bulk-upsert/perf work, freshness + single-writer queue, recall guards. |
364
+ | Kuzu → DuckDB migration (archive, v1.4.0) | Backend swap, perf-invariant re-verification, the concurrency-model deviation that became F2. |
@@ -1,4 +1,13 @@
1
- # Architecture Review — sql-code-graph (sqlcg)
1
+ # Architecture Review — ARCHIVE (sql-code-graph)
2
+
3
+ > **Frozen historical record.** This is the pre-overhaul `ARCHITECTURE_REVIEW.md`,
4
+ > captured verbatim on 2026-06-08 (through the v1.4.0 Kuzu→DuckDB migration). It is **not
5
+ > maintained** — links and findings reflect the repo as it was when each section was
6
+ > written. For the current architecture see
7
+ > [`ARCHITECTURE_REVIEW.md`](ARCHITECTURE_REVIEW.md). Kept for the decision/postmortem
8
+ > trail; nothing below should be treated as current.
9
+
10
+ ---
2
11
 
3
12
  Blueprint version: v1.2 (May 2026)
4
13
  Review date: 2026-05-02 (updated 2026-05-06)
@@ -1,3 +1,36 @@
1
+ ## v1.25.0 (2026-06-13)
2
+
3
+ > **Re-index recommended (no schema change).** `SCHEMA_VERSION` unchanged.
4
+ > View classification (`kind='view'`) and the `gating_join_tables` supplement only
5
+ > take effect on a fresh `sqlcg index <path>`.
6
+
7
+ ### Feat
8
+
9
+ - **view classification**: `CREATE VIEW` targets now stamped `kind='view'` so they
10
+ persist as `SqlTable.kind='view'` instead of being indistinguishable from tables;
11
+ live-verified on a ~1,400-file DWH (582 views classified)
12
+ - **empty-impact** (`sqlcg analyze empty-impact` / `get_empty_propagation` MCP tool):
13
+ downstream blast radius when named table(s) are empty — two views: value-derivation
14
+ (primary, column-lineage refinement) and row-reachability (supplement, direct
15
+ gating-join reads)
16
+ - **pr-impact** (`sqlcg analyze pr-impact` / `get_pr_impact` MCP tool): detect
17
+ producers a PR dropped + their blast radius; code-regression detection (not runtime
18
+ monitoring); rename-handling via column-set AND consumer Jaccard ≥ 0.6
19
+ - **gating-join supplement** (`get_change_scope` / `diff_impact`): `gating_join_tables`
20
+ field added — tables that row-empty via direct gating-join reads supplementing the
21
+ column-lineage blast radius; caveat: depends on join type (not recorded on edges)
22
+ - **3-signal unused** (`analyze_unused` / `sqlcg analyze unused`): redefines "used"
23
+ as the union of (D1) direct `SELECTS_FROM`, (D2) `STAR_SOURCE`, and (D3)
24
+ column-lineage CTE-derived read; `find_table_usages` augmented with `via_lineage`
25
+ entries for the same D3 signal
26
+
27
+ ### Fix
28
+
29
+ - **pr-impact BUG-A**: CLI path was not initialising the backend before calling
30
+ `_compute_pr_impact`, causing `RuntimeError: Backend not initialized`
31
+ - **pr-impact BUG-B**: blast-radius engine was zeroing the result when the resync
32
+ produced no new edges; now computed on the pre-resync graph (Option i)
33
+
1
34
  ## v1.1.3 (2026-06-01)
2
35
 
3
36
  > **Re-index recommended (no schema change).** `SCHEMA_VERSION` stays `6`, so no
@@ -38,7 +71,7 @@
38
71
  > `SCHEMA_VERSION` 4 to 6 (added `start_line` on `SqlQuery`, repurposed
39
72
  > `SqlTable.kind`, added the `ExternalConsumer` node + `CONSUMED_BY` edge). There
40
73
  > is no in-place migration — re-run `sqlcg index <path>` to rebuild the graph. If
41
- > you run the MCP server, restart it (`sqlcg mcp restart`) after re-indexing.
74
+ > you run the MCP server, stop it (`sqlcg mcp stop`) and reconnect via your editor after re-indexing. (Note: as of v1.20.0 the server self-heals on the next tool call — no manual stop needed.)
42
75
 
43
76
  ### Feat
44
77