Skip to content

fix(web): recover aborted srcdoc previews - #7055

Merged
lefarcen merged 8 commits into
mainfrom
fix/community-remix-srcdoc-completion
Aug 18, 2026
Merged

fix(web): recover aborted srcdoc previews#7055
lefarcen merged 8 commits into
mainfrom
fix/community-remix-srcdoc-completion

Conversation

@lefarcen

@lefarcen lefarcen commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Why

Community template remixes and existing HTML artifacts could intermittently open as a blank file preview in packaged clients. We reproduced the issue against the original incident artifact and a colleague's diagnostics from stable 0.19.2: Electron repeatedly aborted the about:srcdoc subframe with ERR_ABORTED (-3), while the injected head bridge could still answer readiness probes. That let a half-parsed document look healthy, leaving users to toggle Code and Preview to force a remount.

The same investigation found that deck thumbnails ignored approved @import webfonts, and that the existing white-screen detector treated hidden tabs, zero-sized preview frames, and one transient blank sample as confirmed failures. Historical PostHog events therefore mixed real blank previews with recoverable layout stalls and false positives.

What users will see

  • An interrupted HTML preview now retries through the lazy shell and renders without requiring a Code/Preview toggle.
  • Deck thumbnails preserve approved imported webfonts; unsafe or malformed layout imports fall back to the isolated iframe renderer.
  • A first blank observation performs one bounded layout/resize nudge. If paint recovers, no white-screen event is emitted.
  • Hidden tabs and zero-sized previews wait until they are visible and measurable. A blank preview is reported only after a second observation 1.5 seconds later.
  • Confirmed blank-preview events include bounded sampling and transport metadata without authored DOM text.

Surface area

  • UI — new page / dialog / panel / menu item / setting / empty state in apps/web or apps/desktop (including Electron menu bar)
  • Keyboard shortcut — new or changed
  • CLI / env var — new od subcommand or flag, new tools-dev / tools-pack flag, or new OD_* env var
  • API / contract — the internal preview-observability wire shape in packages/contracts adds bounded confirmation metadata
  • Extension point — new entry under skills/, design-systems/, design-templates/, or craft/, or change to the skills protocol
  • i18n keys — added new translation keys (see TRANSLATIONS.md for the locale workflow)
  • New top-level dependency — adding any new entry to the root package.json (dependencies or devDependencies); workspace-package package.json files are out of scope. Include a paragraph on what we get vs. what bytes we ship (see CONTRIBUTING.md → Code style)
  • Default behavior change — changes automatic preview recovery and white-screen reporting
  • None — internal refactor, docs, tests, or translation update only

Screenshots

No UI chrome changed. The behavior was verified in real Chrome across initial load, Code → Preview toggling, cold reload, background/foreground transitions, and forced blank/half-document fixtures.

Bug fix verification

  • Red-spec paths:
    • apps/web/tests/components/FileViewer.srcdoc-refresh-recovery.test.tsx
    • apps/web/tests/runtime/preview-observability-bridge.test.ts
  • Red on the previous implementation, green on this branch: yes.
    • An eager head-bridge acknowledgement could survive after the document body was aborted; the recovery tests require the body-tail completion witness and remount when it is absent.
    • The previous detector's four new behavioral tests all failed: hidden tab, zero viewport, recoverable layout stall, and one-sample reporting. All four pass on this branch.

Validation

  • pnpm guard
  • pnpm typecheck
  • White-screen regression group: 7 Web test files, 411 tests passed
  • Preview observability contract: 4 tests passed
  • Real Chrome + Open Browser Use on the final head:
    • hidden tab remained silent beyond the previous timeout
    • foreground layout stall recovered after one resize nudge without reporting
    • confirmed blank preview emitted one event after two observations with blank_observation_count=2 and sample_interval_ms=1500
    • original srcdoc recovery paths remain covered by the unchanged eight-case recovery suite
  • Live PostHog dashboard: https://us.posthog.com/project/420348/dashboard/2007098

@lefarcen lefarcen added the backport release/v0.20.0 Backport this fix to release/v0.20.0 label Aug 18, 2026
@lefarcen
lefarcen requested a review from PerishCode August 18, 2026 10:31
@lefarcen lefarcen added size/L PR changes 300-700 lines risk/medium Medium risk: regular code changes type/bugfix Bug fix labels Aug 18, 2026
@lefarcen
lefarcen marked this pull request as ready for review August 18, 2026 10:38

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The srcdoc completion/recovery path is coherent and the telemetry remains content-bounded, but the new CSS import extraction can corrupt otherwise renderable thumbnail styles because it does not distinguish CSS strings from top-level import rules.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/web/src/runtime/deck-thumbnail-parser.ts Outdated
@lefarcen lefarcen added the needs-validation Runtime change detected; needs human or /explore agent validation. label Aug 18, 2026
@lefarcen

Copy link
Copy Markdown
Contributor Author

🧪 This PR has changes that need a manual QA pass before merge — please hold off self-merging for now; we'll loop QA in once it's merge-ready (and design/product have signed off, where applicable).

@lefarcen
lefarcen requested a review from PerishCode August 18, 2026 10:45

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The srcdoc completion witness and recovery path are coherent, and the previous string-matching blocker is fixed. The import lifting still changes CSS semantics for conditional or otherwise inactive imports, so the thumbnail fidelity portion needs one more correction before merge.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/web/src/runtime/deck-thumbnail-parser.ts
@lefarcen

Copy link
Copy Markdown
Contributor Author

The current blocker is already captured in @PerishCode's review: the new CSS import extraction still needs to avoid treating inert @import text inside CSS string values as a live import. Once that path is fixed on the current head, we can re-check from there.

💡 To drive this PR to merge hands-free, paste this to your AI coding agent (Claude Code / Codex / opencode / Cursor …):
Take over nexu-io/open-design#7055 until it merges — read https://raw.githubusercontent.com/nexu-io/looper/main/skills/pr-takeover/SKILL.md and follow it.

@lefarcen
lefarcen requested a review from PerishCode August 18, 2026 10:52

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The CSS import follow-ups now preserve import placement and conditions, but the new srcdoc completion check is based on mutable authored DOM rather than a latched parser witness. That can misclassify healthy previews or accept incomplete ones, so the recovery path still needs one correction before merge.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/web/src/runtime/srcdoc.ts Outdated
@lefarcen

Copy link
Copy Markdown
Contributor Author

The current blocker has moved since the last push: @PerishCode's latest review is now focused on the srcdoc completion witness using mutable authored DOM rather than a latched parser witness. Once that current-head issue is addressed, we can re-check from there.

@lefarcen
lefarcen requested a review from PerishCode August 18, 2026 11:00

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The generation-specific completion latch fixes the prior mutable-marker problem, and the CSS import follow-ups remain sound. One recovery branch still conflates a healthy parser-blocked document with an aborted document and can re-execute authored code, so this needs correction before merge.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/web/src/components/FileViewer.tsx
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Visual regression review

Head: 58a2825 · Base: afdc388

0 changed · 49 unchanged · 0 new without baseline · 0 failed

Unchanged cases
Case Main PR Diff
visual-avatar-local-agent-list
0 px (0.00%)
main pr diff
visual-avatar-local-agent-list-panel
0 px (0.00%)
main pr diff
visual-avatar-menu
0 px (0.00%)
main pr diff
visual-avatar-menu-panel
0 px (0.00%)
main pr diff
visual-avatar-open-design-model-picker
0 px (0.00%)
main pr diff
visual-critical-settings
0 px (0.00%)
main pr diff
visual-critical-workspace
0 px (0.00%)
main pr diff
visual-critical-workspace-preview
0 px (0.00%)
main pr diff
visual-design-system-detail
0 px (0.00%)
main pr diff
visual-design-systems
0 px (0.00%)
main pr diff
visual-home
0 px (0.00%)
main pr diff
visual-home-catalog
0 px (0.00%)
main pr diff
visual-home-context-picker
0 px (0.00%)
main pr diff
visual-home-context-picker-popover
0 px (0.00%)
main pr diff
visual-home-plugin-filter
0 px (0.00%)
main pr diff
visual-home-plugin-use-staged
0 px (0.00%)
main pr diff
visual-home-plugin-use-with-query
0 px (0.00%)
main pr diff
visual-home-staged-attachment
0 px (0.00%)
main pr diff
visual-integrations
0 px (0.00%)
main pr diff
visual-integrations-mcp
0 px (0.00%)
main pr diff

Visual diff is advisory only and does not block merging.

@lefarcen

Copy link
Copy Markdown
Contributor Author

The current blocker has moved again on this head: @PerishCode's latest review now points at a remaining recovery branch that still conflates a healthy parser-blocked document with an actually aborted one. Once that current-head distinction is fixed, we can re-check from there.

@lefarcen
lefarcen requested a review from PerishCode August 18, 2026 11:14

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@lefarcen The current head now distinguishes completed, settled-incomplete, and still-parsing srcdoc documents without remounting a healthy parser-blocked frame, while retaining bounded recovery for a genuinely stuck generation. I also verified that stylesheet imports are lifted only when doing so preserves activation semantics, with safe iframe fallback otherwise, and that the added telemetry remains content-bounded. The focused recovery, parser, srcdoc, and observability suites pass (92 tests), as does the web typecheck. Thank you for working through the follow-up edge cases carefully—the final recovery lifecycle and regression coverage are strong.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen
lefarcen requested a review from ivy-ting August 18, 2026 11:28
@lefarcen

Copy link
Copy Markdown
Contributor Author

QA:旧版本复现与本 PR 验收

这个问题是 Chromium/Electron 的 about:srcdoc 导航竞态。手工操作会受机器负载影响,因此建议同时使用下面两条验证路径:A 用于用户视角验收,B 是 100% 可重复的回归门禁。

A. 旧客户端用户态复现(0.19.2 / prerelease.2)

  1. 使用干净会话启动旧客户端,进入 Community,Remix 下面这个 Deck:
    • 中文标题:像首席架构师一样讲工程蓝图——一份可商业交付的产品管理 Deck,围绕真实主题、证据链与决策目标组织。
    • 封面标题:PRESENT AN ENGINEERING BLUEPRINT LIKE A PRINCIPAL ARCHITECT
  2. Remix 后保持 index.html 停留在“预览”,不要先切到“代码”;内容开始落盘后执行一次 Cmd/Ctrl+R 冷刷新。
  3. 如第一次未命中,在新的 Remix 副本中重复步骤 1–2。这个竞态在较慢机器/较高 CPU 负载下更容易命中。
  4. 旧版命中后的明确现象:
    • 左侧 slide thumbnails 已有内容;
    • 右侧主预览持续纯白超过 10 秒;
    • 点击“代码”,再切回“预览”,内容立即出现。
  5. 导出 diagnostics。成功命中的日志指纹是同一文件出现 about:srcdoc 子 frame 加载失败,并带 ERR_ABORTED (-3);通常会重复出现。

这条路径已在用户的 prerelease.2 现场和同事的 stable 0.19.2 diagnostics 中命中过同一指纹。由于它是浏览器时序竞态,手工路径是高置信复现,但不能保证每次必现。

B. 确定性复现(推荐作为回归门禁)

在 PR base/旧源码 afdc388b7b47 上,只取本 PR 的测试文件:

git fetch origin pull/7055/head:qa/pr-7055
git show qa/pr-7055:apps/web/tests/components/FileViewer.srcdoc-refresh-recovery.test.tsx > apps/web/tests/components/FileViewer.srcdoc-refresh-recovery.test.tsx
pnpm --filter @open-design/web exec vitest run -c vitest.config.ts --maxWorkers=2 tests/components/FileViewer.srcdoc-refresh-recovery.test.tsx

旧代码会在以下故障注入场景中稳定失败,因为 iframe 不会自愈 remount:

  • eager head acknowledgement 之后发生 aborted navigation、且没有 load
  • head bridge 仍存活,但 DOM 只解析了一半、body-tail marker 缺失;
  • 截断文档长期停留在 document.readyState=loading

切到 PR head 9a401ab342a8 后运行同一命令,预期该文件 8/8 通过

修复版产品验收标准

  • 同样 Remix/冷刷新后,主预览无需“预览 → 代码 → 预览”即可显示;若命中了最坏的 stuck-loading 分支,应在最多约 10 秒内自动恢复。
  • 正常但加载较慢的 parser-blocking 页面不会被误判并重复执行 authored boot script。
  • 左侧 Deck 缩略图与右侧主预览的字体/布局一致。
  • 若确实触发并执行了恢复,PostHog 会收到 client_preview_white_screenreason=srcdoc_transport_unverified;事件只含 transport/DOM 计数和 readyState,不上报用户 HTML 文本。

PostHog 看板:https://us.posthog.com/project/420348/dashboard/2007098

@AmyShang-alt AmyShang-alt removed the needs-validation Runtime change detected; needs human or /explore agent validation. label Aug 18, 2026
@AmyShang-alt AmyShang-alt added the validated Runtime change validated (via /explore Pass or manual QA). label Aug 18, 2026

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@lefarcen The current head preserves the generation-latched srcdoc completion and bounded parser grace recovery, keeps thumbnail font-import lifting semantically safe through iframe fallback, and now confirms blank previews only after a visibility/viewport-aware second sample and one layout nudge. I verified the changed ranges and prior follow-up fixes, then ran the focused web suites (96 tests), the preview-observability contract suite (4 tests), and the web typecheck successfully. Thank you for carrying this through the successive edge cases—the final recovery and observability behavior is carefully bounded and well covered.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen

Copy link
Copy Markdown
Contributor Author

补充浏览器级回归(commit c250eb3):

  • 新增 e2e/ui/app-design-files.test.ts 的 P0 critical Playwright 用例,走真实 daemon → 文件列表 → FileViewer iframe → safety telemetry 链路。
  • 修复前 9a401ab342:1/1 red,恢复型 fixture 持续隐藏,data-monitor-recovered=false
  • 当前 head:连续 2 次 green;恢复型白屏收到一次 resize nudge 后显示且不上报,持续白屏在首次 5s 采样时仍不报告、第二次 1.5s 确认后只报告 1 条,并校验 confirmation metadata。
  • @open-design/e2e typecheck 与 pnpm guard 通过。

隐藏 tab / 零视口门控仍由 apps/web/tests/runtime/preview-observability-bridge.test.ts 的 4/4 红绿行为测试覆盖;无头 Chromium 没有可靠的标准页面可见性仿真,因此没有在 Playwright 中伪造 document.visibilityState

@lefarcen
lefarcen requested a review from PerishCode August 18, 2026 13:13

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@lefarcen The current head keeps the generation-latched srcdoc recovery and semantically safe font-import fallback intact, and the new browser witness covers the full preview-to-safety-telemetry path for both a recoverable layout stall and a persistent blank. I re-reviewed every changed range, verified the focused web suites (96 tests), the preview-observability contract suite (4 tests), and both web and e2e typechecks. Thank you for adding the cross-layer regression coverage and for carrying the recovery behavior through the earlier edge cases—the final implementation is carefully bounded and well supported.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen
lefarcen added this pull request to the merge queue Aug 18, 2026
@AmyShang-alt

Copy link
Copy Markdown
Contributor

@lefarcen

Thanks for the contribution. I completed QA validation for this PR.

QA Acceptance Record

Scope:

  • Recovery of aborted or incomplete about:srcdoc previews without requiring a Preview → Code → Preview toggle.
  • Parser-blocked preview safety, Deck thumbnail font/import fidelity, and content-bounded white-screen telemetry.

Scope-to-evidence:

  • Srcdoc recovery → packaged Electron reproduced ERR_ABORTED (-3) and the main preview recovered automatically; focused Web tests passed.
  • Parser-blocked safety → the delayed authored boot executed once without an unnecessary remount.
  • Thumbnail fidelity → font import rendering and conditional-import iframe fallback passed.
  • Browser telemetry path → the current-head P0 Playwright regression and visibility/viewport/two-sample observability tests passed.
  • Regression scope → all applicable CI checks are green on c250eb35de4f021d8a9126a5f01c15f1253c6478.

Verified:

  • Focused Web and contracts suites and typechecks passed during QA.
  • Current-head CI is green, including the new daemon-to-FileViewer-to-safety-telemetry browser coverage.

Not verified:

  • A clean release package will be sampled after the official package is produced; this follow-up is accepted as non-blocking for this PR.
  • Live PostHog ingestion was not independently queried because the dashboard requires authenticated read access; event naming, bounded properties, and browser emission behavior are covered by code/tests.

Risks / notes:

  • This remains timing-sensitive Chromium/Electron behavior, so the post-build smoke should repeat the cold-refresh scenario on the official package.

Conclusion:

  • Accepted. Post-build package smoke is a non-blocking follow-up.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 18, 2026

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@lefarcen I reviewed the full changed ranges for srcdoc completion recovery, bounded white-screen confirmation telemetry, deck thumbnail font-import handling, and their web, contract, and Playwright coverage. The latest test-helper correction now selects the requested design-file tab before asserting the persistent-blank fixture, so the browser witness exercises the intended preview. The recovery state machine remains bounded and generation-scoped, the telemetry payload stays content-free and normalized, and approved font imports preserve safe fallback behavior. Nice work carrying the successive edge cases through to a focused, verifiable fix.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen
lefarcen added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit 42faa84 Aug 18, 2026
28 checks passed
@open-design-release-bot

Copy link
Copy Markdown
Contributor

Successfully created backport PR for release/v0.20.0:

lefarcen added a commit that referenced this pull request Aug 18, 2026
* fix(web): recover aborted srcdoc previews

* fix(web): parse only top-level stylesheet imports

* fix(web): preserve font import conditions

* fix(web): latch srcdoc parser completion

* fix(web): defer recovery while srcdoc parses

* fix(web): confirm blank previews before reporting

* test(e2e): cover preview white-screen monitoring

* test(e2e): select the requested preview file

(cherry picked from commit 42faa84)

Co-authored-by: lefarcen <935902669@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport release/v0.20.0 Backport this fix to release/v0.20.0 risk/medium Medium risk: regular code changes size/L PR changes 300-700 lines type/bugfix Bug fix validated Runtime change validated (via /explore Pass or manual QA).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants