Skip to content

feat: publish a rendered tree per definition schema - #32

Merged
geodro merged 5 commits into
mainfrom
feat/schema-render
Sep 20, 2026
Merged

geodro merged 5 commits into
mainfrom
feat/schema-render

Conversation

@geodro

@geodro geodro commented Sep 20, 2026

Copy link
Copy Markdown
Member

A definition here reaches every install within a day whatever version of lerd is running, and the path it arrives on is one the binary computes for itself. A binary already in the field cannot be taught a new one, so the unprefixed path has to keep meaning what those binaries expect, and anything a newer lerd understands has to reach it some other way. That is the gap this closes.

Definitions are authored once under sources/ in the newest schema. A schema file states only what changed since the one before it and how to render a document back down, and CI publishes a tree for each: the unprefixed path is schema 1, which is what everything up to 1.35.0 fetches, and schema/2/ is what 1.36.0 and later fetch.

Most of the schema 2 delta is keys an older binary ignores anyway, so rendering them away only makes the published tree mean what it says. One is not cosmetic, and it is the reason for the whole thing. Schema 2 serves a dashboard through a proxy at /_svc// that deletes the upstream's X-Frame-Options and strips frame-ancestors from its CSP. Schema 1 has no such proxy and opens the dashboard URL directly in an iframe, so an upstream that refuses framing, which is every upstream that needs the strip flag, renders a blocked panel. A dashboard that only works behind the proxy is therefore dropped when rendering down, and a 1.35 install gets a service that runs and serves its port with no dashboard card, rather than one that looks broken.

Checked against the solr preset, which is the case that prompted this: rendered to schema 1 it carries no dashboard, rendered to schema 2 it carries the dashboard and the strip flag. The render is semantically lossless for every source, and of the presets published today only four differ for schema 1, each losing only keys 1.35.0 never had a field for.

The guard learned to tell a rendered removal from a real one, and still fails a genuine one. A second job fails a pull request whose published trees have drifted from the sources.

The binary half is lerd-env/lerd#1912, which asks for its own schema first and falls back to the unprefixed path, so these can merge in either order.

A definition here reaches every install within a day whatever version of lerd is running, and the path it arrives on is one the binary computes for itself. A binary already in the field cannot be taught a new one, so the unprefixed path has to keep meaning what those binaries expect, and anything a newer lerd understands has to reach it some other way.

Definitions are now authored once under sources/ in the newest schema. A schema file states only what changed since the one before it and how to render a document back down, and CI publishes a tree for each: the unprefixed path is schema 1, read by everything up to 1.35.0, and schema/2/ is read by 1.36.0 and later.

Most of the delta is keys an older binary ignores anyway, so rendering them away only makes the published tree mean what it says. One is not cosmetic. Schema 2 serves a dashboard through a proxy that strips the upstream's framing headers, and schema 1 opens the dashboard URL directly in an iframe, so a UI that refuses framing renders a blocked panel. A dashboard that only works behind that proxy is therefore dropped when rendering to schema 1, and the service installs and serves its port with no dashboard card rather than a dead one.

The guard learned to tell a rendered removal from a real one, and a second job fails a pull request whose published trees no longer match the sources.
Every definition rendered the same in both trees was being stored in both, with each icon stored twice more on top. The client tries its bases in order and a 404 falls straight through without a retry, so a definition a schema does not change can simply be absent from that schema's tree and be served from the one below it.

A schema above the oldest now carries only the definitions whose render differs, plus its own complete index, since the index is one file and has to list everything. Icons are schema independent and live in the legacy tree alone. Four of twenty seven presets differ today, so the second tree is five files rather than forty three.
…blished

Making the legacy tree an artifact meant rewriting all of it, and re-serialising a definition strips the comments explaining it and makes every install re-download a file whose meaning never moved.

A definition whose downgrade changes nothing is now copied from its source byte for byte, so only the four presets that actually lose a schema 2 key are rewritten, and the rest keep the bytes they were published with.
Every preset was being authored under sources/ and copied into the published tree, so twenty three of twenty seven existed twice for no reason: their two schemas render the same.

A definition now lives in services/ and is published as it stands. It gains a source only when a key a newer lerd reads would be wrong to publish to an older one, and then the source is the one authored copy and both trees are rendered from it. Four presets qualify today.

The index is treated the same way. It is hand maintained and does not always match a projection of the YAML, so regenerating it wholesale would push those differences out as a change nobody asked for. Only the entries a render owns are rewritten.
A source directory held the full fidelity copy of every diverging definition, and the schema 2 tree held the same document again. The two were the same file, one of them formatted by the renderer.

There is one authored copy now, and it lives in the highest schema tree the definition needs: services/ for one needing nothing newer, schema/N/services/ for one carrying a key that would be wrong to publish to an older binary. Every tree below renders down from it, so the same document is never stored twice.
@geodro
geodro merged commit d1e7585 into main Sep 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant