Record the applied transforms in GraphMeta

Ingestion is a partial port, so a graph this backend writes has had only
some of the pipeline applied. Rather than have a reader infer which from
a build version, the build writes it down: `GraphMeta.transforms` names
every transform id applied, projection-time denormalizations included,
and the parity consumer computes the complement and runs only that.

The ids cross a language boundary as data, so they are kebab-case
strings rather than keywords and must stay byte-identical to the
consumer's own list.

This stays off `graph-backend`. Nothing in this repository reads the
column, and an unread column is weight a reviewer is right to question.

AI-assisted-by: mixed models
This commit is contained in:
Álvaro Tejero Cantero 2026-08-07 01:43:21 +02:00
parent 13229dd94e
commit 6bd1af4f4a
No known key found for this signature in database
2 changed files with 43 additions and 7 deletions

View File

@ -59,9 +59,11 @@
(graph.arrow/load-projection! conn {:nodes nodes :edges edges} allocator)
(ladybug/exec-on-connection! conn ["CHECKPOINT;"])
(let [transforms (projection.transforms/apply-transforms! system conn data file)]
;; Written last: its presence doubles as the build-complete marker.
(graph.meta/write! conn {:file-id file-id
:revn (:revn file)})
;; Written last: its presence doubles as the build-complete marker,
;; and it is what the parity consumer reads to know what is left.
(graph.meta/write! conn {:file-id file-id
:revn (:revn file)
:transform-ids (:ids transforms)})
{:file-id file-id
:revn (:revn file)
:name (or (:name data) (:name file))

View File

@ -5,13 +5,20 @@
;; Copyright (c) KALEIDOS INC Sucursal en España SL
(ns app.graph.meta
"`GraphMeta`: the graph's own account of who built it and from what.
"`GraphMeta`: the graph's own account of who built it, from what, and what
it did.
A projected graph is a cache of a file at a revision, built by a known
schema. The row records both, so a reader can decide whether to reuse the
database or rebuild it: a `schema_version` that no longer matches the
registry, or a `source_revn` behind the file's, means the cache is stale.
Ingestion is a partial port, so a graph can arrive with any subset of the
pipeline applied. `transforms` names what this build did, and the parity
consumer computes the complement and runs only that in Python. The ids cross
a language boundary as data, so they are kebab-case strings rather than
keywords and must stay byte-identical to the consumer's own list.
The row is written *last* in a build, so its presence also marks the build
complete.
@ -21,7 +28,8 @@
(:require
[app.common.time :as ct]
[app.graph.ladybug :as ladybug]
[app.graph.schema.nodes :as nodes])
[app.graph.schema.nodes :as nodes]
[clojure.string :as str])
(:import
com.ladybugdb.Connection))
@ -41,12 +49,37 @@
"`producer_version` STRING, "
"`schema_version` STRING, "
"`source_revn` INT64, "
"`transforms` STRING[], "
"`built_at` TIMESTAMP, "
"PRIMARY KEY (`source_file_id`));"))
(def projection-transforms
"Transform ids this backend satisfies while *projecting*, before any
transform pass runs.
A reader cares whether the result is in the graph, not how it got there. The
consumer derives `IsChildOf` from persisted `shapes` arrays in a later pass;
`app.graph.project.document/project-shape-ids` emits the edges during the
tree walk. Same id, same observable graph. The two denormalizations are the
same case."
["add-document"
"link-contained-shapes"
"denormalize-page-id"
"denormalize-component-id"])
(defn- format-transforms
[ids]
(str "[" (->> (sort (distinct ids))
(map ladybug/format-string)
(str/join ", "))
"]"))
(defn write!
"Record what this build produced for `file-id`."
[^Connection conn {:keys [file-id revn]}]
"Record what this build produced for `file-id`.
`transform-ids` are the ids applied *on top of* `projection-transforms`, so
a caller only names what its transform pass did."
[^Connection conn {:keys [file-id revn transform-ids]}]
(ladybug/exec-on-connection! conn [ddl])
(ladybug/exec-on-connection!
conn
@ -55,5 +88,6 @@
"m.producer_version = " (ladybug/format-string (or (System/getenv "PENPOT_BUILD") "devenv")) ", "
"m.schema_version = " (ladybug/format-string nodes/schema-version) ", "
"m.source_revn = " (ladybug/format-int (or revn 0)) ", "
"m.transforms = " (format-transforms (concat projection-transforms transform-ids)) ", "
"m.built_at = " (ladybug/format-timestamp (ct/now)) ";")]))