Files
ersatztv/ErsatzTV.Application/Channels/ChannelGraphicsDefaults.cs
T
timothyandClaude Fable 5.1 352305ade8 fix(568): sync docs/comments to the seeded-path builtIn discriminator, harden UpdateDecoHandler's twin FK ids
Review round on #568 found the branch changed builtIn identity from a bare
filename comparison to the full seeded path (GraphicsElementDefaults.
OnNowNextSeededPath) but left several places still asserting the old rule:

- docs/decisions/records/graphics/channel-level-attachment.md and
  on-now-next-on-by-default.md (both status: active) still described a
  filename-only match; corrected in place and cross-referenced.
- docs/api-conventions.md §8 quoted the retired
  `Path.GetFileName(element.Path) == OnNowNextFileName` expression verbatim;
  replaced with the current OnNowNextSeededPath comparison and a note on the
  UpdateChannelHandler 422 hardening.
- Three in-code comments (GraphicsElementDefaults.cs, GraphicsElementSeeder.cs,
  ChannelGraphicsDefaults.cs) still said "identity is the filename".
- docs/graphics-elements.md's mutation-coverage table (row 10, row 18) named
  clauses that no longer exist or no longer redden any test post-#568;
  re-measured directly (removing the seeded-path check reddens
  Ignores_A_Non_Built_In_Element_With_A_Different_Filename and
  Ignores_A_Same_Named_Same_Kind_Element_Outside_The_Seeded_Folder; removing
  the Kind==Text filter alone reddens nothing, so it moves to the "known
  clauses with no red" list with that measurement dated).

Also closed the should-fix twin: UpdateDecoHandler's graphicsElementIds and
watermarkIds are top-level ReplaceDecoRequest fields in the same position as
UpdateChannelRequest.graphicsElementIds (not the deep-FK-in-a-nested-list
carve-out), and the reconcile in ApplyUpdateRequest blindly Added a join row
for any incoming id -- the identical FK-constraint-to-500 defect #568 fixed
on the channel path. Added GraphicsElementIdsMustExist/WatermarkIdsMustExist
validators mirroring UpdateChannelHandler's, pinned by
UpdateDecoGraphicsElementsTests (reddens when either validator alone is
removed -- verified).

Decisions-Edit: yes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
2026-09-05 21:35:14 +02:00

45 lines
2.1 KiB
C#

using ErsatzTV.Core.Domain;
using ErsatzTV.FFmpeg.State;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Streaming.Graphics;
namespace ErsatzTV.Application.Channels;
/// <summary>
/// #732: the On Now / Next overlay is a default rather than an opt-in, so every newly created channel
/// gets the built-in element attached.
/// </summary>
/// <remarks>
/// This lives in one place because there is more than one channel-creation path and they diverged
/// once already: <c>CreateChannelHandler</c> had it and <c>CreateChannelFromLineupHandler</c> -- the
/// SPA's primary "Add Channel" flow, and the one Auto-Tune bulk-creates through -- did not. Any new
/// site that persists a <c>Channel</c> must call this. The third site, <c>DbInitializer</c>'s default
/// channel, needs no call: it runs before <c>AttachOnNowNextByDefault</c> in the same startup, so the
/// backfill covers it.
/// </remarks>
public static class ChannelGraphicsDefaults
{
public static async Task Attach(TvContext dbContext, Channel channel, CancellationToken cancellationToken)
{
// HLS Direct is skipped because ErsatzTV is not transcoding there -- there is no frame
// pipeline to draw into, and the editor disables the toggle for the same reason. Identity is
// the element's full seeded path (`GraphicsElementDefaults.OnNowNextSeededPath`), never its
// user-editable Name (the #67 lesson, sharpened from filename to full path by #568).
if (channel.StreamingMode is StreamingMode.HttpLiveStreamingDirect)
{
return;
}
Option<int> maybeElementId =
await GraphicsElementSeeder.GetBuiltInElementId(dbContext, cancellationToken);
foreach (int elementId in maybeElementId)
{
// Add rather than assign: a future create path that carries graphics ids would otherwise
// be silently discarded here.
channel.ChannelGraphicsElements ??= [];
channel.ChannelGraphicsElements.Add(new ChannelGraphicsElement { GraphicsElementId = elementId });
}
}
}