Skip to content

feat: emit ingest 'user edit' operations from adlib actions#1671

Open
Julusian wants to merge 4 commits intoSofie-Automation:mainfrom
bbc:feat/user-edit-from-adlibs
Open

feat: emit ingest 'user edit' operations from adlib actions#1671
Julusian wants to merge 4 commits intoSofie-Automation:mainfrom
bbc:feat/user-edit-from-adlibs

Conversation

@Julusian
Copy link
Member

@Julusian Julusian commented Mar 4, 2026

About the Contributor

This pull request is posted on behalf of the BBC

Type of Contribution

This is a: Feature

New Behavior

In certain circumstances, it can be desirable to modify some portions of the planned rundown during playout. This is largely an escape hatch for which we have a proposal for a proper solution, but this can still be useful in certain circumstances.

This leverages the existing user-edits flow, to add a playout event source which certain blueprint playout methods are able to emit.

Testing

  • I have added one or more unit tests for this PR
  • I have updated the relevant unit tests
  • No unit test changes are needed for this PR

Affected areas

Time Frame

Other Information

Status

  • PR is ready to be reviewed.
  • The functionality has been tested by the author.
  • Relevant unit tests has been added / updated.
  • Relevant documentation (code comments, system documentation) has been added / updated.

@Julusian Julusian added the Contribution from BBC Contributions sponsored by BBC (bbc.co.uk) label Mar 4, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

Warning

Rate limit exceeded

@Julusian has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 34 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a4ca8daa-9e8f-4d97-97c0-8a15ddc700c0

📥 Commits

Reviewing files that changed from the base of the PR and between 5fcc941 and b8fd2e9.

📒 Files selected for processing (1)
  • packages/job-worker/src/blueprints/context/lib.ts

Walkthrough

Adds playout-triggered ingest operations: new PlayoutOperationChange type, emitIngestOperation API across blueprint contexts, job-worker plumbing to queue and handle playout ingest jobs, and core worker types for the new job.

Changes

Cohort / File(s) Summary
Blueprint API & types
packages/blueprints-integration/src/ingest.ts, packages/blueprints-integration/src/api/studio.ts
Adds IngestChangeType.Playout and PlayoutOperationChange; expands StudioBlueprintManifest.processIngestData to accept playout changes.
Blueprint contexts & interfaces
packages/blueprints-integration/src/context/executeTsrActionContext.ts, packages/blueprints-integration/src/context/adlibActionContext.ts, packages/blueprints-integration/src/context/onTakeContext.ts, packages/blueprints-integration/src/context/onSetAsNextContext.ts
Introduces ITriggerIngestChangeContext and extends execution contexts with it; IOnSetAsNextContext gains manuallySelected and many part/piece manipulation/query methods.
Core worker types
packages/corelib/src/worker/ingest.ts
Adds IngestJobs.PlayoutExecuteChangeOperation and PlayoutExecuteChangeOperationProps (segmentId, partId, operation).
Job-worker context implementations
packages/job-worker/src/blueprints/context/lib.ts, packages/job-worker/src/blueprints/context/OnTakeContext.ts, packages/job-worker/src/blueprints/context/OnSetAsNextContext.ts, packages/job-worker/src/blueprints/context/adlibActions.ts
Implements emitIngestOperation(context, playoutModel, operation), exposes emitIngestOperation on context classes, queues playout ingest job with rundown/segment/part ids and operation; includes error handling and logging.
Ingest handling & job registration
packages/job-worker/src/ingest/runOperation.ts, packages/job-worker/src/ingest/userOperation.ts, packages/job-worker/src/workers/ingest/jobs.ts
Expands ingest change union to include PlayoutOperationChange, adds handlePlayoutExecuteChangeOperation to produce UpdateIngestRundownChange, and registers handler for the new job type.

Sequence Diagram

sequenceDiagram
    participant Blueprint as Blueprint Code
    participant Context as OnTake/OnSetAsNext Context
    participant Lib as emitIngestOperation Lib
    participant JobQueue as Ingest Job Queue
    participant Handler as PlayoutExecuteChangeOperation Handler
    participant DB as Rundown Data

    Blueprint->>Context: emitIngestOperation(operation)
    Context->>Lib: emitIngestOperation(context, playoutModel, operation)
    Lib->>Lib: select ref PartInstance (current/next)
    Lib->>DB: resolve rundown (playoutModel.getRundown)
    Lib->>JobQueue: queue PlayoutExecuteChangeOperation (rundownExternalId, segmentId, partId, operation)
    JobQueue->>Handler: execute queued job
    Handler->>DB: create UpdateIngestRundownChange with PlayoutOperationChange
    Handler->>DB: persist ingest change
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

Contribution

Suggested reviewers

  • nytamin
  • PeterC89

Poem

🐰 I nudged a job into the queue tonight,
A playout whisper, soft and light,
Parts and pieces hum in flight,
Operation sent — no need to wait,
The show hops on, delightful and bright! 🎩✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature: enabling emission of 'user edit' operations from adlib actions during playout.
Description check ✅ Passed The description is directly related to the changeset, explaining the feature's purpose and implementation approach through the user-edits flow.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@codecov
Copy link

codecov bot commented Mar 4, 2026

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
packages/job-worker/src/blueprints/context/lib.ts (2)

734-740: Redundant optional chaining after null check.

refPartInstance is guaranteed to be non-null after the check on line 729, so the optional chaining on lines 737-738 is unnecessary.

Suggested fix
 	await context
 		.queueIngestJob(IngestJobs.PlayoutExecuteChangeOperation, {
 			rundownExternalId: rundown.rundown.externalId,
-			segmentId: refPartInstance?.partInstance.segmentId ?? null,
-			partId: refPartInstance?.partInstance.part._id ?? null,
+			segmentId: refPartInstance.partInstance.segmentId,
+			partId: refPartInstance.partInstance.part._id,
 			operation,
 		})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/job-worker/src/blueprints/context/lib.ts` around lines 734 - 740,
Remove the redundant optional chaining for refPartInstance when calling
context.queueIngestJob with IngestJobs.PlayoutExecuteChangeOperation: since
refPartInstance is checked to be non-null earlier, replace
refPartInstance?.partInstance.segmentId and
refPartInstance?.partInstance.part._id with
refPartInstance.partInstance.segmentId and refPartInstance.partInstance.part._id
so the call to context.queueIngestJob uses the guaranteed non-null properties.

741-745: Original error details lost in rethrown exception.

The original error is logged but the rethrown error only contains a generic message, making debugging harder for callers who catch this exception. Consider including the original error or using error chaining.

Suggested improvement
 		.catch((e) => {
 			logger.warn(`Failed to queue ingest operation: ${stringifyError(e)}`)
 
-			throw new Error('Internal error while queueing ingest operation')
+			throw new Error(`Internal error while queueing ingest operation: ${stringifyError(e)}`)
 		})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/job-worker/src/blueprints/context/lib.ts` around lines 741 - 745,
The catch block that currently logs the error with logger.warn(`Failed to queue
ingest operation: ${stringifyError(e)}`) then throws new Error('Internal error
while queueing ingest operation') loses the original error details; change the
rethrow to preserve the original error (either rethrow the original error, throw
a new Error with the original message included, or use error chaining via new
Error('Internal error while queueing ingest operation', { cause: e })) so
callers can access the original exception; update the code around the catch
where stringifyError, logger.warn, and the throw occur to include the original
error (e) as the cause or include its message/stack in the thrown Error.
packages/blueprints-integration/src/ingest.ts (1)

196-207: Consider generic typing for PlayoutOperationChange.operation.

operation: unknown forces runtime casting/guards everywhere it’s consumed. A generic operation type (even with a default) would improve blueprint-side type safety without changing runtime behavior.

♻️ Suggested typing upgrade
-export interface PlayoutOperationChange {
+export interface PlayoutOperationChange<TOperation = unknown> {
 	/** Indicate that this change is from playout operations */
 	source: IngestChangeType.Playout
@@
 	/** The blueprint defined payload for the operation */
-	operation: unknown
+	operation: TOperation
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/blueprints-integration/src/ingest.ts` around lines 196 - 207, The
PlayoutOperationChange interface should be made generic so callers can supply a
concrete operation type instead of always using unknown; change
PlayoutOperationChange to a generic like PlayoutOperationChange<T = unknown> and
replace the operation: unknown field with operation: T, then update any places
that reference PlayoutOperationChange (e.g., unions, factory functions,
handlers) to either provide a concrete type argument or rely on the default;
ensure exported types that compose with PlayoutOperationChange (such as any
IngestChange union/type aliases and functions that construct or consume
PlayoutOperationChange) are updated to accept the generic parameter or keep
using the default to preserve runtime behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/blueprints-integration/src/ingest.ts`:
- Around line 196-207: The PlayoutOperationChange interface should be made
generic so callers can supply a concrete operation type instead of always using
unknown; change PlayoutOperationChange to a generic like
PlayoutOperationChange<T = unknown> and replace the operation: unknown field
with operation: T, then update any places that reference PlayoutOperationChange
(e.g., unions, factory functions, handlers) to either provide a concrete type
argument or rely on the default; ensure exported types that compose with
PlayoutOperationChange (such as any IngestChange union/type aliases and
functions that construct or consume PlayoutOperationChange) are updated to
accept the generic parameter or keep using the default to preserve runtime
behavior.

In `@packages/job-worker/src/blueprints/context/lib.ts`:
- Around line 734-740: Remove the redundant optional chaining for
refPartInstance when calling context.queueIngestJob with
IngestJobs.PlayoutExecuteChangeOperation: since refPartInstance is checked to be
non-null earlier, replace refPartInstance?.partInstance.segmentId and
refPartInstance?.partInstance.part._id with
refPartInstance.partInstance.segmentId and refPartInstance.partInstance.part._id
so the call to context.queueIngestJob uses the guaranteed non-null properties.
- Around line 741-745: The catch block that currently logs the error with
logger.warn(`Failed to queue ingest operation: ${stringifyError(e)}`) then
throws new Error('Internal error while queueing ingest operation') loses the
original error details; change the rethrow to preserve the original error
(either rethrow the original error, throw a new Error with the original message
included, or use error chaining via new Error('Internal error while queueing
ingest operation', { cause: e })) so callers can access the original exception;
update the code around the catch where stringifyError, logger.warn, and the
throw occur to include the original error (e) as the cause or include its
message/stack in the thrown Error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fb3ce0c2-8407-4e0e-974d-e58feab14f88

📥 Commits

Reviewing files that changed from the base of the PR and between c5dd995 and 5f8efca.

📒 Files selected for processing (14)
  • packages/blueprints-integration/src/api/studio.ts
  • packages/blueprints-integration/src/context/adlibActionContext.ts
  • packages/blueprints-integration/src/context/executeTsrActionContext.ts
  • packages/blueprints-integration/src/context/onSetAsNextContext.ts
  • packages/blueprints-integration/src/context/onTakeContext.ts
  • packages/blueprints-integration/src/ingest.ts
  • packages/corelib/src/worker/ingest.ts
  • packages/job-worker/src/blueprints/context/OnSetAsNextContext.ts
  • packages/job-worker/src/blueprints/context/OnTakeContext.ts
  • packages/job-worker/src/blueprints/context/adlibActions.ts
  • packages/job-worker/src/blueprints/context/lib.ts
  • packages/job-worker/src/ingest/runOperation.ts
  • packages/job-worker/src/ingest/userOperation.ts
  • packages/job-worker/src/workers/ingest/jobs.ts

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.

2 participants