Repository navigation
Render LaTeX math with KaTeX - #318
Conversation
Enable comrak's math_dollars and math_code extensions everywhere plan Markdown is parsed, allow only data-math-style on comrak's math elements, and typeset them on the client with a lazily loaded KaTeX Stimulus controller. Math is atomic for comment anchoring, round-trips through the rich editor, and has a demo-library example and agent guide section.
|
🤖 @codex review |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Signed-off-by: Hampton Lintorn-Catlin <hampton@squareup.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42c88994e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- readableText reads a section whose root is a math fence as TeX source. - The slide classifier bills inline math as text and display math by rows; math fences are display math, not code slides. SLIDE_SPEC.md documents the cost with conformance examples. - Only parser-generated math keeps data-math-style: an element must sit at the unique source position of a math node, so authored HTML that imitates math stays ordinary, anchorable text.
Signed-off-by: Hampton Lintorn-Catlin <hampton@squareup.com>
|
🤖 Maintenance preparation requested by @HamptonMakes; product acceptance, approval, and merge remain his decision.
Exercised the actual browser in both themes: prose edits preserve raw TeX, currency stays literal, table selection waits for an intentional comment action, and the six-row formula fits in presentation mode. Browser regressions cover selections across/inside formulas, heading previews, lazy loading, failure recovery, and trust boundaries. Local preview stays running: http://localhost:3318/hampton/demo-content/rich-text/math-estimating-a-retry-budget — sign in as hampton@example.com, no password. Use Math on slides → Present, or Edit → Raw to inspect source. The formula-only prose comment limitation remains a product choice: anchor surrounding text; table cells support their own discussions. Integration note: cache 28 avoids #311=25, #313=26, and #314=27. The final combined-render merge must use a fresh value above every previously deployed value.
|
|
🤖 Post-merge verification and release-note evidence Merged by Hampton as af594b7. Post-merge CI completed successfully on that exact merge commit. Release-note text: CoPlan now renders inline and display LaTeX with KaTeX across plans, comments, previews, tables, and slide decks. The rich editor preserves editable TeX through prose edits; currency and code stay literal. Math loads lazily and retains readable source if loading or parsing fails. Prose discussions can anchor surrounding text across formulas, while table cells support independent discussions. Review, focused test results, and light/dark and dense-slide screenshots document the validation. Render cache version is 28; subsequent combined rendering changes must use a fresh value above deployed versions. The local preview remains running at http://localhost:3318/hampton/demo-content/rich-text/math-estimating-a-retry-budget. No further acceptance gate or release publication is part of this housekeeping. |



What changed and why
Plans and comments can now contain LaTeX math. Before this change,
$x^2$showed as plain text.Parsing. Commonmarker 2.6.3 exposes comrak's
math_dollarsandmath_codeoptions, so they are now on inMarkdownHelper::EXTENSION_OPTIONS. Every parser already shares that constant:CoPlan::Markdown,MarkdownTextExtractor,SourceTargets, the slide classifier and splitter, changed sections, and content regions. Supported forms:$inline$$$display$$, inline or as its own multi-line paragraph$`inline`$```mathfencescomrak's dollar rules keep currency such as "costs $5 and $10" as text. A spec pins this.
Sanitizer. comrak marks math with
data-math-style="inline|display"onspan,code(for$`…`$), orpre lang="math"(for fences).data-math-styleis the only attribute added to the allowlist. After sanitizing,prepare_mathkeeps it only on those elements and values at a unique parser-confirmed math source position. Authored HTML imitations lose the attribute and stay anchorable text. Each element that keeps it is wired to the math controller. Because this runs after sanitization, authored markup still can't setdata-controller.Rendering. A new Stimulus controller,
coplan--math, typesets each math element withkatex.render(source, el, { displayMode, throwOnError: false, trust: false, strict: "warn" }). KaTeX 0.19.1 is pinned in the importmap from jsDelivr withpreload: false, the same way Mermaid is pinned. Its stylesheet is version-pinned and loaded with a SHA-384integrityhash. Fonts load relative to that stylesheet.render_markdown: the plan page, comments and comment previews, slides and decks, footnote and references sections, version pages, and editor previews.Comment anchors. Math is an atomic, non-anchorable region, like Mermaid source. The TeX glyphs that KaTeX draws don't spell anything in the source, so keeping the source mappable would mean the server and the browser disagree about the text. Instead, both sides leave math out:
MarkdownTextExtractorskips:mathnodes andmathcode blocks.text_selection_controlleradds[data-math-style]to the elements it leaves out of the anchor text model.The effect on selections:
Agents that anchor on raw TeX through the API still resolve to the source range, but they get no highlight. The guide tells them to anchor on the surrounding text.
Rich editor. A markdown-it inline rule follows comrak's dollar rules. A spec checks it against Commonmarker on about 40 tricky lines.
mathmark over raw TeX, delimiters included. It is editable inline and serializes verbatim withescape: false.```mathfences stay code blocks and are not syntax-highlighted.Docs and demo. The agent Markdown guide has a new "Math" section. A new demo,
math-gallery("Math: estimating a retry budget"), appears under Tables and rich text and indocs/DEMO_LIBRARY.md. It shows inline math, display math, a math fence, math in lists and tables, a six-row retry-budget slide, dollar amounts that stay text, and an invalid expression that falls back to its source.Cache.
RENDER_CACHE_VERSIONgoes from 24 to 28, reserving a distinct value from #311 (25), #313 (26), and #314 (27). The final combined-render merge must use a fresh version above every previously deployed value.No Google Docs or other exporters needed changes.
Evidence
Light and dark screenshots are attached below. Updated gallery, dense-slide evidence, and maintenance validation.
How to try it
bin/setup --skip-server,bin/rails db:seed, andbin/rails server -p 3105(setCOPLAN_DEMO_BASE_URL=http://localhost:3105before the first seed).$$block and amathfence);\frac{1}{in red as readable source.Testing
bundle exec rspec spec/helpers/markdown_helper_spec.rb spec/models/comment_thread_anchor_spec.rb spec/helpers/slideshows_helper_spec.rb spec/lib/development_seed_spec.rb spec/requests/agent_instructions_spec.rb spec/services/plans/writing_provenance_spec.rb spec/services/coplan/markdown_spec.rb spec/lib/stylesheets_spec.rb spec/system/math_rendering_spec.rb spec/system/comment_anchoring_spec.rb spec/system/mermaid_anchor_spec.rb spec/system/writing_provenance_spec.rbpassed. Its failures happened only while another run shared the same test database, and they passed when rerun alone.bundle exec rspec spec/system/editor_math_spec.rb spec/system/editor_*_spec.rb spec/system/document_editor_modes_spec.rb spec/system/human_editing_spec.rb spec/system/inline_editor_spec.rbhad 228 examples. Its one failure was Selenium's "failed to close window" ineditor_caret_spec.rb:16, and that file passes on its own.The full suite,
bundle exec rspec, had 3431 examples, 1 failure:spec/system/agent_connections_spec.rb:16, a known flake where Chrome times out closing a window. It is unrelated to this change.bin/rubocopon the changed Ruby files,bin/importmap audit, andbin/brakemanall passed.I checked the demo plan in light and dark mode in headless Chrome on port 3105; the screenshots are listed under Evidence. The system specs drive the comment popover, the outline and § preview for a heading that contains math, and a page without math, which loads no KaTeX.
Added or updated real JavaScript-enabled browser specs in
spec/system/for changed UI behavior, covering the user interaction and visible result; or explained why no browser UI is involved.Added model, service, or request specs where needed for domain behavior, authorization, or API cases.
Ran
bundle exec rspec, or explained why it could not run and listed the specs that did run.Tested affected UI behavior in both light and dark mode, or explained why mode testing does not apply.
Attached a video or images demonstrating the change, if this PR adds or changes a feature or fixes a UI bug.