rebenitez1802 opened a new pull request, #45826:
URL: https://github.com/apache/superset/pull/45826

   ### SUMMARY
   
   Functional fixes for the Canvas draft lifecycle and its MCP/REST contract, 
targeting `msyavuz/feat/canvas`.
   
   **Draft lifecycle (3 bugs, each reproduced before the fix)**
   - **Canceled new widgets.** If a draft added a new widget and then removed 
it, the staged entity was pruned mid-batch. So the commit failed with 422 "add 
widgets that cannot be placed" (separate calls, one batch, parent removal, 
surviving sibling). A re-added widget also lost its stored content. Drafts now 
keep new widget entities until the final replay (`keep_unplaced`). The commit 
then drops new widgets that end up unplaced, so no orphan widget rows are 
written. Edits to existing widgets are never pruned.
   - **Explicit-null resets.** `set_scope.scope: null` and `set_settings.value: 
null` were removed from the replay log (`exclude_none`), so replay failed with 
`Field required`. The nulls are now logged explicitly. An omitted field is 
still a validation error, never a reset.
   - **Empty close revision.** Closing an empty draft returned the fork's 
`base_revision`, even after another publish. `CommitCanvasDraftCommand` now 
returns a typed `CommitResult` with the canvas revision actually written or 
observed. Both callers (REST and MCP) are updated.
   
   **MCP contract**
   - `apply_canvas_draft_ops.ops` and `create_canvas.ops` advertise the 
canonical `Operation` union in their input schemas 
(`BeforeValidator(json_schema_input_type=...)`). There is no second, 
handwritten grammar.
     - The arguments are unchanged: still flat, camelCase.
     - Omitted, null and default values behave as before. `create_canvas` still 
accepts `ops` omitted, `null` or `[]`.
     - Indexed field-path errors (`/ops/1/index`) are preserved.
   - Results add `error_type` (`ValidationError`, `DraftUnavailable`, 
`DraftRevisionConflict`, `CanvasRevisionConflict`, `WidgetRevisionConflict`), 
`draft_revision` and `current_canvas_revision`. Legacy keys are unchanged.
   - An unavailable or foreign token discloses no revisions.
   - Tool descriptions for `commit_canvas_draft` and `apply_canvas_draft_ops` 
now lead with publish intent and conflict recovery. That guidance survives the 
300-character tool-search truncation.
   
   **REST**
   - 409 bodies add `error_type`, `draftRevision` and `currentCanvasRevision` 
next to the existing `revision` and `canvasChanged`.
   - 404 for an unavailable draft adds `error_type: DraftUnavailable`.
   - Status codes and existing keys are unchanged.
   
   **Behavior worth knowing (pinned by tests, documented in 
`mcp-server.mdx`):** a draft whose operations cancel out, e.g. add a new widget 
and then remove it, commits as a real write. That is the same result as 
publishing those operations without a draft. If the canvas changed meanwhile, 
the commit returns 409 `CanvasRevisionConflict`. Treating such a draft as an 
empty close would be a new behavior and is left for a follow-up.
   
   The query translator and chart-data path were already correct. The new 
real-SQL tests confirm this, and no query code changed.
   
   ### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
   
   N/A (backend and MCP only).
   
   ### TESTING INSTRUCTIONS
   
   ```bash
   pytest tests/unit_tests/canvas tests/unit_tests/mcp_service/canvas \
     tests/unit_tests/mcp_service/test_tool_search_transform.py \
     tests/unit_tests/mcp_service/test_mcp_server.py \
     tests/unit_tests/mcp_service/test_native_tool_surface.py \
     tests/unit_tests/mcp_service/test_tool_inventory.py
   ```
   
   - **Focused suite:** 750 pass.
   - **Run against the old code:** the new lifecycle tests fail 8 times (5 
canceled-widget cases, 1 empty-close revision, 2 null resets).
   - **Mutation testing:** reverting any single production fix turns tests red.
   - **Wider sweep:** `tests/unit_tests/mcp_service` plus 
`tests/unit_tests/canvas` gives 13,665 passed and 0 failed (base: 13,502 
passed).
   - **Checks:** OpenAPI regenerated with marshmallow 4.3.1 shows no drift. 
Pre-commit, MyPy and Pylint (10.00/10) pass on the changed files.
   
   Test additions:
   - `tests/unit_tests/canvas/widget_entities_test.py`, `draft_test.py`, 
`api_test.py`: lifecycle regressions, conflict precedence and provenance, REST 
payloads.
   - `tests/unit_tests/canvas/placement_data_test.py`: real SQLite aggregate 
queries (top and bottom 5, unsorted limit, query-text visibility) through an 
unmocked `ChartDataCommand`.
   - `tests/unit_tests/mcp_service/canvas/tool/test_canvas_contract.py` (new): 
schema exposure, and native vs. `search_tools`/`call_tool` proxy parity with 
protected wrappers and RBAC enabled.
   
   `native_tool_inventory.json` and the 
`apply_canvas_draft_ops`/`create_canvas` budgets in `test_tool_inventory.py` 
were regenerated or raised. The inlined operation grammar grows each entry to 
about 5.3 KB. Only Canvas entries and catalog totals changed.
   
   ### ADDITIONAL INFORMATION
   - [ ] Has associated issue:
   - [x] Required feature flags: `CANVAS`
   - [ ] Changes UI
   - [ ] Includes DB Migration (follow approval process in 
[SIP-59](https://github.com/apache/superset/issues/13351))
     - [ ] 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
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


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