From d9ef6eb78990aed192821609a175d707dfb32310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Tejero=20Cantero?= Date: Tue, 6 Oct 2026 21:45:41 +0200 Subject: [PATCH] :recycle: Rename app.graph.overlay to app.graph.relation-overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The holder vocabulary names a graph by scope and a holder by location, scope, and form, so the overlay namespace takes the holder's name: app.graph.relation-overlay, with its console, queries, and sync children. Aliases keep their short forms. schema-version keeps its "penpot-graph-overlay-2" literal: it is a storage version, and renaming it would rekey stored artefacts without a schema change. AI-assisted-by: glm-5.3-flash Signed-off-by: Álvaro Tejero Cantero --- backend/deps.edn | 2 +- backend/src/app/graph/debug.clj | 26 +++++++++---------- .../{overlay.clj => relation_overlay.clj} | 12 ++++----- .../{overlay => relation_overlay}/console.clj | 6 ++--- .../{overlay => relation_overlay}/queries.clj | 4 +-- .../{overlay => relation_overlay}/sync.clj | 18 ++++++------- .../graph_overlay_console_test.clj | 8 +++--- .../backend_tests/graph_overlay_sync_test.clj | 22 ++++++++-------- .../test/backend_tests/graph_overlay_test.clj | 12 ++++----- common/src/app/common/files/changes.cljc | 2 +- 10 files changed, 56 insertions(+), 56 deletions(-) rename backend/src/app/graph/{overlay.clj => relation_overlay.clj} (98%) rename backend/src/app/graph/{overlay => relation_overlay}/console.clj (96%) rename backend/src/app/graph/{overlay => relation_overlay}/queries.clj (99%) rename backend/src/app/graph/{overlay => relation_overlay}/sync.clj (99%) diff --git a/backend/deps.edn b/backend/deps.edn index 1a3e09758d..5d0595c9ef 100644 --- a/backend/deps.edn +++ b/backend/deps.edn @@ -71,7 +71,7 @@ ;; Required by Arrow RootAllocator (lbug only pulls arrow-memory-core). org.apache.arrow/arrow-memory-netty {:mvn/version "19.0.0"} - ;; graph-overlay: datascript index over the document, replacing the Cypher + ;; relation-overlay: datascript index over the document, replacing the Cypher ;; projection for per-file queries. See docs.local/graph roadmap. datascript/datascript {:mvn/version "1.8.1"}} diff --git a/backend/src/app/graph/debug.clj b/backend/src/app/graph/debug.clj index c42a045a33..f5c27ef1d9 100644 --- a/backend/src/app/graph/debug.clj +++ b/backend/src/app/graph/debug.clj @@ -8,9 +8,9 @@ "In-memory overlay sessions for the debug graph console. A session is a datascript overlay of one file - (`app.graph.overlay`), maintained from the msgbus file-change feed by - `app.graph.overlay.sync` and queried in Datalog through - `app.graph.overlay.console`. The Ladybug engine no longer appears on + (`app.graph.relation-overlay`), maintained from the msgbus file-change feed by + `app.graph.relation-overlay.sync` and queried in Datalog through + `app.graph.relation-overlay.console`. The Ladybug engine no longer appears on this path: it keeps the batch-export tier (`app.graph.ingest`), where columnar output is the point. The overlay is immutable data in an atom, so readers never lock and the sync loop is the only writer." @@ -20,10 +20,10 @@ [app.common.logging :as l] [app.common.time :as ct] [app.db :as db] - [app.graph.overlay :as overlay] - [app.graph.overlay.console :as console] - [app.graph.overlay.queries :as queries] - [app.graph.overlay.sync :as overlay.sync] + [app.graph.relation-overlay :as overlay] + [app.graph.relation-overlay.console :as console] + [app.graph.relation-overlay.queries :as queries] + [app.graph.relation-overlay.sync :as overlay.sync] [app.msgbus :as mbus] [app.srepl.helpers :as h] [clojure.string :as str] @@ -37,7 +37,7 @@ The `filter_*` columns carry node ids for the graph-view result filter; the results table hides them (see `hide-filter-columns` and the template's `renderQueryOutput`). `$` is bound to the overlay and `%` to - the shared rule set of `app.graph.overlay.queries`." + the shared rule set of `app.graph.relation-overlay.queries`." (str "[:find ?component ?instance ?page\n" " ?filter_src_id ?filter_tgt_id\n" " :in $ %\n" @@ -84,7 +84,7 @@ (defn- mark-stale "Record a staleness verdict in a session's sync state, once. - Every verdict `app.graph.overlay.sync/staleness` returns is a permanent + Every verdict `app.graph.relation-overlay.sync/staleness` returns is a permanent divergence: the index has folded a state no rebuild produces, and the batches after it fold onto that state. So a later clean batch must not erase the mark, and only `load-session!` clears it, by building fresh @@ -162,7 +162,7 @@ (if-let [msgbus (:msgbus session)] ;; A dropping buffer is the silence this subsystem cannot see: a full ;; buffer discards a message with no log line and no revision change. - ;; `app.graph.overlay.sync/staleness` catches it one message later, + ;; `app.graph.relation-overlay.sync/staleness` catches it one message later, ;; because the next message's revision is then two beyond the ;; index's, and the read gates refuse until a reload rebuilds. (let [sync-ch (sp/chan :buf (sp/dropping-buffer 64))] @@ -193,7 +193,7 @@ (defn sync-status "Return incremental sync status for the active session. - `:stale` is the verdict `app.graph.overlay.sync/staleness` returned for + `:stale` is the verdict `app.graph.relation-overlay.sync/staleness` returned for the batch that broke the index, nil while the index still equals a rebuild, and `:reason` names which of the three cases it was. The two revisions are reported beside it and neither is the gate: `:revn` is @@ -268,7 +268,7 @@ (defn- check-fresh! "Refuse a read from an index that has fallen behind. - The mark is `app.graph.overlay.sync/staleness`'s verdict, recorded by + The mark is `app.graph.relation-overlay.sync/staleness`'s verdict, recorded by `apply-file-change!`, and a reload clears it by rebuilding (`load-session!`). This refusal is what makes partial change-type coverage a performance property rather than a correctness one: a @@ -286,7 +286,7 @@ "Run a Datalog `statement` against the overlay for `profile-id`. Read-only by construction (`d/q` cannot transact), gated against - function smuggling by `app.graph.overlay.console/check-query!`, and + function smuggling by `app.graph.relation-overlay.console/check-query!`, and gated against a stale index by `check-fresh!`." [profile-id statement] (when (or (nil? statement) (= "" statement)) diff --git a/backend/src/app/graph/overlay.clj b/backend/src/app/graph/relation_overlay.clj similarity index 98% rename from backend/src/app/graph/overlay.clj rename to backend/src/app/graph/relation_overlay.clj index 2c860daaa9..f50a3f919e 100644 --- a/backend/src/app/graph/overlay.clj +++ b/backend/src/app/graph/relation_overlay.clj @@ -4,7 +4,7 @@ ;; ;; Copyright (c) KALEIDOS INC Sucursal en España SL -(ns app.graph.overlay +(ns app.graph.relation-overlay "Datascript index over a Penpot document: identity, type, and topology. The overlay is an index over what Penpot's helpers read, never a @@ -40,7 +40,7 @@ - **Token applications fold the property into the attribute name**: `{:token/fill \"layerTwo.background\"}` on the shape itself, over the closed vocabulary of `app.common.types.token/all-keys`. The - `uses-token` rule in `app.graph.overlay.queries` hides the encoding, + `uses-token` rule in `app.graph.relation-overlay.queries` hides the encoding, so the choice stays reversible. The namespace is deliberately JVM-free (no imports, no interop): the @@ -81,12 +81,12 @@ Color references are stored per source (`fill`, `stroke`, text content) rather than as one union, because the sync path receives `:set` ops one attribute at a time and must be able to rebuild each contribution - independently. The `uses-color` rule in `app.graph.overlay.queries` + independently. The `uses-color` rule in `app.graph.relation-overlay.queries` reunites them. Each source also keeps the raw id it resolved from, as a value rather than a ref: the id joins nothing until `build-asset-maps` finds the asset, and an asset the library does not hold yet leaves the id stored and the reference absent, which is the - state `app.graph.overlay.sync/apply-add-asset` repairs. Folded token + state `app.graph.relation-overlay.sync/apply-add-asset` repairs. Folded token attributes (`:token/fill`, ...) are plain string values and need no declaration." {;; document @@ -128,7 +128,7 @@ :shape/uses-typography {:db/valueType :db.type/ref :db/cardinality :db.cardinality/many} ;; the raw ids those four resolved from, one attribute per source, - ;; indexed because `app.graph.overlay.sync/apply-add-asset` reads the + ;; indexed because `app.graph.relation-overlay.sync/apply-add-asset` reads the ;; shapes waiting on an id :shape/fill-color-ref-id {:db/index true :db/cardinality :db.cardinality/many} @@ -311,7 +311,7 @@ The raw id is written whether or not the ctx resolves it. A shape that names an asset the library does not hold keeps the id and carries no - reference, which is what `app.graph.overlay.sync/apply-add-asset` reads + reference, which is what `app.graph.relation-overlay.sync/apply-add-asset` reads when the asset finally arrives; a reference is written only for an id the ctx resolves." [shape {:keys [colors typographies]}] diff --git a/backend/src/app/graph/overlay/console.clj b/backend/src/app/graph/relation_overlay/console.clj similarity index 96% rename from backend/src/app/graph/overlay/console.clj rename to backend/src/app/graph/relation_overlay/console.clj index 455df30e9b..1d6fc25741 100644 --- a/backend/src/app/graph/overlay/console.clj +++ b/backend/src/app/graph/relation_overlay/console.clj @@ -4,7 +4,7 @@ ;; ;; Copyright (c) KALEIDOS INC Sucursal en España SL -(ns app.graph.overlay.console +(ns app.graph.relation-overlay.console "Free-form Datalog for the debug graph console: parse, gate, run, format. @@ -21,7 +21,7 @@ binder's own courtesy: the error names the symbol." (:require [app.common.exceptions :as ex] - [app.graph.overlay.queries :as queries] + [app.graph.relation-overlay.queries :as queries] [clojure.edn :as edn] [datascript.built-ins :as bi] [datascript.core :as d])) @@ -137,7 +137,7 @@ "Parse, gate, and run `text` against overlay `db`. `$` is always supplied; `%` (the shared rule set of - `app.graph.overlay.queries`) is supplied when the query's :in asks for + `app.graph.relation-overlay.queries`) is supplied when the query's :in asks for it. Returns {:columns [...] :rows [...] :truncated? bool :row-count n} in the shape the console template renders." [db text] diff --git a/backend/src/app/graph/overlay/queries.clj b/backend/src/app/graph/relation_overlay/queries.clj similarity index 99% rename from backend/src/app/graph/overlay/queries.clj rename to backend/src/app/graph/relation_overlay/queries.clj index 25e107dfe3..d7e0414360 100644 --- a/backend/src/app/graph/overlay/queries.clj +++ b/backend/src/app/graph/relation_overlay/queries.clj @@ -4,7 +4,7 @@ ;; ;; Copyright (c) KALEIDOS INC Sucursal en España SL -(ns app.graph.overlay.queries +(ns app.graph.relation-overlay.queries "The relation vocabulary and the standing question set over the overlay. **The relation vocabulary is a rule set, not raw clauses** @@ -36,7 +36,7 @@ stays the oracle and is never reimplemented here." (:require [app.common.uuid :as uuid] - [app.graph.overlay :as overlay] + [app.graph.relation-overlay :as overlay] [datascript.core :as d])) (def rules diff --git a/backend/src/app/graph/overlay/sync.clj b/backend/src/app/graph/relation_overlay/sync.clj similarity index 99% rename from backend/src/app/graph/overlay/sync.clj rename to backend/src/app/graph/relation_overlay/sync.clj index c896445702..65d46d9f2b 100644 --- a/backend/src/app/graph/overlay/sync.clj +++ b/backend/src/app/graph/relation_overlay/sync.clj @@ -4,7 +4,7 @@ ;; ;; Copyright (c) KALEIDOS INC Sucursal en España SL -(ns app.graph.overlay.sync +(ns app.graph.relation-overlay.sync "Incremental overlay updates from Penpot change vectors. The invariant this namespace defends: an overlay maintained from change @@ -50,8 +50,8 @@ [app.common.types.page :as ctp] [app.common.types.tokens-lib :as ctob] [app.common.uuid :as uuid] - [app.graph.overlay :as overlay] - [app.graph.overlay.queries :as queries] + [app.graph.relation-overlay :as overlay] + [app.graph.relation-overlay.queries :as queries] [datascript.core :as d])) (def supported-change-types @@ -77,7 +77,7 @@ (some-> (first (d/datoms db :avet :document/id)) :e)) (defn- sync-asset-ctx - "The asset half of `app.graph.overlay`'s build-ctx, resolved against the + "The asset half of `app.graph.relation-overlay`'s build-ctx, resolved against the live db: values are eids rather than tempids." [db] {:colors (into {} (map (fn [dtm] [(:v dtm) (:e dtm)])) @@ -860,7 +860,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; library assets: colours and typographies ;; -;; The entity is the one `app.graph.overlay/build-tx` writes for a member +;; The entity is the one `app.graph.relation-overlay/build-tx` writes for a member ;; of `:colors` or `:typographies`: identity, the document ref, and the ;; name a standing query asks for. The value lives in the document, ;; which the holder of the overlay already has. @@ -952,7 +952,7 @@ of `ctyl/delete-typography`: both dissoc the asset from the library map and leave every referring shape alone. A rebuild therefore loses the asset entity *and* every resolved reference to it, because - `app.graph.overlay/build-asset-maps` only maps the ids the library + `app.graph.relation-overlay/build-asset-maps` only maps the ids the library still holds. One retraction produces exactly that. Datascript's @@ -971,7 +971,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; design tokens ;; -;; The entity shape is `app.graph.overlay/tokens-tx`'s: one entity per +;; The entity shape is `app.graph.relation-overlay/tokens-tx`'s: one entity per ;; token set (identity, name, document ref) and one per token (identity, ;; name, type, set ref). Values, themes and resolution stay in the lib, ;; which `app.common.types.tokens-lib` already answers. @@ -1016,7 +1016,7 @@ (defn- token-entities "Token entities of one set from a lib-shaped token map, in - `app.graph.overlay/tokens-tx`'s shape." + `app.graph.relation-overlay/tokens-tx`'s shape." [set-ref tokens] (into [] (map (fn [token] @@ -1082,7 +1082,7 @@ and token entity goes, and the incoming library's sets and tokens are written fresh. Nothing outside the pair points at them, because an applied token is folded onto the shape as a plain name - (`app.graph.overlay/token-attrs`), so no shape datom needs repair." + (`app.graph.relation-overlay/token-attrs`), so no shape datom needs repair." [db {:keys [tokens-lib]}] (let [old (-> (mapv (fn [dtm] [:db.fn/retractEntity (:e dtm)]) (d/datoms db :avet :token-set/id)) diff --git a/backend/test/backend_tests/graph_overlay_console_test.clj b/backend/test/backend_tests/graph_overlay_console_test.clj index a4187feceb..f14cb1561d 100644 --- a/backend/test/backend_tests/graph_overlay_console_test.clj +++ b/backend/test/backend_tests/graph_overlay_console_test.clj @@ -6,7 +6,7 @@ (ns backend-tests.graph-overlay-console-test "Pure tests over the console's parse-gate-run pipeline - (`app.graph.overlay.console/run-query`) and the default query it ships + (`app.graph.relation-overlay.console/run-query`) and the default query it ships (`app.graph.debug/default-query`). The gate exists so the console cannot run arbitrary Clojure; these @@ -21,8 +21,8 @@ [app.common.test-helpers.ids-map :as thi] [app.common.test-helpers.shapes :as ths] [app.graph.debug :as debug] - [app.graph.overlay :as overlay] - [app.graph.overlay.console :as console] + [app.graph.relation-overlay :as overlay] + [app.graph.relation-overlay.console :as console] [clojure.string :as str] [clojure.test :as t] [datascript.core :as d])) @@ -80,7 +80,7 @@ (t/deftest shared-rule-invocations-pass-the-gate ;; The gate's allowlist derives from `queries/rules` - ;; (`app.graph.overlay.console/check-query!`), so rule renames pass + ;; (`app.graph.relation-overlay.console/check-query!`), so rule renames pass ;; automatically: the default query proves `instance-of`, and these ;; hold the door open for `descendant-of` (with rows) and `uses-token` ;; (the fixture defines no tokens, so the gate acceptance is the diff --git a/backend/test/backend_tests/graph_overlay_sync_test.clj b/backend/test/backend_tests/graph_overlay_sync_test.clj index 14833b8367..ce78262a4f 100644 --- a/backend/test/backend_tests/graph_overlay_sync_test.clj +++ b/backend/test/backend_tests/graph_overlay_sync_test.clj @@ -8,8 +8,8 @@ "Cold build and incremental sync are two implementations of one mapping, and this namespace holds them to it. - `app.graph.overlay/build` projects a whole file into a fresh overlay. - `app.graph.overlay.sync/apply-changes` replays the change vocabulary the + `app.graph.relation-overlay/build` projects a whole file into a fresh overlay. + `app.graph.relation-overlay.sync/apply-changes` replays the change vocabulary the editor emits onto an overlay that is already open. The overlay the second one maintains must equal the overlay the first one would build from the changed document, or the console shows a graph no rebuild reproduces. @@ -31,9 +31,9 @@ [app.common.types.typography :as ctt] [app.common.uuid :as uuid] [app.graph.debug :as graph.debug] - [app.graph.overlay :as overlay] - [app.graph.overlay.queries :as queries] - [app.graph.overlay.sync :as sync] + [app.graph.relation-overlay :as overlay] + [app.graph.relation-overlay.queries :as queries] + [app.graph.relation-overlay.sync :as sync] [clojure.set :as set] [clojure.string :as str] [clojure.test :as t] @@ -135,7 +135,7 @@ an editing session would emit them, and every indexed attribute at least once: topology (add, reparent, reorder, delete a subtree), the `:mod-obj` set ops - with their asset refs (`app.graph.overlay.sync/set-attr-tx`), a touched + with their asset refs (`app.graph.relation-overlay.sync/set-attr-tx`), a touched swap slot on a shape inside a copy (`ctk/get-swap-slot`), a copy child's `:shape-ref` repointed at another main shape (the resolved `:shape/refers-to` must follow), the whole component lifecycle from add @@ -207,7 +207,7 @@ ;; the frame's children are sorted by the index each named id holds ;; here, and rect-id, which the change does not name, keeps the -1 key ;; and stays first. The sibling ordinals must follow that sort - ;; (`app.graph.overlay.sync/apply-reorder-children`). + ;; (`app.graph.relation-overlay.sync/apply-reorder-children`). {:type :reorder-children :page-id page-id :parent-id frame-id :shapes [circ-id rect2-id]} @@ -686,11 +686,11 @@ ;; The third filter, after the change types and the operations: the ;; attributes a shape entity carries. They do not have one writer each. An ;; operation writes `:shape/name` and its neighbours through -;; `app.graph.overlay.sync/set-attr-tx`, a structural pass writes +;; `app.graph.relation-overlay.sync/set-attr-tx`, a structural pass writes ;; `:shape/refers-to` (`reresolve-refs-tx`) and the sibling ordinal ;; (`order-tx`, which is also how the builder draws it), and the builder ;; writes the identity and topology edges and `:shape/type`. The comparison -;; asks whether every attribute `app.graph.overlay/schema` declares over +;; asks whether every attribute `app.graph.relation-overlay/schema` declares over ;; shape entities, plus the folded token vocabulary, has a writer, and ;; names its kind. An attribute nothing can write fails by name rather than passing ;; as derived, which is the failure mode the operation filter had before @@ -748,7 +748,7 @@ :shape/exit "the fold and the rebuild number the intervals differently; containment is the invariant"}) (defn- declared-shape-attrs - "The attributes `app.graph.overlay/schema` declares over shape entities, + "The attributes `app.graph.relation-overlay/schema` declares over shape entities, plus the folded token vocabulary that needs no declaration." [] (into (into #{} (filter (fn [attr] (= "shape" (namespace attr)))) (keys overlay/schema)) @@ -966,7 +966,7 @@ ;; The Euler-tour invariants hold on the synced db, not only on the ;; built one. The sync path renumbers a container from beyond the ;; global maximum with a different DFS order than the builder - ;; (`app.graph.overlay.sync/renumber-container-tx`), so interval + ;; (`app.graph.relation-overlay.sync/renumber-container-tx`), so interval ;; values are not comparable between the two paths — containment is. ;; Here: every shape of every container carries an interval, the ;; interval form answers the recursive walk exactly, and intervals are diff --git a/backend/test/backend_tests/graph_overlay_test.clj b/backend/test/backend_tests/graph_overlay_test.clj index 1b8cc28ef8..ea9c9a7d32 100644 --- a/backend/test/backend_tests/graph_overlay_test.clj +++ b/backend/test/backend_tests/graph_overlay_test.clj @@ -13,7 +13,7 @@ that is the correctness oracle. A backported assertion that disagrees with a helper is a beadpot bug: the helper's answer is asserted and the divergence is noted in the docstring. Beadpot's idempotency tests have - no port here: `app.graph.overlay/build` is a pure function of the + no port here: `app.graph.relation-overlay/build` is a pure function of the document, so linking twice cannot duplicate an edge by construction. The fixture is built exclusively with the common test helpers @@ -35,8 +35,8 @@ [app.common.types.text :as txt] [app.common.types.tokens-lib :as ctob] [app.common.uuid :as uuid] - [app.graph.overlay :as overlay] - [app.graph.overlay.queries :as queries] + [app.graph.relation-overlay :as overlay] + [app.graph.relation-overlay.queries :as queries] [clojure.test :as t] [datascript.built-ins :as bi] [datascript.core :as d])) @@ -89,7 +89,7 @@ (defn- oracle-containers "The builder's resolution containers, one per page plus one per component that carries its own `:objects` snapshot, as [ctn-container - container-id] pairs (`app.graph.overlay/ref-resolver`)." + container-id] pairs (`app.graph.relation-overlay/ref-resolver`)." [data] (concat (map (fn [[id page]] [(ctn/make-container page :page) id]) (:pages-index data)) @@ -520,7 +520,7 @@ ;; (1) the interval form answers the recursive form, and both equal ;; `cfh/get-children-ids` (the oracle) for every frame of every ;; container; (2) one global counter numbers every container - ;; (`app.graph.overlay/euler-numbering` threads it file-wide), so + ;; (`app.graph.relation-overlay/euler-numbering` threads it file-wide), so ;; [enter exit] intervals across the whole file are pairwise ;; disjoint-or-nested — a partial overlap is the signature of the ;; per-container-counter bug the 20260820 report guards against. @@ -742,7 +742,7 @@ (def ^:private control-symbols "Clause heads that structure a query rather than call a function, the - console gate's own list (`app.graph.overlay.console`)." + console gate's own list (`app.graph.relation-overlay.console`)." '#{not not-join or or-join and pull}) (def ^:private rule-names diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index d70cb3c845..29b45f408d 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -767,7 +767,7 @@ destination's chain up `:parent-id`, reading `:component-id` and `:shape-ref` off every shape it meets: a caller holding those four facts per shape can ask this without a document. It is public because - `app.graph.overlay.sync` is that caller, and the incremental overlay + `app.graph.relation-overlay.sync` is that caller, and the incremental overlay refuses a move the document refuses by asking this predicate rather than by answering the same question a second time." [objects shape-id parent-id {:keys [allow-altering-copies syncing]}]