Skip to content
This repository was archived by the owner on Oct 20, 2026. It is now read-only.

Keep the faces a bake gives the document; give them back on open (ADR 414, 0.1.0-canary.17) - #7

Merged
drietsch merged 2 commits into
mainfrom
fix/document-faces-on-open
Oct 16, 2026
Merged

drietsch merged 2 commits into
mainfrom
fix/document-faces-on-open

Conversation

@drietsch

Copy link
Copy Markdown
Contributor

Why

paged-media/plugin-sdk#17 (ADR 330) makes a document face live as long as the document it was given to. On an older host it lives for the engine session. Either way the face is never saved with the document, but the baked text that names it is. paged.web gave its faces only when it baked, never when a document opened. So with the editor change paged-media/editor#45, every reopen shows baked text as missing and draws it in a substitute, including a reopen in the same session. Before, that only happened in a new session.

Design: keep a record, don't work the faces out again

Working the faces out again from what the document keeps (the source's @font-face rules, the engine's bundled face) is not correct:

  • Without a record, the plugin cannot tell its own baked text from other text that names the same family. It would give the bundled Inter to a document whose own Inter is missing.
  • Once the web frame is deleted after the bake, which is a common way to flatten, its source is gone. The source was the only thing that said which face the text was set in. A data: face is lost with it, and the source part is dropped on the next save (ADR 410).
  • It would also load the roughly 10 MB engine on every open of a document that only holds baked text.

A record is correct in all of these cases and needs no engine to give the faces back. It costs the face bytes in the document. The bundled Inter is about 0.9 MB, kept once per document.

What

  • Once the bake has applied, it keeps each face it gave in a content-addressed part faces/<hash>.json, containing { v, family, style, face } with the bytes in base64. The part is never overwritten and is written only once.
  • Each time a document opens, and at activation, the faces its text names and lacks (according to the Fonts collection) are given back through the same door. There is no re-bake, and no part is read when nothing is kept or missing. A face the document refuses is reported as a problem under media.paged.web#faces.
  • The source-part collector (ADR 410) drops a kept face that no text names on save, for example after an undone bake or once the baked text is deleted.
  • Docs: ADR 414, an amendment to ADR 411, status and architecture.

A merge publishes @paged-media/web@0.1.0-canary.17. publish.yml runs on main after the rust workflow, and package-hash --check reports the version as not yet published. The peer range stays >=0.2.55-canary.0: the bundle works with assets.documentFont@1 and @2.

Tests

test/conformance/baked-faces-reopen.spec.ts was committed first (fa1c303) and fails on main, 3 of 3. It uses the real engine and opens the saved .paged in a new session (a fresh headless host):

  1. The bundled face of a baked run comes back without a re-bake.
  2. An @font-face face comes back after the web frame and its source are deleted.
  3. After an undone bake, a face no text names is not given back, and its record is dropped on the next save.

Local results with REQUIRE_REAL_ENGINE=1: web-bundle 339/339, web-model 290, web-conformance 103. Typecheck, contract-import lint and package-hash --check pass.

Merge order

This PR, then plugin-sdk#17, then plugin-slide#3, then editor#45. The editor's pin bump to web 0.1.0-canary.17 joins #45, which stays a draft until the SDK and web canaries exist.

🤖 Generated with Claude Code

drietsch and others added 2 commits October 15, 2026 13:26
A document face lives as long as the document it was given to (plugin SDK
ADR 330; on an older host, the engine session) and is never saved with it,
while the baked text naming it is. paged.web gives its faces only when it
bakes, so a reopened document draws its baked text in a substitute and
reports the family missing.

Against the real host and engine, opening the saved .paged in a new
session: the bundled face of a baked run comes back without a re-bake; an
@font-face face comes back after the web frame and its source are deleted;
a face no text names after an undone bake is not given back, and its record
is dropped on the next save. All three fail on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on open; 0.1.0-canary.17

A face given through the document-face door lives as long as the document
(plugin SDK ADR 330) and is not saved with it; the baked text naming it is.
Working the faces out again on open is not correct: without a record the
plugin cannot tell its baked text from other text naming the same family
(it would give the bundled Inter to a document whose own Inter is missing),
and once the web frame is deleted after the bake its source, the only thing
naming an @font-face face, is gone.

So the bake keeps each face it gave, once the bake applied, in a
content-addressed part faces/<hash>.json ({ v, family, style, face } with
the bytes in base64; never overwritten, written once). Each time a document
opens, and at activation, the faces its text names and lacks (the Fonts
collection) are given back through the same door: no engine, no re-bake,
and no part read when nothing is kept or missing. A face the document
refuses is a problem under media.paged.web#faces. The source-part collector
drops a kept face no text names on save (after an undone bake, or deleted
text), as it drops unreachable sources.

ADR 414, an amendment to ADR 411, status and architecture.
@paged-media/web 0.1.0-canary.17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@drietsch
drietsch merged commit 35a5308 into main Oct 16, 2026
3 of 4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant