Skip to content

feat(lint): add rules for non-deterministic code, missing clip class, overlapping tracks, and rAF detection#193

Merged
vanceingalls merged 2 commits into
mainfrom
feat/lint-determinism-clip-overlap-raf
Apr 2, 2026
Merged

feat(lint): add rules for non-deterministic code, missing clip class, overlapping tracks, and rAF detection#193
vanceingalls merged 2 commits into
mainfrom
feat/lint-determinism-clip-overlap-raf

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds 4 new lint rules found missing during comprehensive E2E testing:

  • non_deterministic_code (error) — detects Math.random(), Date.now(), new Date(), performance.now(), crypto.getRandomValues() in scripts. Confirmed: two renders with Math.random() produced different checksums.
  • timed_element_missing_clip_class (warning) — flags elements with data-start/data-duration but no class="clip". Without it, elements are visible forever instead of only during their time window.
  • overlapping_clips_same_track (error) — detects clips on the same data-track-index with overlapping time ranges.
  • requestanimationframe_in_composition (warning) — warns that rAF-based animations don't sync with frame capture. Discovered when Vivus.js (rAF-based) produced incorrect output.

12 new tests, all passing.

Part 1 of 5 in a stacked PR series fixing E2E test findings.

Test plan

  • 12 new tests (3 per rule: positive, negative, edge case)
  • Full suite: 56 pass in rule tests
  • npx tsx scripts/lint-skills.ts — no issues

… overlapping tracks, and rAF detection

Add 4 new lint rules to close E2E testing gaps:
- non_deterministic_code (error): detects Math.random(), Date.now(), new Date(), performance.now(), crypto.getRandomValues() in scripts
- timed_element_missing_clip_class (warning): flags timed elements without class="clip"
- overlapping_clips_same_track (error): detects overlapping clips on the same track index
- requestanimationframe_in_composition (warning): flags rAF usage that won't sync with frame capture

All rules strip single-line comments before scanning to avoid false positives.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator

@miguel-heygen should we make these warnings?
non_deterministic_code (error) — detects Math.random(), Date.now(), new Date(), performance.now(), crypto.getRandomValues() in scripts. Confirmed: two renders with Math.random() produced different checksums.

I think there are potential use cases for some simulations to use thse but yes they will not produce the exact same output

unless we seed the RNG ?

Copy link
Copy Markdown
Collaborator

requestanimationframe_in_composition (warning) — warns that rAF-based animations don't sync with frame capture. Discovered when Vivus.js (rAF-based) produced incorrect output.

what does this mean exactly?

Copy link
Copy Markdown
Collaborator Author

requestanimationframe_in_composition (warning) — warns that rAF-based animations don't sync with frame capture. Discovered when Vivus.js (rAF-based) produced incorrect output.

what does this mean exactly?

requestAnimationFrame (raf) doesn't work well with the renderer using vivus.js library

miguel-heygen commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator Author

@miguel-heygen should we make these warnings?
non_deterministic_code (error) — detects Math.random(), Date.now(), new Date(), performance.now(), crypto.getRandomValues() in scripts. Confirmed: two renders with Math.random() produced different checksums.

I think there are potential use cases for some simulations to use thse but yes they will not produce the exact same output

unless we seed the RNG ?

with a seed it's fully deterministic, in my opinion we should make these errors because they can produce unexpected outputs that we can't control with the runtime code in certain cases

@vanceingalls vanceingalls left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review feedback

Important: Non-null assertions
packages/core/src/lint/rules/composition.ts uses clips[i]! and clips[i + 1]! in the overlap rule. Project convention forbids ! assertions — use a guard like if (!current || !next) continue; instead.

Important: Block comment false positives
The comment stripping in non_deterministic_code and requestanimationframe_in_composition only strips // ... single-line comments. Multi-line /* Math.random() */ will still trigger false positives. Fix:

const stripped = script.content
  .replace(/\/\/.*$/gm, "")
  .replace(/\/\*[\s\S]*?\*\//g, "");

Note: Rule overlap
The new timed_element_missing_clip_class (warning) overlaps with the existing timed_element_missing_visibility_hidden (info). A single element could trigger both with slightly contradictory messaging. Consider merging or gating the older rule.

Tests look solid — 3 per rule with positive/negative/edge cases.

Address review feedback:
- Strip /* */ block comments in addition to // line comments to prevent
  false positives in non_deterministic_code and rAF rules
- Replace clips[i]! non-null assertions with guard clause per project
  convention

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@miguel-heygen

Copy link
Copy Markdown
Collaborator Author

All three review items addressed:

  1. Non-null assertions: Replaced clips[i]! and clips[i + 1]! with a guard clause (if (!current || !next) continue;) per project convention.

  2. Block comment false positives: Added /\*[\s\S]*?\*\/ stripping alongside the existing single-line comment strip in both non_deterministic_code and requestanimationframe_in_composition rules.

  3. Rule overlap with timed_element_missing_visibility_hidden: Noted. The existing rule is info severity and suggests opacity:0 or visibility:hidden as alternatives. The new timed_element_missing_clip_class is warning severity and specifically recommends class="clip" which is the canonical approach. They can coexist since they serve different purposes (general hidden state vs framework-specific visibility control). Happy to gate the older rule if you prefer.

All 56 rule tests still passing.

@vanceingalls vanceingalls merged commit 4bb01fd into main Apr 2, 2026
20 of 22 checks passed
miguel-heygen added a commit that referenced this pull request Apr 3, 2026
… overlapping tracks, and rAF detection (#193)

## Summary

Adds 4 new lint rules found missing during comprehensive E2E testing:

- **`non_deterministic_code`** (error) — detects `Math.random()`, `Date.now()`, `new Date()`, `performance.now()`, `crypto.getRandomValues()` in scripts. Confirmed: two renders with Math.random() produced different checksums.
- **`timed_element_missing_clip_class`** (warning) — flags elements with `data-start`/`data-duration` but no `class="clip"`. Without it, elements are visible forever instead of only during their time window.
- **`overlapping_clips_same_track`** (error) — detects clips on the same `data-track-index` with overlapping time ranges.
- **`requestanimationframe_in_composition`** (warning) — warns that rAF-based animations don't sync with frame capture. Discovered when Vivus.js (rAF-based) produced incorrect output.

12 new tests, all passing.

**Part 1 of 5** in a stacked PR series fixing E2E test findings.

## Test plan

- [x] 12 new tests (3 per rule: positive, negative, edge case)
- [x] Full suite: 56 pass in rule tests
- [x] `npx tsx scripts/lint-skills.ts` — no issues
@miguel-heygen miguel-heygen deleted the feat/lint-determinism-clip-overlap-raf branch April 6, 2026 23:24
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.

3 participants