Skip to content

Release v0.50.295 — 3-PR batch (YAML/JSON/diff newlines + macOS scroll race + custom:* providers + glued-bold-lift raw pre)#1643

Merged
nesquena-hermes merged 9 commits intomasterfrom
stage-295
May 4, 2026
Merged

Release v0.50.295 — 3-PR batch (YAML/JSON/diff newlines + macOS scroll race + custom:* providers + glued-bold-lift raw pre)#1643
nesquena-hermes merged 9 commits intomasterfrom
stage-295

Conversation

@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Release v0.50.295 — 3-PR batch (YAML/JSON/diff newlines + macOS scroll race + custom:* providers + glued-bold-lift raw pre)

3 PRs from 3 contributors. Closes 5 issues: #1360, #1451, #1463, #1618, #1619.

What ships

#1642 by @nesquena-hermes — YAML/JSON/diff code block newlines (closes #1618, #1463)

Reporter @Zixim flagged that YAML rendering had been flattened to a single line since v0.50.237 despite PR #1516's CSS-only "fix" in v0.50.279. Live-rendered both ```yaml ... ``` and a control ```yml ... ``` block through renderMd() in the browser to verify — @Zixim was right, the bug was real on master. Root cause: PR #484 introduced <pre class="tree-raw-view"> for JSON/YAML and <pre class="diff-block"> for diff/patch, but the _pre_stash regex matched only literal <pre> (no attributes). One-character regex relax: <pre><pre[^>]*>.

Parallel-discovery: @Michaelyklam independently filed PR #1641 with the same fix 4 minutes earlier; closed as superseded by #1642 (which carries APPROVED + 322 LOC test suite covering YAML+JSON+diff vs YAML-only). UI before/after PNGs from #1641 adopted with Co-authored-by trailer.

#1639 by @bergeouss — macOS WKWebView auto-scroll race (closes #1360)

Trackpad scrolling up during streaming snapped viewport back to bottom. _programmaticScroll setTimeout(0) guard was racing with WKWebView momentum scrolling. rAF-debounce the scroll listener + 2-sample hysteresis counter requires two consecutive near-bottom samples before re-pinning.

#1639 by @bergeouss — custom:* provider model list (closes #1619)

Custom:* providers were only showing the default model in the dropdown. /api/models/live only handled bare custom, not custom:* slugs. Plus defensive belt-and-braces in api/config.py for dedup fallback.

#1637 by @Michaelyklam — protect raw <pre> from glued-bold lift (closes #1451)

renderMd() was restoring raw <pre> blocks BEFORE the glued-bold-heading lift ran, so literal preformatted text containing Para text.**Heading**\n\nNext got mangled by the lift. Move rawPreStash restore to AFTER markdown rewrites, BEFORE HTML sanitization.

Tests

4245 → 4255 passing (+10). 0 regressions. Full suite ~120s.

Pre-release verification

Authors

nesquena-hermes and others added 9 commits May 4, 2026 18:11
Closes #1618 (reported by @Zixim) and corrects #1463's previous fix.

Bug: YAML, JSON, and diff/patch fenced code blocks render flattened to a
single line. Reporter noted the bug persisted v0.50.279 -> v0.50.291 ->
v0.50.292 despite PR #1516's CSS-only "fix".

Root cause: PR #484 (v0.50.237) added a JSON/YAML tree-viewer that routes
those languages through <div class="code-tree-wrap">...<pre class="tree-raw-view">
instead of bare <pre>. Same release added the diff/patch coloring path
that emits <pre class="diff-block">. The _pre_stash regex at
static/ui.js:1914 matched only literal <pre> with no attributes:

    <pre>[\s\S]*?<\/pre>

Both new shapes failed to match, fell through to the paragraph-wrap pass,
and \n characters inside the code blocks got replaced with <br> tags
inside <code>. By the time Prism ran, no newlines remained for the CSS
rule (PR #1516, language-yaml .token { white-space: pre !important }) to
preserve.

Fix: relax the regex to accept any attribute on <pre>:

    <pre>[\s\S]*?<\/pre>  ->  <pre[^>]*>[\s\S]*?<\/pre>

One regex character. Pulls JSON, YAML, and diff/patch blocks into the
stash so paragraph-wrap can't mangle them. Bash, Python, Go, etc. were
never affected because they emit bare <pre>.

Tests: 9 new (2 source-string invariants + 7 behavioural via node-driver
against the actual static/ui.js renderMd()). 6 of the 7 behavioural tests
fail on master and pass with the fix; the 3 sanity checks (yml-alias,
bash, mermaid) pass on both.

Plus widened source-scan window in 3 pre-existing test_745 assertions
from 400 to 1500 chars. The new comment block above the fixed regex
pushed it past the previous scan window. Pure window-narrowness bug,
not a behavior regression.

4245 -> 4254 passing.
…l list (#1619)

#1360 — On macOS WKWebView, trackpad momentum scrolling fires scroll
events that interleave with the _programmaticScroll setTimeout(0) guard.
A mid-momentum scroll event either gets swallowed (_programmaticScroll
still true) or falsely reports nearBottom (momentum hasn't settled),
keeping _scrollPinned=true and snapping the viewport back down.

Fix: rAF-debounce the scroll listener so the nearBottom check runs at
the next paint frame when the browser's scroll position has settled.
Added a hysteresis counter requiring 2 consecutive near-bottom samples
before re-pinning, preventing accidental re-pin during deceleration.

#1619 — When a custom:* provider (e.g. custom:relay via custom_providers)
has models that overlap with auto-detected models from base_url /v1/models,
the dedup logic at config.py:2263 skipped them all. The named custom
group ended up empty, and the continue at line 2334 silently discarded
the auto-detected models. Result: only the default model appeared.

Fix 1 (config.py): When custom:* named group has 0 models after dedup,
fall back to auto_detected_models_by_provider instead of dropping them.

Fix 2 (routes.py): Extended /api/models/live fallback to handle
custom:* slugs (not just bare "custom") for both custom_providers
config lookup and base_url live fetch.
test_scroll_listener_hides_button_when_pinned checked 300 chars after
el.addEventListener('scroll', but the rAF-debounce fix moved the
scrollToBottomBtn logic into the requestAnimationFrame callback,
beyond the 300-char window. Extended to 600 to cover the full block.
#1641)

Adopt the UI media from @Michaelyklam's parallel-discovery PR #1641 which
shipped the same one-character regex relax fix for #1618. PR #1641 is
being closed as superseded by #1642 (which carries nesquena APPROVED +
322 LOC test suite); preserving Michael's UI evidence here so the visual
proof of the fix lives in-tree alongside the canonical PR.

Co-authored-by: Michael Lam <[email protected]>
Constituent PRs:
  #1637 by @Michaelyklam — protect raw pre from glued-bold lift (closes #1451)
  #1639 by @bergeouss — macOS auto-scroll race + custom:* provider list (closes #1360, #1619)
  #1642 by @nesquena-hermes — YAML/JSON/diff code block newlines (closes #1618, #1463)

Opus advisor SHIP verdict on stage-295. One observation absorbed:
- api/config.py:2533 dead-code comment per Opus (defensive belt-and-braces
  for #1619 fallback; load-bearing fix is in routes.py /api/models/live)

PR #1641 (Michaelyklam parallel-discovery duplicate of #1642) closed as
superseded; UI media adopted with co-author trailer.

4245 → 4255 tests passing (+10).
@nesquena-hermes nesquena-hermes merged commit 4085a1f into master May 4, 2026
3 checks passed
@nesquena-hermes nesquena-hermes deleted the stage-295 branch May 4, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment