Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
48d5a21
refactor(compiler)!: remove the python compiler engine and its dead b…
kvlonge Oct 10, 2026
2ca9ac2
test(compiler): drop python-engine parity tests and keep their covera…
kvlonge Oct 10, 2026
b3d5605
chore(compiler): regenerate the fallback allow-list without native an…
kvlonge Oct 10, 2026
44fc323
feat(native): analyse models in a ref cycle in the native session
kvlonge Oct 10, 2026
228f682
feat(native)!: normalize every type and contract natively with Python…
kvlonge Oct 10, 2026
cb862b9
fix(native): normalize nested types on the caller's stack, reading on…
kvlonge Oct 10, 2026
f553ab7
feat(native): analyse non-ASCII models natively and call project-loca…
kvlonge Oct 10, 2026
20140df
feat(native): build FAST lineage natively for every dialect and resto…
kvlonge Oct 10, 2026
acc8f36
feat(native): report model, hook, function and source syntax errors n…
kvlonge Oct 10, 2026
1634a4a
feat(native): fail compilation on internal native analysis failures
kvlonge Oct 10, 2026
1cbb2e5
feat(native): fail FAST lineage on internal native failures without t…
kvlonge Oct 10, 2026
fb7f362
test(native): pin former Python-oracle cases to recorded expected out…
kvlonge Oct 10, 2026
88a1de2
feat(native)!: complete semantic diagnostics natively for every diale…
kvlonge Oct 10, 2026
d2e3f19
feat(native): infer every expression-source shape natively
kvlonge Oct 10, 2026
3bd3a86
feat(native)!: infer columns outside the analysis session natively
kvlonge Oct 10, 2026
a247b9c
feat(native)!: assemble every SQL test and scan every bridged macro c…
kvlonge Oct 10, 2026
dbe70e9
feat(native): carry project graph facts in the native assembly request
kvlonge Oct 10, 2026
e54c565
feat(native)!: scan macro call names natively and expand unbridged st…
kvlonge Oct 10, 2026
ce9f3ca
feat(native): keep typed output columns and dynamic proofs on the fin…
kvlonge Oct 10, 2026
44cd32a
refactor(native): bring the lane's native ports in line with the stru…
kvlonge Oct 10, 2026
7f21fa6
feat(native): expose each model's retained session columns and dynami…
kvlonge Oct 10, 2026
7af82af
feat(native)!: scan nested macro arguments natively
kvlonge Oct 10, 2026
20fdbb7
feat(native): read fixture projection facts natively
kvlonge Oct 10, 2026
c8c3951
feat(native): substitute placeholder defaults natively for analysis
kvlonge Oct 10, 2026
cf64a19
refactor(compiler): delete the unused Python binding-share and qualif…
kvlonge Oct 10, 2026
1d05892
feat(native): normalize parse and legacy query SQL inside native colu…
kvlonge Oct 10, 2026
4bdc0cc
feat(native): collect SQL-test declaration usages from the native ref…
kvlonge Oct 10, 2026
9522116
feat(native): extract hard-coded relation names natively
kvlonge Oct 10, 2026
f0bb556
feat(native): read SQL-test helper CTE reads from the native parse
kvlonge Oct 10, 2026
be1188a
fix(native)!: raise native project assembly panics instead of retryin…
kvlonge Oct 10, 2026
7417e47
feat(native): compose a model's final columns natively in Python's order
kvlonge Oct 10, 2026
87e83e9
feat(native): raise Python's project assembly errors natively without…
kvlonge Oct 10, 2026
61ac780
feat(native): scan SQL test and scenario CTEs natively for every cons…
kvlonge Oct 10, 2026
a074998
feat(native): run compile's explicit-reference checks natively
kvlonge Oct 10, 2026
2b6744b
fix(native): preserve POSIX paths in unknown hook-read diagnostics
kvlonge Oct 10, 2026
04462d5
test: align compiler regression instrumentation with native APIs
kvlonge Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 1 addition & 7 deletions .github/workflows/compiler-differential.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,8 @@ jobs:
run: uv python install 3.12
- name: Install dependencies
run: uv sync --locked --all-groups --all-extras
- name: Compare dense projects with and without custom rules on the preview engine
- name: Compare dense projects with and without custom rules (native vs native-preview)
env:
MODELS: ${{ matrix.models }}
run: make compiler-differential-dense COMPILER_DIFFERENTIAL_DENSE_MODELS="${MODELS}"
- name: Compare dense projects with and without custom rules on the shipped engine
env:
MODELS: ${{ matrix.models }}
run: >-
make compiler-differential-dense COMPILER_DIFFERENTIAL_DENSE_MODELS="${MODELS}"
COMPILER_DIFFERENTIAL_ARGS="--engines python native"

51 changes: 15 additions & 36 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ jobs:
run: uv python install 3.12
- name: Install dependencies
run: uv sync --locked --all-groups --all-extras
- name: Compare fixtures, examples, generated seeds and the failure corpus (python vs native-preview)
- name: Compare fixtures, examples, generated seeds and the failure corpus (native vs native-preview, goldens)
run: >-
make compiler-differential
COMPILER_DIFFERENTIAL_ARGS="--stage-captures --require-discovery-coverage
Expand All @@ -318,12 +318,6 @@ jobs:
path: ${{ runner.temp }}/compiler-differential-wheel-sites.json
if-no-files-found: warn
retention-days: 30
- name: Compare fixtures, examples, generated seeds and the failure corpus (python vs shipped native)
run: >-
make compiler-differential-shipped
COMPILER_DIFFERENTIAL_ARGS="--stage-captures --require-discovery-coverage
--require-render-coverage --require-analysis-coverage
--evidence-dir ${{ runner.temp }}/compiler-differential-evidence/shipped"
- name: Upload differing projects' targets, stderr and compiled-test stats
if: failure()
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -370,19 +364,13 @@ jobs:
uv run --no-sync pytest
tests/integration/src/sqlbuild/compiler/test_native_python_compat_oracle.py
-n auto --dist loadfile
- name: Compare python with native-preview on fixtures, examples, the failure corpus and a few seeds
- name: Compare native with native-preview and the goldens on fixtures, examples, the failure corpus and a few seeds
env:
PYTHONUNBUFFERED: "1"
run: >-
uv run --no-sync python -m scripts.run_compiler_differential
--engines python native-preview
--engines native native-preview --goldens check
--corpus fixtures examples failures seeds --seeds 4 --jobs 4
- name: Compare python with shipped native on the failure corpus and a few seeds
env:
PYTHONUNBUFFERED: "1"
run: >-
uv run --no-sync python -m scripts.run_compiler_differential
--engines python native --corpus failures seeds --seeds 4 --jobs 4

native_discovery_windows:
name: Native compiler on Windows
Expand Down Expand Up @@ -420,14 +408,14 @@ jobs:
tests/integration/src/sqlbuild/compiler/discovery/test_native_yaml_oracle.py
tests/integration/src/sqlbuild/compiler/discovery/test_native_toml_oracle.py
-n auto --dist loadfile
- name: Compile playground projects on the default and Python engines, and build
- name: Compile playground projects on the default and preview engines, and build
run: |
project="${RUNNER_TEMP}/waffle-shop"
oracle="${RUNNER_TEMP}/waffle-shop-python"
oracle="${RUNNER_TEMP}/waffle-shop-preview"
uv run --no-sync sqb playground "${project}"
cp -r "${project}" "${oracle}"
uv run --no-sync sqb --project-dir "${project}" --no-color compile
SQLBUILD_COMPILER_ENGINE=python uv run --no-sync sqb --project-dir "${oracle}" --no-color compile
SQLBUILD_COMPILER_ENGINE=native-preview uv run --no-sync sqb --project-dir "${oracle}" --no-color compile
diff -r "${oracle}/target/compiled" "${project}/target/compiled"
if ! test -f "${project}/target/cache/compiler-native-v1/macro-calls.bin"; then
echo "The default compile did not write the macro-call store; macro bridge debug log:"
Expand Down Expand Up @@ -611,24 +599,18 @@ jobs:
- kind: fresh
max_ratio: "1.10"
- kind: dense
label: native contracts vs python
base_engine: python
head_engine: native
label: contracts CPU vs base
gate_phase: contracts_cpu_ms
max_ratio: "1.00"
max_ratio: "1.10"
- kind: dense
label: native model analysis vs python
base_engine: python
head_engine: native
label: model analysis CPU vs base
gate_phase: model_analysis_cpu_ms
compile_args: --compile-arg=--select=*
max_ratio: "1.50"
max_ratio: "1.10"
- kind: dense
label: native custom rules vs python
base_engine: python
head_engine: native
label: custom rules CPU vs base
gate_phase: custom_rules_cpu_ms
max_ratio: "1.25"
max_ratio: "1.10"
steps:
- uses: actions/checkout@v4
- name: Check out the comparison base
Expand All @@ -655,13 +637,11 @@ jobs:
- name: Install base dependencies
working-directory: base
run: uv sync --locked --all-groups --all-extras
- name: Compare python and native phase CPU on head
- name: Compare base and head phase CPU
if: matrix.gate_phase
env:
KIND: ${{ matrix.kind }}
MAX_RATIO: ${{ matrix.max_ratio }}
BASE_ENGINE: ${{ matrix.base_engine }}
HEAD_ENGINE: ${{ matrix.head_engine }}
GATE_PHASE: ${{ matrix.gate_phase }}
COMPILE_ARGS: ${{ matrix.compile_args }}
run: |
Expand All @@ -670,10 +650,9 @@ jobs:
--modes cold \
--max-ratio "${MAX_RATIO}" \
--models 3000 \
--base-python .venv/bin/python \
--base-root base \
--base-python base/.venv/bin/python \
--head-python .venv/bin/python \
--base-engine "${BASE_ENGINE}" \
--head-engine "${HEAD_ENGINE}" \
--gate-phase "${GATE_PHASE}" \
${COMPILE_ARGS:+"${COMPILE_ARGS}"}
- name: Compare base and head cold, warm and one-model edit compiles
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 1 addition & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,7 @@ pyo3 = { version = "0.26", features = ["abi3-py312"] }
polyglot-sql = { git = "https://github.com/chio-labs/polyglot.git", rev = "ca9e7b6e405fb6f5484472bb08780268789c5e04", default-features = false, features = [
"ast-tools",
"builder",
"dialect-bigquery",
"dialect-databricks",
"dialect-duckdb",
"dialect-postgresql",
"dialect-snowflake",
"dialect-tsql",
"all-dialects",
"semantic",
"stacker",
] }
Expand Down
15 changes: 2 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ SHELL := /bin/bash
test-e2e-duckdb-integrations test-e2e-performance \
test-e2e-cold-compile-performance test-e2e-cache-compile-performance \
test-e2e-dense-compile-performance test-e2e-varied-cache-performance \
compiler-differential compiler-differential-shipped compiler-differential-dense \
compiler-differential compiler-differential-dense \
compiler-baselines

format:
Expand Down Expand Up @@ -291,7 +291,6 @@ test-e2e-varied-cache-performance:

COMPILER_DIFFERENTIAL_JOBS ?= 4
COMPILER_DIFFERENTIAL_SEEDS ?= 12
COMPILER_DIFFERENTIAL_SHIPPED_SEEDS ?= 12
COMPILER_DIFFERENTIAL_DENSE_MODELS ?= 3000
COMPILER_DIFFERENTIAL_ARGS ?=
# Native-to-Python fallbacks and analysis deferrals must match the allow-list exactly, and every
Expand All @@ -303,23 +302,13 @@ compiler-differential:
--jobs $(COMPILER_DIFFERENTIAL_JOBS) --seeds $(COMPILER_DIFFERENTIAL_SEEDS) \
$(COMPILER_DIFFERENTIAL_GATES) $(COMPILER_DIFFERENTIAL_ARGS)

# python vs native-preview above covers every native stage; this keeps the shipped `native` default
# (native discovery, rendering and analysis) and its goldens covered on the same corpus.
compiler-differential-shipped:
env PYTHONUNBUFFERED=1 uv run python -m scripts.run_compiler_differential \
--engines python native --corpus fixtures examples seeds failures \
--jobs $(COMPILER_DIFFERENTIAL_JOBS) --seeds $(COMPILER_DIFFERENTIAL_SHIPPED_SEEDS) \
$(COMPILER_DIFFERENTIAL_GATES) $(COMPILER_DIFFERENTIAL_ARGS)

# Rewrite the goldens (from the python oracle) and the fallback allow-list from both CI runs.
# Rewrite the goldens (from the native oracle) and the fallback allow-list from the CI run.
# Review the diff like code; see scripts/compiler_differential/README.md.
COMPILER_DIFFERENTIAL_CI_ARGS := --stage-captures --require-discovery-coverage --require-render-coverage
compiler-baselines:
rm -rf tests/goldens/compiler
$(MAKE) compiler-differential COMPILER_DIFFERENTIAL_ARGS="$(COMPILER_DIFFERENTIAL_CI_ARGS) \
--require-analysis-coverage --native-fallbacks update --goldens update"
$(MAKE) compiler-differential-shipped COMPILER_DIFFERENTIAL_ARGS="$(COMPILER_DIFFERENTIAL_CI_ARGS) \
--require-analysis-coverage --native-fallbacks update --goldens update"

compiler-differential-dense:
env PYTHONUNBUFFERED=1 uv run python -m scripts.run_compiler_differential \
Expand Down
29 changes: 13 additions & 16 deletions crates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,32 +58,29 @@ stages run natively:

| Engine | Runs |
|---|---|
| `python` | The Python compiler only. It is the oracle every native stage must match byte for byte. |
| `native` | The default: native stages that passed their flip gate (`shipped` tier). |
| `native` | The default: discovery, rendering and analysis, and every native stage that passed its flip gate (`shipped` tier). |
| `native-preview` | Opt-in: shipped stages plus stages still in development (`preview` tier). |

The shipped tier covers discovery, rendering and analysis: declaration files and scopes, model
config, reference extraction, the model loop, macro calls and the macro-call store, attachments,
the type system, model analysis and its `model-analyses.bin` cache, semantic checks, contracts,
lineage facts, SQL-test glue and project assembly. A failing
render raises its first error directly, as the Python stage would, and runs each macro call at
most once; a divergence the bridge detects is reported as a native stage mismatch. Because the
macro-call store is shipped, the
The Python compiler and its `python` engine were removed once discovery, rendering and analysis
shipped natively; setting `python` is an error that says so. Native stages still hand inputs they
cannot reproduce exactly back to Python helpers (the allow-list in
`scripts/compiler_differential/native_fallbacks.toml` lists every such deferral the corpus
reaches). A failing render raises its first error directly and runs each macro call at most
once; a divergence the bridge detects is reported as a native stage mismatch. Because the
macro-call store is always on, the
[macro determinism contract](../website/src/content/docs/docs/concepts/macros.mdx) applies to
every default compile; `SQLBUILD_COMPILER_ENGINE=python` runs every macro call each time.
every compile.

Each native stage declares its tier once, in `NATIVE_STAGE_TIERS` in
`src/sqlbuild/compiler/frontier/constants.py`. A stage moves from `preview` to `shipped` by
changing that line, after its flip gate passes: a byte-identical real project, a green
differential, and no measured slowdown on cold, edit and no-change compiles. Every engine keeps
its own compiler, Rules and compile-reuse stores, so preview output is never reused by `native`.

`make compiler-differential` compares `python` with `native-preview` on the full per-PR corpus.
`make compiler-differential-shipped` compares `python` with `native` on the generated seeds and
the failure corpus, so the shipped default stays covered on its own; CI runs it with stage
captures and requires full discovery and render coverage. CI runs both, compares `python` with
`native` and `native-preview` on Python 3.13 and 3.14 as well, and on Windows checks that the
default compiles a playground project to the same files as `python`.
`make compiler-differential` compares `native` with `native-preview` on the full per-PR corpus
and checks both against the goldens in `tests/goldens/compiler`, with stage captures and full
discovery, render and analysis coverage required. CI also runs it on Python 3.13 and 3.14, and
on Windows checks that both engines compile a playground project to the same files.

## Working on the crates

Expand Down
1 change: 1 addition & 0 deletions crates/sqlbuild-analysis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ sha2.workspace = true
sqlbuild-cache.workspace = true
sqlbuild-core.workspace = true
sqlbuild-model-config.workspace = true
sqlbuild-render.workspace = true
sqlbuild-scopes.workspace = true
sqlbuild-sqltext.workspace = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ impl AnalysisSession {
session_digest: session_digest(&self.request),
keys: vec![None; models],
hits: vec![false; models],
uncacheable: vec![false; models],
legacy_tables: vec![None; models],
stats: AnalysisCacheStats::default(),
});
Expand Down Expand Up @@ -100,6 +99,7 @@ impl AnalysisSession {
}
}
key.flag(self.dependency_ordered);
key.flag(self.cyclic);
key.finish()
}

Expand Down Expand Up @@ -411,12 +411,11 @@ impl<'a> Decoder<'a> {
pub(crate) fn encode_outcome(
outcome: &ModelOutcome,
legacy_tables: Option<&ContentDigest>,
) -> Option<Vec<u8>> {
) -> Vec<u8> {
let analysis: &ModelAnalysis = &outcome.analysis;
let (tag, rows) = match &analysis.lineage {
LineageFacts::Native(rows) => (LINEAGE_NATIVE, rows),
LineageFacts::NativeFacts(rows) => (LINEAGE_FACTS, rows),
LineageFacts::PythonAnalysis | LineageFacts::PythonEnrichment => return None,
};
let mut encoder: Encoder<'_> = Encoder::default();
match legacy_tables {
Expand Down Expand Up @@ -464,7 +463,7 @@ pub(crate) fn encode_outcome(
encoder.text(severity);
}
encoder.flag(analysis.binding_validated);
Some(encoder.into_bytes())
encoder.into_bytes()
}

/// The outcome [`encode_outcome`] stored, validated against `schema`, without cleaned SQL.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! A session copy of the compile's binding catalog that records what Python's would gain.
//! The session's binding catalog copy and Python's published relation shapes.

use std::collections::{HashMap, HashSet};

use crate::assembly::analysis_session::_helpers::compact_batch::{MemoKey, SharedResult};
use crate::assembly::analysis_session::_helpers::mappings::{
ShapeTable, catalog_columns, catalog_relations, same_mapping,
ShapeTable, catalog_columns, catalog_relations, same_mapping, with_pair,
};
use crate::assembly::analysis_session::constants::{QUOTED_IDENTIFIER_DELIMITER, UNKNOWN_TYPE};
use crate::assembly::analysis_session::types::{Pairs, Shapes};
use crate::semantic_validation::models::{Columns, ProjectCatalog};
use crate::semantic_validation::main::normalize::normalize_analysis_sql;
use crate::semantic_validation::models::{Columns, NormalizationInput, ProjectCatalog};
use crate::semantic_validation::types::{BindingRequest, Relations};

/// Python's `BindingCatalog` state that model analysis reads and changes.
Expand Down Expand Up @@ -143,3 +145,71 @@ impl SessionCatalog {
(self.additions, self.analysis_names)
}
}

/// How a session publishes relation shapes.
pub(crate) struct ShapeOptions<'a> {
pub(crate) dialect: &'a str,
pub(crate) case_sensitive: bool,
}

/// One relation's inferred columns and the SQL and inputs they came from.
pub(crate) struct ShapeSource<'a> {
pub(crate) sql: &'a str,
pub(crate) columns: Pairs,
pub(crate) inputs: &'a Shapes,
pub(crate) snapshot_columns: Option<&'a (String, String)>,
}

impl SessionCatalog {
/// A model relation's shape, including snapshot validity columns.
pub(crate) fn published_model_shape(
&self,
options: &ShapeOptions<'_>,
source: ShapeSource<'_>,
) -> Result<Pairs, String> {
let snapshot_columns: Option<&(String, String)> = source.snapshot_columns;
let mut shape: Pairs = self.inferred_binding_shape(options, source)?;
if let Some((valid_from, valid_to)) = snapshot_columns {
shape = with_pair(shape, valid_from, UNKNOWN_TYPE);
shape = with_pair(shape, valid_to, UNKNOWN_TYPE);
}
Ok(shape)
}

/// Column names keep authored quoting only where the dialect binds quoted names exactly.
pub(crate) fn inferred_binding_shape(
&self,
options: &ShapeOptions<'_>,
source: ShapeSource<'_>,
) -> Result<Pairs, String> {
if !options.case_sensitive {
return Ok(source.columns);
}
let normalized: String = normalize_analysis_sql(NormalizationInput {
sql: source.sql.to_owned(),
dialect: options.dialect.to_owned(),
stubs: HashMap::new(),
placeholders: HashMap::new(),
})?;
if !normalized.contains(QUOTED_IDENTIFIER_DELIMITER) && !has_exact_input(source.inputs) {
return Ok(source.columns);
}
Ok(self
.native
.inferred_schema(
&normalized,
catalog_columns(&source.columns),
catalog_relations(source.inputs),
)?
.into_iter()
.map(|(name, data_type)| (name, data_type.unwrap_or_default()))
.collect())
}
}

fn has_exact_input(inputs: &Shapes) -> bool {
inputs
.iter()
.flat_map(|(_, shape)| shape.iter())
.any(|(name, _)| name.contains(QUOTED_IDENTIFIER_DELIMITER))
}
Loading
Loading