Skip to content

Correct the skill's styling attribute guidance and require markup in the reply - #104

Merged
noeltock merged 2 commits into
mainfrom
fix-skill-styling-attrs-and-delivery
Sep 14, 2026
Merged

noeltock merged 2 commits into
mainfrom
fix-skill-styling-attrs-and-delivery

Conversation

@stuartshields

Copy link
Copy Markdown
Contributor

What changed

references/ASSEMBLE.md gains two cases under the attrs passthrough:

  • Nested style attributes. A full-width button is {"style":{"dimensions":{"width":"100%"}}}, not {"width":100}, with a note that the saved markup carries no width class either way and the class must not be written by hand.
  • Colour. A theme preset goes in as a slug ({"backgroundColor":"subtle"}); a colour the palette does not carry goes in {"style":{"color":{"background":"#f5f5f5"}}}. A hex in backgroundColor is named as the failure it is.

SKILL.md gains one delivery rule: where there is no destination to write to, the complete markup comes first in the reply, and a block count, a validation verdict or paste instructions may not be stated for markup the reply does not contain.

Why

attrs is spread straight into wp.createBlock (src/intent/index.ts:90), so WordPress discards any key the block does not declare. There is no error and no warning, and the result still validates, because the saved markup is internally consistent with whatever attributes survived. A wrong shape is therefore indistinguishable from a correct one at every point the agent can observe. The existing text says unknown attributes "are harmless", which is true of the output and misleading about the intent tree.

Two shapes actually bite. core/button declares no width attribute at all: width is a support with __experimentalSkipSerialization, and has-custom-width is added by index.php when the block renders, so the class belongs in no saved post content. And a hex placed in backgroundColor serialises literally into a class naming a preset that does not exist, which styles nothing while passing validation.

The obvious alternative was making the generator reject unknown keys. That was rejected because the passthrough is deliberately open, documented as such, and used for legitimate attributes the schema does not enumerate, so the generator cannot separate a typo from a valid extra attribute without a schema it does not have. Documenting the two shapes that misfire is the narrower change.

Two shortcomings worth a reviewer's attention. The general framing, that a nested style attribute goes in at its full path, may be inert: padding and border radius are already produced in the correct nested shape without it, so the button-width case is what carries the weight. And the delivery rule in SKILL.md is reasoned from an observed failure rather than measured, so it is insurance.

How to verify

The generator's behaviour, run from the repo root:

# Flat key: dropped in silence, and the result still validates.
printf '%s' '{"blocks":[{"block":"core/buttons","children":[{"block":"core/button","text":"X","attrs":{"width":100}}]}]}' \
  | node dist/cli.js assemble -
# => <!-- wp:button -->   (no width attribute, no width class)

# Documented shape: survives.
printf '%s' '{"blocks":[{"block":"core/buttons","children":[{"block":"core/button","text":"X","attrs":{"style":{"dimensions":{"width":"100%"}}}}]}]}' \
  | node dist/cli.js assemble -
# => <!-- wp:button {"style":{"dimensions":{"width":"100%"}}} -->   validate: ok=true, 2/2

# Hex in the wrong field: a class naming no preset, and validate passes it.
printf '%s' '{"blocks":[{"block":"core/group","attrs":{"backgroundColor":"#eef3f1"},"children":[{"block":"core/paragraph","text":"x"}]}]}' \
  | node dist/cli.js assemble -
# => class="wp-block-group has-eef-3-f-1-background-color has-background"

The WordPress claims, checked against the bundled package rather than from memory:

node -e 'console.log(Object.keys(require("./node_modules/@wordpress/block-library/src/button/block.json").attributes).join(", "))'
# => tagName, type, url, title, text, linkTarget, rel, placeholder, backgroundColor, textColor, gradient

grep -rn "has-custom-width" node_modules/@wordpress/block-library/src/button/
# => 8 hits in deprecated.js, 1 in index.php:98 (added at render)

width is absent from the button schema in the bundled @wordpress/block-library@10.5.0 and in the current 11.0.0, which I unpacked from npm to confirm this is not version lag.

Not verified: that the delivery rule in SKILL.md changes behaviour.

Where to start

Start at references/ASSEMBLE.md:37, which holds both cases and is where the reasoning sits.
Read separately SKILL.md:63. It shares no mechanism with the ASSEMBLE.md change and stands or falls on its own.

@noeltock

Copy link
Copy Markdown
Member

Thanks for the PR. The button-width and colour examples are helpful, and I reproduced the documented assembly behaviour. The distinction between valid markup and styling that actually takes effect is worth making explicit.

I have one suggestion for the delivery rule: scope it to generating or repairing page markup.

-- **With no destination, the reply is the delivery, and it has an order.** The complete markup
-  comes first, then whatever you want to say about it. A file you wrote along the way is where the
-  generator put its output, never where the job ended. Do not state a block count, a validation
-  verdict or paste instructions for markup the reply does not contain: a confident description of
-  output the user cannot see reads as success and is the one failure they cannot spot.
+- **Deliver page markup in the reply when no destination is agreed.** When generating or
+  repairing page markup without an agreed file or WordPress destination, include the complete
+  generated markup in the reply before summarising it. Validation-only requests may return
+  findings without reproducing the input.

The current wording sits among rules shared by all five artifact routes. “With no destination” therefore also catches a request to validate existing markup, where a verdict and findings can be the complete answer. It also does not fit registered-block source or custom PHP/editor work, which have their own delivery requirements. The narrower wording keeps the intended protection against describing output the user never receives, while preserving those other routes.

The styling guidance looks good to me. With that small adjustment, the delivery rule would fit the rest of the skill more clearly. Thanks again for putting this together.

@noeltock
noeltock merged commit 2136cbe into main Sep 14, 2026
7 checks passed
@noeltock
noeltock deleted the fix-skill-styling-attrs-and-delivery branch September 14, 2026 23:05
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.

2 participants