---
phase: 15-entry-point-poc
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - cpp/include/duckdb.hpp
  - cpp/src/shim.cpp
  - Cargo.toml
  - build.rs
  - .github/workflows/DuckDBVersionMonitor.yml
autonomous: true
requirements: [BUILD-01, BUILD-02]

must_haves:
  truths:
    - "shim.cpp compiles against vendored duckdb.hpp via cc crate"
    - "cargo test still passes without C++ compilation (feature-gated)"
    - "Extension binary contains the new CPP entry point symbol"
    - "DuckDB Version Monitor CI action has a step to re-fetch duckdb.hpp when bumping versions"
  artifacts:
    - path: "cpp/include/duckdb.hpp"
      provides: "Vendored DuckDB v1.4.4 amalgamation header"
    - path: "cpp/src/shim.cpp"
      provides: "Minimal C++ shim that compiles (stub only, no DuckDB entry point yet)"
    - path: "Cargo.toml"
      provides: "cc as optional build-dependency gated on extension feature"
      contains: "dep:cc"
    - path: "build.rs"
      provides: "cc crate compilation of shim.cpp + updated symbol visibility for CPP entry"
      contains: "semantic_views_duckdb_cpp_init"
    - path: ".github/workflows/DuckDBVersionMonitor.yml"
      provides: "Header re-fetch step when DuckDB version is bumped"
      contains: "duckdb.hpp"
  key_links:
    - from: "build.rs"
      to: "cpp/src/shim.cpp"
      via: "cc::Build::new().file()"
      pattern: 'file\("cpp/src/shim.cpp"\)'
    - from: "Cargo.toml"
      to: "build.rs"
      via: "cc optional build-dependency"
      pattern: 'cc.*optional.*true'
    - from: ".github/workflows/DuckDBVersionMonitor.yml"
      to: "cpp/include/duckdb.hpp"
      via: "Download amalgamation header on version bump"
      pattern: "duckdb.hpp"
---

<objective>
Set up the C++ build infrastructure for the CPP entry point strategy: vendor the DuckDB amalgamation header, create the cpp/ directory structure, add cc as a feature-gated build dependency, update the CI version monitor to re-fetch the header, and verify that a minimal C++ shim compiles against duckdb.hpp without breaking the existing `cargo test` workflow.

Purpose: BUILD-01 and BUILD-02 are prerequisites for the entry point switch. Isolating the build infrastructure in its own plan ensures the C++ compilation pipeline works before attempting the riskier FFI bridge work in Plan 02.
Output: cpp/ directory with vendored header and compiling shim, updated Cargo.toml and build.rs, updated CI workflow
</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/15-entry-point-poc/15-CONTEXT.md
@.planning/phases/15-entry-point-poc/15-RESEARCH.md

<interfaces>
<!-- Key types and contracts the executor needs from existing codebase -->

From build.rs (current, to be replaced):
```rust
// Current: gates on CARGO_FEATURE_EXTENSION, writes symbol visibility for semantic_views_init_c_api
// Must be rewritten to: compile shim.cpp via cc crate, export semantic_views_duckdb_cpp_init
```

From Cargo.toml (current features):
```toml
[features]
default = ["duckdb/bundled"]
extension = ["duckdb/loadable-extension", "duckdb/vscalar"]
# Must add: "dep:cc" to extension feature
```

From .github/workflows/DuckDBVersionMonitor.yml (current "Update version pin" step):
```yaml
- name: Update version pin
  if: steps.latest.outputs.is_new == 'true'
  run: |
    LATEST="${{ steps.latest.outputs.latest }}"
    sed -i "s/TARGET_DUCKDB_VERSION=.*/TARGET_DUCKDB_VERSION=${LATEST}/" Makefile
    sed -i "s/duckdb_version: .*/duckdb_version: ${LATEST}/" .github/workflows/MainDistributionPipeline.yml
    sed -i "s/duckdb_version: .*/duckdb_version: ${LATEST}/" .github/workflows/PullRequestCI.yml
    echo "Updated version pin to ${LATEST}"
# Must add: a step to re-fetch the amalgamation header for the new version
```
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create feature branch, vendor duckdb.hpp, and update Cargo.toml</name>
  <files>cpp/include/duckdb.hpp, cpp/src/shim.cpp, Cargo.toml</files>
  <action>
1. Create a feature branch: `git checkout -b feat/cpp-entry-point`

2. Create directory structure: `cpp/include/` and `cpp/src/`

3. Vendor the DuckDB v1.4.4 amalgamation header into `cpp/include/duckdb.hpp`. The header can be extracted from the libduckdb-sys cargo build cache. Run `cargo test` first (if not already cached) to unpack the source, then find the amalgamation header:
   ```
   find target/debug/build/libduckdb-sys-*/out -name "duckdb.hpp" -path "*/amalgamation/*" 2>/dev/null | head -1
   ```
   Copy that file to `cpp/include/duckdb.hpp`. If not found in cargo cache, download from the DuckDB v1.4.4 GitHub release (libduckdb-src.zip contains the amalgamation).

4. Create a minimal `cpp/src/shim.cpp` that compiles against the header but does NOT register as a DuckDB entry point yet (that is Plan 02). This is purely to validate the cc crate build pipeline:
   ```cpp
   // Minimal compilation test -- proves duckdb.hpp compiles via cc crate.
   // Full entry point and parser hooks added in Plan 02.
   #include "duckdb.hpp"

   // Placeholder: validates that ParserExtension types are available
   static_assert(sizeof(duckdb::ParserExtension) > 0, "ParserExtension type must be available");
   ```

5. Update `Cargo.toml`:
   - Add `cc` as an optional build-dependency: `cc = { version = "1", optional = true }`
   - Add `"dep:cc"` to the `extension` feature list

6. Add `cpp/include/duckdb.hpp` to `.gitignore` -- the 1.8MB amalgamation header should not be committed. Add a comment explaining it is vendored locally and re-fetched by CI / `just update-headers`.

IMPORTANT: The `cc` crate must be an OPTIONAL dependency gated on the `extension` feature. `cargo test` (default features) must never trigger C++ compilation.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && cargo test --lib -- --quiet 2>&amp;1 | tail -5</automated>
  </verify>
  <done>cpp/ directory exists with duckdb.hpp and minimal shim.cpp. Cargo.toml has cc as optional build-dep gated on extension feature. cargo test passes without triggering C++ compilation.</done>
</task>

<task type="auto">
  <name>Task 2: Update build.rs for cc crate compilation and CPP symbol visibility</name>
  <files>build.rs</files>
  <action>
Rewrite `build.rs` to:

1. Keep the existing feature-gate check: `if std::env::var("CARGO_FEATURE_EXTENSION").is_err() { return; }`

2. Add cc crate C++ compilation (AFTER the feature gate):
   ```rust
   cc::Build::new()
       .cpp(true)
       .std("c++17")
       .include("cpp/include")
       .file("cpp/src/shim.cpp")
       .warnings(false)  // Suppress warnings from the 50K-line duckdb.hpp
       .compile("semantic_views_shim");
   ```

3. Update symbol visibility to export `semantic_views_duckdb_cpp_init` instead of `semantic_views_init_c_api`:
   - Linux dynlist: `"{\n  semantic_views_duckdb_cpp_init;\n};\n"`
   - macOS exp: `"_semantic_views_duckdb_cpp_init\n"`

4. Verify the build compiles: `cargo build --no-default-features --features extension`
   - First build will take 15-30 seconds (compiling duckdb.hpp). This is expected per research Pitfall 1.
   - Subsequent builds are cached by cc crate unless shim.cpp or the header changes.

5. Verify `cargo test` (default features, no extension) still works -- it must NOT attempt C++ compilation.

AVOID: Do NOT include `duckdb.cpp` in the build -- only the header is needed. The shim only uses inline definitions and type declarations. Compiling duckdb.cpp (24MB) would be extremely slow and unnecessary.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && cargo build --no-default-features --features extension 2>&amp;1 | tail -10 && cargo test --lib -- --quiet 2>&amp;1 | tail -5</automated>
  </verify>
  <done>build.rs compiles shim.cpp via cc crate when extension feature is active. Symbol visibility exports semantic_views_duckdb_cpp_init. `cargo build --features extension` succeeds. `cargo test` (default) passes without C++ compilation.</done>
</task>

<task type="auto">
  <name>Task 3: Add header re-fetch step to DuckDB Version Monitor CI</name>
  <files>.github/workflows/DuckDBVersionMonitor.yml</files>
  <action>
Add a new step to `.github/workflows/DuckDBVersionMonitor.yml` that re-fetches the vendored `duckdb.hpp` amalgamation header when the DuckDB version is bumped. Per user decision: "Keep header up to date via the existing DuckDB Version Monitor CI action (add a step to re-fetch the header when bumping versions)."

Insert a new step AFTER the existing "Update version pin" step and BEFORE "Install Rust stable":

```yaml
    - name: Update vendored duckdb.hpp header
      if: steps.latest.outputs.is_new == 'true'
      run: |
        LATEST="${{ steps.latest.outputs.latest }}"
        # Download amalgamation source zip for the new version
        curl -L -o /tmp/libduckdb-src.zip \
          "https://github.com/duckdb/duckdb/releases/download/${LATEST}/libduckdb-src.zip"
        # Extract duckdb.hpp from the amalgamation
        unzip -o -j /tmp/libduckdb-src.zip "duckdb.hpp" -d cpp/include/
        rm /tmp/libduckdb-src.zip
        echo "Updated cpp/include/duckdb.hpp to ${LATEST}"
```

This ensures the vendored header stays in sync with the DuckDB version pin automatically. The header is .gitignored locally but committed by the CI PR so downstream builds work.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && grep -c "duckdb.hpp" .github/workflows/DuckDBVersionMonitor.yml</automated>
  </verify>
  <done>DuckDBVersionMonitor.yml contains a step that downloads and updates cpp/include/duckdb.hpp when bumping the DuckDB version pin.</done>
</task>

</tasks>

<verification>
1. `cargo test` passes (no C++ compilation triggered)
2. `cargo build --no-default-features --features extension` succeeds (cc compiles shim.cpp against duckdb.hpp)
3. Files exist: `cpp/include/duckdb.hpp`, `cpp/src/shim.cpp`
4. `build.rs` contains `semantic_views_duckdb_cpp_init` in symbol visibility lists
5. `.github/workflows/DuckDBVersionMonitor.yml` has a step that re-fetches `duckdb.hpp` on version bump
</verification>

<success_criteria>
- C++ shim compiles against vendored duckdb.hpp v1.4.4 via cc crate (BUILD-01)
- Symbol visibility lists updated for CPP entry point name (BUILD-02 partial -- full verification after Plan 02 wires the entry point)
- cargo test (bundled mode) passes without triggering C++ compilation
- DuckDB Version Monitor CI updated to re-fetch header on version bumps
- Feature branch created and all changes committed
</success_criteria>

<output>
After completion, create `.planning/phases/15-entry-point-poc/15-01-SUMMARY.md`
</output>
