Skip to content

fix(penpal): render pending highlights via rehype instead of DOM mutation#355

Merged
loganj merged 1 commit intomainfrom
worktree-dynamic-honking-dijkstra
Mar 6, 2026
Merged

fix(penpal): render pending highlights via rehype instead of DOM mutation#355
loganj merged 1 commit intomainfrom
worktree-dynamic-honking-dijkstra

Conversation

@loganj
Copy link
Collaborator

@loganj loganj commented Mar 5, 2026

Summary

Fixes an intermittent crash ("The object can not be found here" / removeChild) when leaving a comment or reply in Penpal.

Root cause: applyPendingHighlight directly mutated React-managed DOM by wrapping text nodes in <mark> elements. When an SSE event raced with comment submission, React's reconciliation encountered unknown nodes and threw.

Fix: Pending highlights now flow through the existing rehypeCommentHighlights rehype plugin. React owns the full DOM lifecycle — no more race conditions. The DOM-mutating applyPendingHighlight/removePendingHighlight functions are removed; threadHighlights memo in FilePage.tsx includes pendingAnchor as a highlight entry (with pending: true) when present.

Also fixed: occurrenceIndex is now stored on Anchor and passed to the rehype plugin so it can find the Nth occurrence of selected text within a block — preventing mis-highlights when the same text appears multiple times.

Tests

146 tests pass (20 files), including 13 new tests covering:

  • Rehype plugin correctly wraps and splits text nodes, adds pending-highlight class
  • MarkdownViewer renders both regular and pending highlights via plugin
  • FilePage shows/hides pending highlight on toolbar open/cancel
  • No crash when SSE fires a thread update while a pending highlight is active

Generated with Claude Code

@loganj loganj force-pushed the worktree-dynamic-honking-dijkstra branch from 35847af to 8837a3c Compare March 5, 2026 22:50
@loganj loganj added the ai-outer-loop Managed by outer-loop label Mar 5, 2026
@loganj loganj force-pushed the worktree-dynamic-honking-dijkstra branch 2 times, most recently from fbbb9f7 to 9632795 Compare March 5, 2026 22:53
@loganj
Copy link
Collaborator Author

loganj commented Mar 5, 2026

@codex review

Comment posted automatically by outer-loop

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9632795358

ℹ️ 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".

@loganj loganj force-pushed the worktree-dynamic-honking-dijkstra branch 3 times, most recently from 4d02546 to 1b6e0b1 Compare March 6, 2026 04:03
…ead of DOM mutation

The pending highlight (shown while composing a new comment) was applied
by directly mutating React-managed DOM — wrapping text nodes in <mark>
elements. When an SSE event raced with comment submission, React would
re-render the MarkdownViewer and encounter unexpected nodes during
reconciliation, crashing with "The object can not be found here."

Move the pending highlight into the existing rehypeCommentHighlights
plugin so React owns the full lifecycle. When pendingAnchor is set, it's
added to the threadHighlights array with a `pending` flag that adds the
`pending-highlight` CSS class alongside `comment-highlight`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@loganj loganj force-pushed the worktree-dynamic-honking-dijkstra branch from 1b6e0b1 to 4d29e2e Compare March 6, 2026 04:09
@loganj loganj marked this pull request as ready for review March 6, 2026 04:34
@loganj loganj merged commit 66c286b into main Mar 6, 2026
4 checks passed
@loganj loganj deleted the worktree-dynamic-honking-dijkstra branch March 6, 2026 04:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-outer-loop Managed by outer-loop

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant