---
key: sched.clock-padding-existing
title: '2026-07-17 — Clock-boundary schedule padding already exists (FillerMode.Pad); #77 verified, convenience toggle deferred'
status: active
since: '2026-07-17'
supersedes: none
superseded-by: none
rule: 'Clock-boundary padding already exists via `FillerPreset`''s `FillerMode.Pad` (Classic) and `pad_to_next`/`pad_until` (Sequential/YAML); #77 is closed as verified+documented, not built new, with a one-click per-channel toggle deferred behind the #388 design-system epic.'
signals: 'clock padding, FillerMode.Pad, pad_to_next, EPG guide-stop coalescing · paths: `PlayoutModeSchedulerBase.AddFiller`, `ChannelGuideProjector.ProjectFlood`, `/app/filler-presets` · issues: #77, #388'
mechanics: '`PlayoutBuildGoldenTests.Classic_clock_padded`, `ChannelGuideProjectorClockPadTests`'
---

#77 asked to "pad/snap channel schedules to clock boundaries (:00/:15/:30) using filler" — a Tunarr
"Pad Times" analogue for broadcast-looking guides. Investigation found the **core is already
implemented** (upstream ErsatzTV machinery carried into the fork), so #77 was scoped to *verification +
documentation* rather than a new feature:

- **Classic playouts**: a `FillerPreset` with `FillerMode.Pad` + `PadToNearestMinute = N` snaps each
  content item up to the next N-minute clock mark, filling the gap with the preset's filler collection
  (falling back to the item/channel fallback filler). The boundary math is a ceiling-to-the-next-multiple
  on the local minute with seconds zeroed (`PlayoutModeSchedulerBase.AddFiller`, the `FillerMode.Pad`
  block). Live SPA editor at `/app/filler-presets` (increment options 5/10/15/30).
- **Sequential (YAML) playouts**: the `pad_to_next: N` and `pad_until: "HH:mm"` instructions do the same,
  reusing the identical boundary formula.
- **Block playouts**: no per-item Pad, and none is needed — Block is inherently clock-anchored (each
  `Block` starts at a fixed `TemplateItem.StartTime`), so it already yields clean guide times.
- **EPG reflects the padding with no extra code**: `ChannelGuideProjector.ProjectFlood` coalesces trailing
  PostRoll/Tail/GuideMode/Fallback/DecoDefault filler into the programme window, so a programme's `Stop` is
  the padded boundary (the filler run's finish), not the raw content finish.

**What this decision fixes in the record:** the issue's premise ("reverses an earlier not-adopting call")
predates the machinery; do not re-implement pad-to-boundary from scratch. Two deterministic tests lock the
behaviour end-to-end (chosen over a one-off live-E2E because #77 changed **no production code**, so the
live-E2E's write-path/500 justification does not apply): `PlayoutBuildGoldenTests.Classic_clock_padded`
(schedule → `PlayoutItem`s land on :15 through the real `PlayoutBuilder`) and
`ChannelGuideProjectorClockPadTests` (those items → guide programmes stop on :15).

**Deferred (UI-gated):** the only real residual is *convenience* — there is no one-click per-channel /
per-schedule "clock-align this whole channel" toggle; today you hand-build a Pad `FillerPreset` and wire it
into a schedule item's roll slot. That toggle is mostly SPA work and is deferred to a follow-up **blocked on
the #388 design-system sync epic** (all UI work is currently gated on #388), which also covers adding a
60-minute increment to the filler-preset editor's options (the backend already accepts any integer).
