sql-code-graph 1.4.1__tar.gz → 1.4.3__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 (442) hide show
  1. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/PKG-INFO +1 -1
  2. sql_code_graph-1.4.3/plan/diff-impact-producer-file.md +321 -0
  3. sql_code_graph-1.4.3/plan/issue-38-backfill-cte-bridge.md +870 -0
  4. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/pyproject.toml +1 -1
  5. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/__init__.py +1 -1
  6. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/queries.py +4 -0
  7. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/queries.sql +60 -0
  8. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/ansi_parser.py +7 -2
  9. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/models.py +6 -0
  10. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/tools.py +169 -27
  11. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_anchor_tools.py +130 -6
  12. sql_code_graph-1.4.3/tests/integration/test_backfill_impact_consistency.py +427 -0
  13. sql_code_graph-1.4.3/tests/integration/test_case_split_seed_regression.py +152 -0
  14. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_hygiene_config_warning.py +4 -0
  15. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_include_working_tree.py +4 -0
  16. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_index_cmd.py +4 -0
  17. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_index_flags.py +11 -0
  18. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/uv.lock +1 -1
  19. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.claude/agents/api-documenter.md +0 -0
  20. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.claude/agents/architect-planner.md +0 -0
  21. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.claude/agents/architect-reviewer.md +0 -0
  22. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.claude/agents/code-reviewer.md +0 -0
  23. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.claude/agents/developer.md +0 -0
  24. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.claude/agents/plan-reviewer.md +0 -0
  25. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.claude/agents/sprint-planner.md +0 -0
  26. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  27. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  28. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  29. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.github/workflows/benchmark.yml +0 -0
  30. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.github/workflows/e2e-tests.yml +0 -0
  31. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.github/workflows/release.yml +0 -0
  32. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.github/workflows/test.yml +0 -0
  33. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.gitignore +0 -0
  34. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.pre-commit-config.yaml +0 -0
  35. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/.sqlcgignore +0 -0
  36. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/ARCHITECTURE_REVIEW.md +0 -0
  37. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/CHANGELOG.md +0 -0
  38. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/CLAUDE.md +0 -0
  39. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/README.md +0 -0
  40. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/docs/AIRBNB_PARSE_REPORT.md +0 -0
  41. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/docs/cli.md +0 -0
  42. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/e2e_firstuser_report.md +0 -0
  43. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/e2e_run_20260528_101413.output +0 -0
  44. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/main.py +0 -0
  45. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/WORKFLOW.md +0 -0
  46. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/blueprint.md +0 -0
  47. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/bundle_claude_skill.md +0 -0
  48. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/feature_34_unused_presentation_segregation.md +0 -0
  49. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/feature_35_external_downstream_injection.md +0 -0
  50. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/feature_F2_bundle_claude_skill.md +0 -0
  51. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/feature_kuzu_to_duckdb_migration.md +0 -0
  52. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/fix_downstream_sink_location.md +0 -0
  53. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/fix_dynamic_table_parsing.md +0 -0
  54. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/fix_expand_qualify_perf.md +0 -0
  55. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/fix_firstuser_findings.md +0 -0
  56. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/fix_issue29_live_test_followups.md +0 -0
  57. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/fix_schema_case_mismatch.md +0 -0
  58. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/hygiene_config_path_and_survivors.md +0 -0
  59. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/investigation_e5_e4.md +0 -0
  60. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/living_codebase_resync.md +0 -0
  61. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/measurements/schema_comparison_with_schema.json +0 -0
  62. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/measurements/schema_comparison_without_schema.json +0 -0
  63. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
  64. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
  65. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/measurements/sprint_pool_300s_plan.json +0 -0
  66. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/parse_diagnostics.md +0 -0
  67. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/parsing_errors_experiment.md +0 -0
  68. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/snowflake_en_test_suite.md +0 -0
  69. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_01.md +0 -0
  70. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_01_deployment_pypi.md +0 -0
  71. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_02.md +0 -0
  72. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_02_v0.3.0_core.md +0 -0
  73. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_03.md +0 -0
  74. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_03_v0.3.1_postmortem.md +0 -0
  75. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_04_column_lineage.md +0 -0
  76. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_04_column_lineage_fix.md +0 -0
  77. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_05_star_resolution.md +0 -0
  78. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_06_lineage_coverage.md +0 -0
  79. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_07_open_ecodes.md +0 -0
  80. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_07_perf_and_live_test.md +0 -0
  81. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_08_perf_upsert.md +0 -0
  82. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_09_lineage_coverage.md +0 -0
  83. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_10_anchor_tools.md +0 -0
  84. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_11_v1.0.2_bugfix.md +0 -0
  85. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_12_v1.1.0.md +0 -0
  86. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_13_v1.1.0_cluster_b.md +0 -0
  87. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sprint_3.1_postmortem.md +0 -0
  88. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/sqlcg.md +0 -0
  89. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/trust_layer.md +0 -0
  90. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/v1.1.0_cluster_b_provenance_trust.md +0 -0
  91. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/v1.1.0_live_graph_freshness.md +0 -0
  92. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/v1.1.1_batch_upsert_perf.md +0 -0
  93. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/v1_1_2_bugfix.md +0 -0
  94. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/v1_1_3_union_cte_star.md +0 -0
  95. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/v1_2_0_read_proxy.md +0 -0
  96. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/plan/v1_2_1_bugfix.md +0 -0
  97. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/profile.html +0 -0
  98. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/pyrightconfig.json +0 -0
  99. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/scripts/collect_parse_errors.py +0 -0
  100. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/scripts/generate_cli_docs.sh +0 -0
  101. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/__main__.py +0 -0
  102. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/__init__.py +0 -0
  103. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/__init__.py +0 -0
  104. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/analyze.py +0 -0
  105. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/db.py +0 -0
  106. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/find.py +0 -0
  107. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/gain.py +0 -0
  108. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/git.py +0 -0
  109. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/index.py +0 -0
  110. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/install.py +0 -0
  111. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/mcp.py +0 -0
  112. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/reindex.py +0 -0
  113. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/report.py +0 -0
  114. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/uninstall.py +0 -0
  115. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/commands/watch.py +0 -0
  116. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/cli/main.py +0 -0
  117. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/__init__.py +0 -0
  118. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/config.py +0 -0
  119. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/duckdb_backend.py +0 -0
  120. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/freshness.py +0 -0
  121. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/graph_db.py +0 -0
  122. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/jobs.py +0 -0
  123. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/queries.cypher +0 -0
  124. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/schema.cypher +0 -0
  125. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/core/schema.py +0 -0
  126. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/__init__.py +0 -0
  127. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/dbt_adapter.py +0 -0
  128. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/error_classify.py +0 -0
  129. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/git_delta.py +0 -0
  130. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/indexer.py +0 -0
  131. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/pool.py +0 -0
  132. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/walker.py +0 -0
  133. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/indexer/watcher.py +0 -0
  134. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/lineage/__init__.py +0 -0
  135. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/lineage/aggregator.py +0 -0
  136. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/lineage/schema_resolver.py +0 -0
  137. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/metrics/__init__.py +0 -0
  138. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/metrics/store.py +0 -0
  139. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/__init__.py +0 -0
  140. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/base.py +0 -0
  141. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/bigquery_parser.py +0 -0
  142. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/postgres_parser.py +0 -0
  143. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/registry.py +0 -0
  144. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/snowflake_parser.py +0 -0
  145. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/parsers/tsql_parser.py +0 -0
  146. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/__init__.py +0 -0
  147. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/control.py +0 -0
  148. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/exceptions.py +0 -0
  149. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/noise_filter.py +0 -0
  150. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/read_client.py +0 -0
  151. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/server.py +0 -0
  152. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/skill.py +0 -0
  153. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/server/writer.py +0 -0
  154. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/utils/__init__.py +0 -0
  155. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/utils/hashing.py +0 -0
  156. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/utils/ignore.py +0 -0
  157. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/src/sqlcg/utils/logging.py +0 -0
  158. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/__init__.py +0 -0
  159. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/__init__.py +0 -0
  160. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/adversarial/200_join.sql +0 -0
  161. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/adversarial/500_union.sql +0 -0
  162. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/bench_indexer.py +0 -0
  163. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/conftest.py +0 -0
  164. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
  165. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
  166. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
  167. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
  168. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
  169. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
  170. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
  171. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
  172. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
  173. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
  174. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/tpch/q01.sql +0 -0
  175. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/tpch/q02.sql +0 -0
  176. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/tpch/q03.sql +0 -0
  177. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/tpch/q04.sql +0 -0
  178. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/benchmarks/tpch/q05.sql +0 -0
  179. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/__init__.py +0 -0
  180. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/conftest.py +0 -0
  181. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
  182. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_airbnb_e2e.py +0 -0
  183. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_cli_index.py +0 -0
  184. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_git_hook_install.py +0 -0
  185. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_golden_lineage.py +0 -0
  186. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_mcp_lifecycle.py +0 -0
  187. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_mcp_tools.py +0 -0
  188. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
  189. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_star_resolution_e2e.py +0 -0
  190. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/e2e/test_watch.py +0 -0
  191. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
  192. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
  193. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
  194. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
  195. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
  196. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/raw_listings.sql +0 -0
  197. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
  198. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/src_hosts.sql +0 -0
  199. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/src_listings.sql +0 -0
  200. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/airbnb/src_reviews.sql +0 -0
  201. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/bigquery/.gitkeep +0 -0
  202. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/duckdb_parity/kuzu_reference.json +0 -0
  203. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/jaffle_shop/customers.sql +0 -0
  204. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/jaffle_shop/orders.sql +0 -0
  205. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
  206. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/snowflake/base_tables.sql +0 -0
  207. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/snowflake/reports.sql +0 -0
  208. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/snowflake/views.sql +0 -0
  209. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
  210. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
  211. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
  212. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/star_corpus/etl_star.sql +0 -0
  213. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/synthetic/base_tables.sql +0 -0
  214. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/synthetic/reports.sql +0 -0
  215. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/fixtures/synthetic/views.sql +0 -0
  216. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/__init__.py +0 -0
  217. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/snowflake/__init__.py +0 -0
  218. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/snowflake/test_insert_select.py +0 -0
  219. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_T34_presentation_segregation.py +0 -0
  220. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_T35_external_consumers.py +0 -0
  221. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_analyze_case_fold.py +0 -0
  222. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_bare_column_cte_lineage.py +0 -0
  223. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_bulk_upsert.py +0 -0
  224. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_column_lineage_e2e.py +0 -0
  225. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_cross_file_lineage.py +0 -0
  226. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_cte_recall_guard.py +0 -0
  227. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_cte_schema_alias_guard.py +0 -0
  228. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_cte_source_node_invariant.py +0 -0
  229. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_dialect_auto_resolution.py +0 -0
  230. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_dialect_matrix.py +0 -0
  231. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_duckdb_parity.py +0 -0
  232. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
  233. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_freshness_mcp.py +0 -0
  234. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
  235. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_indexer_batching.py +0 -0
  236. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_indexer_commits.py +0 -0
  237. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_indexer_to_graph.py +0 -0
  238. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_live_anchors.py +0 -0
  239. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_mvcc_rebuild.py +0 -0
  240. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_parse_diagnostics.py +0 -0
  241. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_pr1_confidence_reason.py +0 -0
  242. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_pr2_source_location.py +0 -0
  243. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_pr3_kind_tagging.py +0 -0
  244. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_read_via_server.py +0 -0
  245. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_readonly_under_lock.py +0 -0
  246. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_reindex_via_server.py +0 -0
  247. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_resync.py +0 -0
  248. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_single_writer_queue.py +0 -0
  249. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_star_resolution.py +0 -0
  250. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_temp_table_lineage.py +0 -0
  251. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
  252. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_user_surface_recall_guard.py +0 -0
  253. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/integration/test_v141_surface_guards.py +0 -0
  254. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/perf/__init__.py +0 -0
  255. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/perf/test_perf.py +0 -0
  256. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E10/__init__.py +0 -0
  257. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E11/__init__.py +0 -0
  258. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E12/__init__.py +0 -0
  259. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E12/e12_json_path.sql +0 -0
  260. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
  261. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E12/test_e12.py +0 -0
  262. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E13/__init__.py +0 -0
  263. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E14/__init__.py +0 -0
  264. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E15/__init__.py +0 -0
  265. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E16/__init__.py +0 -0
  266. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E16/e16_merge.sql +0 -0
  267. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
  268. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E16/test_e16.py +0 -0
  269. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E17/__init__.py +0 -0
  270. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E18/__init__.py +0 -0
  271. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E18/e18_decode.sql +0 -0
  272. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
  273. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E18/e18_nvl2.sql +0 -0
  274. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E18/test_e18.py +0 -0
  275. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E19/__init__.py +0 -0
  276. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E2/__init__.py +0 -0
  277. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
  278. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E2/e2_function_alias.sql +0 -0
  279. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
  280. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E2/test_e2.py +0 -0
  281. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E20/__init__.py +0 -0
  282. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E21/__init__.py +0 -0
  283. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
  284. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
  285. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E21/test_e21.py +0 -0
  286. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E22/__init__.py +0 -0
  287. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E23/__init__.py +0 -0
  288. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
  289. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
  290. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E23/test_e23.py +0 -0
  291. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E24/__init__.py +0 -0
  292. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E25/__init__.py +0 -0
  293. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E25/e25_cross_db.sql +0 -0
  294. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E25/e25_two_part.sql +0 -0
  295. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E25/test_e25.py +0 -0
  296. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E25/test_e25_full_id.py +0 -0
  297. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E26/__init__.py +0 -0
  298. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E27/__init__.py +0 -0
  299. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
  300. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E27/e27_udf.sql +0 -0
  301. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E27/test_e27.py +0 -0
  302. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E28/__init__.py +0 -0
  303. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E29/__init__.py +0 -0
  304. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E3/__init__.py +0 -0
  305. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E3/e3_alter_table.sql +0 -0
  306. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
  307. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
  308. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E3/test_e3.py +0 -0
  309. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E30/__init__.py +0 -0
  310. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E31/__init__.py +0 -0
  311. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E32/__init__.py +0 -0
  312. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E33/__init__.py +0 -0
  313. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E34/__init__.py +0 -0
  314. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E35/__init__.py +0 -0
  315. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E36/__init__.py +0 -0
  316. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
  317. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E36/e36_temp_table.sql +0 -0
  318. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E36/test_e36.py +0 -0
  319. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E36/test_e36_xfile.py +0 -0
  320. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E37/__init__.py +0 -0
  321. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E38/__init__.py +0 -0
  322. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E4/__init__.py +0 -0
  323. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
  324. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
  325. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
  326. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E4/e4_unpivot.sql +0 -0
  327. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E4/test_e4.py +0 -0
  328. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E5/__init__.py +0 -0
  329. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
  330. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
  331. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
  332. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E5/test_e5.py +0 -0
  333. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
  334. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E8/__init__.py +0 -0
  335. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
  336. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
  337. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E8/e8_uuid.sql +0 -0
  338. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E8/test_e8.py +0 -0
  339. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E9/__init__.py +0 -0
  340. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_aggregates/__init__.py +0 -0
  341. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
  342. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
  343. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
  344. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
  345. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_date_functions/__init__.py +0 -0
  346. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
  347. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
  348. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
  349. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
  350. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
  351. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/README.md +0 -0
  352. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/__init__.py +0 -0
  353. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/anchors/__init__.py +0 -0
  354. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/anchors/fixture_etl.sql +0 -0
  355. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
  356. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
  357. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/anchors/fixture_source.sql +0 -0
  358. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
  359. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
  360. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/conftest.py +0 -0
  361. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/snowflake/test_plan_review_gates.py +0 -0
  362. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/__init__.py +0 -0
  363. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/snowflake/__init__.py +0 -0
  364. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/snowflake/test_scripting_noise.py +0 -0
  365. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
  366. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_BugC_hook_upgrade.py +0 -0
  367. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_F2_install_skill.py +0 -0
  368. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_F2_skill_render.py +0 -0
  369. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_F2_uninstall_skill.py +0 -0
  370. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_T09_01_qualify_once.py +0 -0
  371. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_T09_02_ddl_skip.py +0 -0
  372. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
  373. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_T09_06_log_verbosity.py +0 -0
  374. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_T35_config_external_consumers.py +0 -0
  375. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_aggregator.py +0 -0
  376. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_aggregator_skip.py +0 -0
  377. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_analyze_case_fold.py +0 -0
  378. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_base_parser.py +0 -0
  379. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_branch_monitor.py +0 -0
  380. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_bulk_upsert_invariant.py +0 -0
  381. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_canonical_target_resolution.py +0 -0
  382. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_cli.py +0 -0
  383. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_cli_help.py +0 -0
  384. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_closure_depth.py +0 -0
  385. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_column_lineage_wiring.py +0 -0
  386. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_config.py +0 -0
  387. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_data_models.py +0 -0
  388. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_db_info.py +0 -0
  389. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_dominant_cause.py +0 -0
  390. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_duckdb_backend.py +0 -0
  391. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_duckdb_backend_shared.py +0 -0
  392. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_find_cmd.py +0 -0
  393. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_firstuser_findings.py +0 -0
  394. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_freshness_helper.py +0 -0
  395. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_gain_ratio.py +0 -0
  396. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_git_delta.py +0 -0
  397. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_git_hooks.py +0 -0
  398. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_git_hooks_notify.py +0 -0
  399. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_graph_backend.py +0 -0
  400. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_graph_completeness_invariant.py +0 -0
  401. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_hard_kill_pool.py +0 -0
  402. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_index_progress.py +0 -0
  403. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_indexer_progress.py +0 -0
  404. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_indexer_quality.py +0 -0
  405. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_install.py +0 -0
  406. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_install_message.py +0 -0
  407. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_jobs.py +0 -0
  408. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_judgement.py +0 -0
  409. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_lineage_conversion.py +0 -0
  410. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_literal_column_skip.py +0 -0
  411. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_mcp_best_practices.py +0 -0
  412. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_mcp_control.py +0 -0
  413. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_mcp_stdio_smoke.py +0 -0
  414. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_metrics.py +0 -0
  415. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_noise_filter.py +0 -0
  416. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_parse_file_dependency_filter.py +0 -0
  417. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_parse_quality.py +0 -0
  418. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_parser.py +0 -0
  419. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_perf_scaling_guard.py +0 -0
  420. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_pr07_observability.py +0 -0
  421. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_queries_loader.py +0 -0
  422. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_read_client.py +0 -0
  423. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
  424. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_schema_resolver.py +0 -0
  425. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_server.py +0 -0
  426. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
  427. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_sprint_06_t04_t05.py +0 -0
  428. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_star_resolution_unit.py +0 -0
  429. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_star_schema_unit.py +0 -0
  430. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_submit_feedback.py +0 -0
  431. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_subprocess_isolate.py +0 -0
  432. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_t02_expression_name_extraction.py +0 -0
  433. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_t03_ddl_skip.py +0 -0
  434. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_timeout_cancel.py +0 -0
  435. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_tools_hints.py +0 -0
  436. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_tools_warnings.py +0 -0
  437. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_uninstall.py +0 -0
  438. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_unqualified_fallback.py +0 -0
  439. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_upsert_batch_invariant.py +0 -0
  440. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_walker.py +0 -0
  441. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_watcher.py +0 -0
  442. {sql_code_graph-1.4.1 → sql_code_graph-1.4.3}/tests/unit/test_writer_queue.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql-code-graph
3
- Version: 1.4.1
3
+ Version: 1.4.3
4
4
  Summary: SQL code graph analyzer and lineage tracer
5
5
  Project-URL: Homepage, https://github.com/Warhorze/sql-code-graph
6
6
  Project-URL: Repository, https://github.com/Warhorze/sql-code-graph
@@ -0,0 +1,321 @@
1
+ # Feature Plan: `diff_impact` under-reports blast radius for ETL producer files
2
+
3
+ ## Summary
4
+
5
+ [`diff_impact`](../src/sqlcg/server/tools.py) resolves each changed file to its
6
+ produced tables via `DEFINED_IN` only, which the indexer populates **solely from
7
+ DDL `CREATE TABLE`/`CREATE VIEW` provenance**. On repos where DDL lives in
8
+ separate files from the ETL `INSERT…SELECT` producers (the DWH layout: DDL
9
+ changelog files vs `etl/sql/...` producers), passing a producer file returns
10
+ **no produced table → an empty, silently under-counted blast radius**. This is a
11
+ correctness bug for the tool's primary use case ("here are my PR's changed files,
12
+ what breaks?"). The fix makes `diff_impact`'s file→table resolution additionally
13
+ consult `QUERY_DEFINED_IN` → `SqlQuery.target_table`, unioned with the existing
14
+ `DEFINED_IN`-derived set.
15
+
16
+ This is a **separate issue from #38** (fixed in PR #57): own branch, own PR, own
17
+ patch bump.
18
+
19
+ ## Scope
20
+
21
+ ### In Scope
22
+ - A new read query (proposed `GET_TARGET_TABLES_FOR_FILE`) joining
23
+ `QUERY_DEFINED_IN` (query→file) → `SqlQuery`, filtered to non-empty
24
+ `target_table`, returning the produced/populated tables for a file.
25
+ - Additive change to [`diff_impact`](../src/sqlcg/server/tools.py#L1014) so the
26
+ per-file resolution loop unions `DEFINED_IN`-derived tables with
27
+ `QUERY_DEFINED_IN`-derived target tables, de-duplicated against `seen_changed`.
28
+ - An integration test reproducing the gap (separate DDL file + separate
29
+ `INSERT…SELECT` producer file + downstream consumer), mirroring the
30
+ [`test_anchor_tools.py`](../tests/integration/test_anchor_tools.py) style and
31
+ `_index_fixture` helper.
32
+ - Patch version bump (re-check current version at implementation time; expected
33
+ `1.4.3` once #38's `1.4.2` ships).
34
+
35
+ ### Non-Goals
36
+ - **No** change to `DEFINED_IN` semantics, the indexer's "prefer DDL provenance"
37
+ merge ([`indexer.py` ~L126](../src/sqlcg/indexer/indexer.py#L126)), or any
38
+ perf-invariant surface ([`base.py`](../src/sqlcg/parsers/base.py),
39
+ [`indexer.py`](../src/sqlcg/indexer/indexer.py)).
40
+ - **No** re-index requirement: the fix reads edges that already exist in any
41
+ current graph.
42
+ - **No** change to `get_change_scope` / `get_backfill_order` / `scope_change`'s
43
+ downstream computation — those key off `HAS_COLUMN` + `COLUMN_LINEAGE` and were
44
+ verified correct on the live DWH. Out of scope.
45
+ - The secondary advisory finding (`defining_files` / `get_definition` show only
46
+ the DDL file) — **deferred**, see "Secondary finding" below.
47
+ - No tag, no issue close (user verifies and tags).
48
+
49
+ ## Background / evidence
50
+
51
+ ### How an `INSERT…SELECT` producer is recorded
52
+ An ETL `INSERT INTO t SELECT …` statement is parsed into a `SqlQuery` node with
53
+ `target` set (`QueryKind.INSERT`, see
54
+ [`base.py` ~L317/L645](../src/sqlcg/parsers/base.py#L317)), producing:
55
+ - a `SqlQuery` row with **`target_table` = the populated table** (schema:
56
+ [`schema.cypher` L44](../src/sqlcg/core/schema.cypher#L44), `target_table STRING`),
57
+ - a `QUERY_DEFINED_IN` edge **query→file** (`qdi.src_key = query.id`,
58
+ `qdi.dst_key = file.path`),
59
+ - **but no `DEFINED_IN` edge** — that edge is emitted only by DDL
60
+ `CREATE TABLE`/`CREATE VIEW` provenance.
61
+
62
+ ### Why `diff_impact` misses it today
63
+ The resolution loop calls `GET_TABLES_DEFINED_IN_FILE`
64
+ ([`tools.py` L1047](../src/sqlcg/server/tools.py#L1047)), whose query is purely
65
+ `SqlTable` ⋈ `DEFINED_IN` ⋈ filter `di.dst_key = ?`
66
+ ([`queries.sql` L194](../src/sqlcg/core/queries.sql#L194)). A producer file has no
67
+ `DEFINED_IN` edge, so `changed_tables` stays empty → empty blast radius. The
68
+ existing "No tables are defined in the given files" hint
69
+ ([`tools.py` L1090](../src/sqlcg/server/tools.py#L1090)) fires, but a caller passing
70
+ a real changed producer file reasonably reads an empty result as "safe". Silent
71
+ under-count is the worst failure mode for an impact tool.
72
+
73
+ ### The edges/columns the fix relies on already exist and are already used
74
+ - `QUERY_DEFINED_IN` query→file is joined identically in `SEARCH_SQL_PATTERN`
75
+ ([`queries.sql` L79](../src/sqlcg/core/queries.sql#L79)),
76
+ `DEPENDENT_FILES_OF_TABLES` ([L227](../src/sqlcg/core/queries.sql#L227)), and
77
+ `FIND_TABLE_USAGES` ([L57](../src/sqlcg/core/queries.sql#L57)).
78
+ - `SqlQuery.target_table` filtered to non-empty (`<> ''`) is exactly the pattern
79
+ in `HUB_RANKING` ([L215](../src/sqlcg/core/queries.sql#L215)) and the
80
+ `EXPAND_STAR_SOURCES` family ([L111](../src/sqlcg/core/queries.sql#L111)).
81
+
82
+ So no schema change, no new edge type, no indexer change, no re-index.
83
+
84
+ ## Chosen fix approach: query-layer union (vs. index-time `DEFINED_IN` edge)
85
+
86
+ **Chosen: query-layer.** Add `GET_TARGET_TABLES_FOR_FILE` and union its result
87
+ into `diff_impact`'s per-file resolution. Rationale:
88
+
89
+ | Criterion | Query-layer (chosen) | Index-time DEFINED_IN edge (rejected) |
90
+ |---|---|---|
91
+ | Re-index required | No — reads existing edges | **Yes** — every user must re-index before the fix takes effect |
92
+ | Perf-invariant surface | Untouched | Touches `indexer.py` edge emission; must re-justify every CLAUDE.md invariant |
93
+ | `DEFINED_IN` semantics | Unchanged (DDL-only) — incremental-reindex closure stays correct | **Changes** the meaning of `DEFINED_IN`; would pollute `find_definition`, `GET_TABLE_DEFINING_FILES`, and the resync closure-frontier seeding ([`indexer.py` L670/L748](../src/sqlcg/indexer/indexer.py#L670)) with producer files, conflating "where defined" with "where populated" |
94
+ | Blast radius of change | One query + one loop union in `diff_impact` | Indexer dedup/merge rules, reindex delete-capture, multiple downstream queries |
95
+ | Cost | One extra read per changed file (cheap; same JOIN shape already used elsewhere) | N/A |
96
+
97
+ The index-time alternative has a **fatal coherence flaw**: `DEFINED_IN` is the
98
+ backbone of `find_definition` and the incremental-reindex closure. Overloading it
99
+ to also mean "populated here" would silently change `find_definition`'s
100
+ authoritative-file detection and the resync delete-capture set — exactly the
101
+ sensitive paths this plan must NOT disturb. The query-layer fix keeps "defined"
102
+ (DDL) and "produced/populated" (DML target) as distinct concepts and unions them
103
+ only at the one call site that needs both.
104
+
105
+ ## Design
106
+
107
+ ### New query — `GET_TARGET_TABLES_FOR_FILE`
108
+ Add to [`queries.sql`](../src/sqlcg/core/queries.sql) and register in
109
+ [`queries.py`](../src/sqlcg/core/queries.py) as
110
+ `GET_TARGET_TABLES_FOR_FILE_QUERY` (mirroring the existing
111
+ `GET_TABLES_DEFINED_IN_FILE_QUERY` registration at
112
+ [L59](../src/sqlcg/core/queries.py#L59)). Return the same column name
113
+ `table_qualified` so the `diff_impact` loop can treat both result sets uniformly:
114
+
115
+ ```sql
116
+ -- GET_TARGET_TABLES_FOR_FILE
117
+ -- params: [file_path]
118
+ SELECT DISTINCT q.target_table AS table_qualified
119
+ FROM "SqlQuery" q
120
+ JOIN "QUERY_DEFINED_IN" qdi ON qdi.src_key = q.id
121
+ WHERE qdi.dst_key = ?
122
+ AND q.target_table <> ''
123
+ ```
124
+
125
+ Notes:
126
+ - `q.target_table <> ''` excludes SELECT-only queries (no produced table). Confirm
127
+ at implementation that the parser writes `''` (not NULL) for SELECT-only
128
+ queries; the `EXPAND_STAR_SOURCES`/`HUB_RANKING` queries already rely on `<> ''`
129
+ on this same column, so `''` is the established empty sentinel. If NULL is
130
+ possible, add `AND q.target_table IS NOT NULL`.
131
+ - `target_table` is stored as written by the parser. The `diff_impact` produced
132
+ tables flow straight into `GET_COLUMNS_FOR_TABLE` /
133
+ `_affected_columns_closure`, which already key off `SqlTable.qualified` /
134
+ `HAS_COLUMN`; an unresolved `target_table` simply yields an empty column set
135
+ (no downstream), which is correct degradation, not a crash.
136
+
137
+ ### `diff_impact` change (additive)
138
+ In the per-file loop ([`tools.py` L1041-L1052](../src/sqlcg/server/tools.py#L1041)),
139
+ after the existing `GET_TABLES_DEFINED_IN_FILE_QUERY` read, run
140
+ `GET_TARGET_TABLES_FOR_FILE_QUERY` against the same resolved `str(fp)` and feed its
141
+ rows through the **same** `seen_changed` de-dup append. Shape:
142
+
143
+ ```python
144
+ for query in (GET_TABLES_DEFINED_IN_FILE_QUERY, GET_TARGET_TABLES_FOR_FILE_QUERY):
145
+ rows = db.run_read(query, {"file_path": str(fp)})
146
+ for row in rows:
147
+ tq = row["table_qualified"]
148
+ if tq and tq not in seen_changed:
149
+ seen_changed.add(tq)
150
+ changed_tables.append(tq)
151
+ ```
152
+
153
+ The `seen_changed` set already de-dups a table that is both DDL-defined and
154
+ DML-populated in the changed set, so the union is order-preserving and
155
+ idempotent. No change to the downstream closure, noise filter, presentation, topo
156
+ sort, or external-consumer batch — they all consume `changed_tables` unchanged.
157
+
158
+ ### Data models
159
+ No model changes. `DiffImpactResult` is returned unchanged; only `changed_tables`
160
+ (and therefore `affected_tables`/`backfill_order`/`external_consumers`) become
161
+ correctly populated for producer files.
162
+
163
+ ### Dependencies
164
+ None new.
165
+
166
+ ## Implementation Steps
167
+
168
+ ### Phase 1: Query
169
+ **Step 1.1**: Add `GET_TARGET_TABLES_FOR_FILE` block to
170
+ [`queries.sql`](../src/sqlcg/core/queries.sql) (after `GET_TABLES_DEFINED_IN_FILE`,
171
+ ~L199) and register `GET_TARGET_TABLES_FOR_FILE_QUERY` in
172
+ [`queries.py`](../src/sqlcg/core/queries.py).
173
+ - Files affected: `queries.sql`, `queries.py`.
174
+ - Acceptance: a unit/integration assertion confirms the query, run against a graph
175
+ containing one `INSERT…SELECT` producer, returns the produced table by qualified
176
+ name and excludes SELECT-only queries.
177
+
178
+ ### Phase 2: Tool
179
+ **Step 2.1**: Import `GET_TARGET_TABLES_FOR_FILE_QUERY` in
180
+ [`tools.py`](../src/sqlcg/server/tools.py) (alongside the existing import at
181
+ [L26](../src/sqlcg/server/tools.py#L26)) and union it into the `diff_impact`
182
+ per-file loop as designed above. Add `if tq` guard against empty/NULL.
183
+ - Files affected: `tools.py`.
184
+ - Acceptance: grep-confirmed call site — `GET_TARGET_TABLES_FOR_FILE_QUERY` is
185
+ imported AND invoked inside `diff_impact` (not merely defined). The new query is
186
+ called, not just registered.
187
+
188
+ ### Phase 3: Repro test
189
+ **Step 3.1**: Add `test_diff_impact_producer_file_blast_radius` to
190
+ [`test_anchor_tools.py`](../tests/integration/test_anchor_tools.py) using
191
+ `_index_fixture`, with three SEPARATE files:
192
+ - `ddl.sql`: `CREATE TABLE ba.dim (id INT);` (DDL only — DEFINED_IN edge, no producer query)
193
+ - `producer.sql`: `INSERT INTO ba.dim SELECT id FROM ba.source;` plus a
194
+ `CREATE TABLE ba.source (id INT);` (so `ba.source` resolves) — OR put
195
+ `ba.source` DDL in its own file; the key is `ba.dim` is **populated** by
196
+ `producer.sql`, not DDL-defined there.
197
+ - `consumer.sql`: `CREATE TABLE ba.mart AS SELECT id FROM ba.dim;` (downstream).
198
+
199
+ Assertions (observable output, not "no exception"):
200
+ - `result = tools.diff_impact([str(tmp_path / "producer.sql")])`
201
+ - `"ba.dim" in result.changed_tables` — the produced table IS resolved from the
202
+ producer file (the core fix; fails pre-fix with an empty `changed_tables`).
203
+ - `"ba.mart" in result.affected_tables` — its downstream consumer appears in the
204
+ blast radius.
205
+ - Optionally assert `result.hint is None` (no "no tables defined" hint) to pin
206
+ that the silent-empty path is gone.
207
+ - Files affected: `tests/integration/test_anchor_tools.py`.
208
+ - Acceptance: test is RED on `master`+#38 baseline (confirm by running before the
209
+ `tools.py` edit) and GREEN after the fix.
210
+
211
+ **Step 3.2** (regression guard): keep the existing CTAS-based
212
+ `test_diff_impact_file_to_blast_radius` ([L265](../tests/integration/test_anchor_tools.py#L265))
213
+ green — it pins the `DEFINED_IN` path still works (the union must be additive, not
214
+ a replacement).
215
+
216
+ ### Phase 4: Version + housekeeping
217
+ **Step 4.1**: Re-check current version at implementation time. If `1.4.2` (#38)
218
+ has shipped to `master`, bump to `1.4.3` (patch — pure bug fix, additive query, no
219
+ surface change) in [`pyproject.toml`](../pyproject.toml) and
220
+ [`src/sqlcg/__init__.py`](../src/sqlcg/__init__.py); run `uv lock`. If `1.4.2` has
221
+ NOT yet merged, coordinate so this branch bumps to the next patch after it. No tag
222
+ (user tags after merge), no issue close.
223
+
224
+ ## Test Strategy
225
+ - **Integration** (primary): the producer-file repro in Phase 3 — the only test
226
+ that exercises the real DEFINED_IN-vs-QUERY_DEFINED_IN gap end to end through a
227
+ real DuckDB graph and the actual `diff_impact` tool.
228
+ - **Regression**: existing CTAS `test_diff_impact_file_to_blast_radius`,
229
+ presentation tests, and the full `test_anchor_tools.py` suite stay green.
230
+ - **Reindex non-interference**: assert (or reason in PR) that
231
+ `GET_TABLES_DEFINED_IN_FILE_QUERY` is unchanged and the new query is referenced
232
+ ONLY from `diff_impact`. The incremental-reindex paths at
233
+ [`indexer.py` L670](../src/sqlcg/indexer/indexer.py#L670) and
234
+ [L748](../src/sqlcg/indexer/indexer.py#L748) (delete-capture and closure-frontier
235
+ seeding) intentionally use DDL provenance and must keep using
236
+ `GET_TABLES_DEFINED_IN_FILE_QUERY` only — verify via grep that
237
+ `GET_TARGET_TABLES_FOR_FILE_QUERY` has zero references in
238
+ [`indexer.py`](../src/sqlcg/indexer/indexer.py).
239
+ - No new unit test of the query in isolation is required beyond what the
240
+ integration repro covers, but a thin query-level assertion (Step 1.1) is welcome.
241
+
242
+ ## Acceptance Criteria
243
+ - [ ] `GET_TARGET_TABLES_FOR_FILE` exists in `queries.sql` and is registered as
244
+ `GET_TARGET_TABLES_FOR_FILE_QUERY` in `queries.py`.
245
+ - [ ] `diff_impact` imports AND invokes `GET_TARGET_TABLES_FOR_FILE_QUERY` inside
246
+ its per-file loop (grep-confirmed call site, not just a definition).
247
+ - [ ] New integration test: `diff_impact([producer_file])` returns the produced
248
+ table in `changed_tables` and its downstream consumer in `affected_tables`;
249
+ the test is demonstrably RED before the `tools.py` edit and GREEN after.
250
+ - [ ] Existing CTAS `test_diff_impact_file_to_blast_radius` and all
251
+ `test_anchor_tools.py` tests remain green (additive, non-regressive).
252
+ - [ ] `GET_TARGET_TABLES_FOR_FILE_QUERY` has zero references in
253
+ [`indexer.py`](../src/sqlcg/indexer/indexer.py); `GET_TABLES_DEFINED_IN_FILE`
254
+ query text is byte-for-byte unchanged.
255
+ - [ ] No edit to [`base.py`](../src/sqlcg/parsers/base.py) or
256
+ [`indexer.py`](../src/sqlcg/indexer/indexer.py) (perf-invariant surface
257
+ untouched); no re-index required for the fix to take effect.
258
+ - [ ] SELECT-only queries (`target_table = ''`/NULL) do not pollute
259
+ `changed_tables`.
260
+ - [ ] Version bumped to the correct next patch (expected `1.4.3`) with `uv lock`
261
+ refreshed; no tag, no issue close.
262
+ - [ ] Full gate green: `uv run pytest`, `uv run pyright`, `uv run ruff check`.
263
+
264
+ ## Secondary finding — DEFER (recommended)
265
+ `get_change_scope.defining_files` and `find_definition` report only the DDL file,
266
+ not the ETL producer, because both run `GET_TABLE_DEFINING_FILES_QUERY` (DDL
267
+ `DEFINED_IN` only — [`tools.py` L907](../src/sqlcg/server/tools.py#L907),
268
+ [`queries.sql` L167](../src/sqlcg/core/queries.sql#L167)).
269
+
270
+ **Recommendation: defer to a separate follow-up, do NOT bundle here.** Reasons:
271
+ 1. **Different semantics, different decision.** `defining_files` answers "where is
272
+ this table *defined*" (an authoritativeness/governance question that
273
+ `find_definition` builds is_authoritative/is_backup/duplicate_ddl on top of).
274
+ Folding producer files in changes the meaning of that field and would ripple
275
+ into `find_definition`'s authoritative-file logic and its model — a design
276
+ choice that deserves its own plan, not a rider on an impact-tool patch.
277
+ 2. **`diff_impact` is the bug with the silent-under-count failure mode**; the
278
+ secondary one is advisory (a user inspecting a *table* still gets correct
279
+ downstream via `get_change_scope`). Coupling them widens the PR's blast radius
280
+ and review surface for no urgency.
281
+ 3. **Memory rule** "never fold new work into an already-reviewed PR / ship a
282
+ separate patch" applies in spirit: keep this PR tightly scoped to the
283
+ file→produced-table resolution fix.
284
+
285
+ If pursued later, the shape would be a new `producing_files` field (NOT overloading
286
+ `defining_files`) sourced from `QUERY_DEFINED_IN` + non-empty `target_table` for
287
+ the given table — a clean additive surface. Note it in `ARCHITECTURE_REVIEW.md` as
288
+ a deferred follow-up.
289
+
290
+ ## Risks and Mitigations
291
+ - **Risk: unresolved `target_table` (no matching `SqlTable`).** A produced table
292
+ whose `qualified` does not match any `SqlTable` row yields an empty
293
+ `GET_COLUMNS_FOR_TABLE` result → no downstream contribution, but it still
294
+ correctly appears in `changed_tables`. Degrades gracefully; no crash.
295
+ *Mitigation*: covered by the repro (the produced `ba.dim` has DDL elsewhere so it
296
+ resolves; assert it appears in `changed_tables` regardless).
297
+ - **Risk: NULL vs empty-string `target_table`.** *Mitigation*: confirm parser
298
+ writes `''`; the `<> ''` filter matches existing `HUB_RANKING`/`EXPAND_STAR`
299
+ convention. Add `IS NOT NULL` if NULL is observed.
300
+ - **Risk: double-count when a table is both DDL-defined and DML-populated in the
301
+ same changed set.** *Mitigation*: `seen_changed` de-dup already handles this;
302
+ union is idempotent.
303
+ - **Risk: perf — one extra read per changed file.** *Mitigation*: `diff_impact`
304
+ operates on a PR-sized file list (tens, not thousands); the new query reuses an
305
+ index-friendly JOIN already present in three other queries. Not on the
306
+ index/parse hot path; CLAUDE.md perf invariants are untouched.
307
+ - **Risk: breaking incremental reindex.** *Mitigation*: the fix never touches
308
+ `GET_TABLES_DEFINED_IN_FILE` or `DEFINED_IN`; acceptance criterion pins zero
309
+ `indexer.py` references to the new query.
310
+
311
+ ## Rollout / rollback
312
+ - Rollout: ships in the patch release; takes effect immediately on existing graphs
313
+ (no re-index).
314
+ - Rollback: revert the `tools.py` union and the two query additions — fully
315
+ isolated, no migration, no data shape change.
316
+
317
+ ### Blocking Questions
318
+ None. `QUERY_DEFINED_IN` (query→file via `dst_key`) and `SqlQuery.target_table`
319
+ are confirmed present in [`schema.cypher`](../src/sqlcg/core/schema.cypher) and
320
+ already used by `SEARCH_SQL_PATTERN` / `DEPENDENT_FILES_OF_TABLES` /
321
+ `GET_TABLE_DIRECT_UPSTREAMS`; the empty sentinel `''` convention is established.