Skip to content

fix(desktop): prevent code blocks with no tag, text, or yaml from bei… - #77258

Open
gfpyc wants to merge 2 commits into
NousResearch:mainfrom
gfpyc:fix/code-block-prose-misclassification
Open

fix(desktop): prevent code blocks with no tag, text, or yaml from bei…#77258
gfpyc wants to merge 2 commits into
NousResearch:mainfrom
gfpyc:fix/code-block-prose-misclassification

Conversation

@gfpyc

@gfpyc gfpyc commented Aug 3, 2026

Copy link
Copy Markdown

What does this PR do?

Fixes a bug where Hermes Desktop misclassifies fenced code blocks as prose — losing their CodeCard, stripping fence markers, and collapsing whitespace. Affected: text/plain/plaintext, yaml with bullet lists, markdown/md fences (rich-rendered as prose instead of code), and any non-COMMON language tag (gdscript, zsh, ...) whose content looks prose-like.

Root cause: Two functions in markdown-code.ts:

  • isLikelyProseFenceNON_CODE_FENCE_LANGUAGES included '', text, plain, plaintext, md, markdown, so explicit text-like tags were never treated as code; proseLines >= 3 && codeSignals === 0 then misclassified zero-code-signal content as prose.
  • isLikelyProseCodeBlock — the bulletLines >= 1 prose check caught YAML list items; the fallthrough caught text/plain/plaintext and any non-COMMON explicit tag (gdscript, zsh, ...).

Fix (2 files):

  1. isLikelyProseFence — any explicit, valid language tag (VALID_LANGUAGE_RE) is respected and rendered as code. Covers text/plain/plaintext/md/markdown (previously in NON_CODE_FENCE_LANGUAGES) and gdscript/zsh and other non-COMMON tags.
  2. isLikelyProseCodeBlock
    • exempt known code languages (COMMON_CODE_LANGUAGES, e.g. yaml/markdown) from the bullet-prose heuristic so their lists render as code;
    • respect any explicit, valid language tag, same guard as isLikelyProseFence.

Bare fences ('') keep the existing behavior: untagged paragraph fences still unwrap to prose, and config/key-value listings (SSH config, .env, INI) stay fenced via the existing isLikelyStructuredText guard. Unknown tags (e.g. Streamdown's heads) still classify as prose.

Related Issue

Fixes #77253

Type of Change

  • 🐛 Bug fix

Changes Made

  • apps/desktop/src/lib/markdown-code.ts: classification logic — explicit-tag respect in both prose-detection paths
  • apps/desktop/src/lib/markdown-code.test.ts: extended repro matrix (22 assertions)

How to Test

  1. text fence with 3+ lines of keyword-free text — CodeCard
  2. yaml fence with a bullet list — CodeCard
  3. gdscript (or any non-COMMON tag) fence with prose-like lines — CodeCard
  4. markdown/md fence — CodeCard with raw (highlighted) content
  5. bare (no tag) fence with 3+ lines of plain prose — still unwraps (existing behavior)
  6. text fence with SSH config / .env content — CodeCard (structured guard preserved)
  7. python``/bash` control — still renders normally

Verification

Trigger precision (verified): the misclassification fires at proseLines >= 3 && codeSignals === 0... content with zero code signals (no JS keywords like for/while, no operators => }{``,} ;, no HTML tags). English sentences frequently contain for/while` and are accidentally immune, which is why line-count alone looked unreliable. No sticky state: after a misclassified block, subsequent well-formed blocks render fine.

Behaviour table (tested on Windows 11, packaged app, after rebase onto latest main @ 1f8fdc7 desktop v0.17.0):

Fence type Before After
text with keyword-free lines Prose, collapsed CodeCard
yaml with bullet list Prose CodeCard
gdscript with prose-like lines Prose, no card CodeCard
markdown/md fence Rich-rendered as prose CodeCard (raw, highlighted)
Bare fence (no tag), plain prose Unwrapped (existing behavior) Unwrapped (unchanged)
text with SSH config / .env CodeCard (structured guard) CodeCard (unchanged)
python`` / bash` CodeCard CodeCard

Tests: 22/22 pass (markdown-code.test.ts): explicit-tag matrix (text/plain/plaintext/markdown/md/gdscript/yaml) across both functions + upstream regression cases (SSH config, .env, bullet-prose with unknown tags, structured-text veto, bare-prose unwrap).

Notes

Lebased onto latest main (includes upstream isLikelyStructuredText guard, #84664). The fix was narrowed to explicit-tag respect — bare fences intentionally keep the upstream unwrap philosophy.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/desktop Electron desktop app (apps/desktop/*) needs-decision Awaiting maintainer decision before any implementation labels Aug 3, 2026
@gfpyc
gfpyc force-pushed the fix/code-block-prose-misclassification branch 2 times, most recently from 9d91de0 to 6cda16a Compare August 14, 2026 12:24
@spfcraze

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary:
isLikelyProseCodeBlock still returns prose (no CodeCard) for a non-COMMON explicit language tag such as gdscript or zsh when the fenced body is a bullet list, because the new explicit-tag guard sits after a bullet-prose heuristic that only exempts COMMON_CODE_LANGUAGES.

Problems:

  • In apps/desktop/src/lib/markdown-code.ts the new explicit-tag guard (line 422) runs after the bullet-prose heuristic (lines 403-407), whose exemption names only COMMON_CODE_LANGUAGES (line 406), so a non-COMMON tag with bulletLines >= 1 and proseLines >= 2 returns prose before the guard is reached.
  • Verified against the PR head logic: isLikelyProseCodeBlock('gdscript', '- item one\n- item two') returns true (prose) while isLikelyProseFence on the same input returns false (code); isLikelyProseCodeBlock is the render-time decision point consulted for CodeCard rendering, so such a fence renders without a CodeCard.

Solution:
Place the explicit-tag respect ahead of the bullet-prose check in isLikelyProseCodeBlock (or fold non-COMMON explicit tags into the exemption) and add a test exercising a non-COMMON tag whose body is a bullet list.

Evidence

no deterministic fact backs this claim — model belief, not executed or read evidence


Checked against 6cda16a — the tip of fix/code-block-prose-misclassification when this was written — and c896c09, main at the same moment.

gfpyc added 2 commits August 15, 2026 01:26
…ction

XpycT's repro matrix (text/markdown/gdscript/yaml fences whose content
looks prose-like, >=3 lines with zero code signals) is still broken on
main: the prose heuristics strip the fence and collapse the block into a
flat paragraph. The recent isLikelyStructuredText guard only protects
config/structured listings, not explicit-tag fences with prose-looking
content.

Respect any explicit, valid language tag in both isLikelyProseFence and
isLikelyProseCodeBlock: a fenced block with a real tag (text, plain,
plaintext, markdown, md, gdscript, yaml, ...) renders as code regardless
of how prose-like the body looks. Bare fences ('') keep the existing
behavior — untagged paragraph fences still unwrap, and config/key-value
listings stay fenced via isLikelyStructuredText.

Also exempt COMMON code languages from the bullet-prose heuristic in
isLikelyProseCodeBlock so yaml/markdown lists render as code, while
unknown tags (e.g. Streamdown's 'heads') still classify as prose.
The explicit-tag guard ran after the bullet-prose heuristic, so non-COMMON
languages (gdscript/zsh) and NON_CODE tags (text/plain/plaintext) with
bullet-list bodies were still prose-classified before the guard was reached.

Move the explicit-tag guard ahead of the bullet heuristic, keeping the
Streamdown 'heads' case (bullet + inline markdown emphasis) as prose per the
upstream test. Adds whole-class bullet-list coverage plus the numbered
Chinese prose repro reported on macOS (text/prompt tags).
@gfpyc
gfpyc force-pushed the fix/code-block-prose-misclassification branch from 6cda16a to 040b277 Compare August 14, 2026 17:27
@gfpyc

gfpyc commented Aug 14, 2026

Copy link
Copy Markdown
Author

@spfcraze Thanks for the triage report — confirmed and fixed.

You were right that the explicit-tag guard ran after the bullet-prose heuristic, and the gap was wider than reported: it covered not just gdscript/zsh but the whole NON_CODE family (text/plain/plaintext) too, since none of them are in COMMON_CODE_LANGUAGES.

What changed in 040b277:

  • Moved the explicit-tag guard ahead of the bullet heuristic in isLikelyProseCodeBlock.
    • Kept the Streamdown heads case (bullet + inline markdown emphasis) as prose — the upstream test still passes.
    • Added whole-class regression tests: gdscript/zsh/text/plain/plaintext with bullet-list bodies (fence and code-block layers), plus the numbered Chinese prose repro Stone441 reported on macOS (text/prompt tags).
      Verified: 30/30 vitest pass, plus packaged-app rendering on Windows 11 — bullet lists under non-COMMON tags now render as CodeCards; heads and bare-prose unwrap behavior unchanged.

@gfpyc

gfpyc commented Aug 18, 2026

Copy link
Copy Markdown
Author

Hi @danspicytaco — thanks for cross-referencing this. Since #58023 and this PR both touch the fence-classification heuristics in apps/desktop/src/lib/markdown-code.ts from complementary angles, let me lay out the current coverage so we can consolidate rather than compete:

This PR (#77258) — 30 vitest cases covering:

  • Any explicit valid language tag (gdscript, zsh, text, plain, plaintext, md, markdown, ...) renders as code, never downgraded to prose
  • Bullet-list bodies under non-COMMON tags (the spfcraze regression class)
  • md/markdown fences stay raw code blocks (mainstream AI chat UI convention)
  • Chinese numbered prose under text/prompt fences (Stone441's macOS repro)
  • Bare fences still unwrap as prose when the content is prose-like (upstream philosophy preserved)

#58023 covers:

  • Shell fence aliases (zsh/fish/powershell/cmd) with $HOME/$USER markdown/math side effects
  • End-to-end preprocessMarkdown regression coverage

Neither is a strict superset of the other — they touch different guard branches in the same file, so both change sets can merge cleanly if the maintainers want to consolidate. I'm happy to rebase/coordinate so we land a single fix quickly; this bug has been open since early August and is reproducible on Windows 11 (XpycT) and macOS (Stone441).

@alt-glitch @teknium1 — could we get a consolidation decision (and the workflows approved)? The P3 label may undersell this: it breaks code-card rendering for any non-COMMON tagged fence on Desktop.

@djedi

djedi commented Aug 19, 2026

Copy link
Copy Markdown

Merge this please! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) needs-decision Awaiting maintainer decision before any implementation P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Desktop code blocks with no language tag, text, or yaml are not rendered — misclassified as prose by isLikelyProseFence

4 participants