Skip to content

Commit 0964666

Browse files
authored
feat!: remove virtual data environments and validate models at compile time (#852)
* feat: validate semantic SQL bindings and project metadata * feat: enable dialect-aware semantic type diagnostics * fix: retain semantic warnings with Polyglot 0.13.0 * fix: integrate Polyglot 0.13.1 semantic corrections * fix: explain semantic diagnostics and recover downstream cascades Add code-owned help, authored spans, schema and operand notes, SQL-test snippets, and detailed cold/warm partial-check notices. Preserve independent downstream errors with column-specific recovery. Avoid all-project schema construction per model and reuse identical SQL-test body analysis. The 1000-model guard measures 12.14s versus 8.73s on bc9a5fc, within the unchanged 14s budget. Update the dense JSON golden explicitly for the intentional empty semantic_checks_partial field: 99f2f5c6 becomes 1a9ce1be. Fingerprint normalization and time/RSS thresholds remain unchanged. * fix: honor target semantics and recover poisoned output types Accept temporal cursor families and honor Snowflake quoted-identifier session settings in offline and physical binding, including cache identity. Replace repeated character-level diagnostic alignment with lazy cached token maps. Reuse native root diagnostics while propagating unknown types through output lineage; retain independent downstream errors and avoid cascading contract warnings. Add synthetic integration coverage for temporal types, target settings, physical rebinding, repetitive SQL spans, transitive recovery, and warm-cache parity. Preserve the existing performance thresholds and semantic golden. * perf: reuse parsed SQL and guard diagnostic-heavy compilation Fuse full semantic validation with compact native analysis when input schemas are unchanged. Preserve required rebinding and cache identity, skip empty batches, and batch SQL-test interface inference. Add CI-wired guards for large diagnostic-heavy models, position-mapping scaling, and deep poisoned DAGs. Match repeated diagnostic messages by occurrence and attribute cascades through the failing output's lineage. Verify cold fusion, unchanged warm-cache reuse, and schema invalidation with synthetic integration tests. Keep existing dense performance ceilings and semantic fingerprints unchanged. * fix: integrate Polyglot 0.13.2 Snowflake semantics * fix: report resources that Rules cannot evaluate * fix: group unevaluated Rules by resource and cause * fix: preserve the custom Rule host wire contract * feat: add native binding catalogs and authored position maps * perf: move compiler binding work behind native catalogs * perf: reuse parsed ASTs during catalog validation * perf: reuse fused bindings and batch SQL normalization * test: verify target-controlled semantic cache reuse * docs: explain compiler cache bypass and warm measurement * feat!: remove virtual data environments BREAKING CHANGE: Projects run only in direct mode. Virtual commands, flags, configuration keys, state backends, and prepare_version hooks are removed. Concurrent microbatch event IDs changed; drop existing _sqlbuild_microbatches tables before the next concurrent run. Sequential runs never use this table. * test: retain direct-mode coverage and remove virtual CI paths * docs: describe direct mode and regenerate bundled references * refactor: prune orphaned virtual compiler entrypoints Remove unused public facades and their exclusive planning helpers, models, and tests. Preserve live direct-mode sibling interfaces as compiler-internal entrypoints and route direct identity hashing to its existing implementation. * docs: require real-project verification and worst-case performance guards * fix: keep supplemental clause checks partial for open inputs * fix: reject the removed clone skip-locked option * fix: reject removed unchanged-run policy and drop dead planning output * fix: preserve exact binding shapes and validate physical downstreams Compose nested normalization edits and translate native unwinds to named compiler errors. Preserve inferred and physical column identity, apply dialect-aware metadata coercion and field matching, and rebind affected downstream shapes before execution. * test: refresh dense guard fingerprints for partial-check reporting Compared normalized CLI JSON and every compiled artifact between release base 7b710a9 (0.119.1) and the combined branch for 3000, 5000 and 10000 models. The sole JSON difference is the intentional empty semantic_checks_partial field; compiled artifact paths and content hashes are identical. Base fingerprints match the former expectations in all three cases. The 1000 entry already accounts for this field. No time or RSS budgets changed. * fix: retain completed star analysis across partial cache hits Fingerprint comparisons exposed stale compact projections replacing completed derived-star output on unrelated edits, and CTE star projections losing their syntactic has_star flag. Reuse completed entry results for partial as well as complete batch hits, retain root-star identity, and invalidate older analysis cache records. Real CLI regressions compare edited cached output with an uncached oracle. * test: reconcile fresh and cached guard fingerprints with complete analysis Compared normalized base 7b710a9 and HEAD JSON plus SHA-256 maps of every compiled artifact for fresh and cached 3000/5000/10000 projects and all varied-1000 edits. Varied output differs only by the intentional empty semantic_checks_partial field. Fresh/cache differences are that field plus CHI-373 inferred-schema completion: 150/250/500 formerly zero-column derived-star shapes and 185/312/628 recovered lineage edge counts. SQL, dependency lists, all other output fields, and compiled artifact maps agree between engines in every phase. Repair invalid benchmark SQL first by qualifying input.id in projections, predicates and macro arguments. DuckDB rejects the previous unqualified id when a seed is joined. Both engines used this same corrected fixture for comparison. Partial-cache projection drift and the conflation of syntactic stars with unresolved expansion were fixed separately. Leaf edits now change only their authored query, matching the uncached result. No time, RSS or cache-size budget changed. * fix: distinguish resolved star facts from pending lineage expansion Carry native bound-star completeness through compact analysis and entry caches separately from the syntactic has_star flag. Preserve native EXCLUDE and REPLACE provenance instead of appending excluded source columns during Python fallback. Verified the real CLI/DuckDB bound projection regressions and cached-versus-uncached shape regressions. * perf: reuse the model-name set during binding graph construction Construct the immutable available-name set once rather than rebuilding all N names for each of N models. Dependency membership and ordering are unchanged. This removes quadratic Python allocation work; it does not bypass semantic validation or relax performance budgets. * test: align guard assertions with resolved-star metadata Update the compact-boundary expectation and keep the new regression fixtures compliant with repository static checks. Formatting preserves generated SQL and all measured semantic fingerprints. * fix: adopt polyglot 0.13.3 for prefix predicate parsing Pin Python 0.13.3 and Rust merge revision 76b494021afff9115e013789018b2c999ae85041. Replace the obsolete opaque-prefix-predicate expectation with real CLI coverage proving prefix NOT LIKE evaluates in WHERE and CASE, including cached Rules execution. Corpus and focused binding regressions pass; aggregate private validation confirms the unevaluated-resource fault disappears with no new diagnostics. * perf: memoize expression source shapes within the compile catalog Reuse immutable source-shape results by expression and inference policy within a catalog, including open results. Physical catalog copies preserve the memo without sharing caller-mutable result dictionaries. A CLI regression verifies shared expressions are analyzed once and changed content invalidates binding. Using the same native binary for paired CPU counters: dense 3000 source analysis falls from 720 calls / 2.066 CPU-s to 12 / 0.108; fresh 3000 falls from 2852 / 0.990 to 1426 / 0.480. Normalized JSON and the existing dense/fresh 3000 semantic fingerprints are unchanged. No budgets changed. * perf: bind model inputs in dependency-ready analysis waves Analyze open model inputs in topological waves, preserving parallel native batches within each wave. Publish completed producer shapes before consumers run, invalidate cached consumers when producer signatures change, and reuse completed cache entries across waves. Exact quoted-name binding retains its catalog-specific path. Fresh 3000 deferred requests fall from 2630 to zero. Same-binary process CPU counters: binding 7.712 to 0.002 CPU-s; total model analysis 27.049 to 18.796 CPU-s. The 150 derived-star enrichments remain separately visible for the next change. Existing fresh-3000 and all cache-3000 cold/warm/edit fingerprints are unchanged; warm keeps 3000 hits and leaf/scoped-macro edits keep 2999 hits plus one miss. Focused CLI binding/cache regressions pass. * perf: complete derived star projections during native model analysis Use the compatibility resolver for bound derived-star outputs in the first native pass, preserving the expression lineage previously recovered by enrichment. Extend the cache regression through an inferred producer. Fresh 3000 enrichment calls fall from 150 to zero with identical normalized JSON. Model-analysis CPU is 18.254 versus 18.796 seconds after dependency waves: most resolver cost moves into the first pass rather than disappearing. Native analysis is 16.569 CPU-s; deferred binding remains zero. No fingerprints or budgets changed. * perf: reuse fixture eligibility across built-in Rules Memoize supported and unsupported fixture parsing by SQL content for one fixed-dialect Rules evaluation. Preserve per-Rule unevaluated findings, suppression and grouping. On an identical dense-3000 captured Rules request, isolated native process CPU falls from 2.939 to 1.687 seconds and built_in_ms from 2226 to 808. All non-timing response fields are identical. CPU samples identify fixture eligibility parsing rather than semantic result reads; concurrent test-planning samples were excluded from attribution. Existing unevaluated CLI regressions pass. * perf: bound wave catalog preparation to referenced tables Avoid rescanning the complete accumulated catalog for each analysis wave. Validate fixed-width native lineage index triples without allocating a generator per source; retain rejection of booleans and noninteger indexes. Py-spy attributes the residual Python work to compact lineage decoding and repeated catalog preparation, while the former enrichment interval also included native work. Fresh-3000 preparation CPU changes from 0.328 to 0.274 seconds and projection CPU from 0.371 to 0.217 seconds. Overall model CPU is unchanged within sampling variability (18.254 versus 18.325); normalized output remains identical. Focused binding and cache regressions pass. * fix: preserve restored shape invalidation across analysis waves Propagate signature invalidation through the full dependent closure, including producer cache entries restored from an older compile. Complete each wave once and restrict shape completion to its participating relations. Preserve compact and entry cache probe accounting. Extend the CLI regression through restoring the producer; align unit batch expectations with dependency-ready scheduling. Focused binding, identifier and cache regressions pass. Fresh-3000 deferred binding and derived-star enrichment remain zero, and every cache-3000 cold/warm/edit fingerprint matches. Static CI checks pass after aligning import order and the repository's comment/comprehension rules. * perf: reuse parsed expressions for exact identifier binding Complete catalog-specific quoted-name validation within the native model pass, consuming the expression already returned by compilation. Preserve the existing SQL fallback when no parsed expression is available. No ASTs are retained beyond their model work item. Remove Python's forced quoted-name deferred round and assert zero deferred requests in the dialect-identity CLI regressions. A synthetic 200-model quoted chain keeps identical normalized output: deferred binding requests fall from 398 to zero, model-analysis CPU from 0.387 to 0.264 seconds. Focused schema, semantic, quoted-binding and real compiled-fact tests pass. The exact Rust 1.98 gate still reports the six pre-existing Clippy findings assigned to the separate CI-fix worker. * fix: preserve bound projections during quoted catalog validation Keep the existing borrowed-projection eligibility decision when applying parsed catalog validation. Real-project validation caught lineage drift when the quoted path skipped that decision; retain its original projection result and separately validate the saved unannotated AST. All 1016 real-project resource records and diagnostics now match the pre-optimization output. Add synthetic quoted-policy type-error and bound CASE-lineage regressions. Focused quoted/catalog checks pass (32 tests), the semantic corpus passes (227 passed, 7 expected failures), and make check-ci passes. * test: print dense compiler timings before budget assertions Emit the dense guard measurement with flushed stdout so pytest includes phase timings in captured failure output regardless of logging configuration. Keep subprocess timeouts and all wall, memory and fingerprint assertions unchanged. * test: record CPU utilization in dense compile guards Collect child user and system CPU time with GNU time and include their sum and CPU/wall ratio in the dense guard's flushed measurement output. Preserve every budget, timeout and semantic fingerprint assertion. Verified the updated measurement helper against the real CLI and replayed a recorded over-budget dense result to confirm CPU and compiler timings are printed before the existing assertion. Matching Python 3.12.13 / Rust 1.98.1 comparisons did not establish a repeatable loss of dense parallelism, so no speculative runtime scheduler change is included. * test: report compile measurements before helper failures Print wall time, user+system CPU, utilisation, peak RSS, major/minor page faults and full compiler timings from the fresh-process helper's finally block. Report unavailable fields explicitly for interrupted output. Keep every budget and subprocess timeout unchanged. Bound the measurement result's failure repr to metrics instead of rendering the entire compiled project. Verified real CLI success and semantic-failure paths emit metrics before helper assertions, plus incomplete-output and large-payload reporting. Raw hosted job logs confirm the previous caller print did execute; the aggregate failed-log view omitted its captured-output tail. * test: centralize benchmark measurement reporting Keep interrupted/completed result parsing in the benchmark infrastructure, following the repository boundary that local test helpers remain branch-free. Preserve the helper's pre-assertion reporting and bounded failure representation. make test: 7585 passed. Full static CI target, real-CLI reporting checks and public hygiene scan passed. Real 4 GiB scopes and the complete eight-commit capped sweep retained fingerprints with no memory-limit hits or major faults; no production scheduler or memory changes were justified by those measurements. * fix: satisfy clippy 1.98 lints in the native rules crate Rust 1.98 clippy rejects type_complexity, collapsible_if, manual_ok_err, manual_unwrap_or_default and needless_range_loop findings introduced by the semantic compile work. Reuse the DiagnosticRow alias for the binding signature, collapse the let chain, iterate tokens directly, bind fixture parse results with let-else, and cache the Snowflake reparse as a Result so a parse failure explicitly leaves the diagnostic unproven. * fix: test native panic conversion without an embedded interpreter cargo test runs with --all-features, which enables pyo3's extension-module feature and therefore does not link libpython. The new panic test initialised an interpreter, so the test binary failed to link once clippy stopped masking it. Extract the unwind capture and panic classification into interpreter-free helpers and test those directly. * test: give the microbatch cursor-window fixture its cursor output column CHI-373 validates model cursor metadata against the known output shape (B300), matching the documented contract that cursor is an output column. The hourly_orders fixture declared cursor order_hour without selecting it, so it could never build (delete_insert deletes by the cursor column). Select order_hour while keeping one aggregate row so the test still proves the microbatch model runs in one pass. * fix: keep unresolved star outputs open in semantic shapes A model whose root projection has a star was treated as a closed shape whenever every input had a shape, but its inferred columns only include the star expansion when native binding resolved the star against authoritative relations. A qualified star over an inferred upstream therefore produced an incomplete closed shape and false B302 errors on valid SQL-test expected columns. Require the resolved-star fact before closing such shapes; unresolved stars stay open and are reported as partial semantic checks. * fix: accept DuckDB keyword timestamp functions in semantic checks Polyglot parses CURRENT_TIMESTAMP, CURRENT_TIME, LOCALTIMESTAMP and LOCALTIME as no-paren function calls, but its DuckDB function catalogue does not list them, so valid DuckDB models failed compile with B101. Drop that unknown-function diagnostic only when every call to the name is the keyword form; the invalid parenthesized form is still rejected. * test: align SQL-test fixture cases with semantic compile validation CHI-373 makes enforced model contracts authoritative closed shapes and validates SQL-test mock and expected column names at compile time (B302). - The open star-model fixture declared an enforced contract, which the runtime contract check also treats as exact; use a partial schema without enforcement so the case still exercises an open star model. - Misspelled mock and unknown expected columns are now reported as B302 compile errors with exact positions before any connection, instead of planner fixture messages. Exit code and no-connection behaviour are unchanged. * fix: omit the semantic coverage notice when SQL validation is disabled With --no-sql-validation the compiler skips model analysis, yet compile still reported partial semantic checks, naming unselected upstream models as open inputs and advising users to declare shapes. Skip the text notice and report an empty semantic_checks_partial map when validation was disabled for the run. * fix: expand stars over inferred inputs before publishing binding shapes Binding completion published a star model's inferred columns as a closed shape once every input had a shape, but only re-analyzed the query when the star produced no columns at all. A qualified star beside explicit columns therefore published only the explicit columns, and downstream readers of the expanded columns failed with false B002 errors. Re-analyze any unresolved star once its inputs are complete, record the expansion as a resolved star, and publish star shapes only when resolved. Cached and uncached compiles report the same diagnostics. * fix: include snapshot validity columns in semantic shapes Snapshot relations add valid_from and valid_to (or their configured names) to the query output, but semantic shapes only carried the query columns. Downstream models and snapshot audits that read the validity columns failed compile with false B002 errors. Add the validity columns, with unknown types, wherever binding and metadata shapes are published, and share the default names with the snapshot executor. * test: expect compile-time B300 for invalid unique_key and cursor_inputs CHI-373 validates unique_key and cursor_inputs names against known output shapes at compile time. A snapshot unique_key missing from the query output and a cursor_inputs column absent from an enforced upstream contract are now reported as B300 compile errors with source positions, before planning or execution. Exit codes are unchanged. * test: use a runtime-only failure for the local scenario error case CHI-373 rejects unknown functions at compile time (B101), so the local scenario model calling an undefined function no longer reaches execution. Use a value conversion that only fails when DuckDB runs the model, keeping the case focused on reporting a local execution ERROR. * fix: normalize package-qualified dbt references for semantic binding Analysis normalization only recognised single-argument reference intrinsics, so __dbt_ref("package", "model") stayed in the binding SQL and planner source-binding checks reported false B002/B101 errors. In sqb dbt build that planner error fell back to a display-only plan and executed the unresolved marker. Accept the optional package argument and bind the model relation name, matching the reference's binding name. * test: cover compile lineage for a star over a joined derived table The star fix in "fix: expand stars over inferred inputs before publishing binding shapes" marks a star as resolved once its columns are known. Before that, the unresolved flag made fast lineage append a textual star expansion over every input relation, so a star over a derived table that joins a seed reported an extra edge for the seed's unprojected label column. Pin the corrected edge count on cold and warm compiles. * test: update semantic compile fingerprints for corrected star lineage "fix: expand stars over inferred inputs before publishing binding shapes" marks a star resolved once its columns are known, so fast lineage no longer appends a textual star expansion over every input. In the generated semantic projects this removes one bogus edge from each star over a nested query that joins a seed: the seed's unprojected label column. Payload comparison against the release branch shows edge_count as the only change (2 models at 3000, 7 at 10000). Compiled SQL, diagnostics and summaries are unchanged. Update the fresh-process 3000/5000/10000 fingerprints and the cache 3000/5000/10000 cold, leaf-edit, macro-edit and project-config fingerprints. Dense and varied cache fingerprints are unchanged. * fix: adopt polyglot 0.13.4 for engine-verified DuckDB and PostgreSQL types DuckDB division is DOUBLE, so plan no longer reports a false schema change for models that divide integers; bare USER and DuckDB keyword time functions resolve as functions. * feat: enforce implicit type conversions as compile errors Native W210-W216 findings are implicit conversions that the warehouse accepts but that fail or match unintended rows depending on the data. Report each as a blocking error under the SQLBuild code of the incompatibility it risks (comparisons B217, arithmetic B212, assignments B214, casts and coercible literals B218, set-operation branches B215, predicates B211, function arguments B213), with the explicit-conversion remedy. Declared UDF argument mismatches become B301 errors. Unemitted W217-W219 codes are dropped, and there is no per-model suppression. Cover star-sourced type conflicts without set operations in the E2E semantic corpus. * docs: add performance and native SQL change rules to agent instructions * feat: isolate scenario artifacts with optional run namespaces * fix: use warehouse SQL statement size limits for tests * fix: isolate chained SQL test CTE namespaces * docs: move semantic compilation and upgrade notes to the website The legacy docs folder was retired in favour of the website docs. Port the semantic compilation reference and the direct-mode and implicit-conversion upgrade notes to website pages, add them to the sidebar, drop the branch's remaining legacy docs files, and regenerate the bundled skill references from the website. * ci: add a same-runner compile performance ratio guard Absolute compile budgets must absorb large hosted-runner variance, so real regressions of 30-50% passed or failed depending on the runner. Build the pull request's base and head in one job, generate the dense or fresh 3,000-model project once, warm both builds, then alternate three cold compiles each. Fail when the head's median wall or CPU time exceeds the base's by more than 10%, and report medians, ratios, the runner CPU and per-phase timings in the job summary. Refs CHI-403. * fix: adopt polyglot 0.13.6 for star-sourced type checks Polyglot 0.13.5 type-checks star-sourced columns in every query through ordered CTE and source star expansion instead of requalifying only statements with a set operation; 0.13.6 skips requalification for stars no scope consumes. * fix: align semantic SQL normalization with compiler dollar-quote scanning The rebase onto main added the dollar_quotes quote-policy field. SQL analysis normalization already skips $$ literals itself; opt into the compiler's dollar-quote handling so tagged literals are skipped the same way, and cover a tagged literal containing an apostrophe end to end. * test: cover direct-mode janitor completion wording * docs: drop the upgrading page The removed configuration keys already fail with explicit errors, and the implicit-conversion guidance lives on the semantic compilation page, which applies to new and existing projects alike. * fix: satisfy fensu rules in star enrichment and its lineage test make check-ci and make rust-check reported two fensu faults introduced by the star-lineage work: a multi-line docstring on _complete_inferred_bindings (FFH001) and a filtered generator in the new lineage integration test (FFT104). Name the native-expansion condition instead of documenting it, and index compiled models by name in the test. No behaviour change. * fix: restore the terminal plan progress test type and satisfy fensu rules * perf: infer expression-source shapes in one batch and reuse them after compile Assembly inferred each expression source in its own native call, and the coverage, recovery and detail passes re-inferred every source under a default profile. Batch the sources and key the compile catalog's cache by expression, so later passes reuse the shapes compile validated against. * build: adopt Polyglot 0.13.7 * perf: reserve only generated-prefix names when isolating SQL test CTEs The CTE namespace lowercased and stored every token of every test's SQL to avoid collisions, although only tokens with the generated-name prefix can collide. Keep only those, and move CTE bodies into the rename instead of copying them. Rendered test artifacts are unchanged. * perf: stop scanning for a diagnostic's binary expression past its offset * perf: reuse the parsed statement for borrowed-query validation * perf: share binding-mode native queries across models with equal shapes Binding-mode models whose relation-stubbed SQL and effective analysis and binding input shapes are equal now share one native query and template. A shared result is reused only when the representative analysis succeeded without any diagnostic; otherwise each member is re-analysed with its own relation names. Qualified, quoted, colliding or otherwise lossy names keep the per-model query. Batches with recomputed members are not published to the compact-batch cache. * perf: reuse exact shared binding analyses across dependency waves Exact representative results of shared binding queries are remembered per binding catalog, keyed by stubbed SQL, effective input shapes and template inputs, and projected onto later members through their own resource names without another native call or fact decoding. Only results that analysed successfully without diagnostics are remembered, and batches that publish the compact-batch cache do not reuse them. Candidates are gated by a cheap compile-wide relation-marker pre-key so projects that barely share skip the full key. * ci: run every SQL test and ratio guard E2E file in a DuckDB shard * fix: restore the PostgreSQL CI path filter and never share stub-named SQL The virtual-state path removal dropped the PostgreSQL case pattern, which left the suite-selection script unparsable on pull requests. Separately, binding-query sharing only checked reference names for the stub prefix, so an authored CTE with a stub name could capture the shared reference. * test: measure diagnostic-heavy compiles with positioned conversion errors Implicit conversions are now blocking errors, and literal casts carry no source position, so the workload's literal-cast warnings collapsed into one statement-level error. Use column comparisons so every model still produces 100 independently positioned errors. * build: adopt Polyglot 0.13.8 * test: refresh compile guard fingerprints and set fresh budgets to measured values Chained SQL test CTE isolation renames lifted CTEs in compiled test artifacts, which changes every compile fingerprint; compile output is otherwise unchanged. Fresh cold compiles still cost more than before semantic validation, so the fresh-process and cache budgets and the fresh same-runner ratio limit are set to the measured values until the remaining gap is closed. Dense limits are unchanged. * test: raise fresh-process and cache budgets to the slowest measured CI runs * test: accept a complete wave-level cache hit after a leaf edit and settle fresh budgets Dependency-wave analysis caches each wave as its own batch, so the edit compile republishes the edited wave and the next compile is served entirely from batch hits instead of one entry hit. Assert a complete cache hit, as the macro-edit path already does. Raise the fresh 5000 and cache 5000 cold budgets to just above the slowest CI runs. * test: drop the macro-edit entry-hit requirement and settle the fresh 5000 budget Wave-level analysis batches serve every model outside the edited one from batch hits, so a macro edit re-analyses exactly one model with no entry hits. The miss count and complete-hit checks still catch any extra re-analysis. * test: refresh varied compile cache fingerprints for isolated test CTE names
1 parent 33127a2 commit 0964666

688 files changed

Lines changed: 16809 additions & 64096 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/verify.yml‎

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
performance=true
7777
rules_performance=true
7878
;;
79-
src/sqlbuild/cli/commands/_helpers/compile/*|src/sqlbuild/executor/testing/*|scripts/cold_compile_performance/*|tests/e2e/src/sqlbuild/cli/commands/main/compile/*)
79+
src/sqlbuild/cli/commands/_helpers/compile/*|src/sqlbuild/executor/testing/*|scripts/cold_compile_performance/*|scripts/compile_performance_ratio/*|scripts/compare_compile_performance.py|tests/e2e/src/sqlbuild/cli/commands/main/compile/*)
8080
broad=true
8181
performance=true
8282
;;
@@ -90,7 +90,7 @@ jobs:
9090
duckdb=true
9191
format_performance=true
9292
;;
93-
tests/e2e/src/sqlbuild/cli/commands/main/postgres/*|tests/integration/src/sqlbuild/adapters/postgres/*|tests/integration/src/sqlbuild/virtual/state/classes/postgres/*|tests/integration/src/sqlbuild/runtime/execution_history/*)
93+
tests/e2e/src/sqlbuild/cli/commands/main/postgres/*|tests/integration/src/sqlbuild/adapters/postgres/*|tests/integration/src/sqlbuild/runtime/execution_history/*)
9494
postgres=true
9595
;;
9696
tests/e2e/*)
@@ -195,14 +195,12 @@ jobs:
195195
target: test-e2e-duckdb-build-core
196196
- name: build incremental
197197
target: test-e2e-duckdb-build-incremental
198-
- name: build virtual
199-
target: test-e2e-duckdb-build-virtual
200198
- name: CLI data
201199
target: test-e2e-duckdb-cli-data
202200
- name: CLI commands
203201
target: test-e2e-duckdb-cli
204-
- name: virtual environments
205-
target: test-e2e-duckdb-virtual
202+
- name: CLI inspection
203+
target: test-e2e-duckdb-inspection
206204
- name: integrations
207205
target: test-e2e-duckdb-integrations
208206
env:
@@ -390,6 +388,62 @@ jobs:
390388
make test-e2e-dense-compile-performance \
391389
SQLBUILD_BENCHMARK_MODELS="${BENCHMARK_MODELS}"
392390
391+
- name: Run diagnostic-heavy compile guards
392+
if: matrix.models == 1000
393+
run: make test-e2e-diagnostic-compile-performance
394+
395+
compile_performance_ratio:
396+
name: Same-runner compile ratio (${{ matrix.kind }} 3000 models)
397+
needs: [changes, lockfile]
398+
if: needs.changes.outputs.performance == 'true'
399+
runs-on: ubuntu-24.04
400+
timeout-minutes: 45
401+
strategy:
402+
fail-fast: false
403+
matrix:
404+
include:
405+
- kind: dense
406+
max_ratio: "1.10"
407+
- kind: fresh
408+
max_ratio: "1.30"
409+
steps:
410+
- uses: actions/checkout@v4
411+
- name: Check out the comparison base
412+
uses: actions/checkout@v4
413+
with:
414+
ref: ${{ github.event.pull_request.base.sha || 'main' }}
415+
path: base
416+
- uses: astral-sh/setup-uv@v5
417+
with:
418+
version: "0.12.3"
419+
enable-cache: true
420+
cache-dependency-glob: |
421+
uv.lock
422+
Cargo.lock
423+
base/uv.lock
424+
base/Cargo.lock
425+
- uses: dtolnay/rust-toolchain@master
426+
with:
427+
toolchain: stable
428+
- name: Install Python
429+
run: uv python install 3.12
430+
- name: Install head dependencies
431+
run: uv sync --locked --all-groups --all-extras
432+
- name: Install base dependencies
433+
working-directory: base
434+
run: uv sync --locked --all-extras
435+
- name: Compare base and head cold compiles
436+
env:
437+
KIND: ${{ matrix.kind }}
438+
MAX_RATIO: ${{ matrix.max_ratio }}
439+
run: |
440+
uv run python -m scripts.compare_compile_performance \
441+
--kind "${KIND}" \
442+
--max-ratio "${MAX_RATIO}" \
443+
--models 3000 \
444+
--base-python base/.venv/bin/python \
445+
--head-python .venv/bin/python
446+
393447
cache_compile_performance:
394448
name: Fresh-process compile cache (${{ matrix.models }} models)
395449
needs: [changes, lockfile]
@@ -551,6 +605,7 @@ jobs:
551605
performance,
552606
cold_compile_performance,
553607
dense_compile_performance,
608+
compile_performance_ratio,
554609
cache_compile_performance,
555610
rules_performance,
556611
postgres,
@@ -568,6 +623,7 @@ jobs:
568623
PERFORMANCE_RESULT: ${{ needs.performance.result }}
569624
COLD_COMPILE_PERFORMANCE_RESULT: ${{ needs.cold_compile_performance.result }}
570625
DENSE_COMPILE_PERFORMANCE_RESULT: ${{ needs.dense_compile_performance.result }}
626+
COMPILE_PERFORMANCE_RATIO_RESULT: ${{ needs.compile_performance_ratio.result }}
571627
CACHE_COMPILE_PERFORMANCE_RESULT: ${{ needs.cache_compile_performance.result }}
572628
RULES_PERFORMANCE_RESULT: ${{ needs.rules_performance.result }}
573629
POSTGRES_RESULT: ${{ needs.postgres.result }}
@@ -587,6 +643,7 @@ jobs:
587643
"${PERFORMANCE_RESULT}" \
588644
"${COLD_COMPILE_PERFORMANCE_RESULT}" \
589645
"${DENSE_COMPILE_PERFORMANCE_RESULT}" \
646+
"${COMPILE_PERFORMANCE_RATIO_RESULT}" \
590647
"${CACHE_COMPILE_PERFORMANCE_RESULT}" \
591648
"${RULES_PERFORMANCE_RESULT}" \
592649
"${POSTGRES_RESULT}"; do

‎AGENTS.md‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,56 @@
1818
explicitly requests it; rely on CI for those suites.
1919
- Before pushing, run the exact static CI target with all optional dependencies available: `uv sync --all-extras` followed by `make check-ci`.
2020

21+
## Real-Project Verification and Performance Guards
22+
23+
- Synthetic fixtures and clean benchmark projects do not exercise every path. Before releasing
24+
changes to compilation, SQL analysis, diagnostics, formatting, Rules, or planning, run the built
25+
branch against at least one large real project available locally outside this repository, and
26+
compare it with the latest release. Compare diagnostic counts by code, cold compile wall time and
27+
peak memory, and, for formatter changes, that formatting preserves compiled dependencies, lineage,
28+
and query semantics.
29+
- Treat every new diagnostic on a real project as a false positive until warehouse evidence proves
30+
otherwise, for example a model that has built successfully since its SQL last changed.
31+
- A material slowdown or new false positive is a release blocker, not a follow-up.
32+
- Real-project names, SQL, identifiers, file paths, and results never enter this repository, commits,
33+
pull requests, or CI output. Record only neutral aggregate conclusions, and rebuild every
34+
reproduction synthetically.
35+
- Performance guards must cover worst-case paths, not only clean projects: very large models,
36+
diagnostic-heavy compiles with many errors and warnings, wide queries, and deep macro expansion.
37+
Any per-diagnostic, per-reference, or per-token work must be bounded by a test with a strict time
38+
limit. A path that is only slow when something is wrong is still a regression.
39+
40+
## Performance Work
41+
42+
- Never compare timings across different machines, runners, or sessions. Every performance claim
43+
must come from a same-machine comparison: base and candidate built from the same toolchain, run
44+
alternately at least three times each, reporting medians of both wall time and CPU time
45+
(user+sys) plus the per-phase `compile_timings`.
46+
- On shared local machines, confirm no concurrent builds or benchmarks are running and record the
47+
load average. If load exceeds the core count, treat wall times as unreliable and report CPU time.
48+
- Hosted CI runners vary by up to ~60%. Do not diagnose regressions from absolute CI budgets or
49+
from runs on different runners; use the same-runner ratio guard or a same-job paired comparison.
50+
- Before attributing a regression to a cause, prove it with an on/off experiment (a temporary
51+
kill switch or a revert) on the same machine. Profiles identify suspects; experiments convict.
52+
Remove experiment switches before committing.
53+
- Measure the modes users run: cold without cache, cold writing the cache, and warm. A change that
54+
affects analysis, validation, or caching must report all three.
55+
- Performance fixes must not reduce coverage. Show that diagnostics are unchanged or a strict,
56+
validated superset on the dense benchmark and a real-project run.
57+
- Do not raise performance budgets or tolerances to make a regression pass.
58+
59+
## Native SQL (Polyglot) Changes
60+
61+
- Treat every Polyglot change as a compiler change: before adopting a new Polyglot version, run the
62+
same-machine dense and fresh 3,000-model comparisons against the current version and report the
63+
ratio and per-phase timings.
64+
- Polyglot diagnostics adopted by SQLBuild are enforceable errors or dropped. Never surface a new
65+
native finding as a non-blocking warning; map it to a SQLBuild error code with a mechanical remedy.
66+
- Coverage conditions must not depend on incidental query shape (for example, only checking
67+
statements with a set operation). Checks apply uniformly or the gap is documented and ticketed.
68+
- Run the Polyglot feature-gate checks (`make test-rust-feature-gates`) before pushing Polyglot
69+
changes; cross-module helpers must respect feature gates.
70+
2171
## Public Repository Hygiene
2272

2373
- Treat every tracked file, generated artifact, fixture, benchmark, filename, commit, branch, pull
@@ -68,6 +118,9 @@
68118
requests local verification or CI is unavailable.
69119
- State the expected verification scope in subagent prompts and explicitly prohibit unnecessary full-suite runs.
70120
- Do not delay committing and pushing a focused fix solely to repeat checks already completed successfully by another agent or CI.
121+
- Subagents reporting performance results must include wall time, CPU time, run count, machine
122+
load, and whether base and candidate ran on the same machine. Results lacking these are
123+
hypotheses, not evidence.
71124

72125
## State and Source of Truth
73126

‎Cargo.lock‎

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fensu-policy = "=0.22.0"
1515
globset = "0.4"
1616
proc-macro2 = { version = "1", features = ["span-locations"] }
1717
pyo3 = { version = "0.26", features = ["abi3-py312"] }
18-
polyglot-sql = { git = "https://github.com/chio-labs/polyglot.git", rev = "f3774102f518f716cd648e4fdebb9d8558a0b63a", default-features = false, features = [
18+
polyglot-sql = { git = "https://github.com/chio-labs/polyglot.git", rev = "25ad011c49f2c7cd48f4427abb8fc0a6af2e4120", default-features = false, features = [
1919
"ast-tools",
2020
"builder",
2121
"dialect-bigquery",

‎Makefile‎

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ SHELL := /bin/bash
22

33
.PHONY: verify verify-quick verify-pg coverage cli-preview rust-check \
44
check-e2e-shards test-e2e-duckdb test-e2e-duckdb-build-core \
5-
test-e2e-duckdb-build-incremental test-e2e-duckdb-build-virtual \
6-
test-e2e-duckdb-cli-data test-e2e-duckdb-cli test-e2e-duckdb-virtual \
5+
test-e2e-duckdb-build-incremental \
6+
test-e2e-duckdb-cli-data test-e2e-duckdb-cli test-e2e-duckdb-inspection \
77
test-e2e-duckdb-integrations test-e2e-performance \
88
test-e2e-cold-compile-performance test-e2e-cache-compile-performance \
99
test-e2e-dense-compile-performance test-e2e-varied-cache-performance
@@ -102,24 +102,17 @@ E2E_DUCKDB_BUILD_INCREMENTAL_PATHS := \
102102
tests/e2e/src/sqlbuild/cli/commands/main/build/test_seed_watermark_build.py \
103103
tests/e2e/src/sqlbuild/cli/commands/main/build/test_snapshot_build.py
104104

105-
E2E_DUCKDB_BUILD_VIRTUAL_PATHS := \
106-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_build_state.py \
107-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_incremental_build.py \
108-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_microbatch_lifecycle.py \
109-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_mode_guard.py \
110-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_promote.py \
111-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_python_build.py \
112-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_rollback.py \
113-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_seed_build.py \
114-
tests/e2e/src/sqlbuild/cli/commands/main/build/test_virtual_source_freshness_build.py
115105

116106
E2E_DUCKDB_CLI_DATA_PATHS := \
117107
tests/e2e/src/sqlbuild/cli/commands/main/load \
118108
tests/e2e/src/sqlbuild/cli/commands/main/providers \
119-
tests/e2e/src/sqlbuild/cli/commands/main/scenario
109+
tests/e2e/src/sqlbuild/cli/commands/main/scenario/test_scenario.py \
110+
tests/e2e/src/sqlbuild/cli/commands/main/scenario/test_capture.py \
111+
tests/e2e/src/sqlbuild/cli/commands/main/scenario/test_namespace.py
120112

121113
E2E_DUCKDB_CLI_PATHS := \
122114
tests/e2e/scripts/cli_preview \
115+
tests/e2e/scripts/compile_performance_ratio \
123116
tests/e2e/src/sqlbuild/cli/commands/main/adapters \
124117
tests/e2e/src/sqlbuild/cli/commands/main/audit \
125118
tests/e2e/src/sqlbuild/cli/commands/main/bigquery \
@@ -144,23 +137,20 @@ E2E_DUCKDB_CLI_PATHS := \
144137
tests/e2e/src/sqlbuild/cli/commands/main/sqlserver \
145138
tests/e2e/src/sqlbuild/cli/commands/main/test
146139

147-
E2E_DUCKDB_VIRTUAL_PATHS := \
140+
E2E_DUCKDB_INSPECTION_PATHS := \
148141
tests/e2e/src/sqlbuild/cli/commands/main/clone \
149142
tests/e2e/src/sqlbuild/cli/commands/main/diff \
150143
tests/e2e/src/sqlbuild/cli/commands/main/janitor \
151-
tests/e2e/src/sqlbuild/cli/commands/main/plan \
152-
tests/e2e/src/sqlbuild/cli/commands/main/reconcile \
153-
tests/e2e/src/sqlbuild/cli/commands/main/state
144+
tests/e2e/src/sqlbuild/cli/commands/main/plan
154145

155146
E2E_DUCKDB_INTEGRATIONS_PATHS := tests/e2e/src/sqlbuild/integrations
156147

157148
E2E_DUCKDB_PATHS := \
158149
$(E2E_DUCKDB_BUILD_CORE_PATHS) \
159150
$(E2E_DUCKDB_BUILD_INCREMENTAL_PATHS) \
160-
$(E2E_DUCKDB_BUILD_VIRTUAL_PATHS) \
161151
$(E2E_DUCKDB_CLI_DATA_PATHS) \
162152
$(E2E_DUCKDB_CLI_PATHS) \
163-
$(E2E_DUCKDB_VIRTUAL_PATHS) \
153+
$(E2E_DUCKDB_INSPECTION_PATHS) \
164154
$(E2E_DUCKDB_INTEGRATIONS_PATHS)
165155

166156
define run_e2e_duckdb
@@ -199,17 +189,15 @@ test-e2e-duckdb-build-core:
199189
test-e2e-duckdb-build-incremental:
200190
$(call run_e2e_duckdb,$@,$(E2E_DUCKDB_BUILD_INCREMENTAL_PATHS))
201191

202-
test-e2e-duckdb-build-virtual:
203-
$(call run_e2e_duckdb,$@,$(E2E_DUCKDB_BUILD_VIRTUAL_PATHS))
204192

205193
test-e2e-duckdb-cli-data:
206194
$(call run_e2e_duckdb,$@,$(E2E_DUCKDB_CLI_DATA_PATHS))
207195

208196
test-e2e-duckdb-cli:
209197
$(call run_e2e_duckdb,$@,$(E2E_DUCKDB_CLI_PATHS))
210198

211-
test-e2e-duckdb-virtual:
212-
$(call run_e2e_duckdb,$@,$(E2E_DUCKDB_VIRTUAL_PATHS))
199+
test-e2e-duckdb-inspection:
200+
$(call run_e2e_duckdb,$@,$(E2E_DUCKDB_INSPECTION_PATHS))
213201

214202
test-e2e-duckdb-integrations:
215203
$(call run_e2e_duckdb,$@,$(E2E_DUCKDB_INTEGRATIONS_PATHS))
@@ -218,10 +206,9 @@ check-e2e-shards:
218206
bash scripts/check_e2e_shards.sh \
219207
--shard build-core $(E2E_DUCKDB_BUILD_CORE_PATHS) \
220208
--shard build-incremental $(E2E_DUCKDB_BUILD_INCREMENTAL_PATHS) \
221-
--shard build-virtual $(E2E_DUCKDB_BUILD_VIRTUAL_PATHS) \
222209
--shard cli-data $(E2E_DUCKDB_CLI_DATA_PATHS) \
223210
--shard cli $(E2E_DUCKDB_CLI_PATHS) \
224-
--shard virtual $(E2E_DUCKDB_VIRTUAL_PATHS) \
211+
--shard inspection $(E2E_DUCKDB_INSPECTION_PATHS) \
225212
--shard integrations $(E2E_DUCKDB_INTEGRATIONS_PATHS)
226213

227214

@@ -244,6 +231,13 @@ test-e2e-cold-compile-performance:
244231
-m cold_compile_performance -k "models_$(SQLBUILD_BENCHMARK_MODELS)" \
245232
-vv --log-cli-level=INFO --color=yes
246233

234+
.PHONY: test-e2e-diagnostic-compile-performance
235+
test-e2e-diagnostic-compile-performance:
236+
env PYTHONUNBUFFERED=1 SQLBUILD_CONCURRENCY=4 uv run pytest \
237+
tests/e2e/src/sqlbuild/cli/commands/main/compile/test_diagnostic_compile_performance.py \
238+
-n auto --dist loadfile -m cold_compile_performance \
239+
-vv -rP --log-level=INFO --log-cli-level=INFO --color=yes
240+
247241
test-e2e-dense-compile-performance:
248242
test -n "$(SQLBUILD_BENCHMARK_MODELS)"
249243
env PYTHONUNBUFFERED=1 SQLBUILD_CONCURRENCY=4 uv run pytest \
@@ -266,17 +260,6 @@ test-e2e-varied-cache-performance:
266260
-n auto --dist loadfile -m cache_compile_performance \
267261
-vv -rP --log-level=INFO --log-cli-level=INFO --color=yes
268262

269-
test-virtual:
270-
@mkdir -p /tmp/opencode
271-
@log="/tmp/opencode/test-virtual-$$(date +%Y%m%d-%H%M%S).log"; \
272-
echo "Logging to $$log"; \
273-
env PYTHONUNBUFFERED=1 TESTCONTAINERS_RYUK_DISABLED=true SQLBUILD_CONCURRENCY=$(SQLBUILD_CONCURRENCY) uv run pytest \
274-
$(VIRTUAL_TEST_ROOTS) \
275-
-k "$(VIRTUAL_TEST_KEYWORD)" \
276-
-m "not dbt and not performance" -vv --color=yes -n auto --dist loadfile 2>&1 | tee "$$log"; \
277-
status=$${PIPESTATUS[0]}; \
278-
echo "TEST_VIRTUAL_EXIT=$$status (log: $$log)" | tee -a "$$log"; \
279-
exit $$status
280263

281264

282265
skills:
@@ -290,8 +273,6 @@ export DBT_EXECUTABLE
290273

291274
SQLBUILD_CONCURRENCY ?= 8
292275

293-
VIRTUAL_TEST_ROOTS ?= tests/e2e/src/sqlbuild/cli/commands/main tests/e2e/src/sqlbuild/integrations/dagster
294-
VIRTUAL_TEST_KEYWORD ?= virtual or reconcile or diff or janitor or snapshot or dagster
295276

296277

297278
test-dbt:

0 commit comments

Comments
 (0)