Skip to content

staging round 2: MHTML support (mirror of upstream #149) - #10

Open
marcellmanfrin wants to merge 58 commits into
mainfrom
fix/ultrareview-mhtml-round2
Open

marcellmanfrin wants to merge 58 commits into
mainfrom
fix/ultrareview-mhtml-round2

Conversation

@marcellmanfrin

@marcellmanfrin marcellmanfrin commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Staging PR for Cubic ultrareview round 2 — mirrors the content of firecrawl#149 at candidate 932bf18 (round-1 staging #7 + HTML round-2 cherry-pick + ultrareview fixes: encapsulated message preflight, boundary/header caps, QP delimiter bound, encoding-problem rejection, base64 encoded-size bound). Do not merge; the real review happens upstream.


Summary by cubic

Adds standalone HTML and MHTML input support so .html, .mhtml, and .mht files now convert to GitHub-Flavored Markdown instead of failing as unrecognized formats.

New Features

  • Detects HTML from a leading doctype or <html> marker, and MHTML from a multipart/related MIME type with archive evidence such as Snapshot-Content-Location.
  • Resolves embedded images and stylesheets only from MIME parts inside the archive; no network requests are made and JavaScript is not executed.
  • Exposes html and mhtml formats in the Node, Python, and WASM bindings, content/extension detection, and CLI help.

Hardening

  • Preflight caps MIME nesting depth, boundary length, and header-block size, and walks encapsulated message/rfc822 chains recursively against those limits, decoding transfer-encoded bodies first so encoded chains can't hide their nesting.
  • Boundary matching requires the RFC 2046 delimiter suffix at line start, allows transport padding, and rejects closing delimiters that don't end cleanly.
  • Resource lookups strip query strings and fragments, and relative references join against a root location whose authority ends at /, ?, or #.
  • Bounds quoted-printable parts up front and rejects broken transfer encodings, including linked stylesheets; base64 bodies are checked by decoded size only, since base64 expands by 4/3.
  • HTML depth preflight mirrors the parser: block starts close open paragraphs in button scope, foreign content (SVG/MathML) never triggers HTML implied closes or raw-text states, implied closes are context-gated per HTML5 insertion rules, duplicate wrappers don't undercount depth, end tags pop only their in-scope special elements, table-family starts clear stray foster content above the table, and bare frame tags never stack.
  • Keeps RTF and PDF detection precedence when non-archive files carry MHTML-looking headers.

Written for commit cfd9b80. Summary will update on new commits.

Review in cubic

github-actions Bot and others added 30 commits August 28, 2026 12:59
Integrates, as one tree identical to candidate ee4aefd:
- standalone HTML PR 147 head ce79482 (frameset + relative image fixes for the latest Cubic findings)
- the MHTML resource-hardening follow-up validated in fork PR #4 (base64 pre-decode reserve check, encoded/decoded part size limits, MIME nesting depth bound, RTF/PDF detection precedence, README/metadata)

Full gate passed on tree-identical candidate ee4aefd (fork Actions run on branch verify/mhtml-pr4-reconciled-full, success, 2026-08-30T08:12Z) and again locally on this exact commit. Canonical fixtures .local/fixtures/example.mhtml and example.root.html convert with clean Portuguese encoding on this tree.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 existing issue remains and 3 new issues found across 42 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/formats/html.rs">

<violation number="1" location="src/formats/html.rs:38">
P2: Standalone HTML preserves executable URL schemes such as `javascript:` in generated links. Override `link_target` for this context and allow only safe schemes (or reject `javascript:`, `data:`, and similar active schemes) before emitting Markdown.</violation>
</file>

<file name="src/formats/mhtml.rs">

<violation number="1" location="src/formats/mhtml.rs:27">
P2: An RFC 2557 MHTML file without a `Snapshot-Content-Location` header is not detected as Mhtml because `looks_like_mhtml` requires both `multipart/related` and that header. Such files already carry the `multipart/related` MIME type, which is the RFC container identity; consider treating a `multipart/related` content type alone as sufficient (or as a fallback) so valid archives without the Microsoft header still convert.</violation>

<violation number="2" location="src/formats/mhtml.rs:584">
P2: Base64 parts are limited by encoded size before decoded size, so valid parts larger than roughly 96 MiB are rejected despite fitting `MAX_ENTRY_BYTES`. Remove the encoded-size check and rely on the decoded upper-bound and final decoded-size checks.</violation>
</file>

Requires human review: Auto-approval blocked by 4 unresolved issues from previous reviews.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread src/formats/mhtml.rs Outdated
Comment thread src/formats/html.rs
}

let text = decode_html(bytes);
parse_text_with_context(&text, None, &StandaloneCtx, Vec::new())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Standalone HTML preserves executable URL schemes such as javascript: in generated links. Override link_target for this context and allow only safe schemes (or reject javascript:, data:, and similar active schemes) before emitting Markdown.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/formats/html.rs, line 38:

<comment>Standalone HTML preserves executable URL schemes such as `javascript:` in generated links. Override `link_target` for this context and allow only safe schemes (or reject `javascript:`, `data:`, and similar active schemes) before emitting Markdown.</comment>

<file context>
@@ -0,0 +1,700 @@
+    }
+
+    let text = decode_html(bytes);
+    parse_text_with_context(&text, None, &StandaloneCtx, Vec::new())
+}
+
</file context>

Comment thread src/formats/mhtml.rs
};
let compact: String = content_type.chars().filter(|c| !c.is_ascii_whitespace()).collect();

(compact == "multipart/related" || compact.starts_with("multipart/related;")) && snapshot

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: An RFC 2557 MHTML file without a Snapshot-Content-Location header is not detected as Mhtml because looks_like_mhtml requires both multipart/related and that header. Such files already carry the multipart/related MIME type, which is the RFC container identity; consider treating a multipart/related content type alone as sufficient (or as a fallback) so valid archives without the Microsoft header still convert.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/formats/mhtml.rs, line 27:

<comment>An RFC 2557 MHTML file without a `Snapshot-Content-Location` header is not detected as Mhtml because `looks_like_mhtml` requires both `multipart/related` and that header. Such files already carry the `multipart/related` MIME type, which is the RFC container identity; consider treating a `multipart/related` content type alone as sufficient (or as a fallback) so valid archives without the Microsoft header still convert.</comment>

<file context>
@@ -0,0 +1,1098 @@
+    };
+    let compact: String = content_type.chars().filter(|c| !c.is_ascii_whitespace()).collect();
+
+    (compact == "multipart/related" || compact.starts_with("multipart/related;")) && snapshot
+}
+
</file context>

Review findings (staging PRs #11 and #10):

- Duplicate <html>/<body> start tags are ignored by html5ever; pushing
  them moved the body-relative depth baseline upward and undercounted
  every later descendant. Skip a wrapper token when that wrapper is
  already on the modeled stack.
- End-tag scope rules are now tag-specific like the parser's: the table
  family uses table scope (html, table, template), </li> uses list-item
  scope (adds ol/ul/button), </p> uses button scope (adds button), and
  svg/math foreign roots end every HTML scope search. Previously an end
  tag crossing a template, ol/ul, button, or foreign root truncated the
  modeled stack that html5ever leaves intact, undercounting depth.
- Refactor the repeated inline depth-error assertions in tests/html.rs
  to the existing assert_preflight_depth_limit helper.

Regressions: a duplicate <body> no longer moves the baseline (260 divs
rejected before DOM construction); </p> blocked by button scope keeps
150+150 nested divs counted; </table> blocked by a template keeps 260
nested spans counted.
marcellmanfrin pushed a commit that referenced this pull request Sep 5, 2026
Review findings (staging PRs #11 and #10):

- Duplicate <html>/<body> start tags are ignored by html5ever; pushing
  them moved the body-relative depth baseline upward and undercounted
  every later descendant. Skip a wrapper token when that wrapper is
  already on the modeled stack.
- End-tag scope rules are now tag-specific like the parser's: the table
  family uses table scope (html, table, template), </li> uses list-item
  scope (adds ol/ul/button), </p> uses button scope (adds button), and
  svg/math foreign roots end every HTML scope search. Previously an end
  tag crossing a template, ol/ul, button, or foreign root truncated the
  modeled stack that html5ever leaves intact, undercounting depth.
- Refactor the repeated inline depth-error assertions in tests/html.rs
  to the existing assert_preflight_depth_limit helper.

Regressions: a duplicate <body> no longer moves the baseline (260 divs
rejected before DOM construction); </p> blocked by button scope keeps
150+150 nested divs counted; </table> blocked by a template keeps 260
nested spans counted.
@marcellmanfrin

Copy link
Copy Markdown
Owner Author

@cubic-dev-ai review this pull request

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown

@cubic-dev-ai review this pull request

@marcellmanfrin I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/formats/html.rs">

<violation number="1" location="src/formats/html.rs:205">
P2: When `<html>` appears inside SVG, html5ever treats it as a foreign element, but this guard compares only local names and skips every subsequent `<html>`. Restrict duplicate-wrapper suppression to HTML content, or track namespaces, so foreign nesting cannot bypass the preflight depth check.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/formats/html.rs

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 42 files

Requires human review: Auto-approval blocked by 1 unresolved issue from a previous review of this commit.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread src/formats/html.rs Outdated
Marcell Manfrin added 2 commits September 5, 2026 18:52
- close_element: </body> and </html> never truncate the open-element
  stack; html5ever only switches insertion modes and later start tags
  keep nesting, so truncating undercounted real open depth.
- duplicate html/body wrapper suppression now skips foreign content,
  where <html> is an ordinary foreign element, not a duplicate wrapper.
- is_end_tag_scope_marker: drop "button" from li list-item scope
  markers per the HTML5 spec; </li> must still close the item past an
  open button.
- refresh stale hr comment: void tags reach the implied-close hook via
  close_implied, so <hr> does close an open <p>.

Adds regression tests for all three behavior fixes.
The base64 arm enforced max_entry_bytes on the raw encoded body, but
base64 expands data by 4/3: a part that decodes to exactly the limit
has an encoded body ~33% larger and was wrongly rejected as over the
limit. The decoded upper-bound check and the post-decode size check
already cover the real limit, so the encoded-size check is removed.

A regression test would need a ~128MB fixture, which is impractical
for the suite; behavior is covered by the existing upper-bound and
decoded-size error paths.

Copy link
Copy Markdown
Owner Author

@cubic-dev-ai review this pull request

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown

@cubic-dev-ai review this pull request

@marcellmanfrin I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 existing issue remains and no new issues found across 42 files

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread src/formats/mhtml.rs
Marcell Manfrin added 3 commits September 5, 2026 20:11
Preflight fidelity fixes for the HTML complexity sink (cubic round C):

- close_element: any-other end tags now stop at html5ever's full special
  category (plus svg/math foreign roots), not just the 9 generic scope
  markers. Previously </em> below <em><div><span> truncated real nesting
  the parser keeps open, undercounting depth and defeating the
  reject-before-DOM guarantee. The div family, button, form, headings,
  and template keep their generic-scope rule; dd/dt use button scope and
  rt/rp/rb/rtc use ruby scope, matching the parser.
- close_element: </body>/</html> only stay no-ops in HTML content; inside
  foreign content they are ordinary foreign elements whose end tags pop.
- close_element: option/optgroup end tags only check the current node,
  like html5ever; deeper searches truncated real nesting.
- close_implied_before_start: li/dd/dt walk from the innermost element
  and stop at any special element other than address/div/p; p closes
  only within button scope; rt/rp pop only the current node; option
  pops only the current node and optgroup additionally closes an
  innermost optgroup inside a select context.
- close_implied_before_start: table-family start tags (caption/col/
  colgroup/tbody/td/tfoot/th/thead/tr) outside a table are ignored
  entirely, matching body-context parse errors; pushing them let a later
  implied close truncate divs opened between stray cells (undercount).
  Inside a table the row/body-context clears are unchanged.

Adds 8 regression tests (66 html integration tests total).
The encapsulated-message preflight bounded base64/quoted-printable sizes
but then recursed into the still-encoded bytes: a base64 body exposes no
MIME headers to the raw scan, and a quoted-printable body can hide them
behind =XX escapes, so the walk stopped at the first encoded level while
mail-parser kept decoding and nesting. Deeply nested encoded
message/rfc822 chains could therefore evade the max_mime_depth budget.

Decode the bounded body (enforcing the decoded upper bound for base64,
as the multipart-level walk already does) and recurse on the decoded
bytes. Multipart bodies are still scanned raw: RFC 2046 forbids
transfer encodings on multipart and mail-parser looks for the boundary
in the undecoded bytes.

Regression tests alternate base64/plain chain levels and quote-escape
colons in quoted-printable chain levels; both fail without the decode
step (verified) and hit max_mime_depth with it.
Cubic (run bad77c8a, conf6) proposed treating bare svg/math as
pass-through in is_end_tag_scope_marker, aligning the markers with the
in-body default_scope set. That proposal is rejected: while a bare
svg/math root is reachable, html5ever resolves end tags in the
foreign-content phase, whose walk stops at the first HTML element or
integration point below the root and ignores the token — the same
outcome as the modeled root stop. Integration points always sit below
their root, so both marker sets stop identically; dropping the root
stop instead would let scope-based end tags truncate through an open
foreign root that the parser ignores, undercounting depth.

Verified empirically: with svg/math made pass-through, this test fails
(the deep foreign nesting passes preflight); with the root stop it
rejects before DOM construction, matching the parser.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread tests/html.rs
Cubic (run d03d9e02, tests/html.rs pin) proved — and html5ever 0.39
source confirms — that the previous root-stop model was wrong:

- step_foreign (rules.rs 1652-1684): an end tag in foreign content walks
  the stack for a name match in ANY namespace and truncates there; on
  reaching an HTML element below the root without a match it REPROCESSES
  the token in the current insertion mode.
- default_scope (tag_sets.rs): html_default_scope (incl. select) plus the
  MathML text and SVG HTML integration points; bare svg/math are NOT
  markers, so reprocessed scope searches pop through open foreign roots
  to an in-scope target (e.g. </p> under <p><svg><g> closes the p).
- process_end_tag_in_body (mod.rs 1563): any-other end tags stop at
  special_tag (incl. isindex; integration points are not special).

Changes:
- close_element: unified walk without the svg/math root stop; body/html
  and option/optgroup use a foreign-region match (>= foreign_root_index)
  because their in-body rules never pop, while foreign-region matches do.
- GENERIC_SCOPE_MARKERS: add select and the integration-point names
  (matched without namespaces; HTML title collision is harmless).
- is_special_element: align exactly with html5ever special_tag.
- pop_foreign_breakout refactored onto the new foreign_root_index helper.
- Replace the wrong-premise pin test with two source-verified ones:
  scope end tags pop through foreign roots to their target (converts),
  and unmatched end tags still stop at special elements below roots
  (preflight rejects). All 68 html integration tests pass; fixtures
  byte-identical.

Supersedes the round-C N2 rejection: the rejection was wrong about the
mechanism (foreign-phase name-match pop is real); its undercount warning
applies only to dropping the stop WITHOUT the region logic, which this
commit implements properly.

Copy link
Copy Markdown
Owner Author

@cubic-dev-ai review this pull request

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown

@cubic-dev-ai review this pull request

@marcellmanfrin I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 42 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/formats/mhtml.rs">

<violation number="1" location="src/formats/mhtml.rs:187">
P2: When an MHTML multipart has no valid closing delimiter, this preflight treats EOF as a normal part end and allows truncated archives to convert. Track whether a proper closing delimiter was found and return `Malformed` when the multipart ends without one.</violation>
</file>

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread src/formats/mhtml.rs
)));
}

let next_parent = find_marker(bytes, body_start, end, &marker, true).unwrap_or(end);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When an MHTML multipart has no valid closing delimiter, this preflight treats EOF as a normal part end and allows truncated archives to convert. Track whether a proper closing delimiter was found and return Malformed when the multipart ends without one.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/formats/mhtml.rs, line 187:

<comment>When an MHTML multipart has no valid closing delimiter, this preflight treats EOF as a normal part end and allows truncated archives to convert. Track whether a proper closing delimiter was found and return `Malformed` when the multipart ends without one.</comment>

<file context>
@@ -0,0 +1,1221 @@
+            )));
+        }
+
+        let next_parent = find_marker(bytes, body_start, end, &marker, true).unwrap_or(end);
+
+        if headers_use_base64(headers) {
</file context>

Comment thread src/formats/html.rs
Cubic round D (PR #10 run 10ff97ec, P2 conf8): html5ever ignores a
stray frame start tag in body context and inserts-then-immediately-pops
it in frameset context, so frames never nest in the real DOM. The
preflight stacked every frame, falsely reporting max_xml_depth for
framesets with more than 256 sibling frames. Treat frame like the void
elements in HTML content (it still pushes inside foreign content, where
it is an ordinary foreign element).

Verified discriminating: without the fix, the new frameset test fails;
with it, 70/70 html tests pass.

Also pins two round-D rejections grounded in html5ever 0.39 source:
- markup inside <select> really nests (html5ever has no in-select
  insertion mode; InBody inserts it), so the depth guard must fire —
  ignoring select content would undercount the real DOM.
- the unconditional title/textarea raw-text switch cannot hide deep
  nesting: every mode that accepts those tags inserts them, and the
  frameset modes that ignore them also ignore all later start tags
  (comment only, no behavior change).
marcellmanfrin pushed a commit that referenced this pull request Sep 6, 2026
Cubic round D (PR #10 run 10ff97ec, P2 conf8): html5ever ignores a
stray frame start tag in body context and inserts-then-immediately-pops
it in frameset context, so frames never nest in the real DOM. The
preflight stacked every frame, falsely reporting max_xml_depth for
framesets with more than 256 sibling frames. Treat frame like the void
elements in HTML content (it still pushes inside foreign content, where
it is an ordinary foreign element).

Verified discriminating: without the fix, the new frameset test fails;
with it, 70/70 html tests pass.

Also pins two round-D rejections grounded in html5ever 0.39 source:
- markup inside <select> really nests (html5ever has no in-select
  insertion mode; InBody inserts it), so the depth guard must fire —
  ignoring select content would undercount the real DOM.
- the unconditional title/textarea raw-text switch cannot hide deep
  nesting: every mode that accepts those tags inserts them, and the
  frameset modes that ignore them also ignore all later start tags
  (comment only, no behavior change).

Copy link
Copy Markdown
Owner Author

@cubic-dev-ai review this pull request

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown

@cubic-dev-ai review this pull request

@marcellmanfrin I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 existing issue remains and no new issues found across 42 files

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Cubic round E (PR #11 run e74d240e, P2 conf9): html5ever's InTable arms
for caption, col, colgroup, tbody/tfoot/thead, and td/th/tr all begin
with pop_until_current(table_scope) — stray foster-parented content
above the table leaves the open-element stack. The preflight kept it,
so repaired table markup with deep stray content accumulated phantom
depth and could be falsely rejected at max_xml_depth. Model the clear
(stopping at the innermost table/template/html, exactly the table_scope
set); the phantom tbody/tr wrappers html5ever inserts afterwards remain
unmodeled (bounded, documented deviation). The previous per-tag
rposition truncation is subsumed by the clear and was removed — it
could also reach below the current table for stale matches.

Also strengthens the raw-text tests (P3 conf7): the script test moves
into the body and asserts the script source is NOT rendered, so it
actually distinguishes ScriptData swallowing from data-state parsing;
the title test gains the same negative assertion.

Regression test: table_family_starts_clear_stray_content_above_the_table
(253 stray divs then tbody/tr/td must convert). Discrimination verified:
without the clear the test fails; with it, 71/71 html tests pass.

Copy link
Copy Markdown
Owner Author

@cubic-dev-ai review this pull request

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 7, 2026

Copy link
Copy Markdown

@cubic-dev-ai review this pull request

@marcellmanfrin I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 42 files

You’re at about 97% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Cubic round F (PR #11 run 7cf7afee, P2 conf9): when a block start tag
arrived with an open <p> holding inline descendants, the preflight left
the paragraph (and its descendants) on the modeled stack — html5ever
closes any button-scope p first (close_p_element_in_button_scope,
mod.rs), popping the descendants with it.

The stale p was worse than an overcount: the next p start's button-scope
walk would find it BELOW intervening blocks opened since (blockquote,
etc.) and truncate through them, undercounting the nesting the parser
really keeps open — <blockquote><p><b> repeated stays flat in the model
while html5ever nests the blockquotes without bound, defeating the
reject-before-DOM guarantee.

Walk with the button-scope markers for every paragraph-closing block
start (p included, so the duplicate p-start branch is removed).

Regression test block_starts_close_paragraphs_with_inline_descendants:
255 iterations must reject at preflight depth. Discrimination verified
against the exact previous state (innermost-only block close + p-start
walk): the test fails there and passes with the fix. 72/72 html tests.
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.

1 participant