From a5ae567e2e4af1adebceac9c02a2140a1833d629 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Sat, 27 Jun 2026 19:26:11 -0400 Subject: [PATCH] php-transformer: preserve standalone non-readable form-control inputs as runtime islands Standalone elements that have no faithful native block or readable static approximation (file/hidden/color/date-style inputs, or any control with inline event handlers) previously fell through to the unsupported-element fallback, producing an unacceptable unsupported_element_loss (the unsupported_input pattern family). The corpus survey showed this as the only remaining html_unsupported_element input family: 6 occurrences across 6 website fixtures, all hidden JSON-import file pickers driven by client scripts. These controls genuinely depend on a client runtime and, when hidden, have no visual representation. Forcing a static paragraph approximation would be wrong. Instead, after the readable-control and search paths decline, preserve the control as a bounded runtime island: the source markup is carried in the island snippet so behavior can be re-attached, no misleading static block is emitted, and the outcome is the acceptable runtime_island_preserved loss class rather than unsupported_element_loss. Corpus impact: unsupported_input 6 -> 0; html_unsupported_element 53 -> 47; unsupported_element_loss total 53 -> 47. Adds a dedicated parity fixture asserting the runtime-island outcome and acceptable loss class. Change is additive and localized to input handling to merge cleanly with the in-flight figure/long-tail coverage PR. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/HtmlToBlocks/HtmlTransformer.php | 34 +++++++++++++++++ ...dalone-input-runtime-island-preserved.json | 37 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 php-transformer/tests/fixtures/parity/html-standalone-input-runtime-island-preserved.json diff --git a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php index cc786234..66cc5e85 100644 --- a/php-transformer/src/HtmlToBlocks/HtmlTransformer.php +++ b/php-transformer/src/HtmlToBlocks/HtmlTransformer.php @@ -2165,6 +2165,10 @@ private function convertElement(DOMElement $element, array &$fallbacks, bool $ca return $readableControlBlock; } + if ( $this->preserveStandaloneFormControlAsRuntimeIsland($element) ) { + return null; + } + if ( $captureUnsupported ) { $fallback = array( 'type' => 'unsupported_element', @@ -5200,6 +5204,36 @@ private function readableFormControlBlockFromElement(DOMElement $element): ?arra return $this->createBlock('core/paragraph', array_merge($this->presentationAttributes($element), array( 'content' => $summary )), array(), $element); } + /** + * Preserve a standalone form control that has no faithful native block or + * readable static approximation as a bounded runtime island instead of an + * unsupported-element loss. + * + * Reached only after the readable-control and search paths decline, so the + * control is one whose behavior depends on a client runtime: file/hidden/ + * color/date-style inputs core blocks cannot represent, or any control + * carrying inline event handlers. The source markup is carried in the + * island snippet so the behavior can be re-attached, and no misleading + * static text is emitted for controls (often hidden) that have no visual + * representation. This yields a `preserved_runtime_island` outcome rather + * than an `unsupported_element_loss`. + */ + private function preserveStandaloneFormControlAsRuntimeIsland(DOMElement $element): bool + { + $tagName = strtolower($element->tagName); + if ( ! in_array($tagName, array( 'input', 'select', 'textarea' ), true) ) { + return false; + } + + $this->recordRuntimeIsland($element, 'control', 'form_control_requires_runtime', 'client_form_control_runtime', array( + 'control' => $this->formControlMetadata($element), + 'events' => $this->eventMetadata($element), + 'required_scripts' => $this->requiredScriptsForElement($element), + )); + + return true; + } + /** * @return array|null */ diff --git a/php-transformer/tests/fixtures/parity/html-standalone-input-runtime-island-preserved.json b/php-transformer/tests/fixtures/parity/html-standalone-input-runtime-island-preserved.json new file mode 100644 index 00000000..168ed42f --- /dev/null +++ b/php-transformer/tests/fixtures/parity/html-standalone-input-runtime-island-preserved.json @@ -0,0 +1,37 @@ +{ + "schema": "blocks-engine/php-transformer/parity-fixture/v1", + "name": "html-standalone-input-runtime-island-preserved", + "description": "Preserves a standalone non-readable form-control input (a hidden file picker) as a bounded runtime island with an acceptable runtime_island_preserved loss class instead of an unsupported_element_loss fallback.", + "source_reference": { + "repo": "php-transformer", + "path": "tests/fixtures/parity/html-standalone-input-runtime-island-preserved.json", + "notes": "Mirrors the corpus JSON-import file inputs in 58-infinite-whiteboard, 59-spreadsheet, 60-node-editor, 64-kanban-board, 67-dataviz-studio, and 68-drum-machine, which previously produced unsupported_input (html_unsupported_element) findings." + }, + "legacy_comparison": { + "skip": true, + "reason": "This upstream primitive fixture has no downstream legacy comparison." + }, + "operation": "html_transformer.transform", + "input": { + "content": "" + }, + "expected_blocks": [], + "expected_fallbacks": [], + "expect": [ + { "path": "status", "assert": "equals", "value": "success" }, + { "path": "blocks", "assert": "count", "count": 0 }, + { "path": "fallbacks", "assert": "count", "count": 0 }, + { "path": "source_reports.html.runtime_islands", "assert": "count", "count": 1 }, + { "path": "source_reports.html.runtime_islands.0.kind", "assert": "equals", "value": "control" }, + { "path": "source_reports.html.runtime_islands.0.tag", "assert": "equals", "value": "input" }, + { "path": "source_reports.html.runtime_islands.0.selector", "assert": "equals", "value": "#import-file" }, + { "path": "source_reports.html.runtime_islands.0.preservation_reason", "assert": "equals", "value": "form_control_requires_runtime" }, + { "path": "source_reports.html.runtime_islands.0.source_snippet", "assert": "contains", "value": "