---
phase: 66-expansion-qualification-adbc-tests
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - test/integration/test_adbc_queries.py
  - justfile
autonomous: false
requirements:
  - EXPAND-CTX-02
must_haves:
  truths:
    - "`just test-adbc-queries` is a runnable recipe that wraps `uv run test/integration/test_adbc_queries.py`."
    - "`test-adbc-queries` is part of the `just test-all` aggregate so the regression guard runs in CI."
    - "The test file exercises 7 scenarios from CONTEXT.md D-08: main+default, main+non-default-schema, FACTS+non-default-schema, semi-additive+non-default-schema, window+non-default-schema, materialization-routing+non-default-schema, multi-DB ATTACH+FACTS."
    - "Scenarios 3-7 (5 sites including ATTACH+FACTS) — FACTS / semi-additive / window / materialization-routing through non-default schemas, plus multi-DB ATTACH+FACTS — are gated by `@pytest.mark.skip` (or a local skip helper) referencing 'Phase 66 Plan 02' so the file passes on pre-migration HEAD without false-positive."
    - "Manual D-09 baseline gate is documented inside the test file: removing the skip markers on pre-migration HEAD must reproduce `Catalog Error: Table with name X does not exist!`."
    - "D-07: `test/integration/test_adbc_queries.py` created using `adbc_driver_duckdb`, shape matching `test_adbc_transactions.py`."
    - "D-10: `just test-adbc-queries` recipe added to `justfile`, included in the `test-all` aggregate after `test-adbc`."
  artifacts:
    - path: "test/integration/test_adbc_queries.py"
      provides: "ADBC end-to-end SELECT FROM semantic_view(...) regression coverage across all 7 expansion-path scenarios"
      min_lines: 250
    - path: "justfile"
      provides: "`test-adbc-queries` recipe + `test-all` aggregate entry placing it immediately after `test-adbc`"
  key_links:
    - from: "test/integration/test_adbc_queries.py"
      to: "test_ducklake_helpers.get_ext_dir / get_extension_path"
      via: "sys.path import + extension load via `LOAD '<extension_path>'` after `_connect_adbc`"
      pattern: "from test_ducklake_helpers import"
    - from: "test/integration/test_adbc_queries.py"
      to: "adbc_driver_manager.AdbcDatabase"
      via: "_connect_adbc helper mirrored from test_adbc_transactions.py:60-81"
      pattern: "adbc_driver_manager.AdbcDatabase\\("
    - from: "justfile test-all"
      to: "test-adbc-queries"
      via: "sequential dependency list at justfile:149"
      pattern: "test-adbc test-adbc-queries"
---

<objective>
Land the ADBC end-to-end query regression test scaffolding (file + justfile recipe + `test-all` wiring) for EXPAND-CTX-02, with scenarios 3-6 skipped pending Plan 02's migration so CI stays green.

Purpose: Establish the failing-baseline harness ahead of the migration. Per CONTEXT.md D-09, scenarios 3-6 MUST fail on a pre-migration baseline (Pitfall 5) — gating them with `pytest.mark.skip(reason="Phase 66 Plan 02")` is the cleanest way to commit the scaffolding without breaking CI, then Plan 02 removes the skips at the same commit that lands the migration.

Output:
- New file `test/integration/test_adbc_queries.py` with 7 scenario functions + ADBC bootstrap helpers
- New `test-adbc-queries: build` recipe in `justfile` immediately after `test-adbc` (justfile:111)
- `test-all` aggregate updated to include `test-adbc-queries` after `test-adbc` (justfile:149)
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/66-expansion-qualification-adbc-tests/66-CONTEXT.md
@.planning/phases/66-expansion-qualification-adbc-tests/66-RESEARCH.md
@.planning/phases/66-expansion-qualification-adbc-tests/66-VALIDATION.md

# ADBC test shape — direct template for this plan
@test/integration/test_adbc_transactions.py

# Multi-DB ATTACH setup pattern (reusable for scenario 7)
@test/integration/test_multi_db_isolation.py

# justfile insertion points
@justfile

# Project rules — Rules 1 & 2 non-negotiable
@CLAUDE.md

<interfaces>
<!-- Reusable helpers from test/integration/test_adbc_transactions.py:60-93 -->

```python
# _connect_adbc — opens AdbcDatabase with extension_directory + allow_unsigned_extensions
def _connect_adbc(db_path: str, extension_dir: str):
    db = adbc_driver_manager.AdbcDatabase(
        driver=adbc_driver_duckdb.driver_path(),
        entrypoint="duckdb_adbc_init",
        path=db_path,
        allow_unsigned_extensions="true",
        extension_directory=extension_dir,
    )
    conn = adbc_driver_manager.AdbcConnection(db)
    return adbc_driver_manager.dbapi.Connection(db, conn, autocommit=False)

# _execute(conn, sql) — wraps cur.execute(sql)
# _scalar(conn, sql) — wraps cur.execute(sql); fetchone()[0]
```

```python
# test_ducklake_helpers provides:
get_ext_dir() -> Path          # the directory to set as extension_directory
get_extension_path() -> Path   # full path to the built .duckdb_extension
```

The extension must be loaded into the ADBC connection via `LOAD '<path>'` (or `INSTALL`/`LOAD` pattern from `test_adbc_transactions.py:140-160`) before any `CREATE SEMANTIC VIEW` or `SELECT FROM semantic_view(...)` statements.
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create test_adbc_queries.py with 7 scenario functions</name>
  <files>test/integration/test_adbc_queries.py</files>
  <read_first>
    - test/integration/test_adbc_transactions.py (shape template — PEP 723 header, _connect_adbc, _execute, _scalar, run_tests() runner pattern, extension load sequence)
    - test/integration/test_multi_db_isolation.py (ATTACH setup for scenario 7)
    - .planning/phases/66-expansion-qualification-adbc-tests/66-CONTEXT.md (D-07, D-08, D-09 — exact scenario list and baseline-gate semantics)
    - .planning/phases/66-expansion-qualification-adbc-tests/66-RESEARCH.md §Code Examples (skeleton for scenario 3 FACTS-non-default-schema and scenario 7 ATTACH-FACTS)
    - CLAUDE.md (Rule 1 — never bare-tail long-running uv runs; Rule 2 — sandbox bypass pre-approved for `uv run test/integration/*.py`)
  </read_first>
  <action>
Create `test/integration/test_adbc_queries.py` modeled on `test_adbc_transactions.py`. PEP 723 header MUST match `test_adbc_transactions.py:1-13` exactly (`duckdb==1.5.2`, `adbc-driver-manager>=1.10`, `pyarrow>=16`, `requires-python = ">=3.10"`). Include the comment about `adbc_driver_duckdb` being bundled inside the duckdb wheel.

Module docstring documents EXPAND-CTX-02 coverage and points at the D-09 baseline gate (manual: removing the skip markers on pre-migration HEAD must reproduce `Catalog Error: Table with name X does not exist!`).

Copy verbatim (or import from `test_adbc_transactions.py` style): `_connect_adbc`, `_execute`, `_scalar` helpers. Reuse `from test_ducklake_helpers import get_ext_dir, get_extension_path`.

After `_connect_adbc`, every test must `_execute(conn, f"LOAD '{extension_path}'")` (or equivalent INSTALL+LOAD sequence used in `test_adbc_transactions.py`) before any DDL — confirm the exact sequence from the source-of-truth file.

Implement 7 scenario functions per CONTEXT.md D-08. Naming convention: `test_<scenario>(conn, ext_dir, tmp_path)`:

  1. `test_main_path_default_schema` — view in `memory.main`; SELECT returns rows. NO skip marker.
  2. `test_main_path_non_default_schema` — `CREATE SCHEMA staging; CREATE TABLE staging.t; CREATE SEMANTIC VIEW v (TABLES (staging.t AS x) DIMENSIONS (x.region) METRICS (x.cnt AS COUNT(*)));`. NO skip marker (main path was already wired by Phase 64 and currently passes).
  3. `test_facts_non_default_schema` — staging.sales + FACTS clause. Use the RESEARCH.md §Code Examples skeleton verbatim. SKIP marker.
  4. `test_semi_additive_non_default_schema` — staging.inventory with `MIN_BY(qty, snapshot_date)` semi-additive metric. SKIP marker.
  5. `test_window_non_default_schema` — staging.events with a `LAG()` or `ROW_NUMBER()` window metric. SKIP marker.
  6. `test_materialization_routing_non_default_schema_target` — `CREATE SCHEMA agg; CREATE TABLE agg.daily_revenue; CREATE SEMANTIC VIEW v (... MATERIALIZATIONS (m (target_table => 'agg.daily_revenue', dimensions => [...], metrics => [...])));`. Query selects the exact dim/metric set that routes to the materialization (assert via `explain_semantic_view` if needed). SKIP marker.
  7. `test_attach_facts_path` — `ATTACH 'other.duckdb' AS db2`, then a CREATE SEMANTIC VIEW that uses a FACTS metric on the attached DB's table. Pre-create the other DB outside the ADBC session via a side `duckdb.connect()` (RESEARCH.md §Code Examples shows the pattern). SKIP marker.

Skip marker format — file uses a homegrown runner (not pytest), so use a local skip mechanism. Define a top-level constant:
```
SKIP_UNTIL_PLAN_02 = "Phase 66 Plan 02: requires qualify_and_quote_table_ref migration of FACTS/semi-additive/window/materialization sites"
```
and have `run_tests()` print `SKIP: <name> -- {SKIP_UNTIL_PLAN_02}` for the 4 gated scenarios and exclude them from the pass/fail accounting (i.e. they neither pass nor fail; they count as skipped, like `test_adbc_transactions.py`'s pattern). Plan 02 will flip a single flag `MIGRATION_LANDED = True` at the top of the file to un-skip all four in one diff.

Inline a final docstring section documenting the D-09 manual gate: a developer running `MIGRATION_LANDED = True` against the pre-Plan-02 commit MUST observe scenarios 3-6 fail with `Catalog Error: Table with name <name> does not exist!`; record the failing output as Plan 02's verification evidence.

Runner pattern: `run_tests()` returns 0 on all-pass (skips don't fail), 1 on any failure. `if __name__ == "__main__": sys.exit(run_tests())`. Mirror the print formatting from `test_adbc_transactions.py:run_tests()`.

Tear-down: use `tempfile.TemporaryDirectory(prefix="sv_adbc_q_")` for each test's DB path. The macOS `/var/folders/.../T/` write may trigger Rule 2 sandbox bypass when run via `just test-all` — note this inline so the executor knows.
  </action>
  <verify>
    <automated>uv run test/integration/test_adbc_queries.py > /tmp/claude/adbc_queries_baseline.log 2>&1; RC=$?; tail -100 /tmp/claude/adbc_queries_baseline.log; test "$RC" -eq 0</automated>
  </verify>
  <acceptance_criteria>
    - File exists; `wc -l test/integration/test_adbc_queries.py` ≥ 250.
    - PEP 723 header matches test_adbc_transactions.py header (same pins).
    - `grep -c "^def test_" test/integration/test_adbc_queries.py` returns exactly 7.
    - `grep -n "SKIP_UNTIL_PLAN_02" test/integration/test_adbc_queries.py` shows the constant defined once and referenced from 5 test sites (scenarios 3-7).
    - Running the test file exits 0; output shows: 3 PASS (scenarios 1, 2, 7… wait — re-evaluate: scenario 7 ATTACH+FACTS hits the unmigrated FACTS path so it is also SKIP. Final accounting: 2 PASS (scenarios 1, 2), 5 SKIP (scenarios 3, 4, 5, 6, 7), 0 FAIL.
    - File contains an inline D-09 manual-gate docstring naming `MIGRATION_LANDED = True` as the un-skip flag and referencing the expected `Catalog Error: Table with name X does not exist!` failure mode.
    - No bare `tail` on the `uv run` invocation; the verify command redirects to `/tmp/claude/adbc_queries_baseline.log` first per Rule 1.
  </acceptance_criteria>
  <done>
    Test file lands; all non-skipped scenarios PASS; skipped scenarios are clearly accounted in stdout and gated by the `SKIP_UNTIL_PLAN_02` constant.
  </done>
</task>

<task type="auto">
  <name>Task 2: Add test-adbc-queries justfile recipe and wire into test-all</name>
  <files>justfile</files>
  <read_first>
    - justfile (line 107-112 — `test-adbc` recipe shape; line 149 — `test-all` aggregate)
    - .planning/phases/66-expansion-qualification-adbc-tests/66-CONTEXT.md (D-10 — recipe placement)
    - .planning/phases/66-expansion-qualification-adbc-tests/66-RESEARCH.md §Code Examples (justfile recipe template)
  </read_first>
  <action>
Append a new recipe `test-adbc-queries: build` immediately after the existing `test-adbc` recipe (currently lines 107-112). Recipe body: `uv run test/integration/test_adbc_queries.py`. Include a comment block above the recipe describing the scope (ADBC end-to-end queries across main / FACTS / semi-additive / window / materialization-routing / non-default-schema / multi-DB-ATTACH; regression guard for EXPAND-CTX-01..03 v0.10.0) — see RESEARCH.md §Code Examples for the exact recipe stanza.

Update the `test-all` aggregate recipe at justfile:149: insert `test-adbc-queries` immediately after `test-adbc` in the dependency list. Final list ordering preserves all other entries unchanged.
  </action>
  <verify>
    <automated>grep -n "^test-adbc-queries:" justfile && grep -c "test-adbc-queries" justfile</automated>
  </verify>
  <acceptance_criteria>
    - `grep -n "^test-adbc-queries:" justfile` returns exactly one match.
    - `grep -E "^test-all:" justfile` shows `test-adbc test-adbc-queries` substring (immediately adjacent, in that order).
    - `just --list 2>/dev/null | grep test-adbc-queries` shows the recipe in the recipe list.
    - `just --dry-run test-adbc-queries 2>&1 | grep -E "(build|test_adbc_queries.py)"` shows both the `build` dependency and the python invocation.
  </acceptance_criteria>
  <done>
    Recipe is callable via `just test-adbc-queries`; running it depends on `just build`; the recipe is included in `just test-all`.
  </done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 3: Confirm just test-all stays green with scaffolding landed</name>
  <files>(no files modified — verification only)</files>
  <what-built>
    Test file `test/integration/test_adbc_queries.py` with 2 active scenarios + 5 SKIP-gated scenarios; `test-adbc-queries` justfile recipe; entry in `test-all` aggregate.
  </what-built>
  <action>Pause for human verification. Executor presents the steps under <how-to-verify> to the user and waits for the resume-signal.</action>
  <how-to-verify>
    1. `just build > /tmp/claude/build.log 2>&1; tail -20 /tmp/claude/build.log` — confirm clean build.
    2. `just test-adbc-queries > /tmp/claude/test_adbc_queries.log 2>&1; RC=$?; tail -60 /tmp/claude/test_adbc_queries.log; echo "RC=$RC"` — confirm exit code 0; stdout reports 2 PASS / 5 SKIP / 0 FAIL.
    3. `just test-all > /tmp/claude/test_all.log 2>&1; RC=$?; tail -60 /tmp/claude/test_all.log; echo "RC=$RC"` — confirm exit code 0; full aggregate stays green.
    4. Note for D-09 baseline gate (executed during Plan 02 verification, NOT now): the developer who lands Plan 02 must (a) make migration changes locally without committing, (b) flip `MIGRATION_LANDED = True` in the test file, (c) run `just test-adbc-queries` on pre-migration HEAD with the flag flipped and confirm scenarios 3-6 (and 7) fail with `Catalog Error: Table with name X does not exist!`, (d) record the failing output in Plan 02's task verification log before applying the migration. This is the D-09 evidence record, not a CI gate.
    5. If `mktemp: mkstemp failed ... Operation not permitted` appears at step 2 or 3, retry the same command with `dangerouslyDisableSandbox: true` per CLAUDE.md Rule 2.
  </how-to-verify>
  <verify>
    <automated>echo "Manual checkpoint — see how-to-verify steps; user confirms with resume-signal."</automated>
  </verify>
  <done>User responds to the resume-signal confirming the checkpoint passed.</done>
  <resume-signal>Type "approved" to proceed to Plan 02, or describe issues.</resume-signal>
</task>

</tasks>

<threat_model>
No new threats; see RESEARCH.md §Security Domain. Scaffolding only — no production code touched.
</threat_model>

<verification>
- `just test-adbc-queries` returns 0; reports 2 PASS / 5 SKIP / 0 FAIL.
- `just test-all` returns 0 (aggregate green with new recipe wired in).
- File contains `SKIP_UNTIL_PLAN_02` constant referenced from scenarios 3-7 (5 sites, including ATTACH+FACTS scenario 7).
- D-09 manual-gate documented inline in the test file's module docstring or near `MIGRATION_LANDED`.
</verification>

<success_criteria>
- `test/integration/test_adbc_queries.py` exists with 7 scenario functions.
- 5 scenarios (3, 4, 5, 6, 7) are skipped pending Plan 02 migration; 2 baseline scenarios (1, 2) pass.
- `just test-adbc-queries` runs the file via `uv run`.
- `just test-all` includes the new recipe and stays green.
- Scaffolding commit lands without breaking CI; failing-baseline gate documented for Plan 02 to execute manually.
</success_criteria>

<output>
Create `.planning/phases/66-expansion-qualification-adbc-tests/66-01-SUMMARY.md` when done.

</output>
