Skip to content

docs(tooling): surface SVG diagram alt text in generated llms-full files#4087

Merged
justin808 merged 3 commits into
mainfrom
claude/elegant-hermann-f34d8a
Jun 18, 2026
Merged

docs(tooling): surface SVG diagram alt text in generated llms-full files#4087
justin808 merged 3 commits into
mainfrom
claude/elegant-hermann-f34d8a

Conversation

@justin808

@justin808 justin808 commented Jun 17, 2026

Copy link
Copy Markdown
Member

Why

The #3804 docs-to-SVG initiative replaced inline Mermaid/ASCII diagram blocks with <img src="images/*.svg"> embeds. The generated llms-full.txt / llms-full-pro.txt files (built by script/generate-llms-full.mjs and consumed by LLMs as plain text) copy each doc body verbatim — so after the conversion, an LLM reading those files saw only a raw <img> tag: a relative path that resolves to nothing and no visual. The structured diagram information it had when the Mermaid source was inline was lost.

This was flagged in #4084 review and deliberately deferred from that doc-only PR.

What

generate-llms-full.mjs now rewrites each SVG diagram embed to a [Diagram: <alt text>] marker when building the text reference:

  • Handles both the <p><img src="…svg" alt="…" /></p> HTML form and the ![alt](*.svg) markdown form.
  • Only .svg sources are rewritten — screenshots (.png) and JSX src={…} examples are left alone.
  • Embeds inside fenced code blocks are passed through verbatim, so JSX <img> code samples are never corrupted.

Why alt text rather than re-introducing Mermaid

The alt text is the human-authored, accessibility-grade description of each diagram. It captures the semantic content (branches, decisions, edge labels expressed as prose) that matters to an LLM, while keeping a single source of truth — re-introducing the Mermaid source would mean maintaining a second representation that drifts from the SVGs, defeating the point of #3804. Improving a diagram's machine description is now the same act as improving its accessibility text.

Result

44 diagram embeds across the OSS and Pro docs now render as readable [Diagram: …] blocks in the generated text. Example:

[Diagram: During a rolling deploy, draining old Rails (hash abc) and new Rails (hash def) both send SSR requests to a new renderer pool seeded only with the current hash def. The def requests hit the cache, but the abc requests miss and trigger 410 Gone, re-upload, and retry once per request.]

Tests

  • New generate-llms-full-test.bash case covering both embed forms and the code-fence exclusion.
  • node script/generate-llms-full.mjs --check passes (regenerated llms-full.txt / llms-full-pro.txt committed).
  • Prettier clean.

🤖 Generated with Claude Code


Note

Low Risk
Docs and build-script output only; no application runtime or auth paths change.

Overview
script/generate-llms-full.mjs now runs doc bodies through describeSvgDiagrams so SVG diagram embeds become [Diagram: …] text instead of dead <img src="images/*.svg"> paths in llms-full.txt and llms-full-pro.txt.

Rewriting covers <p><img … /></p> and ![alt](*.svg) forms, limits to .svg sources (PNG screenshots stay as-is), and skips fenced code blocks so JSX <img> examples are not altered. Empty alt collapses to [Diagram].

script/generate-llms-full-test.bash adds coverage for both embed forms, non-SVG passthrough, code-fence preservation, and empty alt. The regenerated llms-full outputs reflect the new markers across OSS and Pro docs.

Reviewed by Cursor Bugbot for commit 4851e64. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Documentation

    • Refreshed generated documentation references by converting embedded SVG diagrams into bracketed, text-based diagram captions (including a generic caption when SVGs lack alt text).
  • Build/Generation

    • Updated documentation generation to rewrite only SVG <img> diagrams into text markers while leaving non-SVG images and fenced code snippets unchanged.
  • Tests

    • Added/extended a generator verification test to confirm SVG-to-text conversion behavior, preservation of PNGs, and exact retention of fenced-code JSX <img> examples.

Merge rationale (maintainer-authorized)

Merged by the coordinator agent under explicit maintainer merge authorization ("you have merge authorization if you are confident and you document why").

Confidence basis, verified at merge time:

  • CI green: pr-ci-readiness verdict READY, no failing/pending checks; check-llms-full passing.
  • Scope is low-risk docs-tooling: changes are confined to script/generate-llms-full.mjs, its test harness, and the regenerated llms-full*.txt. No library/runtime code. Changelog classification: not_user_visible.
  • Review threads: 0 unresolved on the current head. The earlier advisory bot nits (single-quote regex robustness — "low-risk today" since this repo's docs are uniformly double-quoted; a clarifying comment; and extra test assertions) were resolved, and the PNG-untouched / empty-alt test gaps were closed in commit 523b1e2d.
  • Review-decision gate: GitHub reviewDecision is empty (no required reviewers; author cannot self-approve). This is the documented maintainer waiver of that gate, not an unreviewed merge — the change was reviewed by CodeRabbit, Greptile, claude-review, Cursor Bugbot, and CodeQL with no blocking findings.

Coordination: agent-coord merge lane claimed by coord-elegant-hermann-4087-merge; prior implementer worker-batch-4087-llms-full-alt released its claim and handed off "ready".

@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds SVG-diagram-to-text rewriting to the LLM reference-file generator so that diagram embeds (<p><img src="*.svg"> and ![alt](*.svg)) become readable [Diagram: alt text] markers in llms-full.txt / llms-full-pro.txt instead of dead relative-path <img> tags. Content inside fenced code blocks is intentionally left verbatim.

  • generate-llms-full.mjs gains three new functions (diagramMarker, rewriteImgTag, rewriteDiagramEmbeds) and a describeSvgDiagrams line-by-line dispatcher that splits prose from fenced-code content before rewriting, applied to every doc body in generate().
  • generate-llms-full-test.bash adds a self-contained bash test (test_svg_diagram_embeds_become_text_descriptions) that validates both embed forms and the code-fence exclusion; the committed llms-full.txt / llms-full-pro.txt are also regenerated to include the 44 converted diagram markers.

Confidence Score: 5/5

Safe to merge — changes are limited to text post-processing in the reference-file generator and its test suite, with no impact on the live docs or runtime code.

The rewriting logic is correct: multiline <p><img /></p> blocks are handled by \s* in the regex, the fence-detection loop correctly tracks char identity and length so tilde/backtick fences and info-string openers all behave per CommonMark, and the two-pass replace order avoids double-rewriting. The test covers all three embed forms (HTML-wrapped, bare markdown, and code-fence exclusion) in an isolated subshell harness.

No files require special attention.

Important Files Changed

Filename Overview
script/generate-llms-full.mjs Adds diagramMarker, rewriteImgTag, rewriteDiagramEmbeds, and describeSvgDiagrams; wires describeSvgDiagrams into the per-doc content pipeline. Logic correctly handles multiline HTML, CommonMark fence nesting (tilde vs backtick, info-string openers, longer closers), and non-SVG images.
script/generate-llms-full-test.bash Adds fixture content with <p><img .svg/>, a markdown image, and a JSX code-fence, plus a new test function verifying all three cases; test is properly isolated via the existing run_test subshell harness.
llms-full.txt Regenerated output file; 44 <img> embeds replaced with [Diagram: …] markers.
llms-full-pro.txt Regenerated Pro-tier output; same diagram-embed rewriting applied throughout.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["doc content (trimmed)"] --> B["describeSvgDiagrams()"]
    B --> C{line starts with\nfence chars?}
    C -- "no fence open\n(opening fence)" --> D["flushProse()\nset fence state\npush line → result"]
    C -- "fence open &\nclosing condition met" --> E["clear fence state\npush line → result"]
    C -- "fence open &\nnot a closer" --> F["push line → result\n(verbatim)"]
    C -- "not a fence line,\nnot in fence" --> G["accumulate in prose[]"]
    C -- "not a fence line,\nin fence" --> F
    D --> C
    E --> C
    F --> C
    G --> C
    B --> H["flushProse() at EOF"]
    H --> I["rewriteDiagramEmbeds(prose.join)"]
    I --> J["replace p+img.svg → [Diagram: alt]"]
    J --> K["replace standalone img.svg → [Diagram: alt]"]
    K --> L["replace ![alt](*.svg) → [Diagram: alt]"]
    L --> M["result.join('\\n')"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["doc content (trimmed)"] --> B["describeSvgDiagrams()"]
    B --> C{line starts with\nfence chars?}
    C -- "no fence open\n(opening fence)" --> D["flushProse()\nset fence state\npush line → result"]
    C -- "fence open &\nclosing condition met" --> E["clear fence state\npush line → result"]
    C -- "fence open &\nnot a closer" --> F["push line → result\n(verbatim)"]
    C -- "not a fence line,\nnot in fence" --> G["accumulate in prose[]"]
    C -- "not a fence line,\nin fence" --> F
    D --> C
    E --> C
    F --> C
    G --> C
    B --> H["flushProse() at EOF"]
    H --> I["rewriteDiagramEmbeds(prose.join)"]
    I --> J["replace p+img.svg → [Diagram: alt]"]
    J --> K["replace standalone img.svg → [Diagram: alt]"]
    K --> L["replace ![alt](*.svg) → [Diagram: alt]"]
    L --> M["result.join('\\n')"]
Loading

Reviews (1): Last reviewed commit: "docs(tooling): surface SVG diagram alt t..." | Re-trigger Greptile

@claude

claude Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Code Review

Overview

This PR adds SVG diagram alt-text surfacing to the generate-llms-full.mjs build script. The four-function chain (diagramMarkerrewriteImgTagrewriteDiagramEmbedsdescribeSvgDiagrams) is clean and well-decomposed. The code-fence guard is correctly implemented per CommonMark: info strings on opening fences are allowed, closing requires a bare fence of matching char and length ≥ the opener, and mismatched fence characters don't close each other. The test harness covers both embed forms and the fence exclusion. Good PR overall.

Correctness

Attribute quoting assumptionrewriteImgTag extracts src and alt with /\bsrc="([^"]*)"/ (double quotes only). A doc with alt='…' (single-quoted) would silently degrade to [Diagram] instead of [Diagram: <desc>]. The current docs are uniformly double-quoted so this is a non-issue today, but it's a fragile assumption worth hardening with /\bsrc=["']([^"']*)["']/.

Second <img> pass ordering — in rewriteDiagramEmbeds, the <p>…<img>…</p> regex runs first, consuming SVG embeds wrapped in bare paragraph tags. The follow-up /<img\b[^>]*>/gi catch-all then runs on the already-rewritten text, so there is no double-processing. The one edge case it does not fully cover: a mixed-content paragraph like <p>See <img src="foo.svg" alt="…"> for details</p> — the first regex would not match (not just an img), the second would replace the img inline, and the <p> wrapper would survive in the output. Not present in the current docs and acceptable for machine-readable output, but worth noting if doc conventions change.

Empty / missing altdiagramMarker('') correctly falls back to [Diagram], but there is no test case for it. A one-liner fixture assertion would close the gap.

Tests

The new test_svg_diagram_embeds_become_text_descriptions case is solid and covers the three critical paths. One gap: no assertion that a non-SVG <img> (e.g., a PNG screenshot) is left untouched. Worth adding a negative check alongside the existing SVG checks to prevent future regressions if the filter logic is ever adjusted.

Minor Nits

  • The ordering dependency between the two replace calls in rewriteDiagramEmbeds is load-bearing (first handles the full block, second is a fallback for standalone imgs). A one-line comment above the second .replace clarifying "fallback for SVG imgs not wrapped in a bare <p> block" would make this easier to maintain.
  • The markdown image regex [^)\s]*\.svg would not match a query-stringed URL like foo.svg?v=1. Unlikely in this doc set but worth knowing.

Summary

The implementation is correct for all real-world inputs in this repo. Most actionable follow-ups: harden the double-quote assumption in rewriteImgTag and add a negative (non-SVG image pass-through) test case.

Comment thread script/generate-llms-full.mjs
Comment thread script/generate-llms-full.mjs
Comment thread script/generate-llms-full-test.bash
@justin808 justin808 force-pushed the claude/elegant-hermann-f34d8a branch from 4b4b704 to 523b1e2 Compare June 18, 2026 19:51
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e24495ce-7c51-4c3d-8ebe-3448fafb2bec

📥 Commits

Reviewing files that changed from the base of the PR and between eb22595 and 4851e64.

📒 Files selected for processing (4)
  • llms-full-pro.txt
  • llms-full.txt
  • script/generate-llms-full-test.bash
  • script/generate-llms-full.mjs
✅ Files skipped from review due to trivial changes (2)
  • llms-full.txt
  • llms-full-pro.txt
🚧 Files skipped from review as they are similar to previous changes (2)
  • script/generate-llms-full.mjs
  • script/generate-llms-full-test.bash

Walkthrough

script/generate-llms-full.mjs gains a describeSvgDiagrams pass that rewrites SVG <img> embeds (both HTML and markdown syntax) into [Diagram: …] text markers derived from alt text, while leaving fenced code blocks untouched. A new bash test validates the rewriting behavior. llms-full.txt and llms-full-pro.txt are regenerated to reflect this transformation across ~40 diagram sites.

Changes

SVG diagram rewriting in llms-full generator

Layer / File(s) Summary
SVG-to-text rewriting logic and wiring
script/generate-llms-full.mjs
Adds altToMarker, SVG embed replacement helpers, and describeSvgDiagrams function that scans markdown line-by-line, skips fenced code blocks, and rewrites SVG <img> / markdown image embeds into [Diagram: …] markers. Wires the pass into the per-doc content emission in generate().
Test fixture and validation
script/generate-llms-full-test.bash
Extends the how-react-on-rails-works.md fixture with SVG embed, inline SVG, PNG, empty-alt SVG, and JSX-in-code-block cases. Adds and registers test_svg_diagram_embeds_become_text_descriptions asserting SVG → text rewriting, PNG passthrough, empty-alt collapse to [Diagram], and code-block preservation.
Regenerated llms-full.txt output
llms-full.txt
15 SVG diagram embeds across core-concepts, deployment topology, Docker, RSC build pipeline, 'use client' boundary, barrel/chunk contamination, Flight payload, and hydration timeline pages are replaced with [Diagram: …] text references.
Regenerated llms-full-pro.txt output
llms-full-pro.txt
25 SVG diagram embeds across Streaming SSR, Node Renderer, Rolling Deploy adapters, OpenTelemetry, JS memory leaks, selective hydration, RSC concepts/tutorials, Flight protocol, and React Server Components data-sharing pages are replaced with [Diagram: …] text references.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • shakacode/react_on_rails#3903: Modifies the same script/generate-llms-full.mjs pipeline, introducing the generator and --check drift guard that this PR extends with the SVG rewriting pass.
  • shakacode/react_on_rails#4084: Switches Pro documentation diagrams from Mermaid/ASCII to standalone .svg images, which directly feeds this PR's generator/test logic that rewrites .svg image embeds into [Diagram: ...] text descriptions.
  • shakacode/react_on_rails#4077: Adds new .svg diagram <img> embeds across Streaming SSR and related Pro documentation pages that this PR's generator processes and transforms into machine-readable [Diagram: …] markers.

Suggested labels

documentation, full-ci

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'docs(tooling): surface SVG diagram alt text in generated llms-full files' clearly and specifically describes the main change—replacing SVG diagram embeds with alt-text descriptions in the generated LLM reference files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/elegant-hermann-f34d8a

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Code Review

Overview

This PR fixes a real gap: the LLM-reference files were silently copying dead <img src="images/*.svg"> paths after the #3804 Mermaid→SVG migration. The fix is clean and scoped to the right layer (the build script, not the docs).


Strengths

  • Design is correct. Using alt text rather than re-embedding Mermaid avoids maintaining two representations of every diagram, and ties diagram quality improvements directly to accessibility improvements.
  • Fence detection is CommonMark-accurate. The isBareFence guard correctly prevents an opening info-string line (e.g., ```jsx) from being used as a closer, and the len >= fence.len rule matches the spec for minimum-length closing fences.
  • Three-phase replacement order is sound. Phase 1 strips the <p> wrapper when replacing SVG embeds; phase 2 catches any standalone <img svg> not wrapped in <p>; phase 3 handles the markdown-image form. Layering them avoids leaving orphan <p></p> shells.
  • Test coverage is good for the stated cases (HTML embed, markdown image, PNG passthrough, empty alt, code-fence exclusion).

Issues and Suggestions

1. Indented code blocks are not protected (minor correctness risk)

describeSvgDiagrams only detects fenced code blocks (``` / ~~~). CommonMark's 4-space indented code blocks are not handled — a line like <img src="diagram.svg" alt="…"> inside an indented block would be passed to rewriteDiagramEmbeds and rewritten. Today's docs don't appear to use indented code blocks, but this is a silent footgun if someone adds one.

2. Missing test: standalone <img svg> outside <p> (phase-2 path)

The test fixture only exercises the <p><img svg></p> form and the markdown ![](*.svg) form. The second .replace(/<img\b[^>]*>/gi, …) pass in rewriteDiagramEmbeds is the only thing that handles a bare <img src="…svg"> not wrapped in <p>. A fixture line like <img src="images/bare.svg" alt="Bare diagram"> would verify that path.

3. Regex won't match multi-line <img> attributes

[^>]* in <img\b[^>]*> does not cross newlines. An <img> tag with attributes split across lines would not be matched and would pass through as-is. Not a current issue (all doc <img> tags are single-line), but worth a note in the comment so future authors don't add split-attribute tags expecting them to work.

4. Only double-quoted attributes are matched

rewriteImgTag uses /\bsrc="([^"]*)"/ and /\balt="([^"]*)"/. Single-quoted attributes (src='…') would be silently treated as non-SVG and passed through unchanged. This is consistent with the existing doc authoring style, but a comment acknowledging the assumption would prevent confusion.


Summary

Correct, well-scoped, and well-tested for the actual doc corpus. The indented-code-block gap (#1) and the missing phase-2 test (#2) are the only items I'd consider fixing before merge; the rest are hardening notes.

Comment thread script/generate-llms-full.mjs
Comment thread script/generate-llms-full.mjs
Comment thread script/generate-llms-full.mjs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@script/generate-llms-full.mjs`:
- Line 289: The callback argument `whole` in the arrow function passed to the
replace method with the SVG regex pattern is unused, which violates the ESLint
no-unused-vars rule. Rename the `whole` parameter to `_whole` to follow the
convention for intentionally unused arguments, which will satisfy the linter and
prevent CI failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5201a4e7-e17a-4c7a-a1bb-10039b3a0957

📥 Commits

Reviewing files that changed from the base of the PR and between dac814e and 523b1e2.

📒 Files selected for processing (4)
  • llms-full-pro.txt
  • llms-full.txt
  • script/generate-llms-full-test.bash
  • script/generate-llms-full.mjs

Comment thread script/generate-llms-full.mjs Outdated
@claude

claude Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Code Review: docs(tooling): surface SVG diagram alt text in generated llms-full files

Overview

This is a focused, well-motivated PR. The #3804 docs-to-SVG migration left dead <img> tags in the generated llms-full.txt/llms-full-pro.txt plain-text files consumed by LLMs. This PR surfaces each SVG embed's alt text as a [Diagram: ...] marker instead — preserving structured content for LLMs without re-introducing Mermaid as a second source-of-truth. The design reasoning is sound and the implementation is clean.


What's Good

  • Fence exclusion logic is robust: tracks character type and minimum fence length, handles openers with language annotations vs bare closing fences, and correctly skips all embedded <img> inside fenced code blocks.
  • Graceful degradation: empty alt text degrades to bare [Diagram] instead of emitting [Diagram: ].
  • PNG pass-through: the SVG-only check in rewriteImgTag is correct and the test explicitly verifies it.
  • Multi-line <p><img/></p> blocks: the prose-buffer accumulation plus \s* in the first regex ensures multi-line wrappers collapse cleanly.
  • Test coverage is solid across all cases: HTML embed, Markdown embed, code-fence exclusion, PNG pass-through, and empty-alt SVG.

Minor Issues / Observations

1. Inline code is NOT protected

The fence exclusion skips fenced code blocks but not inline backtick spans. If a doc ever contained a backtick-wrapped inline code example showing a raw <img src="diagram.svg"> tag, the SVG reference inside would be rewritten to [Diagram: ...]. This appears to be a non-issue for the current doc content, but the protection gap is asymmetric with the fenced-block handling and there is no test for it.

2. Only double-quoted attributes are matched

rewriteImgTag extracts src and alt with /\bsrc="([^"]*)"/ and /\balt="([^"]*)"/. Single-quoted attributes would fall through — the tag would not be rewritten even for SVG sources. In practice all the docs use double-quoted attributes, so this is low risk.

3. The catch-all second <img> replace

rewriteDiagramEmbeds runs three chained replaces: (1) <p><img .svg></p> blocks, (2) any standalone <img> tag, (3) Markdown ![alt](.svg). The second replace is the safety net for SVG embeds not wrapped in a <p>. For non-SVG images already handled by rule 1, rule 2 sees the inner <img> again and correctly returns it unchanged — a harmless double-pass. A brief comment noting the catch-all intent would help future readers.

4. HTML entities in alt text pass through verbatim

If any alt text contained &amp; or &lt;, the [Diagram: ...] marker would include those entity-escaped sequences. For LLM consumption this is likely fine, but worth being aware of if the output format ever needs to change.


Verdict

Approve. The core implementation is correct, the design rationale is solid, and the tests cover all the main cases. The observations above are minor — none are correctness bugs for the current doc content.

Comment thread script/generate-llms-full.mjs
Comment thread script/generate-llms-full.mjs
justin808 and others added 3 commits June 18, 2026 10:06
The #3804 docs-to-SVG conversion replaced Mermaid/ASCII diagram blocks with
`<img src="images/*.svg">` embeds. In the LLM-facing llms-full*.txt files those
embeds were dead weight — a relative path that resolves to nothing and no
visual — so machine readers lost the structured diagram information they had
when the Mermaid source was inline.

generate-llms-full.mjs now rewrites each SVG diagram embed (both the
`<p><img .../></p>` HTML form and the `![alt](*.svg)` markdown form) to a
`[Diagram: <alt text>]` marker when building the text reference. The alt text is
the human-authored, accessibility-grade description of the diagram, so this
keeps a single source of truth (no Mermaid duplication that would drift from the
SVGs) while restoring the semantic content for LLM consumers. Embeds inside
fenced code blocks are left verbatim so JSX `<img>` examples are never touched.

Adds a generator test covering both embed forms and the code-fence exclusion,
and regenerates llms-full.txt / llms-full-pro.txt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… filter

Address advisory review feedback on the SVG diagram alt-text filter by
adding two negative-path assertions to the generator test:

- A PNG screenshot (non-SVG <img>) passes through verbatim; only .svg
  embeds are rewritten to diagram markers.
- An SVG embed with empty alt collapses to a bare [Diagram] marker rather
  than emitting an empty description or leaving a dead relative path.

These edge cases are the ones most likely to regress silently if the
filter logic is adjusted later. The generator code already handled both
correctly; this only closes the test-coverage gap. No change to generated
llms-full*.txt output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `![alt](*.svg)` replace callback in rewriteDiagramEmbeds binds the
full-match argument as `whole` but only uses `alt`, tripping ESLint
`no-unused-vars` (the shakacode config allows unused args only when
`_`-prefixed). Rename to `_whole`. Pure no-op for generator output —
llms-full*.txt are byte-identical after regeneration.

Flagged by CodeRabbit review. The repo lint job is path-gated and was
skipped for this docs/tooling PR, so the violation would otherwise surface
on a full-CI or main run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@justin808 justin808 force-pushed the claude/elegant-hermann-f34d8a branch from eb22595 to 4851e64 Compare June 18, 2026 20:07
@claude

claude Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Code Review: PR 4087 - Surface SVG diagram alt text in llms-full files

Summary: Clean, well-scoped fix. The approach (alt text as semantic fallback rather than re-embedding Mermaid source) is the right call -- single source of truth is preserved and the accessibility description carries the structural meaning an LLM needs. Low risk: build script and generated outputs only, no application runtime paths changed.

CORRECTNESS

Fence detection is spec-correct. The CommonMark-aligned close-fence check (char === fence.char && len >= fence.len && isBareFence) correctly prevents a fenced block from being closed by a line with an info string (e.g. triple-backtick-jsx) and handles tildes vs backticks independently.

Multi-line img tags are not matched. [^>]* does not cross newlines, so an img tag whose attributes span multiple lines would fall through silently. Current docs always put the img on a single line, so this is safe today -- but a short code comment flagging the constraint would help future maintainers.

Double-quote-only attribute matching. rewriteImgTag matches only src and alt with double-quoted values. Single-quoted attributes are silently skipped. Docs are consistent today, so not a real issue -- just worth noting for future authors.

Two-pass img replacement. The first regex handles the p-wrapped img canonical pattern; the second catches bare img tags outside a p wrapper. A lone SVG img in prose is also rewritten -- appears intentional but is not covered by any test fixture.

TEST COVERAGE GAP

test_svg_diagram_embeds_become_text_descriptions covers five key scenarios well. The one missing case is a bare SVG img outside a p wrapper -- the second .replace in rewriteDiagramEmbeds (line 288) handles it but no fixture exercises it.

MINOR STYLE NOTE

isBareFence (line 314) is always computed in the opener block but only consumed in the fence-close branch. Moving it inside the else-if would make the data flow marginally clearer -- purely cosmetic, not a bug.

VERDICT: Approve. Correct for the current doc conventions, tests are solid, and the design rationale (alt-text-as-semantic-fallback over re-introducing Mermaid source) is sound. Does not block merge.

Comment thread script/generate-llms-full.mjs
Comment thread script/generate-llms-full.mjs
Comment thread script/generate-llms-full.mjs
@justin808 justin808 merged commit 7d8887e into main Jun 18, 2026
50 checks passed
@justin808 justin808 deleted the claude/elegant-hermann-f34d8a branch June 18, 2026 21:36
justin808 added a commit that referenced this pull request Jun 18, 2026
…4053) (#4063)

## Why

Issue #4053: the recommended renderer readiness probe `curl
--http2-prior-knowledge -fsS http://localhost:3800/ready` breaks
container startup. The container never becomes ready; removing `-fsS`
"fixes" it (but then the probe always passes, defeating its purpose).

**Root cause (confirmed in `worker.ts`):** `-f`/`--fail` makes curl exit
non-zero on any HTTP status `>= 400`, and `/ready` returns `503
{"status":"waiting_for_bundle"}` during the cold-start window until the
answering worker compiles its first bundle. A `--fail` probe against
`/ready` with no warm-up path therefore deadlocks startup. This is
intended gating behavior — but the docs lacked an explicit per-endpoint
status-code contract and any Control Plane guidance, so the reporter hit
the deadlock without a clear answer.

Endpoint contract (from
[`worker.ts`](packages/react-on-rails-pro-node-renderer/src/worker.ts)):
- `/health` → always `200`
- `/info` → always `200`
- `/ready` → `200` once a bundle is compiled, else `503`

## What changed

Documentation only —
`docs/oss/building-features/node-renderer/health-checks.md`:

1. **Status-Code Contract** section with a per-endpoint table and a
callout explaining exactly why `curl -fsS .../ready` breaks startup, and
what to probe instead (`/health` or `/info` for an always-passes probe;
reserve `--fail` against `/ready` for setups with a warm-up path).
2. **Control Plane (CPLN)** section: CPLN exposes HTTP and Command
(exec) probes; the HTTP probe is HTTP/1.1 and cannot speak the
renderer's h2c listener, so use a Command probe with h2c-aware curl
against `/health` by default, switching to `/ready` only with a warm-up
path.

This addresses all three of the issue's requests: a probe command that
works, the `/ready`+`/info` status-code contract, and the CPLN-specific
probe options.

## Validation

- `npx prettier --check` passes on the changed file.
- Docs-only; no CHANGELOG entry per
`.claude/docs/changelog-guidelines.md` (docs fixes excluded).

Fixes #4053

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only changes with no runtime, security, or deployment
code modifications.
> 
> **Overview**
> Documents why **`curl --fail` against `/ready`** can deadlock
container readiness during cold start, and how to probe safely.
> 
> Adds a **Status-Code Contract** table for `/health`, `/info`, and
`/ready` (including when `503 waiting_for_bundle` is expected) plus
guidance to use **`/health` or `/info`** for probes that must pass once
the process is up, and **`/ready` with `--fail` only when a warm-up
path** compiles the first bundle.
> 
> Adds a **Control Plane (CPLN)** section explaining that HTTP probes
cannot use the renderer’s **h2c** listener, with example **`exec`
Command probes** using h2c-aware `curl` against `/health` for readiness
and liveness. The same content is mirrored in **`llms-full.txt`**.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
40ae833. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Added a “Status-Code Contract” describing expected HTTP responses for
health endpoints, including when `/ready` may return `503` during cold
start
* Expanded guidance on `curl --fail`/`-f`/`-fsS`, warning against using
`/ready` as a failing readiness gate without a warm-up path
* Added Control Plane-specific probe instructions and example probe
shapes to match connectivity constraints
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

## Agent Merge Confidence (coordinator)

**Merged by Claude Code coordinator under explicit maintainer
(justin808) delegation** — "merge authorization if confident +
documented."

- **Confidence: HIGH.** Docs-only (`docs/oss/.../health-checks.md`) +
regenerated `llms-full.txt`.
- **Rebased** onto merged #4087 (Group B, generated `llms-full.txt`
serialization); `llms-full.txt` regenerated via `node
script/generate-llms-full.mjs` — regeneration produced zero diff and the
`--check` guard passes (auto-merge was correct).
- **Doc accuracy verified vs source:** `/health`→200, `/ready`→200/503
`waiting_for_bundle` confirmed against
`packages/react-on-rails-pro-node-renderer/src/worker.ts`; CPLN probe
schema confirmed against `react_on_rails_pro/.controlplane/rails.yml`.
- **Current-head review threads triaged against the actual file (not
merged blind):** the recurring CodeRabbit/claude/codex "missing
`timeoutSeconds`" and greptile "missing liveness probe" flags are
**stale/incorrect** — the CPLN snippet already contains `timeoutSeconds:
5` on both `readinessProbe` and `livenessProbe`. `startupProbe` omission
is intentional and safe (probes `/health`, always 200; cold start cannot
misfire). The `-sfS` and localhost-qualification notes are
advisory/misreads. No actionable must-fix remained.
- **CI:** `mergeStateStatus: CLEAN`, all checks pass/skip. **Merge
ledger** sole hard violation `unknown_review_decision` — overridden by
maintainer merge delegation. Changelog `not_user_visible`.
- **Cross-batch:** Batch-1 #4037 also touches `llms-full.txt` and must
rebase+regenerate after this merge.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
justin808 added a commit that referenced this pull request Jun 19, 2026
* origin/main: (40 commits)
  feat(pro): use built-in Rails i18n compiler for React Intl demo (#4128)
  Fix pr-merge-ledger UTF-8 crash under non-UTF-8 locale (#4123)
  Add canonical AI-agent prompts source (prompts.yml) (#4124)
  Local benchmark runner: raise server-boot timeout for slower machines (#4073) (#4125)
  Docs(generator): note Pro production devtool for source-mapped SSR stacks (#3893) (#4113)
  docs: add "Consuming an Unreleased Build" guide and fix pnpm git-subdir syntax (#4117)
  Address deferred AI-review feedback on PR-helper scripts (#4069) (#4105)
  Wrap generated demo file paths in onboarding page (Part 1 of #4062) (#4107)
  fix(ci): build bundle-size base from PR merge commit's first parent (#4110)
  Add internal RSC architecture deep-dive docs (RoR Pro vs Next.js) (#4006)
  Disable noisy automatic benchmark regression issue filing (#4071) (#4116)
  Release-train branching + phase-tiered merge gating (beta/RC/final) (#4018)
  Fix Webpack dependency selection in install generator (#4109)
  Document health-probe status-code contract and Control Plane probes (#4053) (#4063)
  Local dedicated-hardware benchmark runner (#4073) (#4088)
  docs(tooling): surface SVG diagram alt text in generated llms-full files (#4087)
  docs(agents): codify review-loop convergence + local/CI parity in PR-batch workflow (#4101)
  Split RenderFunction: drop the legacy renderer arm (#4096)
  Add OSS hydrate_on scheduling (#4037)
  Docs: fix stale evaluate-issue gate cross-reference (#3910) (#4104)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant