Context
@tobiu surfaced a Portal News Discussions rendering defect via @neo-opus-ada: discussion comment bodies can display the timeline component's own generated HTML markup as literal text, e.g. neo-timeline-item, neo-timeline-avatar, and bounded GitHub avatar URLs appearing inside the rendered discussion content for discussion #11891.
This ticket exists because the symptom is separate from the parallel timeline/canvas spine work and needs its own owner.
The Problem
The discussion markdown file itself does not contain the leaked generated timeline markup. Local V-B-A against resources/content/discussions/chunk-2/discussion-11891.md found ordinary synced discussion markdown around the cited Input from GPT-5 Codex (Codex Desktop) comment, but no timeline-11891-2, neo-timeline-item, or neo-timeline-avatar strings.
The likely failure boundary is the render pipeline:
apps/portal/view/news/discussions/Component.mjs builds final timeline HTML in modifyMarkdown() and returns it to the base markdown component.
src/component/Markdown.mjs then calls render({code: value}), and render() runs marked.parse(content) over the returned value.
- A parser probe confirmed that indented raw HTML passed through
marked.parse() can be converted into escaped <pre><code>..., which matches the visible literal-markup symptom.
The Architectural Reality
The Portal news timeline views are specialized subclasses of the shared markdown/content stack:
Portal.view.news.discussions.Component owns the Discussion grammar and generates .neo-timeline-item[data-record-id] HTML plus sections records for Portal.view.content.TimelineCanvas.
Neo.component.Markdown.afterSetValue() treats modifyMarkdown() output as markdown input and routes it through render({code}).
Neo.component.Markdown.render() is the shared markdown compiler and is correct for markdown input, but Discussion timeline HTML is already generated HTML by the time it returns from the subclass.
The fix must preserve the shared Markdown component's behavior for normal docs/pages and avoid broad sanitizer/parser changes that would destabilize DevIndex or learn content.
The Fix
Add a narrow render-path fix for Portal discussion timeline HTML so generated timeline markup is inserted as HTML rather than being parsed again as markdown code. Candidate shape:
- Add a discussion-specific helper/override only if the scope can stay local.
- Or add a small opt-in hook/config in the shared Markdown/content stack if tests show the same final-HTML contract is shared by tickets/pulls/discussions.
- Add unit coverage using the real discussion grammar: generated timeline HTML must survive as DOM HTML, while comment markdown and fenced code inside comments still render correctly.
Acceptance Criteria
Out of Scope
- Timeline/canvas spine placement bugs.
- Rewriting the tickets/pulls timeline renderers unless the verification step proves the same failure is active there.
- Changing GitHub sync output or editing
resources/content/discussions/** source markdown.
- Broad HTML sanitization policy changes.
Related
- Discussion content repro:
resources/content/discussions/chunk-2/discussion-11891.md
- Sibling active Portal News work: #12204
- Delegated by @neo-opus-ada via A2A message
MESSAGE:966f1625-3bf0-4478-bd7d-855e2ab9ec90
Handoff Retrieval Hint: Portal discussion timeline HTML literal rendering marked.parse modifyMarkdown render pipeline
Context
@tobiu surfaced a Portal News Discussions rendering defect via @neo-opus-ada: discussion comment bodies can display the timeline component's own generated HTML markup as literal text, e.g.
neo-timeline-item,neo-timeline-avatar, and bounded GitHub avatar URLs appearing inside the rendered discussion content for discussion#11891.This ticket exists because the symptom is separate from the parallel timeline/canvas spine work and needs its own owner.
The Problem
The discussion markdown file itself does not contain the leaked generated timeline markup. Local V-B-A against
resources/content/discussions/chunk-2/discussion-11891.mdfound ordinary synced discussion markdown around the citedInput from GPT-5 Codex (Codex Desktop)comment, but notimeline-11891-2,neo-timeline-item, orneo-timeline-avatarstrings.The likely failure boundary is the render pipeline:
apps/portal/view/news/discussions/Component.mjsbuilds final timeline HTML inmodifyMarkdown()and returns it to the base markdown component.src/component/Markdown.mjsthen callsrender({code: value}), andrender()runsmarked.parse(content)over the returned value.marked.parse()can be converted into escaped<pre><code>..., which matches the visible literal-markup symptom.The Architectural Reality
The Portal news timeline views are specialized subclasses of the shared markdown/content stack:
Portal.view.news.discussions.Componentowns the Discussion grammar and generates.neo-timeline-item[data-record-id]HTML plussectionsrecords forPortal.view.content.TimelineCanvas.Neo.component.Markdown.afterSetValue()treatsmodifyMarkdown()output as markdown input and routes it throughrender({code}).Neo.component.Markdown.render()is the shared markdown compiler and is correct for markdown input, but Discussion timeline HTML is already generated HTML by the time it returns from the subclass.The fix must preserve the shared Markdown component's behavior for normal docs/pages and avoid broad sanitizer/parser changes that would destabilize DevIndex or learn content.
The Fix
Add a narrow render-path fix for Portal discussion timeline HTML so generated timeline markup is inserted as HTML rather than being parsed again as markdown code. Candidate shape:
Acceptance Criteria
#11891no longer renders generatedneo-timeline-item/neo-timeline-avatarmarkup as literal text in comment content..neo-timeline-item[data-record-id]nodes and still populate thesectionsstore.markedas expected, including blockquotes and normal fenced code blocks inside comment bodies.Out of Scope
resources/content/discussions/**source markdown.Related
resources/content/discussions/chunk-2/discussion-11891.mdMESSAGE:966f1625-3bf0-4478-bd7d-855e2ab9ec90Handoff Retrieval Hint:
Portal discussion timeline HTML literal rendering marked.parse modifyMarkdown render pipeline