sql-code-graph 1.36.1__tar.gz → 1.36.2__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 (623) hide show
  1. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/PKG-INFO +1 -1
  2. sql_code_graph-1.36.2/plan/metrics/gain_1.36.2_f6a335a.json +33 -0
  3. sql_code_graph-1.36.2/plan/metrics/gain_drop_alter_phantom_baseline_v1361.json +30 -0
  4. sql_code_graph-1.36.2/plan/sprints/fix_drop_alter_phantom_source_node.md +551 -0
  5. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/pyproject.toml +1 -1
  6. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/__init__.py +1 -1
  7. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/ansi_parser.py +16 -2
  8. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_incremental_reindex_parity.py +102 -0
  9. sql_code_graph-1.36.2/tests/integration/test_phantom_drop_alter_node.py +123 -0
  10. sql_code_graph-1.36.2/tests/unit/test_phantom_drop_alter_source.py +166 -0
  11. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/uv.lock +1 -1
  12. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.claude/agents/api-documenter.md +0 -0
  13. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.claude/agents/architect-planner.md +0 -0
  14. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.claude/agents/architect-reviewer.md +0 -0
  15. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.claude/agents/code-reviewer.md +0 -0
  16. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.claude/agents/developer.md +0 -0
  17. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.claude/agents/plan-reviewer.md +0 -0
  18. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.claude/agents/sprint-planner.md +0 -0
  19. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  20. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  21. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  22. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.github/workflows/benchmark.yml +0 -0
  23. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.github/workflows/e2e-tests.yml +0 -0
  24. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.github/workflows/release.yml +0 -0
  25. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.github/workflows/test.yml +0 -0
  26. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.gitignore +0 -0
  27. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.pre-commit-config.yaml +0 -0
  28. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/.sqlcgignore +0 -0
  29. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/ARCHITECTURE_REVIEW.md +0 -0
  30. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/ARCHITECTURE_REVIEW_ARCHIVE.md +0 -0
  31. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/CHANGELOG.md +0 -0
  32. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/CLAUDE.md +0 -0
  33. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/README.md +0 -0
  34. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/docs/AIRBNB_PARSE_REPORT.md +0 -0
  35. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/docs/cli.md +0 -0
  36. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/docs/getting-started.md +0 -0
  37. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/docs/releasing-pypi.md +0 -0
  38. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/e2e_firstuser_report.md +0 -0
  39. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/e2e_run_20260528_101413.output +0 -0
  40. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/main.py +0 -0
  41. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/WORKFLOW.md +0 -0
  42. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/measurements/pr2_catalog_load_eval.json +0 -0
  43. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/measurements/pr3_repo_native_plateau.json +0 -0
  44. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/measurements/pr4_transform_kinds.json +0 -0
  45. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/measurements/pr5_extraction_recall_taxonomy.json +0 -0
  46. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
  47. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
  48. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/createkind_dwh_after.json +0 -0
  49. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/createkind_dwh_before.json +0 -0
  50. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/gain_1.29.0_05c6943.json +0 -0
  51. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/gain_1.30.0_2c8ac25.json +0 -0
  52. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/gain_1.30.1_26271fc.json +0 -0
  53. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/gain_1.31.0_a40c837.json +0 -0
  54. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/gain_1.32.0_c1bec3c.json +0 -0
  55. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/identifier_live_acceptance.md +0 -0
  56. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/identifier_live_after_v1.36.0.json +0 -0
  57. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/identifier_live_before_v1.35.3.json +0 -0
  58. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/lineage5_dwh_after_pr5.json +0 -0
  59. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/lineage5_dwh_before_master.json +0 -0
  60. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/pr4_star_promote_after.json +0 -0
  61. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/pr4_star_promote_before.json +0 -0
  62. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/pr_b_phantom_after.json +0 -0
  63. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/pr_b_phantom_before.json +0 -0
  64. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/pr_c_merge_after.json +0 -0
  65. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/pr_c_merge_before.json +0 -0
  66. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/schema_comparison_with_schema.json +0 -0
  67. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/schema_comparison_without_schema.json +0 -0
  68. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/sprint_08_changelogs_fullindex.json +0 -0
  69. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/sprint_08_fullcorpus_index.json +0 -0
  70. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/metrics/sprint_pool_300s_plan.json +0 -0
  71. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/column_coverage_diagnostic.md +0 -0
  72. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/column_coverage_findings.md +0 -0
  73. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/dwh_graph_analysis.md +0 -0
  74. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/dwh_positional_insert_column_blindspot.md +0 -0
  75. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/feature_acceptance_dwh.md +0 -0
  76. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/graph_health_sprint_postmortem.md +0 -0
  77. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/island_lever_live_verification.md +0 -0
  78. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/issue38_pr2_live_acceptance.md +0 -0
  79. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/issue38_pr3_live_acceptance.md +0 -0
  80. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/lineage_identity_sprint_postmortem.md +0 -0
  81. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/pr_impact_followups_2026-06-14.md +0 -0
  82. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/sprint_03_v0.3.1_postmortem.md +0 -0
  83. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/sprint_3.1_postmortem.md +0 -0
  84. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/reports/v1_14_dialect_query_config_postmortem.md +0 -0
  85. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/blueprint.md +0 -0
  86. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/coverage_parse_failure_diagnosis.md +0 -0
  87. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/investigation_e5_e4.md +0 -0
  88. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/observed_usage_overlay_query_history_tableau.md +0 -0
  89. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/parse_diagnostics.md +0 -0
  90. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/parsing_errors_experiment.md +0 -0
  91. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/snowflake_en_test_suite.md +0 -0
  92. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/sql_only_coverage_lever_post_pr2.md +0 -0
  93. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/research/sqlcg.md +0 -0
  94. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/bundle_claude_skill.md +0 -0
  95. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/ci_tests_pool_flake_fix.md +0 -0
  96. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/column_lineage_recall_metric.md +0 -0
  97. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/coverage_p1_p3_p4.md +0 -0
  98. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/coverage_p1_p5_metric.md +0 -0
  99. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/coverage_parse_failures.md +0 -0
  100. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/diff-impact-producer-file.md +0 -0
  101. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/e8_dual_emission.md +0 -0
  102. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/feature_34_unused_presentation_segregation.md +0 -0
  103. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/feature_35_external_downstream_injection.md +0 -0
  104. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/feature_F2_bundle_claude_skill.md +0 -0
  105. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/feature_generic_var_name_resolution.md +0 -0
  106. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/feature_kuzu_to_duckdb_migration.md +0 -0
  107. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/fix_backward_self_heal_index_at_sha.md +0 -0
  108. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/fix_downstream_sink_location.md +0 -0
  109. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/fix_dynamic_table_parsing.md +0 -0
  110. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/fix_expand_qualify_perf.md +0 -0
  111. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/fix_firstuser_findings.md +0 -0
  112. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/fix_issue29_live_test_followups.md +0 -0
  113. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/fix_schema_case_mismatch.md +0 -0
  114. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/gain_coverage_metrics.md +0 -0
  115. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/graph_health_catalog_and_metrics.md +0 -0
  116. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/hygiene_config_path_and_survivors.md +0 -0
  117. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/issue-38-backfill-cte-bridge.md +0 -0
  118. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/issue-38-residual-source-extraction.md +0 -0
  119. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/issue-38-selects-from-island-lever.md +0 -0
  120. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/living_codebase_resync.md +0 -0
  121. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/mcp_server_self_healing.md +0 -0
  122. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/positional_insert_clone_blindspot.md +0 -0
  123. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_01.md +0 -0
  124. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_01_deployment_pypi.md +0 -0
  125. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_02.md +0 -0
  126. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_02_v0.3.0_core.md +0 -0
  127. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_03.md +0 -0
  128. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_04_column_lineage.md +0 -0
  129. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_04_column_lineage_fix.md +0 -0
  130. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_05_star_resolution.md +0 -0
  131. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_06_lineage_coverage.md +0 -0
  132. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_07_open_ecodes.md +0 -0
  133. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_07_perf_and_live_test.md +0 -0
  134. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_08_perf_upsert.md +0 -0
  135. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_09_lineage_coverage.md +0 -0
  136. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_10_anchor_tools.md +0 -0
  137. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_11_v1.0.2_bugfix.md +0 -0
  138. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_12_v1.1.0.md +0 -0
  139. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_13_v1.1.0_cluster_b.md +0 -0
  140. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_lineage_identity_and_session_context.md +0 -0
  141. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/sprint_postmortem_fixes.md +0 -0
  142. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/temp_table_namespacing.md +0 -0
  143. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/trust_layer.md +0 -0
  144. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/unfilled_table_impact.md +0 -0
  145. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1.1.0_cluster_b_provenance_trust.md +0 -0
  146. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1.1.0_live_graph_freshness.md +0 -0
  147. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1.1.1_batch_upsert_perf.md +0 -0
  148. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1.14.0_dialect_and_query_config_fixes.md +0 -0
  149. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1_1_2_bugfix.md +0 -0
  150. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1_1_3_union_cte_star.md +0 -0
  151. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1_2_0_read_proxy.md +0 -0
  152. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/v1_2_1_bugfix.md +0 -0
  153. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/plan/sprints/version-parity-and-restart.md +0 -0
  154. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/profile.html +0 -0
  155. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/pyrightconfig.json +0 -0
  156. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/scripts/collect_parse_errors.py +0 -0
  157. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/scripts/column_coverage_check.py +0 -0
  158. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/scripts/generate_cli_docs.sh +0 -0
  159. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/__main__.py +0 -0
  160. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/__init__.py +0 -0
  161. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/__init__.py +0 -0
  162. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/analyze.py +0 -0
  163. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/catalog.py +0 -0
  164. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/db.py +0 -0
  165. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/find.py +0 -0
  166. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/gain.py +0 -0
  167. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/git.py +0 -0
  168. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/index.py +0 -0
  169. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/install.py +0 -0
  170. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/mcp.py +0 -0
  171. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/reindex.py +0 -0
  172. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/report.py +0 -0
  173. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/uninstall.py +0 -0
  174. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/viz.py +0 -0
  175. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/commands/watch.py +0 -0
  176. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/coverage.py +0 -0
  177. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/cli/main.py +0 -0
  178. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/__init__.py +0 -0
  179. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/config.py +0 -0
  180. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/duckdb_backend.py +0 -0
  181. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/freshness.py +0 -0
  182. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/graph_db.py +0 -0
  183. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/jobs.py +0 -0
  184. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/noise_match.py +0 -0
  185. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/queries.cypher +0 -0
  186. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/queries.py +0 -0
  187. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/queries.sql +0 -0
  188. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/schema.cypher +0 -0
  189. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/core/schema.py +0 -0
  190. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/__init__.py +0 -0
  191. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/dbt_adapter.py +0 -0
  192. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/error_classify.py +0 -0
  193. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/git_delta.py +0 -0
  194. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/indexer.py +0 -0
  195. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/pool.py +0 -0
  196. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/walker.py +0 -0
  197. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/indexer/watcher.py +0 -0
  198. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/lineage/__init__.py +0 -0
  199. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/lineage/aggregator.py +0 -0
  200. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/lineage/schema_resolver.py +0 -0
  201. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/metrics/__init__.py +0 -0
  202. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/metrics/store.py +0 -0
  203. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/__init__.py +0 -0
  204. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/base.py +0 -0
  205. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/bigquery_parser.py +0 -0
  206. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/dynamic_name.py +0 -0
  207. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/postgres_parser.py +0 -0
  208. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/registry.py +0 -0
  209. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/snowflake_parser.py +0 -0
  210. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/parsers/tsql_parser.py +0 -0
  211. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/__init__.py +0 -0
  212. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/control.py +0 -0
  213. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/exceptions.py +0 -0
  214. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/models.py +0 -0
  215. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/noise_filter.py +0 -0
  216. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/read_client.py +0 -0
  217. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/selfheal.py +0 -0
  218. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/server.py +0 -0
  219. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/skill.py +0 -0
  220. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/tools.py +0 -0
  221. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/server/writer.py +0 -0
  222. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/utils/__init__.py +0 -0
  223. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/utils/hashing.py +0 -0
  224. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/utils/ignore.py +0 -0
  225. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/utils/logging.py +0 -0
  226. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/viz/__init__.py +0 -0
  227. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/viz/assets/force-graph.min.js +0 -0
  228. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/viz/assets/template.html +0 -0
  229. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/viz/data.py +0 -0
  230. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/viz/render.py +0 -0
  231. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/src/sqlcg/viz/tags.py +0 -0
  232. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/__init__.py +0 -0
  233. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/__init__.py +0 -0
  234. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/adversarial/200_join.sql +0 -0
  235. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/adversarial/500_union.sql +0 -0
  236. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/bench_indexer.py +0 -0
  237. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/conftest.py +0 -0
  238. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
  239. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
  240. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
  241. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
  242. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
  243. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
  244. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
  245. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
  246. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
  247. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
  248. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/tpch/q01.sql +0 -0
  249. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/tpch/q02.sql +0 -0
  250. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/tpch/q03.sql +0 -0
  251. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/tpch/q04.sql +0 -0
  252. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/benchmarks/tpch/q05.sql +0 -0
  253. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/conftest.py +0 -0
  254. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/__init__.py +0 -0
  255. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/conftest.py +0 -0
  256. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
  257. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_airbnb_e2e.py +0 -0
  258. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_cli_index.py +0 -0
  259. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_empty_impact_cli_e2e.py +0 -0
  260. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_git_hook_install.py +0 -0
  261. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_golden_lineage.py +0 -0
  262. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_mcp_lifecycle.py +0 -0
  263. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_mcp_tools.py +0 -0
  264. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
  265. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_pr_impact_cli_e2e.py +0 -0
  266. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_selfheal_e2e.py +0 -0
  267. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_star_resolution_e2e.py +0 -0
  268. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_viz_cli_e2e.py +0 -0
  269. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/e2e/test_watch.py +0 -0
  270. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
  271. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
  272. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
  273. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
  274. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
  275. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/raw_listings.sql +0 -0
  276. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
  277. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/src_hosts.sql +0 -0
  278. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/src_listings.sql +0 -0
  279. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/airbnb/src_reviews.sql +0 -0
  280. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/bigquery/.gitkeep +0 -0
  281. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/duckdb_parity/kuzu_reference.json +0 -0
  282. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/jaffle_shop/customers.sql +0 -0
  283. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/jaffle_shop/orders.sql +0 -0
  284. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
  285. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/snowflake/base_tables.sql +0 -0
  286. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/snowflake/reports.sql +0 -0
  287. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/snowflake/views.sql +0 -0
  288. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
  289. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
  290. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
  291. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/star_corpus/etl_star.sql +0 -0
  292. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/synthetic/base_tables.sql +0 -0
  293. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/synthetic/reports.sql +0 -0
  294. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/fixtures/synthetic/views.sql +0 -0
  295. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/__init__.py +0 -0
  296. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/snowflake/__init__.py +0 -0
  297. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/snowflake/test_identifier_var_sink_resolution_integration.py +0 -0
  298. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/snowflake/test_insert_select.py +0 -0
  299. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/snowflake/test_qualify_bare_tables_command_guard_integration.py +0 -0
  300. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_T34_presentation_segregation.py +0 -0
  301. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_T35_external_consumers.py +0 -0
  302. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_analyze_case_fold.py +0 -0
  303. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_anchor_tools.py +0 -0
  304. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_backfill_impact_consistency.py +0 -0
  305. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_bare_column_cte_lineage.py +0 -0
  306. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_bulk_upsert.py +0 -0
  307. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_case_split_seed_regression.py +0 -0
  308. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_catalog_kind_upgrade.py +0 -0
  309. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_catalog_load_integration.py +0 -0
  310. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_cli_index_clear_before_rebuild.py +0 -0
  311. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_column_coverage_patterns.py +0 -0
  312. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_column_lineage_e2e.py +0 -0
  313. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_coverage_metrics_integration.py +0 -0
  314. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_cross_file_lineage.py +0 -0
  315. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_cte_key_namespacing_integration.py +0 -0
  316. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_cte_recall_guard.py +0 -0
  317. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_cte_schema_alias_guard.py +0 -0
  318. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_cte_source_node_invariant.py +0 -0
  319. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_dialect_auto_resolution.py +0 -0
  320. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_dialect_matrix.py +0 -0
  321. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_duckdb_parity.py +0 -0
  322. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
  323. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_empty_impact_blast_radius.py +0 -0
  324. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_empty_index_rollback_guard.py +0 -0
  325. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_freshness_mcp.py +0 -0
  326. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_gating_join_retrofit.py +0 -0
  327. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
  328. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_identity_counters_integration.py +0 -0
  329. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_impact_consumer_parity.py +0 -0
  330. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_index_degraded_files_metric.py +0 -0
  331. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_index_filter_node_exclusion.py +0 -0
  332. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_indexer_batching.py +0 -0
  333. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_indexer_commits.py +0 -0
  334. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_indexer_to_graph.py +0 -0
  335. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_issue38_cte_insert_regression.py +0 -0
  336. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_join_col_resolution.py +0 -0
  337. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_key_normalization_chokepoint.py +0 -0
  338. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_live_anchors.py +0 -0
  339. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_mvcc_rebuild.py +0 -0
  340. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_non_table_create_coverage_no_regression.py +0 -0
  341. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_non_table_create_kind_in_graph.py +0 -0
  342. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_parse_diagnostics.py +0 -0
  343. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_phantom_non_table_create_node.py +0 -0
  344. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_pr1_confidence_reason.py +0 -0
  345. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_pr2_source_location.py +0 -0
  346. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_pr3_kind_tagging.py +0 -0
  347. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_pr_impact_integration.py +0 -0
  348. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_qualify_failed_persist.py +0 -0
  349. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_read_via_server.py +0 -0
  350. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_readonly_under_lock.py +0 -0
  351. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_reindex_via_server.py +0 -0
  352. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_repo_relative_cte_namespaces.py +0 -0
  353. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_resolvable_write_col_edges_integration.py +0 -0
  354. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_resync.py +0 -0
  355. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_selects_from_completeness.py +0 -0
  356. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_selects_from_cte_body_source.py +0 -0
  357. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_selects_from_subscope_source.py +0 -0
  358. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_single_writer_queue.py +0 -0
  359. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_skip_counts_integration.py +0 -0
  360. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_star_promote_temp_columns.py +0 -0
  361. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_star_resolution.py +0 -0
  362. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_temp_table_lineage.py +0 -0
  363. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_temp_table_namespacing.py +0 -0
  364. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_tool_version_stamp_integration.py +0 -0
  365. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
  366. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_usage_derived_catalog.py +0 -0
  367. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_use_schema_session_context_integration.py +0 -0
  368. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_user_surface_recall_guard.py +0 -0
  369. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_v141_surface_guards.py +0 -0
  370. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_v1_14_0_dialect_and_query_config_fixes.py +0 -0
  371. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_view_kind_in_graph.py +0 -0
  372. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_viz_data_build.py +0 -0
  373. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/integration/test_write_memory_ceiling.py +0 -0
  374. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/perf/__init__.py +0 -0
  375. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/perf/test_perf.py +0 -0
  376. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E10/__init__.py +0 -0
  377. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E11/__init__.py +0 -0
  378. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E12/__init__.py +0 -0
  379. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E12/e12_json_path.sql +0 -0
  380. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
  381. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E12/test_e12.py +0 -0
  382. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E13/__init__.py +0 -0
  383. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E14/__init__.py +0 -0
  384. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E15/__init__.py +0 -0
  385. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E16/__init__.py +0 -0
  386. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E16/e16_merge.sql +0 -0
  387. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
  388. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E16/test_e16.py +0 -0
  389. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E17/__init__.py +0 -0
  390. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E18/__init__.py +0 -0
  391. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E18/e18_decode.sql +0 -0
  392. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
  393. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E18/e18_nvl2.sql +0 -0
  394. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E18/test_e18.py +0 -0
  395. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E19/__init__.py +0 -0
  396. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E2/__init__.py +0 -0
  397. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
  398. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E2/e2_function_alias.sql +0 -0
  399. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
  400. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E2/test_e2.py +0 -0
  401. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E20/__init__.py +0 -0
  402. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E21/__init__.py +0 -0
  403. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
  404. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
  405. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E21/test_e21.py +0 -0
  406. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E22/__init__.py +0 -0
  407. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E23/__init__.py +0 -0
  408. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
  409. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
  410. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E23/test_e23.py +0 -0
  411. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E24/__init__.py +0 -0
  412. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E25/__init__.py +0 -0
  413. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E25/e25_cross_db.sql +0 -0
  414. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E25/e25_two_part.sql +0 -0
  415. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E25/test_e25.py +0 -0
  416. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E25/test_e25_full_id.py +0 -0
  417. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E26/__init__.py +0 -0
  418. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E27/__init__.py +0 -0
  419. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
  420. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E27/e27_udf.sql +0 -0
  421. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E27/test_e27.py +0 -0
  422. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E28/__init__.py +0 -0
  423. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E29/__init__.py +0 -0
  424. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E3/__init__.py +0 -0
  425. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E3/e3_alter_table.sql +0 -0
  426. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
  427. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
  428. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E3/test_e3.py +0 -0
  429. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E30/__init__.py +0 -0
  430. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E31/__init__.py +0 -0
  431. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E32/__init__.py +0 -0
  432. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E33/__init__.py +0 -0
  433. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E34/__init__.py +0 -0
  434. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E35/__init__.py +0 -0
  435. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E36/__init__.py +0 -0
  436. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
  437. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E36/e36_temp_table.sql +0 -0
  438. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E36/test_e36.py +0 -0
  439. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E36/test_e36_xfile.py +0 -0
  440. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E37/__init__.py +0 -0
  441. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E38/__init__.py +0 -0
  442. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E4/__init__.py +0 -0
  443. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
  444. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
  445. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
  446. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E4/e4_unpivot.sql +0 -0
  447. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E4/test_e4.py +0 -0
  448. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E5/__init__.py +0 -0
  449. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
  450. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
  451. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
  452. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E5/test_e5.py +0 -0
  453. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
  454. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E8/__init__.py +0 -0
  455. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
  456. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
  457. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E8/e8_uuid.sql +0 -0
  458. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E8/test_e8.py +0 -0
  459. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E9/__init__.py +0 -0
  460. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_aggregates/__init__.py +0 -0
  461. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
  462. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
  463. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
  464. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
  465. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_date_functions/__init__.py +0 -0
  466. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
  467. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
  468. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
  469. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
  470. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
  471. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/README.md +0 -0
  472. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/__init__.py +0 -0
  473. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/anchors/__init__.py +0 -0
  474. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/anchors/fixture_etl.sql +0 -0
  475. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
  476. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
  477. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/anchors/fixture_source.sql +0 -0
  478. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
  479. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
  480. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/conftest.py +0 -0
  481. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/snowflake/test_plan_review_gates.py +0 -0
  482. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/__init__.py +0 -0
  483. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/snowflake/__init__.py +0 -0
  484. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/snowflake/test_qualify_bare_tables_command_guard.py +0 -0
  485. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/snowflake/test_scripting_noise.py +0 -0
  486. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
  487. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_BugC_hook_upgrade.py +0 -0
  488. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_F2_install_skill.py +0 -0
  489. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_F2_skill_render.py +0 -0
  490. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_F2_uninstall_skill.py +0 -0
  491. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_T09_01_qualify_once.py +0 -0
  492. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_T09_02_ddl_skip.py +0 -0
  493. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
  494. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_T09_06_log_verbosity.py +0 -0
  495. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_T35_config_external_consumers.py +0 -0
  496. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_aggregator.py +0 -0
  497. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_aggregator_skip.py +0 -0
  498. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_analyze_case_fold.py +0 -0
  499. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_base_parser.py +0 -0
  500. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_branch_monitor.py +0 -0
  501. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_bulk_upsert_invariant.py +0 -0
  502. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_canonical_target_resolution.py +0 -0
  503. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_catalog_csv_parsing.py +0 -0
  504. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_catalog_missing_warning.py +0 -0
  505. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_classify_non_table_create_kind.py +0 -0
  506. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_cli.py +0 -0
  507. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_cli_doc_flag_staleness.py +0 -0
  508. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_cli_help.py +0 -0
  509. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_clone_positional_insert_blindspot.py +0 -0
  510. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_closure_depth.py +0 -0
  511. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_column_lineage_wiring.py +0 -0
  512. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_config.py +0 -0
  513. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_coverage_metrics.py +0 -0
  514. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_cte_key_namespacing.py +0 -0
  515. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_cte_source_gap_metric.py +0 -0
  516. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_data_models.py +0 -0
  517. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_db_info.py +0 -0
  518. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_db_info_coverage.py +0 -0
  519. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_db_path_isolation_fixture.py +0 -0
  520. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_doc_links.py +0 -0
  521. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_doc_markdown_link_existence.py +0 -0
  522. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_dominant_cause.py +0 -0
  523. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_duckdb_backend.py +0 -0
  524. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_duckdb_backend_shared.py +0 -0
  525. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_dynamic_name_resolution.py +0 -0
  526. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_e5_view_alias_resolution.py +0 -0
  527. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_e8_dual_emission.py +0 -0
  528. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_e8_temp_chain_key_mismatch.py +0 -0
  529. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_empty_propagation_unit.py +0 -0
  530. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_extract_select_output_columns.py +0 -0
  531. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_file_ignore_defaults.py +0 -0
  532. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_find_cmd.py +0 -0
  533. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_firstuser_findings.py +0 -0
  534. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_freshness_helper.py +0 -0
  535. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_gain_coverage.py +0 -0
  536. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_gain_ratio.py +0 -0
  537. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_gating_join_field_docstrings.py +0 -0
  538. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_git_delta.py +0 -0
  539. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_git_hooks.py +0 -0
  540. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_git_hooks_notify.py +0 -0
  541. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_graph_backend.py +0 -0
  542. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_graph_completeness_invariant.py +0 -0
  543. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_hard_kill_pool.py +0 -0
  544. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_has_column_precedence_upsert.py +0 -0
  545. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_hook_reindex_detach.py +0 -0
  546. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_hygiene_config_warning.py +0 -0
  547. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_identifier_var_sink_resolution.py +0 -0
  548. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_identity_counters.py +0 -0
  549. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_include_working_tree.py +0 -0
  550. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_index_cmd.py +0 -0
  551. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_index_filter_config.py +0 -0
  552. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_index_flags.py +0 -0
  553. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_index_progress.py +0 -0
  554. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_index_summary_degraded_metric.py +0 -0
  555. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_indexer_progress.py +0 -0
  556. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_indexer_quality.py +0 -0
  557. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_install.py +0 -0
  558. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_install_message.py +0 -0
  559. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_issue_63_readonly_lock.py +0 -0
  560. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_jobs.py +0 -0
  561. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_join_col_resolve_marker.py +0 -0
  562. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_judgement.py +0 -0
  563. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_lineage_conversion.py +0 -0
  564. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_literal_column_skip.py +0 -0
  565. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_mcp_best_practices.py +0 -0
  566. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_mcp_control.py +0 -0
  567. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_mcp_stdio_smoke.py +0 -0
  568. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_merge_column_lineage.py +0 -0
  569. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_metrics.py +0 -0
  570. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_noise_filter.py +0 -0
  571. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_normalize_keys.py +0 -0
  572. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_parse_failed_classification.py +0 -0
  573. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_parse_file_dependency_filter.py +0 -0
  574. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_parse_quality.py +0 -0
  575. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_parser.py +0 -0
  576. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_perf_scaling_guard.py +0 -0
  577. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_phantom_non_table_create_source.py +0 -0
  578. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_pr07_observability.py +0 -0
  579. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_pr6_execute_immediate_unwrap.py +0 -0
  580. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_pr_impact_unit.py +0 -0
  581. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_qualify_failed_unit.py +0 -0
  582. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_queries_loader.py +0 -0
  583. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_read_client.py +0 -0
  584. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_repo_relative_cte_namespaces.py +0 -0
  585. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_resolvable_write_col_edges_unit.py +0 -0
  586. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_resolve_join_columns_sql.py +0 -0
  587. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
  588. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_schema_resolver.py +0 -0
  589. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_selects_from_completeness_unit.py +0 -0
  590. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_selfheal_detector.py +0 -0
  591. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_selfheal_pr1_messages.py +0 -0
  592. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_selfheal_reexec.py +0 -0
  593. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_selfheal_watcher.py +0 -0
  594. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_server.py +0 -0
  595. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_skip_counts_persistence.py +0 -0
  596. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
  597. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_sprint_06_t04_t05.py +0 -0
  598. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_star_resolution_unit.py +0 -0
  599. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_star_schema_unit.py +0 -0
  600. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_submit_feedback.py +0 -0
  601. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_subprocess_isolate.py +0 -0
  602. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_t02_expression_name_extraction.py +0 -0
  603. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_t03_ddl_skip.py +0 -0
  604. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_temp_table_namespacing.py +0 -0
  605. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_timeout_cancel.py +0 -0
  606. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_tool_version_stamp.py +0 -0
  607. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_tools_hints.py +0 -0
  608. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_tools_warnings.py +0 -0
  609. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_transform_kind_classification.py +0 -0
  610. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_uninstall.py +0 -0
  611. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_unknown_sentinel_skip.py +0 -0
  612. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_unqualified_fallback.py +0 -0
  613. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_upsert_batch_invariant.py +0 -0
  614. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_use_schema_session_context.py +0 -0
  615. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_version_parity.py +0 -0
  616. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_view_classification.py +0 -0
  617. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_viz_config_schemas.py +0 -0
  618. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_viz_facets.py +0 -0
  619. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_viz_render_self_contained.py +0 -0
  620. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_walker.py +0 -0
  621. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_watcher.py +0 -0
  622. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/tests/unit/test_worker_error_classification.py +0 -0
  623. {sql_code_graph-1.36.1 → sql_code_graph-1.36.2}/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.36.1
3
+ Version: 1.36.2
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,33 @@
1
+ {"total_calls": 1791, "last_7d_calls": 1791, "index_runs": 5, "feedback_tp": 0,
2
+ "feedback_total": 0, "top_tools": [{"name": "execute_sql", "count": 604},
3
+ {"name": "trace_column_lineage", "count": 470}, {"name":
4
+ "list_dialects_and_repos", "count": 154}], "execute_sql_ratio": 0.34,
5
+ "parse_quality": {"sqlglot": 5162, "scripting": 20, "dynamic_sql": 3},
6
+ "coverage": {"catalogued_tables": 5892, "total_tables": 6553, "good_edges":
7
+ 54998, "total_edges": 63088, "phantom_edges": 12346, "blindspot_tables": 633,
8
+ "good_edges_strict": 49453, "edge_health_strict_pct": 78.39,
9
+ "good_edges_scoped": 37305, "total_edges_scoped": 37628,
10
+ "edge_health_scoped_pct": 99.14, "phantom_confirmed": 11686,
11
+ "phantom_contradicted": 239, "phantom_unverified": 421, "top_blindspot_tables":
12
+ [{"table": "ba.wtfa_kpi_datum_klant", "bad_edges": 70}, {"table":
13
+ "ba.wtfs_voorraad_dagstand", "bad_edges": 55}, {"table":
14
+ "ba.wtfs_voorraad_zondagstand", "bad_edges": 55}, {"table":
15
+ "wtfe_kpi_voorraad_artikel_voorraadlocatie", "bad_edges": 32}, {"table":
16
+ "ba.wtda_toeleverancier", "bad_edges": 13}, {"table":
17
+ "ba.wtfs_voorraad_dagstand_webshop_periode", "bad_edges": 13}, {"table":
18
+ "da.etl_rtwbs_cadeaukaarten", "bad_edges": 12}, {"table":
19
+ "wtfe_kpi_schapbeschikbaarheid_voorraadlocatie", "bad_edges": 12}, {"table":
20
+ "da.ttint_inventdim_formule", "bad_edges": 10}, {"table":
21
+ "ba.wtdm_klant_herkomst", "bad_edges": 8}], "blindspot_tables_for_80pct": 11,
22
+ "files_indexed": 1335, "indexed_sha":
23
+ "fdf1b551a34601a6cf3ce1c8b9f76e27ce2753e6", "db_path":
24
+ "/tmp/sqlcg_dropfix_f6a335a.db", "index_timestamp": 1781505432.175605,
25
+ "degraded_parse_total": 5185, "degraded_parse_queries": 27,
26
+ "degraded_parse_by_dir": {"etl": {"degraded": 8, "total": 2772}, "ddl":
27
+ {"degraded": 19, "total": 2413}}, "zero_edge_write_queries": 956,
28
+ "total_write_queries": 2322, "cte_key_collisions": 71,
29
+ "rescuable_unqualified_edges": 125, "info_schema_has_column_rows": 100193,
30
+ "cte_source_gap_writes": 0, "resolvable_write_col_edges": 38068,
31
+ "transitive_col_edges": 5312, "qualify_failed_statements": 9,
32
+ "tool_version_stale": false, "indexed_tool_version": "1.36.2",
33
+ "running_tool_version": "1.36.2"}}
@@ -0,0 +1,30 @@
1
+ {"total_calls": 1721, "last_7d_calls": 1721, "index_runs": 5, "feedback_tp": 0,
2
+ "feedback_total": 0, "top_tools": [{"name": "execute_sql", "count": 580},
3
+ {"name": "trace_column_lineage", "count": 452}, {"name":
4
+ "list_dialects_and_repos", "count": 148}], "execute_sql_ratio": 0.34,
5
+ "parse_quality": {"sqlglot": 5166, "scripting": 20, "dynamic_sql": 3},
6
+ "coverage": {"catalogued_tables": 5864, "total_tables": 6673, "good_edges":
7
+ 53811, "total_edges": 61983, "phantom_edges": 12241, "blindspot_tables": 631,
8
+ "good_edges_strict": 48907, "edge_health_strict_pct": 78.9, "good_edges_scoped":
9
+ 37502, "total_edges_scoped": 38063, "edge_health_scoped_pct": 98.53,
10
+ "phantom_confirmed": 11701, "phantom_contradicted": 352, "phantom_unverified":
11
+ 188, "top_blindspot_tables": [{"table": "ba.wtfa_kpi_datum_klant", "bad_edges":
12
+ 70}, {"table": "ba.wtfs_voorraad_dagstand", "bad_edges": 55}, {"table":
13
+ "ba.wtfs_voorraad_zondagstand", "bad_edges": 55}, {"table":
14
+ "da.rtgmd_postnl_customer_usage", "bad_edges": 43}, {"table":
15
+ "da.rtgmd_postnl_athome_3s", "bad_edges": 33}, {"table":
16
+ "wtfe_kpi_voorraad_artikel_voorraadlocatie", "bad_edges": 32}, {"table":
17
+ "da.rtgmd_postnl_facturen", "bad_edges": 30}, {"table": "da.hthyb_pages",
18
+ "bad_edges": 23}, {"table": "da.rtgmd_dhb_extra_kosten", "bad_edges": 19},
19
+ {"table": "da.hthyb_page_brandplacement", "bad_edges": 17}],
20
+ "blindspot_tables_for_80pct": 18, "files_indexed": 1335, "indexed_sha":
21
+ "fdf1b551a34601a6cf3ce1c8b9f76e27ce2753e6", "db_path": "/tmp/ab_v1361.db",
22
+ "index_timestamp": 1781502931.191137, "degraded_parse_total": 5189,
23
+ "degraded_parse_queries": 27, "degraded_parse_by_dir": {"etl": {"degraded": 8,
24
+ "total": 2776}, "ddl": {"degraded": 19, "total": 2413}},
25
+ "zero_edge_write_queries": 969, "total_write_queries": 2323,
26
+ "cte_key_collisions": 0, "rescuable_unqualified_edges": 125,
27
+ "info_schema_has_column_rows": 100193, "cte_source_gap_writes": 0,
28
+ "resolvable_write_col_edges": 37713, "transitive_col_edges": 4558,
29
+ "qualify_failed_statements": 9, "tool_version_stale": false,
30
+ "indexed_tool_version": "1.36.1", "running_tool_version": "1.36.1"}}
@@ -0,0 +1,551 @@
1
+ # Feature Plan: DROP/ALTER phantom source-node + edge suppression (#161 part 2)
2
+
3
+ **Status:** REVIEWED
4
+ **Owner:** architect-planner
5
+ **Version target:** PATCH. Master is currently `v1.36.1`; this is a graph-correctness
6
+ fix that only *removes* phantom nodes/edges and adds no public surface (no new CLI
7
+ flag, MCP tool, node/edge type, or config key), so per [CLAUDE.md](../../CLAUDE.md)
8
+ SemVer it is a **patch** bump. Reconcile the exact number against `master` at the
9
+ moment the PR is cut: if master is still `v1.36.1` → ship `v1.36.2`; if a later patch
10
+ has landed, take the next patch above whatever master then carries. Do not assume
11
+ `1.36.2` blindly.
12
+ **Cross-refs:** issue #161 (phantom source node for non-table DDL), #159 (create-kind
13
+ catch-all → OTHER), #166 / PR-B (the non-table-CREATE source-gate that this extends).
14
+ [`sprint_snowflake_lineage_patterns.md`](sprint_snowflake_lineage_patterns.md) PR-B.
15
+
16
+ ## Summary
17
+
18
+ `DROP TABLE/VIEW ... <name>` and `ALTER TABLE <name> ...` statements mint a phantom
19
+ `SqlTable` source node (+ a phantom `SELECTS_FROM` edge) for their *target* object,
20
+ even though DROP/ALTER carry no data flow. This inflates the graph with degree-0
21
+ island nodes (the viz finding) and ~1,308 phantom `SELECTS_FROM` edges on the live
22
+ DWH corpus. The fix extends the existing #161 single source-gate in
23
+ `AnsiParser._parse_statement` to also return `sources = []` for `exp.Drop` /
24
+ `exp.Alter` / `exp.TruncateTable`.
25
+
26
+ ## Live-verification verdict (DONE before planning — evidence below)
27
+
28
+ **VERDICT: hypothesis CONFIRMED at the mechanism level; hypothesis #2 (the #159
29
+ attribution) PARTIALLY DISPROVEN — #159 is NOT the cause. Plan proceeds.**
30
+
31
+ ### Mechanism confirmed (file:line)
32
+
33
+ For `DROP VIEW IF EXISTS IA_ANALYTICS.BA_WTDA_CAMPAIGN`:
34
+ - `sqlglot` parses it to `exp.Drop`, `kind="VIEW"`, and `AnsiParser._classify` →
35
+ `"OTHER"` (verified by probe).
36
+ - `build_scope(stmt)` returns `None` for `exp.Drop`/`exp.Alter` → control falls into
37
+ the `else` fallback branch in
38
+ [`ansi_parser.py:580-595`](../../src/sqlcg/parsers/ansi_parser.py) which calls
39
+ `_fallback_table_scan(stmt)`.
40
+ - [`_fallback_table_scan`](../../src/sqlcg/parsers/ansi_parser.py) (`ansi_parser.py:792`)
41
+ does `find_all(exp.Table)`, which matches the DROP/ALTER *target* table and returns
42
+ it as a "source".
43
+ - The #161 gate `is_non_table_create = isinstance(stmt, exp.Create) and stmt.kind not
44
+ in ("TABLE","VIEW")` (ansi_parser.py:566) is **False** for `exp.Drop`/`exp.Alter`
45
+ (they are not `exp.Create`), so the gate does NOT cover them.
46
+ - The "source" flows into `out.referenced_tables` via the unconditional
47
+ `out.referenced_tables.extend(query_node.sources)` at
48
+ [`ansi_parser.py:246`](../../src/sqlcg/parsers/ansi_parser.py) /
49
+ [`snowflake_parser.py:894`](../../src/sqlcg/parsers/snowflake_parser.py) /
50
+ [`:1054`](../../src/sqlcg/parsers/snowflake_parser.py), minting a `SqlTable` node +
51
+ `SELECTS_FROM` edge.
52
+
53
+ ### Decisive corpus case
54
+
55
+ [`ddl/changelogs/BA-TABLES/WTDA_MARKETING_AUTOMATION_CAMPAIGN.sql`] line 9 is the ONLY
56
+ appearance of `IA_ANALYTICS.BA_WTDA_CAMPAIGN` in the file — a `DROP VIEW IF EXISTS`.
57
+ The CREATEs in that file target `BA.WTDA_MARKETING_AUTOMATION_CAMPAIGN`. Live
58
+ `parse_file` output:
59
+
60
+ ```
61
+ stmt: OTHER target=None sources=['ia_analytics.ba_wtda_campaign'] <- DROP VIEW
62
+ stmt: CREATE_VIEW target=ia_analytics.ba_wtda_marketing_automation_campaign ...
63
+ ```
64
+
65
+ So `ia_analytics.ba_wtda_campaign` can ONLY originate from the DROP. Confirmed present
66
+ as a degree-0 island in the live graph.
67
+
68
+ ### Why `_exclude_synthetic_tables` does NOT catch them
69
+
70
+ [`_exclude_synthetic_tables`](../../src/sqlcg/server/tools.py) (tools.py:388) keys on
71
+ `SqlTable.kind in {"cte","derived","temp"}` (`_SYNTHETIC_TABLE_KINDS`, tools.py:383). A
72
+ DROP-minted source reference is a plain `kind="table"` node (the default source-ref
73
+ kind in [`indexer.py` `_flush_row_batch`](../../src/sqlcg/indexer/indexer.py)), so it
74
+ is never in the synthetic set. **Two reasons the `_bck*` filter misses these:**
75
+ 1. The node's `kind` is `"table"`, not a synthetic kind → the filter passes it through.
76
+ 2. `_exclude_synthetic_tables` is a **query-time** filter inside MCP tools
77
+ (get_change_scope / diff_impact / …). The viz reads `SqlTable` rows directly via
78
+ [`viz/data.py` `_Q_NODES`](../../src/sqlcg/viz/data.py) and emits a node for EVERY
79
+ `SqlTable` regardless of kind — the filter never runs for the viz at all.
80
+
81
+ The corpus `.sqlcg.toml` has `noise_filter.ignore_table_regexes = ["_bck"]`, which
82
+ strips some `_bck` nodes at index time, which is why the viz showed ~136 and not the
83
+ full count — but the mechanism still leaks every non-`_bck` DROP/ALTER target.
84
+
85
+ ### Quantification (live DWH, 1,451 files, current worktree v1.36.1)
86
+
87
+ | Metric | Value | Source |
88
+ |--------|-------|--------|
89
+ | Total `SqlTable` nodes | 6,673 | `_Q_NODES` |
90
+ | Degree-0 island nodes (viz definition, all schemas) | 3,747 | viz logic replica |
91
+ | `SqlTable` nodes whose **sole** origin is the DROP/ALTER source loop | **169** | corpus re-parse |
92
+ | — of which `_bck*` backup | 7 | (most already stripped by noise_filter) |
93
+ | — of which `da.rtgmd_*` | 32 | all sole-DROP-origin (see below) |
94
+ | — `_obsolete` | 2 | |
95
+ | — other | 128 | |
96
+ | Phantom `SELECTS_FROM` edges from OTHER-kind no-target queries | **1,308** | (21% of all 6,239 SELECTS_FROM) |
97
+
98
+ The "169 sole-DROP-origin nodes" closely matches the finding's "136 island tables"
99
+ (difference = noise_filter `_bck` stripping + viz schema scoping).
100
+
101
+ ### A/B vs v1.34.1 (pre-#159) — code-level, definitive
102
+
103
+ A full reindex at v1.34.1 was **not** run (RAM at 145 MB free at the time; the
104
+ code-level A/B is conclusive and a reindex would add no signal for the DROP/ALTER
105
+ target). Evidence:
106
+
107
+ - Pre-#159 commit `2047bc0`: `_classify`'s `exp.Drop`/`exp.Alter` both hit the same
108
+ `case _: return QueryKind.OTHER` arm as today — **unchanged by #159**.
109
+ - Pre-#159 `ansi_parser.py` had the SAME `_fallback_table_scan` fallthrough for
110
+ Drop/Alter and NO `is_non_table_create` gate (the gate is #161, post-#159).
111
+ - #159 (`4a55306`) flipped ONLY the **non-table `exp.Create`** catch-all
112
+ `CREATE_TABLE`→`OTHER`. It did not touch `exp.Drop`/`exp.Alter` classification or
113
+ source extraction.
114
+
115
+ **Conclusion:** the DROP/ALTER phantom-node/edge bug is **pre-existing and independent
116
+ of #159**. #159 changed the *label* of non-table CREATEs (whose source node #166
117
+ already gated); it neither introduced nor increased the DROP/ALTER island nodes. The
118
+ plan corrects the finding's hypothesis #2 accordingly. The fix is still warranted on
119
+ the confirmed mechanism + measured 169 nodes / 1,308 edges.
120
+
121
+ ### rtgmd note (finding said these should REMAIN)
122
+
123
+ The finding noted raw `da.rtgmd_*` ingest tables are genuinely lineage-free and should
124
+ stay. Verified: the 32 `da.rtgmd_*` nodes flagged here appear in the corpus **only** as
125
+ `drop table` targets (e.g. `da.rtgmd_csp_coulances` — sole appearance is
126
+ `ddl/changelogs/DA-TABLES/RTGMD.sql:7 drop table DA.RTGMD_CSP_COULANCES;`, no CREATE,
127
+ no SELECT/INSERT). They are themselves DROP-origin phantoms and SHOULD be removed.
128
+ rtgmd tables that have a **real** CREATE/INSERT definition elsewhere will still appear
129
+ (they have real edges/origins) and are unaffected by this fix — those are the genuine
130
+ lineage-free islands that REMAIN. The fix only removes nodes whose *sole* origin is the
131
+ DROP/ALTER loop.
132
+
133
+ ### gain baseline (acceptance-gate framing)
134
+
135
+ Saved: [`plan/metrics/gain_drop_alter_phantom_baseline_v1361.json`](../metrics/gain_drop_alter_phantom_baseline_v1361.json).
136
+
137
+ | coverage key | baseline (v1.36.1) |
138
+ |---|---|
139
+ | `total_tables` | 6,673 |
140
+ | `total_edges` | 61,983 |
141
+ | `good_edges` | 53,811 |
142
+ | `good_edges_strict` | 48,907 |
143
+ | `good_edges_scoped` | 37,502 |
144
+ | `edge_health_strict_pct` | 78.9 |
145
+ | `edge_health_scoped_pct` | 98.53 |
146
+ | `phantom_edges` | 12,241 |
147
+ | `phantom_confirmed` | 11,701 |
148
+ | `blindspot_tables` | 631 |
149
+
150
+ ## Scope
151
+
152
+ ### In Scope
153
+ - Suppress `sources` for `exp.Drop`, `exp.Alter`, and `exp.TruncateTable` in the single
154
+ source-gate in `AnsiParser._parse_statement` (the same chokepoint as #161). This
155
+ removes both the phantom `SqlTable` node AND the phantom `SELECTS_FROM` edge for these
156
+ statement kinds.
157
+ - Unit test pinning the new behaviour (DROP/ALTER/TRUNCATE emit no source / no
158
+ referenced_table), mirroring [`test_phantom_non_table_create_source.py`](../../tests/unit/test_phantom_non_table_create_source.py).
159
+ - Integration test (real DuckDB) pinning that a DROP-only target does NOT become a
160
+ `SqlTable` node and produces no `SELECTS_FROM` edge, mirroring
161
+ [`test_phantom_non_table_create_node.py`](../../tests/integration/test_phantom_non_table_create_node.py).
162
+ - Control tests proving real DML/CTAS lineage is untouched (UPDATE/DELETE/MERGE/SELECT
163
+ reads and CTAS sources survive), including a same-name DROP+CREATE no-collateral-loss
164
+ case.
165
+ - Incremental-parity test (extend
166
+ [`test_incremental_reindex_parity.py`](../../tests/integration/test_incremental_reindex_parity.py))
167
+ proving the gate holds on `resync_changed` / `reindex_file`, not just `index_repo`.
168
+ - Version bump (patch) + gain re-measure to populate the acceptance gate.
169
+
170
+ ### Non-Goals
171
+ - **Schema qualification** — `ia_analytics.ba_wtda_*` / `ia_tableau.ba_wtda_*` are REAL
172
+ distinct corpus tables (publish layers prefix the source business-area into the
173
+ name). The qualification is CORRECT. Do not "fix" it.
174
+ - **Quoted-identifier islands** (`ia_tableau.prijsadvies aan huis`) — that is #153,
175
+ out of scope here.
176
+ - **rtgmd tables with real definitions** — left as genuine lineage-free islands.
177
+ - Any change to `_exclude_synthetic_tables` or the viz (the fix is upstream, at parse
178
+ time — the right place; no downstream filter is added).
179
+ - Re-classifying DROP/ALTER away from `OTHER` (the kind label is fine; only the
180
+ source-extraction is wrong).
181
+
182
+ ## Design
183
+
184
+ ### Root cause (one chokepoint)
185
+ [`AnsiParser._parse_statement`](../../src/sqlcg/parsers/ansi_parser.py) (ansi_parser.py:566)
186
+ currently gates only non-table CREATEs:
187
+
188
+ ```python
189
+ is_non_table_create = isinstance(stmt, exp.Create) and stmt.kind not in ("TABLE", "VIEW")
190
+ ...
191
+ if is_non_table_create:
192
+ sources = []
193
+ else:
194
+ # build_scope / _fallback_table_scan <- DROP/ALTER target leaks in here
195
+ ```
196
+
197
+ `SnowflakeParser` inherits `_parse_statement` and `_classify` (it subclasses
198
+ `AnsiParser`, no override — verified). So this single gate feeds all three
199
+ `referenced_tables.extend(query_node.sources)` sites in both parsers.
200
+
201
+ ### Proposed change
202
+ Add a sibling predicate and fold it into the same gate. DROP/ALTER/TRUNCATE never carry
203
+ a data-flow source (no SELECT body is structurally possible), so suppressing their
204
+ sources is edge-neutral for real lineage:
205
+
206
+ ```python
207
+ # #161 part 2: DROP / ALTER / TRUNCATE reference their TARGET object, not a
208
+ # data-flow source. build_scope() returns None for these, so _fallback_table_scan
209
+ # would otherwise scoop the target name into `sources`, minting a phantom island
210
+ # SqlTable node + SELECTS_FROM edge (measured: 169 sole-DROP-origin nodes,
211
+ # 1,308 phantom SELECTS_FROM edges on the DWH corpus). Keyed off the AST type,
212
+ # independent of _classify.
213
+ is_non_flow_ddl = isinstance(stmt, (exp.Drop, exp.Alter, exp.TruncateTable))
214
+ ...
215
+ if is_non_table_create or is_non_flow_ddl:
216
+ sources = []
217
+ else:
218
+ ...
219
+ ```
220
+
221
+ (Final naming/structure at developer discretion as long as it is the SAME single gate
222
+ and keyed off the AST type, not `_classify`.)
223
+
224
+ ### CRITICAL INVARIANT — the gate is PER-STATEMENT, no collateral node loss
225
+ `sources = []` is set **for the single DROP/ALTER/TRUNCATE statement currently being
226
+ parsed in `_parse_statement`, and for nothing else.** `_parse_statement` is invoked
227
+ once per top-level statement (see the loop at
228
+ [`ansi_parser.py:212`](../../src/sqlcg/parsers/ansi_parser.py) and the Snowflake
229
+ override sites [`snowflake_parser.py:870`](../../src/sqlcg/parsers/snowflake_parser.py)
230
+ / [`:1024`](../../src/sqlcg/parsers/snowflake_parser.py)); the `isinstance(stmt, ...)`
231
+ predicate is evaluated against *that one statement's* AST node. It cannot reach across
232
+ to another statement in the same file, nor to another file.
233
+
234
+ Consequence — the precise blast radius:
235
+
236
+ - A table whose **sole** appearance in the entire corpus is as a DROP/ALTER/TRUNCATE
237
+ target loses its phantom `SqlTable` node and its phantom `SELECTS_FROM` edge. This is
238
+ the intended removal.
239
+ - A table that is ALSO legitimately the target of a `CREATE TABLE/VIEW` (its CREATE
240
+ statement is a *different* `_parse_statement` call that still emits its real target +
241
+ sources), or that is read by a real `SELECT`/`INSERT…SELECT`/CTAS anywhere (in this
242
+ file or any other), **keeps its `SqlTable` node and all of its real edges.** The graph
243
+ node identity is keyed on `(schema, name)` and is created/kept by any of those real
244
+ origins; suppressing the DROP statement's source list removes only the edge the DROP
245
+ would have contributed, never the node a real statement created.
246
+
247
+ The acceptance metric is therefore **"count of sole-DROP/ALTER/TRUNCATE-origin island
248
+ nodes → ~0"**, NOT "every table named in a DROP is removed". A table named in both a
249
+ DROP and a CREATE must survive with its real edges intact — this is pinned by a
250
+ dedicated integration test (see Step 2.2, the mixed-origin case) and by the live
251
+ acceptance probe (the `da.rtgmd_*` analysis already distinguishes sole-DROP-origin
252
+ phantoms from rtgmd tables with a real CREATE/INSERT that REMAIN).
253
+
254
+ ### All reindex paths inherit the gate (incremental == from-scratch)
255
+ The fix lives in `AnsiParser._parse_statement`
256
+ ([`ansi_parser.py:423`](../../src/sqlcg/parsers/ansi_parser.py), gate block at
257
+ `:568`), which is the SINGLE parse chokepoint shared by every path that turns SQL into
258
+ `ParsedFile.referenced_tables`. Verified call routes (file:line):
259
+
260
+ - **Full index** — `index_repo` → `_index_single_file`
261
+ ([`indexer.py:410`](../../src/sqlcg/indexer/indexer.py)) → `parser.parse_file` →
262
+ `_parse_statement` (loop at [`ansi_parser.py:212`](../../src/sqlcg/parsers/ansi_parser.py)).
263
+ - **Branch-delta incremental** — `resync_changed`
264
+ ([`indexer.py:1010`](../../src/sqlcg/indexer/indexer.py)) re-parses its `reparse_set`
265
+ via the SAME `_index_single_file` → `parse_file` route (Step 4, `indexer.py:122-123`).
266
+ - **Single-file watch** — `reindex_file`
267
+ ([`indexer.py:1420`](../../src/sqlcg/indexer/indexer.py)) calls `parser.parse_file`
268
+ directly ([`indexer.py:1458`](../../src/sqlcg/indexer/indexer.py), the
269
+ `parsed = parser.parse_file(...)` line).
270
+ - **Snowflake** — `SnowflakeParser` does not override `_parse_statement`; both its
271
+ override entry points call `AnsiParser._parse_statement`
272
+ ([`snowflake_parser.py:870`](../../src/sqlcg/parsers/snowflake_parser.py),
273
+ [`:1024`](../../src/sqlcg/parsers/snowflake_parser.py)).
274
+
275
+ Because all four routes funnel through the one gated method, the fix holds identically
276
+ on the incremental path — there is no full-path-only step to drift from. This is the
277
+ **exact bug class of the recent #170/#171 incremental-parity regression** (a step
278
+ present in `index_repo` but absent in `resync_changed`). To make that guarantee
279
+ *falsifiable* rather than asserted, the plan extends the existing parity harness
280
+ [`test_incremental_reindex_parity.py`](../../tests/integration/test_incremental_reindex_parity.py)
281
+ with a DROP-bearing file (Step 2.3): incremental and from-scratch graphs must contain
282
+ the SAME `SqlTable` keys and SELECTS_FROM edges (i.e. neither path mints the phantom).
283
+
284
+ ### Why `exp.TruncateTable` is included — GROUNDED, not class-analogy
285
+ TRUNCATE is NOT a speculative add. **Measured on the live source (file:line / probe):**
286
+
287
+ - The DWH corpus contains **514 files** with a `TRUNCATE TABLE` statement
288
+ (`grep -ilE 'truncate +table'` over `/home/ignwrad/Projects/dwh`), e.g.
289
+ `etl/pdi/template/htwfm_contract_us28254.sql` → `TRUNCATE TABLE da_tmp.htwfm_contract;`.
290
+ - `sqlglot.parse_one("TRUNCATE TABLE s.t", dialect="snowflake")` is `exp.TruncateTable`
291
+ (verified by probe; DROP→`exp.Drop`, ALTER→`exp.Alter` confirmed in the same probe).
292
+ - Pre-fix, the target leaks identically to DROP/ALTER — a live `SnowflakeParser.parse_file`
293
+ probe returned:
294
+ `'TRUNCATE TABLE s.truncated;' -> referenced_tables=['s.truncated']`
295
+ (alongside `DROP VIEW IF EXISTS s.dropped;` → `['s.dropped']` and
296
+ `ALTER TABLE s.altered ADD COLUMN c INT;` → `['s.altered']`).
297
+
298
+ So TRUNCATE is the same confirmed leak mechanism with a large live population, not a
299
+ zero-instance guard. (The base.py `_can_have_column_lineage` docstring already lists
300
+ TruncateTable/Drop/Alter together as structurally lineage-free — this gate is the
301
+ source-side analogue.) NOTE: the original "169 nodes / 1,308 edges" quantification in
302
+ §Quantification was the DROP/ALTER measurement; the live re-measure (Step 3.2) will
303
+ report the TRUNCATE contribution to the removed-node/edge count separately so the
304
+ TRUNCATE share is grounded post-fix, not just pre-fix.
305
+
306
+ ### Stale inline comment to correct (housekeeping, do not skip)
307
+ The existing #161 gate comment at
308
+ [`ansi_parser.py:567`](../../src/sqlcg/parsers/ansi_parser.py) cites the extend sites as
309
+ `snowflake_parser.py:784 / :944`; the live sites are
310
+ [`snowflake_parser.py:894`](../../src/sqlcg/parsers/snowflake_parser.py) and
311
+ [`:1054`](../../src/sqlcg/parsers/snowflake_parser.py) (ansi `:246` is correct). The
312
+ developer updates the comment to the correct lines while editing this block.
313
+
314
+ ### Performance
315
+ Zero hot-path impact: the predicate is one `isinstance` check per statement, evaluated
316
+ BEFORE the (already-skipped) `build_scope`/`_fallback_table_scan` for these kinds — it
317
+ actually *removes* a `_fallback_table_scan` call for every DROP/ALTER/TRUNCATE. No
318
+ change to `_extract_column_lineage`, `body_scope`, qualify-once, or any
319
+ indexer bulk/batch upsert path. All CLAUDE.md performance invariants are untouched.
320
+
321
+ The following invariant suites must pass **UNMODIFIED** (the developer must not edit,
322
+ skip, or relax any of them; a red here means the fix touched a hot path it must not):
323
+ - [`test_perf_scaling_guard.py`](../../tests/unit/test_perf_scaling_guard.py) — the
324
+ general O(N)→O(N²) guard.
325
+ - [`test_bulk_upsert_invariant.py`](../../tests/unit/test_bulk_upsert_invariant.py) —
326
+ `_upsert_parsed_file` uses bulk upserts.
327
+ - [`test_upsert_batch_invariant.py`](../../tests/unit/test_upsert_batch_invariant.py) —
328
+ `_flush_row_batch` flushes once per batch.
329
+ - [`test_T09_01_qualify_once.py`](../../tests/unit/test_T09_01_qualify_once.py) —
330
+ qualify/build_scope once per statement.
331
+
332
+ These are listed not because the fix is expected to touch them — it is a single
333
+ `isinstance` predicate added *above* the `build_scope`/`_fallback_table_scan` branch,
334
+ which it does not modify — but to make the no-regression contract explicit and
335
+ gateable.
336
+
337
+ ### Data model / API
338
+ No schema change, no new method, no new node/edge type. No backward-compat concern
339
+ (re-index is the migration path). Existing phantom nodes/edges disappear on the next
340
+ `sqlcg index`.
341
+
342
+ ### Dependencies
343
+ None new.
344
+
345
+ ## Implementation Steps
346
+
347
+ ### Phase 1: Parser source-gate
348
+
349
+ **Step 1.1** — Extend the source-gate in `_parse_statement`.
350
+ - Files affected: [`src/sqlcg/parsers/ansi_parser.py`](../../src/sqlcg/parsers/ansi_parser.py)
351
+ (the `is_non_table_create` block, ~line 566-595).
352
+ - Add `is_non_flow_ddl = isinstance(stmt, (exp.Drop, exp.Alter, exp.TruncateTable))`
353
+ and OR it into the gate so `sources = []` for those kinds.
354
+ - Update the existing #161 gate comment to document the DROP/ALTER/TRUNCATE extension
355
+ and cross-ref this plan + #161.
356
+ - Acceptance: a `DROP VIEW IF EXISTS s.t` QueryNode has `sources == []` and
357
+ `parsed.referenced_tables == []`; same for `ALTER TABLE s.t ADD COLUMN …` and
358
+ `TRUNCATE TABLE s.t`.
359
+
360
+ ### Phase 2: Tests
361
+
362
+ **Step 2.1** — Unit test (no backend).
363
+ - File: new `tests/unit/test_phantom_drop_alter_source.py` (mirror the #161 unit test
364
+ structure; do NOT seed opaque case codes into test names).
365
+ - Behaviours to pin:
366
+ - DROP TABLE / DROP VIEW (with and without `IF EXISTS`) emit no source, no
367
+ referenced_table.
368
+ - ALTER TABLE emits no source, no referenced_table.
369
+ - TRUNCATE TABLE emits no source, no referenced_table.
370
+ - Control: `UPDATE s.t SET c = (SELECT x FROM s.src)` STILL records `s.src` as a
371
+ referenced source (real read preserved).
372
+ - Control: `DELETE FROM s.t WHERE id IN (SELECT id FROM s.src)` STILL records
373
+ `s.src`.
374
+ - Control: CTAS `CREATE TABLE s.t AS SELECT a FROM s.src` STILL records `s.src`
375
+ (re-assert #161's TABLE/VIEW arm is intact).
376
+ - Gate-keyed-on-AST documentation guard: assert `sqlglot.parse_one("DROP VIEW s.t",
377
+ dialect="snowflake")` is `exp.Drop`, `ALTER …` is `exp.Alter`, `TRUNCATE TABLE …`
378
+ is `exp.TruncateTable`.
379
+
380
+ **Step 2.2** — Integration test (real DuckDB in-memory).
381
+ - File: new `tests/integration/test_phantom_drop_alter_node.py` (mirror
382
+ [`test_phantom_non_table_create_node.py`](../../tests/integration/test_phantom_non_table_create_node.py)).
383
+ - The fixture MUST match the LIVE corpus shape — schema-qualified, snowflake dialect,
384
+ with all three statement forms exactly as they appear in the DWH:
385
+ `DROP VIEW IF EXISTS ia_analytics.ba_wtda_campaign;`, an `ALTER TABLE … ADD COLUMN …`,
386
+ and `TRUNCATE TABLE da_tmp.htwfm_contract;` (the real sampled form). Do NOT use a
387
+ minimal unqualified `DROP TABLE t;` that cannot exhibit the schema-qualified phantom.
388
+ - **Negative control (house rule — tests assert observable output AND must fail on
389
+ pre-fix code):** the dropped/altered/truncated-only target test must be written so it
390
+ FAILS against current (pre-fix) `_parse_statement` — i.e. on pre-fix code the
391
+ `SqlTable` node and `SELECTS_FROM` edge for the target ARE present, so the assertion
392
+ `node absent / edge absent` goes red. The developer must run the new test once against
393
+ the unpatched parser and record (in the PR/handoff) that it failed there, then green
394
+ after the gate. A test that is green both before and after is not a regression test.
395
+ - Behaviours to pin (index a tiny fixture, then query the graph):
396
+ - A file containing ONLY `DROP VIEW IF EXISTS ia_analytics.ba_wtda_campaign;` produces
397
+ NO `SqlTable` row for `ia_analytics.ba_wtda_campaign` and NO `SELECTS_FROM` edge with
398
+ that dst key. Same assertion for an ALTER-only and a TRUNCATE-only target.
399
+ - **Mixed-origin survival (the no-collateral-loss case):** a file with
400
+ `DROP VIEW IF EXISTS s.x;` followed by
401
+ `CREATE OR REPLACE VIEW s.y AS SELECT a FROM s.real;` produces a `SqlTable` row for
402
+ `s.y` and `s.real` (and the real `s.real → s.y` lineage), but NO node for `s.x`.
403
+ - **Same-name DROP + CREATE survives (per-statement invariant, explicit):** a file
404
+ where the SAME object is both DROP'd and re-created —
405
+ `DROP TABLE s.t;` then `CREATE TABLE s.t AS SELECT c FROM s.src;` — MUST keep the
406
+ `SqlTable` node for `s.t` AND the real `s.src → s.t` edge. Only the phantom edge the
407
+ DROP would have contributed is gone; the CREATE's node + edge survive. This pins
408
+ that the gate is per-statement and cannot delete a node a sibling statement
409
+ legitimately created.
410
+
411
+ **Step 2.3** — Incremental-parity test (extend the existing harness).
412
+ - File: extend [`test_incremental_reindex_parity.py`](../../tests/integration/test_incremental_reindex_parity.py)
413
+ (reuse its `_sql_table_keys` / `_selects_from_edges` helpers, `indexer.index_repo`
414
+ vs `indexer.resync_changed` / `indexer.reindex_file` structure at lines 156 / 235).
415
+ - Add a DROP-bearing file to the tree (e.g. a file with
416
+ `DROP VIEW IF EXISTS s.dropped_only;` and a real `CREATE … AS SELECT … FROM s.real;`)
417
+ and assert the incremental graph (`resync_changed` after a branch delta, and
418
+ separately `reindex_file`) has the SAME `SqlTable` keys and the SAME SELECTS_FROM
419
+ edges as a from-scratch `index_repo` of the final tree — i.e. NEITHER path mints the
420
+ phantom `s.dropped_only` node/edge. Guards against the #170/#171-class drift where the
421
+ gate would be honoured on the full path but missed on the incremental path.
422
+
423
+ ### Phase 3: Version + measure
424
+
425
+ **Step 3.1** — Patch version bump.
426
+ - Files: [`pyproject.toml`](../../pyproject.toml), [`src/sqlcg/__init__.py`](../../src/sqlcg/__init__.py),
427
+ `uv lock`. Bug fix only, no added surface → **patch**. Reconcile against `master` at
428
+ PR-cut: master is `v1.36.1` today → ship `v1.36.2`; if a later patch has merged first,
429
+ take the next patch above whatever master then carries (do not hardcode `1.36.2`).
430
+ - Acceptance: `uv run sqlcg --version` reports the new version;
431
+ [`test_version_parity.py`](../../tests/unit/test_version_parity.py) stays green
432
+ (`pyproject.toml` == `__init__.py` == lockfile).
433
+
434
+ **Step 3.2** — Live re-measure for the acceptance gate (delegated index run).
435
+ - Re-index the live DWH corpus on the fix branch, capture `sqlcg gain --json` into
436
+ `plan/metrics/gain_drop_alter_phantom_after_<ver>.json`, and record the deltas in the
437
+ Acceptance Criteria table below. Index time must stay under the 5-min budget; report
438
+ gain table-health.
439
+
440
+ ## Test Strategy
441
+
442
+ - **Unit**: assert observable `QueryNode.sources` / `ParsedFile.referenced_tables`
443
+ contents for DROP/ALTER/TRUNCATE (empty) and the DML/CTAS controls (real source
444
+ present). No "no exception raised" assertions.
445
+ - **Integration**: assert observable graph state — absence of the phantom `SqlTable`
446
+ node and absence of the phantom `SELECTS_FROM` edge for a DROP-only target, presence
447
+ of the real CREATE-VIEW lineage in the same fixture, and the same-name DROP+CREATE
448
+ survival case. Fixtures use the snowflake dialect and schema-qualified names mirroring
449
+ the live corpus shape (`ia_analytics.ba_wtda_*` and `da_tmp.htwfm_contract`-style),
450
+ per the live-config-fidelity rule. The phantom-absence assertion is a **negative
451
+ control**: it must be confirmed RED on pre-fix `_parse_statement` and GREEN after, so
452
+ it genuinely pins the removal rather than passing vacuously.
453
+ - **Incremental parity**: assert the incremental-path graph (`resync_changed` /
454
+ `reindex_file`) equals the from-scratch graph for a DROP-bearing tree (same SqlTable
455
+ keys, same SELECTS_FROM edges) — guards the #170/#171-class drift.
456
+ - **Regression guards**: existing #161 tests
457
+ ([`test_phantom_non_table_create_source.py`](../../tests/unit/test_phantom_non_table_create_source.py),
458
+ [`test_phantom_non_table_create_node.py`](../../tests/integration/test_phantom_non_table_create_node.py))
459
+ must stay green (the TABLE/VIEW arm is unchanged). Perf scaling guard
460
+ ([`test_perf_scaling_guard.py`](../../tests/unit/test_perf_scaling_guard.py)) must
461
+ stay green (no hot-path change).
462
+
463
+ ## Acceptance Criteria
464
+
465
+ - [ ] A `DROP TABLE`/`DROP VIEW` statement (±`IF EXISTS`) yields `QueryNode.sources == []`
466
+ and contributes nothing to `ParsedFile.referenced_tables`. (unit)
467
+ - [ ] An `ALTER TABLE` statement yields `QueryNode.sources == []` and no
468
+ referenced_table. (unit)
469
+ - [ ] A `TRUNCATE TABLE` statement yields `QueryNode.sources == []` and no
470
+ referenced_table. (unit)
471
+ - [ ] `UPDATE … (SELECT … FROM s.src)`, `DELETE … (SELECT … FROM s.src)`, and CTAS
472
+ `CREATE TABLE … AS SELECT … FROM s.src` STILL record `s.src` as a source. (unit
473
+ controls — proves the fix is edge-neutral for real reads)
474
+ - [ ] Indexing a DROP-only / ALTER-only / TRUNCATE-only file produces NO `SqlTable`
475
+ node and NO `SELECTS_FROM` edge for the target object — AND this test was shown to
476
+ FAIL on pre-fix code (negative control). (integration)
477
+ - [ ] A file where the SAME object is both DROP'd and CREATE'd (`DROP TABLE s.t;` +
478
+ `CREATE TABLE s.t AS SELECT c FROM s.src;`) keeps the `s.t` node and the real
479
+ `s.src → s.t` edge — no collateral node loss. (integration, per-statement invariant)
480
+ - [ ] Incremental (`resync_changed` / `reindex_file`) and from-scratch (`index_repo`)
481
+ graphs of a DROP-bearing tree have identical `SqlTable` keys and SELECTS_FROM
482
+ edges — the gate holds on the incremental path. (integration parity)
483
+ - [ ] On the live DWH re-index: the `ia_analytics.ba_wtda_campaign` node is **gone**
484
+ (decisive case), and the count of **sole-DROP/ALTER/TRUNCATE-origin** island nodes
485
+ drops from 169 toward ~0 — measured as sole-origin, NOT "every DROP-named table
486
+ removed". Tables that also have a real CREATE/INSERT/SELECT origin MUST still be
487
+ present. (live; re-run the corpus re-parse probe, and report the TRUNCATE share of
488
+ the removed nodes/edges separately since the original 169/1,308 was DROP/ALTER)
489
+ - [ ] On the live DWH re-index: phantom `SELECTS_FROM` edges from OTHER-kind no-target
490
+ queries drops from 1,308 toward the residual (UPDATE/DELETE/MERGE/SELECT real
491
+ reads must remain — i.e. only the Drop/Alter/Truncate subset is removed). (live)
492
+ - [ ] `gain --json` after the fix: `good_edges_strict` and `good_edges_scoped` are
493
+ **unchanged or up** (no real lineage lost); `total_tables` and `total_edges` go
494
+ **down** (phantom nodes/edges removed); `edge_health_*_pct` unchanged or up.
495
+ Record exact before/after in
496
+ `plan/metrics/gain_drop_alter_phantom_after_<ver>.json`.
497
+ - [ ] Index time stays under the 5-minute budget.
498
+ - [ ] Existing #161 tests remain green. The perf/upsert invariant suites
499
+ (`test_perf_scaling_guard.py`, `test_bulk_upsert_invariant.py`,
500
+ `test_upsert_batch_invariant.py`, `test_T09_01_qualify_once.py`) pass
501
+ **UNMODIFIED** — not edited, skipped, or relaxed.
502
+
503
+ ## Risks and Mitigations
504
+
505
+ | Risk | Mitigation |
506
+ |------|------------|
507
+ | A DROP/ALTER target that is ALSO a real table loses its node (collateral loss) | It does not: the gate is PER-STATEMENT (`_parse_statement` runs once per statement; the `isinstance` check sees only that statement). Real tables get their node from a *different* CREATE/INSERT/SELECT statement and survive with their real edges; only the phantom source the DROP statement contributed is removed. Pinned by two integration cases: mixed-origin (different objects) and same-name DROP+CREATE (same object). The live metric is "sole-DROP/ALTER/TRUNCATE-origin islands → ~0", not "all DROP-named tables removed". |
508
+ | Gate honoured on full index but missed on incremental reindex (#170/#171 class) | The fix is parser-level in `_parse_statement`; all of `index_repo`, `resync_changed`, and `reindex_file` route through `parse_file` → `_parse_statement` (call routes verified in Design). The extended `test_incremental_reindex_parity.py` asserts incremental == from-scratch for a DROP-bearing tree. |
509
+ | Suppressing TRUNCATE sources hides a real dependency | TRUNCATE has no data-flow source by definition (target-only). Edge-neutral. |
510
+ | Removing nodes lowers good_edges (false "regression") | good_edges count only real lineage; phantom DROP edges are not counted as good. The gain gate explicitly requires good_edges_strict/scoped unchanged-or-up. |
511
+ | sqlglot maps some DROP/ALTER variant to a different AST type | The unit doc-guard asserts the AST types for the dialect; if a variant differs, the gate's `isinstance` tuple is extended (cheap, local). |
512
+ | #153 quoted-identifier islands conflated with this fix | Explicitly out of scope; those nodes have a different origin (quoted name handling), untouched here. |
513
+
514
+ ### Deviations
515
+
516
+ #### Deviation 1: UPDATE/DELETE sub-SELECT control assertions could not be used as written
517
+ - **Reason**: The plan (Step 2.1) specified unit controls asserting
518
+ `UPDATE s.t SET c = (SELECT x FROM s.src)` and
519
+ `DELETE FROM s.t WHERE id IN (SELECT id FROM s.src)` STILL record `s.src` as a
520
+ referenced source. Verified on clean (pre-fix) code: the live parser returns
521
+ `referenced_tables == []` for BOTH — it does not extract sub-SELECT sources from
522
+ UPDATE-SET / DELETE-WHERE clauses. This is pre-existing parser behaviour,
523
+ independent of this gate (proven by running the probe with `ansi_parser.py`
524
+ stashed). The asserted source was never recorded, so the control as written would
525
+ be red on master.
526
+ - **Change**: Replaced the UPDATE/DELETE sub-SELECT source controls with controls
527
+ the parser actually produces — `SELECT ... FROM s.src`, `INSERT INTO s.t SELECT ...
528
+ FROM s.src`, and the CTAS arm (`#161` intact) — and added a
529
+ `TestGateEdgeNeutralForNonGatedKinds` class asserting UPDATE/SELECT are outside the
530
+ gate's `isinstance` tuple and unperturbed. This preserves the plan's INTENT
531
+ (prove the gate is edge-neutral for real reads) using observable parser output.
532
+ - **Impact**: No scope change; the edge-neutrality guarantee is still pinned. The
533
+ gate's `isinstance` tuple is `(exp.Drop, exp.Alter, exp.TruncateTable)` only, so
534
+ UPDATE/DELETE are untouched by construction.
535
+ - **Date**: 2026-06-15
536
+
537
+ #### Deviation 2: Live-DWH baseline JSON is a different corpus state than the re-index
538
+ - **Reason**: The committed baseline `gain_drop_alter_phantom_baseline_v1361.json`
539
+ (total_tables=6,673) was captured against a 1,451-file DWH state. The live
540
+ re-index on this branch indexed the current 1,335-file checkout
541
+ (indexed_sha=fdf1b551). The absolute gain totals are therefore NOT a clean
542
+ before/after delta against that JSON (different corpus).
543
+ - **Change**: The acceptance evidence is reported as a controlled STRUCTURAL probe
544
+ on the post-fix graph (decisive node absent; sole-DROP/ALTER/TRUNCATE-origin
545
+ count) plus the pre-fix→post-fix red→green negative-control test, rather than a
546
+ raw gain-total subtraction. The after-JSON
547
+ (`gain_1.36.2_f6a335a.json`) is committed for the record.
548
+ - **Impact**: No scope change. The decisive case is verified (node count 0) and the
549
+ sole-origin phantom population is verified gone (all DDL targets that remain have a
550
+ real CREATE / CREATE-CLONE / HAS_COLUMN / lineage origin).
551
+ - **Date**: 2026-06-15
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sql-code-graph"
7
- version = "1.36.1"
7
+ version = "1.36.2"
8
8
  description = "SQL code graph analyzer and lineage tracer"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1,5 +1,5 @@
1
1
  """SQL Code Graph - SQL lineage and dependency analysis tool."""
2
2
 
3
- __version__ = "1.36.1"
3
+ __version__ = "1.36.2"
4
4
 
5
5
  __all__ = ["__version__"]