codeant-ai-for-open-source[bot] commented on code in PR #40399:
URL: https://github.com/apache/superset/pull/40399#discussion_r3467074194


##########
superset/mcp_service/dashboard/tool/generate_dashboard.py:
##########
@@ -276,27 +288,32 @@ def generate_dashboard(  # noqa: C901
         from superset.models.dashboard import Dashboard
 
         with 
event_logger.log_context(action="mcp.generate_dashboard.db_write"):
-            json_metadata = json.dumps(
-                {
-                    "filter_scopes": {},
-                    "expanded_slices": {},
-                    "refresh_frequency": 0,
-                    "timed_refresh_immune_slices": [],
-                    "color_scheme": None,
-                    "label_colors": {},
-                    "shared_label_colors": {},
-                    "color_scheme_domain": [],
-                    "cross_filters_enabled": False,
-                    "native_filter_configuration": [],
-                    "global_chart_configuration": {
-                        "scope": {
-                            "rootPath": ["ROOT_ID"],
-                            "excluded": [],
-                        }
-                    },
-                    "chart_configuration": {},
-                }
-            )
+            # Build the default json_metadata that every new dashboard gets.
+            # When the caller supplied json_metadata_overrides, merge those
+            # in shallowly so the LLM can override label_colors / color_scheme
+            # / cross_filters_enabled without re-specifying the whole shape.
+            json_metadata_dict: Dict[str, Any] = {
+                "filter_scopes": {},
+                "expanded_slices": {},
+                "refresh_frequency": 0,
+                "timed_refresh_immune_slices": [],
+                "color_scheme": None,
+                "label_colors": {},
+                "shared_label_colors": {},
+                "color_scheme_domain": [],
+                "cross_filters_enabled": False,
+                "native_filter_configuration": [],
+                "global_chart_configuration": {
+                    "scope": {
+                        "rootPath": ["ROOT_ID"],
+                        "excluded": [],
+                    }
+                },
+                "chart_configuration": {},
+            }
+            if request.json_metadata_overrides:
+                json_metadata_dict.update(request.json_metadata_overrides)
+            json_metadata = json.dumps(json_metadata_dict)

Review Comment:
   **Suggestion:** `json_metadata_overrides` is accepted as arbitrary `Any` 
content and merged directly before JSON serialization, but 
non-JSON-serializable values (e.g., sets, custom objects) will raise 
`TypeError`, which is not caught by this handler path. This can crash the tool 
instead of returning a structured error; validate/normalize overrides to 
JSON-safe primitives (or catch `TypeError` and return a controlled failure). 
[type error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ generate_dashboard can crash on json_metadata_overrides custom objects.
   - ⚠️ MCP caller sees generic failure instead of structured error.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. The MCP create tool `generate_dashboard` is the entrypoint for dashboard 
creation
   (`superset/mcp_service/dashboard/tool/generate_dashboard.py:195-212`), and 
its request
   schema `GenerateDashboardRequest` (in 
`superset/mcp_service/dashboard/schemas.py:620-645`)
   exposes `json_metadata_overrides: Dict[str, Any] | None` at lines 642-653, 
with `Any`
   permitting arbitrary Python values.
   
   2. In a Python context (for example, a unit test or internal helper), 
construct a
   `GenerateDashboardRequest` object with valid `chart_ids` and
   `json_metadata_overrides={"label_colors": CustomObject()}`, where 
`CustomObject` is a
   user-defined class instance that is not one of the types handled by 
Superset's JSON
   helpers.
   
   3. Call `generate_dashboard(request, ctx)`; inside the 
`mcp.generate_dashboard.db_write`
   block at 
`superset/mcp_service/dashboard/tool/generate_dashboard.py:290-317`, the code
   builds `json_metadata_dict` (lines 295-313), then executes
   `json_metadata_dict.update(request.json_metadata_overrides)` at line 315, 
inserting
   `CustomObject` into the metadata dict, and then calls `json_metadata =
   json.dumps(json_metadata_dict)` at line 316 using 
`superset.utils.json.dumps`.
   
   4. `superset.utils.json.dumps` (implemented in 
`superset/utils/json.py:188-229`) uses
   `json_iso_dttm_ser` and `base_json_conv` (lines 73-137) to serialize 
non-primitive
   objects; when it encounters `CustomObject`, none of the `isinstance` checks 
in
   `base_json_conv` match, so `base_json_conv` raises 
`TypeError("Unserializable object
   ...")` at line 111.
   
   5. This `TypeError` is not one of the exceptions caught by the outer handler 
`except
   (SQLAlchemyError, ValueError, AttributeError, ValidationError) as e:` at
   `superset/mcp_service/dashboard/tool/generate_dashboard.py:126-137, so it 
propagates out
   of `generate_dashboard` without returning a `GenerateDashboardResponse` and 
causes an
   internal error for the MCP caller instead of a structured error message 
about invalid
   `json_metadata_overrides`.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=dfe2a1d236ee4573b12d1e974b307fc0&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=dfe2a1d236ee4573b12d1e974b307fc0&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/dashboard/tool/generate_dashboard.py
   **Line:** 314:316
   **Comment:**
        *Type Error: `json_metadata_overrides` is accepted as arbitrary `Any` 
content and merged directly before JSON serialization, but 
non-JSON-serializable values (e.g., sets, custom objects) will raise 
`TypeError`, which is not caught by this handler path. This can crash the tool 
instead of returning a structured error; validate/normalize overrides to 
JSON-safe primitives (or catch `TypeError` and return a controlled failure).
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40399&comment_hash=3f1088e364f9909406a8e6a30704e408d8a1631bd42fd6007b2c0989c7aca62f&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40399&comment_hash=3f1088e364f9909406a8e6a30704e408d8a1631bd42fd6007b2c0989c7aca62f&reaction=dislike'>👎</a>



##########
superset/mcp_service/dashboard/tool/generate_dashboard.py:
##########
@@ -363,6 +418,13 @@ def generate_dashboard(  # noqa: C901
                     error="Failed to create dashboard due to a database 
error.",
                 )
 
+        # ``dashboard.id`` is fixed at create-commit time; the post-commit
+        # re-fetch below either returns the same row or fails — in either
+        # outcome the URL doesn't change. Bind it once so the three
+        # downstream consumers (partial response, DashboardInfo.url,
+        # response.dashboard_url) share a single source.
+        dashboard_url = 
f"{get_superset_base_url()}/superset/dashboard/{dashboard.id}/"

Review Comment:
   **Suggestion:** The generated dashboard URL is always built from the numeric 
ID, even when a slug was successfully set. This creates a contract mismatch 
with the rest of dashboard tooling (which prefers slug URLs) and returns the 
wrong canonical link for slugged dashboards; build the URL from `slug or id`. 
[api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ New dashboards with slugs return ID-based URLs.
   - ⚠️ URL shape inconsistent with update_dashboard `_build_dashboard_url`.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. The MCP create tool `generate_dashboard` is implemented in
   `superset/mcp_service/dashboard/tool/generate_dashboard.py:195-212` and 
called by MCP
   clients via the FastMCP tooling aggregator in
   `superset/mcp_service/dashboard/tool/__init__.py:18-31`.
   
   2. The request schema `GenerateDashboardRequest` in
   `superset/mcp_service/dashboard/schemas.py:620-645` defines a `slug` field 
(lines 623-631)
   and documents: "When set, the dashboard is reachable at 
`/superset/dashboard/<slug>/`
   instead of `/superset/dashboard/<id>/`."
   
   3. Call `generate_dashboard` with a non-empty `slug` (for example 
`"q4-exec-review"`) so
   that, inside `generate_dashboard`, `request.slug` is truthy and the slug is 
applied to the
   ORM object at 
`superset/mcp_service/dashboard/tool/generate_dashboard.py:328-329` via
   `dashboard.slug = request.slug`.
   
   4. After committing the dashboard at lines 359-360, the code constructs 
`dashboard_url` at
   line 426 as 
`f"{get_superset_base_url()}/superset/dashboard/{dashboard.id}/"`, always
   using the numeric `dashboard.id` and ignoring the slug, and then passes this 
value both to
   the partial minimal response (lines 63-71) and the full `DashboardInfo` 
response at lines
   80-96.
   
   5. In contrast, the update tool's `_build_dashboard_url` helper in
   `superset/mcp_service/dashboard/tool/update_dashboard.py:48-53` prefers slugs
   (`f"{get_superset_base_url()}/superset/dashboard/{dashboard.slug or 
dashboard.id}/"`), so
   clients that create a dashboard with a slug via `generate_dashboard` and 
later update it
   via `update_dashboard` will receive non-canonical ID-based URLs from create 
and slug-based
   URLs from update for the same dashboard.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=4fb7b9bcd0704737a98112aef185f9a3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=4fb7b9bcd0704737a98112aef185f9a3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/dashboard/tool/generate_dashboard.py
   **Line:** 426:426
   **Comment:**
        *Api Mismatch: The generated dashboard URL is always built from the 
numeric ID, even when a slug was successfully set. This creates a contract 
mismatch with the rest of dashboard tooling (which prefers slug URLs) and 
returns the wrong canonical link for slugged dashboards; build the URL from 
`slug or id`.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40399&comment_hash=320f4faf81ee3b77ce947fffdb5fec1ff75411d9a17454b2cca06c3c9202bb27&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40399&comment_hash=320f4faf81ee3b77ce947fffdb5fec1ff75411d9a17454b2cca06c3c9202bb27&reaction=dislike'>👎</a>



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to