') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); fix(desktop): keep transcript lifecycle registry-owned by Astro-Han · Pull Request #3711 · apache/maka · GitHub
Skip to content

fix(desktop): keep transcript lifecycle registry-owned - #3711

Merged
Astro-Han merged 1 commit into
apache:mainfrom
Astro-Han:fix/transcript-consumer-lifecycle
Aug 25, 2026
Merged

fix(desktop): keep transcript lifecycle registry-owned#3711
Astro-Han merged 1 commit into
apache:mainfrom
Astro-Han:fix/transcript-consumer-lifecycle

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep transcript consumers registered when a delivery send, acknowledgement, or capacity attempt fails
  • make the next delivery reset the existing consumer projection instead of silently detaching it
  • keep RuntimeHostSessionObservationRegistry as the sole transcript lifecycle authority and remove the Observer duplicate renderer-destruction listener

The production diff is +4 / -11. The earlier Renderer close/reopen retry has been removed; this repair adds no retry protocol, recovery state, or second consumer identity.

Root cause

RuntimeHostSessionObserver treated delivery work failure as consumer termination and removed the physical consumer from its indexes. RuntimeHostSessionObservationRegistry still retained the renderer logical registration because it owns continuity across Runtime Host replacement. Every later range request therefore passed the Registry and failed in the Observer with Desktop transcript consumer does not exist.

The diagnostic report cannot distinguish whether the original detach was triggered by a send failure, acknowledgement timeout, or delivery-capacity protection. All three entered the same silent-detach path.

Architecture

The lifecycle is now one-way:

  • the Registry owns whether the renderer transcript intent exists, including renderer destruction and Host replacement
  • the Observer owns bounded replica and delivery work, but a failed delivery is non-terminal; it marks the same consumer for a reset on the next attempt
  • the Renderer owns its materialized range and retains only its existing explicit user-facing reload action

This removes the conflicting Observer termination authority. Explicit close, renderer destruction, and Registry shutdown still release the consumer and idle Session normally.

Verification

  • RED: the new Observer regression failed on the old behavior with Desktop transcript consumer does not exist
  • node --test apps/desktop/dist/main/__tests__/runtime-host-session-observer.test.js apps/desktop/dist/main/__tests__/desktop-transcript-range-store.test.js — 51 passed
  • npm --workspace @maka/desktop run typecheck
  • npx biome check apps/desktop/src/main/runtime-host-session-observer.ts apps/desktop/src/main/__tests__/runtime-host-session-observer.test.ts
  • npm run check:asf-headers
  • real Electron fixture with temporary fault injection: forced a delivery failure, then observed the same consumer ID recover on the next transcript projection; no error toast or ErrorBoundary appeared. The probe, Electron window, fixture Runtime Host, installed Maka process, and residual Runtime Host were removed or stopped afterward.
  • full repository tests were not run locally

The previous CI failure was inherited from five missing ASF headers on the old base. #3708 fixed that baseline failure; this branch is rebased onto current green main and the new exact-head CI is running.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Codex diagnosed the lifecycle mismatch, performed the simplification audit, authored the Observer repair and regression coverage, and ran the focused automated and real-window verification. The commit includes the required Generated-by: Codex trailer.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

@Astro-Han
Astro-Han marked this pull request as ready for review August 24, 2026 11:43
Keep a transcript consumer registered after delivery failures and request a reset instead of silently detaching it. This preserves the Registry as the sole lifecycle authority across Host replacement and removes the Observer's duplicate renderer-destruction listener.
Generated-by: Codex
@Astro-Han
Astro-Hanforce-pushed the fix/transcript-consumer-lifecycle branch from a1da22e to 52adc4eCompareAugust 24, 2026 18:10
@Astro-HanAstro-Han changed the title fix(desktop): recover detached transcript rangesfix(desktop): keep transcript lifecycle registry-ownedAug 24, 2026

@Astro-HanAstro-Han left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this head and found no blocking issues. No P0-P2.

Checks on 52adc4e are test: success.

简体中文该头未发现阻断问题。

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed exact head 52adc4e70c2ae9020d98a822d1233cf37bf9c715 and found no P0-P3 issues.

The change keeps the renderer's logical transcript registration in RuntimeHostSessionObservationRegistry while treating send, acknowledgement-timeout, and delivery-capacity failures as recoverable Observer work. Renderer destruction, explicit close, Host replacement, and Registry shutdown still own the terminal cleanup paths; an initial open failure remains terminal on both layers, so the change does not leave split lifecycle state.

I verified the focused Observer, execution IPC, and Desktop manager suites (81 tests total), the Desktop main TypeScript build, Biome on both changed files, the ASF header audit, and the clean current-main merge tree. The exact-head hosted test check is terminal-success.

简体中文

我审查了精确提交 52adc4e70c2ae9020d98a822d1233cf37bf9c715,未发现 P0-P3 问题。

本变更在发送失败、确认超时或投递容量不足时保留 RuntimeHostSessionObservationRegistry 中的渲染器逻辑 transcript 注册,只把这些情况作为 Observer 的可恢复工作失败处理。渲染器销毁、显式关闭、Host 替换和 Registry 关闭仍负责终止清理;首次打开失败在两层仍然都是终止状态,因此不会留下分裂的生命周期状态。

我验证了 Observer、执行 IPC 与 Desktop manager 的相关测试(共 81 项)、Desktop main TypeScript 构建、两个变更文件的 Biome、ASF header 审计,以及与当前 main 的无冲突合并树。精确提交上的托管 test 检查已终态成功。

@Astro-Han
Astro-Han merged commit ed0a5ad into apache:mainAug 25, 2026
1 check passed
@Astro-Han
Astro-Han deleted the fix/transcript-consumer-lifecycle branch August 25, 2026 02:24
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.

2 participants

@Astro-Han@M4n5ter