🐛 Find the user duplicate after component propagation

Duplicating a nested copy in a main also adds subtrees to that main's
copies. The frontend result lookup counted all of them and threw instead
of returning the user's duplicate. Exclude roots inside component copies.

The regression checks the lookup after the sync cascade creates three
subtrees. Focused common suites pass: 66 tests, 11263 assertions.

AI-assisted-by: GPT-6
This commit is contained in:
alonso.torres 2026-10-23 09:23:09 +02:00
parent d14cd01374
commit 418a060ce4
2 changed files with 18 additions and 3 deletions

View File

@ -965,13 +965,15 @@
(defn- new-subtree-head
"The id of the shape in `page-after` that is not in `page-before` but whose
parent is: the head of the one subtree added between them. Throws when
there is not exactly one, as when the sync also added children to copies."
parent is, outside component copies. Sync can add matching subtrees in
copies too; only the user's new subtree identifies the duplicate."
[page-before page-after]
(let [before (:objects page-before)
heads (->> (vals (:objects page-after))
(filter #(and (not (contains? before (:id %)))
(contains? before (:parent-id %))))
(contains? before (:parent-id %))
(empty? (ctn/get-parent-copy-heads (:objects page-after)
(get-in page-after [:objects (:parent-id %)])))))
(map :id))]
(when-not (= 1 (count heads))
(throw (ex-info (str "Expected one new subtree, found " (count heads))

View File

@ -569,3 +569,16 @@
(t/is false)
(reset! counted @made))))
(t/is (= 2 @counted))))
(t/deftest duplicate-result-finds-the-user-subtree-after-propagation
(let [before (r/run-variant
{:setup setup/empty-situation
:operation (tm/in-sequence [(n/create-component "a" original :size 100)
(n/make-nested-component "a" 1)
(n/instantiate-copy "a")
(n/instantiate-copy "a")])})
duplicate (n/duplicate (n/nested-head-of "a" 0))
after (r/settle (r/step before duplicate))
result (n/applied-result duplicate (tm/file before) (tm/file after))
new-head (tm/shape-by-id after (:new-head result))]
(t/is (= ((n/main-head-of "a") before) (:parent-id new-head)))))