mirror of
https://github.com/penpot/penpot.git
synced 2026-10-30 14:30:37 +00:00
🐛 Bound component sync retries per component
Count repeated processing of each component instead of total graph width. A valid dependency graph with 102 outer components now settles and updates every copy (F108). The non-settling cascade guard remains bounded. The regression failed at 100 passes before the fix, then passed with 103 components. Common JVM/JS, frontend, backend and exporter suites pass. Benchmark vs Phase 1e (lower quantile, ms): world baseline now ratio main-10 1.790 0.993 0.55 main-100 15.415 9.038 0.59 main-1000 153.086 90.145 0.59 three-levels 35.215 18.989 0.54 chain 68.931 35.045 0.51 library-500 83.083 85.830 1.03 many-shapes 4.837 3.344 0.69 variant-100 32.052 33.586 1.05 All worlds pass the 10% regression threshold. AI-assisted-by: GPT-6
This commit is contained in:
parent
c1f10147ab
commit
6002ca5274
@ -1431,7 +1431,7 @@
|
||||
(maybe-sync sync-typographies? done? #(generate-sync-file % file-id :typographies asset-id library-id libraries current-file-id early-return?))))))
|
||||
|
||||
|
||||
;; A guard against a sync cascade that never settles.
|
||||
;; Bound repeated processing of a component, not the width of the graph.
|
||||
(def ^:private max-sync-passes 100)
|
||||
|
||||
(defn changed-components
|
||||
@ -1449,16 +1449,17 @@
|
||||
`{:changes :data :component-ids :passes}`, with `component-ids` the
|
||||
components synced."
|
||||
[changes data file-id pending libraries current-file-id passes]
|
||||
(loop [changes changes
|
||||
data data
|
||||
pending (vec pending)
|
||||
synced #{}
|
||||
passes passes]
|
||||
(loop [changes changes
|
||||
data data
|
||||
pending (vec pending)
|
||||
synced #{}
|
||||
attempts {}
|
||||
passes passes]
|
||||
(cond
|
||||
(empty? pending)
|
||||
{:changes changes :data data :component-ids synced :passes passes}
|
||||
|
||||
(>= passes max-sync-passes)
|
||||
(>= (get attempts (first pending) 0) max-sync-passes)
|
||||
(throw (ex-info "Component sync did not settle"
|
||||
{:type ::sync-not-settled
|
||||
:pending pending
|
||||
@ -1482,6 +1483,7 @@
|
||||
data'
|
||||
(into (subvec pending 1) more)
|
||||
(conj synced component-id)
|
||||
(update attempts component-id (fnil inc 0))
|
||||
(inc passes))))))
|
||||
|
||||
(defn generate-sync-components-cascade
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
(:require
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.logic.instances :as cli]
|
||||
[app.common.logic.libraries :as cll]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.test-helpers.components :as thc]
|
||||
[app.common.test-helpers.compositions :as tho]
|
||||
@ -19,6 +20,30 @@
|
||||
|
||||
(t/use-fixtures :each thi/test-fixture)
|
||||
|
||||
(t/deftest a-wide-component-cascade-settles
|
||||
(let [labels (mapv #(keyword (str "outer-" %)) (range 102))
|
||||
file (reduce (fn [file label]
|
||||
(let [root (keyword (str (name label) "-main"))
|
||||
head (keyword (str (name label) "-nested"))
|
||||
copy (keyword (str (name label) "-copy"))]
|
||||
(-> file
|
||||
(tho/add-frame root)
|
||||
(thc/instantiate-component :inner head :parent-label root)
|
||||
(thc/make-component label root)
|
||||
(thc/instantiate-component label copy))))
|
||||
(-> (thf/sample-file :file1)
|
||||
(tho/add-simple-component :inner :inner-main :inner-child))
|
||||
labels)
|
||||
file (ths/update-shape file :inner-child :fills
|
||||
(ths/sample-fills-color :fill-color "#FF0000"))
|
||||
result (cll/generate-sync-components-cascade
|
||||
(pcb/empty-changes) (:id file) #{(thi/id :inner)}
|
||||
{(:id file) file} (:id file))
|
||||
synced (thf/apply-changes file (:changes result))]
|
||||
(t/is (= 103 (count (:component-ids result))))
|
||||
(doseq [label labels]
|
||||
(t/is (= "#FF0000" (tho/bottom-fill-color synced (keyword (str (name label) "-copy"))))))))
|
||||
|
||||
(defn- first-fill-color [file tag]
|
||||
(-> (ths/get-shape file tag)
|
||||
(:fills)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user