Skip to content

feat(lint): warn on dense compositions#531

Merged
miguel-heygen merged 1 commit intomainfrom
lint/subcomposition-guidance
Apr 28, 2026
Merged

feat(lint): warn on dense compositions#531
miguel-heygen merged 1 commit intomainfrom
lint/subcomposition-guidance

Conversation

@miguel-heygen
Copy link
Copy Markdown
Collaborator

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

Problem

Agents can still pack too much scene structure into one HTML composition. That makes HyperFrames videos harder to inspect, revise, and validate, especially when a single file owns many layers or a dense timeline track.

What this fixes

Adds two non-blocking core lint warnings across every HTML file passed through core lint:

  • composition_file_too_large warns when a composition file has more than 300 physical lines.
  • timeline_track_too_dense warns when more than three timed non-root elements share one data-track-index in the same file.

The warning copy points agents toward coherent sub-compositions under compositions/, mounted from the parent with data-composition-src, so each file stays small enough to inspect, revise, and validate independently.

Root cause

The linter had correctness checks, but no maintainability guidance for agent-authored compositions that were too large or timeline-dense.

Verification

Local checks

  • bun run --filter @hyperframes/core test src/lint/rules/composition.test.ts
  • bunx oxlint packages/core/src/lint/rules/composition.ts packages/core/src/lint/rules/composition.test.ts
  • bunx oxfmt --check packages/core/src/lint/rules/composition.ts packages/core/src/lint/rules/composition.test.ts

Browser verification

No browser flow exists for this lint-only stack layer. Runtime/browser-visible validation remains covered by the parent CLI smoke PR and CI.

Notes

  • This PR is stacked on fix: validate CLI smoke paths #523 (fix/cli-validate-smoke-ci).
  • Registry/example HTML cleanup is intentionally not included here; doing that by minifying files creates huge review noise and works against the sub-composition guidance this lint is meant to teach.

@miguel-heygen miguel-heygen force-pushed the lint/subcomposition-guidance branch 2 times, most recently from d5721e1 to 94ba1c9 Compare April 28, 2026 16:15
@vanceingalls
Copy link
Copy Markdown
Collaborator

Summary

Two new warning-severity lint rules to nudge agents toward
splitting large compositions into sub-compositions.
composition_file_too_large (>300 lines) and
timeline_track_too_dense (>3 timed elements per track). Clean diff,
CI green.

Issues

  1. timeline_track_too_dense doesn't skip /

A composition with 4 sequential audio cues on track 0 (common
pattern for sound design: intro sting, background music, transition
SFX, outro) would fire this warning. Splitting audio across
sub-compositions doesn't help — it just moves the tags to
different files that get bundled back together.

The existing timed_element_missing_visibility_hidden rule (line 9)
skips audio/script/style. timed_element_missing_clip_class (line 142) skips audio/video. This rule should too.

  1. Fix hint copy says "split into sub-compositions" even when file
    IS a sub-composition

Both rules fire regardless of options.isSubComposition. That's
correct — a 400-line sub-comp should split further. But the fixHint
says "split into separate .html files under compositions/" which
is confusing when you're already inside compositions/scene.html.
Consider branching the hint copy, or making it directional ("split
further into smaller files").

  1. Registry test asserts behavior no entry point enforces

Test "warns on large non-index registry composition files" uses
filePath: "/project/registry/blocks/data-chart.html". But
lintProject.ts only walks compositions/ — registry blocks are never
linted by the CLI lint command, studio-api/routes/lint.ts, or
producer/hyperframeLint.ts. The test proves the rule fires on any
HTML, which is fine as a unit test, but the registry/blocks path
framing implies the system enforces this for registry content. It
doesn't. Either add registry walking to lintProject, or rename the
test to something like "warns on any file regardless of path".

  1. 32 of 40 existing registry blocks exceed 300 lines

The PR body acknowledges this ("Registry/example HTML cleanup is
intentionally not included here"). But registry blocks are
single-file-by-design — transitions, shader effects, social cards.
They can't meaningfully split into sub-compositions. If registry
paths ever get linted (point 3), this threshold will be pure noise.
Worth documenting that these files are exempt by architecture, not
just by "cleanup deferred."

  1. Threshold = 3 is aggressive for sequential clips

A 4-image slideshow with sequential non-overlapping clips on one
track is a normal pattern. The fix hint ("split into
sub-compositions") is high-ceremony for what amounts to A | B | C |
D on a timeline. Consider 5 or 6 as the threshold, or scope the
rule to elements that overlap in time (which
overlapping_clips_same_track already covers at severity=error).

  1. No threshold rationale in code

MAX_COMPOSITION_LINES = 300 and MAX_TIMED_ELEMENTS_PER_TRACK = 3 —
where do these numbers come from? Empirical agent failure rate? The
existing examples all stay under both, so they were likely derived from current patterns. A one-line comment
documenting the source would help future calibration.

What's good

  • Warnings not errors — non-blocking is right for guidance rules
  • isCompositionRootOrMount exclusion is correct
  • countPhysicalLines trailing-newline handling is solid
  • Tests are thorough: boundary cases, trailing newline, track splitting, composition-root exclusion

@miguel-heygen miguel-heygen force-pushed the lint/subcomposition-guidance branch from 94ba1c9 to e14ff9b Compare April 28, 2026 19:45
@miguel-heygen
Copy link
Copy Markdown
Collaborator Author

Addressed the actionable feedback in the latest force-push:

  • timeline_track_too_dense now skips audio, video, script, and style, matching the existing timed-element rules and avoiding sound-mix false positives.
  • Fix hints now branch on options.isSubComposition, so sub-compositions say to split further instead of implying they are the root.
  • Renamed the registry-path unit test to describe the actual behavior: the rule fires for any HTML path passed to core lint.
  • Added a short code comment documenting that the 300-line / 3-element values are warning-only agent-guidance thresholds, not correctness limits.

I kept the >3 threshold because that is the product requirement for this warning. I also did not add registry walking here; registry cleanup/enforcement should be a separate architecture decision rather than hidden in this lint-rule PR.

Base automatically changed from fix/cli-validate-smoke-ci to main April 28, 2026 20:44
@miguel-heygen miguel-heygen merged commit e568235 into main Apr 28, 2026
37 checks passed
@miguel-heygen miguel-heygen deleted the lint/subcomposition-guidance branch April 28, 2026 21:08
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.

2 participants