mirror of
https://github.com/apache/superset.git
synced 2026-07-12 09:45:43 +00:00
The diff engine now recurses into nested dicts inside JSON-blob fields (``json_metadata``, ``Slice.params`` non-list sub-keys, layout node ``meta``) via a shared ``_recursive_leaf_diff`` helper, emitting one ``ChangeRecord`` per atomic leaf change rather than one record carrying the whole top-level sub-tree on both sides. Concretely, a dashboard header text change from "VERSION 2!" to "HEADER!" used to emit a single record at path ``["edit", "header", "HEADER-id-1"]`` with the entire layout node duplicated on both sides of the diff. It now emits a single record at path ``["edit", "header", "HEADER-id-1", "text"]`` with just the changed string as ``from_value`` / ``to_value``. Multi-leaf edits produce one record per leaf. Each call site passes its own depth cap via a named constant: * ``_LAYOUT_META_DIFF_DEPTH = 3`` — layout meta is presentation state (text, sizes, colors), shallow by nature. * ``_JSON_METADATA_DIFF_DEPTH = 6`` — native filter configuration can go five levels deep (``defaultDataMask.filterState.value``). * ``_SLICE_PARAMS_DIFF_DEPTH = 6`` — adhoc filter sub-queries and pivot options can be similarly deep. A cap is a usefulness bound (granularity that's meaningful in a timeline), not a safety bound. Cap-on-dict-vs-dict emits a debug log so production tuning can see when a cap is too tight for typical data. Lists are treated as opaque leaves: positional paths break under reorder. Lists with stable identity (adhoc filters, metrics, dataset columns) already have natural-key walkers (``_diff_list_by_natural_key``) that emit per-element records with the right identity; those are unchanged. Backward compatibility: * Top-level scalar fields, child-collection records (column/metric), M2M slice membership, and layout add/remove/move records all keep their existing path/from/to shape. The change is scoped to JSON-blob recursion. * All 56 existing diff unit tests pass without modification. 13 new tests cover the Shape B behaviour (helper directly, type mismatches, opaque list policy, depth cap, nested ``json_metadata``, layout edit, ``Slice.params`` deep unknown key, cross-node aggregation). * Existing integration tests in ``change_records_tests.py`` assert on scalar-field changes only — unaffected. Restoration is unaffected: the restore path reads from Continuum shadow tables, not from ``version_changes``. This change is purely about audit-log granularity. Spec coverage: tasks.md T047d (added in spec repo). Rationale: plan.md "Key Design Decision: Leaf-level recursive diff for JSON-blob fields (Shape B)". Conventions: data-model.md "Leaf-level recursion".
46 KiB
46 KiB