Bound editor presentation delivery - #1478
Conversation
…tor-presentation # Conflicts: # php-transformer/tests/integration/wordpress-site-plan.php
Promotion gate blocker: upstream observer, not this PRThe
The demotion comes entirely from Root causeThis PR moves editor presentation from inline delivery ( The wp-codebox observer harvests identities only from inline inlineStyleContents: Array.from(document.querySelectorAll("style"), (style) => style.textContent ?? "")
// matched against /blocks-engine-presentation:([a-f0-9]{64})/giExternal stylesheet URLs were recorded but never contributed an identity. The stylesheets are genuinely delivered; the observer cannot see them. So this is an upstream capability gap rather than a defect in this PR, and re-inlining the CSS here would defeat the PR's purpose. Upstream fixAutomattic/wp-codebox#2449 — fixed in Automattic/wp-codebox#2451, now merged to What this PR still needsThe gate resolves wp-codebox through a pinned chain, and both pins are behind the fix: That reusable workflow at So, in order: release wp-codebox with #2451, bump Evidence: gate run https://github.com/Automattic/blocks-engine/actions/runs/33463678144 (identical signature on the two prior runs, so it is stable and not a trunk interaction). AI assistance disclosure: diagnosed with Claude Sonnet 4.5 via opencode. The model pulled the failed run artifacts, read the per-fixture |
The gate resolved wp-codebox through an SSI workflow pinned at v0.21.0, so the editor presentation capture could not observe an identity carried by an external stylesheet URL version. Bounded external delivery of the generated editor styles therefore reported 0 of 6 expected identities on both solved fixtures while the stylesheets were in fact loaded. Move the reusable workflow and the checked-out SSI code to 8a9edbce, which pins wp-codebox v0.26.5 and carries the capture fix from Automattic/wp-codebox#2451.
Update: pin chain resolved, and a second regression is now visibleThe wp-codebox pin chain from my earlier comment is done. The gate on this branch now runs
The original 1. Expected identity set is now empty (upstream)With bounded external delivery there are no inline #2451 taught the observation side to read an identity from an external stylesheet URL version, but the expectation side still derives only from inline CSS, so both sides are empty and coverage can never complete. Tracked upstream as Automattic/wp-codebox#2452. 2. Editor canvas no longer renders like the frontend (this PR)This one is not an observability gap. Comparing this branch against
Trunk clears the threshold comfortably on both fixtures; this branch is roughly 3–7× more divergent and hundreds of pixels shorter in the editor. The stylesheets are loaded — 11 URLs are present in the canvas, including the generated ones — so this is not a missing-asset problem. The cascade result differs. Worth noting the previous delivery did two things this PR replaces with one: it injected presentation CSS into So Automattic/wp-codebox#2452 is necessary but not sufficient here. Even once the expected set is populated again, the rendering match still has to pass. I have not changed any transformer code on this branch; the only commit I added is the workflow ref bump. AI assistance disclosure: analyzed with Claude Sonnet 4.5 via opencode. The model ran the release and pin chain, then compared per-fixture |
Mechanism confirmed: the enqueued stylesheets lose the editor cascadeMy previous comment called cascade position a lead rather than a proven cause. It is now evidenced. Comparing this branch against 1. The frontend is untouched. Root heights are identical, so this is purely an editor-side change:
2. The editor shrinks. All 128 captured nodes align between the two editors, so this is a like-for-like comparison:
3. The divergence is margin-specific. Editor-to-editor computed style diffs are almost entirely margins collapsing to zero: 4. The rules are present and losing. Grouping the captured
The author margin declarations are not missing on this branch. Nineteen and twenty-three of them are loaded in the canvas as external theme stylesheets, and they compute to That is the whole regression: identical bytes, different cascade position, different winner. The previous delivery merged presentation CSS into Implication for the fixBounding delivery is compatible with winning the cascade, but the current shape gives up the position that made the author styles authoritative. Options worth weighing: keep the global-styles merge as the delivery channel while bounding which styles are merged, enqueue with an explicit dependency on the core editor handles so the generated sheets load after them, or carry the global-styles scoping so specificity is preserved. Worth noting the loss is silent. The stylesheets load, the identities will be observable once Automattic/wp-codebox#2452 lands, and every asset check passes. Only the rendering comparison catches it, which is a good argument for keeping AI assistance disclosure: analyzed with Claude Sonnet 4.5 via opencode. The model diffed per-node computed styles and margin-rule origins between this branch and trunk from the promotion evidence artifacts, holding contract and runtime constant. An earlier ordering claim of mine was discarded after I confirmed the captured stylesheet list is URL-sorted rather than DOM-ordered. Reviewed by me before posting. |
External delivery loaded the generated presentation stylesheets before the core editor reset and block library rules, so core's margin resets won and author margins computed to 0px inside the canvas. Measured against trunk under an identical acceptance contract and runtime, the editor lost 233.46px on 15-saas and 307.05px on 89-static-site-importer- architecture while both frontends stayed byte-identical, and editor-to-editor diffs were almost entirely marginTop/marginBottom collapsing to zero. The declarations were present in the canvas the whole time; they were simply outranked. wp-edit-blocks is the aggregate core editor stylesheet, depending on wp-base-styles, wp-components, wp-reset-editor-styles, wp-block-library and wp-block-editor-content. Declaring it as a dependency keeps the bounded external delivery this branch introduces while ordering author presentation after every core sheet it has to win against.
The dependency was inert. Run 33518100706 reproduced the previous metrics
to four decimal places: mismatch 0.2888 and 0.3062, height delta 210.61px
and 381.44px, byte-identical to the run before it.
The margin loss is not an ordering problem among linked stylesheets. The
rules that zero the author margins are Gutenberg's inline global-styles
layout rules, and the canvas emits inline editor-settings styles after the
linked assets:
trunk inline layout resets idx 6-9, author rules idx 16 and 21
branch author rules idx 12 and 17, inline layout resets idx 25-28
:root :where(.is-layout-flow) > * { margin-block-start:0; margin-block-end:0 }
A stylesheet dependency only orders links relative to other links, so no
external delivery can be moved after that inline block. Reverting rather
than keeping a passing assertion whose stated rationale the evidence
contradicts.
Correction: the cascade inversion is against inline global styles, not linked stylesheetsI tried the targeted fix implied by my previous comment — declaring Run https://github.com/Automattic/blocks-engine/actions/runs/33518100706 reproduced the previous numbers to four decimal places:
Identical, and the canvas stylesheet set was unchanged. That result is what located the actual mechanism. What actually winsThe author selectors are identical on both branches, so this was never specificity. Ordering the captured margin rules in the live canvas:
The rule that zeroes the margins is Gutenberg's own inline layout reset: :root :where(.is-layout-flow) > * { margin-block-start:0px; margin-block-end:0px }On trunk the author CSS is inlined into Why no enqueue-side fix can work
That makes the constraint structural rather than a tuning problem. Confirmed against core: So this PR's goal of routing editor presentation "without inline-settings serializing stylesheet bodies" and correct editor rendering are mutually exclusive under current WordPress. One of the two has to give, and that is a product call rather than something to settle in an implementation detail:
The branch is back to its pre-experiment state; the only commits I have added are the SSI workflow ref bump and this revert. No transformer behaviour on this branch is mine. AI assistance disclosure: Claude Sonnet 4.5 via opencode. The model proposed the dependency fix, ran it, found it inert, and used that negative result to isolate the inline-versus-linked ordering inversion from the captured margin-rule evidence. Two earlier hypotheses of mine, link ordering and selector specificity, were tested and discarded. Reviewed by me before posting. |
Summary
Verification
php php-transformer/tests/contract/wordpress-site-plan.phpphp php-transformer/tests/contract/staged-artifact-compilation.phpCloses #1465
AI assistance
OpenAI gpt-5.6-terra through OpenCode implemented the candidate and tests. OpenAI gpt-5.6-sol through OpenCode reviewed the branch, commit metadata, diff shape, and repository-native contract results before opening this PR.