---
phase: 41-describe-rewrite
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - test/sql/phase20_extended_ddl.test
  - test/sql/phase21_error_reporting.test
  - test/sql/phase25_keyword_body.test
  - test/sql/phase28_e2e.test
  - test/sql/phase29_facts.test
  - test/sql/phase30_derived_metrics.test
  - test/sql/phase33_cardinality_inference.test
  - src/query/error.rs
autonomous: true
requirements: [DESC-01, DESC-02, DESC-03, DESC-04, DESC-05, DESC-06, DESC-07]

must_haves:
  truths:
    - "All existing sqllogictest files with DESCRIBE assertions pass with the new 5-column property-per-row format"
    - "COUNT(*) assertions in phase33 tests reflect the correct number of property rows"
    - "Error assertions (does not exist) remain unchanged"
    - "Error help message in error.rs is updated to reflect new DESCRIBE output format"
  artifacts:
    - path: "test/sql/phase20_extended_ddl.test"
      provides: "Updated DESCRIBE assertions from query TTTTTT to query TTTTT multi-row"
      contains: "query TTTTT"
    - path: "test/sql/phase33_cardinality_inference.test"
      provides: "Updated COUNT(*) assertions for property-per-row format"
      contains: "describe_semantic_view"
    - path: "src/query/error.rs"
      provides: "Updated help message for DESCRIBE output"
      contains: "describe_semantic_view"
  key_links:
    - from: "test/sql/phase20_extended_ddl.test"
      to: "src/ddl/describe.rs"
      via: "DESCRIBE SEMANTIC VIEW invocation"
      pattern: "DESCRIBE SEMANTIC VIEW"
    - from: "test/sql/phase33_cardinality_inference.test"
      to: "src/ddl/describe.rs"
      via: "describe_semantic_view() table function"
      pattern: "describe_semantic_view"
---

<objective>
Update all existing test files containing DESCRIBE assertions to match the new 5-column property-per-row format, and update the error help message in error.rs.

Purpose: The describe.rs rewrite (Plan 01) changes the output format from 1 row with 6 columns to N rows with 5 columns. All existing tests that assert on DESCRIBE output must be updated atomically to prevent test failures. This plan MUST execute in the same wave as Plan 01.
Output: All 7 existing test files updated, error.rs help message updated, `just test-all` green.
</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/41-describe-rewrite/41-RESEARCH.md
@.planning/phases/41-describe-rewrite/41-01-SUMMARY.md

<interfaces>
<!-- The new DESCRIBE output format from Plan 01. -->

Output schema (5 VARCHAR columns):
- object_kind: TABLE | RELATIONSHIP | DIMENSION | FACT | METRIC | DERIVED_METRIC
- object_name: table alias / dim name / metric name / relationship name
- parent_entity: source table alias (empty for TABLE and DERIVED_METRIC)
- property: BASE_TABLE_DATABASE_NAME | BASE_TABLE_SCHEMA_NAME | BASE_TABLE_NAME | PRIMARY_KEY | TABLE | REF_TABLE | FOREIGN_KEY | REF_KEY | EXPRESSION | DATA_TYPE
- property_value: the value as string

Row emission order: tables, relationships, facts, dimensions, metrics (definition order within each kind).

Property order within each object:
- TABLE: BASE_TABLE_DATABASE_NAME, BASE_TABLE_SCHEMA_NAME, BASE_TABLE_NAME, PRIMARY_KEY (if non-empty)
- RELATIONSHIP: TABLE, REF_TABLE, FOREIGN_KEY, REF_KEY
- FACT/DIMENSION/METRIC: TABLE, EXPRESSION, DATA_TYPE
- DERIVED_METRIC: EXPRESSION, DATA_TYPE (no TABLE)

JSON array format for PK/FK/REF_KEY: ["col1","col2"] (no spaces after commas)

Empty strings for: parent_entity on TABLE/DERIVED_METRIC, DATA_TYPE when output_type is None, database_name/schema_name when not captured.
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Update DESCRIBE assertions in phase20, phase21, phase25 test files</name>
  <files>test/sql/phase20_extended_ddl.test, test/sql/phase21_error_reporting.test, test/sql/phase25_keyword_body.test</files>
  <read_first>
    - src/ddl/describe.rs (Plan 01 output — understand the new format)
    - test/sql/phase20_extended_ddl.test (5 DESCRIBE query assertions + 2 error assertions + 1 SELECT * FROM describe)
    - test/sql/phase21_error_reporting.test (1 DESCRIBE query assertion)
    - test/sql/phase25_keyword_body.test (1 DESCRIBE query assertion)
    - test/sql/phase41_describe.test (Plan 01 output — reference for correct assertion format)
  </read_first>
  <action>
    Update all DESCRIBE assertions in three test files. Each old `query TTTTTT` assertion with 1 result row must become `query TTTTT` with multiple property rows.

    **phase20_extended_ddl.test updates:**

    The test defines views with `TABLES (s AS sv_test PRIMARY KEY (region))`. The view `desc_test` has:
    - 1 table: alias=s, table=sv_test, pk=["region"]
    - 1 dimension: region, expr=region, source_table=s
    - 1 metric: total_amount, expr=SUM(amount), source_table=s
    - 0 joins, 0 facts

    **Line ~199-202** (first DESCRIBE assertion): Change from `query TTTTTT` with 1 row to `query TTTTT` with property rows:
    ```
    query TTTTT
    DESCRIBE SEMANTIC VIEW desc_test;
    ----
    TABLE	s		BASE_TABLE_DATABASE_NAME	{db_name}
    TABLE	s		BASE_TABLE_SCHEMA_NAME	{sch_name}
    TABLE	s		BASE_TABLE_NAME	sv_test
    TABLE	s		PRIMARY_KEY	["region"]
    DIMENSION	region	s	TABLE	s
    DIMENSION	region	s	EXPRESSION	region
    DIMENSION	region	s	DATA_TYPE	
    METRIC	total_amount	s	TABLE	s
    METRIC	total_amount	s	EXPRESSION	SUM(amount)
    METRIC	total_amount	s	DATA_TYPE	
    ```
    NOTE: {db_name} and {sch_name} will be whatever the connection context provides in sqllogictest. Check Plan 01's phase41_describe.test output for the actual values to use.

    **Line ~205-208** (lowercase describe assertion): Same update as above (same view, same expected output).

    **Line ~122-125** (`SELECT * FROM describe_semantic_view('sv_replace_test')` after DROP): This is a `statement error` assertion checking "does not exist" — NO CHANGE needed.

    **Line ~297-300** (lifecycle_test DESCRIBE after CREATE): Update to property-per-row format. View has same structure as desc_test (alias=s, table=sv_test, pk=["region"], 1 dim region, 1 metric total_amount).

    **Line ~322-325** (lifecycle_test DESCRIBE after REPLACE): Update to property-per-row format. After REPLACE, metric changed from total_amount/SUM(amount) to avg_amount/AVG(amount). So metric rows become avg_amount with EXPRESSION=AVG(amount).

    **Line ~332-335** (lifecycle_test DESCRIBE after DROP): This is a `statement error` assertion — NO CHANGE needed.

    **phase21_error_reporting.test updates:**

    **Line ~97-100**: View `err_valid` has alias=s, table=err_source, pk=["id"], 1 dim (id, expr=id, source_table=s), 1 metric (total, expr=SUM(val), source_table=s). Change `query TTTTTT` to `query TTTTT` with property rows.

    **phase25_keyword_body.test updates:**

    **Line ~84-87**: View `p25_orders_view` has alias=o, table=p25_orders, pk=["id"] (need to check actual DDL), 1 dim (region, expr=region, source_table=o), 1 metric (total_revenue, expr=SUM(revenue), source_table=o). Change `query TTTTTT` to `query TTTTT` with property rows.

    IMPORTANT: To determine exact expected output, you MUST read the CREATE SEMANTIC VIEW statement for each view in the test file to understand its tables, PKs, dimensions, metrics, facts, and joins. Then construct the expected property rows following the format from Plan 01.

    IMPORTANT: For empty string values in sqllogictest output, consecutive tabs represent the empty cell. For example, parent_entity empty on TABLE rows means two tabs between object_name and property columns: `TABLE\ts\t\tBASE_TABLE_NAME\tsv_test` where `\t\t` represents the empty parent_entity.

    IMPORTANT: Update the comment lines that say "6 columns" to reflect the new format. E.g., change "DESCRIBE SEMANTIC VIEW returns 6 columns: name, base_table, dimensions, metrics, joins, facts" to "DESCRIBE SEMANTIC VIEW returns property-per-row format (5 columns: object_kind, object_name, parent_entity, property, property_value)".
  </action>
  <verify>
    <automated>cargo test -- describe 2>&1 | tail -5</automated>
  </verify>
  <acceptance_criteria>
    - No `query TTTTTT` patterns remain in phase20_extended_ddl.test for DESCRIBE assertions
    - phase20 DESCRIBE assertions use `query TTTTT` with multi-row property output
    - phase21 DESCRIBE assertion uses `query TTTTT` with multi-row property output
    - phase25 DESCRIBE assertion uses `query TTTTT` with multi-row property output
    - All `statement error` assertions for "does not exist" are unchanged
    - Comment lines updated from "6 columns" to "5 columns" / property-per-row
    - `cargo test` compiles and runs without error
  </acceptance_criteria>
  <done>phase20, phase21, phase25 test files updated with correct property-per-row DESCRIBE assertions. No old 6-column assertions remain.</done>
</task>

<task type="auto">
  <name>Task 2: Update DESCRIBE assertions in phase28, phase29, phase30, phase33 tests and error.rs</name>
  <files>test/sql/phase28_e2e.test, test/sql/phase29_facts.test, test/sql/phase30_derived_metrics.test, test/sql/phase33_cardinality_inference.test, src/query/error.rs</files>
  <read_first>
    - test/sql/phase28_e2e.test (1 DESCRIBE query assertion — complex multi-table view with joins)
    - test/sql/phase29_facts.test (1 DESCRIBE query assertion — view with facts)
    - test/sql/phase30_derived_metrics.test (1 DESCRIBE query assertion — view with derived metrics)
    - test/sql/phase33_cardinality_inference.test (2 COUNT(*) assertions at lines 420 and 675)
    - src/query/error.rs (line 61 — help message referencing describe_semantic_view)
    - src/ddl/describe.rs (Plan 01 output — understand the new format)
    - test/sql/phase41_describe.test (Plan 01 output — reference for correct assertion format)
  </read_first>
  <action>
    Update DESCRIBE assertions in remaining 4 test files and the error help message.

    **phase28_e2e.test (line ~176-179):**

    View `p28_analytics` has:
    - Tables: o=p28_orders PK(id), c=p28_customers PK(id), p=p28_products PK(id)
    - Relationships: order_to_customer AS o(customer_id) REFERENCES c, order_to_product AS o(product_id) REFERENCES p
    - Dimensions: customer_name (source=c, expr=c.name), product_name (source=p, expr=p.name), region (source=o, expr=o.region), tier (source=c, expr=c.tier)
    - Metrics: total_revenue (source=o, expr=sum(o.amount)), order_count (source=o, expr=count(*))
    - No facts

    Read the actual CREATE statement to get exact details. Expected property rows:
    - 3 TABLE blocks (o: 4 rows, c: 4 rows, p: 4 rows) = 12 rows
    - 2 RELATIONSHIP blocks (order_to_customer: 4 rows, order_to_product: 4 rows) = 8 rows
    - 4 DIMENSION blocks (3 rows each) = 12 rows
    - 2 METRIC blocks (3 rows each) = 6 rows
    Total: 38 rows

    Change `query TTTTTT` to `query TTTTT` and provide all expected property rows in definition order.

    **phase29_facts.test (line ~108-111):**

    View `p29_analytics` has:
    - Tables: o=p29_orders PK(id), c=p29_customers PK(id), li=p29_line_items PK(id)
    - Relationships: li_to_order AS li(order_id) REFERENCES o, order_to_customer AS o(customer_id) REFERENCES c
    - Facts: net_price (source=li, expr=li.extended_price * (1 - li.discount)), tax_amount (source=li, expr=li.net_price * li.tax_rate)
    - Dimensions: region (source=o), country (source=c), state (source=c), city (source=c)
    - Metrics: total_net (source=li, expr=SUM(li.net_price)), total_tax (source=li, expr=SUM(li.tax_amount))

    Read actual CREATE to get details. Change `query TTTTTT` to `query TTTTT` with all property rows.

    **phase30_derived_metrics.test (line ~198-201):**

    View `p30_sales_facts` has:
    - Tables: o=p30_orders PK(id), li=p30_line_items PK(id)
    - Relationships: li_to_order AS li(order_id) REFERENCES o
    - Facts: net_price (source=li, expr=li.extended_price * (1 - li.discount))
    - Dimensions: region (source=o, expr=o.region)
    - Metrics: revenue (source=li, expr=SUM(li.net_price)), cost (source=li, expr=SUM(li.unit_cost)), profit (source=None/derived, expr=revenue - cost)

    Key: `profit` has source_table=None so it must be DERIVED_METRIC (no TABLE row, empty parent_entity). `revenue` and `cost` are METRIC (have TABLE row, parent=li).

    Change `query TTTTTT` to `query TTTTT` with property rows.

    **phase33_cardinality_inference.test:**

    **Line ~420** (`SELECT COUNT(*) FROM describe_semantic_view('p33_describe')`):
    View has: 2 tables (c, o) with PKs, 1 relationship (order_to_customer), 1 dimension (c.name), 1 metric (o.revenue).
    Row count: TABLE c (4 rows: DB_NAME, SCH_NAME, BASE_TABLE_NAME, PK) + TABLE o (4 rows) + RELATIONSHIP (4 rows) + DIM (3 rows) + METRIC (3 rows) = 18 rows.
    Change expected from `1` to the correct count (calculate after reading the actual view definition).

    **Line ~675** (`SELECT COUNT(*) FROM describe_semantic_view('p33_pkopt_describe')`):
    View has: 2 tables (c, o) WITHOUT explicit PKs (PKOpt test uses catalog lookup PKs), 1 relationship, 1 dimension, 1 metric.
    Tables without explicit PK from DDL: check if catalog-inferred PKs get stored. Read the CREATE statement. If pk_columns are populated via catalog lookup, they get PK rows. If not, only 3 rows per table.
    Change expected from `1` to the correct count.

    IMPORTANT: For phase33, you must carefully read the CREATE SEMANTIC VIEW statement for each test view to determine exactly which tables have PKs (explicit or inferred) and compute the exact row count.

    **src/query/error.rs (line ~61):**

    Current: `" Run FROM describe_semantic_view('{view_name}') to see available dimensions and metrics."`

    The function name `describe_semantic_view` is unchanged (it's the VTab function name, not the output format). The help message is still valid since the user can still run `FROM describe_semantic_view('...')`. However, update the wording to be more helpful with the new format:

    Change to: `" Run DESCRIBE SEMANTIC VIEW {view_name} to see available dimensions and metrics."`

    This uses the DDL syntax (which is the preferred user-facing interface) instead of the internal table function name.
  </action>
  <verify>
    <automated>just test-all 2>&1 | tail -20</automated>
  </verify>
  <acceptance_criteria>
    - No `query TTTTTT` patterns remain in any of: phase28_e2e.test, phase29_facts.test, phase30_derived_metrics.test
    - phase28 DESCRIBE assertion has multi-row property output covering TABLE, RELATIONSHIP, DIMENSION, METRIC rows
    - phase29 DESCRIBE assertion has property rows covering TABLE, RELATIONSHIP, FACT, DIMENSION, METRIC
    - phase30 DESCRIBE assertion has property rows with both METRIC and DERIVED_METRIC object kinds
    - phase33 COUNT(*) assertions updated from 1 to correct row counts
    - src/query/error.rs help message updated to use `DESCRIBE SEMANTIC VIEW {view_name}` syntax
    - `just test-all` passes (complete quality gate)
  </acceptance_criteria>
  <done>All existing test files updated. Error help message updated. `just test-all` passes with zero failures across all test suites.</done>
</task>

</tasks>

<verification>
1. `cargo test` passes — Rust unit tests, proptests, doc tests
2. `just build && just test-sql` passes — all sqllogictests green
3. `just test-ducklake-ci` passes — DuckLake integration tests
4. `just test-all` passes — complete quality gate
5. No `query TTTTTT` remains in any test file for DESCRIBE assertions
6. Grep for `DESCRIBE SEMANTIC VIEW` across test/ confirms all assertions use `query TTTTT` (5 columns)
</verification>

<success_criteria>
- All 7 existing test files with DESCRIBE assertions are updated to match property-per-row format
- phase33 COUNT(*) assertions reflect correct multi-row counts
- error.rs help message updated
- `just test-all` green — complete quality gate satisfied
</success_criteria>

<output>
After completion, create `.planning/phases/41-describe-rewrite/41-02-SUMMARY.md`
</output>
