You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(lint): break two fix-loops and drop two rules the runtime owns (#3400)
An eval of time-to-finished-video against Remotion found the whole gap sits
after authoring, in the lint/check -> fix -> recheck loop. Lint execution is
3-5% of wall; the cost is the model turn each finding triggers. So the
expensive rule is the one an agent cannot satisfy, and the next most expensive
is the one that fires on correct code.
Two rules could not be satisfied at all.
`gsap_fullscreen_overlay_starts_visible` on a from() reveal was a closed cycle.
It errored on `tl.from("#flash", { opacity: 0 })`, which is not a defect:
from() seats its start values immediately, so on a paused timeline the overlay
already measures opacity 0 at t=0. Both of its fixHints (authored CSS
`opacity: 0`, or an immediate `gsap.set`) turn that working composition into a
real defect, which `gsap_from_opacity_noop` correctly errors on -- and that
rule's fixHint says to remove the very thing we just asked for. Applying either
hint bounced between the two errors forever.
The root cause was not the reporting condition but `laterHidden`, which counted
the reveal itself: a from-tween records its START values, so
`from({opacity: 0})` read as its own later hide. Excluding the reveal, and
excluding from-tweens (which end visible), is what actually fixes it. The
later-hidden shape still reports and still converges.
`caption_text_overflow_risk` told authors to add `overflow: hidden`, which is
exactly what `caption_overflow_clips_scaled_words` errors on. Following the
warning produced an error. The hint now says to keep overflow visible.
Two rules asserted a failure that cannot happen.
`root_composition_missing_data_start` errored because "the runtime needs
data-start=0 on the root element to begin playback". The runtime sets it itself
-- init.ts:286-292, whose comment reads "Agents sometimes omit data-start on the
root composition element ... Default to 0 for the root." The rule demanded the
fix the runtime had already applied. 16 of the 643 shipped registry files.
`overlapping_clips_same_track` claimed overlapping clips "cause rendering
conflicts". Nothing reads the track index at render: timeline.ts:586 states
"Track index is display-only; render never reads it", and grepping
`trackIndex|track-index` across engine and producer source returns zero hits.
Two clips overlapping on one track is a crossfade.
Two false positives fixed rather than removed, because the invariants are real.
`timeline_id_mismatch` fired on the legal one-liner
`window.__timelines = { main: gsap.timeline({ paused: true }) }`. The body regex
was non-greedy, so it stopped at the brace of the inlined OPTIONS object, and
the entry scanner harvested `paused` as a composition id. The resulting fixHint
named a registration that does not exist, so it could never be applied; hoisting
to a variable was the only escape and nothing said so. It now walks brace depth
and reads top-level keys only.
`non_deterministic_code` fired on `new Date("2026-01-01T00:00:00Z")`, which is
deterministic, and on `Math.random()` inside a string literal that a code-display
composition renders but never executes. Date is now zero-arg only, and patterns
run against string-stripped source -- except the GSAP `"random(...)"` tween
value, where the string IS the executed value and must still be scanned. That
exception is what the first attempt got wrong; the existing tests caught it.
Measured over the 643 shipped registry files: 386 -> 370 errors, no new codes.
The corpus does not exercise the loop cases, so it understates the change -- the
point is the turns those loops cost, not the finding count.
message: `Track ${track}: clip ending at ${current.end}s overlaps with clip starting at ${next.start}s. Overlapping clips on the same track cause rendering conflicts.`,
599
-
fixHint:
600
-
"Adjust data-start or data-duration so clips on the same track do not overlap, or move one clip to a different data-track-index.",
// `scansStrings` because here the string IS the executed value: GSAP parses it.
488
+
// Every other pattern above matches executable code, so a match inside a string
489
+
// literal is inert text and must not be reported.
475
490
pattern: /["'`](?:[+-]=)?random\(\s*[-\d[]/,
491
+
scansStrings: true,
476
492
label: '"random(...)" tween value',
477
493
hint: "GSAP random string values re-roll at tween init and each render worker initializes independently. Use fixed values or precompute with a seeded PRNG.",
0 commit comments