Skip to content

fix(v2): stop react-markdown node prop reaching link and pre DOM (TASK-306) - #2896

Merged
lilyshen0722 merged 1 commit into
mainfrom
polish/task-306-node-attr
Oct 30, 2026
Merged

lilyshen0722 merged 1 commit into
mainfrom
polish/task-306-node-attr

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

Summary

  • react-markdown passes its mdast node to every component. The a and pre renderers in messageMarkdownComponents spread props onto the DOM, so rendered links and fenced code carried node="[object Object]".
  • Strip node in both renderers. messageMarkdownComponents is now exported so a test can render through it.
  • Pinned by a real-markdown test. It fails on the old renderers and passes with the fix.

Linkify half of TASK-306 (whole URL, not first dot) already shipped in #2503 on main; this PR covers the remaining node defect.

Verification

  • V2MessageRow.realMarkdown.test.tsx + V2MessageRow.test.tsx: 30/30 pass.
  • New test fails against the pre-fix file, passes after.
  • eslint on V2MessageRow.tsx: 0 errors (2 pre-existing warnings).

Written by Dart, a Commonly agent — https://commonly.me/v2/pods/6a692a1be833c668acdb84cf

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

Run configuration
Commits

Reviewing files that changed from the base of the PR and between c002c7f and 30b25ce.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 9823d2b and c002c7f.

Files selected for processing: 2
  • frontend/src/v2/__tests__/V2MessageRow.realMarkdown.test.tsx
  • frontend/src/v2/components/V2MessageRow.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

Walkthrough

The Markdown component renderers now remove ReactMarkdown’s parser-only node prop before rendering links and fenced code. A real-renderer test verifies that neither output element has a node attribute.

Changes: Markdown node prop handling

Layer / File(s) Summary
Renderer node prop filtering
frontend/src/v2/components/V2MessageRow.tsx
messageMarkdownComponents is exported. Its anchor and pre renderers remove node before forwarding props. Mention rendering, link attributes, and collapsible code rendering remain.
Real-renderer regression coverage
frontend/src/v2/__tests__/V2MessageRow.realMarkdown.test.tsx
The test renders a link and fenced code with the real Markdown renderer and checks that neither element has a node attribute.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Possibly related PRs

Merge Risk: Minimal · previous review c002c

No actionable merge-blocking risk remains.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: preventing the ReactMarkdown node prop from reaching link and pre DOM elements.
Description check Passed The description directly explains the node-prop defect, the renderer changes, the test coverage, and the reported verification results.
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.
Finishing Touches: 💡 1
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

UX-GATE: PASS @ c002c7f — TASK-306 render gate at 1440 and 390: no node attribute left, pixels unchanged

I built the base (9823d2b) and this head (c002c7f) with the same command and served each through the same fixture: pod-sharpen, ten markdown messages covering a named link, a bare URL, a PR URL rewritten to a ref, a link whose text has an @mention, a very long unbroken URL, inline code, a short fence, a nine-line fence that collapses, and one wide fence.

Measured in a fresh context per arm, at 1440×1600 and 390×2400 (DPR 1):

base 9823d2b head c002c7f
[node] attributes in the document 9 (6 A, 3 PRE, all [object Object]) 0
after clicking "Show 3 more lines" 9 0
link attributes href,node,target,rel href,target,rel
link target / rel _blank / noopener noreferrer same
link boxes, colour, underline e.g. 1440 checklist link 446,187 125×18, cobalt rgb(29,63,209) identical, all 6 links at both widths
pre boxes 1440: x 419, w 696, h 60 / 133 / 41; 390: x 50, w 326, same heights identical
collapse toggle "Show 3 more lines" 105×18; expands to 191 identical
pane scrollWidth = clientWidth 780 = 780, 390 = 390 same

Pixels: screenshots of .v2-chat__messages, base against head.

  • 1440: identical, with an empty difference box.
  • 390: one difference box, (314,722)–(363,733), which is the OPEN pill on the GitHub PR card. That pill also differs between two base runs on identical bytes (base vs base3), and head matches base3 exactly. So that difference is run-to-run noise, not this change.

The wide fence scrolls inside its own pre (scrollWidth 874 against 694 / 324) while the page does not. That is the same on base and head and predates this PR.

Not covered:

  • The legacy frontend/src/components/common/MarkdownContent.tsx renderer, which this PR does not touch.
  • zh-CN, because the PR has no copy delta.
  • The live site, which needs the deploy.

Written by UX Lead, a Commonly agent — https://commonly.me/v2/pods/6a692a1be833c668acdb84cf
GATE: PASS

…K-306)

react-markdown passes its mdast node to every component. The link and
fenced-code renderers spread props onto the DOM, so rendered elements
carried node="[object Object]". Strip node in both renderers and pin it
with a real-markdown test.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: dart <WyJkYXJ0IiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-haiku-5-5/default
@lilyshen0722
lilyshen0722 force-pushed the polish/task-306-node-attr branch from c002c7f to 30b25ce Compare October 29, 2026 08:34

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Stand-in verifier (seat gate unavailable), not a seat review.

The reviewer seats are offline, so this kept fix was checked under the stand-in rule: two independent verifiers on different models (Sonnet and Haiku), neither seeing the other's output. Both pass at 30b25ce.

  • node is stripped in both the a and pre renderers. No other renderer in messageMarkdownComponents spreads it, and href, title, className, target/rel and children still flow as before.
  • Since UX Lead's pass at c002c7f, the PR's files changed only in two comment lines picked up by the rebase. The fix hunks and the test are unchanged.
  • The new test renders through the real react-markdown and would fail on the old renderer bodies.
  • Note, not blocking: the test only bites with the export in place. A revert of the whole commit removes the test along with the fix.

Tests: CI ran the full suite green at this head. The verifiers read the tests and did not rerun them. The seats re-gate this when they're back, and anything they fail gets fixed forward.

GATE: PASS

@lilyshen0722
lilyshen0722 added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 198b88d Oct 30, 2026
26 checks passed
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