Skip to content

feat(studio,lint): carve targets voiceover groups — always, when plural - #3288

Open
vanceingalls wants to merge 1 commit into
wa-23c-group-previewfrom
wa-23f-carve-groups
Open

feat(studio,lint): carve targets voiceover groups — always, when plural#3288
vanceingalls wants to merge 1 commit into
wa-23c-group-previewfrom
wa-23f-carve-groups

Conversation

@vanceingalls

Copy link
Copy Markdown
Collaborator

Summary

Implements B6 from plans/audio-execution/B6-carve-groups.md: plural voiceover carve always targets a group instead of naming each clip.

  • Analysis-time resolution: resolveCarveSourceIds (core audioGroups.ts) expands a group id to its current members at analysis time, so a clip added to the group later is covered without touching sources. DSP untouched — mixCarveSources already sums multiple sources correctly.
  • Picker: offers a grouped voice as one option instead of one row per member; overlap is a union of member spans (a group overlaps the bed if ANY member does); a qualifying group is preferred over its individual members in autoSourceIds.
  • Auto-group on multi-pick: picking two or more ungrouped voice clips mints a group behind them (mintGroupId, de-duped against every id in the document) and writes data-audio-group on each picked clip atomically, one undo entry (createAudioGroupAndAssignMembers, copies setElementsHidden's multi-target write shape).
  • New lint rule audio_carve_ungrouped_sources (alongside audio_volume_double_automation): warns when data-fx-carve's sources names two or more plain clip ids instead of a group.
  • /hyperframes-audio states the same rule as an invariant with the grouped-narration HTML example from the design doc.

Notable fix mid-implementation

resolveNextCarveSettings is deliberately not an async function — wrapping it in one forces a microtask on every call, including the synchronous branch, which is the exact bug withAutoGroupedSources's sync-when-possible contract exists to avoid. Caught this via propertyPanelAudioFxGroup.test.tsx (10 failures) during a complexity-driven refactor, fixed back to a plain function the caller conditionally awaits.

Housekeeping

Extracted useEffectiveTimelineDuration (App.tsx) and useRemoveBackground (StudioRightPanel.tsx) — both pushed past the 600-line studio filesize cap from an added prop wire (onAutoGroupCarveSources). Decomposed useFxCarve.ts's picker IIFE into useFxCarveGrouping.ts to clear fallow's complexity gate.

Stacks on and depends on:

Test plan

  • bun run build clean
  • packages/core full suite: 2364/2364
  • packages/studio full suite: 4253/4253
  • packages/lint full suite: 524/524 (39 in media.test.ts, incl. 4 new audio_carve_ungrouped_sources cases)
  • oxfmt/oxlint clean
  • fallow: 0 new findings (2 remaining are pre-existing in untouched audioFx.ts)
  • Manual verification in hyperframes preview (needs a running dev server / browser)

🤖 Generated with Claude Code

Plural voiceover carve now targets a group instead of naming each clip:
`resolveCarveSourceIds` (core `audioGroups.ts`) expands a group id to its
current members at analysis time, so a clip added to the group later is
covered without touching `sources`. The picker (`useFxCarve.ts`) offers a
grouped voice as one option instead of one row per member, tests overlap
as a union of member spans (a group overlaps the bed if ANY member does),
and prefers a qualifying group over its individual members in
`autoSourceIds`.

Picking two or more ungrouped voice clips in the carve flow now mints a
group behind them (`mintGroupId`, de-duped against every id in the
document) and writes `data-audio-group` on each picked clip atomically,
one undo entry — `createAudioGroupAndAssignMembers` in
`timelineTrackVisibility.ts` copies `setElementsHidden`'s multi-target
write shape. The DSP is untouched: `mixCarveSources` already sums
multiple sources correctly (verified in the design doc's own
investigation) — this only fixes the picker.

New lint rule `audio_carve_ungrouped_sources` (`packages/lint/src/rules/
media.ts`, alongside `audio_volume_double_automation`) warns when a
`data-fx-carve`'s `sources` names two or more plain clip ids instead of a
group — the shape that silently rots when a clip is added. `/hyperframes-
audio` states the same rule as an invariant, not a tip, with the grouped-
narration HTML example from the design doc.

The group-matching and auto-group logic (`withAutoGroupedSources`,
`collectCarveCandidates`) is split into `useFxCarveGrouping.ts` —
`useFxCarve.ts` was pushing past the 600-line cap. `resolveNextCarveSettings`
is deliberately NOT an `async function`: wrapping it in one would force a
microtask on every call, including the synchronous branch — the exact bug
`withAutoGroupedSources`'s own sync-when-possible contract exists to avoid,
and one caught via `propertyPanelAudioFxGroup.test.tsx` (10 failures)
before fixing it back to a plain function the caller conditionally awaits.

Also extracted `useEffectiveTimelineDuration` out of `App.tsx` and
`useRemoveBackground` out of `StudioRightPanel.tsx` (both pushed past 600
lines from an added prop wire), and decomposed `useFxCarve.ts`'s picker
IIFE to clear fallow's complexity gate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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