@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix content: <http://purl.org/rss/1.0/modules/content/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://lhero.org/portfolio/lh-mcp-block-transformer/>
  a sioc:Post ;
  dc:title "Architecture notes" ;
  dcterms:identifier 147454 ;
  dc:modified "2026-09-14T13:38:00Z"^^xsd:dateTime ;
  dc:created "2026-09-14T13:38:00Z"^^xsd:dateTime ;
  sioc:link <https://lhero.org/portfolio/lh-mcp-block-transformer/architecture-notes/> ;
  sioc:has_creator <https://lhero.org/author/1/#account> ;
  sioc:has_container <https://lhero.org/#posts> ;
  content:encoded "<ul class=\"lh_portfolio-meta\"><li><strong>Part of:</strong> <a href=\"https://lhero.org/portfolio/lh-mcp-block-transformer/\">LH MCP Block Transformer</a></li></ul><h2 class=\"wp-block-heading\">One bridge, both directions</h2><p class=\"wp-block-paragraph\">Every conversion routes through the same <code>FormatBridge::convertResult()</code> call from <a href=\"https://github.com/Automattic/blocks-engine/tree/trunk/php-transformer\">automattic/blocks-engine-php-transformer</a>, which is symmetric across its html, markdown and blocks adapters. The plugin supplies the source and target format and otherwise stays out of the way.</p><p class=\"wp-block-paragraph\">Markdown input is a genuinely weaker source than HTML, for a structural reason rather than a quality one: the richer block patterns are triggered by inline styles and CSS shapes, and Markdown has no way to declare them. Use HTML for anything needing layout, media, buttons or styling; Markdown is fine for plain prose.</p><h2 class=\"wp-block-heading\">Why convert-post-to-blocks exists separately</h2><p class=\"wp-block-paragraph\">It would appear redundant: a caller could call convert-to-blocks and hand the resulting markup to some other ability&#8217;s content parameter. In practice that two-step composition requires transcribing a large, deeply-escaped block-markup string by hand between two calls. On a real run that transcription silently dropped a closing tag and corrupted a live entry, caught only by chance on review.</p><p class=\"wp-block-paragraph\">convert-post-to-blocks removes that failure mode structurally rather than warning against it: only a post ID crosses the boundary, never the markup. This is worth preserving as a design constraint, not just an implementation detail.</p><h2 class=\"wp-block-heading\">Capability model</h2><p class=\"wp-block-paragraph\">The ability-level gate is coarse and answers one question: does this caller edit content here. Authorisation for a specific post is a separate question, answered per ID inside convert-post-to-blocks via <code>current_user_can( 'edit_post', $id )</code>. Routing through <code>edit_post</code> rather than a hand-rolled author comparison means <code>map_meta_cap</code> applies, so published-post restrictions, custom capability types, and any plugin filtering <code>map_meta_cap</code> are all honoured rather than bypassed.</p><h2 class=\"wp-block-heading\">Vendor dependency</h2><p class=\"wp-block-paragraph\">The transformer library lives in this plugin&#8217;s own <code>vendor/</code> directory via Composer. A WordPress zip install wipes that directory, so composer install must be re-run after any such install. A missing autoload returns a clear error rather than fatalling, and the three abilities that need the library check for it before doing anything else. get-pattern-guide is unaffected, as it returns static data only.</p>"^^rdf:XMLLiteral ;
  sioc:content "Part of: LH MCP Block TransformerOne bridge, both directionsEvery conversion routes through the same FormatBridge::convertResult() call from automattic/blocks-engine-php-transformer, which is symmetric across its html, markdown and blocks adapters. The plugin supplies the source and target format and otherwise stays out of the way.Markdown input is a genuinely weaker source than HTML, for a structural reason rather than a quality one: the richer block patterns are triggered by inline styles and CSS shapes, and Markdown has no way to declare them. Use HTML for anything needing layout, media, buttons or styling; Markdown is fine for plain prose.Why convert-post-to-blocks exists separatelyIt would appear redundant: a caller could call convert-to-blocks and hand the resulting markup to some other ability&#8217;s content parameter. In practice that two-step composition requires transcribing a large, deeply-escaped block-markup string by hand between two calls. On a real run that transcription silently dropped a closing tag and corrupted a live entry, caught only by chance on review.convert-post-to-blocks removes that failure mode structurally rather than warning against it: only a post ID crosses the boundary, never the markup. This is worth preserving as a design constraint, not just an implementation detail.Capability modelThe ability-level gate is coarse and answers one question: does this caller edit content here. Authorisation for a specific post is a separate question, answered per ID inside convert-post-to-blocks via current_user_can( 'edit_post', $id ). Routing through edit_post rather than a hand-rolled author comparison means map_meta_cap applies, so published-post restrictions, custom capability types, and any plugin filtering map_meta_cap are all honoured rather than bypassed.Vendor dependencyThe transformer library lives in this plugin&#8217;s own vendor/ directory via Composer. A WordPress zip install wipes that directory, so composer install must be re-run after any such install. A missing autoload returns a clear error rather than fatalling, and the three abilities that need the library check for it before doing anything else. get-pattern-guide is unaffected, as it returns static data only." ;
  sioc:topic <https://lhero.org/?taxonomy=author&term=cap-1> .

<https://lhero.org/author/1/#account> rdfs:seeAlso <https://lhero.org/author/1/?feed=lhrdf&format=turtle> .
<https://lhero.org/?taxonomy=author&term=cap-1> rdfs:seeAlso <https://lhero.org/?taxonomy=author&term=cap-1&feed=lhrdf&format=turtle> .
