fix(lint): respect timed clip visibility for overlays#2496
fix(lint): respect timed clip visibility for overlays#2496miguel-heygen wants to merge 1 commit into
Conversation
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Reviewed at d0397087. Red CI (Tests on windows-latest, Producer: integration tests) are the recurring env/flake surface seen across today's PRs, not lint-touching; running against this diff would help confirm but not blocker-shaped.
Blockers
(none)
Concerns
(none)
Nits
(none)
Green notes
🟢 getClipTagClasses(tag) bail is the right surface. The .clip class is the runtime's contract for timed clips — packages/lint/src/rules/gsap.ts:301 returns non-null iff the element carries it, and the runtime hides such elements outside their [data-start, data-start + data-duration) window (post-#2490 half-open convention). Nothing to reveal → nothing to flash.
🟢 Red-first pin is honest. The test wires a paused timeline with tl.from("#scene-2", { opacity: 0, duration: 0.18 }, 8.00) on a fullscreen .clip with data-start="8" — pre-PR this fires gsap_fullscreen_overlay_starts_visible (false positive); post-PR the finding is undefined. A minimal repro of the exact miscategorization.
🟢 Same helper already used at :315 (clip-boundary collection) and :578 — the "am I a timed clip?" check reuses the module's canonical predicate rather than sprouting a new one. Consistent shape.
What I didn't verify
- Whether a
.clipwithdata-start="0"AND a later GSAP.from()reveal on it would legitimately flash (the clip is visible from the first frame because the runtime doesn't hide it inside its window, so a later reveal starts from opacity:0 and jumps visible). The current bail is unconditional on any.clipclass. Probably a non-pattern in real content — authors don't usually add opacity reveals to clips that are visible from frame 0 — but if the pattern shows up, this rule now silently misses it. Worth a follow-up test only if it becomes real. - The two red CI checks. Windows-latest across today's batches has been the same happy-dom / ECONNREFUSED flake; Producer integration may be the same or different — flagging so you can confirm with a rerun.
Verdict framing
Narrow, correct fix backed by a red-first test. LGTM from my side.
vanceingalls
left a comment
There was a problem hiding this comment.
Reviewed at d0397087. Additive to @james-russo-rames-d-jusso's LGTM — filling the two verification gaps he flagged plus a Rule-15 sibling-rule sweep.
Blockers
(none)
Concerns
(none)
Nits
🟡 Exemption doesn't guard on data-start presence — packages/lint/src/rules/gsap.ts:682 bails on any getClipTagClasses(tag) match, but getClipTagClasses returns non-null iff the tag carries the clip token, independent of data-start. The runtime-contract justification ("hidden outside [data-start, data-start + data-duration)") only holds when the runtime is actually managing the element — collectClipStartBoundariesByComposition at :318-319 itself requires start != null && start > 0 before treating a clip as a boundary. A rogue <div class="clip"> with no data-start slips through both this rule and the inverse guard at packages/lint/src/rules/composition.ts:353 (which only fires on data-start without clip, not the reverse). Almost certainly a non-pattern against current authoring — filing as follow-up test only, not a blocker. If you want to tighten pre-emptively: if (getClipTagClasses(tag) && readAttr(tag.raw, "data-start") != null) continue;
Green notes
🟢 Field-signal repro is exact. The #hyperframes-cli-feedback case (10 sequential scene overlays hidden by data-start, all flagged) reduces to ".clip with data-start > 0 + later GSAP reveal" — the new test at packages/lint/src/rules/gsap.test.ts:217 pins that shape with a minimal 2-scene composition (data-start="0" / data-start="8" + tl.from("#scene-2", ..., 8.00)). Pre-PR fires, post-PR undefined.
🟢 No red-first coverage regressed. The existing transition-flash red tests (gsap.test.ts:147, :264, :285, :308) all target <div id="tr-flash-1"> — non-.clip elements — so the new bail at :682 doesn't over-mute genuine full-frame-overlay violations. Grouped selector, style-block-authored, and .from reveal variants all still fire.
🟢 Sibling audit clean (Rule 15). Grepped packages/lint/src/rules/{composition,core,captions,fonts,media,slideshow,textures}.ts for overlay/visibility semantics — no sibling _starts_visible variant needs the same fix. The two adjacent visibility rules are (a) composition.ts:353 = inverse direction (data-start without clip), orthogonal; (b) scene_layer_missing_visibility_kill at gsap.ts:1026 = exit-tween scope, already clip-aware for fixhint routing. No cross-rule drift; no cascade needed.
🟢 Composite state is redundantly correct. .clip with data-start AND authored opacity:0 / autoAlpha:0 short-circuits at both the new bail (:682) and the pre-existing styleHasHiddenInitialState gate (:689). Belt-and-suspenders, no logical conflict.
What I verified that was flagged unverified
- Both red CI checks are unrelated to
packages/lint.Producer: integration testsfails atpackages/producer/src/services/distributed/renderChunk.test.ts:204—expect(a.encodeStageMs).toBeGreaterThan(0)received0(timing/measurement flake).Tests on windows-latestfails in@hyperframes/cli(src/capture/contactSheet.test.tsPNG output +src/utils/npxCommand.test.tshost npx resolution) and@hyperframes/engine(src/services/audioMixer.test.tsffmpeg ENAMETOOLONG regression) — all Windows-specific path/env/command-length surfaces, pre-existing onmain, no code path touchespackages/lint. Not a blocker for this diff; rerun would confirm.
Verdict
Approve. Narrow fix, red-first + green-first coverage honest, no sibling drift, red CI is unrelated.
— Review by Via
Summary
Full-frame scene clips no longer fail
gsap_fullscreen_overlay_starts_visiblemerely because their reveal begins after time zero. The runtime already hides timed.clipelements outside theirdata-start/data-durationwindow, so the rule now remains focused on unmanaged overlays that can actually cover earlier frames while preserving the existing transition-flash protections.A regression test pins a later full-frame clip whose GSAP reveal begins at its own clip boundary.
Test plan
bun test packages/lint/src/rules/gsap.test.ts— 91 passedbun run --cwd packages/lint test— 377 passedbun run --cwd packages/lint typecheckbunx oxfmt --check packages/lint/src/rules/gsap.ts packages/lint/src/rules/gsap.test.tsbunx oxlint packages/lint/src/rules/gsap.ts packages/lint/src/rules/gsap.test.ts