fix(dbt-tools): move to dbt-integration 0.3.15 so the dbt adapter starts under Bun

Draft
RA
1d ago
+151-579

Issue for this PR

Closes #1367

Type of change

  • Bug fix

What does this PR do?

Moves packages/dbt-tools from @altimateai/dbt-integration 0.2.14 to ^0.3.15. 0.2.x started its Python child through python-bridge, which fails under Bun (bluebird.promisifyAll on child_process throws Cannot access invalid private field (evaluating 'this.#stdin')), so the dbt-first path of sql_execute never ran. 0.3.x vendors the bridge and uses a plain fd-3 pipe; python-bridge and bluebird leave the lockfile. From 0.3.15, a bridge running inside a single-file executable writes its script to a temporary directory and removes it on exit, so the compiled binary starts the bridge too.

  • adapter.ts: 0.3.x's DBTProjectIntegrationAdapter takes a UnitTestParser and a SemanticModelParser; the Fusion integration no longer takes the cloud-variant detector (the Cloud integration still does).
  • copy-python.ts / release.yml / publish.ts: the vendored bridge finds node_python_bridge.py from the bundle's own location at runtime (fileURLToPath(import.meta.url)), so the python-bridge __dirname patch is gone. The build and the release smoke check now assert the new resolution instead of the patch.
  • Tests: build-adversarial.test.ts tested the removed patch. The checks in it that don't depend on the patch move to build-integrity.test.ts (no build-machine path in the bundle, Python packages copied, createRequire, byte-identical rebuilds). A new test runs the package as publish.ts lays it out, from another directory, and checks that it starts the bridge script next to its own bundle.

Claims

  • C1: Under Bun, the dbt-first path of sql_execute starts the dbt adapter and runs the query through dbt, from source and from the compiled binary.
  • C2: The compiled binary runs the bridge from a real directory, not from /$bunfs. No Python process and no temporary bridge directory is left after the call.
  • C3: altimate-dbt, laid out as publish.ts ships it and run by Node from another directory, starts the node_python_bridge.py next to its own bundle. The build and the release smoke check fail if a build-time path is baked into the bundle.
  • C4: adapter.ts builds the adapter with what 0.3.x's constructors take: both new parsers, and the cloud-variant detector for dbt Cloud only.

Residuals

  • R1: 0.3.15 was published on 2026-10-13 05:44Z, inside this repo's 3-day minimumReleaseAge. In this repo, bun install resolves it again even with --frozen-lockfile, and the window blocks that, so CI can't install this branch until 2026-10-16 05:44Z. Every failing check fails at that install step. Nothing needs to change then: rerun CI. The lockfile already pins 0.3.15 with npm's integrity hash, and its dependencies are the same as 0.3.13's.
  • R2: When the adapter can't start (no dbt in the venv, a broken project), sql_execute still falls back to the configured warehouse without saying why. That's unchanged by this PR.

How did you verify your code works?

sql_execute called through the real tool registry (debug agent build --tool sql_execute, no model turn), against a two-model dbt-core 1.11.7 / DuckDB project with its own venv, query select count(*) as n from customer_totals:

beforethis branch (ccc92cc431; since then only a test changed)
compiled binaryv0.12.7 release: falls back, "No warehouse configured"n = 2 via dbt
from source (Bun)main (2026-09-29): falls back, "No warehouse configured"n = 2 via dbt
  • Compiled binary: the bridge ran as /tmp/altimate-dbt-integration-<random>/bridge.py. Python processes were sampled every 200 ms; none was left after the call, and neither was the temporary directory.
  • From source, the bridge ran from @altimateai/dbt-integration@0.3.15/dist/node_python_bridge.py.
  • altimate-dbt as npm ships it (publish.ts layout, Node 22, run from another directory), execute --query …: [{"n": 2}], as on main.
  • packages/dbt-tools on 97f6c2c4fd: typecheck clean, build verified, 185 tests pass. The relocation test fails when a fixed path is baked into the bundle. It compares against the install directory's real path, and passes with TMPDIR pointing at a symlink, which is how tmpdir() sits on macOS. packages/opencode: typecheck clean.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Appendix: complexity delta

✅ No touched function changed in complexity (2 touched, 0 new, all under 10). Advisory, not a gate.

🤖 Generated with Claude Code

https://claude.ai/code/session_0172qrhMa5TQgETASi5hxMqD

Summary by CodeRabbit

  • New Features
    • Added support for parsing dbt unit tests and semantic models.
  • Bug Fixes
    • Improved Python bridge location resolution so the CLI can find the bridge alongside its bundled files, including when run from a different directory.
    • Improved package build checks to catch missing bridge files and references to local checkout or CI paths.