Skip to content

fix(apps): promote inline srcDoc frames to their own layer (#8037) - #8076

Merged
iamwhatever merged 1 commit into
mainfrom
fix/srcdoc-frame-compositing-promotion-8037
Sep 3, 2026
Merged

fix(apps): promote inline srcDoc frames to their own layer (#8037)#8076
iamwhatever merged 1 commit into
mainfrom
fix/srcdoc-frame-compositing-promotion-8037

Conversation

@bolichen97

@bolichen97 bolichen97 commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Problem / Motivation

Two model-authored HTML frames build their document inline and hand it straight to srcDoc, never reaching the gateway sandbox-doc mint that #7931 covered:

Frame Site Promotion before this PR
Mochi widget frame website/src/apps/mochi/src/renderer/WidgetFrame.tsx (~:101) none — no transform at all
Meetings agent panel (html widget) website/src/apps/meetings/components/AgentPanel.tsx (~:251, buildSketchSrcdoc ~:260) none — no transform at all

Without layer promotion an engine can lay the document out, run its scripts, report a correct height, and never rasterize it: a correctly sized, visible frame painting an empty box, silent by construction — nothing fails, so there is no error state and no retry affordance. This is exactly the mechanism measured and fixed for the four useSandboxDoc consumers in #7931 (c222244), whose commit message filed these inline frames as the tracked remainder: #8037.

Why it matters

Both frames are model-output surfaces: Mochi's <mcwidget> renderer and the meetings sketch-artist panel. When the failure fires, the user's generated content silently doesn't exist — the worst kind of display bug, because the app looks healthy while showing nothing.

What changed (motivation → approach → change)

Port #7931's exact remedy onto the two inline-srcDoc frames:

  • WidgetFrame.tsx: add transform: 'translateZ(0)' to the iframe's inline style (composed into the existing style object; nothing dropped).
  • AgentPanel.tsx: same one-line promotion on the html-output iframe.

Neither frame carried an existing transform, so the plain 3D form suffices (the compose-onto-scale() care #7931 needed on its gallery thumbnail does not apply here). Per #7931's invariants, nothing about sandbox flags, CSP, or how the documents are built changes — buildSrcdoc / buildSketchSrcdoc and both sandbox attributes are byte-identical.

Scope. This PR fixes the two frames #8037 names — the model-authored surfaces #7931's commit message filed as the remainder. The review pass for this PR enumerated the rest of the un-promoted inline-srcDoc population, which is deliberately out of scope here and filed as #8075: McpAppFrame.tsx (~:1018, the primary residual — allow-scripts + script-reported height), both pptx-maker/BoardFrame.tsx frames (2D scale() only, needs the compose treatment), and FileRenderers.tsx HtmlViewer (:267). Keeping this PR at the issue's two frames mirrors #7931's own scope discipline.

Tests

  • New website/src/apps/mochi/test/mochiWidgetFramePromotion.test.tsx — first test to mount this component:
    • pins iframe.style.transform === 'translateZ(0)' (the regression is invisible in Chromium and in a test DOM, so the style assertion is the whole guard, as fix(dashboard): promote the widget and remote artifact frames to their own layer #7931's tests state);
    • pins the promotion is additive (display: block, width: 100%, border style survive) and that the wrapper's overflow: hidden clip is still present (the frame's bottom corners come from the rounded card);
    • pins the security invariants the promotion must not disturb: sandbox is exactly allow-scripts, and the model HTML reaches the frame only through buildSrcdoc's minted document, never raw.
  • website/src/test/MeetingsAgentPanel.test.tsx — the html-output suite gains the same promotion pin plus the sizing-survives assertion.

Local gates, all green: npx tsc -b; full website vitest suite (1783 files) exit 0; npx eslint src/ --max-warnings 597 → 0 errors, warnings at baseline; npx jscpd . → 0 clones; brand/feature-map/focus-cue root gates pass. Backend gates unaffected (frontend-only diff; CI skips backend jobs for this class).

Manual verification

Rendered both components in the test DOM and inspected the produced inline styles; verified both sandbox attributes and both srcdoc builders are byte-unchanged against base (git diff shows style-object-only edits). The defect itself has no deterministic local reproduction (engine-dependent rasterization skip), which is why #7931 established source-level pins as the guard; this PR follows that precedent.

Screenshots / video

Why no screenshot: translateZ(0) is a non-rendering compositing hint — on a correctly-rasterizing engine the before/after pixels are identical, so a screenshot pair would show two identical images (same waiver #7931 used for the same change class).

Related Issues

Closes #8037
Refs #7931
Refs #8075 (follow-up: remaining un-promoted srcDoc frames, enumerated during this PR's review)

Pattern harvest

The failure class is "sandboxed frame laid out but never rasterized"; the durable pattern is that every srcDoc/sandbox-doc frame needs translateZ(0) composed onto its transform, there is no enumerating test for the class, and each new frame must add its own pin. #8075 now carries the enumeration record for the remaining sites, so the next sweep starts from a list instead of a manual grep.

Rule candidate: every sandboxed srcDoc/sandbox-doc iframe must carry translateZ(0) composed onto its transform (a 2D transform alone makes a stacking context but does not promote), plus a source-level style assertion in its own test — the regression is invisible in Chromium and in a test DOM, so the pin is the whole guard.

Checklist

Contribution License Agreement

By submitting this pull request, I confirm that my contribution is made under the terms of the project license.

Mochi's WidgetFrame and the meetings AgentPanel render model-authored HTML
in sandboxed frames whose documents are built inline and passed to srcDoc,
so they never reach the gateway sandbox-doc mint that #7931 covered. Both
frames carried no compositing promotion, leaving them exposed to the same
measured failure mode: an engine lays the document out, runs its scripts,
reports a correct height, and never rasterizes it -- a correctly sized,
visible frame painting an empty box, silent by construction.

Port #7931's exact remedy onto both sites: transform: translateZ(0) added
to each iframe's inline style. Neither frame carried an existing transform,
so the plain 3D form suffices; nothing about sandbox flags, CSP, or how the
documents are built changes, matching the invariants #7931 kept.

Tests mirror #7931's promotion assertions: a new mochi test renders
WidgetFrame and pins the transform plus the survival of its existing inline
sizing, and the AgentPanel html-output suite gains the same pin. The
regression is invisible in Chromium and in a test DOM, so the style
assertions are the whole guard.

Closes #8037
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

UX-level review of 305a8bc3b9c0a25849269c6cfb6e15d6ec926308 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

The diff is minimal: it adds transform: translateZ(0) (compositing layer promotion) to two existing sandboxed iframes — the Meetings AgentPanel HTML output frame and the Mochi WidgetFrame — plus tests pinning the style. No new user-facing strings, no layout, control, or flow changes; it fixes a silent blank-frame rendering defect, extending a fix already shipped for sibling frames in #8037. translateZ(0) on an iframe doesn't alter perceived geometry, and the tests pin that sizing/clipping survive. Nothing for any UX lens to flag.

UX-Verdict: PASS

Invisible-by-design fix: promotes two srcDoc iframes to their own compositing layer so widgets stop rendering as silent empty boxes — pure UX win, zero surface change.

[UX-REVIEWED] 305a8bc

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 305a8bc3b9c0a25849269c6cfb6e15d6ec926308 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 305a8bc

Verdict parsed from the review's SHA-scoped output markers for commit 305a8bc3b9c0a25849269c6cfb6e15d6ec926308.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 305a8bc3b9c0a25849269c6cfb6e15d6ec926308: <one-sentence reason>

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of 305a8bc3b9c0a25849269c6cfb6e15d6ec926308 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Design-Verdict: PASS

A measured silent-blank failure, fixed with the codebase's established remedy, scoped exactly to the two frames the tracking issue names.

Suggestions

[DESIGN-REVIEWED] 305a8bc

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ PASS

Premise-level review of 305a8bc3b9c0a25849269c6cfb6e15d6ec926308 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

The verification is complete: the four #7931-promoted sites exist (ArtifactBody.tsx:459, components/WidgetFrame.tsx:629, ArtifactThumbs.tsx:184 composed with scale, RemoteArtifactDetailPage.tsx:377), the two touched frames had no prior transform, the diff changes nothing but the style objects plus tests, and the remaining un-promoted srcDoc siblings the description enumerates are exactly the ones my grep finds. Final review:

First-Principles-Verdict: PASS

A tracked defect's filed remainder, fixed by the codebase's own established remedy, with every rider absent and every unfixed sibling counted and declared.

What this change ships

Intent: make model-generated HTML in the Mochi widget frame and the meetings sketch panel actually paint instead of silently rendering an empty box. This is a FIX.

  1. Mochi widget frame gets its own compositing layer (translateZ(0)) — justified (tracked remainder of measured defect fix(dashboard): promote the widget and remote artifact frames to their own layer #7931/Model-authored srcDoc frames in mochi and meetings can render blank (no compositing promotion, outside the sandbox-doc mint) #8037)
  2. Meetings html-output frame gets the same promotion — justified (same defect, same tracked issue)
  3. New mochi test pinning the promotion, sizing survival, and sandbox/mint invariants — justified (style pin is the only possible guard; sandbox pins protect the external-content boundary)
  4. Meetings test gains the same promotion + sizing pin — justified

Verified mechanically: no existing shared helper does this job — all four #7931 sites (ArtifactBody.tsx:459, components/WidgetFrame.tsx:629, ArtifactThumbs.tsx:184, RemoteArtifactDetailPage.tsx:377) inline the same literal, so this is the existing spelling, not a second one. Sibling count: grepped srcDoc — 4 un-promoted frames remain (FileRenderers.tsx:267, McpAppFrame.tsx:1009, BoardFrame.tsx:61, BoardFrame.tsx:108), all four named in the description and filed as #8075, so the point-patch scope is declared and tracked, not silent. No undeclared items: both edits, both tests, and the security pins all appear in the description. The style objects are byte-additive; both sandbox attributes and srcdoc builders are untouched, as claimed.

[FIRST-PRINCIPLES-REVIEWED] 305a8bc

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of 305a8bc3b9c0a25849269c6cfb6e15d6ec926308 and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 305a8bc

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 305a8bc3b9c0a25849269c6cfb6e15d6ec926308: <one-sentence reason>

@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: passed Eligible automated validation passed for the current revision and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 3, 2026
@iamwhatever
iamwhatever enabled auto-merge (squash) September 3, 2026 05:04

@iamwhatever iamwhatever left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Tier 1 auto-approve: fix (4 files). Criteria: no conflict, no requested changes, security path denylist clean, design-doc gate clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: two srcDoc-built sandbox frames (meetings AgentPanel, mochi WidgetFrame) were left out of the #7931 compositing promotion because they never reach the sandbox-doc mint; adds transform: translateZ(0) plus style-contract tests that also pin the unchanged sandbox=allow-scripts and srcdoc-wrapper invariants.

@iamwhatever
iamwhatever merged commit 7f01086 into main Sep 3, 2026
71 of 73 checks passed
@iamwhatever
iamwhatever deleted the fix/srcdoc-frame-compositing-promotion-8037 branch September 3, 2026 05:04
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Sep 3, 2026

@chenmingwei23 chenmingwei23 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.

Tier 1 auto-approve: fix (4 files). Criteria: no conflict, no requested changes, security path denylist clean, design-doc gate clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: fix - adds a CSS compositing-layer promotion (transform translateZ(0)) to two inline srcDoc iframes so they paint; sandbox attribute untouched, no behaviour change beyond rendering.

Sign up for free to 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.

Model-authored srcDoc frames in mochi and meetings can render blank (no compositing promotion, outside the sandbox-doc mint)

3 participants