68 lines
2.9 KiB
Markdown
68 lines
2.9 KiB
Markdown
# ADR-0001 — Render what you will save
|
|
|
|
* **Status**: Accepted
|
|
* **Date**: 2025-07-25
|
|
* **Plan reference**: §2.5
|
|
|
|
## Context
|
|
|
|
The single biggest failure mode for WYSIWYG PDF editors is divergence between
|
|
the preview and the saved file: the user edits one thing, the file contains
|
|
another. Overlay-style editors avoid this by not really editing — they cover
|
|
old text with a white rectangle and draw new text on top, producing files that
|
|
look right and are broken for search, copy-paste, accessibility, and
|
|
redaction. We chose full content editing (§1.1), so we own an interpreter and
|
|
an emitter, and divergence is a structural risk.
|
|
|
|
The decision must be made before any rendering or editing code lands because
|
|
it shapes the whole pipeline: every edit's effect on the saved bytes must be
|
|
computable, and the rasterizer must render the *saved* bytes, not a model
|
|
projection.
|
|
|
|
## Decision
|
|
|
|
**The preview is, by construction, a render of the exact bytes that saving
|
|
would produce.** Concretely:
|
|
|
|
1. Every edit mutates the semantic model (L5).
|
|
2. The dirty page's content stream is re-emitted immediately into an
|
|
in-memory buffer (§4.4).
|
|
3. The rasterizer renders *that buffer*, not the model.
|
|
|
|
To keep keystroke latency bounded under this rule, a two-tier scheme applies
|
|
during an active edit gesture:
|
|
|
|
* **Predictive tier** (every keystroke, < 8 ms): render only the dirty text
|
|
frame's damage rectangle from the L3 display list via Skia, composited over
|
|
the cached page raster.
|
|
* **Authoritative tier** (on 120 ms idle, on gesture end, and always before
|
|
save): re-emit and re-render through PDFium, then diff against the
|
|
predictive tier. A mismatch above threshold repaints and logs a fidelity
|
|
event.
|
|
|
|
Nothing is ever *saved* that has not been rendered from its own bytes.
|
|
|
|
## Consequences
|
|
|
|
**Positive.** The preview and the saved file cannot diverge by construction.
|
|
The predictive-vs-authoritative diff gives a continuous, free, in-production
|
|
consistency check between our interpreter and PDFium's — exactly the
|
|
divergence we are most exposed to (§11).
|
|
|
|
**Negative.** Re-emission must be fast (< 5 ms for a typical page) which
|
|
drives the surgical (not full-rebuild) design of ADR-0002. The predictive
|
|
tier requires a first-class Skia display-list renderer, which is real ongoing
|
|
cost — it is a tracked metric with a budget, not a debugging toy.
|
|
|
|
**Neutral.** Fidelity events (§2.5, §4.3, §4.4) are recorded locally and
|
|
visible in the fidelity panel; they are only transmitted if the user
|
|
explicitly submits a diagnostic bundle.
|
|
|
|
## Alternatives considered
|
|
|
|
* **Overlay editing** — rejected; produces files that are broken for search,
|
|
copy-paste, accessibility, and redaction (§1.1).
|
|
* **Model-driven rendering (render the L5 model directly, save separately)**
|
|
— rejected; reintroduces divergence as the model and the emitter can drift.
|
|
* **Re-render through PDFium on every keystroke** — rejected for latency on
|
|
dense pages; kept as the authoritative tier only. |