---
phase: 17.1-python-vtab-crash-investigation
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - test/integration/test_vtab_crash.py
autonomous: false
requirements:
  - CRASH-01
  - CRASH-02

must_haves:
  truths:
    - "Python reproduction script exercises all five crash vectors (CV-1 through CV-5) systematically"
    - "Crash is reproduced (or definitively ruled out for each vector) with clear diagnostic output"
    - "Root cause is identified with crash signal type (SIGABRT vs SIGSEGV) and backtrace"
  artifacts:
    - path: "test/integration/test_vtab_crash.py"
      provides: "Systematic Python crash reproduction test script"
      min_lines: 100
  key_links:
    - from: "test/integration/test_vtab_crash.py"
      to: "target/debug/semantic_views.duckdb_extension"
      via: "LOAD extension in Python duckdb client"
      pattern: "con.execute.*LOAD"
---

<objective>
Reproduce the Python vtab crash systematically and identify the root cause.

Purpose: The extension crashes when used from the Python DuckDB client. Before fixing anything, we need a reliable reproduction and clear diagnosis of which crash vector is responsible.
Output: A Python test script that triggers the crash (or exercises all crash vectors), plus a diagnosis recorded in the task output identifying the root cause.
</objective>

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

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/17.1-python-vtab-crash-investigation/17.1-RESEARCH.md

@src/query/table_function.rs
@src/lib.rs
@cpp/src/shim.cpp
@test/integration/test_ducklake_ci.py
@test/integration/test_ducklake_helpers.py
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create systematic Python crash reproduction script</name>
  <files>test/integration/test_vtab_crash.py</files>
  <action>
Create a Python test script `test/integration/test_vtab_crash.py` that systematically exercises all five crash vectors from the research (CV-1 through CV-5). The script must be runnable via `python3 test/integration/test_vtab_crash.py` (or `uv run test/integration/test_vtab_crash.py`).

Structure the script with these test functions, each targeting a specific crash vector:

**CV-1 tests (type mismatch in duckdb_vector_reference_vector):**
- `test_cv1_basic_types()`: Define a view with VARCHAR, INTEGER, BIGINT columns. Query it. Should work.
- `test_cv1_decimal_sum()`: Define a view over a table with DECIMAL(10,2) column, use `sum(amount)` metric. This is the most likely crash trigger -- sum() on DECIMAL may produce HUGEINT at plan time but BIGINT at runtime.
- `test_cv1_date_trunc()`: Define a view with a `date_trunc('month', dt)` dimension and `count(*)` metric. Tests DATE type flow.
- `test_cv1_mixed_aggregates()`: Define a view with `count(*)`, `sum(integer_col)`, `avg(decimal_col)`, `min(date_col)` -- exercises multiple type paths simultaneously.
- `test_cv1_many_types()`: Define a table with BOOLEAN, TINYINT, SMALLINT, INTEGER, BIGINT, FLOAT, DOUBLE, DECIMAL(18,4), VARCHAR, DATE, TIMESTAMP, INTERVAL columns. Create a view and query with various combinations.

**CV-2 tests (connection lifetime):**
- `test_cv2_explicit_close()`: Define view, query it, then call `con.close()` explicitly. Check for crash on close.
- `test_cv2_gc_collection()`: Define view, query it, then `del con` and `import gc; gc.collect()`. Check for crash during GC.
- `test_cv2_multiple_queries()`: Run multiple queries on same view in sequence (exercises connection reuse).

**CV-3 tests (duckdb_query during bind):**
- `test_cv3_inmemory_bind()`: In-memory DB, define view + query (exercises bind-time LIMIT 0 on query_conn).
- `test_cv3_file_backed_bind()`: File-backed DB in temp dir, define view + query (exercises persist_conn path).

**CV-4 tests (materialized vs streaming):**
- `test_cv4_large_result()`: Insert 10,000 rows, query the view (large result forces multiple chunks).
- `test_cv4_empty_result()`: Query with filter that returns zero rows (if possible via dimensions).

**CV-5 tests (extra_info pointer lifetime):**
- `test_cv5_define_query_define_query()`: Define view A, query A, define view B, query B, query A again (exercises extra_info stability across multiple registrations).

Each test function should:
1. Print the test name and which crash vector it targets
2. Use a 30-second `signal.alarm` timeout (catches deadlocks, CV-3)
3. Wrap the test body in try/except, printing PASS/FAIL/CRASH/TIMEOUT
4. Return True/False for pass/fail

Use the same extension loading pattern as `test_ducklake_ci.py` (import helpers from `test_ducklake_helpers.py`). Use in-memory databases (`:memory:`) for most tests. Use `tempfile.mkdtemp()` for file-backed tests.

Add a `main()` that runs all tests, prints a summary, and exits with code 0 (all pass) or 1 (any fail/crash).

Script header should include the `uv` inline script metadata:
```python
# /// script
# dependencies = ["duckdb"]
# requires-python = ">=3.9"
# ///
```

IMPORTANT: Build the extension first with `just build` before running the script. The script itself should NOT build.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && just build && python3 test/integration/test_vtab_crash.py 2>&1 | tail -20</automated>
  </verify>
  <done>Python test script exists, is executable, and produces clear output for each crash vector (PASS, FAIL, CRASH, or TIMEOUT). At least one test reproduces the crash, OR all tests pass (meaning the crash requires different conditions, requiring investigation pivot).</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 2: Review crash reproduction results and confirm root cause</name>
  <files>test/integration/test_vtab_crash.py</files>
  <action>
CHECKPOINT: User reviews the crash reproduction test output and confirms the root cause.

What was built: Systematic Python crash reproduction script covering all 5 crash vectors (CV-1 through CV-5). Tests type mismatches, connection lifetime, bind-time SQL execution, streaming results, and extra_info pointer stability.

How to verify:
1. Review the test output from Task 1 -- which tests passed, failed, or crashed?
2. If a crash was reproduced: note the crash vector (CV-1/2/3/4/5) and the specific test that triggered it
3. If NO crash was reproduced: we need to discuss -- the crash may require DuckLake tables, specific Python versions, or other conditions not covered by the test matrix
4. Run `python3 test/integration/test_vtab_crash.py` yourself if you want to verify
5. Decide: proceed to Plan 02 (fix the identified issue), OR pivot the investigation

Expected: At least CV-1 (type mismatch) tests should trigger the crash, specifically `test_cv1_decimal_sum` or `test_cv1_mixed_aggregates`.

Resume signal: Type "proceed" with the identified crash vector(s), or describe what you observed and whether to pivot.
  </action>
  <verify>User confirms diagnosis and approves proceeding to Plan 02</verify>
  <done>Root cause identified and confirmed by user. Investigation direction for Plan 02 is clear.</done>
</task>

</tasks>

<verification>
- test/integration/test_vtab_crash.py exists and runs without Python import errors
- Script exercises all 5 crash vectors with clear diagnostic output
- Each test prints its crash vector target and PASS/FAIL/CRASH/TIMEOUT result
- Crash is reproduced OR all vectors are ruled out (requiring investigation pivot)
</verification>

<success_criteria>
- Python crash reproduction script runs and produces diagnostic output for all crash vectors
- Root cause is identified (which CV, which test, what signal/error) or investigation pivots to different conditions
- User confirms diagnosis and approves proceeding to fix phase
</success_criteria>

<output>
After completion, create `.planning/phases/17.1-python-vtab-crash-investigation/17.1-01-SUMMARY.md`
</output>
