Skip to content

fix(session-end): preserve $-sequences in user messages (summary corruption)#2180

Merged
affaan-m merged 1 commit into
affaan-m:mainfrom
bymle:fix/session-end-dollar-replace
Jun 7, 2026
Merged

fix(session-end): preserve $-sequences in user messages (summary corruption)#2180
affaan-m merged 1 commit into
affaan-m:mainfrom
bymle:fix/session-end-dollar-replace

Conversation

@bymle

@bymle bymle commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Problem

session-end.js (Stop hook) silently corrupts the persisted session summary when a user message contains a $-sequence ($&, $$, $\``, $') — which is common in dev work (regexes, PASS=$1, prices like $5`, shell snippets).

Root cause

The regenerated summary block embeds raw user-message text, and is passed as the replacement argument to String.prototype.replace (lines 259 & 265):

updatedContent = updatedContent.replace(markerRegex, summaryBlock); // summaryBlock has user text

In a replacement string, $& = the whole match, $$ = $, etc. buildSummarySection escapes newlines and backticks but not $. So on any repeat Stop (when the file already has the summary markers), a user message like release $& fallback makes $& re-inject the entire matched old block, duplicating the summary markers and dropping the user's text.

Verified corruption on a release $& fallback $$ done message (markers duplicated, $$$):

### Tasks
- release <!-- ECC:SUMMARY:START -->
## Session Summary
### Tasks
- old task
<!-- ECC:SUMMARY:END --> fallback $ done

Fix

Use function replacers (() => summaryBlock) at both rewrite sites — a function replacement is treated literally, so no $-interpretation occurs. (Equivalent to escaping $$$; the function form is cleaner and covers all sequences.)

Tests

Adds tests/hooks/session-end.test.js — an end-to-end regression test (seeds a marker'd session file + a transcript whose user message contains $&/$$, runs the hook, asserts the text survives verbatim and the markers appear exactly once). Confirmed it fails on the current code and passes with the fix.


Summary by cubic

Fixes summary corruption in the session-end hook when user messages include $-sequences (e.g., $&amp;, $$). Replacements now treat the summary block literally so user text is preserved and markers appear once.

  • Bug Fixes
    • Use function replacers for both summary rewrite paths to avoid $ interpretation by String.prototype.replace.
    • Add an end-to-end regression test that verifies $&, $$, $', and `$`` are preserved and that the summary marker pair appears exactly once.

Written for commit d5c3e81. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where certain special characters in user messages could interfere with session summary generation and storage.
  • Tests

    • Added regression tests to verify session summary reliability with various message content.

…g summary

The regenerated summary block embeds raw user-message text and was passed
as the *replacement* argument to String.prototype.replace, where $-sequences
($&, $$, $`, $') are special. A user message containing $& re-injected the
entire matched block (duplicating the summary markers) and $$ collapsed to $,
silently corrupting the persisted session summary. buildSummarySection only
escapes newlines and backticks, not $.

Fix: use function replacers (() => summaryBlock) at both rewrite sites so the
replacement text is treated literally. Adds an end-to-end regression test.
@bymle bymle requested a review from affaan-m as a code owner June 7, 2026 00:41
@coderabbitai

coderabbitai Bot commented Jun 7, 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0cee8001-0e95-4484-8496-19cc7c84829f

📥 Commits

Reviewing files that changed from the base of the PR and between 7113b5b and d5c3e81.

📒 Files selected for processing (2)
  • scripts/hooks/session-end.js
  • tests/hooks/session-end.test.js

📝 Walkthrough

Walkthrough

The session-end hook's session-summary update logic now uses function replacers to prevent $-sequence interpolation from user-message-derived content when calling String.replace. A new regression test validates the fix with synthetic transcripts containing $ special sequences.

Changes

Session-end hook $-sequence interpolation fix and test

Layer / File(s) Summary
Function replacer fix in session-end hook
scripts/hooks/session-end.js
The session file update path now passes () => summaryBlock function replacers instead of string values to String.replace(), preventing $-sequence expansion from user-message-derived content in both the summary-marker block replacement and legacy migration path.
Regression test for $-sequence interpolation
tests/hooks/session-end.test.js
New test file with helpers and a core regression case that seeds a session file with summary markers, writes a transcript containing $& and $$ characters in user content, executes the hook via spawnSync, and validates that the user text appears verbatim and the summary marker pair is not duplicated.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

A hook that replaced strings with care,
Now guards against $ snares with flair,
Function replacers keep content true,
No interpolation mishaps to pursue! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: using function replacers in session-end.js to preserve $-sequences in user messages and prevent summary corruption. It directly reflects the core issue and fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 2 files

Re-trigger cubic

@affaan-m affaan-m merged commit e7e38cd into affaan-m:main Jun 7, 2026
3 checks passed
syarfandi pushed a commit to syarfandi/ECC that referenced this pull request Jun 9, 2026
…g summary (affaan-m#2180)

The regenerated summary block embeds raw user-message text and was passed
as the *replacement* argument to String.prototype.replace, where $-sequences
($&, $$, $`, $') are special. A user message containing $& re-injected the
entire matched block (duplicating the summary markers) and $$ collapsed to $,
silently corrupting the persisted session summary. buildSummarySection only
escapes newlines and backticks, not $.

Fix: use function replacers (() => summaryBlock) at both rewrite sites so the
replacement text is treated literally. Adds an end-to-end regression test.

Co-authored-by: bymle <229636660+bymle@users.noreply.github.com>
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.

2 participants