Review army (6 specialists + red team) findings, all fixed: - Indented fences replay byte-for-byte and indented diagram fences are NOT extracted (red-team conf-9: the pre-pass reconstructed fences at column 0, splitting any list containing fenced code — every ordinary document). - String.replace $-pattern injection killed at every seam: substituteSlots, mergeStyle, img/src rewrites all use function replacements (a diagram label containing $' duplicated the document tail). - Big-expression transport reworked: browse `eval <file>` (one spawn, any size, Windows-safe) replaces the 64KB chunked window-buffer eval — fixes the per-chunk spawn cost, the char-vs-byte argv units, AND the Windows 32,767-char command-line ceiling in one move. - Staged-bundle trust: content verified by hash even when the file exists, and the rename-failure path re-hashes the survivor (sticky-bit /tmp EPERM would otherwise ride a pre-planted file past the check). - Windows drive-letter img srcs (C:/x.png) reach the local-path branch instead of being swallowed as unknown URL schemes. - DOCX rasterize-failure now embeds the decoded source as visible text — returning the figure made diagrams vanish silently (converter drops svg). - Fence source preserved as base64 data-gstack-source attribute (the comment encoding corrupted every '-->' arrow); decodeFigureSource() round-trips. - inlineLocalImages memoizes per path; file:// uses fileURLToPath; preview prints a divergence note for fences/local images; --to docx strips the watermark div and warns about print-only flags; TOC links resolve in html/docx (heading ids assigned); waitForExpression sleeps instead of busy-spinning; escapeHtml/svg-dims deduped to single definitions; typography stragglers (blockquote 12pt, footnotes 10pt, 42em screen measure); bundle BUILD_INFO gains srcSha256 for no-node_modules drift detection; MAX_TARGET_PX shared guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
diagram-render
Offline diagram rendering for make-pdf and /diagram. One self-contained HTML
page (dist/diagram-render.html, ~9MB) bundles mermaid, the excalidraw export
utilities, and the official mermaid→excalidraw converter. The browse daemon
loads it with load-html; callers drive it through browse js and pull bytes
back with js --out.
The built page is committed (eng-review D2): rendering works with zero
network at install time and render time, and there is no npm supply-chain
surface in ./setup. The drift test (test/diagram-render-drift.test.ts)
fails CI if dist/ is edited by hand or falls out of sync with BUILD_INFO.json.
Page API (window functions)
| Function | In → Out |
|---|---|
__renderMermaid(id, text) |
mermaid text → SVG string. id must be unique per fence (mermaid-fence-<n>) — it namespaces every internal SVG id. |
__mermaidToExcalidraw(text) |
mermaid text → .excalidraw scene JSON (flowcharts fully; other types degrade upstream). |
__excalidrawToSvg(sceneJson) |
scene JSON → SVG string (Excalifont embedded, offline). |
__rasterize(svg, targetWidthPx) |
SVG → PNG data URL. Callers own DPI math: targetWidthPx = placed width (in) × 300. Throws on tainted canvas. |
__mountForScreenshot(svg, px) |
taint-proof fallback: mounts SVG at #raster-stage for browse screenshot --selector. |
__probeImage(src) |
data URI/URL → {width, height} JSON. |
__bundleInfo |
{ name, deps } — pinned dependency versions baked at build. |
Readiness: poll until #status text is ready (or browse wait '#done').
Page errors accumulate in window.__errors.
Updating
# 1. edit the exact pin in package.json
cd lib/diagram-render && bun install
# 2. rebuild (deterministic; build twice → same sha)
bun run build
# 3. commit package.json + bun.lock + dist/ together
Render contract details (securityLevel strict, htmlLabels false, print-css font
lock, <base href> + </scri escaping) are documented in src/entry.ts and
scripts/build.ts — read both before touching either.