sql-code-graph 1.1.3__tar.gz → 1.3.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.
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/ARCHITECTURE_REVIEW.md +329 -1
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/CLAUDE.md +21 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/PKG-INFO +11 -1
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/README.md +10 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/docs/cli.md +111 -8
- sql_code_graph-1.3.0/plan/fix_downstream_sink_location.md +119 -0
- sql_code_graph-1.3.0/plan/fix_issue29_live_test_followups.md +442 -0
- sql_code_graph-1.3.0/plan/v1_2_0_read_proxy.md +597 -0
- sql_code_graph-1.3.0/plan/v1_2_1_bugfix.md +669 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/pyproject.toml +1 -1
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/__init__.py +1 -1
- sql_code_graph-1.3.0/src/sqlcg/cli/commands/analyze.py +327 -0
- sql_code_graph-1.3.0/src/sqlcg/cli/commands/db.py +210 -0
- sql_code_graph-1.3.0/src/sqlcg/cli/commands/find.py +78 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/gain.py +13 -11
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/git.py +11 -4
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/index.py +167 -4
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/mcp.py +70 -3
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/reindex.py +146 -76
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/config.py +15 -13
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/kuzu_backend.py +10 -6
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/indexer.py +91 -11
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/lineage/aggregator.py +17 -45
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/metrics/store.py +48 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/ansi_parser.py +2 -2
- sql_code_graph-1.3.0/src/sqlcg/server/read_client.py +192 -0
- sql_code_graph-1.3.0/src/sqlcg/server/server.py +556 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/server/tools.py +155 -14
- sql_code_graph-1.3.0/src/sqlcg/server/writer.py +634 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_mcp_lifecycle.py +29 -9
- sql_code_graph-1.3.0/tests/integration/test_cross_file_lineage.py +125 -0
- sql_code_graph-1.3.0/tests/integration/test_dialect_auto_resolution.py +178 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_indexer_commits.py +7 -2
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_pr3_kind_tagging.py +24 -19
- sql_code_graph-1.3.0/tests/integration/test_read_via_server.py +235 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_readonly_under_lock.py +31 -22
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_reindex_via_server.py +60 -28
- sql_code_graph-1.3.0/tests/integration/test_single_writer_queue.py +382 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_star_resolution.py +10 -2
- sql_code_graph-1.3.0/tests/integration/test_user_surface_recall_guard.py +455 -0
- sql_code_graph-1.3.0/tests/unit/test_BugB_escalation_uses_init_path.py +101 -0
- sql_code_graph-1.3.0/tests/unit/test_BugC_hook_upgrade.py +184 -0
- sql_code_graph-1.3.0/tests/unit/test_aggregator.py +68 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_aggregator_skip.py +21 -30
- sql_code_graph-1.3.0/tests/unit/test_canonical_target_resolution.py +270 -0
- sql_code_graph-1.3.0/tests/unit/test_db_info.py +142 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_find_cmd.py +19 -28
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_freshness_helper.py +20 -21
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_gain_ratio.py +5 -12
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_git_hooks_notify.py +29 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_hygiene_config_warning.py +2 -4
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_kuzu_lock.py +4 -4
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_noise_filter.py +8 -2
- sql_code_graph-1.3.0/tests/unit/test_read_client.py +234 -0
- sql_code_graph-1.3.0/tests/unit/test_resolve_pass2_passes_dependency_filter.py +174 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_star_schema_unit.py +26 -25
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_unqualified_fallback.py +9 -24
- sql_code_graph-1.3.0/tests/unit/test_writer_queue.py +323 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/uv.lock +1 -1
- sql_code_graph-1.1.3/src/sqlcg/cli/commands/analyze.py +0 -325
- sql_code_graph-1.1.3/src/sqlcg/cli/commands/db.py +0 -181
- sql_code_graph-1.1.3/src/sqlcg/cli/commands/find.py +0 -81
- sql_code_graph-1.1.3/src/sqlcg/server/server.py +0 -382
- sql_code_graph-1.1.3/tests/integration/test_cross_file_lineage.py +0 -129
- sql_code_graph-1.1.3/tests/unit/test_aggregator.py +0 -55
- sql_code_graph-1.1.3/tests/unit/test_db_info.py +0 -173
- sql_code_graph-1.1.3/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -149
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.claude/agents/api-documenter.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.claude/agents/architect-planner.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.claude/agents/architect-reviewer.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.claude/agents/code-reviewer.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.claude/agents/developer.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.claude/agents/plan-reviewer.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.claude/agents/sprint-planner.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.github/workflows/benchmark.yml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.github/workflows/e2e-tests.yml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.github/workflows/release.yml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.github/workflows/test.yml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.gitignore +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.pre-commit-config.yaml +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/.sqlcgignore +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/CHANGELOG.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/docs/AIRBNB_PARSE_REPORT.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/e2e_firstuser_report.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/e2e_run_20260528_101413.output +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/main.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/WORKFLOW.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/blueprint.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/bundle_claude_skill.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/feature_34_unused_presentation_segregation.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/feature_35_external_downstream_injection.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/feature_F2_bundle_claude_skill.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/fix_dynamic_table_parsing.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/fix_expand_qualify_perf.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/fix_firstuser_findings.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/fix_schema_case_mismatch.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/hygiene_config_path_and_survivors.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/investigation_e5_e4.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/living_codebase_resync.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/measurements/schema_comparison_with_schema.json +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/measurements/schema_comparison_without_schema.json +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/measurements/sprint_pool_300s_plan.json +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/parse_diagnostics.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/parsing_errors_experiment.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/snowflake_en_test_suite.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_01.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_01_deployment_pypi.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_02.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_02_v0.3.0_core.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_03.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_03_v0.3.1_postmortem.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_04_column_lineage.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_04_column_lineage_fix.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_05_star_resolution.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_06_lineage_coverage.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_07_open_ecodes.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_07_perf_and_live_test.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_08_perf_upsert.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_09_lineage_coverage.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_10_anchor_tools.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_11_v1.0.2_bugfix.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_12_v1.1.0.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_13_v1.1.0_cluster_b.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sprint_3.1_postmortem.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/sqlcg.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/trust_layer.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/v1.1.0_cluster_b_provenance_trust.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/v1.1.0_live_graph_freshness.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/v1.1.1_batch_upsert_perf.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/v1_1_2_bugfix.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/plan/v1_1_3_union_cte_star.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/profile.html +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/pyrightconfig.json +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/scripts/collect_parse_errors.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/scripts/generate_cli_docs.sh +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/__main__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/install.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/report.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/uninstall.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/commands/watch.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/cli/main.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/freshness.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/graph_db.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/jobs.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/neo4j_backend.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/queries.cypher +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/queries.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/schema.cypher +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/core/schema.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/dbt_adapter.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/error_classify.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/git_delta.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/pool.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/walker.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/indexer/watcher.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/lineage/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/lineage/schema_resolver.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/metrics/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/base.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/bigquery_parser.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/postgres_parser.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/registry.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/snowflake_parser.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/parsers/tsql_parser.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/server/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/server/control.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/server/exceptions.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/server/models.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/server/noise_filter.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/server/skill.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/utils/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/utils/hashing.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/utils/ignore.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/src/sqlcg/utils/logging.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/adversarial/200_join.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/adversarial/500_union.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/bench_indexer.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/conftest.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/tpch/q01.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/tpch/q02.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/tpch/q03.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/tpch/q04.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/benchmarks/tpch/q05.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/conftest.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_airbnb_e2e.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_cli_index.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_git_hook_install.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_golden_lineage.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_mcp_tools.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_star_resolution_e2e.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/e2e/test_watch.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/raw_listings.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/src_hosts.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/src_listings.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/airbnb/src_reviews.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/bigquery/.gitkeep +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/jaffle_shop/customers.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/jaffle_shop/orders.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/snowflake/base_tables.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/snowflake/reports.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/snowflake/views.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/star_corpus/etl_star.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/synthetic/base_tables.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/synthetic/reports.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/fixtures/synthetic/views.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/snowflake/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/snowflake/test_insert_select.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_T34_presentation_segregation.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_T35_external_consumers.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_anchor_tools.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_bulk_upsert.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_column_lineage_e2e.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_cte_recall_guard.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_cte_schema_alias_guard.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_cte_source_node_invariant.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_dialect_matrix.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_freshness_mcp.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_indexer_batching.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_indexer_to_graph.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_live_anchors.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_parse_diagnostics.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_pr1_confidence_reason.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_pr2_source_location.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_resync.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_temp_table_lineage.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/perf/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/perf/test_perf.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E10/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E11/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E12/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E12/e12_json_path.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E12/test_e12.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E13/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E14/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E15/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E16/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E16/e16_merge.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E16/test_e16.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E17/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E18/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E18/e18_decode.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E18/e18_nvl2.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E18/test_e18.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E19/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E2/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E2/e2_function_alias.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E2/test_e2.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E20/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E21/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E21/test_e21.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E22/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E23/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E23/test_e23.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E24/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E25/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E25/e25_cross_db.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E25/e25_two_part.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E25/test_e25.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E25/test_e25_full_id.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E26/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E27/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E27/e27_udf.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E27/test_e27.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E28/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E29/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E3/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E3/e3_alter_table.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E3/test_e3.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E30/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E31/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E32/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E33/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E34/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E35/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E36/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E36/e36_temp_table.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E36/test_e36.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E36/test_e36_xfile.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E37/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E38/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E4/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E4/e4_unpivot.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E4/test_e4.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E5/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E5/test_e5.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E8/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E8/e8_uuid.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E8/test_e8.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E9/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_aggregates/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_date_functions/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/README.md +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/anchors/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/anchors/fixture_etl.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/anchors/fixture_source.sql +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/conftest.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/snowflake/test_plan_review_gates.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/snowflake/__init__.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/snowflake/test_scripting_noise.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_F2_install_skill.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_F2_skill_render.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_F2_uninstall_skill.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_T09_01_qualify_once.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_T09_02_ddl_skip.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_T09_06_log_verbosity.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_T35_config_external_consumers.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_base_parser.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_branch_monitor.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_bulk_upsert_invariant.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_cli.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_cli_help.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_closure_depth.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_column_lineage_wiring.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_config.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_data_models.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_dominant_cause.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_firstuser_findings.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_git_delta.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_git_hooks.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_graph_backend.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_hard_kill_pool.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_include_working_tree.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_index_cmd.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_index_flags.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_index_progress.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_indexer_progress.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_indexer_quality.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_install.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_install_message.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_jobs.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_judgement.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_kuzu_backend.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_lineage_conversion.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_literal_column_skip.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_mcp_best_practices.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_mcp_control.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_mcp_stdio_smoke.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_metrics.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_parse_file_dependency_filter.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_parse_quality.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_parser.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_perf_scaling_guard.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_pr07_observability.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_queries_loader.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_schema_resolver.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_server.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_sprint_06_t04_t05.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_star_resolution_unit.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_submit_feedback.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_subprocess_isolate.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_t02_expression_name_extraction.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_t03_ddl_skip.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_timeout_cancel.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_tools_hints.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_tools_warnings.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_uninstall.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_upsert_batch_invariant.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_walker.py +0 -0
- {sql_code_graph-1.1.3 → sql_code_graph-1.3.0}/tests/unit/test_watcher.py +0 -0
|
@@ -478,7 +478,15 @@ both concrete backends override it — the blueprint does not enforce this.
|
|
|
478
478
|
Risk: HIGH. A failed re-index leaves orphaned graph nodes that produce incorrect
|
|
479
479
|
lineage results until the next full re-index.
|
|
480
480
|
|
|
481
|
-
### 3.2 [HIGH] `CrossFileAggregator.resolve_pass2` re-opens files without error handling
|
|
481
|
+
### 3.2 ~~[HIGH]~~ **RESOLVED (v1.2.1)** `CrossFileAggregator.resolve_pass2` re-opens files without error handling
|
|
482
|
+
|
|
483
|
+
**Resolution (2026-06-02, v1.2.1, PR #48):** `resolve_pass2` was deleted entirely. It had
|
|
484
|
+
zero production call sites — the production pass-2 path in `index_repo` reimplements the
|
|
485
|
+
dep-filter + reparse logic inline (worker calls `parse_file(..., dependency_filter=...)`
|
|
486
|
+
in [`pool.py`](src/sqlcg/indexer/pool.py)), and that path already handles file-read errors
|
|
487
|
+
defensively. The dead method (and the four tests that exercised it) were the same
|
|
488
|
+
test-measures-a-dead-path blind-spot class as #40. Tests realigned to drive `index_repo`
|
|
489
|
+
end-to-end. See [`v1_2_1_bugfix.md`](plan/v1_2_1_bugfix.md) Phase 5.
|
|
482
490
|
|
|
483
491
|
```python
|
|
484
492
|
def resolve_pass2(self, parser, parsed):
|
|
@@ -2947,4 +2955,324 @@ editor owns the stdio process lifecycle and v1.1 has no launcher to re-spawn it
|
|
|
2947
2955
|
owner-only, but any same-uid local process can send `stop`/`reindex`).
|
|
2948
2956
|
- **Freshness on every tool result by default** — v1.1 ships it gated/off to
|
|
2949
2957
|
protect hot-path latency; default-on pending an overhead measurement.
|
|
2958
|
+
|
|
2959
|
+
## 18. v1.2.1 — Lineage recall guards + canonical INSERT target + CTE filter fixes
|
|
2960
|
+
|
|
2961
|
+
Review date: 2026-06-02 · Reconciled by: architect-planner · Branch:
|
|
2962
|
+
`feat/v1.2.1-bugfix` · PR #48 · Verdict: **PLAN-COMPLIANT (PASS)**
|
|
2963
|
+
|
|
2964
|
+
> **Bundled release note (2026-06-02):** the v1.2.1 bugfix scope (this section) and the
|
|
2965
|
+
> downstream-sink `file:line` fix (§19.2) ship as a **single `v1.2.2` release** — the
|
|
2966
|
+
> lower `v1.2.1` tag is skipped (precedent: v1.1.2→v1.1.3). Both change sets live on
|
|
2967
|
+
> `feat/v1.2.1-bugfix` (PR #48, fast-forwarded to `b5bf7a3`); version is `1.2.2`. The
|
|
2968
|
+
> combined plan-compliance verdict (PASS, both scopes) is recorded in
|
|
2969
|
+
> [`v1_2_1_bugfix.md`](plan/v1_2_1_bugfix.md) → "Bundled v1.2.2 release compliance".
|
|
2970
|
+
|
|
2971
|
+
Patch release fixing the residual user-facing lineage defects (#44 canonical-name
|
|
2972
|
+
split, #45 `file:line=?` + `cte_*` leak), repairing the v1.2.0 read-proxy filter
|
|
2973
|
+
regression (the #39 read-half), deleting the dead `resolve_pass2` (resolves §3.2),
|
|
2974
|
+
and landing the #40 user-surface regression-guard suite. Plan:
|
|
2975
|
+
[`v1_2_1_bugfix.md`](plan/v1_2_1_bugfix.md) (full phase-by-phase compliance log appended there).
|
|
2976
|
+
|
|
2977
|
+
### 18.1 #44 — canonical INSERT-target resolution
|
|
2978
|
+
|
|
2979
|
+
A new `CrossFileAggregator.canonical_by_bare` index (bare name → sole DDL `full_id`)
|
|
2980
|
+
plus `_ambiguous_bare` (names defined in >1 schema, never rewritten) is built in
|
|
2981
|
+
`register_pass1` from DDL tables only. It is threaded `index_repo` →
|
|
2982
|
+
`_upsert_file_batch` → `_build_file_rows`, where an unqualified / non-DDL INSERT
|
|
2983
|
+
target whose bare name resolves to a sole DDL canonical is rewritten to share that
|
|
2984
|
+
node's identity (`qualified` == DDL `full_id`, all fields derived from the canonical),
|
|
2985
|
+
keeping `kind:"table"`. The fix lands in the node-emission loop, **not** the deleted
|
|
2986
|
+
`resolve_pass2` and **not** the per-column lineage hot path — pure row-dict mutation,
|
|
2987
|
+
no new `execute()`. Degrades to a no-op when `canonical_by_bare is None`
|
|
2988
|
+
(single-file `reindex_file` / `resync_changed` paths) — known limitation, re-index is
|
|
2989
|
+
the migration path per CLAUDE.md.
|
|
2990
|
+
|
|
2991
|
+
### 18.2 #45 — `file:line` recall + structural `cte_*` suppression
|
|
2992
|
+
|
|
2993
|
+
- **#45.1**: `analyze upstream/downstream` now bind location from the source's
|
|
2994
|
+
*outgoing* `COLUMN_LINEAGE` edge and aggregate `WITH … min(start_line), min(file_path)`
|
|
2995
|
+
**before** `LIMIT 100`, so multi-hop sources carry a real `file:line` and the limit
|
|
2996
|
+
counts distinct sources, not edge-fanout rows.
|
|
2997
|
+
- **#45.2**: chosen mechanism is **graph-truth, not a name heuristic** — unresolved
|
|
2998
|
+
synthetic INSERT targets are emitted `kind:"derived"` (the #44 emission change), and
|
|
2999
|
+
the restored `kind IN ['table','external']` read filter excludes them. No name-prefix
|
|
3000
|
+
belt was needed.
|
|
3001
|
+
|
|
3002
|
+
### 18.3 Two implementation invariants discovered during the fix
|
|
3003
|
+
|
|
3004
|
+
Both are now load-bearing; recorded so a future refactor does not silently undo them.
|
|
3005
|
+
|
|
3006
|
+
1. **KuzuDB: a `WHERE` clause inside `OPTIONAL MATCH` filters the match attempt, not
|
|
3007
|
+
the surrounding row.** To filter rows on an optionally-matched node's property, an
|
|
3008
|
+
explicit `WITH <carried>, t WHERE …` must follow. `analyze._kind_filter` uses this
|
|
3009
|
+
form (`OPTIONAL MATCH (t:SqlTable {…}) WITH <alias>, t WHERE t.kind IS NULL OR …`).
|
|
3010
|
+
The `IS NULL` branch is intentional: it keeps node-less physical sources (the #39
|
|
3011
|
+
tail) while CTE/derived intermediates (`kind='cte'`/`'derived'`) are excluded.
|
|
3012
|
+
Guarded by TC1/TC4 in [`test_user_surface_recall_guard.py`](tests/integration/test_user_surface_recall_guard.py).
|
|
3013
|
+
2. **`_flush_row_batch` dedup must prefer structural kinds over the default `'table'`.**
|
|
3014
|
+
A CTE alias is emitted twice in a batch — first `kind='table'` (incidental source
|
|
3015
|
+
reference) then `kind='cte'` (CTE destination). The pre-existing first-seen-wins
|
|
3016
|
+
dedup kept the wrong one, defeating #45.2. New Rule 2: `{'cte','derived','external'}`
|
|
3017
|
+
beats default `'table'` (Rule 1 — DDL provenance via `defined_in_file` — still takes
|
|
3018
|
+
precedence). This logic lives in the documented `_flush_row_batch` perf hot path but
|
|
3019
|
+
is pure dict comparison in the existing dedup loop — no change to flush cardinality,
|
|
3020
|
+
batch/scaling guards stay green (CLAUDE.md performance invariants intact).
|
|
3021
|
+
|
|
3022
|
+
### 18.4 Resolved / out-of-scope
|
|
3023
|
+
|
|
3024
|
+
- **§3.2 `resolve_pass2`** — RESOLVED (deleted; see §3.2 update).
|
|
3025
|
+
- **Residual #38 (UNION-ALL sibling CTEs)** — already fixed in 1.1.3; live DWH
|
|
3026
|
+
re-verification (80→47 `cte_insert` islands) recorded in the plan; the surviving 47
|
|
3027
|
+
are likely legitimately source-less computed measures, not a regression. Shape B of
|
|
3028
|
+
the #40 guard now asserts a computed-measure projection so a real gap there reds the guard.
|
|
3029
|
+
- **#28 server read-only-by-default + reindex escalation** — **IMPLEMENTED in 1.3.0**
|
|
3030
|
+
(#29 single-writer queue + RO→RW escalation; plan
|
|
3031
|
+
[`fix_issue_29_single_writer_queue.md`](plan/fix_issue_29_single_writer_queue.md)).
|
|
3032
|
+
The read half was already handled by the v1.2.0 routing proxy; 1.3.0 adds the write half:
|
|
3033
|
+
the server serves RO after a startup RW schema-ensure window, and escalates RO→RW only for
|
|
3034
|
+
the duration of a single-writer drain. See §20 for the compliance postmortem and two
|
|
3035
|
+
accepted/flagged deviations.
|
|
2950
3036
|
- **`connected_clients` fidelity** — best-effort `1` today; no real counter.
|
|
3037
|
+
|
|
3038
|
+
## 19. v1.2.1 live DWH re-verification — two residual findings (2026-06-02)
|
|
3039
|
+
|
|
3040
|
+
Source: live verification of the v1.2.1 fixes against the full DWH corpus
|
|
3041
|
+
(`../dwh`, 1,335 SQL files, clean index ~1:56). **The v1.2.1 fixes themselves
|
|
3042
|
+
PASSED** — both findings below are residual / design-limit behaviour surfaced by
|
|
3043
|
+
the run, not regressions in PR #48. Corpus graph snapshot (kind-typed `SqlTable`):
|
|
3044
|
+
2,222 `table` / 383 `cte` / 272 `derived`.
|
|
3045
|
+
|
|
3046
|
+
### 19.1 [KEEP — LOW] Residual scratch-object leak into the default `analyze` surface
|
|
3047
|
+
|
|
3048
|
+
**Measurement.** The #45.2 fix essentially closed the `cte_` leak it targeted:
|
|
3049
|
+
of nodes still typed `kind='table'`, only 3 carry a `cte_` prefix (vs 383 now
|
|
3050
|
+
correctly `kind='cte'`). The broader leak persists: **495 of 2,222 `table`-kind
|
|
3051
|
+
nodes (~22%) carry scratch-object name prefixes** — 471 `tmp_*`, 21 `temp_*`,
|
|
3052
|
+
3 `cte_*` — plus ~575 unqualified single-token nodes (a mix of real bare tables
|
|
3053
|
+
and CTE aliases). These surface in default (filtered) `analyze` output because the
|
|
3054
|
+
filter is correctly kind-based (graph-truth) but these aliases were never classified
|
|
3055
|
+
`cte`/`derived` at parse/aggregation time. This is the known #38 islands residual
|
|
3056
|
+
(s18.4 / `47 cte_insert islands`); the leak is now `tmp_*`-dominated, not
|
|
3057
|
+
`cte_*`-dominated. See memory `project_issue38_cte_filter_regression`.
|
|
3058
|
+
|
|
3059
|
+
**Decision: KEEP as a future ticket, LOW priority.** Rationale tied to existing
|
|
3060
|
+
decisions:
|
|
3061
|
+
- The standing **"no name-prefix filtering"** decision (s18.2; CLAUDE.md) is correct
|
|
3062
|
+
and stays. The fix therefore **cannot** live in the filter — it must happen at
|
|
3063
|
+
**classification time** in the aggregator/parser, exactly like the #44 synthetic
|
|
3064
|
+
INSERT-target → `kind='derived'` emission change (s18.1). A `CREATE [OR REPLACE]
|
|
3065
|
+
TEMP/TRANSIENT TABLE tmp_x AS SELECT …` whose target is a scratch object should be
|
|
3066
|
+
emitted `kind='derived'` at `_build_file_rows` time, the same place #44 already
|
|
3067
|
+
rewrites node identity. 492/495 of the leak (`tmp_*`/`temp_*`) are this CTAS-into-
|
|
3068
|
+
scratch shape — addressable by classifying on the parsed CTAS-into-temp statement
|
|
3069
|
+
kind (DDL-derived structural truth), **not** on the name prefix.
|
|
3070
|
+
- **Non-goal for the ticket:** the ~575 unqualified single-token nodes. They are a
|
|
3071
|
+
genuine mix of real bare tables and CTE aliases; auto-classifying them risks
|
|
3072
|
+
hiding real physical tables from the default surface (a false-negative worse than
|
|
3073
|
+
the current cosmetic leak). They stay `kind='table'` until a structural signal
|
|
3074
|
+
(CTE membership, CTAS target) is available — never a name guess.
|
|
3075
|
+
|
|
3076
|
+
**Risk/reward.** Reward: cleaner default `analyze` surface, ~22% fewer scratch
|
|
3077
|
+
intermediates leaking; closes the visible tail of #38. Risk: medium — must classify
|
|
3078
|
+
on parsed statement structure (TEMP/TRANSIENT CTAS target), and must not reclassify
|
|
3079
|
+
a real `tmp_`-named physical table that is read by a non-CTAS statement; needs a guard
|
|
3080
|
+
asserting a real table named `tmp_*` is still surfaced. Effort: medium (one emission
|
|
3081
|
+
site, reuses #44 plumbing, plus a behavioural guard). Below the open HIGH §3.x items
|
|
3082
|
+
and Finding 19.2 in the ranking. Recorded here; no plan stub drafted yet (pull when
|
|
3083
|
+
a lineage-coverage sprint next touches `_build_file_rows`).
|
|
3084
|
+
|
|
3085
|
+
### 19.2 [RESOLVED in v1.2.2] `file:line='?'` on downstream terminal sinks
|
|
3086
|
+
|
|
3087
|
+
**Measurement.** The #45.1 fix rebinds a result's location from its **outgoing**
|
|
3088
|
+
`COLUMN_LINEAGE` edge ("where is this column used as a source"). For *downstream*
|
|
3089
|
+
traces this means terminal sinks render `?`: a sink has no outgoing edge, so
|
|
3090
|
+
`min(q.start_line)`/`min(q.file_path)` are NULL. Corpus measurement: of 36,892
|
|
3091
|
+
distinct columns reachable as a downstream result, **29,827 (81%) are sinks → render
|
|
3092
|
+
`file:line='?'`**. The fix populates only the locatable 19%. Upstream is unaffected
|
|
3093
|
+
(an upstream source legitimately has an outgoing edge). The TC6 guard asserts non-null
|
|
3094
|
+
`file:line` on one specific *located* case, so it passed despite the 81%.
|
|
3095
|
+
|
|
3096
|
+
**Decision: KEEP — pick up next.** This is a genuine bug, **not** deliberate
|
|
3097
|
+
semantics. Analysis tied to #45.1's own intent:
|
|
3098
|
+
- #45.1 chose the outgoing edge so a *source*'s location reads as "where it is
|
|
3099
|
+
produced/consumed as a source" — correct for the **upstream** direction. The same
|
|
3100
|
+
pattern was copied verbatim into the **downstream** query
|
|
3101
|
+
([`analyze.py`](src/sqlcg/cli/commands/analyze.py) lines 134–137, fallback 146–149):
|
|
3102
|
+
`OPTIONAL MATCH (dst)-[dstedge]->()`. For a downstream *result*, the natural,
|
|
3103
|
+
user-meaningful location is the query that **produced** the column — i.e. the
|
|
3104
|
+
**incoming** edge `()-[dstedge]->(dst)`, not the outgoing one.
|
|
3105
|
+
- **Key lever (confirmed in code):** every one of the 36,892 columns has an incoming
|
|
3106
|
+
`COLUMN_LINEAGE` edge by definition — that is how it became a downstream result —
|
|
3107
|
+
and that producing query carries a real `start_line`/`file_path`. Flipping the two
|
|
3108
|
+
downstream `OPTIONAL MATCH` arrows from `(dst)-[dstedge]->()` to
|
|
3109
|
+
`()-[dstedge]->(dst)` binds location from the producing query, turning ~81% of `?`
|
|
3110
|
+
rows into a real `file:line`. Upstream stays on the outgoing edge unchanged.
|
|
3111
|
+
|
|
3112
|
+
**Risk/reward.** Reward: HIGH — ~81% of downstream result rows flip from `?` to a
|
|
3113
|
+
real `file:line` on a corpus this shape. Effort: LOW — a ~2-line arrow flip in two
|
|
3114
|
+
downstream queries (primary + bare-name fallback), no schema/index/perf change, no
|
|
3115
|
+
parser change. Risk: LOW and bounded — only the downstream direction; upstream and
|
|
3116
|
+
the kind-filter (s18.3) untouched. The one trap: TC6 passes today on a located case,
|
|
3117
|
+
so it does **not** catch the regression — the ticket must add a guard asserting a
|
|
3118
|
+
**terminal sink** (no outgoing edge) renders a real `file:line`, not `?`.
|
|
3119
|
+
Plan stub drafted: [`fix_downstream_sink_location.md`](plan/fix_downstream_sink_location.md).
|
|
3120
|
+
Suggested release: patch (1.2.2) or fold into the next lineage minor.
|
|
3121
|
+
|
|
3122
|
+
**RESOLVED — shipped in v1.2.2 (bundled with v1.2.1; see §18 bundled-release note).**
|
|
3123
|
+
Both downstream queries in [`analyze.py`](src/sqlcg/cli/commands/analyze.py) (primary
|
|
3124
|
+
L134, bare-name fallback L146) now bind location from the **incoming**
|
|
3125
|
+
`()-[dstedge:COLUMN_LINEAGE]->(dst)` edge — the producing query — so terminal sinks
|
|
3126
|
+
carry a real `file:line`. Upstream (L77/L89) keeps the outgoing-edge binding, unchanged.
|
|
3127
|
+
Guarded by the TC6b terminal-sink test in
|
|
3128
|
+
[`test_user_surface_recall_guard.py`](tests/integration/test_user_surface_recall_guard.py),
|
|
3129
|
+
demonstrably RED on master before the fix.
|
|
3130
|
+
|
|
3131
|
+
### 19.3 Cross-finding note
|
|
3132
|
+
|
|
3133
|
+
Both findings share the v1.2.1 root theme: the *graph store* is correct (edges intact,
|
|
3134
|
+
kinds mostly right); the defects live in the **graph→user presentation layer**
|
|
3135
|
+
(filter classification for 19.1, location binding for 19.2) — the same blind-spot
|
|
3136
|
+
class as #38/#40 where anchors traversing raw edges pass while the user-facing query
|
|
3137
|
+
path is wrong. Any guard for either must drive the **user-facing `analyze` path**,
|
|
3138
|
+
not raw `COLUMN_LINEAGE` traversal.
|
|
3139
|
+
|
|
3140
|
+
### 19.4 [KEEP — LOW] TC6b guard reconstructs the query instead of running `analyze downstream`
|
|
3141
|
+
|
|
3142
|
+
Raised by the plan-reviewer on the §19.2 sink fix. The TC6b terminal-sink guard's helper
|
|
3143
|
+
`_downstream_filtered_query()` in
|
|
3144
|
+
[`test_user_surface_recall_guard.py`](tests/integration/test_user_surface_recall_guard.py)
|
|
3145
|
+
**reconstructs the downstream Cypher query string** rather than invoking
|
|
3146
|
+
`analyze.downstream()` end-to-end. It therefore can drift from the production query if
|
|
3147
|
+
[`analyze.py`](src/sqlcg/cli/commands/analyze.py) changes and the helper is not updated in
|
|
3148
|
+
lockstep — exactly the §19.3 blind-spot (a guard not driving the true user-facing path).
|
|
3149
|
+
The fix held for v1.2.2 (the helper mirrors the shipped query), but the divergence risk is
|
|
3150
|
+
structural. **Future hardening:** replace the string-reconstruction helper with a
|
|
3151
|
+
`CliRunner`-based guard that runs the real `analyze downstream` command and asserts the
|
|
3152
|
+
rendered output. LOW priority; below §19.1 and the open §3.x items. No plan stub drafted.
|
|
3153
|
+
|
|
3154
|
+
## 20. v1.3.0 — Single-Writer Queue + RO→RW Escalation (#29 / #28) (2026-06-04)
|
|
3155
|
+
|
|
3156
|
+
Implements the long-deferred §18.4 "#28 server read-only-by-default + reindex escalation"
|
|
3157
|
+
item. Plan: [`fix_issue_29_single_writer_queue.md`](plan/fix_issue_29_single_writer_queue.md).
|
|
3158
|
+
Branch `feat/fix-issue-29-single-writer-queue`, 8 commits (T-01…T-08). Test suite
|
|
3159
|
+
1009 passed / 7 skipped / 1 xfailed; pyright clean; ruff clean.
|
|
3160
|
+
|
|
3161
|
+
### 20.1 What shipped (plan-compliance verdict)
|
|
3162
|
+
|
|
3163
|
+
The five phases landed as planned. The hard invariants were honoured **in the
|
|
3164
|
+
control-socket / drain path**:
|
|
3165
|
+
|
|
3166
|
+
- **B1 (no co-existence window)** — Steps 2.2 (drain task + escalation primitive) and 2.3
|
|
3167
|
+
(retire the inline `reindex` op) landed in **one commit** (`62c19cd`). The `reindex` and
|
|
3168
|
+
`index` socket-op handlers in [`server.py`](src/sqlcg/server/server.py) `_control_socket_task`
|
|
3169
|
+
enqueue onto `WriterQueue` and never call `backend_ref()`; the drain task is the sole
|
|
3170
|
+
backend consumer, resolving the backend under `backend_lock` via `escalate_to_rw`.
|
|
3171
|
+
- **B2 (shutdown vs. drain ordering)** — `_stop_watcher`
|
|
3172
|
+
([`server.py`](src/sqlcg/server/server.py) L394-410) sets `shutdown_requested` then
|
|
3173
|
+
acquires `backend_lock` **before** `shutdown_backend()`; `de_escalate_to_ro`
|
|
3174
|
+
([`writer.py`](src/sqlcg/server/writer.py)) skips the RO reopen when the event is set.
|
|
3175
|
+
Both guarantees (a)+(b) present.
|
|
3176
|
+
- **B3 (status framing atomic)** — server-side `status` framing (Step 4.1) and the CLI
|
|
3177
|
+
recv-exactly parse (Step 4.2) shipped in one commit (`af2c85d`); `mcp_stop`'s
|
|
3178
|
+
`s.recv(128)` and the unframed `stop` reply are untouched.
|
|
3179
|
+
- **W3 (`from=null`)** — the `reindex` op stores `from_sha=None`; the drain resolves the
|
|
3180
|
+
stored SHA via `rw.get_indexed_sha()` and HEAD via `git rev-parse`, with an actionable
|
|
3181
|
+
"no prior index" error on a never-indexed DB. The CLI refusal was removed.
|
|
3182
|
+
- **W5 (`done:true` sentinel)** — both server emit and CLI recv loops key off
|
|
3183
|
+
`done == true`, not EOF; failure relays `ok:false, done:true, error:…`.
|
|
3184
|
+
- **W6 (`find_lock_holder` public)** — promoted in `kuzu_backend.py`, in-module call site
|
|
3185
|
+
updated, imported by `writer.py`.
|
|
3186
|
+
- **W7 (drain exception handler)** — the drain's `except Exception` clears `_active`
|
|
3187
|
+
(`mark_active_failed`), relays an `ok:false,done:true` terminal frame to waiters, and the
|
|
3188
|
+
loop survives; `EscalationLockError` keeps its dedicated C3 path with the ERROR log.
|
|
3189
|
+
|
|
3190
|
+
### 20.2 Deviation 1 — MCP `index_repo` tool inline escalation (FLAGGED — follow-up required)
|
|
3191
|
+
|
|
3192
|
+
**What the developer added (not in the plan):** a `_serving_ro` flag +
|
|
3193
|
+
`_get_or_escalate_rw` / `_de_escalate_to_ro_from_tool` helpers in
|
|
3194
|
+
[`tools.py`](src/sqlcg/server/tools.py) so the MCP `index_repo` **tool** (invoked over the
|
|
3195
|
+
stdio transport, distinct from the CLI `index` socket op) escalates RO→RW inline when the
|
|
3196
|
+
server is serving RO.
|
|
3197
|
+
|
|
3198
|
+
**Verdict: the intent is consistent with the single-writer model, but the implementation
|
|
3199
|
+
violates the plan's central invariant and leaks the write lock on failure. Track as a
|
|
3200
|
+
v1.3.x follow-up, not a release blocker (the happy path works and tests are green), but
|
|
3201
|
+
it must be fixed before it is relied on under concurrency.**
|
|
3202
|
+
|
|
3203
|
+
Three concrete problems:
|
|
3204
|
+
|
|
3205
|
+
1. **Escalation outside `backend_lock` (breaks B1/OD-7).** The plan's load-bearing invariant
|
|
3206
|
+
is "once escalation exists, **no op may operate on a backend resolved outside
|
|
3207
|
+
`backend_lock`**; the only backend consumer is the drain task." The MCP `index_repo` tool
|
|
3208
|
+
escalates and writes with **no lock held** — a second path that can swap
|
|
3209
|
+
`tools._backend` concurrently with a `query` op or a drain. This is exactly the class of
|
|
3210
|
+
bug B1 was written to prevent.
|
|
3211
|
+
2. **RW-lock leak on the failure path.** `_de_escalate_to_ro_from_tool` is called only on the
|
|
3212
|
+
success branch ([`tools.py`](src/sqlcg/server/tools.py) L613-614), **not in a `finally`**.
|
|
3213
|
+
Any exception during `index_repo` / `upsert_node` / `run_read` / `upsert_edge` re-raises
|
|
3214
|
+
(L634) with the backend still RW — the exclusive write lock stays held, blocking all
|
|
3215
|
+
subsequent routed reads until the server is restarted. (Contrast the drain path, which
|
|
3216
|
+
de-escalates in a `finally`.)
|
|
3217
|
+
3. **Dead `_set_backend_lock` / `_backend_lock`.** `_set_backend_lock`
|
|
3218
|
+
([`tools.py`](src/sqlcg/server/tools.py) L117) and the `_backend_lock` global are
|
|
3219
|
+
**defined but never called** — a zero-value stub that looks like the intended lock plumbing
|
|
3220
|
+
for the tool escalation but was never wired. This is the CLAUDE.md "every new method must
|
|
3221
|
+
have a grep-confirmed call site" rule unmet, and the "function defined but never invoked"
|
|
3222
|
+
smell.
|
|
3223
|
+
|
|
3224
|
+
**Follow-up (recommended):** route the MCP `index_repo` tool write through the same
|
|
3225
|
+
`WriterQueue`/drain as the CLI `index` op (so there is genuinely one writer), or — minimally —
|
|
3226
|
+
acquire `backend_lock` for the escalation and move the de-escalation into a `finally`. There
|
|
3227
|
+
is **no test** for this path today (no test references `_get_or_escalate_rw` / `_serving_ro`),
|
|
3228
|
+
so the leak and the lock-bypass are unguarded. A regression test asserting (a) the tool
|
|
3229
|
+
escalates under the lock and (b) a raising `index_repo` de-escalates back to RO is required
|
|
3230
|
+
with the fix.
|
|
3231
|
+
|
|
3232
|
+
### 20.3 Deviation 2 — Step 4.3 "queued behind N" display (ACCEPTED, minor)
|
|
3233
|
+
|
|
3234
|
+
The plan's Step 4.3 specified that a client queued behind other work prints
|
|
3235
|
+
`queued behind: <op> (done/total files) — position N` before attaching to live progress.
|
|
3236
|
+
The developer implemented the `done:true` terminal sentinel and the progress-bar attach
|
|
3237
|
+
fully, but **omitted the "queued behind … position N" pre-active display**: the CLI receives
|
|
3238
|
+
the `{queued:true, position:N}` frame and the subsequent progress frames, but the queued
|
|
3239
|
+
frame is silently consumed (it carries no `files_total`, so the progress loop renders
|
|
3240
|
+
nothing for it) — see [`index.py`](src/sqlcg/cli/commands/index.py) L307-311.
|
|
3241
|
+
|
|
3242
|
+
**Verdict: ACCEPTED as a cosmetic shortfall.** The functional contract (enqueue, attach,
|
|
3243
|
+
stream progress, terminate on `done:true`, exit non-zero on `ok:false`) is intact; only the
|
|
3244
|
+
human-readable "you are behind N others" hint is missing. The `position` is already on the
|
|
3245
|
+
wire, so completing it is a one-line render in the existing loop. Track as a polish item,
|
|
3246
|
+
not a correctness gap.
|
|
3247
|
+
|
|
3248
|
+
### 20.4 Test-coverage gaps vs. the plan's Test Strategy (FLAGGED)
|
|
3249
|
+
|
|
3250
|
+
The plan's Test Strategy enumerated several **deterministic** integration tests that were
|
|
3251
|
+
not implemented as test functions, even though
|
|
3252
|
+
[`test_single_writer_queue.py`](tests/integration/test_single_writer_queue.py)'s module
|
|
3253
|
+
docstring lists B2 / W3 among its coverage (the docstring overstates what is asserted):
|
|
3254
|
+
|
|
3255
|
+
- **B2 stop-mid-drain** (in-flight write commits; `tools._backend is None` after shutdown,
|
|
3256
|
+
no reopen-after-shutdown) — listed in the docstring, **no test function**.
|
|
3257
|
+
- **W3** arg-level assertion (`resync_changed(from=stored SHA, to=HEAD)`) and the
|
|
3258
|
+
never-indexed "no prior index" error — **no test** (the drain code is present and exercised
|
|
3259
|
+
indirectly by Scenario A, but the W3-specific arg/branch assertions are missing).
|
|
3260
|
+
- **W7** drain-body-raises → `_active` cleared + `ok:false,done:true` terminal frame + loop
|
|
3261
|
+
survives — **no test**.
|
|
3262
|
+
- **Reads block during a drain** (OD-1, deterministic `anyio.Event` ordering) — **no test**.
|
|
3263
|
+
- **B1 structural guard** (the `reindex` op body contains no pre-lock `backend_ref()`,
|
|
3264
|
+
mirroring the perf-invariant guard discipline) — **no test**.
|
|
3265
|
+
- **Escalation transition on real Kuzu** (second in-process RO holder forces
|
|
3266
|
+
`EscalationLockError`) — **no test** (only the injected-`opener` unit tests cover retry).
|
|
3267
|
+
|
|
3268
|
+
What **is** covered: fresh-DB init, stale-schema refusal (Step 1.4), `db reset` refusal
|
|
3269
|
+
(Step 3.4), framed `status` + `writer_queue` shape (Steps 4.1/4.2), metrics persisted +
|
|
3270
|
+
`SQLCG_METRICS=0` suppression (Step 4.5), the escalation retry/backoff + ERROR-log unit tests
|
|
3271
|
+
(Steps 1.2/4.4), the coalescing rules (Step 2.1), and the drain-runs-`resync_changed`-once
|
|
3272
|
+
invariant guard (Scenario A in `test_reindex_via_server.py`).
|
|
3273
|
+
|
|
3274
|
+
**Verdict:** these are real plan deviations (the named deterministic guards were specified
|
|
3275
|
+
and not delivered), but the shipped behaviour is exercised indirectly and the suite is green,
|
|
3276
|
+
so they are **follow-up hardening**, not a ship blocker. They should be filed alongside the
|
|
3277
|
+
Deviation-1 fix — the B2/W7/reads-block tests in particular guard the exact concurrency
|
|
3278
|
+
contract that Deviation 1 currently bypasses.
|
|
@@ -59,6 +59,27 @@ This project uses `uv`. Never activate a virtualenv manually, never use `pip`, n
|
|
|
59
59
|
| Lint | `rtk uv run ruff check src tests` |
|
|
60
60
|
| Format | `uv run ruff format src tests` |
|
|
61
61
|
|
|
62
|
+
## Releasing (version bump + tag)
|
|
63
|
+
|
|
64
|
+
Every feature/fix PR that ships bumps the version; after it merges to `master`, tag the release.
|
|
65
|
+
Do **all** of this — the tag is the step most easily forgotten.
|
|
66
|
+
|
|
67
|
+
1. **Bump the version** (in the feature branch, before the PR merges):
|
|
68
|
+
- [`pyproject.toml`](pyproject.toml) `version = "X.Y.Z"`
|
|
69
|
+
- [`src/sqlcg/__init__.py`](src/sqlcg/__init__.py) `__version__ = "X.Y.Z"`
|
|
70
|
+
- `uv lock` (refreshes the lockfile's own version entry)
|
|
71
|
+
- **SemVer**: new capability/surface → **minor** (`1.1.x` → `1.2.0`); bug fix only → **patch**.
|
|
72
|
+
No backward-compat shims, so an additive feature is still minor (not major) when nothing breaks.
|
|
73
|
+
2. **Merge the PR to `master`** (squash or `--merge` per the existing `Merge #NN` history).
|
|
74
|
+
3. **Tag the merge commit on `master`** — **annotated**, `v`-prefixed, message `vX.Y.Z — <one-line summary>`:
|
|
75
|
+
```bash
|
|
76
|
+
git checkout master && git pull --ff-only origin master
|
|
77
|
+
git tag -a vX.Y.Z -m "vX.Y.Z — <summary>" <merge-commit-sha>
|
|
78
|
+
git push origin vX.Y.Z
|
|
79
|
+
```
|
|
80
|
+
All existing tags are annotated and look like `v1.1.3` (never bare `1.1.3`). Confirm with
|
|
81
|
+
`git tag -l --format='%(contents)' vX.Y.Z` and verify it points at the master merge commit.
|
|
82
|
+
|
|
62
83
|
## Target scale — serve both ends of the spectrum
|
|
63
84
|
|
|
64
85
|
This project must work correctly and comfortably at two very different scales:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sql-code-graph
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.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
|
|
@@ -267,6 +267,16 @@ sqlcg mcp restart # stop the server (client must respawn it
|
|
|
267
267
|
sqlcg version # show installed version
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
### Reads while the server is running (v1.2.0)
|
|
271
|
+
|
|
272
|
+
KuzuDB allows a single writer, so while the MCP server is live it holds the
|
|
273
|
+
database lock. CLI **read** commands (`find`, `analyze`, `db info`, `list-repos`,
|
|
274
|
+
`gain`) automatically route their query through the running server over its
|
|
275
|
+
control socket and return rows as usual — no flag, no config. When no server is
|
|
276
|
+
running they open the database directly, exactly as before. If the server is
|
|
277
|
+
mid-reindex the read waits for it to finish rather than failing with
|
|
278
|
+
"Database is locked".
|
|
279
|
+
|
|
270
280
|
## Supported dialects
|
|
271
281
|
|
|
272
282
|
sqlcg is built on [sqlglot](https://github.com/tobymao/sqlglot), so other dialects
|
|
@@ -229,6 +229,16 @@ sqlcg mcp restart # stop the server (client must respawn it
|
|
|
229
229
|
sqlcg version # show installed version
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
+
### Reads while the server is running (v1.2.0)
|
|
233
|
+
|
|
234
|
+
KuzuDB allows a single writer, so while the MCP server is live it holds the
|
|
235
|
+
database lock. CLI **read** commands (`find`, `analyze`, `db info`, `list-repos`,
|
|
236
|
+
`gain`) automatically route their query through the running server over its
|
|
237
|
+
control socket and return rows as usual — no flag, no config. When no server is
|
|
238
|
+
running they open the database directly, exactly as before. If the server is
|
|
239
|
+
mid-reindex the read waits for it to finish rather than failing with
|
|
240
|
+
"Database is locked".
|
|
241
|
+
|
|
232
242
|
## Supported dialects
|
|
233
243
|
|
|
234
244
|
sqlcg is built on [sqlglot](https://github.com/tobymao/sqlglot), so other dialects
|
|
@@ -17,7 +17,7 @@ bash scripts/generate_cli_docs.sh
|
|
|
17
17
|
| `watch` | Watch a directory and re-index on SQL file changes. |
|
|
18
18
|
| `gain` | Show metrics and feedback analytics. |
|
|
19
19
|
| `report` | Generate a metrics report with FP clusters and parse error patterns. |
|
|
20
|
-
| `install` | Register sqlcg as an MCP server in Claude Code
|
|
20
|
+
| `install` | Register sqlcg as an MCP server in Claude Code. |
|
|
21
21
|
| `uninstall` | Uninstall sqlcg from Claude Code and optionally clean up resources. |
|
|
22
22
|
| `version` | Show version. |
|
|
23
23
|
| `db` | Database management commands |
|
|
@@ -62,6 +62,13 @@ sqlcg index [OPTIONS] PATH
|
|
|
62
62
|
|
|
63
63
|
Index SQL files in a directory.
|
|
64
64
|
|
|
65
|
+
When a server is live on this DB, the index is routed through the server's
|
|
66
|
+
control socket so the DB is never opened directly (avoids lock contention).
|
|
67
|
+
Use --detach to enqueue and return immediately (fire-and-forget).
|
|
68
|
+
|
|
69
|
+
With no server live, falls back to the direct-write path unchanged
|
|
70
|
+
(zero-config small-repo invariant).
|
|
71
|
+
|
|
65
72
|
Schema aliases (staging schema → canonical schema) can be configured in
|
|
66
73
|
.sqlcg.toml under sqlcg.schema_aliases, e.g. da_tmp = "da".
|
|
67
74
|
|
|
@@ -71,13 +78,16 @@ Schema aliases (staging schema → canonical schema) can be configured in
|
|
|
71
78
|
| --- | --- | --- | --- | --- | --- |
|
|
72
79
|
| --dialect, -d | TEXT | No | No | | SQL dialect (or 'auto' to read from .sqlcg.toml) |
|
|
73
80
|
| --dbt-manifest | PATH | No | No | | Path to dbt manifest |
|
|
74
|
-
| --timeout-per-file | INTEGER | No | No |
|
|
81
|
+
| --timeout-per-file | INTEGER | No | No | 10 | Timeout per file in seconds |
|
|
75
82
|
| --buffer-pool-size | INTEGER | No | No | 0 | KuzuDB buffer pool size in MB (0 = default). Set to 256-512 on memory-constrained machines. |
|
|
76
83
|
| --batch-size | INTEGER | No | No | 50 | Files per KuzuDB transaction in the upsert pass. Default 50 balances commit-overhead reduction (vs. legacy per-file commits) against per-batch memory cost. Lower values are safer for memory-constrained machines; higher values give marginal speedup at the cost of larger working sets. Set to 1 to reproduce legacy per-file commit behaviour. |
|
|
77
84
|
| --no-ddl | BOOLEAN | No | No | False | Skip table-node upserts for DDL-only files |
|
|
78
85
|
| --quiet, -q | BOOLEAN | No | No | False | Suppress summary console output |
|
|
86
|
+
| --verbose, -v | BOOLEAN | No | No | False | Print parse warnings to stderr instead of log file |
|
|
79
87
|
| --debug | BOOLEAN | No | No | False | Show detailed log output during indexing |
|
|
80
88
|
| --profile / --no-profile | BOOLEAN | No | No | False | Emit per-stage timing after indexing |
|
|
89
|
+
| --include-working-tree | BOOLEAN | No | No | False | Index the working tree including uncommitted changes. Marks freshness as 'indexed with working-tree changes'. |
|
|
90
|
+
| --detach | BOOLEAN | No | No | False | When routing through a live server, return immediately after enqueueing (fire-and-forget). Default is to wait for the index to complete. |
|
|
81
91
|
|
|
82
92
|
## `sqlcg reindex`
|
|
83
93
|
|
|
@@ -106,7 +116,8 @@ build — run 'sqlcg db reset && sqlcg db init && sqlcg index <path>' to re-init
|
|
|
106
116
|
| --dialect, -d | TEXT | No | No | | SQL dialect (or 'auto' to read from .sqlcg.toml) |
|
|
107
117
|
| --quiet, -q | BOOLEAN | No | No | False | Suppress summary output |
|
|
108
118
|
| --batch-size | INTEGER | No | No | 50 | Files per KuzuDB transaction (same default as index command) |
|
|
109
|
-
| --timeout-per-file | INTEGER | No | No |
|
|
119
|
+
| --timeout-per-file | INTEGER | No | No | 10 | Per-file parse timeout in seconds |
|
|
120
|
+
| --notify | BOOLEAN | No | No | False | If a server is live on this DB, route the reindex through the server (avoids lock contention). Falls back to direct write if no server is found. |
|
|
110
121
|
|
|
111
122
|
## `sqlcg watch`
|
|
112
123
|
|
|
@@ -181,7 +192,10 @@ If no metrics database exists, prints a message and exits 0.
|
|
|
181
192
|
sqlcg install [OPTIONS]
|
|
182
193
|
```
|
|
183
194
|
|
|
184
|
-
Register sqlcg as an MCP server in Claude Code
|
|
195
|
+
Register sqlcg as an MCP server in Claude Code.
|
|
196
|
+
|
|
197
|
+
Runs ``claude mcp add -s user sql-code-graph <cmd> <args>`` when the
|
|
198
|
+
``claude`` CLI is on PATH; otherwise writes ~/.claude.json directly.
|
|
185
199
|
|
|
186
200
|
Also provisions a Claude skill file (SKILL.md) at the chosen location.
|
|
187
201
|
Pass --scope project or --scope global to specify where the skill is written.
|
|
@@ -333,7 +347,7 @@ Find a table by name.
|
|
|
333
347
|
|
|
334
348
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
335
349
|
| --- | --- | --- | --- | --- | --- |
|
|
336
|
-
|
|
|
350
|
+
| --raw | BOOLEAN | No | No | False | Disable noise filtering on results |
|
|
337
351
|
|
|
338
352
|
## `sqlcg find column`
|
|
339
353
|
|
|
@@ -347,7 +361,7 @@ Find a column by table.column reference.
|
|
|
347
361
|
|
|
348
362
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
349
363
|
| --- | --- | --- | --- | --- | --- |
|
|
350
|
-
|
|
|
364
|
+
| --raw | BOOLEAN | No | No | False | Disable noise filtering on results |
|
|
351
365
|
|
|
352
366
|
## `sqlcg find pattern`
|
|
353
367
|
|
|
@@ -394,6 +408,8 @@ Trace upstream column lineage.
|
|
|
394
408
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
395
409
|
| --- | --- | --- | --- | --- | --- |
|
|
396
410
|
| --depth | INTEGER | No | No | 5 | Maximum traversal depth |
|
|
411
|
+
| --raw | BOOLEAN | No | No | False | Disable noise filtering on results |
|
|
412
|
+
| --include-intermediate | BOOLEAN | No | No | False | Include CTE/derived intermediate nodes |
|
|
397
413
|
|
|
398
414
|
## `sqlcg analyze downstream`
|
|
399
415
|
|
|
@@ -408,6 +424,8 @@ Trace downstream column lineage.
|
|
|
408
424
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
409
425
|
| --- | --- | --- | --- | --- | --- |
|
|
410
426
|
| --depth | INTEGER | No | No | 5 | Maximum traversal depth |
|
|
427
|
+
| --raw | BOOLEAN | No | No | False | Disable noise filtering on results |
|
|
428
|
+
| --include-intermediate | BOOLEAN | No | No | False | Include CTE/derived intermediate nodes |
|
|
411
429
|
|
|
412
430
|
## `sqlcg analyze impact`
|
|
413
431
|
|
|
@@ -421,7 +439,7 @@ Show all queries impacted by a table.
|
|
|
421
439
|
|
|
422
440
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
423
441
|
| --- | --- | --- | --- | --- | --- |
|
|
424
|
-
|
|
|
442
|
+
| --raw | BOOLEAN | No | No | False | Disable noise filtering on results |
|
|
425
443
|
|
|
426
444
|
## `sqlcg analyze failures`
|
|
427
445
|
|
|
@@ -431,6 +449,9 @@ sqlcg analyze failures [OPTIONS]
|
|
|
431
449
|
|
|
432
450
|
List files that failed to parse, with their dominant cause (E-code bucket).
|
|
433
451
|
|
|
452
|
+
Valid --cause buckets (from highest to lowest severity):
|
|
453
|
+
timeout, E8, E3, E2, E5, E1, qualify_failed, func_fallback, pure_ddl_skip.
|
|
454
|
+
|
|
434
455
|
Requires a graph indexed with sqlcg >= v3 (schema version 3). Re-index
|
|
435
456
|
with 'sqlcg db reset && sqlcg index <path>' if the graph was built with
|
|
436
457
|
an earlier version.
|
|
@@ -439,7 +460,7 @@ an earlier version.
|
|
|
439
460
|
|
|
440
461
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
441
462
|
| --- | --- | --- | --- | --- | --- |
|
|
442
|
-
| --cause | TEXT | No | No | | Filter by E-code bucket
|
|
463
|
+
| --cause | TEXT | No | No | | Filter by E-code bucket. Valid values: timeout, E8, E3, E2, E5, E1, qualify_failed, func_fallback, pure_ddl_skip |
|
|
443
464
|
| --limit | INTEGER | No | No | 100 | Maximum rows to return |
|
|
444
465
|
|
|
445
466
|
## `sqlcg analyze unused`
|
|
@@ -455,6 +476,7 @@ Find tables with no query references.
|
|
|
455
476
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
456
477
|
| --- | --- | --- | --- | --- | --- |
|
|
457
478
|
| --threshold | INTEGER | No | No | 0 | Minimum reference count threshold |
|
|
479
|
+
| --raw | BOOLEAN | No | No | False | Disable noise filtering on results |
|
|
458
480
|
|
|
459
481
|
## `sqlcg mcp`
|
|
460
482
|
|
|
@@ -471,6 +493,9 @@ MCP server commands
|
|
|
471
493
|
| `setup` | Print or write MCP server config JSON. |
|
|
472
494
|
| `start` | Start the MCP server. |
|
|
473
495
|
| `best-practices` | Print MCP tool best-practices (the fact/heuristic boundary). |
|
|
496
|
+
| `status` | Print server status JSON (connects to control socket). |
|
|
497
|
+
| `stop` | Stop the running MCP server gracefully. |
|
|
498
|
+
| `restart` | Stop the server. The client (editor) must respawn. |
|
|
474
499
|
|
|
475
500
|
## `sqlcg mcp setup`
|
|
476
501
|
|
|
@@ -480,6 +505,11 @@ sqlcg mcp setup [OPTIONS]
|
|
|
480
505
|
|
|
481
506
|
Print or write MCP server config JSON.
|
|
482
507
|
|
|
508
|
+
--print (default): print the JSON snippet for manual insertion.
|
|
509
|
+
--write: write to ~/.claude.json under mcpServers.user (the correct path
|
|
510
|
+
for Claude Code — not settings.json, which Claude Code does not read
|
|
511
|
+
for MCP servers).
|
|
512
|
+
|
|
483
513
|
### Options
|
|
484
514
|
|
|
485
515
|
| Option | Type | Required | Repeatable | Default | Description |
|
|
@@ -517,6 +547,77 @@ that have not installed the skill.
|
|
|
517
547
|
| --- | --- | --- | --- | --- | --- |
|
|
518
548
|
| _none_ | | | | | |
|
|
519
549
|
|
|
550
|
+
## `sqlcg mcp status`
|
|
551
|
+
|
|
552
|
+
```bash
|
|
553
|
+
sqlcg mcp status [OPTIONS]
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
Print server status JSON (connects to control socket).
|
|
557
|
+
|
|
558
|
+
Returns JSON with fields: running, pid, db_path, indexed_sha, head_sha,
|
|
559
|
+
stale_by_commits, connected_clients, uptime, writer_queue when a server
|
|
560
|
+
is live.
|
|
561
|
+
|
|
562
|
+
The status response is length-prefixed framed (v1.3.0, B3) so large
|
|
563
|
+
writer_queue payloads are received in full — the client uses the
|
|
564
|
+
recv-exactly makefile+readline+read(n) pattern, NOT a single recv(4096).
|
|
565
|
+
|
|
566
|
+
When no server is found: {"running": false}.
|
|
567
|
+
When the PID file exists with a live process but the socket is unavailable:
|
|
568
|
+
{"running": true, "degraded": "socket unavailable", ...}.
|
|
569
|
+
|
|
570
|
+
R3 (stale socket): if the socket file exists but the server is not
|
|
571
|
+
responding (ConnectionRefusedError / FileNotFoundError), falls through
|
|
572
|
+
to the PID-file probe — never hangs or errors on a dead socket.
|
|
573
|
+
|
|
574
|
+
### Options
|
|
575
|
+
|
|
576
|
+
| Option | Type | Required | Repeatable | Default | Description |
|
|
577
|
+
| --- | --- | --- | --- | --- | --- |
|
|
578
|
+
| _none_ | | | | | |
|
|
579
|
+
|
|
580
|
+
## `sqlcg mcp stop`
|
|
581
|
+
|
|
582
|
+
```bash
|
|
583
|
+
sqlcg mcp stop [OPTIONS]
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Stop the running MCP server gracefully.
|
|
587
|
+
|
|
588
|
+
Sends a ``stop`` op via the control socket; waits up to 5 s for the
|
|
589
|
+
socket file to disappear (confirming clean exit). Falls back to SIGTERM
|
|
590
|
+
on the PID-file PID if the socket is unavailable.
|
|
591
|
+
|
|
592
|
+
R3 (stale socket): ``ConnectionRefusedError`` / ``FileNotFoundError`` are
|
|
593
|
+
caught — never hangs on a dead socket.
|
|
594
|
+
|
|
595
|
+
### Options
|
|
596
|
+
|
|
597
|
+
| Option | Type | Required | Repeatable | Default | Description |
|
|
598
|
+
| --- | --- | --- | --- | --- | --- |
|
|
599
|
+
| _none_ | | | | | |
|
|
600
|
+
|
|
601
|
+
## `sqlcg mcp restart`
|
|
602
|
+
|
|
603
|
+
```bash
|
|
604
|
+
sqlcg mcp restart [OPTIONS]
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Stop the server. The client (editor) must respawn.
|
|
608
|
+
|
|
609
|
+
v1.1 cannot re-parent an editor-spawned stdio process. This command
|
|
610
|
+
stops the current server and prints guidance for the user to restart
|
|
611
|
+
the MCP server via their editor's MCP configuration.
|
|
612
|
+
|
|
613
|
+
True auto-restart (re-parenting stdio) is deferred to v1.2.
|
|
614
|
+
|
|
615
|
+
### Options
|
|
616
|
+
|
|
617
|
+
| Option | Type | Required | Repeatable | Default | Description |
|
|
618
|
+
| --- | --- | --- | --- | --- | --- |
|
|
619
|
+
| _none_ | | | | | |
|
|
620
|
+
|
|
520
621
|
## `sqlcg git`
|
|
521
622
|
|
|
522
623
|
```bash
|
|
@@ -542,6 +643,8 @@ Install git hooks for sqlcg integration.
|
|
|
542
643
|
Writes a post-checkout hook that triggers incremental resync after branch switches
|
|
543
644
|
and a post-merge hook that triggers resync after pulls/merges.
|
|
544
645
|
Idempotent: running multiple times produces one hook entry per hook.
|
|
646
|
+
The hooks embed the absolute path of the installing sqlcg binary so version skew
|
|
647
|
+
between the installed binary and the hook command is avoided.
|
|
545
648
|
|
|
546
649
|
### Options
|
|
547
650
|
|