🐛 Preserve remote sync state in inverse child add and delete changes

Make structural inverses ignore touched so undoing derived propagation
keeps the parent's remote-synced flag. Fix F132.

Both add and delete regressions pass exact undo/redo comparisons. Runner
suite: 43 tests, 107 assertions, all green.
Benchmark ratios against Phase 1e: main 10/100/1000 0.46/0.52/0.53;
three levels 0.47; chain 0.51; library 0.51; many shapes 0.49;
variant switch 0.61. No regression flag.

AI-assisted-by: GPT-6
This commit is contained in:
alonso.torres 2026-10-23 14:52:45 +02:00
parent 8a034be8fd
commit 3ff24dc190
2 changed files with 17 additions and 1 deletions

View File

@ -485,7 +485,8 @@
del-change
{:type :del-obj
:id (:id obj)
:page-id (::page-id (meta changes))}
:page-id (::page-id (meta changes))
:ignore-touched true}
restore-touched-change
{:type :mod-obj
@ -694,6 +695,7 @@
(some? shape)
(conj {:type :add-obj
:id id
:ignore-touched true
:page-id page-id
:parent-id (:parent-id shape)
:frame-id (:frame-id shape)

View File

@ -15,11 +15,25 @@
[app.common.test-helpers.composable.core :as tm]
[app.common.test-helpers.files :as thf]
[app.common.test-helpers.ids-map :as thi]
[app.common.test-helpers.normalize :as thn]
[app.common.uuid :as uuid]
[clojure.test :as t]))
(t/use-fixtures :each thi/test-fixture)
(t/deftest undo-main-child-structure-restores-remote-sync-state
(let [initial (setup/nested-component-with-copy)
updated (-> initial
(r/step (n/change-property :main2-nested-head :opacity 0.4)) r/settle
(r/step (n/update-main :main2-nested-head)) r/settle)]
(t/is (:remote-synced (tm/resolve-shape updated :main2-nested-head)))
(doseq [op [(n/remove-child :main1-child) (n/add-child :main1-root :added-child)]]
(let [changed (-> updated (r/step op) r/settle)
undone (r/step changed (n/undo))
redone (r/step undone (n/redo))]
(t/is (true? (= (thn/normalize-file (tm/file updated)) (thn/normalize-file (tm/file undone)))))
(t/is (true? (= (thn/normalize-file (tm/file changed)) (thn/normalize-file (tm/file redone)))))))))
(def ^:private original setup/labeled-fill)
(def ^:private red "#ff0000")
(def ^:private green "#00ff00")