feat(workspace): route warehouse tools through the bound workspace's engine
Issue for this PR
Closes #1155
Type of change
- Bug fix
- New feature
- Refactor / code improvement
- Documentation
What does this PR do?
Stacked on #1167 — review that first; this PR is the commit on top. It is the precedence change from #1156 restacked onto the overlay attach; the mechanism is unchanged, the attach seam it reads is now the overlay's.
When a bound workspace's engine is attached, the model gets two ways to do the same thing: the native warehouse tools over local keychain connections, and the engine's MCP tools over the workspace's SaaS connection. Nothing chose between them, so the model picked whichever description read better — and that pick decided which credentials ran the query and whether it was audited (engine calls are audited server-side; native ones are not).
This adds a per-session decision: shadow only what materialised and is attributable to the bound workspace; anything undetermined runs locally and says why; nothing is silent.
- Materialised, not declared — it reads the engine tool keys actually present, so a declared-but-absent integration shadows nothing.
- Attributed — routing engages only when the attach outcome is
attached(the overlay's own pinned engine, connected at this turn boundary) and the configured entry's pin names the bound workspace. Any other outcome, or none, fails open with a reason. - Per capability, not per warehouse type — Snowflake has execute, explain and table stats; BigQuery and Postgres have execute only. Keying on the type would send an explain on BigQuery to a tool that does not exist, and there is deliberately no fallback.
- Calls naming no warehouse are judged against the target they would really reach, mirroring each handler's own resolution, including the registry connection dbt falls back to.
- The redirect names the exact engine tool, executes nothing, is marked in metadata so telemetry can tell it from an execution, and is only offered to a caller whose agent may call that tool.
- It runs after every native safety check — the hard deny on destructive statements and the write confirmation both guard things the engine side has no equivalent for.
--integrations=localturns it off for a session.
Two deliberate deviations: the guard needs a companion call to attach the fail-open notice, which a pre-execution check cannot do; and an adjacent warehouse-type reporting bug is left alone, since fixing it changes a shipped telemetry field.
How did you verify your code works?
bun run typecheck clean; precedence, default-target, guard-order and workspace suites pass (161 tests across the six directly affected files; the tool/native/prompt suites green). The union test now asserts the allowlist is exactly attached over the whole outcome union, so a future outcome kind refuses routing by default.
End-to-end rows from #1156 (shadow marking, redirect with a proven no-local-execution control, DuckDB control, default target, model following the redirect unprompted, write confirmation, escape hatch) are re-run on this stack and recorded in the review-log comment below before this leaves draft.
GitGuardian flags a masked placeholder (eight literal asterisks) in a help-text snapshot that only moved columns; it is present unchanged on the base commit and is not a credential.
Screenshots / recordings
n/a — CLI change, no UI.
Checklist
- I have tested my changes locally
- I have not included unrelated changes in this PR
Summary by cubic
Routes warehouse operations through the bound workspace's engine when that engine materialised a matching tool and attach proves it owns the workspace; anything undetermined runs locally with a stated reason, and --integrations=local disables routing process-wide. Closes #1155.
Routing rules
- Shadowing requires the engine tool to be materialised and attributed via attach outcome
attachedplus a configured pin naming the bound workspace. - Engine tools are identified by the MCP client that served them, not the
datamate_prefix; foreign-client keys get no precedence and warn once per session. - An unrecognisable connection type, unreadable binding, or throwing derivation fails open with a reason; a failed config invalidation refuses attribution instead of trusting the cached pin.
- Matching is per capability: Snowflake gets execute, explain, and table stats; BigQuery, Postgres, and Databricks get execute only.
- Calls naming no warehouse are judged against their real target; concurrent
warehouse-less calls no longer construct the dbt adapter twice, and a superseded adapter attempt no longer publishes over the newer attempt's cache. - The re-link guard runs only when a redirect is about to be returned, so local calls do not pay for the binding read.
- The redirect names the exact engine tool, executes nothing, is marked in metadata for telemetry, and appears only to callers whose agent may call that tool.
warehouse_listannotates rows from a live precedence snapshot re-validated against the current binding.- The guard runs after native safety checks, and
schema_inspectvalidates inputs before precedence through a shared module, so bad input is never forwarded to the engine tool. - A delivered announcement is recorded against the session's incarnation, so per-step refreshes still count it and a recreated session's newer record can't be overwritten by a stale completion.
- Tests pin the guard order, attribution refusals, single-flight adapter, dbt-fallback wording, and the stale-connection guard through production.
Summary by CodeRabbit
-
New Features
- Added workspace-aware routing for SQL execution, explanations, and schema inspection.
- Added workspace annotations and shadowed-connection details to warehouse listings.
- Added the
--integrations workspace|localoption and local-routing escape hatch. - Improved tool descriptions, routing notices, and foreign-tool handling.
- Added safer default connection resolution and protection against connection changes during queries.
-
Bug Fixes
- Prevented duplicate concurrent adapter initialization and improved recovery after resets.
- Added clearer validation for warehouse and table inputs.
-
Tests
- Expanded coverage for routing, precedence, concurrency, safety checks, validation, and fallback behavior.