jerryshao commented on code in PR #12627:
URL: https://github.com/apache/gravitino/pull/12627#discussion_r4236207243


##########
docs/open-api/semantic-models.yaml:
##########
@@ -0,0 +1,1588 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+
+paths:
+
+  /metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+
+    get:
+      tags:
+        - semantic-model
+      summary: List Semantic Models
+      description: >-
+        Lists the Semantic Models in a schema. Semantic Models are supported 
only for relational
+        catalogs. Each returned identifier uses the full 
metalake.catalog.schema.name namespace.
+      operationId: listSemanticModels
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelListResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"

Review Comment:
   [Important] All seven operations document `405` for a non-relational 
catalog, but the server returns `501 Not Implemented`.
   
   `SemanticModelExceptionHandler` routes `UnsupportedOperationException` to 
`Utils.unsupportedOperation` (`ExceptionHandlers.java:1036-1037`), which builds 
`Response.status(Response.Status.NOT_IMPLEMENTED)` 
(`server-common/src/main/java/org/apache/gravitino/server/web/Utils.java:213-218`).
 `TestSemanticModelOperations.java:413-425` throws `new 
UnsupportedOperationException("catalog is not relational")` and asserts 
`Response.Status.NOT_IMPLEMENTED` with `UNSUPPORTED_OPERATION_CODE`. The 
sibling spec documents the identical situation as 501: 
`docs/open-api/statistics.yaml:55` - "Not Implemented - Statistics are not 
supported for the specified object". This file is the only one under 
`docs/open-api/` that uses `405` at all.
   
   Please change `"405"` to `"501"` at lines 45, 77, 137, 172, 205, 240 and 
284, and reword the shared response at line 1212-1213 from `Method Not Allowed 
- ...` to `Not Implemented - ...` (the component name is fine as is; only the 
status and the description are wrong). Worth fixing rather than leaving: 405 is 
also what a servlet container returns for a wrong HTTP method, so a client that 
branches on it will mis-handle a non-relational catalog as a routing bug.
   
   Verified by: reading ExceptionHandlers.java:1024-1048, Utils.java:202-218, 
TestSemanticModelOperations.java:413-425, and comparing with 
statistics.yaml:40-62 on this branch.



##########
docs/open-api/semantic-models.yaml:
##########
@@ -0,0 +1,1588 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+
+paths:
+
+  /metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+
+    get:
+      tags:
+        - semantic-model
+      summary: List Semantic Models
+      description: >-
+        Lists the Semantic Models in a schema. Semantic Models are supported 
only for relational
+        catalogs. Each returned identifier uses the full 
metalake.catalog.schema.name namespace.
+      operationId: listSemanticModels
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelListResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+    post:
+      tags:
+        - semantic-model
+      summary: Create a Semantic Model
+      description: >-
+        Creates a schema-scoped Semantic Model in a relational catalog. The 
complete definition is
+        validated before the model is stored, including source identifier 
shape. Source existence,
+        source columns, and source authorization checks are not yet 
implemented.
+      operationId: createSemanticModel
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SemanticModelCreateRequest"
+            examples:
+              SemanticModelCreateRequest:
+                $ref: "#/components/examples/SemanticModelCreateRequest"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlreadyExistsResponse"
+        "502":
+          $ref: "#/components/responses/SemanticModelConnectionFailedResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+  
/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models/ossie:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+
+    post:
+      tags:
+        - semantic-model
+      summary: Import an Apache Ossie Semantic Model
+      description: >-
+        Imports one standalone Apache Ossie document and creates the 
represented Semantic Model.
+        The request body is the raw JSON or YAML document, not a JSON-encoded 
string. Content-Type
+        selects the parser, and parsing does not fall back to another format.
+      operationId: importOssieDocument
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          application/yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          application/x-yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          text/yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlreadyExistsResponse"
+        "415":
+          description: >-
+            Unsupported Media Type - Content-Type must be application/json, 
application/yaml,
+            application/x-yaml, or text/yaml

Review Comment:
   [Question] This text says Content-Type must be one of the four listed media 
types, which matches `@Consumes({APPLICATION_JSON, application/yaml, 
application/x-yaml, text/yaml})` on `importOssieDocument`. But that method's 
own Javadoc states the opposite for the absent case: "The `Content-Type` header 
selects the document format; an absent header defaults to YAML" 
(`server/src/main/java/org/apache/gravitino/server/web/rest/SemanticModelOperations.java:171`).
 Under JAX-RS a request with no Content-Type is matched as 
`application/octet-stream`, which none of the four `@Consumes` values accepts, 
so I would expect 415 rather than a YAML default - and no test settles it 
(`TestSemanticModelOperations.java:775-781` only covers `text/plain` -> 415).
   
   Which is the intended contract? If 415 is correct, the Javadoc is stale; if 
the YAML default is correct, this 415 description should say the header is 
optional. Either way one sentence here would stop clients that omit the header 
from guessing.
   
   Verified by: reading SemanticModelOperations.java:169-186 (@Consumes and 
Javadoc) and the import tests in TestSemanticModelOperations.java:761-796; no 
test exercises a missing Content-Type.



##########
docs/open-api/semantic-models.yaml:
##########
@@ -0,0 +1,1588 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+
+paths:
+
+  /metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+
+    get:
+      tags:
+        - semantic-model
+      summary: List Semantic Models
+      description: >-
+        Lists the Semantic Models in a schema. Semantic Models are supported 
only for relational
+        catalogs. Each returned identifier uses the full 
metalake.catalog.schema.name namespace.
+      operationId: listSemanticModels
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelListResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+    post:
+      tags:
+        - semantic-model
+      summary: Create a Semantic Model
+      description: >-
+        Creates a schema-scoped Semantic Model in a relational catalog. The 
complete definition is
+        validated before the model is stored, including source identifier 
shape. Source existence,
+        source columns, and source authorization checks are not yet 
implemented.
+      operationId: createSemanticModel
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SemanticModelCreateRequest"
+            examples:
+              SemanticModelCreateRequest:
+                $ref: "#/components/examples/SemanticModelCreateRequest"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlreadyExistsResponse"
+        "502":
+          $ref: "#/components/responses/SemanticModelConnectionFailedResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+  
/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models/ossie:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+
+    post:
+      tags:
+        - semantic-model
+      summary: Import an Apache Ossie Semantic Model
+      description: >-
+        Imports one standalone Apache Ossie document and creates the 
represented Semantic Model.
+        The request body is the raw JSON or YAML document, not a JSON-encoded 
string. Content-Type
+        selects the parser, and parsing does not fall back to another format.
+      operationId: importOssieDocument
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          application/yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          application/x-yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          text/yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlreadyExistsResponse"
+        "415":
+          description: >-
+            Unsupported Media Type - Content-Type must be application/json, 
application/yaml,
+            application/x-yaml, or text/yaml
+        "502":
+          $ref: "#/components/responses/SemanticModelConnectionFailedResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+  
/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models/{semanticModel}:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+      - $ref: "./openapi.yaml#/components/parameters/semanticModel"
+
+    get:
+      tags:
+        - semantic-model
+      summary: Load a Semantic Model
+      description: Returns the specified Semantic Model with its nested 
definition and audit data.
+      operationId: loadSemanticModel
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+    put:
+      tags:
+        - semantic-model
+      summary: Alter a Semantic Model
+      description: >-
+        Applies the ordered updates atomically. The server validates and 
converts the complete
+        update batch before dispatch; if any update or the resulting model is 
invalid, none of the
+        updates is applied. Only replaceDefinition revalidates the complete 
definition. Source
+        existence, source columns, and source authorization checks are not yet 
implemented.
+      operationId: alterSemanticModel
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SemanticModelUpdatesRequest"
+            examples:
+              SemanticModelUpdatesRequest:
+                $ref: "#/components/examples/SemanticModelUpdatesRequest"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlterConflictResponse"
+        "502":
+          $ref: "#/components/responses/SemanticModelConnectionFailedResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+    delete:
+      tags:
+        - semantic-model
+      summary: Drop a Semantic Model
+      description: >-
+        Drops the specified Semantic Model. A missing schema or Semantic Model 
is reported as a
+        successful response with dropped set to false.
+      operationId: dropSemanticModel
+      responses:
+        "200":
+          $ref: "./openapi.yaml#/components/responses/DropResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          description: Not Found - The target metalake or catalog does not 
exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "./openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NoSuchMetalakeException:
+                  $ref: 
"./metalakes.yaml#/components/examples/NoSuchMetalakeException"
+                NoSuchCatalogException:
+                  $ref: 
"./catalogs.yaml#/components/examples/NoSuchCatalogException"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelOptimisticLockResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+  
/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models/{semanticModel}/ossie:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+      - $ref: "./openapi.yaml#/components/parameters/semanticModel"
+
+    get:
+      tags:
+        - semantic-model
+      summary: Export a Semantic Model as an Apache Ossie document
+      description: >-
+        Exports the specified Semantic Model as a standalone Apache Ossie YAML 
or JSON document.
+        The response is downloadable document content rather than the native 
Gravitino response
+        envelope. The format query parameter selects the representation 
independently of the
+        Accept header, and its value is case-insensitive.
+      operationId: exportOssieDocument
+      parameters:
+        - name: format
+          in: query
+          description: The serialized document format
+          required: false
+          schema:
+            type: string
+            enum:
+              - yaml
+              - json
+            default: yaml
+      responses:
+        "200":
+          $ref: "#/components/responses/OssieSemanticModelDocumentResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+components:
+
+  schemas:
+    AIContext:
+      description: Additional context for AI tools, encoded as exactly one 
string or object value
+      oneOf:
+        - type: string
+        - $ref: "#/components/schemas/AIContextObject"
+
+    AIContextObject:
+      type: object
+      description: >-
+        Structured context for AI tools. Unknown properties may contain any 
JSON value and are
+        retained losslessly in input order.
+      properties:
+        instructions:
+          type: string
+          description: Instructions for AI tools on how to use the entity
+        synonyms:
+          type: array
+          description: >-
+            Alternative names and terms. Omitting the property differs from 
supplying an empty
+            array.
+          items:
+            type: string
+        examples:
+          type: array
+          description: >-
+            Sample questions or use cases. Omitting the property differs from 
supplying an empty
+            array.
+          items:
+            type: string
+      additionalProperties: true
+
+    SemanticModelSource:
+      type: object
+      description: >-
+        A governed Table or logical View expressed as catalog.schema.name. The 
endpoint metalake is
+        inherited and therefore is not included in this identifier.
+      required:
+        - namespace
+        - name
+      properties:
+        namespace:
+          type: array
+          minItems: 2
+          maxItems: 2
+          description: Exactly the catalog and schema containing the source, 
in that order
+          items:
+            type: string
+            minLength: 1
+        name:
+          type: string
+          minLength: 1
+          description: The source Table or logical View name
+      additionalProperties: false
+
+    Dataset:
+      type: object
+      description: A logical dataset backed by a governed Gravitino Table or 
logical View
+      required:
+        - name
+        - source
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The dataset name, unique within the Semantic Model
+        source:
+          $ref: "#/components/schemas/SemanticModelSource"
+        primaryKey:
+          type: array
+          description: >-
+            Source columns that form the primary key. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: string
+            minLength: 1
+        uniqueKeys:
+          type: array
+          description: >-
+            Source column sets that form unique keys. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: array
+            minItems: 1
+            items:
+              type: string
+              minLength: 1
+        description:
+          type: string
+          description: The human-readable dataset description
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        fields:
+          type: array
+          description: >-
+            Ordered fields in the dataset. The property may be omitted; an 
explicitly supplied
+            empty array is retained as empty.
+          items:
+            $ref: "#/components/schemas/Field"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    OssieDataset:
+      type: object
+      description: >-
+        An Apache Ossie dataset backed by a governed Gravitino Table or 
logical View
+      required:
+        - name
+        - source
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The dataset name, unique within the Semantic Model
+        source:
+          type: string
+          minLength: 1
+          description: >-
+            A catalog.schema.name source identifier. Segments containing dots 
or backticks use
+            backtick quoting, and a backtick inside a quoted segment is 
doubled. Query sources are
+            not supported.
+        primary_key:
+          type: array
+          description: >-
+            Source columns that form the primary key. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: string
+            minLength: 1
+        unique_keys:
+          type: array
+          description: >-
+            Source column sets that form unique keys. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: array
+            minItems: 1
+            items:
+              type: string
+              minLength: 1
+        description:
+          type: string
+          description: The human-readable dataset description
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        fields:
+          type: array
+          description: >-
+            Ordered fields in the dataset. The property may be omitted; an 
explicitly supplied
+            empty array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieField"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    Field:
+      type: object
+      description: A row-level semantic attribute in a dataset
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The field name, unique within its dataset
+        expression:
+          $ref: "#/components/schemas/Expression"
+        dimension:
+          $ref: "#/components/schemas/Dimension"
+        label:
+          type: string
+          description: The display label used to categorize the field
+        description:
+          type: string
+          description: The human-readable field description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    Relationship:
+      type: object
+      description: A relationship between two datasets in the same Semantic 
Model
+      required:
+        - name
+        - from
+        - to
+        - fromColumns
+        - toColumns
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The relationship name, unique within the Semantic Model
+        from:
+          type: string
+          minLength: 1
+          description: The source dataset name
+        to:
+          type: string
+          minLength: 1
+          description: The target dataset name
+        fromColumns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty source columns. The array must have the same number of 
entries as toColumns.
+          items:
+            type: string
+            minLength: 1
+        toColumns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty target columns. The array must have the same number of 
entries as
+            fromColumns.
+          items:
+            type: string
+            minLength: 1
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    Metric:
+      type: object
+      description: A model-scoped quantitative measure
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The metric name, unique within the Semantic Model
+        expression:
+          $ref: "#/components/schemas/Expression"
+        description:
+          type: string
+          description: The human-readable metric description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    Expression:
+      type: object
+      description: An expression with one or more ordered dialect-specific 
representations
+      required:
+        - dialects
+      properties:
+        dialects:
+          type: array
+          minItems: 1
+          description: Each dialect identifier may occur at most once
+          items:
+            $ref: "#/components/schemas/DialectExpression"
+      additionalProperties: false
+
+    DialectExpression:
+      type: object
+      description: An expression written in a specific dialect
+      required:
+        - dialect
+        - expression
+      properties:
+        dialect:
+          type: string
+          minLength: 1
+          description: >-
+            An open dialect identifier. ANSI_SQL, SNOWFLAKE, MDX, TABLEAU, 
DATABRICKS, MAQL, and
+            BIGQUERY are well-known Apache Ossie values; other non-empty 
identifiers are accepted
+            and preserved without conversion or fallback.
+        expression:
+          type: string
+          minLength: 1
+          description: The non-empty dialect-specific expression text
+      additionalProperties: false
+
+    Dimension:
+      type: object
+      description: >-
+        Dimension metadata for a field. An empty object is valid and remains 
distinct from an
+        omitted dimension.
+      properties:
+        isTime:
+          type: boolean
+          nullable: true
+          description: Whether consumers should treat the field as a time 
dimension
+      additionalProperties: false
+
+    CustomExtension:
+      type: object
+      description: Vendor-specific attributes retained for Semantic Model 
interchange
+      required:
+        - vendorName
+        - data
+      properties:
+        vendorName:
+          type: string
+          description: The extension vendor name
+        data:
+          type: string
+          description: Opaque vendor-specific data retained as a string
+      additionalProperties: false
+
+    OssieField:
+      type: object
+      description: A row-level semantic attribute in a dataset
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The field name, unique within its dataset
+        expression:
+          $ref: "#/components/schemas/Expression"
+        dimension:
+          $ref: "#/components/schemas/OssieDimension"
+        label:
+          type: string
+          description: The display label used to categorize the field
+        description:
+          type: string
+          description: The human-readable field description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    OssieRelationship:
+      type: object
+      description: A relationship between two datasets in the same Semantic 
Model
+      required:
+        - name
+        - from
+        - to
+        - from_columns
+        - to_columns
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The relationship name, unique within the Semantic Model
+        from:
+          type: string
+          minLength: 1
+          description: The source dataset name
+        to:
+          type: string
+          minLength: 1
+          description: The target dataset name
+        from_columns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty source columns. The array must have the same number of 
entries as to_columns.
+          items:
+            type: string
+            minLength: 1
+        to_columns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty target columns. The array must have the same number of 
entries as
+            from_columns.
+          items:
+            type: string
+            minLength: 1
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    OssieMetric:
+      type: object
+      description: A model-scoped quantitative measure
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The metric name, unique within the Semantic Model
+        expression:
+          $ref: "#/components/schemas/Expression"
+        description:
+          type: string
+          description: The human-readable metric description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    OssieDimension:
+      type: object
+      description: >-
+        Dimension metadata for a field. An empty object is valid and remains 
distinct from an
+        omitted dimension.
+      properties:
+        is_time:
+          type: boolean
+          description: Whether consumers should treat the field as a time 
dimension
+      additionalProperties: false
+
+    OssieCustomExtension:
+      type: object
+      description: Vendor-specific attributes retained for Semantic Model 
interchange
+      required:
+        - vendor_name
+        - data
+      properties:
+        vendor_name:
+          type: string
+          description: The extension vendor name
+        data:
+          type: string
+          description: Opaque vendor-specific data retained as a string
+      additionalProperties: false
+
+    SemanticModelDataType:
+      type: string
+      description: The exact wire value for a logical field or metric data type
+      enum:
+        - String
+        - Integer
+        - Decimal
+        - Float
+        - Boolean
+        - Date
+        - Time
+        - DateTime
+        - DateTimeTz
+        - Opaque
+
+    SemanticModelDefinition:
+      type: object
+      description: The complete replaceable semantic definition, without 
entity metadata
+      required:
+        - datasets
+      properties:
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        datasets:
+          type: array
+          minItems: 1
+          description: The non-empty ordered datasets in the Semantic Model
+          items:
+            $ref: "#/components/schemas/Dataset"
+        relationships:
+          type: array
+          description: >-
+            Ordered relationships. The property may be omitted; an explicitly 
supplied empty array
+            is retained as empty.
+          items:
+            $ref: "#/components/schemas/Relationship"
+        metrics:
+          type: array
+          description: >-
+            Ordered metrics. The property may be omitted; an explicitly 
supplied empty array is
+            retained as empty.
+          items:
+            $ref: "#/components/schemas/Metric"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The root vendorName 
GRAVITINO_PROPERTIES is reserved and
+            cannot be supplied in a native definition. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    OssieSemanticModelDocument:
+      type: object
+      description: >-
+        A standalone Apache Ossie document. Unlike the native Gravitino 
response, its semantic
+        definition is at the document root and it contains no response 
envelope, audit data, or
+        direct properties object.
+      required:
+        - version
+        - name
+        - datasets
+      properties:
+        version:
+          type: string
+          minLength: 1
+          description: >-
+            The non-blank Apache Ossie document version, stored in the 
ossie-version model property
+            on import. Export uses that property or defaults to 0.2.0.dev0 
when it is absent. The
+            version is preserved without restricting it to a fixed allowlist.
+        name:
+          type: string
+          minLength: 1
+          description: The Semantic Model name
+        description:
+          type: string
+          description: The human-readable Semantic Model description
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        datasets:
+          type: array
+          minItems: 1
+          description: The non-empty ordered datasets in the Semantic Model
+          items:
+            $ref: "#/components/schemas/OssieDataset"
+        relationships:
+          type: array
+          description: >-
+            Ordered relationships. The property may be omitted; an explicitly 
supplied empty array
+            is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieRelationship"
+        metrics:
+          type: array
+          description: >-
+            Ordered metrics. The property may be omitted; an explicitly 
supplied empty array is
+            retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieMetric"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. At most one root GRAVITINO_PROPERTIES 
extension carries
+            Gravitino-specific properties as a JSON object encoded in a 
string, with string values
+            only. Import consumes this extension into model properties; an 
ossie-version value in
+            its data must match the document version. Export omits 
ossie-version from the extension
+            and writes it as version instead. Other extensions and nested 
GRAVITINO_PROPERTIES
+            extensions remain opaque. The property may be omitted; an 
explicitly supplied empty
+            array is normalized to an absent customExtensions in the native 
definition on import.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    SemanticModel:
+      type: object
+      description: A schema-scoped analytical Semantic Model with a nested 
semantic definition
+      required:
+        - name
+        - definition
+        - properties
+        - audit
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The Semantic Model name
+        comment:
+          type: string
+          nullable: true
+          description: The comment, or null when no comment is set

Review Comment:
   [Nit] `SemanticModel.comment` is documented as `nullable: true` / "or null 
when no comment is set", but the server never emits `comment: null`: 
`SemanticModelDTO` is annotated `@JsonInclude(JsonInclude.Include.NON_NULL)` 
(`common/src/main/java/org/apache/gravitino/dto/semantic/SemanticModelDTO.java:38`)
 and the server's mapper independently applies 
`setSerializationInclusion(JsonInclude.Include.NON_NULL)` 
(`server-common/src/main/java/org/apache/gravitino/server/web/ObjectMapperProvider.java:112`),
 so an unset comment is absent from the payload.
   
   Suggest "The comment; the property is omitted when no comment is set" and 
dropping `nullable: true` on this one field. 
(`SemanticModelCreateRequest.comment` and 
`UpdateSemanticModelCommentRequest.newComment` are request fields and are 
correct as written - a null there really is accepted.) Raising it only because 
the rest of the file is careful about the omitted-vs-explicit distinction, e.g. 
the `Dimension` description at line 608.
   
   Verified by: reading SemanticModelDTO.java:36-72 and 
ObjectMapperProvider.java:100-115 on this branch.



##########
docs/open-api/semantic-models.yaml:
##########
@@ -0,0 +1,1588 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+
+paths:
+
+  /metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+
+    get:
+      tags:
+        - semantic-model
+      summary: List Semantic Models
+      description: >-
+        Lists the Semantic Models in a schema. Semantic Models are supported 
only for relational
+        catalogs. Each returned identifier uses the full 
metalake.catalog.schema.name namespace.
+      operationId: listSemanticModels
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelListResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+    post:
+      tags:
+        - semantic-model
+      summary: Create a Semantic Model
+      description: >-
+        Creates a schema-scoped Semantic Model in a relational catalog. The 
complete definition is
+        validated before the model is stored, including source identifier 
shape. Source existence,
+        source columns, and source authorization checks are not yet 
implemented.
+      operationId: createSemanticModel
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SemanticModelCreateRequest"
+            examples:
+              SemanticModelCreateRequest:
+                $ref: "#/components/examples/SemanticModelCreateRequest"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlreadyExistsResponse"
+        "502":
+          $ref: "#/components/responses/SemanticModelConnectionFailedResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+  
/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models/ossie:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+
+    post:
+      tags:
+        - semantic-model
+      summary: Import an Apache Ossie Semantic Model
+      description: >-
+        Imports one standalone Apache Ossie document and creates the 
represented Semantic Model.
+        The request body is the raw JSON or YAML document, not a JSON-encoded 
string. Content-Type
+        selects the parser, and parsing does not fall back to another format.
+      operationId: importOssieDocument
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          application/yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          application/x-yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+          text/yaml:
+            schema:
+              $ref: "#/components/schemas/OssieSemanticModelDocument"
+            examples:
+              OssieSemanticModelDocument:
+                $ref: "#/components/examples/OssieSemanticModelDocument"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelParentNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlreadyExistsResponse"
+        "415":
+          description: >-
+            Unsupported Media Type - Content-Type must be application/json, 
application/yaml,
+            application/x-yaml, or text/yaml
+        "502":
+          $ref: "#/components/responses/SemanticModelConnectionFailedResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+  
/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models/{semanticModel}:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+      - $ref: "./openapi.yaml#/components/parameters/semanticModel"
+
+    get:
+      tags:
+        - semantic-model
+      summary: Load a Semantic Model
+      description: Returns the specified Semantic Model with its nested 
definition and audit data.
+      operationId: loadSemanticModel
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+    put:
+      tags:
+        - semantic-model
+      summary: Alter a Semantic Model
+      description: >-
+        Applies the ordered updates atomically. The server validates and 
converts the complete
+        update batch before dispatch; if any update or the resulting model is 
invalid, none of the
+        updates is applied. Only replaceDefinition revalidates the complete 
definition. Source
+        existence, source columns, and source authorization checks are not yet 
implemented.
+      operationId: alterSemanticModel
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SemanticModelUpdatesRequest"
+            examples:
+              SemanticModelUpdatesRequest:
+                $ref: "#/components/examples/SemanticModelUpdatesRequest"
+      responses:
+        "200":
+          $ref: "#/components/responses/SemanticModelResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelAlterConflictResponse"
+        "502":
+          $ref: "#/components/responses/SemanticModelConnectionFailedResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+    delete:
+      tags:
+        - semantic-model
+      summary: Drop a Semantic Model
+      description: >-
+        Drops the specified Semantic Model. A missing schema or Semantic Model 
is reported as a
+        successful response with dropped set to false.
+      operationId: dropSemanticModel
+      responses:
+        "200":
+          $ref: "./openapi.yaml#/components/responses/DropResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          description: Not Found - The target metalake or catalog does not 
exist
+          content:
+            application/vnd.gravitino.v1+json:
+              schema:
+                $ref: "./openapi.yaml#/components/schemas/ErrorModel"
+              examples:
+                NoSuchMetalakeException:
+                  $ref: 
"./metalakes.yaml#/components/examples/NoSuchMetalakeException"
+                NoSuchCatalogException:
+                  $ref: 
"./catalogs.yaml#/components/examples/NoSuchCatalogException"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "409":
+          $ref: "#/components/responses/SemanticModelOptimisticLockResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+  
/metalakes/{metalake}/catalogs/{catalog}/schemas/{schema}/semantic-models/{semanticModel}/ossie:
+    parameters:
+      - $ref: "./openapi.yaml#/components/parameters/metalake"
+      - $ref: "./openapi.yaml#/components/parameters/catalog"
+      - $ref: "./openapi.yaml#/components/parameters/schema"
+      - $ref: "./openapi.yaml#/components/parameters/semanticModel"
+
+    get:
+      tags:
+        - semantic-model
+      summary: Export a Semantic Model as an Apache Ossie document
+      description: >-
+        Exports the specified Semantic Model as a standalone Apache Ossie YAML 
or JSON document.
+        The response is downloadable document content rather than the native 
Gravitino response
+        envelope. The format query parameter selects the representation 
independently of the
+        Accept header, and its value is case-insensitive.
+      operationId: exportOssieDocument
+      parameters:
+        - name: format
+          in: query
+          description: The serialized document format
+          required: false
+          schema:
+            type: string
+            enum:
+              - yaml
+              - json
+            default: yaml
+      responses:
+        "200":
+          $ref: "#/components/responses/OssieSemanticModelDocumentResponse"
+        "400":
+          $ref: "#/components/responses/SemanticModelBadRequestResponse"
+        "403":
+          $ref: "#/components/responses/SemanticModelForbiddenResponse"
+        "404":
+          $ref: "#/components/responses/SemanticModelNotFoundResponse"
+        "405":
+          $ref: 
"#/components/responses/SemanticModelUnsupportedCatalogResponse"
+        "5xx":
+          $ref: "./openapi.yaml#/components/responses/ServerErrorResponse"
+
+components:
+
+  schemas:
+    AIContext:
+      description: Additional context for AI tools, encoded as exactly one 
string or object value
+      oneOf:
+        - type: string
+        - $ref: "#/components/schemas/AIContextObject"
+
+    AIContextObject:
+      type: object
+      description: >-
+        Structured context for AI tools. Unknown properties may contain any 
JSON value and are
+        retained losslessly in input order.
+      properties:
+        instructions:
+          type: string
+          description: Instructions for AI tools on how to use the entity
+        synonyms:
+          type: array
+          description: >-
+            Alternative names and terms. Omitting the property differs from 
supplying an empty
+            array.
+          items:
+            type: string
+        examples:
+          type: array
+          description: >-
+            Sample questions or use cases. Omitting the property differs from 
supplying an empty
+            array.
+          items:
+            type: string
+      additionalProperties: true
+
+    SemanticModelSource:
+      type: object
+      description: >-
+        A governed Table or logical View expressed as catalog.schema.name. The 
endpoint metalake is
+        inherited and therefore is not included in this identifier.
+      required:
+        - namespace
+        - name
+      properties:
+        namespace:
+          type: array
+          minItems: 2
+          maxItems: 2
+          description: Exactly the catalog and schema containing the source, 
in that order
+          items:
+            type: string
+            minLength: 1
+        name:
+          type: string
+          minLength: 1
+          description: The source Table or logical View name
+      additionalProperties: false
+
+    Dataset:
+      type: object
+      description: A logical dataset backed by a governed Gravitino Table or 
logical View
+      required:
+        - name
+        - source
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The dataset name, unique within the Semantic Model
+        source:
+          $ref: "#/components/schemas/SemanticModelSource"
+        primaryKey:
+          type: array
+          description: >-
+            Source columns that form the primary key. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: string
+            minLength: 1
+        uniqueKeys:
+          type: array
+          description: >-
+            Source column sets that form unique keys. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: array
+            minItems: 1
+            items:
+              type: string
+              minLength: 1
+        description:
+          type: string
+          description: The human-readable dataset description
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        fields:
+          type: array
+          description: >-
+            Ordered fields in the dataset. The property may be omitted; an 
explicitly supplied
+            empty array is retained as empty.
+          items:
+            $ref: "#/components/schemas/Field"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    OssieDataset:
+      type: object
+      description: >-
+        An Apache Ossie dataset backed by a governed Gravitino Table or 
logical View
+      required:
+        - name
+        - source
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The dataset name, unique within the Semantic Model
+        source:
+          type: string
+          minLength: 1
+          description: >-
+            A catalog.schema.name source identifier. Segments containing dots 
or backticks use
+            backtick quoting, and a backtick inside a quoted segment is 
doubled. Query sources are
+            not supported.
+        primary_key:
+          type: array
+          description: >-
+            Source columns that form the primary key. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: string
+            minLength: 1
+        unique_keys:
+          type: array
+          description: >-
+            Source column sets that form unique keys. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            type: array
+            minItems: 1
+            items:
+              type: string
+              minLength: 1
+        description:
+          type: string
+          description: The human-readable dataset description
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        fields:
+          type: array
+          description: >-
+            Ordered fields in the dataset. The property may be omitted; an 
explicitly supplied
+            empty array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieField"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    Field:
+      type: object
+      description: A row-level semantic attribute in a dataset
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The field name, unique within its dataset
+        expression:
+          $ref: "#/components/schemas/Expression"
+        dimension:
+          $ref: "#/components/schemas/Dimension"
+        label:
+          type: string
+          description: The display label used to categorize the field
+        description:
+          type: string
+          description: The human-readable field description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    Relationship:
+      type: object
+      description: A relationship between two datasets in the same Semantic 
Model
+      required:
+        - name
+        - from
+        - to
+        - fromColumns
+        - toColumns
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The relationship name, unique within the Semantic Model
+        from:
+          type: string
+          minLength: 1
+          description: The source dataset name
+        to:
+          type: string
+          minLength: 1
+          description: The target dataset name
+        fromColumns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty source columns. The array must have the same number of 
entries as toColumns.
+          items:
+            type: string
+            minLength: 1
+        toColumns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty target columns. The array must have the same number of 
entries as
+            fromColumns.
+          items:
+            type: string
+            minLength: 1
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    Metric:
+      type: object
+      description: A model-scoped quantitative measure
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The metric name, unique within the Semantic Model
+        expression:
+          $ref: "#/components/schemas/Expression"
+        description:
+          type: string
+          description: The human-readable metric description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    Expression:
+      type: object
+      description: An expression with one or more ordered dialect-specific 
representations
+      required:
+        - dialects
+      properties:
+        dialects:
+          type: array
+          minItems: 1
+          description: Each dialect identifier may occur at most once
+          items:
+            $ref: "#/components/schemas/DialectExpression"
+      additionalProperties: false
+
+    DialectExpression:
+      type: object
+      description: An expression written in a specific dialect
+      required:
+        - dialect
+        - expression
+      properties:
+        dialect:
+          type: string
+          minLength: 1
+          description: >-
+            An open dialect identifier. ANSI_SQL, SNOWFLAKE, MDX, TABLEAU, 
DATABRICKS, MAQL, and
+            BIGQUERY are well-known Apache Ossie values; other non-empty 
identifiers are accepted
+            and preserved without conversion or fallback.
+        expression:
+          type: string
+          minLength: 1
+          description: The non-empty dialect-specific expression text
+      additionalProperties: false
+
+    Dimension:
+      type: object
+      description: >-
+        Dimension metadata for a field. An empty object is valid and remains 
distinct from an
+        omitted dimension.
+      properties:
+        isTime:
+          type: boolean
+          nullable: true
+          description: Whether consumers should treat the field as a time 
dimension
+      additionalProperties: false
+
+    CustomExtension:
+      type: object
+      description: Vendor-specific attributes retained for Semantic Model 
interchange
+      required:
+        - vendorName
+        - data
+      properties:
+        vendorName:
+          type: string
+          description: The extension vendor name
+        data:
+          type: string
+          description: Opaque vendor-specific data retained as a string
+      additionalProperties: false
+
+    OssieField:
+      type: object
+      description: A row-level semantic attribute in a dataset
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The field name, unique within its dataset
+        expression:
+          $ref: "#/components/schemas/Expression"
+        dimension:
+          $ref: "#/components/schemas/OssieDimension"
+        label:
+          type: string
+          description: The display label used to categorize the field
+        description:
+          type: string
+          description: The human-readable field description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    OssieRelationship:
+      type: object
+      description: A relationship between two datasets in the same Semantic 
Model
+      required:
+        - name
+        - from
+        - to
+        - from_columns
+        - to_columns
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The relationship name, unique within the Semantic Model
+        from:
+          type: string
+          minLength: 1
+          description: The source dataset name
+        to:
+          type: string
+          minLength: 1
+          description: The target dataset name
+        from_columns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty source columns. The array must have the same number of 
entries as to_columns.
+          items:
+            type: string
+            minLength: 1
+        to_columns:
+          type: array
+          minItems: 1
+          description: >-
+            Non-empty target columns. The array must have the same number of 
entries as
+            from_columns.
+          items:
+            type: string
+            minLength: 1
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    OssieMetric:
+      type: object
+      description: A model-scoped quantitative measure
+      required:
+        - name
+        - expression
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The metric name, unique within the Semantic Model
+        expression:
+          $ref: "#/components/schemas/Expression"
+        description:
+          type: string
+          description: The human-readable metric description
+        datatype:
+          $ref: "#/components/schemas/SemanticModelDataType"
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The property may be omitted; an 
explicitly supplied empty
+            array is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    OssieDimension:
+      type: object
+      description: >-
+        Dimension metadata for a field. An empty object is valid and remains 
distinct from an
+        omitted dimension.
+      properties:
+        is_time:
+          type: boolean
+          description: Whether consumers should treat the field as a time 
dimension
+      additionalProperties: false
+
+    OssieCustomExtension:
+      type: object
+      description: Vendor-specific attributes retained for Semantic Model 
interchange
+      required:
+        - vendor_name
+        - data
+      properties:
+        vendor_name:
+          type: string
+          description: The extension vendor name
+        data:
+          type: string
+          description: Opaque vendor-specific data retained as a string
+      additionalProperties: false
+
+    SemanticModelDataType:
+      type: string
+      description: The exact wire value for a logical field or metric data type
+      enum:
+        - String
+        - Integer
+        - Decimal
+        - Float
+        - Boolean
+        - Date
+        - Time
+        - DateTime
+        - DateTimeTz
+        - Opaque
+
+    SemanticModelDefinition:
+      type: object
+      description: The complete replaceable semantic definition, without 
entity metadata
+      required:
+        - datasets
+      properties:
+        aiContext:
+          $ref: "#/components/schemas/AIContext"
+        datasets:
+          type: array
+          minItems: 1
+          description: The non-empty ordered datasets in the Semantic Model
+          items:
+            $ref: "#/components/schemas/Dataset"
+        relationships:
+          type: array
+          description: >-
+            Ordered relationships. The property may be omitted; an explicitly 
supplied empty array
+            is retained as empty.
+          items:
+            $ref: "#/components/schemas/Relationship"
+        metrics:
+          type: array
+          description: >-
+            Ordered metrics. The property may be omitted; an explicitly 
supplied empty array is
+            retained as empty.
+          items:
+            $ref: "#/components/schemas/Metric"
+        customExtensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. The root vendorName 
GRAVITINO_PROPERTIES is reserved and
+            cannot be supplied in a native definition. The property may be 
omitted; an explicitly
+            supplied empty array is retained as empty.
+          items:
+            $ref: "#/components/schemas/CustomExtension"
+      additionalProperties: false
+
+    OssieSemanticModelDocument:
+      type: object
+      description: >-
+        A standalone Apache Ossie document. Unlike the native Gravitino 
response, its semantic
+        definition is at the document root and it contains no response 
envelope, audit data, or
+        direct properties object.
+      required:
+        - version
+        - name
+        - datasets
+      properties:
+        version:
+          type: string
+          minLength: 1
+          description: >-
+            The non-blank Apache Ossie document version, stored in the 
ossie-version model property
+            on import. Export uses that property or defaults to 0.2.0.dev0 
when it is absent. The
+            version is preserved without restricting it to a fixed allowlist.
+        name:
+          type: string
+          minLength: 1
+          description: The Semantic Model name
+        description:
+          type: string
+          description: The human-readable Semantic Model description
+        ai_context:
+          $ref: "#/components/schemas/AIContext"
+        datasets:
+          type: array
+          minItems: 1
+          description: The non-empty ordered datasets in the Semantic Model
+          items:
+            $ref: "#/components/schemas/OssieDataset"
+        relationships:
+          type: array
+          description: >-
+            Ordered relationships. The property may be omitted; an explicitly 
supplied empty array
+            is retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieRelationship"
+        metrics:
+          type: array
+          description: >-
+            Ordered metrics. The property may be omitted; an explicitly 
supplied empty array is
+            retained as empty.
+          items:
+            $ref: "#/components/schemas/OssieMetric"
+        custom_extensions:
+          type: array
+          description: >-
+            Vendor-specific extensions. At most one root GRAVITINO_PROPERTIES 
extension carries
+            Gravitino-specific properties as a JSON object encoded in a 
string, with string values
+            only. Import consumes this extension into model properties; an 
ossie-version value in
+            its data must match the document version. Export omits 
ossie-version from the extension
+            and writes it as version instead. Other extensions and nested 
GRAVITINO_PROPERTIES
+            extensions remain opaque. The property may be omitted; an 
explicitly supplied empty
+            array is normalized to an absent customExtensions in the native 
definition on import.
+          items:
+            $ref: "#/components/schemas/OssieCustomExtension"
+      additionalProperties: false
+
+    SemanticModel:
+      type: object
+      description: A schema-scoped analytical Semantic Model with a nested 
semantic definition
+      required:
+        - name
+        - definition
+        - properties
+        - audit
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The Semantic Model name
+        comment:
+          type: string
+          nullable: true
+          description: The comment, or null when no comment is set
+        definition:
+          $ref: "#/components/schemas/SemanticModelDefinition"
+        properties:
+          type: object
+          description: Gravitino-specific Semantic Model properties, including 
the Ossie version
+          additionalProperties:
+            type: string
+        audit:
+          $ref: "./openapi.yaml#/components/schemas/Audit"
+      additionalProperties: false
+
+    SemanticModelCreateRequest:
+      type: object
+      description: The request to create a Semantic Model
+      required:
+        - name
+        - definition
+      properties:
+        name:
+          type: string
+          minLength: 1
+          description: The non-blank Semantic Model name
+        comment:
+          type: string
+          nullable: true
+          description: The optional Semantic Model comment
+        definition:
+          $ref: "#/components/schemas/SemanticModelDefinition"
+        properties:
+          type: object
+          nullable: true
+          description: >-
+            Optional Gravitino-specific properties. Omitted or null properties 
use the defaults.
+            The ossie-version property must be non-blank and defaults to 
0.2.0.dev0.
+          additionalProperties:
+            type: string
+      additionalProperties: false
+
+    SemanticModelUpdatesRequest:
+      type: object
+      description: A non-empty ordered update batch applied atomically
+      required:
+        - updates
+      properties:
+        updates:
+          type: array
+          minItems: 1
+          items:
+            $ref: "#/components/schemas/SemanticModelUpdateRequest"
+      additionalProperties: false
+
+    SemanticModelUpdateRequest:
+      description: One polymorphic Semantic Model update
+      oneOf:
+        - $ref: "#/components/schemas/RenameSemanticModelRequest"
+        - $ref: "#/components/schemas/UpdateSemanticModelCommentRequest"
+        - $ref: "#/components/schemas/SetSemanticModelPropertyRequest"
+        - $ref: "#/components/schemas/RemoveSemanticModelPropertyRequest"
+        - $ref: "#/components/schemas/ReplaceSemanticModelDefinitionRequest"
+      discriminator:
+        propertyName: "@type"
+        mapping:
+          rename: "#/components/schemas/RenameSemanticModelRequest"
+          updateComment: 
"#/components/schemas/UpdateSemanticModelCommentRequest"
+          setProperty: "#/components/schemas/SetSemanticModelPropertyRequest"
+          removeProperty: 
"#/components/schemas/RemoveSemanticModelPropertyRequest"
+          replaceDefinition: 
"#/components/schemas/ReplaceSemanticModelDefinitionRequest"
+
+    RenameSemanticModelRequest:
+      type: object
+      description: Renames the Semantic Model
+      required:
+        - "@type"
+        - newName
+      properties:
+        "@type":
+          type: string
+          enum:
+            - rename
+        newName:
+          type: string
+          minLength: 1
+          description: The new non-blank Semantic Model name
+      example: {
+        "@type": "rename",
+        "newName": "sales_model_v2"
+      }
+
+    UpdateSemanticModelCommentRequest:
+      type: object
+      description: >-
+        Replaces the comment. An omitted or null newComment clears the 
comment; an explicit empty
+        string is stored as an empty comment.
+      required:
+        - "@type"
+      properties:
+        "@type":
+          type: string
+          enum:
+            - updateComment
+        newComment:
+          type: string
+          nullable: true
+          description: The new comment, null to clear it, or an empty string 
to retain empty
+      example: {
+        "@type": "updateComment",
+        "newComment": "Updated sales definitions"
+      }
+
+    SetSemanticModelPropertyRequest:
+      type: object
+      description: Sets or replaces one Gravitino-specific property
+      required:
+        - "@type"
+        - property
+        - value
+      properties:
+        "@type":
+          type: string
+          enum:
+            - setProperty
+        property:
+          type: string
+          minLength: 1
+          description: The non-blank property name
+        value:
+          type: string
+          description: The property value; an empty string is valid
+      example: {
+        "@type": "setProperty",
+        "property": "domain",
+        "value": "sales"
+      }
+
+    RemoveSemanticModelPropertyRequest:
+      type: object
+      description: Removes one Gravitino-specific property if it exists
+      required:
+        - "@type"
+        - property
+      properties:
+        "@type":
+          type: string
+          enum:
+            - removeProperty
+        property:
+          type: string
+          minLength: 1
+          description: The non-blank property name
+      example: {
+        "@type": "removeProperty",
+        "property": "legacy"
+      }
+
+    ReplaceSemanticModelDefinitionRequest:
+      type: object
+      description: Replaces and validates the complete nested definition 
atomically
+      required:
+        - "@type"
+        - definition
+      properties:
+        "@type":
+          type: string
+          enum:
+            - replaceDefinition
+        definition:
+          $ref: "#/components/schemas/SemanticModelDefinition"
+      example: {
+        "@type": "replaceDefinition",
+        "definition": {
+          "datasets": [
+            {
+              "name": "orders",
+              "source": {
+                "namespace": ["sales", "mart"],
+                "name": "orders"
+              },
+              "fields": []
+            }
+          ],
+          "relationships": [],
+          "metrics": [],
+          "customExtensions": []
+        }
+      }
+
+  responses:
+    SemanticModelListResponse:
+      description: Returns the Semantic Model identifiers in the schema
+      content:
+        application/vnd.gravitino.v1+json:
+          schema:
+            type: object
+            required:
+              - code
+              - identifiers
+            properties:
+              code:
+                type: integer
+                format: int32
+                description: Status code of the response
+                enum:
+                  - 0
+              identifiers:
+                type: array
+                description: Full Semantic Model identifiers
+                items:
+                  $ref: "./openapi.yaml#/components/schemas/NameIdentifier"
+            additionalProperties: false
+          examples:
+            SemanticModelListResponse:
+              $ref: "#/components/examples/SemanticModelListResponse"
+
+    SemanticModelResponse:
+      description: Returns the Semantic Model object with its nested definition
+      content:
+        application/vnd.gravitino.v1+json:
+          schema:
+            type: object
+            required:
+              - code
+              - semanticModel
+            properties:
+              code:
+                type: integer
+                format: int32
+                description: Status code of the response
+                enum:
+                  - 0
+              semanticModel:
+                $ref: "#/components/schemas/SemanticModel"
+            additionalProperties: false
+          examples:
+            SemanticModelResponse:
+              $ref: "#/components/examples/SemanticModelResponse"
+
+    OssieSemanticModelDocumentResponse:
+      description: Returns a standalone Apache Ossie document in the requested 
format
+      headers:
+        Content-Disposition:
+          description: Attachment filename ending in .ossie.yaml or .ossie.json

Review Comment:
   [Nit] The Content-Disposition description does not mention that the filename 
is sanitized. `ossieContentDisposition` runs 
`semanticModel.replaceAll("[^A-Za-z0-9._-]", "_")` before appending the 
extension 
(`server/src/main/java/org/apache/gravitino/server/web/rest/SemanticModelOperations.java:445-449`),
 so a model named `sales model` or `sales/model` downloads as 
`sales_model.ossie.yaml`. A client cannot derive the filename from the model 
name, which is worth one clause here since the example at line 1145 shows a 
name that happens to need no escaping.
   
   Verified by: reading ossieContentDisposition at 
SemanticModelOperations.java:445-449 on this branch.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to