Skip to content

fix(html): turn the dialect's silent losses into named errors - #147

Closed
LeadcodeDev wants to merge 1 commit into
fix/audit-lot4-batchfrom
fix/audit-lot5-html
Closed

fix(html): turn the dialect's silent losses into named errors#147
LeadcodeDev wants to merge 1 commit into
fix/audit-lot4-batchfrom
fix/audit-lot5-html

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Refs #142 — CLI/HTML workstream, third of three. Four confirmed findings in rustmotion-html.

Stacked on #146 to keep the diff readable — it contains only the rustmotion-html changes. Rebase to chantier/audit-remediation once #146 lands.

Every one of these degraded input without a word, and rustmotion validate answered "Valid scenario" for all of them. In a dialect an author writes by hand, a construct the transpiler cannot honour has to be named, not dropped.

<style> refused, <script> skipped — and why they differ

<style> and <script> content was transpiled into text components and painted into the video.

The audit proposed excluding both, plus head/title/noscript/template, as one block. The implementation splits them, on a criterion worth stating: does an author believe this construct does something visible?

  • Nobody expects a <script> to appear on screen. Skipping it defeats no intent — it only stops the text leaking onto the canvas. Same for <title>, <noscript>, <template>, <head>.
  • Everybody expects a <style> block to have an effect. The dialect has no cascade engine and cannot deliver one, so ignoring it silently defeats a real intent. Refused, with a named error.

Nested <scene> refused, recursively

A <scene> inside any container vanished from the scenario — one scene silently became zero, and validate reported the shorter duration as correct.

Now refused, naming the offending parent. The search is recursive, which turned out to matter beyond the audit's reproduction: with an unclosed <p>, HTML5 error recovery hoists the <h1> out of the scene and leaves the <scene> node nested under <p> with no children. A non-recursive check would miss it, and auto-recursing would have silently repaired a structure the author had actually broken — hiding the corruption instead of reporting it.

<img>, <video>, <svg> refused, not mapped

These became empty divs. They are now refused with the equivalent rm-image / rm-video / rm-svg named in the message.

The audit proposed mapping them automatically; that was declined. <svg> would require re-serialising the DOM subtree into the data field, and <img>/<video> need attribute translation into style.width/style.height — that is a new feature, not a bug fix, and it would duplicate logic the rm-* path already implements and tests. Redirecting to the existing, schema-checked path is the smaller and safer change. code/pre were deliberately left alone: they lose no content today, they are merely styled as plain containers.

Boolean attributes

No bool schema field was reachable from HTML: coerce_value left "false" as a string, so auto_scroll, diff, loop, show_grid, show_borders, pulse could not be expressed at all. Now aligned with coerce_dsl_value.

Behaviour change worth flagging: an empty attribute value (attr="") now yields true rather than being dropped. html5ever cannot distinguish <rm-codeblock diff> from diff="" at DOM level, so the two cannot be told apart — a bare boolean is idiomatic HTML, an intentionally-empty string attribute in a video dialect is not, so the trade favours the former. A field expecting a string and given attr="" now produces a named type error instead of silently falling back to its default.

Verification

cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace — 752 passed, 0 failed, re-run by the orchestrator on the integrated tree. 24 new tests (10 unit, 14 integration in tests/silent_loss_regressions.rs), each written red first.

Known gap, reported not fixed

Text written directly inside <head> still leaks as a text component: html5ever removes the <head> node itself under the "in body" rule and re-parents its text as a sibling, so there is no element left to match by the time transpilation runs. Outside the audit's reproduction; recorded rather than papered over.

The HTML dialect degraded four classes of input without a word, and
`rustmotion validate` answered "Valid scenario" for all of them. An author
who writes a construct the transpiler cannot honour has to be told.

`<style>` content was transpiled into a `text` component and painted into
the video. It is now refused: `<style>` has a real, expected visual effect
that the dialect cannot deliver (there is no cascade engine), so dropping
it silently defeats a genuine intent. `<script>`, `<title>`, `<noscript>`,
`<template>` and `<head>` are skipped instead — no browser paints them, so
ignoring them defeats nothing and merely stops their text leaking onto the
canvas.

A `<scene>` nested inside any container disappeared from the scenario. It
is now refused, naming the offending parent, and the search is recursive:
that also catches the case an unclosed `<p>` creates, where HTML5 error
recovery hoists the `<h1>` out of the scene and leaves an empty one behind.
Recursing silently would have hidden exactly that corruption.

`<img>`, `<video>` and `<svg>` became empty `div`s. They are now refused
with the equivalent `rm-*` element named in the message.

No `bool` schema field was reachable: `coerce_value` left `"false"` a
string, so `auto_scroll`, `diff`, `loop`, `show_grid` and friends could not
be expressed at all. It now matches `coerce_dsl_value`, and a bare HTML
boolean attribute resolves to `true`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant