Skip to content

feat: partInstances invalid state SOFIE-317 (#69)#1732

Open
Julusian wants to merge 1 commit into
Sofie-Automation:mainfrom
bbc:feat/partinstances-invalid-state
Open

feat: partInstances invalid state SOFIE-317 (#69)#1732
Julusian wants to merge 1 commit into
Sofie-Automation:mainfrom
bbc:feat/partinstances-invalid-state

Conversation

@Julusian
Copy link
Copy Markdown
Member

About the Contributor

This pull request is posted on behalf of the BBC

Type of Contribution

This is a: Feature

New Behavior

This allows the nexted partinstance to be marked as invalid, while preserving it as the next partinstance.
Visually it is similar to an invalid part, but not the same

image

It is already possible for blueprints to block a take in onTake, this expands upon that ability by making it visible to the user that a part is unplayable right now, while keeping it as the next one to be taken.
This is intended to be used when hitting resource limitations, typically one that is fixable by using an adlib.

This behaves differently to a part being invalid, as this partinstance will remain as nexted. the user is free to use adlibs, change the next and other actions as usual, but they are blocked from taking into this part.

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.

Co-authored-by: Jonas Hummelstrand <jonas@hummelstrand.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Walkthrough

This pull request extends the PartInstance system to support runtime validation failures through a new invalidReason field. The feature allows part instances to be marked invalid at runtime (distinct from planned/ingest-level invalid states), prevents taking such instances as next, generates segment notes for invalid instances, and updates UI components to display both planned and runtime invalid states.

Changes

Cohort / File(s) Summary
Core data models
packages/corelib/src/dataModel/PartInstance.ts, packages/blueprints-integration/src/documents/partInstance.ts
Add invalidReason?: PartInvalidReason field to DBPartInstance and new IBlueprintMutatablePartInstance interface; IBlueprintPartInstance now extends the mutable interface.
Blueprint context API updates
packages/blueprints-integration/src/context/onSetAsNextContext.ts, packages/blueprints-integration/src/context/partsAndPieceActionContext.ts, packages/blueprints-integration/src/context/syncIngestChangesContext.ts
Extend updatePartInstance method signatures across three context interfaces to accept optional instanceProps?: Partial<IBlueprintMutatablePartInstance> parameter alongside existing props parameter.
Job worker blueprint implementations
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/SyncIngestUpdateToPartInstanceContext.ts
Implement updatePartInstance signature updates to accept and forward instanceProps to underlying service layer; SyncIngestUpdateToPartInstanceContext additionally applies invalidReason updates via setInvalidReason.
Blueprint conversion utilities
packages/job-worker/src/blueprints/context/lib.ts
Add convertPartialBlueprintMutatablePartInstanceToCore function to convert blueprint-format invalidReason to core format, wrapping messages with blueprint namespace and setting severity to ERROR; add PlayoutMutatablePartInstance interface.
Instance action service
packages/job-worker/src/blueprints/context/services/PartAndPieceInstanceActionService.ts
Update updatePartInstance to accept instanceProps parameter, convert it to core form, and apply to selected PartInstance; enforce invalidReason updates only on 'next' part instances.
Part instance model
packages/job-worker/src/playout/model/PlayoutPartInstanceModel.ts, packages/job-worker/src/playout/model/implementation/PlayoutPartInstanceModelImpl.ts
Add public setInvalidReason method to allow callers to set or clear the runtime invalid reason for part instances.
Take validation
packages/job-worker/src/playout/take.ts
Add validation in performTakeToNextedPart to throw TakePartInstanceInvalid error if next part instance has invalidReason set, preventing take execution.
Publication and reactive caching
meteor/server/publications/segmentPartNotesUI/publication.ts, meteor/server/publications/segmentPartNotesUI/reactiveContentCache.ts, meteor/server/publications/segmentPartNotesUI/rundownContentObserver.ts
Migrate from DeletedPartInstances to PartInstances collection; update reactive cache to expose PartInstances with expanded field spec including invalidReason; update observer to track invalidReason conditions.
Segment notes generation
meteor/server/publications/segmentPartNotesUI/generateNotesForSegment.ts
Add logic to generate UISegmentPartNote entries for part instances with runtime invalidReason, using severity from reason and appending origin payload referencing segment and part details.
Web UI utilities
packages/webui/src/client/lib/partInstanceUtil.ts
Add getEffectiveInvalidReason helper to select planned part.invalidReason when present, otherwise runtime invalidReason; add isPartInstanceInvalid for boolean invalid state checking; export supporting types PartInstanceLike and PartInvalidReasonExt.
UI component updates
packages/webui/src/client/ui/SegmentList/LinePart.tsx, packages/webui/src/client/ui/SegmentList/LinePartTimeline.tsx, packages/webui/src/client/ui/SegmentTimeline/Parts/SegmentTimelinePart.tsx, packages/webui/src/client/ui/SegmentStoryboard/StoryboardPart.tsx, packages/webui/src/client/ui/SegmentTimeline/Parts/InvalidPartCover.tsx
Update components to use isPartInstanceInvalid and getEffectiveInvalidReason helpers; refactor InvalidPartCover to accept invalidReason prop instead of full part object; apply distinct invalid styling for runtime-invalid instances.
UI styling
packages/webui/src/client/styles/rundownView.scss, packages/webui/src/client/ui/SegmentStoryboard/SegmentStoryboard.scss
Update invalid part cover styling with mix-blend-mode: color-burn and repeating diagonal gradients; add new .segment-timeline__part__invalid-part-instance-cover rules for distinct runtime-invalid visual treatment; change pointer-events from none to all for invalid covers.
Error handling
packages/corelib/src/error.ts
Add TakePartInstanceInvalid = 51 error code to UserErrorMessage enum and register translated message.
Tests - publication and notes
meteor/server/publications/segmentPartNotesUI/__tests__/publication.test.ts, meteor/server/publications/segmentPartNotesUI/__tests__/generateNotesForSegment.test.ts
Update mocks to use PartInstances instead of DeletedPartInstances; add three new test cases covering invalidReason handling: presence with reset=false, presence with reset=true, and undefined invalidReason scenarios.
Tests - blueprint context
packages/job-worker/src/blueprints/__tests__/context-OnSetAsNextContext.test.ts, packages/job-worker/src/blueprints/__tests__/context-OnTakeContext.test.ts, packages/job-worker/src/blueprints/__tests__/context-adlibActions.test.ts
Update test expectations for three-argument updatePartInstance calls; add new tests verifying instanceProps containing invalidReason are forwarded to action service.
Tests - action service
packages/job-worker/src/blueprints/context/services/__tests__/PartAndPieceInstanceActionService.test.ts
Update existing test calls to pass new third instanceProps argument; add coverage for invalidReason enforcement (error when setting on 'current' part, success when setting on 'next' part) and clearing via subsequent updates.

Sequence Diagram

sequenceDiagram
    participant Blueprint as Blueprint<br/>(Action Handler)
    participant Context as Context<br/>(updatePartInstance)
    participant Service as Action Service
    participant Model as PartInstance<br/>Model
    participant Publication as Segment Notes<br/>Publication
    participant UI as UI<br/>Component

    Blueprint->>Context: updatePartInstance(part, props, instanceProps)
    Context->>Service: updatePartInstance(part, props, instanceProps)
    Service->>Model: setInvalidReason(reason)
    Model-->>Service: invalidReason updated
    Service-->>Context: IBlueprintPartInstance (updated)
    Context-->>Blueprint: IBlueprintPartInstance
    
    Note over Model: invalidReason persisted<br/>on PartInstance
    
    Model-->>Publication: observe invalidReason change
    Publication->>Publication: generateNotesForSegment()
    Publication->>Publication: emit UISegmentPartNote
    Publication-->>UI: notes published
    
    UI->>UI: getEffectiveInvalidReason()
    UI->>UI: render with<br/>invalid styling
    UI-->>Blueprint: visual feedback of invalid state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Contribution from BBC, Contribution, ✨ enhancement

Suggested reviewers

  • jstarpl
  • nytamin
  • PeterC89
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: partInstances invalid state SOFIE-317 (#69)' clearly summarizes the main feature: enabling an invalid state for partInstances while keeping them as next parts.
Description check ✅ Passed The description is well-structured, explaining the feature, its use case, behavior, and includes testing confirmation. It directly relates to the changesets across multiple files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown

@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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (2)
packages/webui/src/client/ui/SegmentTimeline/Parts/InvalidPartCover.tsx (1)

43-45: ⚠️ Potential issue | 🟡 Minor

Typo in TODO comment.

Line 44 has "TODOD" instead of "TODO".

🔧 Proposed fix
 	return (
 		<div className={className} ref={element} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
-			{/* TODOD - add back hover with warnings */}
+			{/* TODO - add back hover with warnings */}
 		</div>
 	)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/webui/src/client/ui/SegmentTimeline/Parts/InvalidPartCover.tsx`
around lines 43 - 45, Fix the typo in the inline comment inside the
InvalidPartCover component: change "TODOD - add back hover with warnings" to
"TODO - add back hover with warnings" so the TODO is correctly recognized;
locate the comment within the JSX block that renders the div with props
className, ref={element}, onMouseEnter and onMouseLeave and update the text
accordingly.
packages/job-worker/src/blueprints/context/SyncIngestUpdateToPartInstanceContext.ts (1)

208-244: ⚠️ Potential issue | 🟠 Major

Missing validation: invalidReason should only be allowed on 'next' PartInstance.

Unlike PartAndPieceInstanceActionService.updatePartInstance (which validates that invalidReason can only be set on 'next') and unlike removePartInstance in the same class (which validates playStatus === 'next'), this method allows setting invalidReason for any playStatus ('previous', 'current', or 'next'). This inconsistency could allow blueprints to incorrectly set invalidReason on the current or previous part instance during ingest sync.

🐛 Proposed fix to add validation
 		if (playoutUpdatePartInstance) {
+			if (this.playStatus !== 'next') {
+				throw new Error(`Can only set invalidReason on the next PartInstance`)
+			}
 			this.#partInstance.setInvalidReason(playoutUpdatePartInstance.invalidReason)
 			instancePropsUpdated = true
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/job-worker/src/blueprints/context/SyncIngestUpdateToPartInstanceContext.ts`
around lines 208 - 244, The updatePartInstance method allows setting
invalidReason for any playStatus; add a guard so invalidReason can only be set
when the target PartInstance is the 'next' part. After creating
playoutUpdatePartInstance (convertPartialBlueprintMutatablePartInstanceToCore)
and before calling this.#partInstance.setInvalidReason(...), check
playoutUpdatePartInstance.invalidReason and if present assert
this.#partInstance.partInstance.playStatus === 'next' (throw an Error
otherwise), mirroring the validation used in
removePartInstance/PartAndPieceInstanceActionService.updatePartInstance; only
call setInvalidReason when the check passes.
🧹 Nitpick comments (2)
packages/job-worker/src/playout/take.ts (1)

233-235: Consider adding an appropriate HTTP status code.

Other take-blocking errors in this file use specific HTTP status codes (e.g., TakeBlockedDuration uses 425, TakeFromIncorrectPart uses 412). Without a status code, this will default to 500 (Internal Server Error), which doesn't accurately represent a user-correctable precondition failure.

Proposed fix to add status code
 	if (takePartInstance.partInstance.invalidReason) {
-		throw UserError.create(UserErrorMessage.TakePartInstanceInvalid)
+		throw UserError.create(UserErrorMessage.TakePartInstanceInvalid, undefined, 412)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/job-worker/src/playout/take.ts` around lines 233 - 235, The throw
for takePartInstance.partInstance.invalidReason currently creates a UserError
without an HTTP status, causing a 500; update the throw to include an
appropriate status (use 412 Precondition Failed to match other
precondition-style take errors) by passing the status into UserError.create for
UserErrorMessage.TakePartInstanceInvalid (e.g., add the status option when
calling UserError.create in the block that checks
takePartInstance.partInstance.invalidReason).
packages/webui/src/client/styles/rundownView.scss (1)

1326-1376: Consider extracting a mixin to reduce duplication.

The .segment-timeline__part__invalid-cover and .segment-timeline__part__invalid-part-instance-cover classes are nearly identical, differing only in stripe spacing (5px vs 6px). A mixin could reduce duplication.

♻️ Optional refactor using a mixin
`@mixin` invalid-cover-base($stripe-width) {
  position: absolute;
  top: 0;
  left: 1px;
  bottom: 0;
  right: 1px;
  z-index: 10;
  pointer-events: all;
  mix-blend-mode: color-burn;
  background-image:
    repeating-linear-gradient(
      45deg,
      var(--invalid-reason-color-transparent) 0%,
      var(--invalid-reason-color-transparent) $stripe-width,
      var(--invalid-reason-color-opaque) $stripe-width,
      var(--invalid-reason-color-opaque) 8px
    ),
    repeating-linear-gradient(
      -45deg,
      var(--invalid-reason-color-transparent) 0%,
      var(--invalid-reason-color-transparent) $stripe-width,
      var(--invalid-reason-color-opaque) $stripe-width,
      var(--invalid-reason-color-opaque) 8px
    );
}

.segment-timeline__part__invalid-cover {
  `@include` invalid-cover-base(5px);
}

.segment-timeline__part__invalid-part-instance-cover {
  `@include` invalid-cover-base(6px);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/webui/src/client/styles/rundownView.scss` around lines 1326 - 1376,
The two CSS classes .segment-timeline__part__invalid-cover and
.segment-timeline__part__invalid-part-instance-cover duplicate most properties
except stripe spacing; extract a SCSS mixin (e.g.,
invalid-cover-base($stripe-width)) that contains the shared positioning,
z-index, pointer-events, mix-blend-mode and the two repeating-linear-gradient
definitions parameterized by the stripe width, then replace each class body to
include that mixin with 5px and 6px respectively (refer to the class names
.segment-timeline__part__invalid-cover and
.segment-timeline__part__invalid-part-instance-cover and the new mixin name
invalid-cover-base).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/webui/src/client/ui/SegmentStoryboard/StoryboardPart.tsx`:
- Around line 130-132: The segment-end marker visibility is still using the
static flag part.instance.part.invalid instead of the runtime-aware isInvalid;
update the guard that currently checks !part.instance.part.invalid to use
!isInvalid so the segment-end marker follows the same runtime-invalid logic used
elsewhere (see getEffectiveInvalidReason and isPartInstanceInvalid usages) and
keep visuals consistent across StoryboardPart.

In `@packages/webui/src/client/ui/SegmentTimeline/Parts/SegmentTimelinePart.tsx`:
- Around line 691-693: Several UI branches in SegmentTimelinePart still check
the planned-only flag innerPart.invalid instead of the runtime-aware
isInvalid/effectiveInvalidReason; this lets runtime-invalid parts render as
next/auto-next and show end-of-segment affordances. Update all those branches to
use the computed isInvalid (and where relevant effectiveInvalidReason) instead
of innerPart.invalid — specifically replace checks of innerPart.invalid in the
conditional logic around next/auto-next rendering and inside renderEndOfSegment
with isInvalid so runtime invalidity flows through; ensure the same symbols
(isPartInstanceInvalid, getEffectiveInvalidReason, isInvalid,
effectiveInvalidReason, renderEndOfSegment, innerPart) are used to locate and
update the conditionals.

---

Outside diff comments:
In
`@packages/job-worker/src/blueprints/context/SyncIngestUpdateToPartInstanceContext.ts`:
- Around line 208-244: The updatePartInstance method allows setting
invalidReason for any playStatus; add a guard so invalidReason can only be set
when the target PartInstance is the 'next' part. After creating
playoutUpdatePartInstance (convertPartialBlueprintMutatablePartInstanceToCore)
and before calling this.#partInstance.setInvalidReason(...), check
playoutUpdatePartInstance.invalidReason and if present assert
this.#partInstance.partInstance.playStatus === 'next' (throw an Error
otherwise), mirroring the validation used in
removePartInstance/PartAndPieceInstanceActionService.updatePartInstance; only
call setInvalidReason when the check passes.

In `@packages/webui/src/client/ui/SegmentTimeline/Parts/InvalidPartCover.tsx`:
- Around line 43-45: Fix the typo in the inline comment inside the
InvalidPartCover component: change "TODOD - add back hover with warnings" to
"TODO - add back hover with warnings" so the TODO is correctly recognized;
locate the comment within the JSX block that renders the div with props
className, ref={element}, onMouseEnter and onMouseLeave and update the text
accordingly.

---

Nitpick comments:
In `@packages/job-worker/src/playout/take.ts`:
- Around line 233-235: The throw for takePartInstance.partInstance.invalidReason
currently creates a UserError without an HTTP status, causing a 500; update the
throw to include an appropriate status (use 412 Precondition Failed to match
other precondition-style take errors) by passing the status into
UserError.create for UserErrorMessage.TakePartInstanceInvalid (e.g., add the
status option when calling UserError.create in the block that checks
takePartInstance.partInstance.invalidReason).

In `@packages/webui/src/client/styles/rundownView.scss`:
- Around line 1326-1376: The two CSS classes
.segment-timeline__part__invalid-cover and
.segment-timeline__part__invalid-part-instance-cover duplicate most properties
except stripe spacing; extract a SCSS mixin (e.g.,
invalid-cover-base($stripe-width)) that contains the shared positioning,
z-index, pointer-events, mix-blend-mode and the two repeating-linear-gradient
definitions parameterized by the stripe width, then replace each class body to
include that mixin with 5px and 6px respectively (refer to the class names
.segment-timeline__part__invalid-cover and
.segment-timeline__part__invalid-part-instance-cover and the new mixin name
invalid-cover-base).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f92b2852-1ffe-4766-a598-81c1aa6d5e73

📥 Commits

Reviewing files that changed from the base of the PR and between bb2a27d and 705847e.

📒 Files selected for processing (33)
  • meteor/server/publications/segmentPartNotesUI/__tests__/generateNotesForSegment.test.ts
  • meteor/server/publications/segmentPartNotesUI/__tests__/publication.test.ts
  • meteor/server/publications/segmentPartNotesUI/generateNotesForSegment.ts
  • meteor/server/publications/segmentPartNotesUI/publication.ts
  • meteor/server/publications/segmentPartNotesUI/reactiveContentCache.ts
  • meteor/server/publications/segmentPartNotesUI/rundownContentObserver.ts
  • packages/blueprints-integration/src/context/onSetAsNextContext.ts
  • packages/blueprints-integration/src/context/partsAndPieceActionContext.ts
  • packages/blueprints-integration/src/context/syncIngestChangesContext.ts
  • packages/blueprints-integration/src/documents/partInstance.ts
  • packages/corelib/src/dataModel/PartInstance.ts
  • packages/corelib/src/error.ts
  • packages/job-worker/src/blueprints/__tests__/context-OnSetAsNextContext.test.ts
  • packages/job-worker/src/blueprints/__tests__/context-OnTakeContext.test.ts
  • packages/job-worker/src/blueprints/__tests__/context-adlibActions.test.ts
  • packages/job-worker/src/blueprints/context/OnSetAsNextContext.ts
  • packages/job-worker/src/blueprints/context/OnTakeContext.ts
  • packages/job-worker/src/blueprints/context/SyncIngestUpdateToPartInstanceContext.ts
  • packages/job-worker/src/blueprints/context/adlibActions.ts
  • packages/job-worker/src/blueprints/context/lib.ts
  • packages/job-worker/src/blueprints/context/services/PartAndPieceInstanceActionService.ts
  • packages/job-worker/src/blueprints/context/services/__tests__/PartAndPieceInstanceActionService.test.ts
  • packages/job-worker/src/playout/model/PlayoutPartInstanceModel.ts
  • packages/job-worker/src/playout/model/implementation/PlayoutPartInstanceModelImpl.ts
  • packages/job-worker/src/playout/take.ts
  • packages/webui/src/client/lib/partInstanceUtil.ts
  • packages/webui/src/client/styles/rundownView.scss
  • packages/webui/src/client/ui/SegmentList/LinePart.tsx
  • packages/webui/src/client/ui/SegmentList/LinePartTimeline.tsx
  • packages/webui/src/client/ui/SegmentStoryboard/SegmentStoryboard.scss
  • packages/webui/src/client/ui/SegmentStoryboard/StoryboardPart.tsx
  • packages/webui/src/client/ui/SegmentTimeline/Parts/InvalidPartCover.tsx
  • packages/webui/src/client/ui/SegmentTimeline/Parts/SegmentTimelinePart.tsx

Comment on lines +130 to +132
// Get effective invalidReason: planned (Part) takes precedence over runtime (PartInstance)
const effectiveInvalidReason = getEffectiveInvalidReason(part.instance)
const isInvalid = isPartInstanceInvalid(part.instance)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use the runtime-aware invalid flag everywhere in this component.

After introducing isInvalid, Line 249 still gates the segment-end marker with !part.instance.part.invalid. Runtime-invalid parts will therefore keep showing the segment-end affordance even though the rest of this component treats them as invalid. Switch that guard to !isInvalid to keep the storyboard visuals consistent with the new state.

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

In `@packages/webui/src/client/ui/SegmentStoryboard/StoryboardPart.tsx` around
lines 130 - 132, The segment-end marker visibility is still using the static
flag part.instance.part.invalid instead of the runtime-aware isInvalid; update
the guard that currently checks !part.instance.part.invalid to use !isInvalid so
the segment-end marker follows the same runtime-invalid logic used elsewhere
(see getEffectiveInvalidReason and isPartInstanceInvalid usages) and keep
visuals consistent across StoryboardPart.

Comment on lines +691 to +693
// Get effective invalidReason: planned (Part) takes precedence over runtime (PartInstance)
const effectiveInvalidReason = getEffectiveInvalidReason(partInstance)
const isInvalid = isPartInstanceInvalid(partInstance)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace the remaining innerPart.invalid checks with isInvalid.

This file now computes runtime-aware invalidity, but several UI branches still key off planned invalidity only. In particular, Lines 724, 781, 794, 816, 828, and the checks inside renderEndOfSegment still use innerPart.invalid, so a runtime-invalid next part can continue to render as next/auto-next and show end-of-segment affordances. Thread isInvalid through those paths as well.

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

In `@packages/webui/src/client/ui/SegmentTimeline/Parts/SegmentTimelinePart.tsx`
around lines 691 - 693, Several UI branches in SegmentTimelinePart still check
the planned-only flag innerPart.invalid instead of the runtime-aware
isInvalid/effectiveInvalidReason; this lets runtime-invalid parts render as
next/auto-next and show end-of-segment affordances. Update all those branches to
use the computed isInvalid (and where relevant effectiveInvalidReason) instead
of innerPart.invalid — specifically replace checks of innerPart.invalid in the
conditional logic around next/auto-next rendering and inside renderEndOfSegment
with isInvalid so runtime invalidity flows through; ensure the same symbols
(isPartInstanceInvalid, getEffectiveInvalidReason, isInvalid,
effectiveInvalidReason, renderEndOfSegment, innerPart) are used to locate and
update the conditionals.

@Julusian Julusian added the Contribution from BBC Contributions sponsored by BBC (bbc.co.uk) label May 12, 2026
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