Skip to content

fix(cli): snapshot warns when self-closed audio or video clips have swallowed the page - #6915

Merged
miguel-heygen merged 1 commit into
mainfrom
fix/lint-self-closed-media
Nov 1, 2026
Merged

miguel-heygen merged 1 commit into
mainfrom
fix/lint-self-closed-media

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

What

snapshot prints a warning (and adds it to the result's warnings) when the project's index.html has self-closed <audio> or <video> tags, naming how many and the first few ids: index.html has 21 self-closed <audio>/<video> tags (#a1, #a2, #a3): HTML leaves them open, so everything after the first one is hidden and stills come out blank. Write <audio ...></audio>.

Why

snapshot gave fully blank stills on projects with many root <audio> clips (about 20 sound effects). HTML does not close a non-void element with />, so each self-closed clip stays open and takes in everything after it, including the visible scenes; elements inside a media element never paint. Reproduced on the Linux devbox: 20 self-closed <audio ... /> clips followed by a headline gave a background-only PNG at every time, the same project with closing tags rendered the headline.

An earlier version of this PR added a second lint rule for it. That was my miss: lint already reports self_closing_media_tag as an error on every self-closed audio/video (media.ts:656), the reporter simply never ran lint, because snapshot never reads it. This version drops the duplicate rule and the docs entry, and surfaces the existing finding where the report came from.

How

selfClosedMediaWarning(source) in snapshot.ts runs lintHyperframeHtml on the entry file and keeps the self_closing_media_tag findings; captureSnapshots prints and records the result before capturing. No new lint code and no change to the lint package.

Not done: only index.html is read, not sub-composition files; render does not warn.

Test plan

fails without the fix: snapshot.selfClosedMedia.test.ts "names the self-closed clips and what they do to the still" (and its closed-tag counterpart: selfClosedMediaWarning is not a function at main).

  • The new test and snapshot.test.ts: 98 passed, 3 runs in a row (devbox); both new tests fail with snapshot.ts at main.
  • Real snapshot of a 21-clip self-closed project prints the warning before the first frame (devbox).
  • oxfmt check clean; no type errors in snapshot.ts.
  • The Comments check failure on the earlier version came from the lint file's line scanner re-exposing an older docblock; this version does not touch media.ts.

Size

About 55 changed lines: one helper, one call and one test file.

@mintlify

mintlify Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
hyperframes 🟢 Ready View Preview Nov 1, 2026, 6:01 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: REQUEST CHANGES · 2 blocker · 1 important · 0 nits

The root cause is right, but lint on main already catches it. self_closing_media_tag (media.ts:656-674, docs lint-rules.mdx:688, tests media.test.ts:1525) is an error on every self-closed <audio>/<video>. I ran your 20-clip report shape at this head and got self_closing_media_tag ×20 plus media_element_holds_elements ×1. So the blank stills were never a lint gap, and the tests on the fails without the fix: line only fail because they filter on the new code. ↓ inline

  • important: Comments fails (not a required check). The checker's line scanner already loses template-literal state above line 1152 on main, so the old 13-line carve docblock at media.ts:1211 is hidden there. Your new lines bring it back into view, and the checker charges it to this PR as +9 comment lines and a new 12+ line block. This PR only adds a one-line comment. Please note this in the PR body.
Scope

Read the full diff, parseHtmlStructure (utils.ts), the existing self_closing_media_tag and audio_group_holds_elements, and scripts/comment-ratchet.mjs / check-comment-citations.mjs. The media.test.ts suite passes (149 tests). With the registration commented out, the 2 named tests fail. Probes: a self-closed clip as the last child is quiet, a chain is reported once, and a clip inside a <template> is flagged.

Comment thread packages/lint/src/rules/media.ts Outdated

// audio_group_holds_elements
findAudioGroupHoldsElementsFindings,
findMediaHoldsElementsFindings,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocker: This duplicates self_closing_media_tag (line 656), which is already an error on every self-closed <audio>/<video>. A self-closed clip now gets two errors for one mistake. The PR body says lint had "nothing for the media elements", but that rule already covers them. If the extra context is useful (how many elements were swallowed, a chain reported once), add it to the existing rule's message rather than adding a second code. The blank-stills report is better handled where the user was: snapshot/render could fail fast or warn when lint errors exist (the PR's "Not done" item).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Fixed in 6a35790: the duplicate rule is gone.

Comment thread packages/lint/src/rules/media.ts Outdated
const first = readAttr(held[0]!.raw, "id");
findings.push({
code: "media_element_holds_elements",
severity: "error",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocker: For a properly closed media element, held is legitimate fallback content. For example, <video id="v" src="v.mp4" ...><p>Your browser does not support video.</p></video> (probed at this head) gets this error, so check fails. The message also says "everything after a self-closed clip disappears", which is false here. This is the only case the new rule adds beyond self_closing_media_tag. Either drop the rule or limit it to the swallowed-siblings shape (for example, when closeIndex is the parent's implied close).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Fixed in 6a35790: the duplicate rule is gone.

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 100 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

@miguel-heygen
miguel-heygen force-pushed the fix/lint-self-closed-media branch from 6e0eba6 to 6a35790 Compare November 1, 2026 05:57
@miguel-heygen miguel-heygen changed the title feat(lint): flag a self-closed audio or video clip that swallows the rest of the composition fix(cli): snapshot warns when self-closed audio or video clips have swallowed the page Nov 1, 2026
@miguel-heygen

Copy link
Copy Markdown
Collaborator Author

You are right, and I missed self_closing_media_tag (media.ts:656): I searched lint for 'self-clos', found only the audio-group rule, and wrote a duplicate. Replaced at 6a35790: the lint rule, its docs entry and tests are gone (so the false positive on fallback content and the Comments failure go with them); snapshot now runs the existing lint on the entry file and warns with the count and ids when self_closing_media_tag fires, which is where the report came from. Test red at main, 98 green x3, and a real snapshot of a 21-clip project prints the warning.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: APPROVE · 3 resolved, 0 open, 0 new · 6e0eba6 → 6a35790

Scope

The duplicate lint rule and its docs entry are gone, and media.ts is untouched; Comments is green. snapshot now repeats the existing self_closing_media_tag finding as a warning. @hyperframes/lint is already a CLI dependency, used the same way by studioServer.ts:580. The 2 new tests pass here, and snapshot.ts has no type errors. Optional follow-up: run() already gets lintProject(project.dir), which covers sub-compositions too. Reusing that result would close the PR's "only index.html" gap and save a second lint pass, but diff calls captureSnapshots without it, so that's a design choice, not a blocker. CI was still running when I reviewed.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit 8c22ddb Nov 1, 2026
117 of 118 checks passed
@miguel-heygen
miguel-heygen deleted the fix/lint-self-closed-media branch November 1, 2026 06:32

This branch was successfully deployed

1 active deployment
staging - docs — 6a357900 Deployed Nov 1, 2026 by mintlify[bot]
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