Act on the whole-branch review
The Fable review found one blocking defect and a set of real non-blocking ones. It also did the verification this branch said it could not: it installed pypdf and fontTools and parsed the exported PDF and its embedded subsets independently — strict mode, checksum validation, text extraction including "café", em dashes and curly quotes. So the Identity-H and ToUnicode construction is confirmed by something nobody here wrote, which is the gap the PDF commit was honest about leaving open. BLOCKING, now fixed: the PDF export logged document content. On a substitution it wrote Report.String() — the actual missing characters — into the instance log, and an instance's logs reach the platform's own store. Spec §2.1's leak list, item 5, is categorical that a handler never interpolates document content into a log or an error, and for a short document in an unshipped script the deduplicated set of its characters approximates the document. It would have leaked most of one in plaintext, out of a system whose premise is that documents are sealed at rest, and it would have done it to exactly the people the missing fonts already disadvantage. It now logs a count and Unicode block names — which is what an operator can act on anyway, since blocks say which faces to add. Report.String() keeps its behaviour and gains a comment saying what it must not be used for. TestPDFIsDeterministic could not see what it claimed to. It compared with strings.EqualFold, and a PDF is mostly Flate — mostly invalid UTF-8 — where every invalid byte decodes to U+FFFD on both sides and compares equal. Two files with different compressed bodies passed, in the test whose whole subject is bytes. bytes.Equal now. That is the AGENTS.md shape appearing in the one test written to rule it out. And the nondeterminism it was too weak to catch is real: a run carrying two size marks — impossible through the schema, possible through raw POST /updates bytes — picked one by ranging a map with a break, so the same document could export differently. Fixed order, and its own test. A list item whose first line falls on a new page lost its marker entirely: the guard compared an offset on the old page with one on the new. In an ordered list that is a silently missing number. The marker now follows the line wherever it actually lands. Verified by restoring the original logic and watching items 28 and 55 — the two page breaks — lose their numbers. The three toolbar selects were never disabled server-side though a comment claimed they were, so with no JavaScript a person could change Font to Monospace and watch the document ignore them; and the Size control listed "Small" first, so it displayed the wrong current state until the first sync, and forever without script. Disabled like the buttons, enabled by the same sync, and Normal listed first. The subset dropped cvt /fpgm/prep. Liberation's glyph programs call functions defined in fpgm and read values from cvt , so the embedded font was executing instructions against definitions that were not in the file — ISO 32000-1 §9.9 requires them, and about 15KB a face is the cheapest correctness in the package. Smaller: Get's fallback comment said "regular serif" and returned Liberation Mono Bold, because faces is sorted by served path — it now asks for the face it means by name. parseCmap12 skipped rather than stopped on a short group table, so a hostile count could spin billions of no-op iterations in a parser whose own header advertises it is one step from untrusted input. toolbar.mjs was 350 lines against spec §12's 300-line cap, which this branch's own plan promised to respect. The roving-tabindex logic is now fixtures/toolbar-roving.mjs — a genuinely separate concern, since it decides which control the keyboard is on and knows nothing about ProseMirror. 273 and 86 lines. The browser drive still passes 22/22, including all three keyboard checks.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YYB9fUAfxXNzkeC3fsFYzR
fixtures/toolbar-roving.mjs+86 −0fixtures/toolbar.mjs+8 −78internal/docs/export.go+26 −2internal/docs/static/{editor.3dbb8fa17262528b.js => editor.30d1bd8b9ffef032.js}+12 −12internal/docs/views/show.html+3 −3internal/export/pdf.go+122 −16internal/export/pdf_test.go+66 −1internal/fonts/fonts.go+15 −3internal/fonts/fonts_test.go+47 −0internal/fonts/truetype.go+32 −1
CI passed — run details
Intent
<task-notification> <task-id>bswsetyb9</task-id> <tool-use-id>toolu_011oucwt2ZYc54inMLRe62XC</tool-use-id> <output-file>/home/paulca/.cache/tmp/claude-1001/-home-paulca-amadan-net-oficina-docs/8c293727-d922-4f5a-bfde-9457b649670f/tasks/bswsetyb9.output</output-file> <status>completed</status> <summary>Background command "Wait for CI" completed (exit code 0)</summary> </task-notification>
shall we do search now, so i can find docs by title?
Attributed to this commit: 311 g CO₂e (41038715 tokens). This is an attribution, not a measurement — usage counted from this commit's own marker forward to the next one on formatting-and-export, never backward from it. A turn that produced more than one commit books all of its tokens to the last one, and a concurrent session on this branch can add to the same figure. Some of it was priced using the shared default rate, because no model-specific factor row exists yet for at least one model involved. The Carbon view has the repo total, which is never derived from this attribution.
fixtures/toolbar-roving.mjsLoading diff…
fixtures/toolbar.mjsLoading diff…
internal/docs/export.goLoading diff…
internal/docs/static/{editor.3dbb8fa17262528b.js => editor.30d1bd8b9ffef032.js}Loading diff…
internal/docs/views/show.htmlLoading diff…
internal/export/pdf.goLoading diff…
internal/export/pdf_test.goLoading diff…
internal/fonts/fonts.goLoading diff…
internal/fonts/fonts_test.goLoading diff…
internal/fonts/truetype.goLoading diff…