perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

perf(chat): bound MarkdownState residency with windowed eviction - #252

Merged
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction
Aug 22, 2026
Merged

perf(chat): bound MarkdownState residency with windowed eviction#252
Tryanks merged 1 commit into
mainfrom
perf/117-mdstate-eviction

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Implements the MarkdownState half of #117 (timeline payload paging deliberately deferred — noted in the issue).

  • Window: visible turns ±8 build margin; eviction beyond ±24 (3× hysteresis vs the build margin, on top of the list's 4-viewport measurement overdraw) — scrolling can't thrash build/evict.
  • Pins: active/streaming turns, the last two composer-adjacent turns, selection participants; no eviction during an active selection drag.
  • Stability: eviction removes only md_states entries — the outer ListState height cache survives, so absolute scroll anchors hold to the pixel (asserted turn 40 + 7px in tests). Rebuilds remeasure only contiguous rebuilt ranges. Tail-follow and the palette one-shot turn-target jump (rebuild → scroll → highlight → consume) keep working.
  • Measured (240-turn × 3-entry synthetic session): 720 resident states before → 48 at tail, 78 mid-history — red baseline test failed pre-fix, passes post-fix, with a test-accessible resident count as the regression hook.

Gates: fmt / clippy -D warnings / full workspace tests (825 passed) — green locally.

Closes#117

🤖 Generated with Claude Code

sync_markdown_states no longer materializes a MarkdownState per entry
for the whole session. States are built for the visible turn range ±8
turns and evicted beyond ±24 (3x hysteresis so scrolling doesn't
thrash), with pins for active/streaming turns, the composer-adjacent
tail, and any selection participants; nothing is evicted during a drag.
Outer list measurements survive eviction so scroll anchors stay exact;
rebuilds remeasure only the rebuilt ranges. Palette turn-target jumps
rebuild the destination before scrolling. A 240-turn synthetic session
drops from 720 resident states to 48 at tail / 78 mid-scroll
(regression-tested with a resident-count hook).
Timeline payload paging stays deferred (#117 discussion) — this bounds
the UI-entity side only.
Closes#117
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge (squash) August 22, 2026 15:47
@Tryanks
Tryanks merged commit 64e3ed9 into mainAug 22, 2026
3 checks passed
@Tryanks
Tryanks deleted the perf/117-mdstate-eviction branch August 22, 2026 15:53
@TryanksTryanks mentioned this pull request Aug 23, 2026
12 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded in-memory growth: timeline + per-message MarkdownState never evicted

1 participant

@Tryanks