Fix webgl rendering corruption from atlas page merges#5883
Open
vsych wants to merge 1 commit into
Open
Conversation
e7ccd52 to
15a2469
Compare
15a2469 to
ae77634
Compare
26430b0 to
d9accc4
Compare
This was referenced May 18, 2026
d9accc4 to
dc726a2
Compare
hesnotsoharry
added a commit
to hesnotsoharry/Ouroboros
that referenced
this pull request
May 19, 2026
Per ADR Decision 3 (RESOLVED 2026-05-18): keep WebGL, vendor upstream fix via self-contained Node postinstall patcher (no new deps - avoids the per-repo lockfile-sync dance). Root cause (Phase C sonnet-diagnostician, high confidence): - Upstream: xtermjs/xterm.js#5847 (OPEN 2026-04-27) - WebGL atlas page-merge corruption with allowTransparency:true + heavy streaming. - Fix: xtermjs/xterm.js#5883 (OPEN 2026-05-17, NOT MERGED). - Symptom in Ouroboros: ghost cursors in random positions during Claude TUI thinking; ghost in front of typing cursor. - Match: same lib version (@xterm/addon-webgl 0.19.0), same config flag, same workload as the upstream repro. Vendor patch shape: - patches/addon-webgl-0.19.0.original.{mjs,js} - shipped 0.19.0 snapshot. - patches/addon-webgl-0.19.0.patched.{mjs,js} - PR #5883 changes applied: (1) AtlasPage.version becomes monotonic global (5 increment sites); (2) TextureAtlas.beginFrame() resets _requestClearModel before return; (3) WebglRenderer.renderRows() adds bounded retry loop (max 3) after _updateModel to handle mid-update merges. - tools/apply-patches.mjs - SHA-256 based; copies patched bundle if installed matches original. Idempotent. Soft-warns and exits 0 if bundle SHA matches neither (upstream update detected - patch needs re-mapping or removal). Wired into package.json postinstall chain. - patches/README.md - removal flow (bump dep + delete patch files when upstream ships >= 0.19.1). Companion changes: - eslint.config.mjs - tools/**/*.mjs added to Node-globals block. - Terminal/CLAUDE.md - gotcha entry pointing to the patch + removal. - useTerminalSetup.lifecycle.ts - structural baseline trace from diagnostician (3 [xterm-init] log lines, kept per debug-before-fix.md). Live verification by Cole REQUIRED before marking phase resolved - ghost cursor disappearance can only be confirmed by running the IDE against a real Claude TUI streaming workload. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two bugs in the webgl renderer cause the corruption from #5847.
1. Texture binding stale after a same-index page swap.
GlyphRenderer.renderonly rebinds a texture unit onversionmismatch, but after_createNewPagemerges 4 pages into 1, the page object at the merged index swaps to a freshmergedPage. With per-page counters the new page'sversionoften coincided with the version we last bound at that index (the freshly-pushed mergedPage always landed on1). The rebind was skipped and the texture kept the old page's canvas, so glyphs sampling that unit got garbage.Make
AtlasPage.versionmonotonic across all pages and the existing comparison detects a same-index swap, no extra bookkeeping required.2. Stale
texturePagein the vertex buffer after a mid-update merge. When a merge fires inside_updateModel, cached glyphs get a newtexturePage. Cells already written in this pass (or carried over via the model-unchanged early-exit) still point at the pre-merge index._requestClearModelwas set on merge butbeginFramenever reset it, so it stayed true forever; andrenderRowsonly checked it before_updateModel, so a mid-pass merge went unhandled._requestClearModelwhenbeginFramereads it_updateModel, re-run a full update if a merge fired during the pass (capped atMERGE_RETRY_LIMIT)Before:


After:
Stress repro with the script from #5847 (full-screen rewrite, many colors, frequent merges):
Before this PR:
After this PR: