---
phase: 08-cpp-shim-infrastructure
plan: "01"
type: execute
wave: 1
depends_on: []
files_modified:
  - Cargo.toml
  - duckdb_capi/duckdb.hpp
  - src/shim/shim.cpp
  - src/shim/shim.h
  - src/shim/mod.rs
  - Justfile
autonomous: true
requirements:
  - INFRA-01

must_haves:
  truths:
    - "duckdb_capi/duckdb.hpp exists and is the v1.4.4 amalgam (or full header tree)"
    - "src/shim/shim.cpp includes duckdb.hpp and duckdb/main/config.hpp without modification"
    - "src/shim/shim.h declares semantic_views_register_shim with the correct extern C guard"
    - "Cargo.toml has cc = \"1.2\" under [build-dependencies]"
    - "Justfile has an update-headers recipe that re-vendors the header from the build cache"
  artifacts:
    - path: "duckdb_capi/duckdb.hpp"
      provides: "DuckDB C++ single-header or amalgam entry point for shim.cpp"
    - path: "src/shim/shim.cpp"
      provides: "C++ skeleton with extern C no-op stub"
    - path: "src/shim/shim.h"
      provides: "extern C boundary header shared by C++ and Rust"
    - path: "src/shim/mod.rs"
      provides: "Rust module file exposing the shim module"
    - path: "Cargo.toml"
      provides: "cc build-dependency declared"
    - path: "Justfile"
      provides: "update-headers recipe for future header refresh"
  key_links:
    - from: "src/shim/shim.cpp"
      to: "duckdb_capi/duckdb.hpp"
      via: '#include "duckdb.hpp"'
      pattern: '#include "duckdb\.hpp"'
    - from: "src/shim/shim.cpp"
      to: "src/shim/shim.h"
      via: '#include "shim.h"'
      pattern: '#include "shim\.h"'
---

<objective>
Create all C++ shim source files and vendor the DuckDB C++ header so the build system has everything it needs before build.rs wires it together.

Purpose: Isolate file creation from build wiring. This plan creates the C++ artifacts; plan 02 creates the build.rs that compiles them. If anything is wrong with the header or shim skeleton, it can be diagnosed without touching the build system.

Output: duckdb_capi/duckdb.hpp vendored, src/shim/ skeleton, Cargo.toml updated, Justfile updated.
</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/08-cpp-shim-infrastructure/08-RESEARCH.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Vendor duckdb.hpp and update Cargo.toml + Justfile</name>
  <files>duckdb_capi/duckdb.hpp, Cargo.toml, Justfile</files>
  <action>
**Step 1 — Create duckdb_capi/ directory and vendor duckdb.hpp.**

The project already uses `libduckdb-sys = "=1.4.4"`. Its bundled build unpacks the full DuckDB source into the Cargo build cache. The headers are already present on disk. Copy from there rather than downloading:

```bash
# Find the existing unpacked header tree (already on disk from cargo test runs)
find target/debug/build/libduckdb-sys-*/out/duckdb/src/include/ -name "duckdb.hpp" 2>/dev/null | head -1
```

If the above finds a path, copy the entire `duckdb/src/include/` directory tree to `duckdb_capi/`:

```bash
# Copy full header tree (handles case where duckdb.hpp is not self-contained)
SRC=$(find target/debug/build/libduckdb-sys-*/out/duckdb/src/include/ -maxdepth 0 -type d 2>/dev/null | head -1)
cp -r "$SRC/." duckdb_capi/
```

If the find returns nothing (fresh checkout), download from the release archive:

```bash
curl -L https://github.com/duckdb/duckdb/releases/download/v1.4.4/libduckdb-src.zip \
     -o /tmp/libduckdb-src.zip
unzip -j /tmp/libduckdb-src.zip "duckdb.hpp" -d duckdb_capi/
```

After copying, verify `duckdb_capi/duckdb.hpp` exists.

**Step 2 — Update Cargo.toml.**

Add `cc = "1.2"` to a new `[build-dependencies]` section at the end of Cargo.toml (after the existing `[lints]` section). Do NOT add it to `[dependencies]`. The exact addition:

```toml
[build-dependencies]
cc = "1.2"
```

**Step 3 — Add update-headers recipe to Justfile.**

Add the following recipe to Justfile after the `clean` recipe:

```just
# Re-vendor DuckDB C++ headers from the cargo build cache (run after DuckDB version bump)
# Requires `cargo test` to have been run at least once to unpack the bundled source.
update-headers:
    @echo "Copying DuckDB headers from cargo build cache..."
    @SRC=$$(find target/debug/build/libduckdb-sys-*/out/duckdb/src/include/ -maxdepth 0 -type d 2>/dev/null | head -1); \
    if [ -z "$$SRC" ]; then echo "ERROR: Run 'cargo test' first to unpack DuckDB headers"; exit 1; fi; \
    cp -r "$$SRC/." duckdb_capi/; \
    echo "Headers copied from $$SRC"
```
  </action>
  <verify>
    <automated>test -f /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/duckdb_capi/duckdb.hpp && grep -q "build-dependencies" /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/Cargo.toml && grep -q 'cc = ' /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/Cargo.toml && grep -q "update-headers" /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/Justfile && echo "OK"</automated>
  </verify>
  <done>duckdb_capi/duckdb.hpp exists, Cargo.toml has [build-dependencies] with cc = "1.2", Justfile has update-headers recipe.</done>
</task>

<task type="auto">
  <name>Task 2: Create C++ shim skeleton and Rust module stub</name>
  <files>src/shim/shim.cpp, src/shim/shim.h, src/shim/mod.rs</files>
  <action>
Create `src/shim/` directory with three files.

**src/shim/shim.h** — C header declaring the extern C boundary. This header is included by both shim.cpp and will be referenced from Rust via extern "C" declarations:

```c
// src/shim/shim.h
// extern "C" boundary between the C++ shim and Rust.
// Must be includable from both C++ (shim.cpp) and plain C.
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

// Called from Rust init_extension to wire up C++ hooks.
// Phase 8: intentional no-op. Phases 10/11 add parser and pragma registration.
// db_instance_ptr is a pointer to a DuckDB DatabaseInstance; cast in later phases.
void semantic_views_register_shim(void* db_instance_ptr);

#ifdef __cplusplus
}
#endif
```

**src/shim/shim.cpp** — C++ skeleton. Includes DuckDB headers to prove they compile. The include for `duckdb/main/config.hpp`, `duckdb/parser/parser_extension.hpp`, and `duckdb/function/pragma_function.hpp` are intentionally included now to catch compilation errors early — these are the exact headers Phases 10 and 11 will use. Do NOT add any logic:

```cpp
// src/shim/shim.cpp
// Phase 8 skeleton: proves Rust+C++ build boundary compiles cleanly.
// No logic — registration callbacks added in Phases 10 (pragma_query_t)
// and 11 (parser_extension).
#include "duckdb.hpp"
#include "duckdb/main/config.hpp"
#include "duckdb/parser/parser_extension.hpp"
#include "duckdb/function/pragma_function.hpp"
#include "shim.h"

using namespace duckdb;

extern "C" {

// Phase 8: intentional no-op.
// db_instance_ptr will be cast to DatabaseInstance* in Phase 10:
//   auto& db = *reinterpret_cast<DatabaseInstance*>(db_instance_ptr);
//   auto& config = DBConfig::GetConfig(db);
//   config.parser_extensions.push_back(...);  // Phase 11
void semantic_views_register_shim(void* /* db_instance_ptr */) {
    // Intentional no-op. Proves C++ compilation and extern "C" boundary work.
}

} // extern "C"
```

**IMPORTANT for include paths:** The `build.rs` will set the include path to `duckdb_capi/`. The `#include "duckdb.hpp"` line resolves against that path. The `#include "duckdb/main/config.hpp"` lines resolve against subdirectories of the vendored tree. If the vendored tree is a full include directory (Task 1 copied the full tree), these subdirectory includes work. If only `duckdb.hpp` was vendored, check whether it is self-contained by looking for `#include "duckdb/` directives inside the file — if present and unresolved, the full tree copy is required.

**src/shim/mod.rs** — Empty Rust module file (Phase 8 exposes no Rust types from the shim):

```rust
// src/shim/mod.rs
// Phase 8: empty module — the C++ shim has no Rust-visible exports yet.
// Phases 10 and 11 will add types here as the shim grows.
```
  </action>
  <verify>
    <automated>test -f /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/src/shim/shim.cpp && test -f /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/src/shim/shim.h && test -f /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/src/shim/mod.rs && grep -q "semantic_views_register_shim" /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/src/shim/shim.cpp && grep -q "semantic_views_register_shim" /Users/paul/Documents/Dev/Personal/duckdb-semantic-views/src/shim/shim.h && echo "OK"</automated>
  </verify>
  <done>src/shim/shim.cpp exists with extern C no-op, src/shim/shim.h declares semantic_views_register_shim, src/shim/mod.rs is an empty module file.</done>
</task>

</tasks>

<verification>
After both tasks complete:
1. `test -f duckdb_capi/duckdb.hpp` — header vendored
2. `grep "build-dependencies" Cargo.toml` — cc dependency declared
3. `test -f src/shim/shim.cpp && test -f src/shim/shim.h && test -f src/shim/mod.rs` — shim files present
4. `grep "semantic_views_register_shim" src/shim/shim.h` — boundary declaration exists
5. `cargo test` still passes — no regressions (shim files exist but build.rs not yet added, so cc not invoked)
</verification>

<success_criteria>
All C++ shim source files exist with correct content. Cargo.toml declares the cc build-dependency. duckdb_capi/duckdb.hpp is vendored. cargo test passes (build.rs not yet present, so no C++ compilation triggered). Ready for plan 02 to add build.rs and wire lib.rs.
</success_criteria>

<output>
After completion, create `.planning/phases/08-cpp-shim-infrastructure/08-01-SUMMARY.md`
</output>
