Skip to content

feat(rules): read built-in rule facts with SQLQuack parsers - #1361

Closed
kvlonge wants to merge 18 commits into
mainfrom
feat/rule-facts-sqlquack
Closed

kvlonge wants to merge 18 commits into
mainfrom
feat/rule-facts-sqlquack

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Why

Stacked on #1350 (L007). Built-in rules read query facts with Polyglot's parser, tokenizer and SQL generator. SQLQuack's shared parser builds the same tree and records source ranges, so no SQL generation is needed.

Changes

  • Query facts and SQL-test fixtures parse with SQLQuack's shared parser in located mode (DuckDB, MotherDuck, Snowflake, PostgreSQL, SQLite), with tokens from its lossless tokenizer.
  • A comparison with no column anchor, such as 3 < 7, is located from its node's source range. A cast type with no item range comes from the cast node's range.
  • Snowflake's 3-argument DATEDIFF/TIMEDIFF/TIMESTAMPDIFF date part stays out of string literals.
  • BigQuery, ClickHouse, Databricks, SQL Server: built-in rules that read SQL give one L007 warning per model or SQL-test file, naming the dialect and rules. L007 never changes an exit code. Syntax errors in parsed dialects still fail.
  • Statements deeper than 512 levels are refused as before (E_GUARD_AST_DEPTH_EXCEEDED), not walked.
  • sqlbuild-rules drops polyglot-sql. The Rules page gets a per-adapter support table.

Verification

  • Parity on 8,617 compiled DuckShop models, base vs head: no new refusals. Facts and fixture summaries are identical for DuckDB (6,201), PostgreSQL (639), SQLite (340) and Snowflake (1,337 of 1,341). The other 4 differ only in a CTE cast's spelling, NUMBER(38, 3) from source vs a generated DECIMAL(38, 3); these compare equal.
  • cargo test -p sqlbuild-rules --lib: 104/104. Two-line literal comparisons fail without the node-range lookup; a 50k-term chain segfaults without the depth check.
  • E2E: one project gives SQBRMODEL102, exit 1, on DuckDB and two L007, exit 0, on BigQuery.
  • Targeted pytest on a native build (rules E2E, BigQuery/ClickHouse compile E2E, integration rules): 263 pass; the 3,000/5,000-model budgets time out locally for released wheels too.

DuckShop: already covers Snowflake DATEDIFF('day', …) and CTE casts.

A native lint response can report that the engine does not parse the project's
dialect yet. Each such file now gets one L007 warning carrying the engine's
reason, instead of looking lint-clean. A non-string reason is rejected as an
invalid response.
…le and rules run

compile and rules run kept only selected Rule codes, so an unavailable dialect
looked clean there. L007 now passes through as a warning-severity Rule
diagnostic in compile and is left out of rules run's failing-finding count.
counts_toward_exit owns the exemption.
The plan and build rules gate failed on any finding, so an L007-only project
could not plan. Rule exceptions also validate every finding's code as a rule
code and rejected L007 with an invalid-lifecycle error. The gate now counts only
findings that count toward exit, and L007 passes through rule exceptions
unsuppressed. An end-to-end test replays a cached finding as L007 and as a rule
code through compile, rules run, plan and build.
@kvlonge
kvlonge enabled auto-merge (squash) November 8, 2026 03:44

kvlonge commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

Closing: every commit on this branch is already contained in #1374 (the combined parser train), which will land this change. The branch is kept; reopen if #1374 is dropped.

@kvlonge kvlonge closed this Nov 8, 2026
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