build_wasm.ps1 built the `wasm` STUB preset (PDFENGINE_WITH_PDFIUM=OFF, reflow #ifdef'd out)
and deployed it to the UNUSED pdfengine.{mjs,wasm}. The frontend actually loads
pdfium-engine.{mjs,wasm} (the `wasm-pdfium` preset). So "rebuild the WASM" silently shipped a
reflow-less stub to the wrong file — engine changes never reached the browser.
- Build the `wasm-pdfium` preset (PDFium ON) into pdfeng-build/wasm-pdfium (outside OneDrive).
- Deploy bin/pdfengine.{mjs,wasm} -> public/pdfium-engine.{mjs,wasm} (the rename the frontend expects).
- Set EMSDK_QUIET before sourcing emsdk_env.ps1 (its stderr tripped $ErrorActionPreference='Stop').
- Run a new pdfium-engine.smoke.mjs (buildInfo + live-preview exports) instead of pdfengine.test.mjs,
which targets the stub facade (mock render / engineHasSkia / getDocumentFonts) and can't pass here.
- Relax EAP around the smoke node call so a real failure reports cleanly, not as NativeCommandError.
- pdfengine.test.mjs: de-brittle the buildInfo assertion (was pinned to a stale exact phrase).
Verified: scripts/build_wasm.ps1 runs green end-to-end and deploys pdfium-engine.wasm (md5 53d1ec9f).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The live-preview engine the frontend loads is pdfium-engine.wasm, built by the
`wasm-pdfium` CMake preset (PDFENGINE_WITH_PDFIUM=ON). The reflow code is inside
`#ifdef PDFENGINE_WITH_PDFIUM`, so the `wasm` stub preset (PDFium OFF) — which
scripts/build_wasm.ps1 builds and copies to the UNUSED pdfengine.wasm — never
contained reflow at all. Result: every prior "WASM rebuilt" step updated the wrong,
reflow-less artifact, so the caret x0 fix (and center/right) never reached the browser.
Rebuilt the wasm-pdfium preset and deployed bin/pdfengine.{mjs,wasm} ->
public/pdfium-engine.{mjs,wasm} (md5 now 53d1ec9f, reflow object 631KB vs the 18KB
stub). Bumped the cache-buster so browsers fetch the new engine.
Engine .pyd + overlay-diff gate unchanged (1.70%/1.69%, render identical); the x0
change is caret-only metadata.
Follow-up: build_wasm.ps1 builds the wrong (stub) preset and deploys the wrong file.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The reflow caret layout hardcoded x0 = columnLeft. That matched only left-aligned
lines; for the new center/right headings the line renders at a shifted x (e.g. a
centered title starts ~215pt while columnLeft is the page margin ~54pt), so the
frontend mapped clicks and drew the caret ~160pt off the actual glyphs.
Record the line's true starting x (after lineX/center/right) as x0 instead. x0 is
caret-only metadata read by the live editor — it does not affect glyph emission or
the rendered page, so output is unchanged (overlay-diff gate identical: 1.70%/1.69%,
STRESS PASS). Rebuilt .pyd + WASM; cache version bumped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reflow (primary editor):
- Geometric backstop in reflow_paragraph: adopt any text object fully inside the paragraph
bbox that the model's objectIndices omitted (PDFium glyph->object map can return -1), so it's
deleted + its original font is resolved. Fixes both the leftover-glyph "bulge/merge" and the
font-substitution-on-edit (same root cause). No-op on correctly-indexed paragraphs (gate-proven
byte-identical: overlay diff unchanged at 1.69%/1.70%).
- Preserve data-fid on edited contentEditable nodes (extractFlatRuns climbs to nearest styled
ancestor / inherits from adjacent run) so edits keep their real font instead of the dominant.
- Converge preview & commit through one buildReflowData (no preview-OK/commit-wrong drift).
- Center/right alignment: additive emission branch (greedy path only) + heading-align inference.
- IME composition handling (suppress render mid-composition; don't commit on composing Enter).
- Fix WASM document-handle leak (free superseded versions on documentId change/unmount).
- Quiet the backstop instrumentation (warn -> debug) now the root cause is confirmed.
Raw Text / StreamEditor (beta companion):
- Permission-gate both text_objects endpoints behind canModify; label tool "(beta)".
- P1a: preserve TJ kerning numbers for same-length edits (redistribute into original slots),
fall back to single-string collapse otherwise (never worse than before).
- P1b: reject edits with characters unencodable in the run's font (clear 400 instead of corruption).
- P2a: commit Raw Text edits as a new document version (add_document) and adopt the id via
pushHistory, so they join undo/redo instead of mutating in place.
- P2b: exact hit-boxes from real font metrics (re-measured once @font-face loads).
WASM preview rebuilt with the reflow changes; cache version bumped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>