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


##########
superset/mcp_service/chart/schemas.py:
##########
@@ -2019,13 +2125,14 @@ def validate_percentiles_and_dimensions(self) -> 
"BoxPlotChartConfig":
     | HandlebarsChartConfig
     | BigNumberChartConfig
     | HistogramChartConfig
-    | BoxPlotChartConfig,
+    | BoxPlotChartConfig
+    | WaterfallChartConfig,

Review Comment:
   **Suggestion:** This adds `waterfall` as a first-class chart type in request 
validation, but the chart-data recommendation classifier still lacks a 
`waterfall` category mapping, so downstream recommendation dedup treats 
existing waterfall charts as an unknown category and can suggest redundant `bar 
chart` recommendations for the same semantic family. Update the viz-category 
mapping to classify waterfall with bar-like charts to keep recommendation 
behavior consistent with other registered chart types. [incomplete 
implementation]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ get_chart_data suggests redundant bar-style charts for waterfalls.
   - ⚠️ Recommendation dedup ignores waterfall’s bar-like category semantics.
   - ⚠️ LLM chart guidance less coherent for datasets with waterfall charts.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Use the MCP `get_chart_data` tool implemented in
   `superset/mcp_service/chart/tool/get_chart_data.py`, which constructs 
human-readable
   chart-type candidates (e.g. "line chart", "bar chart", "waterfall chart") 
and normalizes
   them via the `_CANDIDATE_CATEGORY` map at `get_chart_data.py:207-213` where 
each candidate
   string is mapped to a canonical category for dedup against the current 
`viz_type`.
   
   2. Create or retrieve a Superset chart with `viz_type="waterfall"` (the 
Waterfall plugin
   is registered in `superset/mcp_service/chart/plugins/__init__.py:40` and 
resolves
   `viz_type` to `"waterfall"` in 
`superset/mcp_service/chart/plugins/waterfall.py:102-103`),
   then invoke `get_chart_data` so it can compute recommended chart-type 
candidates for the
   same dataset.
   
   3. Because `_CANDIDATE_CATEGORY` currently includes mappings for strings 
like `"bar
   chart": "bar"` but lacks an entry for `"waterfall chart"`, any candidate 
phrase referring
   to waterfall charts is treated as an unclassified category when deduping 
recommendations
   against the existing `viz_type="waterfall"`.
   
   4. The dedup logic in `get_chart_data.py` (commented at lines 207-208 as 
“Maps each
   candidate string to a canonical category for dedup against the current 
viz_type”)
   therefore fails to recognize waterfall as part of the bar-like family, 
allowing redundant
   recommendations such as “bar chart” for data already visualized as a 
waterfall chart,
   leading to inconsistent and noisy suggestion behavior for the new chart type.
   ```
   </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=b5a8957bc9cf4e0ea4176ccf3a019dc6&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=b5a8957bc9cf4e0ea4176ccf3a019dc6&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/chart/schemas.py
   **Line:** 2127:2129
   **Comment:**
        *Incomplete Implementation: This adds `waterfall` as a first-class 
chart type in request validation, but the chart-data recommendation classifier 
still lacks a `waterfall` category mapping, so downstream recommendation dedup 
treats existing waterfall charts as an unknown category and can suggest 
redundant `bar chart` recommendations for the same semantic family. Update the 
viz-category mapping to classify waterfall with bar-like charts to keep 
recommendation behavior consistent with other registered chart types.
   
   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%2F42070&comment_hash=3d1d44418fa0e343bb04794eed243c48f56764d6f0d4027914cbe4cbdbf076c5&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42070&comment_hash=3d1d44418fa0e343bb04794eed243c48f56764d6f0d4027914cbe4cbdbf076c5&reaction=dislike'>👎</a>



##########
superset/mcp_service/chart/schemas.py:
##########
@@ -2009,6 +2009,112 @@ def validate_percentiles_and_dimensions(self) -> 
"BoxPlotChartConfig":
         return self
 
 
+class WaterfallChartConfig(UnknownFieldCheckMixin):
+    """Config for waterfall charts (viz_type ``waterfall``)."""
+
+    model_config = ConfigDict(extra="ignore", populate_by_name=True)
+
+    chart_type: Literal["waterfall"] = "waterfall"
+    x_axis: ColumnRef = Field(
+        ...,
+        description="Category or period column along the x-axis (often "
+        "temporal, e.g. month); each value is one waterfall step",
+    )
+    metric: ColumnRef = Field(
+        ...,
+        description="Metric whose per-step change is plotted (use aggregate "
+        "e.g. SUM for ad-hoc, or saved_metric=True for a saved metric)",
+    )
+    breakdown: ColumnRef | None = Field(
+        None,
+        validation_alias=AliasChoices("breakdown", "groupby"),
+        description="Optional single category column that breaks each "
+        "x-axis period into per-category steps (form_data 'groupby'; the "
+        "frontend Breakdowns control is single-select)",
+    )
+    time_grain: TimeGrain | None = Field(
+        None,
+        description="Time bucket for a temporal x_axis (PT1H, P1D, P1W, "
+        "P1M, P1Y); each bucket becomes one waterfall step. Ignored for a "
+        "non-temporal x_axis.",
+        validation_alias=AliasChoices("time_grain", "time_grain_sqla"),
+    )
+    show_total: bool = Field(
+        True, description="Append a total bar per period (frontend default)"
+    )
+    show_legend: bool = Field(
+        False, description="Show the legend (frontend default: off)"
+    )
+    increase_label: str = Field("Increase", max_length=50)
+    decrease_label: str = Field("Decrease", max_length=50)
+    total_label: str = Field("Total", max_length=50)
+    x_axis_time_format: str = Field(
+        "smart_date",
+        description="Time format for a temporal x-axis (e.g. 'smart_date', 
'%Y-%m-%d')",
+        max_length=50,
+    )
+    y_axis_format: str = Field("SMART_NUMBER", max_length=50)
+    currency_format: CurrencyFormat | None = Field(
+        None,
+        description="Currency symbol applied to the metric value",
+    )
+    filters: List[FilterConfig] | None = Field(
+        None,
+        description="Structured filters (column/op/value). "
+        "Do NOT use adhoc_filters or raw SQL expressions.",
+    )
+    row_limit: int = Field(
+        10000,
+        description="Max grouped rows (frontend shared default)",
+        ge=1,
+        le=50000,
+    )
+
+    @model_validator(mode="before")
+    @classmethod
+    def unwrap_list_breakdown(cls, data: Any) -> Any:
+        """Accept the native form_data shape where ``groupby`` is a list.
+
+        The frontend Breakdowns control is single-select but stores its value
+        as a one-item list (e.g. ``["region"]``), so a config round-tripped
+        from existing waterfall form_data sends a list. Unwrap a length-1
+        list to the single value; reject longer lists rather than silently
+        dropping breakdowns. Native form_data also names physical columns as
+        bare strings, so a string is coerced to ``{"name": ...}``.
+        """
+
+        def _coerce(value: Any) -> Any:
+            if isinstance(value, list):
+                if len(value) > 1:
+                    raise ValueError(
+                        "waterfall breakdown is single-select; pass at most 
one column"
+                    )
+                value = value[0] if value else None
+            if isinstance(value, str):
+                return {"name": value}
+            return value
+
+        if isinstance(data, dict):
+            for key in ("groupby", "breakdown"):
+                if key in data:
+                    data[key] = _coerce(data[key])
+        return data

Review Comment:
   **Suggestion:** The pre-validation coercion only normalizes 
`groupby`/`breakdown`, but native waterfall form_data also uses a bare string 
for `x_axis` (for example `"x_axis": "month"`). Because `x_axis` is typed as 
`ColumnRef`, those valid round-tripped payloads fail schema parsing with a 
validation error. Extend this same coercion path to normalize `x_axis` string 
input into `{"name": ...}` so existing waterfall form_data can be accepted 
consistently. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ MCP generate_chart rejects valid waterfall configs with string x_axis.
   - ⚠️ LLM clients copying Superset form_data see validation errors.
   - ⚠️ WaterfallChartPlugin.normalize_column_refs cannot run on rejected 
configs.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Call the MCP `generate_chart` tool so that request data is validated via
   `SchemaValidator.validate_request` in
   `superset/mcp_service/chart/validation/schema_validator.py:40-56`, passing a 
config like
   `{"chart_type": "waterfall", "x_axis": "month", "metric": {"name": 
"revenue", "aggregate":
   "SUM"}}` copied from native Superset waterfall form_data (`x_axis` as bare 
string).
   
   2. The `GenerateChartRequest` Pydantic model (defined in
   `superset/mcp_service/chart/schemas.py` later in the file) runs
   `ChartRequestNormalizerMixin._normalize_request_vocabulary`, which calls
   `_normalize_chart_request_input` at 
`superset/mcp_service/chart/schemas.py:29-59` to
   translate Superset vocabulary (e.g. `viz_type` to `chart_type`) but does not 
modify the
   `x_axis` field.
   
   3. The discriminated union `ChartConfig` at
   `superset/mcp_service/chart/schemas.py:220-240` selects 
`WaterfallChartConfig` based on
   `chart_type="waterfall"` and invokes its `@model_validator(mode="before")
   unwrap_list_breakdown` at `superset/mcp_service/chart/schemas.py:174-203`, 
which only
   coerces `groupby`/`breakdown` values and leaves `x_axis` as the original 
string.
   
   4. Pydantic then attempts to populate the `x_axis: ColumnRef` field of
   `WaterfallChartConfig` (lines 118-123 in 
`superset/mcp_service/chart/schemas.py`) from the
   bare string `"month`; since `ColumnRef` expects a structured column object, 
this results
   in a `ValidationError`, causing `SchemaValidator.validate_request` to return 
a
   `ChartGenerationError` instead of a parsed request and blocking waterfall 
chart generation
   for otherwise valid native form_data.
   ```
   </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=5f16c672479247bbb6e85743ab5a709a&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=5f16c672479247bbb6e85743ab5a709a&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/chart/schemas.py
   **Line:** 2097:2101
   **Comment:**
        *Api Mismatch: The pre-validation coercion only normalizes 
`groupby`/`breakdown`, but native waterfall form_data also uses a bare string 
for `x_axis` (for example `"x_axis": "month"`). Because `x_axis` is typed as 
`ColumnRef`, those valid round-tripped payloads fail schema parsing with a 
validation error. Extend this same coercion path to normalize `x_axis` string 
input into `{"name": ...}` so existing waterfall form_data can be accepted 
consistently.
   
   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%2F42070&comment_hash=ea9b45f90eb5dfb177e236c4c2342e7d9bd3167532f69dab5ba8f64ae1bd814e&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F42070&comment_hash=ea9b45f90eb5dfb177e236c4c2342e7d9bd3167532f69dab5ba8f64ae1bd814e&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