---
phase: 44-show-describe-metadata-surface-enhancements
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - src/ddl/list.rs
  - src/ddl/show_dims.rs
  - src/ddl/show_metrics.rs
  - src/ddl/show_facts.rs
  - src/ddl/describe.rs
  - test/sql/phase34_1_show_commands.test
  - test/sql/phase34_1_1_show_filtering.test
  - test/sql/phase44_show_metadata.test
  - test/sql/phase44_describe_metadata.test
  - test/sql/TEST_LIST
autonomous: true
requirements: [SHOW-01, SHOW-06]

must_haves:
  truths:
    - "SHOW SEMANTIC DIMENSIONS/METRICS/FACTS output includes synonyms and comment columns (8 columns total)"
    - "SHOW SEMANTIC VIEWS output includes a comment column (6 columns total)"
    - "DESCRIBE SEMANTIC VIEW includes COMMENT, SYNONYMS, ACCESS_MODIFIER property rows for annotated objects"
    - "DESCRIBE SEMANTIC VIEW omits COMMENT/SYNONYMS rows when values are empty/None"
    - "DESCRIBE SEMANTIC VIEW shows ACCESS_MODIFIER for all facts and metrics (both PUBLIC and PRIVATE)"
    - "DESCRIBE SEMANTIC VIEW shows view-level COMMENT as object_kind=(empty), object_name=(empty)"
    - "All existing sqllogictest files pass after column count updates"
  artifacts:
    - path: "src/ddl/show_dims.rs"
      provides: "8-column output schema for SHOW SEMANTIC DIMENSIONS"
      contains: "synonyms"
    - path: "src/ddl/show_metrics.rs"
      provides: "8-column output schema for SHOW SEMANTIC METRICS"
      contains: "synonyms"
    - path: "src/ddl/show_facts.rs"
      provides: "8-column output schema for SHOW SEMANTIC FACTS"
      contains: "synonyms"
    - path: "src/ddl/list.rs"
      provides: "6-column output schema for SHOW SEMANTIC VIEWS (with comment)"
      contains: "comment"
    - path: "src/ddl/describe.rs"
      provides: "COMMENT, SYNONYMS, ACCESS_MODIFIER property rows"
      contains: "ACCESS_MODIFIER"
    - path: "test/sql/phase44_show_metadata.test"
      provides: "Integration tests for SHOW-01 metadata columns"
    - path: "test/sql/phase44_describe_metadata.test"
      provides: "Integration tests for SHOW-06 DESCRIBE metadata properties"
  key_links:
    - from: "src/ddl/show_dims.rs"
      to: "src/model.rs"
      via: "Dimension.synonyms, Dimension.comment fields"
      pattern: "d\\.synonyms|d\\.comment"
    - from: "src/ddl/describe.rs"
      to: "src/model.rs"
      via: "AccessModifier enum, comment/synonyms on all structs"
      pattern: "AccessModifier|format_json_array"
---

<objective>
Surface Phase 43 metadata annotations (COMMENT, SYNONYMS, PRIVATE/PUBLIC) through SHOW and DESCRIBE introspection commands.

Purpose: Users need to see metadata they set in DDL when inspecting semantic views. This is the read side of the metadata system -- Phase 43 added the write side.

Output: Updated VTab output schemas for all SHOW commands with new columns, extended DESCRIBE property rows, updated existing tests, new integration tests.
</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/44-show-describe-metadata-surface-enhancements/44-RESEARCH.md
@.planning/phases/43-metadata-foundation/43-01-SUMMARY.md
@.planning/phases/43-metadata-foundation/43-02-SUMMARY.md

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

From src/model.rs:
```rust
pub struct SemanticViewDefinition {
    pub comment: Option<String>,        // view-level comment
    pub database_name: Option<String>,
    pub schema_name: Option<String>,
    pub created_on: Option<String>,
    // ... tables, dimensions, metrics, facts ...
}

pub struct Dimension {
    pub comment: Option<String>,
    pub synonyms: Vec<String>,
    // ... name, expr, source_table, output_type ...
}

pub struct Metric {
    pub comment: Option<String>,
    pub synonyms: Vec<String>,
    pub access: AccessModifier,
    // ... name, expr, source_table, output_type, using_relationships ...
}

pub struct Fact {
    pub comment: Option<String>,
    pub synonyms: Vec<String>,
    pub access: AccessModifier,
    // ... name, expr, source_table, output_type ...
}

pub struct TableRef {
    pub comment: Option<String>,
    pub synonyms: Vec<String>,
    // ... alias, table, pk_columns, unique_constraints ...
}

pub enum AccessModifier { Public, Private }
```

From src/ddl/describe.rs:
```rust
fn format_json_array(items: &[String]) -> String;  // ["col1","col2"] format
struct DescribeRow { object_kind, object_name, parent_entity, property, property_value: String }
fn collect_table_rows(def: &SemanticViewDefinition, rows: &mut Vec<DescribeRow>);
fn collect_fact_rows(def, base_table, alias_map, rows);
fn collect_dimension_rows(def, base_table, alias_map, rows);
fn collect_metric_rows(def, base_table, alias_map, rows);
```

From src/ddl/show_dims.rs (same pattern in show_metrics.rs, show_facts.rs):
```rust
struct ShowDimRow { database_name, schema_name, semantic_view_name, table_name, name, data_type: String }
fn bind_output_columns(bind: &BindInfo);  // declares 6 VARCHAR columns
fn collect_dims(view_name: &str, json: &str) -> Vec<ShowDimRow>;
fn emit_rows(func, output) -> Result<...>;  // writes rows into output vectors 0-5
```

From src/ddl/list.rs:
```rust
struct ListRow { created_on, name, kind, database_name, schema_name: String }
// ListSemanticViewsVTab::bind declares 5 VARCHAR columns, writes vectors 0-4
```
</interfaces>
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Add synonyms+comment columns to all SHOW VTabs and update existing tests</name>
  <files>
    src/ddl/list.rs,
    src/ddl/show_dims.rs,
    src/ddl/show_metrics.rs,
    src/ddl/show_facts.rs,
    test/sql/phase34_1_show_commands.test,
    test/sql/phase34_1_1_show_filtering.test,
    test/sql/phase44_show_metadata.test,
    test/sql/TEST_LIST
  </files>
  <read_first>
    src/ddl/list.rs,
    src/ddl/show_dims.rs,
    src/ddl/show_metrics.rs,
    src/ddl/show_facts.rs,
    src/ddl/describe.rs,
    src/model.rs,
    test/sql/phase34_1_show_commands.test,
    test/sql/phase34_1_1_show_filtering.test,
    test/sql/phase34_1_show_dims_for_metric.test,
    test/sql/TEST_LIST
  </read_first>
  <behavior>
    - Test: SHOW SEMANTIC DIMENSIONS for a view with COMMENT and SYNONYMS on dimensions returns 8 columns with correct synonyms JSON and comment text
    - Test: SHOW SEMANTIC METRICS for a view with COMMENT and SYNONYMS on metrics returns 8 columns with correct values
    - Test: SHOW SEMANTIC FACTS for a view with COMMENT and SYNONYMS on facts returns 8 columns with correct values
    - Test: SHOW SEMANTIC VIEWS for a view with COMMENT returns 6 columns with comment text in last column
    - Test: SHOW DIMS/METRICS/FACTS for objects without annotations shows empty synonyms and empty comment
    - Test: All existing phase34_1_show_commands.test cases pass with updated column counts
    - Test: All existing phase34_1_1_show_filtering.test cases pass with updated column counts
  </behavior>
  <action>
    **SHOW SEMANTIC VIEWS (list.rs) -- add comment column (5 -> 6 columns):**
    Per Snowflake, SHOW SEMANTIC VIEWS has `comment` but NOT `synonyms`. Add:
    - Add `comment: String` field to `ListRow` struct
    - Add `bind.add_result_column("comment", LogicalTypeHandle::from(LogicalTypeId::Varchar))` after schema_name in bind
    - In bind's loop, read `def.comment.clone().unwrap_or_default()` into the new field (for views that fail to parse, use empty string)
    - In func, add `let comment_vec = output.flat_vector(5)` and `comment_vec.insert(i, row.comment.as_str())`

    **SHOW SEMANTIC DIMENSIONS (show_dims.rs) -- add synonyms+comment (6 -> 8 columns):**
    - Add `synonyms: String, comment: String` fields to `ShowDimRow` struct
    - In `bind_output_columns`, add two new `add_result_column` calls at end: `"synonyms"` and `"comment"`, both Varchar
    - In `collect_dims`, for each dimension row, add:
      - `synonyms: format_json_array(&d.synonyms)` -- import `format_json_array` from `super::describe` (make it `pub(crate)` in describe.rs)
      - `comment: d.comment.clone().unwrap_or_default()`
    - In `emit_rows`, add `let syn_vec = output.flat_vector(6)` and `let cmt_vec = output.flat_vector(7)`, insert for each row

    **SHOW SEMANTIC METRICS (show_metrics.rs) -- same pattern as dims (6 -> 8 columns):**
    - Add `synonyms: String, comment: String` to `ShowMetricRow`
    - In `bind_output_columns`, add `"synonyms"` and `"comment"` Varchar columns
    - In `collect_metrics`, read `format_json_array(&m.synonyms)` and `m.comment.clone().unwrap_or_default()`
    - In `emit_rows`, add vectors 6 and 7 for synonyms and comment

    **SHOW SEMANTIC FACTS (show_facts.rs) -- same pattern (6 -> 8 columns):**
    - Add `synonyms: String, comment: String` to `ShowFactRow`
    - In `bind_output_columns`, add `"synonyms"` and `"comment"` Varchar columns
    - In `collect_facts`, read `format_json_array(&f.synonyms)` and `f.comment.clone().unwrap_or_default()`
    - In `emit_rows`, add vectors 6 and 7 for synonyms and comment

    **Make `format_json_array` accessible from show_* modules:**
    In `src/ddl/describe.rs`, change `fn format_json_array` to `pub(crate) fn format_json_array`. Import it in show_dims.rs, show_metrics.rs, show_facts.rs as `use super::describe::format_json_array`.

    **Update existing test files for column count changes:**

    `test/sql/phase34_1_show_commands.test`:
    - All `query TTTTTT` for SHOW DIMS/METRICS/FACTS -> `query TTTTTTTT` (8 T's)
    - All data rows for DIMS/METRICS/FACTS: append two tab-separated empty columns `(empty)` and `(empty)` at end (since these views don't use annotations)
    - NOTE: The SHOW SEMANTIC VIEWS tests in phase20_extended_ddl.test use SELECT on specific columns, so they should not break from adding a column.

    `test/sql/phase34_1_1_show_filtering.test`:
    - All `query TTTTTT` for SHOW DIMS/METRICS/FACTS -> `query TTTTTTTT` (8 T's)
    - All data rows for DIMS/METRICS/FACTS: append `(empty)	(empty)` at end
    - NOTE: SHOW VIEWS tests in this file use `query TTTT` with SELECT on specific columns (name, kind, etc.) -- these do NOT need updating since they use explicit column selection, not `SELECT *`

    `test/sql/phase34_1_show_dims_for_metric.test`:
    - Check whether this file's output includes synonyms/comment columns. SHOW DIMS FOR METRIC uses `show_semantic_dimensions_for_metric` VTab which has its own schema (4 columns: semantic_view_name, dimension_name, data_type, required). It does NOT change -- leave as-is.

    **Create new test file `test/sql/phase44_show_metadata.test`:**
    Integration test that creates a semantic view with COMMENT and SYNONYMS annotations, then verifies SHOW commands include the metadata:
    - Setup: Create table + semantic view with COMMENT on view, COMMENT + SYNONYMS on dimensions, metrics, and facts
    - Test 1: SHOW SEMANTIC DIMENSIONS IN view -- verify synonyms JSON and comment text in columns 7-8
    - Test 2: SHOW SEMANTIC METRICS IN view -- verify synonyms and comment
    - Test 3: SHOW SEMANTIC FACTS IN view -- verify synonyms and comment
    - Test 4: SHOW SEMANTIC VIEWS -- verify comment column
    - Test 5: Cross-view SHOW SEMANTIC DIMENSIONS -- verify metadata from multiple views

    Add `test/sql/phase44_show_metadata.test` to `test/sql/TEST_LIST`.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && cargo test 2>&1 | tail -5 && just build && just test-sql 2>&1 | tail -10</automated>
  </verify>
  <acceptance_criteria>
    - src/ddl/list.rs contains `comment_vec = output.flat_vector(5)` and `add_result_column("comment"`
    - src/ddl/show_dims.rs contains `synonyms: String` and `comment: String` in ShowDimRow struct
    - src/ddl/show_dims.rs contains `format_json_array(&d.synonyms)`
    - src/ddl/show_dims.rs contains `output.flat_vector(6)` and `output.flat_vector(7)`
    - src/ddl/show_metrics.rs contains `synonyms: String` and `comment: String` in ShowMetricRow struct
    - src/ddl/show_facts.rs contains `synonyms: String` and `comment: String` in ShowFactRow struct
    - src/ddl/describe.rs contains `pub(crate) fn format_json_array`
    - test/sql/phase34_1_show_commands.test contains `query TTTTTTTT` (no remaining `query TTTTTT` for DIMS/METRICS/FACTS queries)
    - test/sql/phase34_1_1_show_filtering.test: DIMS/METRICS/FACTS queries use `query TTTTTTTT`
    - test/sql/phase44_show_metadata.test exists and contains SHOW SEMANTIC DIMENSIONS and SHOW SEMANTIC VIEWS tests
    - test/sql/TEST_LIST contains phase44_show_metadata.test
    - `cargo test` passes (all Rust tests)
    - `just test-sql` passes (all sqllogictest files including updated existing tests and new test file)
  </acceptance_criteria>
  <done>
    SHOW SEMANTIC VIEWS outputs 6 columns (added comment). SHOW SEMANTIC DIMENSIONS/METRICS/FACTS output 8 columns (added synonyms + comment). All existing test files updated for new column counts. New integration test verifies metadata columns are populated from DDL annotations.
  </done>
</task>

<task type="auto" tdd="true">
  <name>Task 2: Add COMMENT, SYNONYMS, ACCESS_MODIFIER properties to DESCRIBE output</name>
  <files>
    src/ddl/describe.rs,
    test/sql/phase44_describe_metadata.test,
    test/sql/TEST_LIST
  </files>
  <read_first>
    src/ddl/describe.rs,
    src/model.rs,
    test/sql/phase41_describe.test,
    test/sql/TEST_LIST
  </read_first>
  <behavior>
    - Test: DESCRIBE on a view with view-level COMMENT shows object_kind=(empty), object_name=(empty), property=COMMENT, property_value=comment text
    - Test: DESCRIBE on a view with TABLE COMMENT shows object_kind=TABLE, property=COMMENT with comment text
    - Test: DESCRIBE on a view with TABLE SYNONYMS shows object_kind=TABLE, property=SYNONYMS with JSON array
    - Test: DESCRIBE on a view with DIMENSION COMMENT and SYNONYMS shows both property rows
    - Test: DESCRIBE on a view with METRIC COMMENT, SYNONYMS, and ACCESS_MODIFIER shows all three property rows
    - Test: DESCRIBE on a view with FACT COMMENT, SYNONYMS, and ACCESS_MODIFIER shows all three property rows
    - Test: DESCRIBE on a view with DERIVED_METRIC ACCESS_MODIFIER shows ACCESS_MODIFIER row
    - Test: DESCRIBE omits COMMENT row when comment is None
    - Test: DESCRIBE omits SYNONYMS row when synonyms is empty
    - Test: DESCRIBE shows ACCESS_MODIFIER=PUBLIC for public facts/metrics (always emitted)
    - Test: DESCRIBE shows ACCESS_MODIFIER=PRIVATE for private metrics/facts
  </behavior>
  <action>
    **Add view-level COMMENT to DESCRIBE bind function:**
    In `DescribeSemanticViewVTab::bind`, after `collect_table_rows` but BEFORE `collect_relationship_rows`, add:
    ```rust
    // View-level COMMENT (SHOW-06)
    if let Some(ref comment) = def.comment {
        rows.push(DescribeRow {
            object_kind: String::new(),
            object_name: String::new(),
            parent_entity: String::new(),
            property: "COMMENT".to_string(),
            property_value: comment.clone(),
        });
    }
    ```

    **Extend `collect_table_rows` to emit COMMENT and SYNONYMS:**
    After the existing property rows for each table (BASE_TABLE_DATABASE_NAME, BASE_TABLE_SCHEMA_NAME, BASE_TABLE_NAME, PRIMARY_KEY), add:
    ```rust
    if let Some(ref comment) = table.comment {
        rows.push(DescribeRow {
            object_kind: "TABLE".to_string(),
            object_name: obj_name.clone(),
            parent_entity: String::new(),
            property: "COMMENT".to_string(),
            property_value: comment.clone(),
        });
    }
    if !table.synonyms.is_empty() {
        rows.push(DescribeRow {
            object_kind: "TABLE".to_string(),
            object_name: obj_name.clone(),
            parent_entity: String::new(),
            property: "SYNONYMS".to_string(),
            property_value: format_json_array(&table.synonyms),
        });
    }
    ```
    Note: the `obj_name` reference already exists in the loop; add these rows after the PRIMARY_KEY block inside the `for table in &def.tables` loop.

    **Extend `collect_dimension_rows` to emit COMMENT and SYNONYMS:**
    After the existing DATA_TYPE row push, add:
    ```rust
    if let Some(ref comment) = dim.comment {
        rows.push(DescribeRow {
            object_kind: "DIMENSION".to_string(),
            object_name: dim.name.clone(),
            parent_entity: parent.clone(),
            property: "COMMENT".to_string(),
            property_value: comment.clone(),
        });
    }
    if !dim.synonyms.is_empty() {
        rows.push(DescribeRow {
            object_kind: "DIMENSION".to_string(),
            object_name: dim.name.clone(),
            parent_entity: parent.clone(),
            property: "SYNONYMS".to_string(),
            property_value: format_json_array(&dim.synonyms),
        });
    }
    ```
    Note: `parent` is already a `clone()` in the existing code, so `.clone()` on parent is fine.

    **Extend `collect_fact_rows` to emit COMMENT, SYNONYMS, ACCESS_MODIFIER:**
    After the existing DATA_TYPE row push, add:
    ```rust
    if let Some(ref comment) = fact.comment {
        rows.push(DescribeRow {
            object_kind: "FACT".to_string(),
            object_name: fact.name.clone(),
            parent_entity: parent.clone(),
            property: "COMMENT".to_string(),
            property_value: comment.clone(),
        });
    }
    if !fact.synonyms.is_empty() {
        rows.push(DescribeRow {
            object_kind: "FACT".to_string(),
            object_name: fact.name.clone(),
            parent_entity: parent.clone(),
            property: "SYNONYMS".to_string(),
            property_value: format_json_array(&fact.synonyms),
        });
    }
    // Always emit ACCESS_MODIFIER for facts
    rows.push(DescribeRow {
        object_kind: "FACT".to_string(),
        object_name: fact.name.clone(),
        parent_entity: parent.clone(),
        property: "ACCESS_MODIFIER".to_string(),
        property_value: match fact.access {
            crate::model::AccessModifier::Public => "PUBLIC".to_string(),
            crate::model::AccessModifier::Private => "PRIVATE".to_string(),
        },
    });
    ```
    Import `AccessModifier` at the top of describe.rs: `use crate::model::AccessModifier;` (it is already in model.rs as `pub enum`).

    **Extend `collect_metric_rows` to emit COMMENT, SYNONYMS, ACCESS_MODIFIER:**
    After the existing DATA_TYPE row push (but still inside the for loop), add:
    ```rust
    if let Some(ref comment) = metric.comment {
        rows.push(DescribeRow {
            object_kind: object_kind.to_string(),
            object_name: metric.name.clone(),
            parent_entity: parent.clone(),
            property: "COMMENT".to_string(),
            property_value: comment.clone(),
        });
    }
    if !metric.synonyms.is_empty() {
        rows.push(DescribeRow {
            object_kind: object_kind.to_string(),
            object_name: metric.name.clone(),
            parent_entity: parent.clone(),
            property: "SYNONYMS".to_string(),
            property_value: format_json_array(&metric.synonyms),
        });
    }
    // Always emit ACCESS_MODIFIER for metrics (both regular and derived)
    rows.push(DescribeRow {
        object_kind: object_kind.to_string(),
        object_name: metric.name.clone(),
        parent_entity: parent.clone(),
        property: "ACCESS_MODIFIER".to_string(),
        property_value: match metric.access {
            crate::model::AccessModifier::Public => "PUBLIC".to_string(),
            crate::model::AccessModifier::Private => "PRIVATE".to_string(),
        },
    });
    ```
    Note: `object_kind` is already computed in the existing code as `"DERIVED_METRIC"` or `"METRIC"`.

    **Create `test/sql/phase44_describe_metadata.test`:**
    Integration test that creates a semantic view with full metadata annotations and verifies DESCRIBE output includes the new property rows:
    - Setup: Create table + semantic view with:
      - View-level COMMENT
      - TABLE with COMMENT and SYNONYMS
      - DIMENSION with COMMENT and SYNONYMS
      - FACT with COMMENT, SYNONYMS, and PRIVATE
      - METRIC with COMMENT, SYNONYMS (PUBLIC by default)
      - DERIVED_METRIC with COMMENT (test ACCESS_MODIFIER=PUBLIC)
    - Test 1: DESCRIBE -- verify view-level COMMENT row (object_kind=(empty), object_name=(empty), property=COMMENT)
    - Test 2: Verify TABLE COMMENT and SYNONYMS rows
    - Test 3: Verify DIMENSION COMMENT and SYNONYMS rows
    - Test 4: Verify FACT COMMENT, SYNONYMS, ACCESS_MODIFIER=PRIVATE rows
    - Test 5: Verify METRIC COMMENT, SYNONYMS, ACCESS_MODIFIER=PUBLIC rows
    - Test 6: Verify DERIVED_METRIC ACCESS_MODIFIER=PUBLIC row
    - Test 7: Create a view WITHOUT any annotations and verify NO COMMENT/SYNONYMS rows appear, but ACCESS_MODIFIER still appears for facts and metrics

    Add `test/sql/phase44_describe_metadata.test` to `test/sql/TEST_LIST`.

    **Verify existing test/sql/phase41_describe.test still passes:**
    The existing DESCRIBE tests use `query TTTTT` (5 T's) which remains correct since DESCRIBE output schema is unchanged (still 5 columns: object_kind, object_name, parent_entity, property, property_value). Only the NUMBER of rows per object changes (more property rows). Existing tests should pass because they don't use annotated views.
  </action>
  <verify>
    <automated>cd /Users/paul/Documents/Dev/Personal/duckdb-semantic-views && cargo test 2>&1 | tail -5 && just build && just test-sql 2>&1 | tail -10</automated>
  </verify>
  <acceptance_criteria>
    - src/ddl/describe.rs contains `use crate::model::AccessModifier`
    - src/ddl/describe.rs collect_table_rows contains `property: "COMMENT".to_string()` and `property: "SYNONYMS".to_string()`
    - src/ddl/describe.rs collect_dimension_rows contains `property: "COMMENT".to_string()` and `property: "SYNONYMS".to_string()`
    - src/ddl/describe.rs collect_fact_rows contains `property: "ACCESS_MODIFIER".to_string()`
    - src/ddl/describe.rs collect_metric_rows contains `property: "ACCESS_MODIFIER".to_string()`
    - src/ddl/describe.rs bind function contains view-level COMMENT push with `object_kind: String::new()`
    - test/sql/phase44_describe_metadata.test exists and contains at least 5 test cases
    - test/sql/phase44_describe_metadata.test contains `ACCESS_MODIFIER` in expected output
    - test/sql/TEST_LIST contains phase44_describe_metadata.test
    - `cargo test` passes
    - `just test-sql` passes (including new test file and existing phase41_describe.test)
  </acceptance_criteria>
  <done>
    DESCRIBE SEMANTIC VIEW emits COMMENT, SYNONYMS, and ACCESS_MODIFIER property rows for annotated objects. View-level COMMENT appears with empty object_kind/object_name. ACCESS_MODIFIER emitted for all facts and metrics (both PUBLIC and PRIVATE). COMMENT and SYNONYMS omitted when not set.
  </done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| DDL input -> VTab output | User-defined COMMENT/SYNONYMS text flows from stored JSON into output columns |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-44-01 | Information Disclosure | describe.rs, show_*.rs | accept | Metadata (comments, synonyms) are intentionally surfaced to the user who defined them. No cross-user boundary exists in DuckDB single-user model. |
| T-44-02 | Tampering | format_json_array | accept | Synonyms are stored as Vec<String> from DDL parse; format_json_array quotes them. No SQL injection risk since output flows to VTab result columns, not to SQL execution. |
</threat_model>

<verification>
1. `cargo test` -- all Rust unit tests pass (including existing describe.rs tests)
2. `just build && just test-sql` -- all sqllogictest files pass, including:
   - Updated phase34_1_show_commands.test (8-column DIMS/METRICS/FACTS)
   - Updated phase34_1_1_show_filtering.test (8-column queries)
   - New phase44_show_metadata.test (metadata column values)
   - New phase44_describe_metadata.test (metadata property rows)
   - Existing phase41_describe.test (unchanged, still passes)
   - Existing phase34_1_show_dims_for_metric.test (unchanged 4-column FOR METRIC)
3. `just test-all` -- full quality gate passes
</verification>

<success_criteria>
- SHOW SEMANTIC VIEWS returns 6 columns (created_on, name, kind, database_name, schema_name, comment)
- SHOW SEMANTIC DIMENSIONS/METRICS/FACTS returns 8 columns (+ synonyms, comment)
- DESCRIBE SEMANTIC VIEW includes COMMENT, SYNONYMS, ACCESS_MODIFIER property rows for annotated objects
- All 20+ existing sqllogictest files pass with updated column counts
- Two new integration test files validate metadata column content
</success_criteria>

<output>
After completion, create `.planning/phases/44-show-describe-metadata-surface-enhancements/44-01-SUMMARY.md`
</output>
