---
phase: 62
plan: 04
type: execute
wave: 3
depends_on: ["62-01", "62-02", "62-03"]
files_modified:
  - test/integration/test_caret_position.py
  - test/integration/test_multi_db_isolation.py
  - test/sql/error_caret_create.test
  - test/sql/error_caret_drop.test
  - test/sql/error_caret_alter.test
  - test/sql/error_caret_multiline.test
  - test/sql/error_caret_unicode.test
  - test/sql/lru_removed_isolation.test
  - test/sql/extension_reload.test
  - test/sql/peg_compat.test
  - CHANGELOG.md
  - TECH-DEBT.md
autonomous: false
requirements: []
notes: |
  Wave 3 — Test population + docs. Now that caret rendering is back (Plan 03)
  and LRU removed (Plan 02), populate every Wave 0 fixture with concrete
  expected text and tighten the Python integration test assertions. Also adds
  the rc=3 actionable-error sqllogistest case to peg_compat.test, updates
  CHANGELOG.md with the Phase 62 entry under [0.8.0] - Unreleased, and marks
  TECH-DEBT items 20 and 22 as ✅ resolved with back-references to this phase.
  Includes a checkpoint:human-verify gate at the end for the manual caret
  smoke (terminal rendering visual fidelity per VALIDATION.md manual-only).

must_haves:
  truths:
    - "All 7 sqllogictest fixtures created in Plan 01 have real `statement error` blocks (no more `halt` no-ops)"
    - "test_caret_position.py: 3 existing tests + 4 new tests all assert `extract_caret_position(...)` returns a non-None integer at the expected column"
    - "test_multi_db_isolation.py: 17-DB sequential test + 50-DB RSS-bounded test are no longer skipped; both pass"
    - "test/sql/peg_compat.test contains a `disable_peg_parser` + CREATE case asserting the rc=3 actionable hint substring"
    - "CHANGELOG.md `[0.8.0] - Unreleased` section contains a Phase 62 entry describing caret restoration and LRU removal"
    - "TECH-DEBT.md items 20 and 22 are marked ✅ resolved with a Phase 62 back-reference"
    - "`just test-all` green; `just ci` green"
  artifacts:
    - path: "test/integration/test_caret_position.py"
      provides: "Tightened assertions on caret column for B1–B7"
      contains: "assert caret_col is not None"
    - path: "test/integration/test_multi_db_isolation.py"
      provides: "Active 17-DB and 50-DB tests (no longer skipped)"
    - path: "test/sql/peg_compat.test"
      provides: "rc=3 actionable error case (B8)"
      contains: "SET allow_parser_override_extension"
    - path: "CHANGELOG.md"
      provides: "Phase 62 entry under [0.8.0] - Unreleased"
      contains: "Phase 62"
    - path: "TECH-DEBT.md"
      provides: "Items 20 and 22 marked resolved"
      contains: "✅ resolved.*Phase 62"
  key_links:
    - from: "test/integration/test_caret_position.py existing tests"
      to: "extract_caret_position helper"
      via: "Now-active assertion"
      pattern: "assert caret_col is not None"
    - from: "test/sql/peg_compat.test"
      to: "rc=3 actionable error path in sv_parse_function_rust"
      via: "disable_peg_parser → CREATE without re-arming → caret-rendered hint"
      pattern: "allow_parser_override_extension.*FALLBACK"
---

<objective>
Wave 3 — close out Phase 62. Population, tightening, documentation, and a
final manual gate.

Now that:
- Wave 0 (Plan 01) installed all fixture skeletons
- Wave 1 (Plan 02) removed the LRU
- Wave 2 (Plan 03) restored caret rendering

…we fill in the concrete expected text in every fixture, flip the Python
integration tests from skip → assert, add the new rc=3 sqllogictest case to
`peg_compat.test`, and update CHANGELOG + TECH-DEBT.

Final task is a `checkpoint:human-verify` for the terminal-rendering visual
fidelity check (VALIDATION.md "Manual-Only Verifications" — the duckdb CLI
caret alignment is human-perceptible and not captured by sqllogictest's
substring matchers).

Purpose: TECH-DEBT 20 + 22 marked ✅ resolved with full test coverage.
Phase 62 verification ready.

Output: 7 populated sqllogistest fixtures + tightened Python tests + new
peg_compat case + CHANGELOG entry + TECH-DEBT updates + visual smoke
confirmed.
</objective>

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

<context>
@.planning/STATE.md
@.planning/phases/62-caret-restoration-lru-removal/62-RESEARCH.md
@.planning/phases/62-caret-restoration-lru-removal/62-VALIDATION.md
@.planning/phases/62-caret-restoration-lru-removal/62-01-SUMMARY.md
@.planning/phases/62-caret-restoration-lru-removal/62-02-SUMMARY.md
@.planning/phases/62-caret-restoration-lru-removal/62-03-SUMMARY.md
@CLAUDE.md
@TECH-DEBT.md
@CHANGELOG.md

<interfaces>
<!-- The exact rc=3 message from Plan 03 Task 1 — sqllogistest must substring-match this -->
"semantic_views: parser_override is not active for this connection
 (allow_parser_override_extension is 'DEFAULT' or 'STRICT'). Re-enable with:
 SET allow_parser_override_extension='FALLBACK';"

<!-- extract_caret_position helper signature (test/integration/test_caret_position.py:73) -->
def extract_caret_position(error_text: str) -> int | None: ...
# Returns 0-based column relative to query (after subtracting "LINE 1: " 8-char prefix)
# Returns None if no caret line found.
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Populate 7 sqllogictest fixtures with concrete expected text</name>
  <files>test/sql/error_caret_create.test, test/sql/error_caret_drop.test, test/sql/error_caret_alter.test, test/sql/error_caret_multiline.test, test/sql/error_caret_unicode.test, test/sql/lru_removed_isolation.test, test/sql/extension_reload.test</files>
  <read_first>
    - All 7 fixture files in their post-Plan-01 (halted) state
    - test/sql/peg_compat.test (mature reference for `statement error` matchers)
    - test/sql/v080_transactional_ddl.test (reference for multi-statement DDL fixtures)
    - .planning/phases/62-caret-restoration-lru-removal/62-RESEARCH.md §6 (B1–B19 expected behaviours)
    - test/integration/test_caret_position.py (the 3 existing test bodies — replicate query shapes for sqllogictest where possible)
  </read_first>
  <action>
    Replace each `halt` directive with concrete `statement error` blocks. Use
    the `<expected error substring>` pattern that sqllogictest matches as
    substring (per spike report all matchers are substring, not prefix-anchored).

    **`test/sql/error_caret_create.test`:**
    Remove `halt`. Add (verify exact validator message strings against current src/parse.rs error text — the strings below are pinned by RESEARCH §6 but the planner may need to grep `src/parse.rs` for the exact wording at execution time):

    ```
    require semantic_views

    statement ok
    LOAD semantic_views;

    statement ok
    CREATE TABLE t(id INTEGER PRIMARY KEY);

    # B1: missing '(' after TABLES — caret should land on the position after TABLES
    statement error
    CREATE SEMANTIC VIEW v_bad_paren AS TABLES t;
    ----
    LINE 1:

    # B2: clause keyword typo (TBLES → TABLES)
    statement error
    CREATE SEMANTIC VIEW v_bad_kw AS TBLES (t);
    ----
    LINE 1:

    # B3: prefix near-miss
    statement error
    CRETAE SEMANTIC VIEW v_typo AS TABLES (t);
    ----
    Did you mean
    ```

    Note: sqllogictest matches the error substring against the FULL rendered
    error including `Parser Error: ... LINE 1: ... ^`. Putting `LINE 1:` as
    the matcher pins that caret rendering is happening — substring match on
    `LINE 1:` is the verifier we have for "caret was rendered." Likewise
    `Did you mean` pins the near-miss helper.

    **`test/sql/error_caret_drop.test`:**
    ```
    require semantic_views
    statement ok
    LOAD semantic_views;

    # B7: DROP without name
    statement error
    DROP SEMANTIC VIEW;
    ----
    LINE 1:
    ```

    **`test/sql/error_caret_alter.test`:**
    ```
    require semantic_views
    statement ok
    LOAD semantic_views;

    statement ok
    CREATE TABLE t(id INTEGER PRIMARY KEY);

    statement ok
    CREATE SEMANTIC VIEW v_for_alter AS TABLES (t);

    # B6: ALTER with typo (RENAM → RENAME)
    statement error
    ALTER SEMANTIC VIEW v_for_alter RENAM TO w;
    ----
    LINE 1:
    ```

    **`test/sql/error_caret_multiline.test`:**
    ```
    require semantic_views
    statement ok
    LOAD semantic_views;

    statement ok
    CREATE TABLE t(id INTEGER PRIMARY KEY);

    # B4: multi-line CREATE with malformed clause on line 3 — verify caret line label
    statement error
    CREATE SEMANTIC VIEW v_ml AS
    TABLES (t)
    DIMENSIONS (TBLES x);
    ----
    LINE
    ```

    (The matcher `LINE` is intentionally loose — DuckDB may render `LINE 1:`,
    `LINE 2:`, or `LINE 3:` depending on whether the input has been
    line-folded. The presence of `LINE` proves caret rendering happened; the
    Python test pins exact column positions where we control them.)

    **`test/sql/error_caret_unicode.test`:**
    ```
    require semantic_views
    statement ok
    LOAD semantic_views;

    statement ok
    CREATE TABLE t(id INTEGER PRIMARY KEY);

    # B5: multibyte UTF-8 identifier before error token. DuckDB renders byte columns;
    # this test pins the contract (substring match for caret presence — exact
    # column counted in test_caret_position.py::test_caret_unicode_prefix).
    statement error
    CREATE SEMANTIC VIEW vüé AS TBLES (t);
    ----
    LINE 1:
    ```

    **`test/sql/lru_removed_isolation.test`:**
    ```
    require semantic_views
    statement ok
    LOAD semantic_views;

    # B15 sqllogictest companion — ATTACH 17 in-memory DBs, CREATE on each.
    # Pre-Phase-62 the LRU evicted the oldest at the 17th attach.
    statement ok
    ATTACH ':memory:' AS db_01;
    statement ok
    ATTACH ':memory:' AS db_02;
    statement ok
    ATTACH ':memory:' AS db_03;
    statement ok
    ATTACH ':memory:' AS db_04;
    statement ok
    ATTACH ':memory:' AS db_05;
    statement ok
    ATTACH ':memory:' AS db_06;
    statement ok
    ATTACH ':memory:' AS db_07;
    statement ok
    ATTACH ':memory:' AS db_08;
    statement ok
    ATTACH ':memory:' AS db_09;
    statement ok
    ATTACH ':memory:' AS db_10;
    statement ok
    ATTACH ':memory:' AS db_11;
    statement ok
    ATTACH ':memory:' AS db_12;
    statement ok
    ATTACH ':memory:' AS db_13;
    statement ok
    ATTACH ':memory:' AS db_14;
    statement ok
    ATTACH ':memory:' AS db_15;
    statement ok
    ATTACH ':memory:' AS db_16;
    statement ok
    ATTACH ':memory:' AS db_17;
    ```

    NOTE: ATTACH does not load the extension into the attached database — it
    creates a database within the same DBConfig. The LRU concern is about
    multiple `duckdb.connect()` calls in a Python process (each gets its own
    DBConfig). The above tests ATTACH-attachment limits but does NOT
    reproduce the LRU eviction. The TRUE test for B15 is in
    `test/integration/test_multi_db_isolation.py` which uses 17 separate
    `duckdb.connect()` calls. Keep the ATTACH test here as a defensive smoke
    (it cost nothing) — but note in a comment that the load-bearing test is
    the Python integration test:

    ```
    # NB: load-bearing B15 test is test/integration/test_multi_db_isolation.py::test_seventeen_dbs_sequential_create
    # — that test creates 17 separate duckdb.connect() instances (each with its own DBConfig and
    # therefore its own SemanticViewsParserInfo). This sqllogictest is a smoke for ATTACH-side
    # multi-DB which exercises a different path (single DBConfig, multiple AttachedDatabase).
    ```

    **`test/sql/extension_reload.test`:**
    ```
    require semantic_views
    statement ok
    LOAD semantic_views;

    statement ok
    CREATE TABLE t(id INTEGER PRIMARY KEY);

    statement ok
    CREATE SEMANTIC VIEW v_reload AS TABLES (t);

    # B18: re-LOAD should be idempotent (DuckDB de-dupes; or composes safely with two parser_info).
    statement ok
    LOAD semantic_views;

    # The view is still there and DROP still works.
    statement ok
    DROP SEMANTIC VIEW v_reload;
    ```

    **Validator-message exact-text reconciliation:** at execution time, the
    executor must grep `src/parse.rs` for the actual error message strings
    referenced by name above (e.g. `TBLES` clause failure produces what
    exact text?) and confirm the substring matchers match. If a chosen
    matcher doesn't appear in the actual error output, replace with one
    that does. This is a known integration step — not a planning gap.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && for f in test/sql/error_caret_create.test test/sql/error_caret_drop.test test/sql/error_caret_alter.test test/sql/error_caret_multiline.test test/sql/error_caret_unicode.test test/sql/lru_removed_isolation.test test/sql/extension_reload.test; do grep -q "halt" "$f" && { echo "$f still has halt"; exit 1; }; grep -q "statement" "$f" || { echo "$f missing statement blocks"; exit 1; }; done && just test-sql 2>&1 | tail -20</automated>
  </verify>
  <acceptance_criteria>
    - All 7 fixture files no longer contain `halt`
    - All 7 fixture files contain at least one `statement error` or `statement ok` block beyond the load preamble
    - `just test-sql` exits 0 — every fixture passes (caret matchers find their substring; ATTACH smoke succeeds)
  </acceptance_criteria>
  <done>7 sqllogictest fixtures populated and green; substring matchers pin caret rendering for CREATE/DROP/ALTER/multiline/Unicode/multi-DB/reload paths.</done>
</task>

<task type="auto">
  <name>Task 2: Tighten Python integration assertions; activate 17-DB + 50-DB tests; add rc=3 case to peg_compat.test</name>
  <files>test/integration/test_caret_position.py, test/integration/test_multi_db_isolation.py, test/sql/peg_compat.test</files>
  <read_first>
    - test/integration/test_caret_position.py post-Plan-01-Task-3 state (3 existing tests with skip-on-None pattern; 4 new test skeletons currently skipping)
    - test/integration/test_multi_db_isolation.py post-Plan-01-Task-3 state (2 new tests currently `print("SKIP"); return`)
    - test/sql/peg_compat.test (full file, especially lines 115–145 around the existing FALLBACK workaround)
    - .planning/phases/62-caret-restoration-lru-removal/62-RESEARCH.md §6 row B8 (rc=3 actionable hint)
    - .planning/phases/62-caret-restoration-lru-removal/62-RESEARCH.md §4 Refinement 2 (exact rc=3 wording)
  </read_first>
  <action>
    **Sub-step 2a — `test/integration/test_caret_position.py`:**

    1. Replace the module-level docstring at lines 14–21 (the v0.8.1 prose
       about runtime `Invalid Input Error`) with a Phase 62 update:
       ```
       Phase 62 (v0.8.0 — 2026-05-06): caret rendering restored. Validation
       errors now arrive as `Parser Error: ... LINE 1: ... ^` via parse_function
       (parser_override defers all errors; default parser fails; parse_function
       returns DISPLAY_EXTENSION_ERROR with byte-offset error_location).
       Tests assert both message text and caret column position.

       Resolves TECH-DEBT item 22.
       ```

    2. For each of the 3 existing tests (`test_caret_missing_paren`,
       `test_caret_clause_typo`, `test_caret_near_miss`): remove the Plan-01
       `pytest.skip(...)` (or `print("SKIP"); return`) on the
       `extract_caret_position` None-branch. Replace with:
       ```python
       caret_col = extract_caret_position(error_text)
       assert caret_col is not None, f"Phase 62 contract: caret column should be reported, got error_text={error_text!r}"
       assert caret_col >= 0, f"caret column must be non-negative, got {caret_col}"
       # Tighten further: caret should land on the start of the offending token
       # for each test. Per RESEARCH §6 these are the expected columns:
       #   test_caret_missing_paren: column of the offending token
       #   test_caret_clause_typo: column of "TBLES"
       #   test_caret_near_miss: column 0 (start of "CRETAE")
       ```

       Pin the EXACT expected column per test by computing it from the query
       string (e.g. `query.index("TBLES")`). Be conservative — if DuckDB's
       column counting differs by 1 (1-based vs 0-based) account for that
       once empirically observed in the manual smoke from Plan 03.

    3. For each of the 4 new tests added in Plan 01
       (`test_caret_multiline_typo`, `test_caret_unicode_prefix`,
       `test_caret_alter_typo`, `test_caret_drop_missing_name`): remove the
       `pytest.skip("Plan 04 will populate")` and assert
       `extract_caret_position(error_text) is not None`. For
       `test_caret_unicode_prefix`, allow a wide tolerance on the column
       value — DuckDB uses byte-based positioning per RESEARCH §6 — and
       PIN the contract: assert column equals byte-position of TBLES, NOT
       character-position. Document the contract in a comment.

    **Sub-step 2b — `test/integration/test_multi_db_isolation.py`:**

    1. Activate `test_seventeen_dbs_sequential_create`: remove the
       `print("SKIP"); return` and uncomment the body. Verify it runs
       successfully — pre-Phase-62 the 17th DB would have triggered the LRU
       eviction error on a CREATE; post-Phase-62 every CREATE succeeds.

    2. Activate `test_fifty_db_open_close_rss_bounded`: remove the skip,
       uncomment the body. Use `psutil` if available, else `resource.getrusage(resource.RUSAGE_SELF).ru_maxrss`
       (note: returns KB on Linux, bytes on macOS — handle both). Assert
       RSS delta < 50 MB across the 50-iteration loop. Be lenient — this is
       a coarse smoke, not a precision benchmark.

    **Sub-step 2c — `test/sql/peg_compat.test`:**

    1. Locate the existing block around lines 120–145 that calls
       `disable_peg_parser` and re-arms `allow_parser_override_extension='FALLBACK'`.

    2. Add a NEW block immediately before that (or after — wherever it fits
       contextually) that demonstrates the rc=3 actionable error WITHOUT
       re-arming FALLBACK:

       ```
       # B8: Phase 62 — disable_peg_parser resets allow_parser_override_extension to DEFAULT.
       # Without re-arming FALLBACK, our parse_function emits the actionable hint with caret.
       statement ok
       CALL disable_peg_parser();

       statement error
       CREATE SEMANTIC VIEW v_b8 AS TABLES (t);
       ----
       SET allow_parser_override_extension='FALLBACK'

       # Recovery: re-arm FALLBACK and CREATE succeeds.
       statement ok
       SET allow_parser_override_extension='FALLBACK';

       statement ok
       CREATE TABLE t(id INTEGER PRIMARY KEY);

       statement ok
       CREATE SEMANTIC VIEW v_b8 AS TABLES (t);

       statement ok
       DROP SEMANTIC VIEW v_b8;
       ```

       The matcher `SET allow_parser_override_extension='FALLBACK'` is a
       substring of the rc=3 actionable message text from Plan 03 Task 1.
       sqllogistest substring match handles the rest.

    3. Confirm the EXISTING peg_compat workaround case at lines 130-ish
       still passes — it's a happy path test (re-arm THEN issue CREATE)
       and should continue to work.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && just test-caret 2>&1 | tail -20 && just test-multi-db 2>&1 | tail -15 && just test-sql 2>&1 | tail -15</automated>
  </verify>
  <acceptance_criteria>
    - `test/integration/test_caret_position.py` contains `assert caret_col is not None` (the Plan 04 tightening landed)
    - `test/integration/test_caret_position.py` does NOT contain `pytest.skip` referencing Phase 62 / Plan 04
    - `test/integration/test_multi_db_isolation.py` does NOT contain `print("SKIP: Phase 62 Plan 04")`
    - `test/sql/peg_compat.test` contains `SET allow_parser_override_extension='FALLBACK'` as a `statement error` matcher (the rc=3 case)
    - `just test-caret` exits 0 (all 7 caret tests now actively assert column position)
    - `just test-multi-db` exits 0 (17-DB + 50-DB tests pass)
    - `just test-sql` exits 0 (peg_compat with new rc=3 case passes)
  </acceptance_criteria>
  <done>All Python integration tests fully active; rc=3 case wired into peg_compat.test; tight assertions on caret column positions; suite green.</done>
</task>

<task type="auto">
  <name>Task 3: Update CHANGELOG.md (Phase 62 entry) + mark TECH-DEBT 20 + 22 resolved</name>
  <files>CHANGELOG.md, TECH-DEBT.md</files>
  <read_first>
    - CHANGELOG.md (full file — locate the `[0.8.0] - Unreleased` section; per CLAUDE.md the v0.8.1 entries were folded in)
    - TECH-DEBT.md lines 162–198 (items 19, 20, 21, 22, 23 — items 20 and 22 are the ones to mark resolved)
  </read_first>
  <action>
    **Sub-step 3a — `CHANGELOG.md`:**

    Add a new sub-section under `[0.8.0] - Unreleased`. Place it as a peer
    of the existing Phase 58/59/60/61 sub-sections (or wherever the
    consolidated v0.8.0 changelog text is grouped):

    ```markdown
    ### Phase 62 — Caret restoration + LRU removal

    - **Caret rendering restored** for CREATE / DROP / ALTER SEMANTIC VIEW
      validation errors. Errors now arrive as `Parser Error: ... LINE 1: ... ^`
      with the caret aligned to the offending token, matching DuckDB's native
      parser-error rendering. Resolves the v0.8.1 known limitation
      (TECH-DEBT 22).
    - **Bounded multi-DB LRU removed.** The per-`db_token` 16-entry catalog
      LRU introduced in Phase 61 is gone; each `SemanticViewsParserInfo`
      now owns its `OverrideContext` directly, lifetime-tied to `DBConfig`.
      Long-running processes loading the extension into more than 16 distinct
      DuckDB instances no longer surface a "catalog context evicted" error.
      Resolves TECH-DEBT 20.
    - **New actionable error** when `allow_parser_override_extension` is
      `DEFAULT` or `STRICT` (e.g. after `CALL disable_peg_parser()`). The
      error includes the recovery hint: `SET allow_parser_override_extension='FALLBACK'`.
    - **Mechanism:** `parser_override` keeps the success / transactional path
      (rewrite to native SQL, re-parse on caller's connection). For every
      validation error it now defers (DISPLAY_ORIGINAL_ERROR); the default
      parser fails on the unrecognized DDL prefix; DuckDB calls
      `parse_function`, which re-runs validation and returns
      DISPLAY_EXTENSION_ERROR with `error_location` byte offset.
      `ParserException::SyntaxError` formats the caret automatically.
    ```

    Do NOT remove or rewrite the existing v0.8.1 known-limitations entry
    if it's still in the file — instead, add a leading note to it
    indicating "RESOLVED in Phase 62" with a back-reference. (Or move it
    into the resolved list — match the file's existing convention.)

    **Sub-step 3b — `TECH-DEBT.md`:**

    1. **Item 20 (line 171–176):** change the leading marker `❓` to `✅`.
       Add a "**Resolved:**" line:
       ```markdown
       ### 20. ✅ Bounded LRU evictions are silent at the parser-override site

       **Resolved in Phase 62 (v0.8.0).** The bounded LRU is gone — each
       `SemanticViewsParserInfo` owns an `OverrideContext` directly, lifetime
       tied to `DBConfig`. Multi-DB processes can load the extension into
       arbitrarily many DuckDB instances without eviction. The
       `duckdb_connection` inside each `OverrideContext` is intentionally
       leaked at DB shutdown to avoid a use-after-free on
       `~DatabaseInstance` destruction order — bounded at one Connection
       (~few KB) per DB ever opened in the process. See
       `.planning/phases/62-caret-restoration-lru-removal/62-RESEARCH.md` §Q2
       for the destruction-order trace.

       Original limitation (preserved for archaeology):
       <existing text>
       ```

    2. **Item 22 (line 185–190):** same treatment.
       ```markdown
       ### 22. ✅ FALLBACK_OVERRIDE silently drops `DISPLAY_EXTENSION_ERROR`

       **Resolved in Phase 62 (v0.8.0).** `parse_function` re-introduced
       purely as the error-reporting layer. parser_override now defers all
       validation errors (DISPLAY_ORIGINAL_ERROR / rc=2); the default parser
       fails; DuckDB calls our `sv_parse_stub`; we return
       DISPLAY_EXTENSION_ERROR with `error_location` byte offset.
       `ParserException::SyntaxError` renders `LINE 1: ... ^` for free.
       The synthesised `SELECT error('...')` workaround (`sql_throwing`)
       is removed.

       Original limitation (preserved for archaeology):
       <existing text>
       ```

    3. Items 19, 21, 23 remain `❓` (out of scope per RESEARCH §1).

    **Sub-step 3c — Final quality gate run:**
    - `just test-all` — full suite green
    - `just ci` — adds clippy pedantic + fmt + cargo-deny + fuzz compile + docs-check (per justfile:144 — this is the pre-push gate per CLAUDE.md)
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && grep -q "Phase 62" CHANGELOG.md && grep -q "✅.*[Bb]ounded LRU" TECH-DEBT.md && grep -q "✅.*FALLBACK_OVERRIDE" TECH-DEBT.md && just test-all 2>&1 | tail -10 && just ci 2>&1 | tail -20</automated>
  </verify>
  <acceptance_criteria>
    - `CHANGELOG.md` contains `Phase 62` under `[0.8.0] - Unreleased`
    - `CHANGELOG.md` Phase 62 section mentions both `Caret rendering restored` AND `LRU removed`
    - `TECH-DEBT.md` item 20 starts with `### 20. ✅` (was `### 20. ❓`)
    - `TECH-DEBT.md` item 22 starts with `### 22. ✅` (was `### 22. ❓`)
    - Both resolved items contain the substring `Phase 62`
    - `just test-all` exits 0
    - `just ci` exits 0 (lint + test-all + check-fuzz + docs-check all green)
  </acceptance_criteria>
  <done>CHANGELOG entry added; TECH-DEBT 20 + 22 marked resolved with Phase 62 back-reference; full CI gate green.</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 4: Manual visual smoke — caret alignment in interactive Python session</name>
  <files>(no files modified — manual verification only)</files>
  <action>See <how-to-verify> below. Manual checkpoint — pause for human confirmation of caret alignment in terminal output.</action>
  <verify>Manual visual inspection per <how-to-verify> instructions; resume signal carries the pasted error outputs.</verify>
  <done>Human approves all three smoke outputs; pastes them into resume signal for inclusion in phase summary.</done>
  <what-built>
    Phase 62 end-to-end. Caret rendering restored for all CREATE/DROP/ALTER validation errors; LRU removed; TECH-DEBT 20 + 22 marked resolved.
  </what-built>
  <how-to-verify>
    Run an interactive Python session against the freshly built debug extension and confirm caret alignment by EYE (sqllogictest substring matchers can't catch visual misalignment).

    Step 1 — start a Python REPL with the project's venv (`configure/venv/bin/python` or whichever makes the duckdb pip pkg available):
    ```
    cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views
    configure/venv/bin/python
    ```

    Step 2 — paste the smoke script:
    ```python
    import duckdb, os
    EXT = os.path.abspath("build/debug/semantic_views.duckdb_extension")
    EXT_DIR = os.path.dirname(EXT)
    conn = duckdb.connect(config={
        "allow_unsigned_extensions": "true",
        "extension_directory": EXT_DIR,
    })
    conn.execute(f"FORCE INSTALL '{EXT}'")
    conn.execute("LOAD semantic_views")
    conn.execute("CREATE TABLE t(id INTEGER PRIMARY KEY)")

    # Smoke 1: clause typo — caret should land on T of TBLES
    try:
        conn.execute("CREATE SEMANTIC VIEW bad AS TBLES (t);")
    except Exception as e:
        print("--- SMOKE 1 (TBLES typo) ---")
        print(repr(e))

    # Smoke 2: near-miss — caret should land on C of CRETAE (column 0)
    try:
        conn.execute("CRETAE SEMANTIC VIEW bad AS TABLES (t);")
    except Exception as e:
        print("--- SMOKE 2 (CRETAE near-miss) ---")
        print(repr(e))

    # Smoke 3: rc=3 actionable error — disable_peg_parser then CREATE
    conn.execute("CALL disable_peg_parser();")
    try:
        conn.execute("CREATE SEMANTIC VIEW bad AS TABLES (t);")
    except Exception as e:
        print("--- SMOKE 3 (rc=3 actionable) ---")
        print(repr(e))
    ```

    Step 3 — check each output for:
    - `Parser Error:` prefix (NOT `Invalid Input Error:`)
    - `LINE 1: ` followed by the user's input
    - A line containing only whitespace + a single `^`
    - The `^` is positioned UNDER the offending token (TBLES / CRETAE) — visually aligned in your terminal

    For SMOKE 3, also confirm the message contains:
    `SET allow_parser_override_extension='FALLBACK'`

    Paste all three error outputs into the resume signal so they end up in
    the phase summary.
  </how-to-verify>
  <resume-signal>
    Type "approved" with the three pasted error outputs OR describe any
    misalignment / unexpected text. Approval requires ALL three smokes pass
    visual inspection.
  </resume-signal>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| Wave 3 changes are test population + documentation only | No new production trust boundary; all documentation/test changes. |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-62-W3-01 | Information disclosure | TECH-DEBT.md description revealing internal architecture | accept | Project is open source; TECH-DEBT.md is checked-in transparency about known limitations. No secrets exposed. |
| T-62-W3-02 | DoS | 50-DB RSS-bounded test running long | mitigate | Test is bounded at 50 iterations with explicit per-iteration close. Total runtime < 60 seconds. |

No high-severity threats in Wave 3 — pure test / documentation work.
</threat_model>

<verification>
- `just test-all` exits 0
- `just ci` exits 0 (= lint + test-all + check-fuzz + docs-check)
- `rg "Phase 62" CHANGELOG.md` returns at least one hit
- `rg "✅.*Phase 62" TECH-DEBT.md` returns at least 2 hits (items 20 + 22)
- `rg "halt" test/sql/error_caret_*.test test/sql/lru_removed_isolation.test test/sql/extension_reload.test` returns ZERO hits
- `rg "pytest.skip.*Plan 04" test/integration/` returns ZERO hits
- Manual smoke approved (Task 4 checkpoint)
</verification>

<success_criteria>
- 7 sqllogictest fixtures populated and green
- 7 caret tests in test_caret_position.py actively asserting column position (no skips)
- 17-DB + 50-DB multi-DB tests passing (B15 + B16)
- rc=3 actionable error case in peg_compat.test (B8)
- CHANGELOG.md updated with Phase 62 entry
- TECH-DEBT 20 + 22 marked ✅ resolved
- `just ci` green — Phase 62 ready for `/gsd-verify-work`
- Manual visual smoke approved
</success_criteria>

<output>
After completion, create `.planning/phases/62-caret-restoration-lru-removal/62-04-SUMMARY.md` documenting:
- Final test counts (sqllogictest count delta; integration test counts; unit test counts)
- The pasted manual smoke outputs from Task 4
- A grep snapshot proving no remaining `halt` directives, `Plan 04` skip stubs, `parser_override_catalog`, `sql_throwing`, `db_token` references
- `just ci` final exit code + summary
</output>
