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