sql-code-graph 1.35.3__tar.gz → 1.36.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (615) hide show
  1. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/PKG-INFO +1 -1
  2. sql_code_graph-1.36.0/plan/sprints/feature_generic_var_name_resolution.md +518 -0
  3. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/pyproject.toml +1 -1
  4. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/__init__.py +1 -1
  5. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/registry.py +7 -3
  6. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/snowflake_parser.py +114 -4
  7. sql_code_graph-1.36.0/tests/integration/snowflake/test_identifier_var_sink_resolution_integration.py +96 -0
  8. sql_code_graph-1.36.0/tests/unit/test_identifier_var_sink_resolution.py +201 -0
  9. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_perf_scaling_guard.py +76 -0
  10. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/uv.lock +1 -1
  11. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.claude/agents/api-documenter.md +0 -0
  12. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.claude/agents/architect-planner.md +0 -0
  13. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.claude/agents/architect-reviewer.md +0 -0
  14. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.claude/agents/code-reviewer.md +0 -0
  15. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.claude/agents/developer.md +0 -0
  16. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.claude/agents/plan-reviewer.md +0 -0
  17. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.claude/agents/sprint-planner.md +0 -0
  18. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  19. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  21. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.github/workflows/benchmark.yml +0 -0
  22. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.github/workflows/e2e-tests.yml +0 -0
  23. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.github/workflows/release.yml +0 -0
  24. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.github/workflows/test.yml +0 -0
  25. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.gitignore +0 -0
  26. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.pre-commit-config.yaml +0 -0
  27. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/.sqlcgignore +0 -0
  28. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/ARCHITECTURE_REVIEW.md +0 -0
  29. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/ARCHITECTURE_REVIEW_ARCHIVE.md +0 -0
  30. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/CHANGELOG.md +0 -0
  31. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/CLAUDE.md +0 -0
  32. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/README.md +0 -0
  33. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/docs/AIRBNB_PARSE_REPORT.md +0 -0
  34. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/docs/cli.md +0 -0
  35. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/docs/getting-started.md +0 -0
  36. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/docs/releasing-pypi.md +0 -0
  37. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/e2e_firstuser_report.md +0 -0
  38. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/e2e_run_20260528_101413.output +0 -0
  39. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/main.py +0 -0
  40. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/WORKFLOW.md +0 -0
  41. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/measurements/pr2_catalog_load_eval.json +0 -0
  42. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/measurements/pr3_repo_native_plateau.json +0 -0
  43. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/measurements/pr4_transform_kinds.json +0 -0
  44. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/measurements/pr5_extraction_recall_taxonomy.json +0 -0
  45. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
  46. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
  47. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/createkind_dwh_after.json +0 -0
  48. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/createkind_dwh_before.json +0 -0
  49. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/gain_1.29.0_05c6943.json +0 -0
  50. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/gain_1.30.0_2c8ac25.json +0 -0
  51. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/gain_1.30.1_26271fc.json +0 -0
  52. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/gain_1.31.0_a40c837.json +0 -0
  53. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/gain_1.32.0_c1bec3c.json +0 -0
  54. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/lineage5_dwh_after_pr5.json +0 -0
  55. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/lineage5_dwh_before_master.json +0 -0
  56. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/pr4_star_promote_after.json +0 -0
  57. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/pr4_star_promote_before.json +0 -0
  58. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/pr_b_phantom_after.json +0 -0
  59. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/pr_b_phantom_before.json +0 -0
  60. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/pr_c_merge_after.json +0 -0
  61. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/pr_c_merge_before.json +0 -0
  62. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/schema_comparison_with_schema.json +0 -0
  63. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/schema_comparison_without_schema.json +0 -0
  64. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/sprint_08_changelogs_fullindex.json +0 -0
  65. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/sprint_08_fullcorpus_index.json +0 -0
  66. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/metrics/sprint_pool_300s_plan.json +0 -0
  67. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/column_coverage_diagnostic.md +0 -0
  68. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/column_coverage_findings.md +0 -0
  69. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/dwh_graph_analysis.md +0 -0
  70. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/dwh_positional_insert_column_blindspot.md +0 -0
  71. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/feature_acceptance_dwh.md +0 -0
  72. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/graph_health_sprint_postmortem.md +0 -0
  73. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/island_lever_live_verification.md +0 -0
  74. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/issue38_pr2_live_acceptance.md +0 -0
  75. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/issue38_pr3_live_acceptance.md +0 -0
  76. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/lineage_identity_sprint_postmortem.md +0 -0
  77. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/pr_impact_followups_2026-06-14.md +0 -0
  78. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/sprint_03_v0.3.1_postmortem.md +0 -0
  79. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/sprint_3.1_postmortem.md +0 -0
  80. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/reports/v1_14_dialect_query_config_postmortem.md +0 -0
  81. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/blueprint.md +0 -0
  82. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/coverage_parse_failure_diagnosis.md +0 -0
  83. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/investigation_e5_e4.md +0 -0
  84. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/observed_usage_overlay_query_history_tableau.md +0 -0
  85. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/parse_diagnostics.md +0 -0
  86. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/parsing_errors_experiment.md +0 -0
  87. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/snowflake_en_test_suite.md +0 -0
  88. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/sql_only_coverage_lever_post_pr2.md +0 -0
  89. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/research/sqlcg.md +0 -0
  90. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/bundle_claude_skill.md +0 -0
  91. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/ci_tests_pool_flake_fix.md +0 -0
  92. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/column_lineage_recall_metric.md +0 -0
  93. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/coverage_p1_p3_p4.md +0 -0
  94. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/coverage_p1_p5_metric.md +0 -0
  95. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/coverage_parse_failures.md +0 -0
  96. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/diff-impact-producer-file.md +0 -0
  97. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/e8_dual_emission.md +0 -0
  98. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/feature_34_unused_presentation_segregation.md +0 -0
  99. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/feature_35_external_downstream_injection.md +0 -0
  100. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/feature_F2_bundle_claude_skill.md +0 -0
  101. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/feature_kuzu_to_duckdb_migration.md +0 -0
  102. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/fix_backward_self_heal_index_at_sha.md +0 -0
  103. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/fix_downstream_sink_location.md +0 -0
  104. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/fix_dynamic_table_parsing.md +0 -0
  105. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/fix_expand_qualify_perf.md +0 -0
  106. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/fix_firstuser_findings.md +0 -0
  107. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/fix_issue29_live_test_followups.md +0 -0
  108. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/fix_schema_case_mismatch.md +0 -0
  109. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/gain_coverage_metrics.md +0 -0
  110. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/graph_health_catalog_and_metrics.md +0 -0
  111. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/hygiene_config_path_and_survivors.md +0 -0
  112. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/issue-38-backfill-cte-bridge.md +0 -0
  113. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/issue-38-residual-source-extraction.md +0 -0
  114. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/issue-38-selects-from-island-lever.md +0 -0
  115. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/living_codebase_resync.md +0 -0
  116. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/mcp_server_self_healing.md +0 -0
  117. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/positional_insert_clone_blindspot.md +0 -0
  118. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_01.md +0 -0
  119. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_01_deployment_pypi.md +0 -0
  120. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_02.md +0 -0
  121. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_02_v0.3.0_core.md +0 -0
  122. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_03.md +0 -0
  123. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_04_column_lineage.md +0 -0
  124. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_04_column_lineage_fix.md +0 -0
  125. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_05_star_resolution.md +0 -0
  126. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_06_lineage_coverage.md +0 -0
  127. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_07_open_ecodes.md +0 -0
  128. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_07_perf_and_live_test.md +0 -0
  129. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_08_perf_upsert.md +0 -0
  130. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_09_lineage_coverage.md +0 -0
  131. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_10_anchor_tools.md +0 -0
  132. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_11_v1.0.2_bugfix.md +0 -0
  133. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_12_v1.1.0.md +0 -0
  134. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_13_v1.1.0_cluster_b.md +0 -0
  135. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_lineage_identity_and_session_context.md +0 -0
  136. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/sprint_postmortem_fixes.md +0 -0
  137. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/temp_table_namespacing.md +0 -0
  138. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/trust_layer.md +0 -0
  139. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/unfilled_table_impact.md +0 -0
  140. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1.1.0_cluster_b_provenance_trust.md +0 -0
  141. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1.1.0_live_graph_freshness.md +0 -0
  142. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1.1.1_batch_upsert_perf.md +0 -0
  143. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1.14.0_dialect_and_query_config_fixes.md +0 -0
  144. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1_1_2_bugfix.md +0 -0
  145. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1_1_3_union_cte_star.md +0 -0
  146. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1_2_0_read_proxy.md +0 -0
  147. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/v1_2_1_bugfix.md +0 -0
  148. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/plan/sprints/version-parity-and-restart.md +0 -0
  149. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/profile.html +0 -0
  150. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/pyrightconfig.json +0 -0
  151. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/scripts/collect_parse_errors.py +0 -0
  152. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/scripts/column_coverage_check.py +0 -0
  153. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/scripts/generate_cli_docs.sh +0 -0
  154. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/__main__.py +0 -0
  155. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/__init__.py +0 -0
  156. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/__init__.py +0 -0
  157. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/analyze.py +0 -0
  158. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/catalog.py +0 -0
  159. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/db.py +0 -0
  160. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/find.py +0 -0
  161. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/gain.py +0 -0
  162. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/git.py +0 -0
  163. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/index.py +0 -0
  164. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/install.py +0 -0
  165. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/mcp.py +0 -0
  166. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/reindex.py +0 -0
  167. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/report.py +0 -0
  168. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/uninstall.py +0 -0
  169. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/viz.py +0 -0
  170. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/commands/watch.py +0 -0
  171. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/coverage.py +0 -0
  172. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/cli/main.py +0 -0
  173. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/__init__.py +0 -0
  174. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/config.py +0 -0
  175. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/duckdb_backend.py +0 -0
  176. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/freshness.py +0 -0
  177. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/graph_db.py +0 -0
  178. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/jobs.py +0 -0
  179. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/noise_match.py +0 -0
  180. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/queries.cypher +0 -0
  181. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/queries.py +0 -0
  182. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/queries.sql +0 -0
  183. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/schema.cypher +0 -0
  184. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/core/schema.py +0 -0
  185. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/__init__.py +0 -0
  186. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/dbt_adapter.py +0 -0
  187. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/error_classify.py +0 -0
  188. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/git_delta.py +0 -0
  189. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/indexer.py +0 -0
  190. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/pool.py +0 -0
  191. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/walker.py +0 -0
  192. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/indexer/watcher.py +0 -0
  193. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/lineage/__init__.py +0 -0
  194. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/lineage/aggregator.py +0 -0
  195. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/lineage/schema_resolver.py +0 -0
  196. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/metrics/__init__.py +0 -0
  197. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/metrics/store.py +0 -0
  198. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/__init__.py +0 -0
  199. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/ansi_parser.py +0 -0
  200. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/base.py +0 -0
  201. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/bigquery_parser.py +0 -0
  202. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/dynamic_name.py +0 -0
  203. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/postgres_parser.py +0 -0
  204. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/parsers/tsql_parser.py +0 -0
  205. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/__init__.py +0 -0
  206. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/control.py +0 -0
  207. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/exceptions.py +0 -0
  208. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/models.py +0 -0
  209. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/noise_filter.py +0 -0
  210. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/read_client.py +0 -0
  211. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/selfheal.py +0 -0
  212. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/server.py +0 -0
  213. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/skill.py +0 -0
  214. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/tools.py +0 -0
  215. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/server/writer.py +0 -0
  216. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/utils/__init__.py +0 -0
  217. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/utils/hashing.py +0 -0
  218. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/utils/ignore.py +0 -0
  219. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/utils/logging.py +0 -0
  220. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/viz/__init__.py +0 -0
  221. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/viz/assets/force-graph.min.js +0 -0
  222. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/viz/assets/template.html +0 -0
  223. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/viz/data.py +0 -0
  224. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/viz/render.py +0 -0
  225. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/src/sqlcg/viz/tags.py +0 -0
  226. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/__init__.py +0 -0
  227. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/__init__.py +0 -0
  228. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/adversarial/200_join.sql +0 -0
  229. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/adversarial/500_union.sql +0 -0
  230. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/bench_indexer.py +0 -0
  231. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/conftest.py +0 -0
  232. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
  233. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
  234. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
  235. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
  236. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
  237. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
  238. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
  239. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
  240. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
  241. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
  242. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q01.sql +0 -0
  243. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q02.sql +0 -0
  244. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q03.sql +0 -0
  245. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q04.sql +0 -0
  246. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/benchmarks/tpch/q05.sql +0 -0
  247. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/conftest.py +0 -0
  248. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/__init__.py +0 -0
  249. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/conftest.py +0 -0
  250. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
  251. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_airbnb_e2e.py +0 -0
  252. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_cli_index.py +0 -0
  253. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_empty_impact_cli_e2e.py +0 -0
  254. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_git_hook_install.py +0 -0
  255. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_golden_lineage.py +0 -0
  256. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_mcp_lifecycle.py +0 -0
  257. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_mcp_tools.py +0 -0
  258. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
  259. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_pr_impact_cli_e2e.py +0 -0
  260. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_selfheal_e2e.py +0 -0
  261. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_star_resolution_e2e.py +0 -0
  262. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_viz_cli_e2e.py +0 -0
  263. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/e2e/test_watch.py +0 -0
  264. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
  265. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
  266. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
  267. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
  268. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
  269. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/raw_listings.sql +0 -0
  270. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
  271. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/src_hosts.sql +0 -0
  272. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/src_listings.sql +0 -0
  273. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/airbnb/src_reviews.sql +0 -0
  274. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/bigquery/.gitkeep +0 -0
  275. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/duckdb_parity/kuzu_reference.json +0 -0
  276. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/jaffle_shop/customers.sql +0 -0
  277. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/jaffle_shop/orders.sql +0 -0
  278. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
  279. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/snowflake/base_tables.sql +0 -0
  280. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/snowflake/reports.sql +0 -0
  281. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/snowflake/views.sql +0 -0
  282. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
  283. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
  284. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
  285. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/star_corpus/etl_star.sql +0 -0
  286. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/synthetic/base_tables.sql +0 -0
  287. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/synthetic/reports.sql +0 -0
  288. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/fixtures/synthetic/views.sql +0 -0
  289. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/__init__.py +0 -0
  290. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/snowflake/__init__.py +0 -0
  291. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/snowflake/test_insert_select.py +0 -0
  292. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/snowflake/test_qualify_bare_tables_command_guard_integration.py +0 -0
  293. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_T34_presentation_segregation.py +0 -0
  294. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_T35_external_consumers.py +0 -0
  295. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_analyze_case_fold.py +0 -0
  296. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_anchor_tools.py +0 -0
  297. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_backfill_impact_consistency.py +0 -0
  298. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_bare_column_cte_lineage.py +0 -0
  299. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_bulk_upsert.py +0 -0
  300. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_case_split_seed_regression.py +0 -0
  301. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_catalog_kind_upgrade.py +0 -0
  302. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_catalog_load_integration.py +0 -0
  303. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_cli_index_clear_before_rebuild.py +0 -0
  304. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_column_coverage_patterns.py +0 -0
  305. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_column_lineage_e2e.py +0 -0
  306. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_coverage_metrics_integration.py +0 -0
  307. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_cross_file_lineage.py +0 -0
  308. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_cte_key_namespacing_integration.py +0 -0
  309. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_cte_recall_guard.py +0 -0
  310. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_cte_schema_alias_guard.py +0 -0
  311. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_cte_source_node_invariant.py +0 -0
  312. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_dialect_auto_resolution.py +0 -0
  313. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_dialect_matrix.py +0 -0
  314. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_duckdb_parity.py +0 -0
  315. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
  316. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_empty_impact_blast_radius.py +0 -0
  317. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_empty_index_rollback_guard.py +0 -0
  318. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_freshness_mcp.py +0 -0
  319. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_gating_join_retrofit.py +0 -0
  320. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
  321. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_identity_counters_integration.py +0 -0
  322. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_impact_consumer_parity.py +0 -0
  323. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_incremental_reindex_parity.py +0 -0
  324. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_index_degraded_files_metric.py +0 -0
  325. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_index_filter_node_exclusion.py +0 -0
  326. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_indexer_batching.py +0 -0
  327. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_indexer_commits.py +0 -0
  328. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_indexer_to_graph.py +0 -0
  329. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_issue38_cte_insert_regression.py +0 -0
  330. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_join_col_resolution.py +0 -0
  331. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_key_normalization_chokepoint.py +0 -0
  332. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_live_anchors.py +0 -0
  333. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_mvcc_rebuild.py +0 -0
  334. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_non_table_create_coverage_no_regression.py +0 -0
  335. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_non_table_create_kind_in_graph.py +0 -0
  336. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_parse_diagnostics.py +0 -0
  337. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_phantom_non_table_create_node.py +0 -0
  338. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_pr1_confidence_reason.py +0 -0
  339. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_pr2_source_location.py +0 -0
  340. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_pr3_kind_tagging.py +0 -0
  341. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_pr_impact_integration.py +0 -0
  342. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_qualify_failed_persist.py +0 -0
  343. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_read_via_server.py +0 -0
  344. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_readonly_under_lock.py +0 -0
  345. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_reindex_via_server.py +0 -0
  346. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_repo_relative_cte_namespaces.py +0 -0
  347. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_resolvable_write_col_edges_integration.py +0 -0
  348. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_resync.py +0 -0
  349. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_selects_from_completeness.py +0 -0
  350. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_selects_from_cte_body_source.py +0 -0
  351. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_selects_from_subscope_source.py +0 -0
  352. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_single_writer_queue.py +0 -0
  353. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_skip_counts_integration.py +0 -0
  354. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_star_promote_temp_columns.py +0 -0
  355. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_star_resolution.py +0 -0
  356. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_temp_table_lineage.py +0 -0
  357. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_temp_table_namespacing.py +0 -0
  358. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_tool_version_stamp_integration.py +0 -0
  359. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
  360. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_usage_derived_catalog.py +0 -0
  361. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_use_schema_session_context_integration.py +0 -0
  362. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_user_surface_recall_guard.py +0 -0
  363. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_v141_surface_guards.py +0 -0
  364. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_v1_14_0_dialect_and_query_config_fixes.py +0 -0
  365. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_view_kind_in_graph.py +0 -0
  366. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_viz_data_build.py +0 -0
  367. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/integration/test_write_memory_ceiling.py +0 -0
  368. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/perf/__init__.py +0 -0
  369. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/perf/test_perf.py +0 -0
  370. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E10/__init__.py +0 -0
  371. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E11/__init__.py +0 -0
  372. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E12/__init__.py +0 -0
  373. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E12/e12_json_path.sql +0 -0
  374. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
  375. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E12/test_e12.py +0 -0
  376. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E13/__init__.py +0 -0
  377. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E14/__init__.py +0 -0
  378. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E15/__init__.py +0 -0
  379. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E16/__init__.py +0 -0
  380. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E16/e16_merge.sql +0 -0
  381. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
  382. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E16/test_e16.py +0 -0
  383. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E17/__init__.py +0 -0
  384. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E18/__init__.py +0 -0
  385. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E18/e18_decode.sql +0 -0
  386. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
  387. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E18/e18_nvl2.sql +0 -0
  388. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E18/test_e18.py +0 -0
  389. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E19/__init__.py +0 -0
  390. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E2/__init__.py +0 -0
  391. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
  392. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E2/e2_function_alias.sql +0 -0
  393. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
  394. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E2/test_e2.py +0 -0
  395. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E20/__init__.py +0 -0
  396. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E21/__init__.py +0 -0
  397. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
  398. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
  399. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E21/test_e21.py +0 -0
  400. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E22/__init__.py +0 -0
  401. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E23/__init__.py +0 -0
  402. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
  403. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
  404. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E23/test_e23.py +0 -0
  405. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E24/__init__.py +0 -0
  406. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E25/__init__.py +0 -0
  407. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E25/e25_cross_db.sql +0 -0
  408. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E25/e25_two_part.sql +0 -0
  409. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E25/test_e25.py +0 -0
  410. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E25/test_e25_full_id.py +0 -0
  411. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E26/__init__.py +0 -0
  412. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E27/__init__.py +0 -0
  413. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
  414. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E27/e27_udf.sql +0 -0
  415. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E27/test_e27.py +0 -0
  416. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E28/__init__.py +0 -0
  417. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E29/__init__.py +0 -0
  418. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E3/__init__.py +0 -0
  419. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E3/e3_alter_table.sql +0 -0
  420. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
  421. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
  422. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E3/test_e3.py +0 -0
  423. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E30/__init__.py +0 -0
  424. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E31/__init__.py +0 -0
  425. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E32/__init__.py +0 -0
  426. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E33/__init__.py +0 -0
  427. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E34/__init__.py +0 -0
  428. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E35/__init__.py +0 -0
  429. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E36/__init__.py +0 -0
  430. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
  431. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E36/e36_temp_table.sql +0 -0
  432. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E36/test_e36.py +0 -0
  433. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E36/test_e36_xfile.py +0 -0
  434. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E37/__init__.py +0 -0
  435. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E38/__init__.py +0 -0
  436. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E4/__init__.py +0 -0
  437. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
  438. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
  439. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
  440. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E4/e4_unpivot.sql +0 -0
  441. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E4/test_e4.py +0 -0
  442. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E5/__init__.py +0 -0
  443. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
  444. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
  445. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
  446. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E5/test_e5.py +0 -0
  447. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
  448. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E8/__init__.py +0 -0
  449. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
  450. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
  451. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E8/e8_uuid.sql +0 -0
  452. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E8/test_e8.py +0 -0
  453. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E9/__init__.py +0 -0
  454. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/__init__.py +0 -0
  455. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
  456. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
  457. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
  458. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
  459. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/__init__.py +0 -0
  460. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
  461. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
  462. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
  463. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
  464. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
  465. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/README.md +0 -0
  466. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/__init__.py +0 -0
  467. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/anchors/__init__.py +0 -0
  468. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_etl.sql +0 -0
  469. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
  470. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
  471. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/anchors/fixture_source.sql +0 -0
  472. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
  473. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
  474. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/conftest.py +0 -0
  475. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/snowflake/test_plan_review_gates.py +0 -0
  476. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/__init__.py +0 -0
  477. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/snowflake/__init__.py +0 -0
  478. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/snowflake/test_qualify_bare_tables_command_guard.py +0 -0
  479. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/snowflake/test_scripting_noise.py +0 -0
  480. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
  481. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_BugC_hook_upgrade.py +0 -0
  482. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_F2_install_skill.py +0 -0
  483. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_F2_skill_render.py +0 -0
  484. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_F2_uninstall_skill.py +0 -0
  485. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_T09_01_qualify_once.py +0 -0
  486. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_T09_02_ddl_skip.py +0 -0
  487. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
  488. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_T09_06_log_verbosity.py +0 -0
  489. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_T35_config_external_consumers.py +0 -0
  490. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_aggregator.py +0 -0
  491. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_aggregator_skip.py +0 -0
  492. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_analyze_case_fold.py +0 -0
  493. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_base_parser.py +0 -0
  494. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_branch_monitor.py +0 -0
  495. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_bulk_upsert_invariant.py +0 -0
  496. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_canonical_target_resolution.py +0 -0
  497. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_catalog_csv_parsing.py +0 -0
  498. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_catalog_missing_warning.py +0 -0
  499. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_classify_non_table_create_kind.py +0 -0
  500. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_cli.py +0 -0
  501. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_cli_doc_flag_staleness.py +0 -0
  502. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_cli_help.py +0 -0
  503. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_clone_positional_insert_blindspot.py +0 -0
  504. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_closure_depth.py +0 -0
  505. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_column_lineage_wiring.py +0 -0
  506. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_config.py +0 -0
  507. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_coverage_metrics.py +0 -0
  508. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_cte_key_namespacing.py +0 -0
  509. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_cte_source_gap_metric.py +0 -0
  510. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_data_models.py +0 -0
  511. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_db_info.py +0 -0
  512. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_db_info_coverage.py +0 -0
  513. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_db_path_isolation_fixture.py +0 -0
  514. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_doc_links.py +0 -0
  515. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_doc_markdown_link_existence.py +0 -0
  516. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_dominant_cause.py +0 -0
  517. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_duckdb_backend.py +0 -0
  518. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_duckdb_backend_shared.py +0 -0
  519. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_dynamic_name_resolution.py +0 -0
  520. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_e5_view_alias_resolution.py +0 -0
  521. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_e8_dual_emission.py +0 -0
  522. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_e8_temp_chain_key_mismatch.py +0 -0
  523. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_empty_propagation_unit.py +0 -0
  524. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_extract_select_output_columns.py +0 -0
  525. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_file_ignore_defaults.py +0 -0
  526. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_find_cmd.py +0 -0
  527. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_firstuser_findings.py +0 -0
  528. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_freshness_helper.py +0 -0
  529. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_gain_coverage.py +0 -0
  530. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_gain_ratio.py +0 -0
  531. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_gating_join_field_docstrings.py +0 -0
  532. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_git_delta.py +0 -0
  533. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_git_hooks.py +0 -0
  534. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_git_hooks_notify.py +0 -0
  535. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_graph_backend.py +0 -0
  536. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_graph_completeness_invariant.py +0 -0
  537. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_hard_kill_pool.py +0 -0
  538. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_has_column_precedence_upsert.py +0 -0
  539. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_hook_reindex_detach.py +0 -0
  540. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_hygiene_config_warning.py +0 -0
  541. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_identity_counters.py +0 -0
  542. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_include_working_tree.py +0 -0
  543. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_index_cmd.py +0 -0
  544. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_index_filter_config.py +0 -0
  545. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_index_flags.py +0 -0
  546. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_index_progress.py +0 -0
  547. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_index_summary_degraded_metric.py +0 -0
  548. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_indexer_progress.py +0 -0
  549. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_indexer_quality.py +0 -0
  550. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_install.py +0 -0
  551. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_install_message.py +0 -0
  552. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_issue_63_readonly_lock.py +0 -0
  553. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_jobs.py +0 -0
  554. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_join_col_resolve_marker.py +0 -0
  555. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_judgement.py +0 -0
  556. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_lineage_conversion.py +0 -0
  557. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_literal_column_skip.py +0 -0
  558. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_mcp_best_practices.py +0 -0
  559. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_mcp_control.py +0 -0
  560. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_mcp_stdio_smoke.py +0 -0
  561. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_merge_column_lineage.py +0 -0
  562. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_metrics.py +0 -0
  563. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_noise_filter.py +0 -0
  564. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_normalize_keys.py +0 -0
  565. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_parse_failed_classification.py +0 -0
  566. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_parse_file_dependency_filter.py +0 -0
  567. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_parse_quality.py +0 -0
  568. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_parser.py +0 -0
  569. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_phantom_non_table_create_source.py +0 -0
  570. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_pr07_observability.py +0 -0
  571. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_pr6_execute_immediate_unwrap.py +0 -0
  572. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_pr_impact_unit.py +0 -0
  573. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_qualify_failed_unit.py +0 -0
  574. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_queries_loader.py +0 -0
  575. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_read_client.py +0 -0
  576. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_repo_relative_cte_namespaces.py +0 -0
  577. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_resolvable_write_col_edges_unit.py +0 -0
  578. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_resolve_join_columns_sql.py +0 -0
  579. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
  580. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_schema_resolver.py +0 -0
  581. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_selects_from_completeness_unit.py +0 -0
  582. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_detector.py +0 -0
  583. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_pr1_messages.py +0 -0
  584. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_reexec.py +0 -0
  585. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_selfheal_watcher.py +0 -0
  586. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_server.py +0 -0
  587. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_skip_counts_persistence.py +0 -0
  588. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
  589. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_sprint_06_t04_t05.py +0 -0
  590. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_star_resolution_unit.py +0 -0
  591. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_star_schema_unit.py +0 -0
  592. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_submit_feedback.py +0 -0
  593. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_subprocess_isolate.py +0 -0
  594. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_t02_expression_name_extraction.py +0 -0
  595. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_t03_ddl_skip.py +0 -0
  596. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_temp_table_namespacing.py +0 -0
  597. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_timeout_cancel.py +0 -0
  598. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_tool_version_stamp.py +0 -0
  599. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_tools_hints.py +0 -0
  600. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_tools_warnings.py +0 -0
  601. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_transform_kind_classification.py +0 -0
  602. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_uninstall.py +0 -0
  603. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_unknown_sentinel_skip.py +0 -0
  604. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_unqualified_fallback.py +0 -0
  605. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_upsert_batch_invariant.py +0 -0
  606. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_use_schema_session_context.py +0 -0
  607. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_version_parity.py +0 -0
  608. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_view_classification.py +0 -0
  609. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_viz_config_schemas.py +0 -0
  610. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_viz_facets.py +0 -0
  611. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_viz_render_self_contained.py +0 -0
  612. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_walker.py +0 -0
  613. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_watcher.py +0 -0
  614. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/tests/unit/test_worker_error_classification.py +0 -0
  615. {sql_code_graph-1.35.3 → sql_code_graph-1.36.0}/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.35.3
3
+ Version: 1.36.0
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,518 @@
1
+ # Feature Plan: Generic variable-name resolution for dynamic table names
2
+
3
+ **Status:** REVIEWED (plan-reviewer gate 2026-06-14 — VERDICT REVIEWED, no blockers. Both load-bearing
4
+ checks PROVEN empirically: (1) fold-core catalog rule correct — `to_table('DHB.KOSTEN')`→cat='' (wildcard
5
+ opaque catalog), `to_table('PRD_DB.DHB.KOSTEN')`→cat='PRD_DB' (KEEP literal catalog), bare `KOSTEN`→give-up;
6
+ (2) flow-gate structurally enforced — `ALTER WAREHOUSE`/`CALL` parse to `exp.Command`, never `exp.Table`, so
7
+ the demand-driven resolver auto-excludes them. Forks: F1 accept (env-param + keep-literal-catalog + PR-3
8
+ zero-collision assert), F2 absorb PR-A scaffolding into PR-2, F3 chain-depth=1, F4 two pre-scan maps.
9
+ **3 corrections to FOLD AT PR-2:** (a) master is v1.35.1 → next MINOR = **v1.36.0** (not 1.35.0); (b) sink
10
+ predicate must match `IDENTIFIER` CASE-INSENSITIVELY (`table.this.name == 'IDENTIFIER'` is UPPERCASE — else
11
+ matches nothing and PR-2 tests silently pass-as-noop); (c) PR-1 bind-param→OPAQUE fixture asserts via
12
+ `exp.Placeholder`. Anchors verified on master: pre-scan snowflake_parser.py:355-364, wiring :428,
13
+ EXEC-IMMEDIATE var :640/655 (file now 976 lines, re-grep at impl). READY — PR-1 → PR-2 → PR-3.)
14
+ **Source study:** `git show research/generic-var-name-resolution:plan/research/generic_variable_name_resolution.md` (commit `60635c7`, VERDICT **HOLDS**)
15
+ **Foundation (dropped):** [`fix/identifier-var-indirection`](src/sqlcg/parsers/snowflake_parser.py) commit `0f655d0` — handles the LITERAL case only; this feature extends "is the RHS a literal?" → "FOLD the RHS".
16
+ **Branch:** `plan/generic-var-name-resolution`
17
+ **Target version:** **MINOR** — new lineage capability (no break). Master is **v1.34.3** at planning time (see [Version note](#version-note)); plan targets **v1.35.0**, reconcile the exact number at merge.
18
+
19
+ ---
20
+
21
+ ## Summary
22
+
23
+ Generic, bounded constant-propagation of string-valued Snowflake session variables to
24
+ resolve dynamic table names (`IDENTIFIER($var)` in DML position), recovering ~187
25
+ currently-dropped DML-context references across ~136 files at `schema.table` grain.
26
+ A dialect-agnostic fold core does the work; only a one-line Snowflake sink predicate is
27
+ dialect-coupled.
28
+
29
+ ---
30
+
31
+ ## Version note
32
+
33
+ The dispatch brief says "master ~v1.35.x / v1.35.0+". The actual current master at
34
+ planning time is **v1.34.3** ([`pyproject.toml`](pyproject.toml), confirmed via
35
+ `git show master:pyproject.toml`). The worktree this plan was authored alongside carried
36
+ unrelated in-flight work bumped to 1.34.4, which is **not** master. Treat the version as
37
+ **the next MINOR after whatever master is at merge** — currently `v1.35.0`. Reconcile at
38
+ merge time, as the project's release notes routinely do (e.g. the v10/1.33.0 collision).
39
+
40
+ ---
41
+
42
+ ## Scope
43
+
44
+ ### In Scope
45
+
46
+ - A dialect-agnostic `resolve_dynamic_name(rhs_expr, var_env, *, chain_depth=1)` that
47
+ partial-constant-folds a string-expression AST: string literals, `||`/`CONCAT`,
48
+ 1-hop `$var` chains; marks runtime funcs / scalar subqueries / bind params OPAQUE;
49
+ interprets the fold as `[catalog.]db.name` (name-last, dot-split); keeps the
50
+ statically-determined trailing components; wildcards a leading OPAQUE catalog but
51
+ keeps a static literal catalog; gives up honestly otherwise.
52
+ - A Snowflake-only sink predicate `is_dynamic_name_sink(table)` recognising
53
+ `IDENTIFIER($var)` (an `exp.Anonymous` named `identifier` wrapping an
54
+ `exp.Parameter`) **in a table position** (FROM/JOIN/INTO/UPDATE/MERGE/USING).
55
+ - Landing PR-A's scaffolding (the literal-only `_resolve_identifier_tables` + the
56
+ `exp.Set` / `exp.PropertyEQ` var pre-scan) and rewiring it to call the fold core;
57
+ extending the pre-scan to store the **RHS AST**, not just literal strings.
58
+ - A perf-guard counter so the fold stays once-per-statement (no qualify/expand/sg_lineage).
59
+ - Live-DWH `gain --json` before/after acceptance with the no-literal-catalog-collision
60
+ assertion.
61
+
62
+ ### Non-Goals
63
+
64
+ - **Other-dialect dynamic-SQL sinks** (T-SQL `sp_executesql` / `EXEC(@sql)`, Postgres
65
+ `format()`+`EXECUTE`, Spark string-built names). The core is built generic so a later
66
+ dialect adds only its own `is_dynamic_name_sink`; **no other predicate ships here.**
67
+ - The 40 scalar-subquery delta vars that are genuinely runtime-dynamic (no static tail)
68
+ stay unresolved — they hit the honest give-up.
69
+ - A general dataflow interpreter / fixpoint var resolution / chain depth > 1
70
+ (corpus max is 1; see [The bound](#the-bound-flow-gate--enforced-limits)).
71
+ - `ALTER WAREHOUSE IDENTIFIER()` (`exp.Command`), `CALL …($v)` proc-args, scalar/WHERE
72
+ vars — these are excluded **structurally** (the walk visits `exp.Table` sinks only);
73
+ preserve that auto-exclusion, do not add a name blocklist.
74
+ - Parse-time schema feeding into `exp.expand()`/`qualify()` (forbidden by CLAUDE.md).
75
+
76
+ ---
77
+
78
+ ## Design
79
+
80
+ ### Fold-core API (dialect-agnostic)
81
+
82
+ Suggested home: a new module [`parsers/dynamic_name.py`](src/sqlcg/parsers/) (the study's
83
+ preference; keeps `base.py` lean and the seam obvious). Pure function, no parser state.
84
+
85
+ ```python
86
+ def resolve_dynamic_name(
87
+ rhs_expr: exp.Expression,
88
+ var_env: dict[str, exp.Expression], # lowercased var name → its RHS AST
89
+ *,
90
+ chain_depth: int = 1,
91
+ ) -> exp.Table | None:
92
+ """Bounded partial constant-fold of a string-expression AST into a TableRef.
93
+
94
+ Returns an exp.Table for the resolvable trailing identifier components, or None
95
+ (give up honestly — caller leaves the sink dropped, today's behaviour).
96
+ """
97
+ ```
98
+
99
+ #### Fold rules (the OPAQUE/LIT classification)
100
+
101
+ Fold the RHS into an ordered list of parts, each `LIT(s)` or `OPAQUE`:
102
+
103
+ - Descend through `exp.Subquery` / `exp.Select` **single-projection only**,
104
+ `exp.Paren`, `exp.DPipe`, `exp.Concat`.
105
+ - `exp.Literal(is_string=True)` → `LIT(s)`.
106
+ - `exp.Parameter`→`exp.Var` (`$other_var`): look it up in `var_env` **once** (chain
107
+ depth 1); fold that RHS one level; if it folds to a leading constant prefix use it,
108
+ else `OPAQUE`. Do **not** re-follow `$vars` discovered inside that value
109
+ (chain-depth bound).
110
+ - Everything else — runtime funcs (`exp.CurrentDatabase`, `current_warehouse`,
111
+ `current_schema`), `exp.SplitPart`, `exp.Substring`, a scalar subquery that is not a
112
+ pure single-projection of folds, a bind param (`?`, `:x`), an unresolved/undefined var
113
+ → `OPAQUE`.
114
+
115
+ #### Name-extraction rules (the keep/wildcard/give-up policy)
116
+
117
+ A SQL object id is `[catalog.]db.name`, dot-separated, **name-last**. From the folded
118
+ parts:
119
+
120
+ 1. Take the **rightmost run of `LIT` parts** (the static suffix), concatenate, and
121
+ `to_table(suffix, dialect=...)` it.
122
+ 2. **KEEP the statically-determined trailing components.** The tail is normally
123
+ `.db.name` (= `schema.table`); the leading catalog position is OPAQUE.
124
+ 3. **Wildcard / drop a leading OPAQUE catalog** → emit `db.name` with empty catalog.
125
+ This is the existing catalog-less identity (`to_table('DHB.KOSTEN')` → cat='' db=DHB
126
+ name=KOSTEN, **probed live**), so the resolved node **merges** with DDL / plain-SQL
127
+ refs to the same table.
128
+ 4. **KEEP a static literal catalog when present.** If the fold yields a fully-literal
129
+ `catalog.schema.table` (no OPAQUE in the leading position), do NOT collapse it —
130
+ `to_table('PRD_DB.DHB.KOSTEN')` → cat=PRD_DB (**probed live**). This is the cross-DB
131
+ safety valve ([fork F1](#design-forks-needing-a-maintainer-decision)).
132
+ 5. **Give up honestly** (return `None`) when: the result is all-OPAQUE; the static tail
133
+ has no dot (a bare name like `'TMP_TABLE_DATASET'`); or the tail lacks a resolvable
134
+ `db.name`. Never emit a guessed/partial edge — silence over a wrong edge.
135
+
136
+ #### Worked folds (from the study; the PR-1 fixture spec, behaviourally)
137
+
138
+ | RHS | Parts | Result |
139
+ |---|---|---|
140
+ | `'DL_' \|\| split_part(current_database(),'_',2) \|\| '.DHB.KOSTEN'` | `LIT('DL_'),OPAQUE,LIT('.DHB.KOSTEN')` | `DHB.KOSTEN` (cat='') |
141
+ | `(SELECT 'DL_' \|\| split_part(...) \|\| '.DHB.KOSTEN')` | same (descend Subquery) | `DHB.KOSTEN` (cat='') |
142
+ | `$ODS_DB \|\| '.ods.ig_stibat'` where `ODS_DB`→OPAQUE | `OPAQUE,LIT('.ods.ig_stibat')` | `ods.ig_stibat` (cat='') |
143
+ | `'TMP_TABLE_DATASET'` | `LIT('TMP_TABLE_DATASET')` | **give up** (bare name) |
144
+ | all-runtime, no literal tail | `OPAQUE…` | **give up** |
145
+ | `'PRD_DB.DHB.KOSTEN'` (literal catalog) | `LIT(...)` | `PRD_DB.DHB.KOSTEN` (cat KEPT) |
146
+
147
+ ### Sink predicate (the only dialect-specific piece)
148
+
149
+ ```python
150
+ # SnowflakeParser
151
+ @staticmethod
152
+ def is_dynamic_name_sink(table: exp.Table) -> exp.Expression | None:
153
+ """Return the $var Parameter to resolve if `table` is IDENTIFIER($var) in a
154
+ table position, else None. Snowflake's IDENTIFIER() is the dynamic-name sink:
155
+ exp.Table.this == exp.Anonymous(name='identifier') wrapping an exp.Parameter."""
156
+ ```
157
+
158
+ - Returns the `exp.Parameter` (the `$var`) when `table.this` is an `exp.Anonymous` named
159
+ `identifier` wrapping a Parameter; else `None`.
160
+ - Base/ANSI parser: no override → no generic sink ships (Non-Goal).
161
+ - **Why this auto-excludes the 91 `ALTER WAREHOUSE` cases + proc-args + WHERE vars:**
162
+ those never parse to an `exp.Table` (`ALTER WAREHOUSE IDENTIFIER()` → `exp.Command`;
163
+ `CALL …($v)` arg is a Parameter not a Table). The resolver only walks `exp.Table`
164
+ sinks, so they are never even asked. This structural gate is the bound — **do not
165
+ replace it with a name blocklist.**
166
+
167
+ ### Var pre-scan (RHS-AST, extends PR-A)
168
+
169
+ PR-A's pre-scan (on its branch; on **current master** lines **355-364** cover only
170
+ `PropertyEQ`) stores `var name → literal string`. Extend it to store
171
+ `var name → RHS AST` so the fold can run on demand:
172
+
173
+ - `exp.PropertyEQ` (`var := <expr>`) — store `stmt.expression` (the AST), not just when
174
+ it is an `exp.Literal`.
175
+ - `exp.Set` ▸ `exp.SetItem(kind=VARIABLE)` ▸ `exp.EQ(Column, <expr>)` — store
176
+ `eq.expression` (the AST). This is the **session-variable** form the DWH actually uses;
177
+ PR-A added the `exp.Set` branch on its branch but stored only literals.
178
+ - **Last-write-wins** in file source order (study §3.4: only reassignment-looking case is
179
+ the UPDATE-column trap, which is `exp.Update`, structurally distinct — never captured).
180
+ - Keep the existing literal-string map used by the EXECUTE IMMEDIATE path
181
+ ([`snowflake_parser.py`](src/sqlcg/parsers/snowflake_parser.py) lines **639-651**,
182
+ `_recover_execute_immediate` / `_EXEC_IMMEDIATE_VAR_RE`, and `_inner_stmts_from_command`
183
+ at line **655**) **untouched** — that path needs the resolved string, not the AST; do
184
+ not regress it. Either keep two maps, or derive the literal map from the AST map for the
185
+ literal-only entries. See [fork F4](#design-forks-needing-a-maintainer-decision).
186
+
187
+ ### Wiring
188
+
189
+ Rewire `_resolve_identifier_tables` (the literal-only method on PR-A's branch) to:
190
+ 1. `for table in stmt.find_all(exp.Table)`,
191
+ 2. `param = self.is_dynamic_name_sink(table)`; if `None`, continue,
192
+ 3. `new = resolve_dynamic_name(var_env[param.name.lower()], var_env)`; if `None`,
193
+ continue (leave dropped),
194
+ 4. preserve the FROM/INSERT `alias`, `table.replace(new)`.
195
+
196
+ Call it **before** `_qualify_bare_tables` (as PR-A does, current master ~line **427**) so
197
+ a catalog-less resolved tail still inherits the active `USE SCHEMA` prefix.
198
+
199
+ ### Data Models / API surface
200
+
201
+ - No graph-schema change. Resolved nodes are ordinary `SqlTable` `db.name` refs that
202
+ merge with existing identities.
203
+ - No CLI change. No new MCP tool. `gain` already reports the coverage metrics used in PR-3.
204
+
205
+ ### Dependencies
206
+
207
+ - sqlglot AST nodes only (`exp.DPipe`, `exp.Concat`, `exp.Subquery`, `exp.Literal`,
208
+ `exp.Parameter`, `exp.Var`, `exp.Anonymous`, `exp.Set`, `exp.SetItem`, `exp.EQ`,
209
+ `exp.PropertyEQ`, `exp.CurrentDatabase`, `exp.SplitPart`, `exp.Substring`) — all
210
+ confirmed present in the study §3.2.
211
+ - PR-A scaffolding on `fix/identifier-var-indirection` (NOT yet on master — see
212
+ [fork F2](#design-forks-needing-a-maintainer-decision)).
213
+
214
+ ---
215
+
216
+ ## Implementation Steps
217
+
218
+ ### PR-1 — Generic fold core + exhaustive unit fixtures (no wiring)
219
+
220
+ **Scope:** Pure `resolve_dynamic_name` (fold + extract + opaque-wildcard + give-up).
221
+ No parser change, no sink predicate — falsifiable in isolation.
222
+
223
+ **Files:**
224
+ - `src/sqlcg/parsers/dynamic_name.py` (new) — the core.
225
+ - `tests/unit/test_dynamic_name_resolution.py` (new) — fixtures below.
226
+
227
+ **Anchor (re-confirmed against current master, v1.34.3):** none in the hot path; this is
228
+ a new module. The empty-id drop it works around is in
229
+ [`base.py`](src/sqlcg/parsers/base.py) (`full_id` lines ~95-99 + the reject-empty rule)
230
+ — unchanged by this PR.
231
+
232
+ **Acceptance (each a behaviour, not a code):**
233
+ - direct-concat fold → `DHB.KOSTEN`, catalog empty.
234
+ - `(SELECT …)`-wrapped concat → same `DHB.KOSTEN` (descends Subquery/Select).
235
+ - 1-hop `$var` chain (`$ODS_DB || '.ods.ig_stibat'`, `ODS_DB`→OPAQUE) → `ods.ig_stibat`.
236
+ - all-opaque RHS (only `current_database()`/`split_part`) → returns `None`.
237
+ - bare-name give-up (`'TMP_TABLE_DATASET'`, no dot) → returns `None`.
238
+ - dynamic-schema give-up (OPAQUE in the schema/name position, tail has no static
239
+ `db.name`) → returns `None`.
240
+ - literal-catalog-keep (`'PRD_DB.DHB.KOSTEN'`) → catalog `PRD_DB` retained, NOT collapsed.
241
+ - chain-depth bound: a `$a` whose value references `$b` resolves only `$a`'s one hop;
242
+ `$b` is not re-followed (assert the depth-2 ref stays OPAQUE).
243
+
244
+ **Version:** none on its own (lands with the trio). **Metric impact:** none (no wiring).
245
+
246
+ **Frozen-perf note:** new module, not on the parser hot path; the four frozen suites
247
+ ([`test_T09_01_qualify_once.py`](tests/unit/test_T09_01_qualify_once.py),
248
+ [`test_bulk_upsert_invariant.py`](tests/unit/test_bulk_upsert_invariant.py),
249
+ [`test_upsert_batch_invariant.py`](tests/unit/test_upsert_batch_invariant.py),
250
+ [`test_perf_scaling_guard.py`](tests/unit/test_perf_scaling_guard.py)) are untouched and
251
+ must stay green.
252
+
253
+ ### PR-2 — Snowflake sink predicate + wiring + RHS-AST pre-scan + perf counter
254
+
255
+ **Scope:** Land PR-A's scaffolding, add `is_dynamic_name_sink`, extend the pre-scan to
256
+ store RHS ASTs, rewire `_resolve_identifier_tables` to call the PR-1 core, add a
257
+ perf-guard counter.
258
+
259
+ **Files:**
260
+ - `src/sqlcg/parsers/snowflake_parser.py` — pre-scan (master lines **355-364**, currently
261
+ `PropertyEQ`-only; add the `exp.Set` branch and switch both to store ASTs);
262
+ `is_dynamic_name_sink` (new static method); `_resolve_identifier_tables` (port from
263
+ PR-A branch + rewire to the core); wiring call before `_qualify_bare_tables`
264
+ (master ~line **427**).
265
+ - `tests/unit/test_perf_scaling_guard.py` — add a `resolve_dynamic_name` op counter to
266
+ the `count_hot_ops()` context (the file's established counter pattern; see the
267
+ `sg_lineage`/`build_scope`/`traverse_scope` axes ~lines **226-253**); assert it stays
268
+ flat when column count doubles AND fires once per `IDENTIFIER` sink, not per column.
269
+ - `tests/unit/test_identifier_var_indirection.py` + the integration test
270
+ (`tests/integration/snowflake/test_identifier_var_indirection_integration.py`) — port
271
+ from PR-A branch, extend with fold cases.
272
+
273
+ **Anchors (re-confirmed against current master, v1.34.3):**
274
+ - Pre-scan: [`snowflake_parser.py`](src/sqlcg/parsers/snowflake_parser.py) lines
275
+ **355-364** (`var_literals` dict, `PropertyEQ` branch only). The `exp.Set` branch and
276
+ `_resolve_identifier_tables` method do **NOT** exist on master — they are PR-A-branch
277
+ only (confirmed: `git show master:… | grep _resolve_identifier_tables` → empty).
278
+ - Wiring point: before `_qualify_bare_tables(stmt, current_schema)`, master line **427**.
279
+ - EXECUTE IMMEDIATE var path to NOT regress: lines **639-651**
280
+ (`_recover_execute_immediate`, `_EXEC_IMMEDIATE_VAR_RE`) and `_inner_stmts_from_command`
281
+ line **655** — these consume the literal-string map; the AST-map change must keep them
282
+ working.
283
+
284
+ **Acceptance:**
285
+ - `SET v='DL_'||split_part(current_database(),'_',2)||'.DHB.KOSTEN'; FROM identifier($v)`
286
+ → a `DHB.KOSTEN` source edge with non-empty `full_id` (no empty-id leak).
287
+ - INSERT INTO `identifier($v)` target resolves the write target.
288
+ - JOIN `identifier($v)` resolves.
289
+ - MERGE INTO `identifier($v)` resolves.
290
+ - `ALTER WAREHOUSE IDENTIFIER($w)` produces **no** resolved table (stays `exp.Command`).
291
+ - `CALL MA.MERGE_PREDICTION($SRC_TABLE_NAME, …)` arg produces **no** resolved table.
292
+ - 1-hop chain (`$ODS_DB || '.ods.ig_stibat'`) resolves end-to-end through the parser.
293
+ - A file with no `IDENTIFIER` sink: edge output unchanged (no-op path).
294
+
295
+ **Version:** ships the capability → **v1.35.0** (MINOR). Bump
296
+ [`pyproject.toml`](pyproject.toml) + [`src/sqlcg/__init__.py`](src/sqlcg/__init__.py) +
297
+ `uv lock` in the feature branch per CLAUDE.md release steps.
298
+
299
+ **Metric impact:** wiring active; real gain measured in PR-3.
300
+
301
+ **Frozen-perf note:** the fold is once-per-statement on demand — no qualify / build_scope
302
+ / exp.expand / sg_lineage, no per-column op. All four frozen suites must stay green; the
303
+ new counter pins the fold's once-per-statement behaviour (a **behavioural** assertion, per
304
+ CLAUDE.md guidance, not a volume count that hides in a too-simple fixture).
305
+
306
+ **Grep-confirmed call sites (required before PR opens):**
307
+ - `resolve_dynamic_name` called from `_resolve_identifier_tables`.
308
+ - `is_dynamic_name_sink` called from `_resolve_identifier_tables`.
309
+ - `_resolve_identifier_tables` called from the file-level statement loop (master ~line
310
+ 427 area), before `_qualify_bare_tables`.
311
+ - the RHS-AST pre-scan map read by both `_resolve_identifier_tables` and (literal subset)
312
+ the EXECUTE IMMEDIATE path.
313
+ No method ships defined-but-uncalled.
314
+
315
+ ### PR-3 — Live-DWH acceptance + `gain --json` before/after
316
+
317
+ **Scope:** Index the real DWH (`/home/ignwrad/Projects/dwh`) on master and on the feature
318
+ branch; record `sqlcg gain --json` before/after; assert the gain and no regression.
319
+
320
+ **Files:**
321
+ - `plan/metrics/generic_var_name_before_v1.34.3.json` (or the actual master version).
322
+ - `plan/metrics/generic_var_name_after_v1.35.0.json`.
323
+ - `plan/metrics/generic_var_name_gain_context.md` (before/after narrative + the
324
+ catalog-wildcard assumption documented + DWH timing).
325
+
326
+ **Acceptance (run by the planner during compliance, or the DWH tester):**
327
+ - **~136 files gain edges** that previously had none from their `IDENTIFIER($var)` sink
328
+ (count files whose primary FROM/INSERT target newly resolves).
329
+ - **No regression:** `good_edges_strict` and `good_edges_scoped` must **not drop** vs the
330
+ before baseline.
331
+ - **No-literal-catalog-collision assertion** (the study's decisive safety check): assert
332
+ that no two **distinct literal-catalog** tables were merged into one node by the
333
+ wildcard. The wildcard only fires when the catalog position is OPAQUE; a fully-literal
334
+ `catalog.schema.table` keeps its catalog (PR-1 rule 4), so distinct literal catalogs
335
+ cannot collapse. Verify the corpus still has **zero** fully-literal
336
+ `catalog.schema.table` references that would collide (study §3.4 found zero) — record
337
+ the grep result in the context doc.
338
+
339
+ **Version:** none (metrics/docs only); merges with the trio under v1.35.0.
340
+
341
+ **Metric impact:** the headline — ~187 DML refs / ~136 files recovered; record the exact
342
+ delta.
343
+
344
+ **Frozen-perf note:** confirm DWH index time stays within the project's measured baseline
345
+ (~210-256s, CLAUDE.md memory) — the fold adds only an O(nodes-in-RHS) walk per
346
+ `IDENTIFIER` sink. Record the timing in the context doc.
347
+
348
+ ---
349
+
350
+ ## Test Strategy
351
+
352
+ - **Unit (PR-1):** the eight fold/extract behaviours above, each named
353
+ `test_<behaviour>_<scenario>_<expected>`, docstring linking this plan. Pure-function,
354
+ no parser, no graph.
355
+ - **Unit (PR-2):** sink-predicate positive (FROM/JOIN/INSERT/MERGE) and negative
356
+ (ALTER WAREHOUSE → Command, CALL-arg) cases; end-to-end parse → edge assertions on
357
+ observable `full_id` pairs (the PR-A test pattern: assert edge `src.full_id` /
358
+ `dst.full_id`, and that no empty-id endpoint leaks).
359
+ - **Perf (PR-2):** extend `count_hot_ops()` with a `resolve_dynamic_name` counter; assert
360
+ it is flat under doubled columns and fires once per sink (behavioural, not volume).
361
+ - **Integration (PR-2):** real in-memory DuckDB, a Snowflake file with a folded
362
+ `IDENTIFIER($v)` source and target, assert the SELECTS_FROM + column-lineage edges land
363
+ with the resolved `db.name`.
364
+ - **Live acceptance (PR-3):** `gain --json` before/after on the DWH; the three PR-3
365
+ acceptance assertions above.
366
+
367
+ > Tests describe the behaviour they verify. The developer names them
368
+ > `test_<unit>_<scenario>_<expected>` and links this plan in the docstring. No opaque
369
+ > case codes are seeded here.
370
+
371
+ ---
372
+
373
+ ## Acceptance Criteria
374
+
375
+ - [ ] `resolve_dynamic_name` folds literal/concat/`(SELECT …)`/1-hop-chain to the correct
376
+ catalog-empty `db.name`; gives up (returns `None`) on all-opaque, bare-name, and
377
+ dynamic-schema inputs; keeps a static literal catalog. (PR-1 unit tests pass.)
378
+ - [ ] `is_dynamic_name_sink` returns the `$var` Parameter for `IDENTIFIER($v)` in a table
379
+ position and `None` otherwise; `ALTER WAREHOUSE` and `CALL`-arg never resolve.
380
+ (PR-2 unit tests pass.)
381
+ - [ ] `FROM/INSERT/JOIN/MERGE identifier($v)` with a folded RHS emits a real edge whose
382
+ endpoints have non-empty `full_id`; no empty-id endpoint leaks. (PR-2 tests pass.)
383
+ - [ ] The four frozen perf suites stay green; the new `resolve_dynamic_name` counter stays
384
+ flat when columns double and fires once per sink. (PR-2.)
385
+ - [ ] EXECUTE IMMEDIATE literal-var path (lines 639-651 / `_inner_stmts_from_command`) is
386
+ not regressed by the RHS-AST pre-scan change. (PR-2 — existing tests stay green.)
387
+ - [ ] Live DWH: ~136 files gain edges; `good_edges_strict` / `good_edges_scoped` do not
388
+ drop; no distinct-literal-catalog collision (grep confirms zero literal
389
+ `catalog.schema.table` refs). (PR-3 — metrics recorded.)
390
+
391
+ ---
392
+
393
+ ## The bound (flow-gate + enforced limits)
394
+
395
+ This is **not** "resolve all variables". Four enforced gates (study §2.3):
396
+
397
+ 1. **Flow gate — string var → table-position sink only.** The fold fires only when a var
398
+ is dereferenced in an `exp.Table` sink via `is_dynamic_name_sink`. Demand-driven: start
399
+ at the sink, resolve backwards; `SET` definitions are never enumerated.
400
+ 2. **Fold-depth bound.** Structural recursion over one RHS AST, no fixpoint, no SQL
401
+ execution. O(nodes-in-RHS).
402
+ 3. **Chain-depth bound = 1** (default, configurable param). One lookup hop into `var_env`;
403
+ the looked-up value's own `$vars` are not re-followed. Corpus max is 1.
404
+ 4. **Give-up-honestly.** All-opaque / no `db.name` tail / unbound var → leave the sink
405
+ dropped (today's behaviour). Silence over a wrong edge.
406
+
407
+ Gates (1)+(4) are the structural answer to the maintainer's "resolve all variables" worry:
408
+ we resolve the **one** name a table sink demands, fold what is constant, and stop.
409
+
410
+ ---
411
+
412
+ ## Risks and Mitigations
413
+
414
+ | Risk | Mitigation |
415
+ |---|---|
416
+ | Catalog-wildcard collapse merges distinct cross-DB tables | KEEP a static literal catalog (PR-1 rule 4); the wildcard only fires on an OPAQUE catalog. PR-3 asserts zero literal `catalog.schema.table` refs to collide with (study §3.4 = zero). Document the env-parameterisation assumption (fork F1). |
417
+ | RHS-AST pre-scan regresses the EXECUTE IMMEDIATE literal path | Keep the literal-string map intact (or derive it); existing tests for lines 639-651 stay green (acceptance criterion). |
418
+ | Over-reach (a var resolving where it should not) | Structural flow gate — non-`exp.Table` sinks never reach the resolver; verified for ALTER WAREHOUSE / CALL / WHERE. Do not add a name blocklist that could rot. |
419
+ | Fold starts scaling with column/edge count | New perf-guard counter pins once-per-statement / once-per-sink, behaviourally. |
420
+ | Branch-scoped reassigned vars | Last-write-wins in source order; none in corpus (study §3.4). Acceptable (better than dropping). |
421
+
422
+ ---
423
+
424
+ ## Design forks needing a maintainer decision
425
+
426
+ ### F1 — Catalog-wildcard env-parameterisation ASSUMPTION (document, do not block)
427
+
428
+ Collapsing every DB's `DHB.KOSTEN` into one catalog-less node is **correct** in a
429
+ single-warehouse, env-parameterised setup (DEV/TST/ACC/PRD are the *same* logical table)
430
+ and **safe here** because the corpus has zero fully-literal `catalog.schema.table`
431
+ references to collide with (study §3.4). It would be **wrong** in a true cross-DB topology
432
+ where `PROD_DB.DHB.KOSTEN` and `STAGING_DB.DHB.KOSTEN` are distinct *and* referenced
433
+ literally. **Decision needed:** accept the env-parameterisation assumption (recommended —
434
+ it matches the existing catalog-less identity behaviour, and PR-1 rule 4 already keeps a
435
+ *static* literal catalog), and document it in the PR-3 context doc + the postmortem. No
436
+ code gate beyond rule 4 is proposed; flag if the maintainer wants a hard config switch.
437
+
438
+ ### F2 — PR-A landing strategy (genuine fork — pick one)
439
+
440
+ PR-A (`fix/identifier-var-indirection`, the literal-only scaffolding) is **NOT merged to
441
+ master** and its referenced plan (`sprint_snowflake_lineage_patterns.md`) does not exist on
442
+ master. Two options:
443
+
444
+ - **Option A (recommended):** absorb PR-A's scaffolding directly into PR-2 of this feature
445
+ (port `_resolve_identifier_tables` + the `exp.Set` pre-scan branch + the two test files),
446
+ rewiring to the fold core in the same PR. The literal case becomes a special case of the
447
+ fold (a single `LIT` part), so PR-A as a standalone literal-only PR adds little value and
448
+ would resolve **zero** real DWH cases (study §1).
449
+ - **Option B:** merge PR-A first as-is (literal-only), then this feature extends it. Costs
450
+ an extra round-trip for a PR the study says resolves zero real corpus cases on its own.
451
+
452
+ **Recommendation: Option A** — fold the literal case into PR-2. Maintainer to confirm.
453
+
454
+ ### F3 — Chain depth > 1
455
+
456
+ Planner found **no** chain deeper than 1 hop in the corpus (study §3.4 re-confirmed). The
457
+ `chain_depth` param defaults to 1 and is the enforced bound. No fork unless the maintainer
458
+ wants depth > 1 pre-emptively — **not recommended** (would only fold more OPAQUE here).
459
+
460
+ ### F4 — Pre-scan map shape (minor)
461
+
462
+ Keep two maps (literal-string for EXECUTE IMMEDIATE + RHS-AST for the fold), or one AST
463
+ map with a literal-string accessor. Recommend **two maps** for clarity / zero regression
464
+ risk to the EXECUTE IMMEDIATE path. Plan-reviewer to confirm the minimal-risk shape.
465
+
466
+ ---
467
+
468
+ ### Deviations
469
+
470
+ #### Deviation 1: PR-1 was not on master at PR-2 implementation time
471
+ - **Reason**: The PR-2 dispatch brief stated "PR-1 (the fold core) is ALREADY MERGED
472
+ to master" and that `src/sqlcg/parsers/dynamic_name.py` exists on master. On
473
+ inspection master (v1.35.1, commit `a530c6b`) did **not** contain
474
+ `dynamic_name.py`; PR-1 lives unmerged on branch `feat/generic-var-fold-core`
475
+ (commit `34d68c4`), cleanly stacked on master with no open PR.
476
+ - **Change**: The PR-2 branch `feat/generic-var-sink-rewire` was created off
477
+ `feat/generic-var-fold-core` (PR-1) rather than off master, so the fold core is
478
+ present. PR-1's commit was left byte-for-byte unchanged; all PR-2 work sits in
479
+ commits on top. PR-2 must therefore merge AFTER (or together with) PR-1.
480
+ - **Impact**: No code-scope change. The PR diff against master includes PR-1's
481
+ `dynamic_name.py` + its 12 unit fixtures as the base commit. Reviewer/merger
482
+ should land PR-1 first or merge this branch as the combined PR-1+PR-2 unit.
483
+ - **Date**: 2026-06-14
484
+
485
+ #### Deviation 2: `exp.Set` statements are NOT suppressed
486
+ - **Reason**: The plan's var-pre-scan section described capturing `exp.Set` RHS ASTs;
487
+ an initial implementation also suppressed the `SET var = <expr>` statement (mirroring
488
+ the existing `exp.PropertyEQ` suppression). That regressed the pre-existing contract
489
+ `test_set_session_variable_not_parse_failed`, which asserts `SET var = 5;` yields
490
+ exactly one OTHER-kind, non-parse-failed statement (not zero).
491
+ - **Change**: The RHS-AST pre-scan still captures `exp.Set` assignments into `var_rhs`
492
+ (independent of statement emission), but the `exp.Set` statement flows through to be
493
+ emitted as OTHER, exactly as before this feature. Only `exp.PropertyEQ` remains
494
+ suppressed (unchanged pre-existing behaviour).
495
+ - **Impact**: No effect on IDENTIFIER resolution (the pre-scan runs first). Preserves
496
+ the parse-classification contract. Net: one fewer suppression than the plan implied.
497
+ - **Date**: 2026-06-14
498
+
499
+ #### Deviation 3: `registry.register` made generic to preserve concrete parser type
500
+ - **Reason**: `is_dynamic_name_sink` is defined only on `SnowflakeParser`. The
501
+ `@register` decorator's signature `decorator(cls: type[SqlParser]) -> type[SqlParser]`
502
+ narrowed `SnowflakeParser` to `type[SqlParser]`, so pyright rejected
503
+ `SnowflakeParser.is_dynamic_name_sink` access in the new tests.
504
+ - **Change**: `register`'s inner decorator now uses a `TypeVar` bound to
505
+ `type[SqlParser]`, returning the class with its concrete type preserved. The class is
506
+ still returned unchanged at runtime.
507
+ - **Impact**: Pure type-checker improvement; no runtime behaviour change. Benefits any
508
+ future dialect-specific static method, not just this feature.
509
+ - **Date**: 2026-06-14
510
+
511
+ #### Note: pre-existing pyright errors in `tests/unit/test_perf_scaling_guard.py`
512
+ The src-only pyright gate (`.pre-commit-config.yaml` `files: ^src/`) is clean (0 errors).
513
+ `uv run pyright` over the test tree reports 6 `reportPrivateImportUsage` errors for
514
+ `sqlglot.expressions.Expression` annotations on lines 100–188 of
515
+ `test_perf_scaling_guard.py`. These pre-exist on the PR-1 base commit (`34d68c4`,
516
+ verified: 7 such errors before any PR-2 edit) and are not in code this PR added; the
517
+ test files are outside the type-check gate. Left as-is to match the file's existing
518
+ convention.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sql-code-graph"
7
- version = "1.35.3"
7
+ version = "1.36.0"
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.35.3"
3
+ __version__ = "1.36.0"
4
4
 
5
5
  __all__ = ["__version__"]
@@ -1,6 +1,6 @@
1
1
  """Parser registry and factory for dialect-specific SQL parsers."""
2
2
 
3
- from typing import TYPE_CHECKING
3
+ from typing import TYPE_CHECKING, TypeVar
4
4
 
5
5
  if TYPE_CHECKING:
6
6
  from sqlcg.lineage.schema_resolver import SchemaResolver
@@ -9,6 +9,8 @@ if TYPE_CHECKING:
9
9
  # Global registry of dialect -> parser class mapping
10
10
  PARSERS: dict[str | None, type["SqlParser"]] = {}
11
11
 
12
+ _ParserT = TypeVar("_ParserT", bound="type[SqlParser]")
13
+
12
14
 
13
15
  def register(dialect: str | None):
14
16
  """Decorator to register a parser class for a dialect.
@@ -17,10 +19,12 @@ def register(dialect: str | None):
17
19
  dialect: SQL dialect identifier (None for ANSI, "snowflake", etc.)
18
20
 
19
21
  Returns:
20
- Decorator function
22
+ Decorator function. It returns the decorated class *unchanged* and with its
23
+ concrete type preserved, so dialect-specific static methods (e.g.
24
+ ``SnowflakeParser.is_dynamic_name_sink``) remain accessible to type checkers.
21
25
  """
22
26
 
23
- def decorator(cls: type["SqlParser"]) -> type["SqlParser"]:
27
+ def decorator(cls: _ParserT) -> _ParserT:
24
28
  PARSERS[dialect] = cls
25
29
  return cls
26
30