Skip to content

fix(mcp): preserve table chart state during updates - #42655

Open
aminghadersohi wants to merge 7 commits into
apache:masterfrom
aminghadersohi:sc-115627-mcp-update-table-charts
Open

fix(mcp): preserve table chart state during updates#42655
aminghadersohi wants to merge 7 commits into
apache:masterfrom
aminghadersohi:sc-115627-mcp-update-table-charts

Conversation

@aminghadersohi

@aminghadersohi aminghadersohi commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

SUMMARY

Adds safe patch semantics for updating existing table charts through MCP and fixes stale-filter handling during previews.

  • Adds add_columns to update_chart, allowing callers to append table dimensions or metrics without reconstructing or replacing the saved column list.
  • Preserves an explicit dataset rebind during additive updates.
  • Rejects metric-shaped additions to raw tables instead of silently discarding aggregation semantics.
  • Honors an explicit filters: [] by removing saved ad hoc filters from preview form data.
  • Treats only Superset's inert temporal No filter placeholder as non-filtering during dataset-column validation.
  • Clarifies validation guidance so it describes the accepted filter-clearing request exactly.
  • Adds regression coverage for additive updates, parenthesized column names, explicit filter clearing, and inert stale filters.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Not applicable. This changes the MCP API and validation behavior without UI changes.

TESTING INSTRUCTIONS

ruff check superset/mcp_service/chart/schemas.py superset/mcp_service/chart/tool/update_chart.py superset/mcp_service/chart/compile.py tests/unit_tests/mcp_service/chart/tool/test_update_chart.py tests/unit_tests/mcp_service/chart/test_compile.py
python -m pytest -q tests/unit_tests/mcp_service/chart/tool/test_update_chart.py tests/unit_tests/mcp_service/chart/test_compile.py
pre-commit run --files superset/mcp_service/chart/compile.py superset/mcp_service/chart/schemas.py superset/mcp_service/chart/tool/update_chart.py tests/unit_tests/mcp_service/chart/test_compile.py tests/unit_tests/mcp_service/chart/tool/test_update_chart.py

The focused MCP suite passes 87 tests and the changed-file pre-commit gate passes. The required all-files gate was also run; unrelated repository-wide mypy errors and unavailable frontend dependencies prevent a clean all-files result in this environment.

Eval evidence: Focused regression coverage includes additive metric preservation, dataset rebinding, raw-table metric rejection, parenthesized column names, explicit empty-filter replacement, and inert stale-filter validation.

Cost & latency delta: Adds 0 LLM calls and 0 external requests. The update path adds only in-memory list/dictionary merging and a linear scan of saved filters; no model or prompt behavior changes.

ADDITIONAL INFORMATION

Blast radius: Limited to MCP update_chart table updates and MCP chart filter validation. Existing full-config replacement behavior remains available.

Risk and rollback: Low. The new request field is additive, and reverting the commits restores the prior behavior. Non-table charts and metric additions to raw tables return actionable validation errors.

Review guidance: Focus on preservation of existing groupby/metrics/all_columns, dataset rebinding, and the distinction between omitted filters (preserve) and explicit filters: [] (clear).

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 11.53846% with 69 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.73%. Comparing base (1605676) to head (79f2704).

Files with missing lines Patch % Lines
superset/mcp_service/chart/tool/update_chart.py 6.34% 59 Missing ⚠️
superset/mcp_service/chart/compile.py 28.57% 5 Missing ⚠️
superset/mcp_service/chart/schemas.py 37.50% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42655      +/-   ##
==========================================
- Coverage   65.79%   65.73%   -0.06%     
==========================================
  Files        2842     2842              
  Lines      162106   162165      +59     
  Branches    37148    37159      +11     
==========================================
- Hits       106653   106606      -47     
- Misses      53388    53494     +106     
  Partials     2065     2065              
Flag Coverage Δ
hive 38.05% <11.53%> (-0.03%) ⬇️
mysql 57.86% <11.53%> (-0.04%) ⬇️
postgres 57.91% <11.53%> (-0.04%) ⬇️
presto 39.97% <11.53%> (-0.03%) ⬇️
python 59.28% <11.53%> (-0.05%) ⬇️
sqlite 57.54% <11.53%> (-0.04%) ⬇️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@netlify

netlify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 9c962f0
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a728d4b7fd490000899d114
😎 Deploy Preview https://deploy-preview-42655--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@aminghadersohi
aminghadersohi marked this pull request as ready for review August 4, 2026 23:42
@dosubot dosubot Bot added api Related to the REST API viz:charts:table Related to the Table chart labels Aug 4, 2026
@github-actions github-actions Bot removed the api Related to the REST API label Aug 4, 2026
aminghadersohi and others added 4 commits August 5, 2026 00:57
Co-Authored-By: Claude <noreply@anthropic.com>
test_sub_day_last_normalizes asserts a premise -- that the raw value
blows up inside get_since_until() -- before checking the normalization.
That premise compares a sub-day since-expression against an until of
midnight-today, so it only holds once the clock is far enough past
midnight.

Bare-unit values ("Last hour", "Last Hour") truncate to the previous
whole unit rather than resolving relative to now, which leaves them
behind midnight until 02:00 and makes get_since_until() return a valid
range instead of raising. Runs landing in that window failed with
"DID NOT RAISE ValueError" for exactly those two parameters.

Freeze the clock at midday so the case no longer depends on when the
suite runs. Test-only: the validator's behaviour is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
@aminghadersohi
aminghadersohi force-pushed the sc-115627-mcp-update-table-charts branch from 16dbdb4 to 9c962f0 Compare August 5, 2026 01:09

@bito-code-review bito-code-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Agent Run #b295fd

Actionable Suggestions - 2
  • superset/mcp_service/chart/schemas.py - 2
Additional Suggestions - 3
  • superset/mcp_service/chart/tool/update_chart.py - 3
    • Missing deduplication for all_columns · Line 131-133
      When `add_columns` is called multiple times or includes columns already in `all_columns`, duplicates are silently appended. Superset may behave unpredictably with duplicate column entries. Consider deduplicating: `existing = set(existing_form_data.get('all_columns') or []); merged['all_columns'] = list(existing | {c.name for c in columns if c.name})`
    • Missing deduplication for groupby/metrics · Line 138-139
      Same pattern as `all_columns` — `groupby` and `metrics` lists are blindly extended without checking for existing entries. Duplicate metrics/groupby fields can cause Superset query failures or unexpected aggregations.
    • Incomplete doc example for add_columns · Line 441-441
      The docstring at line 441 mentions `add_columns` but the JSON examples only show it standalone. Users may not realize it can be combined with `chart_name` for rename + column-append operations, limiting discoverability.
Review Details
  • Files reviewed - 6 · Commit Range: 163a694..36c68d8
    • superset/mcp_service/chart/compile.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/update_chart.py
    • tests/unit_tests/mcp_service/chart/test_compile.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart.py
    • tests/unit_tests/mcp_service/common/test_time_range_validation.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment on lines +2350 to +2357
add_columns: List[ColumnRef] | None = Field(
None,
description=(
"Table columns or metrics to append while preserving every existing "
"column and metric. Use this instead of config.columns when adding "
"columns to an existing table chart."
),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for new field

The new add_columns field (lines 2350-2357) has no corresponding unit tests in test_chart_schemas.py. Per the project's testing guidelines, every new MCP mutation tool schema field requires dedicated unit test coverage including request validation and schema serialization.

Code Review Run #b295fd


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partly. The add_columns field itself is covered — test_update_chart.py has test_add_columns_preserves_existing_columns_and_metrics, test_add_columns_rebinds_requested_dataset, and a parametrized test_add_metric_to_raw_table_returns_actionable_error. They live next to the other _build_update_payload tests rather than in test_chart_schemas.py, which is why the search missed them.

The validator was a real gap though, so I've added TestUpdateChartRequestColumnPatchValidation covering both error branches and the valid additive shape (see the reply on the validate_column_patch thread).

Writing the coverage you asked for also turned up an actual bug, so thanks — details in the other thread and in the PR comment.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is good to hear that the coverage gaps have been addressed and that the additional testing led to the discovery of a bug. The addition of TestUpdateChartRequestColumnPatchValidation to cover both error branches and the valid additive shape is an appropriate way to resolve the concern regarding missing test coverage for the new field.

Comment on lines +2393 to +2398
if self.config is not None and self.add_columns is not None:
raise ValueError(
"Use either 'config' for a full visualization replacement or "
"'add_columns' to append table columns while preserving the existing "
"configuration, not both."
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test for validator error branches

The validate_column_patch validator (lines 2393-2401) that enforces mutual exclusivity of config and add_columns has no unit tests. Both its error branches — blocking co-provision and blocking empty list — are untested.

Code Review Run #b295fd


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid — both branches were untested. Added in 79f2704:

class TestUpdateChartRequestColumnPatchValidation:
    def test_config_and_add_columns_together_rejected(self)  # "not both"
    def test_empty_add_columns_rejected(self)                # "at least one column"
    def test_add_columns_alone_accepted(self)                # the valid shape

Writing these paid for itself: the dimension-only case they exercise led me to a real bug where appending a plain column to an aggregate table silently dropped it. Fixed in the same commit — see the PR comment.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggestion to add unit tests for the validator error branches is appropriate and improves the code's robustness. Implementing these tests ensures that the mutual exclusivity of 'config' and 'add_columns' is correctly enforced and helps prevent regressions, as demonstrated by the bug you identified and fixed.

Addresses review feedback on apache#42655.

_append_table_columns() built its patch with
map_config_to_form_data(TableChartConfig(columns=...)), which infers
query_mode from the columns it is handed. A dimension-only append
compiles to a raw table whose groupby is empty, so appending a plain
column to an aggregate table extended groupby with nothing and the
column was silently dropped. Route columns by ColumnRef.is_metric
instead, so dimensions reach groupby and metrics reach metrics
regardless of the mix.

Appends also blindly extended the saved lists, so re-adding a column
already on the chart duplicated it. Skip entries that are already
present, keyed on a stable serialization -- metric lists mix saved
names with adhoc dicts, so they are not reliably hashable and a set
would both crash and lose the ordering that drives table layout.

Cover the config/add_columns validator error branches, which had no
tests, and document that add_columns combines with chart_name.

Co-Authored-By: Claude <noreply@anthropic.com>
@pull-request-size pull-request-size Bot added size/XL and removed size/L labels Aug 5, 2026
@aminghadersohi

Copy link
Copy Markdown
Contributor Author

Thanks @bito-code-review — worked through all five suggestions. All are addressed in 79f2704, and chasing the dedup one uncovered a genuine bug in this PR.

The bug the review led to

_append_table_columns() built its patch with map_config_to_form_data(TableChartConfig(columns=...)), which infers query_mode from the columns it's handed:

appended columns inferred mode groupby
plain only raw None
metric only aggregate None
mixed aggregate ['region']

So a dimension-only append compiled to a raw patch, patch.get("groupby") was None, and .extend(... or []) appended nothing — adding a plain column to an aggregate table silently did nothing. Confirmed against the unmodified branch:

groupby -> ['employer']        # expected ['employer', 'region']

Existing tests missed it because they either appended a metric (aggregate="MIN") or asserted only on datasource_id. Columns are now routed by ColumnRef.is_metric, so dimensions reach groupby and metrics reach metrics regardless of the mix, and the chart is never flipped out of aggregate mode.

Suggestions 1 & 2 — test coverage

add_columns was already covered behaviorally in test_update_chart.py (not test_chart_schemas.py, hence the miss). The validator was genuinely untested — both error branches now are. Replied on both threads.

Suggestions 3 & 4 — deduplication

Agreed on the substance, with one correction: the proposed set() approach doesn't work here.

>>> set(['count', {'label': 'Earliest Go Live Date', 'aggregate': 'MIN'}])
TypeError: unhashable type: 'dict'

metrics mixes saved-metric names with adhoc metric dicts, so a set raises — and it would also discard the ordering that drives table column layout. Dedup is instead keyed on a stable serialization and preserves first-occurrence order, applied to all_columns, groupby, and metrics. Re-adding an existing column is now a no-op rather than a silent duplicate.

Suggestion 5 — docs

Added an example combining chart_name with add_columns, noting that repeating an existing column is safe.

Verification

tests/unit_tests/mcp_service/3283 passed; chart/1184 passed. Ruff format + check clean on the pinned 0.9.7. Six new tests, including regression coverage for the dropped-column bug.

@bito-code-review

bito-code-review Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #089551

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset/mcp_service/chart/tool/update_chart.py - 1
    • Performance: repeated JSON serialization · Line 103-110
      `_entry_key` uses `json.dumps` for every comparison, which serializes the entire entry on every `in`-set check. For large chart configs (100+ columns/metrics), this adds O(n) overhead per lookup. Consider caching serialized keys or using a structural hash for hot-path reuse.
Review Details
  • Files reviewed - 2 · Commit Range: 36c68d8..79f2704
    • superset/mcp_service/chart/tool/update_chart.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants