Uh oh!
There was an error while loading. Please reload this page.
feat(backend/kernel): add use_kernel=True flag — route through the Rust kernel via PyO3 - #787
Conversation
vikrantpuppala
commented
May 14, 2026
Two updates since the initial PR: 1. Dropped External auth → PAT-only on the kernel backend (25723627). 2. Live e2e tests moved into the repo (6b308156). The previous ad-hoc The auth_bridge unit tests are updated: OAuth providers / ExternalAuthProvider now assert |
vikrantpuppala
commented
May 14, 2026
CI status, final: 33 / 34 checks pass. The one failing check ( Failure breakdown:
My PR contributions to this job (all working as intended):
I don't believe my PR should be responsible for fixing the 7 pre-existing failures — they need their own fixes (server-side investigation for MST metadata; switching |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
vikrantpuppala
commented
May 15, 2026
Code Review Squad — Failed Inline CommentsCould not post inline comments for: F2, F4, F7, F10, F11, F13, F14, F19, F22, F25 — see body below. F2 — Federated-PAT token refresh is dead — single snapshot at construct timeHigh severity — flagged by security + devils-advocate
The bridge captures only the first exchanged token and never re-extracts. Long-running kernel sessions outlive the exchanged token's TTL and start failing The bridge's own docstring acknowledges this failure mode while justifying OAuth rejection: "routing OAuth through PAT would silently break token refresh during long-running sessions." That exact failure mode applies to the federated-PAT case the bridge accepts. Recommend: either (a) propagate a refresh callback into the kernel F4 — |
…ve review fixes
Major change: route the kernel backend through a new ``use_kernel=True``
connection kwarg instead of repurposing ``use_sea=True``. ``use_sea=True``
once again routes to the native pure-Python SEA backend (no behaviour
change); ``use_kernel=True`` routes to the Rust kernel via PyO3. The
two flags are mutually exclusive.
This addresses the largest reviewer concern from the multi-agent
review: silently hijacking a documented public flag broke OAuth /
federation / parameter-binding callers on ``use_sea=True`` who had no
opt-out. With the new flag, the kernel backend is fully opt-in and
existing ``use_sea=True`` users continue to get the native SEA backend
they signed up for.
Other substantive fixes:
- session.py: restore ``SeaDatabricksClient`` import + routing. Reject
``use_kernel=True`` + ``use_sea=True`` together with a clear
``ValueError``.
- client.py (kernel ``Cursor.columns``): update docstring to flag the
``catalog_name=None`` divergence — kernel requires a catalog,
Thrift / native SEA do not (F13).
- conftest.py: drop the collection-time ``pytest_collection_modifyitems``
hook that was skipping ``extra_params={"use_sea": True}`` cases. With
``use_sea=True`` back on the native SEA backend, those cases run as
they did before this PR (F8).
- kernel/client.py: ``get_tables`` now applies the ``table_types``
filter client-side using ``ResultSetFilter._filter_arrow_table``
(the same helper the native SEA backend uses), wrapped in a tiny
``_StaticArrowHandle`` that flows the filtered table back through
the normal ``KernelResultSet`` path. Replaces the previous
"log a warning and return unfiltered" behaviour (F4).
- kernel/client.py: guard ``_async_handles`` with ``threading.RLock``
so concurrent cursors on the same connection don't race on
submit / close / close-session (F15).
- kernel/result_set.py: ``KernelResultSet.close()`` now drops the
entry from ``backend._async_handles`` so async-submitted statements
don't leave stale references behind (F5).
- kernel/{__init__,client,auth_bridge}.py, tests/e2e/test_kernel_backend.py:
update docstrings, error messages, and the e2e fixture to refer to
``use_kernel=True`` instead of ``use_sea=True``.
- client.py (``Connection`` docstring): document the new
``use_kernel`` kwarg + its Phase-1 limitations.
New tests:
- tests/unit/test_kernel_client.py (38 cases): cover the 14-entry
``_CODE_TO_EXCEPTION`` table, ``_reraise_kernel_error`` attribute
forwarding, the 6-entry ``_STATE_TO_COMMAND_STATE`` table, the
no-open-session guards on every method, ``open_session`` double-open,
``parameters`` / ``query_tags`` rejection, ``get_columns``'
catalog-required check, ``cancel_command`` / ``close_command``
no-handle tolerance, ``get_query_state`` sync-path SUCCEEDED, the
Failed-state re-raise, the synthetic-command-id UUID shape, and
``close_session`` cleanup even when per-handle close errors fire.
Uses a fake ``databricks_sql_kernel`` module installed into
``sys.modules`` so the test runs with no Rust extension dependency
(F9).
77/77 kernel unit tests pass.
Co-authored-by: Isaac
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>- src/databricks/sql/backend/kernel/result_set.py: fix the 3 mypy errors at L237/239/241 by casting ``self.backend`` to ``KernelDatabricksClient`` (the base ``DatabricksClient`` doesn't declare ``_async_handles`` / ``_async_handles_lock``). Folds in gopalldb's nit (3249904284) — replace the explicit ``acquire()/try/finally/release()`` with a ``with`` block to match the rest of the file. - tests/e2e/test_kernel_backend.py: harden the module-level skip so the suite doesn't run when the kernel wheel is absent in CI. The unit suite installs a fake ``databricks_sql_kernel`` ``ModuleType`` into ``sys.modules`` so the connector's import-time ``import databricks_sql_kernel`` succeeds without the Rust extension; that fake leaks across into the same pytest session and ``pytest.importorskip`` happily returns it. A real wheel exposes ``__file__`` (compiled extension on disk); the fake does not. Skip the module when ``__file__`` is missing. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
24e9a5c to
5a6f1f0Comparem1 — install hint (comment 3249904266): The ``databricks-sql-kernel`` wheel is not yet published on PyPI; ``pip install databricks-sql-kernel`` either finds nothing or pulls a squatted package. Drop the misleading hint from ``ImportError`` and from the ``use_kernel`` docstring on ``databricks.sql.connect``; point users at the ``maturin develop --release`` dev path until the wheel ships. m4a — auth_bridge ValueError → ProgrammingError (comment 3249904276): Two sites in ``_extract_bearer_token`` / ``kernel_auth_kwargs`` were raising bare ``ValueError`` for caller-misuse cases (control chars in the token, PAT provider that produced no Authorization header). The rest of the kernel-backend error surface uses PEP 249 exception types — code paths that catch ``DatabaseError`` / ``ProgrammingError`` would miss these. Convert to ``ProgrammingError`` and update the unit test. m4b — description null_ok (comment 3249904282): ``description_from_arrow_schema`` was hardcoding the 7th tuple element to ``None`` even though ``pyarrow.Field.nullable`` is available. PEP 249 §Cursor.description defines ``null_ok`` as "True if NULL values are allowed"; callers branching on it would have lost useful information the kernel already provides. Now emits ``field.nullable``; added a unit test covering both nullable and non-nullable fields; updated the two existing tests that asserted the old all-``None`` shape. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Addresses gopalldb's four major / two minor remaining review comments. The shared error-mapping primitives move to a new ``_errors.py`` module so both ``client.py`` and ``result_set.py`` can use them without ``result_set.py`` importing from ``client.py``. M1 — async handle leak in get_execution_result (3249904251): ``ResultStream`` from ``await_result()`` is wrapped in ``KernelResultSet``; the underlying ``ExecutedAsyncStatement`` has no further role once the stream is in hand. Close it immediately, drop the entry from ``_async_handles``, and add the guid to ``_closed_commands``. A failed ``async_exec.close()`` is logged but doesn't break the result-set return — the kernel's Drop impl reaps server-side state. M2 — PyO3 native exceptions wrapped as OperationalError (3249904255): Added ``kernel_call(what)`` context manager (in the new ``_errors.py``). ``KernelError`` flows through ``reraise_kernel_error`` as before; anything else (``TypeError`` / ``OverflowError`` / ``ValueError`` from PyO3 argument conversion, extension-internal errors) is wrapped in ``OperationalError`` so DB-API callers only ever see PEP 249 exception types. Applied at every PyO3 call site: ``open_session``, ``execute_command``, ``cancel_command``, ``close_command``, ``get_query_state``, ``get_execution_result``, ``get_catalogs`` / ``get_schemas`` / ``get_tables`` / ``get_columns``, plus ``fetch_next_batch`` / ``arrow_schema`` in ``KernelResultSet``. M3 — KernelError during result-set construction (3249904259): ``KernelResultSet.__init__`` calls ``kernel_handle.arrow_schema()`` which can itself raise. Every call to ``_make_result_set`` is now inside a ``kernel_call`` scope so the schema-fetch error becomes a mapped PEP 249 exception instead of leaking raw ``KernelError``. m3 — get_query_state of a closed async command (3249904273): Added ``_closed_commands: Set[str]`` (guarded by the existing ``_async_handles_lock``). ``close_command`` records the guid; ``close_session`` records every swept guid; ``get_execution_result`` records its own command after closing the async_exec. ``get_query_state`` now returns ``CommandState.CLOSED`` instead of falling through to ``SUCCEEDED`` for these. m2 — unit test for get_tables table_types client-side filter (3249904269): Added ``test_get_tables_with_table_types_filters_rows`` and ``test_get_tables_without_table_types_returns_full_stream`` in ``tests/unit/test_kernel_client.py``. The first feeds a fake stream with mixed ``TABLE`` / ``VIEW`` rows and asserts only ``TABLE`` survives; the second confirms the no-filter path bypasses the drain-and-rewrap and returns all rows unchanged. Plus new tests for every change above: - test_pyo3_native_exception_wrapped_as_operational_error (M2) - test_pyo3_native_exception_wrapped_for_metadata_calls (M2) - test_kernel_error_during_result_set_construction_is_mapped (M3) - test_get_execution_result_closes_async_exec_and_drops_tracking (M1) - test_get_execution_result_does_not_raise_on_async_exec_close_failure (M1) - test_get_query_state_returns_closed_after_close_command (m3) - test_close_session_marks_swept_handles_as_closed (m3) 87/87 kernel unit tests pass (added 9). Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
vikrantpuppala
commented
May 18, 2026
Review round-trip — addressed gopalldb's 9 unresolved comments + CI-greening pass. Three commits since the last review pass:
M4 (GIL release in |
…plicit try/except
Using a ``with`` block for error translation is bad form: ``with``
conventionally signals resource lifecycle (locks, files), so
``with kernel_call("X"):`` hides the fact that the block raises a
mapped exception. Replace with explicit ``try/except Exception as
exc: raise _wrap_kernel_exception("X", exc) from exc`` at every
PyO3 call site.
What changed:
- ``_errors.py``: drop the ``kernel_call`` context manager; export
``wrap_kernel_exception(what, exc)`` — a pure function that maps
a raw exception to a PEP 249 one (KernelError → mapped class via
``reraise_kernel_error``; existing Error → passthrough; anything
else → OperationalError).
- ``client.py``: replace 12 ``with _kernel_call(...):`` blocks with
inline try/except calling the helper.
- ``result_set.py``: same for the 3 sites (arrow_schema on
construct, fetch_next_batch in _pull_one_batch, fetch_next_batch
in _drain).
Behaviour is unchanged — same KernelError → PEP 249 mapping, same
non-KernelError → OperationalError wrapping. Just spelled in a way
that makes control flow visible at the call site and keeps
tracebacks one frame shorter (no ``__exit__`` frame).
87/87 kernel unit tests still pass.
Co-authored-by: Isaac
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>Fixes ``check-linting`` CI: one long line in ``execute_command``'s async-submit branch needed to wrap (the ``CommandId.from_sea_statement_id`` call). Pure formatting; no behaviour change. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
gopalldb
commented
May 18, 2026
P0 — Critical (must fix before merge)
P1 — Important (should fix)
|
Local kernel-package fixes from the follow-up review pass on PR #787 (#787 (comment)). The two cross-cutting / pre-existing issues (P0 #1 async leak in shared ``Cursor.close()``, P1 #8/#9 fetch-after-close not raising ``InterfaceError``) are tracked separately as #791 and #792 — they affect Thrift and SEA equally and are out of scope for this PR. P1 #2 — call ``backend.close_command`` from ``KernelResultSet.close()``: The override previously bypassed the base ``ResultSet.close()`` entirely. Honour the contract by invoking ``backend.close_command(self.command_id)`` after the per-handle close + ``_async_handles`` pop. Our own ``close_command`` is tolerant of already-popped guids (no-op), so this is safe even though the per-handle close above already released server-side state. Doesn't go through ``super().close()`` directly because the base path warns when ``self.results`` is ``None`` (which it is for kernel result sets) — replicate the meaningful part of the base contract without the noisy warning. P1 #3 — case-insensitive ``Bearer`` prefix in auth_bridge: RFC 6750 §2.1 says the Authorization scheme is case-insensitive. Match leniently in case a federation proxy or future provider normalises the casing differently — failing closed would surface as a confusing ``ProgrammingError`` from the bridge. P1 #4 — drop redundant ``__cause__`` set in ``reraise_kernel_error``: ``raise wrap_kernel_exception(...) from exc`` already sets ``__cause__`` at the call site; the manual assignment in ``reraise_kernel_error`` was redundant. Updated the test that asserted on it; added ``test_kernel_error_chains_through_wrap`` to cover the end-to-end chain. P1 #5 — ``get_tables`` filter looks up TABLE_TYPE by name: Replaced ``schema.field(5).name`` (positional) with the literal ``"TABLE_TYPE"`` plus a missing-column guard. A future kernel reshape of ``SHOW TABLES`` now surfaces an explicit ``OperationalError`` instead of silently filtering the wrong column. The case-sensitive contract is now documented in the surrounding comment (matches SEA + warehouse). P1 #6 — ``KernelResultSet.close()`` guards on ``connection.open``: ``__del__``-driven close arriving after the parent connection is already closed previously issued a kernel call into a disposed session. Skip the kernel call entirely in that case; still mark the result set ``CLOSED`` locally so ``__del__`` is idempotent. P1 #7 — defer ``kernel_auth_kwargs`` to ``open_session``: ``KernelDatabricksClient.__init__`` previously called ``kernel_auth_kwargs(auth_provider)`` and stored the bearer token on ``self._auth_kwargs`` indefinitely. If ``open_session`` never ran (test paths, error paths, lazy retries) the token stayed resident on the connector object. Build the kwargs locally inside ``open_session`` now — local variable, GC-eligible the moment ``open_session`` returns. Also tightened the install-hint comment in ``pyproject.toml`` to match the rest of the codebase (the wheel isn't on PyPI; only the ``maturin develop`` path is supported today). 88/88 kernel unit tests pass (added 1). Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Thanks @gopalldb — addressed the 6 in-scope items in Fixed in this PR (
88/88 kernel unit tests pass (added 1). Filed as separate issues — pre-existing on Thrift/SEA, out of scope for this PR:
Isolation sweep done: every kernel change is gated on (Edited: review-finding numbers like |
Uh oh!
There was an error while loading. Please reload this page.
gopalldb
left a comment
There was a problem hiding this comment.
Some more minor feedbacks, can merge after addressing them
gopalldb
commented
May 18, 2026
P1 findings
Each is ~5 lines; the gap is worth closing. P2 findings
|
Review comment: #787 (comment) P1.1 — get_query_state handles non-BaseException failure: Previously ``raise _reraise_kernel_error(failure) from failure`` would explode with ``TypeError: exception causes must derive from BaseException`` if the kernel's ``status()`` ever returned a ``failure`` that wasn't a real ``KernelError`` (struct, dict — kernel API drift). Now route through ``_wrap_kernel_exception``, which isinstance-checks and falls through to ``OperationalError`` for non-PEP-249-shaped values. New unit test ``test_get_query_state_handles_non_baseexception_failure``. P1.2 — regression tests for prior fixes: - ``test_bearer_prefix_is_case_insensitive`` (P1 #3 from the earlier review): parametrised over "Bearer "/"bearer "/ "BEARER "/"BeArEr ". RFC 6750 §2.1 compliance was added but not covered by a test. - ``test_close_skips_kernel_call_when_connection_already_closed`` (P1 #6 from the earlier review): exercises the ``connection.open is False`` branch in ``KernelResultSet.close()`` — asserts neither the kernel handle's close nor backend.close_command fire, but the result set still ends in ``CLOSED`` so ``__del__`` is idempotent. - ``test_token_with_control_chars_or_whitespace_rejected`` (pre-existing security guard): parametrised over NUL / CR / LF / DEL / space / tab — the regex previously missed space (0x20). Covered + extended. P2.1 — wrap session_id extraction in open_session: ``SessionId.from_sea_session_id(self._kernel_session.session_id)`` was outside the ``try/except _wrap_kernel_exception`` scope. A raw PyO3 attribute-conversion error on the ``self._kernel_session.session_id`` access could escape unwrapped. Now wrapped. P2.2 — drop redundant _async_handles.pop in result-set close: After the M1 fix (``get_execution_result`` pops the guid before constructing the result set), the pop in ``KernelResultSet.close`` is dead code — every call misses. Sync-execute and metadata paths never registered in ``_async_handles`` to begin with. Drop the per-close pop; rewrote the surrounding comment so ``backend.close_command`` is now the single bookkeeping seam. P2.3 — control-char regex includes whitespace: Extended ``[\x00-\x1f\x7f]`` → ``[\x00-\x20\x7f]`` and renamed ``_CONTROL_CHAR_RE`` → ``_TOKEN_REJECT_RE``. RFC 6750 forbids whitespace within the credential token itself; a token like ``"Bearer doubled-space-token"`` previously slipped past the injection guard. Test parametrised above. type_mapping reuse — use SqlType constants: Replaced literal type strings ("bigint", "string", …) in ``_arrow_type_to_dbapi_string`` with the ``SqlType`` constants from ``databricks.sql.backend.sea.utils.conversion`` — same single source of truth the SEA backend already uses, so the kernel and SEA backends emit byte-identical type-code strings. The Arrow → SqlType lookup itself stays local to the kernel (SEA receives type-text from the server and normalises it; the kernel receives Arrow schemas directly), but the names are now shared. 100/100 kernel unit tests pass (added 12). Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
vikrantpuppala
commented
May 18, 2026
Thanks @gopalldb — addressed all P1 and the in-scope P2 items in P1.1 ( P1.2 (missing regression tests) — Added all three:
P2.1 ( P2.2 (redundant P2.3 (whitespace token slipping the injection guard) — Extended
Deferred:
100/100 kernel unit tests pass (added 12 this round). |
Uh oh!
There was an error while loading. Please reload this page.
Summary
Phase 2 of the PySQL × kernel integration plan (design doc). Adds a new opt-in
use_kernel=Trueconnection flag that routes through a newbackend/kernel/module delegating to the Rust kernel via thedatabricks_sql_kernelPyO3 extension (kernel PR #13).This replaces the previous ADBC POC branches (
backend/adbc/andbackend/adbc_dm/onadbc-rust-backend-via-dm, which were never merged) with a clean port that uses the kernel's v0 Databricks-native API directly instead of layering through ADBC.Flag semantics
use_kernel=TrueKernelDatabricksClient(Rust kernel via PyO3)use_sea=TrueSeaDatabricksClient(pure-Python SEA)ThriftDatabricksClient(Thrift)use_kernel=Trueanduse_sea=Trueare mutually exclusive — passing both raisesValueError. Existinguse_sea=Truecallers are unaffected.What
use_kernel=TruedoesNew module layout
src/databricks/sql/backend/kernel/client.pyKernelDatabricksClient(DatabricksClient). Lazy-importsdatabricks_sql_kernelso a connector install without the kernel wheel doesn't fail at startup — onlyuse_kernel=Truesurfaces the missing-extra ImportError.src/databricks/sql/backend/kernel/auth_bridge.pyAuthProviderto kernelSessionauth kwargs. PAT (includingTokenFederationProvider-wrapped PAT — every provider is wrapped, so the naiveisinstance(AccessTokenAuthProvider)check has to look through the wrapper) routes throughauth_type='pat'. Anything else raisesNotSupportedErroruntil the kernel exposes a full external-auth surface.src/databricks/sql/backend/kernel/result_set.pyKernelResultSet(ResultSet). Duck-typed over the kernel'sExecutedStatement(sync exec) andResultStream(metadata + asyncawait_result); both exposearrow_schema / fetch_next_batch / close. FIFO batch buffer forfetchmany(n)semantics, with O(1) buffered-row accounting via a running counter.src/databricks/sql/backend/kernel/type_mapping.pyError mapping
KernelError.code→ PEP 249 exception class, in a single table inclient.py. Structured fields (sql_state,error_code,query_id,http_status,retryable,vendor_code) are copied onto the re-raised exception so callers can branch onerr.code/err.sql_statedirectly. Live e2e verified: bad SQL onuse_kernel=Truesurfaces asDatabaseError(code='SqlError', sql_state='42P01').Packaging
Without the kernel wheel,
use_kernel=Trueraises:Local dev:
cd databricks-sql-kernel/pyo3 && maturin develop --releaseinto the connector's venv. (The[kernel]extra is intentionally not declared inpyproject.tomlyet —databricks-sql-kernelisn't on PyPI, and declaring an unpublished dep breakspoetry lockfor every CI job. The extra will land once the wheel is on PyPI.)execute_command(parameters=[...])raisesNotSupportedErrorStatement.bind_paramlands in a small follow-up PR on the kernel repoquery_tagsNotSupportedErrorstatement_confget_columns(catalog_name=None)ProgrammingError(kernel'sSHOW COLUMNScannot span catalogs)Cursor.columns()docstringNotSupportedErrorfrom the auth bridgeexecution_result/retry_count/ chunk-level latency under-report onuse_kernel=Truessl_options/http_headers/http_clientare accepted-and-ignoredCode review feedback addressed in this revision
Multi-reviewer (architecture, security, ops, performance, test, maintainability, agent-compat, language, devil's advocate) review surfaced several issues; the highest-impact ones are addressed in commits
37fa5446(mechanical) and24e9a5c2(substantive):use_sea=Trueto a dedicateduse_kernel=True; native SEA routing is unchanged. (Was the largest reviewer concern.)table_typesfilter inget_tablesusing the SEA backend's_filter_arrow_tablehelper, replacing the previous "log a warning and return unfiltered" behaviour.KernelResultSetwith a running counter (_buffered_count).KernelResultSet.close()now drops the entry frombackend._async_handlesto avoid stale references.threading.RLockaround_async_handlesmutations / reads for concurrent-cursor safety.CommandIds use plainuuid.uuid4().hex(nometadata-prefix) socursor.query_idstays parseable downstream.KernelDatabricksClient._auth_kwargsafter the kernelSessionis constructed._use_arrow_native_complex_typeskwarg; tightened_reraise_kernel_errorsignature and dropped dead branch; collapsed threeKernelResultSet(...)construction sites through one_make_result_sethelper.Cursor.columns()docstring now documents thecatalog_name=Nonedivergence onuse_kernel=True.TokenFederationProvider(http_client=Mock())instead of bypassing__init__.Test plan
tests/unit/test_kernel_client.py(new in this revision, 38 cases) — covers_CODE_TO_EXCEPTION(14 entries),_reraise_kernel_errorattribute forwarding,_STATE_TO_COMMAND_STATE(6 entries), all no-open-session guards,open_sessiondouble-open, parameters / query_tags rejection,get_columnscatalog-required,cancel_command/close_commandtolerance,get_query_statesync-path SUCCEEDED and Failed-state re-raise, synthetic CommandId shape,close_sessioncleanup on partial close failures. Uses a fakedatabricks_sql_kernelmodule so the test runs with no Rust extension dependency.tests/unit/test_kernel_auth_bridge.py— PAT, federation-wrapped PAT (now via realTokenFederationProvider(http_client=Mock())), non-PAT rejection paths.tests/unit/test_kernel_type_mapping.py— Arrow type mapping per type, description-tuple shape, fallback tostr()for unknowns.tests/unit/test_kernel_result_set.py— buffer semantics,fetchmanyslicing within batch + across batch boundaries, idempotent close, close() swallowing handle-close failures, empty stream.test_useragent_header— agent detection addsagent/claude-codein this env, fails onmaintoo) is unrelated to this change.use_kernel=True(PAT): SELECT 1,SELECT * FROM range(10000),fetchmanypacing,fetchall_arrow, all four metadata calls (catalogs / schemas / tables / columns),session_configuration={'ANSI_MODE': 'false'}round-trips, bad SQL surfaces as DatabaseError withcode='SqlError'andsql_state='42P01'.This pull request and its description were written by Isaac.