Skip to content

feat: add clgraph detect and clgraph init - #81

Open
mingjerli wants to merge 1 commit into
feat/mcp-config-resolutionfrom
feat/detect-and-init
Open

mingjerli wants to merge 1 commit into
feat/mcp-config-resolutionfrom
feat/detect-and-init

Conversation

@mingjerli

Copy link
Copy Markdown
Owner

Step 2 of packaging clgraph as a coding-agent plugin: A6 (detection) and A7 (clgraph init).

Stacked on #80. Base is feat/mcp-config-resolution, not main — this builds directly on clgraph.mcp.config. Merge #80 first and GitHub will retarget this to main.

Why

The dialect can't be guessed safely, so it has to be asked. But an MCP server on stdio has no channel to ask through — stdin and stdout are the protocol. So asking lives in the CLI, and later in /clgraph:setup where the agent asks on the server's behalf.

clgraph detect

Proposes a SQL directory and a dialect, with evidence attached and a confidence rating. Writes nothing, decides nothing.

SQL directories:
  models  (34 files, dbt)

Dialect: snowflake  (confidence: high)
  - profiles.yml declares adapter type 'snowflake'

Evidence is ranked: a dbt profile's adapter type: (authoritative → high), then dialect-specific syntax markers (QUALIFY, SAFE_CAST, ::VARIANT, …), then parse scoring. --json for agents.

clgraph init

Records the answer in clgraph.toml, or [tool.clgraph] with --into-pyproject, and adds .clgraph/ to .gitignore. Run bare it prompts with detection pre-filling the defaults; --yes never prompts and fails instead — how agents and CI invoke it. A missing dialect is an error either way, never a guess.

Validation runs before anything is written, so a rejected call leaves the project untouched.

Two bugs testing turned up

Parse scoring counted the wrong thing. It counted raised ParseErrors, but sqlglot far more often degrades unsupported syntax into an exp.Command node without erroring — so a wrong dialect scored as a clean parse. Both now count as failures.

Even fixed, scoring stays weak: Snowflake-only syntax like QUALIFY and IFF() parses cleanly under all eight candidates. TestParseScoringIsWeak pins that, because it's the concrete evidence for why this design refuses to guess. The module docstring says so plainly rather than overselling the heuristic.

sqlglot warnings corrupted --json. Probing wrong dialects logs warnings, and in any process with logging configured to stdout they landed inside the JSON an agent was parsing. Caught only when the full suite ran in an order where airflow had configured logging — it passed in isolation. Scoring now silences sqlglot and restores the prior level.

Test plan

  • tests/test_detect.py — 30 tests: directory ranking, noise exclusion, dbt marking, all three evidence tiers, low-confidence honesty on portable SQL, JSON serialization, a read-only assertion, and the output-purity regression
  • tests/test_config_writer.py — 23 tests: round trip through resolve(), both config surfaces, overwrite refusal, validation-before-write, .gitignore idempotence and formatting
  • tests/test_cli.py — 11 new tests for both commands
  • Full suite: 1763 passed, 40 skipped, 2 xfailed
  • make pre-commit clean; ty holds at its 52-diagnostic baseline
  • Manual end-to-end: detect proposes snowflake from QUALIFY/IFF() at medium confidence → --yes without a dialect refuses and names the suggestion → init writes config and gitignore → the MCP server boots configured and traces analytics.revenue.bucket → raw.orders.amount → re-running init refuses without --force

Next

Step 3 — A2, clgraph index and the on-disk cache.

Step 2 of the plugin work. The dialect cannot be guessed safely, so it
has to be asked — and an MCP server on stdio has no channel to ask
through. Asking therefore lives in the CLI and, later, in /clgraph:setup.

clgraph detect proposes a SQL directory and a dialect with the evidence
attached, ranked: a dbt profile's adapter type (authoritative, high
confidence), then dialect-specific syntax markers, then parse scoring.
It writes nothing and decides nothing. --json makes it agent-readable.

clgraph init records the answer in clgraph.toml, or [tool.clgraph] with
--into-pyproject, and adds .clgraph/ to .gitignore. Run bare it prompts
with detection pre-filling the defaults; with --yes it never prompts and
fails instead, which is how agents and CI invoke it. A missing dialect is
an error either way.

Two things testing turned up, both fixed here:

Parse scoring counted only raised ParseErrors, but sqlglot far more often
degrades unsupported syntax into an exp.Command node without erroring —
so a wrong dialect scored as a clean parse. Both now count as failures.
Even so, scoring stays weak: Snowflake-only syntax like QUALIFY and IFF()
parses cleanly under all eight candidates. TestParseScoringIsWeak pins
that, since it is the concrete reason this design refuses to guess.

sqlglot logged warnings while probing wrong dialects, and in any process
with logging configured to stdout those landed inside the JSON that
`clgraph detect --json` emits. Scoring now silences sqlglot and restores
the prior level.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant