Skip to content

Update atem-state#445

Merged
mint-dewit merged 1 commit into
mainfrom
chore/update-atem-state
Mar 9, 2026
Merged

Update atem-state#445
mint-dewit merged 1 commit into
mainfrom
chore/update-atem-state

Conversation

@mint-dewit

Copy link
Copy Markdown
Member

About the Contributor

This pull request is posted on behalf of the BBC.

Type of Contribution

Updates for Sofie-Automation/sofie-atem-state#46

@mint-dewit mint-dewit added the contribution from BBC Contributions sponsored by BBC (bbc.co.uk) label Mar 9, 2026
@sonarqubecloud

sonarqubecloud Bot commented Mar 9, 2026

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown

Walkthrough

The changes refactor ATEM integration type definitions and state handling. A new AtemTransitionSelection enum with bit-flag values is introduced. TimelineContentAtemME.me is restructured from a discriminated union to an explicit object with transition-related fields including transition style, selection, position, and preview behavior. Implementation logic is updated to use ProgramInputCommand instead of separate PreviewInputCommand/CutCommand sequences, and programInput derivation uses nullish coalescing.

Changes

Cohort / File(s) Summary
Type Definitions
packages/timeline-state-resolver-types/src/integrations/atem.ts
Introduced AtemTransitionSelection enum with bit-flag values. Refactored TimelineContentAtemME.me from XOR-based union to single object with explicit transition fields (transition, programInput, previewInput, transitionSelection, transitionPosition, transitionSettings, inTransition, transitionPreview). Added deprecation notes for input field.
Dependency Update
packages/timeline-state-resolver/package.json
Upgraded atem-state dependency from 1.2.1 to 1.3.0.
Test Updates
packages/timeline-state-resolver/src/integrations/atem/__tests__/atem.spec.ts, packages/timeline-state-resolver/src/integrations/atem/__tests__/diffStates.spec.ts
Updated expected commands from PreviewInputCommand/CutCommand pairs to single ProgramInputCommand in transition tests. Reduced expected command count from 2 to 1 in initial state transition scenarios.
State Implementation
packages/timeline-state-resolver/src/integrations/atem/state.ts
Changed programInput derivation to use nullish coalescing operator (me.input ?? me.programInput). Updated resolveUpstreamKeyerState call signature with additional undefined argument. Modified result checking from output.length to output.commands.length.
State Builder
packages/timeline-state-resolver/src/integrations/atem/stateBuilder.ts
Changed transitionSelection handling from merge operation to explicit mapping to transitionProperties.nextSelection, ensuring separate handling path in mix effect application.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • fix: shared control undefined state #419 — Directly related changes to ATEM integration including resolveUpstreamKeyerState usage, programInput/ProgramInputCommand behavior, and state handling patterns.

Suggested labels

Contribution from BBC

Suggested reviewers

  • Julusian
  • nytamin
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Update atem-state' is vague and generic, using a non-descriptive term that doesn't convey meaningful information about the specific changes made. Use a more descriptive title that highlights the primary change, such as 'Refactor ATEM ME transition handling and update atem-state dependency' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description is related to the changeset as it indicates this PR is an update for atem-state and references a related upstream PR, but lacks detail about the actual changes made.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/update-atem-state

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/timeline-state-resolver-types/src/integrations/atem.ts (1)

161-190: ⚠️ Potential issue | 🟠 Major

Keep the M/E input shapes mutually exclusive.

previewInput being “cuts only” and the input/programInput split are now comment-level rules only. The runtime still treats them as discriminated branches: packages/timeline-state-resolver/src/integrations/atem/state.ts suppresses previewInput only when input exists, so programInput + previewInput and input + previewInput now both type-check but are serialized differently. Please keep the old XOR/discriminated shape for the input fields and layer the new transition properties on top of it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/timeline-state-resolver-types/src/integrations/atem.ts` around lines
161 - 190, The me input shape must be a discriminated (mutually exclusive) union
so previewInput cannot coexist with programInput/input; change the me
property/type in the ATEM integration types to express an XOR between (a) {
input?: number } or { programInput?: number } and (b) { previewInput?: number }
so that previewInput is only valid when no program/input is present, then
compose/extend that union with the existing transition-related fields
(transition, inTransition, transitionPreview, transitionPosition,
transitionSettings, transitionSelection) so the transition properties remain
layered on top; ensure this matches the runtime handling in
packages/timeline-state-resolver/src/integrations/atem/state.ts (which currently
suppresses previewInput only when input exists) by making the type reflect the
same discriminated branches.
packages/timeline-state-resolver/src/integrations/atem/stateBuilder.ts (1)

153-173: ⚠️ Potential issue | 🟠 Major

Stamp the .base controlValue when transitionSelection changes.

A selection-only M/E object now updates transitionProperties.nextSelection, but Line 484 still only records the .base address for previewInput or transition. That means video.mixEffects.{index}.base can change without ever getting a fresh controlValue, which breaks granular tracking for selection-only layers.

🩹 Minimal fix
-		if ('previewInput' in content.me || 'transition' in content.me) {
+		if ('previewInput' in content.me || 'transition' in content.me || 'transitionSelection' in content.me) {
 			addresses.push('video.mixEffects.' + mapping.index + '.base')
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/timeline-state-resolver/src/integrations/atem/stateBuilder.ts`
around lines 153 - 173, When handling selection-only updates you currently set
stateMixEffect.transitionProperties.nextSelection from
content.me.transitionSelection but don’t update the corresponding controlValue
address, so video.mixEffects.{index}.base can be stale; when
content.me.transitionSelection exists (and has length) also stamp the mix effect
base controlValue the same way you do for previewInput/transition updates —
i.e., update this.#deviceState.video.mixEffects[mapping.index].base (the
controlValue/address derived from content.me.base or the same
previewInput/transition path you use elsewhere) so selection-only M/E changes
get a fresh .base controlValue alongside
stateMixEffect.transitionProperties.nextSelection.
🧹 Nitpick comments (1)
packages/timeline-state-resolver/src/integrations/atem/__tests__/atem.spec.ts (1)

165-166: Cover the new programInput path in at least one integration test.

These updated assertions still drive the M/E through deprecated me.input, so the new serialization path in packages/timeline-state-resolver/src/integrations/atem/state.ts is still untested. Swapping one of these happy-path cases to programInput would give this upgrade a regression test for the behavior it is actually introducing.

Also applies to: 200-201, 281-282

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/timeline-state-resolver/src/integrations/atem/__tests__/atem.spec.ts`
around lines 165 - 166, Update one (or more) integration tests so a happy-path
case drives the M/E via the new programInput field instead of the deprecated
me.input; replace the old expectation that asserted the deprecated path with an
assertion that the resolver emits the new
AtemConnection.Commands.ProgramInputCommand (use
compareAtemCommands(allCommands[0], new
AtemConnection.Commands.ProgramInputCommand(...)) to assert payload), and
similarly adjust the other two test locations mentioned (the assertions around
the other cases at the ranges referenced) so at least one test explicitly
exercises the programInput serialization path implemented in
packages/timeline-state-resolver/src/integrations/atem/state.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/timeline-state-resolver-types/src/integrations/atem.ts`:
- Around line 161-190: The me input shape must be a discriminated (mutually
exclusive) union so previewInput cannot coexist with programInput/input; change
the me property/type in the ATEM integration types to express an XOR between (a)
{ input?: number } or { programInput?: number } and (b) { previewInput?: number
} so that previewInput is only valid when no program/input is present, then
compose/extend that union with the existing transition-related fields
(transition, inTransition, transitionPreview, transitionPosition,
transitionSettings, transitionSelection) so the transition properties remain
layered on top; ensure this matches the runtime handling in
packages/timeline-state-resolver/src/integrations/atem/state.ts (which currently
suppresses previewInput only when input exists) by making the type reflect the
same discriminated branches.

In `@packages/timeline-state-resolver/src/integrations/atem/stateBuilder.ts`:
- Around line 153-173: When handling selection-only updates you currently set
stateMixEffect.transitionProperties.nextSelection from
content.me.transitionSelection but don’t update the corresponding controlValue
address, so video.mixEffects.{index}.base can be stale; when
content.me.transitionSelection exists (and has length) also stamp the mix effect
base controlValue the same way you do for previewInput/transition updates —
i.e., update this.#deviceState.video.mixEffects[mapping.index].base (the
controlValue/address derived from content.me.base or the same
previewInput/transition path you use elsewhere) so selection-only M/E changes
get a fresh .base controlValue alongside
stateMixEffect.transitionProperties.nextSelection.

---

Nitpick comments:
In
`@packages/timeline-state-resolver/src/integrations/atem/__tests__/atem.spec.ts`:
- Around line 165-166: Update one (or more) integration tests so a happy-path
case drives the M/E via the new programInput field instead of the deprecated
me.input; replace the old expectation that asserted the deprecated path with an
assertion that the resolver emits the new
AtemConnection.Commands.ProgramInputCommand (use
compareAtemCommands(allCommands[0], new
AtemConnection.Commands.ProgramInputCommand(...)) to assert payload), and
similarly adjust the other two test locations mentioned (the assertions around
the other cases at the ranges referenced) so at least one test explicitly
exercises the programInput serialization path implemented in
packages/timeline-state-resolver/src/integrations/atem/state.ts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1c6347af-52c7-4760-9b9c-cd7300fe2bfc

📥 Commits

Reviewing files that changed from the base of the PR and between 5310e15 and dea89c9.

⛔ Files ignored due to path filters (3)
  • packages/timeline-state-resolver-types/src/__tests__/__snapshots__/index.spec.ts.snap is excluded by !**/*.snap
  • packages/timeline-state-resolver/src/__tests__/__snapshots__/index.spec.ts.snap is excluded by !**/*.snap
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • packages/timeline-state-resolver-types/src/integrations/atem.ts
  • packages/timeline-state-resolver/package.json
  • packages/timeline-state-resolver/src/integrations/atem/__tests__/atem.spec.ts
  • packages/timeline-state-resolver/src/integrations/atem/__tests__/diffStates.spec.ts
  • packages/timeline-state-resolver/src/integrations/atem/state.ts
  • packages/timeline-state-resolver/src/integrations/atem/stateBuilder.ts

@mint-dewit mint-dewit merged commit d04961f into main Mar 9, 2026
38 of 42 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 27, 2026
4 tasks
@nytamin nytamin deleted the chore/update-atem-state branch June 16, 2026 05:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution from BBC Contributions sponsored by BBC (bbc.co.uk)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant