`);
+ return lead+'\x00UF'+(stash.length-1)+'\x00';
+ });
+ s=_stashUserSelectedContextBlocks(s, stashContext);
+ s=esc(s).replace(/\n/g,' ');
+ s=s.replace(/\x00UF(\d+)\x00/g,(_,i)=>stash[+i]);
+ s=s.replace(/\x00UC(\d+)\x00/g,(_,i)=>contextStash[+i]||'');
+ return s;
+}
+process.stdout.write(_renderUserFencedBlocks(input));
+'''
+ result = subprocess.run(
+ ["node", "-e", script, json.dumps(input_text)],
+ check=True,
+ cwd=ROOT,
+ text=True,
+ capture_output=True,
+ )
+ return result.stdout
+
+
+def test_sent_selected_context_renders_as_semantic_card_and_escapes_content():
+ html = _run_user_renderer(
+ "Here is my reply.\n\n**:**\n"
+ "\n> \n> second line"
+ )
+
+ assert '' in html
+ assert '<img src=x onerror=alert(1)>' in html
+ assert '
<script>alert(1)</script>\nsecond line
' in html
+ assert "**" not in html
+
+
+def test_sent_selected_context_parser_accepts_user_renamed_edge_labels():
+ html = _run_user_renderer("***Evidence: alpha:**\n\n> quoted")
+
+ assert 'class="sent-selection-context"' in html
+ assert '*Evidence: alpha' in html
+ assert "***Evidence" not in html
+
+
+def test_matching_shape_inside_user_code_fence_stays_code_not_context_card():
+ html = _run_user_renderer("```md\n**Evidence:**\n> keep literal\n```")
+
+ assert 'class="sent-selection-context"' not in html
+ assert '
' in html
+ assert '**Evidence:**' in html
+ assert '> keep literal' in html
+
+
+def test_manual_labelled_blockquote_without_marker_stays_literal_user_text():
+ html = _run_user_renderer("**Manual note:**\n> manually typed quote")
+
+ assert 'class="sent-selection-context"' not in html
+ assert '**Manual note:**' in html
+ assert '> manually typed quote' in html