Skip to content

refactor: port clone, load, check, test, seed and diff commands, rule caches and state helpers to the native extension - #1102

Merged
kvlonge merged 37 commits into
mainfrom
feat/native-group-3
Oct 13, 2026
Merged

kvlonge merged 37 commits into
mainfrom
feat/native-group-3

Conversation

@kvlonge

@kvlonge kvlonge commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Why

Rust-hosted SQLBuild port (CHI-585), third combined PR: more Phase 3 (CHI-592) commands, the Phase 1 (CHI-589) rule engine split, Phase 4 (CHI-593) state helpers, and the CHI-599 guard for Rust-to-Python calls.

Changes

  • CLI: sqb clone, load, check, test, seed, diff; dbt interop static parts (profiles, dbt init, plan, manifest); sqb dbt ... --json progress now goes to stderr (pre-existing bug).
  • Rules: diagnostics redaction; SQL and custom-rule result caches with new key formats (one cache miss after upgrade); config loading; findings/rows; built-in catalogue. Custom-rule dispatch and thread code split out and kept in Python.
  • State: new sqlbuild-state crate for migration event IDs/SQL and freshness versions.
  • Rust imports Python only by complete literal module paths, checked by tests/unit/scripts/native_module_paths.
  • Movable Python: 89,820 → 79,435 lines.

Intentional differences: cache formats; diff cells no longer get Rich auto-highlighting/markup; traceback frames; internal Python APIs removed or renamed.

Verification

  • Per command, old vs new real CLI runs on DuckDB fixtures (clone 16, load 24, check 18, test 22, seed 19, diff 76, dbt 35) incl. warehouse state and written files: identical apart from noted differences and spinner timing.
  • Generated-input comparisons vs the old Python (event IDs, freshness, redaction, dbt profiles/TOML, diff output): 0 mismatches.
  • 10,953 focused tests incl. ~28 e2e files (dbt run locally); compiler differential with full coverage; byte-identical compile output on a 1k-model and a large private project; make check-ci.
  • Independent review: one low finding (check rows lost on non-JSON metadata), fixed with a test.

…ersions natively

The new plain-Rust sqlbuild-state crate computes the content-addressed
migration, column-rename and old-name view event IDs, renders the
idempotent event lookup and typed INSERT statements, and normalizes,
hashes, compares and age-checks source freshness data versions. Stored
IDs and hashes are pinned to values the Python implementation wrote.
Reads and writes still go through the adapter, and warehouse
orchestration stays in Python.
Secret redaction of diagnostic text and structured logging fields runs in
sqlbuild-core with Rust regex. The Python logging handlers, formatters,
filters and the LogRecord field collection stay in Python and are listed
as stays in python-boundary.toml.
SQL rule cache keys (lint settings, rule codes, model SQL and dynamic
column contract, non-model file text), stored-entry lookup and the cache
file now live in sqlbuild-rules as pure functions with a new key format
(sql-rules-v6), so the first run after upgrading misses once. A new
integration test pins cold misses, warm hits and invalidation on model,
threshold, exception-policy and rule-selection edits.
…natively

Custom-rule identities (code identity, host runtime, rule metadata, source
fingerprint, rules settings, dialect, project root), subject identities,
read-set lookup, result merging, finding validation and ordering, and the
cache file now live in sqlbuild-rules as pure functions behind a
CustomRuleCache binding, with a new key format (custom-rules-native-v1),
so the first run after upgrading misses once. Fact digests stay with the
Python fact views the rule hosts read. A new integration test pins cold
misses, warm hits, a hit through an unread model edit, and invalidation
on a rule source edit.
The native loader now returns the RulesConfig models directly and raises
RulesError or RulesConfigError itself; the allow_exceptions policy check
moves to sqlbuild-rules. The JSON configuration hand-off and its Python
normalisation are removed. Selector resolution against the compiled
project stays with the planner scope in Python.
The rules request binding now reads compiled SQL tests, scenarios and
initial findings straight from the Python objects, and evaluation,
finalisation, the SQL rule cache lookup and the custom-rule cache return
Finding models built natively. Finalisation keeps each original finding's
fixable mark natively, and undecodable cached SQL findings are dropped as
misses inside the lookup, so its handled-error entry is removed. The
Python row builders and finding decoders are deleted; a new
NativeRulesRequest.sql_facts_json accessor lets tests inspect the facts
sent to the engine.
…dules

Thread pools, futures and stop events around a rules run move to
run/rule_threads.py, and custom-rule submission beside native evaluation
moves to engine/custom_dispatch.py. Run planning, SQL rule evaluation
and result finalisation stay in run/rules.py as plain functions. The two
new modules and engine/custom_rules.py, which dispatches to the rule-host
worker pool, are listed as user-code stays.
Built-in Rule models, their declared options and guidance are built by a
native builtin_rules binding from the sqlbuild-rules catalogue, and the
early-lint SQL code selection runs natively. The JSON catalogue hand-off
and the Python option table are removed. Loading custom rule modules and
validating their declared options stay in Python with the user code.
@kvlonge
kvlonge enabled auto-merge (squash) October 13, 2026 20:34
@kvlonge
kvlonge merged commit fac17f3 into main Oct 13, 2026
40 checks passed
@kvlonge
kvlonge deleted the feat/native-group-3 branch October 13, 2026 21:08
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