diff --git a/dev/test/fixtures/visual-review/README.md b/dev/test/fixtures/visual-review/README.md new file mode 100644 index 0000000..7a86d84 --- /dev/null +++ b/dev/test/fixtures/visual-review/README.md @@ -0,0 +1,44 @@ +# Visual finishing exercise + +Two synthetic regions exercise [the rendered-delivery workflow](../../../../skills/block-runner/references/VISUAL.md): a long-copy page and a shared template part. The reference uses different HTML elements from the native block tree. Its copy must survive unchanged. + +`styles/native.css` deliberately narrows the article and closing note and forces the highlight wider than a phone. `styles/native.corrected.css` contains the source correction, including the WordPress first-child spacing rule found during review. Keep the original fixture intact; copy it to a separate working directory before substituting corrected CSS. + +## Replay + +Build the checkout with `npm run build`. Serve this directory with a local static server and open `reference.html`. Compile the native source: + +```sh +node dist/cli.js site compile dev/test/fixtures/visual-review/site.intent.json --asset-root dev/test/fixtures/visual-review --out /tmp/visual-review-before --strict --json +``` + +Use a new output path if that directory already exists. Install the emitted `theme/` as `visual-review-demo` on an explicitly selected disposable WordPress 7.1 site and activate it. Use the existing `site plan` / hash-confirmed `site apply` route from [SITE.md](../../../../skills/block-runner/references/SITE.md); retain the plan, journal and readback. No production target is needed. + +Compare the rendered reference and native homepage at 1280×900 and 390×844, with the same scale and scrollbar state. Check content, then the article, highlight and closing note. Retain paired screenshots and targeted bounding boxes; inspect the images. + +Copy this fixture to a working directory, replace that copy's `styles/native.css` with `styles/native.corrected.css`, then compile to a new output directory. Deploy the changed theme bytes to the same disposable target, plan/apply again and recapture the same regions. Do not patch serialized block delimiters or discard the initial evidence. Finish with a representative native editor edit, save and reopen. + +## Observed comparison + +On 2026-10-24, local WordPress 7.1 / PHP 8.4.27 and the in-app Chromium browser showed: + +| Region / view | Reference | Before | After | +| --- | --- | --- | --- | +| Article / desktop | 720px wide | 480px; extra wrapping | 720px | +| Closing part / desktop | 960px, centred text | 440px, left-aligned | 960px, centred | +| Highlight / mobile | 342px | 520px; document overflow to 544px | 342px; document width 390px | +| Article top / desktop, mobile | 48px, 24px | 0px, 0px | 48px, 24px | + +Matched mobile viewports used 390 CSS pixels with scrollbars hidden on both sides; desktop used 1280. The corrected region text, widths, heights, positions and alignment matched the reference. The screenshots showed the same wrapping and spacing. Both strict compilations had no diagnostics; the site applies completed with readback. These are separate validity, operational and visual observations, not a universal fidelity score. + +No new helper, renderer, command or dependency was needed. A clean comparison ends after the paired inspection; it does not require a correction loop. Missing-reference, unavailable-browser and source-only cases remain explicitly unverified under the workflow, and do not block ordinary source delivery. + +## Native editing and retained evidence + +In Chrome 154, the page highlight paragraph was edited, saved and reopened in the native editor; the saved WordPress content and frontend both contained the test sentence. The closing-note template part passed the same edit/save/reopen and frontend check. Both original texts were then restored through the editor. The restored page also passed the existing validation gate. + +- Desktop: [reference](evidence/reference-desktop-matched.png), [before](evidence/before-desktop-matched.png), [after](evidence/after-desktop-matched.png). +- Mobile: [reference](evidence/reference-mobile-matched.png), [before](evidence/before-mobile-matched.png), [after](evidence/after-mobile-matched.png). +- Native persistence: [page reopened](evidence/editor-reopened.png), [template part reopened](evidence/part-editor-reopened.png). + +The paired after comparison was taken before the deliberate editor test edits. These captures show synthetic content only. The exercise was performed by one operator; independent reviewer replay remains separate. diff --git a/dev/test/fixtures/visual-review/evidence/after-desktop-matched.png b/dev/test/fixtures/visual-review/evidence/after-desktop-matched.png new file mode 100644 index 0000000..639611d Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/after-desktop-matched.png differ diff --git a/dev/test/fixtures/visual-review/evidence/after-mobile-matched.png b/dev/test/fixtures/visual-review/evidence/after-mobile-matched.png new file mode 100644 index 0000000..67f9c68 Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/after-mobile-matched.png differ diff --git a/dev/test/fixtures/visual-review/evidence/before-desktop-matched.png b/dev/test/fixtures/visual-review/evidence/before-desktop-matched.png new file mode 100644 index 0000000..7d1b4be Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/before-desktop-matched.png differ diff --git a/dev/test/fixtures/visual-review/evidence/before-mobile-matched.png b/dev/test/fixtures/visual-review/evidence/before-mobile-matched.png new file mode 100644 index 0000000..f447491 Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/before-mobile-matched.png differ diff --git a/dev/test/fixtures/visual-review/evidence/editor-reopened.png b/dev/test/fixtures/visual-review/evidence/editor-reopened.png new file mode 100644 index 0000000..c833e00 Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/editor-reopened.png differ diff --git a/dev/test/fixtures/visual-review/evidence/part-editor-reopened.png b/dev/test/fixtures/visual-review/evidence/part-editor-reopened.png new file mode 100644 index 0000000..d4cd846 Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/part-editor-reopened.png differ diff --git a/dev/test/fixtures/visual-review/evidence/reference-desktop-matched.png b/dev/test/fixtures/visual-review/evidence/reference-desktop-matched.png new file mode 100644 index 0000000..639611d Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/reference-desktop-matched.png differ diff --git a/dev/test/fixtures/visual-review/evidence/reference-mobile-matched.png b/dev/test/fixtures/visual-review/evidence/reference-mobile-matched.png new file mode 100644 index 0000000..67f9c68 Binary files /dev/null and b/dev/test/fixtures/visual-review/evidence/reference-mobile-matched.png differ diff --git a/dev/test/fixtures/visual-review/reference.html b/dev/test/fixtures/visual-review/reference.html new file mode 100644 index 0000000..be48442 --- /dev/null +++ b/dev/test/fixtures/visual-review/reference.html @@ -0,0 +1,13 @@ + + +Visual review reference +
+

A quiet place to read

+

A good reading page gives every sentence enough room. The words should feel unhurried, with a clear measure, familiar type and a useful rhythm between paragraphs. The design is modest on purpose: changes to its width are easy to see, but the content must remain exactly the same.

+

The article can be read on a large screen or on a phone. Neither reader should need to scroll sideways to finish a sentence. When a theme adds a narrower container, the extra wrapping can look like a content problem even though every word is still present.

+ +

The highlighted note is part of the article, not a picture of some text. It should fit within the available width, stay in the reading order and remain editable through the normal paragraph control. A successful correction fixes the layout without rewriting the message.

+

After checking the page, inspect the shared closing note as a separate region. It has a different purpose and a wider measure. Matching these two regions by meaning makes the comparison useful even when the reference and WordPress use different element trees.

+
+ + diff --git a/dev/test/fixtures/visual-review/site.intent.json b/dev/test/fixtures/visual-review/site.intent.json new file mode 100644 index 0000000..5a917e5 --- /dev/null +++ b/dev/test/fixtures/visual-review/site.intent.json @@ -0,0 +1,136 @@ +{ + "version": 1, + "siteId": "visual-review-demo", + "homePageId": "home", + "theme": { + "slug": "visual-review-demo", + "title": "Visual Review Demo", + "themeJson": { + "version": 3, + "settings": { + "appearanceTools": true + }, + "styles": { + "spacing": { + "blockGap": "0" + }, + "typography": { + "fontFamily": "Georgia, serif", + "fontSize": "18px", + "lineHeight": "1.6" + }, + "color": { + "background": "#f6f4ee", + "text": "#252c28" + } + } + } + }, + "templates": { + "index": { + "body": { + "blocks": [ + { + "block": "core/post-content" + }, + { + "block": "core/template-part", + "attrs": { + "slug": "closing-note" + } + } + ] + } + } + }, + "parts": { + "closing-note": { + "body": { + "blocks": [ + { + "block": "core/group", + "attrs": { + "className": "review-note" + }, + "children": [ + { + "block": "core/paragraph", + "text": "This is a shared closing note. Its text remains a native paragraph." + } + ] + } + ] + } + } + }, + "patterns": {}, + "pages": [ + { + "id": "home", + "route": "/", + "title": "Reading page", + "template": "index", + "status": "publish", + "body": { + "blocks": [ + { + "block": "core/group", + "attrs": { + "className": "review-article" + }, + "children": [ + { + "block": "core/heading", + "level": 1, + "text": "A quiet place to read" + }, + { + "block": "core/paragraph", + "text": "A good reading page gives every sentence enough room. The words should feel unhurried, with a clear measure, familiar type and a useful rhythm between paragraphs. The design is modest on purpose: changes to its width are easy to see, but the content must remain exactly the same." + }, + { + "block": "core/paragraph", + "text": "The article can be read on a large screen or on a phone. Neither reader should need to scroll sideways to finish a sentence. When a theme adds a narrower container, the extra wrapping can look like a content problem even though every word is still present." + }, + { + "block": "core/group", + "attrs": { + "className": "review-highlight" + }, + "children": [ + { + "block": "core/paragraph", + "text": "Keep the words. Correct the layout. Check the result at both sizes." + } + ] + }, + { + "block": "core/paragraph", + "text": "The highlighted note is part of the article, not a picture of some text. It should fit within the available width, stay in the reading order and remain editable through the normal paragraph control. A successful correction fixes the layout without rewriting the message." + }, + { + "block": "core/paragraph", + "text": "After checking the page, inspect the shared closing note as a separate region. It has a different purpose and a wider measure. Matching these two regions by meaning makes the comparison useful even when the reference and WordPress use different element trees." + } + ] + } + ] + } + } + ], + "assets": [ + { + "id": "base", + "path": "styles/base.css", + "kind": "stylesheet", + "role": "theme-file" + }, + { + "id": "native", + "path": "styles/native.css", + "kind": "stylesheet", + "role": "theme-file" + } + ], + "assetUses": [] +} diff --git a/dev/test/fixtures/visual-review/styles/base.css b/dev/test/fixtures/visual-review/styles/base.css new file mode 100644 index 0000000..13cb063 --- /dev/null +++ b/dev/test/fixtures/visual-review/styles/base.css @@ -0,0 +1,14 @@ +/* Shared design vocabulary; reference and native markup deliberately differ. */ +body { margin: 0; background: #f6f4ee; color: #252c28; font: 18px/1.6 Georgia, serif; } +.wp-site-blocks { padding: 0; } +.reference-article, .review-article { box-sizing: border-box; width: calc(100% - 48px); max-width: 720px; margin: 48px auto; } +.reference-article h1, .review-article h1 { font: bold 44px/1.12 Georgia, serif; margin: 0 0 24px; } +.reference-article p, .review-article p { margin: 0 0 24px; } +.reference-highlight, .review-highlight { box-sizing: border-box; background: #e2e8dd; padding: 24px; border-left: 4px solid #596d4e; margin: 32px 0; } +.reference-highlight p, .review-highlight p { margin: 0; } +.reference-note, .review-note { box-sizing: border-box; width: calc(100% - 48px); max-width: 960px; margin: 48px auto; padding: 24px; background: #252c28; color: #f6f4ee; text-align: center; } +.reference-note p, .review-note p { margin: 0; } +@media (max-width: 600px) { + .reference-article, .review-article { margin-top: 24px; } + .reference-article h1, .review-article h1 { font-size: 34px; } +} diff --git a/dev/test/fixtures/visual-review/styles/native.corrected.css b/dev/test/fixtures/visual-review/styles/native.corrected.css new file mode 100644 index 0000000..398b036 --- /dev/null +++ b/dev/test/fixtures/visual-review/styles/native.corrected.css @@ -0,0 +1,8 @@ +/* Scoped source correction, after the initial comparison identifies the defects. */ +.review-article { max-width: 720px; } +.review-highlight { min-width: 0; } +.review-note { max-width: 960px; text-align: center; } + +/* Keep the authored top spacing against WordPress first-child layout defaults. */ +.wp-block-post-content > .review-article { margin-block-start: 48px; } +@media (max-width: 600px) { .wp-block-post-content > .review-article { margin-block-start: 24px; } } diff --git a/dev/test/fixtures/visual-review/styles/native.css b/dev/test/fixtures/visual-review/styles/native.css new file mode 100644 index 0000000..c397f8f --- /dev/null +++ b/dev/test/fixtures/visual-review/styles/native.css @@ -0,0 +1,4 @@ +/* Three intentional presentation defects; native content stays identical. */ +.review-article { max-width: 480px; } +.review-highlight { min-width: 520px; } +.review-note { max-width: 440px; text-align: left; } diff --git a/skills/block-runner/SKILL.md b/skills/block-runner/SKILL.md index 9a4421e..d890adf 100644 --- a/skills/block-runner/SKILL.md +++ b/skills/block-runner/SKILL.md @@ -19,7 +19,7 @@ compatibility: Requires Node.js ^22.13.0 || >=24.0.0 and shell access. An uncach ## Pick the artifact first Choose the visible result before discovering a project. Read the named first reference, use the -condition, and stop at its stated boundary. Do not load a construction taxonomy for a +condition, and respect its stated boundary. Do not load a construction taxonomy for a self-contained page-content or markup-repair task. | Requested artifact | First reference | Use when | Completion boundary | @@ -36,6 +36,15 @@ If “reusable section” does not say whether it is page `post_content` or a na block, ask that one artifact question before writing. Do not use this skill for unrelated WordPress administration, non-WordPress HTML, or frontend-scraped HTML presented as source. +## Finish rendered delivery + +When the task creates or changes visible WordPress output, follow +[VISUAL.md](references/VISUAL.md) by default before calling the delivery complete. +Check the affected region on desktop/mobile, correct meaningful differences and verify +the applicable native edit/save behaviour. Do not ask whether the user wants this check. +Respect source-only delivery and explicit skips; disclose unavailable rendering or +unverified checks. Existing CLI/API behaviour and write permissions remain unchanged. + ## Discover only missing project facts For a component that belongs in an existing project, use [GUIDE.md §0](references/GUIDE.md) after diff --git a/skills/block-runner/references/GUIDE.md b/skills/block-runner/references/GUIDE.md index dc47765..47e560f 100644 --- a/skills/block-runner/references/GUIDE.md +++ b/skills/block-runner/references/GUIDE.md @@ -289,6 +289,10 @@ tool is broken. **Always say what you did** — where it went, how many blocks, and anything that fell back to Custom HTML. A silent success is indistinguishable from a silent failure. +For a rendered delivery, follow [VISUAL.md](VISUAL.md) by default: compare desktop/mobile, +correct meaningful differences and check native editing/save. Source-only delivery still +finishes normally; say when rendering or persistence has not been verified. + --- ## 7. Matching the user's site diff --git a/skills/block-runner/references/SITE.md b/skills/block-runner/references/SITE.md index 72826e6..96c04d5 100644 --- a/skills/block-runner/references/SITE.md +++ b/skills/block-runner/references/SITE.md @@ -151,3 +151,7 @@ theme proof checks the theme's declared PHP requirement. Both routes require the optional pinned WordPress/browser tooling. They pin the captured theme snapshot automatically, so a separate plugin-style `--input` is unnecessary. Save proof and visual/editor acceptance are separate claims. + +When delivering a rendered site or theme change, use [VISUAL.md](VISUAL.md) by default +to compare the affected views, correct source-level differences and retain the observed +limits. The proof commands above do not replace that comparison or authorise production writes. diff --git a/skills/block-runner/references/VISUAL.md b/skills/block-runner/references/VISUAL.md new file mode 100644 index 0000000..46c4b6a --- /dev/null +++ b/skills/block-runner/references/VISUAL.md @@ -0,0 +1,84 @@ +# Finish rendered output + +Use this after creating or changing a rendered WordPress page, section, template/part, +site or integrated block. It is the default delivery check: do not wait for a separate +QA request. Existing CLI/library calls remain headless and unchanged. + +Check the changed region and surrounding layout on desktop and mobile. Reuse the +current browser session and evidence that still matches the delivered revision. +For a site, cover its different templates and responsive behaviour; do not revisit +every unrelated page for a small edit. A clean first comparison needs no correction pass. + +## Establish the comparison + +Record the authored input/revision, native destination, intended regions and any +approved design differences. Use the authored design's render or supplied screenshots +as the reference. Rendered HTML is visual evidence, never a substitute for authored +converter input. + +Match viewport, scale and UI state between reference and target. Choose desktop/mobile +widths appropriate to the design; add a breakpoint-adjacent view when a defect needs it. +Wait for fonts and images with a bounded timeout, and disclose missing resources. +Freeze animation consistently for static comparison; check its behaviour separately +when it is part of the requested result. Retain the actual browser/version and views. + +Without a visual reference, inspect the render against the stated content/layout +requirements and check overflow, missing assets and obvious presentation failures. +Say that source fidelity was not compared. An inaccessible target/browser, missing +required reference or explicit user skip is an unverified check, never a visual pass. +Source-only or batch work without a rendered destination still delivers normally. +This check grants no deployment, credential or production-write authority. + +## Compare, explain, correct + +1. **Check content first:** section order, headings, body text, media, links and required + interactions, including fragment-link destinations and drawn/animated graphics. + A similar silhouette cannot compensate for lost content. A present canvas element + does not prove that its artwork rendered. +2. **Compare corresponding regions:** widths/alignment, spacing, typography/wrapping, + image crop and mobile overflow or clipping. `overflow: hidden` can conceal broken + layouts while document width still looks correct. Confirm breakpoint rules still + affect the native regions. Match regions by meaning; source and native DOM + trees need not share selectors. Inspect the screenshots, not just capture success. +3. **Measure a discrepancy:** use the browser's bounding boxes/computed styles for + the affected region. Record both selectors or region labels. Missing/ambiguous + regions block that comparison; screenshot-only references have no DOM measurements. + Do not collect every CSS property or require DOM/style equality. A pixel diff can + locate differences; it does not establish fidelity or editorial quality. +4. **Fix the responsible input:** identify the authored selector, intent node path or + theme rule. Keep uncertain attribution explicit. Prioritise missing content, + broken interaction and overflow before decorative differences. Preserve unrelated + copy and native editability; never hand-patch generated block delimiters. +5. **Regenerate and recapture:** use the existing conversion/assembly and delivery + route, including its gate, confirmation and drift checks. Preserve human edits. + Compare the same views again, keeping the original capture. Stop when the result + meets the brief or a real blocker/task budget is reached, not after an arbitrary + number of passes. Keep unresolved differences and editorial TODOs visible. + +A short working list is enough; it is not a required formal handoff: + +| Region / viewport | Expected → observed, evidence | Impact / source to inspect | Action / result | +| --- | --- | --- | --- | +| Article / desktop | Reference 720px → native 480px; paired capture and width | Extra wrapping; theme content width | Correct width, regenerate; resolved in recapture | + +Finish with the applicable native editor check: make a representative edit through +its actual control, save and reopen, and inspect the rendered result. Keep permission +to mutate the target and preservation of existing content explicit. If this cannot +be exercised, record persistence as unverified rather than deriving it from a screenshot. + +## Reuse the existing facilities + +Use the harness's available browser controls for paired inspection and targeted +measurements. The project's existing proof runners retain screenshots, errors and +receipts and exercise native editing. `proof --theme` / `proof --site` use controlled +sandboxes and may write fixture state: see [SITE.md](SITE.md#prove-the-right-result). +They are not read-only capture commands for arbitrary sites. + +Registered-block `ProofFixture.visual` compares a render to a reviewed golden. That +regression gate retains its own thresholds/masks; do not replace the golden to hide +a source-to-native mismatch. Reuse captured evidence, without treating a successful +gate as proof of a comparison it did not perform. + +Tell the user what was checked, what was corrected, and what remains. Distinguish +block validity, visual observations, interaction and save persistence. No universal +fidelity score, new CLI mode or separate report package is required.