Skip to content

fix(dashboard): drop missing semantic-view controls on restore - #45130

Open
mikebridge wants to merge 4 commits into
apache:masterfrom
mikebridge:sc-125586-dashboard-restore-missing-semantic-filters
Open

mikebridge wants to merge 4 commits into
apache:masterfrom
mikebridge:sc-125586-dashboard-restore-missing-semantic-filters

Conversation

@mikebridge

Copy link
Copy Markdown
Contributor

SUMMARY

An archived dashboard can outlive a semantic view used by its native filters or display controls. Restoring the dashboard previously kept those dangling references, leaving broken controls in the recovered dashboard.

Restore now removes an entire control when any of its explicitly typed semantic-view targets is missing or has an invalid ID, and removes links to that control from the remaining controls' cascadeParentIds. Table filters and other unaffected controls are preserved, including table targets with the same numeric ID as a deleted semantic view.

The check uses metadata existence, not provider availability or datasource permissions: an existing view is kept even when its provider is disabled or unavailable to the restoring user. Cleanup and unarchive share the existing transaction, after editorship and slug validation. If stored metadata cannot be safely parsed or traversed, restore leaves its bytes unchanged, skips cleanup and returns a warning instead of preventing recovery.

Warnings are returned in the existing REST/MCP message field. This PR does not add a UI warning toast; the archive UI does not display successful response messages. Callers should review the remaining dashboard filters before relying on its results.

This complements #45071, which guards semantic-source deletion for live dependent assets. Archived dashboards are intentionally excluded from that guard, so they need this recovery handling. This is not a new concurrency protocol: a concurrent or later source deletion can still invalidate a restored dashboard.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Not applicable: backend restore handling, with no UI change.

Scenario Before After
Filter/display control targets a deleted semantic view Dangling control survives restore Whole control and incoming cascade links removed; response warns
Existing view is inaccessible or its provider is disabled Control retained Control retained
Malformed legacy dashboard metadata Restorable without cleanup Still restorable, metadata preserved byte-for-byte; response warns cleanup was skipped
Ordinary table filter Retained Retained

TESTING INSTRUCTIONS

  1. Enable SOFT_DELETE and SEMANTIC_LAYERS. Create a dashboard with a semantic-view native filter or display control, an unaffected table filter, and a control cascading from the semantic control.
  2. Archive the dashboard, then delete the semantic view (with no other live dependents). Restore the dashboard as an editor through REST or MCP.
  3. Verify the broken control is removed, incoming cascade links are pruned, unrelated metadata/table filters remain, and the response message warns about the removed control. No UI warning toast is expected.
  4. Repeat while retaining the view but disabling its provider or removing datasource access. The control must remain.
  5. Regression tests cover persisted malformed/deep JSON, invalid IDs, rollback on commit failure, denied editorship, slug conflict and both REST/MCP warning propagation.
pytest tests/unit_tests/commands/dashboard/restore_semantic_filters_test.py \
       tests/unit_tests/commands/dashboard/restore_test.py \
       tests/unit_tests/commands/test_base_restore_command.py \
       tests/unit_tests/soft_delete/test_restore_purge_hoist.py \
       tests/unit_tests/mcp_service/dashboard/tool/test_restore_dashboard.py \
       tests/unit_tests/commands/chart/restore_test.py \
       tests/unit_tests/commands/dataset/restore_test.py

Local validation: the focused suite passed 124 tests. Both deeply nested JSON regression cases failed before the parser fix and passed after it. Changed-file pre-commit hooks passed, including MyPy, Ruff and pylint. PostgreSQL/MySQL and browser validation were not run locally.

Whole unit suite (TZ=UTC): 22,668 passed, 40 skipped, 2 xfailed, with exactly three known local-environment baseline failures in unchanged numeric-contract and translation-fixture tests. All 40 semantic-restore cases passed in that full run.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags: SOFT_DELETE, SEMANTIC_LAYERS
  • 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

Related: #45071. @aminghadersohi @rebenitez1802

AI-assisted implementation and review with Codex and Claude.

SC-125586: archived dashboards can outlive the semantic views referenced by their native filters and display controls. Remove affected controls and cascade links inside the restore transaction, after editorship and slug validation, and include a warning in REST and MCP responses. Preserve existing views regardless of provider/access availability and do not confuse table and semantic IDs. Cover persisted cleanup, rollback, source identity and warning delivery.
SC-125586 review follow-up: legacy JSON and malformed control shapes must not make archived dashboards unrestorable. Validate the cleanup input first, preserve malformed metadata unchanged and warn when cleanup is skipped. Require ASCII semantic IDs, handle oversized numeric input, and document invalid-ID removal without expanding the response schema. Add red-first persisted restore regressions.
Catch decoder RecursionError before dependency cleanup, preserving legacy metadata and allowing recovery. Cover nested roots and controls through the persisted restore path; both cases failed before the fix.
@github-actions github-actions Bot added the doc Namespace | Anything related to documentation label Oct 9, 2026
@netlify

netlify Bot commented Oct 9, 2026

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 5b43490
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6ac8339d5faa280008a82a0b
😎 Deploy Preview https://deploy-preview-45130--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.

@codecov

codecov Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.73%. Comparing base (e10e268) to head (5b43490).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #45130      +/-   ##
==========================================
+ Coverage   82.72%   82.73%   +0.01%     
==========================================
  Files        3011     3011              
  Lines      188350   188415      +65     
  Branches    43725    43740      +15     
==========================================
+ Hits       155819   155893      +74     
+ Misses      29761    29753       -8     
+ Partials     2770     2769       -1     
Flag Coverage Δ
hive 36.14% <13.04%> (-0.02%) ⬇️
mysql 55.19% <42.02%> (-0.02%) ⬇️
postgres 55.20% <42.02%> (-0.01%) ⬇️
presto 38.00% <13.04%> (-0.02%) ⬇️
python 86.55% <100.00%> (+0.01%) ⬆️
sqlite 54.94% <42.02%> (-0.01%) ⬇️
unit 79.89% <100.00%> (+0.03%) ⬆️

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.

@mikebridge
mikebridge marked this pull request as ready for review October 9, 2026 04:37
Comment thread superset/commands/dashboard/restore.py
@codeant-ai-for-open-source

codeant-ai-for-open-source Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

CodeAnt PR Risk: Low Risk

  • The PR appears safe to merge; it removes dashboard controls with missing semantic views during restore while preserving unaffected controls.
  • Malformed metadata leaves the dashboard recoverable and unchanged, with a warning; tests cover cleanup, rollback, and response messaging.
  • The unbatched lookup concern is not compelling for IDs collected from one dashboard’s controls, whose expected count is small.

Assessed commit: 5b434908a357

@rebenitez1802 rebenitez1802 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.

Approving — this is a well-designed, genuinely well-tested fix. The existence-not-permission check is the right signal (SemanticView is a hard delete via AuditMixinNullable, so the probe is exact), the "skip + warn, never block restore" fallback is the correct recovery posture, metadata is preserved byte-for-byte on the skip path, and the transaction/rollback behavior is asserted against a real DB across all 40 semantic-restore cases. Security model is intact: restore is already gated by editorship and the view probe leaks nothing. 🟢

Two non-blocking items I'd suggest tightening, either here or in a follow-up:

1. Valid-but-non-dict metadata is falsely reported as "malformed"
In _parse_restore_metadata, a json_metadata of "null" or "[]" is valid JSON but non-dict, so it returns None and prepare_restore appends the "metadata is malformed … review the dashboard filters" warning on a dashboard that actually has nothing to clean. Legacy rows can carry these values, so users get a misleading warning telling them to review filters that are fine. Consider treating a non-dict root as "nothing to clean" (no-op, no warning) and reserving the warning for genuine json.loads / structural failures.

2. Legacy chart_customization_config semantic refs can survive restore silently
Cleanup keys off targets[].datasourceType == "semantic_view". Pre-migration chart-customization entries (shape {"customization": {"dataset": N}}, per isLegacyChartCustomizationFormat in migrateChartCustomization.ts) have no targets and no datasourceType discriminator, so a legacy control bound to a deleted semantic view is kept with no warning — the one case that defeats the fix's purpose without even flagging it. This may be an unavoidable limitation if the legacy format can't be distinguished from a plain-dataset ref — but could you confirm whether legacy entries can reference semantic views? If so, migrate-then-check; if not, worth documenting the carve-out, since the docs currently state all controls "referencing a semantic view" are removed.

A few smaller nits (hardcoded "semantic_view" literal vs DatasourceType.SEMANTIC_VIEW, duplicated key tuple across the two helpers, and a theoretical duplicate-id cascade-pruning edge) are minor and left to your discretion.

This branch has not been deployed

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

Labels

doc Namespace | Anything related to documentation size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants