Skip to content

Inline citations delete the line breaks that follow them, collapsing paragraphs into the previous block #1289

Closed

Description

@paullizer

Issue

Inline document citations in assistant chat messages delete the whitespace that follows them. The citation link itself renders correctly, but the text that comes after the citation is jammed onto the end of the closing ) instead of starting a new paragraph, list item, or sentence. This affects every user reading a cited answer in chat.

Steps to Reproduce

  1. Ask a question in a workspace that returns document citations (personal, group, or public).

  2. Have the model answer with a citation followed by a blank line and then more prose, which is its normal output shape:

    ... used to support cited answers in chat. (Source: application_workflows.md, Page: 1) [#181b54f7-fcf9-479b-a58b-81a5da3ba251_1]
    
    Admins can configure the extraction approach for images and PDFs under **Admin Settings > Search & Extract**.
    
  3. Look at the rendered assistant message.

Expected Behavior

The paragraph after the citation renders as its own block, exactly as the model wrote it:

... used to support cited answers in chat. (Source: application_workflows.md, Page: 1)

Admins can configure the extraction approach for images and PDFs under Admin Settings > Search & Extract.

Actual Behavior

The blank line is gone and the following paragraph is absorbed into the line — and, when the citation is inside a numbered list, into the list item:

  1. Grounded chat: ... used to support cited answers in chat. (Source: application_workflows.md, Page: 1)Admins can configure the extraction approach for images and PDFs under Admin Settings > Search & Extract. The available modes are:

Other observed forms in the same message:

  • ...warrants it (Source: document-intelligence.md, Page: 1)For best results, upload clear, readable images.
  • ...(Source: uploading_documents.md, Page: 1)Thank you, Paul.

Impact

  • Message structure is visibly wrong: paragraphs collapse into the preceding list item, headings and bullets shift, and sentences run together with no space after ).
  • The damage happens before markdown parsing, so it changes how the whole remainder of the block is interpreted, not just the characters next to the citation.
  • Copied and exported message markdown is built from the same parsed output, so it inherits the lost line breaks.
  • Content is still readable, so this is a presentation defect rather than a data-loss or security issue.

Notes

Suspected root cause is in parseCitations() in application/single_app/static/js/chat/chat-citations.js:

const citationRegex = /\(Source:\s*(...),\s*(Page(?:s)?|Sheet(?:s)?|Location):\s*(...)\)\s*((?:\[#.*?\]\s*)+)/gi;

The trailing \s* inside the repeated bracket group is greedy and matches newlines, so it consumes the whitespace after the [#citation-id] marker. The replacement callback returns only the rebuilt (Source: ...) string and never re-emits that whitespace.

parseCitations() runs on raw markdown before marked.parse() (chat-messages.js, renderAiMessageContent()), so a swallowed \n\n changes markdown block parsing and the following paragraph becomes a continuation of the current block.

The cleanup pass a few lines below has the same class of defect in the other direction — its leading \s* can consume the newlines before a leftover [#guid] bracket that starts its own paragraph.

Reproduced against the production regex in isolation:

Input : "... in chat. (Source: application_workflows.md, Page: 1) [#181b54f7-..._1]\n\nAdmins can configure ..."
Output: "... in chat. (Source: application_workflows.md, Page: 1)Admins can configure ..."

Fix direction: preserve the trailing whitespace captured by the bracket group and re-emit it, and restrict the cleanup pass to horizontal whitespace so line structure survives. Server-side functions_citation_tracking.py is not implicated — it matches with a non-consuming lookahead.

Activity

  1. moved this from Pending Evaluation to Pending Assignment in Simple Chat Roadmapon Aug 19, 2026
  2. paullizer commented on Aug 19, 2026

    @paullizer
    ContributorAuthor

    Fixed on branch paullizer-fix-citation-whitespace-collapse (v0.250.228).

    What changed

    parseCitations() in chat-citations.js now captures the trailing whitespace off the matched [#citation-id] bracket group and re-emits it, so the blank line separating a citation from the next markdown block survives. Whitespace is restored exactly as the model emitted it, so a citation followed immediately by punctuation renders byte-identically to before.

    The leftover [#guid] cleanup pass had the same defect in reverse via its leading greedy \s*. It is now three ordered passes: a bracket run occupying a whole line is removed with its line, a run opening a line is removed with its trailing spacing, and an inline run consumes only spaces and tabs.

    These are whitespace-only changes. The emitted citation HTML is unchanged, so escaping, sanitization, and the XSS surface are untouched.

    Validation

    • functional_tests/test_chat_citation_whitespace_preservation.py executes the real parseCitations() in a Node sandbox, then renders the result with the vendored marked bundle, so it asserts user-visible block structure rather than regex output. 4/4 pass. All four fail against the pre-fix source, and each half of the fix was reverted independently to confirm both are covered.
    • ui_tests/test_chat_citation_paragraph_spacing.py seeds the reported message into the chat page and asserts the DOM: the numbered list item ends at its citation, the following text renders as its own <p>, and no sentence collides with a citation's closing parenthesis. Env-gated like the other UI tests.
    • Related suites re-run clean: test_agent_document_search_citations.py, test_markdown_citation_lookup_fallback.py, test_chat_cited_source_tracking.py, test_unicode_table_conversion.py, test_comprehensive_table_support.py, test_stored_xss_chat_workspace_rendering_fix.py, test_external_links_new_window.py, test_azure_maps_tile_token_refresh_fix.py.
    • A code review pass measured ReDoS behaviour on adversarial input (no new blowup; the pre-existing [^\]]*\] cost is unchanged) and probed CRLF, fenced code blocks, tables, blockquotes, headings, and list markers against the ^/m anchors. Every case where the new cleanup differs from the old is strictly less destructive — notably the old pass could break a fenced code block by pulling its closing fence onto the previous line.

    Before / after

    Rendered HTML for the reported message, before:

    <li><strong>Grounded chat:</strong> ... in chat. (Source: application_workflows.md, Page: <a ...>1</a>)Admins can configure ... The available modes are:</li>

    After:

    <li><strong>Grounded chat:</strong> ... in chat. (Source: application_workflows.md, Page: <a ...>1</a>)</li>
    </ol>
    <p>Admins can configure the extraction approach for images and PDFs under <strong>Admin Settings &gt; Search &amp; Extract</strong>. The available modes are:</p>

    Side effects worth noting

    • Back-to-back citations no longer collide.
    • copyMarkdown is built from the same parsed output, so copied and exported message text keeps its line breaks too.

    Docs

    • docs/explanation/fixes/CHAT_CITATION_WHITESPACE_COLLAPSE_FIX.md
    • Release notes entry under v0.250.228.

    No unresolved risks or follow-ups.

  3. added a commit that references this issue on Aug 19, 2026
    2cc66a1
  4. paullizer commented on Aug 19, 2026

    @paullizer
    ContributorAuthor

    PR: #1291 — open against Development, all 12 checks passing, merge state clean.

    One correction to my earlier comment: #1290 landed while this was in flight and had already claimed v0.250.228, so this fix rebased onto Development and ships as v0.250.229 instead. The release notes conflict was resolved by moving this entry into a new v0.250.229 section above the figure-chunk entry; the diff against Development is 7 files, all belonging to this fix.

  5. paullizer commented on Aug 19, 2026

    @paullizer
    ContributorAuthor

    Shipped in v0.250.229 via #1291.

    Release note entries:

    • v0.250.229: Citations No Longer Eat the Line Break After Them

    Full notes: https://microsoft.github.io/simplechat/explanation/release_notes/

    Closing as completed. This issue stayed open after the fix merged because pull requests target Development while the repository default branch is main, so GitHub never applied the Fixes # keyword automatically.

  6. moved this from Pending Assignment to Released in Simple Chat Roadmapon Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions