Repository: dbt-labs/dbt-core

Issue:
[CT-3067] [Bug] Docs blocks don't work in model versions
### Is this a new bug in dbt-core?

- [X] I believe this is a new bug in dbt-core
- [X] I have searched the existing issues, and I could not find an existing issue for this bug

### Current Behavior

Currently, `.yml` with model definitions do not support using doc blocks inside the fields.

I believe this could be similar to #2913

Commenting or removing the doc block removes the error.


### Expected Behavior

I would expect the doc to be loaded as a string.

### Steps To Reproduce

with this model configuration:

```
version: 2

models:
  - name: working_model
        columns:
          - name: column_id
            description: '{{ doc("column_id_doc") }}'
  - name: error_model
    description: my description
    latest_version: 1
    versions:
      - v: 1
        config:
          alias: my_alias
        columns:
          - name: column_id
            description: '{{ doc("column_id_doc") }}'
      - v: 2
        columns:
          - name: other_id
```

DBT cloud Raises an error when trying to run the tests for the model.

```
Compilation Error
  Could not render {{ doc("column_id_doc") }}: 'doc' is undefined
```

Also, running `dbt docs generate` creates the right documentation for `working_model` and an empty string for the column `column_id` in the model `error_model`

### Relevant log output

_No response_

### Environment

```markdown
dbt cloud
```


### Which database adapter are you using with dbt?

snowflake

### Additional Context

_No response_


Discussion:
Thanks @Gonzalo933! I was able to reproduce using the example you've provided, and I agree that the intended behavior is to support docs blocks for column-level descriptions at all levels.

Basically, while docs blocks are supported in the `description` field specified for columns at the top level, it isn't supported when specified for `columns` on a specific version:
```yaml
models:
  - name: versioned_model
    description: '{{ doc("any_doc_block") }}'  # this works
    columns:
      - name: id
        description: '{{ doc("any_doc_block") }}'  # this works
    versions:
      - v: 1
        columns:
          - name: id
            description: '{{ doc("any_doc_block") }}'  # this does NOT work
```
Very similar to:
- #8509
Next step: @aranke to check if fix for #8509 fixes this issue as well.
From estimation:
- Not exactly the same as #8509, but very similar
- Compare to fix in #8709

Resolving patch:
diff --git a/core/dbt/parser/manifest.py b/core/dbt/parser/manifest.py
--- a/core/dbt/parser/manifest.py
+++ b/core/dbt/parser/manifest.py
@@ -1117,10 +1117,12 @@ def update_semantic_model(self, semantic_model) -> None:
                 database=refd_node.database,
             )
 
-    # nodes: node and column descriptions
+    # nodes: node and column descriptions, version columns descriptions
     # sources: source and table descriptions, column descriptions
     # macros: macro argument descriptions
     # exposures: exposure descriptions
+    # metrics: metric descriptions
+    # semantic_models: semantic model descriptions
     def process_docs(self, config: RuntimeConfig):
         for node in self.manifest.nodes.values():
             if node.created_at < self.started_at:
diff --git a/core/dbt/parser/schema_renderer.py b/core/dbt/parser/schema_renderer.py
--- a/core/dbt/parser/schema_renderer.py
+++ b/core/dbt/parser/schema_renderer.py
@@ -34,12 +34,18 @@ def _is_norender_key(self, keypath: Keypath) -> bool:
         Return True if it's tests or description - those aren't rendered now
         because they're rendered later in parse_generic_tests or process_docs.
         """
+        # top level descriptions and tests
         if len(keypath) >= 1 and keypath[0] in ("tests", "description"):
             return True
 
+        # columns descriptions and tests
         if len(keypath) == 2 and keypath[1] in ("tests", "description"):
             return True
 
+        # versions
+        if len(keypath) == 5 and keypath[4] == "description":
+            return True
+
         if (
             len(keypath) >= 3
             and keypath[0] in ("columns", "dimensions", "measures", "entities")


Test patch:
diff --git a/tests/functional/docs/test_model_version_docs_blocks.py b/tests/functional/docs/test_model_version_docs_blocks.py
new file mode 100644
--- /dev/null
+++ b/tests/functional/docs/test_model_version_docs_blocks.py
@@ -0,0 +1,74 @@
+import pytest
+
+from dbt.tests.util import run_dbt
+
+model_1 = """
+select 1 as id, 'joe' as first_name
+"""
+
+model_versioned = """
+select 1 as id, 'joe' as first_name
+"""
+
+docs_md = """
+{% docs model_description %}
+unversioned model
+{% enddocs %}
+
+{% docs column_id_doc %}
+column id for some thing
+{% enddocs %}
+
+{% docs versioned_model_description %}
+versioned model
+{% enddocs %}
+
+"""
+
+schema_yml = """
+models:
+  - name: model_1
+    description: '{{ doc("model_description") }}'
+    columns:
+        - name: id
+          description: '{{ doc("column_id_doc") }}'
+
+  - name: model_versioned
+    description: '{{ doc("versioned_model_description") }}'
+    latest_version: 1
+    versions:
+      - v: 1
+        config:
+          alias: my_alias
+        columns:
+          - name: id
+            description: '{{ doc("column_id_doc") }}'
+          - name: first_name
+            description: 'plain text'
+      - v: 2
+        columns:
+          - name: other_id
+"""
+
+
+class TestVersionedModelDocsBlock:
+    @pytest.fixture(scope="class")
+    def models(self):
+        return {
+            "model_1.sql": model_1,
+            "model_versioned.sql": model_versioned,
+            "schema.yml": schema_yml,
+            "docs.md": docs_md,
+        }
+
+    def test_versioned_doc_ref(self, project):
+        manifest = run_dbt(["parse"])
+        model_1 = manifest.nodes["model.test.model_1"]
+        model_v1 = manifest.nodes["model.test.model_versioned.v1"]
+
+        assert model_1.description == "unversioned model"
+        assert model_v1.description == "versioned model"
+
+        assert model_1.columns["id"].description == "column id for some thing"
+        assert model_v1.columns["id"].description == "column id for some thing"
+        assert model_v1.columns["first_name"].description == "plain text"